85d87d1c62b34156ca5fa53ee96083200f526cca
Adds a per-student daily rate (students.daily_tuition_cents) and a trigger that writes a tuition charge when a student is marked present or late. Idempotency is the crux. The attendance UI upserts on (student_id, date) and teachers toggle a status freely — present, absent, present again. A naive "insert a charge on attendance" trigger bills the family once per click. So each auto-charge is bound to the attendance row that caused it via ledger_entries.attendance_id (UNIQUE), which turns the write into an upsert, lets a change back to absent delete the charge, and cascades the charge away if the attendance record is deleted. Manual entries keep attendance_id NULL — Postgres allows unlimited NULLs in a unique index — so hand-entered charges are untouched and the UI can tell auto from manual. A NULL rate (the default) means never auto-charge, so nothing begins billing until a rate is deliberately set on a student. Existing attendance is not backfilled: retroactively generating charges against families' balances should be an explicit decision, not a side effect of deploying a migration. The trigger is SECURITY DEFINER because the writer is a teacher marking attendance while ledger_entries is admin-write under RLS; teachers gain no general ledger access, only this fixed attendance-derived write. Verified against the live schema across all eight paths: charge on present, reversal on absent, no duplicate on re-mark, late billable, excused free, no rate means no charge, rate change on re-save, and cascade on attendance delete. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Description
No description provided
1 MiB
Languages
JavaScript
42.2%
Dockerfile
30.4%
TypeScript
27.4%