Statistiche Ordini Cliente
Dati Mago4Scegli un cliente
Trovi tutto su di lui in una pagina: ordinato e fatturato, ordini aperti, articoli, fatture.
getConnection(); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // --- Permessi: pagina visibile solo con 'sales.stats.view' --- if (!userCan('sales.stats.view')) { if (isset($_GET['action']) || isset($_POST['action'])) { MagoSalesStats::jsonOut(['success' => false, 'ok' => false, 'message' => 'Non hai i permessi per questa pagina']); } while (ob_get_level()) ob_end_clean(); http_response_code(403); echo '
'; exit; } $canDeliveries = userCan('sales.deliveries.view'); /* ============================================================ * AJAX * ============================================================ */ $action = $_GET['action'] ?? ''; if ($action === 'filters') { MagoSalesStats::jsonOut(MagoSalesStats::filterOptions($pdo)); } if ($action === 'data') { try { $c = trim((string)($_GET['c'] ?? '')); if ($c === '') MagoSalesStats::jsonOut(['success' => false, 'message' => 'Cliente non indicato']); $p = ['c' => $c]; $curY = (int)date('Y'); $from = MagoSalesStats::baseFrom(); $val = "CASE WHEN x.status <> 'annullato' THEN x.taxable_amount ELSE 0 END"; // --- anagrafica --- $st = $pdo->prepare("SELECT cust_supp AS code, company_name AS name, city, county, region, country FROM mago_cust_supp WHERE cust_supp_type = " . MagoSalesStats::CUSTOMER_TYPE . " AND cust_supp = ?"); $st->execute([$c]); $info = $st->fetch(PDO::FETCH_ASSOC) ?: ['code' => $c, 'name' => $c, 'city' => '', 'county' => '', 'region' => '', 'country' => '']; // --- ordini del cliente (dal 2020, "listino" esclusi) --- $orders = MagoSalesStats::fetchAllQ($pdo, " SELECT x.sale_ord_id, x.internal_ord_no, x.external_ord_no, x.your_reference, x.order_date, x.salesperson, x.area, x.status, x.invoiced, x.taxable_amount, x.is_late, x.open_lines, x.late_lines, x.zibo_date, x.client_date, (x.summary_tb_modified IS NULL) AS no_amount FROM $from WHERE x.customer = :c ORDER BY x.order_date DESC, x.sale_ord_id DESC ", $p); if (!$orders) { $hasInv = false; try { $q = $pdo->prepare("SELECT 1 FROM mago_sale_doc WHERE customer = ? LIMIT 1"); $q->execute([$c]); $hasInv = (bool)$q->fetchColumn(); } catch (Throwable $e) { } if (!$hasInv) MagoSalesStats::jsonOut(['success' => false, 'message' => 'Nessun dato per questo cliente']); } $last = $orders[0] ?? null; $firstDate = $orders ? end($orders)['order_date'] : null; // ritmo d'ordine (ultimi N anni, annullati esclusi) $limit = date('Y-m-d', strtotime('-' . MagoSalesStats::DORMANT_WINDOW_YEARS . ' years')); $dates = []; foreach ($orders as $o) { if ($o['status'] !== 'annullato' && $o['order_date'] >= $limit) $dates[] = $o['order_date']; } $rhythm = MagoSalesStats::rhythmInfo($dates); // --- ordinato per anno (totale e a pari data) --- $ordYears = MagoSalesStats::fetchAllQ($pdo, " SELECT YEAR(x.order_date) AS y, SUM($val) AS full, SUM(x.status <> 'annullato') AS n, SUM(CASE WHEN DATE_FORMAT(x.order_date, '%m-%d') <= DATE_FORMAT(CURDATE(), '%m-%d') THEN $val ELSE 0 END) AS ytd FROM $from WHERE x.customer = :c GROUP BY y ORDER BY y ", $p); $since24 = date('Y-m-01', strtotime('first day of -23 months')); $ordMonths = MagoSalesStats::fetchAllQ($pdo, " SELECT DATE_FORMAT(x.order_date, '%Y-%m') AS ym, SUM($val) AS v FROM $from WHERE x.customer = :c AND x.order_date >= '$since24' GROUP BY ym ORDER BY ym ", $p); // --- fatturato (se le fatture sono sincronizzate) --- $inv = ['available' => false, 'years' => [], 'months' => [], 'docs' => [], 'v12' => 0, 'cn12' => 0, 'cn12_n' => 0]; try { $iFrom = MagoSalesStats::invoiceFrom(); $inv['available'] = (bool)$pdo->query("SELECT 1 FROM mago_sale_doc LIMIT 1")->fetchColumn(); if ($inv['available']) { $inv['years'] = MagoSalesStats::fetchAllQ($pdo, " SELECT YEAR(i.document_date) AS y, SUM(i.revenue) AS full, SUM(CASE WHEN DATE_FORMAT(i.document_date, '%m-%d') <= DATE_FORMAT(CURDATE(), '%m-%d') THEN i.revenue ELSE 0 END) AS ytd FROM $iFrom WHERE i.customer = :c GROUP BY y ORDER BY y ", $p); $inv['months'] = MagoSalesStats::fetchAllQ($pdo, " SELECT DATE_FORMAT(i.document_date, '%Y-%m') AS ym, SUM(i.revenue) AS v FROM $iFrom WHERE i.customer = :c AND i.document_date >= '$since24' GROUP BY ym ORDER BY ym ", $p); $inv['docs'] = MagoSalesStats::fetchAllQ($pdo, " SELECT i.document_date, i.doc_no, i.document_type, i.is_credit_note, i.revenue, i.no_amount FROM $iFrom WHERE i.customer = :c AND i.document_date >= CURDATE() - INTERVAL 3 YEAR ORDER BY i.document_date DESC, i.doc_no DESC ", $p); $r12 = MagoSalesStats::fetchAllQ($pdo, " SELECT COALESCE(SUM(CASE WHEN i.is_credit_note = 0 THEN i.revenue END), 0) AS v, COALESCE(SUM(CASE WHEN i.is_credit_note = 1 THEN -i.revenue END), 0) AS cn, SUM(i.is_credit_note = 1) AS cn_n FROM $iFrom WHERE i.customer = :c AND i.document_date > CURDATE() - INTERVAL 365 DAY ", $p)[0]; $inv['v12'] = (float)$r12['v']; $inv['cn12'] = (float)$r12['cn']; $inv['cn12_n'] = (int)$r12['cn_n']; } } catch (Throwable $e) { $inv['available'] = false; } // --- righe da consegnare --- $open = MagoSalesStats::fetchAllQ($pdo, " SELECT r.sale_ord_id, r.internal_ord_no, r.order_date, r.item, r.description, r.uom, r.qty, r.delivered_qty, r.residual_qty, r.residual_value, r.zibo_date, r.client_date, r.due_date, r.status, r.your_reference, CASE WHEN r.due_date < CURDATE() THEN DATEDIFF(CURDATE(), r.due_date) ELSE 0 END AS late_days FROM " . MagoSalesStats::openLinesFrom() . " WHERE r.customer = :c ORDER BY r.due_date IS NULL, r.due_date, r.internal_ord_no ", $p); // --- articoli (righe ordine non annullate) --- $items = MagoSalesStats::fetchAllQ($pdo, " SELECT d.item, MAX(d.description) AS description, MAX(d.uom) AS uom, COUNT(DISTINCT d.sale_ord_id) AS n_orders, SUM(d.qty) AS qty, SUM(d.taxable_amount) AS value, MAX(x.order_date) AS last_date, SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 365 DAY THEN d.taxable_amount END) AS v12, SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 365 DAY THEN d.qty END) AS q12, SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 365 DAY AND x.order_date > CURDATE() - INTERVAL 730 DAY THEN d.taxable_amount END) AS vp, SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 365 DAY AND x.order_date > CURDATE() - INTERVAL 730 DAY THEN d.qty END) AS qp FROM mago_sale_ord_detail d JOIN $from ON x.sale_ord_id = d.sale_ord_id WHERE x.customer = :c AND x.status <> 'annullato' AND d.cancelled = 0 AND d.item <> '' GROUP BY d.item ORDER BY value DESC LIMIT 500 ", $p); foreach ($items as &$it) { $it['price12'] = (float)$it['q12'] > 0 ? round((float)$it['v12'] / (float)$it['q12'], 4) : null; $it['pricep'] = (float)$it['qp'] > 0 ? round((float)$it['vp'] / (float)$it['qp'], 4) : null; } unset($it); MagoSalesStats::jsonOut([ 'success' => true, 'today' => date('Y-m-d'), 'info' => $info, 'last' => $last ? ['salesperson' => $last['salesperson'], 'area' => $last['area'], 'date' => $last['order_date'], 'no' => $last['internal_ord_no']] : null, 'first' => $firstDate, 'rhythm' => $rhythm, 'rhythm_cfg' => ['years' => MagoSalesStats::DORMANT_WINDOW_YEARS, 'min_orders' => MagoSalesStats::DORMANT_MIN_ORDERS], 'ordYears' => $ordYears, 'ordMonths' => $ordMonths, 'since' => $since24, 'inv' => $inv, 'types' => MagoSalesStats::INVOICE_TYPE_LABELS, 'orders' => array_slice($orders, 0, 300), 'open' => $open, 'items' => $items, ]); } catch (Throwable $e) { MagoSalesStats::jsonOut(['success' => false, 'message' => $e->getMessage()]); } } ?>