• Claude's avatar
    Give every expense a receipt you can open · cc417ba9
    Claude authored
    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: 's avatarClaude Opus 5 <noreply@anthropic.com>
    cc417ba9
Name
Last commit
Last update
..
activities Loading commit data...
admin Loading commit data...
assignments Loading commit data...
attendance Loading commit data...
audit Loading commit data...
auth Loading commit data...
branches Loading commit data...
cash-sessions Loading commit data...
components Loading commit data...
dashboard Loading commit data...
documents Loading commit data...
enrollments Loading commit data...
evaluations Loading commit data...
events Loading commit data...
facilities Loading commit data...
financial Loading commit data...
groups Loading commit data...
guardian Loading commit data...
hr Loading commit data...
inventory Loading commit data...
invoices Loading commit data...
messaging Loading commit data...
notifications Loading commit data...
parent Loading commit data...
participants Loading commit data...
people Loading commit data...
pos Loading commit data...
pricing Loading commit data...
profile Loading commit data...
programs Loading commit data...
public Loading commit data...
receptionist Loading commit data...
reports Loading commit data...
roles Loading commit data...
schedule Loading commit data...
settings Loading commit data...
trainer Loading commit data...
training Loading commit data...
users Loading commit data...
wallets Loading commit data...
website Loading commit data...
whatsapp Loading commit data...
wizards Loading commit data...
branch-switcher.blade.php Loading commit data...
dashboard.blade.php Loading commit data...
global-search.blade.php Loading commit data...