From 5c12d97d0e2e473602c3c627f186a78994c5cf77 Mon Sep 17 00:00:00 2001 From: solocla Date: Tue, 22 Sep 2026 13:58:14 +0200 Subject: [PATCH] added error page and logs linked --- .../20260922113321_add_log_file_to_datadb.php | 21 + ...60922114451_add_error_status_to_datadb.php | 23 ++ public/userarea/download_logs.php | 37 ++ public/userarea/errors.php | 363 ++++++++++++++++++ public/userarea/export_to_lims.php | 84 ++-- public/userarea/import_xls2.php | 1 + public/userarea/imported.php | 3 +- public/userarea/tolims.php | 10 +- 8 files changed, 513 insertions(+), 29 deletions(-) create mode 100644 db/migrations/20260922113321_add_log_file_to_datadb.php create mode 100644 db/migrations/20260922114451_add_error_status_to_datadb.php create mode 100644 public/userarea/download_logs.php create mode 100644 public/userarea/errors.php diff --git a/db/migrations/20260922113321_add_log_file_to_datadb.php b/db/migrations/20260922113321_add_log_file_to_datadb.php new file mode 100644 index 00000000..f5d82452 --- /dev/null +++ b/db/migrations/20260922113321_add_log_file_to_datadb.php @@ -0,0 +1,21 @@ +table('datadb'); + if (!$table->hasColumn('log_file')) { + $table->addColumn('log_file', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null, + 'after' => 'commessaweb', // aggiusta se la colonna non esiste + ])->update(); + } + } +} diff --git a/db/migrations/20260922114451_add_error_status_to_datadb.php b/db/migrations/20260922114451_add_error_status_to_datadb.php new file mode 100644 index 00000000..ec28b537 --- /dev/null +++ b/db/migrations/20260922114451_add_error_status_to_datadb.php @@ -0,0 +1,23 @@ +execute("ALTER TABLE `datadb` + MODIFY `status` ENUM('i','P','l','x') NULL DEFAULT NULL"); + } + + public function down(): void + { + // Rollback: riporta le eventuali 'x' a NULL prima di togliere il valore + $this->execute("UPDATE `datadb` SET `status` = NULL WHERE `status` = 'x'"); + $this->execute("ALTER TABLE `datadb` + MODIFY `status` ENUM('i','P','l') NULL DEFAULT NULL"); + } +} diff --git a/public/userarea/download_logs.php b/public/userarea/download_logs.php new file mode 100644 index 00000000..4aeda11c --- /dev/null +++ b/public/userarea/download_logs.php @@ -0,0 +1,37 @@ +getConnection(); +$logDir = __DIR__ . '/logs/api/'; + +$iddatadb = (int)($_GET['iddatadb'] ?? 0); +if ($iddatadb <= 0) { + http_response_code(400); + exit('iddatadb mancante'); +} + +$stmt = $pdo->prepare("SELECT log_file, commessaweb FROM datadb WHERE iddatadb = :id LIMIT 1"); +$stmt->execute(['id' => $iddatadb]); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$row || empty($row['log_file'])) { + http_response_code(404); + exit('Nessun log per questa commessa'); +} + +// solo basename: niente path traversal +$path = $logDir . basename($row['log_file']); +if (!is_file($path)) { + http_response_code(404); + exit('File di log non trovato: ' . basename($row['log_file'])); +} + +while (ob_get_level() > 0) { + ob_end_clean(); +} +$label = preg_replace('/[^A-Za-z0-9_\-]/', '_', (string)($row['commessaweb'] ?: $iddatadb)); +header('Content-Type: text/plain; charset=utf-8'); +header('Content-Disposition: attachment; filename="log_' . $label . '_' . $iddatadb . '.log"'); +header('Content-Length: ' . filesize($path)); +readfile($path); +exit; diff --git a/public/userarea/errors.php b/public/userarea/errors.php new file mode 100644 index 00000000..585302f4 --- /dev/null +++ b/public/userarea/errors.php @@ -0,0 +1,363 @@ +getConnection(); +$logDir = __DIR__ . '/logs/api/'; + +// Estrae un riassunto breve dell'errore dal file di log della commessa +function extractErrorSummary(string $logDir, ?string $logFile): string +{ + if (empty($logFile)) return ''; + $path = $logDir . basename($logFile); + if (!is_file($path)) return ''; + $content = @file_get_contents($path); + if ($content === false || $content === '') return ''; + + // 1) prova col "detail" del JSON del 500 + if (preg_match('/"detail"\s*:\s*"([^"]+)"/', $content, $m)) { + return trim(stripcslashes($m[1])); + } + // 2) fallback: ultima riga MESSAGE: + if (preg_match_all('/^MESSAGE:\s*(.+)$/m', $content, $m) && !empty($m[1])) { + return trim(end($m[1])); + } + return ''; +} + +// Query: solo le righe in errore per questo template +$userFilter = $show_all_users ? '' : 'AND d.user_id = ?'; +$baseWhere = "WHERE d.templateid = ? AND d.status = 'x' {$userFilter}"; +$baseParams = [$template_id]; +if (!$show_all_users) $baseParams[] = $user_id; + +$countStmt = $pdo->prepare("SELECT COUNT(*) FROM datadb d {$baseWhere}"); +$countStmt->execute($baseParams); +$totalRows = (int)$countStmt->fetchColumn(); +$totalPages = max(1, (int)ceil($totalRows / $perPage)); +if ($page > $totalPages) $page = $totalPages; + +$stmt = $pdo->prepare(" + SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name + FROM datadb d + LEFT JOIN auth_users u ON d.user_id = u.id + {$baseWhere} + ORDER BY d.export_date DESC, d.iddatadb DESC + LIMIT {$perPage} OFFSET " . (($page - 1) * $perPage) . " +"); +$stmt->execute($baseParams); +$rowsData = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> + + + + + + + + + + + Export Errors - <?= htmlspecialchars($titlewebsite ?? '', ENT_QUOTES, 'UTF-8'); ?> + + + +
+ + +
+
+ +
+ Imported (i) + To LIMS (l) + Errors (x) + + + + ( of errori) +
+ + 1): + $pageQuery = $_GET; + unset($pageQuery['page']); + $pageBase = 'errors.php?' . http_build_query($pageQuery); ?> +
+ Pagina di — righe + + + + + +
+ + +
+
+ Export falliti verso il LIMS +
+
+ +

Nessun errore di export. 🎉

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
AzioniStatusClientErroreData exportFile import
+ + + + + + + Error + + + + File
+
+ +
+
+ +
+
+
+ +
+ + + + + + \ No newline at end of file diff --git a/public/userarea/export_to_lims.php b/public/userarea/export_to_lims.php index fc189ae2..cf0fde72 100644 --- a/public/userarea/export_to_lims.php +++ b/public/userarea/export_to_lims.php @@ -55,22 +55,29 @@ $apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/'; // 🔹 Batch UUID — if present, all logs go to a single file $batchUuid = $_POST['batch_uuid'] ?? null; -$writeLog = (function () use ($batchUuid, $logDir) { - $batchLogFile = $batchUuid ? $logDir . "batch_export_{$batchUuid}.log" : null; +// File unico per questa commessa (nominato per iddatadb, che conosciamo sempre) +$iddatadbForLog = $_POST['iddatadb'] ?? 'unknown'; +$commessaLogFile = $logDir . "commessa_{$iddatadbForLog}_" . time() . ".log"; - return function ($individualPath, $content, $stepLabel = null) use ($batchLogFile) { - if ($batchLogFile) { - $header = "\n" . str_repeat("=", 60) . "\n"; - if ($stepLabel) { - $header .= "[{$stepLabel}] " . date('Y-m-d H:i:s') . "\n"; - } - $header .= str_repeat("=", 60) . "\n"; - file_put_contents($batchLogFile, $header . $content . "\n", FILE_APPEND); - } else { - file_put_contents($individualPath, $content); - } - }; -})(); +// File di lotto: resta come INDICE (quali commesse nel lotto), non più tutti gli step +$batchIndexFile = $batchUuid ? $logDir . "batch_export_{$batchUuid}.log" : null; + +// $writeLog ora appende sempre sul file unico della commessa, con header di step +$writeLog = function ($individualPath, $content, $stepLabel = null) use ($commessaLogFile) { + $header = "\n" . str_repeat("=", 60) . "\n"; + if ($stepLabel) { + $header .= "[{$stepLabel}] " . date('Y-m-d H:i:s') . "\n"; + } + $header .= str_repeat("=", 60) . "\n"; + file_put_contents($commessaLogFile, $header . $content . "\n", FILE_APPEND); +}; + +// Helper per registrare una riga nell'indice di lotto +$writeBatchIndex = function ($line) use ($batchIndexFile) { + if ($batchIndexFile) { + file_put_contents($batchIndexFile, "[" . date('Y-m-d H:i:s') . "] " . $line . "\n", FILE_APPEND); + } +}; // 🔹 Funzione per validare e convertire date function validateDate($value) @@ -693,16 +700,20 @@ try { } } - // 🔹 STEP 8: Update datadb with idcommessaweb, commessaweb, status and export date + // 🔹 STEP 8: Update datadb with idcommessaweb, commessaweb, log_file and export date + // NB: lo status 'l' viene impostato SOLO dopo invio+import ok (vedi più sotto), + // così una riga rimasta indietro non risulta "To LIMS" per errore. $stmt = $pdo->prepare(" UPDATE datadb - SET idcommessaweb = :idcommessaweb, commessaweb = :commessaweb, status = 'l', export_date = NOW() + SET idcommessaweb = :idcommessaweb, commessaweb = :commessaweb, + log_file = :log_file, export_date = NOW() WHERE iddatadb = :iddatadb "); $stmt->execute([ 'idcommessaweb' => $commessaId, - 'commessaweb' => $commessaWebCode, - 'iddatadb' => $iddatadb + 'commessaweb' => $commessaWebCode, + 'log_file' => basename($commessaLogFile), + 'iddatadb' => $iddatadb ]); // 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto) @@ -770,9 +781,12 @@ try { "); $stmt->execute([ 'commessaweb' => substr($finalCodiceCommessa, 0, 30), - 'iddatadb' => $iddatadb + 'iddatadb' => $iddatadb ]); } + + // Indice di lotto: esito OK di questa commessa + $writeBatchIndex("OK iddatadb={$iddatadb} commessa={$commessaId} codice={$finalCodiceCommessa} log=" . basename($commessaLogFile)); // 🔹 STEP 11: Prepare final response $finalCommessa = [ "Cliente" => $clienteId, @@ -818,10 +832,32 @@ try { $errContent .= "MESSAGE: " . $e->getMessage() . "\n\n"; $errContent .= "TRACE:\n" . $e->getTraceAsString() . "\n"; - $errName = $errCommessaId - ? "commessa_{$errCommessaId}_ERROR_{$errIddatadb}_" . time() . ".txt" - : "commessa_ERROR_{$errIddatadb}_" . time() . ".txt"; - @file_put_contents($logDir . $errName, $errContent); + // Appendi l'errore in coda al file unico della commessa (se esiste), + // così resta tutto in un posto solo. + if (isset($commessaLogFile)) { + $header = "\n" . str_repeat("=", 60) . "\n[ERROR] " . date('Y-m-d H:i:s') . "\n" . str_repeat("=", 60) . "\n"; + @file_put_contents($commessaLogFile, $header . $errContent . "\n", FILE_APPEND); + $errFileToSave = basename($commessaLogFile); + } else { + // fallback: file d'errore dedicato + $errName = "commessa_ERROR_{$errIddatadb}_" . time() . ".txt"; + @file_put_contents($logDir . $errName, $errContent); + $errFileToSave = $errName; + } + + // Segna la riga come errore ('x') e registra il log_file, senza lasciarla 'l' + if ($errIddatadb !== 'unknown') { + try { + $up = $pdo->prepare("UPDATE datadb SET status = 'x', log_file = :log_file WHERE iddatadb = :iddatadb"); + $up->execute(['log_file' => $errFileToSave, 'iddatadb' => $errIddatadb]); + } catch (Exception $ignore) { /* non bloccare la risposta d'errore */ } + } + } + + // Indice di lotto: esito KO di questa commessa + if (isset($writeBatchIndex)) { + $writeBatchIndex("FAIL iddatadb={$errIddatadb} commessa=" . ($errCommessaId ?? '-') . " log={$errFileToSave} :: " . $e->getMessage()); + } error_log("LIMS Export Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString()); diff --git a/public/userarea/import_xls2.php b/public/userarea/import_xls2.php index b3d94d03..5b280800 100644 --- a/public/userarea/import_xls2.php +++ b/public/userarea/import_xls2.php @@ -164,6 +164,7 @@ error_log("Loaded template: " . print_r($template, true));
Imported (i) To LIMS (l) + Errors (x)
diff --git a/public/userarea/imported.php b/public/userarea/imported.php index 11c74624..6ae3bd1c 100644 --- a/public/userarea/imported.php +++ b/public/userarea/imported.php @@ -1530,7 +1530,8 @@ $gridMeta = [
Imported (i) - To LIMS (l) + To LIMS (l) + Errors (x)