server: pay station + fee calc — full transient loop now passes
computeFee() in @parking/shared: pure integer fee over a TariffStructure (stepped blocks, rolling-24h cap). Two edges fixed under test: grace uses RAW duration (not rounded-up minutes), and the block ladder resets each 24h day. PayStation + routes (GET /api/pay/quote, POST /api/pay): look up the open session, resolve the active tariff version (latest effectiveFrom <= entry), computeFee, append a signed payment event (amount/currency/tender/ tariffVersionId/graceExitMin). overrideMinor handles lost-ticket/dispute. PCI stays out of the app: tender only records cash/card. Verified end to end: entry -> quote (300 for 90min) -> pay -> exit opens and closes the session, verifyChain ok.
This commit is contained in:
+17
@@ -517,3 +517,20 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
- GAP flagged: lane_devices has no entry/exit DIRECTION model (door mapping hardcoded to 1 for exit);
|
||||
fine while entry=button/exit=read, but multi-reader lanes need a lane-direction/role model (ties to
|
||||
[[open-questions]] #1). Updated [[parking-session]] as-built + gap, [[index]].
|
||||
|
||||
## [2026-06-15] build | Pay station + fee calc; JWT 8h → until-logout
|
||||
- JWT: dropped the 8h `expiresIn` (server.ts global + login). Token now valid **until explicit
|
||||
logout**; cookie maxAge = 30 days so a browser restart doesn't log out an active operator
|
||||
(auth.ts `COOKIE_MAX_AGE_SECONDS`). Closes the pending change from the shift decision; updated
|
||||
[[local-jwt-auth]].
|
||||
- `computeFee(enteredAt, asOf, structure)` in `packages/shared` — pure integer fee calc.
|
||||
TWO BUGS caught by tests: (1) grace must use RAW duration, not the rounded-up minutes (a 10-min
|
||||
stay was being charged a full hour); (2) the block ladder must RESET each rolling-24h day (decision:
|
||||
day 2 restarts at first-block pricing → 25h = 1200 cap + 200). Both fixed; 9 cases pass.
|
||||
- Pay station (`apps/server/src/pay-station.ts` + routes `GET /api/pay/quote`, `POST /api/pay`):
|
||||
open session → active tariff version → computeFee → signed `payment` event (amount/currency/tender/
|
||||
tariffVersionId/graceExitMin); `overrideMinor` for lost-ticket/dispute. Cashier/operator/admin guard.
|
||||
- VERIFIED: full loop entry→quote(300 for 90min)→pay→exit opens+closes, verifyChain ok. (A
|
||||
raw-SQL backdate in one test correctly broke the chain — the tamper-evidence working, not a flow bug.)
|
||||
- Updated [[tariff]] (settled edges + as-built), [[parking-session]] (pay station as-built; full
|
||||
loop passes).
|
||||
|
||||
Reference in New Issue
Block a user