gruene-seele/resources/views/admin/inventory/stock-disposals/index.blade.php
Kevin Adametz b8180a06a1 Warenwirtschaft: AP-53 — Gramm-Mengen mit drei Nachkommastellen (Produktion, Wareneingang, Ausschuss)
Kundennachtrag 09.09.2026: Ist-Mengen je Charge in der Produktion sollen auf das Milligramm eingegeben werden können (z. B. 0,125 g). Bisher rundeten Datenbank (decimal 12,2), Bestandslogik, Anzeige und Toleranzsockel auf zwei Stellen; „0,125" wurde still zu 0,13, „0.125" nach der Punkt-Regel zu 125 g.

- Migration 2026_09_09_100000: production_ingredients.quantity_used, stock_entries.ordered_quantity/received_quantity, stock_disposals.quantity → decimal(12,3); Casts decimal:3. Auf der Dev-DB (Live-Kopie) ausgeführt, 53/78/7 Zeilen unverändert.
- InventoryService::QUANTITY_DECIMALS = 3; roundWawiQuantity() ersetzt alle round(…, 2) in InventoryService, ProductionService, StockDisposalController/-Request, StockEntryRepository/-Controller, RawMaterialStockController.
- formatWawiQuantity($v, $min = 2): bis drei Stellen, mindestens zwei — Produktionsdetail, Einkauf Liste/Detail/Formular, Ausschuss-Liste, Chargen-Rest im Rohstoff-Detail.
- Eingaberegel (reFormatWawiNumber, JS parseGerman/parseNumber): zusätzlich „0.xxx" als Dezimalzahl; „1.500" bleibt 1500. Produktions-JS: fmt() bis drei Stellen, fmtInput() schreibt gespeicherte Zahlen deutsch ins Feld (1,125 statt 1.125 = 1125).
- Soll-Ist-Toleranz: Sockel 0,05 → 0,005 g; Ausschuss min 0,001.
- Doku: Hinweise (Neu/geändert), Leitfaden Version 3.1 mit Abschnitt 26, Plan V7 AP-53, README (Deploy-Checkliste, Suite 378).

Tests: QuantityPrecisionTest (6) — Parsing, Anzeige, Produktion 0,125 g exakt + Rest 9,875 g, Entwurf 1,125 wiederöffnen, Toleranz Kleinmengen, Ausschuss 0,005 g.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 15:54:29 +00:00

106 lines
6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.layout-2')
@section('content')
@include('admin.inventory.partials.wawi-ui')
<div class="wawi-page">
<div class="wawi-page-head">
<div>
<h1 class="wawi-page-head__title">{{ __('Ausgang / Ausschuss') }}</h1>
<p class="wawi-page-head__subtitle">{{ __('Erfasste Bestandsabgänge von Rohstoffen und Verpackung') }}</p>
</div>
<div class="wawi-page-head__actions">
@if (Auth::user()->isAdmin())
<a href="{{ route('admin.inventory.stock-disposals.create') }}" class="btn btn-primary btn-sm">
<span class="fas fa-plus mr-1"></span>{{ __('Ausschuss erfassen') }}
</a>
@endif
</div>
</div>
<div class="wawi-card">
<div class="wawi-toolbar">
<form method="get" class="mb-0">
<select name="type" class="form-control form-control-sm" style="width:auto" onchange="this.form.submit()">
<option value="">{{ __('Alle Arten') }}</option>
<option value="ingredient" @selected($typeFilter === 'ingredient')>{{ __('Rohstoff') }}</option>
<option value="packaging" @selected($typeFilter === 'packaging')>{{ __('Verpackung') }}</option>
</select>
</form>
</div>
<div class="table-responsive">
<table class="table wawi-table">
<thead>
<tr>
<th>{{ __('Datum') }}</th>
<th>{{ __('Art') }}</th>
<th>{{ __('Artikel') }}</th>
<th>{{ __('Charge') }}</th>
<th>{{ __('Lagerort') }}</th>
<th class="text-right">{{ __('Menge') }}</th>
<th>{{ __('Grund') }}</th>
<th>{{ __('Hinweis') }}</th>
<th>{{ __('Mitarbeiter') }}</th>
<th></th>
</tr>
</thead>
<tbody>
@forelse($values as $disposal)
<tr>
<td>{{ $disposal->disposed_at?->format('d.m.Y') }}</td>
<td>
@if ($disposal->isIngredient())
<span class="wawi-pill wawi-pill--ok">{{ __('Rohstoff') }}</span>
@else
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">{{ __('Verpackung') }}</span>
@endif
</td>
<td><span class="wawi-item-name">{{ $disposal->articleName() }}</span></td>
<td>
@if ($disposal->stockEntry)
{{ $disposal->stockEntry->batch_number ?: '#'.$disposal->stockEntry->id }}
@else
<span class="text-muted">—</span>
@endif
</td>
<td>{{ $disposal->location?->name ?? '—' }}</td>
<td class="text-right text-danger font-weight-bold">
−{{ $disposal->unit === 'piece' ? \App\Services\Util::formatNumber($disposal->quantity, 0) : formatWawiQuantity($disposal->quantity) }}
{{ $disposal->unit === 'piece' ? __('Stück') : 'g' }}
</td>
<td>{{ $disposal->reason }}</td>
<td class="text-muted">{{ $disposal->note }}</td>
<td>{{ $disposal->user?->getFullName(false) ?: ($disposal->user?->email ?? '—') }}</td>
<td>
@if(Auth::user()->isAdmin())
<form action="{{ route('admin.inventory.stock-disposals.destroy', $disposal) }}" method="post" class="d-inline"
onsubmit="return confirm(@json(__('Ausschuss-Buchung wirklich löschen? Die Menge steht dem Bestand danach wieder zur Verfügung.')));">
@csrf
@method('DELETE')
<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>
</tr>
@empty
<tr>
<td colspan="10">
<div class="wawi-empty">
<div><span class="fas fa-dumpster"></span></div>
{{ __('Noch keine Ausgänge erfasst.') }}
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if(($listLimit ?? null) !== null && $values->count() >= $listLimit)
<p class="text-muted small px-3 pb-2 mb-0">
{{ __('Es werden die neuesten :n Abgänge angezeigt.', ['n' => $listLimit]) }}
<a href="{{ route('admin.inventory.stock-disposals.index', array_filter(['all' => 1, 'type' => $typeFilter])) }}">{{ __('Alle anzeigen') }}</a>
</p>
@endif
</div>
</div>
@endsection