April 2026 waren Wirtschaft Feedback

This commit is contained in:
Kevin Adametz 2026-04-10 17:14:38 +02:00
parent 02f2a4c23e
commit 9ce711d6b2
167 changed files with 25278 additions and 8518 deletions

View file

@ -0,0 +1,111 @@
@php
/** @var \App\Models\StockEntry $model */
$isEdit = $model->exists;
@endphp
<div class="form-group">
<label for="entry_type">{{ __('Art') }}</label>
<select name="entry_type" id="entry_type" class="form-control @error('entry_type') is-invalid @enderror" required>
@foreach($entryTypeLabels as $value => $label)
<option value="{{ $value }}" @selected(old('entry_type', $model->entry_type ?? 'ingredient') === $value)>{{ $label }}</option>
@endforeach
</select>
@error('entry_type')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div id="stock-entry-ingredient-block" class="form-group" style="display:none;">
<label for="ingredient_id">{{ __('Inhaltsstoff') }}</label>
<div class="light-style">
<select name="ingredient_id" id="ingredient_id" class="w-100" data-search-url="{{ route('admin.inventory.api.ingredients.search') }}">
@if($model->ingredient_id && $model->ingredient)
<option value="{{ $model->ingredient_id }}" selected>{{ $model->ingredient->name }}@if($model->ingredient->inci) ({{ $model->ingredient->inci }})@endif</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="stock-entry-packaging-block" class="form-group" style="display:none;">
<label for="packaging_item_id">{{ __('Verpackungsartikel') }}</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($model->packaging_item_id && $model->packagingItem)
<option value="{{ $model->packaging_item_id }}" selected>{{ $model->packagingItem->name }}</option>
@elseif(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="supplier_id">{{ __('Lieferant') }}</label>
<select name="supplier_id" id="supplier_id" class="form-control @error('supplier_id') is-invalid @enderror" required>
<option value="">{{ __('Bitte wählen') }}</option>
@foreach($suppliers as $sup)
<option value="{{ $sup->id }}" @selected((string)old('supplier_id', $model->supplier_id) === (string)$sup->id)>{{ $sup->name }}</option>
@endforeach
</select>
@error('supplier_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="location_id">{{ __('Lagerort') }}</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', $model->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="ordered_at">{{ __('Bestelldatum') }}</label>
<input type="date" name="ordered_at" id="ordered_at" class="form-control @error('ordered_at') is-invalid @enderror"
value="{{ old('ordered_at', $model->ordered_at ? $model->ordered_at->format('Y-m-d') : '') }}" required>
@error('ordered_at')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="ordered_quantity">{{ __('Bestellte Menge') }}</label>
<input type="text" name="ordered_quantity" id="ordered_quantity" class="form-control @error('ordered_quantity') is-invalid @enderror"
value="{{ old('ordered_quantity', $model->ordered_quantity !== null ? \App\Services\Util::formatNumber($model->ordered_quantity) : '') }}" required>
<small class="text-muted">{{ __('Bei Rohstoff in Gramm, bei Verpackung in Stück.') }}</small>
@error('ordered_quantity')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div id="price-per-kg-block" class="form-group" style="display:none;">
<label for="price_per_kg">{{ __('Netto-Preis pro kg') }}</label>
<input type="text" name="price_per_kg" id="price_per_kg" class="form-control @error('price_per_kg') is-invalid @enderror"
value="{{ old('price_per_kg', $model->price_per_kg !== null ? \App\Services\Util::formatNumber($model->price_per_kg) : '') }}">
@error('price_per_kg')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div id="price-total-block" class="form-group" style="display:none;">
<label for="price_total">{{ __('Gesamtpreis netto') }}</label>
<input type="text" name="price_total" id="price_total" class="form-control @error('price_total') is-invalid @enderror"
value="{{ old('price_total', $model->price_total !== null ? \App\Services\Util::formatNumber($model->price_total) : '') }}">
@error('price_total')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>

View file

@ -0,0 +1,79 @@
<script>
(function ($) {
function toggleBlocks() {
var t = $('#entry_type').val();
var isIng = t === 'ingredient';
$('#stock-entry-ingredient-block').toggle(isIng);
$('#stock-entry-packaging-block').toggle(!isIng);
$('#price-per-kg-block').toggle(isIng);
$('#price-total-block').toggle(!isIng);
}
function initIngredientSelect2() {
var $el = $('#ingredient_id');
if ($el.data('select2')) {
$el.select2('destroy');
}
$el.select2({
theme: 'default',
width: '100%',
placeholder: '{{ __('Inhaltsstoff suchen…') }}',
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 initPackagingSelect2() {
var $el = $('#packaging_item_id');
if ($el.data('select2')) {
$el.select2('destroy');
}
$el.select2({
theme: 'default',
width: '100%',
placeholder: '{{ __('Verpackungsartikel suchen…') }}',
allowClear: true,
ajax: {
url: $el.data('search-url'),
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term || '',
entry_type: $('#entry_type').val()
};
},
processResults: function (data) {
return {results: data.results || []};
},
cache: true
},
minimumInputLength: 0
});
}
$(document).ready(function () {
toggleBlocks();
initIngredientSelect2();
initPackagingSelect2();
$('#entry_type').on('change', function () {
toggleBlocks();
$('#packaging_item_id').val(null).trigger('change');
initPackagingSelect2();
});
});
})(jQuery);
</script>

View file

@ -0,0 +1,19 @@
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">{{ __('Neuer Einkauf (Stufe 1)') }}</h4>
<div class="card">
<div class="card-body">
<form method="post" action="{{ route('admin.inventory.stock-entries.store') }}">
@csrf
@include('admin.inventory.stock-entries._form')
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
<a href="{{ route('admin.inventory.stock-entries.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
</form>
</div>
</div>
@endsection
@section('scripts')
@include('admin.inventory.stock-entries._scripts')
@endsection

View file

@ -0,0 +1,20 @@
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">{{ __('Bestellung bearbeiten') }}</h4>
<div class="card">
<div class="card-body">
<form method="post" action="{{ route('admin.inventory.stock-entries.update', $model) }}">
@csrf
@method('PUT')
@include('admin.inventory.stock-entries._form')
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
<a href="{{ route('admin.inventory.stock-entries.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
</form>
</div>
</div>
@endsection
@section('scripts')
@include('admin.inventory.stock-entries._scripts')
@endsection

View file

@ -0,0 +1,85 @@
@extends('layouts.layout-2')
@section('content')
<div class="card">
<h6 class="card-header d-flex justify-content-between align-items-center">
<span>{{ __('Wareneingang') }}</span>
@if(Auth::user()->isAdmin())
<a href="{{ route('admin.inventory.stock-entries.create') }}" class="btn btn-sm btn-primary">{{ __('Neuer Einkauf') }}</a>
@endif
</h6>
<div class="card-datatable table-responsive">
<table class="datatables-style table table-striped table-bordered">
<thead>
<tr>
<th>{{ __('Status') }}</th>
<th>{{ __('Bestellt') }}</th>
<th>{{ __('Art') }}</th>
<th>{{ __('Artikel') }}</th>
<th>{{ __('Lieferant') }}</th>
<th>{{ __('Menge') }}</th>
<th style="max-width: 80px;"></th>
</tr>
</thead>
<tbody>
@foreach($values as $row)
<tr>
<td data-sort="{{ $row->status === 'pending' ? 0 : 1 }}">
@if($row->status === 'pending')
<span class="badge badge-warning">{{ __('Offen') }}</span>
@else
<span class="badge badge-success">{{ __('Eingegangen') }}</span>
@endif
</td>
<td data-sort="{{ $row->ordered_at?->timestamp ?? 0 }}">{{ $row->ordered_at?->format('d.m.Y') }}</td>
<td>{{ $entryTypeLabels[$row->entry_type] ?? $row->entry_type }}</td>
<td>
@if($row->entry_type === 'ingredient' && $row->ingredient)
{{ $row->ingredient->name }}
@elseif($row->packagingItem)
{{ $row->packagingItem->name }}
@else
@endif
</td>
<td>{{ $row->supplier?->name ?? '—' }}</td>
<td>
@if($row->unit === 'gram')
{{ \App\Services\Util::formatNumber($row->ordered_quantity) }} g
@else
{{ \App\Services\Util::formatNumber($row->ordered_quantity, 0) }} {{ __('Stk.') }}
@endif
</td>
<td>
<a href="{{ route('admin.inventory.stock-entries.show', $row) }}" class="btn icon-btn btn-sm btn-primary" title="{{ __('Details') }}">
<span class="far fa-eye"></span>
</a>
@if(Auth::user()->isAdmin() && $row->status === 'pending')
<a href="{{ route('admin.inventory.stock-entries.edit', $row) }}" class="btn icon-btn btn-sm btn-secondary">
<span class="far fa-edit"></span>
</a>
<form action="{{ route('admin.inventory.stock-entries.destroy', $row) }}" method="post" class="d-inline"
onsubmit="return confirm(@json(__('Eintrag wirklich löschen?')));">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-link text-danger p-0" title="{{ __('Delete') }}"><i class="far fa-trash-alt"></i></button>
</form>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<script>
$(document).ready(function () {
$('.datatables-style').dataTable({
"bLengthChange": false,
"iDisplayLength": 100,
"order": [[0, "asc"], [1, "desc"]],
"language": {"url": "/js/German.json"}
});
});
</script>
@endsection

View file

@ -0,0 +1,191 @@
@php
/** @var \App\Models\StockEntry $model */
@endphp
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">{{ __('Wareneingang') }}</h4>
<div class="card mb-3">
<h6 class="card-header d-flex justify-content-between align-items-center">
<span>
@if($model->status === 'pending')
<span class="badge badge-warning">{{ __('Offen') }}</span>
@else
<span class="badge badge-success">{{ __('Eingegangen') }}</span>
@endif
</span>
<span>
<a href="{{ route('admin.inventory.stock-entries.index') }}" class="btn btn-sm btn-outline-secondary">{{ __('Zurück zur Liste') }}</a>
@if(Auth::user()->isAdmin() && $model->isPending())
<a href="{{ route('admin.inventory.stock-entries.edit', $model) }}" class="btn btn-sm btn-primary">{{ __('Bearbeiten') }}</a>
@endif
</span>
</h6>
<div class="card-body">
<dl class="row mb-0">
<dt class="col-sm-3">{{ __('Art') }}</dt>
<dd class="col-sm-9">{{ $entryTypeLabels[$model->entry_type] ?? $model->entry_type }}</dd>
<dt class="col-sm-3">{{ __('Artikel') }}</dt>
<dd class="col-sm-9">
@if($model->entry_type === 'ingredient' && $model->ingredient)
{{ $model->ingredient->name }}@if($model->ingredient->inci) ({{ $model->ingredient->inci }})@endif
@elseif($model->packagingItem)
{{ $model->packagingItem->name }}
@if($model->packagingItem->packagingMaterial)
<span class="text-muted"> {{ $model->packagingItem->packagingMaterial->name }}</span>
@endif
@else
@endif
</dd>
<dt class="col-sm-3">{{ __('Lieferant') }}</dt>
<dd class="col-sm-9">{{ $model->supplier?->name ?? '—' }}</dd>
<dt class="col-sm-3">{{ __('Lagerort') }}</dt>
<dd class="col-sm-9">{{ $model->location?->name ?? '—' }}</dd>
<dt class="col-sm-3">{{ __('Bestelldatum') }}</dt>
<dd class="col-sm-9">{{ $model->ordered_at?->format('d.m.Y') }}</dd>
<dt class="col-sm-3">{{ __('Bestellte Menge') }}</dt>
<dd class="col-sm-9">
@if($model->unit === 'gram')
{{ \App\Services\Util::formatNumber($model->ordered_quantity) }} g
@else
{{ \App\Services\Util::formatNumber($model->ordered_quantity, 0) }} {{ __('Stk.') }}
@endif
</dd>
@if(Auth::user()->isAdmin())
<dt class="col-sm-3">{{ __('Preise (Stufe 1)') }}</dt>
<dd class="col-sm-9">
@if($model->entry_type === 'ingredient')
@if($model->price_per_kg !== null)
{{ \App\Services\Util::formatNumber($model->price_per_kg) }} / kg
@else
@endif
@else
@if($model->price_total !== null)
{{ \App\Services\Util::formatNumber($model->price_total) }} {{ __('netto') }}
@else
@endif
@endif
</dd>
@endif
<dt class="col-sm-3">{{ __('Bestellt von') }}</dt>
<dd class="col-sm-9">{{ $model->orderedByUser?->getFullName(false) ?: $model->orderedByUser?->email ?? '—' }}</dd>
@if($model->isReceived())
<dt class="col-sm-3">{{ __('Eingangsdatum') }}</dt>
<dd class="col-sm-9">{{ $model->received_at?->format('d.m.Y') }}</dd>
<dt class="col-sm-3">{{ __('Eingegangene Menge') }}</dt>
<dd class="col-sm-9">
@if($model->unit === 'gram')
{{ \App\Services\Util::formatNumber($model->received_quantity) }} g
@else
{{ \App\Services\Util::formatNumber($model->received_quantity, 0) }} {{ __('Stk.') }}
@endif
</dd>
@if($model->entry_type === 'ingredient')
<dt class="col-sm-3">{{ __('Charge') }}</dt>
<dd class="col-sm-9">{{ $model->batch_number ?: '—' }}</dd>
<dt class="col-sm-3">{{ __('Mindesthaltbarkeit') }}</dt>
<dd class="col-sm-9">{{ $model->best_before?->format('d.m.Y') ?? '—' }}</dd>
<dt class="col-sm-3">{{ __('Materialqualität') }}</dt>
<dd class="col-sm-9">{{ $model->quality?->name ?? '—' }}</dd>
@endif
<dt class="col-sm-3">{{ __('Eingebucht von') }}</dt>
<dd class="col-sm-9">{{ $model->receivedByUser?->getFullName(false) ?: $model->receivedByUser?->email ?? '—' }}</dd>
@endif
</dl>
</div>
</div>
@if($model->isPending())
<div class="card">
<h6 class="card-header">{{ __('Wareneingang buchen (Stufe 2)') }}</h6>
<div class="card-body">
<form method="post" action="{{ route('admin.inventory.stock-entries.receive', $model) }}">
@csrf
@method('PUT')
<div class="form-group">
<label for="received_at">{{ __('Eingangsdatum') }}</label>
<input type="date" name="received_at" id="received_at" required
class="form-control @error('received_at') is-invalid @enderror"
value="{{ old('received_at', now()->toDateString()) }}">
@error('received_at')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="received_quantity">{{ __('Eingegangene Menge') }}</label>
<input type="text" name="received_quantity" id="received_quantity" required
class="form-control @error('received_quantity') is-invalid @enderror"
value="{{ old('received_quantity', \App\Services\Util::formatNumber($model->ordered_quantity)) }}">
<small class="text-muted">
@if($model->unit === 'gram')
{{ __('Angabe in Gramm') }}
@else
{{ __('Angabe in Stück') }}
@endif
</small>
@error('received_quantity')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
@if($model->entry_type === 'ingredient')
<div class="form-group">
<label for="batch_number">{{ __('Chargennummer') }}</label>
<input type="text" name="batch_number" id="batch_number" maxlength="100"
class="form-control @error('batch_number') is-invalid @enderror"
value="{{ old('batch_number') }}">
@error('batch_number')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="best_before">{{ __('Mindesthaltbarkeit') }}</label>
<input type="date" name="best_before" id="best_before"
class="form-control @error('best_before') is-invalid @enderror"
value="{{ old('best_before') }}">
@error('best_before')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="quality_id">{{ __('Materialqualität') }}</label>
<select name="quality_id" id="quality_id" class="form-control @error('quality_id') is-invalid @enderror">
<option value="">{{ __('Bitte wählen') }}</option>
@foreach($materialQualities as $mq)
<option value="{{ $mq->id }}" @selected((string)old('quality_id') === (string)$mq->id)>{{ $mq->name }}</option>
@endforeach
</select>
@error('quality_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
@endif
<button type="submit" class="btn btn-primary">{{ __('Als eingegangen buchen') }}</button>
</form>
</div>
</div>
@endif
@endsection