REALTY/i — Property Management: Leases, Rent Roll & Tenant Ledger

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

REALTY/i is a property-management application: a property/unit inventory, tenant and lease master, a monthly rent-roll charge run, daily cash-receipt application against the tenant ledger, a period AR ageing run with late-fee assessment, a lease-expiry sweep, an owner-distribution calculation, and a balanced GL feed with an AR control report. It is built as a classic IBM i application — RPG and ILE COBOL over keyed physical/logical files, DDS display and printer files, an SQL GL distribution table, and CL job cycles — and the money-moving programs enforce a single hard invariant: a lease's AR balance moves only by the charge run (up) and cash application (down). This manual is the reference for the operator who runs the online screens and the periodic cycles, and for the developer maintaining the application. It is grounded entirely in the committed source (property-app/src/sources.mjs, src/seed.mjs, and the test/rl_build.mjs / test/rl_cycle.mjs drivers). Everything runs in library REALTY.

Contents

A. Overview & Architecture ↑ top

A.1 What it does

REALTY/i services the full month of a small property book — two properties (Riverside Court, Oakwood Plaza), seven units, five tenants, five active leases, two owners in the seeded book:

A.2 Layered architecture: keyed-file RPG/COBOL with an SQL GL edge

The application is a conventional IBM i keyed-file design with one SQL edge:

The design deliberately mirrors the sibling order-app (ORDERIS/i): the ledger/receipt/balance model follows OEAROP/OECASH/OECUST, and the durable history file RLHIST mirrors OESHIS — one accumulating audit trail every posting program contributes to, with disjoint numeric key ranges per program derived from a stable business key, which is what makes every cycle idempotent (Section F.2).

A.3 Component & flow

  ONLINE                     BATCH CYCLES (CL-driven)
  ------                     ------------------------
  RLMENU (5250 menu)         RLDAILY  -> RLCASHAP          (cash application)
    opt 1 -> RLUNTIQ         RLMONTH  -> RLCHRUN           (rent + CAM charge run)
    opt 2 -> RLLEDIQ         RLPERIOD -> RLLATE            (ageing + late fees)
                                      -> RLRENEW           (lease-expiry sweep)
       (inquiry only)                 -> RLDISTRB          (owner distribution)
                                      -> RLGLPST           (balanced GL post)
                                      -> RLARRPT           (AR control report)
              \                    /
               \                  /
                v                v
     RLLEASE (LBAL: AR balance)  <-- raised ONLY by RLCHRUN/RLLATE, lowered ONLY by RLCASHAP
        |  \
        |   +--> RLLEDG  (one row per charge: rent 'R' / CAM 'C' / late fee 'L')
        |   +--> RLHIST  (durable audit trail; every posting program appends)
        +------> RLDIST (owner distribution)   RLGLDIST (SQL GL distribution)

A single business event — say the monthly charge run — flows: RLMONTH calls RLCHRUN → RLCHRUN reads each active lease, writes a rent and a CAM row to RLLEDG, appends charge rows to RLHIST, and adds the total to RLLEASE.LBAL. The seeded charge period is 2026-09-01 and the period-run date is 2026-09-25 (constants inside the programs; see Section C).

A.4 Object inventory

ObjectTypeRole
RLPROPPFProperty master (building/complex).
RLUNITPFUnit master (composite key PROPID+UNITNO).
RLUNTLFLFUnits keyed by PROPID alone (rent-roll-by-property path).
RLTENPFTenant master.
RLLEASEPFLease master (carries LBAL, the AR balance).
RLLSULFLFLeases keyed by PROPID+UNITNO (unit-inquiry path).
RLLEDGPFTenant AR open-item ledger (the receivables sub-ledger).
RLLEDLFLFLedger keyed by CHGDUE (due-date ageing path).
RLRCPTPFCash receipts.
RLOWNPFOwner master (mgmt-fee & distribution %).
RLDISTPFOwner-distribution history.
RLHISTPFDurable audit trail (all posting programs append).
RLGLDISTSQL tableGL distribution (balanced DR/CR).
RLUNTD / RLLEDD / RLMENUDDSPFUnit inquiry / ledger subfile / main menu.
RLAGEPPRTFAR ageing / owner report printer file.
RLREFLDRPGLESeed reference data (properties/units/tenants/leases/owners).
RLCHRUNRPGLEMonthly rent-roll charge run.
RLCASHAPRPGLEDaily cash-receipt application.
RLLATERPGLEPeriod AR ageing + late-fee assessment.
RLDISTRBRPGLEPeriod owner distribution.
RLGLPSTSQLRPGLEPeriod GL post (balanced DR/CR).
RLRENEWRPGLEPeriod lease-expiry sweep.
RLUNTIQ / RLLEDIQ / RLMENURPGLEUnit inquiry / ledger inquiry / menu drivers.
RLARRPTCBLLEAR control report (ILE COBOL).
RLSETUPCLPCreate every object & compile every program.
RLDAILY / RLMONTH / RLPERIODCLPThe three job cycles.

The full catalogue is 9 PFs + 3 LFs + 1 SQL table + 3 DSPF + 1 PRTF, driven by 10 RPG programs, 1 ILE COBOL program and 4 CL programs, all seeded into library REALTY by seedRealty(). Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

REALTY/i has no CICS transaction identifiers. On IBM i each program is reached by name from a 5250 command-entry line (or a JOBQ/scheduler for the batch cycles). Before invoking anything the job's library list must include REALTY — the tested jobs run with LIBL = QSYS QGPL REALTY QTEMP and CURLIB = REALTY. The online surface is inquiry-only (a main menu that dispatches to two inquiry programs); every money-moving action is a batch program driven by a CL cycle.

To do thisType on the command line
Open the main menu (unit inquiry / ledger inquiry)CALL REALTY/RLMENU
Open the unit / lease inquiry directlyCALL REALTY/RLUNTIQ
Open the tenant-ledger subfile inquiry directlyCALL REALTY/RLLEDIQ
Run the daily cash cycleCALL REALTY/RLDAILY (or SBMJOB it)
Run the monthly rent-roll cycleCALL REALTY/RLMONTH
Run the period-end cycleCALL REALTY/RLPERIOD
(Re)build every object & programCALL REALTY/RLSETUP
Seed the reference dataCALL REALTY/RLREFLD

The batch drivers take no CALL parameters. Rather than a control-row date, each posting program carries its processing date as a program constant in its source (the charge run posts for WPERDT = 20260901; the period programs run for WRUNDT = 20260925). A production reschedule for a new period is therefore a source-constant change and recompile, not a data update — an honest reflection of how this teaching application is written.

B.2 The inquiry screens (RLMENU / RLUNTIQ / RLLEDIQ)

RLMENU (DDS RLMENUD) is a plain menu: option 1 calls RLUNTIQ, option 2 calls RLLEDIQ, any other non-blank option shows Invalid option.; F3 exits.

RLUNTIQ — Unit / Lease Inquiry (plain DSPF)

A non-subfile screen. The operator keys a property and unit; the program CHAINs the unit master, then walks the unit's leases via the RLLSULF (PROPID+UNITNO) access path to find the current active lease, chains the tenant for the name, and displays the derived total monthly charge (rent + CAM) and the lease's AR balance.

Unit / Lease Inquiry - REALTY/i Property . . . : P00001 Unit . . . . . : 0101 Description . : ONE BED FLAT Status . . . . : O Lease number . : L0000001 Tenant . . . . : ALDEN, MARIA Monthly rent . : 850.00 Monthly CAM . : 45.00 Total monthly : 895.00 Lease balance : 0.00 Unit and lease found. F3=Exit Enter=Inquire
FieldType (DDS)Shows
IPROP / IUNIT6A / 4A inputProperty and unit keyed by the operator.
DDESC / DUSTAT20A / 1A outputUnit description and status (V/O/N).
DLEASE / DTEN8A / 30A outputCurrent active lease number and tenant name.
DRENT / DCAM / DTOT14A outputContracted rent, CAM, and their sum (%editc 'K').
DBAL14A outputLease AR balance (LBAL).
DMSG50A outputResult line (unit not found / no current lease / found).

RLLEDIQ — Tenant Ledger Inquiry (subfile)

The app's subfile screen (DDS RLLEDD: record LSFL under control record LCTL, SFLPAG(5) / SFLSIZ(20), ROLLUP/ROLLDOWN paging). The operator keys a lease number; the program chains the lease and tenant, then walks the lease's ledger via RLLEDG's own primary key (which starts with LEASENO), loading one subfile row per charge. The subfile is cleared and reloaded on every pass, and SFLDSP is driven from *IN31 so the list displays only once at least one row has loaded — the same subfile-refresh discipline as the sibling order-app's OEORDIQ.

Tenant Ledger Inquiry - REALTY/i Lease number: L0000002 Tenant . . . . : BRUNSWICK, JAMES Lease balance : 715.00 Seq Ty Description Amount Open Age 1 R MONTHLY RENT 1100.00 600.00 1 2 C CAM CHARGE 60.00 60.00 1 3 L LATE FEE ASSESSED 55.00 55.00 0 Lease found. F3=Exit Roll=Page Enter=Inquire
FieldType (DDS)Shows
ILEASE8A inputLease number keyed by the operator.
DLTEN / DLBAL30A / 14A outputTenant name and lease AR balance.
SSEQ / STYPE5S / 1A outputCharge sequence and type (R/C/L).
SDESC25A outputCharge description (MONTHLY RENT / CAM CHARGE / LATE FEE ASSESSED).
SAMT / SOPEN12A outputCharge amount as raised / outstanding open amount.
SAGE1A outputAgeing bucket stamped by RLLATE (0/1/2/3).
Both inquiry screens are read-only. Neither posts a charge, applies cash, nor edits a balance — those happen only in the batch programs (Section C). The screens exist to look up a unit's current lease and to read a lease's open-item ledger.

B.3 Controls & audit workflow (no online maker–checker)

Honest statement: REALTY/i does not model a four-eyes maker–checker / separate-authorization workflow, and the online screens post nothing at all. There is no "one user posts, a second approves" step in the code. The control model the application does have is enforced in the batch/data layer:

In sum, the control posture is durable audit + a strict AR balance invariant + per-run idempotency + status gating + balanced double-entry, all in the batch and data layers, rather than an online segregation-of-duties approval workflow.

C. Batch Jobs & the Periodic Cycle ↑ top

REALTY/i's servicing runs as three CL-driven cycles rather than one monolithic nightly job: a daily cycle (cash application), a monthly cycle (the rent-roll charge run), and a period cycle (ageing + late fees → lease-expiry sweep → owner distribution → GL post → AR control report). Each CL ADDLIBLE REALTY, CALLs its programs in a fixed order, and sends a completion banner. All batch programs take no CALL parameters and carry their processing date as a program constant.

-- the three cycles are bare parameterless submissions
SBMJOB CMD(CALL PGM(REALTY/RLMONTH))  JOB(RLMONTH)   rent-roll charge run
SBMJOB CMD(CALL PGM(REALTY/RLDAILY))  JOB(RLDAILY)   cash-receipt application
SBMJOB CMD(CALL PGM(REALTY/RLPERIOD)) JOB(RLPERIOD)  ageing/renewal/distribution/GL/AR

C.1 Full batch program set

ProgramCyclePurposeReads / writesDSPLY line
RLREFLDsetup Seed reference data. Writes RLPROP/RLUNIT/RLTEN/RLLEASE/RLOWN. RLREFLD PROP=2 UNIT=7 TEN=5 LEASE=5 OWN=2
RLCHRUNRLMONTH Rent-roll charge run: rent + CAM per active lease. Reads RLLEASE; writes RLLEDG (R/C), RLHIST; raises RLLEASE.LBAL. RLCHRUN CHARGED=n SKIP=n
RLCASHAPRLDAILY Apply each unapplied receipt to its named charge. Reads RLRCPT; updates RLLEDG open/status, RLRCPT status; lowers RLLEASE.LBAL; writes RLHIST (P). RLCASHAP APPLIED=n SKIP=n
RLLATERLPERIOD Age every open charge; assess ≤1 late fee per lease past grace. Updates RLLEDG.CHGAGE; writes late-fee RLLEDG (L) + RLHIST (L); raises RLLEASE.LBAL. RLLATE B0=n B1=n B2=n B3=n FEES=n
RLRENEWRLPERIOD Expire past-LEND active leases; flag near-expiry units on notice. Updates RLLEASE.LSTAT (→X), RLUNIT.USTAT (→V / N). RLRENEW EXPIRED=n NOTICE=n SAME=n
RLDISTRBRLPERIOD Per owner: distribute cash collected, less mgmt fee. Reads RLOWN, sums RLHIST 'P' rows for the owner's property; writes RLDIST, RLHIST (D). RLDISTRB DIST=n SKIP=n
RLGLPSTRLPERIOD Post balanced DR/CR into the SQL GL distribution. Reads RLHIST; EXEC SQL INSERT into RLGLDIST. RLGLPST BATCH=202609 ROWS=n
RLARRPTRLPERIOD AR control report over the ledger (ILE COBOL). Reads RLLEDG sequentially. RLARRPT RAISED/OPEN/ITEMS/OVERDUE

C.2 Daily / monthly / period detail

Monthly — RLMONTH → RLCHRUN

For every LSTAT='A' lease, RLCHRUN posts a rent charge (CHGTYPE='R', MONTHLY RENT) and a CAM charge ('C', CAM CHARGE) to RLLEDG for period 20260901 (due 20260901), each with its own ledger sequence and its own RLHIST row, then adds LRENT + LCAM to the lease's LBAL. It finds the next ledger sequence with a SETLL/READE partial-key walk of the lease's existing charges. Idempotent: the history key is 10000000 + leaseDigits×10 + type (rent 0, CAM 1), so a same-period re-run is refused by the CHAIN(EN) guard.

Expected DSPLY (5 active leases, first run):
  RLCHRUN CHARGED= 5 SKIP= 0

AR invariant after the run (LBAL raised by rent+CAM):
  L0000001 -> 895.00   L0000002 -> 1160.00   L0000003 -> 1160.00
  L0000004 -> 2350.00  L0000005 -> 1710.00        (10 ledger rows total)

Daily — RLDAILY → RLCASHAP

RLCASHAP reads every RCSTAT='U' receipt, CHAINs the ledger charge it names by the composite key (LEASENO,RCCHGSQ), and applies only what is owed: wtake = min(RCAMT, CHGOPEN). It reduces CHGOPEN (marking the charge CHGSTAT='P' when fully applied), lowers the lease's LBAL by exactly wtake, writes a negative RLHIST 'P' row, and stamps the receipt 'A' (fully) or 'P' (part). Idempotent: history key 20000000 + receiptDigits.

Seeded receipts (RCDT 20260910): RC000001 pays L1 rent 850.00 full,
RC000002 pays L1 CAM 45.00 full, RC000003 pays 500.00 of L2 rent (1100 open).
  RLCASHAP APPLIED= 3 SKIP= 0
  L0000001 -> 0.00   (895.00 fully settled)     L0000002 -> 660.00 (1160.00 - 500.00)
  L0000002 rent charge open falls 1100.00 -> 600.00; L1 rent+CAM open 0, status P

Period — RLPERIOD → RLLATE, RLRENEW, RLDISTRB, RLGLPST, RLARRPT

Run date 20260925 throughout. Days overdue use a 30/360 date serial: ((yyyy×12 + mm)×30 + dd), so charges due 20260901 are 24 days overdue.

Expected period DSPLY (after the monthly + daily runs above):
  RLLATE B0= 0 B1= 8 B2= 0 B3= 0 FEES= 4     8 open charges aged, 4 late fees (L2..L5)
  RLRENEW EXPIRED= 1 NOTICE= 0 SAME= ...      L0000002 (LEND 20260831) expires; unit 0102 -> V
  RLDISTRB DIST= 1 SKIP= 1                     Riverside distributes; Oakwood collected nothing
  RLGLPST BATCH=202609 ROWS= 4                 DR receivable + 3 CR revenue lines
  RLARRPT ITEMS 00014                          10 charges + 4 late fees

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library REALTY, grounded in the DDS members in sources.mjs. Dates are stored as signed integers in YYYYMMDD form (8S 0); money is packed decimal 11P 2; percentages (fees) are packed 5P 2. Key fields are noted per file.

RLPROP — Property master (key PROPID)

FieldTypeMeaning
PROPID6AProperty id (key), e.g. P00001.
PNAME / PADDR / PCITY30A/30A/20AName, address, city.
PUNITS5S 0Unit count (informational).
PSTAT1AProperty status (A active).

RLUNIT — Unit master (composite key PROPID, UNITNO)

FieldTypeMeaning
PROPID / UNITNO6A / 4AOwning property + unit number (composite key).
UDESC20AUnit description (e.g. ONE BED FLAT, RETAIL UNIT A).
USQFT6S 0Square footage.
URENT / UCAM11P 2STANDING (list) monthly rent / CAM — the lease may carry different contracted figures.
USTAT1AV vacant, O occupied, N notice-to-vacate.

RLTEN — Tenant master (key TENNO)

FieldTypeMeaning
TENNO6ATenant number (key), e.g. T00001.
TNAME / TPHONE30A / 14ATenant name and phone.
TSTAT1ATenant status (A active).

RLLEASE — Lease master (key LEASENO)

FieldTypeMeaning
LEASENO8ALease number (key), e.g. L0000001.
PROPID / UNITNO / TENNO6A/4A/6AThe property, unit and tenant this lease is for.
LSTART / LEND8S 0Lease start / end dates (YYYYMMDD).
LRENT / LCAM11P 2CONTRACTED monthly rent / CAM this lease actually posts.
LDEP11P 2Security deposit held at move-in (held, not AR).
LTERMS3S 0Grace-period days before a late fee applies.
LBAL11P 2Running AR balance — moved ONLY by charge/late-fee (up) and cash (down).
LSTAT1AN new, A active, X expired, T terminated.

RLLEDG — Tenant AR open-item ledger (composite key LEASENO, CHGSEQ)

FieldTypeMeaning
LEASENO / CHGSEQ8A / 5S 0Lease + per-lease charge sequence (composite key).
CHGTYPE1AR rent, C CAM, L late fee.
CHGDT / CHGDUE8S 0Charge date / due date (YYYYMMDD).
CHGAMT11P 2Charge as raised (never changed after posting).
CHGOPEN11P 2Outstanding amount (CHGAMT less cash applied).
CHGAGE1S 0Ageing bucket stamped by RLLATE: 0/1/2/3.
CHGDESC25ADescription (MONTHLY RENT / CAM CHARGE / LATE FEE ASSESSED).
CHGSTAT1AO open, P part/fully-applied (set when CHGOPEN reaches 0).

RLRCPT — Cash receipts (key RCPTNO)

FieldTypeMeaning
RCPTNO8AReceipt number (key), e.g. RC000001.
LEASENO / RCCHGSQ8A / 5S 0The lease + ledger charge sequence this receipt names.
RCDT8S 0Receipt date (YYYYMMDD).
RCAMT11P 2Amount received.
RCAPPL11P 2Amount actually applied to the open charge.
RCSTAT1AU unapplied, A fully applied, P part-applied.

RLOWN — Owner master (key OWNID)

FieldTypeMeaning
OWNID6AOwner id (key), e.g. O00001.
ONAME30AOwner name.
PROPID6AProperty this owner owns.
ODISTPCT5P 2Owner's share of NET collected rent (%).
OMGMTPCT5P 2Management-fee % deducted before the owner's share.
OSTAT1AOwner status (A active).

RLDIST — Owner-distribution history (composite key OWNID, DISTSEQ)

FieldTypeMeaning
OWNID / DISTSEQ6A / 5S 0Owner + per-owner distribution sequence (composite key).
PROPID / DISTDT6A / 8S 0Property and distribution run date.
DISTGROSS11P 2Cash actually collected for the property this period.
DISTFEE11P 2Management fee withheld.
DISTNET11P 2Distributed (DISTGROSS − DISTFEE) — the balanced figure.

RLHIST — Durable audit trail (key HSEQ)

FieldTypeMeaning
HSEQ8S 0History key (unique). Disjoint ranges: charge 10M, cash 20M, late fee 30M, distribution 40M — derived from a stable business key.
LEASENO / HITEM8A / 8ALease affected / item (lease or owner) reference.
HTYPE1AR rent, C CAM, P payment, L late fee, D distribution.
HDT / HAMT8S 0 / 11P 2Date and amount (payment 'P' rows carry a negative amount).
HREF / HMEMO8A / 25AReference (receipt/property) and free-text memo.

RLGLDIST — SQL GL distribution (PK GLSEQ)

FieldTypeMeaning
GLSEQDECIMAL(8,0)GL sequence (PK).
GLBATCHDECIMAL(6,0)Post batch (e.g. 202609).
ACCT / DRCRCHAR(9) / CHAR(1)Account (1400-TAR, 4100-RENT, 4200-CAM, 4300-LATE) and D/C.
AMTDECIMAL(11,2)Posted amount.
GLREF / GLDTCHAR(8) / DECIMAL(8,0)Reference and post date. Index RLGLDACC on (ACCT, DRCR).

Logical files (alternate access paths)

LFOverKeyed byWhy it exists
RLUNTLFRLUNITPROPIDRead a whole property's units together (rent-roll by property) with a partial key.
RLLSULFRLLEASEPROPID, UNITNOFind a unit's current/most-recent lease without scanning the file (unit inquiry).
RLLEDLFRLLEDGCHGDUE, LEASENOWalk the ledger oldest-due-first for the ageing report without sorting.

Relationships

E. Operations Runbook ↑ top

E.1 Day-in-the-life

One-time (or on a rebuild): compile and stand up the application, then seed the reference book.

  1. Confirm the job's library list includes REALTY (LIBL = QSYS QGPL REALTY QTEMP, CURLIB = REALTY).
  2. Build every object & program: CALL REALTY/RLSETUP — expect the REALTY setup complete. banner.
  3. Seed reference data: CALL REALTY/RLREFLD — expect RLREFLD PROP=2 UNIT=7 TEN=5 LEASE=5 OWN=2.

Then, for a normal period:

  1. Charge run (start of month): SBMJOB CMD(CALL PGM(REALTY/RLMONTH)). Check the RLCHRUN CHARGED=n SKIP=n line and confirm each active lease's LBAL rose by exactly its rent + CAM.
  2. Cash application (daily): post receipts to RLRCPT as RCSTAT='U', then SBMJOB CMD(CALL PGM(REALTY/RLDAILY)). Check RLCASHAP APPLIED=n SKIP=n and confirm each paid lease's LBAL fell by exactly the applied amount.
  3. Inquiry as needed: CALL REALTY/RLMENU → option 1 (unit/lease) or 2 (ledger) to look up a unit's lease or a lease's open items.

Post-checks after cash application:

E.2 Period-end close

  1. Confirm the month's charge run and all cash application have completed.
  2. Submit the period cycle: SBMJOB CMD(CALL PGM(REALTY/RLPERIOD)). It runs, in order, RLLATERLRENEWRLDISTRBRLGLPSTRLARRPT, then sends the period-end banner.
  3. Review the GL distribution and the AR control report.
SELECT ACCT, DRCR, SUM(AMT) FROM REALTY.RLGLDIST GROUP BY ACCT, DRCR;
-- proves DR total = CR total
SELECT SUM(CASE WHEN DRCR='D' THEN AMT END) AS DR,
       SUM(CASE WHEN DRCR='C' THEN AMT END) AS CR FROM REALTY.RLGLDIST;

Reconciling figures (the same ones the cycle battle verifies against a hand-derived JS oracle, for the seeded book after the September charge run + the three seeded receipts):

E.3 Failure & re-run rules

Each program DSPLYs a one-line result. A cycle can be re-submitted whole; the idempotency guards make every posting a no-op the second time.

SituationBehaviourAction
Charge run re-run (same period)History key 10M+leaseDigits×10+type already exists; the CHAIN(EN) guard refuses it (counted in SKIP).Safe no-op. L0000001 stays 895.00, ledger stays 10 rows. Idempotent.
Cash application re-runReceipt history key 20M+receiptDigits already present.Safe no-op — APPLIED=0, no lease balance falls twice.
Cash names a missing chargeLedger CHAIN fails (*IN91); the receipt is skipped, not applied.Correct RCCHGSQ and re-run; the receipt is still U.
Late-fee run re-run (same run date)Late-fee history key 30M+leaseDigits exists.Safe no-op — no lease is fee'd twice. (Pass 1 re-ages harmlessly.)
Lease-expiry sweep re-runAn already-expired lease is LSTAT='X', no longer active, so it is not swept again.Naturally idempotent for a fixed book.
Owner distribution re-runOwner history key 40M+ownerDigits exists.Safe no-op — no second RLDIST row.
GL post re-runIncremental: it subtracts what is already debited to 1400-TAR, leaving nothing new.Safe no-op — ROWS=0, DR still equals CR.
Because every money movement is journaled to RLHIST (charge, cash, late fee, distribution) and every open item lives in RLLEDG, any cycle's effect is fully reconstructable after the fact for reconciliation and recovery — and the AR balance invariant plus the balanced GL/distribution give an independent cross-check on every figure.

F. Developer Reference ↑ top

The complete program surface, from property-app/src/sources.mjs. All objects are in library REALTY. The fixed-form RPG is generated with two column-exact helpers in sources.mjs (C() for C-specs, D() for D-specs), mirroring the ibmi/samples.js convention.

F.1 Programs

RLREFLD (RPGLE) — reference-data seed
Writes 2 properties, 7 units, 5 tenants, 5 active leases (all LBAL=0), 2 owners, then DSPLYs the seed counts. The one-time source of the seeded book every test and figure in this manual is grounded in.
RLCHRUN (RPGLE) — monthly rent-roll charge run
Reads RLLEASE (SETLL *LOVAL / READ); per active lease, finds the next CHGSEQ by a partial-key SETLL/READE walk, writes a rent and a CAM RLLEDG row and their RLHIST rows, then re-CHAINs the lease and adds WRENT+WCAM to LBAL. Idempotency guard on history key 10000000 + wdig×10 + type.
RLCASHAP (RPGLE) — daily cash-receipt application
Reads RLRCPT; for each U receipt CHAINs the named (LEASENO,CHGSEQ) ledger charge via a KLIST, applies min(RCAMT, CHGOPEN), updates the charge and receipt status, lowers LBAL, writes a negative RLHIST 'P' row. Guard on 20000000 + receiptDigits.
RLLATE (RPGLE) — period ageing + late fee
Pass 1: sequentially age every open charge (30/360 days overdue → bucket 0/1/2/3), update CHGAGE. Pass 2: per active lease, walk its open rent/CAM charges; if any exceeds the lease's LTERMS grace, write one L charge of LRENT×5%, an RLHIST 'L' row, and raise LBAL. Guard on 30000000 + leaseDigits.
RLRENEW (RPGLE) — period lease-expiry sweep
Per active lease: if LEND < run date, vacate the unit (via a PROPID+UNITNO KLIST CHAIN) and, after re-CHAINing the lease, set LSTAT='X'; if within 30 days of expiry, flag an occupied unit USTAT='N'. Counts EXPIRED / NOTICE / SAME.
RLDISTRB (RPGLE) — period owner distribution
Per active owner: sum the negated RLHIST 'P' rows whose lease belongs to the owner's property (cash actually collected), deduct OMGMTPCT, write a balanced RLDIST row (DISTGROSS = DISTFEE + DISTNET) and an RLHIST 'D' row. An owner with zero collected is skipped. Guard on 40000000 + ownerDigits.
RLGLPST (SQLRPGLE) — period GL post
Accumulates RLHIST by type (R/C/L), reads the current 1400-TAR debit total via EXEC SQL, and posts only the incremental movement: DR 1400-TAR, CR 4100-RENT/4200-CAM/4300-LATE, each via EXEC SQL INSERT into REALTY.RLGLDIST. A refused insert is not counted as a posted row.
RLRENEW / RLUNTIQ / RLLEDIQ / RLMENU (RPGLE)
The two inquiry drivers and the menu (Section B). RLLEDIQ is the subfile program; RLUNTIQ uses the RLLSULF access path to find a unit's active lease.
RLARRPT (ILE COBOL) — AR control report
Sequential READ of RLLEDG accumulating RAISED (LG-AMT), OPEN (LG-OPEN), item count, and overdue count (LG-AGE > 0); proves the receivables sub-ledger totals reconcile.
RLSETUP / RLDAILY / RLMONTH / RLPERIOD (CL)
RLSETUP DLTFs then CRTPF/CRTLF/CRTDSPF/CRTPRTF/RUNSQLSTM/CRTBNDRPG/CRTBNDCBL every member. The three cycle CLs ADDLIBLE REALTY and CALL the cycle's programs in order.

F.2 The AR invariant & idempotency

Two properties define the application's correctness and are asserted to the penny by test/rl_cycle.mjs:

ProgramHistory key formulaRange
RLCHRUN10000000 + leaseDigits×10 + type (rent 0, CAM 1)10M
RLCASHAP20000000 + receiptDigits20M
RLLATE30000000 + leaseDigits30M
RLDISTRB40000000 + ownerDigits40M

F.3 Access paths & file discipline

The three logical files are genuine alternate orderings, not decoration — the build test asserts each LF's leading key differs from its PF's:

One-record-format-per-program discipline. RLLATE deliberately does not open RLLEDLF alongside RLLEDG: two files sharing one record format cannot both be declared in the same program without a RENAME the emulator does not support, and the lease-keyed walk RLLATE needs is already RLLEDG's own primary key (which starts with LEASENO). This mirrors the sibling order-app's OEALLOC/OEINVGEN discipline. Several programs also re-CHAIN a master record after intervening ledger/history writes, because those writes move the file cursor; and RLRENEW sets LSTAT='X' only after the unit CHAIN, since a CHAIN reloads the whole record from disk and would otherwise discard an in-memory field.

F.4 Date-serial & embedded-SQL patterns

G. Glossary ↑ top

AR (accounts receivable) balance — LBAL
The running amount a lease owes, on RLLEASE.LBAL. Raised only by the charge run and late fees, lowered only by cash application — the invariant the tests assert.
Ageing bucket — CHGAGE
A classification of how overdue an open charge is at the run date: 0 current, 1 = 1–30, 2 = 31–60, 3 = 61+ days, stamped by RLLATE on the 30/360 convention.
CAM — Common Area Maintenance
A recurring charge (alongside rent) for shared-space upkeep. Posted as a separate ledger row (CHGTYPE='C') with its own revenue account 4200-CAM.
Charge run / rent roll
The monthly posting of every active lease's rent and CAM to the tenant ledger (RLCHRUN), raising each lease's AR balance.
Grace period — LTERMS
The number of days past a charge's due date before a late fee applies. Per lease (10, 15 or 5 days in the seeded book).
Idempotent
Safe to run again with the same result. Each posting program's stable history key + CHAIN(EN) guard (and the GL post's incremental logic) makes every cycle re-runnable.
Late fee
A charge assessed once per lease whose grace period is breached, at 5% of contracted rent (CHGTYPE='L', revenue 4300-LATE).
Lease-expiry sweep
The period pass (RLRENEW) that expires any active lease past its LEND and vacates its unit, and flags near-expiry units notice-to-vacate.
Management fee — OMGMTPCT
The percentage a property charges its owner, deducted from collected cash before the owner's distribution (DISTFEE).
Open item
A ledger charge with a non-zero outstanding balance (CHGOPEN > 0). Cash application reduces it; a fully-applied item is skipped by ageing and late fees.
Owner distribution
The period calculation (RLDISTRB) of what to pay each owner: cash collected less management fee, as a balanced RLDIST row (DISTGROSS = DISTFEE + DISTNET).
SBMJOB
Submit Job — the IBM i command that queues a program to run as a batch job (e.g. SBMJOB CMD(CALL PGM(REALTY/RLPERIOD))).
Subfile
A 5250 display construct listing many rows on one screen (DDS SFL/SFLCTL). RLLEDIQ's ledger list is a subfile with 5-per-page paging.
Tenant ledger — RLLEDG
The receivables sub-ledger: one open-item row per charge (rent, CAM, late fee), reduced as cash is applied.