api change dahsboard
This commit is contained in:
parent
08b89e01cc
commit
b3ce489348
@ -1,6 +1,6 @@
|
|||||||
<?php include('include/headscript.php');
|
<?php include('include/headscript.php');
|
||||||
|
|
||||||
// Recupera tutte le routine dal database
|
// Retrieve all routines from database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
$stmt = $pdo->prepare("SELECT * FROM routine");
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
@ -18,26 +18,29 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<title>Insert XLS Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Insert Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
|
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">Insert new XLS Template</h5>
|
<h5 class="mb-0">Insert New Template</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-2">Fill the following form in order to create a new import XLS template</p>
|
<p class="mb-2">Fill the following form in order to create a new import template</p>
|
||||||
<p class="mb-2">Mandatory Fields</p>
|
<p class="mb-2">Mandatory Fields</p>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Source Type</li>
|
||||||
<li>Schema and client</li>
|
<li>Schema and Client</li>
|
||||||
|
<li>Row Header and Column Header only for XLS templates</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -50,22 +53,33 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<form id="insertTemplateForm" method="POST">
|
<form id="insertTemplateForm" method="POST">
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="name" class="form-control" required>
|
<input type="text" name="name" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label">Source Type *</label>
|
||||||
<input type="number" name="header_row" class="form-control" required>
|
<select name="source_type" id="sourceType" class="form-control" required>
|
||||||
|
<option value="XLS" selected>XLS</option>
|
||||||
|
<option value="API">API</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Choose the source used by this template</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3" id="headerRowWrapper">
|
||||||
|
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
|
<input type="number" name="header_row" id="headerRow" class="form-control" value="1" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="startColumnWrapper">
|
||||||
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="start_column" class="form-control" required>
|
<input type="text" name="start_column" id="startColumn" class="form-control" value="A" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -86,12 +100,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Background Color</label>
|
<label class="form-label">Button Background Color</label>
|
||||||
<input type="color" name="button_bg_color" class="form-control" value="#007bff">
|
<input type="color" name="button_bg_color" class="form-control form-control-color" value="#007bff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Text Color</label>
|
<label class="form-label">Button Text Color</label>
|
||||||
<input type="color" name="button_text_color" class="form-control" value="#ffffff">
|
<input type="color" name="button_text_color" class="form-control form-control-color" value="#ffffff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -125,6 +139,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div id="routineDetails" class="mt-2" style="display: none;">
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<h6>Routine Details</h6>
|
<h6>Routine Details</h6>
|
||||||
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
||||||
@ -142,8 +157,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
@ -167,6 +184,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const routineAction2 = document.getElementById("routineAction2");
|
const routineAction2 = document.getElementById("routineAction2");
|
||||||
const routineAction3 = document.getElementById("routineAction3");
|
const routineAction3 = document.getElementById("routineAction3");
|
||||||
|
|
||||||
|
const sourceType = document.getElementById("sourceType");
|
||||||
|
const headerRowWrapper = document.getElementById("headerRowWrapper");
|
||||||
|
const startColumnWrapper = document.getElementById("startColumnWrapper");
|
||||||
|
const headerRow = document.getElementById("headerRow");
|
||||||
|
const startColumn = document.getElementById("startColumn");
|
||||||
|
|
||||||
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
||||||
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
||||||
return;
|
return;
|
||||||
@ -187,30 +210,66 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
allowClear: true
|
allowClear: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateSourceFields() {
|
||||||
|
const selectedSource = sourceType.value;
|
||||||
|
|
||||||
|
if (selectedSource === 'API') {
|
||||||
|
headerRowWrapper.style.opacity = '0.6';
|
||||||
|
startColumnWrapper.style.opacity = '0.6';
|
||||||
|
|
||||||
|
headerRow.required = false;
|
||||||
|
startColumn.required = false;
|
||||||
|
|
||||||
|
headerRow.disabled = true;
|
||||||
|
startColumn.disabled = true;
|
||||||
|
} else {
|
||||||
|
headerRowWrapper.style.opacity = '1';
|
||||||
|
startColumnWrapper.style.opacity = '1';
|
||||||
|
|
||||||
|
headerRow.required = true;
|
||||||
|
startColumn.required = true;
|
||||||
|
|
||||||
|
headerRow.disabled = false;
|
||||||
|
startColumn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceType.addEventListener('change', updateSourceFields);
|
||||||
|
updateSourceFields();
|
||||||
|
|
||||||
async function loadClients() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("clientSelect");
|
const select = document.getElementById("clientSelect");
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
|
||||||
data.value.forEach(client => {
|
data.value.forEach(client => {
|
||||||
const nome = client.Nominativo || "Nome non disponibile";
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
const id = client.IdCliente || "ID non disponibile";
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
clientLoadingStatus.textContent = "Clienti caricati.";
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare i clienti: " + error.message,
|
text: "Impossibile caricare i clienti: " + error.message,
|
||||||
@ -226,16 +285,23 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
try {
|
try {
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_schemi.php", {
|
const response = await fetch("get_schemi.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("schemaSelect");
|
const select = document.getElementById("schemaSelect");
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
|
|
||||||
const sortedSchemas = [...data.value].sort((a, b) => {
|
const sortedSchemas = [...data.value].sort((a, b) => {
|
||||||
const nomeA = (a.Nome || "").trim().toLowerCase();
|
const nomeA = (a.Nome || "").trim().toLowerCase();
|
||||||
const nomeB = (b.Nome || "").trim().toLowerCase();
|
const nomeB = (b.Nome || "").trim().toLowerCase();
|
||||||
@ -250,10 +316,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
schemaLoadingStatus.textContent = "Schemi caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare gli schemi: " + error.message,
|
text: "Impossibile caricare gli schemi: " + error.message,
|
||||||
@ -278,6 +346,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
|
|
||||||
const routines = <?php echo json_encode($routines); ?>;
|
const routines = <?php echo json_encode($routines); ?>;
|
||||||
@ -285,8 +354,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
function updateRoutineDetails() {
|
function updateRoutineDetails() {
|
||||||
const selectedId = routineSelect.value;
|
const selectedId = routineSelect.value;
|
||||||
routineDetails.style.display = selectedId ? 'block' : 'none';
|
routineDetails.style.display = selectedId ? 'block' : 'none';
|
||||||
|
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
const routine = routines.find(r => r.idroutine == selectedId);
|
const routine = routines.find(r => r.idroutine == selectedId);
|
||||||
|
|
||||||
if (routine) {
|
if (routine) {
|
||||||
routineName.textContent = routine.name || 'N/A';
|
routineName.textContent = routine.name || 'N/A';
|
||||||
routineDescription.textContent = routine.description || 'N/A';
|
routineDescription.textContent = routine.description || 'N/A';
|
||||||
@ -308,6 +379,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
routineAction3.textContent = '';
|
routineAction3.textContent = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routineSelect.addEventListener('change', updateRoutineDetails);
|
routineSelect.addEventListener('change', updateRoutineDetails);
|
||||||
updateRoutineDetails();
|
updateRoutineDetails();
|
||||||
|
|
||||||
@ -358,6 +430,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("idschema", schemaId);
|
formData.append("idschema", schemaId);
|
||||||
formData.append("schemaname", schemaName);
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,36 @@ session_start();
|
|||||||
require_once '../../vendor/autoload.php';
|
require_once '../../vendor/autoload.php';
|
||||||
require_once __DIR__ . '/class/db-functions.php';
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
|
||||||
|
function findHeaderRow(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, array $expectedHeaders, int $startCol, int $highestColIndex, int $maxRowsToScan = 20): ?int
|
||||||
|
{
|
||||||
|
$normalizedExpected = array_filter(array_map(function ($h) {
|
||||||
|
return strtolower(trim(str_replace(['\\r\\n', '\r\n', "\r\n", "\n", "\r"], ' ', $h)));
|
||||||
|
}, $expectedHeaders));
|
||||||
|
$normalizedExpected = array_values($normalizedExpected);
|
||||||
|
sort($normalizedExpected);
|
||||||
|
|
||||||
|
for ($row = 1; $row <= $maxRowsToScan; $row++) {
|
||||||
|
$rowHeaders = [];
|
||||||
|
for ($col = $startCol; $col <= $highestColIndex; $col++) {
|
||||||
|
$colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
||||||
|
$cell = $worksheet->getCell($colLetter . $row);
|
||||||
|
$val = $cell ? trim((string)$cell->getCalculatedValue()) : '';
|
||||||
|
if ($val !== '') {
|
||||||
|
$rowHeaders[] = strtolower(trim(str_replace(["\r\n", "\n", "\r"], ' ', $val)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$normalizedRow = $rowHeaders;
|
||||||
|
sort($normalizedRow);
|
||||||
|
|
||||||
|
$matches = count(array_intersect($normalizedExpected, $normalizedRow));
|
||||||
|
$threshold = (int) ceil(count($normalizedExpected) * 0.6);
|
||||||
|
if ($matches >= $threshold) {
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'apply_routine' => false];
|
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'apply_routine' => false];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -71,9 +101,35 @@ try {
|
|||||||
$highestColumn = $worksheet->getHighestColumn();
|
$highestColumn = $worksheet->getHighestColumn();
|
||||||
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);
|
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);
|
||||||
|
|
||||||
$startRow = max(1, $header_row);
|
|
||||||
$startColumn = max(1, $start_column);
|
$startColumn = max(1, $start_column);
|
||||||
|
|
||||||
|
// Recupera routine e headers dal template — DEVE essere prima dell'auto-detect
|
||||||
|
$stmt = $pdo->prepare("SELECT idroutine, idclient, xls_headers FROM excel_templates WHERE id = ?");
|
||||||
|
$stmt->execute([$template_id]);
|
||||||
|
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
error_log("=== DEBUG TEMPLATE ===");
|
||||||
|
error_log("template raw: " . print_r($template, true));
|
||||||
|
error_log("xls_headers value: " . var_export($template['xls_headers'] ?? 'KEY NON ESISTE', true));
|
||||||
|
error_log("xls_headers empty check: " . var_export(empty($template['xls_headers']), true));
|
||||||
|
// Auto-detect della riga header se xls_headers è disponibile
|
||||||
|
$detectedHeaderRow = $header_row;
|
||||||
|
if (!empty($template['xls_headers'])) {
|
||||||
|
$expectedHeaders = json_decode($template['xls_headers'], true);
|
||||||
|
if (is_array($expectedHeaders) && !empty($expectedHeaders)) {
|
||||||
|
error_log("Expected headers from DB: " . print_r($expectedHeaders, true));
|
||||||
|
$found = findHeaderRow($worksheet, $expectedHeaders, $startColumn, $highestColumnIndex);
|
||||||
|
error_log("findHeaderRow result: " . var_export($found, true));
|
||||||
|
if ($found !== null) {
|
||||||
|
$detectedHeaderRow = $found;
|
||||||
|
error_log("Header row auto-detected at row: $detectedHeaderRow (was: $header_row)");
|
||||||
|
} else {
|
||||||
|
error_log("Header row auto-detection failed, using provided header_row: $header_row");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$startRow = max(1, $detectedHeaderRow);
|
||||||
|
$header_row = $detectedHeaderRow;
|
||||||
|
|
||||||
// Debug dei parametri
|
// Debug dei parametri
|
||||||
error_log("Processing - template_id: $template_id, startRow: $startRow, startColumn: $startColumn, highestRow: $highestRow, highestColumn: $highestColumn, highestColumnIndex: $highestColumnIndex");
|
error_log("Processing - template_id: $template_id, startRow: $startRow, startColumn: $startColumn, highestRow: $highestRow, highestColumn: $highestColumn, highestColumnIndex: $highestColumnIndex");
|
||||||
|
|
||||||
@ -94,7 +150,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Estrai i dati a partire dalla riga successiva, includendo excelrow
|
// Estrai i dati a partire dalla riga successiva, includendo excelrow
|
||||||
for ($row = $startRow + 1; $row <= $highestRow; $row++) {
|
for ($row = $header_row + 1; $row <= $highestRow; $row++) {
|
||||||
$rowData = [];
|
$rowData = [];
|
||||||
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
||||||
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
||||||
@ -107,10 +163,7 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera routine dal template
|
|
||||||
$stmt = $pdo->prepare("SELECT idroutine, idclient FROM excel_templates WHERE id = ?");
|
|
||||||
$stmt->execute([$template_id]);
|
|
||||||
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if ($template && $template['idroutine']) {
|
if ($template && $template['idroutine']) {
|
||||||
$stmtRoutine = $pdo->prepare("SELECT idroutine, name, filename, headerrow, instruction FROM routine WHERE idroutine = ?");
|
$stmtRoutine = $pdo->prepare("SELECT idroutine, name, filename, headerrow, instruction FROM routine WHERE idroutine = ?");
|
||||||
|
|||||||
@ -9,12 +9,13 @@ try {
|
|||||||
throw new Exception("Invalid request method.");
|
throw new Exception("Invalid request method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera e sanifica i dati
|
// Retrieve and sanitize form data
|
||||||
$name = trim($_POST['name']);
|
$name = trim($_POST['name'] ?? '');
|
||||||
$header_row = intval($_POST['header_row']);
|
$source_type = strtoupper(trim($_POST['source_type'] ?? 'XLS'));
|
||||||
$start_column = trim($_POST['start_column']);
|
$header_row = isset($_POST['header_row']) && $_POST['header_row'] !== '' ? intval($_POST['header_row']) : null;
|
||||||
|
$start_column = trim($_POST['start_column'] ?? '');
|
||||||
$description = trim($_POST['description'] ?? '');
|
$description = trim($_POST['description'] ?? '');
|
||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table'] ?? 'datadb');
|
||||||
$idclient = intval($_POST['client_id'] ?? 0);
|
$idclient = intval($_POST['client_id'] ?? 0);
|
||||||
$clientname = trim($_POST['client_name'] ?? '');
|
$clientname = trim($_POST['client_name'] ?? '');
|
||||||
$idschema = intval($_POST['idschema'] ?? 0);
|
$idschema = intval($_POST['idschema'] ?? 0);
|
||||||
@ -25,24 +26,61 @@ try {
|
|||||||
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
||||||
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
// Normalize source type
|
||||||
if (empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idclient <= 0 || $idschema <= 0) {
|
if (!in_array($source_type, ['XLS', 'API'], true)) {
|
||||||
|
$source_type = 'XLS';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required fields validation
|
||||||
|
if ($name === '' || $target_table === '' || $idclient <= 0 || $idschema <= 0) {
|
||||||
throw new Exception("All fields marked with * are required, including client and schema.");
|
throw new Exception("All fields marked with * are required, including client and schema.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connessione al database
|
// XLS-only validation
|
||||||
|
if ($source_type === 'XLS') {
|
||||||
|
if ($header_row === null || $header_row <= 0 || $start_column === '') {
|
||||||
|
throw new Exception("Header Row and Start Column are required for XLS templates.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API templates do not require XLS coordinates
|
||||||
|
if ($source_type === 'API') {
|
||||||
|
$header_row = null;
|
||||||
|
$start_column = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database connection
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Inserisci il nuovo template
|
// Insert the new template
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
INSERT INTO excel_templates
|
INSERT INTO excel_templates
|
||||||
(name, header_row, start_column, description, target_table, idclient, clientname, idschema, schemaname, idroutine,
|
(
|
||||||
button_size, button_bg_color, button_text_color, button_label, created_at, updated_at)
|
name,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
source_type,
|
||||||
|
header_row,
|
||||||
|
start_column,
|
||||||
|
description,
|
||||||
|
target_table,
|
||||||
|
idclient,
|
||||||
|
clientname,
|
||||||
|
idschema,
|
||||||
|
schemaname,
|
||||||
|
idroutine,
|
||||||
|
button_size,
|
||||||
|
button_bg_color,
|
||||||
|
button_text_color,
|
||||||
|
button_label,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||||
");
|
");
|
||||||
|
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
|
$source_type,
|
||||||
$header_row,
|
$header_row,
|
||||||
$start_column,
|
$start_column,
|
||||||
$description,
|
$description,
|
||||||
|
|||||||
@ -56,6 +56,56 @@
|
|||||||
input:checked+.slider:before {
|
input:checked+.slider:before {
|
||||||
transform: translateX(14px);
|
transform: translateX(14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-source {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0.30rem 0.55rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-xls {
|
||||||
|
background-color: #e7f1ff;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-api {
|
||||||
|
background-color: #e8fff1;
|
||||||
|
color: #198754;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable th,
|
||||||
|
#xlsTemplatesTable td {
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable td.description-cell,
|
||||||
|
#xlsTemplatesTable td.client-cell,
|
||||||
|
#xlsTemplatesTable td.name-cell,
|
||||||
|
#xlsTemplatesTable td.button-cell {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions .btn {
|
||||||
|
padding: 0.25rem 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-card .card-body {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -65,18 +115,20 @@
|
|||||||
<!--sidebar wrapper -->
|
<!--sidebar wrapper -->
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<!--end sidebar wrapper -->
|
<!--end sidebar wrapper -->
|
||||||
|
|
||||||
<!--start header -->
|
<!--start header -->
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<!--end header -->
|
<!--end header -->
|
||||||
|
|
||||||
<!--start page wrapper -->
|
<!--start page wrapper -->
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<?php include('top_stat_widget.php'); ?>
|
<?php include('top_stat_widget.php'); ?>
|
||||||
|
|
||||||
<div class="card radius-10">
|
<div class="card radius-10 compact-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<h6 class="mb-0">XLS Templates Dashboard</h6>
|
<h6 class="mb-0">Templates Dashboard</h6>
|
||||||
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
||||||
<i class="fas fa-plus"></i> New Template
|
<i class="fas fa-plus"></i> New Template
|
||||||
</a>
|
</a>
|
||||||
@ -85,22 +137,22 @@
|
|||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="xlsTemplatesTable" class="table table-striped table-bordered">
|
<table id="xlsTemplatesTable" class="table table-striped table-bordered table-sm w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
|
||||||
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th>Client Name</th>
|
|
||||||
<th>Button Label</th>
|
|
||||||
<th>Status</th> <!-- Aggiunta colonna Status -->
|
|
||||||
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Row</th>
|
||||||
|
<th>Col</th>
|
||||||
|
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Button</th>
|
||||||
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- DataTables riempirà questa sezione automaticamente -->
|
<!-- DataTables will populate this section automatically -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -110,25 +162,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
<!--end page wrapper -->
|
||||||
|
|
||||||
<!--start overlay-->
|
<!--start overlay-->
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<!--end overlay-->
|
<!--end overlay-->
|
||||||
|
|
||||||
<!--Start Back To Top Button-->
|
<!--Start Back To Top Button-->
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<!--End Back To Top Button-->
|
<!--End Back To Top Button-->
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<!--end wrapper-->
|
<!--end wrapper-->
|
||||||
|
|
||||||
<!-- search modal -->
|
|
||||||
<?php //include('include/searchmodal.php');
|
|
||||||
?>
|
|
||||||
<!-- end search modal -->
|
|
||||||
|
|
||||||
<!--start switcher-->
|
|
||||||
<?php //include('include/themeswitcher.php');
|
|
||||||
?>
|
|
||||||
<!--end switcher-->
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
||||||
@ -139,47 +185,92 @@
|
|||||||
processing: true,
|
processing: true,
|
||||||
serverSide: false,
|
serverSide: false,
|
||||||
ajax: 'load_templates.php',
|
ajax: 'load_templates.php',
|
||||||
|
pageLength: 50,
|
||||||
|
autoWidth: false,
|
||||||
columns: [{
|
columns: [{
|
||||||
data: 'id', // ID del template
|
data: 'id',
|
||||||
title: "ID"
|
orderable: false,
|
||||||
},
|
searchable: false,
|
||||||
{
|
title: "Actions",
|
||||||
data: 'name', // Nome del template
|
className: "table-actions text-center",
|
||||||
title: "Template Name"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: 'header_row', // Riga degli header
|
|
||||||
title: "Header Row"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'start_column', // Colonna di partenza
|
|
||||||
title: "Start Column"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'description', // Descrizione del template
|
|
||||||
title: "Description",
|
|
||||||
defaultContent: 'No description'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: null, // Nuova colonna per Client Name e ID
|
|
||||||
title: "Client Name",
|
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
const clientName = row.clientname || "No client";
|
return `
|
||||||
const clientId = row.idclient || "N/A";
|
<div class="d-flex justify-content-center gap-1">
|
||||||
return `${clientName} (ID: ${clientId})`;
|
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary" title="Edit">
|
||||||
|
<i class="bx bx-edit-alt"></i>
|
||||||
|
</a>
|
||||||
|
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success" title="Mapping">
|
||||||
|
<i class="bx bx-link-alt"></i>
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})" title="Delete">
|
||||||
|
<i class="bx bx-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'button_label', // Nuova colonna per Button Label
|
data: 'name',
|
||||||
title: "Button Label",
|
title: "Template Name",
|
||||||
|
className: "name-cell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'source_type',
|
||||||
|
title: "Type",
|
||||||
|
className: "text-center",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const sourceType = (data || 'XLS').toUpperCase();
|
||||||
|
|
||||||
|
if (type === 'display') {
|
||||||
|
if (sourceType === 'API') {
|
||||||
|
return '<span class="badge-source badge-source-api">API</span>';
|
||||||
|
}
|
||||||
|
return '<span class="badge-source badge-source-xls">XLS</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'header_row',
|
||||||
|
title: "Row",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'start_column',
|
||||||
|
title: "Col",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'description',
|
||||||
|
title: "Description",
|
||||||
|
className: "description-cell",
|
||||||
|
defaultContent: 'No description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
title: "Client",
|
||||||
|
className: "client-cell",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const clientName = row.clientname || "No client";
|
||||||
|
const clientId = row.idclient || "N/A";
|
||||||
|
return `${clientName} <small class="text-muted">(ID: ${clientId})</small>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'button_label',
|
||||||
|
title: "Button",
|
||||||
|
className: "button-cell",
|
||||||
defaultContent: 'Click Me'
|
defaultContent: 'Click Me'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'status', // Stato con Toggle Switch
|
data: 'status',
|
||||||
title: "Status",
|
title: "Status",
|
||||||
orderable: false,
|
orderable: false,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
|
className: "text-center",
|
||||||
render: function(status, type, row) {
|
render: function(status, type, row) {
|
||||||
let checked = (status === "active") ? "checked" : "";
|
let checked = (status === "active") ? "checked" : "";
|
||||||
return `
|
return `
|
||||||
@ -189,31 +280,13 @@
|
|||||||
</label>
|
</label>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'id', // Azioni: Modifica, Mappatura e Eliminazione
|
|
||||||
orderable: false,
|
|
||||||
searchable: false,
|
|
||||||
title: "Actions",
|
|
||||||
render: function(data) {
|
|
||||||
return `
|
|
||||||
<div class="d-flex">
|
|
||||||
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary me-1">
|
|
||||||
<i class="bx bx-edit-alt"></i>
|
|
||||||
</a>
|
|
||||||
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success me-1">
|
|
||||||
<i class="bx bx-link-alt"></i>
|
|
||||||
</a>
|
|
||||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})">
|
|
||||||
<i class="bx bx-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
||||||
lengthMenu: [10, 25, 50, 100],
|
lengthMenu: [10, 25, 50, 100],
|
||||||
|
order: [
|
||||||
|
[1, 'asc']
|
||||||
|
],
|
||||||
language: {
|
language: {
|
||||||
search: "Cerca:",
|
search: "Cerca:",
|
||||||
lengthMenu: "Mostra _MENU_ elementi",
|
lengthMenu: "Mostra _MENU_ elementi",
|
||||||
@ -252,20 +325,21 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: "update_template_status.php",
|
url: "update_template_status.php",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
data: {
|
data: {
|
||||||
id: templateId,
|
id: templateId,
|
||||||
status: newStatus
|
status: newStatus
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
console.log("✅ Status updated successfully.");
|
console.log("Status updated successfully.");
|
||||||
} else {
|
} else {
|
||||||
console.error("❌ Error updating status:", response.message);
|
console.error("Error updating status:", response.message);
|
||||||
alert("Error updating status: " + response.message);
|
alert("Error updating status: " + response.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function(xhr) {
|
||||||
console.error("❌ AJAX error.");
|
console.error("AJAX error:", xhr.responseText);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user