getConnection(); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); const PV_TODO = 1; // Da programmare const PV_PLAN = 6; // Programmato const PV_ACTIVE = [2, 7, 8]; // In produzione, Pausa, Problema function pvOut(array $a) { while (ob_get_level()) ob_end_clean(); header('Content-Type: application/json; charset=utf-8'); echo json_encode($a); exit; } if (!userCan('production.programming.view')) { if (isset($_GET['action']) || isset($_POST['action'])) pvOut(['success' => false, 'message' => 'Non hai i permessi per questa pagina']); while (ob_get_level()) ob_end_clean(); http_response_code(403); echo '

Accesso non consentito

Torna alla Dashboard
'; exit; } function pvHas(PDO $pdo, $t) { static $c = []; if (!isset($c[$t])) { try { $pdo->query("SELECT 1 FROM `$t` LIMIT 0"); $c[$t] = true; } catch (Throwable $e) { $c[$t] = false; } } return $c[$t]; } function pvMs($utc) { return $utc ? (new DateTime($utc, new DateTimeZone('UTC')))->getTimestamp() * 1000 : null; } /** Lavori aperti (da programmare, programmati, in macchina) con tutto quello che serve alla pagina. */ function pvJobs(PDO $pdo) { $mago = pvHas($pdo, 'mago_prod_queue'); $photos = pvHas($pdo, 'production_photos') ? "(SELECT GROUP_CONCAT(ph.photo_type) FROM production_photos ph WHERE ph.production_id = p.id)" : 'NULL'; $in = implode(',', array_merge([PV_TODO, PV_PLAN], PV_ACTIVE)); $rows = $pdo->query(" SELECT p.id, p.id_status, p.id_linea, p.priority, p.conferma_ordine, p.idmatrice, m.nome AS matrice, m.photo, p.id_cliente, c.nome AS cliente, p.data_zibo, p.data_cliente, p.data_produzione, p.metri, p.kg_sp, p.kg_p, p.ore_previste, p.note_extra, p.note_operatore, p.start_time, s.nome AS status_nome, COALESCE(s.badge_color, '#6c757d') AS status_color, (SELECT GROUP_CONCAT(ms.nome ORDER BY ms.nome SEPARATOR '||') FROM productiondata_mescole pm JOIN mescole ms ON ms.id = pm.id_mescola WHERE pm.id_productiondata = p.id) AS mescole, (SELECT GROUP_CONCAT(pm.id_mescola) FROM productiondata_mescole pm WHERE pm.id_productiondata = p.id) AS mescole_ids, (SELECT GROUP_CONCAT(ml.idlinea) FROM matrici_lines ml WHERE ml.idmatrice = p.idmatrice) AS matrice_lines, (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, " . ($mago ? "(SELECT MAX(q.mago_changed) FROM mago_prod_queue q WHERE q.productiondata_id = p.id)" : "NULL") . " AS mago_changed, " . ($mago ? "(SELECT COUNT(*) FROM mago_prod_queue q WHERE q.productiondata_id = p.id)" : "0") . " AS from_mago, $photos AS photos FROM productiondata p LEFT JOIN matrice m ON m.id = p.idmatrice LEFT JOIN clients c ON c.id = p.id_cliente LEFT JOIN production_status s ON s.id = p.id_status WHERE p.id_status IN ($in) ORDER BY p.priority IS NULL, p.priority, p.id")->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as &$j) { foreach (['id', 'id_status', 'id_linea', 'idmatrice', 'id_cliente', 'priority'] as $k) $j[$k] = $j[$k] === null ? null : (int)$j[$k]; foreach (['metri', 'kg_sp', 'kg_p', 'ore_previste'] as $k) $j[$k] = (float)$j[$k]; $j['mescole'] = $j['mescole'] ? explode('||', $j['mescole']) : []; $j['mescole_ids'] = $j['mescole_ids'] ? array_map('intval', explode(',', $j['mescole_ids'])) : []; $j['matrice_lines'] = $j['matrice_lines'] ? array_map('intval', explode(',', $j['matrice_lines'])) : []; $j['from_mago'] = (int)$j['from_mago'] > 0; $j['mago_changed'] = (int)$j['mago_changed'] === 1; $j['start_ms'] = pvMs($j['start_time']); $j['open_pause_ms'] = pvMs($j['open_pause']); $j['pause_sec'] = (int)$j['pause_sec']; $ph = ['lotto_mescola' => 0, 'parametri_macchina' => 0, 'problema' => 0]; foreach (array_filter(explode(',', (string)$j['photos'])) as $t) if (isset($ph[$t])) $ph[$t]++; $j['photos'] = $ph; unset($j['start_time'], $j['open_pause']); } unset($j); return $rows; } function pvDate($k) { $v = trim((string)($_POST[$k] ?? '')); return MagoSalesStats::isValidDate($v) ? $v : null; } /* ===================== AJAX ===================== */ $action = $_GET['action'] ?? $_POST['action'] ?? ''; if ($action !== '') { try { if ($action === 'list') { $lines = []; foreach ($pdo->query("SELECT * FROM production_lines ORDER BY line_number, id")->fetchAll(PDO::FETCH_ASSOC) as $l) { $lines[] = [ 'id' => (int)$l['id'], 'name' => $l['name'], 'color' => !empty($l['color']) ? $l['color'] : '#64748b', 'active' => !isset($l['status']) || $l['status'] === '' || $l['status'] === 'active' ]; } $nuovi = pvHas($pdo, 'mago_prod_queue') ? (int)$pdo->query("SELECT COUNT(*) FROM mago_prod_queue WHERE queue_status = 'nuovo' OR (queue_status = 'importato' AND mago_changed = 1)")->fetchColumn() : 0; pvOut(['success' => true, 'now_ms' => time() * 1000, 'lines' => $lines, 'jobs' => pvJobs($pdo), 'nuoviMago' => $nuovi]); } if ($action === 'options') { pvOut([ 'success' => true, 'matrici' => $pdo->query("SELECT id, nome FROM matrice WHERE TRIM(nome) <> '' ORDER BY nome")->fetchAll(PDO::FETCH_ASSOC), 'mescole' => $pdo->query("SELECT id, nome FROM mescole WHERE is_active = 1 ORDER BY nome")->fetchAll(PDO::FETCH_ASSOC), 'clienti' => $pdo->query("SELECT id, nome FROM clients ORDER BY nome")->fetchAll(PDO::FETCH_ASSOC), ]); } if ($action === 'matinfo') { pvOut(['success' => true, 'info' => MagoProduction::matriceInfo($pdo, (int)($_GET['id'] ?? 0))]); } // ---------- nuovo / modifica ---------- if ($action === 'save') { $id = (int)($_POST['id'] ?? 0); $idm = (int)($_POST['idmatrice'] ?? 0); $lin = (int)($_POST['id_linea'] ?? 0); if (!$idm) throw new RuntimeException('Scegli la matrice'); if (!$lin) throw new RuntimeException('Scegli la linea'); $status = (int)($_POST['id_status'] ?? PV_TODO); if (!in_array($status, [PV_TODO, PV_PLAN], true)) $status = PV_TODO; $num = function ($k, $max = 99999999) { return min($max, round((float)str_replace(',', '.', (string)($_POST[$k] ?? 0)), 2)); }; $f = [ 'conferma_ordine' => mb_substr(trim((string)($_POST['conferma_ordine'] ?? '')), 0, 50) ?: null, 'idmatrice' => $idm, 'id_linea' => $lin, 'id_cliente' => (int)($_POST['id_cliente'] ?? 0) ?: null, 'data_zibo' => pvDate('data_zibo'), 'data_cliente' => pvDate('data_cliente'), 'data_produzione' => pvDate('data_produzione'), 'metri' => $num('metri'), 'kg_sp' => $num('kg_sp'), 'kg_p' => $num('kg_p'), 'ore_previste' => $num('ore_previste', 999.99), 'note_extra' => trim((string)($_POST['note_extra'] ?? '')) ?: null, ]; $pdo->beginTransaction(); if ($id) { $st = $pdo->prepare("SELECT id_status FROM productiondata WHERE id = ? FOR UPDATE"); $st->execute([$id]); $cur = $st->fetchColumn(); if ($cur === false) throw new RuntimeException('Lavoro non trovato'); $cur = (int)$cur; $set = implode(', ', array_map(fn($k) => "$k = :$k", array_keys($f))); if (in_array($cur, [PV_TODO, PV_PLAN], true) && $status !== $cur) { $set .= ', id_status = :st, priority = :pr'; $f['st'] = $status; $f['pr'] = MagoProduction::nextPriority($pdo, $status); } $f['id'] = $id; $pdo->prepare("UPDATE productiondata SET $set WHERE id = :id")->execute($f); } else { $f['id_status'] = $status; $f['priority'] = MagoProduction::nextPriority($pdo, $status); $cols = array_keys($f); $pdo->prepare("INSERT INTO productiondata (Data, " . implode(', ', $cols) . ", fermomacchina, `hour`, hourprod, kgprod, mtprod, scarto) VALUES (CURDATE(), :" . implode(', :', $cols) . ", 0, '00:00:00', '00:00:00', 0, 0, 0)")->execute($f); $id = (int)$pdo->lastInsertId(); } $pdo->prepare("DELETE FROM productiondata_mescole WHERE id_productiondata = ?")->execute([$id]); $ins = $pdo->prepare("INSERT INTO productiondata_mescole (id_productiondata, id_mescola) VALUES (?, ?)"); foreach (array_unique(array_filter(array_map('intval', (array)($_POST['mescole'] ?? [])))) as $m) $ins->execute([$id, $m]); $pdo->commit(); pvOut(['success' => true, 'id' => $id]); } // ---------- ordine di tutte le righe (anche quelle nascoste dal filtro) ---------- if ($action === 'order') { $p = json_decode((string)($_POST['payload'] ?? ''), true); if (!is_array($p)) throw new RuntimeException('Dati non validi'); $upd = $pdo->prepare("UPDATE productiondata SET id_status = ?, priority = ? WHERE id = ? AND id_status IN (" . PV_TODO . "," . PV_PLAN . ")"); $pdo->beginTransaction(); foreach ([PV_PLAN => 'plan', PV_TODO => 'todo'] as $st => $k) { $n = 0; foreach ((array)($p[$k] ?? []) as $id) $upd->execute([$st, ++$n, (int)$id]); } $pdo->commit(); pvOut(['success' => true]); } // ---------- azioni su più righe ---------- if ($action === 'bulk') { $ids = array_values(array_filter(array_map('intval', (array)($_POST['ids'] ?? [])))); if (!$ids) throw new RuntimeException('Nessuna riga selezionata'); $op = (string)($_POST['op'] ?? ''); $pdo->beginTransaction(); if ($op === 'program' || $op === 'unprogram') { $to = $op === 'program' ? PV_PLAN : PV_TODO; $prio = MagoProduction::nextPriority($pdo, $to); $st = $pdo->prepare("UPDATE productiondata SET id_status = ?, priority = ? WHERE id = ? AND id_status IN (" . PV_TODO . "," . PV_PLAN . ")"); foreach ($ids as $id) $st->execute([$to, $prio++, $id]); } elseif ($op === 'line') { $lin = (int)($_POST['line'] ?? 0); if (!$lin) throw new RuntimeException('Scegli la linea'); $st = $pdo->prepare("UPDATE productiondata SET id_linea = ? WHERE id = ? AND id_status IN (" . PV_TODO . "," . PV_PLAN . ")"); foreach ($ids as $id) $st->execute([$lin, $id]); } else { throw new RuntimeException('Azione sconosciuta'); } $pdo->commit(); pvOut(['success' => true, 'n' => count($ids)]); } // ---------- duplica (per ripetere un lavoro) ---------- if ($action === 'duplicate') { $id = (int)($_POST['id'] ?? 0); $pdo->beginTransaction(); $prio = MagoProduction::nextPriority($pdo, PV_TODO); $st = $pdo->prepare("INSERT INTO productiondata (Data, conferma_ordine, idmatrice, id_linea, id_cliente, data_zibo, data_cliente, metri, kg_sp, kg_p, ore_previste, note_extra, id_status, priority, fermomacchina, `hour`, hourprod, kgprod, mtprod, scarto) SELECT CURDATE(), conferma_ordine, idmatrice, id_linea, id_cliente, data_zibo, data_cliente, metri, kg_sp, kg_p, ore_previste, note_extra, ?, ?, 0, '00:00:00', '00:00:00', 0, 0, 0 FROM productiondata WHERE id = ?"); $st->execute([PV_TODO, $prio, $id]); if (!$st->rowCount()) throw new RuntimeException('Lavoro non trovato'); $new = (int)$pdo->lastInsertId(); $pdo->prepare("INSERT INTO productiondata_mescole (id_productiondata, id_mescola) SELECT ?, id_mescola FROM productiondata_mescole WHERE id_productiondata = ?")->execute([$new, $id]); $pdo->commit(); pvOut(['success' => true, 'id' => $new]); } // ---------- elimina (solo non avviati) ---------- if ($action === 'delete') { $id = (int)($_POST['id'] ?? 0); $pdo->beginTransaction(); $st = $pdo->prepare("SELECT id_status FROM productiondata WHERE id = ? FOR UPDATE"); $st->execute([$id]); $cur = $st->fetchColumn(); if ($cur === false) throw new RuntimeException('Lavoro non trovato'); if (!in_array((int)$cur, [PV_TODO, PV_PLAN], true)) throw new RuntimeException('Si possono eliminare solo i lavori non ancora avviati'); if (pvHas($pdo, 'mago_prod_queue')) { $pdo->prepare("UPDATE mago_prod_queue SET queue_status = 'nuovo', productiondata_id = NULL, imported_at = NULL, mago_changed = 0, mago_changes = '', updated_at = NOW() WHERE productiondata_id = ?")->execute([$id]); } $pdo->prepare("DELETE FROM productiondata_mescole WHERE id_productiondata = ?")->execute([$id]); $pdo->prepare("DELETE FROM productiondata WHERE id = ?")->execute([$id]); $pdo->commit(); pvOut(['success' => true]); } // ---------- foto di un lavoro in macchina ---------- if ($action === 'photos') { $id = (int)($_GET['id'] ?? 0); $st = $pdo->prepare("SELECT id, photo_type, param_position, filename, created_at FROM production_photos WHERE production_id = ? ORDER BY created_at DESC, id DESC"); $st->execute([$id]); $params = []; $st2 = $pdo->prepare("SELECT pl.position, pl.short_label, pl.label FROM production_line_params pl JOIN productiondata p ON p.id_linea = pl.line_id WHERE p.id = ? ORDER BY pl.position"); try { $st2->execute([$id]); $params = $st2->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { } pvOut(['success' => true, 'rows' => $st->fetchAll(PDO::FETCH_ASSOC), 'params' => $params]); } pvOut(['success' => false, 'message' => 'Azione sconosciuta']); } catch (Throwable $e) { if ($pdo->inTransaction()) $pdo->rollBack(); $msg = $e->getMessage(); if (strpos($msg, '1451') !== false) $msg = 'Il lavoro ha dati collegati (foto, registrazioni) e non si può eliminare'; pvOut(['success' => false, 'message' => $msg]); } } ?> Programmazione produzione - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?>
Programmazione produzione
Clic su una riga per modificarla · trascina per cambiare l'ordine
In macchina
0
Programmati
0 L'ordine vale per tutte le righe, anche quelle nascoste dal filtro
# Ordine Matrice Mescole Linea Cliente Data Zibo Data cliente Metri Kg SP Kg P Ore Note Azioni
Da programmare
0 Clic sulle intestazioni per ordinare · seleziona più righe per azioni multiple
Ordine Matrice Mescole Linea Cliente Data Zibo Data cliente Metri Kg SP Kg P Ore Note Azioni