FITHUB/i — Fitness Club Membership & Billing

SteelFrame X application operation manual  ·  ← back to Operation Manuals  ·  Sign On

FITHUB/i is a single-location fitness-club membership and billing application: member and agreement maintenance, recurring monthly dues billing with freeze/pause and first-month pro-ration, auto-pay receipt posting, dunning/late-fee assessment, capacity-checked class booking and check-in, personal-training package usage with session-by-session revenue recognition, and a balanced GL close posted under commitment control. The whole estate is column-exact IBM i source — DDS physical and logical files, an SQL DDL table for the GL feed, RPG (fixed-form and **FREE) cycle programs, a COBOL cross-check report, and CL cycle drivers — loaded into library FITHUB. This manual is the reference for the operator who runs the online screens and the periodic batch cycles, and for the developer maintaining the application. It is grounded entirely in the committed source (fitness-app/src/sources.mjs, src/seed.mjs, and the test/fithub_build.mjs / fithub_daily.mjs drivers).

Contents

A. Overview & Architecture ↑ top

A.1 What it does

FITHUB/i services the life of a fitness-club membership:

A.2 Design shape: RPG/COBOL over DDS + a running-account ledger

FITHUB/i is a classic record-level-access IBM i application, not an SQL-PL app. A few shape points matter to operations:

Everything runs in library FITHUB. Journaling (FHJRN/FHRCV) is active on the two audit files FHAGREE and FHLEDG.

A.3 Component & flow

  MAINTENANCE / ONLINE        BATCH (periodic, via *JOBQ)
  --------------------        ---------------------------
  FHMNT  (member/agr,         MONTHLY  FHMONTH --> FHDUES(cutoff)  recurring dues
         freeze/unfreeze)                       --> FHDUESPR       dues statements
  FHBOOK1 (book/checkin/      DAILY    FHDAILY --> FHAUTOPAY       receipt posting
           cancel)            PERIOD   FHPERIOD--> FHDUNNING(dt)   delinquency + late fee
  FHMENU (5250 menu)                            --> FHPTUSE        PT usage recognition
    1 -> FHMBRIQ (plain)                        --> FHGLPST        balanced GL close
    2 -> FHLEDIQ (subfile)              cross-check: FHGLRPT (COBOL)

  every posting program --writes--> FHLEDG (durable keyed ledger, disjoint LEDGSEQ bands)
                                     FHMEMBR.MBAL (running balance)
  FHGLPST --summarizes FHLEDG by LTYPE--> FHGLF (balanced DR/CR, commit if in balance)

A single billing event flows: operator (or the FHMONTH CL) submits FHDUES with a cutoff date → it scans open agreements in NEXTBILL order via the FHAGEL access path → for each due, unfrozen agreement it computes the (possibly pro-rated) dues, raises FHMEMBR.MBAL, writes an FHLEDG 'D' row, and advances NEXTBILL one calendar month on FHAGREE (journaled).

A.4 Object inventory

ObjectTypeRole
FHMEMBRPFMember master (running balance MBAL, status MSTAT).
FHPLANPFMembership plan / dues-rate catalog (BAS/PLS/PRM).
FHAGREEPFMembership agreements (plan link, freeze, NEXTBILL cursor).
FHCLASSPFClasses / sessions (capacity CAPMAX / CAPCNT).
FHBOOKPFBookings / check-ins.
FHPTPKGPFPT packages (deferred-revenue liability drawdown).
FHPTUSGPFPT usage-event trail (one row per session recognized).
FHLEDGPFMember ledger / A/R audit trail (durable keyed).
FHRCPTPFReceipts / auto-pay input.
FHAGRML / FHAGELLFAgreements by member / by NEXTBILL (billing cursor).
FHBOKCL / FHBOKMLLFBookings by class / by member.
FHLEDMLLFLedger by member (inquiry access path).
FHGLFSQL tableDB2 GL posting feed (DR/CR rows).
FHMBRD / FHLEDGD / FHMENUDDSPFMember inquiry / ledger subfile / menu.
FHDUESPPRTFMonthly dues statement printer file.
FHPLNLDRPGLEPlan-catalog loader (reference data).
FHMNTRPGLEMember/agreement maintenance + freeze/unfreeze.
FHDUESRPGLERecurring dues billing (freeze + pro-ration aware).
FHBOOK1RPGLEClass booking / check-in / cancel (capacity-checked).
FHAUTOPAYRPGLEAuto-pay / receipt posting.
FHDUNNINGRPGLEDunning + flat late-fee assessment.
FHPTUSERPGLEPT session drawdown + revenue recognition.
FHGLPSTSQLRPGLEBalanced GL posting under commitment control.
FHDUESPRRPGLEDues-statement print (spool).
FHMBRIQ / FHLEDIQ / FHMENURPGLEMember inquiry / ledger subfile / menu.
FHGLRPTCBLLECOBOL GL cross-check report.
FHSETUPCLPBuild all objects, journal, authority, seed plans.
FHMONTH / FHDAILY / FHPERIODCLPCycle drivers (monthly / daily / period).

The full catalogue is 9 PFs + 5 LFs + 1 SQL table, 3 DSPFs + 1 PRTF, 12 RPG programs + 1 COBOL program, and 4 CL programs, plus journal (FHJRN) and receiver (FHRCV). Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

FITHUB/i has no CICS transaction identifiers and no menu-driven transid switch. On IBM i, each program is reached by name from a 5250 command-entry line (or a JOBQ/scheduler for the batch jobs). The operator equivalent of "type a transid and Enter" is "type a CALL command and Enter". Before invoking anything, the job's library list must include FITHUB — the tested jobs run with LIBL = QSYS QGPL FITHUB QTEMP and CURLIB = FITHUB.

To do thisType on the command line
Open the operator menu (routes to the two inquiries)CALL FITHUB/FHMENU
Member inquiry directly (plain screen)CALL FITHUB/FHMBRIQ
Ledger inquiry directly (subfile screen)CALL FITHUB/FHLEDIQ
Maintain a member / agreement, freeze / unfreezeCALL FITHUB/FHMNT PARM(...)
Book / check-in / cancel a class bookingCALL FITHUB/FHBOOK1 PARM(...)
Recognize one PT sessionCALL FITHUB/FHPTUSE PARM(...)
Run a cycle (monthly / daily / period)SBMJOB CMD(CALL FITHUB/FHMONTH) (or FHDAILY/FHPERIOD)
Bill dues to a specific cutoff dateSBMJOB CMD(CALL FITHUB/FHDUES PARM('YYYYMMDD'))

FHMNT, FHBOOK1 and FHPTUSE are callable programs with an *ENTRY parameter interface (dcl-pi): they are the program-to-program CALL idiom used by the test harness and by any wrapper. FHMENU, FHMBRIQ and FHLEDIQ are the three interactive 5250 programs. The batch cycle programs are covered in section C.

B.2 The operator menu & inquiries (FHMENU / FHMBRIQ / FHLEDIQ)

FHMENU displays a two-option menu (FHMENUD) and routes by a dynamic CALL: option 1 calls FHMBRIQ (member inquiry, plain WORKSTN), option 2 calls FHLEDIQ (ledger inquiry, subfile). F3 exits.

FITHUB/i Main Menu 1. Member Inquiry 2. Ledger Inquiry Option . . . . : _ F3=Exit Enter=Select

FHMBRIQ — member inquiry (plain)

Keys a member number; CHAINs FHMEMBR for name/status/balance and FHAGRML (agreements by member) for the plan, freeze flag and next-bill date, then redisplays. Enter re-inquires; F3 exits back to the menu.

Member Inquiry - FITHUB/i Member number: M00002 Name . . . . . : BLAIR NAKAMURA Status . . . . : A Plan . . . . . : PLS Freeze . . . . : N Next bill . . : 20260901 Balance . . . : 105.95 Member found. F3=Exit Enter=Inquire

FHLEDIQ — ledger inquiry (subfile)

The app's one subfile screen (FHLEDGD: record LSFL under control LCTL, SFLPAG(0012), SFLSIZ(0030)). Keys a member; on a match it clears the subfile (SFLCLR), loads the member's ledger rows from FHLEDML (ledger by member), and displays them. Control indicators are 41=SFLDSP, 42=SFLDSPCTL, 43=SFLCLR, 44=SFLEND(*MORE).

Ledger Inquiry - FITHUB/i Member number: M00003 Name . . . . . : CASEY OKAFOR Balance . . . : 114.99 Typ Date Amount Memo D 20260701 99.99 DUES A0000003 F 20260901 15.00 LATE FEE Member found. F3=Exit Enter=Inquire
Subfile field (LSFL)Type (DDS)Shows
SLTYPE1A outputLedger type: D dues, P payment, F fee, R PT revenue.
SLDT8A outputLedger date (from LDT).
SLAMT14A outputAmount (rendered from LAMT).
SLMEMO20A outputMemo (e.g. DUES A0000003, LATE FEE).

B.3 Maintenance & controls (FHMNT / FHBOOK1)

FHMNT is the member/agreement maintenance program, dispatched by a two-character action:

ActionDoes
MCMember create/change (keyed by pMbrno). CHAIN + UPDATE if found, else WRITE a fresh member (MSTAT='A', MBAL=0).
ACAgreement create/change (keyed by pKey=AGRNO; pMbrno links it). A create sets FRZSTAT='N', NEXTBILL=STARTDT, AGRSTAT='O'.
MIMember inquire (returns name/city/state via OUT parms).
FZFreeze agreement: FRZSTAT='Y', FRZDT set.
UFUnfreeze agreement: FRZSTAT='N', FRZDT=0.

Create/change is validate-before-write and idempotent: a change re-CHAINs on the full key and UPDATEs the found record; a create WRITEs a fresh record. The program re-CHAINs immediately before each UPDATE so it never double-UPDATEs a stale read.

FHBOOK1 is the class booking program, also dispatched by action:

ActionDoes
BKBook a member into a class. Capacity-checked: rejected with CLASS FULL if CAPCNT ≥ CAPMAX; otherwise increments CAPCNT, writes a BSTAT='B' booking, returns the new BOOKNO.
CICheck a booked member in: finds their open ('B') booking for the class, sets BSTAT='C' and CKINDT.
CXCancel a booking: sets BSTAT='X' and decrements CAPCNT back so the seat frees up.
Control posture. FITHUB/i does not model a four-eyes maker–checker workflow: maintenance and postings apply immediately. The controls it does have are: a durable, keyed ledger (FHLEDG) recording every dues/payment/fee/PT-revenue movement; journaling (FHJRN, IMAGES *BOTH) on FHAGREE and FHLEDG; capacity gating on bookings; a dunning idempotency guard (a member already MSTAT='D' is not re-flagged/re-feed); and object-authority scoping on the ledger (FHSETUP revokes *PUBLIC *ALL and grants only *CHANGE). The GL close (FHGLPST) enforces its own control: it commits only if debits equal credits, else ROLLBACK.

C. Batch Jobs & the Periodic Cycle ↑ top

FITHUB/i's processing runs as three periodic cycles rather than one monolithic nightly job: a monthly cycle (recurring dues + statements), a daily cycle (auto-pay), and a period cycle (dunning + PT revenue + GL close). Each cycle is a small CL driver that ADDLIBLE FITHUB then calls its programs in order. The drivers are meant to be submitted through a *JOBQ (the tested queue is FITHUB/NITEQ) so each program fully closes its output files before the next opens them — the same single-threaded-batch idiom the setup notes call out.

-- create the batch queue once
CRTJOBQ JOBQ(FITHUB/NITEQ) TEXT('FITHUB batch queue')

-- submit a cycle driver (parameterless)
SBMJOB CMD(CALL FITHUB/FHMONTH) JOB(FHMONTH) JOBQ(FITHUB/NITEQ) HOLD(*NO)

-- or drive dues billing to a SPECIFIC cutoff date directly
SBMJOB CMD(CALL FITHUB/FHDUES PARM('20260801')) JOB(FHDUES1) JOBQ(FITHUB/NITEQ) HOLD(*NO)

The dues and dunning programs take a cutoff/run date parameter (PRUNDT, YYYYMMDD, via the *ENTRY PLIST). The FHMONTH / FHPERIOD wrappers pass the sentinel '99999999' to bill/dun the whole due backlog in one pass; a caller that needs to stop at a specific business date instead calls FHDUES/FHDUNNING directly with that date, exactly as the daycycle test does.

C.1 Full batch program set

ProgramPurposeFiles touchedInputsOutputs (DSPLY / effect)Frequency
FHDUES Recurring monthly dues billing (freeze + first-month pro-ration aware). FHAGEL/FHAGREE, FHPLAN, FHMEMBR, FHLEDG. PRUNDT cutoff (YYYYMMDD PARM). FHDUES BILLED=n FROZEN-SKIPPED=n PRORATED=n; raises MBAL, D ledger rows, advances NEXTBILL +1 month. Monthly.
FHDUESPR Print a dues statement per dues ('D') ledger row. FHLEDG, FHMEMBR, FHDUESP (PRTF). none. FHDUESPR PRINTED=n; spooled statements. Monthly (after FHDUES).
FHAUTOPAY Apply cash receipts against member balances. FHRCPT, FHMEMBR, FHLEDG. none (one pass over FHRCPT). FHAUTOPAY POSTED=n NOMEMBER=n; reduces MBAL, P ledger rows. Daily.
FHDUNNING Flag delinquent members over threshold, assess a flat late fee. FHMEMBR, FHLEDG. PRUNDT (YYYYMMDD PARM) stamps the fee date. FHDUNNING FLAGGED=n; MSTAT→'D', +15.00 fee, F ledger rows. Period.
FHPTUSE Draw one PT session down, recognize its revenue slice. FHPTPKG, FHPTUSG, FHMEMBR, FHLEDG. PARM: pPkgno, pUsgdt. FHPTUSE PKGnnnnn <result>; usage-event row, R ledger row, PKGSTAT→'X' at exhaustion. Per session (period cycle drives repeatedly).
FHGLPST Summarize the ledger, post balanced GL rows under commitment control. FHLEDG (read via SQL), FHGLF (insert). none. FHGLPST IN BALANCE ... COMMITTED or OUT OF BALANCE ... ROLLED BACK. Period (last).
FHGLRPT COBOL cross-check: member-balance total + GL A/R vs dues+fees. FHMEMBR (COMP-3 FD), FHLEDG + FHGLF (embedded SQL). none. FHGLRPT ... CROSS-CHECK: IN BALANCE / OUT OF BALANCE. Period (verification).

C.2 Monthly / daily / period detail

Monthly — FHMONTH (FHDUES → FHDUESPR)

FHDUES does a forward SETLL *LOVAL / READ pass over FHAGEL (agreements keyed by NEXTBILL), stopping at the first agreement whose NEXTBILL > PRUNDT. For each open agreement due for billing:

It then raises FHMEMBR.MBAL, writes an FHLEDG 'D' row, and advances NEXTBILL one calendar month (month +1, wrapping the year at 12→1, day forced to 01). FHDUESPR then prints one statement per 'D' ledger row.

Expected DSPLY (cycle 1: 3 agreements, one prorated first bill, none frozen):
  FHDUES BILLED=3 FROZEN-SKIPPED=0 PRORATED=1
M1 BAS full 39.99, M2 PLS prorated 59.99*16/31 -> 30.96 (truncated), M3 PRM full 99.99
Expected DSPLY (cycle 2, M3 frozen):
  FHDUES BILLED=2 FROZEN-SKIPPED=1 PRORATED=0

Daily — FHDAILY (FHAUTOPAY)

FHAUTOPAY makes one pass over FHRCPT (arrival). Each receipt reduces the member's MBAL directly (MBAL = MBAL − RCPTAMT; may go negative — a valid credit balance) and writes an FHLEDG 'P' row. There are no per-invoice rows to apply against — this is a running account.

Expected DSPLY (one receipt applied):
  FHAUTOPAY POSTED=1 NOMEMBER=0

Period — FHPERIOD (FHDUNNING → FHPTUSE → FHGLPST)

FHDUNNING does a forward pass over FHMEMBR: any active ('A') member with MBAL over the threshold (WTHRESH, seeded 0.00) is flagged MSTAT='D' and assessed a flat 15.00 late fee (added to MBAL, 'F' ledger row). A member already 'D' is not re-flagged/re-feed on a second pass — only a fresh crossing from 'A' triggers a new fee.

FHPTUSE (called once per session) draws one session from a package: the per-session recognized amount is PKGPRC / SESSBUY, and the final session recognizes whatever balance of PKGPRC remains (sweeping the rounding residue) and sets PKGSTAT='X', so a package's recognized revenue sums to PKGPRC exactly. It writes an FHPTUSG usage-event row and an FHLEDG 'R' row; it does not touch MBAL (the member paid up front).

FHGLPST sums FHLEDG by LTYPE and inserts balanced DR/CR rows into FHGLF under commitment control, then re-reads the batch and COMMITs only if DR=CR (else ROLLBACK).

Expected DSPLY:
  FHDUNNING FLAGGED=2               e.g. M2 + M3 both over threshold
  FHPTUSE PKG00001 SESSION RECOGNIZED  33.33, 33.33, 33.34 -> sums 100.00
  FHGLPST IN BALANCE DR=... CR=... COMMITTED
  FHGLRPT ... CROSS-CHECK: IN BALANCE

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library FITHUB, grounded in the DDS/SQL in fitness-app/src/sources.mjs. Dates are stored as signed numeric YYYYMMDD (8S 0); money is packed decimal (xP 2); A is character.

FHMEMBR — Member master (key MBRNO)

FieldTypeMeaning
MBRNO6AMember number (key).
MNAME25AMember name.
MADDR / MCITY / MST / MZIP25A / 15A / 2A / 5AAddress, city, state, zip.
MJOINDT8S 0Join date (YYYYMMDD).
MSTAT1AA active, F frozen, D delinquent/hold, C cancelled.
MBAL9P 2Running account balance (dues raise it, payments reduce it; may be negative).

FHPLAN — Plan / dues-rate catalog (key PLANCD)

FieldTypeMeaning
PLANCD3APlan code (key): BAS, PLS, PRM.
PDESC20APlan description.
MONDUES7P 2Monthly recurring dues rate.
PTINCL3S 0PT sessions bundled free per month.

Seeded catalog (FHPLNLD): BAS “Basic Monthly” 39.99 / 0 PT; PLS “Plus Monthly” 59.99 / 1 PT; PRM “Premium Monthly” 99.99 / 4 PT.

FHAGREE — Membership agreements (key AGRNO)

FieldTypeMeaning
AGRNO8AAgreement number (key), e.g. A0000001.
MBRNO6AOwning member.
PLANCD3APlan link (→ FHPLAN).
STARTDT8S 0Agreement start date (YYYYMMDD).
TERMMO3S 0Contract term in months (0 = month-to-month).
FRZSTAT1AN not frozen, Y frozen.
FRZDT8S 0Date freeze began (0 if not frozen).
NEXTBILL8S 0Next dues billing date (YYYYMMDD, day always 01) — the recurring-billing cursor.
AGRSTAT1AO open/active, X cancelled.

FHCLASS — Classes / sessions (key CLSNO)

FieldTypeMeaning
CLSNO8AClass number (key).
CNAME20AClass name.
CDATE8S 0Session date.
CINSTR / CROOM15A / 8AInstructor / room.
CAPMAX3S 0Seat capacity.
CAPCNT3S 0Current booked count (maintained by FHBOOK1).
CSTAT1AClass status.

FHBOOK — Bookings / check-ins (key BOOKNO)

FieldTypeMeaning
BOOKNO8S 0Booking number (key; deterministic ascending sequence).
MBRNO / CLSNO6A / 8AMember / class.
BOOKDT / CKINDT8S 0Booked date / check-in date.
BSTAT1AB booked, C checked-in, X cancelled.

FHPTPKG — PT packages (key PKGNO)

FieldTypeMeaning
PKGNO8APackage number (key).
MBRNO6AOwning member.
SESSBUY3S 0Sessions purchased.
SESSUSE3S 0Sessions used to date (drawn down by FHPTUSE).
PKGPRC9P 2Total package price = deferred-revenue liability at purchase.
PKGSTAT1AO open (sessions remain), X exhausted/closed.

FHPTUSG — PT usage events (key USGSEQ)

FieldTypeMeaning
USGSEQ8S 0Usage-event sequence (key).
PKGNO / MBRNO8A / 6APackage / member.
USGDT8S 0Session date.
USGAMT9P 2Revenue recognized for this session (PKGPRC/SESSBUY, residual swept on the last).

FHLEDG — Member ledger / A/R audit trail (key LEDGSEQ, UNIQUE)

FieldTypeMeaning
LEDGSEQ8S 0Ledger sequence (key). Assigned from a per-program disjoint band (section F.2) so keys never collide and writes append.
MBRNO6AMember.
LTYPE1AD dues, P payment, F fee, R PT revenue.
LDT8S 0Ledger date.
LAMT9P 2Amount.
LMEMO20AMemo (e.g. DUES A0000001, AUTOPAY RCPT, LATE FEE, PT USE PKG00001).

FHRCPT — Receipts / auto-pay input (key RCPTNO)

FieldTypeMeaning
RCPTNO8S 0Receipt number (key).
MBRNO6AMember.
RCPTDT8S 0Receipt date.
RCPTAMT9P 2Receipt amount (applied against MBAL).
RTYPE1AA auto-pay, M manual.

FHGLF — GL posting feed (DB2 SQL table)

FieldTypeMeaning
BATCHIDCHAR(8)Posting batch id (GLB00001).
ACCTCHAR(6)GL account (section F.3).
DRCRCHAR(1)D debit, C credit.
AMTDECIMAL(11,2)Posting amount.
SRCPGMCHAR(8)Source program (FHGLPST).

Logical files & access paths

Relationships

E. Operations Runbook ↑ top

E.1 Day-in-the-life

  1. Ensure the library list includes FITHUB and the batch queue exists (CRTJOBQ JOBQ(FITHUB/NITEQ), once).
  2. Handle interactive work as it arrives: CALL FITHUB/FHMENU for inquiries; CALL FITHUB/FHMNT PARM(...) to create/change members and agreements or freeze/unfreeze; CALL FITHUB/FHBOOK1 PARM(...) to book/check-in/cancel; CALL FITHUB/FHPTUSE PARM(...) to recognize a PT session.
  3. Load the day's receipts into FHRCPT, then submit the daily cycle: SBMJOB CMD(CALL FITHUB/FHDAILY) JOBQ(FITHUB/NITEQ).
  4. Post-check the auto-pay run (below).

Pre-checks: confirm the plan catalog is loaded (FHPLNLD ran; BAS/PLS/PRM present); confirm the job's library list includes FITHUB.

Post-checks after the daily cycle:

E.2 Month-end & period close

  1. Monthly dues. Submit FHMONTH (bills the whole backlog via the '99999999' sentinel), or drive a specific cutoff: SBMJOB CMD(CALL FITHUB/FHDUES PARM('<YYYYMMDD>')). Confirm FHDUES BILLED=/FROZEN-SKIPPED=/PRORATED= matches expectation and statements printed (FHDUESPR PRINTED=).
  2. Period close. Submit FHPERIOD (FHDUNNINGFHPTUSEFHGLPST); recognize outstanding PT sessions with FHPTUSE before the GL post. Confirm FHGLPST IN BALANCE ... COMMITTED.
  3. Cross-check. CALL FITHUB/FHGLRPT and confirm CROSS-CHECK: IN BALANCE.
  4. Review and reconcile the GL feed:
SELECT ACCT, DRCR, SUM(AMT) FROM FITHUB.FHGLF GROUP BY ACCT, DRCR ORDER BY ACCT, DRCR;

Reconciling figures (the same ones the daycycle simulation checks against a hand-derived oracle; note RPG division truncates):

E.3 Failure & re-run rules

Each program DSPLYs a one-line result (section F.5). The critical safety points are the ledger key bands (no cross-program collisions), the freeze/NEXTBILL cursor discipline, and the dunning guard.

SituationBehaviourAction
Re-run FHDUES same period, no calendar advanceNot naturally idempotent: anything still NEXTBILL ≤ PRUNDT re-bills (by design — the job is scheduled once per period).Do not re-invoke FHDUES for the same billing month without advancing the cutoff. Within one invocation each due agreement is billed exactly once (the forward *LOVAL scan advances NEXTBILL).
Re-run FHDUES at an earlier cutoffBills nothing new (every NEXTBILL now > cutoff).Safe no-op — the daycycle test verifies this.
Unfreeze after a frozen periodFreeze never advanced NEXTBILL, so billing resumes from the same date — no backlog, no gap.Unfreeze (FHMNT UF), then run FHDUES normally.
Re-run FHDUNNING same periodA member already MSTAT='D' is not re-flagged/re-feed.Safe: only a fresh 'A'→over-threshold crossing assesses a new fee.
Re-run a posting program (FHDUES/FHAUTOPAY/FHDUNNING)The high-water LEDGSEQ scan resumes above the last key in this program's band, so a second run never collides with the first's rows.Safe re-key; watch the DSPLY counts for double-posting from a same-period re-run.
FHPTUSE on an exhausted packageRejected (PACKAGE ALREADY EXHAUSTED); PKGSTAT already 'X'.Naturally idempotent — a package recognizes at most SESSBUY sessions, summing to PKGPRC.
FHGLPST debits ≠ creditsROLLBACK; no FHGLF rows committed.Investigate the ledger totals, correct, and re-post. The commitment-control gate prevents an unbalanced batch.
FHAUTOPAY NOMEMBER>0A receipt's MBRNO had no member; that receipt is skipped (no ledger row).Fix the receipt's member reference and re-run only those receipts.
Because every money movement is journaled to FHLEDG (and FHAGREE status changes to FHJRN), any cycle's effect is fully reconstructable after the fact for reconciliation and recovery (DSPJRN JRN(FITHUB/FHJRN) FILE(FITHUB/FHLEDG)).

F. Developer Reference ↑ top

The complete program surface, from fitness-app/src/sources.mjs. All objects are in library FITHUB.

F.1 Programs (12 RPG + 1 COBOL + 4 CL)

FHPLNLD (RPGLE) — plan-catalog loader
WRITEs the three reference plans (BAS 39.99/0PT, PLS 59.99/1PT, PRM 99.99/4PT) into FHPLAN. Called from FHSETUP.
FHMNT (RPGLE) — member/agreement maintenance
dcl-pi *ENTRY callable. Actions MC/AC/MI/FZ/UF (section B.3). Validate-before-write; re-CHAIN immediately before each UPDATE. Returns pOutFound and pOutMsg.
FHDUES (RPGLE) — recurring dues billing
Forward SETLL *LOVAL/READ over FHAGEL (NEXTBILL order); skips frozen (no NEXTBILL advance), pro-rates the first partial month, bills full months otherwise; raises MBAL, writes 'D' ledger row, advances NEXTBILL +1 month on FHAGREE. PARM PRUNDT cutoff.
FHBOOK1 (RPGLE) — booking / check-in / cancel
dcl-pi *ENTRY callable. Actions BK/CI/CX; capacity-checked booking (CAPCNT vs CAPMAX), cancel decrements CAPCNT. BOOKNO from a whole-file high-water scan.
FHAUTOPAY (RPGLE) — receipt posting
One pass over FHRCPT; MBAL = MBAL − RCPTAMT, writes 'P' ledger row. LEDGSEQ band 20000000.
FHDUNNING (RPGLE) — dunning + late fee
Forward pass over FHMEMBR; active member with MBAL > WTHRESH (0.00) → MSTAT='D', +WLATEFEE (15.00), 'F' ledger row. Guard: already-'D' not re-feed. PARM PRUNDT.
FHPTUSE (RPGLE) — PT usage + revenue recognition
dcl-pi *ENTRY callable. Per-session amount PKGPRC/SESSBUY; final session sweeps the residual and sets PKGSTAT='X'. Writes an FHPTUSG event and an FHLEDG 'R' row; does not touch MBAL. Rejects not-found / already-exhausted.
FHGLPST (SQLRPGLE) — GL posting, commitment control
ctl-opt commit(*yes). Sums FHLEDG by LTYPE, inserts balanced DR/CR rows (section F.3), then re-reads the batch: COMMIT if DR=CR, else ROLLBACK.
FHDUESPR (RPGLE) — dues-statement print
Forward pass over FHLEDG; for each 'D' row, CHAIN FHMEMBR and write the FHDUESP statement lines to spool.
FHMBRIQ (RPGLE) — member inquiry (plain WORKSTN)
CHAIN FHMEMBR by IMBRNO, then FHAGRML for the member's agreement (plan/freeze/next-bill); redisplay.
FHLEDIQ (RPGLE) — ledger inquiry (subfile)
CHAIN FHMEMBR; SFLCLR then load the member's FHLEDML rows into LSFL. Indicators 41/42/43/44 = SFLDSP/SFLDSPCTL/SFLCLR/SFLEND.
FHMENU (RPGLE) — operator menu
Reads MOPT; indicator-conditioned dynamic CALL 'FHMBRIQ' (opt 1) / 'FHLEDIQ' (opt 2).
FHGLRPT (CBLLE) — COBOL GL cross-check
Reads FHMEMBR (COMP-3 FD) totalling balances; embedded SQL sums dues+fees from FHLEDG and the A/R debit from FHGLF; DISPLAYs IN BALANCE / OUT OF BALANCE.
FHSETUP / FHMONTH / FHDAILY / FHPERIOD (CLP)
Setup (build/journal/authority/seed) and the three cycle drivers (section C).

F.2 Ledger key bands (the collision-free durable ledger)

FHLEDG is UNIQUE-keyed so writes append instead of truncating on OPEN. Each posting program seeds its LEDGSEQ from a disjoint band and, at start, does a high-water scan of that band to resume above the last key it wrote — so a second same-period run never collides with the first run's rows.

ProgramLedger typeLEDGSEQ band
FHDUESD (dues)10000000 – 10999999
FHAUTOPAYP (payment)20000000 – 20999999
FHDUNNINGF (late fee)30000000 – 30999999
FHPTUSER (PT revenue)40000000 +

F.3 GL account map (FHGLPST postings)

Ledger sourceDebitCredit
Dues ('D')120000 A/R400000 Dues Revenue
Auto-pay ('P')100000 Cash120000 A/R
Late fee ('F')120000 A/R410000 Fee Revenue
PT usage ('R')230000 PT Package Liability420000 PT Revenue

PT usage debits the package-liability account (not A/R) because the member already paid cash for the package at purchase (booked as a liability then); recognizing revenue as sessions are used draws that liability down.

F.4 Notable idioms & conventions

F.5 Program result messages (DSPLY)

ProgramResult line
FHDUESFHDUES BILLED=n FROZEN-SKIPPED=n PRORATED=n
FHDUESPRFHDUESPR PRINTED=n
FHAUTOPAYFHAUTOPAY POSTED=n NOMEMBER=n
FHDUNNINGFHDUNNING FLAGGED=n
FHMNTFHMNT <action> <MEMBER CREATED / CHANGED / AGREEMENT FROZEN / ...>
FHBOOK1FHBOOK1 <action> <BOOKED / CHECKED IN / CANCELLED / CLASS FULL / ...>
FHPTUSEFHPTUSE <pkgno> <SESSION RECOGNIZED / PACKAGE ALREADY EXHAUSTED / PACKAGE NOT FOUND>
FHGLPSTFHGLPST IN BALANCE DR=.. CR=.. COMMITTED / OUT OF BALANCE .. ROLLED BACK
FHGLRPTFHGLRPT MEMBERS n TOTBAL a, DUES+FEES a, GLAR a, CROSS-CHECK: IN BALANCE

G. Glossary ↑ top

Agreement (membership agreement)
The member→plan link (FHAGREE) carrying the recurring-billing cursor (NEXTBILL), freeze state, and term. One member may hold agreements over time.
Auto-pay
Applying a cash receipt (FHRCPT) against the member's running balance (FHAUTOPAY), writing a 'P' ledger row. RTYPE 'A' auto-pay vs 'M' manual.
Commitment control
DB2 transaction scope (commit(*yes)). FHGLPST posts GL rows, checks balance, and COMMITs only if debits equal credits, else ROLLBACKs.
Deferred revenue / PT-package liability
A PT package's price is a liability at purchase (cash received, service owed); recognizing revenue session-by-session draws the liability (account 230000) down.
Delinquency threshold (WTHRESH)
The balance above which dunning flags an active member delinquent and assesses a late fee. Seeded 0.00.
Dunning
The collections pass (FHDUNNING) that flags over-threshold members MSTAT='D' and assesses a flat late fee (WLATEFEE, 15.00), once per crossing.
Freeze / pause-resume
Suspending an agreement's billing (FRZSTAT='Y'). FHDUES skips it and does NOT advance NEXTBILL, so an unfreeze resumes from the same date with no backlog and no gap.
Ledger (running-account ledger)
The durable UNIQUE-keyed FHLEDG audit trail of every dues/payment/fee/PT-revenue movement, keyed by disjoint LEDGSEQ bands so writes append across the cycle chain.
NEXTBILL (billing cursor)
The agreement's next dues billing date (day always 01), advanced one calendar month per bill; the field FHAGEL is keyed on to drive billing in due order.
Pro-ration (first-month)
Charging only the partial first month when an agreement starts mid-month: MONDUES × remaining-days / days-in-month, truncated to cents. Only the very first bill, only if the start day isn't the 1st.
Revenue recognition (PT)
Recognizing PT-package revenue one session at a time (PKGPRC/SESSBUY), with the final session sweeping the rounding residue so recognized revenue sums to PKGPRC exactly.
Running account
A single balance per member (MBAL) that dues raise and payments reduce (may go negative — a credit balance), rather than a per-invoice A/R.
SBMJOB / *JOBQ
Submit Job to a job queue — the IBM i idiom for queuing the cycle drivers so each program closes its output files before the next opens them (queue FITHUB/NITEQ).
Subfile
A 5250 display construct listing many rows on one screen (DDS SFL/SFLCTL). FHLEDIQ's ledger list is the app's one subfile.