Compare commits

...

3 Commits

Author SHA1 Message Date
cfbbc36116 Fix TZ Issue 2026-04-28 12:53:21 +03:00
50d578eea1 commesssa on commessaweb 2026-04-27 16:02:50 +02:00
6b0d2aa9b9 fixed color and import dahboard 2026-04-27 14:34:45 +02:00
14 changed files with 460 additions and 102 deletions

View File

@ -3,6 +3,9 @@ ob_start();
session_start();
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' => []];
try {

View File

@ -3,6 +3,9 @@ require_once dirname(__DIR__, 3) . '/vendor/autoload.php';
use Dotenv\Dotenv;
Dotenv::createImmutable(dirname(__DIR__, 3))->safeLoad();
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
class DBHandlerSelect
{
private static $instance = null;

View File

@ -17,6 +17,8 @@ try {
exit(1);
}
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome');
// Recupera le variabili d'ambiente
$dbHost = $_ENV['DB_HOST'];
$dbName = $_ENV['DB_DATABASE'];

View File

@ -542,7 +542,23 @@ try {
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
$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
$finalCommessa = [
"Cliente" => $clienteId,
@ -557,7 +573,7 @@ try {
echo json_encode([
"success" => true,
"idcommessaweb" => $commessaId,
"commessaweb" => $commessaWebCode,
"commessaweb" => $finalCodiceCommessa ?: $commessaWebCode,
"commessaWeb" => $finalCommessa,
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
"totalCampioni" => count($campioni),

View File

@ -331,6 +331,28 @@
function createCell(col, rowIndex, cellIndex) {
const div = document.createElement("div");
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.colType = col.type;
div.dataset.row = rowIndex;
@ -744,6 +766,27 @@
columns.forEach((col, colIdx) => {
const cell = document.createElement("div");
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`;
if (

View File

@ -10,65 +10,125 @@
<title>Template Buttons - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<style>
/* Layout flessibile per gestire dimensioni diverse */
#templateButtons {
/* Main buttons container */
.template-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
gap: 12px;
justify-content: flex-start;
/* Allinea a sinistra */
padding: 20px;
padding: 10px 0;
}
/* Definizione delle dimensioni */
/* Definizione delle dimensioni */
/* Button sizes */
.btn-small {
font-size: 12px;
padding: 6px 12px;
min-width: 100px;
min-height: 30px;
display: flex;
/* Aggiunto */
min-height: 36px;
display: inline-flex;
justify-content: center;
/* Aggiunto */
align-items: center;
/* Aggiunto */
gap: 8px;
border-radius: 8px;
text-align: center;
}
.btn-medium {
font-size: 16px;
padding: 10px 20px;
min-width: 130px;
min-height: 45px;
display: flex;
/* Aggiunto */
min-width: 140px;
min-height: 48px;
display: inline-flex;
justify-content: center;
/* Aggiunto */
align-items: center;
/* Aggiunto */
gap: 8px;
border-radius: 10px;
text-align: center;
}
.btn-large {
font-size: 20px;
padding: 14px 28px;
min-width: 180px;
min-height: 60px;
display: flex;
/* Aggiunto */
min-width: 190px;
min-height: 64px;
display: inline-flex;
justify-content: center;
/* Aggiunto */
align-items: center;
/* Aggiunto */
gap: 10px;
border-radius: 12px;
text-align: center;
}
/* Stile della barra di ricerca */
.template-icon {
font-size: 18px;
line-height: 1;
}
.btn-large .template-icon {
font-size: 22px;
}
.btn-small .template-icon {
font-size: 15px;
}
/* Search box */
#searchInput {
width: 100%;
padding: 10px;
padding: 10px 14px;
font-size: 16px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 18px;
border: 1px solid #d9d9d9;
border-radius: 8px;
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>
</head>
@ -87,14 +147,54 @@
<h6 class="mb-0">Active Templates</h6>
</div>
<div class="card-body">
<!-- Barra di ricerca -->
<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 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 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>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
@ -104,47 +204,138 @@
<script>
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")
.then(response => response.json())
.then(data => {
if (!data.success) {
console.error("Error loading templates:", data.message);
clearContainers();
Object.values(containers).forEach(container => {
container.innerHTML = `<div class="empty-message">Error loading templates.</div>`;
});
return;
}
let templateButtons = document.getElementById("templateButtons");
templateButtons.innerHTML = '';
data.data.forEach(template => {
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);
if (!Array.isArray(data.data)) {
clearContainers();
Object.values(containers).forEach(container => {
container.innerHTML = `<div class="empty-message">Invalid response format.</div>`;
});
})
.catch(error => console.error("Fetch error:", error));
// Funzione per la ricerca live
document.getElementById("searchInput").addEventListener("input", function() {
let searchValue = this.value.toLowerCase();
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";
return;
}
allTemplates.push(...data.data);
renderTemplates();
})
.catch(error => {
console.error("Fetch error:", error);
clearContainers();
Object.values(containers).forEach(container => {
container.innerHTML = `<div class="empty-message">Fetch error while loading templates.</div>`;
});
});
document.getElementById("searchInput").addEventListener("input", function() {
const searchValue = this.value.toLowerCase().trim();
renderTemplates(searchValue);
});
});
</script>

View File

@ -1,10 +1,6 @@
<?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'])) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
exit;

View File

@ -1,10 +1,6 @@
<?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);
if (!$template_id) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
@ -374,20 +370,10 @@ $gridMeta = [
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,
select.required-input {
@ -426,17 +412,9 @@ $gridMeta = [
outline: none !important;
}
textarea.auto-input {
background-color: #d4edda;
}
textarea.manual-input {
background-color: #fff3cd;
}
textarea.required-input {
background-color: #f8d7da;
}
.status-badge {
display: inline-block;
@ -1044,11 +1022,7 @@ $gridMeta = [
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 ── */
.pager-bar {
@ -1161,6 +1135,128 @@ $gridMeta = [
color: #adb5bd;
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>
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head>

View File

@ -10,6 +10,9 @@ error_reporting(E_ALL | E_STRICT);
include('../../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
// logged in, and in that case we redirect
// the user to vanguard login page.

View File

@ -13,7 +13,10 @@ try {
}
// Recupera solo i template attivi
$stmt = $pdo->query("SELECT id, button_label, button_bg_color, button_text_color, button_size FROM excel_templates WHERE status = 'active'");
$stmt = $pdo->query("SELECT id, button_label, button_size, button_bg_color, button_text_color, source_type
FROM excel_templates
WHERE status = 'active'
ORDER BY button_label ASC");
$templates = $stmt->fetchAll(PDO::FETCH_ASSOC);
$response["success"] = true;

View File

@ -10,6 +10,9 @@ session_start();
// Includi PHPSpreadsheet
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' => ''];
try {

View File

@ -653,7 +653,7 @@
"IdSchemaCustomFields": 163,
"ConteggioClienti": 0,
"Nome": "Devred",
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024\r\n\r\n"
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024 aggiornato il 23\/04\/2026\r\n\r\n"
},
{
"IdSchemaCustomFields": 164,

View File

@ -8,6 +8,9 @@ ini_set('log_errors', 1);
require_once dirname(__DIR__, 2) . '/vendor/autoload.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');
try {

View File

@ -1,10 +1,6 @@
<?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);
if (!$template_id) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));