SCHOLARIS/i is a K-12 school business-office application: a family/payer master and student
master, grade-level tuition schedules, per-year fee items and financial-aid awards, a family accounts-receivable
(AR) ledger, installment payment plans and cash receipts, prepaid lunch/POS accounts that are never allowed to
go negative, and a balanced general-ledger (GL) feed. The book flows one way — enrollment → tuition
and fees net of aid → the family ledger → cash / payment plans / lunch accounts → the GL —
and every money movement is journaled to a durable audit trail. The application is deliberately minimal and
hand-derivable: every posted figure is stated as exact arithmetic in the tests. This manual is the reference for
the operator who runs the online screens and the three job cycles, and for the developer maintaining the
application. It is grounded entirely in the committed source (school-app/src/sources.mjs,
src/seed.mjs, the test/sc_*.mjs drivers, and school-app/FINDINGS.md).
Everything runs in library SCHOLARIS.
SCHOLARIS/i runs a school's business office across three cycles:
SCHOLARIS/i has a single financial invariant that ties the whole application together: the family's
running AR balance (SCFAM.FBAL) moves only two ways — up when a charge is posted
(term assessment, a plan installment, a late fee) and down when cash is applied. It is never edited
directly. Every posting program that raises or lowers FBAL also writes the matching ledger line
(SCLEDG) and a durable history row (SCHIST), so the book stays reconstructable and the
COBOL trial balance SCGLRPT can prove, at any time, that the sum of every open ledger item's
LOPEN reconciles to the sum of every family's FBAL (its BALDIFF is zero).
Two design choices keep the arithmetic honest and hand-derivable. First, tuition is charged as an exact one-third of the annual figure per term (the seeded annual tuitions — K5 6000.00, grade 03 7200.00, grade 08 8400.00 — divide cleanly into 2000.00 / 2400.00 / 2800.00, so three terms sum back to the annual figure with no rounding drift). Second, a financial-aid award is posted as a negative ledger line, so the ledger lines for a student sum directly to the net charge and the family balance rises by exactly that net.
ONLINE (5250) TERM DAILY MONTHLY
------------- ---- ----- -------
SCMENU SCTERM SCDAILY SCMONTH
1 -> SCSTUIQ SCASSESS SCLPOS (lunch) SCINST (plan installments)
2 -> SCLEDIQ (assess) SCCASH (cash) SCLATE (aging + late fees)
SCGLRPT SCLWARN (lunch low-bal sweep)
(trial bal) SCGLDST (GL distribution)
SCGLRPT (trial balance)
\ | | /
\ v v /
+----------------> SCFAM.FBAL (family AR balance: up on charge, down on cash) <-+
|
v
SCLEDG (open-item ledger) --+-- SCHIST (durable audit trail, disjoint key ranges)
SCLUNCH / SCLTXN (lunch) +-- SCGLDIST (SQL GL, balanced DR/CR pairs)
SCPLAN (payment plans) +-- SCRCPT (cash receipts)
A single event — say, one term charge — flows: SCASSESS reads the active enrollment
→ looks up the grade tuition schedule and the grade's fee links → caps any aid at the gross →
writes the tuition, fee and aid ledger lines into SCLEDG → raises SCFAM.FBAL by the
net → writes the SCHIST history rows the monthly GL post later sums.
| Object | Type | Role |
|---|---|---|
| SCFAM | PF | Family / payer master; FBAL is the AR spine. |
| SCSTU | PF | Student master (family, grade, status). |
| SCSTULF | LF | Students keyed by FAMNO (a family's roster). |
| SCGRADE | PF | Grade-level annual tuition schedule per school year. |
| SCENR | PF | Enrollment (student × school year → grade). |
| SCFEE | PF | Fee-item master (registration / activity / lab …). |
| SCGFEE | PF | Which fee items apply to which grade. |
| SCAID | PF | Financial-aid / scholarship awards. |
| SCLEDG | PF | Family AR open-item ledger. |
| SCLEDLF | LF | The ledger keyed by due date (oldest-due-first aging). |
| SCPLAN | PF | Installment payment plans. |
| SCRCPT | PF | Cash receipts against the ledger. |
| SCLUNCH | PF | Prepaid lunch/POS account (never negative). |
| SCLTXN | PF | Lunch POS transactions (charge / reload). |
| SCHIST | PF | Durable audit trail; disjoint key ranges per program. |
| SCGLDIST | SQL table | GL distribution (DR/CR pairs), + index SCGLDACC. |
| SCSTUD / SCLEDD / SCMENUD | DSPF | Student inquiry / ledger subfile / menu. |
| SCAGEP | PRTF | AR ageing / billing statement printer file. |
| SCREFLD | RPGLE | Reference-data seed loader. |
| SCASSESS | RPGLE | Term tuition + fee assessment. |
| SCCASH | RPGLE | Cash-receipt application. |
| SCLPOS | RPGLE | Lunch POS charge/reload run. |
| SCINST | RPGLE | Payment-plan installment due-posting. |
| SCLATE | RPGLE | AR aging + late-fee assessment. |
| SCLWARN | RPGLE | Lunch low-balance alert sweep (read-only). |
| SCGLDST | SQLRPGLE | GL distribution post (embedded SQL). |
| SCSTUIQ / SCLEDIQ / SCMENU | RPGLE | Inquiry / subfile inquiry / menu drivers. |
| SCGLRPT | CBLLE | COBOL AR trial balance. |
| SCSETUP | CLP | Object build/compile driver. |
| SCTERM / SCDAILY / SCMONTH | CLP | The three job-cycle drivers. |
The catalogue is 13 PFs + 2 LFs, 1 SQL table + 1 index, 3 DSPFs and 1 PRTF, driven by 11 RPGLE programs + 1 SQLRPGLE + 1 COBOL program, wired together by 4 CL programs. Sections D and F expand each.
SCHOLARIS/i has no CICS transaction identifiers and no transid switch. On IBM i each program is
reached by name from a 5250 command-entry line (or through the menu SCMENU for the two
inquiries, or a JOBQ/scheduler for the batch cycles). Before invoking anything, the job's library list must
include SCHOLARIS — the tested jobs run with LIBL = QSYS QGPL SCHOLARIS QTEMP and
CURLIB = SCHOLARIS.
| To do this | Type on the command line |
|---|---|
| Open the main menu (routes to the two inquiries) | CALL SCHOLARIS/SCMENU |
| Student / family inquiry directly | CALL SCHOLARIS/SCSTUIQ |
| Family ledger (subfile) inquiry directly | CALL SCHOLARIS/SCLEDIQ |
| Build/compile every object (first-time setup) | CALL SCHOLARIS/SCSETUP |
| Seed reference data (families, students, grades, fees, aid) | CALL SCHOLARIS/SCREFLD |
| Run the term assessment cycle | CALL SCHOLARIS/SCTERM (or SBMJOB it) |
| Run the daily lunch + cash cycle | CALL SCHOLARIS/SCDAILY |
| Run the monthly close cycle | CALL SCHOLARIS/SCMONTH |
The batch cycles take no CALL parameters. Unlike a control-row-driven design, each SCHOLARIS/i batch
program carries its processing dates as literals in the source (the term run posts for period 20260901 / due
20260915; the plan run dates 20261001; the aging run dates 20261025; the GL batch is 202610), so a scheduled
submission is a bare CALL. Only SCMENU, SCSTUIQ and SCLEDIQ
are interactive; the batch programs run to completion and DSPLY a one-line result per step.
Three interactive programs share the shipped DSPFs. The menu (SCMENU over SCMENUD)
simply routes: option 1 CALLs SCSTUIQ, option 2 CALLs SCLEDIQ, any other
non-blank option sets 'Invalid option.' and re-displays the menu; F3 ends
it. Both inquiries return to the menu on F3.
Key a student number and press Enter. SCSTUIQ CHAINs
SCSTU for the master, then SCFAM for the billing family (showing the derived
family AR balance), then SCLUNCH for that student's prepaid lunch balance. A miss clears the detail
and reports 'Student not found.'; a student with no lunch account leaves the lunch field blank
rather than showing a stale value.
Key a family number and press Enter. SCLEDIQ CHAINs SCFAM
for the header (family name + derived balance), then walks SCLEDG on the family key and loads one
subfile row per open ledger item in sequence order. The subfile is SFLPAG(5) per page over
SFLSIZ(20) with Roll paging (ROLLUP/ROLLDOWN), so a longer ledger pages.
| Field | Type (DDS) | Shows |
|---|---|---|
| SSEQ | 5S,0 output | Ledger sequence number (LSEQ). |
| STYPE | 1A output | Line type: T tuition, F fee, A aid credit, L late fee. |
| SDESC | 25A output | Line description (e.g. SCIENCE LAB FEE). |
| SAMT | 12A output | Charge as raised (LAMT; aid credits are negative). |
| SOPEN | 12A output | Outstanding amount (LOPEN). |
| SAGE | 1A output | Ageing bucket (LAGE): 0 current, 1 =1-30, 2 =31-60, 3 =61+. |
F00003, whose sole
enrollment was withdrawn and never assessed) writes zero subfile rows and reports
'No ledger for this family.' rather than a blanket “found”. This message logic was an
app-level fix during development (see FINDINGS.md) so the header and message are always trustworthy — which
matters because of the engine subfile-render quirk noted in F.4.Honest statement: SCHOLARIS/i does not model a true four-eyes maker–checker / separate-authorization workflow. There is no “one clerk posts, a second approves” gate: the term assessment, cash application, plan installments, late fees and lunch POS all post immediately when their cycle runs. The manual documents the control model the application does have:
SCASSESS), cash applied (SCCASH), plan
installments (SCINST), late fees (SCLATE) and lunch POS charges
(SCLPOS). This is the after-the-fact accountability trail.SCHIST on that key;
if the row already exists it skips. So a re-run of any cycle for the same period posts nothing twice.SCLPOS refuses a charge that would overdraw a
prepaid lunch balance — it stamps the transaction 'D' (declined) and leaves the balance
untouched, rather than letting LBAL go negative.SCASSESS caps a financial-aid award at the term's gross
charge, so a family is never credited past zero for a single term.SCGLRPT proves ΣLOPEN =
ΣFBAL (BALDIFF zero) at the end of every cycle chain, and
SCGLDST posts only balanced DR/CR pairs into the SQL GL.In sum, the control posture is durable audit + idempotency guards + hard invariants (never-negative lunch, aid cap) + trial-balance reconciliation, all enforced in the posting programs and the data, rather than a segregation-of-duties approval workflow.
SCHOLARIS/i runs as three periodic cycles rather than one monolithic nightly job: a term cycle
(tuition + fee assessment), a daily cycle (lunch POS + cash application), and a monthly cycle
(plan installments + aging + late fees + lunch sweep + GL close). Each cycle is a CL driver that
ADDLIBLE SCHOLARIS, CALLs its programs in a fixed order, and sends a completion banner. The batch
programs take no CALL parameters — their processing dates are literals in the source — so a
scheduled/JOBQ submission is a bare CALL.
-- first-time setup (once): build/compile objects, seed reference data CALL PGM(SCHOLARIS/SCSETUP) CALL PGM(SCHOLARIS/SCREFLD) -- then submit a (parameterless) cycle SBMJOB CMD(CALL PGM(SCHOLARIS/SCTERM)) JOB(SCTERM)
| Program | Cycle | Purpose | Reads / writes | DSPLY result |
|---|---|---|---|---|
| SCREFLD | setup | Seed families, students, grade schedules, enrollments, fee items, grade-fee links, aid. | Writes SCFAM/SCSTU/SCGRADE/SCENR/SCFEE/SCGFEE/SCAID. | SCREFLD FAM=3 STU=4 GRADE=3 ENR=4 FEE=3 GFEE=7 AID=1 |
| SCASSESS | term | Assess tuition + fees net of aid for every active enrollment. | Reads SCENR/SCSTU/SCGRADE/SCGFEE/SCFEE/SCAID; writes SCLEDG + SCHIST; updates SCFAM. | SCASSESS ASSESSED=3 SKIP=1 |
| SCLPOS | daily | Apply pending lunch POS charges/reloads; decline overdrafts. | Reads/updates SCLTXN/SCLUNCH; writes SCHIST. | SCLPOS APPLIED=3 DECLINED=1 SKIP=0 |
| SCCASH | daily | Apply unapplied cash receipts against ledger charges. | Reads/updates SCRCPT/SCLEDG/SCFAM; writes SCHIST. | SCCASH APPLIED=2 SKIP=0 |
| SCINST | monthly | Post one installment per active plan; advance/complete the plan. | Reads/updates SCPLAN/SCFAM; writes SCLEDG + SCHIST. | SCINST POSTED=1 SKIP=0 |
| SCLATE | monthly | Age every open charge; assess one flat late fee per overdue family. | Reads/updates SCLEDG/SCFAM; writes SCHIST. | SCLATE B0=0 B1=1 B2=11 B3=0 FEES=2 |
| SCLWARN | monthly | Report lunch accounts at/below their own warn line (read-only). | Reads SCLUNCH only. | SCLWARN LOW=1 OK=3 |
| SCGLDST | monthly | Post balanced GL DR/CR pairs for the movement since the last close. | Reads SCHIST; SELECT/INSERT into SCGLDIST (embedded SQL). | SCGLDST BATCH=202610 ROWS=n |
| SCGLRPT | term/monthly | COBOL AR trial balance: prove ΣLOPEN = ΣFBAL. | Reads SCLEDG + SCFAM. | SCGLRPT LEDGOPEN / FAMBAL / BALDIFF / ITEMS / FAMS |
SCASSESS walks SCENR; for each enrollment it skips a withdrawn enrollment
(ESTAT≠'A') or a wrong-year row, confirms the student is still active, then for the active
enrollment: (1) charges one term's tuition = grade schedule TUITION / 3 as a 'T'
ledger line; (2) writes one 'F' ledger line per active fee item linked to the grade for the year;
(3) credits any active aid award, capped at the gross charge, as a negative 'A' line;
then (4) raises SCFAM.FBAL by the net (gross − aid). It writes the SCHIST rows the
GL post later sums. SCGLRPT then proves the trial balance.
Expected DSPLY (3 active enrollments, S00004 withdrawn): SCASSESS ASSESSED=3 SKIP=1 Worked arithmetic (from the test oracle): S00001 K5 2000.00 tuition + 150 REG + 75 ACT = 2225.00 gross - 500.00 aid = 1725.00 net S00002 03 2400.00 + 150 + 75 = 2625.00 net (no aid) F00001 balance = 1725.00 + 2625.00 = 4350.00 S00003 08 2800.00 + 150 + 75 + 50 (LAB) = 3075.00 net F00002 balance = 3075.00 F00003 balance (S00004 enrollment withdrawn) = 0.00 school-wide: gross 7925.00 - aid 500.00 = 7425.00
SCIENCE LAB FEE grade-fee link, so only S00003's ledger gets the 50.00 'F' line. This
is why F00001 has 4 fee lines (REG×2 + ACT×2, no LAB) and F00002 has 3 (REG + ACT + LAB).SCLPOS applies each pending ('E') lunch transaction in TSEQ order against the
student's SCLUNCH balance: a reload ('R') always applies and raises the balance; a
charge ('C') applies only if TAMT ≤ LBAL, otherwise it is declined
(TSTAT='D', balance unchanged). Because reloads and charges apply in sequence, a reload posted
before a charge tops the balance up first. SCCASH then applies each unapplied receipt
(RCSTAT='U') against the ledger charge it names: it takes only what is owed (any excess stays
unapplied), never touches a negative-open aid credit, lowers SCFAM.FBAL by exactly what it applied,
and stamps the receipt 'A' (fully applied) or 'P' (part-applied).
Expected DSPLY: SCLPOS APPLIED=3 DECLINED=1 SKIP=0 SCCASH APPLIED=2 SKIP=0 Lunch worked example: S00001 20.00 - 4.50 charge = 15.50 (applied) S00002 3.00 + 20.00 reload = 23.00, then - 4.50 = 18.50 (TSEQ order) S00003 10.00 - 15.00 charge = DECLINED, stays 10.00 (never-negative) Cash worked example (against the term ledger): RC000001 2000.00 vs S00001 K5 tuition 2000.00 open -> full: open 0.00, P F00001 4350.00 -> 2350.00 RC000002 1000.00 vs F00002 tuition 2800.00 open -> part: open 1800.00, O F00002 3075.00 -> 2075.00; receipt itself fully applied (A)
SCINST posts one installment per active plan with installments remaining
(PLPAID < PLCNT): a new 'T' ledger charge of PLINST, raising
FBAL, advancing PLPAID and flipping the plan to 'C' when the last one
posts — a plan smooths when money falls due, it does not discount the total. SCLATE
runs two passes on a 30/360 date convention: pass 1 ages every open positive charge into bucket 0/1/2/3 by days
overdue; pass 2 assesses one flat 25.00 late fee per active family that has any open charge past the
30-day grace (a negative aid-credit line is never aged and never triggers a fee). SCLWARN reports
(read-only) any active lunch account at/below its own LWARN line. SCGLDST sums the
SCHIST history by type and posts balanced GL pairs for the movement since the last close.
SCGLRPT proves the trial balance.
Expected DSPLY: SCINST POSTED=1 SKIP=0 SCLATE B0=0 B1=1 B2=11 B3=0 FEES=2 SCLWARN LOW=1 OK=3 SCGLDST BATCH=202610 ROWS=n GL balanced pairs (worked, from the test oracle): DR 1400-FAR 7975.00 (charges: tuition 7200 + fees 725 + late 50) CR 4100-TUIT 7200.00 / CR 4200-FEE 725.00 / CR 4300-LATE 50.00 DR 5100-AID 500.00 / CR 1400-FAR 500.00 (the aid pair, its own balanced leg) => SUM(DR) = SUM(CR) to the cent
'T' but writes an SCHIST
row of type 'I', which is not part of the T/F/A/L taxonomy SCGLDST recognises,
so the installment does not double-count into tuition revenue. The GL sums history, not the ledger. Aging is
genuinely per-charge: in the test month F00002's original term charges land in bucket 2 (40 days overdue) while
its fresh 1-Oct installment lands in bucket 1 (24 days overdue).SCASSESS has run.SCLPOS) then cash application (SCCASH) —
the two halves are independent (lunch accounts vs the family ledger) but the driver fixes the order.SCINST) → aging + late fees (SCLATE)
→ lunch sweep (SCLWARN) → GL distribution (SCGLDST) → trial
balance (SCGLRPT). Installments post before aging so the fresh installment charge is itself
aged; the GL post runs after all charges (including late fees) exist so it sums the full period.CHAIN(EN) history
guard means a re-run in the same period is safe (see E.3 and F.3).All files are in library SCHOLARIS, grounded in the DDS/SQL source in
src/sources.mjs. Dates are stored as signed numeric in YYYYMMDD form; money is packed
decimal. Field types are given as they appear in DDS (P packed, S zoned,
A character).
| Field | Type | Meaning |
|---|---|---|
| FAMNO | 6A | Family number (key), e.g. F00001. |
| FNAME / FADDR / FPHONE | 30A / 30A / 14A | Name, address, phone. |
| FBAL | 11P 2 | Running AR balance — the spine; moved only up (charge) and down (cash). |
| FSTAT | 1A | A active, I inactive (withdrawn, no current enrollments). |
| Field | Type | Meaning |
|---|---|---|
| STUNO | 6A | Student number (key), unique school-wide, e.g. S00001. |
| SNAME | 30A | Student name. |
| FAMNO | 6A | Billing family. |
| GRADE | 2A | Grade (drives which tuition schedule applies), e.g. K5, 08. |
| SSTAT | 1A | A active, W withdrawn, G graduated. |
SCSTULF is a non-unique logical over SCSTU keyed by FAMNO,
so a family's whole roster can be walked without scanning the student file.
| Field | Type | Meaning |
|---|---|---|
| GRADE | 2A | Grade. |
| SCHYR | 4S 0 | School year. |
| TUITION | 11P 2 | Standing annual tuition (term charges one-third). |
| GSTAT | 1A | A active. |
Seeded 2026 schedule: K5 6000.00, grade 03 7200.00, grade 08 8400.00.
| Field | Type | Meaning |
|---|---|---|
| STUNO / SCHYR | 6A / 4S 0 | Student + school year (key). |
| GRADE | 2A | Grade enrolled for the year. |
| ENRDT | 8S 0 | Enrollment date (YYYYMMDD). |
| ESTAT | 1A | A active, W withdrawn (the term run skips a withdrawn enrollment). |
| Field | Type | Meaning |
|---|---|---|
| FEECD | 4A | Fee code, e.g. REG, ACT, LAB. |
| SCHYR | 4S 0 | School year. |
| FEEDESC | 20A | Description (e.g. SCIENCE LAB FEE). |
| FAMT | 9P 2 | Flat per-term amount. |
| FSTAT2 | 1A | A active (charged), S suspended (waived this year). |
SCGFEE maps (GRADE, FEECD, SCHYR): which fee
items apply to which grade. Seeded links: REG + ACT for every grade, LAB for grade 08 only.
| Field | Type | Meaning |
|---|---|---|
| STUNO / SCHYR | 6A / 4S 0 | Student + school year (key). |
| AWDAMT | 11P 2 | Flat award (SCASSESS caps it at the gross charge). |
| ASTAT | 1A | A active award, D declined/withdrawn. |
| Field | Type | Meaning |
|---|---|---|
| FAMNO / LSEQ | 6A / 5S 0 | Family + per-family sequence (key). |
| LTYPE | 1A | T tuition, F fee, A aid credit (negative), L late fee. |
| LDT / LDUE | 8S 0 | Charge date / due date (YYYYMMDD). |
| LAMT | 11P 2 | Charge as raised (never changed after posting; aid credits are negative). |
| LOPEN | 11P 2 | Outstanding amount (LAMT less cash applied; an aid credit's LOPEN is negative). |
| LAGE | 1S 0 | Ageing bucket stamped by SCLATE: 0/1/2/3. |
| LDESC | 25A | Line description. |
| LSTAT | 1A | O open, P part/paid (LOPEN reached 0). |
SCLEDLF is a logical over SCLEDG keyed by due date, so the aging run can
walk oldest-due-first — the access path an ageing report wants and the family-keyed PF cannot give.
| Field | Type | Meaning |
|---|---|---|
| FAMNO | 6A | Family (key). |
| PLTOT | 11P 2 | Total enrolled under the plan. |
| PLINST | 11P 2 | Flat installment amount due each month. |
| PLCNT / PLPAID | 3S 0 | Installment count / installments posted so far. |
| PSTAT | 1A | A active, C completed (all installments posted). |
| Field | Type | Meaning |
|---|---|---|
| RCPTNO | 8A | Receipt number (key), e.g. RC000001. |
| FAMNO / RCLSEQ | 6A / 5S 0 | Family and the ledger LSEQ this receipt names. |
| RCDT | 8S 0 | Receipt date. |
| RCAMT / RCAPPL | 11P 2 | Amount tendered / amount actually applied. |
| RCSTAT | 1A | U unapplied, A fully applied, P part-applied. |
| Field | Type | Meaning |
|---|---|---|
| STUNO | 6A | Student (key). |
| LBAL | 9P 2 | Prepaid balance — NEVER goes negative. |
| LWARN | 9P 2 | Low-balance threshold the monthly sweep alerts against. |
| LSTAT | 1A | A active. |
| SCLTXN field | Type | Meaning |
|---|---|---|
| STUNO / TSEQ | 6A / 5S 0 | Student + transaction sequence (key; apply order). |
| TTYPE | 1A | C charge (reduces balance), R reload (increases balance). |
| TDT / TAMT | 8S 0 / 9P 2 | Date / amount (always positive; sign implied by TTYPE). |
| TDESC | 20A | Description. |
| TSTAT | 1A | E entered/pending, A applied, D declined (insufficient balance). |
| Field | Type | Meaning |
|---|---|---|
| HSEQ | 8S 0 | Stable, business-key-derived sequence (key; disjoint ranges per program — see F.3). |
| HKEY | 8A | The business key (student or family) the row was derived from. |
| HTYPE | 1A | T tuition, F fee, A aid, P cash payment, I plan installment, L late fee. |
| HDT / HAMT | 8S 0 / 11P 2 | Date / amount (cash is negative). |
| HREF / HMEMO | 8A / 25A | Reference and free-text memo. |
| Column | Type | Meaning |
|---|---|---|
| GLSEQ | DECIMAL(8,0) | Sequence (PK). |
| GLBATCH | DECIMAL(6,0) | Batch YYYYMM. |
| ACCT | CHAR(9) | Account, e.g. 1400-FAR, 4100-TUIT, 4200-FEE, 4300-LATE, 5100-AID. |
| DRCR | CHAR(1) | D debit, C credit. |
| AMT | DECIMAL(11,2) | Amount. |
| GLREF / GLDT | CHAR(8) / DECIMAL(8,0) | Reference / date. |
Index SCGLDACC is on (ACCT, DRCR) — the access path
the incremental GL post uses to sum what has already been debited per account.
CALL SCHOLARIS/SCSETUP (build/compile every object), then
CALL SCHOLARIS/SCREFLD (seed reference data). Confirm the banner
SCREFLD FAM=3 STU=4 GRADE=3 ENR=4 FEE=3 GFEE=7 AID=1.SBMJOB CMD(CALL PGM(SCHOLARIS/SCTERM)).SCDAILY. Check the SCLPOS/SCCASH lines.CALL SCHOLARIS/SCMENU (option 1 student inquiry, option 2
family ledger) as questions arrive.Pre-checks: confirm the job's library list includes SCHOLARIS; confirm reference data is
seeded (a fresh library needs SCREFLD before SCTERM can assess anything).
Post-checks after the term cycle:
SCASSESS ASSESSED= equals the active enrollments and SKIP= the withdrawn/other-year ones.FBAL equals the sum of its ledger lines (aid credits netting off) — the term test asserts F00001=4350.00, F00002=3075.00, F00003=0.00.LOPEN = LAMT (nothing paid yet).SCGLRPT BALDIFF 0.00.SCPLAN) that should post an installment this month.SCMONTH. Confirm the completion banner and the four DSPLY lines
(SCINST/SCLATE/SCLWARN/SCGLDST).SELECT ACCT, DRCR, SUM(AMT) FROM SCHOLARIS.SCGLDIST GROUP BY ACCT, DRCR; SELECT SUM(CASE WHEN DRCR='D' THEN AMT ELSE -AMT END) AS NET FROM SCHOLARIS.SCGLDIST;
Reconciling figures (the same ones the monthly volume simulation checks against a hand-derived oracle):
SUM(DR) = SUM(CR) to the cent (the NET above is 0.00).4100-TUIT = tuition history total (7200.00), 4200-FEE = 725.00, 4300-LATE = 25.00×(late fees) = 50.00.5100-AID debited 500.00 with a matching 1400-FAR credit — the aid reduces the receivable rather than floating unbalanced.1400-FAR DR (charges) 7975.00, CR (aid) 500.00 — both legs of the one control account.SCGLRPT BALDIFF 0.00: ΣLOPEN = ΣFBAL.Ad-hoc statement: the AR ageing / billing report writes through the SCAGEP printer file
(header AGEHDR, one AGEDTL per aged line, an AGETOT footer with item count
and total outstanding).
Each program DSPLYs a one-line result. A healthy chain also ends with the completion banner its CL driver sends. Because every posting program guards on a stable history key, most cycles are safe to re-run.
| Situation | Behaviour | Action |
|---|---|---|
| Re-run the term cycle | Every student already has its tuition history row; all are skipped. | Safe: the second run reports ASSESSED=0 SKIP=4 and family balances are unchanged. Idempotent. |
| Re-run the daily cycle | Applied transactions/receipts have left their pending state; nothing new matches. | Safe: SCLPOS APPLIED=0 DECLINED=0 SKIP=4, SCCASH APPLIED=0 SKIP=2; balances unchanged. |
| Re-run SCLATE / SCGLDST in the same period | Late-fee guard key is stable per run date; GL posts only the movement since the last close. | Safe: SCLATE FEES=0 on the second call; the GL debit total does not double. |
| Re-run SCINST across a genuinely new month | The guard key is derived from PLPAID+1, so a new month posts the NEXT installment. | Correct by design: installment #2, then #3, then the plan completes (PSTAT='C'); a further call reports POSTED=0 SKIP=1. |
| Lunch charge would overdraw | SCLPOS declines it (TSTAT='D'), balance unchanged. | Reload the account (a 'R' transaction) and re-run; the never-negative invariant is intentional, not an error. |
| Cash receipt exceeds the open charge | SCCASH applies only what is owed; the excess stays unapplied (receipt 'P'). | Raise a further receipt against another open charge, or leave the remainder unapplied. |
SCHIST and every charge to
SCLEDG with a live LOPEN, any cycle's effect is fully reconstructable after the fact,
and SCGLRPT's BALDIFF is the single number that confirms the book still balances.The full program surface, from src/sources.mjs. Programs are fixed-form RPG IV with embedded
/free blocks (built by the C()/D() column-exact helpers), one SQLRPGLE, and
one ILE COBOL. All objects are in library SCHOLARIS.
SCENR; per active in-year enrollment: CHAINs SCSTU (family + still-active
check), CHAINs SCGRADE for TUITION/3, walks the grade's SCGFEE links
CHAINing each active SCFEE, caps SCAID at the gross, writes the T/F/A ledger lines
and history rows, and raises SCFAM.FBAL by the net. The next LSEQ is found by a
SETLL/READE partial-key walk keeping the highest seq seen.SCRCPT; for each unapplied receipt CHAINs the named SCLEDG charge (KLIST
FAMNO+LSEQ), takes min(RCAMT, LOPEN) of a POSITIVE open charge (never an aid credit), lowers
SCFAM.FBAL, writes a negative-amount 'P' history row, and stamps the receipt A/P.SCLTXN in key (TSEQ) order; a reload always applies, a charge applies only if it fits the
balance else it is declined; re-CHAINs the transaction row after each SCLUNCH update (the
update moved the file cursor) to stamp A/D. DSPLYs applied/declined/skip counts.SCPLAN; for an active plan with PLPAID < PLCNT posts one
PLINST as a 'T' ledger charge, raises FBAL, advances
PLPAID and flips PSTAT to 'C' on the last one.LAGE). Pass 2 walks SCFAM, and per family re-walks its own ledger rows to decide
if any open charge is past the 30-day grace, assessing at most one flat 25.00 late fee (its own ledger line
+ history row + FBAL bump). Aid credits are never aged and never trigger a fee.SCLUNCH: counts active accounts at/below their own LWARN line vs
OK, DSPLYs the tally. Never mutates a balance.SCHIST by type (T/F/A/L), reads what has already been debited to
1400-FAR and 5100-AID via EXEC SQL SELECT, and posts only the
movement since the last close as balanced pairs (the glrow subroutine INSERTs and counts only
sqlcod=0 rows). The financial-aid pair is posted separately so DR total = CR total.SCLEDG.LOPEN and every SCFAM.FBAL, then DISPLAYs
LEDGOPEN, FAMBAL, BALDIFF (should be 0.00), ITEMS and
FAMS. Proves the AR sub-ledger reconciles to the family master.1 CALLs SCSTUIQ, 2 CALLs
SCLEDIQ, any other non-blank sets 'Invalid option.'; *IN03 (F3) ends.SCSTU → SCFAM → SCLUNCH, editing
FBAL/LBAL with %editc(:'K'). Clears detail and reports the outcome
message; a miss says 'Student not found.', a family-less student 'Student found -- no
family on file.'*IN31 (SFLCLR) after the EXFMT returns the new key,
CHAINs SCFAM for the header, then SETLL/READE SCLEDG on the family key writing one
LSFL row per open item. The message is decided AFTER the load from RRN:
'Family found.' if rows loaded, else 'No ledger for this family.'There is no control table and no transaction sequence generator. Instead, every posting program derives its
SCHIST.HSEQ from a stable business key in a range disjoint per program, CHAINs
SCHIST on it before posting (CHAIN(EN)), and skips if the row already exists. A re-run
regenerates the same key and is refused — this is the app's idempotency guard.
| Program | HSEQ formula | Base | Stable across |
|---|---|---|---|
| SCASSESS | 10000000 + student-digits×10 + component# | 10M | same term (per student, per component) |
| SCCASH | 20000000 + receipt-digits | 20M | the receipt (applied once) |
| SCLATE | 30000000 + family-digits | 30M | the run date (one fee per family) |
| SCINST | 40000000 + family-digits×100 + installment# | 40M | one installment number (advances by month) |
| SCLPOS | 50000000 + student-digits×1000 + txn-seq | 50M | the transaction (applied once) |
Because the ranges are disjoint, the five programs never collide, and each is idempotent in exactly the sense its business needs: SCASSESS/SCCASH/SCLPOS/SCLATE are period-stable (a re-run posts nothing), while SCINST's key advances with the installment number so a genuinely new month posts the next installment — and refuses a second post of the same number.
Two implementation details are documented in the source and matter operationally:
SCGFEE and SCFEE both carry
a field named SCHYR, which share one storage slot across externally-described files. The
fee-item loop therefore captures SCHYR/FEECD into work fields
(WGFYR/WGFFEE) immediately after the SCGFEER READE, before the
SCFEER CHAIN reloads the shared slot. (An app-level fix, per FINDINGS.md.)UPDATE to a second file moves the record
cursor, so these programs re-CHAIN the transaction/family row after each dependent update before stamping
or reading it. This is a deliberate accommodation, not a bug.SCLEDIQ session, if the new family has FEWER or ZERO ledger rows than the first,
the previous enquiry's detail rows can remain visible on the rendered screen alongside the new (correct) header
and message, and the SFLEND(*MORE) indicator may still show. This is not an
SCLEDIQ logic fault: the program issues SFLCLR (*IN31) before the reload,
the header is re-derived correctly, and the row-count (RRN) and SCLEDG reads are
correct — proven by the interactive test asserting the header/balance/message change. The discrepancy is in
the emulator's render path for SFLCLR/EXFMT re-display. It is the same recurring quirk
already logged against the UNMODIFIED sibling apps — payroll (PYSLPIQ) and mrp
(FGWOIQ); SCLEDIQ reproducing it on a third, independently written subfile program is
what strengthens the case that the fault is platform-side (the estate's NA-07 area). No engine change is made
(hard rule); the app's message logic was fixed so the header and message are always trustworthy even if stale
rows show. Trust the header, balance and message — not the detail rows — on a repeat enquiry.SCFAM.FBAL, backed by the
open-item ledger SCLEDG.SCLEDG.LAGE, stamped by SCLATE on a 30/360 convention).SCENR) tying a student to a grade for a school year — the thing the term
assessment bills. A withdrawn enrollment (ESTAT='W') is skipped even if the student master is
active.SCAID) posted as a NEGATIVE ledger line, capped at the gross charge, so the
family's net charge is gross minus aid.CHAIN(EN) guard on a stable,
business-key-derived SCHIST.HSEQ (see F.3). Term/daily/late/GL cycles are idempotent within a
period; plan installments advance across months by design.SCLUNCH). A charge that would overdraw it is declined —
the never-negative invariant.SCGLRPT proves
ΣLOPEN = ΣFBAL.SCPLAN) that smooths WHEN a family's charges fall due; SCINST posts
one installment per month as a ledger charge. It does not discount the total owed.SBMJOB CMD(CALL PGM(SCHOLARIS/SCTERM))).SCLEDIQ's family
ledger list is a subfile.BALDIFF is
the single “does the book balance” number.