295 lines
12 KiB
PHP
295 lines
12 KiB
PHP
<?php
|
|
include('include/headscript.php');
|
|
require_once __DIR__ . '/class/Mailer.class.php';
|
|
header('Content-Type: application/json');
|
|
|
|
/**
|
|
* Risolve [IdCliente => Nominativo] leggendo la stessa cache di search_clienti.php.
|
|
* Non chiama l'API: usa cache/clienti.json (già mantenuto aggiornato dalla ricerca clienti).
|
|
*/
|
|
function resolveClientNames(array $ids): array
|
|
{
|
|
$ids = array_values(array_filter(array_map('intval', $ids), fn($v) => $v > 0));
|
|
if (empty($ids)) return [];
|
|
|
|
$cacheFile = __DIR__ . '/cache/clienti.json';
|
|
if (!file_exists($cacheFile)) return [];
|
|
|
|
$data = json_decode((string)@file_get_contents($cacheFile), true);
|
|
$clients = $data['value'] ?? [];
|
|
if (empty($clients)) return [];
|
|
|
|
// indicizza per IdCliente
|
|
$byId = [];
|
|
foreach ($clients as $c) {
|
|
$cid = (int)($c['IdCliente'] ?? 0);
|
|
if ($cid > 0) {
|
|
$byId[$cid] = trim((string)($c['Nominativo'] ?? ''));
|
|
}
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($ids as $id) {
|
|
if (isset($byId[$id]) && $byId[$id] !== '') {
|
|
$out[$id] = $byId[$id];
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
$db = DBHandlerSelect::getInstance();
|
|
$pdo = $db->getConnection();
|
|
|
|
// input: solo POST (endpoint che invia email — niente attivazione via URL)
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
http_response_code(405);
|
|
echo json_encode(['success' => false, 'message' => 'Metodo non consentito']);
|
|
exit;
|
|
}
|
|
$ids = $_POST['ids'] ?? [];
|
|
if (!is_array($ids)) $ids = explode(',', (string)$ids);
|
|
$ids = array_values(array_filter(array_map('intval', $ids), fn($v) => $v > 0));
|
|
$templateId = (int)($_POST['template_id'] ?? 0);
|
|
|
|
if (empty($ids)) {
|
|
echo json_encode(['success' => false, 'message' => 'Nessun id']);
|
|
exit;
|
|
}
|
|
|
|
// Fallback: se il template_id non arriva, ricavalo dalla prima commessa
|
|
if ($templateId <= 0) {
|
|
$tq = $pdo->prepare("SELECT templateid FROM datadb WHERE iddatadb = ? LIMIT 1");
|
|
$tq->execute([$ids[0]]);
|
|
$templateId = (int)$tq->fetchColumn();
|
|
}
|
|
|
|
// tutti i main field del template (possono essere fino a 2), in ordine
|
|
$mainMappingIds = [];
|
|
$templateName = '';
|
|
if ($templateId > 0) {
|
|
$s = $pdo->prepare("
|
|
SELECT id FROM template_mapping
|
|
WHERE template_id = ? AND main_field = '1' AND is_visible_import = 1
|
|
ORDER BY field_order ASC, id ASC
|
|
");
|
|
$s->execute([$templateId]);
|
|
$mainMappingIds = array_map('intval', $s->fetchAll(PDO::FETCH_COLUMN));
|
|
|
|
// nome del template per l'intestazione mail
|
|
$t = $pdo->prepare("SELECT name FROM excel_templates WHERE id = ? LIMIT 1");
|
|
$t->execute([$templateId]);
|
|
$templateName = (string)$t->fetchColumn();
|
|
}
|
|
|
|
// esiti delle commesse
|
|
$ph = implode(',', array_fill(0, count($ids), '?'));
|
|
$sql = "
|
|
SELECT d.iddatadb, d.commessaweb, d.status, d.user_id,
|
|
d.idclient, d.ClienteFatturazione,
|
|
CONCAT(u.first_name,' ',u.last_name) AS user_name,
|
|
u.email AS user_email, u.notify_export_email
|
|
FROM datadb d
|
|
LEFT JOIN auth_users u ON d.user_id = u.id
|
|
WHERE d.iddatadb IN ($ph)
|
|
";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($ids);
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
if (empty($rows)) {
|
|
echo json_encode(['success' => false, 'message' => 'Righe non trovate']);
|
|
exit;
|
|
}
|
|
|
|
// --- Risoluzione nomi cliente (idclient + ClienteFatturazione) ---
|
|
$clientIdsToResolve = [];
|
|
foreach ($rows as $r) {
|
|
if (!empty($r['idclient'])) $clientIdsToResolve[(int)$r['idclient']] = true;
|
|
if (!empty($r['ClienteFatturazione'])) $clientIdsToResolve[(int)$r['ClienteFatturazione']] = true;
|
|
}
|
|
$clientNames = resolveClientNames(array_keys($clientIdsToResolve)); // [id => nome]
|
|
|
|
// helper: id cliente → nome, con fallback all'id se non risolto
|
|
$clientLabel = function ($id) use ($clientNames) {
|
|
$id = (int)$id;
|
|
if ($id <= 0) return '—';
|
|
return htmlspecialchars($clientNames[$id] ?? (string)$id);
|
|
};
|
|
|
|
// valori dei main field per ogni iddatadb — concatena i main valorizzati
|
|
$mainValues = [];
|
|
if (!empty($mainMappingIds)) {
|
|
$mph = implode(',', array_fill(0, count($mainMappingIds), '?'));
|
|
$s = $pdo->prepare("
|
|
SELECT id AS iddatadb, mapping_id, field_value
|
|
FROM import_data_details
|
|
WHERE id IN ($ph) AND mapping_id IN ($mph)
|
|
");
|
|
$s->execute(array_merge($ids, $mainMappingIds));
|
|
|
|
// raggruppa per iddatadb, mantenendo l'ordine dei main
|
|
$byRow = []; // iddatadb => [mapping_id => value]
|
|
foreach ($s->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$byRow[(int)$r['iddatadb']][(int)$r['mapping_id']] = $r['field_value'];
|
|
}
|
|
foreach ($byRow as $idd => $vals) {
|
|
$parts = [];
|
|
foreach ($mainMappingIds as $mid) { // ordine dei main
|
|
$v = trim((string)($vals[$mid] ?? ''));
|
|
if ($v !== '') $parts[] = $v;
|
|
}
|
|
$mainValues[$idd] = implode(' — ', $parts); // es. "descrizione — style code"
|
|
}
|
|
}
|
|
|
|
// analisi senza prezzo (NULL o 0) per ogni iddatadb
|
|
$noPriceByRow = []; // iddatadb => [ [part_number, part_description, analysis_name], ... ]
|
|
$s = $pdo->prepare("
|
|
SELECT a.iddatadb, MAX(a.analysis_name) AS analysis_name
|
|
FROM identification_parts_analyses a
|
|
WHERE a.iddatadb IN ($ph)
|
|
AND (a.analysis_price IS NULL OR a.analysis_price <= 0)
|
|
GROUP BY a.iddatadb, a.analysis_recordkey
|
|
ORDER BY a.iddatadb, analysis_name
|
|
");
|
|
$s->execute($ids);
|
|
foreach ($s->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$noPriceByRow[(int)$r['iddatadb']][] = $r;
|
|
}
|
|
$noPriceTotal = array_sum(array_map('count', $noPriceByRow));
|
|
|
|
// destinatari: utente/i dell'export che hanno la notifica attiva + admin fisso
|
|
$recipients = [];
|
|
foreach ($rows as $r) {
|
|
if (!empty($r['user_email']) && (int)($r['notify_export_email'] ?? 1) === 1) {
|
|
$recipients[$r['user_email']] = true;
|
|
}
|
|
}
|
|
$adminEmail = env('EXPORT_SUMMARY_ADMIN', 'admin@cesoft.io'); // sempre, indipendente dalla preferenza
|
|
if ($adminEmail) $recipients[$adminEmail] = true;
|
|
$recipients = array_keys($recipients);
|
|
|
|
// Se dopo il filtro non resta nessuno, non inviare
|
|
if (empty($recipients)) {
|
|
echo json_encode(['success' => true, 'message' => 'Nessun destinatario (notifiche disattivate)', 'recipients' => []]);
|
|
exit;
|
|
}
|
|
|
|
// conteggi
|
|
$okCount = 0;
|
|
$errCount = 0;
|
|
foreach ($rows as $r) {
|
|
if ($r['status'] === 'l') $okCount++;
|
|
elseif ($r['status'] === 'x') $errCount++;
|
|
}
|
|
$hasError = $errCount > 0;
|
|
|
|
// --- tabella righe ---
|
|
$rowsHtml = '';
|
|
foreach ($rows as $r) {
|
|
$st = $r['status'];
|
|
if ($st === 'l') {
|
|
$label = 'Inviata';
|
|
$bg = '#e6f4ea';
|
|
$col = '#1e7e34';
|
|
} elseif ($st === 'x') {
|
|
$label = 'ERRORE';
|
|
$bg = '#fdecea';
|
|
$col = '#c0392b';
|
|
} else {
|
|
$label = htmlspecialchars((string)$st);
|
|
$bg = '#fff8e1';
|
|
$col = '#8a6d3b';
|
|
}
|
|
|
|
$commessa = htmlspecialchars($r['commessaweb'] ?: '—');
|
|
$main = htmlspecialchars($mainValues[(int)$r['iddatadb']] ?? '—');
|
|
|
|
$committente = $clientLabel($r['idclient'] ?? 0);
|
|
$fatturazione = $clientLabel($r['ClienteFatturazione'] ?? 0);
|
|
|
|
$rowsHtml .= "<tr>
|
|
<td style='padding:10px 10px;border-bottom:1px solid #eee;font-family:monospace;white-space:nowrap;vertical-align:top;'>{$commessa}</td>
|
|
<td style='padding:10px 10px;border-bottom:1px solid #eee;word-break:break-word;vertical-align:top;'>{$committente}</td>
|
|
<td style='padding:10px 10px;border-bottom:1px solid #eee;word-break:break-word;vertical-align:top;'>{$fatturazione}</td>
|
|
<td style='padding:10px 10px;border-bottom:1px solid #eee;word-break:break-word;vertical-align:top;'>{$main}</td>
|
|
<td style='padding:10px 10px;border-bottom:1px solid #eee;text-align:center;white-space:nowrap;vertical-align:top;'>
|
|
<span style='display:inline-block;padding:3px 10px;border-radius:12px;background:{$bg};color:{$col};font-weight:600;font-size:13px;'>{$label}</span>
|
|
</td>
|
|
</tr>";
|
|
|
|
// sotto-riga: solo le analisi No Price di questa commessa
|
|
$np = $noPriceByRow[(int)$r['iddatadb']] ?? [];
|
|
if (!empty($np)) {
|
|
$items = '';
|
|
foreach ($np as $n) {
|
|
$analysisName = htmlspecialchars((string)($n['analysis_name'] ?: 'Unnamed analysis'));
|
|
$items .= "<li style='margin:2px 0;'>{$analysisName}</li>";
|
|
}
|
|
$npCount = count($np);
|
|
|
|
$rowsHtml .= "<tr>
|
|
<td colspan='5' style='padding:8px 12px 12px 24px;border-bottom:1px solid #eee;background:#fff5f5;'>
|
|
<div style='margin-bottom:4px;font-size:12px;color:#c0392b;font-weight:600;'>
|
|
<span style='display:inline-block;padding:2px 8px;border-radius:10px;background:#c0392b;color:#fff;font-size:11px;'>No price</span>
|
|
Analisi senza prezzo ({$npCount})
|
|
</div>
|
|
<ul style='margin:0;padding-left:18px;font-size:13px;color:#555;'>{$items}</ul>
|
|
</td>
|
|
</tr>";
|
|
}
|
|
}
|
|
|
|
$headerColor = $hasError ? '#c0392b' : '#1e7e34';
|
|
$headerText = $hasError ? 'Export completato con errori' : 'Export completato con successo';
|
|
$total = count($rows);
|
|
|
|
$html = "
|
|
<div style='font-family:Arial,Helvetica,sans-serif;max-width:820px;margin:0 auto;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;'>
|
|
<div style='background:{$headerColor};color:#fff;padding:18px 24px;'>
|
|
<h2 style='margin:0;font-size:18px;'>{$headerText}</h2>
|
|
<p style='margin:6px 0 0;font-size:13px;opacity:.9;'>Riepilogo esportazione verso LIMS" .
|
|
($templateName !== '' ? " · Template: <strong>" . htmlspecialchars($templateName) . "</strong>" : "") . "</p>
|
|
<p style='margin:6px 0 0;font-size:13px;opacity:.95;'>
|
|
Committente: <strong>" . $clientLabel($rows[0]['idclient'] ?? 0) . "</strong>
|
|
·
|
|
FatturazioneAvanzata: <strong>" . $clientLabel($rows[0]['ClienteFatturazione'] ?? 0) . "</strong>
|
|
</p>
|
|
</div>
|
|
<div style='padding:20px 24px;'>
|
|
<p style='margin:0 0 14px;font-size:14px;color:#333;'>
|
|
Totale commesse: <strong>{$total}</strong> •
|
|
<span style='color:#1e7e34;'>Inviate: {$okCount}</span> •
|
|
<span style='color:#c0392b;'>Errori: {$errCount}</span>" .
|
|
($noPriceTotal > 0 ? " • <span style='color:#c0392b;'>Analisi No price: {$noPriceTotal}</span>" : "") . "
|
|
</p>
|
|
<table style='width:100%;border-collapse:collapse;font-size:14px;table-layout:fixed;'>
|
|
<thead>
|
|
<tr style='background:#f5f5f5;'>
|
|
<th style='padding:10px 10px;text-align:left;border-bottom:2px solid #ddd;width:14%;'>Commessa</th>
|
|
<th style='padding:10px 10px;text-align:left;border-bottom:2px solid #ddd;width:24%;'>Committente</th>
|
|
<th style='padding:10px 10px;text-align:left;border-bottom:2px solid #ddd;width:24%;'>Fatturazione</th>
|
|
<th style='padding:10px 10px;text-align:left;border-bottom:2px solid #ddd;width:24%;'>Riferimento</th>
|
|
<th style='padding:10px 10px;text-align:center;border-bottom:2px solid #ddd;width:14%;'>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>{$rowsHtml}</tbody>
|
|
</table>
|
|
" . ($hasError ? "<p style='margin:18px 0 0;padding:12px;background:#fdecea;border-left:4px solid #c0392b;color:#c0392b;font-size:13px;border-radius:4px;'>⚠️ Alcune commesse non sono state inviate al LIMS. Controlla la sezione <strong>Errors</strong> nell'applicazione per i dettagli e per rilanciarle.</p>" : "") . "
|
|
</div>
|
|
<div style='background:#fafafa;padding:14px 24px;font-size:12px;color:#999;border-top:1px solid #eee;'>
|
|
Messaggio automatico da SmartTRF — non rispondere a questa email.
|
|
</div>
|
|
</div>";
|
|
|
|
$subjectPrefix = $hasError ? '⚠️ Errori Export LIMS' : '✅ Export LIMS OK';
|
|
$subject = "{$subjectPrefix} — {$total} commesse ({$okCount} ok, {$errCount} err)";
|
|
|
|
$res = Mailer::send($recipients, $subject, $html);
|
|
|
|
echo json_encode([
|
|
'success' => $res['ok'],
|
|
'message' => $res['ok'] ? 'Mail inviata' : ('Mail non inviata: ' . $res['error']),
|
|
'recipients' => $recipients,
|
|
'counts' => ['ok' => $okCount, 'err' => $errCount, 'total' => $total],
|
|
]);
|