Warenwirtschaft: F-07 — Verpackungsvorschau aus dem Produktionsergebnis
Stückliste je Ergebnisprodukt wird ins Formular gegeben; die Vorschau rechnet Outputs × Stückliste (wie die Buchung) und reagiert auf Hinzufügen/Entfernen, Produkt- und Mengenwechsel. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
122d28bc4f
commit
fd1572df35
3 changed files with 49 additions and 14 deletions
|
|
@ -285,12 +285,23 @@ class ProductionController extends Controller
|
|||
$existingOutputIds = $production?->outputs?->pluck('product_id')->map(fn ($id) => (int) $id)->all() ?? [];
|
||||
|
||||
$outputProducts = Product::query()
|
||||
->with('packagings:id,name')
|
||||
->where(fn ($q) => $q->where('active', 1)->where('is_set', false))
|
||||
->when($existingOutputIds !== [], fn ($q) => $q->orWhereIn('id', $existingOutputIds))
|
||||
->orderBy('name')
|
||||
->get($columns);
|
||||
|
||||
return ['products' => $products, 'outputProducts' => $outputProducts];
|
||||
// F-07: Verpackungs-Stückliste je Ergebnisprodukt für die Vorschau im Browser —
|
||||
// dieselbe Basis wie die Buchung (syncPackagingSnapshot: Outputs × Stückliste).
|
||||
$packagingBom = $outputProducts
|
||||
->mapWithKeys(fn (Product $p) => [(int) $p->id => $p->packagings->map(fn ($pk) => [
|
||||
'id' => (int) $pk->id,
|
||||
'name' => $pk->name,
|
||||
'per_unit' => (float) ($pk->pivot->quantity ?? 1),
|
||||
])->values()->all()])
|
||||
->all();
|
||||
|
||||
return ['products' => $products, 'outputProducts' => $outputProducts, 'packagingBom' => $packagingBom];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
|
||||
{{-- AP-41: Verpackungs-Vorschau direkt unter die INCI-Tabelle — man sieht auf
|
||||
einen Blick, was zusätzlich zu den Rohstoffen gebraucht wird. --}}
|
||||
<h6>{{ __('Verpackung (Vorschau)') }}</h6>
|
||||
<h6>{{ __('Verpackung (Vorschau)') }} <small class="text-muted font-weight-normal">{{ __('aus dem Produktionsergebnis') }}</small></h6>
|
||||
<div class="table-responsive border rounded mb-3">
|
||||
<table class="table table-sm mb-0">
|
||||
<thead><tr><th>{{ __('Artikel') }}</th><th>{{ __('Stück gesamt') }}</th></tr></thead>
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
<div class="col-sm-3">{{ __('Chargen-Nr.') }}</div>
|
||||
<div class="col-sm-1"></div>
|
||||
</div>
|
||||
<div id="production-outputs" data-initial='@json($initialOutputs)'></div>
|
||||
<div id="production-outputs" data-initial='@json($initialOutputs)' data-packaging-bom='@json(($packagingBom ?? []) === [] ? (object) [] : $packagingBom)'></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">
|
||||
|
|
|
|||
|
|
@ -301,12 +301,7 @@
|
|||
$('#recipe-hint')
|
||||
.text('{{ __('Dieses Produkt benötigt keine Rezeptur. Es wird ohne Rohstoffverbrauch produziert.') }}')
|
||||
.removeClass('text-danger').addClass('text-muted');
|
||||
var $pkOnly = $('#recipe-packaging-preview').empty();
|
||||
(data.packagings || []).forEach(function (pk) {
|
||||
$pkOnly.append($('<tr></tr>')
|
||||
.append($('<td></td>').text(pk.name))
|
||||
.append($('<td></td>').text(pk.total_pieces)));
|
||||
});
|
||||
renderPackagingPreview();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -365,12 +360,35 @@
|
|||
.removeClass('text-danger').addClass('text-muted');
|
||||
}
|
||||
|
||||
var $pk = $('#recipe-packaging-preview').empty();
|
||||
(data.packagings || []).forEach(function (pk) {
|
||||
$pk.append($('<tr></tr>')
|
||||
.append($('<td></td>').text(pk.name))
|
||||
.append($('<td></td>').text(pk.total_pieces)));
|
||||
renderPackagingPreview();
|
||||
}
|
||||
|
||||
// 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') || {};
|
||||
function renderPackagingPreview() {
|
||||
var totals = {};
|
||||
var order = [];
|
||||
$('#production-outputs .output-row').each(function () {
|
||||
var pid = String($(this).find('.output-product').val() || '');
|
||||
var qty = parseInt($(this).find('.output-quantity').val(), 10) || 0;
|
||||
(packagingBom[pid] || []).forEach(function (pk) {
|
||||
if (!totals[pk.id]) {
|
||||
totals[pk.id] = {name: pk.name, pieces: 0};
|
||||
order.push(pk.id);
|
||||
}
|
||||
totals[pk.id].pieces += pk.per_unit * qty;
|
||||
});
|
||||
});
|
||||
var $pk = $('#recipe-packaging-preview').empty();
|
||||
order.forEach(function (id) {
|
||||
$pk.append($('<tr></tr>')
|
||||
.append($('<td></td>').text(totals[id].name))
|
||||
.append($('<td></td>').text(Math.round(totals[id].pieces))));
|
||||
});
|
||||
if (!order.length) {
|
||||
$pk.append('<tr><td colspan="2" class="text-muted">{{ __('Keine Verpackung hinterlegt.') }}</td></tr>');
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on('click', '.btn-add-split', function (e) {
|
||||
|
|
@ -482,6 +500,7 @@
|
|||
if (!data || !data.batch_number) {
|
||||
refreshBatch($row);
|
||||
}
|
||||
renderPackagingPreview();
|
||||
}
|
||||
|
||||
$('#btn-add-output').on('click', function (e) {
|
||||
|
|
@ -495,16 +514,19 @@
|
|||
return;
|
||||
}
|
||||
$(this).closest('.output-row').remove();
|
||||
renderPackagingPreview();
|
||||
});
|
||||
|
||||
$(document).on('change', '.output-product', function () {
|
||||
var $row = $(this).closest('.output-row');
|
||||
$row.data('auto', false);
|
||||
refreshBatch($row);
|
||||
renderPackagingPreview();
|
||||
});
|
||||
|
||||
$(document).on('input change', '.output-quantity', function () {
|
||||
$(this).closest('.output-row').data('auto', false);
|
||||
renderPackagingPreview();
|
||||
});
|
||||
|
||||
$(document).on('input', '.output-batch', function () {
|
||||
|
|
@ -521,6 +543,7 @@
|
|||
refreshBatch($row);
|
||||
}
|
||||
});
|
||||
renderPackagingPreview();
|
||||
});
|
||||
|
||||
$('#quantity').on('change input', function () {
|
||||
|
|
@ -531,6 +554,7 @@
|
|||
$row.find('.output-quantity').val(val || 1);
|
||||
}
|
||||
});
|
||||
renderPackagingPreview();
|
||||
});
|
||||
|
||||
$('#produced_at').on('change', function () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue