diff --git a/db/migrations/20260716105010_add_template_note_to_excel_templates.php b/db/migrations/20260716105010_add_template_note_to_excel_templates.php new file mode 100644 index 0000000..b04ab41 --- /dev/null +++ b/db/migrations/20260716105010_add_template_note_to_excel_templates.php @@ -0,0 +1,20 @@ +table('excel_templates') + ->addColumn('template_note', 'text', [ + 'null' => true, + 'default' => null, + 'after' => 'idroutine', + 'comment' => 'Nota opzionale del template, aggiunta in fondo alle note in esportazione', + ]) + ->update(); + } +} diff --git a/public/userarea/edit_template_xls.php b/public/userarea/edit_template_xls.php index 9677ba6..c7826c7 100644 --- a/public/userarea/edit_template_xls.php +++ b/public/userarea/edit_template_xls.php @@ -265,7 +265,11 @@ if (!array_key_exists($currentButtonTextColor, array_change_key_case($buttonText - +
+ + + If set, this note will be appended at the end of the notes during export. +
diff --git a/public/userarea/export_to_lims.php b/public/userarea/export_to_lims.php index 45bb9eb..42069ad 100644 --- a/public/userarea/export_to_lims.php +++ b/public/userarea/export_to_lims.php @@ -151,6 +151,7 @@ try { // Also fetch fixed fields stored in datadb $stmt = $pdo->prepare(" SELECT d.idclient AS clienteId, et.idschema AS schemaId, et.id AS templateId, + et.template_note, d.cliente_responsabile_id, d.moltiplicatore_prezzo_id, d.anagrafica_certest_object_id, @@ -280,6 +281,14 @@ try { $addnoteText = implode(' - ', $addnoteChunks); + // Nota del template: appesa in fondo alle note in esportazione + $templateNote = trim((string)($result['template_note'] ?? '')); + if ($templateNote !== '') { + $addnoteText = $addnoteText !== '' + ? $addnoteText . ' - ' . $templateNote + : $templateNote; + } + // Logga i fieldValues in error_log $logFieldValues = "FieldValues dal DB (iddatadb={$iddatadb}):\n" . json_encode($fieldValues, JSON_PRETTY_PRINT); error_log($logFieldValues); diff --git a/public/userarea/process_edit_template_xls.php b/public/userarea/process_edit_template_xls.php index e333d9a..dc54851 100644 --- a/public/userarea/process_edit_template_xls.php +++ b/public/userarea/process_edit_template_xls.php @@ -39,6 +39,7 @@ try { $button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff'); $button_text_color = trim($_POST['button_text_color'] ?? '#ffffff'); $button_label = trim($_POST['button_label'] ?? 'Click Me'); + $template_note = trim($_POST['template_note'] ?? ''); // Allowed source types if (!in_array($source_type, ['XLS', 'API', 'JSON', 'PDF'], true)) { @@ -122,6 +123,7 @@ try { button_bg_color = ?, button_text_color = ?, button_label = ?, + template_note = ?, updated_at = NOW() WHERE id = ? "); @@ -144,6 +146,7 @@ try { $button_bg_color, $button_text_color, $button_label, + $template_note, $id ]); diff --git a/public/userarea/stats_export_lims.php b/public/userarea/stats_export_lims.php index 21807c4..797d13f 100644 --- a/public/userarea/stats_export_lims.php +++ b/public/userarea/stats_export_lims.php @@ -47,6 +47,27 @@ .filter-bar { gap: .75rem; } + + .stat-card-extra { + background: linear-gradient(135deg, #021bff 0%, #010983 100%); + border: none; + } + + .stat-card-extra .stat-label { + color: #d7d2f5; + } + + .stat-card-extra .stat-value { + color: #ffffff !important; + } + + .stat-card-extra small.text-muted { + color: #c9c2ec !important; + } + + .kpi-row { + margin-bottom: 1rem; + } @@ -71,7 +92,10 @@
- @@ -79,33 +103,51 @@ -
-
-
+
+
+
-
Export (status L)
+
Export mese
+
0
+ Dati dal 16/07/2026 +
+
+
+
+
+
+
Export anno
+
0
+ Dati dal 16/07/2026 +
+
+
+
+
+
+
Export giorno (status L)
0
-
-
+
+
Campioni inseriti LIMS
0
-
-
+
+
% Esportati / inseriti
-
-
+
+
Clienti distinti
0
@@ -388,10 +430,27 @@ // KPI $('#kpiExport').text(res.totals.export); + $('#kpiExportMonth').text(res.totalsMonth ? res.totalsMonth.export : 0); + $('#kpiExportYear').text(res.totalsYear ? res.totalsYear.export : 0); $('#kpiClienti').text(res.byClient.length); $('#kpiLimsSamples').text(res.limsSamples ?? 0); $('#limsSamplesInput').val(res.limsSamples ?? ''); + // Etichette mese/anno dei box totali + if (res.month) { + const MESI_IT = ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', + 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre' + ]; + const mParts = res.month.split('-'); + const mIdx = parseInt(mParts[1], 10) - 1; + if (mIdx >= 0 && mIdx < 12) { + $('#kpiMonthLabel').text('(' + MESI_IT[mIdx] + ' ' + mParts[0] + ')'); + } + } + if (res.year) { + $('#kpiYearLabel').text('(' + res.year + ')'); + } + const limsTot = parseInt(res.limsSamples ?? 0, 10); if (limsTot > 0) { const perc = (res.totals.export / limsTot) * 100; diff --git a/public/userarea/stats_export_lims_data.php b/public/userarea/stats_export_lims_data.php index b211abb..a918633 100644 --- a/public/userarea/stats_export_lims_data.php +++ b/public/userarea/stats_export_lims_data.php @@ -70,6 +70,26 @@ try { // --- Totale export della giornata --- $totExport = array_sum(array_column($byClient, 'tot')); + // --- Totale export del MESE della data selezionata (status = 'l') --- + $stmtM = $pdo->prepare(" + SELECT COUNT(*) + FROM datadb d + WHERE d.status = 'l' + AND DATE_FORMAT(d.export_date, '%Y-%m') = :m + "); + $stmtM->execute(['m' => $d->format('Y-m')]); + $totExportMonth = (int)$stmtM->fetchColumn(); + + // --- Totale export dell'ANNO della data selezionata (status = 'l') --- + $stmtY = $pdo->prepare(" + SELECT COUNT(*) + FROM datadb d + WHERE d.status = 'l' + AND YEAR(d.export_date) = :y + "); + $stmtY->execute(['y' => $d->format('Y')]); + $totExportYear = (int)$stmtY->fetchColumn(); + // --- Campioni totali inseriti nel LIMS per la giornata (tabella lims_daily_samples) --- $stmtL = $pdo->prepare("SELECT total_samples FROM lims_daily_samples WHERE sample_date = :d LIMIT 1"); $stmtL->execute(['d' => $date]); @@ -77,12 +97,16 @@ try { $limsSamples = ($limsSamples !== false) ? (int)$limsSamples : null; echo json_encode([ - 'success' => true, - 'date' => $date, - 'totals' => ['export' => (int)$totExport], - 'byClient' => $byClient, - 'byUser' => $byUser, - 'limsSamples' => $limsSamples, + 'success' => true, + 'date' => $date, + 'month' => $d->format('Y-m'), + 'year' => (int)$d->format('Y'), + 'totals' => ['export' => (int)$totExport], + 'totalsMonth' => ['export' => $totExportMonth], + 'totalsYear' => ['export' => $totExportYear], + 'byClient' => $byClient, + 'byUser' => $byUser, + 'limsSamples' => $limsSamples, ]); } catch (Exception $e) { error_log('Stats export LIMS error: ' . $e->getMessage()); diff --git a/public/userarea/stats_export_lims_monthly.php b/public/userarea/stats_export_lims_monthly.php new file mode 100644 index 0000000..3d81b79 --- /dev/null +++ b/public/userarea/stats_export_lims_monthly.php @@ -0,0 +1,426 @@ + + + + + + + + + + TRF-Project - Statistiche Export LIMS Mensili + + + + + +
+ + + +
+
+ + +
+
+
+
Statistiche Export LIMS — Mensili
+
+ + +
+
+ + +
+ + + Vista giornaliera + + +
+
+
+ + +
+
+
+
+
Export mese (status L)
+
0
+
+
+
+
+
+
+
Export anno (status L)
+
0
+ Dati a partire dal 16/07/2026 +
+
+
+
+
+
+
Campioni inseriti LIMS (mese)
+
0
+
+
+
+
+
+
+
% Esportati / inseriti
+
+
+
+
+
+
+
+
Clienti distinti (mese)
+
0
+
+
+
+
+ + +
+
+
+
+
Export per cliente (idclient) — top 15
+
+
+
+
+
+
+
+
+
+
Export per utente (user_id) — top 15
+
+
+
+
+
+
+
+ + +
+
+
+
+
Dettaglio per cliente
+
+
+
+ + + + + + + + + +
ID ClienteClienteExport
+
+
+
+
+
+
+
+
Dettaglio per utente
+
+
+
+ + + + + + + + + +
ID UtenteUtenteExport
+
+
+
+
+
+ +
+
+ +
+ + +
+ + + + + + + + + + \ No newline at end of file diff --git a/public/userarea/stats_export_lims_monthly_data.php b/public/userarea/stats_export_lims_monthly_data.php new file mode 100644 index 0000000..f5ff68c --- /dev/null +++ b/public/userarea/stats_export_lims_monthly_data.php @@ -0,0 +1,107 @@ +getConnection(); + +try { + // Mese richiesto (default mese corrente). Formato atteso: Y-m + $month = $_GET['month'] ?? date('Y-m'); + $dm = DateTime::createFromFormat('Y-m', $month); + if (!$dm || $dm->format('Y-m') !== $month) { + throw new Exception('Mese non valido'); + } + + $year = $dm->format('Y'); + + // --- Export per cliente (status = 'l', giornata su export_date, filtro mese) --- + $stmtC = $pdo->prepare(" + SELECT d.idclient AS idclient, + COUNT(*) AS tot + FROM datadb d + WHERE d.status = 'l' + AND DATE_FORMAT(d.export_date, '%Y-%m') = :m + GROUP BY d.idclient + ORDER BY tot DESC + "); + $stmtC->execute(['m' => $month]); + $byClient = $stmtC->fetchAll(PDO::FETCH_ASSOC); + + // --- Risolvi Nominativo cliente dalla cache locale --- + $clientNames = []; + $cacheFile = __DIR__ . '/cache/clienti.json'; + if (is_file($cacheFile)) { + $cache = json_decode(file_get_contents($cacheFile), true); + foreach (($cache['value'] ?? []) as $c) { + $clientNames[(int)($c['IdCliente'] ?? 0)] = trim($c['Nominativo'] ?? ''); + } + } + + // --- Export per utente (status = 'l', filtro mese) --- + $stmtU = $pdo->prepare(" + SELECT d.user_id AS user_id, + TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))) AS username, + COUNT(*) AS tot + FROM datadb d + LEFT JOIN auth_users u ON u.id = d.user_id + WHERE d.status = 'l' + AND DATE_FORMAT(d.export_date, '%Y-%m') = :m + GROUP BY d.user_id, username + ORDER BY tot DESC + "); + $stmtU->execute(['m' => $month]); + $byUser = $stmtU->fetchAll(PDO::FETCH_ASSOC); + + // Normalizza tipi + foreach ($byClient as &$r) { + $r['idclient'] = $r['idclient'] !== null ? (int)$r['idclient'] : null; + $r['tot'] = (int)$r['tot']; + $nm = $clientNames[$r['idclient']] ?? ''; + $r['clientname'] = $nm !== '' ? $nm : null; + } + unset($r); + foreach ($byUser as &$r) { + $r['user_id'] = $r['user_id'] !== null ? (int)$r['user_id'] : null; + $r['tot'] = (int)$r['tot']; + if (isset($r['username'])) $r['username'] = $r['username'] !== null && $r['username'] !== '' ? $r['username'] : null; + } + unset($r); + + // --- Totale export del mese --- + $totExport = array_sum(array_column($byClient, 'tot')); + + // --- Totale export dell'ANNO del mese selezionato --- + $stmtY = $pdo->prepare(" + SELECT COUNT(*) + FROM datadb d + WHERE d.status = 'l' + AND YEAR(d.export_date) = :y + "); + $stmtY->execute(['y' => $year]); + $totExportYear = (int)$stmtY->fetchColumn(); + + // --- Campioni LIMS: somma dei total_samples di tutti i giorni del mese --- + $stmtL = $pdo->prepare(" + SELECT COALESCE(SUM(total_samples), 0) + FROM lims_daily_samples + WHERE DATE_FORMAT(sample_date, '%Y-%m') = :m + "); + $stmtL->execute(['m' => $month]); + $limsSamples = (int)$stmtL->fetchColumn(); + + echo json_encode([ + 'success' => true, + 'month' => $month, + 'year' => (int)$year, + 'totals' => ['export' => (int)$totExport], + 'totalsYear' => ['export' => $totExportYear], + 'byClient' => $byClient, + 'byUser' => $byUser, + 'limsSamples' => $limsSamples, + ]); +} catch (Exception $e) { + error_log('Stats export LIMS monthly error: ' . $e->getMessage()); + echo json_encode(['success' => false, 'message' => $e->getMessage()]); +}