FREIGHT/i — Freight Carrier TMS & Billing

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

FREIGHT/i is a for-hire trucking / freight-brokerage back office — a Transportation Management System (TMS) and billing engine. It carries a shipper master, a driver and tractor/trailer master, a lane rate table, and the loads (tendered shipments with pickup/delivery stops) that walk a strict lifecycle: tendered → dispatched → delivered → rated → invoiced → settled. A nightly cycle dispatches, confirms delivery, rates, bills and accrues driver pay; a weekly cycle settles drivers; a monthly cycle posts the GL feed. All logic is classic RPG (fixed-form + free), one ILE COBOL report, CL job streams, DDS files and a single SQL GL table — there is no SQL-PL layer here; the RPG programs own the business math directly. 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 (freight-app/src/sources.mjs, src/seed.mjs, and the test/fr_build.mjs / fr_daily.mjs / fr_cycles.mjs drivers). Everything runs in library FREIGHT.

Contents

A. Overview & Architecture ↑ top

A.1 What it does

FREIGHT/i runs the operational and financial back office of a for-hire carrier:

A.2 The load lifecycle is the spine

Every load carries a status field LSTAT on FRLOAD that walks one strictly forward chain. A load only ever advances; each batch program keys off the status, so the status itself is the primary integrity and idempotency control (see F.3):

LSTATStateMeaning — and what set it
TTenderedShipper booked it; stops exist, nothing has moved. Seeded / booked state.
DDispatchedDriver + unit committed, driver active. Set by FRDISP; stamps LDSPDT.
LDeliveredEvery stop confirmed (POD). Set by FRPOD; stamps LDELDT.
RRatedLinehaul + FSC + accessorials computed. Transient — FRRATE passes through R.
IInvoicedA freight invoice (FRINVH/FRINVL) has been cut. Set by FRRATE in the same pass.
SSettledThe driver has been paid for it (an FRSETD load-pay line reassigned to a real settlement).
Because FRRATE rates and bills in one nightly run, a load moves through R straight to I in a single pass; there is no separate hold-for-rate-review state in this build. "Has this load been rated?" is answered by LSTAT ≥ 'R', never inferred from a zero/nonzero amount — LRATED/LFSC/LACCTOT/LTOTAL are zero until the rating run fills them.

A.3 Component & flow

  REFERENCE            ONLINE                 BATCH (periodic)
  ---------            ------                 ----------------
  FRREFLD  (seed)      FRMENU (5250)          DAILY  FRDAILY
   FRSHIP/FRDRVR         |  1 -> FRBRDIQ         FRDISP  T -> D
   FRUNIT/FRLANE         |  2 -> FRSTPIQ         FRPOD   D -> L (stops O -> C)
                         v    (subfile)         FRRATE  L -> R -> I  + accrue FRSETD(SETNO 0)
                     board / stops inquiry
                                              WEEKLY FRWEEK
                                                 FRSETRUN  FRSETD(0) -> FRSETH + real SETNO
   FRLOAD  <--writes-- every batch program        FRSETRP   COBOL recon report
     |  \
     |   +--> FRSTOP  (pickup/delivery/accessorial stops)   MONTHLY FRMONTH
     |   +--> FRINVH / FRINVL  (freight invoice hdr+lines)     FRGLPST  invoices+settlements
     |   +--> FRSETD / FRSETH  (settlement detail+header)               -> FRGLFEED (SQL)
     +------> FRGLFEED (GL feed, SQL table)

A single load flows: booked TENDERED with a driver/unit and stops → FRDISP commits it DISPATCHED → FRPOD confirms its stops and marks it DELIVERED → FRRATE prices it, writes FRINVH+FRINVL, accrues an FRSETD pending pay line, and sets it INVOICED → the weekly FRSETRUN turns pending pay into an FRSETH settlement → the monthly FRGLPST posts revenue, pay and deductions into FRGLFEED.

A.4 Object inventory

