From d03371dca18d6230e85e61f08a3418fe30ba8b39 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Thu, 2 Jul 2026 14:55:05 +0000 Subject: [PATCH] Auto-save drafts, reorder float/takings, 5-col reconciliation table - Auto-save: every 60s while editing, silently saves draft if form has data. Status "Auto-saved at HH:MM" appears next to the Save Draft button briefly. - Float Count moved above Cash Takings and defaults to open so staff count the float first before counting takings. - Reconciliation table gains a fifth "Card Total" column: PDQ Visa/MC and PDQ Amex rows share a rowspan=2 cell showing the combined PDQ variance. If the per-category rows are red but the combined is green it means only the Visa/Amex split was mis-allocated, not an actual cash discrepancy (labelled "split only"). Gateway rows similarly grouped (always auto 0). Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/pages/DailyCashUp.tsx | 100 +++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/frontend/src/pages/DailyCashUp.tsx b/frontend/src/pages/DailyCashUp.tsx index f3aa284..8375b57 100644 --- a/frontend/src/pages/DailyCashUp.tsx +++ b/frontend/src/pages/DailyCashUp.tsx @@ -53,7 +53,9 @@ export function DailyCashUp({ user }: Props) { const [fetching, setFetching] = useState(false) const [saving, setSaving] = useState(false) const [msg, setMsg] = useState<{ text: string; ok: boolean } | null>(null) - const [showFloat, setShowFloat] = useState(false) + const [showFloat, setShowFloat] = useState(true) + const [autoSaveMsg, setAutoSaveMsg] = useState('') + const autoSaveFnRef = useRef<() => void>(() => {}) const isFinal = pageState === 'locked' @@ -98,6 +100,33 @@ export function DailyCashUp({ user }: Props) { setPageState(data.cash_up.status === 'final' ? 'locked' : 'editing') } + // Auto-save ref — updated every render so the interval always captures latest state + autoSaveFnRef.current = () => { + if (pageState !== 'editing' || saving) return + const allDenoms = [...takings, ...float].filter(d => d.total_amount > 0) + if (allDenoms.length === 0 && machines.every(m => m.total_amount === 0) && !notes) return + api.post('/cashup/save', { + session_date: date, status: 'draft', notes, checked_transactions: [...checkedItems], + denominations: allDenoms.map(d => ({ + count_type: d.count_type, type: d.denomination_type, value: d.denomination_value, + quantity: d.quantity, value_entered: d.value_entered, total_amount: d.total_amount, + })), + card_machines: machines.map(m => ({ + name: m.machine_name, total: m.total_amount, amex: m.amex_amount, visa_mc: m.visa_mc_amount, + })), + }).then(() => { + setAutoSaveMsg('Auto-saved at ' + new Date().toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })) + setTimeout(() => setAutoSaveMsg(''), 5000) + }).catch(() => {}) + } + + // Run auto-save every 60 s while editing + useEffect(() => { + if (pageState !== 'editing') return + const interval = setInterval(() => autoSaveFnRef.current(), 60_000) + return () => clearInterval(interval) + }, [pageState]) + // Fetch till float target once on mount useEffect(() => { api.get<{ till_float_target?: string }>('/settings') @@ -230,6 +259,9 @@ export function DailyCashUp({ user }: Props) { const totalPdq = machines.reduce((s, m) => s + m.total_amount, 0) const floatCounted = denomTotal(float) const floatVariance = tillFloatTarget > 0 ? floatCounted - tillFloatTarget : null + // Combined PDQ variance: accounts for Visa/Amex split being misallocated between machines + const pdqCombinedReported = newbookTotals ? newbookTotals.manual_visa_mc + newbookTotals.manual_amex : 0 + const pdqCombinedVariance = totalPdq - pdqCombinedReported return (
@@ -283,16 +315,7 @@ export function DailyCashUp({ user }: Props) { {(pageState === 'editing' || pageState === 'locked') && <> - {/* Cash denomination — Takings */} - -
-

Cash Takings

- {fmtGBP(denomTotal(takings))} -
- updateDenom(takings, setTakings, i, f, v)} disabled={isFinal} tabBase={0} /> -
- - {/* Float (collapsible) */} + {/* Float Count — shown first so staff confirm float before counting takings */}