added error page and logs linked
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddLogFileToDatadb extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function change(): void
|
||||||
|
{
|
||||||
|
$table = $this->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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddErrorStatusToDatadb extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// Aggiunge 'x' (errore export) all'enum status, preservando i valori esistenti
|
||||||
|
$this->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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->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;
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$template_id = intval($_GET['id'] ?? 0);
|
||||||
|
if (!$template_id) {
|
||||||
|
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Template ID mancante"));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $iduserlogin ?? 1;
|
||||||
|
$show_all_users = isset($_GET['all_users']) && $_GET['all_users'] == '1';
|
||||||
|
$allowedLimits = [20, 40, 60, 100];
|
||||||
|
$rawLimit = (int)($_GET['limit'] ?? 20);
|
||||||
|
$perPage = in_array($rawLimit, $allowedLimits) ? $rawLimit : 20;
|
||||||
|
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->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);
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="it">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||||
|
<?php include('cssinclude.php'); ?>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
<style>
|
||||||
|
.err-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.err-table th,
|
||||||
|
.err-table td {
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.err-table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.err-table tr:hover {
|
||||||
|
background: #fff8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-x {
|
||||||
|
background: #dc3545;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.err-msg {
|
||||||
|
color: #b02a37;
|
||||||
|
max-width: 420px;
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commessa-code {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #555;
|
||||||
|
display: block;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 5px 8px;
|
||||||
|
margin-right: 4px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-resend {
|
||||||
|
background: #28a745;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-log {
|
||||||
|
background: #17a2b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-revert {
|
||||||
|
background: #fd7e14;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pager-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pager-num,
|
||||||
|
.pager-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 6px;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #495057;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pager-num.active {
|
||||||
|
background: #0d6efd;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #0d6efd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>Export Errors - <?= htmlspecialchars($titlewebsite ?? '', ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<?php include('include/navbar.php'); ?>
|
||||||
|
<?php include('include/topbar.php'); ?>
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<div class="page-content">
|
||||||
|
|
||||||
|
<div class="mb-3 d-flex align-items-center gap-2">
|
||||||
|
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
|
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success me-2">To LIMS (l)</a>
|
||||||
|
<a href="errors.php?id=<?= $template_id ?>" class="btn btn-danger">Errors (x)</a>
|
||||||
|
<span class="ms-3">
|
||||||
|
<label class="form-check-label" style="font-size:13px; cursor:pointer;">
|
||||||
|
<?php $tp = $_GET;
|
||||||
|
unset($tp['all_users']);
|
||||||
|
$toggleBase = 'errors.php?' . http_build_query($tp); ?>
|
||||||
|
<input type="checkbox" class="form-check-input" <?= $show_all_users ? 'checked' : '' ?>
|
||||||
|
onchange="window.location.href='<?= htmlspecialchars($toggleBase) ?>' + (this.checked ? '&all_users=1' : '')">
|
||||||
|
Show all users
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="text-muted" style="font-size:12px;">(<?= count($rowsData) ?> of <?= $totalRows ?> errori<?= !$show_all_users ? ' — my records' : '' ?>)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($totalPages > 1):
|
||||||
|
$pageQuery = $_GET;
|
||||||
|
unset($pageQuery['page']);
|
||||||
|
$pageBase = 'errors.php?' . http_build_query($pageQuery); ?>
|
||||||
|
<div class="pager-bar">
|
||||||
|
<span>Pagina <?= $page ?> di <?= $totalPages ?> — <?= $totalRows ?> righe</span>
|
||||||
|
<span>
|
||||||
|
<?php for ($p = 1; $p <= $totalPages; $p++): ?>
|
||||||
|
<a href="<?= htmlspecialchars($pageBase . '&page=' . $p) ?>" class="pager-num <?= $p === $page ? 'active' : '' ?>"><?= $p ?></a>
|
||||||
|
<?php endfor; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card radius-10">
|
||||||
|
<div class="card-header">
|
||||||
|
<span style="font-weight:600;"><i class="fas fa-triangle-exclamation" style="color:#dc3545;"></i> Export falliti verso il LIMS</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php if (empty($rowsData)): ?>
|
||||||
|
<p class="text-muted mb-0">Nessun errore di export. 🎉</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<div style="overflow-x:auto;">
|
||||||
|
<table class="err-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:170px;">Azioni</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Errore</th>
|
||||||
|
<th style="width:150px;">Data export</th>
|
||||||
|
<th>File import</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($rowsData as $row):
|
||||||
|
$errMsg = extractErrorSummary($logDir, $row['log_file'] ?? null); ?>
|
||||||
|
<tr data-id="<?= (int)$row['iddatadb'] ?>">
|
||||||
|
<td>
|
||||||
|
<button type="button" class="action-btn btn-resend resend-btn" data-iddatadb="<?= (int)$row['iddatadb'] ?>" title="Reinvia al LIMS"><i class="fas fa-paper-plane"></i></button>
|
||||||
|
<?php if (!empty($row['log_file'])): ?>
|
||||||
|
<a href="download_logs.php?iddatadb=<?= (int)$row['iddatadb'] ?>" class="action-btn btn-log" title="Scarica log"><i class="fas fa-file-download"></i></a>
|
||||||
|
<?php endif; ?>
|
||||||
|
<button type="button" class="action-btn btn-revert revert-btn" data-iddatadb="<?= (int)$row['iddatadb'] ?>" title="Riporta a Imported"><i class="fas fa-rotate-left"></i></button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-badge status-x">Error</span>
|
||||||
|
<?php if (!empty($row['commessaweb'])): ?>
|
||||||
|
<span class="commessa-code"><?= htmlspecialchars($row['commessaweb']) ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><span class="client-text" data-client-id="<?= htmlspecialchars((string)($row['idclient'] ?? '')) ?>"><?= htmlspecialchars((string)($row['idclient'] ?? '')) ?></span></td>
|
||||||
|
<td class="err-msg"><?= htmlspecialchars($errMsg ?: '—') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string)($row['export_date'] ?? '')) ?></td>
|
||||||
|
<td><?php if (!empty($row['filename_import'])): ?><a href="imported_trf/<?= htmlspecialchars($row['filename_import']) ?>" target="_blank">File</a><?php endif; ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overlay toggle-icon"></div>
|
||||||
|
<?php include('include/footer.php'); ?>
|
||||||
|
</div>
|
||||||
|
<?php include('jsinclude.php'); ?>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// Risoluzione nomi cliente (come in tolims.php)
|
||||||
|
(function() {
|
||||||
|
const ids = new Set();
|
||||||
|
document.querySelectorAll('.client-text').forEach(el => {
|
||||||
|
const id = el.dataset.clientId;
|
||||||
|
if (id) ids.add(id);
|
||||||
|
});
|
||||||
|
ids.forEach(id => {
|
||||||
|
fetch('search_clienti.php?id=' + encodeURIComponent(id))
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(j => {
|
||||||
|
const it = (j.results || [])[0];
|
||||||
|
if (it) document.querySelectorAll('.client-text[data-client-id="' + id + '"]').forEach(el => el.textContent = it.text);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Reinvia: richiama export_to_lims.php da capo (create incluso)
|
||||||
|
$(document).on('click', '.resend-btn', function() {
|
||||||
|
const $btn = $(this);
|
||||||
|
const iddatadb = $btn.data('iddatadb');
|
||||||
|
if (!confirm('Reinviare questa commessa al LIMS? Verrà creata una nuova commessa nel LIMS.')) return;
|
||||||
|
|
||||||
|
const original = $btn.html();
|
||||||
|
$btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i>');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'export_to_lims.php',
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
iddatadb: iddatadb
|
||||||
|
},
|
||||||
|
success: function(res) {
|
||||||
|
if (res && res.success) {
|
||||||
|
const $tr = $('tr[data-id="' + iddatadb + '"]');
|
||||||
|
$tr.css('background', '#d4edda');
|
||||||
|
setTimeout(() => $tr.fadeOut(300, () => $tr.remove()), 500);
|
||||||
|
} else {
|
||||||
|
alert('Ancora errore: ' + ((res && res.message) ? res.message : 'invio non riuscito'));
|
||||||
|
$btn.prop('disabled', false).html(original);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
alert('Errore di rete durante il reinvio.');
|
||||||
|
$btn.prop('disabled', false).html(original);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Revert a Imported (i)
|
||||||
|
$(document).on('click', '.revert-btn', function() {
|
||||||
|
const $btn = $(this);
|
||||||
|
const iddatadb = $btn.data('iddatadb');
|
||||||
|
if (!confirm('Riportare questo record a Imported (i)?')) return;
|
||||||
|
$.ajax({
|
||||||
|
url: 'revert_status.php',
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
iddatadb: iddatadb,
|
||||||
|
status: 'i'
|
||||||
|
},
|
||||||
|
success: function(res) {
|
||||||
|
if (res && res.success) {
|
||||||
|
const $tr = $('tr[data-id="' + iddatadb + '"]');
|
||||||
|
$tr.fadeOut(300, () => $tr.remove());
|
||||||
|
} else {
|
||||||
|
alert('Errore: ' + ((res && res.message) ? res.message : 'operazione non riuscita'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
alert('Errore di rete.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -55,22 +55,29 @@ $apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/';
|
|||||||
// 🔹 Batch UUID — if present, all logs go to a single file
|
// 🔹 Batch UUID — if present, all logs go to a single file
|
||||||
$batchUuid = $_POST['batch_uuid'] ?? null;
|
$batchUuid = $_POST['batch_uuid'] ?? null;
|
||||||
|
|
||||||
$writeLog = (function () use ($batchUuid, $logDir) {
|
// File unico per questa commessa (nominato per iddatadb, che conosciamo sempre)
|
||||||
$batchLogFile = $batchUuid ? $logDir . "batch_export_{$batchUuid}.log" : null;
|
$iddatadbForLog = $_POST['iddatadb'] ?? 'unknown';
|
||||||
|
$commessaLogFile = $logDir . "commessa_{$iddatadbForLog}_" . time() . ".log";
|
||||||
|
|
||||||
return function ($individualPath, $content, $stepLabel = null) use ($batchLogFile) {
|
// File di lotto: resta come INDICE (quali commesse nel lotto), non più tutti gli step
|
||||||
if ($batchLogFile) {
|
$batchIndexFile = $batchUuid ? $logDir . "batch_export_{$batchUuid}.log" : null;
|
||||||
$header = "\n" . str_repeat("=", 60) . "\n";
|
|
||||||
if ($stepLabel) {
|
// $writeLog ora appende sempre sul file unico della commessa, con header di step
|
||||||
$header .= "[{$stepLabel}] " . date('Y-m-d H:i:s') . "\n";
|
$writeLog = function ($individualPath, $content, $stepLabel = null) use ($commessaLogFile) {
|
||||||
}
|
$header = "\n" . str_repeat("=", 60) . "\n";
|
||||||
$header .= str_repeat("=", 60) . "\n";
|
if ($stepLabel) {
|
||||||
file_put_contents($batchLogFile, $header . $content . "\n", FILE_APPEND);
|
$header .= "[{$stepLabel}] " . date('Y-m-d H:i:s') . "\n";
|
||||||
} else {
|
}
|
||||||
file_put_contents($individualPath, $content);
|
$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
|
// 🔹 Funzione per validare e convertire date
|
||||||
function validateDate($value)
|
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("
|
$stmt = $pdo->prepare("
|
||||||
UPDATE datadb
|
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
|
WHERE iddatadb = :iddatadb
|
||||||
");
|
");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
'idcommessaweb' => $commessaId,
|
'idcommessaweb' => $commessaId,
|
||||||
'commessaweb' => $commessaWebCode,
|
'commessaweb' => $commessaWebCode,
|
||||||
'iddatadb' => $iddatadb
|
'log_file' => basename($commessaLogFile),
|
||||||
|
'iddatadb' => $iddatadb
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
|
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
|
||||||
@@ -770,9 +781,12 @@ try {
|
|||||||
");
|
");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
'commessaweb' => substr($finalCodiceCommessa, 0, 30),
|
'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
|
// 🔹 STEP 11: Prepare final response
|
||||||
$finalCommessa = [
|
$finalCommessa = [
|
||||||
"Cliente" => $clienteId,
|
"Cliente" => $clienteId,
|
||||||
@@ -818,10 +832,32 @@ try {
|
|||||||
$errContent .= "MESSAGE: " . $e->getMessage() . "\n\n";
|
$errContent .= "MESSAGE: " . $e->getMessage() . "\n\n";
|
||||||
$errContent .= "TRACE:\n" . $e->getTraceAsString() . "\n";
|
$errContent .= "TRACE:\n" . $e->getTraceAsString() . "\n";
|
||||||
|
|
||||||
$errName = $errCommessaId
|
// Appendi l'errore in coda al file unico della commessa (se esiste),
|
||||||
? "commessa_{$errCommessaId}_ERROR_{$errIddatadb}_" . time() . ".txt"
|
// così resta tutto in un posto solo.
|
||||||
: "commessa_ERROR_{$errIddatadb}_" . time() . ".txt";
|
if (isset($commessaLogFile)) {
|
||||||
@file_put_contents($logDir . $errName, $errContent);
|
$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());
|
error_log("LIMS Export Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString());
|
||||||
|
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
<div class="mb-3 text">
|
<div class="mb-3 text">
|
||||||
<a href="imported.php?id=<?= $id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
<a href="imported.php?id=<?= $id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
<a href="tolims.php?id=<?= $id ?>" class="btn btn-success">To LIMS (l)</a>
|
<a href="tolims.php?id=<?= $id ?>" class="btn btn-success">To LIMS (l)</a>
|
||||||
|
<a href="errors.php?id=<?= $id ?>" class="btn btn-danger">Errors (x)</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card radius-10">
|
<div class="card radius-10">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|||||||
@@ -1530,7 +1530,8 @@ $gridMeta = [
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="mb-3 text d-flex align-items-center gap-2">
|
<div class="mb-3 text d-flex align-items-center gap-2">
|
||||||
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success">To LIMS (l)</a>
|
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success me-2">To LIMS (l)</a>
|
||||||
|
<a href="errors.php?id=<?= $template_id ?>" class="btn btn-danger">Errors (x)</a>
|
||||||
<?php if ($importref === ''): ?>
|
<?php if ($importref === ''): ?>
|
||||||
<span class="ms-3">
|
<span class="ms-3">
|
||||||
<label class="form-check-label" style="font-size: 13px; cursor: pointer;">
|
<label class="form-check-label" style="font-size: 13px; cursor: pointer;">
|
||||||
|
|||||||
@@ -822,12 +822,12 @@ function resolveFixedValue(string $key, $val, array $fixedLookup): string
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
padding: 6px 8px;
|
padding: 6px 4px;
|
||||||
margin-right: 5px;
|
margin-right: 3px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 35px;
|
width: 26px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1243,7 +1243,8 @@ function resolveFixedValue(string $key, $val, array $fixedLookup): string
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="mb-3 text d-flex align-items-center gap-2">
|
<div class="mb-3 text d-flex align-items-center gap-2">
|
||||||
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success">To LIMS (l)</a>
|
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success me-2">To LIMS (l)</a>
|
||||||
|
<a href="errors.php?id=<?= $template_id ?>" class="btn btn-danger">Errors (x)</a>
|
||||||
<span class="ms-3">
|
<span class="ms-3">
|
||||||
<label class="form-check-label" style="font-size: 13px; cursor: pointer;">
|
<label class="form-check-label" style="font-size: 13px; cursor: pointer;">
|
||||||
<?php
|
<?php
|
||||||
@@ -1717,6 +1718,7 @@ function resolveFixedValue(string $key, $val, array $fixedLookup): string
|
|||||||
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Photos" style="background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-camera"></i></button>
|
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Photos" style="background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-camera"></i></button>
|
||||||
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Parts" style="background: #ffc107; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-puzzle-piece"></i></button>
|
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Parts" style="background: #ffc107; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-puzzle-piece"></i></button>
|
||||||
<button type="button" class="revert-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" data-commessaweb="<?= htmlspecialchars($row['commessaweb'] ?? '', ENT_QUOTES) ?>" title="Riporta a Imported (i)" style="background: #fd7e14; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-rotate-left"></i></button>
|
<button type="button" class="revert-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" data-commessaweb="<?= htmlspecialchars($row['commessaweb'] ?? '', ENT_QUOTES) ?>" title="Riporta a Imported (i)" style="background: #fd7e14; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-rotate-left"></i></button>
|
||||||
|
<a href="download_logs.php?iddatadb=<?= (int)$row['iddatadb'] ?>" class="logs-btn action-btn" title="Scarica log LIMS" style="background:#17a2b8; color:white; border:none; border-radius:5px; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; text-decoration:none;"><i class="fas fa-file-download"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($mainFieldMapping):
|
<?php if ($mainFieldMapping):
|
||||||
$detail = array_filter($manualDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id'] && $d['datadb_id'] == $row['iddatadb']);
|
$detail = array_filter($manualDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id'] && $d['datadb_id'] == $row['iddatadb']);
|
||||||
|
|||||||
Reference in New Issue
Block a user