Give every expense a receipt you can open
An expense recorded with a scan attached arrived in the database with no
scan at all. ExpenseForm uploaded the file and passed the path to
ExpenseService::recordExpense(), which builds its Expense::create() array
by hand and never copied the two attachment keys across — so the file
landed on disk and the row forgot about it. It landed on the `public`
disk too, which needs a storage symlink the containers never create, so
even a persisted path would have 404'd.
Receipts now go to the private disk and are read back through
ExpenseAttachmentController, which checks the permission, the academy and
the active branch before streaming a byte.
The list was also a dead end: a row showed a number and a description and
offered nothing but "cancel". Rows are now clickable and carry a view
button, with a paperclip marking the ones that have evidence behind them.
The new detail page is where the expense explains itself — amount,
category, recipient, method, receipt reference, branch, notes, who
recorded it and when, and, if it was cancelled, by whom and why. Below
that sit the journal entries it produced, the original debit/credit pair
and any reversing entry, so the accounting effect is visible rather than
implied. The receipt itself previews inline: images as images, PDFs in a
frame, with download beside them.
An expense recorded without a scan is no longer stuck that way — attach
one from the detail page, replace it (the displaced file is deleted), or
remove it. Every attachment records who uploaded it and when. A cancelled
expense refuses all three: its evidence is frozen with its journal.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>
Showing
This diff is collapsed.
This diff is collapsed.
Please register or sign in to comment