new template schema

This commit is contained in:
Claudio 2025-07-07 11:39:56 +02:00
parent 78089cadc1
commit b092abf8c7
15 changed files with 996 additions and 47 deletions

View File

@ -31,6 +31,6 @@ Content-Length: 51
< strict-transport-security: max-age=2592000
< x-powered-by: ASP.NET
< x-content-type-options: nosniff
< date: Fri, 04 Jul 2025 16:25:36 GMT
< date: Mon, 07 Jul 2025 09:08:43 GMT
<
* Connection #0 to host 93.43.5.102 left intact

View File

@ -10,19 +10,26 @@
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/Cliente
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/SchemaCustomField
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: 93.43.5.102]
* [HTTP/2] [1] [:path: /limsapi/api/odata/Cliente]
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1MTY1MzUzNiwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.uKseoLi3vffY69suryyXBm3DsL83Cfz8P8_lLgLcjak]
* [HTTP/2] [1] [:path: /limsapi/api/odata/SchemaCustomField]
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1MTg4NjUyMywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.63LcA-ce-Jf1aQdZwd_GWXNLJSGn38259WyoqzxUgRc]
* [HTTP/2] [1] [accept: application/json]
> GET /limsapi/api/odata/Cliente HTTP/2
> GET /limsapi/api/odata/SchemaCustomField HTTP/2
Host: 93.43.5.102
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1MTY1MzUzNiwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.uKseoLi3vffY69suryyXBm3DsL83Cfz8P8_lLgLcjak
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1MTg4NjUyMywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.63LcA-ce-Jf1aQdZwd_GWXNLJSGn38259WyoqzxUgRc
Accept: application/json
* Recv failure: Connection was reset
* OpenSSL SSL_read: Connection was reset, errno 10054
* Failed receiving HTTP2 data: 56(Failure when receiving data from the peer)
< HTTP/2 200
< cache-control: max-age=0
< content-type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
< server: Microsoft-IIS/10.0
< strict-transport-security: max-age=2592000
< odata-version: 4.0
< x-powered-by: ASP.NET
< x-content-type-options: nosniff
< date: Mon, 07 Jul 2025 09:08:43 GMT
<
* Connection #0 to host 93.43.5.102 left intact

File diff suppressed because one or more lines are too long

View File

@ -41,3 +41,21 @@ https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField

View File

