Case Study 2: Branch Performance Summary Report
Background
Great Plains National Bank operates 42 branches organized into 6 regions across a four-state territory. Executive leadership requires a weekly performance summary report that shows key metrics at the branch level, with subtotals at the regional level and grand totals at the company level. The report includes transaction volumes, deposit totals, loan origination amounts, and revenue figures.
This report is a classic example of a multi-level control break report -- the kind of report that Report Writer was specifically designed to handle. The data is sorted by region, then by branch within each region. As the program reads through the data, it must detect when the branch changes (minor control break) and when the region changes (major control break), printing appropriate subtotals at each transition.
Without Report Writer, implementing a three-level control break report requires approximately 15 to 20 paragraphs of procedural code: save-and-compare logic for each control field, separate accumulator variables at each level, explicit rollup of minor-level totals into major-level totals, and page overflow handling that interacts with the control break logic. With Report Writer, the entire control break mechanism is declared in the REPORT SECTION and managed automatically by the runtime.
Data Design
The Performance Input File
The input file is sorted by region code and branch code. Each record represents one branch's weekly performance data:
SELECT PERFORMANCE-INPUT-FILE
ASSIGN TO PERFINP
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-INPUT-STATUS.
FD PERFORMANCE-INPUT-FILE
RECORDING MODE IS F
RECORD CONTAINS 200 CHARACTERS.
01 PERFORMANCE-INPUT-RECORD.
05 PIR-REGION-CODE PIC X(3).
05 PIR-REGION-NAME PIC X(20).
05 PIR-BRANCH-CODE PIC X(5).
05 PIR-BRANCH-NAME PIC X(25).
05 PIR-BRANCH-MANAGER PIC X(25).
05 PIR-WEEK-ENDING PIC 9(8).
05 PIR-TXN-COUNT PIC 9(7).
05 PIR-NEW-ACCOUNTS PIC 9(4).
05 PIR-CLOSED-ACCOUNTS PIC 9(4).
05 PIR-DEPOSIT-TOTAL PIC S9(11)V99.
05 PIR-WITHDRAWAL-TOTAL PIC S9(11)V99.
05 PIR-LOAN-ORIGINATIONS PIC S9(11)V99.
05 PIR-INTEREST-INCOME PIC S9(9)V99.
05 PIR-FEE-INCOME PIC S9(9)V99.
05 PIR-OPERATING-EXPENSE PIC S9(9)V99.
05 PIR-FILLER PIC X(43).
Working-Storage Computed Fields
Several metrics on the report are derived from the raw input data:
WORKING-STORAGE SECTION.
01 WS-COMPUTED-FIELDS.
05 WS-NET-DEPOSIT-FLOW PIC S9(11)V99.
05 WS-TOTAL-REVENUE PIC S9(11)V99.
05 WS-NET-INCOME PIC S9(11)V99.
05 WS-EFFICIENCY-RATIO PIC 9(3)V99.
05 WS-BRANCH-COUNT PIC 9(3).
05 WS-REGION-BRANCH-COUNT PIC 9(3).
05 WS-TOTAL-BRANCH-COUNT PIC 9(3).
The Report Output File
SELECT PERFORMANCE-REPORT-FILE
ASSIGN TO PERFRPT
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-REPORT-STATUS.
FD PERFORMANCE-REPORT-FILE
REPORT IS BRANCH-PERFORMANCE-REPORT.
The Report Section
Report Description (RD)
REPORT SECTION.
RD BRANCH-PERFORMANCE-REPORT
CONTROLS ARE FINAL
PIR-REGION-CODE
PIR-BRANCH-CODE
PAGE LIMIT IS 66 LINES
HEADING 1
FIRST DETAIL 10
LAST DETAIL 56
FOOTING 62.
The three control levels create the hierarchical structure: - FINAL: Company-level grand totals (printed once at the end) - PIR-REGION-CODE: Region-level subtotals (printed when the region changes) - PIR-BRANCH-CODE: Branch-level detail (one line per branch)
Report Heading
01 TYPE IS REPORT HEADING.
02 LINE 1.
05 COLUMN 1 PIC X(80) VALUE ALL "=".
02 LINE 2.
05 COLUMN 20 PIC X(40) VALUE
"GREAT PLAINS NATIONAL BANK".
02 LINE 3.
05 COLUMN 17 PIC X(45) VALUE
"WEEKLY BRANCH PERFORMANCE SUMMARY".
02 LINE 4.
05 COLUMN 1 PIC X(80) VALUE ALL "=".
02 LINE 5.
05 COLUMN 1 PIC X(20) VALUE
"Report Generated: ".
05 COLUMN 22 PIC X(10)
SOURCE WS-REPORT-DATE-FORMATTED.
05 COLUMN 45 PIC X(15) VALUE
"Week Ending: ".
05 COLUMN 61 PIC X(10)
SOURCE WS-WEEK-ENDING-FORMATTED.
Page Heading
01 TYPE IS PAGE HEADING.
02 LINE 7.
05 COLUMN 1 PIC X(5) VALUE "Brch".
05 COLUMN 8 PIC X(15) VALUE "Branch Name".
05 COLUMN 25 PIC X(7) VALUE "Txn Cnt".
05 COLUMN 34 PIC X(8) VALUE "New Acct".
05 COLUMN 44 PIC X(14) VALUE "Net Deposits".
05 COLUMN 60 PIC X(14) VALUE "Loan Orig.".
05 COLUMN 76 PIC X(12) VALUE "Net Income".
02 LINE 8.
05 COLUMN 1 PIC X(90) VALUE ALL "-".
Region Control Heading
When the region changes, a heading line announces the new region:
01 TYPE IS CONTROL HEADING PIR-REGION-CODE.
02 LINE PLUS 2.
05 COLUMN 1 PIC X(10) VALUE "REGION: ".
05 COLUMN 11 PIC X(3)
SOURCE PIR-REGION-CODE.
05 COLUMN 16 PIC X(20)
SOURCE PIR-REGION-NAME.
02 LINE PLUS 1.
05 COLUMN 1 PIC X(50) VALUE ALL "-".
Detail Line (One Per Branch)
The detail line shows each branch's performance on a single row:
01 BRANCH-DETAIL TYPE IS DETAIL.
02 LINE PLUS 1.
05 COLUMN 1 PIC X(5)
SOURCE PIR-BRANCH-CODE.
05 COLUMN 8 PIC X(15)
SOURCE PIR-BRANCH-NAME.
05 COLUMN 24 PIC ZZZ,ZZ9
SOURCE PIR-TXN-COUNT.
05 COLUMN 35 PIC Z,ZZ9
SOURCE PIR-NEW-ACCOUNTS.
05 COLUMN 42 PIC $(5),$$9,999.99-
SOURCE WS-NET-DEPOSIT-FLOW.
05 COLUMN 58 PIC $(5),$$9,999.99-
SOURCE PIR-LOAN-ORIGINATIONS.
05 COLUMN 74 PIC $(4),$$9,999.99-
SOURCE WS-NET-INCOME.
```
### Branch Control Footing
Since each branch has only one detail line, the branch control footing is used not for subtotals but for an efficiency indicator that prints below each branch when the ratio exceeds a threshold:
```cobol
01 TYPE IS CONTROL FOOTING PIR-BRANCH-CODE.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(25)
SOURCE WS-EFFICIENCY-MESSAGE.
```
### Region Control Footing (Regional Subtotals)
```cobol
01 REGION-FOOTING
TYPE IS CONTROL FOOTING PIR-REGION-CODE.
02 LINE PLUS 1.
05 COLUMN 1 PIC X(50) VALUE ALL "-".
02 LINE PLUS 1.
05 COLUMN 1 PIC X(7) VALUE "Region".
05 COLUMN 9 PIC X(3)
SOURCE PIR-REGION-CODE.
05 COLUMN 14 PIC X(7) VALUE "Total:".
05 COLUMN 22 PIC ZZZZ,ZZ9
SUM PIR-TXN-COUNT.
05 COLUMN 33 PIC ZZ,ZZ9
SUM PIR-NEW-ACCOUNTS.
05 COLUMN 42 PIC $(5),$$9,999.99-
SUM WS-NET-DEPOSIT-FLOW.
05 COLUMN 58 PIC $(5),$$9,999.99-
SUM PIR-LOAN-ORIGINATIONS.
05 COLUMN 74 PIC $(4),$$9,999.99-
SUM WS-NET-INCOME.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(10) VALUE "Branches:".
05 COLUMN 20 PIC ZZ9
SOURCE WS-REGION-BRANCH-COUNT.
05 COLUMN 28 PIC X(15) VALUE
"Avg Efficiency:".
05 COLUMN 45 PIC ZZ9.99
SOURCE WS-REGION-AVG-EFFICIENCY.
05 COLUMN 52 PIC X(1) VALUE "%".
The SUM clauses at the region level automatically accumulate the values from every branch detail line within the region. When the region code changes, these accumulated totals are printed and then reset to zero for the next region.
Final Control Footing (Company Grand Totals)
01 TYPE IS CONTROL FOOTING FINAL.
02 LINE PLUS 2.
05 COLUMN 1 PIC X(80) VALUE ALL "=".
02 LINE PLUS 1.
05 COLUMN 1 PIC X(30) VALUE
"COMPANY GRAND TOTALS".
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"Transactions:".
05 COLUMN 22 PIC Z,ZZZ,ZZ9
SUM PIR-TXN-COUNT.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"New Accounts:".
05 COLUMN 22 PIC ZZZ,ZZ9
SUM PIR-NEW-ACCOUNTS.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"Net Deposits:".
05 COLUMN 22 PIC $(9),$$9,999.99-
SUM WS-NET-DEPOSIT-FLOW.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"Loan Orig.:".
05 COLUMN 22 PIC $(9),$$9,999.99-
SUM PIR-LOAN-ORIGINATIONS.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"Net Income:".
05 COLUMN 22 PIC $(9),$$9,999.99-
SUM WS-NET-INCOME.
02 LINE PLUS 1.
05 COLUMN 8 PIC X(14) VALUE
"Total Branches:".
05 COLUMN 22 PIC ZZ9
SOURCE WS-TOTAL-BRANCH-COUNT.
02 LINE PLUS 1.
05 COLUMN 1 PIC X(80) VALUE ALL "=".
At the FINAL level, the SUM clauses accumulate from all region-level SUMs, providing the automatic three-tier rollup: branch detail accumulates into region subtotals, and region subtotals accumulate into company grand totals.
Page Footing
01 TYPE IS PAGE FOOTING.
02 LINE 64.
05 COLUMN 1 PIC X(30) VALUE
"CONFIDENTIAL - INTERNAL USE".
05 COLUMN 55 PIC X(5) VALUE "Page ".
05 COLUMN 60 PIC ZZ9
SOURCE PAGE-COUNTER.
The Procedure Division
PROCEDURE DIVISION.
DECLARATIVES.
BEFORE-DETAIL SECTION.
USE BEFORE REPORTING BRANCH-DETAIL.
COMPUTE-BRANCH-METRICS.
* Calculate derived fields before each detail line
COMPUTE WS-NET-DEPOSIT-FLOW =
PIR-DEPOSIT-TOTAL - PIR-WITHDRAWAL-TOTAL
COMPUTE WS-TOTAL-REVENUE =
PIR-INTEREST-INCOME + PIR-FEE-INCOME
COMPUTE WS-NET-INCOME =
WS-TOTAL-REVENUE - PIR-OPERATING-EXPENSE
IF WS-TOTAL-REVENUE > 0
COMPUTE WS-EFFICIENCY-RATIO ROUNDED =
(PIR-OPERATING-EXPENSE /
WS-TOTAL-REVENUE) * 100
ELSE
MOVE 999.99 TO WS-EFFICIENCY-RATIO
END-IF
IF WS-EFFICIENCY-RATIO > 80
MOVE "** HIGH COST BRANCH **"
TO WS-EFFICIENCY-MESSAGE
ELSE IF WS-EFFICIENCY-RATIO < 50
MOVE "(Top Performer)"
TO WS-EFFICIENCY-MESSAGE
ELSE
MOVE SPACES TO WS-EFFICIENCY-MESSAGE
END-IF
ADD 1 TO WS-REGION-BRANCH-COUNT
ADD 1 TO WS-TOTAL-BRANCH-COUNT
* Accumulate for region average efficiency
ADD WS-EFFICIENCY-RATIO
TO WS-REGION-EFFICIENCY-TOTAL
.
BEFORE-REGION-FOOT SECTION.
USE BEFORE REPORTING REGION-FOOTING.
COMPUTE-REGION-AVERAGES.
IF WS-REGION-BRANCH-COUNT > 0
COMPUTE WS-REGION-AVG-EFFICIENCY ROUNDED =
WS-REGION-EFFICIENCY-TOTAL /
WS-REGION-BRANCH-COUNT
ELSE
MOVE 0 TO WS-REGION-AVG-EFFICIENCY
END-IF
* Reset region-level accumulators
MOVE 0 TO WS-REGION-BRANCH-COUNT
MOVE 0 TO WS-REGION-EFFICIENCY-TOTAL
.
END DECLARATIVES.
MAIN-PROCESSING SECTION.
0000-MAIN.
OPEN INPUT PERFORMANCE-INPUT-FILE
OPEN OUTPUT PERFORMANCE-REPORT-FILE
INITIATE BRANCH-PERFORMANCE-REPORT
MOVE 0 TO WS-TOTAL-BRANCH-COUNT
MOVE 0 TO WS-REGION-BRANCH-COUNT
MOVE 0 TO WS-REGION-EFFICIENCY-TOTAL
PERFORM 1000-READ-INPUT
PERFORM UNTIL WS-INPUT-EOF
GENERATE BRANCH-DETAIL
PERFORM 1000-READ-INPUT
END-PERFORM
TERMINATE BRANCH-PERFORMANCE-REPORT
CLOSE PERFORMANCE-INPUT-FILE
CLOSE PERFORMANCE-REPORT-FILE
DISPLAY "REPORT COMPLETE: "
WS-TOTAL-BRANCH-COUNT " BRANCHES PROCESSED"
STOP RUN
.
1000-READ-INPUT.
READ PERFORMANCE-INPUT-FILE
AT END SET WS-INPUT-EOF TO TRUE
END-READ
.
The Role of USE BEFORE REPORTING
This program uses two USE BEFORE REPORTING declaratives:
-
BEFORE-DETAIL: Fires before each branch detail line. It computes derived metrics (net deposit flow, total revenue, net income, efficiency ratio) from the raw input fields. These computed fields are then available as SOURCE items in the detail line and as operands for SUM accumulation.
-
BEFORE-REGION-FOOT: Fires before each region control footing. It computes the average efficiency ratio for the region by dividing the accumulated efficiency total by the branch count. It then resets the region-level accumulators for the next region.
This pattern -- computing derived values in a declarative and resetting accumulators in a control footing declarative -- is a standard Report Writer technique. The accumulators for values that Report Writer cannot SUM automatically (like averages, which cannot be computed by summing) must be managed manually in the declaratives.
JCL for the Performance Report
//PERFRPT JOB (ACCT),'BRANCH PERF REPORT',
// CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//*
//* ENSURE INPUT IS SORTED BY REGION AND BRANCH
//*
//SORT EXEC PGM=SORT
//SORTIN DD DSN=BANK.WEEKLY.BRANCH.METRICS,DISP=SHR
//SORTOUT DD DSN=&&SORTED,DISP=(NEW,PASS),
// SPACE=(CYL,(5,2)),
// DCB=(RECFM=FB,LRECL=200,BLKSIZE=0)
//SYSIN DD *
SORT FIELDS=(1,3,CH,A,24,5,CH,A)
//SYSOUT DD SYSOUT=*
//*
//* GENERATE THE PERFORMANCE REPORT
//*
//REPORT EXEC PGM=PERFRPT
//STEPLIB DD DSN=PROD.LOADLIB,DISP=SHR
//PERFINP DD DSN=&&SORTED,DISP=(OLD,DELETE)
//PERFRPT DD SYSOUT=A,
// DCB=(RECFM=FBA,LRECL=133,BLKSIZE=0)
//SYSOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
Sample Output
================================================================================
GREAT PLAINS NATIONAL BANK
WEEKLY BRANCH PERFORMANCE SUMMARY
================================================================================
Report Generated: 02/10/2026 Week Ending: 02/07/2026
Brch Branch Name Txn Cnt New Acct Net Deposits Loan Orig. Net Income
------------------------------------------------------------------------------------------
REGION: MW1 Midwest North
--------------------------------------------------
MW101 Minneapolis 187,443 247 $ 12,445,102 $ 8,291,445 $ 345,221
MW102 St. Paul 142,887 183 $ 9,876,334 $ 5,443,221 $ 287,109
(Top Performer)
MW103 Duluth 67,221 89 $ 3,221,009 $ 2,108,776 $ 98,443
MW104 Rochester 73,445 94 $ 4,112,887 $ 2,556,332 $ 112,776
--------------------------------------------------
Region MW1 Total: 470,996 613 $ 29,655,332 $ 18,399,774 $ 843,549
Branches: 4 Avg Efficiency: 62.34%
REGION: MW2 Midwest South
--------------------------------------------------
MW201 Kansas City 198,776 312 $ 14,887,221 $ 9,776,554 $ 412,887
MW202 Omaha 156,443 234 $ 11,221,887 $ 7,332,109 $ 298,554
MW203 Wichita 89,112 127 $ 5,443,665 $ 3,887,221 $ 156,221
** HIGH COST BRANCH **
MW204 Lincoln 71,887 101 $ 3,998,776 $ 2,665,443 $ 121,887
--------------------------------------------------
Region MW2 Total: 516,218 774 $ 35,551,549 $ 23,661,327 $ 989,549
Branches: 4 Avg Efficiency: 65.12%
...
================================================================================
COMPANY GRAND TOTALS
Transactions: 2,847,221
New Accounts: 4,287
Net Deposits: $187,443,221.34
Loan Orig.: $124,887,665.78
Net Income: $ 5,221,887.45
Total Branches: 42
================================================================================
CONFIDENTIAL - INTERNAL USE Page 1
The Three-Level SUM Rollup in Action
The SUM mechanism works through automatic cascading:
-
Detail level: Each GENERATE adds the branch's
PIR-TXN-COUNTto the region-level SUM accumulator for that field. -
Region level: When the region changes, the region footing prints the accumulated SUM and the value automatically rolls up to the FINAL-level SUM accumulator. The region accumulator resets to zero.
-
FINAL level: When TERMINATE executes, the FINAL footing prints the grand totals, which are the sum of all region-level subtotals.
This cascade happens entirely within the Report Writer runtime. The programmer never writes an ADD statement for these fields, never declares an accumulator variable, and never writes reset logic. The REPORT SECTION declarations alone define the entire accumulation hierarchy.
Lessons Learned
1. Report Writer Handles Control Breaks Flawlessly
The three-level control break (branch within region within company) is managed entirely by the CONTROLS clause and the control heading/footing groups. In manual code, this pattern requires careful save-and-compare logic, explicit footing triggers before heading triggers, and proper ordering of reset operations. Report Writer eliminates this entire class of bugs.
2. Computed Fields Require USE BEFORE REPORTING
Report Writer's SUM can only accumulate fields that appear as SOURCE items on detail lines. For derived metrics like net income (revenue minus expense) or efficiency ratio (expense divided by revenue), the programmer must compute these values in a USE BEFORE REPORTING declarative so they are ready when the detail line is generated.
3. Averages Cannot Be Computed by SUM
The average efficiency ratio across branches in a region cannot be computed by summing and dividing at the CONTROL FOOTING level, because Report Writer's SUM operates on individual detail values, not on aggregated values. The solution is to maintain manual accumulators in the declaratives and compute the average in the USE BEFORE REPORTING for the region footing.
4. Input Must Be Sorted Correctly
Report Writer assumes the input is sorted on the CONTROLS fields in major-to-minor order. If the input is not sorted correctly, Report Writer triggers control breaks at incorrect points, producing garbled output with wrong subtotals. The JCL includes a pre-sort step to guarantee correct ordering.
Discussion Questions
-
The report currently shows one line per branch. If the bank wanted to show weekly trends (four weeks of data per branch, with each week on a separate detail line), what changes to the CONTROLS clause and detail line definition would be needed?
-
The efficiency ratio average is computed manually because SUM cannot produce averages. Describe an alternative approach using GENERATE with a summary report group instead of detail lines. Would this simplify or complicate the program?
-
What happens when a region has no branches (an empty control group)? Does Report Writer generate a region heading followed immediately by a region footing with zero totals?
-
The report is currently sent to SYSOUT for printing. If management wanted the same data in a comma-separated format for import into a spreadsheet, could Report Writer produce CSV output? Why or why not?
-
How would you modify the report to highlight branches where net income is negative (operating at a loss)? Consider both Report Writer capabilities and the limitations of line-printer output.