o.order_date THEN o.confirmed_delivery_date END, o.compulsory_delivery_date ) AS due_date, CASE WHEN o.cancelled = 1 THEN 'annullato' WHEN o.delivered = 1 THEN 'evaso' WHEN o.is_blocked = 1 THEN 'bloccato' ELSE 'aperto' END AS status FROM mago_sale_ord o LEFT JOIN mago_cust_supp c ON c.cust_supp_type = " . self::CUSTOMER_TYPE . " AND c.cust_supp = o.customer ) x"; } /** * WHERE + parametri dai filtri in querystring. * $override sostituisce from/to (stringa vuota = nessun filtro data). */ public static function buildWhere(array $override = []) { $w = ['1=1']; $p = []; $from = array_key_exists('from', $override) ? $override['from'] : ($_GET['from'] ?? ''); $to = array_key_exists('to', $override) ? $override['to'] : ($_GET['to'] ?? ''); if (self::isValidDate($from)) { $w[] = 'x.order_date >= :from'; $p['from'] = $from; } if (self::isValidDate($to)) { $w[] = 'x.order_date <= :to'; $p['to'] = $to; } $multi = [ 'customers' => 'x.customer', 'salespeople' => 'x.salesperson', 'areas' => 'x.area', ]; foreach ($multi as $key => $col) { $vals = self::arrParam($key); if (!$vals) continue; $ph = []; foreach ($vals as $i => $v) { $name = $key . $i; $ph[] = ':' . $name; $p[$name] = $v; } $w[] = "$col IN (" . implode(',', $ph) . ")"; } $statusMap = [ 'aperto' => "x.status = 'aperto'", 'evaso' => "x.status = 'evaso'", 'annullato' => "x.status = 'annullato'", 'bloccato' => "x.status = 'bloccato'", 'ritardo' => "(x.status IN ('aperto','bloccato') AND x.due_date < CURDATE())", 'da_fatturare' => "(x.delivered = 1 AND x.invoiced = 0 AND x.cancelled = 0)", 'fatturato' => "x.invoiced = 1", ]; $statuses = array_intersect(self::arrParam('statuses'), array_keys($statusMap)); if ($statuses) { $w[] = '(' . implode(' OR ', array_map(function ($s) use ($statusMap) { return $statusMap[$s]; }, $statuses)) . ')'; } $q = trim((string)($_GET['q'] ?? '')); if ($q !== '') { $like = '%' . $q . '%'; $w[] = '(x.internal_ord_no LIKE :q1 OR x.external_ord_no LIKE :q2 OR x.your_reference LIKE :q3 OR x.company_name LIKE :q4 OR x.customer LIKE :q5)'; $p['q1'] = $p['q2'] = $p['q3'] = $p['q4'] = $p['q5'] = $like; } return [implode(' AND ', $w), $p]; } public static function fetchAllQ(PDO $pdo, $sql, array $params) { $st = $pdo->prepare($sql); $st->execute($params); return $st->fetchAll(PDO::FETCH_ASSOC); } /** Stato dell'ultima sincronizzazione (per il badge in alto). */ public static function syncInfo(PDO $pdo) { try { $rows = $pdo->query("SELECT * FROM mago_sync_state")->fetchAll(PDO::FETCH_ASSOC); $out = []; foreach ($rows as $r) { $out[$r['entity']] = [ 'last_run_at' => $r['last_run_at'] ? date('d/m/Y H:i', strtotime($r['last_run_at'])) : '', 'last_status' => $r['last_status'], 'last_message' => $r['last_message'], 'records' => (int)$r['records_last_run'], ]; } $out['total_orders'] = (int)$pdo->query("SELECT COUNT(*) FROM mago_sale_ord")->fetchColumn(); return $out; } catch (Throwable $e) { return ['error' => 'Tabelle Mago non presenti: eseguire la migrazione Phinx', 'total_orders' => 0]; } } /** Opzioni dei filtri (clienti, agenti, aree, anni disponibili). */ public static function filterOptions(PDO $pdo) { try { $customers = $pdo->query(" SELECT o.customer AS code, COALESCE(NULLIF(c.company_name,''), o.customer) AS name, COUNT(*) AS n FROM mago_sale_ord o LEFT JOIN mago_cust_supp c ON c.cust_supp_type = " . self::CUSTOMER_TYPE . " AND c.cust_supp = o.customer WHERE o.customer <> '' GROUP BY o.customer, name ORDER BY name ")->fetchAll(PDO::FETCH_ASSOC); $salespeople = $pdo->query("SELECT salesperson AS code, COUNT(*) AS n FROM mago_sale_ord WHERE salesperson <> '' GROUP BY salesperson ORDER BY salesperson")->fetchAll(PDO::FETCH_ASSOC); $areas = $pdo->query("SELECT area AS code, COUNT(*) AS n FROM mago_sale_ord WHERE area <> '' GROUP BY area ORDER BY area")->fetchAll(PDO::FETCH_ASSOC); $range = $pdo->query("SELECT MIN(order_date) AS min_date, MAX(order_date) AS max_date FROM mago_sale_ord")->fetch(PDO::FETCH_ASSOC); $years = array_map('intval', $pdo->query("SELECT DISTINCT YEAR(order_date) FROM mago_sale_ord WHERE order_date IS NOT NULL ORDER BY 1")->fetchAll(PDO::FETCH_COLUMN)); return [ 'success' => true, 'customers' => $customers, 'salespeople' => $salespeople, 'areas' => $areas, 'range' => $range, 'years' => $years, 'sync' => self::syncInfo($pdo), ]; } catch (Throwable $e) { return ['success' => false, 'message' => $e->getMessage(), 'sync' => self::syncInfo($pdo)]; } } }