@ -0,0 +1,23 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once(__DIR__ . '/class/db-functions.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$template_id = $_GET['template_id'] ?? 0;
try {
$stmt = $pdo->prepare("SELECT id, field_id, excel_column, is_manual, manual_default, field_label FROM template_mapping WHERE template_id = ?");
$stmt->execute([$template_id]);
$mappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(["success" => true, "mappings" => $mappings]);
} catch (Exception $e) {
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
}
exit;

View File

@ -0,0 +1,461 @@
<?php include('include/headscript.php');
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
die("Invalid template ID");
}
$id = intval($_GET['id']);
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$stmt = $pdo->prepare("SELECT name, header_row, start_column, target_table, sample_xlsx, idclient, clientname, idschema, schemaname, schemajson, xls_headers FROM excel_templates WHERE id = ?");
$stmt->execute([$id]);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$template) {
die("Template not found");
}
$clientName = $template['clientname'] ?: '';
$schemaName = $template['schemaname'] ?: '';
$schemajson = $template['schemajson'] ? json_decode($template['schemajson'], true) : [];
$isSchemajsonEmpty = empty(trim($template['schemajson']));
// Recupera i campi dalla tabella template_mapping
$stmt = $pdo->prepare("SELECT id, field_id, excel_column, is_manual, manual_default, data_type, is_required, default_value, has_list, length, decimals, min_value, max_value, default_curr_date, tablename, field_label FROM template_mapping WHERE template_id = ?");
$stmt->execute([$id]);
$mappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Recupera le colonne già associate nel database
$usedColumnsFromDB = array_filter(array_column($mappings, 'excel_column'));
// Decodifica l'header XLS salvato, se presente
$xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], true) : [];
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<title>Configure Template <?= htmlspecialchars($template['name'], ENT_QUOTES, 'UTF-8'); ?></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<?php include('top_stat_widget.php'); ?>
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Configure Template: <span id="templateName"><?php echo htmlspecialchars($template['name']); ?></span></h6>
<p>
Client: <span id="clientName"><?php echo htmlspecialchars($clientName); ?></span> |
Schema: <span id="schemaName"><?php echo htmlspecialchars($schemaName); ?></span> |
Header Row: <span id="headerRow"><?php echo $template['header_row']; ?></span> |
Start Column: <span id="startColumn"><?php echo htmlspecialchars($template['start_column']); ?></span>
</p>
</div>
</div>
</div>
<div class="card-body">
<div class="mb-4">
<label class="form-label">Upload XLS Example:</label>
<input type="file" id="xlsUpload" class="form-control">
<small id="uploadStatus">
<?php if (!empty($template['sample_xlsx'])): ?>
Current file: <a href="xlstemplates/<?php echo htmlspecialchars($template['sample_xlsx']); ?>" target="_blank"><?php echo htmlspecialchars($template['sample_xlsx']); ?></a>
<?php else: ?>
No file uploaded yet.
<?php endif; ?>
</small>
</div>
<div class="row">
<div class="col-12">
<div class="d-flex align-items-center mb-2">
<h5>Schema Fields Configuration</h5>
<button id="updateSchemaButton" class="btn btn-primary ms-2" data-empty="<?php echo $isSchemajsonEmpty ? 'true' : 'false'; ?>">
<?php echo $isSchemajsonEmpty ? 'Load Schema Details' : 'Update Schema Details'; ?>
</button>
</div>
<table id="schemaFieldsTable" class="table table-striped">
<thead>
<tr>
<th>Title</th>
<th>ID</th>
<th>Type</th>
<th>Mapping</th>
<th>Default Value</th>
</tr>
</thead>
<tbody id="schemaFieldsBody">
<?php foreach ($mappings as $mapping): ?>
<tr>
<td><?php echo htmlspecialchars($mapping['field_label'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($mapping['field_id'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($mapping['data_type'] ?? 'N/A'); ?></td>
<td>
<select class="form-select mapping-select" data-id="<?php echo $mapping['id']; ?>" data-field-id="<?php echo $mapping['field_id']; ?>">
<option value="">Select Option</option>
<option value="xls" <?php echo !$mapping['is_manual'] && $mapping['excel_column'] ? 'selected' : ''; ?>>Map to XLS Column</option>
<option value="manual" <?php echo $mapping['is_manual'] ? 'selected' : ' '; ?>>Manual Entry</option>
</select>
<select class="form-select xls-columns" style="display:<?php echo !$mapping['is_manual'] && $mapping['excel_column'] ? 'block' : 'none'; ?>" data-id="<?php echo $mapping['id']; ?>" <?php echo $mapping['excel_column'] ? 'data-current-xls="' . htmlspecialchars($mapping['excel_column']) . '"' : ''; ?>></select>
<?php if ($mapping['excel_column']): ?>
<span class="mapped-column" style="margin-left: 5px;"><?php echo htmlspecialchars($mapping['excel_column']); ?></span>
<button class="btn btn-danger btn-sm remove-xls" data-id="<?php echo $mapping['id']; ?>" style="margin-left: 5px;">X</button>
<?php endif; ?>
</td>
<td>
<input type="text" class="form-control manual-default" placeholder="Default value" value="<?php echo htmlspecialchars($mapping['manual_default'] ?? ''); ?>" style="display:<?php echo $mapping['is_manual'] ? 'block' : 'none'; ?>" data-field-id="<?php echo $mapping['field_id']; ?>">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="mt-4 text-end">
<a href="templates_dashboard.php" class="btn btn-primary"> Back to Template Dashboard</a>
</div>
</div>
</div>
</div>
</div>
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script>
let availableXlsColumns = <?php echo json_encode($xlsHeaders); ?> || [];
let usedColumnsFromDB = <?php echo json_encode($usedColumnsFromDB); ?> || [];
document.getElementById('xlsUpload').addEventListener('change', function(event) {
let file = event.target.files[0];
if (!file) return;
let formData = new FormData();
formData.append("xls_file", file);
formData.append("template_id", <?php echo $id; ?>);
let statusText = document.getElementById('uploadStatus');
statusText.innerText = "Uploading...";
fetch('upload_xls_example.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (!data.success) {
statusText.innerText = "❌ Upload failed: " + data.message;
return;
}
statusText.innerHTML = `✅ File uploaded: <a href="xlstemplates/${data.filename}" target="_blank">${data.filename}</a>`;
processXLSX(file);
})
.catch(error => {
statusText.innerText = "❌ Upload failed. Check console.";
console.error(error);
});
});
function processXLSX(file) {
let reader = new FileReader();
reader.onload = function(e) {
let data = new Uint8Array(e.target.result);
let workbook = XLSX.read(data, {
type: 'array'
});
let sheet = workbook.Sheets[workbook.SheetNames[0]];
let rowIndex = parseInt(document.getElementById('headerRow').textContent) || 1;
let startColumn = parseInt(document.getElementById('startColumn').textContent.charCodeAt(0) - 64) || 1;
let sheetData = XLSX.utils.sheet_to_json(sheet, {
header: 1,
defval: "",
raw: false,
range: 0
});
if (!sheetData[rowIndex - 1]) {
document.getElementById('schemaFieldsBody').querySelectorAll('select.xls-columns').forEach(select => {
select.innerHTML = '<option value="">No headers found</option>';
});
return;
}
let headers = sheetData[rowIndex - 1].slice(startColumn - 1).filter(header => header !== undefined && header.trim() !== "");
availableXlsColumns = [...headers];
usedColumnsFromDB = []; // Resetta le colonne usate dal DB dopo un nuovo caricamento
saveXlsHeaders(headers);
updateXlsDropdowns();
};
reader.readAsArrayBuffer(file);
}
function saveXlsHeaders(headers) {
fetch('update_xls_headers.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: <?php echo $id; ?>,
xls_headers: JSON.stringify(headers)
})
}).then(response => response.json())
.then(data => {
if (!data.success) console.error("❌ Error saving XLS headers:", data.message);
})
.catch(error => console.error("❌ Fetch error:", error));
}
function updateXlsDropdowns() {
let usedColumns = Array.from(document.querySelectorAll('select.xls-columns'))
.filter(select => select.style.display === 'block' && select.value)
.map(select => select.value)
.concat(usedColumnsFromDB); // Aggiunge le colonne già salvate nel DB
document.querySelectorAll('select.xls-columns').forEach(select => {
let currentValue = select.value || select.dataset.currentXls || '';
let options = availableXlsColumns
.filter(col => !usedColumns.includes(col) || col === currentValue) // Esclude colonne già usate, tranne la corrente
.map(col => `<option value="${col}" ${col === currentValue ? 'selected' : ''}>${col}</option>`)
.join('');
select.innerHTML = '<option value="">Select XLS Column</option>' + options;
select.dataset.currentXls = currentValue;
if (currentValue && !options.includes(currentValue)) {
select.value = ''; // Reset se il valore non è più valido
}
});
}
document.addEventListener("DOMContentLoaded", function() {
let templateId = <?php echo $id; ?>;
let schemaId = <?php echo json_encode($template['idschema'] ?? 0); ?>;
let isSchemajsonEmpty = <?php echo json_encode($isSchemajsonEmpty); ?>;
async function loadClientAndSchemaNames() {
if (<?php echo json_encode($template['idclient'] ?? 0); ?> > 0) {
let response = await fetch(`get_clienti.php?id=<?php echo $template['idclient']; ?>`);
let data = await response.json();
if (response.ok && data.value?.length) document.getElementById('clientName').textContent = data.value[0].Nominativo || 'N/A';
}
if (schemaId > 0) {
let response = await fetch(`get_schemi.php?id=${schemaId}`);
let data = await response.json();
if (response.ok && data.value?.length) document.getElementById('schemaName').textContent = data.value[0].Nome || 'N/A';
}
}
loadClientAndSchemaNames();
async function updateSchemaDetails() {
if (!schemaId) {
document.getElementById('schemaFieldsBody').innerHTML = '<tr><td colspan="5" class="text-warning">No schema associated.</td></tr>';
return;
}
let updateSchemaButton = document.getElementById('updateSchemaButton');
updateSchemaButton.disabled = true;
updateSchemaButton.textContent = 'Loading...';
try {
let response = await fetch(`get_schema_details.php?id=${schemaId}`);
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
let data = JSON.parse(await response.text());
if (!data.SchemiCustomFieldsDettagli) throw new Error('Missing "SchemiCustomFieldsDettagli"');
await saveSchemaJson(templateId, JSON.stringify(data));
alert('Schema updated successfully. Refresh the page to see changes.');
} catch (error) {
document.getElementById('schemaFieldsBody').innerHTML = '<tr><td colspan="5" class="text-danger">Error: ' + error.message + '</td></tr>';
} finally {
updateSchemaButton.disabled = false;
updateSchemaButton.textContent = 'Update Schema Details';
}
}
async function saveSchemaJson(templateId, schemaJson) {
let response = await fetch('update_schemajson.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: templateId,
schemajson: schemaJson
})
});
let data = await response.json();
if (!data.success) throw new Error(data.message || 'Failed to save schema JSON');
}
document.getElementById('updateSchemaButton').addEventListener('click', updateSchemaDetails);
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (event.target.classList.contains('mapping-select')) {
let tr = event.target.closest('tr');
let mappingId = event.target.getAttribute('data-id');
let xlsSelect = tr.querySelector('.xls-columns');
let manualInput = tr.querySelector('.manual-default');
let mappedColumn = tr.querySelector('.mapped-column');
let removeBtn = tr.querySelector('.remove-xls');
if (event.target.value === 'xls') {
xlsSelect.style.display = 'block';
manualInput.style.display = 'none';
manualInput.value = '';
if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = xlsSelect.value ? 'inline-block' : 'none';
} else if (event.target.value === 'manual') {
xlsSelect.style.display = 'none';
manualInput.style.display = 'block';
if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = 'none';
} else {
xlsSelect.style.display = 'none';
manualInput.style.display = 'none';
manualInput.value = '';
if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = 'none';
}
saveMapping(mappingId, event.target.value, manualInput.value, xlsSelect.value);
updateXlsDropdowns();
}
});
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (event.target.classList.contains('xls-columns')) {
let tr = event.target.closest('tr');
let mappingId = event.target.getAttribute('data-id');
let manualInput = tr.querySelector('.manual-default');
let mappedColumn = tr.querySelector('.mapped-column');
let removeBtn = tr.querySelector('.remove-xls');
// Aggiungi dinamicamente mappedColumn e removeBtn se non esistono
if (!mappedColumn) {
mappedColumn = document.createElement('span');
mappedColumn.className = 'mapped-column';
mappedColumn.style.marginLeft = '5px';
tr.querySelector('td:nth-child(4)').appendChild(mappedColumn);
}
if (!removeBtn) {
removeBtn = document.createElement('button');
removeBtn.className = 'btn btn-danger btn-sm remove-xls';
removeBtn.textContent = 'X';
removeBtn.style.marginLeft = '5px';
removeBtn.setAttribute('data-id', mappingId);
tr.querySelector('td:nth-child(4)').appendChild(removeBtn);
// Aggiungi l'event listener per il nuovo pulsante
removeBtn.addEventListener('click', function(e) {
let tr = e.target.closest('tr');
let xlsSelect = tr.querySelector('.xls-columns');
let mappingSelect = tr.querySelector('.mapping-select');
xlsSelect.value = '';
xlsSelect.style.display = 'none';
mappingSelect.value = '';
if (mappedColumn) mappedColumn.style.display = 'none';
e.target.style.display = 'none';
saveMapping(mappingId, '', '', null);
updateXlsDropdowns();
});
}
console.log("XLS Column changed:", {
id: mappingId,
value: event.target.value
});
if (mappedColumn) {
mappedColumn.textContent = event.target.value ? `(${event.target.value})` : '';
mappedColumn.style.display = event.target.value ? 'inline' : 'none';
}
if (removeBtn) removeBtn.style.display = event.target.value ? 'inline-block' : 'none';
saveMapping(mappingId, 'xls', manualInput.value, event.target.value);
updateXlsDropdowns();
}
});
document.getElementById('schemaFieldsBody').addEventListener('input', function(event) {
if (event.target.classList.contains('manual-default')) {
let tr = event.target.closest('tr');
let mappingId = tr.querySelector('.mapping-select').getAttribute('data-id');
let xlsSelect = tr.querySelector('.xls-columns');
console.log("Manual default changed:", {
id: mappingId,
value: event.target.value
});
saveMapping(mappingId, 'manual', event.target.value, xlsSelect.value);
}
});
document.getElementById('schemaFieldsBody').addEventListener('click', function(event) {
if (event.target.classList.contains('remove-xls')) {
let mappingId = event.target.getAttribute('data-id');
let tr = event.target.closest('tr');
let xlsSelect = tr.querySelector('.xls-columns');
let mappingSelect = tr.querySelector('.mapping-select');
let mappedColumn = tr.querySelector('.mapped-column');
xlsSelect.value = '';
xlsSelect.style.display = 'none';
mappingSelect.value = '';
if (mappedColumn) mappedColumn.style.display = 'none';
event.target.style.display = 'none';
console.log("Removing XLS mapping:", {
id: mappingId
});
saveMapping(mappingId, '', '', null);
updateXlsDropdowns();
}
});
function saveMapping(mappingId, mappingType, defaultValue, excelColumn) {
console.log("Saving mapping:", {
id: mappingId,
mapping_type: mappingType,
excel_column: excelColumn,
manual_default: defaultValue
});
fetch('save_mapping_json.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: mappingId,
mapping_type: mappingType,
excel_column: mappingType === 'xls' ? excelColumn : null,
manual_default: mappingType === 'manual' ? defaultValue : null,
tablename: "<?php echo $template['target_table']; ?>"
})
}).then(response => response.json())
.then(data => {
console.log("Save response:", data);
if (!data.success) console.error("❌ Error saving mapping:", data.message);
if (data.success && excelColumn) {
usedColumnsFromDB = usedColumnsFromDB.filter(col => col !== excelColumn); // Rimuovi dalla lista se salvata
usedColumnsFromDB.push(excelColumn); // Aggiungi la nuova colonna usata
updateXlsDropdowns();
}
})
.catch(error => console.error("❌ Fetch error:", error));
}
if (availableXlsColumns.length) updateXlsDropdowns();
});
</script>
</body>
</html>