ObjectTypeRole
FRSHIPPFShipper (customer) master; per-shipper fuel-surcharge pct & payment terms.
FRDRVRPFDriver master; contracted settlement pay percentage.
FRUNITPFTractor/trailer unit master.
FRLANEPFLane rate table (per-mile rate, lane minimum, base FSC pct).
FRLOADPFLoad (shipment) header — the spine of the app.
FRLODLFLFLoads by status/shipper (alternate access path over FRLOAD).
FRSTOPPFLoad stops (pickup / delivery / accessorial).
FRINVH / FRINVLPFFreight invoice header + itemised lines.
FRSETH / FRSETDPFDriver settlement header + detail lines.
FRSETLFLFSettlement detail by driver (alternate access path over FRSETD).
FRGLFEEDSQL tableThe GL feed the monthly close posts into (with index FRGLFACC).
FRBRDD / FRSTPD / FRMENUDDSPFBoard inquiry, stops subfile, main menu display files.
FRSETPPRTFDriver settlement statement printer file.
FRREFLDRPGLESeed reference data (shippers/drivers/units/lanes).
FRDISP / FRPOD / FRRATERPGLEThe three daily-cycle programs.
FRSETRUNRPGLEWeekly driver settlement run.
FRGLPSTSQLRPGLEMonthly GL close (embedded SQL against FRGLFEED).
FRBRDIQ / FRSTPIQ / FRMENURPGLEOnline board inquiry / stops subfile / menu.
FRSETRPCBLLEILE COBOL settlement reconciliation report.
FRSETUPCLPCreate every object & compile every program.
FRDAILY / FRWEEK / FRMONTHCLPThe three job-cycle drivers.

The full catalogue is 10 PFs + 2 LFs + 1 SQL table (+ index), 3 display files and 1 printer file, driven by 9 RPG programs, 1 ILE COBOL program and 5 CL programs. Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

FREIGHT/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 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 FREIGHT — the tested jobs run with LIBL = QSYS QGPL FREIGHT QTEMP and CURLIB = FREIGHT.

To do thisType on the command line
Open the main menu (fans out to the two inquiries)CALL FREIGHT/FRMENU
Load-board inquiry (one load, derived status + total)CALL FREIGHT/FRBRDIQ
Load-stops subfile inquiryCALL FREIGHT/FRSTPIQ
Build/compile every object, then seed reference dataCALL FREIGHT/FRSETUP then CALL FREIGHT/FRREFLD
Run the nightly cycleCALL FREIGHT/FRDAILY (or SBMJOB it)
Run the weekly settlement cycleCALL FREIGHT/FRWEEK
Run the monthly GL closeCALL FREIGHT/FRMONTH

The batch drivers (FRDAILY/FRWEEK/FRMONTH) are CL streams that take no parameters — each simply CALLs its RPG programs in order. Unlike some sister apps, FREIGHT/i has no control-row date table: the processing dates are literals inside the RPG (for the reference scenario, e.g. dispatch stamps 20260901, POD/rate stamp 20260902, the GL batch is 202609 dated 20260930). Only FRMENU/FRBRDIQ/ FRSTPIQ are interactive; the batch programs run to completion and DSPLY a one-line counter per step.

B.2 The menu & inquiry screens

Main menu (FRMENU / FRMENUD)

A plain menu record. Key 1 or 2 in MOPT and press Enter; the program CALLs FRBRDIQ or FRSTPIQ respectively, blanks the option and re-displays. Any other non-blank value shows "Invalid option.". F3 exits.

FREIGHT/i Main Menu 1. Load Board Inquiry 2. Load Stops Inquiry Option . . . . : _ F3=Exit Enter=Select

Load-board inquiry (FRBRDIQ / FRBRDD)

A plain (non-subfile) inquiry. Key a load number in IBLOAD, Enter. FRBRDIQ CHAINs FRLOAD by load number, then CHAINs FRSHIP and FRDRVR for the shipper and driver names, and renders a derived lifecycle description (TENDERED/DISPATCHED/DELIVERED/RATED/INVOICED/SETTLED) plus the lane, miles and rated total. A missing load shows "Load not found." with the output fields blanked.

Load Board Inquiry - FREIGHT/i Load number: L0000001 Shipper . . . : NORTHERN FREIGHT CO Lane . . . . . : ATL-CHI Driver . . . . : MARTIN OKAFOR Status . . . . : INVOICED Miles . . . . : 200.0 Rated total . : 624.00 Load found. F3=Exit Enter=Inquire

Load-stops inquiry (FRSTPIQ / FRSTPD)

The app's subfile screen. Key a load number in ISLOAD, Enter; FRSTPIQ clears the subfile, then READEs FRSTOP by that load and loads one SSFL row per stop, showing sequence, type, location, accessorial charge and confirmation status — plus header totals (stop count, total accessorials, open-stop count). The subfile is SFLPAG(5) per page over SFLSIZ(20), so Roll↑/ Roll↓ page it. The screen displays first, then clears and reloads from the keyed load, so re-keying a new load number refreshes the list (the same discipline as the sister DEPOT/i pick inquiry).

