Warenwirtschaft: F-04 — Rezeptur-Phase an Verbrauchszeilen, keine Vervielfachung beim Wiederöffnen

production_ingredients.recipe_phase_id; Formular sendet die Phase je Zeile,
Vorbelegung je Rohstoff|Phase. Altbestand ohne Phase wird nur einmal eingesetzt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-08 10:54:59 +00:00
parent 859b1f083d
commit 104671e929
8 changed files with 109 additions and 3 deletions

View file

@ -5,6 +5,7 @@
var excludeProductionId = @json($excludeProductionId ?? null);
var lineIndex = 0;
var legacyLinesUsed = {};
var recipeIngredients = [];
// AP-35: Umrechnung Anteil (%) → Gramm/Stück (Füllgewicht / 100; 1,0 ohne Basis).
var recipeGramScale = 1;
@ -83,6 +84,8 @@
var $colSelect = $('<div class="col-12 col-sm-7 mb-1"></div>');
$colSelect.append($('<input type="hidden" name="ingredient_lines[' + idx + '][ingredient_id]">').val(ing.id));
// F-04: Phase mitsenden, damit die Zeile beim Wiederöffnen in derselben Phase landet.
$colSelect.append($('<input type="hidden" name="ingredient_lines[' + idx + '][recipe_phase_id]">').val(ing.phase_id != null ? ing.phase_id : ''));
$colSelect.append(buildStockSelect(idx, ing.batches, preselectedBatchKey));
$row.append($colSelect);
@ -264,7 +267,15 @@
$wrap.append('<button type="button" class="btn btn-sm btn-outline-secondary btn-add-split mt-1">{{ __('Weitere Charge') }}</button>');
$container.append($wrap);
var existing = existingLines[String(ing.id)] || [];
// F-04: Vorbelegung je Rohstoff|Phase. Altbestand ohne Phase (Schlüssel „id|“)
// wird nur einmal — beim ersten Vorkommen des Rohstoffs — eingesetzt.
var phaseKey = String(ing.id) + '|' + (ing.phase_id != null ? String(ing.phase_id) : '');
var legacyKey = String(ing.id) + '|';
var existing = existingLines[phaseKey] || [];
if (!existing.length && phaseKey !== legacyKey && existingLines[legacyKey] && !legacyLinesUsed[legacyKey]) {
existing = existingLines[legacyKey];
legacyLinesUsed[legacyKey] = true;
}
if (existing.length > 0) {
existing.forEach(function (ex) {
addIngredientRow($wrap, ing, ex.batch_key, ex.quantity_used);
@ -280,6 +291,7 @@
recipeGramScale = data.recipe_gram_scale != null ? data.recipe_gram_scale : 1;
$('#recipe-ingredient-lines').empty();
lineIndex = 0;
legacyLinesUsed = {};
if (data.recipe_required === false) {
$('#recipe-warning').hide();

View file

@ -21,8 +21,9 @@
@section('scripts')
@php
// AP-27: Zeilen je Charge (batch_key) zusammenfassen — mehrere Einkäufe derselben Charge = eine Formularzeile.
// F-04: Schlüssel = Rohstoff|Phase, damit ein Rohstoff in zwei Phasen je Phase seinen Anteil behält.
$existingLines = $model
? $model->productionIngredients->groupBy('ingredient_id')->map(function ($lines) {
? $model->productionIngredients->groupBy(fn ($l) => $l->formGroupKey())->map(function ($lines) {
return $lines
->groupBy(fn ($l) => $l->formBatchKey())
->map(fn ($group, $key) => ['batch_key' => $key, 'quantity_used' => (float) $group->sum('quantity_used')])

View file

@ -29,7 +29,8 @@
@section('scripts')
@php
// AP-27: Zeilen je Charge (batch_key) zusammenfassen — mehrere Einkäufe derselben Charge = eine Formularzeile.
$existingLines = $model->productionIngredients->groupBy('ingredient_id')->map(function ($lines) {
// F-04: Schlüssel = Rohstoff|Phase, damit ein Rohstoff in zwei Phasen je Phase seinen Anteil behält.
$existingLines = $model->productionIngredients->groupBy(fn ($l) => $l->formGroupKey())->map(function ($lines) {
return $lines
->groupBy(fn ($l) => $l->formBatchKey())
->map(fn ($group, $key) => ['batch_key' => $key, 'quantity_used' => (float) $group->sum('quantity_used')])