From 2e9b4a2ca3a4539a3fffd76a55bb1065a8b98a7b Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Mon, 3 Aug 2026 08:53:00 +0000 Subject: [PATCH] Let admins unfinalise a cash up from history Adds POST /api/cashup/:id/unfinalise (admin-only) to revert a finalised cash up back to draft so it can be corrected, plus an Unfinalise button in the history table for admin users. --- backend/src/routes/cashup.js | 13 +++++++++++++ frontend/src/pages/History.tsx | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/backend/src/routes/cashup.js b/backend/src/routes/cashup.js index 06f357d..5e89756 100644 --- a/backend/src/routes/cashup.js +++ b/backend/src/routes/cashup.js @@ -117,6 +117,19 @@ export async function cashupRoutes(app) { return { message: 'Deleted' } }) + // POST /api/cashup/:id/unfinalise (admin only) + app.post('/api/cashup/:id/unfinalise', async (req, reply) => { + if (!req.user.is_admin) return reply.status(403).send({ error: 'Admin only' }) + const { rows } = await pool.query('SELECT status FROM cash_ups WHERE id = $1', [req.params.id]) + if (!rows.length) return reply.status(404).send({ error: 'Not found' }) + if (rows[0].status !== 'final') return reply.status(409).send({ error: 'Not finalised' }) + await pool.query( + 'UPDATE cash_ups SET status=$1, submitted_at=NULL, submitted_by=NULL WHERE id=$2', + ['draft', req.params.id] + ) + return { message: 'Cash up reverted to draft.' } + }) + // POST /api/cashup/bulk-finalize (requires cashup:finalise) app.post('/api/cashup/bulk-finalize', async (req, reply) => { if (!hasCap(req, 'finalise')) return reply.status(403).send({ error: 'Missing capability: finalise' }) diff --git a/frontend/src/pages/History.tsx b/frontend/src/pages/History.tsx index caf21e0..9ca3dec 100644 --- a/frontend/src/pages/History.tsx +++ b/frontend/src/pages/History.tsx @@ -56,6 +56,13 @@ export function History({ user }: { user: User }) { load() } + async function unfinalise(id: number) { + if (!confirm('Revert this cash up to draft so it can be edited?')) return + await api.post(`/cashup/${id}/unfinalise`, {}) + flash('Reverted to draft.') + load() + } + async function bulkFinalize() { if (!selected.size) return if (!confirm(`Finalise ${selected.size} draft(s)?`)) return @@ -155,6 +162,9 @@ export function History({ user }: { user: User }) { {canFinalise && row.status === 'draft' && ( deleteDraft(row.id)}>Delete )} + {user.is_admin && row.status === 'final' && ( + unfinalise(row.id)}>Unfinalise + )} ))}