CBSTM03A
Source: cbl/CBSTM03A.CBL
Type: Batch program
Purpose
CBSTM03A generates customer account statements from card transaction data, producing two parallel output formats: a plain-text statement file and an HTML-formatted statement file. It runs as a batch step (CREASTMT.STEP040) that joins card cross-reference, customer, account, and transaction data to build one statement per account, listing basic account details (balance, FICO score) followed by a list of transactions and their total. This is a CardDemo sample program explicitly designed to exercise legacy COBOL patterns (control block addressing, ALTER/GO TO, COMP-3, 2D tables) for modernization tooling testing.
How it works
-
Startup (lines before 0000-START) — The program inspects mainframe control blocks (PSA → TCB → TIOT) purely to DISPLAY the job/step name and list DD names with their UCB validity. This has no effect on business logic. It then opens STMT-FILE and HTML-FILE and initializes the in-memory transaction table.
-
File-open sequencing via ALTER/GO TO — 0000-START is a dispatcher driven by WS-FL-DD, using the classic COBOL ALTER statement to redirect the paragraph 8100-FILE-OPEN's GO TO target. The sequence is:
-
Open TRNXFILE (8100-TRNXFILE-OPEN) → read first transaction record → switch to READTRNX mode
-
8500-READTRNX-READ loops, reading all transaction records into an in-memory table (WS-TRNX-TABLE, keyed by card number, up to 51 cards × 10 transactions each) grouped by card number, counting transactions per card (WS-TRCT)
-
Once transactions are exhausted, switches to XREFFILE, opens it (8200-XREFFILE-OPEN), then CUSTFILE (8300-CUSTFILE-OPEN), then ACCTFILE (8400-ACCTFILE-OPEN), finally falling into 1000-MAINLINE.
-
Main processing loop (1000-MAINLINE) — For each cross-reference record:
-
1000-XREFFILE-GET-NEXT reads the next XREF record (via subroutine call, see below); return code '10' signals end-of-file.
-
2000-CUSTFILE-GET looks up the customer record by XREF-CUST-ID.
-
3000-ACCTFILE-GET looks up the account record by XREF-ACCT-ID.
-
5000-CREATE-STATEMENT writes the statement header/basic-details block to both the text file (ST-LINE0…ST-LINE12) and HTML file (5100-WRITE-HTML-HEADER, 5200-WRITE-HTML-NMADBS).
-
4000-TRNXFILE-GET scans the in-memory transaction table (WS-CARD-TBL) for entries matching the current card number, writes each matching transaction via 6000-WRITE-TRANS, accumulates WS-TOTAL-AMT, then writes the totals/footer lines to both files.
-
The loop repeats until END-OF-FILE = 'Y'.
-
Shutdown — 1000-MAINLINE performs the four file-close paragraphs (9100–9400), then closes STMT-FILE/HTML-FILE, and 9999-GOBACK ends the program.
-
Actual file I/O is delegated — None of TRNXFILE, XREFFILE, CUSTFILE, ACCTFILE are declared as COBOL files in this program (no SELECT/FD). All reads/opens/closes for them are performed by passing a request block (WS-M03B-AREA) to CALL 'CBSTM03B', which presumably owns the actual file definitions. Return code WS-M03B-RC drives success/failure/eof handling here.
Inputs & outputs
No CICS commands or SQL tables are used — this is pure batch COBOL with subroutine-mediated file access.
Things to know
-
Uses ALTER + GO TO — 0000-START/8100-FILE-OPEN use the legacy ALTER verb to change the destination of a GO TO at runtime. This is a self-modifying-code pattern that is hard to trace statically and is flagged in the source comments as intentional (to stress-test modernization tooling). Any refactoring tool must handle this control flow carefully; it does not behave like a normal PERFORM.
-
All external file I/O goes through CALL 'CBSTM03B', not native COBOL OPEN/READ/WRITE/CLOSE verbs, for TRNXFILE, XREFFILE, CUSTFILE, ACCTFILE. The actual physical file assignments, VSAM/QSAM details, and error semantics live in CBSTM03B, which is not shown here — behavior of return codes '00', '04', '10', and others is inferred from calling code, not verified against CBSTM03B source.
-
In-memory transaction table is hard-limited: WS-TRNX-TABLE holds at most 51 cards (OCCURS 51) with 10 transactions each (OCCURS 10). Any card with more than 51 distinct cards in a batch, or more than 10 transactions per card, will cause a table-overflow condition. No explicit bounds-checking/error handling for this limit is visible in the shown code — this is a risk if input volumes exceed these hard-coded sizes.
-
Error handling is uniform but abrupt: nearly every I/O paragraph checks WS-M03B-RC and calls 9999-ABEND-PROGRAM on unexpected codes, which displays a message and calls CEE3ABD (LE abend) — there is no recovery/retry logic, the job simply abends.
-
Only 1000-XREFFILE-GET-NEXT treats RC '10' as expected end-of-file; other GET paragraphs (CUSTFILE, ACCTFILE) treat any non-'00' code as an error, so a missing customer/account (e.g., broken cross-reference) will abend the whole job rather than skip the record.
-
Statement totals field ST-TOTAL-TRAMT/WS-TOTAL-AMT is described as "Total EXP" (total expense) in the text file, accumulated across all transactions per account — labeled as such in the layout (ST-LINE14A), though the field simply sums TRNX-AMT, so it is a net sum, not necessarily "expenses only" (no separate credit/debit distinction is visible in the shown code).
-
Control-block/TIOT inspection code at the top of PROCEDURE DIVISION (PSA/TCB/TIOT addressing) is diagnostic/display-only and has no effect on program logic or outputs — safe to ignore functionally, but reflects direct mainframe memory addressing that has no equivalent in non-mainframe environments and will need to be removed or stubbed during modernization.
-
Hard-coded HTML content: bank name ("Bank of XYZ"), address ("410 Terry Ave N, Seattle WA 99999"), and styling are embedded as level-88 literals directly in the program (HTML-L16–HTML-L18), meaning any branding change requires a code change/recompile.
-
CR-CNT/CR-JMP/TR-CNT/TR-JMP are used both as table subscripts and loop-control counters shared across paragraphs (8500-READTRNX-READ populates them, 4000-TRNXFILE-GET consumes them) — the coupling between these paragraphs via shared working-storage state (rather than parameters) is a maintenance risk.
Files
| Logical file | DD name |
|---|---|
| STMT-FILE | STMTFILE |
| HTML-FILE | HTMLFILE |
Copybooks
COSTM01, CUSTREC, CVACT01Y, CVACT03Y
Calls
CBSTM03B, CEE3ABD
Executed by
CREASTMT.STEP040
Paragraph flow
flowchart TD
0000_START["0000-START"]
1000_MAINLINE["1000-MAINLINE"]
9999_GOBACK["9999-GOBACK"]
1000_XREFFILE_GET_NEXT["1000-XREFFILE-GET-NEXT"]
2000_CUSTFILE_GET["2000-CUSTFILE-GET"]
3000_ACCTFILE_GET["3000-ACCTFILE-GET"]
4000_TRNXFILE_GET["4000-TRNXFILE-GET"]
5000_CREATE_STATEMENT["5000-CREATE-STATEMENT"]
5100_WRITE_HTML_HEADER["5100-WRITE-HTML-HEADER"]
5100_EXIT["5100-EXIT"]
5200_WRITE_HTML_NMADBS["5200-WRITE-HTML-NMADBS"]
5200_EXIT["5200-EXIT"]
6000_WRITE_TRANS["6000-WRITE-TRANS"]
8100_FILE_OPEN["8100-FILE-OPEN"]
8100_TRNXFILE_OPEN["8100-TRNXFILE-OPEN"]
8200_XREFFILE_OPEN["8200-XREFFILE-OPEN"]
8300_CUSTFILE_OPEN["8300-CUSTFILE-OPEN"]
8400_ACCTFILE_OPEN["8400-ACCTFILE-OPEN"]
8500_READTRNX_READ["8500-READTRNX-READ"]
8599_EXIT["8599-EXIT"]
9100_TRNXFILE_CLOSE["9100-TRNXFILE-CLOSE"]
9200_XREFFILE_CLOSE["9200-XREFFILE-CLOSE"]
9300_CUSTFILE_CLOSE["9300-CUSTFILE-CLOSE"]
9400_ACCTFILE_CLOSE["9400-ACCTFILE-CLOSE"]
9999_ABEND_PROGRAM["9999-ABEND-PROGRAM"]
0000_START -.-> 8100_FILE_OPEN
0000_START -.-> 8500_READTRNX_READ
0000_START -.-> 9999_GOBACK
1000_MAINLINE --> 1000_XREFFILE_GET_NEXT
1000_MAINLINE --> 2000_CUSTFILE_GET
1000_MAINLINE --> 3000_ACCTFILE_GET
1000_MAINLINE --> 4000_TRNXFILE_GET
1000_MAINLINE --> 5000_CREATE_STATEMENT
1000_MAINLINE --> 9100_TRNXFILE_CLOSE
1000_MAINLINE --> 9200_XREFFILE_CLOSE
1000_MAINLINE --> 9300_CUSTFILE_CLOSE
1000_MAINLINE --> 9400_ACCTFILE_CLOSE
1000_XREFFILE_GET_NEXT --> 9999_ABEND_PROGRAM
2000_CUSTFILE_GET --> 9999_ABEND_PROGRAM
3000_ACCTFILE_GET --> 9999_ABEND_PROGRAM
4000_TRNXFILE_GET --> 6000_WRITE_TRANS
5000_CREATE_STATEMENT --> 5100_WRITE_HTML_HEADER
5000_CREATE_STATEMENT --> 5200_WRITE_HTML_NMADBS
8100_FILE_OPEN -.-> 8100_TRNXFILE_OPEN
8100_TRNXFILE_OPEN -.-> 0000_START
8100_TRNXFILE_OPEN --> 9999_ABEND_PROGRAM
8200_XREFFILE_OPEN -.-> 0000_START
8200_XREFFILE_OPEN --> 9999_ABEND_PROGRAM
8300_CUSTFILE_OPEN -.-> 0000_START
8300_CUSTFILE_OPEN --> 9999_ABEND_PROGRAM
8400_ACCTFILE_OPEN -.-> 1000_MAINLINE
8400_ACCTFILE_OPEN --> 9999_ABEND_PROGRAM
8500_READTRNX_READ -.-> 8500_READTRNX_READ
8500_READTRNX_READ -.-> 8599_EXIT
8500_READTRNX_READ --> 9999_ABEND_PROGRAM
8599_EXIT -.-> 0000_START
9100_TRNXFILE_CLOSE --> 9999_ABEND_PROGRAM
9200_XREFFILE_CLOSE --> 9999_ABEND_PROGRAM
9300_CUSTFILE_CLOSE --> 9999_ABEND_PROGRAM
9400_ACCTFILE_CLOSE --> 9999_ABEND_PROGRAM
Paragraphs
| Paragraph | Line | Performs |
|---|---|---|
| 0000-START | 296 | |
| 1000-MAINLINE | 316 | 1000-XREFFILE-GET-NEXT, 2000-CUSTFILE-GET, 3000-ACCTFILE-GET, 5000-CREATE-STATEMENT, 4000-TRNXFILE-GET, 9100-TRNXFILE-CLOSE |
| 9999-GOBACK | 341 | |
| 1000-XREFFILE-GET-NEXT | 345 | 9999-ABEND-PROGRAM |
| 2000-CUSTFILE-GET | 368 | 9999-ABEND-PROGRAM |
| 3000-ACCTFILE-GET | 392 | 9999-ABEND-PROGRAM |
| 4000-TRNXFILE-GET | 416 | 6000-WRITE-TRANS |
| 5000-CREATE-STATEMENT | 458 | 5100-WRITE-HTML-HEADER, 5200-WRITE-HTML-NMADBS |
| 5100-WRITE-HTML-HEADER | 506 | |
| 5100-EXIT | 554 | |
| 5200-WRITE-HTML-NMADBS | 558 | |
| 5200-EXIT | 671 | |
| 6000-WRITE-TRANS | 675 | |
| 8100-FILE-OPEN | 726 | |
| 8100-TRNXFILE-OPEN | 730 | 9999-ABEND-PROGRAM, 9999-ABEND-PROGRAM |
| 8200-XREFFILE-OPEN | 765 | 9999-ABEND-PROGRAM |
| 8300-CUSTFILE-OPEN | 783 | 9999-ABEND-PROGRAM |
| 8400-ACCTFILE-OPEN | 801 | 9999-ABEND-PROGRAM |
| 8500-READTRNX-READ | 818 | 9999-ABEND-PROGRAM |
| 8599-EXIT | 849 | |
| 9100-TRNXFILE-CLOSE | 856 | 9999-ABEND-PROGRAM |
| 9200-XREFFILE-CLOSE | 873 | 9999-ABEND-PROGRAM |
| 9300-CUSTFILE-CLOSE | 889 | 9999-ABEND-PROGRAM |
| 9400-ACCTFILE-CLOSE | 905 | 9999-ABEND-PROGRAM |
| 9999-ABEND-PROGRAM | 921 |