Compare commits
1 Commits
main
...
feature/an
| Author | SHA1 | Date | |
|---|---|---|---|
| 67bbd9bbbb |
@ -3,9 +3,6 @@ ob_start();
|
|||||||
session_start();
|
session_start();
|
||||||
require_once '../../vendor/autoload.php';
|
require_once '../../vendor/autoload.php';
|
||||||
|
|
||||||
Dotenv\Dotenv::createImmutable(dirname(__DIR__, 2))->safeLoad();
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'excel_data' => []];
|
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'excel_data' => []];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -3,9 +3,6 @@ require_once dirname(__DIR__, 3) . '/vendor/autoload.php';
|
|||||||
|
|
||||||
use Dotenv\Dotenv;
|
use Dotenv\Dotenv;
|
||||||
|
|
||||||
Dotenv::createImmutable(dirname(__DIR__, 3))->safeLoad();
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
class DBHandlerSelect
|
class DBHandlerSelect
|
||||||
{
|
{
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
|||||||
@ -17,8 +17,6 @@ try {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
// Recupera le variabili d'ambiente
|
// Recupera le variabili d'ambiente
|
||||||
$dbHost = $_ENV['DB_HOST'];
|
$dbHost = $_ENV['DB_HOST'];
|
||||||
$dbName = $_ENV['DB_DATABASE'];
|
$dbName = $_ENV['DB_DATABASE'];
|
||||||
|
|||||||
@ -432,6 +432,71 @@ try {
|
|||||||
$logFilePhotos = $logDir . "commessa_{$commessaId}_photos_step5_2_" . time() . ".txt";
|
$logFilePhotos = $logDir . "commessa_{$commessaId}_photos_step5_2_" . time() . ".txt";
|
||||||
$writeLog($logFilePhotos, $logContentPhotos, "STEP 6.2 - Photos (commessa={$commessaId})");
|
$writeLog($logFilePhotos, $logContentPhotos, "STEP 6.2 - Photos (commessa={$commessaId})");
|
||||||
|
|
||||||
|
// 🔹 STEP 6.3: Add Analyses (AnalisiCampione) via Campione({id})/AddAnalisi bound action
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT part_id, analysis_recordkey, analysis_name, analysis_method
|
||||||
|
FROM identification_parts_analyses
|
||||||
|
WHERE iddatadb = :iddatadb
|
||||||
|
ORDER BY part_id, id
|
||||||
|
");
|
||||||
|
$stmt->execute(['iddatadb' => $iddatadb]);
|
||||||
|
$analysesRows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$partIdToIndex = [];
|
||||||
|
foreach ($parts as $idx => $part) {
|
||||||
|
$partIdToIndex[(int)$part['part_id']] = $idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalAnalyses = count($analysesRows);
|
||||||
|
$addedAnalyses = 0;
|
||||||
|
$failedAnalyses = [];
|
||||||
|
$logContentStep63Analisi = "Analyses for iddatadb={$iddatadb}: total={$totalAnalyses}\n\n";
|
||||||
|
|
||||||
|
foreach ($analysesRows as $a) {
|
||||||
|
$partId = (int)$a['part_id'];
|
||||||
|
$recordKey = trim((string)($a['analysis_recordkey'] ?? ''));
|
||||||
|
$idx = $partIdToIndex[$partId] ?? null;
|
||||||
|
|
||||||
|
if ($idx === null || !isset($campioni[$idx]) || $recordKey === '') {
|
||||||
|
$logContentStep63Analisi .= "SKIP (no campione for part_id={$partId} / empty recordkey): '{$recordKey}'\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$campioneId = (int)($campioni[$idx]['IdCampione'] ?? 0);
|
||||||
|
if ($campioneId <= 0) {
|
||||||
|
$logContentStep63Analisi .= "SKIP (invalid IdCampione for part_id={$partId}): '{$recordKey}'\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = ['RecordKey' => $recordKey];
|
||||||
|
$jsonPayload = json_encode($payload, JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
$logContentStep63Analisi .= "curl --location --request POST '{$apiBaseUrl}Campione({$campioneId})/AddAnalisi' \\\n" .
|
||||||
|
"--header 'Content-Type: application/json' \\\n" .
|
||||||
|
"--header 'Authorization: Bearer ••••••' \\\n" .
|
||||||
|
"--data '{$jsonPayload}'\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $api->post("Campione({$campioneId})/AddAnalisi", $payload);
|
||||||
|
$logContentStep63Analisi .= "OK (part_id={$partId}, campione={$campioneId}): " .
|
||||||
|
($a['analysis_name'] ?? '') . "\n---\n";
|
||||||
|
$addedAnalyses++;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errMsg = $e->getMessage();
|
||||||
|
$logContentStep63Analisi .= "FAIL: {$errMsg}\n---\n";
|
||||||
|
$failedAnalyses[] = [
|
||||||
|
'part_id' => $partId,
|
||||||
|
'campione_id' => $campioneId,
|
||||||
|
'analysis_recordkey' => $recordKey,
|
||||||
|
'analysis_name' => $a['analysis_name'] ?? '',
|
||||||
|
'error' => $errMsg,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$logFileStep63Analisi = $logDir . "commessa_{$commessaId}_analyses_step63_" . time() . ".txt";
|
||||||
|
$writeLog($logFileStep63Analisi, $logContentStep63Analisi, "STEP 6.3 - AddAnalisi (commessa={$commessaId})");
|
||||||
|
|
||||||
// 🔹 STEP 7: Update Custom Fields for CommessaWeb
|
// 🔹 STEP 7: Update Custom Fields for CommessaWeb
|
||||||
if (!empty($fieldValues)) {
|
if (!empty($fieldValues)) {
|
||||||
// GET con espansione per CustomField
|
// GET con espansione per CustomField
|
||||||
@ -542,23 +607,7 @@ try {
|
|||||||
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
|
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
|
||||||
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
|
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
|
||||||
$writeLog($logFileStep10, $logContentStep10, "STEP 10 - GET verify (commessa={$commessaId})");
|
$writeLog($logFileStep10, $logContentStep10, "STEP 10 - GET verify (commessa={$commessaId})");
|
||||||
// 🔹 STEP 10.1: Save final CodiceCommessa into datadb.commessaweb
|
|
||||||
// After ImportaCommessa, the API returns the final LIMS job code in CodiceCommessa.
|
|
||||||
// Example: CodiceCommessa = 2614795, CodiceCommessaWeb = 26C0103.
|
|
||||||
$finalCodiceCommessa = trim((string)($commessaAfterPatch['CodiceCommessa'] ?? ''));
|
|
||||||
|
|
||||||
if ($finalCodiceCommessa !== '') {
|
|
||||||
$stmt = $pdo->prepare("
|
|
||||||
UPDATE datadb
|
|
||||||
SET commessaweb = :commessaweb,
|
|
||||||
status = 'l'
|
|
||||||
WHERE iddatadb = :iddatadb
|
|
||||||
");
|
|
||||||
$stmt->execute([
|
|
||||||
'commessaweb' => substr($finalCodiceCommessa, 0, 30),
|
|
||||||
'iddatadb' => $iddatadb
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// 🔹 STEP 11: Prepare final response
|
// 🔹 STEP 11: Prepare final response
|
||||||
$finalCommessa = [
|
$finalCommessa = [
|
||||||
"Cliente" => $clienteId,
|
"Cliente" => $clienteId,
|
||||||
@ -573,17 +622,21 @@ try {
|
|||||||
echo json_encode([
|
echo json_encode([
|
||||||
"success" => true,
|
"success" => true,
|
||||||
"idcommessaweb" => $commessaId,
|
"idcommessaweb" => $commessaId,
|
||||||
"commessaweb" => $finalCodiceCommessa ?: $commessaWebCode,
|
"commessaweb" => $commessaWebCode,
|
||||||
"commessaWeb" => $finalCommessa,
|
"commessaWeb" => $finalCommessa,
|
||||||
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
|
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
|
||||||
"totalCampioni" => count($campioni),
|
"totalCampioni" => count($campioni),
|
||||||
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
|
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
|
||||||
"totalPhotos" => count($photos),
|
"totalPhotos" => count($photos),
|
||||||
|
"totalAnalyses" => $totalAnalyses,
|
||||||
|
"addedAnalyses" => $addedAnalyses,
|
||||||
|
"failedAnalyses" => $failedAnalyses,
|
||||||
"message" => "Export successful",
|
"message" => "Export successful",
|
||||||
"logFiles" => [
|
"logFiles" => [
|
||||||
"step5_create" => $logFileStep5,
|
"step5_create" => $logFileStep5,
|
||||||
"step5_2_photos" => $logFilePhotos,
|
"step5_2_photos" => $logFilePhotos,
|
||||||
"step6_campioni" => $logFileStep6,
|
"step6_campioni" => $logFileStep6,
|
||||||
|
"step63_analyses" => $logFileStep63Analisi,
|
||||||
"step7_patch" => $logFileStep7 ?? null,
|
"step7_patch" => $logFileStep7 ?? null,
|
||||||
"step9_1_importa" => $logFileStep91,
|
"step9_1_importa" => $logFileStep91,
|
||||||
"step10_get" => $logFileStep10
|
"step10_get" => $logFileStep10
|
||||||
@ -599,6 +652,7 @@ try {
|
|||||||
"step5_create" => $logFileStep5 ?? null,
|
"step5_create" => $logFileStep5 ?? null,
|
||||||
"step5_2_photos" => $logFilePhotos ?? null,
|
"step5_2_photos" => $logFilePhotos ?? null,
|
||||||
"step6_campioni" => $logFileStep6 ?? null,
|
"step6_campioni" => $logFileStep6 ?? null,
|
||||||
|
"step63_analyses" => $logFileStep63Analisi ?? null,
|
||||||
"step7_patch" => $logFileStep7 ?? null,
|
"step7_patch" => $logFileStep7 ?? null,
|
||||||
"step9_1_importa" => $logFileStep91 ?? null,
|
"step9_1_importa" => $logFileStep91 ?? null,
|
||||||
"step10_get" => $logFileStep10 ?? null
|
"step10_get" => $logFileStep10 ?? null
|
||||||
|
|||||||
@ -331,28 +331,6 @@
|
|||||||
function createCell(col, rowIndex, cellIndex) {
|
function createCell(col, rowIndex, cellIndex) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.className = "grid-cell editable-cell";
|
div.className = "grid-cell editable-cell";
|
||||||
|
|
||||||
// Field color classification
|
|
||||||
// Schema/customfield fields are green.
|
|
||||||
// Fixed and standard fields stay white.
|
|
||||||
if (col.type === "detail" || col.type === "main_field") {
|
|
||||||
div.classList.add("schema-field");
|
|
||||||
} else if (col.type === "fixed") {
|
|
||||||
div.classList.add("fixed-field");
|
|
||||||
} else {
|
|
||||||
div.classList.add("standard-field");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required field classification.
|
|
||||||
// This comes from template_mapping.is_required or template_fixed_mapping.is_required.
|
|
||||||
if (
|
|
||||||
col.isRequired === true ||
|
|
||||||
col.isRequired === 1 ||
|
|
||||||
col.isRequired === "1"
|
|
||||||
) {
|
|
||||||
div.classList.add("required-field");
|
|
||||||
}
|
|
||||||
|
|
||||||
div.dataset.col = col.key;
|
div.dataset.col = col.key;
|
||||||
div.dataset.colType = col.type;
|
div.dataset.colType = col.type;
|
||||||
div.dataset.row = rowIndex;
|
div.dataset.row = rowIndex;
|
||||||
@ -766,27 +744,6 @@
|
|||||||
columns.forEach((col, colIdx) => {
|
columns.forEach((col, colIdx) => {
|
||||||
const cell = document.createElement("div");
|
const cell = document.createElement("div");
|
||||||
cell.className = "grid-cell grid-top-cell";
|
cell.className = "grid-cell grid-top-cell";
|
||||||
|
|
||||||
// Field color classification for top propagation row
|
|
||||||
// Schema/customfield fields are green.
|
|
||||||
// Fixed and standard fields stay white.
|
|
||||||
if (col.type === "detail" || col.type === "main_field") {
|
|
||||||
cell.classList.add("schema-field");
|
|
||||||
} else if (col.type === "fixed") {
|
|
||||||
cell.classList.add("fixed-field");
|
|
||||||
} else {
|
|
||||||
cell.classList.add("standard-field");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required field classification also for the top propagation row.
|
|
||||||
if (
|
|
||||||
col.isRequired === true ||
|
|
||||||
col.isRequired === 1 ||
|
|
||||||
col.isRequired === "1"
|
|
||||||
) {
|
|
||||||
cell.classList.add("required-field");
|
|
||||||
}
|
|
||||||
|
|
||||||
cell.style.flex = `0 0 ${col.width}px`;
|
cell.style.flex = `0 0 ${col.width}px`;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -10,125 +10,65 @@
|
|||||||
<title>Template Buttons - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Template Buttons - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Main buttons container */
|
/* Layout flessibile per gestire dimensioni diverse */
|
||||||
.template-buttons {
|
#templateButtons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 12px;
|
gap: 10px;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: 10px 0;
|
/* Allinea a sinistra */
|
||||||
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Button sizes */
|
/* Definizione delle dimensioni */
|
||||||
|
/* Definizione delle dimensioni */
|
||||||
.btn-small {
|
.btn-small {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
min-height: 36px;
|
min-height: 30px;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
|
/* Aggiunto */
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
/* Aggiunto */
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
/* Aggiunto */
|
||||||
border-radius: 8px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-medium {
|
.btn-medium {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
min-width: 140px;
|
min-width: 130px;
|
||||||
min-height: 48px;
|
min-height: 45px;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
|
/* Aggiunto */
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
/* Aggiunto */
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
/* Aggiunto */
|
||||||
border-radius: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-large {
|
.btn-large {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
padding: 14px 28px;
|
padding: 14px 28px;
|
||||||
min-width: 190px;
|
min-width: 180px;
|
||||||
min-height: 64px;
|
min-height: 60px;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
|
/* Aggiunto */
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
/* Aggiunto */
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
/* Aggiunto */
|
||||||
border-radius: 12px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.template-icon {
|
/* Stile della barra di ricerca */
|
||||||
font-size: 18px;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-large .template-icon {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-small .template-icon {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search box */
|
|
||||||
#searchInput {
|
#searchInput {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px 14px;
|
padding: 10px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 15px;
|
||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #ccc;
|
||||||
border-radius: 8px;
|
border-radius: 5px;
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchInput:focus {
|
|
||||||
border-color: #0d6efd;
|
|
||||||
box-shadow: 0 0 0 0.15rem rgba(13, 110, 253, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tabs */
|
|
||||||
.custom-tabs {
|
|
||||||
border-bottom: 1px solid #e5e5e5;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .nav-link {
|
|
||||||
border: none;
|
|
||||||
border-radius: 10px 10px 0 0;
|
|
||||||
color: #555;
|
|
||||||
font-weight: 500;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 10px 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .nav-link:hover {
|
|
||||||
background: #f8f9fa;
|
|
||||||
color: #0d6efd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs .nav-link.active {
|
|
||||||
background: #0d6efd;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-pane {
|
|
||||||
min-height: 140px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-message {
|
|
||||||
color: #6c757d;
|
|
||||||
font-style: italic;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-message {
|
|
||||||
color: #6c757d;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@ -147,54 +87,14 @@
|
|||||||
<h6 class="mb-0">Active Templates</h6>
|
<h6 class="mb-0">Active Templates</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
<!-- Barra di ricerca -->
|
||||||
<input type="text" id="searchInput" placeholder="Search template...">
|
<input type="text" id="searchInput" placeholder="Search template...">
|
||||||
|
<div id="templateButtons"></div>
|
||||||
<ul class="nav nav-tabs custom-tabs" id="templateTabs" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link active" id="xls-tab" data-bs-toggle="tab" data-bs-target="#xls-pane" type="button" role="tab" aria-controls="xls-pane" aria-selected="true">
|
|
||||||
<i class="bx bx-spreadsheet template-icon"></i>
|
|
||||||
XLS
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="api-tab" data-bs-toggle="tab" data-bs-target="#api-pane" type="button" role="tab" aria-controls="api-pane" aria-selected="false">
|
|
||||||
<i class="bx bx-transfer-alt template-icon"></i>
|
|
||||||
JSON/API
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="pdf-tab" data-bs-toggle="tab" data-bs-target="#pdf-pane" type="button" role="tab" aria-controls="pdf-pane" aria-selected="false">
|
|
||||||
<i class="bx bx-file-pdf template-icon"></i>
|
|
||||||
PDF
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tab-content" id="templateTabsContent">
|
|
||||||
<div class="tab-pane fade show active" id="xls-pane" role="tabpanel" aria-labelledby="xls-tab">
|
|
||||||
<div id="templateButtonsXLS" class="template-buttons">
|
|
||||||
<div class="loading-message">Loading XLS templates...</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane fade" id="api-pane" role="tabpanel" aria-labelledby="api-tab">
|
|
||||||
<div id="templateButtonsAPI" class="template-buttons">
|
|
||||||
<div class="loading-message">Loading API templates...</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane fade" id="pdf-pane" role="tabpanel" aria-labelledby="pdf-tab">
|
|
||||||
<div id="templateButtonsPDF" class="template-buttons">
|
|
||||||
<div class="loading-message">Loading PDF templates...</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'); ?>
|
||||||
@ -204,137 +104,46 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
const allTemplates = [];
|
|
||||||
|
|
||||||
const containers = {
|
|
||||||
XLS: document.getElementById("templateButtonsXLS"),
|
|
||||||
API: document.getElementById("templateButtonsAPI"),
|
|
||||||
PDF: document.getElementById("templateButtonsPDF")
|
|
||||||
};
|
|
||||||
|
|
||||||
function getSizeClass(buttonSize) {
|
|
||||||
if (buttonSize === "small") return "btn-small";
|
|
||||||
if (buttonSize === "large") return "btn-large";
|
|
||||||
return "btn-medium";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTemplateIcon(sourceType) {
|
|
||||||
switch ((sourceType || '').toUpperCase()) {
|
|
||||||
case 'XLS':
|
|
||||||
return 'bx bx-spreadsheet';
|
|
||||||
case 'API':
|
|
||||||
return 'bx bx-transfer-alt';
|
|
||||||
case 'PDF':
|
|
||||||
return 'bx bx-file-pdf';
|
|
||||||
default:
|
|
||||||
return 'bx bx-file';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createButton(template) {
|
|
||||||
const sizeClass = getSizeClass(template.button_size);
|
|
||||||
const sourceType = (template.source_type || '').toUpperCase();
|
|
||||||
const iconClass = getTemplateIcon(sourceType);
|
|
||||||
|
|
||||||
const btn = document.createElement("a");
|
|
||||||
btn.href = `import_xls2.php?id=${template.id}`;
|
|
||||||
btn.className = `btn ${sizeClass}`;
|
|
||||||
btn.style.backgroundColor = template.button_bg_color || '#0d6efd';
|
|
||||||
btn.style.color = template.button_text_color || '#ffffff';
|
|
||||||
btn.setAttribute("data-label", (template.button_label || '').toLowerCase());
|
|
||||||
btn.setAttribute("data-source-type", sourceType);
|
|
||||||
|
|
||||||
btn.innerHTML = `
|
|
||||||
<i class="${iconClass} template-icon"></i>
|
|
||||||
<span>${escapeHtml(template.button_label || 'Unnamed')}</span>
|
|
||||||
`;
|
|
||||||
|
|
||||||
return btn;
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(text) {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.textContent = text;
|
|
||||||
return div.innerHTML;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearContainers() {
|
|
||||||
Object.values(containers).forEach(container => {
|
|
||||||
container.innerHTML = '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTemplates(searchValue = '') {
|
|
||||||
clearContainers();
|
|
||||||
|
|
||||||
const grouped = {
|
|
||||||
XLS: [],
|
|
||||||
API: [],
|
|
||||||
PDF: []
|
|
||||||
};
|
|
||||||
|
|
||||||
allTemplates.forEach(template => {
|
|
||||||
const sourceType = (template.source_type || '').toUpperCase();
|
|
||||||
const label = (template.button_label || '').toLowerCase();
|
|
||||||
|
|
||||||
if (searchValue && !label.includes(searchValue)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grouped[sourceType]) {
|
|
||||||
grouped[sourceType].push(template);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(grouped).forEach(type => {
|
|
||||||
const container = containers[type];
|
|
||||||
if (!container) return;
|
|
||||||
|
|
||||||
if (grouped[type].length === 0) {
|
|
||||||
container.innerHTML = `<div class="empty-message">No templates found in this section.</div>`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
grouped[type].forEach(template => {
|
|
||||||
container.appendChild(createButton(template));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("load_active_templates.php")
|
fetch("load_active_templates.php")
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data.success) {
|
if (!data.success) {
|
||||||
console.error("Error loading templates:", data.message);
|
console.error("Error loading templates:", data.message);
|
||||||
clearContainers();
|
|
||||||
Object.values(containers).forEach(container => {
|
|
||||||
container.innerHTML = `<div class="empty-message">Error loading templates.</div>`;
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(data.data)) {
|
let templateButtons = document.getElementById("templateButtons");
|
||||||
clearContainers();
|
templateButtons.innerHTML = '';
|
||||||
Object.values(containers).forEach(container => {
|
|
||||||
container.innerHTML = `<div class="empty-message">Invalid response format.</div>`;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
allTemplates.push(...data.data);
|
data.data.forEach(template => {
|
||||||
renderTemplates();
|
let sizeClass = "btn-medium"; // Default
|
||||||
|
if (template.button_size === "small") sizeClass = "btn-small";
|
||||||
|
if (template.button_size === "large") sizeClass = "btn-large";
|
||||||
|
|
||||||
|
let btn = document.createElement("a");
|
||||||
|
btn.href = `import_xls2.php?id=${template.id}`;
|
||||||
|
btn.className = `btn ${sizeClass}`;
|
||||||
|
btn.style.backgroundColor = template.button_bg_color;
|
||||||
|
btn.style.color = template.button_text_color;
|
||||||
|
btn.textContent = template.button_label;
|
||||||
|
btn.setAttribute("data-label", template.button_label.toLowerCase()); // Attributo per ricerca
|
||||||
|
|
||||||
|
templateButtons.appendChild(btn);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => console.error("Fetch error:", error));
|
||||||
console.error("Fetch error:", error);
|
|
||||||
clearContainers();
|
|
||||||
Object.values(containers).forEach(container => {
|
|
||||||
container.innerHTML = `<div class="empty-message">Fetch error while loading templates.</div>`;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Funzione per la ricerca live
|
||||||
document.getElementById("searchInput").addEventListener("input", function() {
|
document.getElementById("searchInput").addEventListener("input", function() {
|
||||||
const searchValue = this.value.toLowerCase().trim();
|
let searchValue = this.value.toLowerCase();
|
||||||
renderTemplates(searchValue);
|
document.querySelectorAll("#templateButtons a").forEach(btn => {
|
||||||
|
let label = btn.getAttribute("data-label");
|
||||||
|
if (label.includes(searchValue)) {
|
||||||
|
btn.style.display = "inline-block";
|
||||||
|
} else {
|
||||||
|
btn.style.display = "none";
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
include('include/headscript.php');
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// ✅ FIX timezone (Rome)
|
||||||
|
ini_set('date.timezone', 'Europe/Rome');
|
||||||
|
date_default_timezone_set('Europe/Rome');
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !isset($_POST['selected_rows']) || !isset($_POST['filename'])) {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !isset($_POST['selected_rows']) || !isset($_POST['filename'])) {
|
||||||
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
|
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
include('include/headscript.php');
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// ✅ FIX timezone (Rome)
|
||||||
|
ini_set('date.timezone', 'Europe/Rome');
|
||||||
|
date_default_timezone_set('Europe/Rome');
|
||||||
|
|
||||||
$template_id = intval($_GET['id'] ?? 0);
|
$template_id = intval($_GET['id'] ?? 0);
|
||||||
if (!$template_id) {
|
if (!$template_id) {
|
||||||
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
|
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
|
||||||
@ -370,10 +374,20 @@ $gridMeta = [
|
|||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.auto-input,
|
||||||
|
select.auto-input {
|
||||||
|
background-color: #d4edda;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.manual-input,
|
||||||
|
select.manual-input {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.required-input,
|
||||||
|
select.required-input {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
}
|
||||||
|
|
||||||
input.required-input,
|
input.required-input,
|
||||||
select.required-input {
|
select.required-input {
|
||||||
@ -412,9 +426,17 @@ $gridMeta = [
|
|||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea.auto-input {
|
||||||
|
background-color: #d4edda;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.manual-input {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.required-input {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
}
|
||||||
|
|
||||||
.status-badge {
|
.status-badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -1022,7 +1044,11 @@ $gridMeta = [
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.api-fixed-select.required-input:invalid,
|
||||||
|
.api-fixed-select[required]:not([value]):not([data-select2-id]) {
|
||||||
|
background-color: #f8d7da !important;
|
||||||
|
border-color: #dc3545 !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Pagination bar ── */
|
/* ── Pagination bar ── */
|
||||||
.pager-bar {
|
.pager-bar {
|
||||||
@ -1135,128 +1161,6 @@ $gridMeta = [
|
|||||||
color: #adb5bd;
|
color: #adb5bd;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =========================================================
|
|
||||||
FINAL GRID COLORS
|
|
||||||
Schema/customfield fields = green
|
|
||||||
Fixed/standard fields = white
|
|
||||||
Required fields = red border only
|
|
||||||
========================================================= */
|
|
||||||
|
|
||||||
/* Default: all fields white */
|
|
||||||
.grid-container input,
|
|
||||||
.grid-container select,
|
|
||||||
.grid-container textarea,
|
|
||||||
.grid-top input,
|
|
||||||
.grid-top select,
|
|
||||||
.grid-top textarea {
|
|
||||||
background-color: #ffffff !important;
|
|
||||||
color: #333 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Schema/customfield fields: green background */
|
|
||||||
.grid-container .schema-field input,
|
|
||||||
.grid-container .schema-field select,
|
|
||||||
.grid-container .schema-field textarea,
|
|
||||||
.grid-top .schema-field input,
|
|
||||||
.grid-top .schema-field select,
|
|
||||||
.grid-top .schema-field textarea {
|
|
||||||
background-color: #dff3e3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fixed and standard fields: white background */
|
|
||||||
.grid-container .fixed-field input,
|
|
||||||
.grid-container .fixed-field select,
|
|
||||||
.grid-container .fixed-field textarea,
|
|
||||||
.grid-container .standard-field input,
|
|
||||||
.grid-container .standard-field select,
|
|
||||||
.grid-container .standard-field textarea,
|
|
||||||
.grid-top .fixed-field input,
|
|
||||||
.grid-top .fixed-field select,
|
|
||||||
.grid-top .fixed-field textarea,
|
|
||||||
.grid-top .standard-field input,
|
|
||||||
.grid-top .standard-field select,
|
|
||||||
.grid-top .standard-field textarea {
|
|
||||||
background-color: #ffffff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required fields: red border only */
|
|
||||||
.grid-container .required-field input,
|
|
||||||
.grid-container .required-field select,
|
|
||||||
.grid-container .required-field textarea,
|
|
||||||
.grid-top .required-field input,
|
|
||||||
.grid-top .required-field select,
|
|
||||||
.grid-top .required-field textarea {
|
|
||||||
border: 2px solid #dc3545 !important;
|
|
||||||
box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.15) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required schema/customfield fields: green + red border */
|
|
||||||
.grid-container .schema-field.required-field input,
|
|
||||||
.grid-container .schema-field.required-field select,
|
|
||||||
.grid-container .schema-field.required-field textarea,
|
|
||||||
.grid-top .schema-field.required-field input,
|
|
||||||
.grid-top .schema-field.required-field select,
|
|
||||||
.grid-top .schema-field.required-field textarea {
|
|
||||||
background-color: #dff3e3 !important;
|
|
||||||
border: 2px solid #dc3545 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required fixed/standard fields: white + red border */
|
|
||||||
.grid-container .fixed-field.required-field input,
|
|
||||||
.grid-container .fixed-field.required-field select,
|
|
||||||
.grid-container .fixed-field.required-field textarea,
|
|
||||||
.grid-container .standard-field.required-field input,
|
|
||||||
.grid-container .standard-field.required-field select,
|
|
||||||
.grid-container .standard-field.required-field textarea,
|
|
||||||
.grid-top .fixed-field.required-field input,
|
|
||||||
.grid-top .fixed-field.required-field select,
|
|
||||||
.grid-top .fixed-field.required-field textarea,
|
|
||||||
.grid-top .standard-field.required-field input,
|
|
||||||
.grid-top .standard-field.required-field select,
|
|
||||||
.grid-top .standard-field.required-field textarea {
|
|
||||||
background-color: #ffffff !important;
|
|
||||||
border: 2px solid #dc3545 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select2 - schema/customfield fields: green */
|
|
||||||
.grid-container .schema-field .select2-container--default .select2-selection--single,
|
|
||||||
.grid-top .schema-field .select2-container--default .select2-selection--single {
|
|
||||||
background-color: #dff3e3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select2 - fixed/standard fields: white */
|
|
||||||
.grid-container .fixed-field .select2-container--default .select2-selection--single,
|
|
||||||
.grid-container .standard-field .select2-container--default .select2-selection--single,
|
|
||||||
.grid-top .fixed-field .select2-container--default .select2-selection--single,
|
|
||||||
.grid-top .standard-field .select2-container--default .select2-selection--single {
|
|
||||||
background-color: #ffffff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select2 - required fields: red border only */
|
|
||||||
.grid-container .required-field .select2-container--default .select2-selection--single,
|
|
||||||
.grid-top .required-field .select2-container--default .select2-selection--single {
|
|
||||||
border: 2px solid #dc3545 !important;
|
|
||||||
box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.15) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove old red background from required classes */
|
|
||||||
.grid-container input.required-input,
|
|
||||||
.grid-container select.required-input,
|
|
||||||
.grid-container textarea.required-input,
|
|
||||||
.grid-top input.required-input,
|
|
||||||
.grid-top select.required-input,
|
|
||||||
.grid-top textarea.required-input {
|
|
||||||
background-color: inherit !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Missing required cell: red outline only */
|
|
||||||
.grid-cell.missing-required {
|
|
||||||
background-color: inherit !important;
|
|
||||||
border-right: 1px solid #dee2e6 !important;
|
|
||||||
outline: 2px solid #dc3545 !important;
|
|
||||||
outline-offset: -2px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@ -10,9 +10,6 @@ error_reporting(E_ALL | E_STRICT);
|
|||||||
include('../../extra/auth.php');
|
include('../../extra/auth.php');
|
||||||
//require_once __DIR__ . '/extra/auth.php';
|
//require_once __DIR__ . '/extra/auth.php';
|
||||||
|
|
||||||
// Laravel bootstrap (loaded by auth.php) forces UTC via config/app.php — re-apply our TZ
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
// Here we just check if user is not
|
// Here we just check if user is not
|
||||||
// logged in, and in that case we redirect
|
// logged in, and in that case we redirect
|
||||||
// the user to vanguard login page.
|
// the user to vanguard login page.
|
||||||
|
|||||||
@ -13,10 +13,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recupera solo i template attivi
|
// Recupera solo i template attivi
|
||||||
$stmt = $pdo->query("SELECT id, button_label, button_size, button_bg_color, button_text_color, source_type
|
$stmt = $pdo->query("SELECT id, button_label, button_bg_color, button_text_color, button_size FROM excel_templates WHERE status = 'active'");
|
||||||
FROM excel_templates
|
|
||||||
WHERE status = 'active'
|
|
||||||
ORDER BY button_label ASC");
|
|
||||||
$templates = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$templates = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$response["success"] = true;
|
$response["success"] = true;
|
||||||
|
|||||||
@ -10,9 +10,6 @@ session_start();
|
|||||||
// Includi PHPSpreadsheet
|
// Includi PHPSpreadsheet
|
||||||
require_once '../../vendor/autoload.php';
|
require_once '../../vendor/autoload.php';
|
||||||
|
|
||||||
Dotenv\Dotenv::createImmutable(dirname(__DIR__, 2))->safeLoad();
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => ''];
|
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => ''];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -653,7 +653,7 @@
|
|||||||
"IdSchemaCustomFields": 163,
|
"IdSchemaCustomFields": 163,
|
||||||
"ConteggioClienti": 0,
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Devred",
|
"Nome": "Devred",
|
||||||
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024 aggiornato il 23\/04\/2026\r\n\r\n"
|
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024\r\n\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 164,
|
"IdSchemaCustomFields": 164,
|
||||||
|
|||||||
@ -8,9 +8,6 @@ ini_set('log_errors', 1);
|
|||||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
Dotenv\Dotenv::createImmutable(dirname(__DIR__, 2))->safeLoad();
|
|
||||||
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
include('include/headscript.php');
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// ✅ FIX timezone (Rome)
|
||||||
|
ini_set('date.timezone', 'Europe/Rome');
|
||||||
|
date_default_timezone_set('Europe/Rome');
|
||||||
|
|
||||||
$template_id = intval($_GET['id'] ?? 0);
|
$template_id = intval($_GET['id'] ?? 0);
|
||||||
if (!$template_id) {
|
if (!$template_id) {
|
||||||
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
|
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user