Module challenge: sales by region and quarter
Every sales organisation runs a report like this at the end of each quarter: raw transactions go in, a grid of totals comes out, with a total for each row and each column and a grand total in the corner. Finance reconciles the grand total against the ledger, so it must be exact.
This challenge brings together everything in the module:
- Hard-coded tables with
REDEFINES: the region list, and a month-to- quarter lookup. SEARCH ALLto turn a region code into a table position.SETto convert the index into an ordinary subscript.- A two-dimensional table (region × quarter) to accumulate the totals.
- Row and column totals from nested loops.
- An
OCCURSin the report line, so four columns are filled by one loop instead of four copies of the same code.
Direct lookup by subscript
Not every lookup needs a search. When the key already is a position, such as a month number from 1 to 12, subscript directly:
01 WS-QTR-VALUES PIC X(12) VALUE "111222333444".
01 WS-QTR-TABLE REDEFINES WS-QTR-VALUES.
05 WS-QTR-OF-MONTH PIC 9 OCCURS 12 TIMES.
* ...
MOVE WS-QTR-OF-MONTH(SR-MONTH) TO WS-Q
This is only safe after you have checked that the month is 1–12.
Using one table's index on another table
SEARCH ALL WS-REGION leaves REG-IX pointing at the matching region. You
then want to add to row n of the sales table. Do not write
WS-SALES(REG-IX, WS-Q): REG-IX belongs to a table with 9-byte
elements, and on IBM compilers it holds a byte offset calculated for that
element size. Convert it to a plain number first:
WHEN WS-REG-CODE(REG-IX) = SR-REGION
SET WS-R TO REG-IX
Now WS-R is 1–4 and works as a subscript for any table.
Rejecting bad input
A batch job should not stop at the first bad record, and it must not silently drop it either. Display each rejected record, count them, and report the count at the end, so operations can see what was left out and why the totals may not match expectations.
On the job
Totals must balance. Here the ALL line's total must equal the sum of the region totals and the sum of the quarter totals. When you write a report program, check both ways as part of your testing. Auditors will.
Your task
Produce the quarterly sales report. Read sales records until END:
| Columns | Field | Picture |
|---|---|---|
| 1–3 | Region code | X(3) |
| 4–5 | Month | 9(2) |
| 6–12 | Amount, 2 implied decimals | 9(5)V99 |
NTH030007550 is region NTH, March, 75.50.
Rules
- Regions are EST (EAST), NTH (NORTH), STH (SOUTH), WST (WEST). They are already in the starter's region table, in code order.
- Months 1–3 are Q1, 4–6 Q2, 7–9 Q3, 10–12 Q4.
- A record with a month outside 1–12 or an unknown region code is
rejected: display
REJECTED:followed by the whole record, as soon as you read it, and count it.
Report (after all input is read):
REGION Q1 Q2 Q3 Q4 TOTAL
EAST 500.00 0.00 0.00 0.00 500.00
NORTH 200.50 0.00 0.00 300.00 500.50
SOUTH 0.00 200.00 0.00 0.00 200.00
WEST 0.00 0.00 0.00 999.99 999.99
ALL 700.50 200.00 0.00 1299.99 2200.49
REJECTED RECORDS: 02
Every region appears even if it had no sales. The ALL line has each
quarter's total across regions and the grand total. The starter provides
the heading and a report line (WS-REPORT-LINE) with RL-NAME,
RL-QTR(1..4) and RL-TOTAL. MOVE SPACES to it before filling it.
Requirements: look the region up with SEARCH ALL, and accumulate
into a two-dimensional table.