Getting started
Fees troubleshooting
Why bulk generate produces nothing, why a receipt email never arrives, why a waiver will not approve, and why autopay and dunning stay silent.
Getting started guide for day and boarding schools.
Last updated August 29, 2026
Fee tickets divide cleanly into three kinds: nothing was generated, money moved but the paperwork did not follow, or an automated reminder never fired. The first is almost always a fee structure that does not match the class. The second is almost always the email address on the record. The third is almost always the daily cron job, which is not installed on this school and which nothing inside the application replaces.
Telling a permission problem from a configuration problem
The two look identical from the desk and are diagnosed differently. A permission problem produces a 403 and the same result for the same person on every student: the fee screens require one of Platform Admin, Principal, Vice Principal, Support Staff - Finance, or the office Admin role, and no amount of data fixing changes that. A configuration problem produces an empty list, a zero count, or a specific message naming a grade, a year, or a fee structure, and it follows the record rather than the person - a colleague with a different role sees exactly the same emptiness. Ask one question first: does a Principal see it too? If yes, it is configuration.
Setup and generation
| Symptom | Cause | Fix |
|---|---|---|
| Bulk generate loads no students | No class selected, or the class has no ACTIVE members for the year | Pick a class or All classes and press Load preview first - the run button does nothing until a roster is loaded. Place students in the section at /classes. |
| Preview lists students but nothing is created | No fee structure matches the class | Structures at /fees/fee-structures must be active, belong to the selected academic year, and target that class; a grade-level structure only applies to students with no active enrolment. |
| Generation fails for the whole school with a 409 | More than one academic year is marked current | Fix the year at /academic-year. The generator refuses to guess when the current-year invariant is broken. |
| Amounts changed on the structure but not on the bills | Instances are written once | Existing lines are keyed on fee structure and instalment number and are never rewritten by a later run. Waive or adjust the old lines at /fees/waivers. |
| Instalments fall on the wrong dates | Dates are derived, not entered per instalment | Each instalment is the structure amount divided by the instalment count, dated from the structure due date and spaced by twelve divided by the instalment count in months. |
| Transport charge missing from a bill | Stop fee or the TRN fee type | Assign the stop at /transport/assignments with a monthly fee above zero, and create a fee type with the code TRN first - the sync looks it up and stops silently if it is absent. |
| GST not shown on the receipt | Tax configuration off | Configure rates at /fees/settings/gst, or /fees/settings/vat for schools billing VAT. |
Collection, receipts, and online pay
| Symptom | Cause | Fix |
|---|---|---|
| No Pay button for the family | Online payment is disabled | FEES_ONLINE_PAYMENT_MODE accepts simulated, razorpay, stripe, telr, or disabled, and defaults to disabled when nothing is set. Configure it at /fees/settings/payment-gateway. |
| Receipt email marked FAILED | SMTP is unreachable or unconfigured | Confirm delivery at /settings/email-test, then resend with POST /api/fees/receipts/{receiptNumber}/email or the resend action on /fees/payments and /fees/receipts. |
| Receipt email marked NO_EMAIL | Neither the student nor an active guardian record has an address | Add an email to the guardian at /parents. The lookup takes the primary active guardian when the student has none. |
| A waiver was approved but the balance is unchanged | The waiver was not attached to a fee instance | Only a waiver carrying a feeInstanceId is applied to a bill on approval. A standalone waiver record is bookkeeping. |
| Cannot decide a pending waiver or refund | Self-approval block, or the high-value rule | The approver cannot be the requester. Amounts at or above 10,000, or 25 per cent of the instance, need Principal or Vice Principal rather than Platform Admin. |
Reminders that never arrive
Autopay, the dunning ladder, and scheduled notices all run from scripts/run-school-cron.sh, which has to be added to crontab with FEES_CRON_SECRET set. That job is not installed here, so none of them has ever advanced. Even once it is installed, be careful about what each channel means. Dunning moves an overdue instance one ladder step per run and sends according to that step: in-app writes a notification to the student account, email uses SMTP, SMS calls a bundled provider that prints the message to the server log and returns success, and WhatsApp writes a further in-app notification containing a wa.me link for a member of staff to open by hand. A run reporting smsSent has logged, not sent.
Common questions
Quick answers in plain language.
Bulk generate reports zero fee instances created. What is actually missing?+
Generation matches fee structures to the class the student is actively enrolled in. If the student has an ACTIVE ClassStudent row, only structures whose classId equals that class are used; there is no fall-back to grade in that case. If the student has no active enrolment, the matcher falls back to structures with a null classId for the same grade. A structure that is inactive or attached to a different academic year is invisible either way, and the response says "No matching fee structures found" with the grade and year it looked for.
Why can a Platform Admin not approve a large fee waiver?+
High-value adjustments are restricted to Principal and Vice Principal specifically. An adjustment counts as high value when the absolute amount reaches FEE_HIGH_VALUE_ADJUSTMENT_INR, which defaults to 10,000, or when it is 25 per cent or more of the instance. Below that line Platform Admin, Principal, and Vice Principal can all approve. Nobody may approve their own request, whatever the role.
Does fee autopay actually charge the parent?+
No. POST /api/fees/autopay/run-due walks active mandates and creates in-app reminder notifications that link to /fees/me. It records lastRunAt and sets nextRunAt to the same day next month, capped at the 28th. No money moves and no gateway is called, so a mandate is a reminder schedule rather than a standing instruction.
A payment was recorded but the family never got the receipt. Where did it go?+
The receipt email goes to the student record email first and only falls back to the primary active guardian email when the student has none. Students created by admissions enrolment without an email on the application are given a synthetic address ending in @students.local, so the send succeeds into nowhere. Clear the student email or check the payment row on /fees/payments, which carries a [RECEIPT_EMAIL:SENT], [RECEIPT_EMAIL:FAILED], or [RECEIPT_EMAIL:NO_EMAIL] marker in its notes.
Related searches
School leaders and IT teams often search for: how to module troubleshooting fees in school management software, best school software onboarding for K-12 schools, Schoolyi module troubleshooting fees guide, school ERP go live checklist, migrate from Excel to school ERP, and school software training guide.

