Warenwirtschaft: Anforderungsrunde 12.06. — Plan V5.0 + AP-26/AP-25/AP-22
Neue Anforderungen (docs/) interpretiert und als Entwicklungsplan V5.0 (AP-20 bis AP-28) aufgenommen; erste drei Pakete umgesetzt: AP-26 Ausschuss-Gründe konfigurierbar: - Stammdaten-Tabelle disposal_reasons + CRUD unter Einstellungen → Allgemein - StockDisposalController liest aktive DB-Gründe statt hartkodierter Liste - Seeder übernimmt die bisherigen 6 Gründe idempotent AP-25 Lieferbestand — Datum statt Tage: - "Nicht vorrätig" wird über Datepicker "Wieder lieferbar ab" gepflegt; Resttage-Hinweis zählt täglich automatisch herunter - Interne Bestellliste wieder kaufbar: Hinweis erscheint zusätzlich zu den Mengen-Buttons (VP entscheidet selbst) AP-22 Produktbestand-Erweiterungen: - Default-Sortierung nach Dringlichkeit, Status-Kopf toggelt - Alle vier Status-Kacheln als Filter klickbar - Neue Spalte "Verbrauch/Monat" (Ø Abgänge der letzten 6 Monate) - Produkt-Flag "Im Produktbestand anzeigen" (products.show_in_product_stock) Tests: 77 grün (DisposalReasonSettings 8, ProductOutOfStock 8, ProductStock 13 + Regression). Hinweise-Doku + Plan-Protokoll fortgeschrieben; nächster Schritt laut Plan: AP-21 (INCI-Erweiterungen). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a8f6fef38e
commit
e53201f229
32 changed files with 1377 additions and 94 deletions
|
|
@ -4,7 +4,7 @@
|
|||
> wichtige Hinweise für die Nutzung sowie festgehaltene Entscheidungen, die
|
||||
> später noch ausgebaut werden können.
|
||||
>
|
||||
> **Stand:** 03.06.2026
|
||||
> **Stand:** 12.06.2026
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -12,8 +12,9 @@
|
|||
|
||||
### Bereits nutzbar
|
||||
|
||||
- **Einstellungen → Allgemein:** Umsatzsteuersätze und Lieferzeit-Vorlagen
|
||||
(inkl. Tageswert) pflegbar.
|
||||
- **Einstellungen → Allgemein:** Umsatzsteuersätze, Lieferzeit-Vorlagen
|
||||
(inkl. Tageswert) und **Ausschuss-Gründe** pflegbar. Die Ausschuss-Gründe
|
||||
erscheinen im Ausschuss-Formular (nur aktive, in gepflegter Reihenfolge).
|
||||
- **Stammdaten:** Lagerorte, Rohstoffqualität, Verpackungsmaterial,
|
||||
Lieferanten-Kategorien.
|
||||
- **Lieferanten:** Bestellweg (E-Mail / Online-Shop), Bestell-Adresse,
|
||||
|
|
@ -28,11 +29,12 @@
|
|||
- **Produkt-Klassen:** Einzelprodukt vs. **Set** (Bündel mehrerer Einzelprodukte
|
||||
mit Menge). Sets werden nicht produziert; optional kann ein Einzelprodukt einem
|
||||
Hauptprodukt zugeordnet werden.
|
||||
- **„Nicht vorrätig":** Produkt zeitlich begrenzt (mit Tagesangabe →
|
||||
„In ca. X Tagen wieder da!") oder auf unbestimmte Zeit als nicht vorrätig
|
||||
markierbar. Im öffentlichen Shop erscheint nur ein Hinweis, der Kauf bleibt
|
||||
möglich. In der **internen Bestellliste** ersetzt der rote Hinweis die
|
||||
Mengen-Buttons – dort ist das Produkt also vorübergehend nicht bestellbar.
|
||||
- **„Nicht vorrätig":** Produkt zeitlich begrenzt (mit **Datum** „Wieder
|
||||
lieferbar ab" → der Hinweis „In ca. X Tagen wieder da!" zählt täglich
|
||||
automatisch herunter) oder auf unbestimmte Zeit als nicht vorrätig
|
||||
markierbar. Es erscheint **überall nur ein Hinweis** – im öffentlichen Shop
|
||||
**und** in der internen Bestellliste bleibt der Kauf möglich; der
|
||||
Vertriebspartner entscheidet selbst, ob er die Ware später bekommt.
|
||||
- **Rohstoffbestand:** Übersicht aller aktiven Rohstoffe mit echtem Restbestand
|
||||
(Wareneingang abzüglich Produktionsverbrauch), durchschnittlichem Verbrauch
|
||||
pro Tag, voraussichtlichem „auf Null"-Datum und Hochrechnung für 1/3/6/12
|
||||
|
|
@ -53,14 +55,21 @@
|
|||
ausgewähltem Produkt. Suche und Filter „nur kritische anzeigen"; bei
|
||||
unterschrittenem kritischem Bestand ist die Zeile rot, beim Meldebestand gelb –
|
||||
ein Badge in der Navigation zeigt die Anzahl. Schwellwerte werden je Produkt im
|
||||
Produktformular (Warenwirtschaft) gepflegt.
|
||||
Produktformular (Warenwirtschaft) gepflegt. Die Übersicht ist standardmäßig
|
||||
nach **Dringlichkeit** sortiert (kritische Produkte oben, Klick auf „Status"
|
||||
dreht die Reihenfolge), alle vier Status-Kacheln oben sind als Filter
|
||||
anklickbar, und die Spalte **„Verbrauch/Monat"** zeigt den Durchschnitt der
|
||||
Abgänge der letzten 6 Monate. Produkte ohne Lagerführung (z. B. Abrechnung
|
||||
Druckkosten, Logo-Etiketten) lassen sich über die Produkt-Option
|
||||
**„Im Produktbestand anzeigen"** aus der Übersicht ausblenden.
|
||||
- **Produktbestand-Historie:** Revisionssichere Liste aller Bewegungen
|
||||
(Eingang/Ausgang, Stückzahl, Datum, Grund, Hinweis, Mitarbeiter), filterbar
|
||||
nach Produkt, Richtung, Grund und Zeitraum (Monat/Jahr).
|
||||
|
||||
- **Ausgang / Ausschuss:** Erfassung von Rohstoff- und Verpackungs-Abgängen
|
||||
(z. B. Bruch, Verfall/MHD, Qualitätsmangel, Schwund, Testverbrauch). Pflichtfeld
|
||||
**Grund**, optionale **Charge** (setzt den Lagerort automatisch), Menge in
|
||||
(z. B. Bruch, Verfall/MHD, Qualitätsmangel, Schwund, Testverbrauch). Die
|
||||
Gründe sind selbst pflegbar unter **Einstellungen → Allgemein →
|
||||
Ausschuss-Gründe**. Pflichtfeld **Grund**, optionale **Charge** (setzt den Lagerort automatisch), Menge in
|
||||
Gramm (Rohstoff) bzw. Stück (Verpackung) und Datum. Jeder Ausgang reduziert
|
||||
sofort den Bestand – beim Rohstoffbestand also auch die „auf Null"-Prognose und
|
||||
den Kritisch-Status.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
@extends('layouts.layout-2')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<h6 class="card-header">{{ $model->exists ? __('Ausschuss-Grund bearbeiten') : __('Ausschuss-Grund anlegen') }}</h6>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ $model->exists ? route('admin.inventory.disposal-reasons.update', $model) : route('admin.inventory.disposal-reasons.store') }}">
|
||||
@csrf
|
||||
@if($model->exists)
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<label for="label">{{ __('Bezeichnung') }}</label>
|
||||
<input type="text" name="label" id="label" maxlength="100"
|
||||
class="form-control @error('label') is-invalid @enderror"
|
||||
value="{{ old('label', $model->label) }}" placeholder="{{ __('z. B. Bruch / Beschädigung') }}" required>
|
||||
@error('label')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pos">{{ __('Sortierung') }}</label>
|
||||
<input type="number" name="pos" id="pos" min="0" max="255"
|
||||
class="form-control @error('pos') is-invalid @enderror"
|
||||
value="{{ old('pos', $model->pos) }}">
|
||||
@error('pos')
|
||||
<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.general') }}" class="btn btn-outline-secondary">{{ __('Zurück') }}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<div class="wawi-page-head">
|
||||
<div>
|
||||
<h1 class="wawi-page-head__title">{{ __('Einstellungen') }}</h1>
|
||||
<p class="wawi-page-head__subtitle">{{ __('Umsatzsteuersätze und Lieferzeit-Vorlagen') }}</p>
|
||||
<p class="wawi-page-head__subtitle">{{ __('Umsatzsteuersätze, Lieferzeit-Vorlagen und Ausschuss-Gründe') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -119,5 +119,58 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wawi-card">
|
||||
<div class="wawi-card__header">
|
||||
<span>{{ __('Ausschuss-Gründe') }}</span>
|
||||
<a href="{{ route('admin.inventory.disposal-reasons.create') }}" class="btn btn-sm btn-primary">{{ __('Neu anlegen') }}</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table wawi-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="max-width: 60px;"> </th>
|
||||
<th>{{ __('Bezeichnung') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($disposalReasons as $disposalReason)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.inventory.disposal-reasons.edit', $disposalReason) }}"
|
||||
class="btn icon-btn btn-sm btn-primary">
|
||||
<span class="far fa-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $disposalReason->label }}</td>
|
||||
<td>
|
||||
@if ($disposalReason->active)
|
||||
<span class="wawi-pill wawi-pill--ok">{{ __('Aktiv') }}</span>
|
||||
@else
|
||||
<span class="wawi-pill wawi-pill--danger">{{ __('Inaktiv') }}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<form action="{{ route('admin.inventory.disposal-reasons.destroy', $disposalReason) }}"
|
||||
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>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4"><div class="wawi-empty">{{ __('Noch keine Ausschuss-Gründe angelegt.') }}</div></td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -1,35 +1,6 @@
|
|||
@once
|
||||
<style>
|
||||
/* AP-04: iPad-taugliche Aktions-Buttons in Warenwirtschafts-Tabellen */
|
||||
.wawi-table1 td .btn {
|
||||
min-width: 42px;
|
||||
min-height: 42px;
|
||||
padding: 0.5rem 0.65rem !important;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.2;
|
||||
margin: 0.15rem 0.55rem 0.15rem 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.wawi-table1 td .btn:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.wawi-table1 td form.d-inline {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wawi-table1 td .btn .far,
|
||||
.wawi-table1 td .btn .fa,
|
||||
.wawi-table1 td .btn span {
|
||||
font-size: 1.05rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
|
||||
.wawi-table td .btn {
|
||||
|
||||
margin: 0.15rem 0.65rem 0.45rem 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@
|
|||
</div>
|
||||
|
||||
<div class="wawi-stats">
|
||||
<div class="wawi-stat" data-filter="all">
|
||||
<div class="wawi-stat is-clickable" data-filter="all">
|
||||
<div class="wawi-stat__icon"><span class="fas fa-boxes-stacked"></span></div>
|
||||
<div class="wawi-stat__body">
|
||||
<div class="wawi-stat__value">{{ $total }}</div>
|
||||
<div class="wawi-stat__label">{{ __('Produkte') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wawi-stat wawi-stat--ok" data-filter="all">
|
||||
<div class="wawi-stat wawi-stat--ok is-clickable" data-filter="ok">
|
||||
<div class="wawi-stat__icon"><span class="fas fa-circle-check"></span></div>
|
||||
<div class="wawi-stat__body">
|
||||
<div class="wawi-stat__value">{{ $okCount }}</div>
|
||||
|
|
@ -75,7 +75,10 @@
|
|||
<th style="width:3.5rem"></th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th class="text-right">{{ __('Bestand') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th class="text-right" title="{{ __('Durchschnitt der letzten 6 Monate') }}">{{ __('Verbrauch/Monat') }}</th>
|
||||
<th id="ps-sort-status" style="cursor:pointer" title="{{ __('Nach Dringlichkeit sortieren') }}">
|
||||
{{ __('Status') }} <span class="fas fa-sort text-muted small"></span>
|
||||
</th>
|
||||
<th class="text-right" style="width:16rem">{{ __('Aktion') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -86,7 +89,7 @@
|
|||
$rowClass = $row['status'] === 'critical' ? 'is-danger' : ($row['status'] === 'warning' ? 'is-warning' : '');
|
||||
$stockClass = $row['status'] === 'critical' ? 'text-danger font-weight-bold' : ($row['status'] === 'warning' ? 'text-warning font-weight-bold' : '');
|
||||
@endphp
|
||||
<tr class="ps-row {{ $rowClass }}" data-name="{{ Str::lower($product->name) }} {{ Str::lower($product->number ?? '') }}" data-status="{{ $row['status'] }}">
|
||||
<tr class="ps-row {{ $rowClass }}" data-name="{{ Str::lower($product->name) }} {{ Str::lower($product->number ?? '') }}" data-status="{{ $row['status'] }}" data-rank="{{ ['critical' => 0, 'warning' => 1, 'ok' => 2][$row['status']] }}">
|
||||
<td>
|
||||
@if ($product->images->count())
|
||||
<img class="wawi-thumb" alt=""
|
||||
|
|
@ -104,6 +107,13 @@
|
|||
<td class="text-right {{ $stockClass }}">
|
||||
{{ \App\Services\Util::formatNumber($row['stock'], 0) }} <span class="text-muted">{{ __('Stück') }}</span>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
@if ($row['monthly_consumption'] > 0)
|
||||
{{ \App\Services\Util::formatNumber($row['monthly_consumption'], 1) }} <span class="text-muted">{{ __('Stück') }}</span>
|
||||
@else
|
||||
<span class="text-muted">–</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($row['status'] === 'critical')
|
||||
<span class="wawi-pill wawi-pill--danger">{{ __('Kritisch') }}</span>
|
||||
|
|
@ -131,7 +141,7 @@
|
|||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<td colspan="6">
|
||||
<div class="wawi-empty">
|
||||
<div><span class="fas fa-boxes-stacked"></span></div>
|
||||
{{ __('Keine Produkte vorhanden.') }}
|
||||
|
|
@ -188,6 +198,7 @@
|
|||
<script>
|
||||
$(function () {
|
||||
var $rows = $('#ps-table tbody tr.ps-row');
|
||||
var statusFilter = null; // null = alle; sonst 'ok' | 'warning' | 'critical'
|
||||
|
||||
function applyFilter() {
|
||||
var term = ($('#ps-search').val() || '').toLowerCase().trim();
|
||||
|
|
@ -197,23 +208,39 @@
|
|||
var matchesTerm = term === '' || ($row.data('name') || '').toString().indexOf(term) !== -1;
|
||||
var status = $row.data('status');
|
||||
var matchesCritical = !onlyCritical || (status === 'critical' || status === 'warning');
|
||||
$row.toggle(matchesTerm && matchesCritical);
|
||||
var matchesStatus = statusFilter === null || status === statusFilter;
|
||||
$row.toggle(matchesTerm && matchesCritical && matchesStatus);
|
||||
});
|
||||
}
|
||||
|
||||
$('#ps-search').on('keyup', applyFilter);
|
||||
$('#ps-only-critical').on('change', applyFilter);
|
||||
|
||||
// AP-22: alle vier Kacheln filtern (Produkte = Filter aufheben, OK/Niedrig/Kritisch = nur dieser Status).
|
||||
$('.wawi-stat.is-clickable').on('click', function () {
|
||||
var filter = $(this).data('filter');
|
||||
var $this = $(this);
|
||||
var wasActive = $this.hasClass('is-active');
|
||||
$('.wawi-stat').removeClass('is-active');
|
||||
if (filter === 'critical' || filter === 'warning') {
|
||||
$('#ps-only-critical').prop('checked', !wasActive);
|
||||
if (!wasActive) { $this.addClass('is-active'); }
|
||||
applyFilter();
|
||||
$('#ps-only-critical').prop('checked', false);
|
||||
if (filter === 'all' || wasActive) {
|
||||
statusFilter = null;
|
||||
} else {
|
||||
statusFilter = filter;
|
||||
$this.addClass('is-active');
|
||||
}
|
||||
applyFilter();
|
||||
});
|
||||
|
||||
// AP-22: Klick auf „Status" sortiert nach Dringlichkeit (Default bereits dringlichste oben; Klick toggelt).
|
||||
var statusSortAsc = true; // Server liefert bereits kritisch → ok
|
||||
$('#ps-sort-status').on('click', function () {
|
||||
statusSortAsc = !statusSortAsc;
|
||||
var sorted = $rows.get().sort(function (a, b) {
|
||||
var diff = ($(a).data('rank') - $(b).data('rank'));
|
||||
return statusSortAsc ? diff : -diff;
|
||||
});
|
||||
$('#ps-table tbody').append(sorted);
|
||||
});
|
||||
|
||||
var moveTemplate = "{{ route('admin.inventory.product-stock.movement', ['product' => '__ID__']) }}";
|
||||
|
|
|
|||
|
|
@ -572,7 +572,7 @@
|
|||
var indefinite = $('#out_of_stock_indefinite').is(':checked');
|
||||
var active = $('#out_of_stock_active').is(':checked');
|
||||
$('#out_of_stock_active').prop('disabled', indefinite);
|
||||
$('.js-out-of-stock-days').toggle(active && !indefinite);
|
||||
$('.js-out-of-stock-date').toggle(active && !indefinite);
|
||||
}
|
||||
$(document).on('change', '#out_of_stock_active, #out_of_stock_indefinite', toggleOutOfStock);
|
||||
toggleOutOfStock();
|
||||
|
|
|
|||
|
|
@ -103,18 +103,18 @@
|
|||
<div class="card mb-2" id="product-section-verfuegbarkeit">
|
||||
<h5 class="card-header">{{ __('Verfügbarkeit') }}</h5>
|
||||
<div class="card-body">
|
||||
@php($outOfStockDays = $product->outOfStockRemainingDays())
|
||||
@php($outOfStockActive = $product->out_of_stock_until !== null && $product->out_of_stock_until->endOfDay()->isFuture())
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox">
|
||||
{!! Form::checkbox('out_of_stock_active', 1, old('out_of_stock_active', $outOfStockDays !== null), ['class' => 'custom-control-input', 'id' => 'out_of_stock_active']) !!}
|
||||
<span class="custom-control-label">{{ __('Vorübergehend nicht vorrätig (mit Zeitangabe)') }}</span>
|
||||
{!! Form::checkbox('out_of_stock_active', 1, old('out_of_stock_active', $outOfStockActive), ['class' => 'custom-control-input', 'id' => 'out_of_stock_active']) !!}
|
||||
<span class="custom-control-label">{{ __('Vorübergehend nicht vorrätig (mit Datum)') }}</span>
|
||||
</label>
|
||||
<p class="text-muted small mb-0">{{ __('Zeigt im Shop den Hinweis „In ca. X Tagen wieder da!". Der Kauf bleibt weiterhin möglich.') }}</p>
|
||||
<p class="text-muted small mb-0">{{ __('Zeigt im Shop den Hinweis „In ca. X Tagen wieder da!" – die Tage zählen täglich automatisch herunter. Der Kauf bleibt weiterhin möglich.') }}</p>
|
||||
</div>
|
||||
<div class="form-row js-out-of-stock-days" style="display:none;">
|
||||
<div class="form-row js-out-of-stock-date" style="display:none;">
|
||||
<div class="form-group col-sm-4">
|
||||
<label class="form-label" for="out_of_stock_days">{{ __('Wieder verfügbar in (Tagen)') }}</label>
|
||||
{{ Form::number('out_of_stock_days', old('out_of_stock_days', $outOfStockDays), ['placeholder' => __('z. B. 14'), 'class' => 'form-control', 'id' => 'out_of_stock_days', 'min' => 0, 'step' => 1]) }}
|
||||
<label class="form-label" for="out_of_stock_date">{{ __('Wieder lieferbar ab') }}</label>
|
||||
{{ Form::text('out_of_stock_date', old('out_of_stock_date', optional($product->out_of_stock_until)->format('d.m.Y')), ['placeholder' => __('tt.mm.jjjj'), 'class' => 'form-control datepicker-base', 'id' => 'out_of_stock_date', 'autocomplete' => 'off']) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1029,6 +1029,14 @@
|
|||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox">
|
||||
{!! Form::checkbox('show_in_product_stock', 1, old('show_in_product_stock', $product->exists ? $product->show_in_product_stock : true), ['class' => 'custom-control-input', 'id' => 'show_in_product_stock']) !!}
|
||||
<span class="custom-control-label">{{ __('Im Produktbestand anzeigen') }}</span>
|
||||
</label>
|
||||
<p class="text-muted small mb-0">{{ __('Abwählen für Positionen ohne Lagerführung (z. B. Abrechnung Druckkosten, Logo-Etiketten).') }}</p>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-2">{{ __('Produktbestand-Schwellwerte (Stück). Bei Erreichen wird das Produkt im Produktbestand farblich markiert.') }}</p>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-sm-6">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue