Case Study 1: Monthly Statement Generation Batch System
Background
Pacific Coast Credit Union generates monthly account statements for its 120,000 members. The statement generation process runs on the last business day of each month and must complete within a six-hour batch window (midnight to 6:00 AM). The process involves four COBOL programs executed sequentially, each producing output that feeds the next:
-
STMTEXTR (Statement Extract): Reads the account master and transaction history files, extracting all activity for the current statement period. This is the longest-running step, processing millions of transaction records. It implements checkpoint/restart to protect against failures.
-
STMTCALC (Statement Calculate): Reads the extract file and calculates final balances, interest accruals, fee assessments, and period-over-period comparisons for each account.
-
STMTFMT (Statement Format): Formats the calculated data into print-ready statement pages with control break processing for customer-level subtotals (when a customer has multiple accounts).
-
STMTPRNT (Statement Print): Produces the final print files in AFP (Advanced Function Presentation) format for the high-speed laser printer, plus a PDF archive for online banking access.
Senior developer Mariko Tanaka designed and coded the system. This case study presents the complete COBOL programs for the extract and format steps, the JCL for the entire job stream, and the checkpoint/restart implementation.
JCL for the Complete Job Stream
//STMTGEN JOB (PCCU01),'MONTHLY STATEMENTS',
// CLASS=A,MSGCLASS=X,
// MSGLEVEL=(1,1),
// NOTIFY=&SYSUID,
// REGION=0M
//*================================================================*
//* MONTHLY STATEMENT GENERATION - Pacific Coast Credit Union *
//* Schedule: Last business day of each month, 00:00 *
//* Oncall: Operations Center x2200 *
//* Expected runtime: 4-5 hours *
//* *
//* RESTART INSTRUCTIONS: *
//* STEXTRACT: Restart in place - checkpoint/restart will resume. *
//* STCALC: Delete PCCU.PROD.STMT.CALC.OUTPUT, restart STCALC. *
//* STFORMAT: Delete PCCU.PROD.STMT.PRINT.DATA, restart STFORMAT. *
//* STPRINT: Restart STPRINT - output is SYSOUT. *
//*================================================================*
//*
//JOBLIB DD DSN=PCCU.PROD.STMT.LOADLIB,DISP=SHR
// DD DSN=PCCU.PROD.COMMON.LOADLIB,DISP=SHR
//*
//*================================================================*
//* STEP 1: EXTRACT - Pull statement-period data from master files *
//* Long-running step with checkpoint/restart every 10,000 members. *
//*================================================================*
//STEXTRACT EXEC PGM=STMTEXTR,
// TIME=180
//ACCTMAST DD DSN=PCCU.PROD.ACCT.MASTER,DISP=SHR
//TXNHIST DD DSN=PCCU.PROD.TXN.HISTORY,DISP=SHR
//MEMBMAST DD DSN=PCCU.PROD.MEMBER.MASTER,DISP=SHR
//EXTRACT DD DSN=PCCU.PROD.STMT.EXTRACT,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=VB,LRECL=2000,BLKSIZE=27998),
// SPACE=(CYL,(100,20),RLSE),
// UNIT=SYSDA
//CHKPTDS DD DSN=PCCU.PROD.STMT.CHECKPOINT,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=FB,LRECL=200,BLKSIZE=27000),
// SPACE=(CYL,(1,1),RLSE),
// UNIT=SYSDA
//CTLCARD DD *
STMT-PERIOD-START=2025-01-01
STMT-PERIOD-END=2025-01-31
CHECKPOINT-INTERVAL=10000
RESTART-MEMBER-ID=0000000000
/*
//SYSOUT DD SYSOUT=X
//SYSUDUMP DD SYSOUT=X
//*
//*================================================================*
//* STEP 2: CALCULATE - Compute balances, interest, and fees *
//*================================================================*
//STCALC EXEC PGM=STMTCALC,
// COND=(4,LT,STEXTRACT)
//EXTRACT DD DSN=PCCU.PROD.STMT.EXTRACT,DISP=SHR
//RATEFILE DD DSN=PCCU.PROD.INTEREST.RATES,DISP=SHR
//FEESCHED DD DSN=PCCU.PROD.FEE.SCHEDULE,DISP=SHR
//CALCOUT DD DSN=PCCU.PROD.STMT.CALC.OUTPUT,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=VB,LRECL=2500,BLKSIZE=27998),
// SPACE=(CYL,(120,20),RLSE),
// UNIT=SYSDA
//SYSOUT DD SYSOUT=X
//SYSUDUMP DD SYSOUT=X
//*
//*================================================================*
//* STEP 3: FORMAT - Produce print-ready statement pages *
//*================================================================*
//STFORMAT EXEC PGM=STMTFMT,
// COND=(4,LT,STCALC)
//CALCIN DD DSN=PCCU.PROD.STMT.CALC.OUTPUT,DISP=SHR
//PRTOUT DD DSN=PCCU.PROD.STMT.PRINT.DATA,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=FBA,LRECL=133,BLKSIZE=27930),
// SPACE=(CYL,(200,50),RLSE),
// UNIT=SYSDA
//SUMMARY DD SYSOUT=H,
// DCB=(RECFM=FBA,LRECL=133,BLKSIZE=0)
//SYSOUT DD SYSOUT=X
//SYSUDUMP DD SYSOUT=X
//*
//*================================================================*
//* STEP 4: PRINT - Produce AFP print stream and PDF archive *
//*================================================================*
//STPRINT EXEC PGM=STMTPRNT,
// COND=(4,LT,STFORMAT)
//PRTIN DD DSN=PCCU.PROD.STMT.PRINT.DATA,DISP=SHR
//AFPOUT DD SYSOUT=A,
// DCB=(RECFM=FBA,LRECL=133,BLKSIZE=0)
//PDFOUT DD DSN=PCCU.PROD.STMT.PDF.ARCHIVE(+1),
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=VB,LRECL=32756,BLKSIZE=32760),
// SPACE=(CYL,(300,50),RLSE),
// UNIT=SYSDA
//SYSOUT DD SYSOUT=X
//SYSUDUMP DD SYSOUT=X
//*
//*================================================================*
//* CLEANUP: Delete intermediate work files *
//*================================================================*
// IF (STPRINT.RC <= 4) THEN
//STCLEAN EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=X
//SYSIN DD *
DELETE PCCU.PROD.STMT.EXTRACT PURGE
DELETE PCCU.PROD.STMT.CALC.OUTPUT PURGE
DELETE PCCU.PROD.STMT.PRINT.DATA PURGE
DELETE PCCU.PROD.STMT.CHECKPOINT PURGE
SET MAXCC = 0
/*
// ENDIF
Program 1: Statement Extract with Checkpoint/Restart
IDENTIFICATION DIVISION.
PROGRAM-ID. STMTEXTR.
*================================================================*
* STMTEXTR - Monthly Statement Extract Program *
* Reads account master and transaction history, extracting *
* all activity within the statement period for each member. *
* Implements checkpoint/restart for recovery. *
*================================================================*
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT ACCT-MASTER ASSIGN TO ACCTMAST
FILE STATUS IS WS-ACCT-FS.
SELECT TXN-HISTORY ASSIGN TO TXNHIST
FILE STATUS IS WS-TXN-FS.
SELECT MEMBER-MASTER ASSIGN TO MEMBMAST
FILE STATUS IS WS-MEMB-FS.
SELECT EXTRACT-FILE ASSIGN TO EXTRACT
FILE STATUS IS WS-EXTR-FS.
SELECT CHECKPOINT-FILE ASSIGN TO CHKPTDS
FILE STATUS IS WS-CHKP-FS.
SELECT CTL-CARD-FILE ASSIGN TO CTLCARD
FILE STATUS IS WS-CTL-FS.
DATA DIVISION.
FILE SECTION.
FD ACCT-MASTER
RECORDING MODE IS F
RECORD CONTAINS 300 CHARACTERS.
01 ACCT-MASTER-REC PIC X(300).
FD TXN-HISTORY
RECORDING MODE IS F
RECORD CONTAINS 150 CHARACTERS.
01 TXN-HISTORY-REC PIC X(150).
FD MEMBER-MASTER
RECORDING MODE IS F
RECORD CONTAINS 250 CHARACTERS.
01 MEMBER-MASTER-REC PIC X(250).
FD EXTRACT-FILE
RECORDING MODE IS V
RECORD CONTAINS 50 TO 2000 CHARACTERS.
01 EXTRACT-RECORD PIC X(2000).
FD CHECKPOINT-FILE
RECORDING MODE IS F
RECORD CONTAINS 200 CHARACTERS.
01 CHECKPOINT-RECORD PIC X(200).
FD CTL-CARD-FILE
RECORDING MODE IS F
RECORD CONTAINS 80 CHARACTERS.
01 CTL-CARD-REC PIC X(80).
WORKING-STORAGE SECTION.
*================================================================*
* File status fields *
*================================================================*
01 WS-ACCT-FS PIC XX VALUE '00'.
01 WS-TXN-FS PIC XX VALUE '00'.
01 WS-MEMB-FS PIC XX VALUE '00'.
01 WS-EXTR-FS PIC XX VALUE '00'.
01 WS-CHKP-FS PIC XX VALUE '00'.
01 WS-CTL-FS PIC XX VALUE '00'.
*================================================================*
* Account master record layout *
*================================================================*
01 WS-ACCT-REC.
05 WS-ACCT-MEMBER-ID PIC X(10).
05 WS-ACCT-NUMBER PIC X(12).
05 WS-ACCT-TYPE PIC X(3).
88 ACCT-CHECKING VALUE 'CHK'.
88 ACCT-SAVINGS VALUE 'SAV'.
88 ACCT-MONEY-MKT VALUE 'MMK'.
88 ACCT-CERTDEP VALUE 'CRT'.
88 ACCT-LOAN VALUE 'LON'.
05 WS-ACCT-STATUS PIC X(1).
88 ACCT-ACTIVE VALUE 'A'.
88 ACCT-CLOSED VALUE 'C'.
88 ACCT-DORMANT VALUE 'D'.
05 WS-ACCT-OPEN-DATE PIC X(10).
05 WS-ACCT-BALANCE PIC S9(11)V99 COMP-3.
05 WS-ACCT-AVAIL-BAL PIC S9(11)V99 COMP-3.
05 WS-ACCT-PREV-BAL PIC S9(11)V99 COMP-3.
05 WS-ACCT-INT-RATE PIC 9V9(4) COMP-3.
05 WS-ACCT-BRANCH PIC X(4).
05 FILLER PIC X(234).
*================================================================*
* Transaction history record layout *
*================================================================*
01 WS-TXN-REC.
05 WS-TXN-ACCT-NUM PIC X(12).
05 WS-TXN-DATE PIC X(10).
05 WS-TXN-SEQ PIC 9(6).
05 WS-TXN-TYPE PIC X(3).
05 WS-TXN-AMOUNT PIC S9(9)V99 COMP-3.
05 WS-TXN-RUN-BAL PIC S9(11)V99 COMP-3.
05 WS-TXN-DESC PIC X(40).
05 WS-TXN-CHECK-NUM PIC X(8).
05 WS-TXN-REF PIC X(15).
05 FILLER PIC X(38).
*================================================================*
* Member master record layout *
*================================================================*
01 WS-MEMB-REC.
05 WS-MEMB-ID PIC X(10).
05 WS-MEMB-LAST-NAME PIC X(25).
05 WS-MEMB-FIRST-NAME PIC X(20).
05 WS-MEMB-ADDR1 PIC X(30).
05 WS-MEMB-ADDR2 PIC X(30).
05 WS-MEMB-CITY PIC X(20).
05 WS-MEMB-STATE PIC X(2).
05 WS-MEMB-ZIP PIC X(10).
05 WS-MEMB-PHONE PIC X(15).
05 WS-MEMB-EMAIL PIC X(50).
05 WS-MEMB-JOIN-DATE PIC X(10).
05 WS-MEMB-TYPE PIC X(1).
05 FILLER PIC X(27).
*================================================================*
* Extract output record (variable length) *
*================================================================*
01 WS-EXTRACT-OUT.
05 WS-EXT-REC-TYPE PIC X(1).
88 EXT-HEADER VALUE 'H'.
88 EXT-ACCOUNT VALUE 'A'.
88 EXT-TRANSACTION VALUE 'T'.
88 EXT-TRAILER VALUE 'Z'.
05 WS-EXT-MEMBER-ID PIC X(10).
05 WS-EXT-DATA PIC X(1989).
*================================================================*
* Checkpoint data area *
*================================================================*
01 WS-CHECKPOINT-DATA.
05 WS-CHK-TIMESTAMP PIC X(26).
05 WS-CHK-MEMBER-ID PIC X(10).
05 WS-CHK-MEMBERS-PROC PIC 9(7).
05 WS-CHK-ACCTS-PROC PIC 9(7).
05 WS-CHK-TXNS-PROC PIC 9(9).
05 WS-CHK-EXTRACT-COUNT PIC 9(9).
05 FILLER PIC X(132).
*================================================================*
* Control parameters *
*================================================================*
01 WS-PERIOD-START PIC X(10).
01 WS-PERIOD-END PIC X(10).
01 WS-CHKP-INTERVAL PIC 9(7) VALUE 10000.
01 WS-RESTART-MEMBER PIC X(10) VALUE SPACES.
*================================================================*
* Processing counters and flags *
*================================================================*
01 WS-MEMBERS-PROCESSED PIC 9(7) VALUE ZEROS.
01 WS-ACCOUNTS-PROCESSED PIC 9(7) VALUE ZEROS.
01 WS-TXNS-PROCESSED PIC 9(9) VALUE ZEROS.
01 WS-EXTRACT-WRITTEN PIC 9(9) VALUE ZEROS.
01 WS-MEMBERS-SINCE-CHKP PIC 9(7) VALUE ZEROS.
01 WS-ACCT-EOF PIC X VALUE 'N'.
88 ACCT-AT-END VALUE 'Y'.
01 WS-TXN-EOF PIC X VALUE 'N'.
88 TXN-AT-END VALUE 'Y'.
01 WS-MEMB-EOF PIC X VALUE 'N'.
88 MEMB-AT-END VALUE 'Y'.
01 WS-IS-RESTART PIC X VALUE 'N'.
88 IS-RESTART VALUE 'Y'.
*================================================================*
* Account counters for current member *
*================================================================*
01 WS-CURR-MEMB-ACCTS PIC 9(3) VALUE ZEROS.
01 WS-CURR-MEMB-TXNS PIC 9(5) VALUE ZEROS.
01 WS-SAVE-MEMBER-ID PIC X(10) VALUE SPACES.
*================================================================*
* Work fields *
*================================================================*
01 WS-SYS-DATE PIC 9(8).
01 WS-SYS-TIME PIC 9(8).
01 WS-CURRENT-TIMESTAMP PIC X(26).
PROCEDURE DIVISION.
0000-MAIN-CONTROL.
PERFORM 1000-INITIALIZE
PERFORM 2000-PROCESS-MEMBERS
PERFORM 9000-WRAP-UP
STOP RUN.
*================================================================*
* 1000-INITIALIZE: Open files, read control cards, check for *
* restart condition. *
*================================================================*
1000-INITIALIZE.
OPEN INPUT ACCT-MASTER
OPEN INPUT TXN-HISTORY
OPEN INPUT MEMBER-MASTER
OPEN INPUT CTL-CARD-FILE
OPEN OUTPUT EXTRACT-FILE
OPEN I-O CHECKPOINT-FILE
PERFORM 1100-READ-CONTROL-CARDS
PERFORM 1200-CHECK-RESTART
DISPLAY '============================================='
DISPLAY ' STMTEXTR - Statement Extract'
DISPLAY ' Period: ' WS-PERIOD-START
' to ' WS-PERIOD-END
IF IS-RESTART
DISPLAY ' *** RESTART from member: '
WS-RESTART-MEMBER ' ***'
END-IF
DISPLAY '============================================='
.
*================================================================*
* 1100-READ-CONTROL-CARDS: Parse control card parameters. *
*================================================================*
1100-READ-CONTROL-CARDS.
PERFORM UNTIL WS-CTL-FS NOT = '00'
READ CTL-CARD-FILE INTO CTL-CARD-REC
AT END
CONTINUE
NOT AT END
EVALUATE TRUE
WHEN CTL-CARD-REC(1:19) =
'STMT-PERIOD-START='
MOVE CTL-CARD-REC(20:10)
TO WS-PERIOD-START
WHEN CTL-CARD-REC(1:17) =
'STMT-PERIOD-END='
MOVE CTL-CARD-REC(18:10)
TO WS-PERIOD-END
WHEN CTL-CARD-REC(1:21) =
'CHECKPOINT-INTERVAL='
MOVE CTL-CARD-REC(22:7)
TO WS-CHKP-INTERVAL
WHEN CTL-CARD-REC(1:19) =
'RESTART-MEMBER-ID='
MOVE CTL-CARD-REC(20:10)
TO WS-RESTART-MEMBER
END-EVALUATE
END-READ
END-PERFORM
CLOSE CTL-CARD-FILE
.
*================================================================*
* 1200-CHECK-RESTART: If restart member ID is non-zero, *
* skip forward in all input files to that member. *
*================================================================*
1200-CHECK-RESTART.
IF WS-RESTART-MEMBER NOT = '0000000000'
AND WS-RESTART-MEMBER NOT = SPACES
MOVE 'Y' TO WS-IS-RESTART
PERFORM 1210-SKIP-TO-MEMBER
ELSE
MOVE 'N' TO WS-IS-RESTART
END-IF
.
*================================================================*
* 1210-SKIP-TO-MEMBER: Advance all three input files past *
* the restart member ID. *
*================================================================*
1210-SKIP-TO-MEMBER.
* Skip member master
PERFORM UNTIL MEMB-AT-END
OR WS-MEMB-ID >= WS-RESTART-MEMBER
READ MEMBER-MASTER INTO WS-MEMB-REC
AT END MOVE 'Y' TO WS-MEMB-EOF
END-READ
END-PERFORM
* Skip account master
PERFORM UNTIL ACCT-AT-END
OR WS-ACCT-MEMBER-ID >= WS-RESTART-MEMBER
READ ACCT-MASTER INTO WS-ACCT-REC
AT END MOVE 'Y' TO WS-ACCT-EOF
END-READ
END-PERFORM
* Skip transaction history
PERFORM UNTIL TXN-AT-END
OR WS-TXN-ACCT-NUM(1:10) >= WS-RESTART-MEMBER
READ TXN-HISTORY INTO WS-TXN-REC
AT END MOVE 'Y' TO WS-TXN-EOF
END-READ
END-PERFORM
DISPLAY ' Skipped to member: ' WS-RESTART-MEMBER
.
*================================================================*
* 2000-PROCESS-MEMBERS: Main loop - for each member, extract *
* their accounts and transactions for the statement period. *
*================================================================*
2000-PROCESS-MEMBERS.
* Priming read of member master
READ MEMBER-MASTER INTO WS-MEMB-REC
AT END MOVE 'Y' TO WS-MEMB-EOF
END-READ
* Priming read of account master
READ ACCT-MASTER INTO WS-ACCT-REC
AT END MOVE 'Y' TO WS-ACCT-EOF
END-READ
* Priming read of transaction history
READ TXN-HISTORY INTO WS-TXN-REC
AT END MOVE 'Y' TO WS-TXN-EOF
END-READ
PERFORM UNTIL MEMB-AT-END
MOVE WS-MEMB-ID TO WS-SAVE-MEMBER-ID
MOVE ZEROS TO WS-CURR-MEMB-ACCTS
MOVE ZEROS TO WS-CURR-MEMB-TXNS
PERFORM 2100-WRITE-MEMBER-HEADER
PERFORM 2200-EXTRACT-MEMBER-ACCOUNTS
PERFORM 2300-WRITE-MEMBER-TRAILER
ADD 1 TO WS-MEMBERS-PROCESSED
ADD 1 TO WS-MEMBERS-SINCE-CHKP
PERFORM 2400-CHECK-CHECKPOINT
READ MEMBER-MASTER INTO WS-MEMB-REC
AT END MOVE 'Y' TO WS-MEMB-EOF
END-READ
END-PERFORM
.
*================================================================*
* 2100-WRITE-MEMBER-HEADER: Write a header extract record *
* containing member demographic information. *
*================================================================*
2100-WRITE-MEMBER-HEADER.
INITIALIZE WS-EXTRACT-OUT
MOVE 'H' TO WS-EXT-REC-TYPE
MOVE WS-MEMB-ID TO WS-EXT-MEMBER-ID
MOVE WS-MEMB-REC TO WS-EXT-DATA(1:250)
WRITE EXTRACT-RECORD FROM WS-EXTRACT-OUT
ADD 1 TO WS-EXTRACT-WRITTEN
.
*================================================================*
* 2200-EXTRACT-MEMBER-ACCOUNTS: Read all accounts for the *
* current member and their transactions. *
*================================================================*
2200-EXTRACT-MEMBER-ACCOUNTS.
PERFORM UNTIL ACCT-AT-END
OR WS-ACCT-MEMBER-ID > WS-SAVE-MEMBER-ID
IF WS-ACCT-MEMBER-ID = WS-SAVE-MEMBER-ID
AND ACCT-ACTIVE
ADD 1 TO WS-CURR-MEMB-ACCTS
ADD 1 TO WS-ACCOUNTS-PROCESSED
PERFORM 2210-WRITE-ACCOUNT-RECORD
PERFORM 2220-EXTRACT-TRANSACTIONS
END-IF
READ ACCT-MASTER INTO WS-ACCT-REC
AT END MOVE 'Y' TO WS-ACCT-EOF
END-READ
END-PERFORM
.
*================================================================*
* 2210-WRITE-ACCOUNT-RECORD: Write account detail to extract. *
*================================================================*
2210-WRITE-ACCOUNT-RECORD.
INITIALIZE WS-EXTRACT-OUT
MOVE 'A' TO WS-EXT-REC-TYPE
MOVE WS-SAVE-MEMBER-ID TO WS-EXT-MEMBER-ID
MOVE WS-ACCT-REC TO WS-EXT-DATA(1:300)
WRITE EXTRACT-RECORD FROM WS-EXTRACT-OUT
ADD 1 TO WS-EXTRACT-WRITTEN
.
*================================================================*
* 2220-EXTRACT-TRANSACTIONS: Read all transactions for the *
* current account within the statement period. *
*================================================================*
2220-EXTRACT-TRANSACTIONS.
PERFORM UNTIL TXN-AT-END
OR WS-TXN-ACCT-NUM > WS-ACCT-NUMBER
IF WS-TXN-ACCT-NUM = WS-ACCT-NUMBER
IF WS-TXN-DATE >= WS-PERIOD-START
AND WS-TXN-DATE <= WS-PERIOD-END
PERFORM 2221-WRITE-TXN-RECORD
ADD 1 TO WS-CURR-MEMB-TXNS
ADD 1 TO WS-TXNS-PROCESSED
END-IF
END-IF
READ TXN-HISTORY INTO WS-TXN-REC
AT END MOVE 'Y' TO WS-TXN-EOF
END-READ
END-PERFORM
.
*================================================================*
* 2221-WRITE-TXN-RECORD: Write one transaction to extract. *
*================================================================*
2221-WRITE-TXN-RECORD.
INITIALIZE WS-EXTRACT-OUT
MOVE 'T' TO WS-EXT-REC-TYPE
MOVE WS-SAVE-MEMBER-ID TO WS-EXT-MEMBER-ID
MOVE WS-TXN-REC TO WS-EXT-DATA(1:150)
WRITE EXTRACT-RECORD FROM WS-EXTRACT-OUT
ADD 1 TO WS-EXTRACT-WRITTEN
.
*================================================================*
* 2300-WRITE-MEMBER-TRAILER: Write a trailer record with *
* member-level counts. *
*================================================================*
2300-WRITE-MEMBER-TRAILER.
INITIALIZE WS-EXTRACT-OUT
MOVE 'Z' TO WS-EXT-REC-TYPE
MOVE WS-SAVE-MEMBER-ID TO WS-EXT-MEMBER-ID
MOVE WS-CURR-MEMB-ACCTS TO WS-EXT-DATA(1:3)
MOVE WS-CURR-MEMB-TXNS TO WS-EXT-DATA(4:5)
WRITE EXTRACT-RECORD FROM WS-EXTRACT-OUT
ADD 1 TO WS-EXTRACT-WRITTEN
.
*================================================================*
* 2400-CHECK-CHECKPOINT: Write checkpoint every N members. *
*================================================================*
2400-CHECK-CHECKPOINT.
IF WS-MEMBERS-SINCE-CHKP >= WS-CHKP-INTERVAL
PERFORM 2410-WRITE-CHECKPOINT
MOVE ZEROS TO WS-MEMBERS-SINCE-CHKP
END-IF
.
*================================================================*
* 2410-WRITE-CHECKPOINT: Save current position and counters. *
*================================================================*
2410-WRITE-CHECKPOINT.
ACCEPT WS-SYS-DATE FROM DATE YYYYMMDD
ACCEPT WS-SYS-TIME FROM TIME
INITIALIZE WS-CHECKPOINT-DATA
STRING WS-SYS-DATE '-' WS-SYS-TIME
DELIMITED SIZE INTO WS-CHK-TIMESTAMP
MOVE WS-SAVE-MEMBER-ID TO WS-CHK-MEMBER-ID
MOVE WS-MEMBERS-PROCESSED TO WS-CHK-MEMBERS-PROC
MOVE WS-ACCOUNTS-PROCESSED TO WS-CHK-ACCTS-PROC
MOVE WS-TXNS-PROCESSED TO WS-CHK-TXNS-PROC
MOVE WS-EXTRACT-WRITTEN TO WS-CHK-EXTRACT-COUNT
WRITE CHECKPOINT-RECORD FROM WS-CHECKPOINT-DATA
DISPLAY 'CHECKPOINT: Member=' WS-SAVE-MEMBER-ID
' Members=' WS-MEMBERS-PROCESSED
' Accounts=' WS-ACCOUNTS-PROCESSED
' Txns=' WS-TXNS-PROCESSED
.
*================================================================*
* 9000-WRAP-UP: Close files and display summary. *
*================================================================*
9000-WRAP-UP.
CLOSE ACCT-MASTER
CLOSE TXN-HISTORY
CLOSE MEMBER-MASTER
CLOSE EXTRACT-FILE
CLOSE CHECKPOINT-FILE
DISPLAY ' '
DISPLAY '============================================='
DISPLAY ' STMTEXTR - PROCESSING COMPLETE'
DISPLAY ' Members Processed: '
WS-MEMBERS-PROCESSED
DISPLAY ' Accounts Processed: '
WS-ACCOUNTS-PROCESSED
DISPLAY ' Transactions Extracted: '
WS-TXNS-PROCESSED
DISPLAY ' Extract Records: '
WS-EXTRACT-WRITTEN
DISPLAY '============================================='
IF WS-MEMBERS-PROCESSED = ZEROS
DISPLAY '*** WARNING: No members processed ***'
MOVE 4 TO RETURN-CODE
ELSE
MOVE 0 TO RETURN-CODE
END-IF
.
Program 3: Statement Format with Control Break Processing
IDENTIFICATION DIVISION.
PROGRAM-ID. STMTFMT.
*================================================================*
* STMTFMT - Statement Format Program *
* Reads calculated statement data and produces print-ready *
* pages with control break processing for member subtotals. *
*================================================================*
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CALC-INPUT ASSIGN TO CALCIN
FILE STATUS IS WS-CALC-FS.
SELECT PRINT-OUTPUT ASSIGN TO PRTOUT
FILE STATUS IS WS-PRT-FS.
SELECT SUMMARY-FILE ASSIGN TO SUMMARY
FILE STATUS IS WS-SUM-FS.
DATA DIVISION.
FILE SECTION.
FD CALC-INPUT
RECORDING MODE IS V
RECORD CONTAINS 50 TO 2500 CHARACTERS.
01 CALC-INPUT-REC PIC X(2500).
FD PRINT-OUTPUT
RECORDING MODE IS F
RECORD CONTAINS 133 CHARACTERS.
01 PRINT-OUTPUT-REC PIC X(133).
FD SUMMARY-FILE
RECORDING MODE IS F
RECORD CONTAINS 133 CHARACTERS.
01 SUMMARY-OUTPUT-REC PIC X(133).
WORKING-STORAGE SECTION.
01 WS-CALC-FS PIC XX VALUE '00'.
01 WS-PRT-FS PIC XX VALUE '00'.
01 WS-SUM-FS PIC XX VALUE '00'.
*================================================================*
* Input record (from STMTCALC output) *
*================================================================*
01 WS-CALC-REC.
05 WS-CALC-REC-TYPE PIC X(1).
88 CALC-HEADER VALUE 'H'.
88 CALC-ACCOUNT VALUE 'A'.
88 CALC-TRANSACTION VALUE 'T'.
88 CALC-TRAILER VALUE 'Z'.
05 WS-CALC-MEMBER-ID PIC X(10).
05 WS-CALC-DATA PIC X(2489).
*================================================================*
* Parsed fields from calculated data *
*================================================================*
01 WS-MEMB-NAME PIC X(45).
01 WS-MEMB-ADDRESS PIC X(100).
01 WS-ACCT-NUM-DISP PIC X(12).
01 WS-ACCT-TYPE-DISP PIC X(15).
01 WS-ACCT-BAL-CURR PIC S9(11)V99.
01 WS-ACCT-BAL-PREV PIC S9(11)V99.
01 WS-ACCT-INT-EARNED PIC S9(7)V99.
01 WS-ACCT-FEES PIC S9(5)V99.
01 WS-TXN-DATE-DISP PIC X(10).
01 WS-TXN-DESC-DISP PIC X(40).
01 WS-TXN-AMT-DISP PIC S9(9)V99.
01 WS-TXN-BAL-DISP PIC S9(11)V99.
*================================================================*
* Print control fields *
*================================================================*
01 WS-LINE-COUNT PIC 99 VALUE 99.
01 WS-PAGE-COUNT PIC 9(5) VALUE ZEROS.
01 WS-LINES-PER-PAGE PIC 99 VALUE 55.
*================================================================*
* Control break fields *
*================================================================*
01 WS-PREV-MEMBER-ID PIC X(10) VALUE HIGH-VALUES.
01 WS-MEMBER-TOTAL-BAL PIC S9(13)V99 VALUE ZEROS.
01 WS-MEMBER-ACCT-COUNT PIC 9(3) VALUE ZEROS.
01 WS-MEMBER-TXN-COUNT PIC 9(5) VALUE ZEROS.
*================================================================*
* Grand totals for summary report *
*================================================================*
01 WS-GRAND-MEMBERS PIC 9(7) VALUE ZEROS.
01 WS-GRAND-ACCOUNTS PIC 9(7) VALUE ZEROS.
01 WS-GRAND-TXNS PIC 9(9) VALUE ZEROS.
01 WS-GRAND-BALANCE PIC S9(15)V99 VALUE ZEROS.
01 WS-GRAND-PAGES PIC 9(7) VALUE ZEROS.
*================================================================*
* Print line structures *
*================================================================*
01 WS-PRINT-LINE.
05 WS-PL-CC PIC X(1).
05 WS-PL-DATA PIC X(132).
01 WS-STMT-HEADER-1.
05 FILLER PIC X(1) VALUE '1'.
05 FILLER PIC X(30) VALUE SPACES.
05 FILLER PIC X(35)
VALUE 'PACIFIC COAST CREDIT UNION'.
05 FILLER PIC X(40) VALUE SPACES.
05 FILLER PIC X(6) VALUE 'PAGE: '.
05 WS-HDR-PAGE PIC Z(4)9.
05 FILLER PIC X(15) VALUE SPACES.
01 WS-STMT-HEADER-2.
05 FILLER PIC X(1) VALUE ' '.
05 FILLER PIC X(30) VALUE SPACES.
05 FILLER PIC X(30)
VALUE 'MONTHLY ACCOUNT STATEMENT'.
05 FILLER PIC X(71) VALUE SPACES.
01 WS-STMT-MEMBER-LINE.
05 FILLER PIC X(1) VALUE ' '.
05 FILLER PIC X(10) VALUE 'Member: '.
05 WS-SML-NAME PIC X(45).
05 FILLER PIC X(10) VALUE SPACES.
05 FILLER PIC X(12) VALUE 'Member ID: '.
05 WS-SML-ID PIC X(10).
05 FILLER PIC X(44) VALUE SPACES.
01 WS-STMT-ACCT-HDR.
05 FILLER PIC X(1) VALUE '0'.
05 FILLER PIC X(5) VALUE SPACES.
05 FILLER PIC X(15) VALUE 'Account Number'.
05 FILLER PIC X(3) VALUE SPACES.
05 FILLER PIC X(15) VALUE 'Account Type'.
05 FILLER PIC X(3) VALUE SPACES.
05 FILLER PIC X(18) VALUE 'Previous Balance'.
05 FILLER PIC X(3) VALUE SPACES.
05 FILLER PIC X(18) VALUE 'Current Balance'.
05 FILLER PIC X(51) VALUE SPACES.
01 WS-STMT-ACCT-LINE.
05 FILLER PIC X(1) VALUE ' '.
05 FILLER PIC X(5) VALUE SPACES.
05 WS-SAL-ACCT-NUM PIC X(12).
05 FILLER PIC X(6) VALUE SPACES.
05 WS-SAL-ACCT-TYPE PIC X(15).
05 FILLER PIC X(3) VALUE SPACES.
05 WS-SAL-PREV-BAL PIC $$$,$$$,$$$,$$9.99-.
05 FILLER PIC X(1) VALUE SPACES.
05 WS-SAL-CURR-BAL PIC $$$,$$$,$$$,$$9.99-.
05 FILLER PIC X(51) VALUE SPACES.
01 WS-STMT-TXN-HDR.
05 FILLER PIC X(1) VALUE '0'.
05 FILLER PIC X(10) VALUE SPACES.
05 FILLER PIC X(12) VALUE 'Date'.
05 FILLER PIC X(42) VALUE 'Description'.
05 FILLER PIC X(18) VALUE 'Amount'.
05 FILLER PIC X(18) VALUE 'Balance'.
05 FILLER PIC X(33) VALUE SPACES.
01 WS-STMT-TXN-LINE.
05 FILLER PIC X(1) VALUE ' '.
05 FILLER PIC X(10) VALUE SPACES.
05 WS-STL-DATE PIC X(10).
05 FILLER PIC X(2) VALUE SPACES.
05 WS-STL-DESC PIC X(40).
05 FILLER PIC X(2) VALUE SPACES.
05 WS-STL-AMOUNT PIC $$$$,$$$,$$9.99-.
05 FILLER PIC X(2) VALUE SPACES.
05 WS-STL-BALANCE PIC $$$,$$$,$$$,$$9.99-.
05 FILLER PIC X(31) VALUE SPACES.
01 WS-STMT-MEMB-TOTAL.
05 FILLER PIC X(1) VALUE '0'.
05 FILLER PIC X(5) VALUE SPACES.
05 FILLER PIC X(40)
VALUE 'TOTAL RELATIONSHIP BALANCE:'.
05 FILLER PIC X(23) VALUE SPACES.
05 WS-SMT-TOTAL PIC $$$,$$$, MATH9 $,$$9.99-.
05 FILLER PIC X(42) VALUE SPACES.
01 WS-STMT-SEPARATOR.
05 FILLER PIC X(1) VALUE ' '.
05 FILLER PIC X(5) VALUE SPACES.
05 FILLER PIC X(126) VALUE ALL '-'.
05 FILLER PIC X(1) VALUE SPACES.
01 WS-EOF-FLAG PIC X VALUE 'N'.
88 END-OF-FILE VALUE 'Y'.
PROCEDURE DIVISION.
0000-MAIN-CONTROL.
PERFORM 1000-INITIALIZE
PERFORM 2000-FORMAT-STATEMENTS
PERFORM 3000-WRITE-SUMMARY
PERFORM 9000-WRAP-UP
STOP RUN.
*================================================================*
* 1000-INITIALIZE: Open all files. *
*================================================================*
1000-INITIALIZE.
OPEN INPUT CALC-INPUT
OPEN OUTPUT PRINT-OUTPUT
OPEN OUTPUT SUMMARY-FILE
DISPLAY 'STMTFMT - Statement Formatting started.'
.
*================================================================*
* 2000-FORMAT-STATEMENTS: Main processing loop. Reads *
* calculated records and formats them into print pages. *
* Control break fires when member ID changes. *
*================================================================*
2000-FORMAT-STATEMENTS.
READ CALC-INPUT INTO WS-CALC-REC
AT END MOVE 'Y' TO WS-EOF-FLAG
END-READ
PERFORM UNTIL END-OF-FILE
EVALUATE TRUE
WHEN CALC-HEADER
PERFORM 2100-PROCESS-MEMBER-HEADER
WHEN CALC-ACCOUNT
PERFORM 2200-PROCESS-ACCOUNT
WHEN CALC-TRANSACTION
PERFORM 2300-PROCESS-TRANSACTION
WHEN CALC-TRAILER
PERFORM 2400-PROCESS-TRAILER
END-EVALUATE
READ CALC-INPUT INTO WS-CALC-REC
AT END MOVE 'Y' TO WS-EOF-FLAG
END-READ
END-PERFORM
* Fire final control break for last member
IF WS-PREV-MEMBER-ID NOT = HIGH-VALUES
PERFORM 2500-MEMBER-BREAK
END-IF
.
*================================================================*
* 2100-PROCESS-MEMBER-HEADER: New member detected. Fire *
* control break for previous member, then start new statement. *
*================================================================*
2100-PROCESS-MEMBER-HEADER.
* Control break for previous member
IF WS-PREV-MEMBER-ID NOT = HIGH-VALUES
PERFORM 2500-MEMBER-BREAK
END-IF
* Start new member
MOVE WS-CALC-MEMBER-ID TO WS-PREV-MEMBER-ID
MOVE ZEROS TO WS-MEMBER-TOTAL-BAL
MOVE ZEROS TO WS-MEMBER-ACCT-COUNT
MOVE ZEROS TO WS-MEMBER-TXN-COUNT
* Parse member name from calculated data
MOVE WS-CALC-DATA(27:45) TO WS-MEMB-NAME
* Force new page for each member statement
MOVE 99 TO WS-LINE-COUNT
PERFORM 2600-CHECK-PAGE-BREAK
* Print member identification
MOVE WS-MEMB-NAME TO WS-SML-NAME
MOVE WS-CALC-MEMBER-ID TO WS-SML-ID
WRITE PRINT-OUTPUT-REC FROM WS-STMT-MEMBER-LINE
ADD 1 TO WS-LINE-COUNT
WRITE PRINT-OUTPUT-REC FROM WS-STMT-SEPARATOR
ADD 1 TO WS-LINE-COUNT
ADD 1 TO WS-GRAND-MEMBERS
.
*================================================================*
* 2200-PROCESS-ACCOUNT: Format account summary line. *
*================================================================*
2200-PROCESS-ACCOUNT.
PERFORM 2600-CHECK-PAGE-BREAK
* Parse account fields from calculated data
MOVE WS-CALC-DATA(13:12) TO WS-ACCT-NUM-DISP
MOVE WS-CALC-DATA(25:15) TO WS-ACCT-TYPE-DISP
MOVE WS-CALC-DATA(40:13) TO WS-ACCT-BAL-PREV
MOVE WS-CALC-DATA(53:13) TO WS-ACCT-BAL-CURR
* Print account header on first account
IF WS-MEMBER-ACCT-COUNT = ZEROS
WRITE PRINT-OUTPUT-REC FROM WS-STMT-ACCT-HDR
ADD 2 TO WS-LINE-COUNT
END-IF
* Format account line
MOVE WS-ACCT-NUM-DISP TO WS-SAL-ACCT-NUM
MOVE WS-ACCT-TYPE-DISP TO WS-SAL-ACCT-TYPE
MOVE WS-ACCT-BAL-PREV TO WS-SAL-PREV-BAL
MOVE WS-ACCT-BAL-CURR TO WS-SAL-CURR-BAL
WRITE PRINT-OUTPUT-REC FROM WS-STMT-ACCT-LINE
ADD 1 TO WS-LINE-COUNT
* Print transaction header for this account
WRITE PRINT-OUTPUT-REC FROM WS-STMT-TXN-HDR
ADD 2 TO WS-LINE-COUNT
* Accumulate member totals
ADD WS-ACCT-BAL-CURR TO WS-MEMBER-TOTAL-BAL
ADD 1 TO WS-MEMBER-ACCT-COUNT
ADD 1 TO WS-GRAND-ACCOUNTS
.
*================================================================*
* 2300-PROCESS-TRANSACTION: Format transaction detail line. *
*================================================================*
2300-PROCESS-TRANSACTION.
PERFORM 2600-CHECK-PAGE-BREAK
* Parse transaction fields
MOVE WS-CALC-DATA(13:10) TO WS-TXN-DATE-DISP
MOVE WS-CALC-DATA(23:40) TO WS-TXN-DESC-DISP
MOVE WS-CALC-DATA(63:11) TO WS-TXN-AMT-DISP
MOVE WS-CALC-DATA(74:13) TO WS-TXN-BAL-DISP
* Format transaction line
MOVE WS-TXN-DATE-DISP TO WS-STL-DATE
MOVE WS-TXN-DESC-DISP TO WS-STL-DESC
MOVE WS-TXN-AMT-DISP TO WS-STL-AMOUNT
MOVE WS-TXN-BAL-DISP TO WS-STL-BALANCE
WRITE PRINT-OUTPUT-REC FROM WS-STMT-TXN-LINE
ADD 1 TO WS-LINE-COUNT
ADD 1 TO WS-MEMBER-TXN-COUNT
ADD 1 TO WS-GRAND-TXNS
.
*================================================================*
* 2400-PROCESS-TRAILER: Member trailer record - just counts. *
*================================================================*
2400-PROCESS-TRAILER.
CONTINUE
.
*================================================================*
* 2500-MEMBER-BREAK: Print member relationship total. *
*================================================================*
2500-MEMBER-BREAK.
WRITE PRINT-OUTPUT-REC FROM WS-STMT-SEPARATOR
MOVE WS-MEMBER-TOTAL-BAL TO WS-SMT-TOTAL
WRITE PRINT-OUTPUT-REC FROM WS-STMT-MEMB-TOTAL
ADD WS-MEMBER-TOTAL-BAL TO WS-GRAND-BALANCE
.
*================================================================*
* 2600-CHECK-PAGE-BREAK: New page if current page is full. *
*================================================================*
2600-CHECK-PAGE-BREAK.
IF WS-LINE-COUNT >= WS-LINES-PER-PAGE
ADD 1 TO WS-PAGE-COUNT
MOVE WS-PAGE-COUNT TO WS-HDR-PAGE
WRITE PRINT-OUTPUT-REC FROM WS-STMT-HEADER-1
WRITE PRINT-OUTPUT-REC FROM WS-STMT-HEADER-2
MOVE 4 TO WS-LINE-COUNT
ADD 1 TO WS-GRAND-PAGES
END-IF
.
*================================================================*
* 3000-WRITE-SUMMARY: Produce summary report. *
*================================================================*
3000-WRITE-SUMMARY.
INITIALIZE WS-PRINT-LINE
MOVE '1' TO WS-PL-CC
MOVE 'STATEMENT GENERATION SUMMARY'
TO WS-PL-DATA(20:30)
WRITE SUMMARY-OUTPUT-REC FROM WS-PRINT-LINE
INITIALIZE WS-PRINT-LINE
MOVE ' ' TO WS-PL-CC
STRING 'Total Members: ' WS-GRAND-MEMBERS
DELIMITED SIZE INTO WS-PL-DATA
WRITE SUMMARY-OUTPUT-REC FROM WS-PRINT-LINE
INITIALIZE WS-PRINT-LINE
MOVE ' ' TO WS-PL-CC
STRING 'Total Accounts: ' WS-GRAND-ACCOUNTS
DELIMITED SIZE INTO WS-PL-DATA
WRITE SUMMARY-OUTPUT-REC FROM WS-PRINT-LINE
INITIALIZE WS-PRINT-LINE
MOVE ' ' TO WS-PL-CC
STRING 'Total Transactions:' WS-GRAND-TXNS
DELIMITED SIZE INTO WS-PL-DATA
WRITE SUMMARY-OUTPUT-REC FROM WS-PRINT-LINE
INITIALIZE WS-PRINT-LINE
MOVE ' ' TO WS-PL-CC
STRING 'Total Pages: ' WS-GRAND-PAGES
DELIMITED SIZE INTO WS-PL-DATA
WRITE SUMMARY-OUTPUT-REC FROM WS-PRINT-LINE
.
*================================================================*
* 9000-WRAP-UP: Close files and report. *
*================================================================*
9000-WRAP-UP.
CLOSE CALC-INPUT
CLOSE PRINT-OUTPUT
CLOSE SUMMARY-FILE
DISPLAY 'STMTFMT - Complete.'
DISPLAY ' Members: ' WS-GRAND-MEMBERS
DISPLAY ' Accounts: ' WS-GRAND-ACCOUNTS
DISPLAY ' Transactions: ' WS-GRAND-TXNS
DISPLAY ' Pages: ' WS-GRAND-PAGES
.
Solution Walkthrough
Multi-Program Pipeline Architecture
The statement generation system follows the classic mainframe batch pipeline pattern: each program reads the output of the previous program, transforms the data, and produces output for the next. This design offers several advantages:
-
Restartability: If the format step fails, only the format step needs to be rerun. The extract and calculate steps do not need to be repeated because their output files are preserved.
-
Testability: Each program can be tested independently with sample input files. The extract can be tested against a small member file, the formatter can be tested with hand-crafted calculated data.
-
Separation of concerns: The extract program knows about file structures and date filtering. The calculator knows about interest and fee formulas. The formatter knows about page layout and print control. No program needs to know all three.
-
Resource management: The extract step needs heavy I/O against the master files. The format step needs CPU for string manipulation. The print step needs access to the print subsystem. Separating them allows each to be tuned independently.
Checkpoint/Restart in STMTEXTR
The extract program writes a checkpoint record every 10,000 members. The checkpoint contains the last processed member ID and all counters. On restart:
- The control card specifies
RESTART-MEMBER-ID=with the member ID from the last checkpoint. - The program reads and discards input records until reaching that member ID.
- Processing resumes from that point with counters restored.
This is a simplified application-level checkpoint. In a production environment, the checkpoint might also use the system-level REPOSITION facility or IMS checkpoint services. The key design principle is that the checkpoint data must contain enough information to reconstruct the program's state at the checkpoint point.
Control Break Processing in STMTFMT
The format program uses a member-level control break. Each member's statement is a logical group containing a header record, one or more account records (each followed by transaction records), and a trailer record. The control break fires when a new member header is encountered, printing the previous member's relationship total.
The final control break -- for the last member in the file -- is fired explicitly after the main loop ends. This is the same pattern used in Chapter 8's tax collection report case study, applied here to a production statement generation scenario.
ASA Carriage Control
The print output uses FBA (Fixed Block ASA) format. The first byte of each 133-byte record is the ASA carriage control character:
'1'in WS-STMT-HEADER-1: Skip to top of new page before printing.'0'in WS-STMT-ACCT-HDR and WS-STMT-TXN-HDR: Double space before printing.' '(space) in detail lines: Single space before printing.
This carriage control is interpreted by the print subsystem (JES2/JES3) when the SYSOUT dataset is printed.
Discussion Questions
-
The extract program reads three input files (member master, account master, transaction history) simultaneously, coordinating their positions by member ID and account number. What happens if the files are not in the same sort order? How would you add validation to detect misaligned files early?
-
The checkpoint interval of 10,000 members is specified in the control card. If each member averages 3 accounts and 50 transactions, how much data is processed between checkpoints? Calculate the worst-case reprocessing time if the program abends just before a checkpoint, given an I/O rate of 5,000 records per second.
-
The pipeline architecture writes intermediate files between steps. These files can be very large (the extract for 120,000 members with full transaction history). What are the storage implications? How would you estimate the SPACE parameter for each intermediate file? What happens if a file runs out of space mid-write?
-
The format program starts a new page for each member (
MOVE 99 TO WS-LINE-COUNT). For members with only one account and few transactions, this wastes paper. How would you modify the design to print multiple members per page while maintaining clear visual separation? -
If the credit union wanted to add electronic statement delivery (PDF via email) alongside printed statements, what changes would be needed to the pipeline? Would you add a new step or modify an existing one? How would the control flow change for members who opt out of paper statements?
-
The JCL uses COND=(4,LT,previous-step) to allow steps to proceed if the previous step returned RC=4 (warnings). In what situations would an extract program return RC=4 instead of RC=0? Design a warning-level return code scheme for the extract program.