Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.
Finance covers everything a school does with money in Elimu Bora: defining fee items, issuing invoices, accepting and reconciling payments (including M-Pesa STK push and Paybill), running per-student wallets for canteen-style spending, and locking prepaid funds against specific charges with earmarks. Bursars run it day to day. School leadership uses it for oversight and reports. Guardians can view their children’s invoices, payments, wallets, and earmarks, but cannot record payments or move money from the panel.
Finance is an optional module. A school can enable or disable it under Settings. When Finance is disabled, every Finance resource disappears from the sidebar, scheduled overdue checks are skipped for the tenant, and outbound finance notifications are dropped. Inbound M-Pesa callbacks are still received so that late callbacks for payments started before the module was disabled can still be reconciled.
A fee item that can be charged, such as tuition, transport, or lunch.
Billable group
A bundle of billables grouped together (for example, a Term 1 fees bundle).
Billable variant
A pricing variation of a billable when one fee has more than one price (for example, per bus route).
Per-stage amount
A stage-level override of a billable’s price, so Grade 1 tuition can differ from Grade 8 tuition.
Invoice
A bill issued to a student, teacher, or staff member, scoped to a term.
Invoice line
One charge on an invoice, tied to a billable or recorded as ad-hoc. The line’s discount is filled in automatically when the invoice is created, from any active discount the student’s guardians hold for that billable.
Discount
A reduction held on a guardian, scoped to one billable, expressed as a percentage or a fixed amount, with an effective date range. Applied automatically to matching invoice lines.
Invoice payment
A payment recorded against an invoice.
Payment allocation
The split of one payment across the lines of its invoice.
Wallet
A per-student credit balance for student spending (school canteen and similar non-invoice use).
Wallet transaction
A credit or debit entry on a wallet, with a balance snapshot for audit.
Earmark
Prepaid funds locked against a specific billable for a student, drained automatically when a matching invoice payment is recorded.
Earmark transaction
A funding, drain, refund, or bounce entry on an earmark, with a balance snapshot for audit.
Sponsor
A third party paying for an invoice payment (Government, NGO, Corporate, or Individual).
M-Pesa integration
The school’s stored M-Pesa credentials (Paybill shortcode, passkey, consumer key and secret) and the callback URLs registered with Safaricom.
In the sidebar, go to Billables and click New billable.
2
Name the billable and pick a pricing model
Pick one of three pricing models:
Flat: a single price for everyone. Enter the Default amount.
Variants: different prices for different choices (for example, three bus routes). You will add variant rows next.
Per unit: price multiplied by a quantity entered on each invoice line.
3
Optionally group the billable
Pick a Billable group to bundle this billable with related ones (for example, “Term 1 fees”). Groups make it easier to attach a full bundle to an invoice in one step.
4
Save
Click Save. The billable becomes available for invoice lines and earmarks.
[Insert screenshot: Billables list at /billables with columns Name, Pricing model, Default amount, Group, and the New billable button in the header]
Use per-stage amounts to charge different prices by curriculum stage (for example, Grade 1 tuition is lower than Grade 8 tuition). Curriculum stages ship pre-seeded and read-only, so there is no setup before this step.
1
Open the billable and scroll to Per-stage amounts
Open the parent billable and find the Per-stage amounts section.
2
Add an override row per stage
Pick a curriculum stage and enter the amount for that stage. Stages without a per-stage row fall back to the default amount.
3
Save
Save the billable. Invoice generation will use the per-stage amount for students in the matching stage.
You will need: the billable the discount applies to, and the guardian record. Discounts are held on the guardian, not the student. When an invoice is later raised for one of that guardian’s children for the matching billable, the system applies the discount automatically.
A discount reduces the line amount for a specific billable on any invoice raised for the guardian’s children. If a child has more than one guardian and more than one of them holds a discount for the same billable, the largest applicable discount is the one that lands on the line.
1
Open the guardian
Go to Guardians and open the guardian who is entitled to the discount.
2
Open the Discounts tab
Switch to the Discounts tab on the guardian’s profile.
3
Add a discount
Click the create action. Pick the Billable the discount applies to, the Type (Percentage or Amount), and enter the value. Pick the Effective From date (defaults to today) and an optional Effective Until date. Leave Active on. Add notes if useful.
4
Save
Save. The discount is now in effect. The next invoice line raised for one of this guardian’s children that charges the same billable, within the effective date range, will pick up the discount automatically.
An invoice is the document a school issues to a student, teacher, or staff member. Most invoices target students. The invoice is scoped to a single term.
You will need: an active term, the student, teacher, or staff member the invoice is for, and (if you want to use a billable rather than an ad-hoc line) the billable already created. If the billable does not exist yet, add it first under Set up fees, or record the charge as an ad-hoc line with a typed label and amount.
1
Open Invoices
Go to Invoices and click New invoice.
2
Pick the invoiceable
Pick whether the invoice is for a Student, Teacher, or Staff member, then pick the specific person.
3
Pick the term and due date
Pick the term this invoice covers, and an optional due date. The due date is what the overdue scan uses.
4
Add invoice lines
Add one line per charge. Each line is either tied to a billable (and inherits its amount, including any per-stage override for the student’s grade stage) or recorded as an ad-hoc line with a label and amount you type in. The bursar does not enter discounts on the line itself: when the line is saved, the system looks up active Discounts the student’s guardians hold for that billable and applies the largest applicable one automatically, snapshotting it onto the line. See Hold a discount for a guardian.
5
Save the invoice
Click Save. The invoice starts in Pending status. Adding lines automatically recomputes the invoice total. A notification is queued to the invoiceable’s guardians (for student invoices) or to the staff or teacher themselves.
[Insert screenshot: New invoice form at /invoices/create showing the Invoiceable picker (Student/Teacher/Staff), Term selector, Due date, and the repeating Line Items block with Billable, Label, Unit Amount, and Qty columns]
Invoices are immutable once created. The invoice’s lines, amounts, and payments are part of the school’s ledger and cannot be edited or deleted from the panel. If a charge was wrong, raise a new invoice for the corrected amount, or wait for the payment flow to balance things out (a refund happens on the earmark side, not on the invoice itself).
The invoice view page shows the running total, the Total paid, and the current Balance. The Lines tab lists every charge with its discount and total. The Payments tab lists every payment with its method and status. The Activity log captures every change.[Insert screenshot: Invoice view page at /invoices/ showing the header summary (Amount, Total paid, Balance, Status badge), the Lines relation manager, and the Payments relation manager with method and status columns]
All payments are recorded from one place: the Record Invoice Payment modal. Pick a method on the form, fill in the method-specific fields, and save. M-Pesa is one of the methods; selecting it reveals a phone-number input and lets the bursar send an STK push.Payment methods available on the form: M-Pesa, Cash, Bank Transfer, Cheque. The system also sets two internal methods automatically when they apply: Earmark (when a payment is settled from an earmark balance) and Wallet refund (when an earmark is refunded back into a wallet).
On the invoice view page, click Record Invoice Payment.
3
Pick the method and enter the amount
Pick Cash or Bank Transfer. Enter the amount. For bank transfers, record the bank reference.
4
Save
Save the payment. Cash and bank transfer payments go straight to Cleared status. The payment is allocated proportionally across the invoice’s unpaid lines unless you override the allocation manually. The invoice status moves to Partial or Paid based on the new balance. A dashboard notification appears for the school, and a receipt PDF is emailed to the invoice owner (the guardian for a student invoice, or the staff or teacher for theirs).
You will need: a cheque payment in Pending status on the invoice. The action is only available for cheque payments that have not yet cleared.
1
Open the payment
On the invoice’s Payments tab, find the cheque row.
2
Use Acknowledge
Use the Acknowledge action and confirm. The payment status becomes Cleared and the invoice is credited. The invoice status moves to Partial or Paid, and the receipt PDF is emailed to the invoice owner.
You will need: a cheque payment in Pending status on the invoice, and the system billable Bounced Cheque Penalty present in your Billables list (it is pre-seeded; if it is missing, ask a Super Admin to re-seed the billables).
1
Open the payment
On the invoice’s Payments tab, find the cheque row.
2
Use Mark bounced
Use the Mark bounced action.
3
Enter the bounce reason and the penalty amount
The modal prompts for a Bounce reason (free text) and a Penalty amount (the fine to charge the guardian). The penalty defaults to the Bounced Cheque Penalty billable’s default amount; the bursar can override it for this case.
4
Confirm
Confirm. The payment status becomes Bounced (terminal). A new Bounced cheque penalty line is added to the same invoice for the penalty amount, increasing the balance. A Cheque bounced notification goes to the relevant guardians and a dashboard notification appears for the bursar.
You will need: the M-Pesa integration configured under Configure M-Pesa, and a phone number for the guardian who will pay. The guardian’s phone number is on their profile under Users & Identity. Without the integration, the Record Invoice Payment modal does not show the phone-number input for the M-Pesa method, because there is nowhere to send the prompt.
M-Pesa STK push is initiated from the school side. The bursar opens the Record Invoice Payment modal, picks M-Pesa, enters the guardian’s phone number, and sends the prompt. Guardians cannot initiate STK push from their own logins; the Record Invoice Payment action is hidden from the Guardian role.
1
Open the invoice
Open the invoice from Invoices, or from the Invoices tab on the student’s profile.
2
Open the payment modal and pick M-Pesa
Click Record Invoice Payment and pick M-Pesa. The phone-number input appears.
3
Enter the phone and amount, then send the prompt
Enter the guardian’s phone number and the amount. Click Record Payment to send the prompt. The system creates an M-Pesa payment intent (status Pending) and Safaricom delivers a SIM Toolkit prompt to the guardian’s phone.
4
Wait for the callback
The guardian enters their M-Pesa PIN on their phone. Safaricom posts a callback to the school’s tenant subdomain. The system matches the callback to the payment intent, creates a cleared invoice payment, and recomputes the invoice balance. A dashboard notification appears for the school, and a receipt PDF is emailed to the invoice owner.
[Insert screenshot: Record Invoice Payment modal launched from a student invoice showing Method set to M-Pesa with the Phone number and Amount fields and the Record Payment button]
You will need: the M-Pesa integration configured under Configure M-Pesa, and the Paybill callback URLs registered with Safaricom Daraja. Without these URLs, deposits will land in the Paybill account but the system will not know about them.
When a guardian pays the school’s Paybill number from their own M-Pesa menu, the same callback infrastructure receives the deposit and applies it to the matching invoice automatically.
1
Guardian pays the Paybill
The guardian sends money to the school’s M-Pesa Paybill number. The guardian enters the invoice ID as the account reference (this is the number shown on the invoice). The invoice ID, not the admission number, is what the system uses to match the deposit to the right invoice.
2
System receives the C2B callback
Safaricom posts a Confirmation callback to the school’s tenant subdomain. The system writes an M-Pesa payment intent, looks up the invoice by the account reference, and creates a cleared invoice payment for the deposited amount.
3
Verify in the panel
The payment appears on the Payments tab of the resolved invoice within seconds. The invoice status moves to Partial or Paid based on the new balance.
Each student has a single wallet. A wallet is auto-created when the student is admitted, so there is nothing to set up beforehand.The wallet is a credit balance for student spending outside the invoicing flow: school canteen purchases, similar small-value drawdowns the school manages directly. Wallets cannot be used to settle invoices. Use earmarks for prepaid funds that should pay down a specific invoice charge.
You will need: for M-Pesa top-ups, the M-Pesa integration configured under Configure M-Pesa and a phone number on file for the guardian. Cash, bank transfer, and cheque top-ups do not need any integration.
1
Open the wallet
Open Wallets and pick the student’s wallet, or open the student profile and use the Wallet tab.
2
Click Credit Wallet
Click Credit Wallet. Pick the funding method: M-Pesa, Cash, Bank Transfer, or Cheque. For M-Pesa, enter the guardian’s phone number to send the STK push. For cheque, enter the cheque number, the drawing bank, and the cheque drawn date. Add a short description so the ledger entry is self-explanatory.
3
Save
Save. For cash, bank transfer, and successful M-Pesa STK pushes, the wallet is credited immediately, the balance is updated with a before-and-after snapshot, and a Wallet funded notification is sent to the student’s guardians. For cheques, the wallet transaction is Pending until the cheque is acknowledged or marked bounced. If a cheque bounces, you are prompted for a bounce reason and an optional penalty amount; when a penalty greater than zero is entered, a penalty invoice is raised against the student.
You will need: a wallet with a positive balance. The Debit Wallet action is hidden when the balance is zero. Debits cover student spending that happens outside the invoice flow (school canteen, kiosk, similar) and are recorded by the bursar to keep the wallet ledger accurate. To settle an invoice from prepaid funds, use an earmark instead.
1
Open the wallet
Open Wallets and pick the student’s wallet, or open the student profile and use the Wallet tab.
2
Click Debit Wallet
Click Debit Wallet. Pick the method (Cash or Bank Transfer) and enter the amount; the form caps the amount at the available balance. Add a short description so the entry on the ledger explains what the money was spent on.
3
Save
Save. A debit wallet transaction is written, the balance is updated, and the Wallet debited notification is queued to the student’s guardians. If the debit takes the balance below the low-balance threshold, the Wallet low balance notification fires as well.
You will need: a cheque-funded wallet transaction in Pending status (from a Credit Wallet step that used the Cheque method).
On the wallet’s Transactions tab, find the pending cheque row and use the Acknowledge Cheque action. The wallet transaction status becomes Cleared, the wallet balance is updated, and the Wallet funded notification fires. If the cheque bounces instead, use Mark Bounced; the modal prompts for a bounce reason and an optional penalty amount that, when greater than zero, raises a penalty invoice against the student.
Open the wallet and scroll to the Transactions tab. Every credit and debit is listed in date order with the amount, balance before, balance after, and the related earmark transaction (when the entry comes from an earmark refund-to-wallet). Use the Wallet statement header action to download a single-wallet PDF, or the Wallet balances report on the wallets list to export every wallet’s balance to PDF or Excel.[Insert screenshot: Wallet view page at /wallets/ showing the balance summary, the Transactions tab with columns Date, Type, Amount, Balance after, Related, and the Wallet statement action in the header]
When a debit takes a wallet below the configured low-balance threshold, the system sends a Wallet low balance notification to the student’s guardians so they can top up. The threshold is set by the school’s deployment and is not changed from the staff panel.
An earmark is prepaid funds locked against a specific billable for a specific student. When the bursar later records a payment on an invoice that charges the same billable for the same student, the earmark drains automatically and settles that line. Earmarks are how a school accepts payment in advance for a known charge (for example, paying the Term 2 transport fee in January).Earmarks are separate from wallets. Funding an earmark does not pull money from the wallet; it is its own deposit. Refunding an earmark can credit the wallet (one of the refund destinations) but the two balances are not the same balance.
You will need: the target billable to exist. For M-Pesa funding, the M-Pesa integration must be configured under Configure M-Pesa and a phone number must be on file for the guardian. Cash, bank transfer, and cheque funding do not need any integration.
1
Open the student or the billable
Open the student profile and pick the Earmarks tab, or open the billable and use the Prepay Billable action.
2
Pick the billable and the funding method
Pick the billable the earmark is for. Pick the funding method: Cash, M-Pesa, Bank Transfer, or Cheque.
3
Enter the amount and confirm
Enter the amount. Confirm. For non-cheque methods the earmark starts in Active; a Funding entry is added to the earmark transaction ledger. For cheques the earmark starts in Pending clearance until the cheque clears; if the cheque bounces, the earmark funding is reversed and you are prompted for an optional penalty amount that, when greater than zero, raises a penalty invoice against the student. An Earmark cheque bounced notification is sent to the relevant guardians.
[Insert screenshot: Earmark view page at /earmarks/ showing the reserved amount, the linked billable, the student, the status badge (Active, Pending clearance, Depleted, Refunded), and the Refund action]
Earmark drain happens automatically. When the bursar records an invoice payment for the same student and the same billable the earmark covers, the system can settle the payment from the earmark instead of asking the guardian to pay again. A Drain entry is added to the earmark transaction ledger and the invoice is credited. When the earmark balance reaches zero, the earmark status moves to Depleted.
You will need: an earmark in Active status with a positive remaining balance. Depleted, Refunded, and Pending clearance earmarks cannot be refunded.
1
Open the earmark
Open the earmark from Earmarks, or from the Earmarks tab on the student’s profile.
2
Pick a refund destination
Click Refund and pick:
External payout: the bursar pays out the remaining balance through a channel outside the system (cash at the office, bank transfer, M-Pesa B2C). The earmark transaction ledger gets a Refund entry. Elimu Bora records the refund but does not move the money.
Credit to wallet: the remaining balance is moved to the student’s wallet. The earmark ledger gets a Refund to wallet entry, and the wallet records a matching credit.
3
Confirm
Confirm. The earmark status becomes Refunded (terminal).
A sponsor is a third party paying for a student’s charges, such as a government scholarship or an NGO. Sponsors are attached to payments, not invoices: when a sponsor pays, the bursar records the payment and tags it with the sponsor so the reconciliation report can group the payment under that sponsor.
You will need: the sponsor record to exist before you record the payment.
When you record an invoice payment, pick the sponsor from the Sponsor field on the payment form. The payment is tagged. Later, the bursar can group payments by sponsor on the reconciliation reports.
You will need: an M-Pesa Daraja account with the credentials Safaricom issued for your Paybill: shortcode, passkey, consumer key, and consumer secret. If you do not have these, contact Safaricom to register your school as a business and request Daraja API access.
A school’s M-Pesa credentials live on a Payment integration row. Read or change them is restricted to school leadership and bursars in the default role setup.
1
Open Payment Integrations
Go to Payment Integrations in the sidebar.
2
Add or edit the M-Pesa integration
Pick the M-Pesa row, or add one if missing. Enter the shortcode, the passkey, the consumer key, and the consumer secret. These come from the school’s Safaricom Daraja account.
3
Register callback URLs with Safaricom
In Safaricom Daraja, set the callback URLs to point at the school’s tenant subdomain:
Finance carries three lifecycle status lists. Each table lists every status, every transition is labelled with the actor or trigger that moves the record, and reversibility is stated.
Some payment has cleared. Balance is still positive.
Bursar, school leadership
Record additional payments.
Paid
The full amount has cleared. Balance is zero.
Bursar, school leadership
View the receipt history. The invoice is settled.
Overdue
The due date has passed and the balance is positive. Set by the daily overdue scan at 08:00, which also sends an overdue notification.
Bursar, school leadership
Record a payment (returns to Partial or Paid).
A cheque bounce on a previously-cleared cheque payment can reduce the Total paid and return a Paid invoice to Partial; in addition, a penalty line is added to the invoice for the bounce, which increases the Amount.
Recorded but not yet usable. Typically a cheque awaiting clearance.
Bursar
Acknowledge the cheque once funds arrive, or mark bounced if the cheque bounces.
Cleared
Funds confirmed. The payment counts toward the invoice’s Total paid.
(none)
View the audit trail and the receipt.
Bounced
A cheque bounced. The credit is reversed and a penalty line is added to the invoice for the configured penalty amount. A Cheque bounced notification is sent to the relevant guardians.
(none)
View the bounce reason on the payment; record a replacement payment when the funds arrive again.
Cleared and Bounced are terminal for the payment itself. To reverse a Cleared payment, mark the underlying cheque bounced (for cheque payments) or record a compensating earmark refund elsewhere; the original payment record is not edited or deleted.
These are not lifecycles. They appear on form pickers when recording or reading finance records.
Payment method: M-Pesa, Cash, Bank Transfer, Cheque, plus Earmark and Wallet refund which the system sets for you.
Pricing model: Flat, Variants, or Per unit (on a billable).
Refund destination: External payout (pay the guardian outside the system) or Credit to wallet (return the value to the student’s wallet).
Sponsor type: Government, NGO, Individual, or Corporate.
Discount type: Percentage (reduce by N% of the line subtotal) or Amount (reduce by a fixed currency amount).
Earmark transaction type: Funding (initial deposit), Drain (consumed by an invoice payment), Refund (paid out externally), Refund to wallet (returned to the wallet), Bounce (cheque-funded earmark voided).
An invoice is made of one or more lines, and is paid by one or more payments. Each payment is split (allocated) across the invoice’s unpaid lines. The allocation is automatic and proportional by default; a bursar can override it line by line.
A discount is held on a guardian and scoped to a single billable. When an invoice line for one of that guardian’s children charges the same billable, the system snapshots the discount amount onto the line; the value lives on the invoice line afterwards, independent of any later changes to the discount record.
Each student has a single wallet. The wallet keeps a running ledger of every credit and debit. Wallets are spent outside the invoicing flow (canteen and similar).
An earmark belongs to a student and is funded against a specific billable. It is independent of the wallet (refunding an earmark to the wallet is the only path where the two balances meet).
An M-Pesa flow targets exactly one of an invoice, a wallet, or an earmark. The action a bursar takes in the panel, or the invoice ID the guardian uses as the Paybill account reference, tells the system where the cleared payment should land.
Reports come in two shapes: downloads (PDF or Excel, generated when you click the action), and emailed receipts (sent automatically when a payment clears).
Report
Where
Filters
Output
Invoice detail
Download invoice header action on a single invoice
None (single invoice)
Portrait PDF with lines, payments, and balance
Fee Collection Summary
Header action on the Invoices list
Date range, optional grade level, optional billable
Landscape PDF or Excel showing invoiced, paid, and outstanding totals
Outstanding Balances
Header action on the Invoices list
Optional “overdue only” toggle
PDF or Excel listing every unpaid or partial invoice
Line Statement
Per-row action on the Lines tab of an invoice (visible when the line has any payment)
None (single line)
Portrait PDF showing one invoice line with its payment allocations
Payment Receipt
Per-row action on the Payments tab of an invoice
None (single payment)
Portrait PDF receipt (same template as the emailed receipt)
Guardians log in to the tenant panel under the locked Guardian role and have read-only, child-scoped access. They can read:
Their children’s invoices and the line breakdown.
Payment history on each invoice, with the method and status.
Each child’s wallet balance and the wallet transaction ledger.
Each child’s earmarks and the earmark transaction ledger.
The Guardian role explicitly cannot:
Record a payment (the Record Invoice Payment action is hidden).
Credit or debit a wallet from the panel (the Credit Wallet and Debit Wallet actions are hidden).
Lock funds with an earmark from the panel (the Prepay Billable action is hidden).
Refund an earmark.
See or manage M-Pesa payment integration credentials.
Notifications still reach guardians regardless of whether they log in. Invoice creation, overdue reminders, wallet funded, wallet debited, wallet low balance, cheque bounced, and earmark cheque bounced messages are sent to the guardian’s stored contacts. M-Pesa STK push prompts are initiated by the school; the guardian sees them on their phone the same way they would for any other Daraja STK push.
Hold a discount on the guardian if the reduction is a known amount or percentage off a specific billable: open the guardian, switch to the Discounts tab, and add a discount scoped to that billable (see Hold a discount for a guardian). The next invoice line raised for one of the guardian’s children that charges the same billable will pick up the discount automatically. Use a Sponsor if a third party is paying part of the balance: add the sponsor record under Sponsors, then when you record the payment from the sponsor, pick the sponsor on the payment form so the reconciliation report can group the payment under that sponsor.
What happens when a guardian overpays?
The cleared payment applies in full to the invoice and the invoice moves to Paid. To put the surplus to use, create an earmark for the student against the relevant billable for the surplus amount; the earmark will drain automatically the next time you record a payment on an invoice line that charges the same billable.
Can invoices be refunded?
No, invoice payments are not refundable inside Elimu Bora. Refunds exist only on earmarks: when an active earmark still has a positive balance, the bursar can refund what remains, either as an external payout (the bursar pays the guardian outside the system) or as a credit back to the student’s wallet. If a guardian is owed money for a paid invoice, handle the payout outside the system; the invoice itself stays Paid.
Why did an M-Pesa Paybill payment not apply to the right invoice?
Paybill (C2B) deposits are matched using the account reference the guardian typed in their M-Pesa menu, which must be the invoice ID shown on the invoice. If the guardian typed something else (an admission number, a name, a wrong digit), the deposit will land in the school’s M-Pesa account but the system will not match it to any invoice. Confirm with the guardian which reference they used. The system does not expose a manual match action; if the wrong reference was used, treat the deposit as an out-of-band payment and record a fresh payment against the correct invoice.
What happens when a cheque bounces?
For an invoice payment, mark the payment Bounced from the Payments tab. The bursar is prompted for a bounce reason and a penalty amount; on confirm, a new Bounced cheque penalty line is added to the same invoice for the penalty amount, the cheque payment status becomes Bounced, and a Cheque bounced notification is sent to the relevant guardians. For an earmark funded by cheque, the earmark is voided: the funding entry on its ledger is reversed, the bursar can record an optional penalty amount that raises a separate penalty invoice for the student, and an Earmark cheque bounced notification is sent. For a wallet top-up by cheque, the wallet credit is reversed, and a penalty invoice is raised if the bursar entered a penalty amount greater than zero. In every case, ask the guardian to send a replacement payment for the original amount.
Can a guardian pay an invoice directly from their login?
No. Guardians have read-only access to invoices, payments, wallets, and earmarks. The Record Invoice Payment, Credit Wallet, Debit Wallet, and Prepay Billable actions are hidden from the Guardian role. M-Pesa STK push prompts are initiated by the school side; the guardian then authorises the prompt on their phone. Guardians can still push payments to the school’s Paybill from their own M-Pesa menu and use the invoice ID as the account reference; those payments reconcile automatically through C2B.
Why can I not edit or delete an invoice?
Invoices are part of the school’s financial ledger and stay immutable once created. Lines, amounts, and statuses change only through valid actions (recording payments, marking cheques cleared or bounced, the daily overdue scan), never through manual edits. If a charge was wrong on an issued invoice, raise a new invoice for the correction or wait for the payment flow to reconcile.
Where do M-Pesa callbacks go if Finance is disabled?
They are still received and logged. Inbound Safaricom callbacks are intentionally not gated by the module so that late callbacks for payments started before the module was disabled can still be matched. With Finance disabled, however, no new payment intents are being created, so most inbound callbacks find nothing to resolve and become no-ops.
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Elimu Bora ERP Help Center","description":"Help center for Elimu Bora ERP — a school management system for Kenyan schools running CBC and 8-4-4.","colors":{"primary":"#800000","light":"#FF4D4D","dark":"#800000"},"logo":{"light":"https://mintcdn.com/elimuborasolutionsco/_rAr-ZsKVDWTZrZ6/images/elimubora-logo-primary.png?fit=max\u0026auto=format\u0026n=_rAr-ZsKVDWTZrZ6\u0026q=85\u0026s=4ed2d6d18eb543c27f5cb0bbe0b1ac02","dark":"https://mintcdn.com/elimuborasolutionsco/_rAr-ZsKVDWTZrZ6/images/elimubora-logo-white.png?fit=max\u0026auto=format\u0026n=_rAr-ZsKVDWTZrZ6\u0026q=85\u0026s=8998852a8162322751aad5b730aeeb3e"},"favicon":"https://media.brand.dev/28107f06-65a0-45ce-9937-4bc6a00d197b.svg","appearance":{"default":"system"},"navbar":{"links":[{"href":"https://elimuboraerp.com/login","label":"Login","type":"button"}],"primary":{"type":"button","label":"Get Started for Free","href":"https://elimuboraerp.com/get-started/"}},"footer":{"socials":{"website":"https://elimuboraerp.com/","x":"https://x.com/elimuboraerp","facebook":"https://www.facebook.com/elimuborasolutions","instagram":"https://www.instagram.com/elimuboraerp","linkedin":"https://www.linkedin.com/company/elimu-bora-solutions-co"},"links":[{"header":"Product","items":[{"label":"Pricing","href":"https://elimuboraerp.com/pricing"},{"label":"Book a Demo","href":"https://elimuboraerp.com/contact"}]},{"header":"Company","items":[{"label":"Blog \u0026 Resources","href":"https://elimuboraerp.com/blog"},{"label":"Contact Us","href":"https://elimuboraerp.com/contact"}]},{"header":"Legal","items":[{"label":"Privacy Policy","href":"https://elimuboraerp.com/privacy-policy"},{"label":"Terms of Service","href":"https://elimuboraerp.com/terms-of-service"}]},{"header":"Support","items":[{"label":"support@elimuboraerp.com","href":"mailto:support@elimuboraerp.com"},{"label":"Contact Us","href":"https://elimuboraerp.com/contact"}]}]},"fonts":{"heading":{"family":"Sora","weight":700},"body":{"family":"DM Sans","weight":400}},"icons":{"library":"lucide"},"styling":{"eyebrows":"breadcrumbs","latex":true},"integrations":{"posthog":{"apiKey":"phc_qpX7FwgEJa6osP32UU2YEpCp6hYGcwbzVBUdtdnhgPz6","apiHost":"https://b.elimuboraerp.com","sessionRecording":true}},"thumbnails":{"background":"https://mintcdn.com/elimuborasolutionsco/P4BsReXBMB71cxBd/images/cover.png?fit=max\u0026auto=format\u0026n=P4BsReXBMB71cxBd\u0026q=85\u0026s=38f85d7b5b8afb20150889c68acc2ae2","fonts":{"family":"Sora"}},"navigation":{"global":{"anchors":[{"anchor":"Pricing","icon":"tag","href":"https://elimuboraerp.com/pricing/"},{"anchor":"Book a Demo","icon":"calendar-check","href":"https://elimuboraerp.com/contact/"},{"anchor":"Blog \u0026 Resources","icon":"newspaper","href":"https://elimuboraerp.com/blog/"},{"anchor":"Contact Us","icon":"mail","href":"https://elimuboraerp.com/contact/"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"elimuborasolutionsco","hasAudioNarration":false,"actualSubdomain":"elimuborasolutionsco","customDomains":["help.elimuboraerp.com"],"gitSource":{"type":"github","owner":"edaratechnologiesltd","repo":"docs","deployBranch":"main","isPrivate":false,"contentDirectory":"","mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6aa30504002826c9b5476ac2","collectionId":"92ac9a21-c4d2-446d-9cf6-2e90f5f6c95c","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6aa30504002826c9b5476ac2"},"feedback":{"thumbs":true,"agentFeedback":true},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6aa30504002826c9b5476ac2","clientVersion":"0.0.3966","searchFilterCounts":[{"language":"default","tag":"Documentation","count":18},{"language":"default","tag":"Modules","count":12},{"language":"default","tag":"Get Started","count":5},{"language":"default","tag":"More","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":true,"enableContextualStarterQuestions":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"email":"support@elimuboraerp.com","showHelpButton":true}},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":true},"customCss":[{"filePath":"style.css","content":"#navbar img{height:40px;width:auto;max-height:40px}"}],"page":{"pagePath":"modules/finance","slug":"/modules/finance","pageMetadata":{"title":"Finance \u0026 Fee Management","description":"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.","icon":"wallet","href":"/modules/finance"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Accordion,AccordionGroup,Card,CardGroup,Heading,Mermaid,Note,Step,Steps,Table}=_components;if(!Accordion)_missingMdxReference(`Accordion`,true);if(!AccordionGroup)_missingMdxReference(`AccordionGroup`,true);if(!Card)_missingMdxReference(`Card`,true);if(!CardGroup)_missingMdxReference(`CardGroup`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Mermaid)_missingMdxReference(`Mermaid`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Step)_missingMdxReference(`Step`,true);if(!Steps)_missingMdxReference(`Steps`,true);if(!Table)_missingMdxReference(`Table`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`Finance covers everything a school does with money in Elimu Bora: defining fee items, issuing invoices, accepting and reconciling payments (including M-Pesa STK push and Paybill), running per-student wallets for canteen-style spending, and locking prepaid funds against specific charges with earmarks. Bursars run it day to day. School leadership uses it for oversight and reports. Guardians can view their children’s invoices, payments, wallets, and earmarks, but cannot record payments or move money from the panel.`}),`\n`,_jsx(Note,{children:_jsx(_components.p,{children:`Finance is an optional module. A school can enable or disable it under Settings. When Finance is disabled, every Finance resource disappears from the sidebar, scheduled overdue checks are skipped for the tenant, and outbound finance notifications are dropped. Inbound M-Pesa callbacks are still received so that late callbacks for payments started before the module was disabled can still be reconciled.`})}),`\n`,_jsx(Heading,{level:`2`,id:`records-you’ll-work-with`,children:`Records you’ll work with`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Record`}),_jsx(_components.th,{children:`What it is`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Billable`}),_jsx(_components.td,{children:`A fee item that can be charged, such as tuition, transport, or lunch.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Billable group`}),_jsx(_components.td,{children:`A bundle of billables grouped together (for example, a Term 1 fees bundle).`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Billable variant`}),_jsx(_components.td,{children:`A pricing variation of a billable when one fee has more than one price (for example, per bus route).`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Per-stage amount`}),_jsx(_components.td,{children:`A stage-level override of a billable’s price, so Grade 1 tuition can differ from Grade 8 tuition.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Invoice`}),_jsx(_components.td,{children:`A bill issued to a student, teacher, or staff member, scoped to a term.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Invoice line`}),_jsx(_components.td,{children:`One charge on an invoice, tied to a billable or recorded as ad-hoc. The line’s discount is filled in automatically when the invoice is created, from any active discount the student’s guardians hold for that billable.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Discount`}),_jsx(_components.td,{children:`A reduction held on a guardian, scoped to one billable, expressed as a percentage or a fixed amount, with an effective date range. Applied automatically to matching invoice lines.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Invoice payment`}),_jsx(_components.td,{children:`A payment recorded against an invoice.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Payment allocation`}),_jsx(_components.td,{children:`The split of one payment across the lines of its invoice.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Wallet`}),_jsx(_components.td,{children:`A per-student credit balance for student spending (school canteen and similar non-invoice use).`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Wallet transaction`}),_jsx(_components.td,{children:`A credit or debit entry on a wallet, with a balance snapshot for audit.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Earmark`}),_jsx(_components.td,{children:`Prepaid funds locked against a specific billable for a student, drained automatically when a matching invoice payment is recorded.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Earmark transaction`}),_jsx(_components.td,{children:`A funding, drain, refund, or bounce entry on an earmark, with a balance snapshot for audit.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Sponsor`}),_jsx(_components.td,{children:`A third party paying for an invoice payment (Government, NGO, Corporate, or Individual).`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`M-Pesa integration`}),_jsx(_components.td,{children:`The school’s stored M-Pesa credentials (Paybill shortcode, passkey, consumer key and secret) and the callback URLs registered with Safaricom.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`what-you-can-do`,children:`What you can do`}),`\n`,_jsxs(CardGroup,{cols:2,children:[_jsx(Card,{title:`Set up fees`,icon:`list-check`,href:`#set-up-fees`,children:_jsx(_components.p,{children:`Define billables, variants, per-stage amounts, and guardian-level discounts.`})}),_jsx(Card,{title:`Issue invoices`,icon:`file-text`,href:`#issue-invoices`,children:_jsx(_components.p,{children:`Create invoices, add lines with optional discounts, and read the balance.`})}),_jsx(Card,{title:`Record payments`,icon:`hand-coins`,href:`#record-payments`,children:_jsx(_components.p,{children:`Cash, bank transfer, cheque, M-Pesa STK push, and Paybill (C2B).`})}),_jsx(Card,{title:`Run wallets`,icon:`piggy-bank`,href:`#run-wallets`,children:_jsx(_components.p,{children:`Credit a wallet for canteen-style spending, debit it as funds are used, and handle low-balance notifications.`})}),_jsx(Card,{title:`Manage earmarks`,icon:`lock`,href:`#manage-earmarks`,children:_jsx(_components.p,{children:`Lock prepaid funds against a billable; let them drain automatically, or refund what is left.`})}),_jsx(Card,{title:`Attach sponsors`,icon:`handshake`,href:`#attach-sponsors`,children:_jsx(_components.p,{children:`Tag payments with the sponsor that funded them for reconciliation.`})})]}),`\n`,_jsx(Heading,{level:`2`,id:`set-up-fees`,children:`Set up fees`}),`\n`,_jsx(_components.p,{children:`Fees are built from billables. Each billable has a pricing model that decides what other rows are required.`}),`\n`,_jsx(Heading,{level:`3`,id:`create-a-billable`,children:`Create a billable`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open Billables`,children:_jsxs(_components.p,{children:[`In the sidebar, go to `,_jsx(_components.strong,{children:`Billables`}),` and click `,_jsx(_components.strong,{children:`New billable`}),`.`]})}),_jsxs(Step,{title:`Name the billable and pick a pricing model`,children:[_jsx(_components.p,{children:`Pick one of three pricing models:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Flat`}),`: a single price for everyone. Enter the `,_jsx(_components.strong,{children:`Default amount`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Variants`}),`: different prices for different choices (for example, three bus routes). You will add variant rows next.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Per unit`}),`: price multiplied by a quantity entered on each invoice line.`]}),`\n`]})]}),_jsx(Step,{title:`Optionally group the billable`,children:_jsxs(_components.p,{children:[`Pick a `,_jsx(_components.strong,{children:`Billable group`}),` to bundle this billable with related ones (for example, “Term 1 fees”). Groups make it easier to attach a full bundle to an invoice in one step.`]})}),_jsx(Step,{title:`Save`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Save`}),`. The billable becomes available for invoice lines and earmarks.`]})})]}),`\n`,_jsx(_components.p,{children:`[Insert screenshot: Billables list at /billables with columns Name, Pricing model, Default amount, Group, and the New billable button in the header]`}),`\n`,_jsx(Heading,{level:`3`,id:`add-a-billable-variant`,children:`Add a billable variant`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` a billable whose pricing model is set to `,_jsx(_components.strong,{children:`Variants`}),`. Variants do not apply to `,_jsx(_components.strong,{children:`Flat`}),` or `,_jsx(_components.strong,{children:`Per unit`}),` billables.`]})}),`\n`,_jsxs(_components.p,{children:[`When the pricing model is `,_jsx(_components.strong,{children:`Variants`}),`, each variant carries its own amount.`]}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the billable`,children:_jsx(_components.p,{children:`From the Billables list, open the parent billable.`})}),_jsx(Step,{title:`Add a variant row`,children:_jsxs(_components.p,{children:[`In the `,_jsx(_components.strong,{children:`Variants`}),` section, click `,_jsx(_components.strong,{children:`Add variant`}),`. Enter a label (for example, “Route A: Karen”) and the amount.`]})}),_jsx(Step,{title:`Save`,children:_jsx(_components.p,{children:`Save the billable. The new variant becomes selectable when an invoice line uses this billable.`})})]}),`\n`,_jsx(Heading,{level:`3`,id:`set-a-per-stage-amount`,children:`Set a per-stage amount`}),`\n`,_jsx(_components.p,{children:`Use per-stage amounts to charge different prices by curriculum stage (for example, Grade 1 tuition is lower than Grade 8 tuition). Curriculum stages ship pre-seeded and read-only, so there is no setup before this step.`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the billable and scroll to Per-stage amounts`,children:_jsxs(_components.p,{children:[`Open the parent billable and find the `,_jsx(_components.strong,{children:`Per-stage amounts`}),` section.`]})}),_jsx(Step,{title:`Add an override row per stage`,children:_jsx(_components.p,{children:`Pick a curriculum stage and enter the amount for that stage. Stages without a per-stage row fall back to the default amount.`})}),_jsx(Step,{title:`Save`,children:_jsx(_components.p,{children:`Save the billable. Invoice generation will use the per-stage amount for students in the matching stage.`})})]}),`\n`,_jsx(Heading,{level:`3`,id:`hold-a-discount-for-a-guardian`,children:`Hold a discount for a guardian`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` the billable the discount applies to, and the guardian record. Discounts are held on the `,_jsx(_components.strong,{children:`guardian`}),`, not the student. When an invoice is later raised for one of that guardian’s children for the matching billable, the system applies the discount automatically.`]})}),`\n`,_jsx(_components.p,{children:`A discount reduces the line amount for a specific billable on any invoice raised for the guardian’s children. If a child has more than one guardian and more than one of them holds a discount for the same billable, the largest applicable discount is the one that lands on the line.`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the guardian`,children:_jsxs(_components.p,{children:[`Go to `,_jsx(_components.strong,{children:`Guardians`}),` and open the guardian who is entitled to the discount.`]})}),_jsx(Step,{title:`Open the Discounts tab`,children:_jsxs(_components.p,{children:[`Switch to the `,_jsx(_components.strong,{children:`Discounts`}),` tab on the guardian’s profile.`]})}),_jsx(Step,{title:`Add a discount`,children:_jsxs(_components.p,{children:[`Click the create action. Pick the `,_jsx(_components.strong,{children:`Billable`}),` the discount applies to, the `,_jsx(_components.strong,{children:`Type`}),` (`,_jsx(_components.strong,{children:`Percentage`}),` or `,_jsx(_components.strong,{children:`Amount`}),`), and enter the value. Pick the `,_jsx(_components.strong,{children:`Effective From`}),` date (defaults to today) and an optional `,_jsx(_components.strong,{children:`Effective Until`}),` date. Leave `,_jsx(_components.strong,{children:`Active`}),` on. Add notes if useful.`]})}),_jsx(Step,{title:`Save`,children:_jsx(_components.p,{children:`Save. The discount is now in effect. The next invoice line raised for one of this guardian’s children that charges the same billable, within the effective date range, will pick up the discount automatically.`})})]}),`\n`,_jsx(Heading,{level:`2`,id:`issue-invoices`,children:`Issue invoices`}),`\n`,_jsx(_components.p,{children:`An invoice is the document a school issues to a student, teacher, or staff member. Most invoices target students. The invoice is scoped to a single term.`}),`\n`,_jsx(Heading,{level:`3`,id:`create-an-invoice`,children:`Create an invoice`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` an active term, the student, teacher, or staff member the invoice is for, and (if you want to use a billable rather than an ad-hoc line) the billable already created. If the billable does not exist yet, add it first under `,_jsx(_components.a,{href:`#set-up-fees`,children:`Set up fees`}),`, or record the charge as an ad-hoc line with a typed label and amount.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open Invoices`,children:_jsxs(_components.p,{children:[`Go to `,_jsx(_components.strong,{children:`Invoices`}),` and click `,_jsx(_components.strong,{children:`New invoice`}),`.`]})}),_jsx(Step,{title:`Pick the invoiceable`,children:_jsxs(_components.p,{children:[`Pick whether the invoice is for a `,_jsx(_components.strong,{children:`Student`}),`, `,_jsx(_components.strong,{children:`Teacher`}),`, or `,_jsx(_components.strong,{children:`Staff`}),` member, then pick the specific person.`]})}),_jsx(Step,{title:`Pick the term and due date`,children:_jsx(_components.p,{children:`Pick the term this invoice covers, and an optional due date. The due date is what the overdue scan uses.`})}),_jsx(Step,{title:`Add invoice lines`,children:_jsxs(_components.p,{children:[`Add one line per charge. Each line is either tied to a billable (and inherits its amount, including any per-stage override for the student’s grade stage) or recorded as an ad-hoc line with a label and amount you type in. The bursar does not enter discounts on the line itself: when the line is saved, the system looks up active `,_jsx(_components.strong,{children:`Discounts`}),` the student’s guardians hold for that billable and applies the largest applicable one automatically, snapshotting it onto the line. See `,_jsx(_components.a,{href:`#hold-a-discount-for-a-guardian`,children:`Hold a discount for a guardian`}),`.`]})}),_jsx(Step,{title:`Save the invoice`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Save`}),`. The invoice starts in `,_jsx(_components.strong,{children:`Pending`}),` status. Adding lines automatically recomputes the invoice total. A notification is queued to the invoiceable’s guardians (for student invoices) or to the staff or teacher themselves.`]})})]}),`\n`,_jsx(_components.p,{children:`[Insert screenshot: New invoice form at /invoices/create showing the Invoiceable picker (Student/Teacher/Staff), Term selector, Due date, and the repeating Line Items block with Billable, Label, Unit Amount, and Qty columns]`}),`\n`,_jsx(Heading,{level:`3`,id:`read-an-invoice’s-balance-and-history`,children:`Read an invoice’s balance and history`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Invoices are immutable once created.`}),` The invoice’s lines, amounts, and payments are part of the school’s ledger and cannot be edited or deleted from the panel. If a charge was wrong, raise a new invoice for the corrected amount, or wait for the payment flow to balance things out (a refund happens on the earmark side, not on the invoice itself).`]})}),`\n`,_jsxs(_components.p,{children:[`The invoice view page shows the running total, the `,_jsx(_components.strong,{children:`Total paid`}),`, and the current `,_jsx(_components.strong,{children:`Balance`}),`. The `,_jsx(_components.strong,{children:`Lines`}),` tab lists every charge with its discount and total. The `,_jsx(_components.strong,{children:`Payments`}),` tab lists every payment with its method and status. The `,_jsx(_components.strong,{children:`Activity log`}),` captures every change.`]}),`\n`,_jsxs(_components.p,{children:[`[Insert screenshot: Invoice view page at /invoices/`,` showing the header summary (Amount, Total paid, Balance, Status badge), the Lines relation manager, and the Payments relation manager with method and status columns]`]}),`\n`,_jsx(Heading,{level:`2`,id:`record-payments`,children:`Record payments`}),`\n`,_jsxs(_components.p,{children:[`All payments are recorded from one place: the `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` modal. Pick a method on the form, fill in the method-specific fields, and save. M-Pesa is one of the methods; selecting it reveals a phone-number input and lets the bursar send an STK push.`]}),`\n`,_jsxs(_components.p,{children:[`Payment methods available on the form: `,_jsx(_components.strong,{children:`M-Pesa`}),`, `,_jsx(_components.strong,{children:`Cash`}),`, `,_jsx(_components.strong,{children:`Bank Transfer`}),`, `,_jsx(_components.strong,{children:`Cheque`}),`. The system also sets two internal methods automatically when they apply: `,_jsx(_components.strong,{children:`Earmark`}),` (when a payment is settled from an earmark balance) and `,_jsx(_components.strong,{children:`Wallet refund`}),` (when an earmark is refunded back into a wallet).`]}),`\n`,_jsx(Heading,{level:`3`,id:`record-a-cash-or-bank-transfer-payment`,children:`Record a cash or bank transfer payment`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the invoice`,children:_jsxs(_components.p,{children:[`Open the invoice from `,_jsx(_components.strong,{children:`Invoices`}),`.`]})}),_jsx(Step,{title:`Open the payment modal`,children:_jsxs(_components.p,{children:[`On the invoice view page, click `,_jsx(_components.strong,{children:`Record Invoice Payment`}),`.`]})}),_jsx(Step,{title:`Pick the method and enter the amount`,children:_jsxs(_components.p,{children:[`Pick `,_jsx(_components.strong,{children:`Cash`}),` or `,_jsx(_components.strong,{children:`Bank Transfer`}),`. Enter the amount. For bank transfers, record the bank reference.`]})}),_jsx(Step,{title:`Save`,children:_jsxs(_components.p,{children:[`Save the payment. Cash and bank transfer payments go straight to `,_jsx(_components.strong,{children:`Cleared`}),` status. The payment is allocated proportionally across the invoice’s unpaid lines unless you override the allocation manually. The invoice status moves to `,_jsx(_components.strong,{children:`Partial`}),` or `,_jsx(_components.strong,{children:`Paid`}),` based on the new balance. A dashboard notification appears for the school, and a receipt PDF is emailed to the invoice owner (the guardian for a student invoice, or the staff or teacher for theirs).`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`record-a-cheque-payment`,children:`Record a cheque payment`}),`\n`,_jsxs(_components.p,{children:[`Cheques start in `,_jsx(_components.strong,{children:`Pending`}),` until a bursar marks them cleared or bounced.`]}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the payment modal`,children:_jsxs(_components.p,{children:[`On the invoice view page, click `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` and pick `,_jsx(_components.strong,{children:`Cheque`}),` as the method.`]})}),_jsx(Step,{title:`Enter cheque details`,children:_jsx(_components.p,{children:`Enter the cheque number, the drawing bank, the cheque drawn date, and the amount.`})}),_jsx(Step,{title:`Save`,children:_jsxs(_components.p,{children:[`Save the payment. The payment status is `,_jsx(_components.strong,{children:`Pending`}),`. The invoice balance is not yet credited because the cheque has not cleared.`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`acknowledge-a-cheque`,children:`Acknowledge a cheque`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` a cheque payment in `,_jsx(_components.strong,{children:`Pending`}),` status on the invoice. The action is only available for cheque payments that have not yet cleared.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the payment`,children:_jsxs(_components.p,{children:[`On the invoice’s `,_jsx(_components.strong,{children:`Payments`}),` tab, find the cheque row.`]})}),_jsx(Step,{title:`Use Acknowledge`,children:_jsxs(_components.p,{children:[`Use the `,_jsx(_components.strong,{children:`Acknowledge`}),` action and confirm. The payment status becomes `,_jsx(_components.strong,{children:`Cleared`}),` and the invoice is credited. The invoice status moves to `,_jsx(_components.strong,{children:`Partial`}),` or `,_jsx(_components.strong,{children:`Paid`}),`, and the receipt PDF is emailed to the invoice owner.`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`mark-a-cheque-bounced`,children:`Mark a cheque bounced`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` a cheque payment in `,_jsx(_components.strong,{children:`Pending`}),` status on the invoice, and the system billable `,_jsx(_components.strong,{children:`Bounced Cheque Penalty`}),` present in your Billables list (it is pre-seeded; if it is missing, ask a Super Admin to re-seed the billables).`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the payment`,children:_jsxs(_components.p,{children:[`On the invoice’s `,_jsx(_components.strong,{children:`Payments`}),` tab, find the cheque row.`]})}),_jsx(Step,{title:`Use Mark bounced`,children:_jsxs(_components.p,{children:[`Use the `,_jsx(_components.strong,{children:`Mark bounced`}),` action.`]})}),_jsx(Step,{title:`Enter the bounce reason and the penalty amount`,children:_jsxs(_components.p,{children:[`The modal prompts for a `,_jsx(_components.strong,{children:`Bounce reason`}),` (free text) and a `,_jsx(_components.strong,{children:`Penalty amount`}),` (the fine to charge the guardian). The penalty defaults to the `,_jsx(_components.strong,{children:`Bounced Cheque Penalty`}),` billable’s default amount; the bursar can override it for this case.`]})}),_jsx(Step,{title:`Confirm`,children:_jsxs(_components.p,{children:[`Confirm. The payment status becomes `,_jsx(_components.strong,{children:`Bounced`}),` (terminal). A new `,_jsx(_components.strong,{children:`Bounced cheque penalty`}),` line is added to the same invoice for the penalty amount, increasing the balance. A `,_jsx(_components.strong,{children:`Cheque bounced`}),` notification goes to the relevant guardians and a dashboard notification appears for the bursar.`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`trigger-an-m-pesa-stk-push`,children:`Trigger an M-Pesa STK push`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` the M-Pesa integration configured under `,_jsx(_components.a,{href:`#configure-m-pesa`,children:`Configure M-Pesa`}),`, and a phone number for the guardian who will pay. The guardian’s phone number is on their profile under `,_jsx(_components.a,{href:`/modules/users`,children:`Users \u0026 Identity`}),`. Without the integration, the `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` modal does not show the phone-number input for the M-Pesa method, because there is nowhere to send the prompt.`]})}),`\n`,_jsxs(_components.p,{children:[`M-Pesa STK push is initiated from the school side. The bursar opens the `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` modal, picks M-Pesa, enters the guardian’s phone number, and sends the prompt. Guardians cannot initiate STK push from their own logins; the `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` action is hidden from the Guardian role.`]}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the invoice`,children:_jsxs(_components.p,{children:[`Open the invoice from `,_jsx(_components.strong,{children:`Invoices`}),`, or from the `,_jsx(_components.strong,{children:`Invoices`}),` tab on the student’s profile.`]})}),_jsx(Step,{title:`Open the payment modal and pick M-Pesa`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` and pick `,_jsx(_components.strong,{children:`M-Pesa`}),`. The phone-number input appears.`]})}),_jsx(Step,{title:`Enter the phone and amount, then send the prompt`,children:_jsxs(_components.p,{children:[`Enter the guardian’s phone number and the amount. Click `,_jsx(_components.strong,{children:`Record Payment`}),` to send the prompt. The system creates an M-Pesa payment intent (status `,_jsx(_components.strong,{children:`Pending`}),`) and Safaricom delivers a SIM Toolkit prompt to the guardian’s phone.`]})}),_jsx(Step,{title:`Wait for the callback`,children:_jsx(_components.p,{children:`The guardian enters their M-Pesa PIN on their phone. Safaricom posts a callback to the school’s tenant subdomain. The system matches the callback to the payment intent, creates a cleared invoice payment, and recomputes the invoice balance. A dashboard notification appears for the school, and a receipt PDF is emailed to the invoice owner.`})})]}),`\n`,_jsx(_components.p,{children:`[Insert screenshot: Record Invoice Payment modal launched from a student invoice showing Method set to M-Pesa with the Phone number and Amount fields and the Record Payment button]`}),`\n`,_jsx(Heading,{level:`3`,id:`reconcile-an-m-pesa-paybill-c2b-payment`,children:`Reconcile an M-Pesa Paybill (C2B) payment`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` the M-Pesa integration configured under `,_jsx(_components.a,{href:`#configure-m-pesa`,children:`Configure M-Pesa`}),`, and the Paybill callback URLs registered with Safaricom Daraja. Without these URLs, deposits will land in the Paybill account but the system will not know about them.`]})}),`\n`,_jsx(_components.p,{children:`When a guardian pays the school’s Paybill number from their own M-Pesa menu, the same callback infrastructure receives the deposit and applies it to the matching invoice automatically.`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Guardian pays the Paybill`,children:_jsxs(_components.p,{children:[`The guardian sends money to the school’s M-Pesa Paybill number. The guardian enters the `,_jsx(_components.strong,{children:`invoice ID`}),` as the account reference (this is the number shown on the invoice). The invoice ID, not the admission number, is what the system uses to match the deposit to the right invoice.`]})}),_jsx(Step,{title:`System receives the C2B callback`,children:_jsx(_components.p,{children:`Safaricom posts a Confirmation callback to the school’s tenant subdomain. The system writes an M-Pesa payment intent, looks up the invoice by the account reference, and creates a cleared invoice payment for the deposited amount.`})}),_jsx(Step,{title:`Verify in the panel`,children:_jsxs(_components.p,{children:[`The payment appears on the `,_jsx(_components.strong,{children:`Payments`}),` tab of the resolved invoice within seconds. The invoice status moves to `,_jsx(_components.strong,{children:`Partial`}),` or `,_jsx(_components.strong,{children:`Paid`}),` based on the new balance.`]})})]}),`\n`,_jsx(Heading,{level:`2`,id:`run-wallets`,children:`Run wallets`}),`\n`,_jsx(_components.p,{children:`Each student has a single wallet. A wallet is auto-created when the student is admitted, so there is nothing to set up beforehand.`}),`\n`,_jsxs(_components.p,{children:[`The wallet is a credit balance for `,_jsx(_components.strong,{children:`student spending outside the invoicing flow`}),`: school canteen purchases, similar small-value drawdowns the school manages directly. `,_jsx(_components.strong,{children:`Wallets cannot be used to settle invoices.`}),` Use `,_jsx(_components.a,{href:`#manage-earmarks`,children:`earmarks`}),` for prepaid funds that should pay down a specific invoice charge.`]}),`\n`,_jsx(Heading,{level:`3`,id:`credit-a-wallet-top-up`,children:`Credit a wallet (top up)`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` for `,_jsx(_components.strong,{children:`M-Pesa`}),` top-ups, the M-Pesa integration configured under `,_jsx(_components.a,{href:`#configure-m-pesa`,children:`Configure M-Pesa`}),` and a phone number on file for the guardian. Cash, bank transfer, and cheque top-ups do not need any integration.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the wallet`,children:_jsxs(_components.p,{children:[`Open `,_jsx(_components.strong,{children:`Wallets`}),` and pick the student’s wallet, or open the student profile and use the `,_jsx(_components.strong,{children:`Wallet`}),` tab.`]})}),_jsx(Step,{title:`Click Credit Wallet`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Credit Wallet`}),`. Pick the funding method: `,_jsx(_components.strong,{children:`M-Pesa`}),`, `,_jsx(_components.strong,{children:`Cash`}),`, `,_jsx(_components.strong,{children:`Bank Transfer`}),`, or `,_jsx(_components.strong,{children:`Cheque`}),`. For M-Pesa, enter the guardian’s phone number to send the STK push. For cheque, enter the cheque number, the drawing bank, and the cheque drawn date. Add a short description so the ledger entry is self-explanatory.`]})}),_jsx(Step,{title:`Save`,children:_jsxs(_components.p,{children:[`Save. For cash, bank transfer, and successful M-Pesa STK pushes, the wallet is credited immediately, the balance is updated with a before-and-after snapshot, and a `,_jsx(_components.strong,{children:`Wallet funded`}),` notification is sent to the student’s guardians. For cheques, the wallet transaction is `,_jsx(_components.strong,{children:`Pending`}),` until the cheque is acknowledged or marked bounced. If a cheque bounces, you are prompted for a bounce reason and an optional penalty amount; when a penalty greater than zero is entered, a penalty invoice is raised against the student.`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`debit-a-wallet-record-spending`,children:`Debit a wallet (record spending)`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` a wallet with a positive balance. The `,_jsx(_components.strong,{children:`Debit Wallet`}),` action is hidden when the balance is zero. Debits cover student spending that happens `,_jsx(_components.strong,{children:`outside`}),` the invoice flow (school canteen, kiosk, similar) and are recorded by the bursar to keep the wallet ledger accurate. To settle an invoice from prepaid funds, use an `,_jsx(_components.a,{href:`#manage-earmarks`,children:`earmark`}),` instead.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the wallet`,children:_jsxs(_components.p,{children:[`Open `,_jsx(_components.strong,{children:`Wallets`}),` and pick the student’s wallet, or open the student profile and use the `,_jsx(_components.strong,{children:`Wallet`}),` tab.`]})}),_jsx(Step,{title:`Click Debit Wallet`,children:_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Debit Wallet`}),`. Pick the method (`,_jsx(_components.strong,{children:`Cash`}),` or `,_jsx(_components.strong,{children:`Bank Transfer`}),`) and enter the amount; the form caps the amount at the available balance. Add a short description so the entry on the ledger explains what the money was spent on.`]})}),_jsx(Step,{title:`Save`,children:_jsxs(_components.p,{children:[`Save. A debit wallet transaction is written, the balance is updated, and the `,_jsx(_components.strong,{children:`Wallet debited`}),` notification is queued to the student’s guardians. If the debit takes the balance below the low-balance threshold, the `,_jsx(_components.strong,{children:`Wallet low balance`}),` notification fires as well.`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`acknowledge-a-cheque-on-a-wallet`,children:`Acknowledge a cheque on a wallet`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` a cheque-funded wallet transaction in `,_jsx(_components.strong,{children:`Pending`}),` status (from a Credit Wallet step that used the Cheque method).`]})}),`\n`,_jsxs(_components.p,{children:[`On the wallet’s `,_jsx(_components.strong,{children:`Transactions`}),` tab, find the pending cheque row and use the `,_jsx(_components.strong,{children:`Acknowledge Cheque`}),` action. The wallet transaction status becomes Cleared, the wallet balance is updated, and the `,_jsx(_components.strong,{children:`Wallet funded`}),` notification fires. If the cheque bounces instead, use `,_jsx(_components.strong,{children:`Mark Bounced`}),`; the modal prompts for a bounce reason and an optional penalty amount that, when greater than zero, raises a penalty invoice against the student.`]}),`\n`,_jsx(Heading,{level:`3`,id:`read-the-wallet-ledger`,children:`Read the wallet ledger`}),`\n`,_jsxs(_components.p,{children:[`Open the wallet and scroll to the `,_jsx(_components.strong,{children:`Transactions`}),` tab. Every credit and debit is listed in date order with the amount, balance before, balance after, and the related earmark transaction (when the entry comes from an earmark refund-to-wallet). Use the `,_jsx(_components.strong,{children:`Wallet statement`}),` header action to download a single-wallet PDF, or the `,_jsx(_components.strong,{children:`Wallet balances report`}),` on the wallets list to export every wallet’s balance to PDF or Excel.`]}),`\n`,_jsxs(_components.p,{children:[`[Insert screenshot: Wallet view page at /wallets/`,` showing the balance summary, the Transactions tab with columns Date, Type, Amount, Balance after, Related, and the Wallet statement action in the header]`]}),`\n`,_jsx(Heading,{level:`3`,id:`wallet-low-balance-notification`,children:`Wallet low-balance notification`}),`\n`,_jsxs(_components.p,{children:[`When a debit takes a wallet below the configured low-balance threshold, the system sends a `,_jsx(_components.strong,{children:`Wallet low balance`}),` notification to the student’s guardians so they can top up. The threshold is set by the school’s deployment and is not changed from the staff panel.`]}),`\n`,_jsx(Heading,{level:`2`,id:`manage-earmarks`,children:`Manage earmarks`}),`\n`,_jsxs(_components.p,{children:[`An earmark is prepaid funds locked against a `,_jsx(_components.strong,{children:`specific billable`}),` for a `,_jsx(_components.strong,{children:`specific student`}),`. When the bursar later records a payment on an invoice that charges the same billable for the same student, the earmark drains automatically and settles that line. Earmarks are how a school accepts payment in advance for a known charge (for example, paying the Term 2 transport fee in January).`]}),`\n`,_jsxs(_components.p,{children:[`Earmarks are `,_jsx(_components.strong,{children:`separate from wallets`}),`. Funding an earmark does not pull money from the wallet; it is its own deposit. Refunding an earmark can credit the wallet (one of the refund destinations) but the two balances are not the same balance.`]}),`\n`,_jsx(Heading,{level:`3`,id:`lock-funds-with-an-earmark-prepay`,children:`Lock funds with an earmark (Prepay)`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` the target billable to exist. For `,_jsx(_components.strong,{children:`M-Pesa`}),` funding, the M-Pesa integration must be configured under `,_jsx(_components.a,{href:`#configure-m-pesa`,children:`Configure M-Pesa`}),` and a phone number must be on file for the guardian. Cash, bank transfer, and cheque funding do not need any integration.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the student or the billable`,children:_jsxs(_components.p,{children:[`Open the student profile and pick the `,_jsx(_components.strong,{children:`Earmarks`}),` tab, or open the billable and use the `,_jsx(_components.strong,{children:`Prepay Billable`}),` action.`]})}),_jsx(Step,{title:`Pick the billable and the funding method`,children:_jsxs(_components.p,{children:[`Pick the billable the earmark is for. Pick the funding method: `,_jsx(_components.strong,{children:`Cash`}),`, `,_jsx(_components.strong,{children:`M-Pesa`}),`, `,_jsx(_components.strong,{children:`Bank Transfer`}),`, or `,_jsx(_components.strong,{children:`Cheque`}),`.`]})}),_jsx(Step,{title:`Enter the amount and confirm`,children:_jsxs(_components.p,{children:[`Enter the amount. Confirm. For non-cheque methods the earmark starts in `,_jsx(_components.strong,{children:`Active`}),`; a `,_jsx(_components.strong,{children:`Funding`}),` entry is added to the earmark transaction ledger. For cheques the earmark starts in `,_jsx(_components.strong,{children:`Pending clearance`}),` until the cheque clears; if the cheque bounces, the earmark funding is reversed and you are prompted for an optional penalty amount that, when greater than zero, raises a penalty invoice against the student. An `,_jsx(_components.strong,{children:`Earmark cheque bounced`}),` notification is sent to the relevant guardians.`]})})]}),`\n`,_jsxs(_components.p,{children:[`[Insert screenshot: Earmark view page at /earmarks/`,` showing the reserved amount, the linked billable, the student, the status badge (Active, Pending clearance, Depleted, Refunded), and the Refund action]`]}),`\n`,_jsx(Heading,{level:`3`,id:`drain-an-earmark-against-an-invoice-payment`,children:`Drain an earmark against an invoice payment`}),`\n`,_jsxs(_components.p,{children:[`Earmark drain happens automatically. When the bursar records an invoice payment for the same student and the same billable the earmark covers, the system can settle the payment from the earmark instead of asking the guardian to pay again. A `,_jsx(_components.strong,{children:`Drain`}),` entry is added to the earmark transaction ledger and the invoice is credited. When the earmark balance reaches zero, the earmark status moves to `,_jsx(_components.strong,{children:`Depleted`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`refund-an-earmark`,children:`Refund an earmark`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` an earmark in `,_jsx(_components.strong,{children:`Active`}),` status with a positive remaining balance. Depleted, Refunded, and Pending clearance earmarks cannot be refunded.`]})}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open the earmark`,children:_jsxs(_components.p,{children:[`Open the earmark from `,_jsx(_components.strong,{children:`Earmarks`}),`, or from the `,_jsx(_components.strong,{children:`Earmarks`}),` tab on the student’s profile.`]})}),_jsxs(Step,{title:`Pick a refund destination`,children:[_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Refund`}),` and pick:`]}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`External payout`}),`: the bursar pays out the remaining balance through a channel outside the system (cash at the office, bank transfer, M-Pesa B2C). The earmark transaction ledger gets a `,_jsx(_components.strong,{children:`Refund`}),` entry. Elimu Bora records the refund but does not move the money.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Credit to wallet`}),`: the remaining balance is moved to the student’s wallet. The earmark ledger gets a `,_jsx(_components.strong,{children:`Refund to wallet`}),` entry, and the wallet records a matching credit.`]}),`\n`]})]}),_jsx(Step,{title:`Confirm`,children:_jsxs(_components.p,{children:[`Confirm. The earmark status becomes `,_jsx(_components.strong,{children:`Refunded`}),` (terminal).`]})})]}),`\n`,_jsx(Heading,{level:`3`,id:`read-the-earmark-ledger`,children:`Read the earmark ledger`}),`\n`,_jsxs(_components.p,{children:[`Open the earmark and scroll to the `,_jsx(_components.strong,{children:`Transactions`}),` tab. Every funding, drain, refund, refund-to-wallet, and bounce entry is listed in date order.`]}),`\n`,_jsx(Heading,{level:`2`,id:`attach-sponsors`,children:`Attach sponsors`}),`\n`,_jsxs(_components.p,{children:[`A sponsor is a third party paying for a student’s charges, such as a government scholarship or an NGO. Sponsors are attached to `,_jsx(_components.strong,{children:`payments`}),`, not invoices: when a sponsor pays, the bursar records the payment and tags it with the sponsor so the reconciliation report can group the payment under that sponsor.`]}),`\n`,_jsx(Heading,{level:`3`,id:`add-a-sponsor-record`,children:`Add a sponsor record`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open Sponsors`,children:_jsxs(_components.p,{children:[`Go to `,_jsx(_components.strong,{children:`Sponsors`}),` and click `,_jsx(_components.strong,{children:`New sponsor`}),`.`]})}),_jsx(Step,{title:`Pick a type and enter contact details`,children:_jsxs(_components.p,{children:[`Pick a sponsor type: `,_jsx(_components.strong,{children:`Government`}),`, `,_jsx(_components.strong,{children:`NGO`}),`, `,_jsx(_components.strong,{children:`Individual`}),`, or `,_jsx(_components.strong,{children:`Corporate`}),`. Enter the sponsor’s contact details.`]})}),_jsx(Step,{title:`Save`,children:_jsx(_components.p,{children:`Save. The sponsor is now selectable on any new invoice payment.`})})]}),`\n`,_jsx(Heading,{level:`3`,id:`attach-a-sponsor-to-a-payment`,children:`Attach a sponsor to a payment`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` the sponsor record to exist before you record the payment.`]})}),`\n`,_jsxs(_components.p,{children:[`When you record an invoice payment, pick the sponsor from the `,_jsx(_components.strong,{children:`Sponsor`}),` field on the payment form. The payment is tagged. Later, the bursar can group payments by sponsor on the reconciliation reports.`]}),`\n`,_jsx(Heading,{level:`2`,id:`configure-m-pesa`,children:`Configure M-Pesa`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`You will need:`}),` an M-Pesa Daraja account with the credentials Safaricom issued for your Paybill: shortcode, passkey, consumer key, and consumer secret. If you do not have these, contact Safaricom to register your school as a business and request Daraja API access.`]})}),`\n`,_jsxs(_components.p,{children:[`A school’s M-Pesa credentials live on a `,_jsx(_components.strong,{children:`Payment integration`}),` row. Read or change them is restricted to school leadership and bursars in the default role setup.`]}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Open Payment Integrations`,children:_jsxs(_components.p,{children:[`Go to `,_jsx(_components.strong,{children:`Payment Integrations`}),` in the sidebar.`]})}),_jsx(Step,{title:`Add or edit the M-Pesa integration`,children:_jsx(_components.p,{children:`Pick the M-Pesa row, or add one if missing. Enter the shortcode, the passkey, the consumer key, and the consumer secret. These come from the school’s Safaricom Daraja account.`})}),_jsxs(Step,{title:`Register callback URLs with Safaricom`,children:[_jsx(_components.p,{children:`In Safaricom Daraja, set the callback URLs to point at the school’s tenant subdomain:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`STK push: `,_jsx(_components.code,{children:`https://\u003cyour-subdomain>.elimuboraerp.com/api/mpesa/stk/callback`})]}),`\n`,_jsxs(_components.li,{children:[`C2B validation: `,_jsx(_components.code,{children:`https://\u003cyour-subdomain>.elimuboraerp.com/api/mpesa/c2b/validation`})]}),`\n`,_jsxs(_components.li,{children:[`C2B confirmation: `,_jsx(_components.code,{children:`https://\u003cyour-subdomain>.elimuboraerp.com/api/mpesa/c2b/confirmation`})]}),`\n`,_jsxs(_components.li,{children:[`B2C result: `,_jsx(_components.code,{children:`https://\u003cyour-subdomain>.elimuboraerp.com/api/mpesa/b2c/result`})]}),`\n`]}),_jsxs(_components.p,{children:[`Other Daraja callbacks (timeouts, status results, reversals, balance queries) use the matching paths under `,_jsx(_components.code,{children:`/api/mpesa/`}),`.`]})]}),_jsx(Step,{title:`Test with a small STK push`,children:_jsx(_components.p,{children:`Run a small test STK push against a real invoice to confirm the callback round-trips before going live.`})})]}),`\n`,_jsx(Heading,{level:`2`,id:`statuses-and-lifecycle`,children:`Statuses and lifecycle`}),`\n`,_jsx(_components.p,{children:`Finance carries three lifecycle status lists. Each table lists every status, every transition is labelled with the actor or trigger that moves the record, and reversibility is stated.`}),`\n`,_jsx(Heading,{level:`3`,id:`invoice-statuses`,children:`Invoice statuses`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Status`}),_jsx(_components.th,{children:`What it means`}),_jsx(_components.th,{children:`Who can act`}),_jsx(_components.th,{children:`What they can do`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Pending`}),_jsx(_components.td,{children:`New invoice with no cleared payments yet.`}),_jsx(_components.td,{children:`Bursar, school leadership`}),_jsx(_components.td,{children:`Record a payment.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Partial`}),_jsx(_components.td,{children:`Some payment has cleared. Balance is still positive.`}),_jsx(_components.td,{children:`Bursar, school leadership`}),_jsx(_components.td,{children:`Record additional payments.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Paid`}),_jsx(_components.td,{children:`The full amount has cleared. Balance is zero.`}),_jsx(_components.td,{children:`Bursar, school leadership`}),_jsx(_components.td,{children:`View the receipt history. The invoice is settled.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Overdue`}),_jsx(_components.td,{children:`The due date has passed and the balance is positive. Set by the daily overdue scan at 08:00, which also sends an overdue notification.`}),_jsx(_components.td,{children:`Bursar, school leadership`}),_jsx(_components.td,{children:`Record a payment (returns to Partial or Paid).`})]})]})]}),`\n`,_jsx(Mermaid,{chart:`stateDiagram-v2\n [*] --> Pending: invoice created\n Pending --> Partial: payment recorded, balance > 0\n Pending --> Paid: full payment recorded\n Pending --> Overdue: due date passes with no payment\n Partial --> Paid: balance reaches 0\n Partial --> Overdue: due date passes with balance > 0\n Overdue --> Partial: payment recorded, balance > 0\n Overdue --> Paid: full payment recorded\n Paid --> [*]`}),`\n`,_jsxs(_components.p,{children:[`A cheque bounce on a previously-cleared cheque payment can reduce the `,_jsx(_components.strong,{children:`Total paid`}),` and return a Paid invoice to Partial; in addition, a penalty line is added to the invoice for the bounce, which increases the `,_jsx(_components.strong,{children:`Amount`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`payment-statuses`,children:`Payment statuses`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Status`}),_jsx(_components.th,{children:`What it means`}),_jsx(_components.th,{children:`Who can act`}),_jsx(_components.th,{children:`What they can do`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Pending`}),_jsx(_components.td,{children:`Recorded but not yet usable. Typically a cheque awaiting clearance.`}),_jsx(_components.td,{children:`Bursar`}),_jsx(_components.td,{children:`Acknowledge the cheque once funds arrive, or mark bounced if the cheque bounces.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Cleared`}),_jsxs(_components.td,{children:[`Funds confirmed. The payment counts toward the invoice’s `,_jsx(_components.strong,{children:`Total paid`}),`.`]}),_jsx(_components.td,{children:`(none)`}),_jsx(_components.td,{children:`View the audit trail and the receipt.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bounced`}),_jsxs(_components.td,{children:[`A cheque bounced. The credit is reversed and a penalty line is added to the invoice for the configured penalty amount. A `,_jsx(_components.strong,{children:`Cheque bounced`}),` notification is sent to the relevant guardians.`]}),_jsx(_components.td,{children:`(none)`}),_jsx(_components.td,{children:`View the bounce reason on the payment; record a replacement payment when the funds arrive again.`})]})]})]}),`\n`,_jsx(Mermaid,{chart:`stateDiagram-v2\n [*] --> Pending: cheque recorded\n [*] --> Cleared: M-Pesa, cash, or bank transfer\n Pending --> Cleared: cheque cleared\n Pending --> Bounced: cheque bounced\n Cleared --> [*]\n Bounced --> [*]`}),`\n`,_jsx(_components.p,{children:`Cleared and Bounced are terminal for the payment itself. To reverse a Cleared payment, mark the underlying cheque bounced (for cheque payments) or record a compensating earmark refund elsewhere; the original payment record is not edited or deleted.`}),`\n`,_jsx(Heading,{level:`3`,id:`earmark-statuses`,children:`Earmark statuses`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Status`}),_jsx(_components.th,{children:`What it means`}),_jsx(_components.th,{children:`Who can act`}),_jsx(_components.th,{children:`What they can do`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Pending clearance`}),_jsx(_components.td,{children:`Earmark was funded by a cheque that has not yet cleared. Not drainable.`}),_jsx(_components.td,{children:`Bursar`}),_jsx(_components.td,{children:`Mark cheque cleared (status becomes Active) or mark bounced.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Active`}),_jsx(_components.td,{children:`Funded and available to drain against the target billable.`}),_jsx(_components.td,{children:`Bursar`}),_jsx(_components.td,{children:`Refund. Drain is automatic when a matching invoice payment is recorded.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Depleted`}),_jsx(_components.td,{children:`The earmark has been fully drained by invoice payments.`}),_jsx(_components.td,{children:`(none)`}),_jsx(_components.td,{children:`View the audit trail.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Refunded`}),_jsx(_components.td,{children:`The remaining balance was refunded, either externally or back to the wallet.`}),_jsx(_components.td,{children:`(none)`}),_jsx(_components.td,{children:`View the audit trail.`})]})]})]}),`\n`,_jsx(Mermaid,{chart:`stateDiagram-v2\n [*] --> PendingClearance: funded by cheque\n [*] --> Active: funded by cash, M-Pesa, or bank transfer\n PendingClearance --> Active: cheque cleared\n PendingClearance --> [*]: cheque bounced (earmark voided)\n Active --> Depleted: fully drained by invoice payments\n Active --> Refunded: bursar refunds\n Depleted --> [*]\n Refunded --> [*]`}),`\n`,_jsx(_components.p,{children:`A bounced funding cheque voids the earmark and reverses the funding entry; the earmark does not transition to Refunded in that case.`}),`\n`,_jsx(Heading,{level:`3`,id:`categorical-values-used-on-forms`,children:`Categorical values used on forms`}),`\n`,_jsx(_components.p,{children:`These are not lifecycles. They appear on form pickers when recording or reading finance records.`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Payment method`}),`: M-Pesa, Cash, Bank Transfer, Cheque, plus Earmark and Wallet refund which the system sets for you.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Pricing model`}),`: Flat, Variants, or Per unit (on a billable).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Refund destination`}),`: External payout (pay the guardian outside the system) or Credit to wallet (return the value to the student’s wallet).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Sponsor type`}),`: Government, NGO, Individual, or Corporate.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Discount type`}),`: Percentage (reduce by N% of the line subtotal) or Amount (reduce by a fixed currency amount).`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Earmark transaction type`}),`: Funding (initial deposit), Drain (consumed by an invoice payment), Refund (paid out externally), Refund to wallet (returned to the wallet), Bounce (cheque-funded earmark voided).`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`how-records-relate`,children:`How records relate`}),`\n`,_jsx(_components.p,{children:`A few relationships are worth keeping in mind:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`An invoice is made of one or more lines, and is paid by one or more payments. Each payment is split (allocated) across the invoice’s unpaid lines. The allocation is automatic and proportional by default; a bursar can override it line by line.`}),`\n`,_jsx(_components.li,{children:`A discount is held on a guardian and scoped to a single billable. When an invoice line for one of that guardian’s children charges the same billable, the system snapshots the discount amount onto the line; the value lives on the invoice line afterwards, independent of any later changes to the discount record.`}),`\n`,_jsx(_components.li,{children:`Each student has a single wallet. The wallet keeps a running ledger of every credit and debit. Wallets are spent outside the invoicing flow (canteen and similar).`}),`\n`,_jsx(_components.li,{children:`An earmark belongs to a student and is funded against a specific billable. It is independent of the wallet (refunding an earmark to the wallet is the only path where the two balances meet).`}),`\n`,_jsx(_components.li,{children:`An M-Pesa flow targets exactly one of an invoice, a wallet, or an earmark. The action a bursar takes in the panel, or the invoice ID the guardian uses as the Paybill account reference, tells the system where the cleared payment should land.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`reports-and-analytics`,children:`Reports and analytics`}),`\n`,_jsx(_components.p,{children:`Reports come in two shapes: downloads (PDF or Excel, generated when you click the action), and emailed receipts (sent automatically when a payment clears).`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Report`}),_jsx(_components.th,{children:`Where`}),_jsx(_components.th,{children:`Filters`}),_jsx(_components.th,{children:`Output`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Invoice detail`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Download invoice`}),` header action on a single invoice`]}),_jsx(_components.td,{children:`None (single invoice)`}),_jsx(_components.td,{children:`Portrait PDF with lines, payments, and balance`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Fee Collection Summary`}),_jsxs(_components.td,{children:[`Header action on the `,_jsx(_components.strong,{children:`Invoices`}),` list`]}),_jsx(_components.td,{children:`Date range, optional grade level, optional billable`}),_jsx(_components.td,{children:`Landscape PDF or Excel showing invoiced, paid, and outstanding totals`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Outstanding Balances`}),_jsxs(_components.td,{children:[`Header action on the `,_jsx(_components.strong,{children:`Invoices`}),` list`]}),_jsx(_components.td,{children:`Optional “overdue only” toggle`}),_jsx(_components.td,{children:`PDF or Excel listing every unpaid or partial invoice`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Line Statement`}),_jsxs(_components.td,{children:[`Per-row action on the `,_jsx(_components.strong,{children:`Lines`}),` tab of an invoice (visible when the line has any payment)`]}),_jsx(_components.td,{children:`None (single line)`}),_jsx(_components.td,{children:`Portrait PDF showing one invoice line with its payment allocations`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Payment Receipt`}),_jsxs(_components.td,{children:[`Per-row action on the `,_jsx(_components.strong,{children:`Payments`}),` tab of an invoice`]}),_jsx(_components.td,{children:`None (single payment)`}),_jsx(_components.td,{children:`Portrait PDF receipt (same template as the emailed receipt)`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Wallet Balances Report`}),_jsxs(_components.td,{children:[`Header action on the `,_jsx(_components.strong,{children:`Wallets`}),` list`]}),_jsx(_components.td,{children:`Optional grade level, stream, maximum-balance threshold`}),_jsx(_components.td,{children:`PDF or Excel listing every wallet balance`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Wallet Statement`}),_jsx(_components.td,{children:`Header action on a single wallet`}),_jsx(_components.td,{children:`None (single wallet)`}),_jsx(_components.td,{children:`Portrait PDF showing every credit and debit on the wallet`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Emailed receipt`}),_jsx(_components.td,{children:`Sent automatically when a payment clears`}),_jsx(_components.td,{children:`None`}),_jsx(_components.td,{children:`PDF receipt emailed to the invoice owner`})]})]})]}),`\n`,_jsx(_components.p,{children:`Every download inherits the same permission as its parent page, so a user who can see the invoice can pull the report.`}),`\n`,_jsx(Heading,{level:`2`,id:`what-guardians-see`,children:`What guardians see`}),`\n`,_jsxs(_components.p,{children:[`Guardians log in to the tenant panel under the locked `,_jsx(_components.strong,{children:`Guardian`}),` role and have `,_jsx(_components.strong,{children:`read-only`}),`, child-scoped access. They can read:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Their children’s invoices and the line breakdown.`}),`\n`,_jsx(_components.li,{children:`Payment history on each invoice, with the method and status.`}),`\n`,_jsx(_components.li,{children:`Each child’s wallet balance and the wallet transaction ledger.`}),`\n`,_jsx(_components.li,{children:`Each child’s earmarks and the earmark transaction ledger.`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`The Guardian role explicitly `,_jsx(_components.strong,{children:`cannot`}),`:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Record a payment (the `,_jsx(_components.strong,{children:`Record Invoice Payment`}),` action is hidden).`]}),`\n`,_jsxs(_components.li,{children:[`Credit or debit a wallet from the panel (the `,_jsx(_components.strong,{children:`Credit Wallet`}),` and `,_jsx(_components.strong,{children:`Debit Wallet`}),` actions are hidden).`]}),`\n`,_jsxs(_components.li,{children:[`Lock funds with an earmark from the panel (the `,_jsx(_components.strong,{children:`Prepay Billable`}),` action is hidden).`]}),`\n`,_jsx(_components.li,{children:`Refund an earmark.`}),`\n`,_jsx(_components.li,{children:`See or manage M-Pesa payment integration credentials.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`Notifications still reach guardians regardless of whether they log in. Invoice creation, overdue reminders, wallet funded, wallet debited, wallet low balance, cheque bounced, and earmark cheque bounced messages are sent to the guardian’s stored contacts. M-Pesa STK push prompts are initiated by the school; the guardian sees them on their phone the same way they would for any other Daraja STK push.`}),`\n`,_jsx(Heading,{level:`2`,id:`faqs-and-troubleshooting`,children:`FAQs and troubleshooting`}),`\n`,_jsxs(AccordionGroup,{children:[_jsx(Accordion,{title:`How do I apply a partial scholarship?`,id:`how-do-i-apply-a-partial-scholarship`,children:_jsxs(_components.p,{children:[`Hold a `,_jsx(_components.strong,{children:`discount`}),` on the guardian if the reduction is a known amount or percentage off a specific billable: open the guardian, switch to the `,_jsx(_components.strong,{children:`Discounts`}),` tab, and add a discount scoped to that billable (see `,_jsx(_components.a,{href:`#hold-a-discount-for-a-guardian`,children:`Hold a discount for a guardian`}),`). The next invoice line raised for one of the guardian’s children that charges the same billable will pick up the discount automatically. Use a `,_jsx(_components.strong,{children:`Sponsor`}),` if a third party is paying part of the balance: add the sponsor record under `,_jsx(_components.strong,{children:`Sponsors`}),`, then when you record the payment from the sponsor, pick the sponsor on the payment form so the reconciliation report can group the payment under that sponsor.`]})}),_jsx(Accordion,{title:`What happens when a guardian overpays?`,id:`what-happens-when-a-guardian-overpays`,children:_jsxs(_components.p,{children:[`The cleared payment applies in full to the invoice and the invoice moves to `,_jsx(_components.strong,{children:`Paid`}),`. To put the surplus to use, create an `,_jsx(_components.strong,{children:`earmark`}),` for the student against the relevant billable for the surplus amount; the earmark will drain automatically the next time you record a payment on an invoice line that charges the same billable.`]})}),_jsx(Accordion,{title:`Can invoices be refunded?`,id:`can-invoices-be-refunded`,children:_jsxs(_components.p,{children:[`No, invoice payments are not refundable inside Elimu Bora. Refunds exist only on `,_jsx(_components.strong,{children:`earmarks`}),`: when an active earmark still has a positive balance, the bursar can refund what remains, either as an external payout (the bursar pays the guardian outside the system) or as a credit back to the student’s wallet. If a guardian is owed money for a paid invoice, handle the payout outside the system; the invoice itself stays Paid.`]})}),_jsx(Accordion,{title:`Why did an M-Pesa Paybill payment not apply to the right invoice?`,id:`why-did-an-m-pesa-paybill-payment-not-apply-to-the-right-invoice`,children:_jsxs(_components.p,{children:[`Paybill (C2B) deposits are matched using the `,_jsx(_components.strong,{children:`account reference`}),` the guardian typed in their M-Pesa menu, which must be the `,_jsx(_components.strong,{children:`invoice ID`}),` shown on the invoice. If the guardian typed something else (an admission number, a name, a wrong digit), the deposit will land in the school’s M-Pesa account but the system will not match it to any invoice. Confirm with the guardian which reference they used. The system does not expose a manual match action; if the wrong reference was used, treat the deposit as an out-of-band payment and record a fresh payment against the correct invoice.`]})}),_jsx(Accordion,{title:`What happens when a cheque bounces?`,id:`what-happens-when-a-cheque-bounces`,children:_jsxs(_components.p,{children:[`For an invoice payment, mark the payment `,_jsx(_components.strong,{children:`Bounced`}),` from the Payments tab. The bursar is prompted for a bounce reason and a penalty amount; on confirm, a new `,_jsx(_components.strong,{children:`Bounced cheque penalty`}),` line is added to the same invoice for the penalty amount, the cheque payment status becomes `,_jsx(_components.strong,{children:`Bounced`}),`, and a `,_jsx(_components.strong,{children:`Cheque bounced`}),` notification is sent to the relevant guardians. For an earmark funded by cheque, the earmark is voided: the funding entry on its ledger is reversed, the bursar can record an optional penalty amount that raises a separate penalty invoice for the student, and an `,_jsx(_components.strong,{children:`Earmark cheque bounced`}),` notification is sent. For a wallet top-up by cheque, the wallet credit is reversed, and a penalty invoice is raised if the bursar entered a penalty amount greater than zero. In every case, ask the guardian to send a replacement payment for the original amount.`]})}),_jsx(Accordion,{title:`Can a guardian pay an invoice directly from their login?`,id:`can-a-guardian-pay-an-invoice-directly-from-their-login`,children:_jsxs(_components.p,{children:[`No. Guardians have read-only access to invoices, payments, wallets, and earmarks. The `,_jsx(_components.strong,{children:`Record Invoice Payment`}),`, `,_jsx(_components.strong,{children:`Credit Wallet`}),`, `,_jsx(_components.strong,{children:`Debit Wallet`}),`, and `,_jsx(_components.strong,{children:`Prepay Billable`}),` actions are hidden from the Guardian role. M-Pesa STK push prompts are initiated by the school side; the guardian then authorises the prompt on their phone. Guardians can still push payments to the school’s Paybill from their own M-Pesa menu and use the invoice ID as the account reference; those payments reconcile automatically through C2B.`]})}),_jsx(Accordion,{title:`Why can I not edit or delete an invoice?`,id:`why-can-i-not-edit-or-delete-an-invoice`,children:_jsx(_components.p,{children:`Invoices are part of the school’s financial ledger and stay immutable once created. Lines, amounts, and statuses change only through valid actions (recording payments, marking cheques cleared or bounced, the daily overdue scan), never through manual edits. If a charge was wrong on an issued invoice, raise a new invoice for the correction or wait for the payment flow to reconcile.`})}),_jsx(Accordion,{title:`Where do M-Pesa callbacks go if Finance is disabled?`,id:`where-do-m-pesa-callbacks-go-if-finance-is-disabled`,children:_jsx(_components.p,{children:`They are still received and logged. Inbound Safaricom callbacks are intentionally not gated by the module so that late callbacks for payments started before the module was disabled can still be matched. With Finance disabled, however, no new payment intents are being created, so most inbound callbacks find nothing to resolve and become no-ops.`})})]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Finance \u0026 Fee Management","description":"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.","icon":"wallet","href":"/modules/finance"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Records you’ll work with","slug":"records-you’ll-work-with","depth":2,"children":[]},{"title":"What you can do","slug":"what-you-can-do","depth":2,"children":[]},{"title":"Set up fees","slug":"set-up-fees","depth":2,"children":[{"title":"Create a billable","slug":"create-a-billable","depth":3,"children":[]},{"title":"Add a billable variant","slug":"add-a-billable-variant","depth":3,"children":[]},{"title":"Set a per-stage amount","slug":"set-a-per-stage-amount","depth":3,"children":[]},{"title":"Hold a discount for a guardian","slug":"hold-a-discount-for-a-guardian","depth":3,"children":[]}]},{"title":"Issue invoices","slug":"issue-invoices","depth":2,"children":[{"title":"Create an invoice","slug":"create-an-invoice","depth":3,"children":[]},{"title":"Read an invoice’s balance and history","slug":"read-an-invoice’s-balance-and-history","depth":3,"children":[]}]},{"title":"Record payments","slug":"record-payments","depth":2,"children":[{"title":"Record a cash or bank transfer payment","slug":"record-a-cash-or-bank-transfer-payment","depth":3,"children":[]},{"title":"Record a cheque payment","slug":"record-a-cheque-payment","depth":3,"children":[]},{"title":"Acknowledge a cheque","slug":"acknowledge-a-cheque","depth":3,"children":[]},{"title":"Mark a cheque bounced","slug":"mark-a-cheque-bounced","depth":3,"children":[]},{"title":"Trigger an M-Pesa STK push","slug":"trigger-an-m-pesa-stk-push","depth":3,"children":[]},{"title":"Reconcile an M-Pesa Paybill (C2B) payment","slug":"reconcile-an-m-pesa-paybill-c2b-payment","depth":3,"children":[]}]},{"title":"Run wallets","slug":"run-wallets","depth":2,"children":[{"title":"Credit a wallet (top up)","slug":"credit-a-wallet-top-up","depth":3,"children":[]},{"title":"Debit a wallet (record spending)","slug":"debit-a-wallet-record-spending","depth":3,"children":[]},{"title":"Acknowledge a cheque on a wallet","slug":"acknowledge-a-cheque-on-a-wallet","depth":3,"children":[]},{"title":"Read the wallet ledger","slug":"read-the-wallet-ledger","depth":3,"children":[]},{"title":"Wallet low-balance notification","slug":"wallet-low-balance-notification","depth":3,"children":[]}]},{"title":"Manage earmarks","slug":"manage-earmarks","depth":2,"children":[{"title":"Lock funds with an earmark (Prepay)","slug":"lock-funds-with-an-earmark-prepay","depth":3,"children":[]},{"title":"Drain an earmark against an invoice payment","slug":"drain-an-earmark-against-an-invoice-payment","depth":3,"children":[]},{"title":"Refund an earmark","slug":"refund-an-earmark","depth":3,"children":[]},{"title":"Read the earmark ledger","slug":"read-the-earmark-ledger","depth":3,"children":[]}]},{"title":"Attach sponsors","slug":"attach-sponsors","depth":2,"children":[{"title":"Add a sponsor record","slug":"add-a-sponsor-record","depth":3,"children":[]},{"title":"Attach a sponsor to a payment","slug":"attach-a-sponsor-to-a-payment","depth":3,"children":[]}]},{"title":"Configure M-Pesa","slug":"configure-m-pesa","depth":2,"children":[]},{"title":"Statuses and lifecycle","slug":"statuses-and-lifecycle","depth":2,"children":[{"title":"Invoice statuses","slug":"invoice-statuses","depth":3,"children":[]},{"title":"Payment statuses","slug":"payment-statuses","depth":3,"children":[]},{"title":"Earmark statuses","slug":"earmark-statuses","depth":3,"children":[]},{"title":"Categorical values used on forms","slug":"categorical-values-used-on-forms","depth":3,"children":[]}]},{"title":"How records relate","slug":"how-records-relate","depth":2,"children":[]},{"title":"Reports and analytics","slug":"reports-and-analytics","depth":2,"children":[]},{"title":"What guardians see","slug":"what-guardians-see","depth":2,"children":[]},{"title":"FAQs and troubleshooting","slug":"faqs-and-troubleshooting","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"elimuborasolutionsco","siteName":"Elimu Bora ERP Help Center","title":"Finance \u0026 Fee Management - Elimu Bora ERP Help Center","contextualStarterQuestions":[{"_id":"6a0f4a9634ad5fc914a34b34","deploymentId":"69ff495a3eaa1efe3f179aac","questionText":"What is a billable variant?","status":"active","generatedBy":"contextual","path":"modules/finance","createdAt":"2026-05-21T18:10:30.473Z","updatedAt":"2026-05-21T18:10:30.473Z","__v":0},{"_id":"6a0f4a9634ad5fc914a34b33","deploymentId":"69ff495a3eaa1efe3f179aac","questionText":"Can guardians pay fees online?","status":"active","generatedBy":"contextual","path":"modules/finance","createdAt":"2026-05-21T18:10:30.473Z","updatedAt":"2026-05-21T18:10:30.473Z","__v":0},{"_id":"6a0f4a9634ad5fc914a34b32","deploymentId":"69ff495a3eaa1efe3f179aac","questionText":"How do I set up fee items?","status":"active","generatedBy":"contextual","path":"modules/finance","createdAt":"2026-05-21T18:10:30.473Z","updatedAt":"2026-05-21T18:10:30.473Z","__v":0}],"navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-05-21T18:10:21.060Z","originalFileLocation":"modules/finance.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Elimu Bora ERP Help Center\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/svg+xml\" sizes=\"180x180\" href=\"https://media.brand.dev/28107f06-65a0-45ce-9937-4bc6a00d197b.svg\">\u003clink data-mint-head rel=\"icon\" type=\"image/svg+xml\" sizes=\"32x32\" href=\"https://media.brand.dev/28107f06-65a0-45ce-9937-4bc6a00d197b.svg\">\u003clink data-mint-head rel=\"icon\" type=\"image/svg+xml\" sizes=\"16x16\" href=\"https://media.brand.dev/28107f06-65a0-45ce-9937-4bc6a00d197b.svg\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/svg+xml\" href=\"https://media.brand.dev/28107f06-65a0-45ce-9937-4bc6a00d197b.svg\">\u003cmeta data-mint-head property=\"og:title\" content=\"Finance \u0026amp; Fee Management - Elimu Bora ERP Help Center\">\u003cmeta data-mint-head property=\"og:description\" content=\"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Elimu Bora ERP Help Center\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://help.elimuboraerp.com/modules/finance\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://elimuborasolutionsco.mintlify.app/_mintlify/api/og/v2?division=Modules\u0026amp;title=Finance+%26+Fee+Management\u0026amp;description=Charge+fees%2C+issue+invoices%2C+accept+M-Pesa%2C+run+student+wallets+and+earmarks%2C+and+reconcile+payments.\u0026amp;theme=bc6e4384b58753bfe2bf836e\u0026amp;signature=ff360435cff3579d72bcdfc86192cb2ea0cb457f15ebb805ebee0c9384768f9f\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Finance \u0026amp; Fee Management - Elimu Bora ERP Help Center\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://elimuborasolutionsco.mintlify.app/_mintlify/api/og/v2?division=Modules\u0026amp;title=Finance+%26+Fee+Management\u0026amp;description=Charge+fees%2C+issue+invoices%2C+accept+M-Pesa%2C+run+student+wallets+and+earmarks%2C+and+reconcile+payments.\u0026amp;theme=bc6e4384b58753bfe2bf836e\u0026amp;signature=ff360435cff3579d72bcdfc86192cb2ea0cb457f15ebb805ebee0c9384768f9f\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"https://mintlify.s3.us-west-1.amazonaws.com/elimuborasolutionsco/_generated/favicon/browserconfig.xml?v=3\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Elimu Bora ERP Help Center\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#800000\">\u003clink data-mint-head rel=\"canonical\" href=\"https://help.elimuboraerp.com/modules/finance\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/modules/finance.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://help.elimuboraerp.com/#organization\",\"name\":\"Elimu Bora ERP Help Center\",\"url\":\"https://help.elimuboraerp.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/elimuborasolutionsco/_rAr-ZsKVDWTZrZ6/images/elimubora-logo-primary.png?fit=max\u0026auto=format\u0026n=_rAr-ZsKVDWTZrZ6\u0026q=85\u0026s=4ed2d6d18eb543c27f5cb0bbe0b1ac02\"}},{\"@type\":\"WebSite\",\"@id\":\"https://help.elimuboraerp.com#website\",\"name\":\"Elimu Bora ERP Help Center\",\"url\":\"https://help.elimuboraerp.com\",\"publisher\":{\"@id\":\"https://help.elimuboraerp.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://help.elimuboraerp.com/modules/finance#webpage\",\"url\":\"https://help.elimuboraerp.com/modules/finance\",\"name\":\"Finance \u0026 Fee Management\",\"description\":\"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\",\"dateModified\":\"2026-05-21T18:10:21.060Z\",\"isPartOf\":{\"@id\":\"https://help.elimuboraerp.com#website\"},\"breadcrumb\":{\"@id\":\"https://help.elimuboraerp.com/modules/finance#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://help.elimuboraerp.com/modules/finance#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Modules\",\"item\":\"https://help.elimuboraerp.com/modules/users\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Finance \u0026 Fee Management\",\"item\":\"https://help.elimuboraerp.com/modules/finance\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://help.elimuboraerp.com/modules/finance#article\",\"headline\":\"Finance \u0026 Fee Management\",\"name\":\"Finance \u0026 Fee Management\",\"description\":\"Charge fees, issue invoices, accept M-Pesa, run student wallets and earmarks, and reconcile payments.\",\"url\":\"https://help.elimuboraerp.com/modules/finance\",\"mainEntityOfPage\":{\"@id\":\"https://help.elimuboraerp.com/modules/finance#webpage\"},\"dateModified\":\"2026-05-21T18:10:21.060Z\",\"publisher\":{\"@id\":\"https://help.elimuboraerp.com/#organization\"},\"isPartOf\":{\"@id\":\"https://help.elimuboraerp.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Elimu Bora ERP Help Center\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Elimu Bora ERP Help Center","nav":{"global":{"anchors":[{"anchor":"Pricing","icon":"tag","href":"https://elimuboraerp.com/pricing/"},{"anchor":"Book a Demo","icon":"calendar-check","href":"https://elimuboraerp.com/contact/"},{"anchor":"Blog \u0026 Resources","icon":"newspaper","href":"https://elimuboraerp.com/blog/"},{"anchor":"Contact Us","icon":"mail","href":"https://elimuboraerp.com/contact/"}]},"tabs":[{"tab":"Documentation","groups":[{"group":"Get Started","pages":[{"title":"Introduction","icon":"house","href":"/introduction"},{"title":"Quickstart","icon":"rocket","href":"/quickstart"},{"title":"Roles \u0026 permissions","icon":"shield-user","href":"/roles-permissions"},{"title":"For staff","icon":"users","href":"/staff/index"},{"title":"For guardians","icon":"user","href":"/guardians/index"}]},{"group":"Modules","pages":[{"title":"Users \u0026 Identity","icon":"users","href":"/modules/users"},{"title":"Curriculum","icon":"book-open","href":"/modules/curriculum"},{"title":"Academic Years \u0026 Terms","icon":"calendar","href":"/modules/academic-years"},{"title":"Attendance","icon":"clipboard-list","href":"/modules/attendance"},{"title":"Assessments \u0026 Report Cards","icon":"graduation-cap","href":"/modules/assessments"},{"title":"Timetable \u0026 Lessons","icon":"calendar-clock","href":"/modules/timetable"},{"title":"Events","description":"Plan school events, invite attendees, and send reminders.","icon":"calendar-check","href":"/modules/events"},{"title":"Finance \u0026 Fee Management","icon":"wallet","href":"/modules/finance"},{"title":"Inventory \u0026 Procurement","description":"Manage products, suppliers, purchases, stock movements, and requisitions.","icon":"package","href":"/modules/inventory"},{"title":"Sports \u0026 Games","icon":"trophy","href":"/modules/sports"},{"title":"Clubs \u0026 Societies","icon":"users-round","href":"/modules/clubs"},{"title":"Activity Log","icon":"history","href":"/modules/activity-log"}]},{"group":"More","pages":[{"title":"Settings","icon":"settings","href":"/settings/index"}]}]}]},"title":"Finance \u0026 Fee Management - Elimu Bora ERP Help Center","buildId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","deploymentId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","dynamics":[],"chunks":[]}