Update OCR-Positionsauswahl nach Uebernahme konsistent.

Bereits uebernommene Positionen bleiben in der OCR-Liste abgewaehlt und manuell demarkierte Zeilen werden pro Bon gespeichert, damit die Auswahl auch nach erneutem OCR erhalten bleibt.

Made-with: Cursor
This commit is contained in:
Stefan Zwischenbrugger 2026-04-01 12:54:28 +02:00
parent 092e3b2a61
commit bec9b466fc
2 changed files with 32 additions and 1 deletions

View File

@ -115,6 +115,9 @@ class ReceiptScanController extends Controller
if (isset($previousMeta['validated_at'])) {
$rawMeta['validated_at'] = $previousMeta['validated_at'];
}
if (isset($previousMeta['item_selection_state']) && is_array($previousMeta['item_selection_state'])) {
$rawMeta['item_selection_state'] = $previousMeta['item_selection_state'];
}
$nextStoreName = $receiptScan->store_name;
if (trim((string) $nextStoreName) === '' && is_string($ocr['store_name'] ?? null) && trim($ocr['store_name']) !== '') {
@ -182,6 +185,17 @@ class ReceiptScanController extends Controller
$prices = $validated['row_prices'] ?? [];
$qtys = $validated['row_qty'] ?? [];
$take = $validated['row_take'] ?? [];
$selectionState = [];
foreach ($labels as $i => $labelRaw) {
$label = trim((string) $labelRaw);
if ($label === '') {
continue;
}
$priceRaw = trim((string) ($prices[$i] ?? ''));
$qtyRaw = trim((string) ($qtys[$i] ?? ''));
$selectionKey = $this->suggestionRowKey($label, $priceRaw, $qtyRaw);
$selectionState[$selectionKey] = isset($take[$i]);
}
$rows = collect($labels)
->map(function ($label, $i) use ($prices, $qtys, $take) {
@ -285,6 +299,7 @@ class ReceiptScanController extends Controller
$meta = is_array($receiptScan->raw_meta) ? $receiptScan->raw_meta : [];
$meta['validated_items'] = $rows->all();
$meta['validated_at'] = Carbon::now()->toISOString();
$meta['item_selection_state'] = $selectionState;
$receiptScan->update(['raw_meta' => $meta]);
return back()->with(
@ -398,6 +413,11 @@ class ReceiptScanController extends Controller
return trim(preg_replace('/\s+[A-E]\s*$/u', '', $raw) ?? $raw);
}
private function suggestionRowKey(string $label, string $priceRaw, string $quantityRaw): string
{
return mb_strtolower(trim($label)).'|'.trim($priceRaw).'|'.trim($quantityRaw);
}
/**
* @return list<array{label: string, price_raw: string, quantity_raw: string, is_uncertain: bool}>
*/

View File

@ -149,6 +149,9 @@
->filter()
->all();
$appliedSet = array_flip($appliedLowerKeys);
$selectionState = is_array($scan->raw_meta['item_selection_state'] ?? null)
? $scan->raw_meta['item_selection_state']
: [];
@endphp
<div class="mt-3 rounded-md border border-blue-200 bg-blue-50 p-3">
<p class="text-xs font-semibold text-blue-900">
@ -177,13 +180,21 @@
$listKey = mb_strtolower(trim($label));
$listStatus = $listProductLookup[$listKey] ?? null;
$wasAppliedFromReceipt = $listKey !== '' && isset($appliedSet[$listKey]);
$selectionKey = $listKey.'|'.trim((string) $priceRaw).'|'.trim((string) $qtyRaw);
$storedSelection = $selectionState[$selectionKey] ?? null;
$defaultChecked = $storedSelection !== null
? (bool) $storedSelection
: (! $isUncertain);
if ($wasAppliedFromReceipt) {
$defaultChecked = false;
}
@endphp
<div class="receipt-suggestion-row flex flex-nowrap items-center gap-2 w-full min-w-0 {{ $isUncertain ? 'opacity-85' : '' }}">
<input
type="checkbox"
name="row_take[{{ $rowIndex }}]"
value="1"
@checked(! $isUncertain)
@checked($defaultChecked)
class="shrink-0 rounded border-gray-300 text-blue-600 shadow-sm h-5 w-5 mt-0.5"
aria-label="Position als erledigt uebernehmen"
title="Uebernehmen"