Load Stops - FREIGHT/i Load number: L0000001 Stops . . . . : 2 Accessorials . : 75.00 Open stops . . : 0 Sq T Location Accessorial S 1 P ATLANTA GA SHIPPER DOCK .00 C 2 D CHICAGO IL CONSIGNEE DOCK 75.00 C Load found. F3=Exit Roll=Page Enter=Inquire

Subfile columns (SSFL)

FieldType (DDS)Shows
TSEQ3Y,0 outputStop sequence (from SSEQ).
TTYPE1A outputStop type: P pickup, D delivery, X accessorial-only.
TLOC25A outputStop location text.
TACC12A outputAccessorial charge for this stop (edited from SACC).
TSTAT1A outputStop status: O open, C confirmed (POD captured).

B.3 Controls & audit workflow (no maker–checker; state-machine + idempotency)

Honest statement: FREIGHT/i does not model a four-eyes maker–checker / separate-authorization workflow, and there is no trigger-written audit-trail file here (unlike the sister LOANSVC/i). The online screens (FRBRDIQ, FRSTPIQ) are strictly read-only inquiries — they never write. All state changes happen in the batch cycles. The control model the application actually has is:

In sum, the control posture is a strict forward state machine + per-party contract terms + idempotent posting + a fully reconstructable double-entry trail, rather than a segregation-of-duties approval workflow.

C. Batch Jobs & the Periodic Cycle ↑ top

FREIGHT/i's back office runs as three periodic cycles, each a CL stream that CALLs its RPG programs in order: a daily cycle (dispatch → POD → rate/bill/accrue), a weekly cycle (driver settlement + reconciliation report), and a monthly cycle (GL close). None take parameters; each program walks its input files and selects rows purely by LSTAT/SSTAT/ SETNO state, so a scheduled submission is a bare CALL.

-- one-time build + seed (create objects, compile programs, load reference data)
CALL FREIGHT/FRSETUP
CALL FREIGHT/FRREFLD

-- then submit the (parameterless) cycles
SBMJOB CMD(CALL PGM(FREIGHT/FRDAILY)) JOB(FRDAILY)
SBMJOB CMD(CALL PGM(FREIGHT/FRWEEK))  JOB(FRWEEK)
SBMJOB CMD(CALL PGM(FREIGHT/FRMONTH)) JOB(FRMONTH)

C.1 Full batch program set

ProgramCyclePurposeReadsWrites / effectDSPLY counter
FRREFLDsetup Seed reference data. FRSHIP(2), FRDRVR(2), FRUNIT(3), FRLANE(2). FRREFLD SHIPPERS=2 DRIVERS=2 UNITS=3 LANES=2
FRDISPdaily Dispatch tendered loads with an active driver+unit. FRLODLF (by LSTAT='T'), FRDRVR. FRLOAD: LSTAT T→D, LDSPDT stamped. Ineligible → skipped. FRDISP DISPATCHED=n SKIP=m
FRPODdaily Confirm open stops; deliver fully-confirmed loads. FRLOAD (LSTAT='D'), FRSTOP. FRSTOP: SSTAT O→C, SACT stamped. FRLOAD: LSTAT D→L, LDELDT stamped when all stops done. FRPOD CONFIRMED=n DELIVERED=m
FRRATEdaily Rate + bill delivered loads; accrue driver pay. FRLOAD (LSTAT='L'), FRLANE, FRSHIP, FRSTOP, FRDRVR, FRSETD. FRINVH+FRINVL written; FRLOAD amounts + LSTAT→I; FRSETD pending pay line (SETNO 0). FRRATE RATED=n SKIP=m
FRSETRUNweekly Build one settlement per driver from pending pay. FRDRVR, FRSETLF/FRSETD (SETNO 0), FRSETH. FRSETD pending lines reassigned to a real SETNO + 2 deduction lines; FRSETH header written. FRSETRUN SETTLED=n SKIP=m
FRSETRPweekly COBOL settlement reconciliation report. FRSETD (SETNO≠0), sequential. Sums load-pay / deduction / net / line-count; DSPLY only (no file writes). FRSETRP LOADPAY/DEDUCT/NET/LINES
FRGLPSTmonthly GL close: post revenue, driver pay, retained deductions. FRINVH, FRSETH; SQL against FRGLFEED. FRGLFEED: 3 balanced DR/CR postings per unposted invoice/settlement. FRGLPST BATCH=202609 ROWS=n

C.2 Daily / weekly / monthly detail

Daily — FRDAILY (FRDISP → FRPOD → FRRATE)

FRDISP walks every LSTAT='T' load (via the by-status LF FRLODLF); if it carries a driver and unit and the driver is DSTAT='A', it flips the load to 'D' and stamps LDSPDT; otherwise it is counted as SKIP and stays tendered. FRPOD reads every load, and for each LSTAT='D' load confirms every SSTAT='O' stop (→'C', stamp SACT); when no stop remains open it advances the load to 'L' and stamps LDELDT. FRRATE then prices every LSTAT='L' load (see F.1 for the formula), writes the invoice header and lines, accrues one pending driver-pay line, and advances the load through R to 'I'.

Expected DSPLY (two tendered loads, ATL-CHI 200mi and ATL-DAL 400mi):
  FRDISP DISPATCHED=2 SKIP=0
  FRPOD CONFIRMED=4 DELIVERED=2
  FRRATE RATED=2 SKIP=0        2 invoices cut, 2 pending pay lines accrued

Weekly — FRWEEK (FRSETRUN → FRSETRP)

FRSETRUN: for every active driver with at least one pending (SETNO=0) load-pay line, it allocates a new settlement number (one past the highest SETNO ever used), reassigns that driver's pending lines onto it, appends two fixed standing deductions (cargo insurance $45.00 + equipment lease $150.00 = $195.00), and writes the FRSETH header with HGROSS/HDEDUCT/HNET, HSTAT='O' (built, not yet paid — a separate pay run is out of scope for this build). FRSETRP is a COBOL report that re-derives the positive (load-pay) and negative (deduction) sides straight off FRSETD (SETNO≠0), independently of the headers.

Expected DSPLY (DR0001 pending 468.00, DR0002 pending 673.92):
  FRSETRUN SETTLED=2 SKIP=0
  FRSETRP LOADPAY  1141.92     468.00 + 673.92
  FRSETRP DEDUCT    390.00     195.00 x 2
  FRSETRP NET       751.92
  FRSETRP LINES       6.00     3 lines x 2 settlements
Settlement numbers are allocated 1, 2 on the first run (the highest existing SETNO starts at 0). Deductions are deliberately fixed constants so the tests hand-derive the net; a driver's cheque is HNET = HGROSS - HDEDUCT.

Monthly — FRMONTH (FRGLPST)

FRGLPST (SQLRPGLE) posts three balanced double-entry pairs, each driven off the still-open, not-yet-posted rows:

PostingSourceDebitCredit
Revenueeach open FRINVH, at IAMT1200-ARV4000-REV
Driver payeach open FRSETH, at HGROSS6000-DPAY2200-DRVP
Retained deductionssame settlements, at HDEDUCT2200-DRVP4900-OTH

"Not yet posted" is tracked without a posted-flag column: GLREF carries the source key (the invoice number, or 'S'+zero-filled settlement number), and the SELECT excludes any GLREF already present in FRGLFEED, so a re-run posts nothing further.

Expected DSPLY (2 invoices, 2 settlements):
  FRGLPST BATCH=202609 ROWS=12   (2 rev + 2 pay + 2 ded) x 2 rows each

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library FREIGHT, grounded in src/sources.mjs. Dates are stored as zoned 8S,0 in YYYYMMDD form; percentages and money are packed decimals (P); the lane rate is 7P,4. Physical files are keyed UNIQUE; the two logical files are non-unique alternate access paths.

FRSHIP — Shipper (customer) master (K SHIPNO)

FieldTypeMeaning
SHIPNO6AShipper number (key), e.g. SH0001.
SHIPNM30AShipper name.
SBILTO30ABill-to name / AP department.
SFSCPCT5P,2Contracted fuel-surcharge pct — overrides the lane default when nonzero.
SPAYTRM3S,0Payment terms in days (invoice due date = ship date + this).
SSTAT1AShipper status (A active).

Seeded: SH0001 NORTHERN FREIGHT CO (FSC 22.00%, 30-day), SH0002 DELTA RETAIL GROUP (FSC 20.00%, 15-day).

FRDRVR — Driver master (K DRVNO)

FieldTypeMeaning
DRVNO6ADriver number (key), e.g. DR0001.
DNAME30ADriver name.
DHOME3AHome terminal (reporting only).
DPAYPCT5P,2Contracted settlement pct of the rated total (owner-operator/lease).
DCDL15ACDL number.
DSTAT1AA active, H on hold (no new dispatch), T terminated.

Seeded: DR0001 MARTIN OKAFOR (pay 75.00%), DR0002 SUSAN VELASQUEZ (pay 72.00%).

FRUNIT — Tractor/trailer unit master (K UNITNO)

FieldTypeMeaning
UNITNO6AUnit number (key).
UTYPE1AT tractor, R reefer trailer, D dry-van trailer, F flatbed trailer.
UPLATE10ALicence plate.
USTAT1AUnit status (A active).

Seeded: TR0001 & TR0002 (tractors), TL0001 (dry-van trailer). A load's dispatched unit is a tractor.

FRLANE — Lane rate table (K LOZONE, LDZONE)

FieldTypeMeaning
LOZONE / LDZONE3A / 3AOrigin zone / destination zone (composite key).
LDESC30ALane description.
LRATE7P,4Flat per-mile rate.
LMIN9P,2Lane minimum charge (linehaul floor).
LFSCBAS5P,2Base fuel-surcharge pct for the lane (default; shipper SFSCPCT overrides).
LSTAT1ALane status (A active).

Seeded: ATL-CHI 2.1500/mi min 450.00 FSC 18.00%; ATL-DAL 1.9500/mi min 500.00 FSC 20.00%.

FRLOAD — Load (shipment) header (K LOADNO; the spine)

FieldTypeMeaning
LOADNO8ALoad number (key), e.g. L0000001.
SHIPNO6ABooking shipper (→ FRSHIP).
LOZONE / LDZONE3A / 3AOrigin / destination zone (→ FRLANE).
LMILES7P,1Rated distance for the lane.
UEQREQ1ATrailer equipment requirement for the load.
DRVNO / UNITNO6A / 6AAssigned driver / unit (set by booking; committed by dispatch).
LTNDDT / LDSPDT / LDELDT8S,0Tendered / dispatched / delivered dates (YYYYMMDD).
LRATED9P,2Linehaul amount (rate×miles or lane min). Zero until rated.
LFSC9P,2Fuel surcharge. Zero until rated.
LACCTOT9P,2Sum of stop accessorial charges. Zero until rated.
LTOTAL11P,2LRATED + LFSC + LACCTOT. Zero until rated.
LSTAT1ALifecycle status T/D/L/R/I/S (see A.2).

FRLODLF — Loads by status/shipper (LF over FRLOAD; K LSTAT, SHIPNO, LOADNO)

Non-unique logical over FRLOAD leading on LSTAT, so the daily rating run can walk "every delivered-not-rated load" and the board can walk "a shipper's loads" without scanning by LOADNO.

FRSTOP — Load stops (K LOADNO, SSEQ)

FieldTypeMeaning
LOADNO / SSEQ8A / 3S,0Load + stop sequence (composite key); stops walk in SSEQ order.
STYPE1AP pickup, D delivery, X accessorial-only stop.
SLOC25AStop location.
SAPPT / SACT8S,0Appointment date / actual (POD) date.
SACC9P,2Accessorial charge for this stop (detention/layover/lumper); usually zero.
SSTAT1AO open, C confirmed (POD captured).

FRINVH — Freight invoice header (K INVNO; 1:1 with a load once LSTAT='I')

FieldTypeMeaning
INVNO8AInvoice number (key), derived 'I'+load digits so it is stable/idempotent.
LOADNO / SHIPNO8A / 6ABilled load / shipper.
IDATE / IDUEDT8S,0Invoice date / due date (= ship date + shipper SPAYTRM).
IAMT11P,2Invoice amount (= load LTOTAL; foots to the FRINVL lines).
ISTAT1AO open (billed, unpaid), P paid.

FRINVL — Freight invoice lines (K INVNO, ILSEQ)

FieldTypeMeaning
INVNO / ILSEQ8A / 3S,0Invoice + line sequence (composite key).
ITYPE1AL linehaul, F fuel surcharge, A accessorial (one per nonzero stop charge).
IDESC25ALine description.
IAMTL11P,2Line amount; the lines foot to FRINVH.IAMT.

FRSETH — Driver settlement header (K SETNO)

FieldTypeMeaning
SETNO6S,0Settlement number (key), allocated one per (driver, week).
DRVNO6ASettled driver.
HWKEND8S,0Week-ending date.
HGROSS11P,2Sum of load-pay detail lines (before deductions).
HDEDUCT11P,2Sum of deduction lines (stored positive on the header).
HNET11P,2HGROSS − HDEDUCT (the cheque amount).
HSTAT1AO open (built, unpaid), P paid.

FRSETD — Driver settlement detail (K SETNO, SDSEQ)

FieldTypeMeaning
SETNO / SDSEQ6S,0 / 3S,0Settlement + line sequence (composite key). SETNO=0 is the pending bucket.
SDTYPE1AL load-pay line (positive), D deduction line (negative).
DRVNO / LOADNO6A / 8ADriver, and load for a pay line (blank on a deduction line).
SDDESC25ALine description (e.g. LOAD PAY, CARGO INSURANCE, EQUIPMENT LEASE).
SDAMT11P,2Signed amount: positive load-pay, negative deduction. A settlement nets to SUM(SDAMT).

FRSETLF — Settlement detail by driver (LF over FRSETD; K SETNO, DRVNO, SDSEQ)

Non-unique logical over FRSETD the weekly run uses to find a driver's accrued (SETNO 0) pay lines. See F.4 (FR-PLAT-001) for why the reassignment pass then walks the base PF rather than this LF after the first PF-side update.

FRGLFEED — GL feed (SQL table, PK GLSEQ; index FRGLFACC on ACCT, DRCR)

ColumnTypeMeaning
GLSEQDECIMAL(8,0)Feed sequence (PK), max+1 per row.
GLBATCHDECIMAL(6,0)Posting batch (YYYYMM, e.g. 202609).
ACCTCHAR(9)GL account (1200-ARV, 4000-REV, 6000-DPAY, 2200-DRVP, 4900-OTH).
DRCRCHAR(1)D debit / C credit.
AMTDECIMAL(11,2)Posting amount.
GLREFCHAR(8)Source key (invoice no, or 'S'+settlement no) — the idempotency guard.
GLDTDECIMAL(8,0)Posting date (YYYYMMDD).

Relationships

E. Operations Runbook ↑ top

E.1 Day-in-the-life

  1. Confirm the job's library list includes FREIGHT and (first time only) the objects are built: CALL FREIGHT/FRSETUP then CALL FREIGHT/FRREFLD.
  2. Ensure the day's bookings are in place: each new load is a FRLOAD row at LSTAT='T' with its SHIPNO, lane, miles, assigned DRVNO/ UNITNO, and its FRSTOP pickup/delivery (and any accessorial) rows.
  3. Submit the nightly cycle: SBMJOB CMD(CALL PGM(FREIGHT/FRDAILY)).
  4. Post-check the daily run (below).
  5. Answer inquiries interactively through CALL FREIGHT/FRMENU (option 1 board, option 2 stops) as they arrive.

Post-checks after the daily cycle (the counters the tests assert):

E.2 Week-end & month-end close

Weekly (driver settlement):

  1. Confirm the week's dailies have all run, so every hauled load has a pending (SETNO=0) pay line.
  2. Submit FRWEEK. Confirm FRSETRUN SETTLED=n equals the drivers with pending pay, and one FRSETH header per driver with HGROSS/HDEDUCT/HNET.
  3. Review the COBOL reconciliation lines (FRSETRP LOADPAY/DEDUCT/NET/LINES) — these re-derive the settlement sides straight from the detail file, independently of the headers.

Monthly (GL close):

  1. Confirm the month's dailies and weeklies are all run (invoices cut, settlements built).
  2. Submit FRMONTH. Confirm FRGLPST BATCH=202609 ROWS=n.
  3. Reconcile the GL feed:
SELECT ACCT, DRCR, SUM(AMT) FROM FREIGHT.FRGLFEED
  GROUP BY ACCT, DRCR ORDER BY ACCT, DRCR;

Reconciling figures (the exact figures the cycle test derives from the 2-load reference scenario — two loads rated 624.00 and 936.00):

Where the money splits three ways per load: shipper pays the invoice (revenue), the driver earns DPAYPCT of it (pay), the company keeps its margin plus the retained deductions.

E.3 Failure & re-run rules

Each program DSPLYs a counter line. A clean re-run is safe everywhere — every stage is idempotent (F.3):

SituationBehaviourAction
Re-run the daily cycleAll three programs select only the predecessor state; the already-advanced loads are past it.Re-submit FRDAILY: DISPATCHED=0, RATED=0 SKIP=0, no new invoices or pending lines. Idempotent.
Daily fails partway (e.g. after FRDISP, before FRRATE)Loads sit at whatever state they reached; nothing is half-rated.Re-submit FRDAILY; each program picks up its own predecessor state and continues. Safe.
A load stays tendered / deliveredSKIP counted it: no driver/unit, inactive driver, or a missing lane on the rate table.Fix the booking data (assign driver/unit, activate the driver, add the lane), then re-run the cycle.
Re-run the weekly settlementA driver with no SETNO=0 lines left contributes nothing.Re-submit FRWEEK: SETTLED=0, no new headers. Idempotent.
Re-run the monthly closeEvery GLREF is already present in FRGLFEED, so the SELECT excludes it.Re-submit FRMONTH: ROWS=0, feed unchanged. Idempotent.
Because every money movement is journaled — invoices (header+lines), settlement detail (signed lines), and the balanced GL feed — any cycle's effect is fully reconstructable after the fact for reconciliation and recovery, and the COBOL FRSETRP independently re-foots the settlement side.

F. Developer Reference ↑ top

The application logic lives in the RPG programs (there is no SQL-PL layer). All objects are in library FREIGHT, grounded in freight-app/src/sources.mjs.

F.1 The central invariant & rating formula

The invariant asserted throughout the tests: a load's freight-invoice amount is exactly the lane rate × distance (or the lane minimum, whichever is greater), plus fuel surcharge, plus the sum of its accessorial stop charges — and the driver settlement is that amount × the driver's contracted pay percentage, less deductions. So the GL feed, the invoice and the settlement all foot to the same rated amount, split three ways (company margin / driver pay / deductions).

The rating math in FRRATE (subroutine RATE1):

  LRATED  = greater of (LRATE * LMILES) or LMIN     lane-minimum floor
  fsc-pct = shipper SFSCPCT if > 0, else lane LFSCBAS   shipper term overrides
  LFSC    = round(LRATED * fsc-pct / 100, 2)
  LACCTOT = SUM(SACC) over the load's stops
  LTOTAL  = LRATED + LFSC + LACCTOT
  driver-pay accrual = round(LTOTAL * DPAYPCT / 100, 2)   FRSETD, SETNO 0

Worked from the reference scenario:

LoadLane / milesLinehaulFSCAccessorialTotalDriver pay
L0000001ATL-CHI 200mi450.00 (floor: 430<450)99.00 (22% shipper)75.00 (detention)624.00468.00 (75%)
L0000002ATL-DAL 400mi780.00 (rate×mi)156.00 (20% shipper)0.00936.00673.92 (72%)

Load 1 exercises the lane-minimum floor (200×2.15 = 430.00 < 450.00) and the shipper FSC override; load 2 is a plain rate×miles with no accessorials. The freight invoice writes one LINEHAUL line, one FUEL SURCHARGE line, and one ACCESSORIAL line per nonzero stop charge, footing to IAMT.

F.2 Program-by-program notes

FRREFLD (RPGLE)
Fixed-form file spec + free-form body; writes the 2 shippers, 2 drivers, 3 units, 2 lanes.
FRDISP (RPGLE) — daily 1
Reads FRLODLF by LSTAT='T'; per load, skips if no driver/unit or the driver (CHAIN FRDRVR) is not 'A'; else re-CHAINs the base FRLOAD and UPDATEs LSTAT='D', LDSPDT. The base re-CHAIN is required (FR-OWNBUG-001, F.4).
FRPOD (RPGLE) — daily 2
Reads all loads; for each 'D' load, READEs FRSTOP, confirms every open stop, counts still-open stops, and if none remain UPDATEs the load to 'L' + LDELDT.
FRRATE (RPGLE) — daily 3
The commercial heart. For each 'L' load: CHAIN FRLANE (composite KLIST), apply the floor; CHAIN FRSHIP for the FSC override; sum SACC; guard the derived INVNO with CHAIN(EN); write FRINVH+FRINVL; advance the load R→I; accrue the driver-pay line into the SETNO 0 bucket (see the DRVNO-clobber note, F.4).
FRSETRUN (RPGLE) — weekly
Finds the highest existing SETNO; per active driver, reads pending lines on FRSETLF, allocates a new SETNO, reassigns the lines by walking the base PF by SDSEQ (FR-PLAT-001 workaround, F.4), appends the two deductions, writes the FRSETH header.
FRGLPST (SQLRPGLE) — monthly
Embedded SQL. Reads FRINVH and FRSETH; for each unposted row (checked via a SELECT COUNT(*) on GLREF+ACCT) inserts the balanced DR/CR pair(s) into FRGLFEED, taking GLSEQ from MAX(GLSEQ)+1.
FRSETRP (ILE COBOL) — weekly report
Sequential read of FRSETD; for SETNO≠0 lines, sums positive amounts to load-pay and negative to deductions, computes net, and DSPLYs the four totals.
FRBRDIQ / FRSTPIQ / FRMENU (RPGLE)
Read-only inquiries. FRBRDIQ CHAINs load/shipper/driver and derives the status text; FRSTPIQ loads a stops subfile (clear-after-EXFMT, reload-from-key discipline); FRMENU fans out to the two.

F.3 Idempotency model

Each cycle is safe to re-run, but by three different mechanisms, matching the sister DEPOT/i conventions:

F.4 Platform & own-bug notes (honest)

FREIGHT/i surfaced one genuine platform finding and carries one own-bug workaround; both are documented in the app's FINDINGS.md and are worth understanding before editing the settlement or dispatch programs.

FR-PLAT-001 — LF keyed cursor stale after a same-job PF-side key update (platform)
Once a row's key field is UPDATEd through the base PF, a subsequent SETLL/ READE through the logical file used to find it keeps returning that same row at its stale pre-update key — the LF index is not resynced against a same-job PF-side write, so interleaving "find next pending row via the LF" with "update that row" loops forever. Workaround in FRSETRUN: do the read-only find pass on FRSETLF first (capturing the exact SDSEQ upper bound), then perform the reassignment by walking SDSEQ 1..max directly against the base PF (FRSETDR), never touching the LF again after the first PF-side UPDATE. This is a confirmed platform issue (the same one the DDS conditioning-indicator column workaround in FRSTPD references), not re-derived here.
FR-OWNBUG-001 — UPDATE after a cross-LF READE does not persist (this app's bug/accommodation)
Distinct from FR-PLAT-001: an UPDATE against a record last positioned by a READE through a separate logical file does not persist. Workaround in FRDISP: the load number read off FRLODLF is captured into WLOAD, and a fresh CHAIN(E) through the base FRLOADR is issued immediately before the UPDATE.
DRVNO field-clobber (FRRATE accrual)
The pending-line scan over FRSETDR shares the global DRVNO field with FRLOADR/FRDRVRR; scanning past another driver's pending row silently overwrites DRVNO, so the load's driver is captured into WDRV up front and WDRV (not DRVNO) is used in the WRITE.
SDSEQ width vs derived keys (FRRATE)
SDSEQ is only 3S,0 (max 999), too narrow to derive uniquely from an 8-char load number, so the pending accrual is made idempotent by scanning the existing SETNO-0 rows for this load rather than by a derived key — it takes the next free sequence if not already present.

G. Glossary ↑ top

Accessorial
An extra charge on a stop beyond the linehaul — detention, layover, lumper. Held in FRSTOP.SACC; summed into the load's LACCTOT and billed as ITYPE 'A' lines.
Accrual (driver pay)
Booking the driver's earned pay for a rated load as a pending FRSETD line (SETNO 0) before any cheque is built — the company's cost commitment for the haul.
Dispatch
Committing a tendered load to its already-assigned active driver and unit (T→D), stamping LDSPDT. FRDISP does not choose the driver, it commits a booking assignment.
FSC — Fuel Surcharge
A percentage added to linehaul to pass through fuel cost. The shipper's contracted SFSCPCT overrides the lane's LFSCBAS default when nonzero.
GL feed
The FRGLFEED table of balanced double-entry postings the monthly close writes for the general ledger to consume.
Idempotent
Safe to run again with the same result. Here achieved by lifecycle status, a derived-key CHAIN(EN), a GL-feed membership check, and draining the SETNO-0 pending bucket (F.3).
Lane / lane minimum
An origin-destination zone pair (FRLANE) with a per-mile rate and a floor: a short lane still bills at least LMIN, never rate×miles if that is lower.
Linehaul
The base transportation charge: greater of (LRATE×LMILES, LMIN). Billed as the ITYPE 'L' invoice line, stored in LRATED.
Load lifecycle
The strictly-forward status chain a load walks: TENDERED → DISPATCHED → DELIVERED → RATED → INVOICED → SETTLED (LSTAT T/D/L/R/I/S).
POD — Proof of Delivery
Confirmation that a stop has been delivered (SSTAT O→C, SACT stamped). A load is DELIVERED only once every stop is confirmed.
SBMJOB
Submit Job — the IBM i command that queues a program to run as a batch job (e.g. SBMJOB CMD(CALL PGM(FREIGHT/FRDAILY))).
Settlement
A driver's weekly pay statement: load-pay lines less standing deductions. Header FRSETH (HGROSS/HDEDUCT/HNET), detail FRSETD (signed).
Subfile
A 5250 display construct listing many rows on one screen (DDS SFL/SFLCTL). FRSTPIQ's stops list is a subfile, paged 5-at-a-time.
Tender
A booked shipment (FRLOAD at LSTAT='T') with stops defined and a driver/unit assigned, before anything has moved.
TMS — Transportation Management System
The software that manages loads, dispatch, rating, billing and settlement for a carrier — what FREIGHT/i is.