getConnection(); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* ===================== MENU (stesse voci e permessi della dashboard attuale + pagine nuove) ===================== */ $dashboardSections = [ [ 'id' => 'secOperativo', 'title' => 'Operativo', 'subtitle' => 'Produzione di tutti i giorni', 'icon' => 'πŸš€', 'buttons' => [ ['label' => 'Programmazione', 'icon' => 'πŸ—“οΈ', 'class' => 'btn-programmazione', 'url' => 'produzione_programmazione_drag.php', 'permission' => 'production.programming.view'], ['label' => 'Programmazione (nuova)', 'icon' => 'πŸ“‹', 'class' => 'btn-programmazione', 'url' => 'production_programming_v2.php', 'permission' => 'production.programming.view'], ['label' => 'Tabellone', 'icon' => '🧱', 'class' => 'btn-programmazione', 'url' => 'production_board.php', 'permission' => 'production.programming.view'], ['label' => 'Nuovi da Mago', 'icon' => 'πŸ“₯', 'class' => 'btn-mago', 'url' => 'production_mago_queue.php', 'permission' => 'production.programming.view', 'badge' => 'mago'], ['label' => 'Line View', 'icon' => 'βš™οΈ', 'class' => 'btn-status', 'url' => 'production_line_view2.php', 'permission' => 'production.line_view.view'], ['label' => 'Postazione tablet', 'icon' => 'πŸ“±', 'class' => 'btn-status', 'url' => 'production_station.php', 'permission' => 'production.line_view.view'], ['label' => 'Magazzino', 'icon' => 'πŸ“¦', 'class' => 'btn-magazzino', 'url' => 'warehouse_dashboard.php', 'permission' => 'warehouse.dashboard.view'], ['label' => 'Smart-Alert', 'icon' => '⏰', 'class' => 'btn-scadenziario', 'url' => 'scadenzario/index.php', 'permission' => 'deadlines.view'], ], ], [ 'id' => 'secDirezione', 'title' => 'Direzione', 'subtitle' => 'Statistiche, fermi e supervisione', 'icon' => 'πŸ“Š', 'buttons' => [ ['label' => 'Statistiche Produzione', 'icon' => 'πŸ“ˆ', 'class' => 'btn-statistiche', 'url' => 'production_stats.php', 'permission' => 'production.stats.view'], ['label' => 'Pause & Fermi', 'icon' => 'πŸ›‘', 'class' => 'btn-pause-stats', 'url' => 'pause_stats.php', 'permission' => 'production.stats.view'], ['label' => 'Manager', 'icon' => 'πŸ‘”', 'class' => 'btn-manager', 'url' => 'manager_produzione.php', 'permission' => 'production.manager.view'], ['label' => 'Manager Stats', 'icon' => 'πŸ“Š', 'class' => 'btn-manager-stats', 'url' => 'manager_stats.php', 'permission' => 'production.manager_stats.view'], ['label' => 'Schermo reparto', 'icon' => 'πŸ“Ί', 'class' => 'btn-kiosk', 'url' => 'kiosk_admin.php', 'permission' => 'production.programming.view'], ], ], [ 'id' => 'secVendite', 'title' => 'Business Overview', 'subtitle' => 'Ordini, fatturato, clienti e consegne (Mago)', 'icon' => 'πŸ’Ά', 'buttons' => [ ['label' => 'Sommario', 'icon' => '🚦', 'class' => 'btn-sales-summary', 'url' => 'sales_summary.php', 'permission' => 'sales.stats.view'], ['label' => 'Andamento ordini', 'icon' => '🧾', 'class' => 'btn-sales', 'url' => 'sales_orders_stats.php', 'permission' => 'sales.stats.view'], ['label' => 'Confronto anni', 'icon' => 'πŸ“Š', 'class' => 'btn-sales', 'url' => 'sales_orders_years.php', 'permission' => 'sales.stats.view'], ['label' => 'Scheda cliente', 'icon' => 'πŸͺͺ', 'class' => 'btn-sales', 'url' => 'sales_customer.php', 'permission' => 'sales.stats.view'], ['label' => 'Consegne', 'icon' => '🚚', 'class' => 'btn-sales-deliveries', 'url' => 'sales_orders_deliveries.php', 'permission' => 'sales.deliveries.view'], ], ], [ 'id' => 'secAnagrafiche', 'title' => 'Anagrafiche', 'subtitle' => 'Dati di base e setup di produzione', 'icon' => 'πŸ—‚οΈ', 'buttons' => [ ['label' => 'Mescole', 'icon' => 'βš—οΈ', 'class' => 'btn-mescole', 'url' => 'mescole.php', 'permission' => 'masterdata.mescole.view'], ['label' => 'Elenco Profili', 'icon' => '🧩', 'class' => 'btn-matrici', 'url' => 'matrici.php', 'permission' => 'masterdata.matrici.view'], ['label' => 'Linee Produzione', 'icon' => '🏭', 'class' => 'btn-linee', 'url' => 'linee.php', 'permission' => 'masterdata.linee.view'], ['label' => 'Imballaggi', 'icon' => 'πŸ“¦', 'class' => 'btn-setup', 'url' => 'packaging_items.php', 'permission' => 'masterdata.packaging.view'], ['label' => 'Suppliers', 'icon' => '🏷️', 'class' => 'btn-setup', 'url' => 'suppliers.php', 'permission' => 'masterdata.suppliers.view'], ['label' => 'Setup', 'icon' => 'βš™οΈ', 'class' => 'btn-setup', 'url' => 'lookup_values.php', 'permission' => 'masterdata.lookup.view'], ['label' => 'Fogli di lavoro', 'icon' => 'πŸ—’οΈ', 'class' => 'btn-setup', 'url' => 'worksheets.php', 'permission' => 'masterdata.worksheets.view'], ], ], [ 'id' => 'secServizi', 'title' => 'Servizi', 'subtitle' => 'Status, cause pausa, attrezzature', 'icon' => '🧰', 'buttons' => [ ['label' => 'Status', 'icon' => 'πŸ“‹', 'class' => 'btn-setup', 'url' => 'production_status.php', 'permission' => 'services.status.view'], ['label' => 'Cause di Pausa', 'icon' => 'πŸ›‘', 'class' => 'btn-problem', 'url' => 'production_pause_reasons.php', 'permission' => 'services.pause_reasons.view'], ['label' => 'Attrezzature', 'icon' => 'πŸ› οΈ', 'class' => 'btn-tools', 'url' => 'production_tools.php', 'permission' => 'services.tools.view'], ], ], [ 'id' => 'secPersonale', 'title' => 'Personale', 'subtitle' => 'Dipendenti, formazione, skill', 'icon' => 'πŸ‘₯', 'buttons' => [ ['label' => 'Dipendenti', 'icon' => 'πŸ‘₯', 'class' => 'btn-employees', 'url' => 'employees.php', 'permission' => 'hr.employees.view'], ['label' => 'Mansioni', 'icon' => '🧩', 'class' => 'btn-setup', 'url' => 'job-roles.php', 'permission' => 'hr.employees.view'], ['label' => 'Departments', 'icon' => '🏒', 'class' => 'btn-departments', 'url' => 'departments.php', 'permission' => 'hr.departments.view'], ['label' => 'DPI', 'icon' => '🦺', 'class' => 'btn-setup', 'url' => 'ppe-items.php', 'permission' => 'hr.employees.view'], ['label' => 'Gestione Formazione', 'icon' => 'πŸŽ“', 'class' => 'btn-setup', 'url' => 'trainings.php', 'permission' => 'hr.trainings.view'], ['label' => 'Skills', 'icon' => '🧠', 'class' => 'btn-setup', 'url' => 'skills.php', 'permission' => 'hr.skills.view'], ], ], ]; /* ===================== DATI ===================== */ $TZ = new DateTimeZone('Europe/Rome'); $UTC = new DateTimeZone('UTC'); $u = function (DateTime $d) use ($UTC) { $x = clone $d; return $x->setTimezone($UTC)->format('Y-m-d H:i:s'); }; const DV2_NOT_FINISHED = '1,6,2,7'; // da programmare, programmato, in produzione, pausa /** Lavori conclusi tra due istanti locali (per ora di fine, salvata in UTC). */ $produced = function (DateTime $from, DateTime $to) use ($pdo, $u) { $st = $pdo->prepare("SELECT COUNT(*) n, COALESCE(SUM(kgprod),0) kg, COALESCE(SUM(mtprod),0) mt, COALESCE(SUM(scarto),0) sc FROM productiondata WHERE end_time >= ? AND end_time < ? AND id_status NOT IN (" . DV2_NOT_FINISHED . ")"); $st->execute([$u($from), $u($to)]); $r = $st->fetch(PDO::FETCH_ASSOC); $kg = (float)$r['kg']; $sc = (float)$r['sc']; return ['n' => (int)$r['n'], 'kg' => $kg, 'mt' => (float)$r['mt'], 'scarto' => ($kg + $sc) > 0 ? $sc / ($kg + $sc) * 100 : null]; }; $now = new DateTime('now', $TZ); $today = new DateTime('today', $TZ); $yest = (clone $today)->modify('-1 day'); $yestSame = (clone $yest)->setTime((int)$now->format('H'), (int)$now->format('i')); $monthStart = new DateTime('first day of this month 00:00', $TZ); $prevMonthStart = (clone $monthStart)->modify('-1 month'); $prevMonthSame = (clone $prevMonthStart)->modify('+' . ($now->getTimestamp() - $monthStart->getTimestamp()) . ' seconds'); $K = ['today' => null, 'yest' => null, 'month' => null, 'prevMonth' => null]; $stops = null; $todo = ['mago' => 0, 'problemi' => 0, 'compilare' => 0, 'daprog' => 0, 'ritardo' => 0]; $lines = []; try { $K['today'] = $produced($today, $now); $K['yest'] = $produced($yest, $yestSame); $K['month'] = $produced($monthStart, $now); $K['prevMonth'] = $produced($prevMonthStart, $prevMonthSame); // ore di fermo della settimana $mon = new DateTime('monday this week', $TZ); $st = $pdo->prepare("SELECT COALESCE(SUM(GREATEST(0, TIMESTAMPDIFF(SECOND, GREATEST(start_pause, ?), COALESCE(end_pause, UTC_TIMESTAMP())))), 0) FROM production_pauses WHERE COALESCE(end_pause, UTC_TIMESTAMP()) > ?"); $st->execute([$u($mon), $u($mon)]); $stops = (int)$st->fetchColumn() / 3600; // cose da gestire $todo['problemi'] = (int)$pdo->query("SELECT COUNT(*) FROM productiondata WHERE id_status = 8")->fetchColumn(); $todo['compilare'] = (int)$pdo->query("SELECT COUNT(*) FROM productiondata WHERE id_status = 11")->fetchColumn(); $todo['daprog'] = (int)$pdo->query("SELECT COUNT(*) FROM productiondata WHERE id_status = 1")->fetchColumn(); $todo['ritardo'] = (int)$pdo->query("SELECT COUNT(*) FROM productiondata WHERE id_status IN (1,6) AND data_zibo IS NOT NULL AND data_zibo < CURDATE()")->fetchColumn(); try { $todo['mago'] = (int)$pdo->query("SELECT COUNT(*) FROM mago_prod_queue WHERE queue_status = 'nuovo' OR (queue_status = 'importato' AND mago_changed = 1)")->fetchColumn(); } catch (Throwable $e) { } // linee adesso foreach ($pdo->query("SELECT * FROM production_lines ORDER BY line_number, id")->fetchAll(PDO::FETCH_ASSOC) as $l) { if (isset($l['status']) && $l['status'] !== '' && $l['status'] !== 'active') continue; $lines[(int)$l['id']] = ['id' => (int)$l['id'], 'name' => $l['name'], 'color' => $l['color'] ?: '#64748b', 'job' => null, 'queue' => 0, 'next' => null]; } $rows = $pdo->query(" SELECT p.id_linea, p.id_status, p.start_time, p.ore_previste, m.nome AS matrice, (SELECT COALESCE(SUM(TIMESTAMPDIFF(SECOND, pp.start_pause, pp.end_pause)),0) FROM production_pauses pp WHERE pp.id_production = p.id AND pp.end_pause IS NOT NULL) AS pause_sec, (SELECT pp.start_pause FROM production_pauses pp WHERE pp.id_production = p.id AND pp.end_pause IS NULL ORDER BY pp.start_pause DESC LIMIT 1) AS open_pause FROM productiondata p LEFT JOIN matrice m ON m.id = p.idmatrice WHERE p.id_status IN (2,7) ORDER BY p.start_time")->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $r) { $lid = (int)$r['id_linea']; if (!isset($lines[$lid]) || $lines[$lid]['job']) continue; $lines[$lid]['job'] = [ 'matrice' => $r['matrice'], 'paused' => (int)$r['id_status'] === 7, 'start_ms' => $r['start_time'] ? (new DateTime($r['start_time'], $UTC))->getTimestamp() * 1000 : null, 'open_pause_ms' => $r['open_pause'] ? (new DateTime($r['open_pause'], $UTC))->getTimestamp() * 1000 : null, 'pause_sec' => (int)$r['pause_sec'], 'ore' => (float)$r['ore_previste'], ]; } foreach ($pdo->query("SELECT p.id_linea, m.nome FROM productiondata p LEFT JOIN matrice m ON m.id = p.idmatrice WHERE p.id_status = 6 ORDER BY p.priority IS NULL, p.priority, p.id") as $r) { $lid = (int)$r['id_linea']; if (!isset($lines[$lid])) continue; $lines[$lid]['queue']++; if ($lines[$lid]['next'] === null) $lines[$lid]['next'] = $r['nome']; } } catch (Throwable $e) { // la dashboard resta usabile anche se un dato non Γ¨ disponibile } $userName = ''; if (!empty($iduserlogin)) { try { $st = $pdo->prepare("SELECT COALESCE(NULLIF(TRIM(first_name), ''), username, email) FROM auth_users WHERE id = ?"); $st->execute([(int)$iduserlogin]); $userName = (string)$st->fetchColumn(); } catch (Throwable $e) { } } if (!function_exists('visibleButtons')) { function visibleButtons(array $buttons) { return array_values(array_filter($buttons, fn($b) => empty($b['permission']) || userCan($b['permission']))); } } function dv2Num($v, $d = 0) { return number_format((float)$v, $d, ',', '.'); } /** Freccia di confronto (β–² β–Ό) con percentuale. */ function dv2Cmp($cur, $prev, $lowerBetter = false) { if ($cur === null || $prev === null) return 'β€”'; if (!$prev && !$cur) return '= uguale'; if (!$prev) return 'β–² nuovo'; $p = round(($cur - $prev) / $prev * 100); if ($p == 0) return '= uguale'; $good = $lowerBetter ? $p < 0 : $p > 0; return '' . ($p > 0 ? 'β–²' : 'β–Ό') . ' ' . abs($p) . '%'; } $hour = (int)$now->format('H'); $greet = $hour < 13 ? 'Buongiorno' : ($hour < 18 ? 'Buon pomeriggio' : 'Buonasera'); $GIORNI = ['domenica', 'lunedΓ¬', 'martedΓ¬', 'mercoledΓ¬', 'giovedΓ¬', 'venerdΓ¬', 'sabato']; $MESI = ['', 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre']; $canProg = userCan('production.programming.view'); $canLine = userCan('production.line_view.view'); $canStats = userCan('production.stats.view'); ?> $sec['id'], 'title' => $sec['title'], 'icon' => $sec['icon'], 'buttons' => $b]; } $todoItems = []; if ($canProg && $todo['mago']) $todoItems[] = ['n' => $todo['mago'], 'l' => 'Nuovi ordini da Mago', 'u' => 'production_mago_queue.php', 'c' => 'info', 'i' => 'πŸ“₯']; if ($canProg && $todo['ritardo']) $todoItems[] = ['n' => $todo['ritardo'], 'l' => 'Data Zibo giΓ  passata', 'u' => 'production_programming_v2.php', 'c' => 'hot', 'i' => '⏰']; if ($todo['problemi']) $todoItems[] = ['n' => $todo['problemi'], 'l' => 'Chiusi con problema', 'u' => $canLine ? 'production_line_view2.php' : '', 'c' => 'hot', 'i' => '⚠️']; if ($todo['compilare']) $todoItems[] = ['n' => $todo['compilare'], 'l' => 'Dati di fine da compilare', 'u' => $canLine ? 'production_line_view2.php' : '', 'c' => 'warn', 'i' => 'πŸ“']; if ($canProg && $todo['daprog']) $todoItems[] = ['n' => $todo['daprog'], 'l' => 'Da programmare', 'u' => 'production_programming_v2.php', 'c' => 'plain', 'i' => 'πŸ—“οΈ']; $t = $K['today']; $y = $K['yest']; $m = $K['month']; $pm = $K['prevMonth']; ?> Dashboard <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?>

format('w')] . ' ' . $now->format('j') . ' ' . $MESI[(int)$now->format('n')] ?>
format('H:i') ?>

πŸ“Œ Da gestire

>
apri
βœ“Tutto in ordine

⭐ I tuoi preferiti

🧭 Tutte le funzioni

Nessuna funzione disponibile per il tuo profilo.