theloftstore/public/userarea/save_column_mapping.php
2025-07-07 11:39:56 +02:00

412 lines
22 KiB
PHP

<?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 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);
?>
<!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>
<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>