Warenwirtschaft: N-04 — Verpackungsvorschau zeigt bei unveränderten Ergebnissen den gespeicherten Snapshot

Bearbeitungsformular gebuchter Produktionen liefert Snapshot und Ergebnissummen;
die Vorschau folgt derselben Regel wie die Speicherung (F-05) und weist auf eine
Neuberechnung hin, sobald sich Produktsummen ändern. Tests N-01/N-02/N-04.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-08 11:48:02 +00:00
parent 313c6277ce
commit 9acb05380a
4 changed files with 182 additions and 1 deletions

View file

@ -159,6 +159,7 @@
<table class="table table-sm mb-0">
<thead><tr><th>{{ __('Artikel') }}</th><th>{{ __('Stück gesamt') }}</th></tr></thead>
<tbody id="recipe-packaging-preview"></tbody>
<tfoot><tr><td colspan="2" class="text-muted small" id="recipe-packaging-hint"></td></tr></tfoot>
</table>
</div>
@ -197,7 +198,8 @@
<div class="col-sm-3">{{ __('Chargen-Nr.') }}</div>
<div class="col-sm-1"></div>
</div>
<div id="production-outputs" data-initial='@json($initialOutputs)' data-packaging-bom='@json(($packagingBom ?? []) === [] ? (object) [] : $packagingBom)'></div>
<div id="production-outputs" data-initial='@json($initialOutputs)' data-packaging-bom='@json(($packagingBom ?? []) === [] ? (object) [] : $packagingBom)'
data-packaging-snapshot='@json($packagingSnapshot ?? [])' data-initial-output-totals='@json(($initialOutputTotals ?? []) === [] ? (object) [] : $initialOutputTotals)'></div>
<button type="button" class="btn btn-sm btn-outline-secondary mb-3" id="btn-add-output">{{ __('+ weitere Ergebniszeile') }}</button>
<script type="text/template" id="output-row-template">

View file

@ -366,7 +366,48 @@
// F-07: Verpackungs-Vorschau aus dem Produktionsergebnis (Outputs × Stückliste),
// dieselbe Basis wie die Buchung beim Abschluss — nicht aus Planungsprodukt/-menge.
var packagingBom = $('#production-outputs').data('packaging-bom') || {};
// N-04: gespeicherter Snapshot einer gebuchten Produktion + Ergebnissummen beim Öffnen.
var packagingSnapshot = $('#production-outputs').data('packaging-snapshot') || [];
var initialOutputTotals = $('#production-outputs').data('initial-output-totals') || {};
function currentOutputTotals() {
var totals = {};
$('#production-outputs .output-row').each(function () {
var pid = String($(this).find('.output-product').val() || '');
var qty = parseInt($(this).find('.output-quantity').val(), 10) || 0;
if (pid) {
totals[pid] = (totals[pid] || 0) + qty;
}
});
return totals;
}
function sameTotals(a, b) {
var keys = Object.keys(a).concat(Object.keys(b));
for (var i = 0; i < keys.length; i++) {
if ((a[keys[i]] || 0) !== (b[keys[i]] || 0)) {
return false;
}
}
return true;
}
function renderPackagingPreview() {
var $hint = $('#recipe-packaging-hint');
if (packagingSnapshot.length > 0 && sameTotals(currentOutputTotals(), initialOutputTotals)) {
var $snap = $('#recipe-packaging-preview').empty();
packagingSnapshot.forEach(function (pk) {
$snap.append($('<tr></tr>')
.append($('<td></td>').text(pk.name))
.append($('<td></td>').text(pk.pieces)));
});
$hint.text('{{ __('Gespeicherter Verpackungsverbrauch dieser Produktion — bleibt erhalten, solange Ergebnisprodukte und Stückzahlen unverändert sind.') }}');
return;
}
$hint.text(packagingSnapshot.length > 0
? '{{ __('Ergebnis geändert — Verpackungsverbrauch wird beim Speichern mit der aktuellen Stückliste neu berechnet.') }}'
: '');
var totals = {};
var order = [];
$('#production-outputs .output-row').each(function () {