server+web: shifts — open/close + signed Z-report (manned mode)
A shift is two signed ledger events, no mutable table: new shift_open event type + existing shift_z_report. The operator is the logged-in user (carried in event identity); a shift is open iff their latest shift event is a shift_open. ShiftService: close sums payment events in [start,end] by tender (cash/card, by payment time), appends the signed shift_z_report (totals/counts/window), and prints via a new generic PrinterDevice.printReport(title, lines) (Rongta ESC/POS text) to a booth-receipt printer. Print is best-effort — a failed print does not undo the signed close. Routes (cashier/operator/admin): GET /api/shift/current, POST /api/shift/open (409 if open), POST /api/shift/close (409 if none). Web ShiftControl in the shell (non-readonly): Start/End + Z-report totals. Verified: open -> double-open 409 -> payments (cash+card; one outside the window excluded) -> close totals correct + signed + printed -> close-again 409 -> re-open ok; readonly 403; verifyChain ok.
This commit is contained in:
@@ -52,6 +52,24 @@ login ————————————————————————
|
||||
That's the whole human-side requirement: **print the cash and the POS (if any).** No blind count,
|
||||
no variance gate, no manager override.
|
||||
|
||||
### As-built (2026-06-16)
|
||||
|
||||
- A shift is **two signed ledger events**, no mutable table (decision): `shift_open` (new event
|
||||
type) at start, `shift_z_report` at close. The operator is the **logged-in user**, carried in the
|
||||
event `identity`; a shift is **open** iff that operator's most recent shift event is a
|
||||
`shift_open`. `ShiftService` (`apps/server/src/shift-service.ts`).
|
||||
- **Close** sums `payment` events in `[startedAt, endedAt]` by tender (cash vs. card, by **payment
|
||||
time**), appends the signed `shift_z_report` (totals + counts + window), then **prints** via the
|
||||
new generic `PrinterDevice.printReport(title, lines)` (Rongta ESC/POS text) to a booth-receipt
|
||||
printer. Printing is best-effort — a failed print does **not** undo the signed close (the event is
|
||||
the record; `printed:false` is returned).
|
||||
- **Routes** (`routes/shift.ts`, cashier/operator/admin): `GET /api/shift/current`,
|
||||
`POST /api/shift/open` (409 if already open), `POST /api/shift/close` (409 if none open).
|
||||
**UI** `ShiftControl` in the app shell (non-readonly): Start/End + the Z-report totals.
|
||||
- Verified: open → double-open 409 → payments (cash+card, one dated outside the window excluded) →
|
||||
close totals correct + signed + printed → close-again 409 → re-open works; readonly 403;
|
||||
verifyChain ok.
|
||||
|
||||
## Where the fraud control actually lives
|
||||
|
||||
Deliberately **not** in a shift-close ceremony. Because every payment is a **signed event in the
|
||||
|
||||
+15
@@ -577,3 +577,18 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
create 403; update unbinds + REPLACES child rows (old cred gone); revoke→revoked; delete→204 then
|
||||
404, children cleaned. Full build 5/5.
|
||||
- Updated [[permit]] (CRUD as-built).
|
||||
|
||||
## [2026-06-16] build | Shifts: open/close + signed Z-report (manned mode)
|
||||
- Shift = two signed ledger events, NO mutable table: new `shift_open` event type + existing
|
||||
`shift_z_report`. Operator = logged-in user (in event `identity`); open iff their latest shift
|
||||
event is a `shift_open`. `apps/server/src/shift-service.ts`.
|
||||
- Close sums `payment` events in the window by tender (cash/card, by payment time) → signed
|
||||
`shift_z_report` (totals/counts/window) → prints via the NEW generic
|
||||
`PrinterDevice.printReport(title, lines)` (Rongta ESC/POS text) to a booth-receipt printer.
|
||||
Print is best-effort — failure doesn't undo the signed close (`printed:false` returned).
|
||||
- Routes (`routes/shift.ts`, cashier/operator/admin): GET /api/shift/current, POST open (409 if
|
||||
open), POST close (409 if none). UI `ShiftControl` in the shell (non-readonly): Start/End + Z totals.
|
||||
- Added `printReport` to the PrinterDevice interface + Rongta driver (reusable for receipts later).
|
||||
- VERIFIED: open→double-open 409→payments (cash+card; one dated outside the window excluded)→close
|
||||
totals (cash 500/card 250/3)→close-again 409→re-open ok; readonly 403; verifyChain ok. Full build 5/5.
|
||||
- Updated [[shift]] (as-built).
|
||||
|
||||
Reference in New Issue
Block a user