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 '

Accesso non consentito

Non hai i permessi per visualizzare questa pagina.

Torna alla Dashboard
'; exit; } /* ============================================================ * AJAX * ============================================================ */ $action = $_GET['action'] ?? ''; if ($action === 'filters') { MagoSalesStats::jsonOut(MagoSalesStats::filterOptions($pdo)); } if ($action === 'data') { try { $from = MagoSalesStats::baseFrom(); // Filtri cliente / agente / area (le date qui non si usano: si ragiona per anni) [$where, $params] = MagoSalesStats::buildWhere(['from' => '', 'to' => '']); // "A pari data": ogni anno considerato solo fino al giorno/mese di oggi $ytd = !empty($_GET['ytd']); $ytdCond = $ytd ? " AND DATE_FORMAT(x.order_date, '%m-%d') <= DATE_FORMAT(CURDATE(), '%m-%d')" : ''; // Metrica: numero ordini o valore (imponibile); gli annullati sono sempre esclusi $metric = (($_GET['metric'] ?? '') === 'value') ? 'value' : 'count'; $m = $metric === 'value' ? "CASE WHEN x.status <> 'annullato' THEN x.taxable_amount ELSE 0 END" : "CASE WHEN x.status <> 'annullato' THEN 1 ELSE 0 END"; // --- Riepilogo per TUTTI gli anni (serve anche l'anno prima del primo selezionato per la variazione) --- $summary = MagoSalesStats::fetchAllQ($pdo, " SELECT YEAR(x.order_date) AS y, SUM(x.status <> 'annullato') AS orders, COALESCE(SUM(CASE WHEN x.status <> 'annullato' THEN x.taxable_amount END), 0) AS value, COUNT(DISTINCT CASE WHEN x.status <> 'annullato' THEN x.customer END) AS customers, SUM(x.status = 'annullato') AS cancelled, SUM(x.summary_tb_modified IS NULL) AS missing_amounts FROM $from WHERE $where AND x.order_date IS NOT NULL $ytdCond GROUP BY y ORDER BY y ", $params); $available = array_map(function ($r) { return (int)$r['y']; }, $summary); // Anni scelti (validati); default: gli ultimi 3 disponibili $years = array_values(array_intersect(array_map('intval', MagoSalesStats::arrParam('years')), $available)); if (!$years) $years = array_slice($available, -3); sort($years); $monthly = []; $customers = []; if ($years) { $ph = []; $yp = $params; foreach ($years as $i => $y) { $ph[] = ':yy' . $i; $yp['yy' . $i] = $y; } $yearIn = 'YEAR(x.order_date) IN (' . implode(',', $ph) . ')'; // --- Mensile per anno --- $monthly = MagoSalesStats::fetchAllQ($pdo, " SELECT YEAR(x.order_date) AS y, MONTH(x.order_date) AS m, SUM($m) AS v FROM $from WHERE $where AND $yearIn $ytdCond GROUP BY y, m ORDER BY y, m ", $yp); // --- Clienti per anno --- $rows = MagoSalesStats::fetchAllQ($pdo, " SELECT x.customer AS code, x.company_name AS name, YEAR(x.order_date) AS y, SUM($m) AS v FROM $from WHERE $where AND $yearIn $ytdCond AND x.customer <> '' GROUP BY x.customer, x.company_name, y ", $yp); foreach ($rows as $r) { $k = $r['code']; if (!isset($customers[$k])) { $customers[$k] = ['code' => $r['code'], 'name' => $r['name'], 'v' => []]; } $customers[$k]['v'][(int)$r['y']] = (float)$r['v']; } $customers = array_values($customers); } MagoSalesStats::jsonOut([ 'success' => true, 'metric' => $metric, 'ytd' => $ytd, 'today' => date('Y-m-d'), 'available' => $available, 'years' => $years, 'summary' => $summary, 'monthly' => $monthly, 'customers' => $customers, ]); } catch (Throwable $e) { MagoSalesStats::jsonOut(['success' => false, 'message' => $e->getMessage()]); } } ?> Confronto anni - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?>
Statistiche Ordini Cliente
Dati Mago4
Andamento mensile
Stagionalità: un colore per anno
Progressivo dell'anno
Somma da gennaio: dice se si è avanti o indietro rispetto agli anni scorsi
Clienti a confronto
Clicca un cliente per filtrare tutta la pagina