Commit graph

89 commits

Author SHA1 Message Date
90c2188ffa Kunden loeschen: Modal mit Komplett- oder DSGVO-Loeschung ueber alle Dubletten
Ticket dev/_tickets/2026-09-08.md #2:
- "Kunde loeschen" oeffnet ein Modal statt direkt per GET zu loeschen. Es
  zeigt alle Eintraege desselben Kunden (Kundennummer oder E-Mail, ohne
  Platzhalter-Adressen) mit Anzahl Bestellungen.
- Ohne Bestellungen: Komplett-Loeschung (anonymisiert und soft-geloescht,
  Portal-Logins und Stripe-Kunden entfernt, Zahlungs-Tokens inaktiver Abos
  geleert). Mit Bestellungen nur DSGVO-Loeschung (Superadmin); die arbeitet
  jetzt ebenfalls auf der E-Mail-Gruppe und entfernt Portal-Logins.
- Bei aktivem Abo oder Berater-Datensatz wird abgelehnt.
- Die alte "Loeschung" (CustomerRepository::deleteCustomer) entfaellt.
- Fehlermeldungen nutzen alert-error; alert-danger zeigte kein Layout an.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:43:35 +00:00
30589795c7 DATEV: stornierte Rechnungen im Rechnungsmonat, Pruefliste fuer den Steuerberater
- Eine spaeter stornierte Rechnung fehlte im Export ihres Rechnungsmonats,
  weil cancellation = true auch an der Originalrechnung steht. Sie bleibt
  jetzt als Erloes im Rechnungsmonat; die Stornierung wird im Monat des
  Stornobelegs gegengebucht (nur Belege ohne cancellation_id).
- Pruefliste je Buchungsstapel als CSV (Button im Steuerberater-Bereich):
  Belege, die sich ohne Zusatzinformation nicht abstimmen lassen (doppelte
  Rechnungsnummern, Stornos ausserhalb des Systems).
- Korrespondenz und offene Differenzen mit dem Steuerberater unter
  dev/2026-07-17-steuern/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:42:54 +00:00
85d0cc1f48 Absatzmengen: nach Warenausgang (Versanddatum) oder nach Rechnung auswertbar
- shopping_orders.shipped_at (+ Herkunft live/dhl/geschaetzt): gesetzt im
  Model, sobald der Versandstatus auf versendet wechselt, egal an welcher
  Stelle der Status gesetzt wird. sales:backfill-shipped-at traegt
  Altbestellungen aus dem DHL-Label nach oder schaetzt.
- SalesVolumeService rechnet Absatzmengen je Produkt wahlweise nach
  Versand (inkl. externer/API-Bestellungen, Stornos im Monat des
  Stornobelegs) oder nach Rechnung. Sets werden fuer die zweite Liste in
  Einzelartikel aufgeloest.
- Admin-Seite: Umschalter Versand/Rechnung, Datenqualitaet (Anteil
  geschaetzter Versanddaten), Export Produkte und Einzelartikel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:42:39 +00:00
19b9731afa Portal-Abo: Abo-Anlage und Ausfuehrungsliste rendern ohne Fehler
Log-Analyse 26.08. (P0-1, P1-2): getContentByOrder() liefert ein Array,
contains() darauf warf bei jeder Abo-Anlage im Portal einen 500. Die
Ausfuehrungsliste nutzt CRM-Routen, die im Portal fehlen; dort gibt es jetzt
user_order_detail als Alias auf die Portal-Bestellansicht, und die View
prueft die Route vor dem Verlinken.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:40:46 +00:00
9879e6798e Incentive (E1): "Nur fuer VIP sichtbar" und Ranglisten-Seite mit Teilnahme-Block oben
Haken vip_only am Incentive: aktives Incentive erscheint dann nur fuer
VIP-Konten in Sidenav, Dashboard, Teaser, Rangliste und Details, andere
Berater bekommen 404; das Tracking laeuft fuer alle weiter. Seeder setzt den
Haken fuer die Abstimmung der Recruiting Challenge.

Ranglisten-Seite: solange die Teilnahme nicht bestaetigt ist, steht der
Teilnahme-Block mit Praemien-Chips, Checkbox, Button und aufklappbaren
Bedingungen ganz oben, darunter Trennlinie, Titel, Untertitel, Bild,
Beschreibung und die Info-Kacheln. Ueberschriften vergroessert, Abo-Bloecke
nur wenn Abos zaehlen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 11:11:33 +00:00
b28f51bf62 Incentive (E1): Recruiting-Challenge mit Geldpraemie, Auszahlungs-Export und parallelen Incentives
Neue Felder amount_per_partner, bonus_rank_1..3 und include_sales_points an
incentives. Mit ausgeschalteten Umsatzpunkten zaehlt die Wertung nur die
Einmalpunkte je Neupartner, die Rangliste entspricht damit der Anzahl
Neupartner mit Starterpaket. IncentivePayoutService rechnet Neupartner mal
Betrag plus Rang-Bonus fuer qualifizierte Gewinner; Admin-Detailseite bekommt
Praemienspalte, Summen und XLSX-Export fuer die Auszahlung.

