feat(booth): overstay sessions, top-up pricing, and session/feed filters
Rework paid-but-grace-expired sessions and add booth filters. Overstay (was "stuck"): - Stop silently aging out a paid transient whose walk-back grace lapsed with no signed exit. Keep it listed with an OVERSTAY badge — a new parking period began (re-parked) or the car is faulty/abandoned; it is not a system fault. - No free exit: reopenBarrier refuses server-side once a transient's payment grace has expired (allow only subscription OR paid-and-within-grace); the UI hides the Open-barrier button on overstay rows and routes to the pay/exit modal. Closes a hole where a stale payment authorized a free multi-day exit (operator-as-adversary). - Price the overstay as a NEW period from grace-expiry -> now with its own daily-cap ladder, NOT "full stay minus paid" (which a daily cap collapsed to 0 — ticket 1245791632490 owed ALL 0; now owes its real overstay). quote() gains periodStart + overstay; SessionLookup/ActiveSession gain `overstay`. handlePayAndExit charges whenever the session is payable (was: only if !alreadyPaid, skipping the overstay). Filters (new ui/FilterBar): Active Sessions — search + status (unpaid/paid/exiting/overstay) + transient-vs-subscriber. Live feed — search + event (entry/exit/pay/void/anomaly) + direction + source (booth=manual vs reader). All client-side over already-fetched data; matched/total count shown. i18n parity (sq+en). Wiki: booth-exit-flow updated (overstay model, naming history, no-free-exit security fix, new-period pricing; open question on grace-renewal noted). Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -59,11 +59,11 @@ export const en: Catalog = {
|
||||
devices: {
|
||||
footerTitle: "Devices",
|
||||
none: "No devices configured.",
|
||||
catAccess: "Barrier",
|
||||
catAccess: "Relay",
|
||||
catReader: "Reader",
|
||||
catCamera: "Camera",
|
||||
catPrinter: "Printer",
|
||||
catVision: "Vision",
|
||||
catVision: "ANPR",
|
||||
// Role/direction suffixes for the chip label (e.g. "Reader entry").
|
||||
role: {
|
||||
entry: "entry",
|
||||
@@ -101,6 +101,29 @@ export const en: Catalog = {
|
||||
activeSessions: "Active sessions",
|
||||
insideCount: "inside",
|
||||
noActiveSessions: "No active sessions.",
|
||||
noMatch: "No sessions match the filter.",
|
||||
badgeOverstay: "overstay",
|
||||
badgeOverstayTitle:
|
||||
"Paid session. The customer failed to exit during the grace period. A new period began.",
|
||||
// filters
|
||||
filterSearchSessions: "Search ticket / subscriber / plate…",
|
||||
filterSearchFeed: "Search event / identity / plate…",
|
||||
filterAll: "All",
|
||||
fStatusUnpaid: "Unpaid",
|
||||
fStatusPaid: "Paid",
|
||||
fStatusExiting: "Exiting",
|
||||
fStatusOverstay: "Overstay",
|
||||
fKindTransient: "Transient",
|
||||
fKindSubscription: "Subscribers",
|
||||
fDirEntry: "Entry",
|
||||
fDirExit: "Exit",
|
||||
fSrcBooth: "Booth",
|
||||
fSrcReader: "Reader",
|
||||
fEvtEntry: "Entry",
|
||||
fEvtExit: "Exit",
|
||||
fEvtPay: "Pay",
|
||||
fEvtVoid: "Void",
|
||||
fEvtAnomaly: "Anomaly",
|
||||
openPayExit: "Open pay / exit",
|
||||
openBarrier: "Open barrier",
|
||||
openBarrierTitle: "Human-intervention barrier open (audited)",
|
||||
@@ -523,6 +546,9 @@ export const en: Catalog = {
|
||||
statusLabel: "Status",
|
||||
paid: "PAID",
|
||||
unpaid: "UNPAID",
|
||||
overstay: "OVERSTAY",
|
||||
overstayHint: "Earlier session paid. The customer failed to exit during the grace period. Payment for the new period is required. The total below is the new period's fee.",
|
||||
topUp: "New period due",
|
||||
total: "Total",
|
||||
noTariff: "no tariff",
|
||||
tender: "Tender",
|
||||
|
||||
Reference in New Issue
Block a user