diff --git a/public/userarea/class/MagoSalesStats.php b/public/userarea/class/MagoSalesStats.php index b1a047ea..3ac57efe 100644 --- a/public/userarea/class/MagoSalesStats.php +++ b/public/userarea/class/MagoSalesStats.php @@ -95,32 +95,16 @@ class MagoSalesStats $by[$c]['orders'][] = $r; } - $today = new DateTime('today'); $out = []; foreach ($by as $c) { - $dates = array_keys($c['dates']); - sort($dates); - $n = count($dates); - if ($n < self::DORMANT_MIN_ORDERS) continue; - - $gaps = []; - for ($k = 1; $k < $n; $k++) { - $gaps[] = (int)(new DateTime($dates[$k - 1]))->diff(new DateTime($dates[$k]))->days; - } - sort($gaps); - $m = count($gaps); - $median = $m % 2 ? $gaps[intdiv($m, 2)] : ($gaps[$m / 2 - 1] + $gaps[$m / 2]) / 2; - $rhythm = max(7, (float)$median); - - $last = end($dates); - $since = (int)(new DateTime($last))->diff($today)->days; - if ($since < self::DORMANT_MIN_DAYS) continue; - - $ratio = $since / $rhythm; - if ($ratio >= self::DORMANT_LOST || $since >= 365) $level = 'lost'; - elseif ($ratio >= self::DORMANT_SLEEP) $level = 'dormant'; - elseif ($ratio >= self::DORMANT_WATCH) $level = 'watch'; - else continue; + $info = self::rhythmInfo(array_keys($c['dates'])); + if (!$info || !in_array($info['level'], ['watch', 'dormant', 'lost'], true)) continue; + $last = $info['last_date']; + $since = $info['days_since']; + $rhythm = $info['rhythm']; + $ratio = $info['ratio']; + $level = $info['level']; + $n = $info['orders']; // ordinato nei 12 mesi fino all'ultimo ordine = quanto vale il cliente "a regime" $from12 = (new DateTime($last))->modify('-365 days')->format('Y-m-d'); @@ -142,8 +126,8 @@ class MagoSalesStats 'last_date' => $last, 'last_no' => $lastOrder['ord_no'], 'days_since' => $since, - 'rhythm' => (int)round($rhythm), - 'ratio' => round($ratio, 1), + 'rhythm' => $rhythm, + 'ratio' => $ratio, 'orders' => $n, 'value12' => round($v12, 2), 'level' => $level, @@ -155,6 +139,45 @@ class MagoSalesStats return $out; } + /** + * Ritmo d'ordine di un cliente a partire dalle date d'ordine (Y-m-d) degli ultimi DORMANT_WINDOW_YEARS anni. + * level: 'ok' | 'watch' | 'dormant' | 'lost' | 'few' (troppo pochi ordini per stimare un ritmo) + */ + public static function rhythmInfo(array $dates) + { + $dates = array_values(array_unique($dates)); + sort($dates); + $n = count($dates); + if (!$n) return null; + + $today = new DateTime('today'); + $last = end($dates); + $since = (int)(new DateTime($last))->diff($today)->days; + $out = ['orders' => $n, 'last_date' => $last, 'days_since' => $since, 'rhythm' => null, 'ratio' => null, 'level' => 'few']; + if ($n < self::DORMANT_MIN_ORDERS) return $out; + + $gaps = []; + for ($k = 1; $k < $n; $k++) { + $gaps[] = (int)(new DateTime($dates[$k - 1]))->diff(new DateTime($dates[$k]))->days; + } + sort($gaps); + $m = count($gaps); + $median = $m % 2 ? $gaps[intdiv($m, 2)] : ($gaps[$m / 2 - 1] + $gaps[$m / 2]) / 2; + $rhythm = max(7, (float)$median); + $ratio = $since / $rhythm; + + if ($since < self::DORMANT_MIN_DAYS) $level = 'ok'; + elseif ($ratio >= self::DORMANT_LOST || $since >= 365) $level = 'lost'; + elseif ($ratio >= self::DORMANT_SLEEP) $level = 'dormant'; + elseif ($ratio >= self::DORMANT_WATCH) $level = 'watch'; + else $level = 'ok'; + + $out['rhythm'] = (int)round($rhythm); + $out['ratio'] = round($ratio, 1); + $out['level'] = $level; + return $out; + } + /** * Previsione di fine anno: valore dell'anno in corso ad oggi diviso la quota che, negli anni * precedenti (max 3), si era raggiunta alla stessa data. $rows: [y, full, ytd]. diff --git a/public/userarea/include/navbar.php b/public/userarea/include/navbar.php index 0c8920a5..8a0e082a 100644 --- a/public/userarea/include/navbar.php +++ b/public/userarea/include/navbar.php @@ -235,6 +235,11 @@ Confronto anni +