Sidenav und Dashboard zeigen alle aktiven Incentives, damit Montenegro und
die Challenge parallel laufen koennen. Teaser, Rangliste und Details zeigen
bei Geldpraemie die Praemien-Kachel und "Deine Praemie bisher" und blenden
Abo-Bloecke aus, wenn Abos keine Rolle spielen. Montenegro bleibt unveraendert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 12:10:27 +00:00
66c6ae05fb Abo (A1+A2): Liefertag frei waehlbar 1-31, Aenderung nur nach vorn, Sperre erst am Ausfuehrungstag
A1: Jeder Monatstag ist als Liefertag erlaubt (UserAbo::allowedDeliveryDays),
Tage 29-31 liefern in kuerzeren Monaten am letzten Tag. Eine Stelle
AboHelper::dateForDayInMonth klammert; setNextDate, Erstausfuehrung,
Admin-Termin und Pause rechnen darueber, der Folgemonat immer aus dem
Liefertag (31.01 -> 28.02 -> 31.03). Liefertag-Aenderung gilt fuer den
laufenden Zyklus und nur nach vorn: ist der Tag im Referenzmonat vorbei,
wird abgelehnt, der Monat verschiebt sich nie (Rueckfrage R1).
Admin-Filter "naechste Ausfuehrung" als Datumsbereich. Prognose-Kacheln
bekommen die Kachel Monatsende, Team-Abos rechnen bis Monatsende.

A2: Sperrfristen Default 0, Setting 0 ist ausdruecklich 0 (fiel bisher auf
den Default zurueck). Bedingung Kalendertage <= Sperre, zentral in
AboHelper::isWithinLock: am Ausfuehrungstag ab 0:00 Uhr fixiert, Vortag bis
23:59 Uhr frei, fuer Liefertag, Produkte, Pause und Kuendigung (R2). Texte
mit _zero-Varianten ueber AboHelper::lockMessage.

Sprachdateien de/en/es/fr, neuer AboDeliveryDayTest, bestehende Tests
angepasst, Plan-Status mit Deploy-Schritt (Settings auf 0).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 11:28:55 +00:00
ec3ecadc5d Abo (A3): Status und Grund eines Abos sichtbar machen
Neue Spalten user_abos.status_reason / paused_until und
user_abo_orders.error_message. Der Grund wird zentral am Model gepflegt
(saving-Event): Zahlungsfehler, Kuendigung/Deaktivierung mit Akteur aus dem
Formular-Kanal, Loeschen beim Zurueckkehren in den Lauf; die Pause setzt
paused_until und paused_by_*. Cron- und Retry-Zahlung schreiben den Fehlertext
des Anbieters an die Abo-Bestellung.

