Treasury & Payroll — Database & UI Reference

EduIT School Management System · Accounting Module · v1.0

11 tables · 18 pages
PK — primary key
FK — foreign key
computed — never stored

Treasury module — 5 tables

treasury_accounts

Treasury
iduuid PKSystem-generated
school_iduuid FKScoped to school
namevarchare.g. "BK Main Account"
typeenumBANK | CASH | MOMO
account_numbervarchar?Optional bank/MoMo ref
bank_namevarchar?For BANK type only
gl_account_iduuid FK→ COA asset account
opening_balancenumeric(15,2)Balance at creation
opening_datedateWhen OB applies from
statusenumACTIVE | INACTIVE
notestext?Internal notes
current_balancecomputedOB + money_in − money_out
created_attimestamptzUTC
updated_attimestamptzUTC

treasury_transactions

Treasury
iduuid PKSystem-generated
school_iduuid FKScoped to school
reference_numbervarcharTXN-YYYY-NNNNNN
account_iduuid FK→ treasury_accounts
directionenumMONEY_IN | MONEY_OUT
amountnumeric(15,2)Must be > 0
transaction_datedateWithin open period
gl_account_iduuid FKContra COA account
descriptionvarcharRequired — reason
statusenumDRAFT | POSTED | REVERSED
posted_attimestamptz?Set on posting
posted_byuuid FK?→ users
notestext?
attachmentsjsonb?File refs array
created_attimestamptz
updated_attimestamptz

treasury_transfers

Treasury
iduuid PK
school_iduuid FK
reference_numbervarcharTRF-YYYY-NNNNNN
from_account_iduuid FK→ treasury_accounts
to_account_iduuid FK→ treasury_accounts
amountnumeric(15,2)≤ from_account balance
transfer_datedateWithin open period
descriptionvarcharRequired
statusenumDRAFT | POSTED
posted_attimestamptz?
posted_byuuid FK?→ users
notestext?
created_attimestamptz

bank_reconciliation_sessions

Treasury
iduuid PK
school_iduuid FK
account_iduuid FK→ treasury_accounts
period_startdateStatement period start
period_enddateStatement period end
statement_closing_balancenumeric(15,2)From bank statement
statusenumOPEN | CLOSED
closed_attimestamptz?Set when closed
closed_byuuid FK?→ users
created_attimestamptz

bank_statement_lines

Treasury
iduuid PK
reconciliation_iduuid FK→ recon sessions
datedateDate on statement
descriptionvarcharStatement narration
amountnumeric(15,2)+ in / − out
match_statusenumUNMATCHED | MATCHED | EXCLUDED
matched_txn_iduuid FK?→ txn or transfer
matched_txn_typeenum?TRANSACTION | TRANSFER
created_attimestamptz

Payroll module — 6 tables

employee_payroll_profiles

Payroll
iduuid PK
school_iduuid FK
employee_iduuid FK→ HR employees table
employee_numbervarcharEMP-NNNNNN
departmentvarcharTeaching / Admin / Support
employment_typeenumPERMANENT | CONTRACT
salary_typeenumFIXED_MONTHLY | CONTRACT_ONEOFF
base_salarynumeric(15,2)?Required if FIXED_MONTHLY
gl_salary_expense_iduuid FK→ COA expense account
allowancesjsonb?Array of allowance objects
bank_account_numbervarchar?For bank transfer
bank_namevarchar?
statusenumACTIVE | INACTIVE
effective_fromdateProfile active from
notestext?
created_attimestamptz
updated_attimestamptz

payroll_runs

Payroll
iduuid PK
school_iduuid FK
reference_numbervarcharPAY-YYYY-NNNNNN
period_startdatee.g. 2025-11-01
period_enddatee.g. 2025-11-30
payroll_typeenumMONTHLY | CONTRACT
statusenumDRAFT | SUBMITTED | APPROVED | POSTED | PARTIALLY_PAID | PAID | VOIDED
total_grossnumeric(15,2)Sum of line gross_pay
total_payenumeric(15,2)Sum of line paye
total_emp_rssbnumeric(15,2)Pension + maternity
total_net_paynumeric(15,2)Sum of line net_pay
total_er_rssb_pensionnumeric(15,2)Employer pension
total_er_rssb_maternitynumeric(15,2)Employer maternity
total_er_occ_hazardnumeric(15,2)Employer occ. hazard
total_employer_costnumeric(15,2)Gross + employer contribs
notestext?
created_byuuid FK→ users
approved_byuuid FK?→ users
posted_attimestamptz?
created_attimestamptz

payroll_lines

Payroll
iduuid PK
payroll_run_iduuid FK→ payroll_runs
employee_iduuid FK→ HR employees
base_salarynumeric(15,2)Snapshot from profile
allowances_breakdownjsonbSnapshot at run creation
gross_paynumeric(15,2)base + sum(allowances)
rssb_pension_basenumeric(15,2)= gross (incl. transport)
maternity_basenumeric(15,2)gross − transport allowances
employee_pensionnumeric(15,2)pension_base × 6%
employee_maternitynumeric(15,2)maternity_base × 0.3%
total_emp_rssbnumeric(15,2)pension + maternity
taxable_incomenumeric(15,2)gross − total_emp_rssb
payenumeric(15,2)Progressive calc, round up
total_deductionsnumeric(15,2)rssb + paye
net_paynumeric(15,2)gross − total_deductions
employer_pensionnumeric(15,2)pension_base × 6%
employer_maternitynumeric(15,2)maternity_base × 0.3%
employer_occ_hazardnumeric(15,2)gross × 2%
total_er_contributionsnumeric(15,2)Sum employer side
employer_costnumeric(15,2)gross + er_contributions
rate_snapshotjsonbRates used at calc time
is_manual_overridebooleanWas any amount adjusted?
override_notetext?Audit trail if overridden
created_attimestamptz

payroll_disbursements

Payroll
iduuid PK
school_iduuid FK
payroll_run_iduuid FK→ payroll_runs
disbursement_typeenumBANK_TRANSFER | MANUAL
treasury_account_iduuid FK?→ treasury_accounts ★
amountnumeric(15,2)≤ undisbursed net pay
disbursement_datedateWithin open period
referencevarchar?Bank batch ref
notestext?
statusenumDRAFT | POSTED
posted_attimestamptz?
posted_byuuid FK?→ users
created_attimestamptz

payroll_remittances

Payroll
iduuid PK
school_iduuid FK
payroll_run_iduuid FK→ payroll_runs
remittance_typeenumPAYE | RSSB_PENSION | RSSB_MATERNITY | RSSB_OCC_HAZARD
treasury_account_iduuid FK→ treasury_accounts ★
amountnumeric(15,2)
remittance_datedate
referencevarchar?RRA / RSSB payment ref
statusenumDRAFT | POSTED
posted_attimestamptz?
posted_byuuid FK?→ users
created_attimestamptz

statutory_rate_configs

Payrollconfig
iduuid PK
school_iduuid FK
rate_typeenumEMP_RSSB_PENSION | ER_RSSB_PENSION | EMP_MATERNITY | ER_MATERNITY | ER_OCC_HAZARD
rate_valuenumeric(6,4)e.g. 0.0600 = 6%
effective_datedateWhen this rate applies from
notestext?e.g. "RSSB increase 2027"
created_attimestamptz
Companion table: paye_tax_bands — lower, upper, rate, effective_date

Treasury module — 8 pages

Accounts overview

accounting/treasury/
List
Cards grouped by type: BANK / CASH / MOMO
Each card: name, account number, current balance (RWF), last transaction date, status badge
Subtotals per group + grand total liquid assets
+ New Account button → modal/form
Click card → Account detail page

Account detail

accounting/treasury/accounts/[id]
Detail
Header: name, type badge, current balance (large), status
Tab — Transactions: list with running balance column, filters (date range, direction)
Tab — Transfers: all transfers in/out of this account
Tab — Reconciliation: list of all sessions for this account
Actions: + New Transaction, + New Transfer, + Start Reconciliation

