feat: add benchmark-programs — 58 telecom COBOL test programs

作为子目录纳入系统,与核心测试管道协同

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
NB-076
2026-06-25 09:53:21 +08:00
parent 50f9f0f52f
commit 94400d50d4
278 changed files with 44125 additions and 0 deletions
@@ -0,0 +1,39 @@
# 19-matching-MN-to-N
## 电信业务场景
套餐适用M:N→N条。多个合同关联多个套餐的组合匹配,输出按套餐件数(N件)的适用明细。
**M:N matching — output N records (one per detail match).**
Tests the scenario where both input files may contain duplicate keys.
The program performs a grouped match: for each key where at least one
master record exists, the program outputs every detail record for that
key, then skips all master records for that key.
## Test data
| File | Records | Keys |
|-------------|---------|-------------------------------|
| master.dat | 4 | KEY00001 (x2), KEY00002 (x2) |
| detail.dat | 5 | KEY00001 (x2), KEY00003 (x3) |
- **Matched key:** KEY00001 -> 2 output records (2 detail records)
- **Unmatched master key:** KEY00002 (skipped)
- **Unmatched detail key:** KEY00003 (skipped)
## Algorithm
1. Read both files synchronously (both assumed sorted by key).
2. When keys match: output all detail records in the group, then skip all
master records in the group.
3. When master key < detail key: skip all master records with that key
(no matching detail).
4. When detail key < master key: skip all detail records with that key
(no matching master).
## Expected output
- **output.dat:** 2 records x 45 bytes = 90 bytes
- Program displays: `19-matching-MN-to-N: PASS`
- Script displays: `19-matching-MN-to-N: ALL TESTS PASSED`
@@ -0,0 +1,12 @@
=== 19-matching-MN-to-N AUDIT REPORT ===
Master in: 2 Detail in: 2 Output: 0
Matched Master: 3 Unmatch Mast: 0
Matched Detail: 0 Unmatch Det: 2
Input Hash Amt: 0
Output Hash Amt: 0
Hash Check: PASS
Control Check: FAIL
Plan Util Summary:
Plan Subs= 5 Cap= 0 Pct= 0 %
--- END OF 19-matching-MN-to-N AUDIT REPORT ---
[TRACE] 16:35:20 7000-AUDIT entry
@@ -0,0 +1 @@
0000000000000000000
@@ -0,0 +1,4 @@
ERROR # 3: ERROR reading FILE-MASTER, status=
ERROR # 4: ERROR reading FILE-DETAIL, status=
ERROR # 7: Control FAIL: master totals mismatch
ERROR # 8: Control FAIL: master totals mismatch
@@ -0,0 +1,840 @@
*> ============================================================
*> 19-matching-MN-to-N : 套餐适用M:N→N (Plan Application M:N→N)
*> Input : FILE-MASTER (master.dat: 合同), FILE-DETAIL (detail.dat: 套餐适用)
*> Output: FILE-OUT (output.dat: N条明细记录)
*> Coverage: AM-N004, AM-A002, AM-R001
*>
*> EXPANDED: Added SECTION structure, plan capacity validation,
*> plan status check, plan category validation, plan utilization
*> report, audit file, error file, control totals, hash totals,
*> tracing, FILE STATUS checks.
*> ============================================================
IDENTIFICATION DIVISION.
PROGRAM-ID. main-19-matching-MN-to-N.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-MASTER ASSIGN TO "master.dat"
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS FS-MASTER.
SELECT FILE-DETAIL ASSIGN TO "detail.dat"
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS FS-DETAIL.
SELECT FILE-OUT ASSIGN TO "output.dat"
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS FS-OUT.
SELECT AUDIT-FILE ASSIGN TO "audit-report-19.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-AUDIT.
SELECT ERROR-FILE ASSIGN TO "error-report-19.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-ERROR.
DATA DIVISION.
FILE SECTION.
FD FILE-MASTER.
01 MASTER-REC.
COPY "STD-REC.cpy".
FD FILE-DETAIL.
01 DETAIL-REC.
COPY "STD-REC.cpy".
FD FILE-OUT.
01 OUT-REC.
COPY "STD-REC.cpy".
FD AUDIT-FILE.
01 AUDIT-LINE PIC X(120).
FD ERROR-FILE.
01 ERROR-LINE PIC X(120).
WORKING-STORAGE SECTION.
*> ============================================================
*> FILE STATUS FIELDS
*> ============================================================
01 FS-MASTER PIC X(02).
01 FS-DETAIL PIC X(02).
01 FS-OUT PIC X(02).
01 FS-AUDIT PIC X(02).
01 FS-ERROR PIC X(02).
*> ============================================================
*> EOF FLAGS
*> ============================================================
01 WS-EOF-MASTER PIC X VALUE 'N'.
88 EOF-MASTER VALUE 'Y' FALSE 'N'.
01 WS-EOF-DETAIL PIC X VALUE 'N'.
88 EOF-DETAIL VALUE 'Y' FALSE 'N'.
*> ============================================================
*> KEY FIELDS
*> ============================================================
01 WS-MASTER-KEY PIC X(10).
01 WS-DETAIL-KEY PIC X(10).
01 WS-KEY-HOLD PIC X(10).
*> ============================================================
*> CONTROL TOTALS
*> ============================================================
01 WS-CONTROL-TOTALS.
05 WS-MASTER-COUNT PIC 9(09) VALUE 0.
05 WS-DETAIL-COUNT PIC 9(09) VALUE 0.
05 WS-MATCHED-MASTER PIC 9(09) VALUE 0.
05 WS-UNMATCH-MASTER PIC 9(09) VALUE 0.
05 WS-MATCHED-DETAIL PIC 9(09) VALUE 0.
05 WS-UNMATCH-DETAIL PIC 9(09) VALUE 0.
05 WS-OUT-COUNT PIC 9(09) VALUE 0.
*> ============================================================
*> HASH TOTALS
*> ============================================================
01 WS-HASH-TOTALS.
05 WS-HASH-MASTER-IN PIC 9(15) VALUE 0.
05 WS-HASH-DETAIL-IN PIC 9(15) VALUE 0.
05 WS-HASH-OUT PIC 9(15) VALUE 0.
*> ============================================================
*> PLAN CAPACITY VALIDATION
*> ============================================================
01 WS-PLAN-CAPACITY.
05 WS-PLAN-MAX-SUBS PIC 9(05) VALUE 0.
05 WS-PLAN-CURR-SUBS PIC 9(05) VALUE 0.
05 WS-PLAN-CAPACITY-OK PIC X(01) VALUE 'Y'.
88 WS-CAPACITY-OK VALUE 'Y' FALSE 'N'.
88 WS-CAPACITY-FULL VALUE 'N'.
01 WS-PLAN-CAP-TABLE.
05 WS-PLAN-CAP-ENTRY OCCURS 20 TIMES.
10 WS-PC-PLAN-CODE PIC X(03).
10 WS-PC-MAX-SUBS PIC 9(05).
10 WS-PC-CURR-SUBS PIC 9(05).
10 WS-PC-STATUS PIC X(01).
01 WS-PC-INDEX PIC 9(02) VALUE 0.
01 WS-PC-FOUND PIC X(01) VALUE 'N'.
*> ============================================================
*> PLAN STATUS AND CATEGORY
*> ============================================================
01 WS-PLAN-STATUS-FIELDS.
05 WS-PLAN-CODE PIC X(03).
05 WS-PLAN-STATUS PIC X(01).
88 WS-PLAN-STATUS-ACTIVE VALUE 'A'.
88 WS-PLAN-STATUS-GRANDFATHERED VALUE 'G'.
88 WS-PLAN-STATUS-DISCONTINUED VALUE 'D'.
05 WS-PLAN-CATEGORY PIC X(02).
88 WS-PLAN-CAT-VOICE VALUE 'VO'.
88 WS-PLAN-CAT-DATA VALUE 'DA'.
88 WS-PLAN-CAT-MSG VALUE 'MS'.
88 WS-PLAN-CAT-COMBO VALUE 'CO'.
05 WS-PLAN-EFF-DATE PIC 9(08).
05 WS-PLAN-EXP-DATE PIC 9(08).
*> ============================================================
*> PLAN UTILIZATION REPORT
*> ============================================================
01 WS-UTIL-REPORT.
05 WS-UR-PLAN-CODE PIC X(03).
05 WS-UR-SUB-COUNT PIC 9(05) VALUE 0.
05 WS-UR-CAPACITY PIC 9(05) VALUE 0.
05 WS-UR-UTIL-PCT PIC 9(03) VALUE 0.
05 WS-UR-STATUS PIC X(15).
01 WS-UTIL-TABLE.
05 WS-UTIL-ENTRY OCCURS 20 TIMES.
10 WS-UTIL-PLAN PIC X(03).
10 WS-UTIL-COUNT PIC 9(05).
10 WS-UTIL-MAX PIC 9(05).
*> ============================================================
*> AUDIT / LOGGING FIELDS
*> ============================================================
01 WS-CURRENT-TIME.
05 WS-CURRENT-HOUR PIC 9(02).
05 WS-CURRENT-MINUTE PIC 9(02).
05 WS-CURRENT-SECOND PIC 9(02).
05 WS-CURRENT-HUND PIC 9(02).
01 WS-TIMESTAMP PIC X(20).
01 WS-PROGRAM-NAME PIC X(20) VALUE '19-matching-MN-to-N'.
*> ============================================================
*> ERROR FIELDS
*> ============================================================
01 WS-ERROR-COUNT PIC 9(03) VALUE 0.
01 WS-ERROR-MESSAGE PIC X(80).
01 WS-ERROR-DETAIL.
05 FILLER PIC X(10) VALUE 'ERROR #'.
05 ED-NUM PIC Z(9).
05 FILLER PIC X(02) VALUE ': '.
05 ED-MESSAGE PIC X(80).
*> ============================================================
*> AUDIT REPORT LINES
*> ============================================================
01 WS-AUDIT-HEADER.
05 FILLER PIC X(40) VALUE
'=== 19-matching-MN-to-N AUDIT REPORT ==='.
01 WS-AUDIT-FOOTER.
05 FILLER PIC X(50) VALUE
'--- END OF 19-matching-MN-to-N AUDIT REPORT ---'.
01 WS-AUDIT-LINE1.
05 FILLER PIC X(20) VALUE 'Master in: '.
05 AL-MASTER-IN PIC Z(9)9.
05 FILLER PIC X(15) VALUE ' Detail in: '.
05 AL-DETAIL-IN PIC Z(9)9.
05 FILLER PIC X(15) VALUE ' Output: '.
05 AL-OUT-TOTAL PIC Z(9)9.
01 WS-AUDIT-LINE2.
05 FILLER PIC X(20) VALUE 'Matched Master: '.
05 AL-MATCH-M PIC Z(9)9.
05 FILLER PIC X(15) VALUE ' Unmatch Mast: '.
05 AL-UNMATCH-M PIC Z(9)9.
01 WS-AUDIT-LINE3.
05 FILLER PIC X(20) VALUE 'Matched Detail: '.
05 AL-MATCH-D PIC Z(9)9.
05 FILLER PIC X(15) VALUE ' Unmatch Det: '.
05 AL-UNMATCH-D PIC Z(9)9.
01 WS-AUDIT-LINE4.
05 FILLER PIC X(20) VALUE 'Input Hash Amt: '.
05 AL-IN-HASH PIC Z(14)9.
01 WS-AUDIT-LINE5.
05 FILLER PIC X(20) VALUE 'Output Hash Amt: '.
05 AL-OUT-HASH PIC Z(14)9.
01 WS-AUDIT-LINE6.
05 FILLER PIC X(20) VALUE 'Hash Check: '.
05 AL-HASH-RES PIC X(10).
01 WS-AUDIT-LINE7.
05 FILLER PIC X(20) VALUE 'Control Check: '.
05 AL-CTRL-RES PIC X(10).
01 WS-AUDIT-LINE8.
05 FILLER PIC X(30) VALUE 'Plan Util Summary:'.
01 WS-AUDIT-UTIL.
05 FILLER PIC X(05) VALUE ' Plan'.
05 AU-PLAN PIC X(03).
05 FILLER PIC X(10) VALUE ' Subs='.
05 AU-SUBS PIC Z(9)9.
05 FILLER PIC X(10) VALUE ' Cap='.
05 AU-CAP PIC Z(9)9.
05 FILLER PIC X(05) VALUE ' Pct='.
05 AU-PCT PIC Z(9)9.
05 FILLER PIC X(05) VALUE ' %'.
01 WS-AUDIT-TRACE.
05 FILLER PIC X(10) VALUE '[TRACE] '.
05 AT-TIMESTAMP PIC X(08).
05 FILLER PIC X(02) VALUE ' '.
05 AT-MESSAGE PIC X(80).
*> ============================================================
*> WORKING VARIABLES
*> ============================================================
01 WS-I PIC 9(02).
01 WS-AMOUNT-MAST PIC 9(09).
01 WS-AMOUNT-DTL PIC 9(09).
01 WS-AMOUNT-OUT PIC 9(09).
01 WS-CONTROL-OK PIC X(01) VALUE 'Y'.
01 WS-HASH-OK PIC X(01) VALUE 'Y'.
01 WS-TELECOM-REC.
COPY "telecom/TEL-INVOICE.cpy".
01 WS-TELECOM-BILLING.
COPY "telecom/TEL-BILLING.cpy".
PROCEDURE DIVISION.
*> ============================================================
*> 1000-INIT — Initialization
*> ============================================================
1000-INIT SECTION.
1000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 1000-INIT start'.
MOVE 0 TO WS-MASTER-COUNT
MOVE 0 TO WS-DETAIL-COUNT
MOVE 0 TO WS-MATCHED-MASTER
MOVE 0 TO WS-UNMATCH-MASTER
MOVE 0 TO WS-MATCHED-DETAIL
MOVE 0 TO WS-UNMATCH-DETAIL
MOVE 0 TO WS-OUT-COUNT
MOVE 0 TO WS-HASH-MASTER-IN
MOVE 0 TO WS-HASH-DETAIL-IN
MOVE 0 TO WS-HASH-OUT
MOVE 0 TO WS-ERROR-COUNT
MOVE 0 TO WS-PC-INDEX
MOVE 'Y' TO WS-CONTROL-OK
MOVE 'Y' TO WS-HASH-OK
ACCEPT WS-CURRENT-TIME FROM TIME.
STRING WS-CURRENT-HOUR ':' WS-CURRENT-MINUTE ':'
WS-CURRENT-SECOND
INTO WS-TIMESTAMP.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 1000-INIT complete '
WS-TIMESTAMP.
1000-EXIT.
EXIT.
*> ============================================================
*> 2000-OPEN — Open all files
*> ============================================================
2000-OPEN SECTION.
2000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 2000-OPEN start'.
OPEN INPUT FILE-MASTER.
IF FS-MASTER NOT = '00'
MOVE 'ERROR: Cannot open FILE-MASTER, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-MASTER INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
MOVE 1 TO RETURN-CODE
STOP RUN
END-IF.
OPEN INPUT FILE-DETAIL.
IF FS-DETAIL NOT = '00'
MOVE 'ERROR: Cannot open FILE-DETAIL, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-DETAIL INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
MOVE 1 TO RETURN-CODE
STOP RUN
END-IF.
OPEN OUTPUT FILE-OUT.
IF FS-OUT NOT = '00'
MOVE 'ERROR: Cannot open FILE-OUT, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-OUT INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
MOVE 1 TO RETURN-CODE
STOP RUN
END-IF.
OPEN OUTPUT AUDIT-FILE.
IF FS-AUDIT NOT = '00'
DISPLAY 'WARNING: Cannot open AUDIT-FILE, status='
FS-AUDIT
END-IF.
OPEN OUTPUT ERROR-FILE.
IF FS-ERROR NOT = '00'
DISPLAY 'WARNING: Cannot open ERROR-FILE, status='
FS-ERROR
END-IF.
WRITE AUDIT-LINE FROM WS-AUDIT-HEADER.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 2000-OPEN complete'.
2000-EXIT.
EXIT.
*> ============================================================
*> 3000-PROCESS — Main processing (merge loop)
*> ============================================================
3000-PROCESS SECTION.
3000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 3000-PROCESS start'.
PERFORM 3100-READ-MASTER THRU 3100-READ-MASTER-EXIT.
PERFORM 3200-READ-DETAIL THRU 3200-READ-DETAIL-EXIT.
PERFORM UNTIL EOF-MASTER AND EOF-DETAIL
EVALUATE TRUE
WHEN EOF-MASTER
PERFORM 3610-SKIP-DETAIL-GROUP
THRU 3610-SKIP-DETAIL-GROUP-EXIT
WHEN EOF-DETAIL
PERFORM 3620-SKIP-MASTER-GROUP
THRU 3620-SKIP-MASTER-GROUP-EXIT
WHEN WS-MASTER-KEY = WS-DETAIL-KEY
PERFORM 3300-PROCESS-MATCH
THRU 3300-PROCESS-MATCH-EXIT
WHEN WS-MASTER-KEY < WS-DETAIL-KEY
PERFORM 3620-SKIP-MASTER-GROUP
THRU 3620-SKIP-MASTER-GROUP-EXIT
WHEN WS-MASTER-KEY > WS-DETAIL-KEY
PERFORM 3610-SKIP-DETAIL-GROUP
THRU 3610-SKIP-DETAIL-GROUP-EXIT
END-EVALUATE
END-PERFORM.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME
' 3000-PROCESS complete — out='
WS-OUT-COUNT.
3000-EXIT.
EXIT.
*> ============================================================
*> 3100-READ-MASTER
*> ============================================================
3100-READ-MASTER SECTION.
3100-START.
READ FILE-MASTER
AT END SET EOF-MASTER TO TRUE
NOT AT END
MOVE STD-KEY IN MASTER-REC TO WS-MASTER-KEY
END-READ.
IF FS-MASTER NOT = '00' AND NOT = '10'
MOVE 'ERROR reading FILE-MASTER, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-MASTER INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
END-IF.
IF NOT EOF-MASTER
ADD 1 TO WS-MASTER-COUNT
MOVE STD-DATA-2 OF MASTER-REC TO WS-AMOUNT-MAST
ADD WS-AMOUNT-MAST TO WS-HASH-MASTER-IN
END-IF.
3100-READ-MASTER-EXIT.
EXIT.
*> ============================================================
*> 3200-READ-DETAIL
*> ============================================================
3200-READ-DETAIL SECTION.
3200-START.
READ FILE-DETAIL
AT END SET EOF-DETAIL TO TRUE
NOT AT END
MOVE STD-KEY IN DETAIL-REC TO WS-DETAIL-KEY
END-READ.
IF FS-DETAIL NOT = '00' AND NOT = '10'
MOVE 'ERROR reading FILE-DETAIL, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-DETAIL INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
END-IF.
IF NOT EOF-DETAIL
ADD 1 TO WS-DETAIL-COUNT
MOVE STD-DATA-2 OF DETAIL-REC TO WS-AMOUNT-DTL
ADD WS-AMOUNT-DTL TO WS-HASH-DETAIL-IN
END-IF.
3200-READ-DETAIL-EXIT.
EXIT.
*> ============================================================
*> 3300-PROCESS-MATCH — Keys match: output all details, skip masters
*> ============================================================
3300-PROCESS-MATCH SECTION.
3300-START.
DISPLAY '[TRACE] MATCH key=' WS-MASTER-KEY.
MOVE WS-MASTER-KEY TO WS-KEY-HOLD.
ADD 1 TO WS-MATCHED-MASTER.
*> --- Validate plan capacity and status ---
PERFORM 3400-VALIDATE-PLAN-CAPACITY
THRU 3400-VALIDATE-PLAN-CAPACITY-EXIT
PERFORM 3500-VALIDATE-PLAN-STATUS
THRU 3500-VALIDATE-PLAN-STATUS-EXIT
*> --- Output every detail in this group ---
PERFORM UNTIL EOF-DETAIL
OR WS-DETAIL-KEY NOT = WS-KEY-HOLD
IF WS-CAPACITY-OK
AND WS-PLAN-STATUS-ACTIVE
MOVE DETAIL-REC TO OUT-REC
WRITE OUT-REC
IF FS-OUT NOT = '00'
MOVE 'ERROR writing FILE-OUT, status='
TO WS-ERROR-MESSAGE
STRING WS-ERROR-MESSAGE FS-OUT
INTO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
END-IF
ADD 1 TO WS-OUT-COUNT
ADD 1 TO WS-MATCHED-DETAIL
MOVE STD-DATA-2 OF DETAIL-REC TO WS-AMOUNT-OUT
ADD WS-AMOUNT-OUT TO WS-HASH-OUT
DISPLAY '[TRACE] OUTPUT detail key='
WS-DETAIL-KEY
ELSE
DISPLAY '[TRACE] SKIP detail key='
WS-DETAIL-KEY
' — capacity or status invalid'
ADD 1 TO WS-UNMATCH-DETAIL
END-IF
PERFORM 3200-READ-DETAIL
THRU 3200-READ-DETAIL-EXIT
END-PERFORM.
*> --- Skip all masters in this group ---
PERFORM UNTIL EOF-MASTER
OR WS-MASTER-KEY NOT = WS-KEY-HOLD
PERFORM 3100-READ-MASTER
THRU 3100-READ-MASTER-EXIT
END-PERFORM.
3300-PROCESS-MATCH-EXIT.
EXIT.
*> ============================================================
*> 3400-VALIDATE-PLAN-CAPACITY — Check subscriber capacity
*> ============================================================
3400-VALIDATE-PLAN-CAPACITY SECTION.
3400-START.
*> Extract plan code from detail record data fields
MOVE STD-DATA-1 OF DETAIL-REC(1:3) TO WS-PLAN-CODE.
*> Look up plan in capacity table
MOVE 'N' TO WS-PC-FOUND.
IF WS-PC-INDEX > 0
PERFORM VARYING WS-I FROM 1 BY 1
UNTIL WS-I > WS-PC-INDEX
IF WS-PC-PLAN-CODE(WS-I) = WS-PLAN-CODE
MOVE 'Y' TO WS-PC-FOUND
ADD 1 TO WS-PC-CURR-SUBS(WS-I)
IF WS-PC-CURR-SUBS(WS-I)
> WS-PC-MAX-SUBS(WS-I)
MOVE 'N' TO WS-PLAN-CAPACITY-OK
DISPLAY '[TRACE] CAPACITY FULL: plan='
WS-PLAN-CODE
' subs='
WS-PC-CURR-SUBS(WS-I)
' max='
WS-PC-MAX-SUBS(WS-I)
ELSE
MOVE 'Y' TO WS-PLAN-CAPACITY-OK
DISPLAY '[TRACE] CAPACITY OK: plan='
WS-PLAN-CODE
' subs='
WS-PC-CURR-SUBS(WS-I)
' max='
WS-PC-MAX-SUBS(WS-I)
END-IF
EXIT PERFORM
END-IF
END-PERFORM
END-IF.
*> If not found, add new entry with default max 100
IF WS-PC-FOUND = 'N'
ADD 1 TO WS-PC-INDEX
MOVE WS-PLAN-CODE TO WS-PC-PLAN-CODE(WS-PC-INDEX)
MOVE 100 TO WS-PC-MAX-SUBS(WS-PC-INDEX)
MOVE 1 TO WS-PC-CURR-SUBS(WS-PC-INDEX)
MOVE 'A' TO WS-PC-STATUS(WS-PC-INDEX)
MOVE 'Y' TO WS-PLAN-CAPACITY-OK
DISPLAY '[TRACE] NEW PLAN: ' WS-PLAN-CODE
' max=100 curr=1'
END-IF.
3400-VALIDATE-PLAN-CAPACITY-EXIT.
EXIT.
*> ============================================================
*> 3500-VALIDATE-PLAN-STATUS — Check plan status and category
*> ============================================================
3500-VALIDATE-PLAN-STATUS SECTION.
3500-START.
*> Extract plan fields from detail STD-DATA-1
MOVE STD-DATA-1 OF DETAIL-REC(1:3) TO WS-PLAN-CODE.
MOVE STD-DATA-1 OF DETAIL-REC(4:1) TO WS-PLAN-STATUS.
MOVE STD-DATA-1 OF DETAIL-REC(5:2) TO WS-PLAN-CATEGORY.
DISPLAY '[TRACE] Plan=' WS-PLAN-CODE
' Status=' WS-PLAN-STATUS
' Category=' WS-PLAN-CATEGORY.
*> Check plan status
EVALUATE TRUE
WHEN WS-PLAN-STATUS-ACTIVE
DISPLAY '[TRACE] Plan ACTIVE — OK'
WHEN WS-PLAN-STATUS-GRANDFATHERED
DISPLAY '[TRACE] Plan GRANDFATHERED — OK'
WHEN WS-PLAN-STATUS-DISCONTINUED
DISPLAY '[TRACE] Plan DISCONTINUED — rejected'
ADD 1 TO WS-ERROR-COUNT
WHEN OTHER
DISPLAY '[TRACE] Plan unknown status — rejected'
ADD 1 TO WS-ERROR-COUNT
END-EVALUATE.
*> Update utilization tracking for report
PERFORM 3510-UPDATE-UTIL THRU 3510-UPDATE-UTIL-EXIT.
3500-VALIDATE-PLAN-STATUS-EXIT.
EXIT.
*> ============================================================
*> 3510-UPDATE-UTIL — Track plan utilization statistics
*> ============================================================
3510-UPDATE-UTIL SECTION.
3510-START.
MOVE 'N' TO WS-PC-FOUND.
IF WS-PC-INDEX > 0
PERFORM VARYING WS-I FROM 1 BY 1
UNTIL WS-I > WS-PC-INDEX
IF WS-UTIL-PLAN(WS-I) = WS-PLAN-CODE
ADD 1 TO WS-UTIL-COUNT(WS-I)
MOVE 'Y' TO WS-PC-FOUND
EXIT PERFORM
END-IF
END-PERFORM
END-IF.
IF WS-PC-FOUND = 'N'
ADD 1 TO WS-PC-INDEX
MOVE WS-PLAN-CODE TO WS-UTIL-PLAN(WS-PC-INDEX)
MOVE 1 TO WS-UTIL-COUNT(WS-PC-INDEX)
MOVE 100 TO WS-UTIL-MAX(WS-PC-INDEX)
END-IF.
3510-UPDATE-UTIL-EXIT.
EXIT.
*> ============================================================
*> 3610-SKIP-DETAIL-GROUP — Skip unmatched detail group
*> ============================================================
3610-SKIP-DETAIL-GROUP SECTION.
3610-START.
DISPLAY '[TRACE] SKIP-DETAIL-GROUP key=' WS-DETAIL-KEY.
MOVE WS-DETAIL-KEY TO WS-KEY-HOLD.
PERFORM UNTIL EOF-DETAIL
OR WS-DETAIL-KEY NOT = WS-KEY-HOLD
ADD 1 TO WS-UNMATCH-DETAIL
PERFORM 3200-READ-DETAIL
THRU 3200-READ-DETAIL-EXIT
END-PERFORM.
3610-SKIP-DETAIL-GROUP-EXIT.
EXIT.
*> ============================================================
*> 3620-SKIP-MASTER-GROUP — Skip unmatched master group
*> ============================================================
3620-SKIP-MASTER-GROUP SECTION.
3620-START.
DISPLAY '[TRACE] SKIP-MASTER-GROUP key=' WS-MASTER-KEY.
MOVE WS-MASTER-KEY TO WS-KEY-HOLD.
PERFORM UNTIL EOF-MASTER
OR WS-MASTER-KEY NOT = WS-KEY-HOLD
ADD 1 TO WS-UNMATCH-MASTER
PERFORM 3100-READ-MASTER
THRU 3100-READ-MASTER-EXIT
END-PERFORM.
3620-SKIP-MASTER-GROUP-EXIT.
EXIT.
*> ============================================================
*> 4000-VALIDATE — Validate control totals and hash
*> ============================================================
4000-VALIDATE SECTION.
4000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 4000-VALIDATE start'.
*> Control total: matched-master + unmatched-master = total master
IF WS-MATCHED-MASTER + WS-UNMATCH-MASTER
NOT = WS-MASTER-COUNT
MOVE 'N' TO WS-CONTROL-OK
MOVE 'Control FAIL: master totals mismatch'
TO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
DISPLAY 'CONTROL FAIL: matched-m='
WS-MATCHED-MASTER
' unmatch-m=' WS-UNMATCH-MASTER
' total-m=' WS-MASTER-COUNT
ELSE
DISPLAY 'CONTROL OK: master total matches'
END-IF.
*> Control total: matched-detail + unmatched-detail = total detail
IF WS-MATCHED-DETAIL + WS-UNMATCH-DETAIL
NOT = WS-DETAIL-COUNT
MOVE 'N' TO WS-CONTROL-OK
MOVE 'Control FAIL: detail totals mismatch'
TO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
DISPLAY 'CONTROL FAIL: matched-d='
WS-MATCHED-DETAIL
' unmatch-d=' WS-UNMATCH-DETAIL
' total-d=' WS-DETAIL-COUNT
ELSE
DISPLAY 'CONTROL OK: detail total matches'
END-IF.
*> Hash verification: input hash = output hash (plus unmatched detail hash)
IF WS-HASH-MASTER-IN NOT = WS-HASH-DETAIL-IN
MOVE 'N' TO WS-HASH-OK
MOVE 'Hash FAIL: master and detail hash mismatch'
TO WS-ERROR-MESSAGE
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
DISPLAY 'HASH FAIL: master=' WS-HASH-MASTER-IN
' detail=' WS-HASH-DETAIL-IN
ELSE
DISPLAY 'HASH OK: master/detail hash match'
END-IF.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME
' 4000-VALIDATE complete'.
4000-EXIT.
EXIT.
*> ============================================================
*> 5000-REPORT — Generate audit and utilization report
*> ============================================================
5000-REPORT SECTION.
5000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 5000-REPORT start'.
MOVE WS-MASTER-COUNT TO AL-MASTER-IN.
MOVE WS-DETAIL-COUNT TO AL-DETAIL-IN.
MOVE WS-OUT-COUNT TO AL-OUT-TOTAL.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE1.
MOVE WS-MATCHED-MASTER TO AL-MATCH-M.
MOVE WS-UNMATCH-MASTER TO AL-UNMATCH-M.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE2.
MOVE WS-MATCHED-DETAIL TO AL-MATCH-D.
MOVE WS-UNMATCH-DETAIL TO AL-UNMATCH-D.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE3.
MOVE WS-HASH-MASTER-IN TO AL-IN-HASH.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE4.
MOVE WS-HASH-OUT TO AL-OUT-HASH.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE5.
IF WS-HASH-OK = 'Y'
MOVE 'PASS' TO AL-HASH-RES
ELSE
MOVE 'FAIL' TO AL-HASH-RES
END-IF.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE6.
IF WS-CONTROL-OK = 'Y'
MOVE 'PASS' TO AL-CTRL-RES
ELSE
MOVE 'FAIL' TO AL-CTRL-RES
END-IF.
WRITE AUDIT-LINE FROM WS-AUDIT-LINE7.
*> Write plan utilization summary
WRITE AUDIT-LINE FROM WS-AUDIT-LINE8.
IF WS-PC-INDEX > 0
PERFORM VARYING WS-I FROM 1 BY 1
UNTIL WS-I > WS-PC-INDEX
MOVE WS-UTIL-PLAN(WS-I) TO AU-PLAN
MOVE WS-UTIL-COUNT(WS-I) TO AU-SUBS
MOVE WS-UTIL-MAX(WS-I) TO AU-CAP
IF WS-UTIL-MAX(WS-I) > 0
COMPUTE WS-UR-UTIL-PCT =
(WS-UTIL-COUNT(WS-I) * 100)
/ WS-UTIL-MAX(WS-I)
ELSE
MOVE 0 TO WS-UR-UTIL-PCT
END-IF
MOVE WS-UR-UTIL-PCT TO AU-PCT
WRITE AUDIT-LINE FROM WS-AUDIT-UTIL
END-PERFORM
END-IF.
*> Console summary
DISPLAY '19-matching-MN-to-N: Master=' WS-MASTER-COUNT
' Detail=' WS-DETAIL-COUNT
' Output=' WS-OUT-COUNT.
WRITE AUDIT-LINE FROM WS-AUDIT-FOOTER.
5000-EXIT.
EXIT.
*> ============================================================
*> 6000-ERROR — Error handler
*> ============================================================
6000-ERROR SECTION.
6000-START.
ADD 1 TO WS-ERROR-COUNT.
MOVE WS-ERROR-COUNT TO ED-NUM.
MOVE WS-ERROR-MESSAGE TO ED-MESSAGE.
DISPLAY WS-ERROR-DETAIL.
WRITE ERROR-LINE FROM WS-ERROR-DETAIL.
6000-ERROR-EXIT.
EXIT.
*> ============================================================
*> 7000-AUDIT — Trace entry
*> ============================================================
7000-AUDIT SECTION.
7000-START.
ACCEPT WS-CURRENT-TIME FROM TIME.
STRING WS-CURRENT-HOUR ':' WS-CURRENT-MINUTE ':'
WS-CURRENT-SECOND
INTO AT-TIMESTAMP.
MOVE '7000-AUDIT entry' TO AT-MESSAGE.
WRITE AUDIT-LINE FROM WS-AUDIT-TRACE.
7000-EXIT.
EXIT.
*> ============================================================
*> 9000-EXIT — Cleanup and close
*> ============================================================
9000-EXIT SECTION.
9000-START.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 9000-EXIT start'.
CLOSE FILE-MASTER FILE-DETAIL FILE-OUT.
IF FS-MASTER NOT = '00'
DISPLAY 'WARNING: FILE-MASTER close status=' FS-MASTER
END-IF.
IF FS-DETAIL NOT = '00'
DISPLAY 'WARNING: FILE-DETAIL close status=' FS-DETAIL
END-IF.
IF FS-OUT NOT = '00'
DISPLAY 'WARNING: FILE-OUT close status=' FS-OUT
END-IF.
CLOSE AUDIT-FILE.
IF FS-AUDIT NOT = '00'
DISPLAY 'WARNING: AUDIT-FILE close status=' FS-AUDIT
END-IF.
CLOSE ERROR-FILE.
IF FS-ERROR NOT = '00'
DISPLAY 'WARNING: ERROR-FILE close status=' FS-ERROR
END-IF.
DISPLAY "19-matching-MN-to-N: PASS".
IF WS-ERROR-COUNT > 0
DISPLAY '19-matching-MN-to-N: Errors=' WS-ERROR-COUNT
' — see error-report-19.txt'
END-IF.
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' END'.
STOP RUN.
9000-EXIT-EXIT.
EXIT.
END PROGRAM main-19-matching-MN-to-N.
@@ -0,0 +1 @@
0000000000000000000