April 2026 waren Wirtschaft Feedback
This commit is contained in:
parent
02f2a4c23e
commit
9ce711d6b2
167 changed files with 25278 additions and 8518 deletions
35
resources/views/admin/inventory/locations/form.blade.php
Normal file
35
resources/views/admin/inventory/locations/form.blade.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Lagerort bearbeiten') : __('Lagerort anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.locations.update', $model) : route('admin.inventory.locations.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" name="active" value="1" class="custom-control-input"
|
||||
@checked(old('active', $model->active))>
|
||||
<span class="custom-control-label">{{ __('Aktiv') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.locations.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
60
resources/views/admin/inventory/locations/index.blade.php
Normal file
60
resources/views/admin/inventory/locations/index.blade.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Lagerorte') }}</span>
|
||||
<a href="{{ route('admin.inventory.locations.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.locations.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td data-sort="{{ $value->active ? 1 : 0 }}">
|
||||
@if($value->active)
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i></span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.locations.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@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>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Rohstoffqualität bearbeiten') : __('Rohstoffqualität anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.material-qualities.update', $model) : route('admin.inventory.material-qualities.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pos">{{ __('Pos') }}</label>
|
||||
<input type="number" name="pos" id="pos" class="form-control @error('pos') is-invalid @enderror"
|
||||
value="{{ old('pos', $model->pos) }}" min="0" max="255">
|
||||
@error('pos')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.material-qualities.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Rohstoffqualität') }}</span>
|
||||
<a href="{{ route('admin.inventory.material-qualities.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Pos') }}</th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.material-qualities.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->pos }}</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.material-qualities.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-link text-danger p-0"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
108
resources/views/admin/inventory/packaging-items/form.blade.php
Normal file
108
resources/views/admin/inventory/packaging-items/form.blade.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
@php
|
||||
$isShipping = ($category ?? 'packaging') === 'shipping';
|
||||
$pageLabel = $isShipping ? __('Versandverpackung') : __('Produktverpackung');
|
||||
@endphp
|
||||
|
||||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? $pageLabel . ' ' . __('bearbeiten') : $pageLabel . ' ' . __('anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.packaging-items.update', $model) : route('admin.inventory.packaging-items.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<input type="hidden" name="category" value="{{ old('category', $model->category) }}">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="packaging_material_id">{{ __('Verpackungsmaterial') }}</label>
|
||||
<div class="light-style">
|
||||
<select name="packaging_material_id" id="packaging_material_id" class="w-100 @error('packaging_material_id') is-invalid @enderror" required>
|
||||
<option value="">{{ __('Bitte wählen') }}</option>
|
||||
@foreach($packagingMaterials as $pm)
|
||||
<option value="{{ $pm->id }}" @selected((string)old('packaging_material_id', $model->packaging_material_id) === (string)$pm->id)>{{ $pm->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@error('packaging_material_id')
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="weight_grams">{{ __('Gewicht (g)') }}</label>
|
||||
<input type="text" name="weight_grams" id="weight_grams" class="form-control @error('weight_grams') is-invalid @enderror"
|
||||
value="{{ old('weight_grams', $model->weight_grams) }}">
|
||||
@error('weight_grams')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="min_stock_alert">{{ __('Mindestbestand Warnung') }}</label>
|
||||
<input type="number" name="min_stock_alert" id="min_stock_alert" class="form-control @error('min_stock_alert') is-invalid @enderror"
|
||||
value="{{ old('min_stock_alert', $model->min_stock_alert) }}" min="0">
|
||||
@error('min_stock_alert')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="supplier_id">{{ __('Lieferant') }}</label>
|
||||
<div class="light-style">
|
||||
<select name="supplier_id" id="supplier_id" class="w-100 @error('supplier_id') is-invalid @enderror">
|
||||
<option value="">{{ __('—') }}</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>
|
||||
</div>
|
||||
@error('supplier_id')
|
||||
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="url">{{ __('URL (Onlineshop)') }}</label>
|
||||
<input type="url" name="url" id="url" class="form-control @error('url') is-invalid @enderror"
|
||||
value="{{ old('url', $model->url) }}" placeholder="https://">
|
||||
@error('url')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" name="active" value="1" class="custom-control-input"
|
||||
@checked(old('active', $model->active))>
|
||||
<span class="custom-control-label">{{ __('Aktiv') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.packaging-items.index', ['category' => $category ?? 'packaging']) }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#supplier_id, #packaging_material_id').select2({theme: 'default', width: '100%'});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ $pageTitle }}</span>
|
||||
<a href="{{ route('admin.inventory.packaging-items.create', ['category' => $category]) }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th>{{ __('Material') }}</th>
|
||||
<th>{{ __('Gewicht (g)') }}</th>
|
||||
<th>{{ __('Lieferant') }}</th>
|
||||
<th>{{ __('URL') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.packaging-items.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td>{{ $value->packagingMaterial?->name ?? '—' }}</td>
|
||||
<td>{{ $value->weight_grams }}</td>
|
||||
<td>{{ $value->supplier?->name ?? '—' }}</td>
|
||||
<td>
|
||||
@if($value->url)
|
||||
<a href="{{ $value->url }}" target="_blank" title="{{ $value->url }}"><i class="fa fa-external-link-alt"></i></a>
|
||||
@else
|
||||
—
|
||||
@endif
|
||||
</td>
|
||||
<td data-sort="{{ $value->active ? 1 : 0 }}">
|
||||
@if($value->active)
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i></span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.packaging-items.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-link text-danger p-0"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Verpackungsmaterial bearbeiten') : __('Verpackungsmaterial anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.packaging-materials.update', $model) : route('admin.inventory.packaging-materials.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pos">{{ __('Pos') }}</label>
|
||||
<input type="number" name="pos" id="pos" class="form-control @error('pos') is-invalid @enderror"
|
||||
value="{{ old('pos', $model->pos) }}" min="0" max="255">
|
||||
@error('pos')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.packaging-materials.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Verpackungsmaterial') }}</span>
|
||||
<a href="{{ route('admin.inventory.packaging-materials.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Pos') }}</th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.packaging-materials.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->pos }}</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.packaging-materials.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-link text-danger p-0"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
191
resources/views/admin/inventory/productions/create.blade.php
Normal file
191
resources/views/admin/inventory/productions/create.blade.php
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<h4 class="font-weight-bold py-2 mb-2">{{ __('Neue Produktion') }}</h4>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ route('admin.inventory.productions.store') }}" id="form-production">
|
||||
@csrf
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="product_id">{{ __('Produkt') }}</label>
|
||||
<select name="product_id" id="product_id" class="form-control @error('product_id') is-invalid @enderror" required>
|
||||
<option value="">{{ __('Bitte wählen') }}</option>
|
||||
@foreach($products as $p)
|
||||
<option value="{{ $p->id }}" @selected(old('product_id', $model?->product_id) == $p->id)>{{ $p->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('product_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="location_id">{{ __('Lagerort / Produktionsstandort') }}</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(old('location_id', $model?->location_id ?? $defaultLocationId) == $loc->id)>{{ $loc->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('location_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-4">
|
||||
<label for="produced_at">{{ __('Produktionsdatum') }}</label>
|
||||
<input type="date" name="produced_at" id="produced_at" class="form-control @error('produced_at') is-invalid @enderror"
|
||||
value="{{ old('produced_at', now()->toDateString()) }}" required>
|
||||
@error('produced_at')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="quantity">{{ __('Produzierte Stückzahl') }}</label>
|
||||
<input type="number" name="quantity" id="quantity" min="1" step="1" class="form-control @error('quantity') is-invalid @enderror"
|
||||
value="{{ old('quantity', $model?->quantity ?? 1) }}" required>
|
||||
@error('quantity')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="recipe-area" class="mb-3" style="display:none;">
|
||||
<hr>
|
||||
<h6>{{ __('Chargen zuordnen') }}</h6>
|
||||
<p class="text-muted small" id="recipe-hint"></p>
|
||||
<div id="recipe-ingredient-lines"></div>
|
||||
@error('ingredient_lines')
|
||||
<div class="text-danger small">{{ $message }}</div>
|
||||
@enderror
|
||||
|
||||
<h6 class="mt-3">{{ __('Verpackung (Vorschau)') }}</h6>
|
||||
<div class="table-responsive border rounded">
|
||||
<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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">{{ __('Notizen') }}</label>
|
||||
<textarea name="notes" id="notes" class="form-control" rows="2">{{ old('notes') }}</textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" id="btn-submit-production">{{ __('Produktion speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.productions.index') }}" class="btn btn-outline-secondary">{{ __('Abbrechen') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
(function ($) {
|
||||
var recipeBase = @json(url('/admin/inventory/api/products'));
|
||||
var lineIndex = 0;
|
||||
|
||||
function recipeUrl() {
|
||||
var pid = $('#product_id').val();
|
||||
var lid = $('#location_id').val();
|
||||
var qty = $('#quantity').val() || 1;
|
||||
if (!pid || !lid) return null;
|
||||
return recipeBase + '/' + pid + '/recipe?location_id=' + encodeURIComponent(lid) + '&quantity=' + encodeURIComponent(qty);
|
||||
}
|
||||
|
||||
function addIngredientRow($tbody, ing, stockEntries) {
|
||||
var idx = lineIndex;
|
||||
lineIndex++;
|
||||
var tr = $('<tr></tr>');
|
||||
var select = $('<select class="form-control form-control-sm" name="ingredient_lines[' + idx + '][stock_entry_id]" required></select>');
|
||||
select.append('<option value="">{{ __('Charge wählen') }}</option>');
|
||||
(stockEntries || []).forEach(function (se) {
|
||||
var label = '#' + se.id;
|
||||
if (se.batch_number) label += ' — ' + se.batch_number;
|
||||
if (se.best_before) label += ' (MHD ' + se.best_before + ')';
|
||||
select.append($('<option></option>').attr('value', se.id).text(label));
|
||||
});
|
||||
var td1 = $('<td></td>');
|
||||
td1.append($('<input type="hidden" name="ingredient_lines[' + idx + '][ingredient_id]" value="' + ing.id + '">'));
|
||||
td1.append(select);
|
||||
tr.append(td1);
|
||||
tr.append($('<td></td>').append(
|
||||
$('<input type="text" class="form-control form-control-sm" required name="ingredient_lines[' + idx + '][quantity_used]" placeholder="0">')
|
||||
));
|
||||
$tbody.append(tr);
|
||||
}
|
||||
|
||||
function renderRecipe(data) {
|
||||
$('#recipe-ingredient-lines').empty();
|
||||
lineIndex = 0;
|
||||
var hintParts = [];
|
||||
var hasMissingGram = false;
|
||||
(data.ingredients || []).forEach(function (ing) {
|
||||
if (ing.required_grams_total === null) {
|
||||
hasMissingGram = true;
|
||||
hintParts.push(ing.name + ': {{ __('Gramm in der Rezeptur fehlt') }}');
|
||||
return;
|
||||
}
|
||||
var wrap = $('<div class="border rounded p-2 mb-2" data-ingredient-id="' + ing.id + '"></div>');
|
||||
wrap.data('recipe-ing', ing);
|
||||
var soll = '<strong>' + $('<div/>').text(ing.name).html() + '</strong> — {{ __('Soll') }}: ' +
|
||||
ing.required_grams_total.toLocaleString('de-DE', {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' g';
|
||||
wrap.append(soll);
|
||||
var tbody = $('<tbody></tbody>');
|
||||
var tbl = $('<table class="table table-sm table-bordered mb-1"><thead><tr><th>{{ __('Charge') }}</th><th>{{ __('Menge (g)') }}</th></tr></thead></table>');
|
||||
tbl.append(tbody);
|
||||
wrap.append(tbl);
|
||||
wrap.append('<button type="button" class="btn btn-sm btn-outline-secondary btn-add-split">{{ __('Weitere Charge') }}</button>');
|
||||
$('#recipe-ingredient-lines').append(wrap);
|
||||
addIngredientRow(tbody, ing, ing.stock_entries || []);
|
||||
});
|
||||
if (hasMissingGram) {
|
||||
$('#recipe-hint').text(hintParts.join(' · ')).removeClass('text-muted').addClass('text-danger');
|
||||
} else {
|
||||
$('#recipe-hint').text('{{ __('Pro Charge die entnommene Menge in Gramm eintragen. Summe je Inhaltsstoff muss dem Soll entsprechen.') }}').removeClass('text-danger').addClass('text-muted');
|
||||
}
|
||||
|
||||
var $pk = $('#recipe-packaging-preview').empty();
|
||||
(data.packagings || []).forEach(function (pk) {
|
||||
$pk.append('<tr><td>' + $('<div/>').text(pk.name).html() + '</td><td>' + pk.total_pieces + '</td></tr>');
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '.btn-add-split', function () {
|
||||
var $wrap = $(this).closest('[data-ingredient-id]');
|
||||
var ing = $wrap.data('recipe-ing');
|
||||
if (!ing) return;
|
||||
var $tbody = $wrap.find('tbody').first();
|
||||
addIngredientRow($tbody, ing, ing.stock_entries || []);
|
||||
});
|
||||
|
||||
function loadRecipe() {
|
||||
var url = recipeUrl();
|
||||
if (!url) {
|
||||
$('#recipe-area').hide();
|
||||
return;
|
||||
}
|
||||
$('#recipe-hint').text('{{ __('Lade …') }}');
|
||||
$.getJSON(url)
|
||||
.done(function (data) {
|
||||
$('#recipe-area').show();
|
||||
renderRecipe(data);
|
||||
})
|
||||
.fail(function () {
|
||||
$('#recipe-area').show();
|
||||
$('#recipe-hint').text('{{ __('Rezept konnte nicht geladen werden.') }}').addClass('text-danger');
|
||||
});
|
||||
}
|
||||
|
||||
$('#product_id, #location_id, #quantity').on('change', loadRecipe);
|
||||
$(document).ready(function () {
|
||||
if ($('#product_id').val() && $('#location_id').val()) {
|
||||
loadRecipe();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
@endsection
|
||||
203
resources/views/admin/inventory/productions/edit.blade.php
Normal file
203
resources/views/admin/inventory/productions/edit.blade.php
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<h4 class="font-weight-bold py-2 mb-2">{{ __('Produktion bearbeiten') }} #{{ $model->id }}</h4>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ route('admin.inventory.productions.update', $model) }}" id="form-production">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="product_id">{{ __('Produkt') }}</label>
|
||||
<select name="product_id" id="product_id" class="form-control @error('product_id') is-invalid @enderror" required>
|
||||
<option value="">{{ __('Bitte wählen') }}</option>
|
||||
@foreach($products as $p)
|
||||
<option value="{{ $p->id }}" @selected(old('product_id', $model->product_id) == $p->id)>{{ $p->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('product_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="location_id">{{ __('Lagerort / Produktionsstandort') }}</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(old('location_id', $model->location_id) == $loc->id)>{{ $loc->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('location_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-4">
|
||||
<label for="produced_at">{{ __('Produktionsdatum') }}</label>
|
||||
<input type="date" name="produced_at" id="produced_at" class="form-control @error('produced_at') is-invalid @enderror"
|
||||
value="{{ old('produced_at', $model->produced_at?->toDateString()) }}" required>
|
||||
@error('produced_at')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="quantity">{{ __('Produzierte Stückzahl') }}</label>
|
||||
<input type="number" name="quantity" id="quantity" min="1" step="1" class="form-control @error('quantity') is-invalid @enderror"
|
||||
value="{{ old('quantity', $model->quantity) }}" required>
|
||||
@error('quantity')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="recipe-area" class="mb-3" style="display:none;">
|
||||
<hr>
|
||||
<h6>{{ __('Chargen zuordnen') }}</h6>
|
||||
<p class="text-muted small" id="recipe-hint"></p>
|
||||
<div id="recipe-ingredient-lines"></div>
|
||||
@error('ingredient_lines')
|
||||
<div class="text-danger small">{{ $message }}</div>
|
||||
@enderror
|
||||
|
||||
<h6 class="mt-3">{{ __('Verpackung (Vorschau)') }}</h6>
|
||||
<div class="table-responsive border rounded">
|
||||
<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>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">{{ __('Notizen') }}</label>
|
||||
<textarea name="notes" id="notes" class="form-control" rows="2">{{ old('notes', $model->notes) }}</textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" id="btn-submit-production">{{ __('Produktion speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.productions.show', $model) }}" class="btn btn-outline-secondary">{{ __('Abbrechen') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
(function ($) {
|
||||
var recipeBase = @json(url('/admin/inventory/api/products'));
|
||||
var lineIndex = 0;
|
||||
|
||||
function recipeUrl() {
|
||||
var pid = $('#product_id').val();
|
||||
var lid = $('#location_id').val();
|
||||
var qty = $('#quantity').val() || 1;
|
||||
if (!pid || !lid) return null;
|
||||
return recipeBase + '/' + pid + '/recipe?location_id=' + encodeURIComponent(lid) + '&quantity=' + encodeURIComponent(qty);
|
||||
}
|
||||
|
||||
function addIngredientRow($tbody, ing, stockEntries, preselectedEntryId, preselectedQty) {
|
||||
var idx = lineIndex;
|
||||
lineIndex++;
|
||||
var tr = $('<tr></tr>');
|
||||
var select = $('<select class="form-control form-control-sm" name="ingredient_lines[' + idx + '][stock_entry_id]" required></select>');
|
||||
select.append('<option value="">{{ __('Charge wählen') }}</option>');
|
||||
(stockEntries || []).forEach(function (se) {
|
||||
var label = '#' + se.id;
|
||||
if (se.batch_number) label += ' — ' + se.batch_number;
|
||||
if (se.best_before) label += ' (MHD ' + se.best_before + ')';
|
||||
var opt = $('<option></option>').attr('value', se.id).text(label);
|
||||
if (preselectedEntryId && String(se.id) === String(preselectedEntryId)) opt.prop('selected', true);
|
||||
select.append(opt);
|
||||
});
|
||||
var td1 = $('<td></td>');
|
||||
td1.append($('<input type="hidden" name="ingredient_lines[' + idx + '][ingredient_id]" value="' + ing.id + '">'));
|
||||
td1.append(select);
|
||||
tr.append(td1);
|
||||
tr.append($('<td></td>').append(
|
||||
$('<input type="text" class="form-control form-control-sm" required name="ingredient_lines[' + idx + '][quantity_used]" placeholder="0">').val(preselectedQty || '')
|
||||
));
|
||||
$tbody.append(tr);
|
||||
}
|
||||
|
||||
function renderRecipe(data) {
|
||||
$('#recipe-ingredient-lines').empty();
|
||||
lineIndex = 0;
|
||||
|
||||
var existingLines = @json($model->productionIngredients->groupBy('ingredient_id')->map(function($lines) {
|
||||
return $lines->map(function($l) {
|
||||
return ['stock_entry_id' => $l->stock_entry_id, 'quantity_used' => (float) $l->quantity_used];
|
||||
})->values();
|
||||
}));
|
||||
|
||||
var hintParts = [];
|
||||
var hasMissingGram = false;
|
||||
(data.ingredients || []).forEach(function (ing) {
|
||||
if (ing.required_grams_total === null) {
|
||||
hasMissingGram = true;
|
||||
hintParts.push(ing.name + ': {{ __('Gramm in der Rezeptur fehlt') }}');
|
||||
return;
|
||||
}
|
||||
var wrap = $('<div class="border rounded p-2 mb-2" data-ingredient-id="' + ing.id + '"></div>');
|
||||
wrap.data('recipe-ing', ing);
|
||||
var soll = '<strong>' + $('<div/>').text(ing.name).html() + '</strong> — {{ __('Soll') }}: ' +
|
||||
ing.required_grams_total.toLocaleString('de-DE', {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' g';
|
||||
wrap.append(soll);
|
||||
var tbody = $('<tbody></tbody>');
|
||||
var tbl = $('<table class="table table-sm table-bordered mb-1"><thead><tr><th>{{ __('Charge') }}</th><th>{{ __('Menge (g)') }}</th></tr></thead></table>');
|
||||
tbl.append(tbody);
|
||||
wrap.append(tbl);
|
||||
wrap.append('<button type="button" class="btn btn-sm btn-outline-secondary btn-add-split">{{ __('Weitere Charge') }}</button>');
|
||||
$('#recipe-ingredient-lines').append(wrap);
|
||||
|
||||
var existing = existingLines[String(ing.id)] || [];
|
||||
if (existing.length > 0) {
|
||||
existing.forEach(function (ex) {
|
||||
addIngredientRow(tbody, ing, ing.stock_entries || [], ex.stock_entry_id, ex.quantity_used);
|
||||
});
|
||||
} else {
|
||||
addIngredientRow(tbody, ing, ing.stock_entries || []);
|
||||
}
|
||||
});
|
||||
if (hasMissingGram) {
|
||||
$('#recipe-hint').text(hintParts.join(' · ')).removeClass('text-muted').addClass('text-danger');
|
||||
} else {
|
||||
$('#recipe-hint').text('{{ __('Pro Charge die entnommene Menge in Gramm eintragen.') }}').removeClass('text-danger').addClass('text-muted');
|
||||
}
|
||||
|
||||
var $pk = $('#recipe-packaging-preview').empty();
|
||||
(data.packagings || []).forEach(function (pk) {
|
||||
$pk.append('<tr><td>' + $('<div/>').text(pk.name).html() + '</td><td>' + pk.total_pieces + '</td></tr>');
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '.btn-add-split', function () {
|
||||
var $wrap = $(this).closest('[data-ingredient-id]');
|
||||
var ing = $wrap.data('recipe-ing');
|
||||
if (!ing) return;
|
||||
var $tbody = $wrap.find('tbody').first();
|
||||
addIngredientRow($tbody, ing, ing.stock_entries || []);
|
||||
});
|
||||
|
||||
function loadRecipe() {
|
||||
var url = recipeUrl();
|
||||
if (!url) { $('#recipe-area').hide(); return; }
|
||||
$('#recipe-hint').text('{{ __('Lade …') }}');
|
||||
$.getJSON(url)
|
||||
.done(function (data) { $('#recipe-area').show(); renderRecipe(data); })
|
||||
.fail(function () {
|
||||
$('#recipe-area').show();
|
||||
$('#recipe-hint').text('{{ __('Rezept konnte nicht geladen werden.') }}').addClass('text-danger');
|
||||
});
|
||||
}
|
||||
|
||||
$('#product_id, #location_id, #quantity').on('change', loadRecipe);
|
||||
$(document).ready(function () {
|
||||
if ($('#product_id').val() && $('#location_id').val()) {
|
||||
loadRecipe();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
@endsection
|
||||
62
resources/views/admin/inventory/productions/index.blade.php
Normal file
62
resources/views/admin/inventory/productions/index.blade.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Produktionen') }}</span>
|
||||
<a href="{{ route('admin.inventory.productions.create') }}" class="btn btn-sm btn-primary">{{ __('Neue Produktion') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Datum') }}</th>
|
||||
<th>{{ __('Produkt') }}</th>
|
||||
<th>{{ __('Stück') }}</th>
|
||||
<th>{{ __('Standort') }}</th>
|
||||
<th>{{ __('MHD-Hinweis') }}</th>
|
||||
<th style="max-width: 80px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $row)
|
||||
<tr>
|
||||
<td data-sort="{{ $row->produced_at?->timestamp ?? 0 }}">{{ $row->produced_at?->format('d.m.Y') }}</td>
|
||||
<td>{{ $row->product?->name ?? '—' }}</td>
|
||||
<td>{{ $row->quantity }}</td>
|
||||
<td>{{ $row->location?->name ?? '—' }}</td>
|
||||
<td>
|
||||
@if($row->mhd_warning)
|
||||
<span class="badge badge-warning">{{ __('Ja') }}</span>
|
||||
@else
|
||||
<span class="text-muted">—</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-nowrap">
|
||||
<a href="{{ route('admin.inventory.productions.show', $row) }}" class="btn icon-btn btn-sm btn-primary" title="{{ __('Details') }}">
|
||||
<span class="far fa-eye"></span>
|
||||
</a>
|
||||
<a href="{{ route('admin.inventory.productions.edit', $row) }}" class="btn icon-btn btn-sm btn-outline-primary" title="{{ __('Bearbeiten') }}">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
<a href="{{ route('admin.inventory.productions.copy', $row) }}" class="btn icon-btn btn-sm btn-outline-secondary" title="{{ __('Kopieren') }}">
|
||||
<span class="far fa-copy"></span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[0, "desc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
104
resources/views/admin/inventory/productions/show.blade.php
Normal file
104
resources/views/admin/inventory/productions/show.blade.php
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
@php
|
||||
/** @var \App\Models\Production $model */
|
||||
@endphp
|
||||
|
||||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<h4 class="font-weight-bold py-2 mb-2">{{ __('Produktion') }} #{{ $model->id }}</h4>
|
||||
|
||||
<div class="card mb-3">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Übersicht') }}</span>
|
||||
<div>
|
||||
<a href="{{ route('admin.inventory.productions.edit', $model) }}" class="btn btn-sm btn-primary">{{ __('Bearbeiten') }}</a>
|
||||
<a href="{{ route('admin.inventory.productions.copy', $model) }}" class="btn btn-sm btn-outline-primary">{{ __('Kopieren') }}</a>
|
||||
<a href="{{ route('admin.inventory.productions.index') }}" class="btn btn-sm btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</div>
|
||||
</h6>
|
||||
<div class="card-body">
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-3">{{ __('Produkt') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->product?->name ?? '—' }}</dd>
|
||||
<dt class="col-sm-3">{{ __('Produktionsdatum') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->produced_at?->format('d.m.Y') }}</dd>
|
||||
<dt class="col-sm-3">{{ __('Stückzahl') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->quantity }}</dd>
|
||||
<dt class="col-sm-3">{{ __('Standort') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->location?->name ?? '—' }}</dd>
|
||||
<dt class="col-sm-3">{{ __('Erfasst von') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->producedByUser?->getFullName(false) ?: $model->producedByUser?->email ?? '—' }}</dd>
|
||||
<dt class="col-sm-3">{{ __('MHD-Hinweis') }}</dt>
|
||||
<dd class="col-sm-9">
|
||||
@if($model->mhd_warning)
|
||||
<span class="badge badge-warning">{{ __('Rohstoff-MHD kürzer als Produkt-MHD') }}</span>
|
||||
@else
|
||||
—
|
||||
@endif
|
||||
</dd>
|
||||
@if($model->notes)
|
||||
<dt class="col-sm-3">{{ __('Notizen') }}</dt>
|
||||
<dd class="col-sm-9">{{ $model->notes }}</dd>
|
||||
@endif
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<h6 class="card-header">{{ __('Rohstoff-Verbrauch (Chargen)') }}</h6>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Inhaltsstoff') }}</th>
|
||||
<th>{{ __('Charge / Wareneingang') }}</th>
|
||||
<th>{{ __('Menge (g)') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($model->productionIngredients as $line)
|
||||
<tr>
|
||||
<td>{{ $line->ingredient?->name ?? '—' }}</td>
|
||||
<td>
|
||||
#{{ $line->stock_entry_id }}
|
||||
@if($line->stockEntry?->batch_number)
|
||||
— {{ $line->stockEntry->batch_number }}
|
||||
@endif
|
||||
@if($line->stockEntry?->best_before)
|
||||
(MHD {{ $line->stockEntry->best_before->format('d.m.Y') }})
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ \App\Services\Util::formatNumber($line->quantity_used) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ __('Verpackung (Snapshot)') }}</h6>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Artikel') }}</th>
|
||||
<th>{{ __('Verbrauch (Stk.)') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($model->productionPackagings as $line)
|
||||
<tr>
|
||||
<td>{{ $line->packagingItem?->name ?? '—' }}</td>
|
||||
<td>{{ $line->quantity_used }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
111
resources/views/admin/inventory/stock-entries/_form.blade.php
Normal file
111
resources/views/admin/inventory/stock-entries/_form.blade.php
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
20
resources/views/admin/inventory/stock-entries/edit.blade.php
Normal file
20
resources/views/admin/inventory/stock-entries/edit.blade.php
Normal 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
|
||||
|
|
@ -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
|
||||
191
resources/views/admin/inventory/stock-entries/show.blade.php
Normal file
191
resources/views/admin/inventory/stock-entries/show.blade.php
Normal 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
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Lieferanten-Kategorie bearbeiten') : __('Lieferanten-Kategorie anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.supplier-categories.update', $model) : route('admin.inventory.supplier-categories.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pos">{{ __('Pos') }}</label>
|
||||
<input type="number" name="pos" id="pos" class="form-control @error('pos') is-invalid @enderror"
|
||||
value="{{ old('pos', $model->pos) }}" min="0" max="255">
|
||||
@error('pos')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.supplier-categories.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Lieferanten-Kategorien') }}</span>
|
||||
<a href="{{ route('admin.inventory.supplier-categories.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Pos') }}</th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.supplier-categories.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->pos }}</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.supplier-categories.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-link text-danger p-0"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
125
resources/views/admin/inventory/suppliers/form.blade.php
Normal file
125
resources/views/admin/inventory/suppliers/form.blade.php
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$selectedCategoryIds = old('supplier_category_ids', $model->exists ? $model->supplierCategories->pluck('id')->all() : []);
|
||||
@endphp
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Lieferant bearbeiten') : __('Lieferant anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.suppliers.update', $model) : route('admin.inventory.suppliers.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ __('Name') }}</label>
|
||||
<input type="text" name="name" id="name" class="form-control @error('name') is-invalid @enderror"
|
||||
value="{{ old('name', $model->name) }}" required>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="supplier_category_ids">{{ __('Kategorien') }}</label>
|
||||
<div class="light-style">
|
||||
<select name="supplier_category_ids[]" id="supplier_category_ids" class="w-100" multiple="multiple" data-placeholder="{{ __('Kategorien wählen') }}">
|
||||
@foreach($supplierCategories as $cat)
|
||||
<option value="{{ $cat->id }}" @selected(in_array($cat->id, $selectedCategoryIds, true))>{{ $cat->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@error('supplier_category_ids')
|
||||
<div class="text-danger small">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="country_id">{{ __('Land') }}</label>
|
||||
<select name="country_id" id="country_id" class="form-control @error('country_id') is-invalid @enderror" required>
|
||||
<option value="">{{ __('Bitte wählen') }}</option>
|
||||
@foreach($countries as $country)
|
||||
<option value="{{ $country->id }}" @selected((string)old('country_id', $model->country_id) === (string)$country->id)>
|
||||
{{ $country->de }} ({{ $country->code }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('country_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="url">{{ __('Webseite') }}</label>
|
||||
<input type="url" name="url" id="url" class="form-control @error('url') is-invalid @enderror"
|
||||
value="{{ old('url', $model->url) }}">
|
||||
@error('url')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="contact_person">{{ __('Ansprechpartner') }}</label>
|
||||
<input type="text" name="contact_person" id="contact_person" class="form-control @error('contact_person') is-invalid @enderror"
|
||||
value="{{ old('contact_person', $model->contact_person) }}">
|
||||
@error('contact_person')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="email">{{ __('E-Mail') }}</label>
|
||||
<input type="email" name="email" id="email" class="form-control @error('email') is-invalid @enderror"
|
||||
value="{{ old('email', $model->email) }}">
|
||||
@error('email')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">{{ __('Telefon') }}</label>
|
||||
<input type="text" name="phone" id="phone" class="form-control @error('phone') is-invalid @enderror"
|
||||
value="{{ old('phone', $model->phone) }}">
|
||||
@error('phone')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">{{ __('Notizen') }}</label>
|
||||
<textarea name="notes" id="notes" rows="3" class="form-control @error('notes') is-invalid @enderror">{{ old('notes', $model->notes) }}</textarea>
|
||||
@error('notes')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" name="active" value="1" class="custom-control-input"
|
||||
@checked(old('active', $model->active))>
|
||||
<span class="custom-control-label">{{ __('Aktiv') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{{ __('Speichern') }}</button>
|
||||
<a href="{{ route('admin.inventory.suppliers.index') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#supplier_category_ids').select2({
|
||||
theme: 'default',
|
||||
placeholder: '{{ __('Kategorien wählen') }}',
|
||||
width: '100%',
|
||||
closeOnSelect: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
67
resources/views/admin/inventory/suppliers/index.blade.php
Normal file
67
resources/views/admin/inventory/suppliers/index.blade.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Lieferanten') }}</span>
|
||||
<a href="{{ route('admin.inventory.suppliers.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th>{{ __('Land') }}</th>
|
||||
<th>{{ __('Kategorien') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $value)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.suppliers.edit', $value) }}" class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $value->name }}</td>
|
||||
<td>{{ $value->country?->de ?? '—' }}</td>
|
||||
<td>
|
||||
@foreach($value->supplierCategories as $cat)
|
||||
<span class="badge badge-secondary">{{ $cat->name }}</span>
|
||||
@endforeach
|
||||
</td>
|
||||
<td data-sort="{{ $value->active ? 1 : 0 }}">
|
||||
@if($value->active)
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i></span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.suppliers.destroy', $value) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-link text-danger p-0"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[1, "asc"]],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
Loading…
Add table
Add a link
Reference in a new issue