Transactions list

accounting/treasury/transactions/
List
Filters: account, direction, status, date range
Columns: date, reference, account, description, direction badge, amount, status
DRAFT rows: edit + post + delete actions
POSTED rows: view + reverse action
+ New Transaction button

New / edit transaction

accounting/treasury/transactions/new
Form
Fields: Account (dropdown), Direction toggle (In / Out), Amount, Date, Contra GL account (COA picker), Description, Notes, Attachments
Actions: Save Draft, Save & Post
Post triggers GL entry — correctable only by reversal

Transfers list + new

accounting/treasury/transfers/
List + Form
List: date, reference, from account, to account, amount, status
New Transfer form: From account, To account (must differ), Amount, Date, Description
Validation: from_account balance must cover amount before posting
Actions: Save Draft, Save & Post

Reconciliation — session list

accounting/treasury/reconciliation/
List
Filters: account, status (OPEN / CLOSED), date range
Columns: account, period, statement closing balance, status, matched count, unmatched count
+ Start Reconciliation button → new session form
Click row → session workspace

Reconciliation — workspace

accounting/treasury/reconciliation/[id]
Workspace
Header: account, period, statement closing balance, system reconciled balance, difference (must hit 0 to close)
Left panel: unmatched statement lines
Right panel: unmatched system transactions for the period
Match action: select one from each side → Match button
Unresolved statement line → "Create Transaction" inline
Import: upload CSV/Excel or enter lines manually
Close Session button (enabled only when difference = 0)

Treasury reports

accounting/treasury/reports/
Reports
Account Balance Summary — all accounts, grouped, totalled
Transaction History — per account, date range, running balance
Cash Flow Summary — money in vs out by GL account
Reconciliation Report — per session, matched/unmatched, difference
All exportable: Excel, PDF, CSV

Payroll module — 10 pages

Payroll dashboard

accounting/payroll/
Dashboard
Metric cards: current month total gross, total net pay, pending runs, outstanding disbursements
Recent payroll runs table: ref, period, status badge, total net pay
Upcoming remittance deadlines (PAYE / RSSB due 15th of next month)
Quick actions: + New Monthly Run, + New Contract Payment

Employee profiles list

accounting/payroll/employees/
List
Filters: department, employment type, status
Columns: employee number, name, department, salary type, base salary, status
Search by name or employee number
+ New Profile button

Employee profile detail / edit

accounting/payroll/employees/[id]
Detail + Form
Employee info header (name, department, type, status, effective_from)
Salary section: salary type, base salary, GL expense account
Allowances: repeatable rows — name, amount, is_transport toggle, is_taxable toggle, GL account
Payment details: bank name, account number
Payslip history tab: list of all past payslips (view / PDF export per row)

Payroll runs list

accounting/payroll/runs/
List
Filters: status, payroll type, period (month picker)
Columns: reference, period, type, status badge, total gross, total net, total employer cost
Status badges: DRAFT (gray) → SUBMITTED (blue) → APPROVED (amber) → POSTED (green) → PAID (green) → VOIDED (red)
+ New Monthly Run, + New Contract Run buttons

Payroll run detail

accounting/payroll/runs/[id]
Detail + Workflow
Header: reference, period, status, summary totals (gross / deductions / net / employer cost)
Tab — Lines: one row per employee, edit if DRAFT, inline manual override with note field
Tab — Disbursements: list + Record Disbursement button (if POSTED+)
Tab — Remittances: PAYE and RSSB records + Record Remittance button
Tab — Payslips: all payslips, export all as ZIP
Action bar: Submit → Approve → Post (role-gated each step)

Record disbursement

accounting/payroll/runs/[id]/disburse
Form
Run summary (read-only): total net pay, already disbursed, remaining
Fields: Type (Bank Transfer / Manual), Treasury account picker, Amount, Date, Reference, Notes
Validation: amount ≤ remaining undisbursed net pay
Post creates GL: DR Net Salaries Payable / CR Bank

Record remittance

