Warenwirtschaft: Doku — AP-33b abgeschlossen (Hinweise, Testleitfaden, Plan-Protokoll)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-16 12:01:19 +00:00
parent 1252c30820
commit 96615258e9
3 changed files with 12 additions and 4 deletions

View file

@ -41,7 +41,8 @@ V6.0 basiert auf einer **vollständigen Code-Verifikation vom 06.07.2026** (alle
| AP-13 | Shop-Bestandsabzug bei Versand (inkl. Sets) + API-Bestellungen-Protokoll | ✅ **fertig 16.07.2026** (`211aeed`, `71d5591`) | `ProductStockService::syncSaleStock()`, `api_order_logs`, Menüpunkt „API-Bestellungen"; `SaleStockDeductionTest` (10), `ApiOrderLogTest` (8) |
| AP-32 | Versand im System: DHL-Etiketten per API | 🆕 **neu aufgenommen 15.07.2026** (Kundenanforderung) | Umsetzungsansatz in §4; Andockpunkt = Versand-Statuswechsel (wie AP-13) |
| AP-33a | Bestell-Abwicklung: Nav „Bestellungen" + Fulfillment-Board | ✅ **fertig 16.07.2026** (`a367d85`) | `OrderFulfillmentController`, `OrderStatusService`, `shipped_status_locked`; `OrderFulfillmentTest` (10) |
| AP-33b/c | Sammel-Dokumente + Etiketten-Stapel | 🆕 geplant (§4) | b nach 33a; c mit AP-32 |
| AP-33b | Sammel-Dokumente (Lieferscheine/Rechnungen als ein PDF) | ✅ **fertig 16.07.2026** (`1252c30`) | Checkbox-Auswahl im Board, `batchDocuments()` via `PDFMerger`; `OrderFulfillmentTest` (14) |
| AP-33c | Etiketten-Stapel | 🆕 geplant (§4) | mit AP-32 |
| AP-14 | Audit-Trail | ⏸ nachgelagert | kein Package, keine Spur |
| AP-15 | Blockbasierte Rechte | ⏸ nachgelagert | nur `isAdmin()`-Stufen |
| AP-16 | 2FA (Google Authenticator) | ⏸ nachgelagert | kein TOTP-Package in composer.json |
@ -114,7 +115,8 @@ Alle Punkte dieser älteren Runde sind in V4.0 eingeflossen und umgesetzt (URL-F
| 10 | ✅ AP-13 | Shop-Bestandsabzug bei Versand (inkl. Sets) + API-Bestellungen-Protokoll — **erledigt 16.07.2026** | AP-28 (saubere Buchungslogik) ✅ | 3–5 Tage |
| 11 | ✅ AP-33a | Bestell-Abwicklung: Nav „Bestellungen" + Fulfillment-Board — **erledigt 16.07.2026** | AP-13 ✅ | 2–3 Tage |
| 12 | 🆕 AP-32 | Versand im System: DHL-Etiketten per API (Kundenanforderung 15.07.2026, Ansatz §4) | Kundenantworten (DHL-Konto, Versandprodukte, Druck) | 3–5 Tage |
| 13 | 🆕 AP-33b/c | Sammel-Dokumente (Lieferscheine/Rechnungen als ein PDF) + Etiketten-Stapel/Automatik-Option | AP-33a; c: AP-32 | 2–3 Tage |
| 13 | ✅ AP-33b | Sammel-Dokumente (Lieferscheine/Rechnungen als ein PDF) — **erledigt 16.07.2026** | AP-33a ✅ | 1,5–2 Tage |
| 13b | 🆕 AP-33c | Etiketten-Stapel + Automatik-Option | AP-32 | 1 Tag |
| 14 | ⏸ AP-14 | Audit-Trail — nachgelagert | – | 2–3 Tage |
| 15 | ⏸ AP-16 | 2FA für Admins (Google Authenticator) — nachgelagert | – | 2–3 Tage |
| 16 | ⏸ AP-15 | Blockbasierte Rechte (sehen/bearbeiten je Block) — nachgelagert | AP-16 sinnvoll davor | 4–6 Tage |
@ -263,6 +265,7 @@ Der Warenkorb kommt also **per Knopfdruck** (Fulfillment-Übergabe), nicht autom
| 15.07.2026 | **N-1/N-6/N-10 (Kundenentscheide)** | **N-1:** Chargen-Gruppierung je Lieferant (`batchGroupKey` = `b:<supplier>:<lot>`, Batch-Check prüft Lieferant) — Kundenentscheid: Lot-Nummern kommen von extern und können kollidieren (`9b6c9de`). **N-6:** WaWi-Eingaben lesen einen einzelnen Punkt mit 1–2 Nachkommastellen als Dezimaltrenner („5.1" = 5,1; „1.500" = 1500) — neuer Helper `reFormatWawiNumber()` + JS-Parser vereinheitlicht (`016e8bb`). **N-10:** Bewegungs-Modal zeigt aktuellen Bestand + Bestätigung bei Minus-Buchung (`6af6760`). | +2 Tests. Volle Suite: **233 grün, 832 Assertions** |
| 16.07.2026 | **Vorbereitung AP-13: SalesController-Härtung** | `SalesController::store()` (Versand-Statuswechsel) validiert Eingaben (Status aus `$shippedTypes`, Action-Whitelist, txaction/payment_id) und läuft in `DB::transaction` mit `lockForUpdate` gegen Doppelklick/parallele Tabs. Verhalten unverändert. Commit `6b8fcad`. | Neuer `SalesShippedStatusTest` (6 grün). Suite: **239 grün, 847 Assertions** |
| 16.07.2026 | **AP-13 (Shop-Bestandsabzug bei Versand)** | **`ProductStockService::syncSaleStock()`**: idempotenter Differenz-Abgleich der Verkaufs-Abgänge (`source='sale'`, Referenz = Bestellung) mit dem Versandstatus — Abzug je Bestellposition bei `sent`/`close`, **Sets rekursiv** über `product_set_items` in Einzelprodukte aufgelöst (Zyklus-Schutz, `withTrashed` wie N-9); Zurücksetzen/Storno bucht per Gegenbuchung zurück. **Behebt das Doppelabzug-Risiko** Versand→Zurücksetzen→Versand (Ledger-Abgleich statt `shipped_at`-Flag). Andockpunkte: `SalesController::store` (in der Transaktion) **und** `PaymentReminderService` (Auto-Storno per Cron setzt Status 10 auch bei versendeten Bestellungen). „Verbrauch/Monat" zählt Verkaufs-Abgänge automatisch mit. Self-Shipping bewusst ohne Abzug (kein Warenkorb übertragen). Commit `211aeed`. **Erkenntnis für künftige HTTP-Tests:** mehrere Requests im selben Pest-Test müssen denselben `actingAs`-User verwenden, sonst endet der Folge-Request als stiller Login-Redirect. | Neuer `SaleStockDeductionTest` (10 grün: Positionen, Sets/verschachtelt, Idempotenz, Rückbuchung offen/Storno, Wiederversand, Cron-Pfad, Monatsverbrauch). Suite: **249 grün, 903 Assertions** |
| 16.07.2026 | **AP-33b (Sammel-Dokumente)** | Checkbox-Auswahl im Abwicklungs-Board (Kopf-Checkbox = alle sichtbaren, Zähler in den Buttons) + Sammel-Aktionen **„Lieferscheine drucken"** / **„+ Rechnungen"**: `OrderFulfillmentController::batchDocuments()` merged die PDFs der Auswahl (`PDFMerger`/FPDI) zu **einem** Druck-PDF (neuer Tab, max. 100). Fehlende Dokumente werden ohne Mailversand erzeugt (`InvoiceRepository::create`), auf der Platte fehlende Altdateien mit bestehender Nummer regeneriert (`update`). API-Bestellungen: Checkbox deaktiviert, in gemischter Auswahl übersprungen, reine API-Auswahl ⇒ Fehlermeldung. Nebenbei (Kundenfeedback iPad): Tabelle kompaktiert — 6 Spalten, Kundenname mit Ellipsis, Positionen als schmale letzte Spalte, Aktionen+Positionen sticky rechts, Icon-Buttons unter 1200 px (`4c73e64`, `c21cc63`). Commit `1252c30`. | `OrderFulfillmentTest` +4 (Sammel-PDF inkl. Dokument-Erzeugung, reine API-Auswahl abgelehnt, gemischte Auswahl überspringt API, Validierung). Volle Suite: **272 grün, 1001 Assertions** |
| 16.07.2026 | **AP-33a (Bestell-Abwicklung: Nav „Bestellungen" + Fulfillment-Board)** | Neuer Sidenav-Punkt **„Bestellungen"** (copyreader) mit Unterpunkten **Abwicklung** (neu) und **API-Bestellungen** (umgezogen). Board `admin/inventory/orders` (`OrderFulfillmentController`): 4 Filter-Kacheln (heute eingegangen / zu konfektionieren / versandfertig / heute versendet), je Bestellung Packliste aufklappbar (Sets mit Komponenten), Gewicht, Zahlstatus-Pill, Quelle-Badge (API/Shop/Promo), Suche. **Versandfertig-Regel** (Kundenentscheid): `ShoppingOrder::isReadyToShip()` — Rechnung (fnc) sofort, Vorkasse (vor) erst bei `paid`, API (`extern`) immer, `non`/`failed` nie. **Dokumente:** Erstellen (Rechnung + Lieferschein, ohne Mailversand) über bestehendes `InvoiceRepository::create()`; Downloads (einzeln/kombiniert via `PDFMerger`) über eigene copyreader-Routen, da `storage_file` admin ≥ 7 verlangt; **API-Bestellungen bekommen keine Rechnung** — externer Link (`wp_invoice_path`). **Statuswechsel:** Logik aus `SalesController::store()` in neuen **`OrderStatusService::setShipped()`** extrahiert (Transaktion, Lock, Margin-/Promotion-Folgen, AP-13-Abzug) — Verkäufe-Modal und Board nutzen dieselbe Implementierung; Board nur vorwärts (1/2), nur aus Status 0/1. **Sperr-Flag** `shopping_orders.shipped_status_locked` (Migration `2026_07_16_130000`, Kundenentscheid Punkt 3): vom Board gesetzte Status werden vom Auto-Wechsel der Detailseiten (offen → in Bearbeitung, 3 Stellen) nicht mehr überschrieben. Commit `a367d85`. | Neuer `OrderFulfillmentTest` (10 grün: Render/Packliste, Rechte, Versandfertig-Regel, Statuswechsel + Lock + Bestandsabzug, nur-vorwärts, Alt-Status unangetastet, Detailseiten-Sperre, Dokumente ohne Mail, API ohne Rechnung). Volle Suite: **268 grün, 987 Assertions** |
| 16.07.2026 | **AP-13-Nachtrag: Stichtags-Schutz für Alt-Bestellungen** | Beim Blick auf Bestellung 1687 (versendet 12/2025) entdeckt: erneutes Speichern des Versandstatus einer **vor AP-13 versendeten** Bestellung hätte rückwirkend vom heutigen Bestand abgezogen. `syncSaleStock()` überspringt jetzt Bestellungen mit `shipped_at` vor dem Stichtag `ProductStockService::SALE_STOCK_SINCE` (16.07.2026). Kundenentscheid dokumentiert: Self-Shipping ohne Abzug bestätigt. | `SaleStockDeductionTest` +1 (11 grün). Suite: **258 grün, 944 Assertions** |
| 16.07.2026 | **AP-13 (API-Bestellungen — Protokoll + SKU-Fehlermarkierung, Kundenanforderung 16.07.)** | Neue Tabelle **`api_order_logs`** (Migration `2026_07_16_090000`) + Model `ApiOrderLog`; `ShoppingUserController` protokolliert **jede** `wp/order`-Übertragung — erfolgreiche inkl. Zuordnungsergebnis je Position (SKU, Produkt, Menge, Preis, API-Meldungen), abgelehnte mit Grund (Kunde unbekannt, Bestellung existiert bereits, Speicherfehler). Positionen ohne Produktzuordnung ⇒ `has_errors` + Zusammenfassung („x von y Positionen ohne Produktzuordnung"). **Neuer Menüpunkt „API-Bestellungen"** (copyreader, `admin/inventory/api-orders`): Liste (Limit 500/`?all=1`, Filter „nur Fehler"), rote Markierung, **Modal „Ansehen"** mit Positionstabelle (Meldungen deutsch übersetzt, Roh-Payload bei abgelehnten). Dazu SKU-Konsistenz (Plan §4 „mitzulösen"): Warnkarte **doppelte WP-Nummern** aktiver Produkte, aufklappbare Liste **aktive Produkte ohne WP-Nummer**. Commit `71d5591`. | Neuer `ApiOrderLogTest` (8 grün, Ende-zu-Ende über `wp/order` mit `Passport::actingAs`). Suite: **257 grün, 940 Assertions** |
@ -273,4 +276,4 @@ Der Warenkorb kommt also **per Knopfdruck** (Fulfillment-Übergabe), nicht autom
>
> **✅ AP-13 + AP-33a ABGESCHLOSSEN (16.07.2026).** Shop-Bestandsabzug bei Versand (inkl. Sets, Gegenbuchungen, Stichtags-Schutz für Alt-Bestellungen), Menüpunkt „API-Bestellungen" mit SKU-Fehlermarkierung, und das Abwicklungs-Board „Bestellungen → Abwicklung" (Kundenanforderung 16.07.2026, alle Kundenentscheide in §4 dokumentiert). Suite: **268 grün, 987 Assertions.**
>
> **Als Nächstes:** AP-33b (Sammel-Dokumente: Lieferscheine/Rechnungen der Auswahl als ein PDF) — sofort umsetzbar; AP-32 (DHL-Etiketten) sobald die Kundenantworten vorliegen (DHL-Konto/EKP, Versandprodukte, Druckformat, Retourenlabel, §4), dann AP-33c (Etiketten-Stapel, optional Automatik als AP-17-Einstellung). **Nachgelagert:** AP-14 (Audit-Trail) → AP-16 (2FA) → AP-15 (Blockrechte) → AP-17 (WaWi-Einstellungen). ✅ Self-Shipping ohne Bestandsabzug am 16.07.2026 vom Kunden bestätigt (§4 Punkt 4).
> **Als Nächstes:** AP-32 (DHL-Etiketten) sobald die Kundenantworten vorliegen (DHL-Konto/EKP, Versandprodukte, Druckformat, Retourenlabel, §4), dann AP-33c (Etiketten-Stapel, optional Automatik als AP-17-Einstellung). ✅ AP-33b (Sammel-Dokumente) erledigt 16.07.2026. **Nachgelagert:** AP-14 (Audit-Trail) → AP-16 (2FA) → AP-15 (Blockrechte) → AP-17 (WaWi-Einstellungen). ✅ Self-Shipping ohne Bestandsabzug am 16.07.2026 vom Kunden bestätigt (§4 Punkt 4).