Challenge: the nightly stock run
Almost every batch system has a job shaped like this one. Once you can write it, you can read most of the nightly schedule at a bank, an insurer or a retailer:
- Sort the day's transactions into master-file order, dropping the ones that shouldn't be processed.
- Update: a COBOL program matches the sorted transactions against yesterday's master and writes today's master plus a report. This is the match-merge you wrote in the sequential files module.
- Report: the report goes somewhere people will read it.
- Clean up, but only if everything worked, so a bad night can be rerun from the top.
The work in between is carried by temporary datasets. Whether each
step runs is decided by return codes and COND. Each DD's
disposition is chosen with the rerun in mind.
//SORTMOVE EXEC PGM=SORT
//SORTOUT DD DSN=&&MOVES,DISP=(NEW,PASS)
...
//UPDATE EXEC PGM=STKUPD
//MOVESIN DD DSN=&&MOVES,DISP=(OLD,DELETE)
...
//CLEANUP EXEC PGM=IEFBR14,COND=(4,LT)
Plan it on paper first: list each step, its program, every DD with its
dataset and DISP, and the RCs for which the step must run. Then write
the JCL, and read the job log after every run, including the ones that
pass.
How this looks in production
- The master file would be a GDG (generation data group):
DSN=STOCK.MASTER(0)is the current generation, andDSN=STOCK.MASTER(+1),DISP=(NEW,CATLG,DELETE)creates the next. The catalog keeps the last n generations, so yesterday's master is always available for a rerun and no job has to rename anything. - The steps would probably live in a catalogued procedure
(
//NIGHTLY EXEC STKPROC), with symbolic parameters such as&DATE, so test and production run identical JCL with different dataset prefixes. - The job would be submitted by the scheduler once the warehouse feed has arrived, and a failed run would page the on-call developer, who opens the job log you have learned to read.
On the job
When you change a job like this, test the failure paths too: feed it an empty file, an unknown item and an out-of-sequence file in a test region, and check which steps run and which datasets survive. Most batch production incidents are in the paths that "never happen".
Your task
Module challenge. Write the warehouse's nightly stock job,
STKNIGHT, from the outline in the starter. Four steps, in this order:
1. SORTMOVE (SORT). Read today's movements, STOCK.MOVES.DAILY
(keep it; step 4 deals with it). Omit voided movements and sort the
rest by item code, then by time, both ascending. Pass the result
to step 2 as the temporary dataset &&MOVES.
| Field | Positions | Format |
|---|---|---|
| Item code | 1–6 | CH |
Type (R receipt, I issue) |
7 | CH |
| Quantity | 8–12 | ZD |
| Time (HHMM) | 13–16 | CH |
Void flag (V = voided) |
17 | CH |
2. UPDATE runs the update program STKUPD (already written):
| DD | Dataset | Notes |
|---|---|---|
MASTIN |
STOCK.MASTER |
Yesterday's master, read-only |
MOVESIN |
&&MOVES |
Sorted movements; delete after this step |
MASTOUT |
STOCK.MASTER.NEW |
Today's master: new, cataloged, deleted on abend |
RPTOUT |
&&STKRPT |
The stock report, passed to step 3 |
SYSOUT |
spool |
STKUPD ends with RC 0 if all went well, RC 4 if some
movements were for unknown items, RC 8 if an item's stock would go
negative, and RC 12 if its input isn't sorted or still contains
voids.
3. PRINT (IEBGENER) copies the report &&STKRPT to a new
cataloged dataset STOCK.REPORT.DAILY, where the report
distribution system picks it up. It runs when UPDATE ended with RC 8
or less: the warehouse needs the report most when there's a problem.
4. CLEANUP (IEFBR14) deletes STOCK.MOVES.DAILY, but only when
every earlier step ended with RC 4 or less. After a worse night the
movements must be kept so the job can be rerun.
In production the master would be a GDG (STOCK.MASTER(0) in,
STOCK.MASTER(+1) out), but here the two generations are simply
STOCK.MASTER and STOCK.MASTER.NEW.