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) ORDER BY FIELD(d.iddatadb, $ph) "; $stmt = $pdo->prepare($sql); $stmt->execute(array_merge($ids, $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)); // cliente bloccato per ogni iddatadb (CodiceASL con "blocco", letto dalla cache clienti, nessuna chiamata API) $blockByRow = []; // iddatadb => ['idCliente','nominativo','motivo','campo'] foreach ($rows as $r) { $bl = getClientBlockAlert($r['idclient'] ?? 0, $r['ClienteFatturazione'] ?? null); if ($bl) { $blockByRow[(int)$r['iddatadb']] = $bl; } } $blockTotal = count($blockByRow); // 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. La mail riflette lo stato in DB al momento dell'invio: una riga ancora 'i' // (export interrotto da timeout/errore di rete, o ancora in corso) NON è un successo. $okCount = 0; $errCount = 0; $pendingCount = 0; foreach ($rows as $r) { if ($r['status'] === 'l') $okCount++; elseif ($r['status'] === 'x') $errCount++; else $pendingCount++; } $hasError = $errCount > 0; $hasPending = $pendingCount > 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 = 'NON CONFERMATA'; $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 .= "