- AP-09 Produktbestand inkl. Bewegungshistorie (product_stock_movements, ProductStockService) - AP-10 Rohstoffbestand-Ansicht je Lager (RawMaterialStockController) - AP-11 Bestandsschwellen / Out-of-Stock-Handling fuer Produkte und Shop - AP-12 Ausgang/Ausschuss (stock_disposals, StockDisposalController, InventoryService) - Set-Produkte (product_set_items) inkl. Aufloesung - Produktentwicklung & Hinweise-Verwaltung (Notices) - AP-13 Entwicklungskonzept Shop-Bestandsabzug im Plan dokumentiert - Feature-Tests fuer neue Module + aktualisierter Entwicklungsplan Co-authored-by: Cursor <cursoragent@cursor.com>
194 lines
10 KiB
PHP
194 lines
10 KiB
PHP
@extends('layouts.layout-2')
|
|
|
|
@section('content')
|
|
<h4 class="font-weight-bold py-2 mb-2">{{ __('Ausgang / Ausschuss erfassen') }}</h4>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<p class="text-muted small">{{ __('Reduziert den Bestand des gewählten Rohstoffs bzw. Verpackungsartikels. Der Grund ist Pflicht und erscheint in der Ausgangsliste.') }}</p>
|
|
<form method="post" action="{{ route('admin.inventory.stock-disposals.store') }}">
|
|
@csrf
|
|
|
|
<div class="form-group">
|
|
<label for="disposal_type">{{ __('Art') }} <span class="text-danger">*</span></label>
|
|
<select name="disposal_type" id="disposal_type" class="form-control" required>
|
|
<option value="ingredient" @selected(old('disposal_type', $prefill['disposal_type']) === 'ingredient')>{{ __('Rohstoff') }}</option>
|
|
<option value="packaging" @selected(old('disposal_type', $prefill['disposal_type']) === 'packaging')>{{ __('Verpackung') }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div id="disposal-ingredient-block" class="form-group" style="display:none;">
|
|
<label for="ingredient_id">{{ __('Rohstoff') }} <span class="text-danger">*</span></label>
|
|
<div class="light-style">
|
|
<select name="ingredient_id" id="ingredient_id" class="w-100"
|
|
data-search-url="{{ route('admin.inventory.api.ingredients.search') }}"
|
|
data-charges-url="{{ route('admin.inventory.api.disposals.ingredient-charges', ['ingredient' => '__ID__']) }}">
|
|
@if ($prefill['ingredient_id'])
|
|
<option value="{{ $prefill['ingredient_id'] }}" selected>{{ $prefill['ingredient_label'] }}</option>
|
|
@elseif(old('ingredient_id'))
|
|
<option value="{{ old('ingredient_id') }}" selected>{{ old('ingredient_id') }}</option>
|
|
@endif
|
|
</select>
|
|
</div>
|
|
@error('ingredient_id')
|
|
<div class="text-danger small">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div id="disposal-charge-block" class="form-group" style="display:none;">
|
|
<label for="stock_entry_id">{{ __('Charge') }} <span class="text-muted small">({{ __('optional') }})</span></label>
|
|
<select name="stock_entry_id" id="stock_entry_id" class="form-control">
|
|
<option value="">{{ __('— keine bestimmte Charge —') }}</option>
|
|
</select>
|
|
<small class="text-muted">{{ __('Bei Auswahl wird der Lagerort automatisch gesetzt.') }}</small>
|
|
</div>
|
|
|
|
<div id="disposal-packaging-block" class="form-group" style="display:none;">
|
|
<label for="packaging_item_id">{{ __('Verpackungsartikel') }} <span class="text-danger">*</span></label>
|
|
<div class="light-style">
|
|
<select name="packaging_item_id" id="packaging_item_id" class="w-100"
|
|
data-search-url="{{ route('admin.inventory.api.packaging-items.search') }}">
|
|
@if (old('packaging_item_id'))
|
|
<option value="{{ old('packaging_item_id') }}" selected>{{ old('packaging_item_id') }}</option>
|
|
@endif
|
|
</select>
|
|
</div>
|
|
@error('packaging_item_id')
|
|
<div class="text-danger small">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="location_id">{{ __('Lagerort') }} <span class="text-danger">*</span></label>
|
|
<select name="location_id" id="location_id" class="form-control @error('location_id') is-invalid @enderror" required>
|
|
<option value="">{{ __('Bitte wählen') }}</option>
|
|
@foreach ($locations as $loc)
|
|
<option value="{{ $loc->id }}" @selected((string) old('location_id') === (string) $loc->id)>{{ $loc->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
@error('location_id')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="quantity">{{ __('Menge') }} <span class="text-danger">*</span></label>
|
|
<input type="text" name="quantity" id="quantity" autocomplete="off"
|
|
class="form-control @error('quantity') is-invalid @enderror" value="{{ old('quantity') }}" required>
|
|
<small class="text-muted" id="quantity-hint">{{ __('Bei Rohstoff in Gramm, bei Verpackung in Stück.') }}</small>
|
|
@error('quantity')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="reason">{{ __('Grund') }} <span class="text-danger">*</span></label>
|
|
<select name="reason" id="reason" class="form-control @error('reason') is-invalid @enderror" required>
|
|
@foreach ($reasons as $reason)
|
|
<option value="{{ $reason }}" @selected(old('reason') === $reason)>{{ $reason }}</option>
|
|
@endforeach
|
|
</select>
|
|
@error('reason')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="note">{{ __('Hinweis') }}</label>
|
|
<input type="text" name="note" id="note" maxlength="255" autocomplete="off"
|
|
class="form-control @error('note') is-invalid @enderror" value="{{ old('note') }}">
|
|
@error('note')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="disposed_at">{{ __('Datum') }} <span class="text-danger">*</span></label>
|
|
<input type="text" name="disposed_at" id="disposed_at" autocomplete="off"
|
|
class="form-control datepicker-base @error('disposed_at') is-invalid @enderror"
|
|
value="{{ old('disposed_at', now()->format('d.m.Y')) }}" required>
|
|
@error('disposed_at')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary">{{ __('Buchen') }}</button>
|
|
<a href="{{ route('admin.inventory.stock-disposals.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
(function ($) {
|
|
function toggleBlocks() {
|
|
var isIng = $('#disposal_type').val() === 'ingredient';
|
|
$('#disposal-ingredient-block').toggle(isIng);
|
|
$('#disposal-charge-block').toggle(isIng);
|
|
$('#disposal-packaging-block').toggle(!isIng);
|
|
$('#quantity-hint').text(isIng
|
|
? '{{ __('Menge in Gramm.') }}'
|
|
: '{{ __('Menge in Stück.') }}');
|
|
}
|
|
|
|
function initSearchSelect2(id, placeholder) {
|
|
var $el = $('#' + id);
|
|
if ($el.data('select2')) {
|
|
$el.select2('destroy');
|
|
}
|
|
$el.select2({
|
|
theme: 'default',
|
|
width: '100%',
|
|
placeholder: placeholder,
|
|
allowClear: true,
|
|
ajax: {
|
|
url: $el.data('search-url'),
|
|
dataType: 'json',
|
|
delay: 250,
|
|
data: function (params) { return {q: params.term || ''}; },
|
|
processResults: function (data) { return {results: data.results || []}; },
|
|
cache: true
|
|
},
|
|
minimumInputLength: 1
|
|
});
|
|
}
|
|
|
|
function loadCharges(ingredientId) {
|
|
var $charge = $('#stock_entry_id');
|
|
$charge.empty().append($('<option>').val('').text('{{ __('— keine bestimmte Charge —') }}'));
|
|
if (!ingredientId) {
|
|
return;
|
|
}
|
|
var url = $('#ingredient_id').data('charges-url').replace('__ID__', ingredientId);
|
|
$.getJSON(url, function (data) {
|
|
(data.charges || []).forEach(function (c) {
|
|
$charge.append($('<option>').val(c.id).text(c.text).attr('data-location', c.location_id));
|
|
});
|
|
});
|
|
}
|
|
|
|
$(document).ready(function () {
|
|
toggleBlocks();
|
|
initSearchSelect2('ingredient_id', '{{ __('Rohstoff suchen…') }}');
|
|
initSearchSelect2('packaging_item_id', '{{ __('Verpackungsartikel suchen…') }}');
|
|
|
|
$('#disposal_type').on('change', toggleBlocks);
|
|
|
|
$('#ingredient_id').on('change', function () {
|
|
loadCharges($(this).val());
|
|
});
|
|
|
|
$('#stock_entry_id').on('change', function () {
|
|
var loc = $(this).find('option:selected').data('location');
|
|
if (loc) {
|
|
$('#location_id').val(String(loc));
|
|
}
|
|
});
|
|
|
|
@if ($prefill['ingredient_id'])
|
|
loadCharges('{{ $prefill['ingredient_id'] }}');
|
|
@endif
|
|
});
|
|
})(jQuery);
|
|
</script>
|
|
@endsection
|