qr_code_batches + qr_codes tables. State machine via
spatie/laravel-model-states (unassigned → allocated → active → used,
plus expired/voided). Serial format PH-{area}-{YYMM}-{batch}-{code}-
{checksum} with 2-char SHA-256-derived checksum. BatchGenerator
bulk-inserts in chunks. QrAllocator allocates free codes to verified
households (prefers area-targeted batch, falls back to any). Real
HouseholdVerified listener replaces the placeholder. QrBalanceLow
event for Module 11.
Admin: batch CRUD, mark-printed, void code, lifecycle search, PDF
print sheet (24/A4 via dompdf + endroid/qr-code + picqer/barcode).
Resident: list own codes, balance with low_balance flag, activate
allocated codes.
Removed explicit Event::listen for HouseholdVerified — Laravel 11
auto-discovers it via handle() type-hint, and double-registering was
causing double-dispatch.
130 feature tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.0 KiB
PHP
61 lines
2.0 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Verde QR Batch {{ $batch->batch_number }}</title>
|
|
<style>
|
|
@page { margin: 8mm; }
|
|
* { box-sizing: border-box; }
|
|
body { font-family: DejaVu Sans, sans-serif; margin: 0; padding: 0; }
|
|
.header { font-size: 9pt; margin-bottom: 4mm; }
|
|
.header strong { font-size: 11pt; }
|
|
.grid {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
table-layout: fixed;
|
|
}
|
|
.grid td {
|
|
width: 25%;
|
|
border: 1px dashed #999;
|
|
padding: 3mm 2mm;
|
|
vertical-align: top;
|
|
text-align: center;
|
|
}
|
|
.qr { width: 32mm; height: 32mm; }
|
|
.barcode { width: 38mm; height: 9mm; margin-top: 1mm; }
|
|
.serial { font-size: 7pt; word-break: break-all; margin-top: 1mm; font-family: monospace; }
|
|
.pagebreak { page-break-after: always; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
@foreach ($pages as $pageIndex => $page)
|
|
<div class="header">
|
|
<strong>Verde — Batch {{ $batch->batch_number }}</strong>
|
|
· {{ $batch->purpose }}
|
|
· {{ count($page) }} of {{ $batch->quantity }} codes
|
|
· page {{ $pageIndex + 1 }}/{{ count($pages) }}
|
|
</div>
|
|
<table class="grid">
|
|
@php $rows = array_chunk($page, 4); @endphp
|
|
@foreach ($rows as $row)
|
|
<tr>
|
|
@foreach ($row as $cell)
|
|
<td>
|
|
<img class="qr" src="{{ $cell['qr_data_uri'] }}" alt="QR">
|
|
<img class="barcode" src="{{ $cell['barcode_data_uri'] }}" alt="Code-128">
|
|
<div class="serial">{{ $cell['serial'] }}</div>
|
|
</td>
|
|
@endforeach
|
|
@for ($i = count($row); $i < 4; $i++)
|
|
<td> </td>
|
|
@endfor
|
|
</tr>
|
|
@endforeach
|
|
</table>
|
|
@if ($pageIndex < count($pages) - 1)
|
|
<div class="pagebreak"></div>
|
|
@endif
|
|
@endforeach
|
|
</body>
|
|
</html>
|