Punkte/Umsatz korrekt aus per-Zeile points/total_net je status berechnen statt SUM der kumulativen month_*-Snapshots (zaehlte massiv mehrfach). Zentralisiert in SalesVolumePoints, genutzt von Dashboard- & Drilldown-Service. Detail-Tabelle neu gegliedert: Eigenpunkte | Shop | Abo | Sonstige | Kundenpunkte (=Summe) | Gesamt, mit gruener Hervorhebung der Basis-/Summenspalten. Neue VIP-Seite "Meine Statistik" (Untermenue neben Team-Statistik): KPI-Karten + nachvollziehbare Detailtabellen, gruppiert nach eigenen Bestellungen, Shop-Bestellungen und Abos (PersonalStatisticsService). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
2.7 KiB
PHP
71 lines
2.7 KiB
PHP
<?php
|
||
|
||
namespace App\Services\Backoffice;
|
||
|
||
/**
|
||
* Liefert SQL-Aggregat-Ausdrücke für die monatliche Punkte-/Umsatzauswertung
|
||
* der Backoffice-Statistik.
|
||
*
|
||
* Wichtig: In `user_sales_volumes` existiert pro Bestellung eine Zeile, und die
|
||
* Spalten `month_KP_points` / `month_shop_points` / `month_*_total_net` sind der
|
||
* kumulative Monats-Laufstand zum Zeitpunkt der Bestellung – KEINE Einzelbeträge.
|
||
* Eine SUM() über diese Spalten zählt mehrfach. Korrekt wird je Zeile die
|
||
* `points`/`total_net`-Spalte summiert und nach `status` gefiltert – analog zu
|
||
* {@see \App\Services\BusinessPlan\SalesPointsVolume::reCalculateSalesPointsVolume()}.
|
||
*
|
||
* Status-Zuordnung:
|
||
* - Eigenpunkte (KP): status 1, 4, 5, 6
|
||
* - Shop-/Kundenpunkte: status 2 (sowie status 6 mit status_turnover = 2)
|
||
* - status 0 (nicht zugeordnet) und 3 (pending) zählen nicht
|
||
*
|
||
* Alle Spalten werden voll qualifiziert, da `shopping_orders` ebenfalls eine
|
||
* `points`-Spalte besitzt (Join-Mehrdeutigkeit).
|
||
*/
|
||
class SalesVolumePoints
|
||
{
|
||
private const OWN_PREDICATE = 'user_sales_volumes.status IN (1, 4, 5, 6)';
|
||
|
||
private const SHOP_PREDICATE = '(user_sales_volumes.status = 2 OR (user_sales_volumes.status = 6 AND user_sales_volumes.status_turnover = 2))';
|
||
|
||
private const TURNOVER_PREDICATE = 'user_sales_volumes.status IN (1, 2, 4, 5, 6)';
|
||
|
||
public static function ownPoints(): string
|
||
{
|
||
return self::sumWhere(self::OWN_PREDICATE, 'user_sales_volumes.points');
|
||
}
|
||
|
||
public static function externalPoints(): string
|
||
{
|
||
return self::sumWhere(self::SHOP_PREDICATE, 'user_sales_volumes.points');
|
||
}
|
||
|
||
public static function customerAboPoints(): string
|
||
{
|
||
return self::sumWhere(self::SHOP_PREDICATE.' AND shopping_orders.is_abo = 1', 'user_sales_volumes.points');
|
||
}
|
||
|
||
public static function customerSingleOrderPoints(): string
|
||
{
|
||
return self::sumWhere(self::SHOP_PREDICATE.' AND shopping_orders.id IS NOT NULL AND (shopping_orders.is_abo = 0 OR shopping_orders.is_abo IS NULL)', 'user_sales_volumes.points');
|
||
}
|
||
|
||
public static function customerOtherPoints(): string
|
||
{
|
||
return self::sumWhere(self::SHOP_PREDICATE.' AND shopping_orders.id IS NULL', 'user_sales_volumes.points');
|
||
}
|
||
|
||
public static function totalPoints(): string
|
||
{
|
||
return self::ownPoints().' + '.self::externalPoints();
|
||
}
|
||
|
||
public static function turnoverNet(): string
|
||
{
|
||
return self::sumWhere(self::TURNOVER_PREDICATE, 'user_sales_volumes.total_net');
|
||
}
|
||
|
||
private static function sumWhere(string $predicate, string $column): string
|
||
{
|
||
return 'COALESCE(SUM(CASE WHEN '.$predicate.' THEN '.$column.' ELSE 0 END), 0)';
|
||
}
|
||
}
|