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:

  1. 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.

  2. STMTCALC (Statement Calculate): Reads the extract file and calculates final balances, interest accruals, fee assessments, and period-over-period comparisons for each account.

  3. 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).

  4. 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:

  1. 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.

  2. 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.

  3. 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.

  4. 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:

  1. The control card specifies RESTART-MEMBER-ID= with the member ID from the last checkpoint.
  2. The program reads and discards input records until reaching that member ID.
  3. 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

  1. 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?

  2. 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.

  3. 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?

  4. 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?

  5. 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?

  6. 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.