View File

@ -1,46 +1,412 @@
<?php
header('Content-Type: application/json'); // Forza la risposta JSON
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
<?php include('include/headscript.php');
require_once(__DIR__ . '/class/db-functions.php'); // Include la classe di connessione
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
die("Invalid template ID");
}
$id = intval($_GET['id']);
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection(); // Ottieni la connessione
$pdo = $db->getConnection();
$stmt = $pdo->prepare("SELECT name, header_row, start_column, target_table, sample_xlsx, idclient, clientname, idschema, schemaname, schemajson FROM excel_templates WHERE id = ?");
$stmt->execute([$id]);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
$data = json_decode(file_get_contents("php://input"), true);
if (!$data) {
echo json_encode(["success" => false, "message" => "Invalid JSON input"]);
exit;
if (!$template) {
die("Template not found");
}
if (!isset($data['template_id'], $data['tablename'], $data['excel_column'], $data['mysql_column'])) {
echo json_encode(["success" => false, "message" => "Missing required fields"]);
exit;
}
$clientName = $template['clientname'] ?: '';
$schemaName = $template['schemaname'] ?: '';
$schemajson = $template['schemajson'] ? json_decode($template['schemajson'], true) : [];
$isSchemajsonEmpty = empty(trim($template['schemajson']));
$stmt = $pdo->prepare("
INSERT INTO excel_column_mappings
(template_id, tablename, excel_column, mysql_column, data_type, is_required, default_value, headerexcel)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
");
$result = $stmt->execute([
$data['template_id'],
$data['tablename'],
$data['excel_column'],
$data['mysql_column'],
$data['data_type'],
$data['is_required'],
$data['default_value'],
$data['headerexcel']
]);
// Recupera i campi dalla tabella template_mapping
$stmt = $pdo->prepare("SELECT id, field_id, excel_column, is_manual, manual_default, data_type, is_required, default_value, has_list, length, decimals, min_value, max_value, default_curr_date, tablename, field_label FROM template_mapping WHERE template_id = ?");
$stmt->execute([$id]);
$mappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
if (!$result) {
echo json_encode(["success" => false, "message" => "Database insert failed"]);
exit;
}
<!doctype html>
<html lang="en">
echo json_encode(["success" => true]);
exit;
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<title>Configure Template <?= htmlspecialchars($template['name'], ENT_QUOTES, 'UTF-8'); ?></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<?php include('top_stat_widget.php'); ?>
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Configure Template: <span id="templateName"><?php echo htmlspecialchars($template['name']); ?></span></h6>
<p>
Client: <span id="clientName"><?php echo htmlspecialchars($clientName); ?></span> |
Schema: <span id="schemaName"><?php echo htmlspecialchars($schemaName); ?></span> |
Header Row: <span id="headerRow"><?php echo $template['header_row']; ?></span> |
Start Column: <span id="startColumn"><?php echo htmlspecialchars($template['start_column']); ?></span>
</p>
</div>
</div>
</div>
<div class="card-body">
<div class="mb-4">
<label class="form-label">Upload XLS Example:</label>
<input type="file" id="xlsUpload" class="form-control">
<small id="uploadStatus">
<?php if (!empty($template['sample_xlsx'])): ?>
Current file: <a href="xlstemplates/<?php echo htmlspecialchars($template['sample_xlsx']); ?>" target="_blank"><?php echo htmlspecialchars($template['sample_xlsx']); ?></a>
<?php else: ?>
No file uploaded yet.
<?php endif; ?>
</small>
</div>
<div class="row">
<div class="col-12">
<div class="d-flex align-items-center mb-2">
<h5>Schema Fields Configuration</h5>
<button id="updateSchemaButton" class="btn btn-primary ms-2" data-empty="<?php echo $isSchemajsonEmpty ? 'true' : 'false'; ?>">
<?php echo $isSchemajsonEmpty ? 'Load Schema Details' : 'Update Schema Details'; ?>
</button>
</div>
<table id="schemaFieldsTable" class="table table-striped">
<thead>
<tr>
<th>Title</th>
<th>ID</th>
<th>Type</th>
<th>Mapping</th>
<th>Default Value</th>
<th>Action</th>
</tr>
</thead>
<tbody id="schemaFieldsBody">
<?php foreach ($mappings as $mapping): ?>
<tr>
<td><?php echo htmlspecialchars($mapping['field_label'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($mapping['field_id'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($mapping['data_type'] ?? 'N/A'); ?></td>
<td>
<select class="form-select mapping-select" data-id="<?php echo $mapping['id']; ?>" data-field-id="<?php echo $mapping['field_id']; ?>">
<option value="">Select Option</option>
<option value="xls" <?php echo !$mapping['is_manual'] && $mapping['excel_column'] ? 'selected' : ''; ?>>Map to XLS Column</option>
<option value="manual" <?php echo $mapping['is_manual'] ? 'selected' : ''; ?>>Manual Entry</option>
</select>
<select class="form-select xls-columns" style="display:<?php echo !$mapping['is_manual'] && $mapping['excel_column'] ? 'block' : 'none'; ?>" data-id="<?php echo $mapping['id']; ?>"></select>
</td>
<td>
<input type="text" class="form-control manual-default" placeholder="Default value" value="<?php echo htmlspecialchars($mapping['manual_default'] ?? ''); ?>" style="display:<?php echo $mapping['is_manual'] ? 'block' : 'none'; ?>" data-field-id="<?php echo $mapping['field_id']; ?>">
</td>
<td>
<?php if ($mapping['excel_column']): ?>
<button class="btn btn-danger btn-sm remove-association" data-id="<?php echo $mapping['id']; ?>">Remove</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="mt-4">
<h5>Current Configurations</h5>
<ul id="configurationsList" class="list-group border p-3"></ul>
</div>
<div class="mt-4 text-end">
<a href="templates_dashboard.php" class="btn btn-primary"> Back to Template Dashboard</a>
</div>
</div>
</div>
</div>
</div>
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script>
let availableXlsColumns = [];
document.getElementById('xlsUpload').addEventListener('change', function(event) {
let file = event.target.files[0];
if (!file) return;
let formData = new FormData();
formData.append("xls_file", file);
formData.append("template_id", <?php echo $id; ?>);
let statusText = document.getElementById('uploadStatus');
statusText.innerText = "Uploading...";
fetch('upload_xls_example.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (!data.success) {
statusText.innerText = "❌ Upload failed: " + data.message;
return;
}
statusText.innerHTML = `✅ File uploaded: <a href="xlstemplates/${data.filename}" target="_blank">${data.filename}</a>`;
processXLSX(file);
})
.catch(error => {
statusText.innerText = "❌ Upload failed. Check console.";
console.error(error);
});
});
function processXLSX(file) {
let reader = new FileReader();
reader.onload = function(e) {
let data = new Uint8Array(e.target.result);
let workbook = XLSX.read(data, {
type: 'array'
});
let sheet = workbook.Sheets[workbook.SheetNames[0]];
let rowIndex = parseInt(document.getElementById('headerRow').textContent) || 1;
let startColumn = parseInt(document.getElementById('startColumn').textContent.charCodeAt(0) - 64) || 1;
let sheetData = XLSX.utils.sheet_to_json(sheet, {
header: 1,
defval: "",
raw: false,
range: 0
});
if (!sheetData[rowIndex - 1]) {
document.getElementById('schemaFieldsBody').querySelectorAll('select.xls-columns').forEach(select => {
select.innerHTML = '<option value="">No headers found</option>';
});
return;
}
let headers = sheetData[rowIndex - 1].slice(startColumn - 1).filter(header => header !== undefined && header.trim() !== "");
availableXlsColumns = [...headers]; // Memorizza tutte le colonne disponibili
updateXlsDropdowns();
};
reader.readAsArrayBuffer(file);
}
function updateXlsDropdowns() {
let usedColumns = Array.from(document.querySelectorAll('select.xls-columns'))
.filter(select => select.style.display === 'block' && select.value)
.map(select => select.value);
document.querySelectorAll('select.xls-columns').forEach(select => {
let currentValue = select.value || select.dataset.currentXls || '';
let options = availableXlsColumns
.filter(col => !usedColumns.includes(col) || col === currentValue)
.map(col => `<option value="${col}" ${col === currentValue ? 'selected' : ''}>${col}</option>`)
.join('');
select.innerHTML = '<option value="">Select XLS Column</option>' + options;
select.dataset.currentXls = currentValue;
});
}
document.addEventListener("DOMContentLoaded", function() {
let templateId = <?php echo $id; ?>;
let schemaId = <?php echo json_encode($template['idschema'] ?? 0); ?>;
let isSchemajsonEmpty = <?php echo json_encode($isSchemajsonEmpty); ?>;
async function loadClientAndSchemaNames() {
if (<?php echo json_encode($template['idclient'] ?? 0); ?> > 0) {
let response = await fetch(`get_clienti.php?id=<?php echo $template['idclient']; ?>`);
let data = await response.json();
if (response.ok && data.value?.length) document.getElementById('clientName').textContent = data.value[0].Nominativo || 'N/A';
}
if (schemaId > 0) {
let response = await fetch(`get_schemi.php?id=${schemaId}`);
let data = await response.json();
if (response.ok && data.value?.length) document.getElementById('schemaName').textContent = data.value[0].Nome || 'N/A';
}
}
loadClientAndSchemaNames();
async function updateSchemaDetails() {
if (!schemaId) {
document.getElementById('schemaFieldsBody').innerHTML = '<tr><td colspan="6" class="text-warning">No schema associated.</td></tr>';
return;
}
let updateSchemaButton = document.getElementById('updateSchemaButton');
updateSchemaButton.disabled = true;
updateSchemaButton.textContent = 'Loading...';
try {
let response = await fetch(`get_schema_details.php?id=${schemaId}`);
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
let data = JSON.parse(await response.text());
if (!data.SchemiCustomFieldsDettagli) throw new Error('Missing "SchemiCustomFieldsDettagli"');
await saveSchemaJson(templateId, JSON.stringify(data));
alert('Schema updated successfully. Refresh the page to see changes.');
} catch (error) {
document.getElementById('schemaFieldsBody').innerHTML = '<tr><td colspan="6" class="text-danger">Error: ' + error.message + '</td></tr>';
} finally {
updateSchemaButton.disabled = false;
updateSchemaButton.textContent = 'Update Schema Details';
}
}
async function saveSchemaJson(templateId, schemaJson) {
let response = await fetch('update_schemajson.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: templateId,
schemajson: schemaJson
})
});
let data = await response.json();
if (!data.success) throw new Error(data.message || 'Failed to save schema JSON');
}
document.getElementById('updateSchemaButton').addEventListener('click', updateSchemaDetails);
function loadConfigurations() {
fetch('load_mappings.php?template_id=' + templateId)
.then(response => response.json())
.then(data => {
if (!data.success) return;
let configurationsList = document.getElementById('configurationsList');
configurationsList.innerHTML = '';
data.mappings.forEach(mapping => {
let li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between align-items-center';
li.innerHTML = `${mapping.field_label} (${mapping.field_id}) → ${mapping.excel_column || 'Manual: ' + (mapping.manual_default || 'N/A')} <button class="btn btn-danger btn-sm removeMapping" data-id="${mapping.id}">X</button>`;
configurationsList.appendChild(li);
});
})
.catch(error => console.error("❌ Error fetching mappings:", error));
}
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (event.target.classList.contains('mapping-select')) {
let tr = event.target.closest('tr');
let mappingId = event.target.getAttribute('data-id');
let xlsSelect = tr.querySelector('.xls-columns');
let manualInput = tr.querySelector('.manual-default');
let removeBtn = tr.querySelector('.remove-association');
if (event.target.value === 'xls') {
xlsSelect.style.display = 'block';
manualInput.style.display = 'none';
manualInput.value = '';
removeBtn.style.display = xlsSelect.value ? 'inline-block' : 'none';
} else if (event.target.value === 'manual') {
xlsSelect.style.display = 'none';
manualInput.style.display = 'block';
removeBtn.style.display = 'none';
} else {
xlsSelect.style.display = 'none';
manualInput.style.display = 'none';
manualInput.value = '';
removeBtn.style.display = 'none';
}
saveMapping(mappingId, event.target.value, manualInput.value, xlsSelect.value);
updateXlsDropdowns();
}
});
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (event.target.classList.contains('xls-columns')) {
let tr = event.target.closest('tr');
let mappingId = event.target.getAttribute('data-id');
let manualInput = tr.querySelector('.manual-default');
let removeBtn = tr.querySelector('.remove-association');
removeBtn.style.display = event.target.value ? 'inline-block' : 'none';
saveMapping(mappingId, 'xls', manualInput.value, event.target.value);
updateXlsDropdowns();
}
});
document.getElementById('schemaFieldsBody').addEventListener('input', function(event) {
if (event.target.classList.contains('manual-default')) {
let tr = event.target.closest('tr');
let mappingId = tr.querySelector('.mapping-select').getAttribute('data-id');
let xlsSelect = tr.querySelector('.xls-columns');
saveMapping(mappingId, 'manual', event.target.value, xlsSelect.value);
}
});
document.getElementById('schemaFieldsBody').addEventListener('click', function(event) {
if (event.target.classList.contains('remove-association')) {
let mappingId = event.target.getAttribute('data-id');
let tr = event.target.closest('tr');
let xlsSelect = tr.querySelector('.xls-columns');
xlsSelect.value = '';
xlsSelect.style.display = 'none';
tr.querySelector('.mapping-select').value = '';
event.target.style.display = 'none';
saveMapping(mappingId, '', '', null);
updateXlsDropdowns();
}
});
function saveMapping(mappingId, mappingType, defaultValue, excelColumn) {
fetch('save_mapping_json.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: mappingId,
mapping_type: mappingType,
excel_column: mappingType === 'xls' ? excelColumn : null,
manual_default: mappingType === 'manual' ? defaultValue : null,
tablename: "<?php echo $template['target_table']; ?>"
})
}).then(response => response.json())
.then(data => {
if (data.success) loadConfigurations();
else console.error("❌ Error saving mapping:", data.message);
})
.catch(error => console.error("❌ Fetch error:", error));
}
document.getElementById('configurationsList').addEventListener('click', function(event) {
if (event.target.classList.contains('removeMapping')) {
let mappingId = event.target.getAttribute('data-id');
fetch('remove_mapping.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: mappingId
})
}).then(response => response.json())
.then(data => {
if (data.success) {
loadConfigurations();
updateXlsDropdowns(); // Aggiorna la tendina dopo la rimozione
} else console.error("❌ Error removing mapping:", data.message);
})
.catch(error => console.error("❌ Fetch error:", error));
}
});
loadConfigurations();
});
</script>
</body>
</html>