accounting/payroll/runs/[id]/remit
Form
Remittance type selector: PAYE / RSSB Pension / RSSB Maternity / RSSB Occ. Hazard
Shows outstanding amount for selected type (computed from run)
Fields: Treasury account, Amount, Date, Reference, Notes
Post creates GL: DR [relevant payable] / CR Bank

Payslip viewer

accounting/payroll/payslips/[employee_id]/[run_id]
View only
School header: name, logo
Employee: name, number, department, type, period
Earnings table: base salary + each allowance → Gross Pay
Deductions table: RSSB pension, maternity, PAYE → Total Deductions
Net Pay (highlighted) + employer contributions section
Export to PDF button

Payroll reports

accounting/payroll/reports/
Reports
Payroll Summary — per run, all lines, full breakdown
PAYE Report — per employee, taxable income, PAYE withheld (for RRA submission)
RSSB Report — per employee, all contributions (for RSSB submission)
Cost by Department — aggregated gross + employer cost
Remittance History — all PAYE + RSSB payments made
All exportable: Excel, PDF, CSV (payslips: PDF only)

Statutory rates config

accounting/payroll/settings/rates
Settings
Admin-only page
PAYE bands table: lower bound, upper bound, rate %, effective date
RSSB rates table: rate type, rate %, effective date — one row per type per period
History: all past rate configurations preserved
Warning banner if a rate change is scheduled within 30 days

Treasury — foreign keys

treasury module FK map
treasury_accounts.school_idschools.id
treasury_accounts.gl_account_idchart_of_accounts.id (asset type)
treasury_transactions.account_idtreasury_accounts.id
treasury_transactions.gl_account_idchart_of_accounts.id (income/expense)
treasury_transactions.posted_byusers.id
treasury_transfers.from_account_idtreasury_accounts.id (must ≠ to_account_id)
treasury_transfers.to_account_idtreasury_accounts.id
treasury_transfers.posted_byusers.id
bank_reconciliation_sessions.account_idtreasury_accounts.id
bank_reconciliation_sessions.closed_byusers.id
bank_statement_lines.reconciliation_idbank_reconciliation_sessions.id
bank_statement_lines.matched_txn_idtreasury_transactions.id OR treasury_transfers.id (polymorphic — use matched_txn_type)

Payroll — foreign keys

payroll module FK map
employee_payroll_profiles.school_idschools.id
employee_payroll_profiles.employee_idhr_employees.id (HR module)
employee_payroll_profiles.gl_salary_expense_idchart_of_accounts.id (expense type)
payroll_runs.school_idschools.id
payroll_runs.created_byusers.id
payroll_runs.approved_byusers.id
payroll_lines.payroll_run_idpayroll_runs.id (cascade delete if voided)
payroll_lines.employee_idhr_employees.id
payroll_disbursements.payroll_run_idpayroll_runs.id (must be POSTED)
payroll_disbursements.treasury_account_idtreasury_accounts.id ★ cross-module
payroll_disbursements.posted_byusers.id
payroll_remittances.payroll_run_idpayroll_runs.id (must be POSTED)
payroll_remittances.treasury_account_idtreasury_accounts.id ★ cross-module
statutory_rate_configs.school_idschools.id

Cross-module bridges — Payroll ↔ Treasury

The only two places where Payroll reaches into Treasury:

payroll_disbursements.treasury_account_id → treasury_accounts.id
Salary payment goes out of this account. This FK is what makes money actually leave when net salaries are disbursed.

payroll_remittances.treasury_account_id → treasury_accounts.id
PAYE (to RRA) and RSSB contributions also exit via a Treasury account. Same bridge, different purpose.

Treasury never reaches back into Payroll. Purchases & Sales and School Fees also reference treasury_accounts for their payments — Treasury owns the accounts, other modules consume them via FK.

Table count summary

Treasury — 5 tables
treasury_accounts
treasury_transactions
treasury_transfers
bank_reconciliation_sessions
bank_statement_lines
Payroll — 6 tables
employee_payroll_profiles
payroll_runs
payroll_lines
payroll_disbursements
payroll_remittances
statutory_rate_configs