← All tasks

v0.2 Slice E2 — Close-shift Odoo-style + Daily Sale CSV PROD · GATE 2

H3.4's three sub-features verified end-to-end on get-coffee (Pro): Odoo-style per-payment-type layout, Cash In/Out button mounted from inside the close dialog, and the new Daily Sale CSV endpoint actually serving the file (after a parameter-order fix on the first push).

8/8 prod checks green · 51/51 regression green — no regressions. Commits e8a0413 + 14df545. 6 files + 1 new endpoint + 2 new DAOs, no migration.

What's live

H3.4Close-shift dialog opens in the Odoo-style layout

On prod, clicking "Close shift" now opens the dialog Narong sketched in his screenshot: header "N orders · $X" on the right, a Cash section with Opening / Payments / Cash in/out / Counted / Expected sub-rows, one per-method section per non-cash payment method (Card / KHQR / ABA / Bakong) showing just the total. Title is now "Closing Register" (was "Close shift"). All five existing testids (close-shift-cash, close-shift-diff, close-shift-reason, etc.) are preserved so the regression suite + Slice D's session-close tests still pass.

H3.4Cash In/Out button — mounts on top, close dialog stays

Clicking the new close-shift-open-cash button opens the shared CashMovementDialog as a stacked dialog. The close dialog is still in the DOM underneath (asserted in the test) — closing the cash dialog returns the cashier to the close screen, ready to enter Cash count and close. Same pattern works on Starter via the onOpenCashMovements callback the close dialog gets from the parent shell.

H3.4Daily Sale CSV endpoint serves real files

New GET /cafe/api/cafe/sessions/[sessionId]/daily-sale returns CSV with the expected columns (order_number, time, customer, payment_methods, total_usd, state, refunded_at); Content-Type text/csv; Content-Disposition attachment; filename includes session date + short UUID. Click "Daily Sale ⬇" in the dialog and the browser saves the file natively. Caught + fixed mid-Gate-2: first push had getNixSessionById(tenant.id, sessionId) — args swapped; the DAO signature is (id, tenantId), so every fetch 404'd. The dialog still rendered the correct href; the bug was server-side. One-line fix (14df545), 7/8 → 8/8 on re-run.

Screenshots + the actual CSV

Close-shift dialog on prod (get-coffee Pro) — Odoo-style header + Cash section + Daily Sale + Cash In/Out buttons in the buttons row
Cash In/Out clicked — CashMovementDialog opens on top, close dialog stays mounted underneath

CSV the test downloaded: daily-sale.csv (this run joined a pre-existing session with no orders — the file has just the header row, which is the right behaviour for an empty session).

Checks — 8/8

Regression — 51/51, no regressions from this push

All prod suites green.
test-phase1-prod.mjs11/11
test-phase2-sso-outdoor-prod.mjs6/6
test-phase2-cafe-multishop-prod.mjs6/6
test-m1-prod.mjs10/10
test-r7-prod.mjs14/14
test-r8-prod.mjs4/4
+ test-v0-2-slice-e2-prod.mjs8/8
Total59/59

Files changed (6 modified + 1 new, no migration)

New: app/api/cafe/sessions/[sessionId]/daily-sale/route.ts
Modified: lib/db/orders.ts (+2 DAOs) · app/(pos-fullscreen)/pos/register/[configId]/page.tsx · app/(pos-fullscreen)/pos/register/[configId]/lockable-shell.tsx (Pro dialog rewrite) · app/(authed)/pos/_components/starter-lockable-shell.tsx · app/(authed)/pos/_components/starter-close-shift-dialog.tsx (Starter dialog rewrite)