AboStatusExplainer uebersetzt das in einen Satz ("Pausiert bis ... vom Kunden
am ...", "Zahlung am ... fehlgeschlagen - Grund: ...", "Gekuendigt am ... vom
Berater"), Partial _status_explain in Abo-Detail (CRM, Portal, Admin),
Abo-Uebersicht, Kundenabo-Liste, Team-Kundenabos und Admin-Datatable; dort
neuer Filter "Zustand" (pausiert / Zahlung fehlgeschlagen). Backfill-Kommando
abo:backfill-status-reasons fuer Bestandsdaten, Fallback ueber das
Statusprotokoll und die Pausenfelder.

Sprachdateien de/en/es/fr, Tests in AboStatusExplainTest, Plan-Status.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 10:24:18 +00:00
c0535be02f Abo (A4): Abschnitt "Abo pausieren oder kuendigen" mit Kuendigungs-Hinweis
Eigener Abschnitt auf der Abo-Seite (CRM me/ot und Kundenportal) mit
Fortschritt zur Mindestlaufzeit, Pause und Kuendigung. Die Kuendigung laeuft
ueber ein Modal, das die Folgen nennt (Abo endet, Konditionen entfallen, ein
neues Abo hat wieder 6 Pflichtlieferungen), die Pause als Alternative anbietet
und erst nach Bestaetigungs-Checkbox freigibt. Innerhalb der Sperrfrist vor
der Ausfuehrung erscheint statt der Buttons ein Hinweis
(AboHelper::isPauseCancelLocked). Das Einstellungs-Modal verweist nur noch
auf den Abschnitt. Die Kuendigung im Repository ist jetzt wie die Pause eine
eigenstaendige Aktion: Erfolgsmeldung statt Liefertermin-Hinweis, next_date
bleibt unangetastet.

Sprachdateien de/en/es/fr, Tests in AboPauseCancelSectionTest, Plan-Status.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 10:14:51 +00:00
d57687b4e3 Team-Statistik = Team-Struktur (Provisionsbaum, Umschalter) und Laufstand-Fix in user_sales_volumes
K11 aus dem September-Protokoll (Tickets C1 und C2 im Entwicklungsplan), live seit 14.09.2026.

C1 – Statistik rechnet wie die Provision
- Standard-Baum ist der Provisionsbaum (Mitglieder wie TreeCalcBot: Mitgliedsebene,
  Abrechnungskonto, active_date; ausgefilterte Knoten kappen ihren Unterbaum, max. 21 Linien).
  Gesamte Downline bleibt per Umschalter erreichbar, Wahl in der Session.
- Punkte-Definition: Provisionspunkte (TP + Shop), reine Karrierepunkte ausgewiesen statt
  eingerechnet, negative Monatssalden je User wie in der Provision auf 0 gekappt.
- Abgeschlossene Monate nehmen die Mitglieder je Linie aus dem gespeicherten Provisionslauf
  (user_businesses), Snapshots je Baum-Definition (Payload-Version 3, Migration).
- Struktur-Modal: Gesamt aus den Linien-Punkten mit Dezimalen statt der int-Spalte total_pp.
- Messlauf statistics:compare-trees (Downline / Provisionsbaum / Struktur je VIP, Laufstand-Drift).

C2 – Laufstand-Race (Provision zu niedrig bei zeitgleichen Buchungen)
- Neuberechnung liest die Zeilen des Beraters sperrend (FOR UPDATE), Index (user_id, year, month).
- Paid-Pfad der Payone- und Stripe-Webhooks als DB::transaction mit 3 Anlaeufen; Deadlock und
  Lock-Timeout aus der Rechnungserstellung werden nicht mehr geschluckt.
- Sicherheitsnetz sales:repair-running-totals taeglich 02:45 vor dem Provisionslauf;
  abgeschlossene Monate werden nicht angefasst (Entscheid 14.09.: keine Nachzahlung fuer 06/08).

Doku: Entwicklungsplan zum Protokoll, Deploy-Notiz 14.09. (inkl. Migrations-Stolperstein:
Migrationen tragen Werte als Literale, nicht als Konstanten aus dem Anwendungscode).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 15:31:32 +00:00
42ec51cb36 Statistik: Stornos mindern die richtige Punktekategorie
Ein Storno einer Shop-Bestellung wurde als Eigenpunkt gebucht und liess damit
die Shop-Provisionsbasis ungemindert. Betroffen sind 7 Faelle aus April bis
August 2026 (178,82 EUR Differenz in der Provisionsbasis, gegen user_businesses
geprueft).

Ursache: `status_turnover` beschreibt nur, wohin der UMSATZ gehoert. Die Punkte
folgen einer anderen Regel — eine Gutschrift (Status 4) bucht ihre Punkte immer
auf KP/TP, auch wenn ihr Umsatz dem Shop zugeordnet ist. Die Gegenbuchung kann
diese Aufteilung ohne die Ursprungsart nicht spiegeln, deshalb haelt
`storno_origin_status` sie jetzt auf der Stornozeile fest. NULL heisst
"Altzeile ohne Angabe" und faellt auf das bisherige Verhalten zurueck —
abgeschlossene Monate aendern sich dadurch nicht.

Stornoregel (Kundenentscheidung): Ein Storno mindert nur den Monat der
Ursprungsbestellung. Ist der Monat abgeschlossen, passiert nichts mehr, denn
Abrechnung und Gutschriften stehen. Ein Minus in den neuen Monat mitzunehmen
waere nicht nachvollziehbar. Fuer den Ausnahmefall gibt es den Settings-Schalter
`storno-points-current-month`, standardmaessig aus.

Ausserdem: Die persoenliche Monatsstatistik summierte Status 0 (nicht
zugeordnet) und 3 (pending) mit, die gemeinsame Punkteauswertung nicht. Beide
nutzen jetzt dieselbe Statusliste, und ein Storno mindert das Segment seiner
Ursprungsbuchung statt pauschal in "Sonstige" zu laufen.

Die Migration fuer `status_turnover` zieht nur das Schema auf den tatsaechlichen
Stand nach (nullable statt NOT NULL) — auf Produktion faktisch wirkungslos,
aber Neuinstallationen und die Testdatenbank haben damit dieselbe Semantik.

Audit-Befunde A02, A06, A15, R01-R03.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 11:18:40 +00:00
2e71173c66 Stripe: Kundendaten, Rechnungsnummer, manueller Zahlungseingang
Rueckmeldung der Buchhaltung und des Stripe-Calls (dev/2026-08-26-stripe/):
Stripe kannte bisher nur die E-Mail des Kunden, Zahlungen waren im Dashboard
weder ueber die Bestell- noch ueber die Rechnungsnummer auffindbar, und ein
Zahlungseingang mit falschem Verwendungszweck zwang die Buchhaltung dazu, die
Rechnung von Hand zu schreiben.

- SE1: Der Checkout haengt einen Stripe-Customer mit Name, E-Mail und
  Rechnungsanschrift an die Session (customer statt customer_email); die ID
  liegt an shopping_users und wird wiederverwendet. Namensformat "Vorname
  Nachname (Firma)", reine Firmenkunden unter der Firma. Faellt die
  Customer-Anlage aus, laeuft der Checkout auf dem bisherigen Weg weiter.
  DSGVO-Loeschungen entfernen jetzt auch das Customer-Objekt; die Charges
  bleiben als Buchungsbeleg bestehen.
- SE2: StripeMetadataBuilder als einzige Quelle fuer Metadaten und die
  description (Bestellnummer, Referenz, Kundenname) - damit greift die
  Dashboard-Suche, die bisher nichts Lesbares zu fassen bekam.
- SE3: Die Rechnungsnummer entsteht erst nach der Zahlung und wird daher per
  Job am PaymentIntent nachgetragen (Vorab-Reservierung wuerde Luecken im
  Nummernkreis erzeugen). stripe:backfill-invoice-metadata traegt sie
  rueckwirkend ab dem Go-Live 2026-07-10 nach.
- SE4: Neuer Admin-Button "Zahlungseingang erfassen" an jeder unbezahlten
  Bestellung - bisher gab es ihn nur bei Rechnungskauf, und er setzte nur
  paid, ohne Rechnung, Punkte, Abo-Aktivierung oder Mail. Der neue Weg laeuft
  durch paymentStatusPaidAction, verlangt den Verwendungszweck als Beleg und
  laesst einen abweichenden Betrag nur mit ausdruecklicher Bestaetigung zu.
- S6.4 (aus dem Juli-Plan vorgezogen): stripe:sync-payment-status gleicht
  offene Zahlungen aktiv gegen die API ab. Aufgefallen beim Testlauf - ein nie
  zugestellter Webhook war bisher nicht reparierbar, das Geld lag bei Stripe
  waehrend die Bestellung auf offen stand. Laeuft stuendlich im Scheduler.
- 110 Tests (Pest) fuer alle Pfade, Stripe-Client durchgehend gemockt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 09:04:28 +00:00
d65922adfe Statistiken: Kundenfeedback 2026-08-19 komplett (N1-N8) + Review-Fixes + VP-/Incentive-Repair gehärtet
Statistik-Änderungen 2026-08-19 (dev/2026-07-22/entwicklungsplan-2026-08-19.md, alle 8 Pakete gemäß beantworteten F-Fragen):
- N1 Monatsstatistik: Team-Cluster (Firstlines klickbar -> neue Seite user_team_firstlines, Teampartner gesamt/Payline [nur aktive], Abos Payline mit +N) + Level-Kachel (Quali-Stufe, fehlende Payline-/persönliche Punkte, Karriere-Level); LiveCommissionService-Snapshot v3 reicht Level-/Quali-Daten durch
- N2 Abo-Kacheln auf Home monatsbezogen (aboStockCount-Rückrechnung über cancel/deleted/Status-Historie; VIP-Statistik bleibt tagesaktuell)
- N3 VIP-Statistik 'Recruiter des Monats' (Neupartner-Definition wie KPI, rekursives Ketten-Volumen als Gesamtpunkte inkl. Starterpaket) + Drilldown/CSV-Spalte 'Punkte gesamt'
- N4 Prognose-Block 'Level & Provision laut Prognose (Stand 25.)' mit unverbindlich-Kennzeichnung (ebenengenaue offene Abo-Punkte + TP-Laufstände)
- N5 Checkout-Herkunft: Dropdown raus, Pflicht-Freitext (lokalisierte Fehlermeldung)
- N6 Berater-Profilfoto (user_accounts.profile_image, Einwilligung als Sprachkey-Platzhalter, DSGVO-Löschung) + teaminterne Top-3-Karte (TopResultsService, Scope-Schalter)
- N7 USt-Optionen: 'nicht umsatzsteuerpflichtig' zuerst + '§ 19 UStG'-Textfix
- N8 Jahresgebühr-Nachfassliste je Berater (AnnualFeeDueService, überfällig/1-3 Monate, Sidenav)

Kontroll-Review (8 Perspektiven) angewendet: next-Level-Fallback im Steady-State (resolveNextLevel — sonst 'Höchstes Level erreicht' für Normalfälle), _calculated-Punktebasis bei mehr Paylines, keine Wiederbelebung deaktivierter Abos in der Monatsrückrechnung, Payline-Abo-Kachel monatskonsistent, Top-3-Nachrücker; Performance: BackofficeDashboardService als Singleton mit lineBuckets-Memo (+flushLineBucketsMemo), level_forecast 6h-Cache; Reuse: User-Scopes firstlinesOf/newPartnerIn, SalesVolumePoints::totalPointsByUser, Slim::storeCroppedImage (3 Upload-Kopien vereinigt), activeAbo-Scope statt Inline-Prädikate, Form::open-Konvention, Return-Types

Repair-Härtung (Kundenentscheide): VP-Nachtrepair dedupliziert über shopping_order_id (Live-Pfad schreibt sie jetzt mit), zählende Alt-Zeilen-Erkennung, Vormonats-Scan für Monatswechsel, Firmenaccount-Buchungen (config mivita.company_user_id) werden automatisch auf den Berater umgebucht (in place bzw. per Gegenbuchung bei geschlossenem Monat; Echtfall Anna Schall Order 58797 -> Christina Schuder), Berater-zu-Berater nur Warnung; Incentive-Repair: m_sponsor=NULL löscht nicht mehr, FK-Repair vor Stale-Bereinigung, gebatchte Lookups, zentrales Incentive::qualificationWindow(); .env aus dem Git-Tracking entfernt (Pflege per SFTP)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 10:44:44 +00:00
d4e9d108ad Statistiken/Abo: Kundenfeedback 2026-07-24 komplett umgesetzt + Steuern: DATEV-Fixes 08+09/2025 (Sammel-Commit Branch-WIP)
Feedback-Umsetzung (dev/2026-07-22/feedback-analyse-2026-07-24.md, alle 10 Punkte):
- VIP-Statistik: eigener Berater ('ich', Linie 0) in Neue-Kundenabos- und beiden Top-10-Listen; Top-10-Umsatz sortiert nach abgerechneten Ist-Punkten + Abo-Anzahl-Spalte; Fußnote nicht-payline-wirksame Punkte (SalesVolumePoints::nonPaylinePoints)
- Führungskräfte-Liste: beide Sichten 'direkt' (an nächster FK abgeschnitten, additiv) und 'gesamt' (komplette Downline), Gesamt-Spalte nach Kundenzählweise
- Team-Abos: je Ebene 'abgerechnet (Monat)' und 'bis zum 25. erwartet'; Payline-Karte mit Teamabo-/Kundenabo-Zählern
- Incentive-Live-Ranking: Qualifizierte zuerst nummeriert (fixt auch isWinner rank<=max_winners)
- Porto: Netto-/Brutto-Kennzeichnung (Berater netto, Endkunden inkl. MwSt., portal_view-Flag; auch CRM-/Shop-Warenkorb + Checkout), Yard::shipping_tax-Fix
- Struktur-Ansicht: Abo-Badges 'A' (eigenes Abo) und '(n)' (Kundenabos) je Teampartner, gebatcht
- Abo-Löschung: Softdelete setzt active=0 (UserAbo deleting-Hook) + Bereinigungs-Migration für gelöschte-aber-aktive Abos
- Doku: technische Analyse + Kundinnen-Feedback-Dokument unter dev/2026-07-22/
- Tests: IncentiveRankingTest, TeamStructureAboBadgesTest, YardShippingTaxTest (neu); BackofficeStatisticsListsTest, TeamAboOverviewTest, PaylineForecastServiceTest, AboAdminDeleteTest, AboOneTimeViewTest erweitert

Außerdem enthalten (Branch-WIP vor dem Feedback): DATEV-Abgleich-Fixes 08+09/2025, USt-ID-Live-Validierung sowie restliche unkommittete Stände (u. a. Abo-Pause-Sprachkeys).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 13:56:02 +00:00
ad19112750 Stripe-Integration (S7.4): Payment-Dashboard für Stripe
- Provider-Status/Uptime: Stripe-Kachel aktiviert; payment:check-uptime prüft
  zusätzlich api.stripe.com/v1/ (401 ohne Key = erreichbar) inkl. Auto-Incident
- Zahlungen: Anbieter-Filter, Provider-Badges, Umsatz je Provider,
  Stripe-Dashboard-Deep-Links (ShoppingPayment/PaymentTransaction::
  stripeDashboardUrl, pi_-Guard, testmodus-bewusst)
- Rohe Transaktionen: Anbieter-Filter/-Spalte, Erfolgsraten je Anbieter;
  Bugfix: Stringable-Vergleich ließ den txaction-Filter immer mit leerem Wert
  greifen — Liste war dauerhaft leer
- Neue Kachel „Abos je Anbieter" (Index + GF-Ansicht) mit Fehlerzählern und
  Stripe-Anteil-Fortschrittsbalken (Auslaufmodell PAYONE → Stripe ablesbar)
- Incident-Kachel weist Stripe/PAYONE getrennt aus; Log-Viewer mit
  Kanal-Umschalter stripe/payone
- Plan-Doku: S7.4-Umsetzungsstatus, Abo-Go-Live 2026-07-10 vermerkt

Tests: PaymentDashboardProviderTest (9 neu), Dashboard-Suite 49 grün.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:57:50 +00:00
e1da90ff91 Stripe-Integration (S0–S3): Einmalzahlungen über Stripe Checkout + Notfall-Go-Live
Wegen PAYONE-Ausfall vorgezogen live geschaltet: alle Einmalzahlungen
(Shop + Salescenter) laufen über Stripe Hosted Checkout, Abos sind bis
Phase S4 eingefroren.

- Provider-Abstraktion: PaymentProvider-Enum, PaymentGatewayInterface,
  PaymentProviderManager (Settings-Schalter, provider-treu je Bestand),
  PayoneGateway als unveränderter Adapter
- StripePaymentService: Checkout Session (eine Gesamtposition, Metadata,
  success/cancel-Redirects), StripeClientWrapper (lazy, Dark Launch),
  StripeCustomerService, StripeTransactionRecorder (client_secret-Redaction)
- Webhook /stripe/webhook: Signaturprüfung, Idempotenz über
  stripe_webhook_events (Crash-Retry-Reprocessing), txaction-Prioritäten,
  Betrags-Guard, lockForUpdate-Paid-Pfad, genau eine Bestätigungsmail
- Zahlungsmethoden-Anzeige aus charge.succeeded (carddata inkl. Wallet,
  auftragsunabhängiges Backfill aus dem Event-Store)
- Checkout: Wartungsmodus mit Admin-Bypass, Abo-Freeze-Hinweis,
  Stripe-Option (Online-Zahlung) statt Zahlartenwahl, Vorkasse ausblendbar
- Abo-Freeze-Guards: Cron user:make_abo_order, Retry, Kartenupdate
- Admin-Settings-Karte Zahlungen (Provider, Wartung, Freeze, Vorkasse)
- Hotfix: 500 bei Vorkasse ohne Clearing-Daten in admin/sales/_detail
  und checkout-final (PAYONE-Ausfall)
- Doku dev/2026-07-08-stripe/ (Plan S0–S8, Konzept, IST-Analyse)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:56:41 +00:00
1108381988 Abo: Kreditkarte aktualisieren (CRM, Portal, Berater-Link) + Admin-Abo-Löschung
- Karten-Update ohne Abbuchung via PAYONE creditcardcheck/pseudocardpan
  (AboPaymentMethodService, CardUpdateResult/CreditCardCheckData-DTOs)
- Eingabe nur durch Abo-Inhaber: CRM- und Portal-Formular + zeitlich
  begrenzter Berater→Kunde-Link (AboCardUpdateLink + Mail)
- Änderungshistorie in user_abo_card_changes, Anzeige im Admin-Abo-Detail
- Admin: Abo löschen (destroy) inkl. Test
- Portal-Fix: myOrderCreate wirft 404 statt TypeError bei ungültiger ID
- VIP-Sichtbarkeitstests für Einmalartikel-Fenster ergänzt
- Enthält bereits die Freeze-Guards für den Stripe-Notbetrieb (Folge-Commit)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:56:19 +00:00
83ef5f1e52 Widerruf: Gesetzliche Online-Widerrufsfunktion (Formular, Bestätigungsmail, Admin-Verwaltung)
- Öffentliches Widerrufsformular /widerruf mit Bestell-Lookup (throttled)
- Bestätigungsmail an Kunde + Weiterleitung an bestellungen@ (config app.withdrawal_mail)
- Admin-Übersicht/-Detail unter /admin/withdrawals inkl. Sidenav-Eintrag
- Widerruf-Button in Portal-Bestellansicht und Footer-Links
- Model OrderWithdrawal + Migration + Factory + Tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:56:02 +00:00
9dc138e45b Admin-Abo: Produkte trotz Mindestlaufzeit abziehen/entfernen
Die Admin-Detailseite postete Warenkorb-Aktionen mit view=me/ot, wodurch
Add-only-Modus und Change-Lock auch fuer Admins griffen (Reduzieren wurde
verworfen, Entfernen lieferte 403). Formular postet jetzt mit view=admin;
checkPermissions laesst view=admin nur noch fuer Admins zu (schliesst
zugleich die Luecke, dass unbekannte Views alle Besitzer-Pruefungen
uebersprangen).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 08:17:27 +00:00
e7b40bc513 Abo-Recovery: fehlgeschlagene Folgezahlung im Checkout nachholen
- Pay-now-Flow: bei fehlgeschlagenem Abo (Status 3) begleicht der Inhaber die
  offene Rechnung im Standard-Checkout mit frei waehlbarer, abo-faehiger Zahlart
  (nur eigenes Abo: Berater me-View + Kundenportal), payNow-Controller + Routen
- AboRecoveryCheckoutService baut die ShoppingInstance aus den Abo-Artikeln;
  neue Spalte shopping_orders.recovery_user_abo_id verknuepft Bestellung<->Abo
- Bei Erfolg: AboHelper::advanceAboAfterRecoveryPayment schreibt das Abo fort
  (Status->2, next_date) und uebernimmt die gewaehlte Zahlart als neues Token
  fuer kuenftige Abbuchungen
- Neue Pay-now-Fehlermail (AboPaymentFailedMail) ersetzt die generische
  Fehlermail im Abo-Cron; Link fuehrt auf die Abo-Detailseite (CRM bzw. Portal)
- Retry-/"extern erledigt"-Buttons nur noch fuer Admins; tote user/portal-
  Retry-Routen entfernt
- Checkout: Recovery-Hinweis statt "Abschluss des Abonnements", Lieferadresse
  vorbelegt, korrekter Zurueck-Link (Abo statt Shop)
- UserAbo::selfServiceDetailUrl zentralisiert die Abo-URL (Mail, Back-Links)
- Test-Command abo:test-recovery; Tests fuer payNow, Advance-Logik, Fehlermail

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:38:05 +00:00
e401251b0d DHL-Versand: Sendungs-Info-Button in Bestelllisten & Absenderadresse
Neuer schlanker DHL-Info-Button (getDhlShippingButton) in den Order- und
Shop-Sales-Datatables, oeffnet ein Read-only-Modal (modal_dhl_shipping_info)
mit den Tracking-Daten; dhlShipments wird dafuer eager geladen.
Absenderadresse in config/dhl.php aktualisiert, plus kleinere Fixes in
DhlShipmentController/Service/DataHelper und CreateReturnLabelJob.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 13:37:13 +00:00
dcd0384878 Abo Einmalprodukte: Phasen 5-7, konfigurierbare Sperrfristen, Lokalisierung & Dashboard
Rechnung/Lieferschein:
- PDF-Gruppierung Abo- vs. Einmal-Artikel (is_abo_addon), rueckwaertskompatibel
- Vorschau-Command sales:preview-invoice (umgeht Test-System-Gate, ohne Rechnungsnummer)

Reminder-Mail (vorbereitet, Cron inaktiv):
- MailAboExecutionReminder + Template, abo:send-execution-reminder, Spalte onetime_reminder_sent_for
- Berater -> Sales Center, Kunde -> Portal; Vorschau abo:preview-reminder
- Datum-Fix: formatDateDB() statt formatDate() (ICU-Format)

Sperrfristen konfigurierbar (Admin-Settings):
- abo-lock-days-change (Liefertag + Abo-Produkte), abo-lock-days-pause-cancel
- Meldungen mit :lock-Platzhalter; Pausieren/Kuendigen vom Change-Lock entkoppelt
- Abo-Produkt-Aenderungen im Lock-Fenster server- + clientseitig eingefroren
- Selbstbedienung: Add-only/Lock nach $view (kein Admin-Bypass), Stale-Cache-Fix beim Mengen-Update

Dashboard:
- Einmalprodukte-Card + Team-Abo-KPI-Card, News-Card responsiv (col-xl-6)

Lokalisierung:
- Sprachdateien en/es/fr vollstaendig mit de synchronisiert (inkl. marketingplan/portal)
- LocalizationSyncTest sichert Key-Gleichheit ab

Tests: AboOneTimeInvoiceGrouping, AboExecutionReminder, AboLockDaysSetting,
AboOnetimeDashboardAndMail, PreviewInvoiceCommand, TeamAboOverview + erweiterte View-Tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 13:38:11 +00:00
321e7959da Admin-Abos: Filterleiste und Textsuche nach PayOne-ID
Neue serverseitige, pro Admin persistente Filter auf /admin/abos:
- Status (echte Abo-Status aus UserAbo::$statusTypes, nur vorhandene Werte)
- Aktiv / Inaktiv
- Ist fuer (Berater/Kunde, is_for me/ot)
- Zahlung (Kreditkarte/PayPal ueber clearingtype cc/wlt)
- Startdatum (Monat + Jahr, optisch gruppiert; whereMonth/whereYear)
- Naechste Ausfuehrung (feste Liefertage 5/10/20/25 ueber abo_interval)
- Berater-Zuordnung (Member-Dropdown, Proportionen wie /admin/business/points)
- Reset-Button (korrigiert: bleibt auf admin_abos, Label ausserhalb des Buttons)

Layout in zwei Zeilen, damit nichts zusammengequetscht wird.

Textsuche der Tabelle: payone_userid via filterColumn suchbar gemacht
(addColumn-Spalten schliesst Yajra sonst von der globalen Suche aus).

Lang-Keys tables.month/year/all/inactive (de/en) ergaenzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 09:54:50 +00:00
090debf1b4 Abo: Bestellung extern als erledigt markieren (ohne Rechnung/Inkasso)
Neue Admin-Funktion fuer angehaltene Abo-Bestellungen, die der Kunde
ausserhalb des Systems geliefert und verrechnet hat.

Aktion (AboExternalCompletionService):
- Punkte gutschreiben wie bei eingegangener Zahlung (SalesPointsVolume,
  idempotent gegen Doppelbuchung)
- UserAboOrder auf neuen gruenen Status 8 "extern erledigt"; paid bleibt false
- Bestellung: shipped=2 (Lieferung bestaetigt), keine Rechnung/kein Lieferschein
- Blockade aufheben: Abo zurueck auf status=2 (okay), aktiv, next_date neu,
  damit der naechste Termin regulaer laeuft
- wie bei regulaerer Ausfuehrung: IncentiveTracker + AboOneTimeService-Purge

Einstiegspunkte: Button + Bestaetigungs-Modal auf der Kunden-Bestelldetailseite
(SalesController) und auf der Abo-Detailseite (Admin\AboController@externDone,
Route admin_abos_extern_done). Status 8 (gruen) in UserAbo/UserAboOrder, Labels
de/en.

Tests: tests/Feature/AboExternalCompletionTest (Happy Path, Idempotenz,
bezahlt-/Nicht-Abo-Guards, Abo-Detail-Einstieg) - 5 gruen.

Zusaetzlich: docs/2026-06-11-test-suite-vorbestehende-fehler.md - Diagnose der
93 vorbestehenden (von master geerbten) Test-Suite-Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 08:11:45 +00:00
ee04146217 Abo Einmalprodukte: Phase 4 - Ausfuehrung, Purge & User-Retry
- UserMakeOrder: bestaetigte Einmal-Artikel in den Yard, is_abo_addon
  auf ShoppingOrderItem; amount bleibt reiner Abo-Betrag (Reihenfolge)
- AboOneTimeService::purgeAfterExecution: loescht alle Einmal-Artikel
  und rechnet Comp-Produkte neu - nur im Erfolgszweig (Cron + Retry)
- User-Retry in Sales Center und Portal mit Berechtigungspruefung,
  gemeinsames Confirm-Modal; Admin-Retry unveraendert
- Tests: AboMakeOrderOneTimeTest, AboUserRetryTest; Plan-Doku Phase 4

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 15:32:27 +00:00
8288ea59ac Abo Einmalprodukte: Review-Gate (VIP), Verbindlichkeit & Summen-Layout
- Live-Review-Gate: Einmalprodukte nur fuer VIP im Sales Center sichtbar,
  Portal ausgeblendet (AboHelper::isOneTimeFeatureVisible + Gates in Controllern)
- Nur verbindlich bestaetigte Einmal-Artikel fliessen in die Lieferung;
  Service-Helfer confirmedItems/pendingItems/pendingGross
- Footer-Layout der Einmalprodukt-Liste: bestaetigte Summe + Gesamtbetrag,
  Trennstrich, offener Betrag und neue Gesamtsumme (dunkelgruen)
- Uebersetzungen DE/EN/ES/FR (onetime_new_total u.a.), Tests angepasst/ergaenzt

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 14:59:22 +00:00
2269ce031f Abo Einmalprodukte und Bestätigung abschließen
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 15:28:08 +00:00
2bdc9ada3c 27-05-2026 DHL Modul v2.1 / Optimierung tracking 2026-05-27 18:51:23 +02:00
036595be94 27-05-2026 Update DHL Modul v2.0 2026-05-27 13:40:38 +00:00
53bdba33cd User Statistik 2026-05-18 17:23:28 +02:00
245c281541 Steuerberater Modul tax 2026-05-08 15:34:57 +02:00
0f82fea88a 14-04-2026 2026-04-14 18:07:45 +02:00
f58c709945 10.April 2026 2026-04-10 17:15:27 +02:00
a00c42e770 20-02-2026 2026-02-20 17:55:06 +01:00
a8b395e20d 23-01-2026 2026-01-23 17:35:23 +01:00
a939cd51ef update 20.10.2025 2025-10-20 17:42:08 +02:00
8c11130b5d Cocker Setup 2025-08-29 14:48:03 +02:00
Kevin Adametz
8fdaa0ba1d DHL Modul v0.5 Shipping Label ok 2025-08-22 18:18:26 +02:00
Kevin Adametz
480fdc65ed commit 08-2025 2025-08-12 18:01:59 +02:00
Kevin Adametz
9ae662f63e Updates to 03-2025 2025-04-01 10:36:47 +02:00
Kevin Adametz
bfa3bb1df4 08 2024 2024-08-05 12:05:24 +02:00
Kevin Adametz
04d677d37a last changes since 6-2023 2023-07-03 10:07:08 +02:00
Kevin Adametz
0341c9c189 Free Shipping, Business Levels correction, Products Buying, Fonts 2023-01-25 12:37:29 +01:00
Kevin Adametz
3f2fbd6d5b #51 Festschreiben der Points, Gutschriftenmodul 2022-07-29 18:18:05 +02:00
Kevin Adametz
dfd049aaa9 #51 2 Business Points edit / add, user dashboard 2022-07-22 13:43:24 +02:00
Kevin Adametz
263cf93a1e #53, #52, #51 change Points 2022-07-21 10:37:34 +02:00
Kevin Adametz
582ca8299d Sammelbestellung von Extern 2022-07-18 18:07:31 +02:00
Kevin Adametz
d01b4bd560 API Shopping Order backend 2022-07-15 21:21:56 +02:00
Kevin Adametz
7a040c3e19 06 2022 2022-06-15 18:08:45 +02:00
Kevin Adametz
9b0b5feb7e Update Framework, Invoices 2022-04-14 13:14:36 +02:00