- Get Started
- Localhost
- Architecture
- Structure
- Pattern
- Page
- Layout
- Content
- Types
- Config
- Actions
- Queries
- Authorization
- Validation
- Form
- Table
- Detail
- Card
- Util
- Hooks
- List Params
- Views
- README.md
- ISSUE.md
- Technology Stack
- Database
- File
- CDN Assets
- Entry Points
- Dashboard
- Authentication
- Credentials
- OAuth
- Flow Diagrams
- Multi-Tenancy
- Offline
- Onboarding
- Onboarding Videos
- Add Values
- Admission
- Application
- Attendance
- Compliance
- Profile
- Exams
- Exam Wizard
- Timetable
- Classrooms
- Notifications
- Conference
- LMS (Lumos)
- Finance
- Fee Management
- Invoice
- Wallet
- Salary
- Payroll
- Timesheet
- Expenses
- Budget
- Receipt
- Accounts
- Banking
- Reports
- Dashboard
- Permissions
- Messages
- Integration Flow
- Provision
- AI Document Processing
- Document Intelligence
- Internationalization
- Translation
- Translation Guide
- Icons
- Docs Factory
- Inspiration
- Listings
- Teachers
- Students
- Catalog
- Library
- Contributing
- Code of conduct
- GitHub Workflow
- Database Seeds
- Database Safety
- Test Accounts
- Bulk import
- Playwright
- Prettier
- Block Rebound
- Transportation
The invoice module is the school's central billing surface. Invoices are created manually through a wizard or generated automatically by every billable event (enrollment fees, transport route fees, course/video purchases), rendered as a print-first minimalist document, and delivered by public share link, PDF, or email. Mutations gate through the finance guard (requireFinanceActor); reads are owner-scoped so students and guardians always reach their own invoices.
Status
| Sub-module | Status | Notes |
|---|---|---|
| Invoice list | Production | DataTable with filtering, sorting, pagination, ?status= |
| Wizard flow | Production | The creation/edit flow — details + items, draft persistence |
| Document view | Production | Full-page minimalist sheet (monospace design), print-ready |
| Public share links | Production | Token URL a parent can open and print without an account |
| A4 PDF export | Production | Same design; IBM Plex Mono / Rubik (Arabic) |
| Email delivery | Production | Resend, bilingual, links the public page when shared |
| Auto-generation | Production | Enrollment fees, transport route fees, Stripe purchases |
| Itemized lines | Production | One line per fee component; discount/adjustment reconcile |
| Dashboard | Production | Revenue analytics in the school currency, 30-day stats |
| Settings | Production | Logo + signature branding (PDF, email, sheet, public page) |
| CSV export | Ready | Utility exists, no UI button yet |
| Recurring | Planned | Scheduled recurring invoices |
Routes
| Route | Page | Component |
|---|---|---|
.../finance/invoice | Invoice list | content.tsx |
.../finance/invoice/analysis | Analytics dashboard | dashboard/content.tsx |
.../finance/invoice/invoice/create | Creates a draft, redirects into wizard | route page |
.../finance/invoice/invoice/edit/[invoiceId] | Redirects into wizard details | route page |
.../finance/invoice/invoice/view/[id] | Full-page document + action toolbar | invoice/view-content.tsx |
.../finance/invoice/add/[id]/details | Wizard — details (number prefilled) | wizard/details/content.tsx |
.../finance/invoice/add/[id]/items | Wizard — items (server-verified totals) | wizard/items/content.tsx |
.../finance/invoice/settings | Branding (logo, signature) | settings/content.tsx |
.../finance/invoice/onboarding | First-time profile | onboarding/content.tsx |
/[lang]/invoice/[token] (public) | Shared invoice — view + print, no auth | root-level route |
Server actions
| Action | Gate | Purpose |
|---|---|---|
getInvoicesWithFilters | auth + tenant, owner-scoped | Filtered list (privileged roles see all; others own) |
getInvoiceById | auth + tenant, owner-scoped | Detail + linked payments + branding + share state |
deleteInvoice | requireFinanceActor(invoice, delete) | Delete with orphan-address cleanup |
sendInvoiceEmail | requireFinanceActor(invoice, export) | Resend email (public link when shared) |
markInvoicePaid | requireFinanceActor(invoice, edit) | Race-safe flip + ledger posting |
shareInvoice | requireFinanceActor(invoice, edit) | Mint/reuse the public token (share.ts) |
revokeInvoiceShare | requireFinanceActor(invoice, edit) | Disable the link, keep the token (share.ts) |
getSharedInvoice | public — token is the credential | Minimal display payload + view counter (share.ts) |
updateSettings | auth + tenant (own row) | Branding logo + signature |
getDashboardStats | auth + tenant, owner-scoped | 30-day stats + school currency |
Reads deliberately skip the permission gate (owner row-scoping is the authorization) so the student/guardian portal keeps working — the rationale is documented on requireAuthAndTenant in actions.ts.
How invoices are generated
| Source | Trigger | Result |
|---|---|---|
| Manual | "Create Invoice" → wizard | Draft in the school currency with a prefilled sequential number |
| Enrollment / student added | ensureStudentFeeAssignments → fee-invoice-sync | ENR- invoices per fee assignment, itemized per fee component |
| Transport route fees | "Provision to billing" on the transportation fees page | Per route + month structure → assignments → invoices (idempotent) |
| Course / video purchase | Stripe webhook on successful checkout | PUR- invoice already marked PAID (retry-idempotent) |
Registration fees collected at offer acceptance are allocated onto their auto-generated invoice inside the enrollment transaction, so the invoice shows PAID the moment enrollment completes.
Itemization
Single-installment invoices carry one line per non-zero fee component (tuition, admission, registration, exam, library, laboratory, sports, transport, hostel, plus custom otherFees), labeled in the school's language. When a scholarship bills below list price the gap lands in the invoice discount field; billing above adds an adjustment line. Multi-installment invoices keep one "Installment N of M" line each.
Print, share, PDF
- Print — the document view and the public share page both print as a clean A4 sheet via the browser (app chrome is stripped by global print styles).
- Share — the Share dialog mints a public link (
/invoice/{token}); anyone with the link can view and print, no account needed. Revoking disables access but keeps the token, so re-enabling restores the exact same URL. Send via WhatsApp or email straight from the dialog. - PDF — Download PDF renders the same minimalist design via
@react-pdf(IBM Plex Mono for English, Rubik for Arabic). - Email — the Resend email is bilingual and links the public page when sharing is enabled, otherwise the authed detail view.
Role access
| Role | Access |
|---|---|
| Admin / Accountant / Developer | Full — create, edit, delete, mark paid, share, email, settings |
| Student / Guardian | Own invoices only — list scoping, dashboard "Fee Payments", detail, PDF |
| Link holder (no account) | View + print the shared invoice page |
Accounting
markInvoicePaid posts DR Cash / CR Accounts Receivable to the double-entry ledger (race-safe, keyed on the invoice id). Purchase invoices are created without a journal entry for now — a point-of-sale posting rule (DR Cash / CR Revenue) is tracked as a follow-up.