Wer Ende August registriert und am 1. September bezahlt hat, tauchte in keiner
Neupartner-Zaehlung auf: Der August-Snapshot wurde um 04:45 eingefroren, da
fehlte noch das Abrechnungskonto; im September lag active_date im falschen
Monat. Betroffen sind 2026 acht Partner, auch im Recruiting ihrer Sponsoren.
Kundenentscheidung 16.09.2026: der Zeitpunkt der Zahlung ist massgeblich.
Neue Spalte users.partner_paid_at, gesetzt bei der ersten Kontozahlung
(Payment::paymentStatusPaidAction) und bei manueller Freischaltung durch den
Admin — nur, solange sie leer ist; Verlaengerung und Wiederherstellung aendern
sie nicht. Bestehende Partner werden per Migration aus der ersten bezahlten
Registrierungsbestellung rueckgefuellt (Zeitstempel der Punktebuchung, ersatzweise
Bestelldatum, ohne Bestellung das Aktivierungsdatum). Bewusst nicht
payment_account minus ein Jahr: das ergaebe bei Verlaengerern den Jahrestag der
Erstzahlung.
User::scopeNewPartnerIn() und isNewPartnerIn() lesen jetzt partner_paid_at —
damit Kachel, Recruiter-Ranking, Top 3 und Neupartner-Liste gleichermassen.
Die Liste und der CSV-Export zeigen "Bezahlt am" neben "Registriert am".
Unveraendert: die Teamstruktur haengt weiter an active_date (auch im
Provisionsbaum). Wer ist neu dazugekommen und wer gehoert zur Linie sind zwei
verschiedene Fragen.
Die eingefrorenen Monate Januar bis August enthalten sieben dieser Partner
nicht; ob sie per --force neu gebaut werden, ist eine Entscheidung — siehe
dev/2026-07-22/neupartner-zahlungsmonat.md.
Mit drin: die handgebaute SQLite-Tabelle in BackofficeDashboardServiceTest
kannte status_reason aus d6efe56 noch nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8.1 KiB
Deploy 10.09.2026 — Statistik-Paket live
Das Paket aus dem Statistik-Audit ist auf Produktion. Upload per SFTP, anschließend Migration, Snapshot-Neuaufbau und Cache-Leerung im Terminal. Ohne Fehler durchgelaufen.
Was live gegangen ist
| Commit | Inhalt |
|---|---|
42ec51c |
Stornos mindern die richtige Punktekategorie (A02, A06, A15, R01–R03) — enthält beide Migrationen |
8d7a98c |
Abgeschlossene Monate werden vollständig eingefroren (A03, A04, A06, A12) |
94e2b13 |
Übrige Audit-Korrekturen (A01, A08–A11, A13, A14, A16–A19) |
9a3940f |
Dokumentation |
php artisan migrate
php artisan backoffice:store-statistics-snapshots --force
php artisan config:clear && php artisan view:clear && php artisan cache:clear
Die Reihenfolge ist nicht beliebig: ohne die Migration bricht der Neuaufbau mit
Unknown column storno_origin_status ab.
Was sich in den Daten geändert hat
Migrationen. user_sales_volumes bekommt die Spalte storno_origin_status (leer, nullable), und
status_turnover wird nullable — letzteres zieht nur das Schema auf den Stand nach, der auf
Produktion ohnehin galt. Keine vorhandene Zeile wurde verändert.
Snapshot-Neuaufbau. Geschrieben wurde ausschließlich backoffice_statistics_snapshots, für
8 abgeschlossene Monate (Januar bis August 2026) und die VIP-Konten (admin >= 1 AND admin < 4,
derzeit 7). Der Dienst dahinter hat keine Service-Abhängigkeiten und liest nur aus
user_sales_volumes, user_abos, user_levels, shopping_order_items und users.
Nicht angefasst: Provisionen (user_businesses), Gutschriften, Rechnungen, Marketingplan. Die
für April bis August ausgestellten Gutschriften bleiben unverändert — genau das ist die
Einfrier-Regel.
Was das für die Zahlen bedeutet
Die historischen Monatswerte in der Backoffice-Statistik können sich gegenüber vorher verschoben haben, aus zwei Gründen:
- Shop-Stornos zählen jetzt zu den Kundenpunkten statt zu den Eigenpunkten (A15).
- Der neue Snapshot friert die Struktur des Ausführungstags ein, nicht die des damaligen Monatsendes — früheres Sponsoring wird nirgends historisiert. Wer seit damals verschoben wurde oder dazugekommen ist, steckt jetzt in den historischen Zahlen an seiner heutigen Stelle.
Punkt 2 war die bewusste Entscheidung, einen einheitlichen Stand herzustellen. Ab jetzt friert jeder Monatswechsel den Stand fest, und die Werte bleiben stehen.
Ein Vorher/Nachher-Vergleich der alten gegen die neuen Monatswerte wurde nicht erstellt; der Neuaufbau lief direkt. Die alten Snapshot-Stände sind damit überschrieben. Falls später Rückfragen zu einzelnen Monatszahlen kommen, lässt sich der frühere Stand nur noch aus einem Datenbank-Backup holen.
Woran man merken würde, dass etwas nicht stimmt
- Backoffice-Statistik, abgeschlossener Monat: Das Abzeichen muss „Monat abgeschlossen · Stand eingefroren" zeigen, und die Zahl in der Kachel muss mit der verlinkten Detailliste übereinstimmen.
- Laufender Monat: weiterhin live, keine Einfrier-Kennzeichnung.
- Provisionskachel auf dem Dashboard: Bei einer fehlgeschlagenen Berechnung steht jetzt ein Hinweis statt „0,00 €" (A19).
- Abo-Einstellungen (Selbstbedienung): Zustandswechsel nur noch über Pause und Kündigung. Der Admin-Pfad ist unverändert.
Offen
Unverändert offen: A07 (gehört planerisch zu K11), A22/A23 und die drei Kundenfragen A05, A20, A21 — siehe Stand-Block in der Bewertung.
Nicht mit deployt und weiterhin nicht committet: die Arbeit aus anderen Themen im selben
Arbeitsbaum (DHL, Stripe/Payone, DATEV, shipped_at).
Ebenfalls unverändert: die vorbestehenden Testfehler auf dem Branch (rund 42 SQLite-Schemafehler in
Unit-Tests, 25 fehlende Übersetzungsschlüssel in payment.php für es und fr, verwendet in einer
Admin-Ansicht). Gehören in ein eigenes Aufräumpaket.
Nachtrag 11.09.2026 — Kundenabo-Vorschau zeigte nur den Rest des Monats
Beim Nachsehen auf Produktion aufgefallen (Berater 454): Auf /user/abos/ot stand die Kachelreihe
„Punkte aus meinen Kundenabos zum 5. / 10. / 20. / 25." für die bereits vergangenen Termine auf
null, obwohl im Monat längst Lieferungen gebucht waren.
Ursache. Die Vorschau startete bei einer Basis von 0 und addierte nur die noch offenen Ausführungen. Die im Monat bereits abgerechneten Kundenabo-Punkte fehlten vollständig. Die Kachel beantwortete damit „was kommt noch" statt der Frage aus der Anforderung vom 07.09. („wieviel Volumenpunkte habe ich am 5. / 10. / 20. / 25.").
Berater 454, September 2026:
| vorher | jetzt | |
|---|---|---|
| 05.09. | 0 | 457 |
| 10.09. | 0 | 457 |
| 20.09. | 131 | 588 |
| 25.09. | 319 | 776 |
Die 457 Punkte waren bereits abgerechnet (Lieferungen am 1., 5. und 10.), die 319 stehen noch aus. Der Monatsstand aus Kundenabos beträgt 776.
Umfang. Im September betrifft das 86 Berater mit zusammen 15.936 Punkten, die in dieser Kachel nicht sichtbar waren. Nur eine Anzeige — es wurde nichts falsch gebucht oder abgerechnet.
Nicht aus dem Audit-Paket. Die Null-Basis stammt aus der Umsetzung des Kundenwunschs vom 07.09.
(K9), nicht aus der A13-Korrektur; dort wurde in dieser Methode nur der Datumsfilter ersetzt. In die
Git-Historie ist sie erst mit 94e2b13 gekommen, weil der ganze Arbeitsstand vorher nicht committet
war.
Behebung, Teil 1 — die Vorschau rechnet taggenau. Basis jeder Kachel sind die bis zu diesem
Termin aus den eigenen Kundenabos abgerechneten Punkte, dazu die bis dahin noch offenen Lieferungen.
Abgrenzung wie in der Backoffice-Statistik (SalesVolumePoints::shopPredicate()), Stornos
vorzeichengetreu; das eigene Abo des Beraters bleibt draußen. Buchungen nach dem 25. (Nachzügler,
manuelle Gutschriften) hängen sich an die letzte Kachel, damit die immer den Monatsstand zeigt.
Für Beraterin 454 ergibt das 132 / 457 / 588 / 776 statt vorher 0 / 0 / 131 / 319. Jede Kachel zeigt jetzt zusätzlich ihre Aufschlüsselung („457 abgerechnet + 131 offen"), damit man sie gegen die Liste darunter nachrechnen kann.
Behebung, Teil 2 — die Liste zeigt, was tatsächlich gebucht wurde. Die Spalte „Punkte" enthielt nur den wiederkehrenden Abo-Inhalt. Was bei einer Lieferung zusätzlich dabei war — Einmal-Artikel und sonstige Zubuchungen — wird nach der Ausführung aus dem Abo entfernt und tauchte deshalb nirgends mehr auf. Bei Abo 266 waren das 43 Punkte (CBD Öl 27 + MSM PURE 16), bei Abo 418 rund 39.
Neu daneben: „Diesen Monat" mit den je Abo tatsächlich gebuchten Punkten, bei Abweichung mit einem Zusatz „+43 einmalig". Dazu eine Summenzeile unter der Tabelle. Kann eine Monatsbuchung keiner gelisteten Abo-Zeile zugeordnet werden — gelöschtes Abo, Buchung ohne Ausführungsbezug —, weist die Summenzeile den Rest gesondert aus, damit die Addition aufgeht.
Damit stimmt die Rechnung durchgängig:
Summe Spalte "Diesen Monat" = 457 → Basis der letzten Kachel
Summe "Abo-Punkte" der Abos mit Termin 20./25. = 319 → offener Teil der letzten Kachel
---
letzte Kachel 776
Die Monatsspalte erscheint nur, solange kein anderer Monat gefiltert ist; für einen vergangenen Monat wäre sie irreführend.
Deployment: nur Dateien, keine Migration, kein Skript. Danach php artisan view:clear.
Nachtrag 16.09.2026 — Neupartner zählen im Monat der Zahlung
Regeländerung nach Kundenentscheidung, Einzelheiten in neupartner-zahlungsmonat.md. Auslöser: Partner 1623, Ende August registriert, am 1. September bezahlt, in keinem Monat gezählt.
Deployment:
php artisan migrate # neue Spalte users.partner_paid_at + Rueckfuellung (ca. 10 s)
php artisan view:clear
Optional und bewusst zu entscheiden — die eingefrorenen Monate Januar bis August enthalten sieben Partner nicht, die unter der neuen Regel dorthin gehören:
php artisan backoffice:store-statistics-snapshots --force