gruene-seele/app/helpers.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

147 lines
4.1 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.

<?php
use App\Services\InventoryService;
if (! function_exists('make_old_url')) {
function make_old_url($path)
{
return config('app.old_url').$path;
}
}
if (! function_exists('make_old_url')) {
function make_old_url($path)
{
return config('app.old_url').$path;
}
}
if (! function_exists('get_file_last_time')) {
function get_file_last_time($value)
{
if (file_exists($value)) {
return filemtime($value);
}
return date('Ymd-is', time());
}
}
if (! function_exists('get_user_attr')) {
function get_user_attr($key)
{
if ($user = Auth::user()) {
return $user->getSetting($key);
}
return null;
}
}
if (! function_exists('set_user_attr')) {
function set_user_attr($key, $value)
{
if ($user = Auth::user()) {
return $user->setSetting([$key => $value]);
}
return null;
}
}
if (! function_exists('get_active_badge')) {
function get_active_badge($active, $tooltip = false, $pos = 'top')
{
if ($tooltip) {
$tooltip = 'data-toggle="tooltip" data-placement="top" data-original-title="'.$tooltip.'"';
}
return $active ? '<span class="badge badge-pill badge-success" '.$tooltip.'><i class="fa fa-check"></i></span>' : '<span class="badge badge-pill badge-danger" '.$tooltip.'><i class="fa fa-times"></i></span>';
}
}
if (! function_exists('formatDate')) {
function formatDate($date)
{
return Carbon::parse($date)->format(Util::formatDateDB());
}
}
if (! function_exists('formatNumber')) {
function formatNumber($number, $dec = 2)
{
return ! $number ? $number : Util::formatNumber($number, $dec);
}
}
if (! function_exists('reFormatNumber')) {
function reFormatNumber($number)
{
return ! $number ? $number : Util::reFormatNumber($number);
}
}
if (! function_exists('reFormatWawiNumber')) {
/**
* Eingabe-Parsing der Warenwirtschaft (Audit N-6, Kundenentscheid 15.07.2026):
* Ein einzelner Punkt mit genau 1–2 Nachkommastellen gilt als Dezimaltrenner
* („5.1" = 5,1 · „5.12" = 5,12 — kommt beim Kopieren von Daten vor);
* alles andere („1.500", „1.234,56") folgt der deutschen Konvention.
*/
function reFormatWawiNumber($number)
{
// AP-53 (09.09.2026): zusätzlich „0.xxx" mit drei Stellen als Dezimalzahl —
// ein Tausenderpunkt hinter einer 0 ergibt keinen Sinn. „1.500" bleibt 1500.
if (is_string($number) && preg_match('/^-?(\d+\.\d{1,2}|0\.\d{3})$/', trim($number))) {
return (float) trim($number);
}
return reFormatNumber($number);
}
}
if (! function_exists('roundWawiQuantity')) {
/**
* AP-53: Mengenrundung der Warenwirtschaft (Gramm) — einheitlich drei
* Nachkommastellen (Milligramm), siehe InventoryService::QUANTITY_DECIMALS.
*/
function roundWawiQuantity($value): float
{
return round((float) $value, InventoryService::QUANTITY_DECIMALS);
}
}
if (! function_exists('formatWawiQuantity')) {
/**
* AP-53: Mengenanzeige (deutsch) mit bis zu drei Nachkommastellen; mindestens
* $minDecimals werden gezeigt (Standard 2: „12,50", „0,125", „1.500,00").
*/
function formatWawiQuantity($value, int $minDecimals = 2): string
{
$max = InventoryService::QUANTITY_DECIMALS;
$rounded = round((float) $value, $max);
$decimals = $max;
$asString = number_format($rounded, $max, '.', '');
while ($decimals > $minDecimals && str_ends_with($asString, '0')) {
$asString = substr($asString, 0, -1);
$decimals--;
}
return number_format($rounded, $decimals, ',', '.');
}
}
if (! function_exists('formatPlural')) {
function formatPlural($count, $singular, $plural)
{
return Util::formatPlural($count, $singular, $plural);
}
}
if (! function_exists('substr_ellipsis')) {
function substr_ellipsis($str, $len = 100, $clean = false, $ell = '...')
{
return Util::substr_ellipsis($str, $len, $clean, $ell);
}
}