Warenwirtschaft: Rohstoffbestand — Default „Nur aus Herstellerrezepturen" (Kundenentscheid 17.07.2026)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
4f9dca88de
commit
e6af987237
5 changed files with 16 additions and 13 deletions
|
|
@ -23,7 +23,8 @@ class RawMaterialStockController extends Controller
|
|||
public function index(Request $request): View
|
||||
{
|
||||
// AP-20: Modus „alle" / „nur aus Herstellerrezepturen (aktiver Produkte)"
|
||||
$scope = $request->query('scope') === 'recipe' ? 'recipe' : 'all';
|
||||
// Kundenentscheid 17.07.2026: Default = nur Rohstoffe aus Herstellerrezepturen
|
||||
$scope = $request->query('scope') === 'all' ? 'all' : 'recipe';
|
||||
|
||||
$ingredients = Ingredient::query()
|
||||
->where('active', true)
|
||||
|
|
|
|||
|
|
@ -273,6 +273,7 @@ Der Warenkorb kommt also **per Knopfdruck** (Fulfillment-Übergabe), nicht autom
|
|||
| 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** |
|
||||
| 16.07.2026 | **Bugfix Logistik-Mail (Kundenmeldung)** | Fehlversand an die Rechnungsadresse: die Versand-Mail (`MailLogistic`) hängte den **Lieferschein nur bei White-Label-Bestellungen** an. Jetzt wird er **immer** mitgesendet (unabhängig von Logo/White-Label); fehlt die PDF-Datei auf der Platte, wird sie mit bestehender Rechnungsnummer regeneriert. Dazu **tote Duplikat-Klasse `app/Mail/MailLogitic.php` entfernt** (Tippfehler-Dateiname, definierte `MailLogistic` in einer Altversion ohne Lieferschein-Anhang — Kollisionsrisiko im Classmap-Autoload). Commit `7d77314`. **Nachtrag:** gleiche Regeneration auch für die **Rechnungs**-PDF — vorher brach `build()` bei fehlender Rechnungsdatei still ab (Mail ohne Anhänge trotz Erfolgsmeldung im UI). | Neuer `LogisticMailTest` (4 grün: Anhang ohne White-Label, Regeneration Lieferschein + Rechnung, Versand-Button). Volle Suite: **276 grün, 1016 Assertions** |
|
||||
| 17.07.2026 | **AP-32-Brückenlösung (DHL-Label aus WooCommerce übernehmen)** | Bis zur echten DHL-API-Anbindung: Das im Shop erstellte Label (Plugin „DHL for WooCommerce", Meta `_pr_shipment_dhl_label_tracking`) kommt **bei der Bestell-Übertragung mit**. `POST wp/order` akzeptiert `wp_label_url` + `wp_tracking_number` (String oder Array); das System lädt die Label-PDF als **lokale Kopie** in den privaten Storage (`wp-labels/`, Migration `2026_07_17_090000`: `shopping_orders.wp_label_url/wp_label_path`; Sendungsnummer in bestehender Spalte `tracking`) — Begründung: Shop-URL ist öffentlich + erratbar (Kundenadresse!), Kopie überlebt Löschung im Shop; Download-Fehler blockieren die Übertragung nie. **Neuer Endpoint `POST wp/label`** zum Nachreichen (Connector-Hook `pr_save_dhl_label_tracking`); `wp/status` liefert je Bestellung `tracking_number` zurück (Tracking-Link Endkunde). **Anzeige:** Abwicklungs-Board + Bestell-Details mit „Label"-Download (lokale Kopie über copyreader-Dokumentroute `type=label`, Fallback Shop-Link) + Sendungsnummer. Nötiges Connector-Update (WP-Seite) dokumentiert in `dev/product management /ap-32-brueckenloesung-connector-update.md`. Hinweise-Doku + Testleitfaden (§11) fortgeschrieben. Nebenbei: `pint.json` schließt `dev/` (Fremdcode-Referenzen) von der Formatierung aus. | Neuer `WpLabelTransferTest` (10 grün: Übertragung mit Label/Sendungsnr., Download-Fehler + Nicht-PDF blockieren nicht, Mehrpaket-Nummern, Nachreichen, unbekannte Nummer, Status-Poll, Board-Anzeige, Label-Download + 404). Volle Suite: **286 grün, 1052 Assertions** |
|
||||
| 17.07.2026 | **Kundenentscheid: Rohstoffbestand-Default „Nur aus Herstellerrezepturen"** | `RawMaterialStockController@index`: Default-Scope von `all` auf `recipe` gedreht (`?scope=all` zeigt weiterhin alles); Button-Gruppe entsprechend verlinkt, Hinweise-Doku angepasst. | `RawMaterialStockTest` angepasst (Default filtert, `scope=all` zeigt alle). Volle Suite: **286 grün, 1052 Assertions** |
|
||||
| _offen_ | AP-32 | Versand im System: DHL-Etiketten per API — **neu aufgenommen + Ansatz dokumentiert (§4, 15.07.2026)**; Klärungspunkte (DHL-Konto, Versandprodukte, Druck-Setup) für nächste Anforderungsrunde notiert. **Zwischenstand 17.07.2026: Brückenlösung aktiv** (Label aus dem Shop, s. Protokollzeile) — deckt den Versand-Flow ab, bis die DHL-Klärungen da sind | – |
|
||||
| _offen_ | AP-14/15/16/17 | Audit-Trail, Blockrechte, 2FA, WaWi-Einstellungen | – |
|
||||
|
||||
|
|
|
|||
|
|
@ -230,9 +230,10 @@
|
|||
- **INCI-Liste „nur aktive":** Der Filter zeigt nur Inhaltsstoffe, die in der
|
||||
**Hersteller-Rezeptur mindestens eines aktiven Produkts** vorkommen – nicht zu
|
||||
verwechseln mit dem Aktiv-Häkchen am INCI selbst.
|
||||
- **Rohstoffbestand-Filter:** Die Übersicht kennt zwei Modi – **„Alle"** (auch
|
||||
Rohstoffe ohne Rezeptur-Bezug, z. B. für Neuentwicklungen eingekauft) und
|
||||
**„Nur aus Herstellerrezepturen"** (aktiver Produkte). INCI mit dem Häkchen
|
||||
- **Rohstoffbestand-Filter:** Die Übersicht kennt zwei Modi –
|
||||
**„Nur aus Herstellerrezepturen"** (aktiver Produkte, **Standard** seit
|
||||
17.07.2026) und **„Alle"** (auch Rohstoffe ohne Rezeptur-Bezug, z. B. für
|
||||
Neuentwicklungen eingekauft). INCI mit dem Häkchen
|
||||
**„Kein Rohstoffbestand"** (z. B. Allergen-Angaben) erscheinen nie im
|
||||
Rohstoffbestand und zählen nicht im Kritisch-Badge.
|
||||
- **Rezeptur-Phasen:** Die Hersteller-Rezeptur ist in Phasen gegliedert
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@
|
|||
placeholder="{{ __('Rohstoff suchen …') }}">
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm ml-2" role="group" aria-label="{{ __('Rohstoff-Filter') }}">
|
||||
<a href="{{ route('admin.inventory.raw-material-stock.index') }}"
|
||||
<a href="{{ route('admin.inventory.raw-material-stock.index', ['scope' => 'all']) }}"
|
||||
class="btn {{ $scope === 'all' ? 'btn-primary' : 'btn-outline-secondary' }}">{{ __('Alle') }}</a>
|
||||
<a href="{{ route('admin.inventory.raw-material-stock.index', ['scope' => 'recipe']) }}"
|
||||
<a href="{{ route('admin.inventory.raw-material-stock.index') }}"
|
||||
class="btn {{ $scope === 'recipe' ? 'btn-primary' : 'btn-outline-secondary' }}">{{ __('Nur aus Herstellerrezepturen') }}</a>
|
||||
</div>
|
||||
<div class="wawi-toolbar__spacer"></div>
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ test('uebersicht rendert rohstoff mit bestand', function () {
|
|||
ap10MakeStock($ing, $location, $supplier, $user, ['received_quantity' => 2578]);
|
||||
|
||||
$this->actingAs($user, 'user');
|
||||
$response = $this->get(route('admin.inventory.raw-material-stock.index'));
|
||||
$response = $this->get(route('admin.inventory.raw-material-stock.index', ['scope' => 'all']));
|
||||
|
||||
$response->assertSuccessful();
|
||||
$response->assertSee('Rohstoffbestand');
|
||||
|
|
@ -283,7 +283,7 @@ test('kein-rohstoffbestand-flag blendet inci aus uebersicht und kritisch-zaehler
|
|||
expect(app(InventoryService::class)->criticalIngredientCount())->toBe(1);
|
||||
|
||||
$this->actingAs($user, 'user');
|
||||
$response = $this->get(route('admin.inventory.raw-material-stock.index'));
|
||||
$response = $this->get(route('admin.inventory.raw-material-stock.index', ['scope' => 'all']));
|
||||
|
||||
$response->assertSuccessful();
|
||||
$response->assertSee('AP20-Sichtbar');
|
||||
|
|
@ -307,18 +307,18 @@ test('modus recipe zeigt nur rohstoffe aus herstellerrezepturen aktiver produkte
|
|||
|
||||
$this->actingAs($user, 'user');
|
||||
|
||||
// Default „alle": beide sichtbar, Pills werden gerendert
|
||||
// Default (Kundenentscheid 17.07.2026): nur Rohstoffe aus Herstellerrezepturen
|
||||
$this->get(route('admin.inventory.raw-material-stock.index'))
|
||||
->assertSuccessful()
|
||||
->assertSee('AP20-InRezeptur')
|
||||
->assertSee('AP20-Neuentwicklung')
|
||||
->assertDontSee('AP20-Neuentwicklung')
|
||||
->assertSee('Nur aus Herstellerrezepturen');
|
||||
|
||||
// Modus „recipe": nur der Rezeptur-Rohstoff
|
||||
$this->get(route('admin.inventory.raw-material-stock.index', ['scope' => 'recipe']))
|
||||
// Modus „alle": beide sichtbar
|
||||
$this->get(route('admin.inventory.raw-material-stock.index', ['scope' => 'all']))
|
||||
->assertSuccessful()
|
||||
->assertSee('AP20-InRezeptur')
|
||||
->assertDontSee('AP20-Neuentwicklung');
|
||||
->assertSee('AP20-Neuentwicklung');
|
||||
});
|
||||
|
||||
test('letzter netto-preis je lieferant kommt aus dem neuesten einkauf', function () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue