Challenge: customer feed loader
A new online-banking partner sends new and updated customers as a CSV feed. Your job is the front half of the loader program: validate every line, clean up what passes, and turn it into the bank's fixed-width customer record. Anything that fails is rejected with a reason, so the operations team can go back to the partner.
This is exactly the kind of program interface teams write and maintain, and it uses everything in this module:
- UNSTRING with
TALLYINGandON OVERFLOWto split each line and check the field count, - intrinsic functions (
TRIM,UPPER-CASE,LENGTH) to cleanse, - reference modification and a class test to check the key format,
- TEST-NUMVAL-C and NUMVAL-C to validate and convert the balance.
Validate in order, report the first failure
When a record can fail several rules, a common pattern is an EVALUATE
TRUE with one WHEN per rule, in priority order. The first rule that
fails sets the reason, and the rest are skipped:
IDENTIFICATION DIVISION.
PROGRAM-ID. RULES.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CODE PIC X(6) VALUE "C0A042".
01 WS-REASON PIC X(20).
PROCEDURE DIVISION.
MOVE SPACES TO WS-REASON
EVALUATE TRUE
WHEN WS-CODE(1:1) NOT = "C"
MOVE "WRONG PREFIX" TO WS-REASON
WHEN WS-CODE(2:5) IS NOT NUMERIC
MOVE "NOT NUMERIC" TO WS-REASON
END-EVALUATE
IF WS-REASON = SPACES
DISPLAY "VALID"
ELSE
DISPLAY "INVALID: " WS-REASON
END-IF
STOP RUN.
Output: INVALID: NOT NUMERIC. IS NUMERIC on an alphanumeric item (or
a reference-modified piece of one) is true only if every character is a
digit.
Fixed-width output
Build the output record as a group of elementary fields and MOVE into
each one. The group is then the record, with every field at a fixed
position, and moving a trimmed value into a field pads or truncates it for
you. A numeric-edited field such as PIC -9(7).99 gives a fixed-width
amount with a sign position that is a space for positive values.
On the job
Rejects are never silently dropped in production. A loader writes them to an exceptions file with the reason, and the job's control totals (records read, accepted, rejected) must add up, because auditors check them. In the next module you will write real files instead of displaying lines.
Your task
Read CSV lines until one says END. Each line should be:
CUSTOMER-ID,NAME,CITY,BALANCE
Number the lines from 1. Check each line against these rules in this order and stop at the first failure:
| Rule | Reason |
|---|---|
| Exactly 4 fields (no more, no fewer) | FIELD COUNT |
ID, once trimmed and upper-cased, is 6 characters: C followed by 5 digits (c00107 is fine) |
BAD ID |
| Name is not blank | MISSING NAME |
Balance is a valid amount according to TEST-NUMVAL-C (may have $, spaces, a sign or CR) |
BAD BALANCE |
For a rejected line, display REJECT LINE nn: reason, e.g.
REJECT LINE 03: BAD ID.
For a valid line, fill OUT-REC and display it. It is a fixed-width
customer record (already declared in the starter):
| Field | Picture | Content |
|---|---|---|
OUT-ID |
X(6) |
the upper-cased ID |
OUT-NAME |
X(20) |
the name, trimmed and upper-cased |
OUT-CITY |
X(15) |
the city, trimmed and upper-cased |
OUT-BAL |
-9(7).99 |
the balance, converted with NUMVAL-C |
At the end, display the control totals:
READ: 04 ACCEPTED: 03 REJECTED: 01
Example: this input
C00042, Grace Hopper ,Arlington,$1234.56
c00107,alan turing,wilmslow,-20.00
X00001,Ada Lovelace,London,10.00
END
produces
C00042GRACE HOPPER ARLINGTON 0001234.56
C00107ALAN TURING WILMSLOW -0000020.00
REJECT LINE 03: BAD ID
READ: 03 ACCEPTED: 02 REJECTED: 01