CBSTM03A
Source: cbl/CBSTM03A.CBL
Type: Batch program
CBSTM03A — Program Documentation
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 toDISPLAYthe job/step name and list DD names with their UCB validity. This has no effect on business logic. It then opensSTMT-FILEandHTML-FILEand initializes the in-memory transaction table. -
File-open sequencing via ALTER/GO TO —
0000-STARTis a dispatcher driven byWS-FL-DD, using the classic COBOLALTERstatement to redirect the paragraph8100-FILE-OPEN's GO TO target. The sequence is: - Open
TRNXFILE(8100-TRNXFILE-OPEN) → read first transaction record → switch toREADTRNXmode 8500-READTRNX-READloops, 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), thenCUSTFILE(8300-CUSTFILE-OPEN), thenACCTFILE(8400-ACCTFILE-OPEN), finally falling into1000-MAINLINE. -
Main processing loop (
1000-MAINLINE) — For each cross-reference record: 1000-XREFFILE-GET-NEXTreads the next XREF record (via subroutine call, see below); return code'10'signals end-of-file.2000-CUSTFILE-GETlooks up the customer record byXREF-CUST-ID.3000-ACCTFILE-GETlooks up the account record byXREF-ACCT-ID.5000-CREATE-STATEMENTwrites 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-GETscans the in-memory transaction table (WS-CARD-TBL) for entries matching the current card number, writes each matching transaction via6000-WRITE-TRANS, accumulatesWS-TOTAL-AMT, then writes the totals/footer lines to both files.-
The loop repeats until
END-OF-FILE = 'Y'. -
Shutdown —
1000-MAINLINEperforms the four file-close paragraphs (9100–9400), then closesSTMT-FILE/HTML-FILE, and9999-GOBACKends the program. -
Actual file I/O is delegated — None of
TRNXFILE,XREFFILE,CUSTFILE,ACCTFILEare 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) toCALL 'CBSTM03B', which presumably owns the actual file definitions. Return codeWS-M03B-RCdrives success/failure/eof handling here.
Inputs & outputs
| Name | Type | Purpose |
|---|---|---|
TRNXFILE (DD, via WS-FL-DD/CBSTM03B) |
Input | Transaction detail records, read sequentially and buffered into an in-memory table keyed by card number. Accessed only through subroutine CBSTM03B, not a native COBOL file. |
XREFFILE (via CBSTM03B) |
Input | Card cross-reference records (CARD-XREF-RECORD, copybook CVACT03Y), read sequentially; drives the main loop and supplies XREF-CUST-ID/XREF-ACCT-ID/XREF-CARD-NUM. |
CUSTFILE (via CBSTM03B) |
Input | Customer master, read by key (XREF-CUST-ID); copybook CUSTREC supplies name, address, FICO score. |
ACCTFILE (via CBSTM03B) |
Input | Account master, read by key (XREF-ACCT-ID); copybook CVACT01Y supplies account ID and current balance. |
STMT-FILE / DD STMTFILE |
Output | Fixed 80-byte plain-text statement records (FD-STMTFILE-REC), one per account, including header, name/address, balance/FICO, transaction lines, and totals. |
HTML-FILE / DD HTMLFILE |
Output | Fixed 100-byte HTML statement records (FD-HTMLFILE-REC) forming an HTML table document per account, mirroring the text statement content. |
Copybook COSTM01 |
Layout | Statement working-storage layout (not detailed in source shown but included in WORKING-STORAGE). |
Copybook CVACT03Y |
Layout | Card cross-reference record layout (CARD-XREF-RECORD). |
Copybook CUSTREC |
Layout | Customer record layout. |
Copybook CVACT01Y |
Layout | Account record layout. |
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-OPENuse the legacyALTERverb to change the destination of aGO TOat 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 normalPERFORM. - All external file I/O goes through
CALL 'CBSTM03B', not native COBOLOPEN/READ/WRITE/CLOSEverbs, forTRNXFILE,XREFFILE,CUSTFILE,ACCTFILE. The actual physical file assignments, VSAM/QSAM details, and error semantics live inCBSTM03B, which is not shown here — behavior of return codes'00','04','10', and others is inferred from calling code, not verified againstCBSTM03Bsource. - In-memory transaction table is hard-limited:
WS-TRNX-TABLEholds 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-RCand calls9999-ABEND-PROGRAMon unexpected codes, which displays a message and callsCEE3ABD(LE abend) — there is no recovery/retry logic, the job simply abends. - Only
1000-XREFFILE-GET-NEXTtreats 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-AMTis 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 sumsTRNX-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-READpopulates them,4000-TRNXFILE-GETconsumes 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 |