Warenwirtschaft: N-01/N-03/N-05 — Entwurfsmenge ohne Charge, Snapshot-Signatur je Produkt, Alt-Ausschuss in Chargenverfügbarkeit
- N-01: Ist-Menge ohne gewählte Charge bleibt im Entwurf erhalten (Filter in Request und Service, formBatchKey liefert '' für chargenlose Zeilen). - N-03: outputSignature summiert Stückzahlen je Produkt — ein Chargensplit ersetzt den historischen Verpackungs-Snapshot nicht mehr. - N-05: Ausschuss ohne Chargenbezug (Altbestand) wird für die Verfügbarkeit je Standort FEFO auf die Chargen angerechnet (applyUnboundDisposals, lesend); Chargen-Ausschussprüfung nutzt dieselbe Verfügbarkeit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
520d4e2deb
commit
313c6277ce
8 changed files with 138 additions and 23 deletions
|
|
@ -98,14 +98,17 @@ class StoreProductionRequest extends FormRequest
|
|||
|
||||
// AP-43: Im Entwurf dürfen Zeilen unvollständig sein — nur solche mit
|
||||
// Rohstoff + (Charge oder Wareneingang) bzw. Ergebnis-Produkt übernehmen.
|
||||
$ingredientLines = array_values(array_filter($data['ingredient_lines'] ?? [], function ($line): bool {
|
||||
// N-01 (Nachprüfung 08.09.2026): Im Entwurf zählt auch eine Ist-Menge ohne
|
||||
// gewählte Charge als Arbeitsstand; beim Abschluss verlangen die Regeln die Charge.
|
||||
$isDraft = $this->isDraft();
|
||||
$ingredientLines = array_values(array_filter($data['ingredient_lines'] ?? [], function ($line) use ($isDraft): bool {
|
||||
return is_array($line)
|
||||
&& (int) ($line['ingredient_id'] ?? 0) > 0
|
||||
&& (! empty($line['batch_key']) || (int) ($line['stock_entry_id'] ?? 0) > 0);
|
||||
&& (! empty($line['batch_key']) || (int) ($line['stock_entry_id'] ?? 0) > 0
|
||||
|| ($isDraft && trim((string) ($line['quantity_used'] ?? '')) !== ''));
|
||||
}));
|
||||
|
||||
// F-03: Im Entwurf zählt ein gewähltes Ergebnisprodukt auch ohne Stückzahl als Arbeitsstand.
|
||||
$isDraft = $this->isDraft();
|
||||
$outputs = array_values(array_filter($data['outputs'] ?? [], function ($output) use ($isDraft): bool {
|
||||
return is_array($output)
|
||||
&& (int) ($output['product_id'] ?? 0) > 0
|
||||
|
|
@ -128,7 +131,8 @@ class StoreProductionRequest extends FormRequest
|
|||
if (! empty($line['batch_key'])) {
|
||||
$out['batch_key'] = (string) $line['batch_key'];
|
||||
} else {
|
||||
$out['stock_entry_id'] = (int) $line['stock_entry_id'];
|
||||
// N-01: im Entwurf darf beides fehlen (Menge ohne Charge).
|
||||
$out['stock_entry_id'] = (int) ($line['stock_entry_id'] ?? 0);
|
||||
}
|
||||
|
||||
return $out;
|
||||
|
|
|
|||
|
|
@ -113,8 +113,10 @@ class StoreStockDisposalRequest extends FormRequest
|
|||
return;
|
||||
}
|
||||
|
||||
$consumed = app(ProductionService::class)->consumedByStockEntry([$entry->id])[$entry->id] ?? 0.0;
|
||||
$remaining = round((float) $entry->received_quantity - $consumed, 2);
|
||||
// N-05: Verfügbarkeit der Charge wie in der Produktion (inkl. FEFO-Anrechnung von Alt-Ausschuss ohne Charge).
|
||||
$available = app(ProductionService::class)->availableStockEntriesForIngredient($ingredientId, (int) $entry->location_id)
|
||||
->firstWhere('id', $entry->id);
|
||||
$remaining = $available !== null ? round((float) $available->getAttribute('remaining_quantity'), 2) : 0.0;
|
||||
if ($quantity > $remaining) {
|
||||
$validator->errors()->add('quantity', __('Die Menge (:qty g) übersteigt den Restbestand der Charge (:rest g).', [
|
||||
'qty' => number_format($quantity, 2, ',', '.'),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue