HAULPRO/i — Waste Hauling / Disposal

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

HAULPRO/i is a solid-waste hauling and disposal back-office application: customer, service-location, container and route masters; recurring service schedules (the contract); a daily route run that creates service tickets for schedules due that day and logs the disposal/landfill tonnage tickets the hauler pays the tipping fee on; a monthly recurring billing run (contracted base rate × pickups + extra/unscheduled pickups + a fuel/environmental surcharge) into a customer invoice and AR ledger; and a period close that ages the ledger, assesses late fees, and posts revenue, disposal cost, late-fee income and AR to a GL feed. The commercial logic lives in fixed-form and free-form RPG (with one ILE COBOL reconciliation report and one SQLRPGLE GL poster); the three job cycles are CL drivers. This manual is the reference for the operator who runs the online screens and the daily / monthly / period cycles, and for the developer maintaining the application. It is grounded entirely in the committed source (waste-app/src/sources.mjs, src/seed.mjs, and the test/hp_build.mjs / hp_daily.mjs / hp_cycles.mjs drivers).

Contents

A. Overview & Architecture ↑ top

A.1 What it does

HAULPRO/i runs the back office of a commercial waste hauler:

A.2 The spine & the central invariant

The system's spine is a single chain:

Service schedule (recurring contract: location + container + frequency + base rate) → the daily route run creates service tickets for schedules due that day and logs the day's disposal tonnage/tipping-fee tickets → the monthly billing run sums a customer's tickets for the month (base rate × scheduled pickups, plus extra pickups, plus surcharge) into one invoice → posts to the customer ledger (AR) → the period close ages the ledger, assesses late fees, and posts the period's activity to the GL.

The invariant asserted throughout the tests: revenue side and cost side never mix on one row. A service ticket's route pickup is billed to the customer; a disposal ticket's landfill tipping fee is the hauler's own expense, tracked and GL-posted separately, never itemised to any customer. A customer's monthly invoice amount is exactly:

  IAMT = (schedule base rate x scheduled pickups this period)     = IBASE
       + (extra/unscheduled pickup count x extra-pickup rate)    = IEXTRA
       + ((IBASE + IEXTRA) x customer fuel/environmental pct)     = ISURCH

so the GL and the customer ledger always foot to the same billed amount, split three ways (base service revenue / extra-pickup revenue / surcharge revenue), with disposal cost tracked separately.

A.3 Component & flow

  SETUP / REFERENCE      ONLINE                 BATCH (periodic)
  -----------------      ------                 ----------------
  HLSETUP  (CL)          HLMENU (5250)          HLDAILY  ---> HLPICKUP  (service tickets)
    build all objects      opt 1 -> HLCUSTIQ                  HLDISPRUN (disposal tickets)
  HLREFLD  (RPG)          opt 2 -> HLLEDIQ      HLMONTH  ---> HLBILL    (invoice + AR ledger)
    seed masters                (subfile)       HLPRICL  ---> HLAGE     (aging -> late fees)
                                                             HLARRP   (COBOL AR reconcile)
                          \                    /             HLGLPST  (GL close)
                           \                  /
                            v                v
   HLSKED (the contract)  ->  HLTICK  ->  HLBILL  ->  HLINVH/HLINVL + HLLEDG (AR)
                              HLDISP  ------------->  HLGLFEED (GL)   HLAGE -> HLLEDG ('F')

A single daily event flows: operator runs HLDAILYHLPICKUP walks every active HLSKED row and writes one HLTICK (TKTYPE='S') per schedule → HLDISPRUN sums each active route's tickets for the day and writes one HLDISP tonnage/tipping-fee row. Monthly, HLBILL turns unbilled tickets into HLINVH/ HLINVL invoices and an HLLEDG 'I' row; the period close ages and posts to the HLGLFEED GL table.

A.4 Object inventory

ObjectTypeRole
HLCUSTPFCustomer master (surcharge pct, terms, AR balance).
HLLOCPFService-location master.
HLCONTPFContainer/dumpster master (size, type).
HLROUTEPFRoute / truck / driver master.
HLSKEDPFRecurring service schedule (the contract).
HLTICKPFService ticket (one per route pickup).
HLTKLFLFTickets by billed-status / location (billing path).
HLDISPPFDisposal/landfill tonnage ticket (hauler cost).
HLLEDGPFCustomer AR ledger (signed I/P/F rows).
HLLEDCFLFLedger by customer (aging / inquiry path).
HLINVH / HLINVLPFInvoice header / itemised lines.
HLINVLFLFInvoices by status (AR-aging path).
HLGLFEEDSQL tableGL feed the period close posts into.
HLCUSTD / HLLEDD / HLMENUDDSPFInquiry, ledger-subfile, menu screens.
HLINVPPRTFCustomer invoice statement printer file.
HLREFLDRPGLESeed reference/master data.
HLPICKUPRPGLEDaily: create scheduled service tickets.
HLDISPRUNRPGLEDaily: log disposal tonnage tickets.
HLBILLRPGLEMonthly: recurring service billing.
HLAGERPGLEPeriod: AR aging → late fees.
HLGLPSTSQLRPGLEPeriod: GL close (embedded SQL).
HLARRPCBLLEPeriod: COBOL AR reconciliation report.
HLCUSTIQ / HLLEDIQ / HLMENURPGLEOnline inquiry / ledger / menu drivers.
HLSETUPCLPCreate every object & compile every program.
HLDAILY / HLMONTH / HLPRICLCLPThe three job-cycle drivers.

The catalogue is 10 PFs, 3 LFs, 3 DSPFs, 1 PRTF and 1 SQL table, driven by 9 RPG programs, 1 ILE COBOL program and 4 CL programs. All objects live in library HAULPRO. Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

HAULPRO/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 cycles). 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 HAULPRO — the tested jobs run with LIBL = QSYS QGPL HAULPRO QTEMP and CURLIB = HAULPRO. The CL cycle drivers ADDLIBLE LIB(HAULPRO) themselves, so a bare CALL of a cycle is self-sufficient.

To do thisType on the command line
Open the main menu (routes to the two inquiries)CALL HAULPRO/HLMENU
Open customer inquiry directlyCALL HAULPRO/HLCUSTIQ
Open the customer ledger (subfile) inquiry directlyCALL HAULPRO/HLLEDIQ
Build every object & compile every program (first time)CALL HAULPRO/HLSETUP
Seed the reference/master dataCALL HAULPRO/HLREFLD
Run the daily route/disposal cycleCALL HAULPRO/HLDAILY (or SBMJOB it)
Run the monthly billing cycleCALL HAULPRO/HLMONTH
Run the period AR-aging / GL-close cycleCALL HAULPRO/HLPRICL

The batch programs take no CALL parameters. In this build each program's processing date / period is a literal set in working storage (e.g. wtoday = 20260915; in HLPICKUP, wperiod = 20260930; in HLBILL, wasof = 20261101; in HLAGE); a production build would read those from a control row or the system date. The daily and period cycle drivers chain more than one program (see section C); only the three inquiry programs are interactive.

B.2 The menu & inquiry screens

HAULPRO/i has three interactive programs, reached from the menu HLMENU (DDS HLMENUD): option 1 calls HLCUSTIQ, option 2 calls HLLEDIQ; F3 exits. Both inquiries loop on their own screen until F3.

Customer inquiry — HLCUSTIQ / HLCUSTD (plain screen)

A non-subfile screen: the operator keys a customer number and HLCUSTIQ CHAINs HLCUST, rendering the billing detail, a derived status description, and the current AR balance. Not found leaves a "Customer not found." message.

Customer Inquiry - HAULPRO/i Customer number: CU0001 Name . . . . . : RIDGEMONT SHOPPING PLAZA Bill to . . . : RIDGEMONT PLAZA AP DEPT FSC pct . . . : 8.00 Pay terms . . : 30 Status . . . . : ACTIVE AR balance . . : 297.00 Customer found. F3=Exit Enter=Inquire
Field (DDS)Shows
ICUSTInput customer number (6A).
DCNAME / DBILTOCustomer name and bill-to (from CNAME / CBILTO).
DFSC / DTERMFuel/enviro surcharge pct and payment terms (%editc-formatted CFSCPCT / CPAYTRM).
DSTATDDerived status: ACTIVE (A) / DELINQUENT (D) / CLOSED (C) / UNKNOWN.
DBALCurrent AR balance (CBAL, edited).

Customer ledger inquiry — HLLEDIQ / HLLEDD (subfile)

The app's subfile screen. HLLEDD defines a subfile record LSFL under control record LCTL with SFLPAG(5) / SFLSIZ(20) and ROLLUP/ROLLDOWN so paging is exercised. The operator keys a customer number; HLLEDIQ displays the screen, clears then reloads the subfile from HLLEDCF (the by-customer ledger access path), one row per ledger line, and shows a line count and running balance.

Customer Ledger - HAULPRO/i Customer number: CU0001 Lines . . . . : 2 Balance . . . : 326.46 Seq T Date Amount Memo 10000001 I 20260930 297.00 INVOICE CU000101 30000001 F 20261101 29.46 FEE CU000101 F3=Exit Roll=Page Enter=Inquire
Subfile fieldShows
TSEQLedger sequence (LEDGSEQ).
TTYPELedger type: I invoice, P payment, F late fee.
TDT / TAMTLedger date / signed amount (edited from LDT / LAMT).
TMEMOFree-text memo (e.g. INVOICE CU000101, FEE CU000101).
DLCNT / DLBALControl-line line count and running balance.
The subfile is loaded with the real refresh discipline the estate uses: display first (EXFMT LCTL), then set on indicator 31 and WRITE LCTL to clear (SFLCLR), then reload from the keyed access path — so a re-inquiry against a different customer shows fresh rows, not a stale load. The conditioning indicators in HLLEDD are written one column left of the standard DDS position to satisfy the emulator's DDS parser offsets (documented platform quirk HL-PLAT-001, cross-referencing FR-PLAT-001); operationally the screen behaves exactly as described.

B.3 Controls & audit workflow (no four-eyes maker–checker)

Honest statement: HAULPRO/i does not model a true four-eyes maker–checker / separate-authorization workflow. There is no "one user posts, a second user approves" step: the batch cycles post invoices, fees and GL rows directly, and the two online programs are read-only inquiries (they only CHAIN/READ masters and the ledger — no operator can key a maintenance action against a customer or invoice through the screens). The manual documents the control model the application does have:

In sum, the control posture is signed-ledger auditability + status/state gating + idempotency enforcement, plus an independent COBOL reconciliation, rather than a segregation-of-duties approval workflow.

C. Batch Jobs & the Periodic Cycle ↑ top

HAULPRO/i's work runs as three CL-driven cycles rather than one monolithic nightly job: a daily cycle (route pickups + disposal log), a monthly cycle (recurring service billing), and a period cycle (AR aging → late fees, COBOL reconciliation, and the GL close). Each cycle is a CL program that ADDLIBLE LIB(HAULPRO) then CALLs its RPG/COBOL/SQLRPGLE steps in order; a scheduled/JOBQ submission is a bare CALL or SBMJOB.

-- the three cycles, submittable bare (each ADDLIBLEs HAULPRO itself)
SBMJOB CMD(CALL PGM(HAULPRO/HLDAILY))  JOB(HLDAILY)
SBMJOB CMD(CALL PGM(HAULPRO/HLMONTH))  JOB(HLMONTH)
SBMJOB CMD(CALL PGM(HAULPRO/HLPRICL))  JOB(HLPRICL)

C.1 Full batch program set

ProgramCyclePurposeReadsWrites / DSPLY
HLREFLDSetup Seed masters: customers, locations, containers, routes, schedules. — (literals). HLCUST/HLLOC/HLCONT/HLROUTE/HLSKED; DSPLY HLREFLD CUSTOMERS=2 LOCATIONS=2 CONTAINERS=2 ROUTES=2 SCHEDULES=2.
HLPICKUPDaily (1) Create one scheduled service ticket per active schedule. HLSKED, HLCONT. HLTICK (TKTYPE='S'); DSPLY HLPICKUP CREATED=n SKIP=n.
HLDISPRUNDaily (2) Log one disposal tonnage/tipping-fee ticket per active route that had pickups. HLROUTE, HLTICK/HLTKLF. HLDISP; DSPLY HLDISPRUN LOGGED=n SKIP=n.
HLBILLMonthly Recurring service billing: base + extra + surcharge → invoice + AR ledger. HLCUST, HLLOC, HLSKED, HLTICK/HLTKLF. HLINVH/HLINVL, HLLEDG ('I'), rolls CBAL; DSPLY HLBILL BILLED=n SKIP=n.
HLAGEPeriod (1) AR aging: flag past-due invoices/customers delinquent, assess late fees. HLINVH/HLINVLF, HLCUST, HLLEDG. ISTAT→D, CSTAT→D, HLLEDG ('F'), rolls CBAL; DSPLY HLAGE FLAGGED=n ASSESSED=n.
HLARRPPeriod (2) COBOL: re-sum the ledger independently to reconcile CBAL. HLLEDG (sequential). DSPLY HLARRP INVOICED/LATEFEE/PAYMENTS/NET/LINES.
HLGLPSTPeriod (3) GL close: post revenue, late-fee income, disposal-cost pairs. HLLEDG, HLDISP, HLGLFEED (embedded SQL). HLGLFEED rows; DSPLY HLGLPST BATCH=n ROWS=n.

C.2 Daily / monthly / period detail

Daily — HLDAILY (HLPICKUP then HLDISPRUN)

HLPICKUP walks every active schedule (SKSTAT='A') and creates one scheduled ticket (TKTYPE='S') dated today. It derives the pickup weight deterministically from the container's size — TWEIGHT = CSIZE × 0.85 ton/yard (the fixed simplification in place of a live truck-scale feed) — and derives TICKNO = SKEDNO + last-2-digits-of-WTODAY so a re-run for the same day is idempotent (a CHAIN(EN) guard refuses the second attempt).

HLDISPRUN runs second, so today's tickets already exist. For each active route (RSTAT='A') it sums that route's tickets for today, looks up the route's per-ton tipping fee from a fixed table (RT0001 $45.00, RT0002 $50.00, any other route $40.00), and writes one disposal ticket DTAMT = DTWEIGHT × DTPFEE. A route with no pickups today writes nothing (idempotent-by-construction). DISPNO is derived the same way as TICKNO, so a same-day re-run logs nothing further.

Expected DSPLY (2 seeded schedules, one 6-yard on RT0001, one 8-yard on RT0002):
  HLPICKUP CREATED=2 SKIP=0    SK0001->5.10t, SK0002->6.80t
  HLDISPRUN LOGGED=2 SKIP=0    RT0001 5.10x45=229.50, RT0002 6.80x50=340.00
Re-run the same day:
  HLPICKUP CREATED=0 SKIP=2    HLDISPRUN LOGGED=0 SKIP=2

Monthly — HLMONTH (HLBILL)

HLBILL, for each active customer, walks the unbilled bucket of HLTKLF (TBILLED='N'), keeping only tickets at that customer's own service locations (a CHAIN to HLLOC checks CUSTNO). It splits scheduled (TKTYPE='S') from extra (TKTYPE='X') pickups:

Each ticket walked is flipped to TBILLED='Y' (which moves it out of the N bucket), so a re-run bills nothing — idempotent by construction. A customer with no unbilled tickets contributes nothing (no zero-dollar invoice). The invoice header (with three line rows: BASE, EXTRA if any, SURCHARGE) is written, an 'I' ledger row posted, CBAL rolled forward, and the due date computed as period + CPAYTRM (a numeric add on the YYYYMMDD-shaped integer, not a calendar rollover).

Expected DSPLY (2 customers; CU0001 has 1 scheduled + 1 planted extra, CU0002 1 scheduled):
  HLBILL BILLED=2 SKIP=0
    CU0001: BASE 180.00 + EXTRA 95.00 + SURCH 22.00 = 297.00   (FSC 8.00%, due 20260960)
    CU0002: BASE 220.00 + EXTRA  0.00 + SURCH 13.20 = 233.20   (FSC 6.00%, due 20260945)
Re-run same period:  HLBILL BILLED=0 SKIP=2

Period — HLPRICL (HLAGE, HLARRP, HLGLPST)

HLAGE makes one forward pass over open invoices (ISTAT='O' via HLINVLF). Any invoice whose IDUEDT is before the as-of date is past due: flip its ISTAT to 'D', flip the owning customer's CSTAT to 'D', and assess a late fee of $25.00 + 1.5% monthly interest on IAMT (a wide packed multiply, half-up biased with +0.005 then truncated to cents), posting an 'F' ledger row and rolling CBAL forward. An idempotency guard scans HLLEDG for an existing 'F' row already carrying this invoice's memo tag before assessing again, so a re-run assesses nothing.

HLARRP (COBOL) reads the ledger sequentially and sums 'I', 'F' and 'P' rows into invoiced, late-fee and payment totals plus a net — an independent reconstruction of what the customers owe.

HLGLPST (SQLRPGLE) posts three balanced GL pairs, each driven off rows not yet posted (a GLREF-already-present check via embedded SQL makes the whole close idempotent without a posted-flag column): revenue per 'I' ledger row (DR 1200-ARV / CR 4000-REV), late-fee income per 'F' row (DR 1200-ARV / CR 4800-FEE), and disposal cost per disposal ticket (DR 5000-DISP / CR 2000-APV).

Expected DSPLY (as-of 20261101; both invoices past due):
  HLAGE FLAGGED=2 ASSESSED=2      CU0001 fee 29.46, CU0002 fee 28.50
  HLARRP INVOICED 530.20  LATEFEE 57.96  PAYMENTS 0.00  NET 588.16  LINES 4
  HLGLPST BATCH=202610 ROWS=12    SUM(DR)=SUM(CR)=1157.66
Re-run:  HLAGE FLAGGED=0 ASSESSED=0   HLGLPST ... ROWS=0

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library HAULPRO, grounded in the DDS/SQL in src/sources.mjs. Dates are stored as signed numeric in YYYYMMDD form; money and rates are packed P decimal; the surcharge percentage is a packed 5P2 (8.00 = 8%).

HLCUST — Customer master (K CUSTNO, UNIQUE)

FieldTypeMeaning
CUSTNO6ACustomer number (key).
CNAME / CBILTO30A / 30ACustomer name / bill-to name.
CFSCPCT5P 2Fuel/environmental surcharge pct (contract term, per customer).
CPAYTRM3S 0Net payment terms, days.
CBAL11P 2Current AR balance (rolled by billing & aging).
CSTAT1AA active, D delinquent (set by aging), C closed.

HLLOC — Service location (K SLOC, UNIQUE)

FieldTypeMeaning
SLOC6AService-location number (key).
CUSTNO6AOwning customer.
SADDR / SCITY30A / 20AStreet address / city.
SSTAT1ALocation status.

HLCONT — Container/dumpster master (K CONTNO, UNIQUE)

FieldTypeMeaning
CONTNO6AContainer number (key).
CSIZE3S 0Yard capacity (2/4/6/8/20/30/40) — drives the derived pickup weight.
CTYPE1AF front-load, R roll-off.
CTLOC6AService location the container currently sits at.
CTSTAT1AContainer status.

HLROUTE — Route / truck / driver (K RTENO, UNIQUE)

FieldTypeMeaning
RTENO6ARoute number (key).
RTDESC20ARoute description.
TRUCKNO / DRVNO6A / 6ATruck / driver on the route.
RSTAT1AA active, H on hold, T terminated.

HLSKED — Recurring service schedule / the contract (K SKEDNO, UNIQUE)

FieldTypeMeaning
SKEDNO6ASchedule number (key).
SLOC / CONTNO / RTENO6A eachLocation, container and route this contract serves.
SKFREQ1AW weekly, X biweekly (twice weekly), M monthly — drives which day a ticket is created, not the billed amount.
SKRATE9P 2Contracted base rate per pickup.
SKSTAT1AA active, S suspended.

HLTICK — Service ticket (K TICKNO, UNIQUE)

FieldTypeMeaning
TICKNO8ATicket number (key), derived SKEDNO + day-of-month for scheduled tickets.
SKEDNO / SLOC / RTENO6A eachSchedule, location, route (carried on the ticket directly).
TDATE8S 0Pickup date (YYYYMMDD).
TKTYPE1AS scheduled, X extra/unscheduled.
TWEIGHT7P 2Actual tonnage picked up.
TBILLED1AN not yet billed, Y billed (flipped by HLBILL).

HLTKLF — logical file over HLTICK keyed TBILLED, SLOC, TICKNO (non-unique): the by-billed-status access path HLBILL walks so it need not scan HLTICK by ticket number.

HLDISP — Disposal/landfill tonnage ticket (K DISPNO, UNIQUE)

FieldTypeMeaning
DISPNO8ADisposal ticket number (key), derived RTENO + day-of-month.
RTENO6ARoute that dumped this load.
DDATE8S 0Disposal date (YYYYMMDD).
DTWEIGHT9P 2Total tonnage hauled to the landfill that day.
DTPFEE7P 2Tipping-fee rate per ton at the route's landfill.
DTAMT11P 2Hauler's disposal cost = DTWEIGHT × DTPFEE (never billed to a customer).

HLLEDG — Customer AR ledger (K LEDGSEQ, UNIQUE)

FieldTypeMeaning
LEDGSEQ8S 0Global ledger sequence (key); reserved key bands per writer (10M / 30M).
CUSTNO6AOwning customer.
LTYPE1AI invoice (+), P payment (−), F late fee (+).
LDT8S 0Ledger date (YYYYMMDD).
LAMT11P 2Signed amount.
LMEMO25AFree-text memo (e.g. INVOICE CU000101, FEE CU000101).

HLLEDCF — logical file over HLLEDG keyed CUSTNO, LEDGSEQ (non-unique): the by-customer AR path HLAGE and HLLEDIQ walk.

HLINVH — Invoice header (K INVNO, UNIQUE)

FieldTypeMeaning
INVNO8AInvoice number (key), derived from customer + period sequence.
CUSTNO6ABilled customer.
IDATE / IDUEDT8S 0Invoice date / due date (= period + CPAYTRM, numeric add).
IBASE / IEXTRA / ISURCH11P 2Base-service / extra-pickup / surcharge amounts.
IAMT11P 2Invoice total (foots to IBASE+IEXTRA+ISURCH).
ISTAT1AO open, P paid, D delinquent (set by aging).

HLINVL — Invoice lines (K INVNO, ILSEQ, UNIQUE)

FieldTypeMeaning
INVNO / ILSEQ8A / 3S 0Invoice + line sequence (key).
ITYPE1AB base service, X extra pickups, F fuel/enviro surcharge.
IDESC25ALine description.
IAMTL11P 2Line amount (the three lines foot to HLINVH.IAMT).

HLINVLF — logical file over HLINVH keyed ISTAT, CUSTNO, INVNO (non-unique): the by-status AR-aging path HLAGE walks.

HLGLFEED — GL feed (SQL table, PK GLSEQ)

ColumnTypeMeaning
GLSEQDECIMAL(8,0)GL sequence (PK).
GLBATCHDECIMAL(6,0)Posting batch (e.g. 202610).
ACCTCHAR(9)GL account (1200-ARV / 4000-REV / 4800-FEE / 5000-DISP / 2000-APV).
DRCRCHAR(1)D debit, C credit.
AMTDECIMAL(11,2)Posting amount.
GLREFCHAR(8)Source key (ledger seq or disposal ticket no) — the idempotency guard.
GLDTDECIMAL(8,0)Posting date (YYYYMMDD).

Index HLGLFACC on (ACCT, DRCR). The by-GLREF duplicate check drives idempotency.

Relationships

E. Operations Runbook ↑ top

E.1 Day-in-the-life

First-time / rebuild setup (idempotent — HLSETUP DLTFs then re-creates every file):

  1. CALL HAULPRO/HLSETUP — creates every PF/LF/DSPF/PRTF, runs the two SQL DDL members (HLGLFD/HLGLFC), and compiles every program; confirm the "HAULPRO setup complete." banner.
  2. CALL HAULPRO/HLREFLD — seeds 2 customers, 2 locations, 2 containers, 2 routes, 2 schedules; confirm HLREFLD CUSTOMERS=2 ... SCHEDULES=2.

Daily operation:

  1. Submit the daily cycle: SBMJOB CMD(CALL PGM(HAULPRO/HLDAILY)).
  2. Post-check the daily run (below).
  3. Handle customer / ledger inquiries through CALL HAULPRO/HLMENU (options 1 and 2) as needed.

Pre-checks: confirm the job's library list includes HAULPRO (the cycle drivers ADDLIBLE it themselves); confirm the reference data has been seeded (HLREFLD).

Post-checks after the daily cycle:

E.2 Month-end & period close

  1. Confirm every service day of the month has had its daily cycle run (all tickets exist and are TBILLED='N').
  2. Submit the monthly billing cycle: SBMJOB CMD(CALL PGM(HAULPRO/HLMONTH)). Confirm HLBILL BILLED= equals the active customers with unbilled activity, and each invoice foots IAMT = IBASE + IEXTRA + ISURCH.
  3. Submit the period cycle: SBMJOB CMD(CALL PGM(HAULPRO/HLPRICL)) — runs HLAGE, HLARRP, HLGLPST in that order.
  4. Reconcile (below).

Reconciling figures (the same ones the cycle simulation checks against a hand-derived oracle):

Ad-hoc GL review: SELECT ACCT, DRCR, SUM(AMT) FROM HAULPRO.HLGLFEED GROUP BY ACCT, DRCR ORDER BY ACCT, DRCR; gives the trial-balance-style rollup (using the HLGLFACC index).

E.3 Failure & re-run rules

Each program DSPLYs a count summary (CREATED/LOGGED/BILLED/FLAGGED/ASSESSED/ROWS). Every cycle is safe to re-run because each program is idempotent by a derived key or a status flip.

SituationBehaviourAction
Daily cycle fails partwaySome schedules ticketed, some not; disposal only sees the ones ticketed.Re-submit HLDAILY for the same day: already-ticketed schedules skip (CREATED counts only the new ones), then HLDISPRUN re-sums. Idempotent by derived TICKNO/DISPNO.
Re-run the same day's daily cycleCREATED=0 LOGGED=0; no new rows.Safe no-op. Only a different day (different WTODAY) creates new tickets.
Monthly billing re-run same periodBILLED=0; every ticket already TBILLED='Y', plus the INVNO CHAIN(EN) belt-and-suspenders guard.Safe no-op. Idempotent by construction.
Period aging re-run same as-ofFLAGGED=0 ASSESSED=0; invoices no longer ISTAT='O' and each already has its 'F' fee-tag in the ledger.Safe no-op. Do not change the as-of literal to re-age the same invoices.
GL close re-run same periodROWS=0; every GLREF already present in HLGLFEED.Naturally idempotent — the by-GLREF SELECT excludes already-posted sources.
A route with no pickups todayNo disposal ticket written (SKIP incremented).Expected — "nothing due, nothing happens". Not an error.
Ledger key-band exhaustionWriter's reserved band (e.g. 10M/30M) full.Design headroom is 1,000,000 rows per band per program; widen the band before it fills (out of scope for this build's volumes).
Because every money movement is a signed HLLEDG row and every GL posting carries its source key in GLREF, any period's effect is fully reconstructable after the fact — the COBOL HLARRP reconciliation is the built-in proof that CBAL equals the ledger detail.

F. Developer Reference ↑ top

The program surface, from src/sources.mjs. All objects are in library HAULPRO. The RPG programs are column-exact fixed-form with /free blocks; HLGLPST is SQLRPGLE (embedded SQL); HLARRP is ILE COBOL; the cycles are CL.

F.1 Programs

HLREFLD (RPGLE) — reference/master seed
WRITEs the 2 customers, 2 locations, 2 containers, 2 routes and 2 schedules; the surcharge pct and terms are per-customer contract terms, not company constants.
HLPICKUP (RPGLE) — daily service tickets
SETLL/READ over HLSKED; skips non-active (SKSTAT≠'A'); captures SKEDNO/SLOC/RTENO/ CONTNO into work fields before CHAINing HLCONT (shared external field names); derives TWEIGHT = CSIZE × 0.85 and TICKNO = WSKED + %subst(%char(WTODAY):7:2); CHAIN(EN) guard on TICKNO; WRITEs HLTICK with TKTYPE='S', TBILLED='N'.
HLDISPRUN (RPGLE) — daily disposal tickets
Outer loop over active routes; inner scan of HLTICK filtering RTENO=WRTE and TDATE=WTODAY to sum weight; fixed tipping table (RT0001 45 / RT0002 50 / else 40); writes HLDISP with DTAMT = DTWEIGHT × DTPFEE; CHAIN(EN) guard on the derived DISPNO.
HLBILL (RPGLE) — monthly billing
Reserved LEDGSEQ band 10000000–10999999 (high-water scan first); loops active customers; per customer walks the TBILLED='N' bucket of HLTKLF, CHAINing HLLOC to confirm the ticket belongs to this customer, summing BASE (each ticket's own SKRATE via HLSKED CHAIN), counting EXTRA; flips each walked ticket to TBILLED='Y'; computes SURCH and total; WRITEs HLINVH + 2–3 HLINVL lines + an 'I' HLLEDG row; rolls CBAL. INVNO CHAIN(EN) guard.
HLAGE (RPGLE) — AR aging & late fees
Reserved band 30000000–30999999; loops open invoices via HLINVLF; past-due → ISTAT='D', CSTAT='D', fee = $25.00 + IAMT × 0.0150 (wide packed multiply, +0.005 bias, truncate to cents); scans HLLEDG for an existing 'F' + matching LMEMO tag to avoid double-assessing; WRITEs an 'F' HLLEDG row; rolls CBAL.
HLGLPST (SQLRPGLE) — GL close
Three READ loops over HLLEDG ('I' then 'F') and HLDISP; each row's GLREF checked against HLGLFEED via EXEC SQL SELECT COUNT(*) before posting a DR/CR pair through the glrow subroutine (INSERT with MAX(GLSEQ)+1).
HLARRP (ILE COBOL) — AR reconciliation
Sequential READ of HLLEDG summing 'I'/'F'/'P' into W-INV/W-FEE/W-PAY, a net, and a line count; DISPLAYs INVOICED / LATEFEE / PAYMENTS / NET / LINES.
HLCUSTIQ / HLLEDIQ / HLMENU (RPGLE) — online
HLMENU EXFMTs the menu and CALLs HLCUSTIQ (opt 1) or HLLEDIQ (opt 2). HLCUSTIQ CHAINs HLCUST and renders a derived status description. HLLEDIQ loads the LSFL subfile from HLLEDCF with display-clear-reload discipline.
HLSETUP / HLDAILY / HLMONTH / HLPRICL (CL)
HLSETUP DLTFs + CRTPF/CRTLF/CRTDSPF/CRTPRTF + RUNSQLSTM + CRTBNDRPG/CRTBNDCBL for every object. HLDAILY calls HLPICKUP then HLDISPRUN; HLMONTH calls HLBILL; HLPRICL calls HLAGE, HLARRP, HLGLPST.

F.2 Derived keys & idempotency

HAULPRO/i has no separate control table; idempotency is achieved two ways, mirroring the estate's siblings:

F.3 The GL feed & postings

PostingDebitCreditDriven off
Service revenue1200-ARV4000-REVeach HLLEDG 'I' row (base+extra+surcharge)
Late-fee income1200-ARV4800-FEEeach HLLEDG 'F' row
Disposal cost5000-DISP2000-APVeach HLDISP row (tipping fee, hauler expense)

Each source produces exactly one balanced DR/CR pair (two rows). 1200-ARV is the shared AR debit for revenue and fees; 2000-APV is the payable to the landfill. GLREF carries the source key (ledger seq or disposal ticket no) so the close is idempotent without a posted-flag column.

F.4 Engine-compatibility notes

F.5 Worked figures (the test oracle)

The hp_daily.mjs / hp_cycles.mjs scenario, hand-derived end to end from the seed data (2 customers, weekly schedules SK0001 @180.00 / SK0002 @220.00, plus one planted extra ticket at CU0001):

DAILY   (WTODAY 20260915)
  SK0001  6yd x 0.85 = 5.10t   RT0001 x $45/t = $229.50 disposal
  SK0002  8yd x 0.85 = 6.80t   RT0002 x $50/t = $340.00 disposal
MONTHLY (period 20260930)
  CU0001  BASE 180.00 + EXTRA 95.00 + SURCH 22.00 (8%)  = IAMT 297.00  due 20260960
  CU0002  BASE 220.00 + EXTRA  0.00 + SURCH 13.20 (6%)  = IAMT 233.20  due 20260945
PERIOD  (as-of 20261101)
  CU0001 fee = 25.00 + 297.00 x 1.5% (4.455->4.46) = 29.46  CBAL 326.46
  CU0002 fee = 25.00 + 233.20 x 1.5% (3.498->3.50) = 28.50  CBAL 261.70
  HLARRP  INVOICED 530.20  LATEFEE 57.96  PAYMENTS 0.00  NET 588.16  LINES 4
  GL      REV 530.20  FEE 57.96  DISP 569.50   12 rows   SUM(DR)=SUM(CR)=1157.66

G. Glossary ↑ top

Service schedule (the contract)
An HLSKED row tying a location's container to a route at a frequency and a base rate per pickup — the recurring contract the whole system revolves around.
Service ticket
An HLTICK row = one actual route pickup. Scheduled (TKTYPE='S', created by the daily run) or extra (TKTYPE='X', an unplanned pickup). Billed later at the schedule's or the extra-pickup rate.
Disposal / tipping-fee ticket
An HLDISP row = what the hauler pays the landfill to dump a truckload (DTWEIGHT × DTPFEE). A pure cost, never billed to any customer — the hauler's own expense.
Fuel/environmental surcharge (FSC)
A per-customer contract percentage (CFSCPCT) applied by billing to the base+extra subtotal — a contract term looked up per customer, never a hard-coded company constant.
Base / extra / surcharge split
The three revenue components of an invoice: base service (scheduled pickups × SKRATE), extra (unscheduled pickups × flat rate), and the FSC. They foot to IAMT and post as three GL revenue strands.
AR ledger (HLLEDG)
The signed customer accounts-receivable spine: I invoice (+), P payment (−), F late fee (+). CBAL is the sum of a customer's rows and is reconstructible from them (HLARRP proves it).
Reserved key band
A LEDGSEQ range owned by exactly one program (HLBILL 10M, HLAGE 30M) so multiple writers append to the shared ledger without colliding.
Idempotent
Safe to run again with the same result. Every HAULPRO/i cycle is idempotent — by a derived CHAIN(EN) key, a status flip out of the scanned set, or a GLREF-already-present check.
Derived key
A record key built from stable inputs (e.g. TICKNO = SKEDNO + day, INVNO = customer + period) so a re-run derives the same key and the guard refuses a duplicate write.
SBMJOB
Submit Job — the IBM i command that queues a program to run as a batch job (e.g. SBMJOB CMD(CALL PGM(HAULPRO/HLDAILY))).
Subfile
A 5250 display construct listing many rows on one screen (DDS SFL/SFLCTL). HLLEDIQ's ledger list is a subfile with SFLPAG(5)/SFLSIZ(20) paging.
GL feed (HLGLFEED)
The general-ledger interface table the period close posts balanced DR/CR pairs into (revenue, late-fee income, disposal cost), keyed by GLSEQ with GLREF carrying the source key.