Warenwirtschaft: AP-00 bis AP-08 + aktualisierter Entwicklungsplan
Umsetzung der Warenwirtschafts-/Produktmanagement-Erweiterung gemaess Entwicklungsplan V4.0: - AP-00: Regressionsbasis fuer 5.1-Features (ProductPhase51Test) - AP-01: URL-Bugfixes B1/B2 (suppliers/packaging-items, breitere url-Spalten) - AP-04/04.1: iPad-taugliche, vereinheitlichte Tabellen-Aktionen - AP-05: Einstellungen "Allgemein" mit UST-Saetzen (tax_rates) und Lieferzeit-Vorlagen (delivery_times, inkl. Tage-Feld) - AP-06: Lieferanten um Bestellweg, Bestell-Mail/-URL und Lieferzeit erweitert - AP-07/07.1: INCI um Lieferanten-Mehrfachwahl, UST und Lieferzeit erweitert; Lieferanten-Detailansicht im Modal mit pflegbaren INCI-/Verpackungslisten - AP-08: Einkauf um UST-Snapshot, Netto/Brutto-Automatik und Duplizieren erweitert Entwicklungsplan aktualisiert: alle Klaerungspunkte (§5) vom Kunden beantwortet und in die jeweiligen APs eingearbeitet (AP-02/03/09/13/15), neues AP-18 (Hinweise-Doku unter Einstellungen) ergaenzt. Naechster Schritt eindeutig markiert: AP-09 (Produktion auf Hersteller-Rezeptur, kein Fallback, Warnung).
This commit is contained in:
parent
ca3eb663fe
commit
78679e0c55
67 changed files with 3523 additions and 101 deletions
|
|
@ -115,14 +115,51 @@
|
|||
@enderror
|
||||
</div>
|
||||
|
||||
<div id="price-per-kg-block" class="form-group" style="display:none;">
|
||||
<label for="price_per_kg">{{ __('Netto-Preis pro kg') }} <span class="text-danger">*</span></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 id="price-per-kg-block" style="display:none;">
|
||||
<div class="form-group">
|
||||
<label for="tax_rate_id">{{ __('Umsatzsteuer') }}</label>
|
||||
<select name="tax_rate_id" id="tax_rate_id" class="form-control @error('tax_rate_id') is-invalid @enderror">
|
||||
<option value="" data-percent="0">{{ __('— keine Angabe —') }}</option>
|
||||
@foreach ($taxRates as $taxRate)
|
||||
<option value="{{ $taxRate->id }}" data-percent="{{ $taxRate->percent }}"
|
||||
@selected((string) old('tax_rate_id', $model->tax_rate_id) === (string) $taxRate->id)>
|
||||
{{ $taxRate->name }} ({{ \App\Services\Util::formatNumber($taxRate->percent) }} %)
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<small class="text-muted">{{ __('Steuersatz zur Umrechnung zwischen Netto und Brutto.') }}</small>
|
||||
@error('tax_rate_id')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="price_per_kg">{{ __('Netto-Preis pro kg') }} <span class="text-danger">*</span></label>
|
||||
<div class="input-group">
|
||||
<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) : '') }}">
|
||||
<div class="input-group-append"><span class="input-group-text">€</span></div>
|
||||
@error('price_per_kg')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="price_per_kg_gross">{{ __('Brutto-Preis pro kg') }}</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="price_per_kg_gross" id="price_per_kg_gross"
|
||||
class="form-control @error('price_per_kg_gross') is-invalid @enderror"
|
||||
value="{{ old('price_per_kg_gross', $model->price_per_kg_gross !== null ? \App\Services\Util::formatNumber($model->price_per_kg_gross) : '') }}">
|
||||
<div class="input-group-append"><span class="input-group-text">€</span></div>
|
||||
@error('price_per_kg_gross')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted d-block mb-2">{{ __('Netto oder Brutto genügt – der jeweils andere Wert wird automatisch berechnet.') }}</small>
|
||||
</div>
|
||||
|
||||
<div id="price-total-block" class="form-group" style="display:none;">
|
||||
|
|
|
|||
|
|
@ -65,6 +65,43 @@
|
|||
});
|
||||
}
|
||||
|
||||
function parseNumber(value) {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
var normalized = String(value).trim().replace(/\./g, '').replace(',', '.');
|
||||
if (normalized === '' || isNaN(normalized)) {
|
||||
return null;
|
||||
}
|
||||
return parseFloat(normalized);
|
||||
}
|
||||
|
||||
function formatNumber(value) {
|
||||
return value.toFixed(2).replace('.', ',');
|
||||
}
|
||||
|
||||
function currentFactor() {
|
||||
var percent = parseFloat($('#tax_rate_id option:selected').data('percent')) || 0;
|
||||
return 1 + percent / 100;
|
||||
}
|
||||
|
||||
function recalcFromNet() {
|
||||
var net = parseNumber($('#price_per_kg').val());
|
||||
if (net === null) {
|
||||
return;
|
||||
}
|
||||
$('#price_per_kg_gross').val(formatNumber(net * currentFactor()));
|
||||
}
|
||||
|
||||
function recalcFromGross() {
|
||||
var gross = parseNumber($('#price_per_kg_gross').val());
|
||||
if (gross === null) {
|
||||
return;
|
||||
}
|
||||
var factor = currentFactor();
|
||||
$('#price_per_kg').val(formatNumber(factor > 0 ? gross / factor : gross));
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
toggleBlocks();
|
||||
initIngredientSelect2();
|
||||
|
|
@ -75,6 +112,16 @@
|
|||
$('#packaging_item_id').val(null).trigger('change');
|
||||
initPackagingSelect2();
|
||||
});
|
||||
|
||||
$('#price_per_kg').on('input', recalcFromNet);
|
||||
$('#price_per_kg_gross').on('input', recalcFromGross);
|
||||
$('#tax_rate_id').on('change', function () {
|
||||
if (parseNumber($('#price_per_kg').val()) !== null) {
|
||||
recalcFromNet();
|
||||
} else {
|
||||
recalcFromGross();
|
||||
}
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
@include('admin.inventory.partials.table-actions-style')
|
||||
<div class="card">
|
||||
<h6 class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>{{ __('Wareneingang') }}</span>
|
||||
|
|
@ -9,21 +10,37 @@
|
|||
@endif
|
||||
</h6>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-style table table-striped table-bordered">
|
||||
<table class="datatables-style table table-striped table-bordered wawi-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 90px;"></th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th>{{ __('Bestellt') }}</th>
|
||||
<th>{{ __('Art') }}</th>
|
||||
<th>{{ __('Artikel') }}</th>
|
||||
<th>{{ __('Lieferant') }}</th>
|
||||
<th>{{ __('Menge') }}</th>
|
||||
<th style="max-width: 80px;"></th>
|
||||
<th style="max-width: 60px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($values as $row)
|
||||
<tr>
|
||||
<td class="text-nowrap">
|
||||
<a href="{{ route('admin.inventory.stock-entries.show', $row) }}" class="btn icon-btn btn-sm btn-primary" title="{{ __('Ansicht') }}">
|
||||
<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" title="{{ __('Bearbeiten') }}">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
@endif
|
||||
@if(Auth::user()->isAdmin())
|
||||
<a href="{{ route('admin.inventory.stock-entries.copy', $row) }}" class="btn icon-btn btn-sm btn-info" title="{{ __('Duplizieren') }}">
|
||||
<span class="far fa-copy"></span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
<td data-sort="{{ $row->status === 'pending' ? 0 : 1 }}">
|
||||
@if($row->status === 'pending')
|
||||
<span class="badge badge-warning">{{ __('Offen') }}</span>
|
||||
|
|
@ -51,18 +68,12 @@
|
|||
@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>
|
||||
<button type="submit" class="btn btn-link text-danger p-0" title="{{ __('Löschen') }}"><i class="far fa-trash-alt"></i></button>
|
||||
</form>
|
||||
@endif
|
||||
</td>
|
||||
|
|
@ -77,7 +88,8 @@
|
|||
$('.datatables-style').dataTable({
|
||||
"bLengthChange": false,
|
||||
"iDisplayLength": 100,
|
||||
"order": [[0, "asc"], [1, "desc"]],
|
||||
"order": [[1, "asc"], [2, "desc"]],
|
||||
"columnDefs": [{"orderable": false, "targets": [0, 7]}],
|
||||
"language": {"url": "/js/German.json"}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
</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())
|
||||
<a href="{{ route('admin.inventory.stock-entries.copy', $model) }}" class="btn btn-sm btn-outline-info">{{ __('Duplizieren') }}</a>
|
||||
@endif
|
||||
@if(Auth::user()->isAdmin() && $model->isPending())
|
||||
<a href="{{ route('admin.inventory.stock-entries.edit', $model) }}" class="btn btn-sm btn-primary">{{ __('Bearbeiten') }}</a>
|
||||
@endif
|
||||
|
|
@ -70,10 +73,16 @@
|
|||
<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
|
||||
{{ \App\Services\Util::formatNumber($model->price_per_kg) }} € / kg {{ __('netto') }}
|
||||
@else
|
||||
—
|
||||
@endif
|
||||
@if($model->price_per_kg_gross !== null)
|
||||
<span class="text-muted">· {{ \App\Services\Util::formatNumber($model->price_per_kg_gross) }} € / kg {{ __('brutto') }}</span>
|
||||
@endif
|
||||
@if($model->tax_rate_percent !== null)
|
||||
<span class="text-muted">· {{ __('USt.') }} {{ \App\Services\Util::formatNumber($model->tax_rate_percent) }} %</span>
|
||||
@endif
|
||||
@else
|
||||
@if($model->price_total !== null)
|
||||
{{ \App\Services\Util::formatNumber($model->price_total) }} € {{ __('netto') }}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue