VENUE/i is the box office of a live-event venue: halls subdivided into price
zones, events booked into a hall for a promoter, ticket capture and priced ticket sales that
relieve seat inventory by zone, concessions sales against stand stock, per-event settlement to the
promoter (gross ticket sales less venue fee, facility fee and tax = promoter payout), an AP open-item
ledger of what the venue owes each promoter, payout application, AP ageing, and a balanced GL feed.
The application is classic ILE: RPG programs drive keyed physical/logical files, one COBOL control
report, one SQLRPGLE GL post, DDS display/printer files for the online screens and the ageing report,
and CL that wires the object build and the three job cycles. This manual is the reference for the
operator who runs the box office and the periodic cycles, and for the developer maintaining the
application. It is grounded entirely in the committed source under venue-app/
(src/sources.mjs, src/seed.mjs, and the test/vn_*.mjs drivers).
VENUE/i runs the full commercial life of a live event, from putting seats on sale to paying the promoter and feeding the general ledger:
VNHALL) is subdivided, per event, into price
zones (VNZONE); an event (VNEVNT) is booked into one hall for one
promoter, carrying its own venue-fee %, flat facility fee and tax %.VNTKTH/VNTKTL)
is priced at each zone's current price, then sold: each line that fits within its zone's
remaining capacity relieves seat inventory (ZSOLD rises) and is marked sold; a line
that would oversell is rejected whole.ZSOLD + (ZCAP−ZSOLD) =
ZCAP (sold + available = capacity) holds for every zone, always.VNCSAL) relieve on-hand
stock (VNCONC) and compute tax from the item's tax code.VNSETL row and an AP open
item (VNAPOP) are raised, payments (VNPAY) are applied against the open
item, the ledger is aged, and a balanced set of entries is posted to the GL
(VNGLDIST).VENUE/i is a conventional ILE application, not a two-layer SQL-PL design. The business rules live in the RPG programs themselves, each of which does exactly one step of the cycle against keyed native physical and logical files. The pattern is deliberate and repeated:
VNPRICE prices, VNSELL sells,
VNCONCPOST posts concessions, VNSETTL settles, VNPAYAP
applies payouts, VNAGE ages, VNSTMT prints, VNGLPST posts
the GL, VNAPRPT reconciles. Each reads the file(s) it owns, mutates only its own
rows, and DSPLYs a one-line result (e.g. VNSELL SOLD=3 REJECTED=1 SKIP=0).CHAIN,
SETLL/READE, UPDATE/WRITE. Two alternate
access paths (logical files) exist purely to give a step the key order it needs:
VNTKTLLF keys the ticket lines by event+zone for the settlement sum, and
VNAPDLF keys the AP items by due date for oldest-first ageing.VNGLPST,
uses embedded EXEC SQL against the one SQL table (VNGLDIST) to read the
already-posted totals and insert new balanced rows — the GL is the one place a set-based,
re-runnable "post the movement since last close" fits naturally.OSTAT, LSTAT, CSTAT, ESTAT,
PYSTAT) and advances it, so a re-run is a safe no-op — the property every test
suite verifies.The benefit for operations: each step is independently runnable and re-runnable, the CL cycles are
thin CALL chains, and the effect of any step is visible in one DSPLY line and in the file
it touched. Everything runs in library VENUE.
SETUP ONLINE BATCH (periodic)
----- ------ ----------------
VNSETUP (CL) VNMENU (5250) DAILY VNDAILY (CL)
CRT* objects opt 1 -> VNEVQIQ VNPRICE (price order lines)
compile pgms opt 2 -> VNTKTIQ VNSELL (sell / relieve VNZONE)
VNREFLD (seed) VNCONCPOST(post VNCSAL / relieve VNCONC)
halls/proms/patrons VNEVQIQ event avail
events/zones/conc VNTKTIQ order+subfile SETTLE VNSETTLE (CL)
VNSETTL (VNSETL + VNAPOP, event->S)
VNPAYAP (apply VNPAY -> VNAPOP)
MONTHLY VNMONTH (CL)
VNAGE (age VNAPOP via VNAPDLF)
VNSTMT (print VNAGEP)
VNGLPST (post VNGLDIST, SQL)
VNAPRPT (COBOL AP control report)
files: VNHALL VNPROM VNPATR VNEVNT VNZONE VNTKTH VNTKTL(+VNTKTLLF)
VNCONC VNCSAL VNSETL VNAPOP(+VNAPDLF) VNPAY VNGLDIST
A single ticket transaction flows: a patron order is captured into VNTKTH/VNTKTL
as new (OSTAT='N', lines LSTAT='O') → the daily cycle prices it
(VNPRICE), then sells it (VNSELL) — each fitting line relieves its zone
and goes LSTAT='S', the order goes 'P' (or 'H' if any line was
rejected) → after the event, VNSETTL sums the sold lines for the event, computes the
payout, writes VNSETL and raises the VNAPOP open item, and flips the event to
ESTAT='S'.
| Object | Type | Role |
|---|---|---|
| VNHALL | PF | Venue hall master (physical capacity HCAP). |
| VNPROM | PF | Promoter master (the AP "vendor"; PRTERMS payout days). |
| VNPATR | PF | Patron (ticket-buyer) master. |
| VNEVNT | PF | Event/performance header (fee%, facility fee, tax%, status). |
| VNZONE | PF | Price zones per event (ZCAP/ZSOLD). |
| VNTKTH | PF | Ticket order header. |
| VNTKTL | PF | Ticket order lines (one per zone per order). |
| VNTKTLLF | LF | Ticket lines keyed EVNTID+ZONEID (settlement/availability path). |
| VNCONC | PF | Concessions item master (on-hand CONHAND). |
| VNCSAL | PF | Concessions sales journal. |
| VNSETL | PF | Per-event settlement (gross/fees/tax/payout). |
| VNAPOP | PF | AP open items owed to promoters. |
| VNAPDLF | LF | Same AP items keyed by due date (ageing path). |
| VNPAY | PF | Payout runs (payments to promoters). |
| VNGLDIST | SQL table | GL distribution (DR/CR journal), + index VNGLDACC. |
| VNEVQD / VNTKTD / VNMENUD | DSPF | Event-avail / ticket-subfile / menu screens. |
| VNAGEP | PRTF | AP settlement ageing report. |
| VNREFLD | RPGLE | Seeds the reference data. |
| VNPRICE / VNSELL / VNCONCPOST | RPGLE | Daily-cycle steps. |
| VNSETTL / VNPAYAP | RPGLE | Settle-cycle steps. |
| VNAGE / VNSTMT | RPGLE | Monthly ageing & print. |
| VNGLPST | SQLRPGLE | Monthly GL post (embedded SQL). |
| VNAPRPT | ILE COBOL | Monthly AP control report. |
| VNEVQIQ / VNTKTIQ / VNMENU | RPGLE | Interactive inquiry / subfile / menu drivers. |
| VNSETUP | CLP | Object build + program compile. |
| VNDAILY / VNSETTLE / VNMONTH | CLP | The three job-cycle chains. |
The catalogue is 13 physical files + 2 logical files + 1 SQL table (with its index), 3 display files and 1 printer file, driven by 12 RPG programs, 1 SQLRPGLE, 1 ILE COBOL program and 4 CL programs. Sections D and F expand each.
VENUE/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). 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 VENUE — the tested jobs run with
LIBL = QSYS QGPL VENUE QTEMP and CURLIB = VENUE.
| To do this | Type on the command line |
|---|---|
| Open the operator main menu | CALL VENUE/VNMENU |
| Event availability inquiry (direct) | CALL VENUE/VNEVQIQ |
| Ticket order inquiry (direct) | CALL VENUE/VNTKTIQ |
| Build/compile every object (first install) | CALL VENUE/VNSETUP |
| Seed the reference data | CALL VENUE/VNREFLD |
| Run the daily box-office cycle | CALL VENUE/VNDAILY (or SBMJOB it) |
| Run the per-event settlement cycle | CALL VENUE/VNSETTLE |
| Run the monthly AP close | CALL VENUE/VNMONTH |
None of the batch programs take CALL parameters — each walks its file(s) from
*LOVAL and processes every eligible row, so a scheduled submission is a bare
CALL. Only VNMENU, VNEVQIQ and VNTKTIQ are
interactive; the batch programs run to completion and DSPLY a one-line result per step.
VNMENU (VNMENUD) is the operator entry point. It EXFMTs the menu, routes option
1 to a program CALL of VNEVQIQ and option 2 to
VNTKTIQ, reports "Invalid option." for anything else, and exits on F3.
A plain (non-subfile) screen. Key an event number and Enter: the program
CHAINs VNEVNT for the header (name, date, status), then reads the
first zone on file for that event (SETLL/READE on VNZONE)
and shows its price, capacity, sold, and the derived seats available (ZCAP−ZSOLD,
floored at 0) — the figure box-office staff actually care about. An unknown event clears the
detail and shows "Event not found."; F3 exits.
The app's subfile screen (DDS record TSFL under control record TCTL,
SFLPAG(5)/SFLSIZ(20), ROLLUP/ROLLDOWN paging). Key an
order number and Enter: it CHAINs VNTKTH for the
header (patron, status, order total) and loads every ticket line (SETLL/READE
on VNTKTL) into the subfile — sequence, zone, qty, price, net and line status. The
subfile is cleared and reloaded on each enquiry (write TCTL with *IN31
on to clear, drive SFLDSP from *IN32 so it shows only once a row is loaded).
An unknown order clears the header and shows "Order not found."; F3 exits.
ROLLUP(25)/ROLLDOWN(26)).VNTKTH/VNTKTL, VNCSAL, VNPAY) and then processed
by the cycles. VNEVQIQ/VNTKTIQ let the operator see availability and order state; they do not
mutate it.VENUE/i does not model a four-eyes maker–checker workflow. Its control posture is status/state gating + hard inventory limits, enforced in each program:
VNSELL considers only orders with OSTAT='N' and lines
LSTAT='O'; VNCONCPOST only CSTAT='N' sales;
VNSETTL refuses an event already ESTAT='S'/'X' and, as a
second guard, an event that already has a VNSETL row (CHAIN(EN));
VNPAYAP only PYSTAT='U' payments. This makes every step idempotent.ESTAT='H') or cancelled
('X') sells nothing — VNSELL rejects the whole order and skips it,
the box-office-closed state.LSTAT='X'); no partial seat
booking is ever made, and the order is flagged OSTAT='H' for review if any line
rejects. Concessions behave the same: a sale that exceeds on-hand is refused entirely and left
unposted.0.00 — an unsold
event never produces a negative payout, even though the flat facility fee still applies (that
becomes a venue-side loss, not a promoter receivable).VNGLPST posts DR = CR by construction (see F.3), and only the
movement since the last close, so a re-run posts nothing.Accountability is by journal, not by approval gate: every priced/sold ticket line, concessions
sale, settlement, AP open item, payment and GL entry is a durable row you can read back and reconcile
(the VNAPRPT COBOL control report and the VNSTMT ageing print exist for
exactly that).
VENUE/i's processing runs as three CL-chained cycles rather than one monolithic job: a daily
box-office cycle (price → sell → post concessions), a settle cycle (per-event
settlement → payout application), and a monthly AP close (age → print → GL post
→ control report). Each CL program simply ADDLIBLE VENUE and CALLs its
steps in order; none of the steps take parameters — they walk their files and process every
eligible row.
-- the three cycles, submittable as bare jobs SBMJOB CMD(CALL PGM(VENUE/VNDAILY)) JOB(VNDAILY) SBMJOB CMD(CALL PGM(VENUE/VNSETTLE)) JOB(VNSETTLE) SBMJOB CMD(CALL PGM(VENUE/VNMONTH)) JOB(VNMONTH) -- first install: build objects, then seed reference data CALL PGM(VENUE/VNSETUP) CALL PGM(VENUE/VNREFLD)
| Program | Cycle | Purpose | Reads / writes | Result DSPLY |
|---|---|---|---|---|
| VNPRICE | DAILY | Price every open order line at its zone price; stamp header net/tax/total (tax per-event). | reads VNZONE/VNEVNT; updates VNTKTL, VNTKTH. | VNPRICE PRICED=n SKIP=n |
| VNSELL | DAILY | Sell fitting lines (relieve zone inventory), reject oversells whole; set order P/H. | reads VNEVNT; updates VNZONE, VNTKTL, VNTKTH. | VNSELL SOLD=n REJECTED=n SKIP=n |
| VNCONCPOST | DAILY | Post new concessions sales, relieve on-hand stock, compute tax from item tax code. | updates VNCONC, VNCSAL. | VNCONCPOST POSTED=n SHORT=n SKIP=n |
| VNSETTL | SETTLE | Per-event settlement: sum sold lines, compute payout, raise settlement + AP item, event→S. | reads VNTKTLLF/VNPROM; writes VNSETL, VNAPOP; updates VNEVNT. | VNSETTL SETTLED=n SKIP=n |
| VNPAYAP | SETTLE | Apply unapplied payments against their AP open item; reduce open by exactly the amount taken. | updates VNAPOP, VNPAY. | VNPAYAP APPLIED=n SKIP=n |
| VNAGE | MONTHLY | Age each open AP item into bucket 0/1/2/3 by days overdue at the run date (30/360 serial). | reads VNAPDLF (due-date order); updates VNAPOP. | VNAGE B0=n B1=n B2=n B3=n |
| VNSTMT | MONTHLY | Print the AP settlement ageing report over open items, with page overflow. | reads VNAPDLF/VNPROM; writes VNAGEP (PRTF). | VNSTMT LINES=n OPEN=nnn |
| VNGLPST | MONTHLY | Post the settlement register as balanced DR/CR GL rows (movement since last close only). | reads VNSETL; SQL insert into VNGLDIST. | VNGLPST BATCH=202609 ROWS=n |
| VNAPRPT | MONTHLY | ILE COBOL control report proving the AP sub-ledger totals reconcile. | reads VNAPOP sequentially. | VNAPRPT RAISED/OPEN/ITEMS/OVERDUE |
VNPRICE walks the order headers; for each order that is not already posted/cancelled it prices
every non-cancelled line at its zone's current ZPRICE (TNET = TQTY × ZPRICE),
reads the event's ETAXPC, and stamps the header ONETVAL / OTAXVAL
(net × tax%) / OTOTVAL. It re-CHAINs the line and header after the
zone/event reads because those reads move the file cursor. Idempotent: it recomputes from
TQTY and the zone price every time.
VNSELL walks the headers; for each OSTAT='N' order whose event is on sale it reads
each open line, CHAINs the zone, computes free = ZCAP−ZSOLD, and —
whole-line-or-nothing — if free ≥ qty it raises ZSOLD and marks the line
'S', else marks it 'X' (rejected). An order with any rejected line goes
OSTAT='H', else 'P'. An event on hold/cancelled sells nothing.
VNCONCPOST walks new concessions sales; for each it CHAINs the item, refuses the
sale whole if on-hand < qty (leaves it 'N'), else relieves CONHAND, computes
tax (flat 8% for a 'S'-coded item, none for 'Z'), and stamps the sale
'P'.
Expected DSPLY (hand-derived book: 3 orders, 2 concessions sales): VNPRICE PRICED= 3 SKIP= 0 VNSELL SOLD= 3 REJECTED= 1 SKIP= 0 15xGA vs 10-cap zone rejected whole VNCONCPOST POSTED= 1 SHORT= 1 25xWATER vs 20 on-hand refused
VNSETTL walks the events; for a settleable event (not already 'S'/'X',
and no existing settlement row) it sums TNET over every LSTAT='S' ticket line
for the event through the event-keyed VNTKTLLF, computes venue fee (gross ×
EFEEPC/100), facility fee (flat EFACFEE), tax (gross × ETAXPC/100)
and payout (gross − vfee − ffee − tax, clamped ≥ 0), writes
VNSETL, flips the event to 'S', and raises a VNAPOP open item due
settlement-date + PRTERMS.
VNPAYAP walks the payments; for each unapplied (PYSTAT='U') payment it
CHAINs the nominated AP item and applies min(tendered, open): APPAID
rises, APOPEN falls, the item goes 'P' (paid) at zero open, and the payment is
stamped 'A' (fully applied) or 'P' (part).
Expected DSPLY (settle the daily book, then a 2000.00 payment): VNSETTL SETTLED= 2 SKIP= 0 VNPAYAP APPLIED= 1 SKIP= 0 EV0001 gross 4350.00, vfee 435.00, ffee 500.00, tax 217.50 -> payout 3197.50 EV0002 gross 0.00 (only line rejected) -> payout clamped to 0.00 payment 2000.00 vs open 3197.50 -> open falls to 1197.50, item stays open
VNAGE reads the open AP items oldest-due-first through VNAPDLF, and for each
item with open > 0 stamps APAGE from days overdue at the run date (20260930) using the
30/360 serial ((yyyy×12)+mm)×30+dd: 0 current, 1 = 1–30, 2 = 31–60,
3 = 61+. VNSTMT prints one VNAGEP detail line per open item (skipping zero-open
items), joining the promoter name, with page-overflow re-headers, and a total footer. VNGLPST
(SQLRPGLE) accumulates the settlement register and posts the movement since the last close as balanced
rows into VNGLDIST. VNAPRPT (COBOL) reads the whole AP ledger and reports raised /
open / item count / overdue count.
Expected DSPLY (real settled book + 3 seeded ageing items): VNAGE B0= 1 B1= 1 B2= 1 B3= 1 one item in each bucket VNSTMT LINES= 4 OPEN= 7697.5 4 open items; zero-open EV0002 skipped VNGLPST BATCH=202609 ROWS= 3 DR cash / CR AP / CR venue fee VNAPRPT ITEMS 5.00 OVERDUE 3.00 5 AP items, 3 aged past due GL: DR 1000-CASH 4350.00 = CR 2100-AP 3197.50 + CR 4100-VFEE 1152.50 (balances)
TNET
for the sold lines the settlement will later sum), and concessions post is independent but chained
last. The CL fixes this order.LSTAT='S' lines, which the daily
VNSELL produces; run the event's daily sells before settling it.VNAPOP, VNSETL); settle every due event before the monthly close.VNPAYAP needs an open item to apply against. The CL fixes this order.VNAGE
stamped); the GL post and COBOL control report can run in any order after that. The CL runs
age → print → GL → report.All files are in library VENUE, grounded in the DDS/SQL in src/sources.mjs.
Dates are stored as signed numeric YYYYMMDD (packed/zoned per DDS); money is packed decimal
(nP2); fee and tax percentages are packed 5P2 (e.g. 10.00 = 10%).
| Field | Type | Meaning |
|---|---|---|
| HALLID | 4A | Hall id (key), e.g. H001. |
| HNAME / HCITY | 30A / 20A | Hall name / city. |
| HCAP | 7P0 | Physical seat capacity of the hall. |
| HSTAT | 1A | Hall status (A active). |
Seeded: H001 RIVERSIDE ARENA (cap 2000), H002 THE GRANGE THEATRE (cap 600).
| Field | Type | Meaning |
|---|---|---|
| PROMO | 6A | Promoter id (key), e.g. PM0001. |
| PRNAME | 30A | Promoter name. |
| PRTERMS | 3S0 | Days after settlement the payout is due. |
| PRSTAT | 1A | Promoter status (A active). |
Seeded: PM0001 (14-day terms), PM0002 (30-day terms) — different terms so ageing has variety.
| Field | Type | Meaning |
|---|---|---|
| PATRID | 6A | Patron id (key). |
| PNAME / PEMAIL | 30A / 30A | Patron name / email. |
| PSTAT | 1A | Patron status (A active). |
| Field | Type | Meaning |
|---|---|---|
| EVNTID | 6A | Event id (key), e.g. EV0001. |
| HALLID / PROMO | 4A / 6A | Hall booked / promoter (FKs in intent). |
| ENAME | 30A | Event name. |
| EDATE | 8S0 | Event date (YYYYMMDD). |
| ESTAT | 1A | N new/on-sale, H on hold (box office closed), S settled, X cancelled. |
| EFEEPC | 5P2 | Venue fee % on gross ticket sales. |
| EFACFEE | 11P2 | Flat facility fee. |
| ETAXPC | 5P2 | Tax % on ticket sales. |
Seeded: EV0001 (arena, PM0001) 10% fee / 500.00 facility / 5% tax;
EV0002 (theatre, PM0002) 15% fee / 100.00 facility / 0% tax.
| Field | Type | Meaning |
|---|---|---|
| EVNTID / ZONEID | 6A / 2A | Event + zone (key). |
| ZNAME | 20A | Zone name (FLOOR, TIER 1, …). |
| ZPRICE | 9P2 | Per-ticket price in this zone. |
| ZCAP | 6P0 | Seat capacity allocated to this zone for this event. |
| ZSOLD | 6P0 | Running count of tickets sold in the zone. Available = ZCAP−ZSOLD. |
Seeded EV0001: FL 120.00/cap 200, T1 75.00/cap 500, T2 45.00/cap 300 (sum 1000 ≤ hall 2000, headroom). EV0002: GA 35.00/cap 10 (tiny, so an oversell test bites).
| Field | Type | Meaning |
|---|---|---|
| ORDNO | 8A | Order number (key), e.g. ORD00001. |
| PATRID / EVNTID | 6A / 6A | Buyer / event. |
| ODATE | 8S0 | Order date. |
| OSTAT | 1A | N new (not yet sold), P posted (tickets sold), H held (a line rejected), X cancelled. |
| ONETVAL / OTAXVAL / OTOTVAL | 11P2 | Order net / tax / total (stamped by VNPRICE). |
| Field | Type | Meaning |
|---|---|---|
| ORDNO / LSEQ | 8A / 3S0 | Order + line sequence (key). |
| EVNTID | 6A | Event (denormalised onto the line so VNTKTLLF can key on it). |
| ZONEID | 2A | Zone bought into. |
| TQTY | 5P0 | Tickets requested/sold on this line. |
| TPRICE / TNET | 9P2 / 11P2 | Zone price applied / line net (TQTY×TPRICE). |
| LSTAT | 1A | O open/unpriced-unsold, S sold (inventory relieved), X cancelled/rejected (no inventory taken). |
Non-unique logical file over VNTKTL: the per-event/per-zone sales enquiry the settlement
run and the availability screen both want. The base PF is keyed ORDNO/LSEQ and cannot be
walked positioned on an event id, so VNSETTL reads sold lines through this path.
| Field | Type | Meaning |
|---|---|---|
| ITEMNO | 6A | Item number (key). |
| CDESC | 20A | Description. |
| CPRICE | 7P2 | Unit price. |
| CONHAND | 7P0 | On-hand stock (relieved by a posted sale). |
| CTAXCD | 1A | Tax code: S standard (flat 8% at the till), Z zero-rated. |
| CSTAT | 1A | Item status (A active). |
Seeded: CN0001 lager 6.50/'S'/1000, CN0002 hot dog 5.00/'S'/300, CN0003 water 2.50/'Z'/20 (low stock, oversell test).
| Field | Type | Meaning |
|---|---|---|
| SALNO | 8A | Sale number (key). |
| EVNTID / ITEMNO | 6A / 6A | Event / item sold. |
| CQTY | 5P0 | Quantity. |
| CDATE | 8S0 | Sale date. |
| CNET / CTAX / CTOT | 11P2 | Net / tax / total (stamped at post). |
| CSTAT | 1A | N new (not yet posted), P posted (stock relieved). |
| Field | Type | Meaning |
|---|---|---|
| EVNTID / PROMO | 6A / 6A | Event settled / promoter paid. |
| SGROSS | 11P2 | Gross sold-ticket sales (Σ sold-line TNET). |
| SVFEE | 11P2 | Venue fee = SGROSS × EFEEPC/100. |
| SFFEE | 11P2 | Flat facility fee (EFACFEE, copied). |
| STAX | 11P2 | Tax = SGROSS × ETAXPC/100. |
| SPAYOUT | 11P2 | Promoter payout = SGROSS − SVFEE − SFFEE − STAX (clamped ≥ 0). |
| SSTAT | 1A | O open (AP raised, unpaid), P paid, ' ' unsettled. |
| Field | Type | Meaning |
|---|---|---|
| PROMO / EVNTID | 6A / 6A | Promoter owed + the event (key; a promoter's items sit together). |
| APINVDT / APDUEDT | 8S0 | Settlement (invoice) date / due date = invoice + PRTERMS. |
| APAMT | 11P2 | Payout raised (mirrors SPAYOUT at settlement). |
| APPAID | 11P2 | Amount paid so far. |
| APOPEN | 11P2 | Outstanding = APAMT − APPAID. |
| APAGE | 1S0 | Ageing bucket 0/1/2/3 (stamped by VNAGE). |
| APSTAT | 1A | O open, P paid (zero open). |
Second logical file over VNAPOP, keyed by due date, so the monthly ageing and print
walk the ledger oldest-due-first without sorting.
| Field | Type | Meaning |
|---|---|---|
| PAYNO | 8A | Payment number (key). |
| PROMO / PYEVNT | 6A / 6A | Promoter + event the payment nominates (its AP-item key). |
| PYDT | 8S0 | Payment date. |
| PYAMT | 11P2 | Amount tendered. |
| PYAPPL | 11P2 | Amount actually applied against the AP item. |
| PYSTAT | 1A | U unapplied, A fully applied, P part-applied. |
| Column | Type | Meaning |
|---|---|---|
| GLSEQ | DECIMAL(8,0) | Sequence (PK), continued run to run. |
| GLBATCH | DECIMAL(6,0) | Posting batch (e.g. 202609). |
| ACCT / DRCR | CHAR(9) / CHAR(1) | Account (1000-CASH, 2100-AP, 4100-VFEE) / D or C. |
| AMT | DECIMAL(11,2) | Signed posting amount. |
| GLREF / GLDT | CHAR(8) / DECIMAL(8,0) | Reference (SETTLE) / GL date. |
Index VNGLDACC on (ACCT, DRCR) — the by-account read the re-post guard uses.
CALL VENUE/VNSETUP (builds every object and compiles every
program; ends with a "VENUE setup complete." banner), then CALL VENUE/VNREFLD to seed
halls/promoters/patrons/events/zones/concessions.VNTKTH/VNTKTL, orders
OSTAT='N' with lines LSTAT='O') and concessions sales (into
VNCSAL, CSTAT='N').SBMJOB CMD(CALL PGM(VENUE/VNDAILY)).CALL VENUE/VNMENU.Pre-checks: confirm the job's library list includes VENUE; confirm the events
you intend to sell are ESTAT='N' (an 'H' event sells nothing).
Post-checks after the daily cycle:
VNPRICE PRICED= equals the count of orders that were priceable; already-posted
orders show in SKIP.VNSELL SOLD=/REJECTED= reconcile: a fully-sold order is OSTAT='P', an
order with a rejected (oversold) line is 'H', and every sold line is
LSTAT='S'.ZSOLD + (ZCAP−ZSOLD) = ZCAP, and a
rejected oversell left its zone untouched (ZSOLD unchanged).VNCONCPOST POSTED=/SHORT=: a posted sale is CSTAT='P' with
CONHAND relieved; a refused oversell stays 'N' with stock intact.SBMJOB CMD(CALL PGM(VENUE/VNSETTLE)). Confirm VNSETTL SETTLED= covers the
events you expected and VNPAYAP APPLIED= covers the payments you captured in
VNPAY.SELECT EVNTID, SGROSS, SVFEE, SFFEE, STAX, SPAYOUT, SSTAT FROM VENUE.VNSETL;
-- and the AP open items it raised
SELECT PROMO, EVNTID, APAMT, APPAID, APOPEN, APDUEDT, APSTAT FROM VENUE.VNAPOP;
Reconciling figures (the same ones the volume suites check against a hand-derived oracle):
SPAYOUT = SGROSS − SVFEE − SFFEE − STAX,
clamped at 0. Example EV0001: 4350.00 − 435.00 − 500.00 − 217.50 = 3197.50.APAMT=APOPEN equals SPAYOUT at
raise, due settlement-date + PRTERMS (EV0001: 20260901 + 14 = 20260915).APOPEN by exactly
min(tendered, open); a part payment leaves APSTAT='O' (2000.00 on 3197.50
→ open 1197.50).Month-end: submit SBMJOB CMD(CALL PGM(VENUE/VNMONTH)). Confirm the four DSPLY
lines (VNAGE buckets, VNSTMT LINES=/OPEN=, VNGLPST ROWS=,
VNAPRPT ITEMS/OVERDUE). Then reconcile the GL:
SELECT ACCT, DRCR, AMT FROM VENUE.VNGLDIST ORDER BY GLSEQ;
-- DR total must equal CR total: 4350.00 (DR cash) = 3197.50 (CR AP) + 1152.50 (CR VFEE)
Each program DSPLYs its result line. Every mutating step gates on a status flag and advances it, so the safe recovery for almost any partial failure is simply to re-submit — already-processed rows are skipped.
| Situation | Behaviour | Action |
|---|---|---|
| Daily cycle fails partway | Priced/sold rows carry their new status; unprocessed rows keep the old one. | Re-submit VNDAILY: priced orders re-price to the same value (recompute from TQTY×price), sold lines are skipped (LSTAT≠'O'), the rest catch up. Idempotent. |
| Re-run VNSELL | Only OSTAT='N' orders / 'O' lines are considered. | No-op: zone ZSOLD does not double, rejects are not re-rejected. |
| Re-run VNCONCPOST | Only CSTAT='N' sales considered. | Posts nothing new (POSTED=0); stock not double-relieved. |
| Re-run VNSETTL | Event already 'S'/'X', or a VNSETL row already exists (CHAIN(EN) guard). | Settles nothing (SETTLED=0); no duplicate settlement or AP item. |
| Re-run VNPAYAP | Only PYSTAT='U' payments considered. | Applies nothing (APPLIED=0); open balance does not fall twice. |
| Over-payment / zero-open item | Applies min(tendered, open); against a zero-open item applies 0.00 and leaves the payment part-applied (PYSTAT='P'). | Nothing owed is taken; no negative open. |
| Re-run VNAGE (same run date) | Recomputes buckets from due dates; stamps the same values. | Idempotent — identical bucket counts. |
| Re-run VNGLPST | Reads already-posted cash-DR / AP-CR and subtracts; a clean second run has zero movement. | Posts nothing (ROWS=0); GL row count unchanged. No double-post. |
VNAPRPT COBOL control report reconciles the AP sub-ledger (raised vs open vs overdue) and
the GL batch is self-balancing.The complete program surface, from src/sources.mjs. All objects are in library
VENUE. The RPG is fixed-form C-specs with /free islands, driving keyed DDS
files; the one SQLRPGLE program uses embedded EXEC SQL.
WRITEs the reference rows (2 halls, 2 promoters, 3 patrons, 2 events, 4
zones, 3 concessions items). DSPLYs the seed counts.LKEY(ORDNO,LSEQ) and ZKEY(EVNTID,ZONEID); re-CHAINs the line
and header after zone/event reads move the cursor. Skips OSTAT P/X and
LSTAT='X' lines.ZSOLD, sets line S/X and order
P/H. Reads the event first to honour hold/cancel. The seat check is free = ZCAP−ZSOLD
(floored 0), sell iff free ≥ TQTY.CONHAND, computes tax (8% for 'S', 0 for 'Z').
Refuses whole if CONHAND < CQTY (leaves sale 'N').LSTAT='S' TNET via VNTKTLLF, computes
vfee/ffee/tax/payout (payout clamped ≥ 0), WRITEs VNSETL and
VNAPOP, flips event to 'S'. Idempotent via CHAIN(EN) on the existing
settlement row.PYSTAT='U' payments against their AP item by APKEY(PROMO,EVNTID):
takes min(PYAMT, APOPEN), updates paid/open (item → 'P' at zero open), stamps
payment 'A'/'P'.VNAPDLF; stamps APAGE 0/1/2/3 from
days overdue at run date 20260930 using the 30/360 serial. Skips zero-open items.VNAGEP ageing report over open items (joins VNPROM for the
name), with page-overflow re-headers (OFLIND(*IN90)) and a count/total footer.VNGLDIST, subtracts, and if there is new movement posts DR 1000-CASH (gross), CR
2100-AP (payout), CR 4100-VFEE (the remainder) via EXEC SQL INSERT — balanced by
construction. Continues GLSEQ. DSPLYs batch and rows.VNAPOP; totals raised (AP-AMT), open
(AP-OPEN), item count, and overdue count (AP-AGE>0). The AP sub-ledger
reconciliation.CALL chains.The core data invariant the app is built around, asserted at the zone level by the daily suite:
for every VNZONE row, at all times: ZSOLD + (ZCAP - ZSOLD) = ZCAP sold + available = capacity VNSELL enforces it by only ever raising ZSOLD when a whole line fits: free = ZCAP - ZSOLD (floored at 0) if free >= TQTY: ZSOLD += TQTY ; line -> 'S' seats taken else: (zone untouched) ; line -> 'X' rejected whole
A rejected oversell therefore leaves its zone completely untouched (the GA zone stays
ZSOLD=0 after a 15-seat request against 10 seats), and a re-run never double-sells. At the
event level, the sum of a hall's zone capacities is kept within HCAP at seed time (EV0001:
200+500+300 = 1000 ≤ 2000).
Settlement (VNSETTL), per event: SGROSS = SUM(TNET) over LSTAT='S' lines for the event (via VNTKTLLF) SVFEE = SGROSS * EFEEPC / 100 SFFEE = EFACFEE (flat, always applies) STAX = SGROSS * ETAXPC / 100 SPAYOUT = max(0, SGROSS - SVFEE - SFFEE - STAX) AP application (VNPAYAP): take = min(PYAMT, APOPEN) APPAID += take ; APOPEN -= take ; APOPEN==0 -> APSTAT='P' GL post (VNGLPST) — balanced by construction: DR 1000-CASH = SGROSS (new movement only) CR 2100-AP = SPAYOUT CR 4100-VFEE = SGROSS - SPAYOUT (= vfee+ffee+tax retained by venue) => DR total == CR total
The GL re-post guard reads SUM(AMT) already in VNGLDIST for
1000-CASH/D and 2100-AP/C and subtracts, so only the movement since the last
close is posted; a clean second run posts nothing.
SETLL *LOVAL then a DOW/READ
loop terminating on the EOF indicator — the driver loop in every batch step.SETLL + READE on a key (e.g. all lines for an
order, or all lines for an event through VNTKTLLF).KLIST/KFLD for two-part keys
(order+seq, event+zone, promoter+event) used with CHAIN.CHAIN/read against another file moves the current
file's position, the step re-CHAINs the row it was updating before the
UPDATE — called out in the source (VNPRICE, VNSELL).VNTKTLLF event-first, VNAPDLF due-date-first).EXEC SQL SELECT … INTO for the posted totals and
the max sequence, EXEC SQL INSERT for each GL row, checking SQLCOD.*IN31) before reload, drive
SFLDSP from *IN32 so it displays only once a row is loaded.| Field | Value | Meaning |
|---|---|---|
| ESTAT (VNEVNT) | N / H / S / X | New/on-sale · on hold (closed) · settled · cancelled. |
| OSTAT (VNTKTH) | N / P / H / X | New · posted (sold) · held (a line rejected) · cancelled. |
| LSTAT (VNTKTL) | O / S / X | Open · sold (inventory relieved) · cancelled/rejected. |
| CSTAT (VNCSAL) | N / P | New · posted (stock relieved). |
| SSTAT (VNSETL) | O / P / ' ' | Open (AP raised) · paid · unsettled. |
| APSTAT (VNAPOP) | O / P | Open · paid (zero outstanding). |
| APAGE (VNAPOP) | 0 / 1 / 2 / 3 | Current · 1–30 · 31–60 · 61+ days overdue. |
| PYSTAT (VNPAY) | U / A / P | Unapplied · fully applied · part-applied. |
There are no SQLSTATE application codes: VENUE/i signals outcomes through these status
fields and the DSPLY result lines, not through SQL exceptions (the one SQL program, VNGLPST, checks
SQLCOD=0 only to count successful inserts).
VNAPOP row with amount
raised, paid and outstanding, and a due date. The payables mirror of a receivable ledger.VNCONC items,
VNCSAL sales). Posting relieves on-hand stock and taxes 'S'-coded items at a flat 8%.EFACFEE) the venue deducts from gross at settlement,
regardless of ticket volume — it applies even to an unsold event.VNGLDIST) of DR/CR entries. VENUE/i's posting is balanced
by construction: DR cash = CR AP + CR venue-fee remainder.gross − venue fee − facility fee
− tax, clamped at 0. Raised as an AP open item at settlement.VNZONE), with its own price and seat
capacity. Ticket lines buy into a zone and relieve its inventory.SBMJOB CMD(CALL PGM(VENUE/VNDAILY))).ZSOLD + (ZCAP−ZSOLD) = ZCAP (sold + available = capacity) that
holds for every zone at all times, enforced by whole-line-or-nothing selling.VNSETTL) that turns sold-ticket gross into a promoter
payout and an AP open item, and flips the event to settled.serial(yyyymmdd) =
((yyyy×12)+mm)×30+dd, days = serial(run) − serial(due). A stamping
convention, not a real calendar rollover.