View File

@ -0,0 +1,39 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once(__DIR__ . '/class/db-functions.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$data = json_decode(file_get_contents("php://input"), true);
if (!$data || !isset($data['id'])) {
echo json_encode(["success" => false, "message" => "Invalid or missing ID"]);
exit;
}
$mappingId = $data['id'];
$mappingType = $data['mapping_type'] ?? '';
$excelColumn = $data['excel_column'] ?? null;
$manualDefault = $data['manual_default'] ?? null;
$tablename = $data['tablename'] ?? '';
try {
$stmt = $pdo->prepare("UPDATE template_mapping SET is_manual = ?, excel_column = ?, manual_default = ? WHERE id = ?");
$isManual = ($mappingType === 'manual') ? 1 : 0;
$result = $stmt->execute([$isManual, $excelColumn, $manualDefault, $mappingId]);
if (!$result) {
echo json_encode(["success" => false, "message" => "Database update failed"]);
exit;
}
echo json_encode(["success" => true, "message" => "Mapping updated successfully", "data" => $data]); // Aggiunto debug
} catch (Exception $e) {
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
}
exit;

View File

@ -0,0 +1,35 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once(__DIR__ . '/class/db-functions.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$data = json_decode(file_get_contents("php://input"), true);
if (!$data || !isset($data['template_id'], $data['xls_headers'])) {
echo json_encode(["success" => false, "message" => "Invalid or missing data"]);
exit;
}
$templateId = $data['template_id'];
$xlsHeaders = $data['xls_headers'];
try {
$stmt = $pdo->prepare("UPDATE excel_templates SET xls_headers = ? WHERE id = ?");
$result = $stmt->execute([$xlsHeaders, $templateId]);
if (!$result) {
echo json_encode(["success" => false, "message" => "Database update failed"]);
exit;
}
echo json_encode(["success" => true, "message" => "XLS headers saved successfully"]);
} catch (Exception $e) {
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
}
exit;