AP-45: Verpackungsverbrauch (Etikett/Tiegel) wird jetzt aus dem tatsächlichen
Produktionsergebnis gebucht — je Ergebnisprodukt dessen eigene Stückliste ×
Ergebnismenge, über alle Outputs summiert — statt aus der geplanten Stückzahl.
syncPackagingSnapshot liest die production_outputs und läuft daher nach
persistOutputs (store + update umgestellt).
AP-47: Neues Produkt-Kennzeichen „produktionsrelevant" (Boolean, Default true).
Nur so markierte Produkte erscheinen in der Produktions-Auswahl
(ProductionController create/edit/copy) und in der „Enthalten in"-Box des
Rohstoffbestands (blendet z. B. Aloe-Handelsware und Zweitgrößen aus).
Checkbox im Produktformular (mit Hidden-Fallback 0). Migration Default true,
damit Bestandsdaten unverändert bleiben.
Migrationen add_production_relevant auf Dev-/Live-DB ausgeführt. 4 Tests, Suite 314 grün.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Die INCI-Liste (Hersteller-Rezeptur) in der Produktionsmaske wird jetzt nach
Anteil % absteigend sortiert dargestellt (null-Anteile zuletzt). Reine
Anzeige-Sortierung einer Kopie — die Chargen-Zuordnung unten bleibt in
Phasen-/pos-Reihenfolge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AP-40: INCI-Tabelle der Produktion um zwei Spalten ergänzt — „Bestand" (aktueller
Rohstoffbestand je INCI, global) und „Differenz" (Bestand − Soll; negativ rot =
Fehlmenge, sonst grün). Spaltenkopf „Regal" → „Ablage". Bestand kommt aus
InventoryService::remainingByIngredient und wird als current_stock in den
recipeJson-Payload gehängt (lazy aufgelöst — InventoryService hängt selbst von
ProductionService ab, Konstruktor-Injektion wäre zirkulär).
AP-41: „Verpackung (Vorschau)" direkt unter die INCI-Tabelle verschoben (man sieht
auf einen Blick den Gesamtbedarf). Je Phase die Gesamt-Gramm hinter dem Namen
(„Phase A (345 g)"), aktualisiert sich mit Stückzahl und Füllgewicht-Skala.
Test für den current_stock-Payload ergänzt. Suite 311 grün.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AP-35 (Mengenberechnung): Die Hersteller-Rezeptur ist in Prozent hinterlegt; die
Sollmengen skalieren jetzt auf das Füllgewicht statt fest auf ~100 g. Neuer
Faktor recipeGramScale = Füllgewicht/100. Basis = neues, optionales Produkt-Feld
"fill_weight" (g); ist es leer, gilt bei ml-Produkten (unit=1) die Füllmenge
(contents_total) als Gramm (1 g/ml). Ohne Massenbasis (z. B. Stück-Produkte)
bleibt es beim Altverhalten (Anteil = Gramm), sodass Bestandsprodukte/Tests
unverändert rechnen. Skala wird an die Maske durchgereicht (recipe_gram_scale),
damit Client und Server identisch rechnen (Service + 4 JS-Stellen).
AP-39 (Abwiegen): Die Ist-Menge je INCI muss nicht mehr aufs Gramm passen —
assertLinesMatchRecipe erlaubt ±5 % (kleiner absoluter Sockel), gebucht wird der
reale Ist-Wert. Status-Ampel in der Maske: Orange = nichts eingetragen,
Grün = eingetragen und ±5 %, Rot = >5 % daneben (Zahlendreher-Schutz).
Migration add_fill_weight_to_products auf Dev-/Live-DB ausgeführt (nullable).
Product fillable/cast + Produktformular-Feld ergänzt. 5 Tests, Suite 310 grün.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phasen ohne Rohstoffzeile (reine Hinweisphasen wie „Vorbereitung"/„Nachbereitung")
verschwanden in der Produktionsmaske, weil buildPhaseGroups() leere Gruppen
wegfilterte. Filter so angepasst, dass benannte Phasen erhalten bleiben und nur
der namenlose „lose" Sammeltopf verworfen wird. Die Phasen kommen serverseitig
bereits in pos-Reihenfolge (recipePhases orderBy pos), sodass „Vorbereitung"
korrekt über „Phase A" steht. Test sichert den recipeJson-Datenvertrag ab.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Jedes Produkt trägt einen Rohstoff i. d. R. in zwei product_ingredients-Zeilen
(recipe_type manufacturer + product); die belongsToMany-Relation Ingredient::products
lieferte das Produkt dadurch doppelt in der „Enthalten in"-Box. In
RawMaterialStockController::show() die Produktliste nach ID dedupliziert
(setRelation), wovon auch der abgeleitete Produktbestand profitiert. Reine
Anzeige-Korrektur, Pivot-Daten unangetastet. Test ergänzt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Klärungspunkte beantwortet (26.08.): Varianten haben eigene Artikelnummer
(Connector sendet künftig Variations-Nr.); Gramm-Rechnung über ml+Dichte auf
Rohstoff- UND Produktebene (Produkt-Füllgewicht, Rohstoff-Dichte); getrennte
pflegbare Buchungsgründe Ein/Aus; Waldbröl auf Köln übernehmen, Funktion bleibt.
Nur D-3 (Shop-Status-Cron) noch kundenseitig in Prüfung. AP-34/35/42/48/50
entsprechend geschärft.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Kundenfeedback aus der Testphase am Code + Live-DB verifiziert und in einen
Umsetzungsplan überführt (AP-34…AP-51, ~15–26 PT): 9 bestätigte Bugs (u. a.
Varianten-Artikelnummer, Produktionsmengen 100 g statt Füllmenge, leere
Rezepturphasen, „Enthalten in"-Doppelung) plus Erweiterungen. WooCommerce-Ampel
ist voraussichtlich shopseitig (Status-Cron/Auth), kein ERP-Fehler. Sechs
Klärungspunkte (D-1…D-6) offen. Noch nichts umgesetzt.
Rohfeedback des Kunden liegt als entwicklungsplan-aktualisiert-2026-08-26.md bei.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Product-Management-Ordner in 00-konzept / 01-entwicklungsplaene / 02-audit /
03-status-und-vorschlaege gegliedert (Datei-Moves bereits in 037ec4d). Ergänzt:
- README.md als Einstieg mit grober Roadmap (Ist-Stand live/in Test, erledigte
APs, offene AP-32/33c/14/15/16/17, Deckel-Varianten-Vorschlag) und Verweisen.
- Leistungsübersicht + Deckel-Varianten-Vorschlag (23.07.) in den Ordner
einsortiert und nun mitversioniert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
routes/api 2.php und routes/web_bak.php werden nicht geladen (Bootstrap lädt
routes/api.php + web.php) und stiften nur Verwirrung. route:list unverändert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review 26.08.2026 (Testphase). Änderungen in ShoppingUserController::order():
- Bestellanlage läuft transaktional (DB::transaction um makeShoppingOrder) —
schlägt das Anlegen der Positionen fehl, bleibt keine halbe Bestellung zurück.
- Bestätigungsmail hinter den Commit verschoben und fehlertolerant (try/catch,
Log-Warnung): ein SMTP-Fehler lässt die bereits gespeicherte Übertragung nicht
mehr auf HTTP 500 laufen. Vorher meldete der Shop dann Fehlschlag, und der
Retry scheiterte an der „Bestellung existiert bereits"-Sperre → verwaiste
Bestellung.
- Preis-Abgleich als Integer-Cent (int) round(price*100) statt Gleitkomma-!=,
das sonst falsche „different price"-Meldungen erzeugte (19,99 * 100 = 1998.99…).
- Auskommentierte API-Zugangsdaten (Mail/Passwort) aus dem Quelltext entfernt —
Passwort bitte rotieren, falls je real genutzt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bots klopfen /oauth/authorize ohne gültige OAuth-Parameter ab; Passport
wirft dann korrekt einen 4xx-Fehler. Da der Handler bei jeder gemeldeten
Exception mailt und die API ausschliesslich Personal Access Tokens nutzt
(Authorize-Flow nie legitim genutzt), war jede dieser Mails Rauschen.
OAuthServerException wandert in $dontReport – Endpoint-Verhalten bleibt
unveraendert, nur der Mail-Versand fuer diese Client-Fehler entfaellt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bestätigt, dass die Bestellannahme rein über die WP-Nummer zuordnet und
show_on nur die Anzeige steuert — Produkte „zur internen Berechnung"
sind damit API-bestellbar, ohne in Shops/Bestelllisten aufzutauchen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shop-Variationen (z. B. „10042-1") sind dasselbe Produkt mit derselben
WP-Nummer. Bei der Bestellannahme zählt für die Zuordnung nur der Teil
vor dem ersten „-"; die Original-SKU bleibt im API-Protokoll erhalten.
Leere Basis (z. B. „-1") wird nicht zugeordnet statt auf 0 zu matchen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Produkt-Speichern wird eine leere wp_number aus der Artikelnummer
(number) befüllt, reduziert auf reine Ziffern (Integer-Spalte). Die
Ableitung passiert vor der Validierung, damit die Unique-Regel greift.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Das Lösch-Formular für gespeicherte Rezeptur-Inhaltsstoffe war in das
Produkt-Formular verschachtelt; Browser verwerfen das innere <form>-Tag,
wodurch _method=DELETE ins Speichern-Formular leakte. Jetzt Button, der
per JS ein eigenes Formular außerhalb erzeugt und abschickt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
usersDetail/customersDetail (samt users/usersStore/customersStore) waren
in einem großen Kommentarblock auskommentiert — die darin ergänzten
AP-33-shipped_status_locked-Guards also wirkungslos; der aktive Guard
sitzt in detail(). Block und die bereits auskommentierten Routen
ersatzlos entfernt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Indizes auf shopping_orders.shipped/shipped_at/created_at (Board-Filter,
Tages-Kacheln) und products.wp_number (SKU-Auflösung). Die
API-Bestellungen-Seite lud das komplette JSON-payload für alle 500 Zeilen
und serialisierte es in Inline-Attribute; jetzt persistierte
positions_count, Liste ohne payload, Inhalt on-demand über show-Endpoint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Default-Scope 'recipe' blendet rezepturlose Rohstoffe aus, das
Sidebar-Badge zählt aber alle aktiven kritischen — Badge und Seite
konnten sich widersprechen. Die recipe-Ansicht zeigt jetzt einen Hinweis
mit 'Alle anzeigen', sobald das Badge mehr zählt; Empty-State-Text
scope-abhängig.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bestellnummern-Links auf admin_sales_detail (admin >= 7) waren für
Versand-Mitarbeiter tote Links (stiller Redirect) — jetzt rollenabhängig.
Kachel-Zähler und pick/ready-Filter rechnen über alle offenen
Bestellungen statt über die neuesten 500; gekappt wird nur die Anzeige,
der Hinweis-Banner zeigt 'neueste n von total' korrekt. whereDate durch
indexfähiges whereBetween ersetzt; Packlisten-Toggle über data-order-id;
Gewicht über formatNumber().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
document('combined') lief bei fehlender Alt-PDF ungeprüft in eine
PDFMerger-Exception (500); der Sammel-Druck prüfte nur den Lieferschein,
eine fehlende Rechnungs-PDF ließ den ganzen Batch platzen. Neue zentrale
InvoiceRepository::ensureFilesOnDisk() ersetzt den dreifach kopierten
Altdaten-Check (MailLogistic 2x, batchDocuments); Merge-/Response-Code im
OrderFulfillmentController zu mergedPdf()/pdfResponse() dedupliziert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
recordTransfer() löste die SKU erneut auf und markierte nur unbekannte
Artikel als Fehler — Zeilen mit gültiger SKU aber fehlender Menge/Preis
wurden verworfen und trotzdem grün protokolliert. prepareOrder() reicht
jetzt included/product_id/product_name durch; failed = Position nicht
übernommen. Entfernt zugleich die N+1-Produkt-Queries je Position.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Brücke hätte live nicht funktioniert: Connector 1.4.0 sendete die
label_url aus dem per 'deny from all' geschützten DHL-Ordner (403), dazu
SSRF-Risiko durch serverseitigen Abruf einer Client-URL und Timeout-
Mismatch (20 s Download vs. 5 s WordPress-Default). Der Connector liest
die PDF jetzt vom Shop-Dateisystem (realpath-Pinning auf wp-uploads) und
sendet sie Base64; storeWpLabel() validiert und speichert ohne Http::get;
tote Shop-Link-Fallbacks aus den Views entfernt; Connector-Timeout 30 s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Auto-Storno der Zahlungserinnerung schrieb shipped=10 direkt und rief
nur syncSaleStock() — Margen-Storno-Flag, pending_to/shipped_at-Reset und
Promotions-/Guthaben-Folgen fehlten. Die Partnerprovision einer
versendeten, nie bezahlten Bestellung wäre zahlbar geblieben.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Schutz historischer Bestellungen hing an shipped_at, das der
OrderStatusService beim Status-Toggle nullt und neu stempelt — Storno +
erneutes Versenden einer Alt-Bestellung hätte rückwirkend vom heutigen
Bestand abgezogen. Migration mit einmaligem Backfill (shipped_at vor
16.07.2026), Guard prüft nur noch das Flag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
compose_label_data() liest das Meta-Feld _pr_shipment_dhl_label_tracking
(DHL for WooCommerce); write_order_items() schickt Label-URL + Sendungsnummer
beim wp/order-Transfer mit. Neuer Listener auf pr_save_dhl_label_tracking
reicht Labels nach, die erst nach der Übertragung erstellt werden (nur bei
bereits übertragenen Bestellungen, via neuem wp/label-Endpoint).
Connector-Doku auf die konkrete Umsetzung aktualisiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bestell-Übertragung (wp/order) akzeptiert wp_label_url + wp_tracking_number:
Label-PDF wird als lokale Kopie im privaten Storage gespeichert (Shop-URL ist
öffentlich erratbar; Kopie überlebt Löschung im Shop), Sendungsnummer landet
in shopping_orders.tracking. Neuer Endpoint wp/label zum Nachreichen
(Connector-Hook pr_save_dhl_label_tracking), wp/status liefert die
Sendungsnummer an den Shop zurück. Abwicklungs-Board + Bestell-Details zeigen
Label-Download (copyreader-Dokumentroute type=label, Fallback Shop-Link) und
Sendungsnummer. Download-Fehler blockieren die Übertragung nie.
Doku: Connector-Update-Anleitung (dev/product management), Hinweise,
Testleitfaden §11, Plan-Protokoll. pint.json schließt dev/ (Fremdcode) aus.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nachtrag zum Lieferschein-Fix (7d77314): Fehlte die Rechnungs-PDF auf der
Platte (Altdaten), brach MailLogistic::build() still ab — die Mail ging ohne
Anhänge bzw. gar nicht raus, obwohl das UI Erfolg meldete. Jetzt wird die
Rechnung wie der Lieferschein mit bestehender Rechnungsnummer regeneriert.
Hinweise-Doku und Plan-Protokoll fortgeschrieben.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kundenmeldung 16.07.2026: Fehlversand an die Rechnungsadresse, weil der
Lieferschein (mit der Lieferadresse) in der Versand-Mail fehlte. Ursache:
MailLogistic hängte ihn nur bei White-Label-Bestellungen an. Jetzt wird der
Lieferschein unabhängig von Logo/White-Label immer mitgesendet; fehlt die
PDF-Datei auf der Platte (Altdaten), wird sie mit bestehender Rechnungsnummer
regeneriert. Dazu tote Duplikat-Klasse app/Mail/MailLogitic.php entfernt
(Tippfehler-Dateiname, definierte dieselbe Klasse in einer Altversion ganz
ohne Lieferschein-Anhang — Kollisionsrisiko im Classmap-Autoload).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Checkbox-Auswahl im Abwicklungs-Board (Alle-auswählen, Zähler in den Buttons)
+ zwei Sammel-Aktionen: „Lieferscheine drucken" und „+ Rechnungen" — je ein
zusammengeführtes PDF (PDFMerger/FPDI) im neuen Tab zum Stapeldruck. Fehlende
Dokumente werden dabei ohne Mailversand erzeugt, auf der Platte fehlende
Altdateien mit bestehender Nummer regeneriert. API-Bestellungen sind von der
Auswahl ausgenommen (deaktivierte Checkbox, Rechnung liegt im externen Shop)
und werden in gemischter Auswahl übersprungen; max. 100 je Druck.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kundenname mit Ellipsis begrenzt (150px, iPad 110px; voller Name als Tooltip),
Zellen-Padding reduziert, Positionen-Toggle als schmale letzte Spalte —
zusammen mit den Aktionen rechts angepinnt, beim Scrollen bleibt beides sichtbar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9 → 6 Spalten (Datum unter Bestellnr., Gewicht in die Packliste, Zahlung in
die Status-Spalte); Aktionen-Spalte sticky am rechten Rand (bleibt beim
horizontalen Scrollen sichtbar); unterhalb Desktop-Breite Icon-Buttons ohne
Beschriftung (Tooltip bleibt).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inkl. dokumentationspflichtiger Regel (Kundenwunsch): WaWi-Status hat Vorrang,
Detailseiten überschreiben ihn nicht mehr automatisch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer Nav-Punkt „Bestellungen" (Abwicklung + API-Bestellungen als Unterpunkte).
Board für Versand-Mitarbeiter (copyreader): 4 Filter-Kacheln (heute eingegangen /
zu konfektionieren / versandfertig / heute versendet), Packliste je Bestellung
(Sets mit Komponenten), Dokumente (Rechnung/Lieferschein/Kombi-Download über
eigene copyreader-Route, Erstellen ohne Mailversand; API-Bestellungen verlinken
die externe Rechnung), Aktionen Konfektioniert/Versendet (nur vorwärts, Storno
bleibt Verkäufe/admin). Versandfertig-Regel per Kundenentscheid: Rechnung sofort,
Vorkasse nach Zahlungseingang, API immer (ShoppingOrder::isReadyToShip()).
Statuswechsel-Logik in OrderStatusService extrahiert (Verkäufe-Modal + Board
teilen Transaktion/Lock/Margin-Folgen/AP-13-Abzug). Kundenentscheid Punkt 3:
Board-Statuswechsel setzt shipped_status_locked — die Bestell-Detailseiten
ändern den Status dann nicht mehr automatisch (offen → in Bearbeitung).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kundenanforderung 16.07.2026 als AP-33a/b/c in Plan §4 aufgenommen:
Abwicklungs-Board (Konfektionierung, Dokumente, Versand-Klick), Sammel-PDFs
(Lieferscheine/Rechnungen/Etiketten), Etiketten-Integration mit AP-32;
Klärungspunkte für den Kunden dokumentiert, Roadmap neu nummeriert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Erneutes Speichern des Versandstatus einer Alt-Bestellung (shipped_at vor
16.07.2026) hätte rückwirkend vom heutigen Bestand abgezogen. syncSaleStock()
überspringt historische Bestellungen jetzt per Stichtag SALE_STOCK_SINCE.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer Navigationspunkt „API-Bestellungen": jede wp/order-Übertragung wird
protokolliert (api_order_logs) — auch abgelehnte (Kunde unbekannt, Bestellung
existiert bereits, Speicherfehler). Positionen ohne Produktzuordnung
(unbekannte WP-Nummer) markieren den Eintrag rot; das Modal zeigt den Inhalt
der Übertragung je Position (SKU, Produkt, Menge, Preis, Meldung übersetzt).
Dazu SKU-Konsistenzprüfung auf der Seite: doppelte WP-Nummern aktiver Produkte
(Warnung) und aktive Produkte ohne WP-Nummer (aufklappbar). Behebt die stille
Lücke, dass „article not found" nur in der API-Antwort unterging und die
Position kommentarlos in Bestellung und Bestandsabzug fehlte (Plan §4).
ShoppingUserController per Pint formatiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ProductStockService::syncSaleStock(): idempotenter Differenz-Abgleich der
Verkaufs-Abgänge (source='sale', Referenz = Bestellung) mit dem Versandstatus —
Abzug je Bestellposition bei versendet/abgeschlossen, Sets rekursiv über
product_set_items in Einzelprodukte aufgelöst; Zurücksetzen/Storno führt per
Gegenbuchung zurück (behebt auch das Doppelabzug-Risiko Versand→Zurücksetzen→
Versand). Andockpunkte: SalesController::store (in der Transaktion) und
PaymentReminderService (Auto-Storno per Cron). Verbrauch/Monat zählt
Verkaufs-Abgänge automatisch mit (source != production).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vorbereitung AP-13: Versand-Statuswechsel validiert Eingaben (Status aus
shippedTypes, Action-Whitelist), läuft in DB::transaction mit lockForUpdate
gegen Doppelklick/parallele Tabs. Verhalten sonst unverändert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kundenanforderung 15.07.: Versand komplett im System inkl. Label-Erstellung
ueber die DHL Parcel DE Shipping API. Gleicher Andockpunkt wie AP-13
(Versand-Statuswechsel). AP-13-Ansatz vom Kunden bestaetigt.
Klaerungspunkte (DHL-Konto, Versandprodukte, CH-Zoll, Druck-Setup) notiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugin-Trigger verifiziert (Kundendaten automatisch, Warenkorb per
Fulfillment-Button, Status per Cron-Poll). Bestandsabzug wird reiner
Serverseiten-Hook am Versand-Statuswechsel, kein Plugin-Update noetig.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der in den Partner-Shops installierte WooCommerce-Connector, der Bestellungen
per REST an /api/wp/* uebertraegt (Kunde anlegen, Warenkorb, Status-Abgleich).
Grundlage fuer AP-13 (Shop-Bestandsabzug beim Versand).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>