mivita/dev/2026-07-22/neupartner-zahlungsmonat.md
Kevin d5ad1ba50b Statistik: Neupartner zaehlen im Monat der Zahlung, nicht der Registrierung
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 ec3ecad noch nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 14:48:01 +00:00

86 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Neupartner zählen im Monat der Zahlung
**Entscheidung der Kundin, 16.09.2026.** Ein neuer Vertriebspartner gehört in den Monat, in dem
er **bezahlt** hat — nicht in den Monat seiner Registrierung. Das gilt für jede Stelle, die
Neupartner zählt: Kachel, Recruiter-Ranking, Top 3 „Recruiter des Monats", Neupartner-Liste,
CSV-Export.
## Der Fall, der es ausgelöst hat
Partner 1623 (Sponsor 454): registriert am 28.08., erster Zahlungslink abgelaufen, zweiter am
**01.09. um 06:49** bezahlt. Der Snapshot für August wurde am 01.09. um 04:45 eingefroren — da
hatte er noch kein Abrechnungskonto und fiel im August raus. Im September lag sein
Aktivierungsdatum im falschen Monat. **Er tauchte nirgends auf**, auch nicht beim Recruiting
seines Sponsors.
Das ist kein Einzelfall: 2026 betrifft es **8 Partner**, jeweils Ende des Monats registriert und
Anfang des Folgemonats bezahlt — 2 im Januar, 1 im April, 1 im Juni, 3 im Juli, 1 im September.
## Was sich geändert hat
Die Neupartner-Regel hing an `users.active_date` (Abschluss der Registrierung). Neu ist die Spalte
**`users.partner_paid_at`**: der Zeitpunkt der ersten Kontozahlung.
| | vorher | jetzt |
| --- | --- | --- |
| Neupartner im Monat X | `active_date` in X | `partner_paid_at` in X |
| Abrechnungskonto gültig am Stichtag | ja | ja, unverändert |
| Mitgliedsebene gesetzt | ja | ja, unverändert |
Die Regel steht an **einer** Stelle — `User::scopeNewPartnerIn()` und das PHP-Gegenstück
`User::isNewPartnerIn()` — und alle Zählungen gehen darüber.
**Gesetzt wird `partner_paid_at`** bei der ersten Kontozahlung (`Payment::paymentStatusPaidAction`,
Produktaktion `payment_for_account`) und bei manueller Kontofreischaltung durch den Admin. Beides
über `UserUtil::markPartnerPaid()`, das den Wert **nur setzt, solange er leer ist**. Eine
Verlängerung oder eine Wiederherstellung ändert ihn nicht — sonst würde ein alter Partner in der
Neupartner-Statistik wieder auftauchen.
**Rückgefüllt** wurde per Migration aus der ersten bezahlten Registrierungsbestellung
(`shopping_orders.payment_for = 1`): die Punktebuchung dazu entsteht im Moment der Zahlung, deren
Zeitstempel ist der Wert. Ohne Buchung das Änderungsdatum der Bestellung; ohne Bestellung (Konto
vom Admin freigeschaltet, 14 Fälle) das Aktivierungsdatum. **Nicht** verwendet wurde
`payment_account` minus ein Jahr: bei Verlängerungen wird vom alten Ablaufdatum aus verlängert, das
Ergebnis wäre der Jahrestag der Erstzahlung und jeder Verlängerer ein „Neupartner".
## Was sich nicht geändert hat
**Die Teamstruktur.** Ob jemand zum Monatsende zur Linie gehört, hängt weiterhin an `active_date` —
so auch im Provisionsbaum. Das ist eine andere Frage als „wer ist neu dazugekommen": Partner 1623
steht im September in der Struktur seines Sponsors, und er ist der September-Neupartner. Ein Partner,
der am 28.09. registriert und am 02.10. bezahlt, steht im September schon in der Struktur, zählt aber
erst im Oktober als neu.
**Provisionen, Gutschriften, Marketingplan.** Unberührt. Die Migration fügt eine leere Spalte hinzu
und füllt sie; keine vorhandene Zeile wird sonst geändert.
## Wiederhergestellte Partner
Vier Partner haben ein `active_date` Jahre **nach** ihrer Registrierungszahlung (414, 522, 610,
663) — sie wurden offenbar wiederhergestellt, und `restoreUser()` setzt `active_date` neu. Unter der
alten Regel zählten sie als Neupartner im Monat der Wiederherstellung. Unter der neuen Regel zählen
sie im Monat ihrer ursprünglichen Zahlung (2021–2023), also **nicht** als Neupartner 2026. Das ist
fachlich richtig, wenn eine Wiederherstellung keine Neuwerbung ist. Falls die Kundin das anders
sieht, müsste `restoreUser()` den Wert zurücksetzen — bewusst nicht gemacht.
## Die eingefrorenen Monate
Die Snapshots Januar bis August wurden mit der **alten** Regel gebaut. Sieben der acht
Partner von oben fehlen darin vollständig — in beiden Monaten. Der Snapshot friert bewusst ein
(siehe [monatsabschluss-eingefrorene-statistik.md](monatsabschluss-eingefrorene-statistik.md)), ein
Neuaufbau ist deshalb eine Entscheidung, keine Routine:
```bash
php artisan backoffice:store-statistics-snapshots --force
```
Damit landen die sieben in ihren Zahlungsmonaten. Wie am 10.09. gilt: der Neuaufbau friert die
Teamstruktur des **Ausführungstags** ein, nicht die des damaligen Monatsendes. Wer seit dem 10.09.
verschoben wurde oder dazukam, steht danach an seiner heutigen Stelle in den historischen Zahlen.
## Sichtprüfung nach dem Deploy
- Backoffice → September → Neupartner-Liste: Partner 1623 steht drin, Spalte „Bezahlt am" =
01.09.2026, „Registriert am" = 28.08.2026.
- Recruiter-Ranking September: Sponsor 454 hat ihn angerechnet.
- Backoffice → August (eingefroren): unverändert, solange kein Neuaufbau läuft.