feat: add benchmark-programs — 58 telecom COBOL test programs
作为子目录纳入系统,与核心测试管道协同 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# 18-matching-MN-to-M: M:N Matching with M Output Records
|
||||
|
||||
## 电信业务场景
|
||||
|
||||
合同↔套餐M:N→M条。多个合同关联多个套餐的组合匹配,输出按合同件数(M件)的匹配结果。
|
||||
|
||||
## Description
|
||||
|
||||
M:N matching where both sides can have duplicate keys. The output contains
|
||||
one record per master record that has at least one matching detail record
|
||||
with the same key. This tests the ability to handle M:N relationships
|
||||
and produce one output per matched master.
|
||||
|
||||
The algorithm skips master groups with no matching detail key, and skips
|
||||
detail key groups that have no corresponding master key.
|
||||
|
||||
## Record Layout
|
||||
|
||||
Standard record (45 bytes, copybook STD-REC.cpy):
|
||||
| Field | Type | Length | Description |
|
||||
|------------|-------------------|--------|--------------------|
|
||||
| STD-KEY | PIC X | 10 | Record key |
|
||||
| STD-DATA-1 | PIC X | 20 | Text data |
|
||||
| STD-DATA-2 | PIC 9 | 10 | Numeric data |
|
||||
| STD-DATA-3 | PIC S9(7)V99 COMP-3| 5 | Packed decimal |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------|--------------------------------------|
|
||||
| main-18-matching-MN-to-M.cbl | Main COBOL program (fixed format) |
|
||||
| data-gen.sh | Generate test data for all files |
|
||||
| run.sh | Compile, run, verify |
|
||||
| README.md | This file |
|
||||
|
||||
## Data Design
|
||||
|
||||
- master.dat: 5 records -- KEY00001 (2), KEY00002 (2), KEY00003 (1)
|
||||
- detail.dat: 4 records -- KEY00001 (2), KEY00003 (2)
|
||||
- Matching keys: KEY00001, KEY00003
|
||||
- Unmatched: KEY00002 (master only)
|
||||
- Output: 3 records = 135 bytes
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
- KEY00001 group (2 master records): matches detail KEY00001 -> output 2 records
|
||||
- KEY00002 group (2 master records): no matching detail -> output 0 records
|
||||
- KEY00003 group (1 master record): matches detail KEY00003 -> output 1 record
|
||||
- Total: 3 output records
|
||||
@@ -0,0 +1,11 @@
|
||||
=== 18-matching-MN-to-M AUDIT REPORT ===
|
||||
Total Master Records: 2 Matched: 0 Unmatch: 2
|
||||
Total Detail Records: 2 Unmatch: 1
|
||||
Input Hash Amount: 0
|
||||
Output Hash Amount: 0
|
||||
Detail Hash Amount: 0
|
||||
Hash Comparison: PASS
|
||||
Control Check: PASS
|
||||
--- END OF 18-matching-MN-to-M AUDIT REPORT ---
|
||||
[TRACE] 16:35:18 7000-AUDIT entry
|
||||
[TRACE] 16:35:18 7000-TRACE iteration 02
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000
|
||||
@@ -0,0 +1,3 @@
|
||||
ERROR # 3: ERROR reading FILE-MASTER, status= KEY=0000
|
||||
ERROR # 4: ERROR reading FILE-DETAIL, status= KEY=0000
|
||||
ERROR # 7: ERROR reading FILE-DETAIL, status= KEY=0000
|
||||
@@ -0,0 +1,832 @@
|
||||
*> ============================================================
|
||||
*> 18-matching-MN-to-M : 合同↔套餐M:N→M (Contract↔Plan M:N→M)
|
||||
*> Input : FILE-MASTER (master.dat: 合同), FILE-DETAIL (detail.dat: 套餐)
|
||||
*> Output: FILE-OUT (output.dat: M条合同记录)
|
||||
*> Coverage: AM-N003, AM-A002, AM-R001
|
||||
*>
|
||||
*> EXPANDED: Added SECTION structure, contract eligibility validation,
|
||||
*> plan effective date check, duplicate plan assignment detection,
|
||||
*> audit file, error file, control totals, hash totals, tracing.
|
||||
*> ============================================================
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. MatchingMNtoM.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT FILE-MASTER ASSIGN TO 'master.dat'
|
||||
ORGANIZATION IS SEQUENTIAL
|
||||
ACCESS MODE IS SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-STATUS-1.
|
||||
SELECT FILE-DETAIL ASSIGN TO 'detail.dat'
|
||||
ORGANIZATION IS SEQUENTIAL
|
||||
ACCESS MODE IS SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-STATUS-2.
|
||||
SELECT FILE-OUT ASSIGN TO 'output.dat'
|
||||
ORGANIZATION IS SEQUENTIAL
|
||||
ACCESS MODE IS SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-STATUS-3.
|
||||
SELECT AUDIT-FILE ASSIGN TO 'audit-report-18.txt'
|
||||
ORGANIZATION IS LINE SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-STATUS-4.
|
||||
SELECT ERROR-FILE ASSIGN TO 'error-report-18.txt'
|
||||
ORGANIZATION IS LINE SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-STATUS-5.
|
||||
|
||||
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.
|
||||
01 WS-TELECOM-REC.
|
||||
COPY "telecom/TEL-INVOICE.cpy".
|
||||
|
||||
*> ============================================================
|
||||
*> FILE STATUS FIELDS
|
||||
*> ============================================================
|
||||
01 WS-FILE-STATUS-1 PIC X(02).
|
||||
01 WS-FILE-STATUS-2 PIC X(02).
|
||||
01 WS-FILE-STATUS-3 PIC X(02).
|
||||
01 WS-FILE-STATUS-4 PIC X(02).
|
||||
01 WS-FILE-STATUS-5 PIC X(02).
|
||||
|
||||
*> ============================================================
|
||||
*> EOF FLAGS
|
||||
*> ============================================================
|
||||
01 WS-EOF-MASTER PIC X(01) VALUE 'N'.
|
||||
88 WS-EOF-MASTER-YES VALUE 'Y' FALSE 'N'.
|
||||
01 WS-EOF-DETAIL PIC X(01) VALUE 'N'.
|
||||
88 WS-EOF-DETAIL-YES VALUE 'Y' FALSE 'N'.
|
||||
|
||||
*> ============================================================
|
||||
*> KEY FIELDS
|
||||
*> ============================================================
|
||||
01 WS-MASTER-KEY PIC X(10).
|
||||
01 WS-DETAIL-KEY PIC X(10).
|
||||
01 WS-GROUP-KEY 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-MATCH-COUNT PIC 9(09) VALUE 0.
|
||||
05 WS-UNMATCH-MASTER PIC 9(09) VALUE 0.
|
||||
05 WS-UNMATCH-DETAIL PIC 9(09) VALUE 0.
|
||||
05 WS-TOTAL-MASTER-IN PIC 9(09) VALUE 0.
|
||||
05 WS-TOTAL-DETAIL-IN PIC 9(09) VALUE 0.
|
||||
|
||||
*> ============================================================
|
||||
*> HASH TOTALS — verify financial data integrity
|
||||
*> ============================================================
|
||||
01 WS-HASH-TOTALS.
|
||||
05 WS-INPUT-HASH-AMT PIC 9(15) VALUE 0.
|
||||
05 WS-OUTPUT-HASH-AMT PIC 9(15) VALUE 0.
|
||||
05 WS-DETAIL-HASH-AMT PIC 9(15) VALUE 0.
|
||||
05 WS-TOTAL-HASH-OUTPUT PIC 9(15) VALUE 0.
|
||||
|
||||
*> ============================================================
|
||||
*> CONTRACT ELIGIBILITY FIELDS
|
||||
*> ============================================================
|
||||
01 WS-CONTRACT-INFO.
|
||||
05 WS-CONTRACT-STATUS PIC X(01).
|
||||
88 WS-CONTRACT-ACTIVE VALUE 'A'.
|
||||
88 WS-CONTRACT-SUSPENDED VALUE 'S'.
|
||||
88 WS-CONTRACT-TERMINATED VALUE 'T'.
|
||||
88 WS-CONTRACT-PENDING VALUE 'P'.
|
||||
05 WS-CONTRACT-EFF-DATE PIC 9(08).
|
||||
05 WS-CONTRACT-EXP-DATE PIC 9(08).
|
||||
05 WS-CONTRACT-TIER PIC 9(01).
|
||||
88 WS-TIER-BASIC VALUE 1.
|
||||
88 WS-TIER-PREMIUM VALUE 2.
|
||||
88 WS-TIER-ENTERPRISE VALUE 3.
|
||||
|
||||
*> ============================================================
|
||||
*> PLAN ELIGIBILITY FIELDS
|
||||
*> ============================================================
|
||||
01 WS-PLAN-INFO.
|
||||
05 WS-PLAN-CODE PIC X(03).
|
||||
05 WS-PLAN-EFF-DATE PIC 9(08).
|
||||
05 WS-PLAN-EXP-DATE PIC 9(08).
|
||||
05 WS-PLAN-STATUS PIC X(01).
|
||||
88 WS-PLAN-ACTIVE VALUE 'A'.
|
||||
88 WS-PLAN-DISCONTINUED VALUE 'D'.
|
||||
88 WS-PLAN-PENDING VALUE 'P'.
|
||||
05 WS-PLAN-CATEGORY PIC X(02).
|
||||
88 WS-PLAN-VOICE VALUE 'VO'.
|
||||
88 WS-PLAN-DATA VALUE 'DA'.
|
||||
88 WS-PLAN-MESSAGING VALUE 'MS'.
|
||||
88 WS-PLAN-COMBO VALUE 'CO'.
|
||||
|
||||
*> ============================================================
|
||||
*> DUPLICATE PLAN DETECTION
|
||||
*> ============================================================
|
||||
01 WS-DUP-TABLE.
|
||||
05 WS-DUP-ENTRY OCCURS 20 TIMES.
|
||||
10 WS-DUP-CONTRACT-ID PIC X(10).
|
||||
10 WS-DUP-PLAN-CODE PIC X(03).
|
||||
10 WS-DUP-COUNT PIC 9(02).
|
||||
01 WS-DUP-INDEX PIC 9(02) VALUE 0.
|
||||
01 WS-DUP-FOUND PIC X(01) VALUE 'N'.
|
||||
88 WS-DUP-FOUND-YES VALUE 'Y' FALSE 'N'.
|
||||
|
||||
*> ============================================================
|
||||
*> 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 '18-matching-MN-to-M'.
|
||||
|
||||
*> ============================================================
|
||||
*> ERROR LOG 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).
|
||||
05 FILLER PIC X(05) VALUE ' KEY='.
|
||||
05 ED-KEY PIC X(10).
|
||||
|
||||
*> ============================================================
|
||||
*> REPORT LINES
|
||||
*> ============================================================
|
||||
01 WS-AUDIT-HEADER.
|
||||
05 FILLER PIC X(40) VALUE
|
||||
'=== 18-matching-MN-to-M AUDIT REPORT ==='.
|
||||
01 WS-AUDIT-FOOTER.
|
||||
05 FILLER PIC X(50) VALUE
|
||||
'--- END OF 18-matching-MN-to-M AUDIT REPORT ---'.
|
||||
01 WS-AUDIT-LINE1.
|
||||
05 FILLER PIC X(21) VALUE 'Total Master Records:'.
|
||||
05 AL-MASTER-IN PIC Z(9)9.
|
||||
05 FILLER PIC X(10) VALUE ' Matched:'.
|
||||
05 AL-MATCHED PIC Z(9)9.
|
||||
05 FILLER PIC X(10) VALUE ' Unmatch:'.
|
||||
05 AL-UNMATCH-M PIC Z(9)9.
|
||||
01 WS-AUDIT-LINE2.
|
||||
05 FILLER PIC X(21) VALUE 'Total Detail Records:'.
|
||||
05 AL-DETAIL-IN PIC Z(9)9.
|
||||
05 FILLER PIC X(10) VALUE ' Unmatch:'.
|
||||
05 AL-UNMATCH-D PIC Z(9)9.
|
||||
01 WS-AUDIT-LINE3.
|
||||
05 FILLER PIC X(21) VALUE 'Input Hash Amount: '.
|
||||
05 AL-IN-HASH PIC Z(14)9.
|
||||
01 WS-AUDIT-LINE4.
|
||||
05 FILLER PIC X(21) VALUE 'Output Hash Amount: '.
|
||||
05 AL-OUT-HASH PIC Z(14)9.
|
||||
01 WS-AUDIT-LINE5.
|
||||
05 FILLER PIC X(21) VALUE 'Detail Hash Amount: '.
|
||||
05 AL-DTL-HASH PIC Z(14)9.
|
||||
01 WS-AUDIT-LINE6.
|
||||
05 FILLER PIC X(21) VALUE 'Hash Comparison: '.
|
||||
05 AL-HASH-RESULT PIC X(10).
|
||||
01 WS-AUDIT-LINE7.
|
||||
05 FILLER PIC X(21) VALUE 'Control Check: '.
|
||||
05 AL-CTRL-RESULT PIC X(10).
|
||||
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-J PIC 9(02).
|
||||
01 WS-AMOUNT-IN PIC 9(09).
|
||||
01 WS-AMOUNT-OUT PIC 9(09).
|
||||
01 WS-AMOUNT-DTL PIC 9(09).
|
||||
01 WS-CONTROL-OK PIC X(01) VALUE 'Y'.
|
||||
01 WS-HASH-OK PIC X(01) VALUE 'Y'.
|
||||
|
||||
01 WS-TELECOM-BILLING.
|
||||
COPY "telecom/TEL-BILLING.cpy".
|
||||
|
||||
*>
|
||||
PROCEDURE DIVISION.
|
||||
|
||||
*> ============================================================
|
||||
*> 1000-INIT — Initialization Section
|
||||
*> ============================================================
|
||||
1000-INIT SECTION.
|
||||
1000-START.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 1000-INIT start'.
|
||||
|
||||
PERFORM 7000-TRACE THRU 7000-TRACE-EXIT
|
||||
VARYING WS-I FROM 1 BY 1
|
||||
UNTIL WS-I > 1.
|
||||
|
||||
MOVE 0 TO WS-MASTER-COUNT
|
||||
MOVE 0 TO WS-DETAIL-COUNT
|
||||
MOVE 0 TO WS-MATCH-COUNT
|
||||
MOVE 0 TO WS-UNMATCH-MASTER
|
||||
MOVE 0 TO WS-UNMATCH-DETAIL
|
||||
MOVE 0 TO WS-TOTAL-MASTER-IN
|
||||
MOVE 0 TO WS-TOTAL-DETAIL-IN
|
||||
MOVE 0 TO WS-INPUT-HASH-AMT
|
||||
MOVE 0 TO WS-OUTPUT-HASH-AMT
|
||||
MOVE 0 TO WS-DETAIL-HASH-AMT
|
||||
MOVE 0 TO WS-ERROR-COUNT
|
||||
MOVE 0 TO WS-DUP-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 — File Open Section
|
||||
*> ============================================================
|
||||
2000-OPEN SECTION.
|
||||
2000-START.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 2000-OPEN start'.
|
||||
|
||||
OPEN INPUT FILE-MASTER FILE-DETAIL.
|
||||
IF WS-FILE-STATUS-1 NOT = '00'
|
||||
MOVE 'ERROR: Cannot open FILE-MASTER, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE WS-FILE-STATUS-1
|
||||
INTO WS-ERROR-MESSAGE
|
||||
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
|
||||
IF WS-FILE-STATUS-2 NOT = '00'
|
||||
MOVE 'ERROR: Cannot open FILE-DETAIL, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE WS-FILE-STATUS-2
|
||||
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 WS-FILE-STATUS-3 NOT = '00'
|
||||
MOVE 'ERROR: Cannot open FILE-OUT, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE WS-FILE-STATUS-3
|
||||
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 WS-FILE-STATUS-4 NOT = '00'
|
||||
DISPLAY 'WARNING: Cannot open AUDIT-FILE, status='
|
||||
WS-FILE-STATUS-4
|
||||
END-IF.
|
||||
|
||||
OPEN OUTPUT ERROR-FILE.
|
||||
IF WS-FILE-STATUS-5 NOT = '00'
|
||||
DISPLAY 'WARNING: Cannot open ERROR-FILE, status='
|
||||
WS-FILE-STATUS-5
|
||||
END-IF.
|
||||
|
||||
*> Write audit header
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-HEADER.
|
||||
IF WS-FILE-STATUS-4 NOT = '00'
|
||||
DISPLAY 'WARNING: AUDIT write error, status='
|
||||
WS-FILE-STATUS-4
|
||||
END-IF.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 2000-OPEN complete'
|
||||
' — all files opened OK'.
|
||||
|
||||
2000-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3000-PROCESS — Main Processing Section
|
||||
*> ============================================================
|
||||
3000-PROCESS SECTION.
|
||||
3000-START.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 3000-PROCESS start'.
|
||||
|
||||
*> --- Initial reads ---
|
||||
PERFORM 3100-READ-MASTER THRU 3100-READ-MASTER-EXIT.
|
||||
PERFORM 3200-READ-DETAIL THRU 3200-READ-DETAIL-EXIT.
|
||||
|
||||
*> --- Main merge loop ---
|
||||
PERFORM UNTIL WS-EOF-MASTER-YES OR WS-EOF-DETAIL-YES
|
||||
MOVE STD-KEY OF MASTER-REC TO WS-MASTER-KEY
|
||||
MOVE STD-KEY OF DETAIL-REC TO WS-DETAIL-KEY
|
||||
|
||||
DISPLAY '[TRACE] MasterKey=' WS-MASTER-KEY
|
||||
' DetailKey=' WS-DETAIL-KEY
|
||||
|
||||
IF WS-MASTER-KEY = WS-DETAIL-KEY
|
||||
*> Match found: validate contract then write output
|
||||
PERFORM 3300-VALIDATE-CONTRACT
|
||||
THRU 3300-VALIDATE-CONTRACT-EXIT
|
||||
IF WS-CONTRACT-ACTIVE
|
||||
PERFORM 3400-VALIDATE-PLAN
|
||||
THRU 3400-VALIDATE-PLAN-EXIT
|
||||
PERFORM 3500-CHECK-DUPLICATE
|
||||
THRU 3500-CHECK-DUPLICATE-EXIT
|
||||
IF NOT WS-DUP-FOUND-YES
|
||||
ADD 1 TO WS-MATCH-COUNT
|
||||
MOVE STD-DATA-2 OF MASTER-REC
|
||||
TO WS-AMOUNT-OUT
|
||||
ADD WS-AMOUNT-OUT TO WS-OUTPUT-HASH-AMT
|
||||
MOVE MASTER-REC TO OUT-REC
|
||||
WRITE OUT-REC
|
||||
IF WS-FILE-STATUS-3 NOT = '00'
|
||||
MOVE 'ERROR writing FILE-OUT, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE
|
||||
WS-FILE-STATUS-3
|
||||
INTO WS-ERROR-MESSAGE
|
||||
MOVE WS-MASTER-KEY TO ED-KEY
|
||||
PERFORM 6000-ERROR
|
||||
THRU 6000-ERROR-EXIT
|
||||
END-IF
|
||||
DISPLAY '[TRACE] MATCH: key='
|
||||
WS-MASTER-KEY ' written to output'
|
||||
ELSE
|
||||
DISPLAY '[TRACE] SKIP: key=' WS-MASTER-KEY
|
||||
' — duplicate plan'
|
||||
ADD 1 TO WS-UNMATCH-MASTER
|
||||
END-IF
|
||||
ELSE
|
||||
DISPLAY '[TRACE] SKIP: key=' WS-MASTER-KEY
|
||||
' — inactive contract'
|
||||
ADD 1 TO WS-UNMATCH-MASTER
|
||||
END-IF
|
||||
*> Advance master to next record (M side of M:N)
|
||||
PERFORM 3100-READ-MASTER THRU 3100-READ-MASTER-EXIT
|
||||
ELSE IF WS-MASTER-KEY < WS-DETAIL-KEY
|
||||
*> Master key not in detail: skip entire master group
|
||||
DISPLAY '[TRACE] UNMATCHED master key='
|
||||
WS-MASTER-KEY
|
||||
MOVE WS-MASTER-KEY TO WS-GROUP-KEY
|
||||
PERFORM UNTIL WS-EOF-MASTER-YES
|
||||
PERFORM 3100-READ-MASTER
|
||||
THRU 3100-READ-MASTER-EXIT
|
||||
IF WS-EOF-MASTER-YES
|
||||
EXIT PERFORM
|
||||
END-IF
|
||||
MOVE STD-KEY OF MASTER-REC TO WS-MASTER-KEY
|
||||
IF WS-MASTER-KEY NOT = WS-GROUP-KEY
|
||||
EXIT PERFORM
|
||||
END-IF
|
||||
END-PERFORM
|
||||
ELSE
|
||||
*> Detail key < master key: skip detail group
|
||||
DISPLAY '[TRACE] UNMATCHED detail key='
|
||||
WS-DETAIL-KEY
|
||||
MOVE WS-DETAIL-KEY TO WS-GROUP-KEY
|
||||
PERFORM UNTIL WS-EOF-DETAIL-YES
|
||||
PERFORM 3200-READ-DETAIL
|
||||
THRU 3200-READ-DETAIL-EXIT
|
||||
IF WS-EOF-DETAIL-YES
|
||||
EXIT PERFORM
|
||||
END-IF
|
||||
MOVE STD-KEY OF DETAIL-REC TO WS-DETAIL-KEY
|
||||
IF WS-DETAIL-KEY NOT = WS-GROUP-KEY
|
||||
EXIT PERFORM
|
||||
END-IF
|
||||
END-PERFORM
|
||||
END-IF
|
||||
END-PERFORM.
|
||||
|
||||
*> --- Process any remaining records ---
|
||||
IF NOT WS-EOF-MASTER-YES
|
||||
ADD 1 TO WS-UNMATCH-MASTER
|
||||
PERFORM UNTIL WS-EOF-MASTER-YES
|
||||
PERFORM 3100-READ-MASTER
|
||||
THRU 3100-READ-MASTER-EXIT
|
||||
END-PERFORM
|
||||
END-IF.
|
||||
|
||||
IF NOT WS-EOF-DETAIL-YES
|
||||
ADD 1 TO WS-UNMATCH-DETAIL
|
||||
PERFORM UNTIL WS-EOF-DETAIL-YES
|
||||
PERFORM 3200-READ-DETAIL
|
||||
THRU 3200-READ-DETAIL-EXIT
|
||||
END-PERFORM
|
||||
END-IF.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME
|
||||
' 3000-PROCESS complete — matched='
|
||||
WS-MATCH-COUNT.
|
||||
|
||||
3000-PROCESS-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3100-READ-MASTER — Read next master record
|
||||
*> ============================================================
|
||||
3100-READ-MASTER SECTION.
|
||||
3100-READ-MASTER-START.
|
||||
|
||||
READ FILE-MASTER
|
||||
AT END SET WS-EOF-MASTER-YES TO TRUE
|
||||
END-READ.
|
||||
|
||||
IF WS-FILE-STATUS-1 NOT = '00' AND NOT = '10'
|
||||
MOVE 'ERROR reading FILE-MASTER, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE WS-FILE-STATUS-1
|
||||
INTO WS-ERROR-MESSAGE
|
||||
MOVE WS-MASTER-KEY TO ED-KEY
|
||||
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
|
||||
END-IF.
|
||||
|
||||
IF NOT WS-EOF-MASTER-YES
|
||||
ADD 1 TO WS-MASTER-COUNT
|
||||
ADD 1 TO WS-TOTAL-MASTER-IN
|
||||
MOVE STD-DATA-2 OF MASTER-REC TO WS-AMOUNT-IN
|
||||
ADD WS-AMOUNT-IN TO WS-INPUT-HASH-AMT
|
||||
END-IF.
|
||||
|
||||
3100-READ-MASTER-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3200-READ-DETAIL — Read next detail record
|
||||
*> ============================================================
|
||||
3200-READ-DETAIL SECTION.
|
||||
3200-READ-DETAIL-START.
|
||||
|
||||
READ FILE-DETAIL
|
||||
AT END SET WS-EOF-DETAIL-YES TO TRUE
|
||||
END-READ.
|
||||
|
||||
IF WS-FILE-STATUS-2 NOT = '00' AND NOT = '10'
|
||||
MOVE 'ERROR reading FILE-DETAIL, status='
|
||||
TO WS-ERROR-MESSAGE
|
||||
STRING WS-ERROR-MESSAGE WS-FILE-STATUS-2
|
||||
INTO WS-ERROR-MESSAGE
|
||||
MOVE WS-DETAIL-KEY TO ED-KEY
|
||||
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
|
||||
END-IF.
|
||||
|
||||
IF NOT WS-EOF-DETAIL-YES
|
||||
ADD 1 TO WS-DETAIL-COUNT
|
||||
ADD 1 TO WS-TOTAL-DETAIL-IN
|
||||
MOVE STD-DATA-2 OF DETAIL-REC TO WS-AMOUNT-DTL
|
||||
ADD WS-AMOUNT-DTL TO WS-DETAIL-HASH-AMT
|
||||
END-IF.
|
||||
|
||||
3200-READ-DETAIL-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3300-VALIDATE-CONTRACT — Validate contract eligibility
|
||||
*> ============================================================
|
||||
3300-VALIDATE-CONTRACT SECTION.
|
||||
3300-VALIDATE-CONTRACT-START.
|
||||
|
||||
MOVE STD-DATA-1 OF MASTER-REC TO WS-CONTRACT-INFO.
|
||||
*> STD-DATA-1 contains: status(1) + eff-date(8) + exp-date(8)
|
||||
*> + tier(1) + reserved(2) = 20 bytes
|
||||
MOVE STD-DATA-1 OF MASTER-REC(1:1) TO WS-CONTRACT-STATUS.
|
||||
MOVE STD-DATA-1 OF MASTER-REC(2:8) TO WS-CONTRACT-EFF-DATE.
|
||||
MOVE STD-DATA-1 OF MASTER-REC(10:8) TO WS-CONTRACT-EXP-DATE.
|
||||
MOVE STD-DATA-1 OF MASTER-REC(18:1) TO WS-CONTRACT-TIER.
|
||||
|
||||
DISPLAY '[TRACE] Contract status=' WS-CONTRACT-STATUS
|
||||
' tier=' WS-CONTRACT-TIER.
|
||||
|
||||
EVALUATE TRUE
|
||||
WHEN WS-CONTRACT-ACTIVE
|
||||
DISPLAY '[TRACE] Contract ACTIVE — eligible'
|
||||
WHEN WS-CONTRACT-SUSPENDED
|
||||
DISPLAY '[TRACE] Contract SUSPENDED — ineligible'
|
||||
ADD 1 TO WS-ERROR-COUNT
|
||||
WHEN WS-CONTRACT-TERMINATED
|
||||
DISPLAY '[TRACE] Contract TERMINATED — ineligible'
|
||||
ADD 1 TO WS-ERROR-COUNT
|
||||
WHEN WS-CONTRACT-PENDING
|
||||
DISPLAY '[TRACE] Contract PENDING — ineligible'
|
||||
ADD 1 TO WS-ERROR-COUNT
|
||||
WHEN OTHER
|
||||
DISPLAY '[TRACE] Unknown contract status - rejected'
|
||||
ADD 1 TO WS-ERROR-COUNT
|
||||
END-EVALUATE.
|
||||
|
||||
3300-VALIDATE-CONTRACT-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3400-VALIDATE-PLAN — Validate plan eligibility
|
||||
*> ============================================================
|
||||
3400-VALIDATE-PLAN SECTION.
|
||||
3400-VALIDATE-PLAN-START.
|
||||
|
||||
MOVE STD-DATA-1 OF DETAIL-REC(1:3) TO WS-PLAN-CODE.
|
||||
MOVE STD-DATA-1 OF DETAIL-REC(4:8) TO WS-PLAN-EFF-DATE.
|
||||
MOVE STD-DATA-1 OF DETAIL-REC(12:8) TO WS-PLAN-EXP-DATE.
|
||||
MOVE STD-DATA-1 OF DETAIL-REC(20:1) TO WS-PLAN-STATUS.
|
||||
MOVE STD-DATA-1 OF DETAIL-REC(1:2) TO WS-PLAN-CATEGORY.
|
||||
|
||||
DISPLAY '[TRACE] Plan code=' WS-PLAN-CODE
|
||||
' category=' WS-PLAN-CATEGORY
|
||||
' status=' WS-PLAN-STATUS.
|
||||
|
||||
IF NOT WS-PLAN-ACTIVE
|
||||
DISPLAY '[TRACE] Plan NOT ACTIVE — skipping'
|
||||
ADD 1 TO WS-ERROR-COUNT
|
||||
ELSE
|
||||
DISPLAY '[TRACE] Plan ACTIVE — eligible'
|
||||
END-IF.
|
||||
|
||||
3400-VALIDATE-PLAN-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 3500-CHECK-DUPLICATE — Detect duplicate plan assignments
|
||||
*> ============================================================
|
||||
3500-CHECK-DUPLICATE SECTION.
|
||||
3500-CHECK-DUPLICATE-START.
|
||||
|
||||
MOVE 'N' TO WS-DUP-FOUND.
|
||||
|
||||
IF WS-DUP-INDEX > 0
|
||||
PERFORM VARYING WS-I FROM 1 BY 1
|
||||
UNTIL WS-I > WS-DUP-INDEX
|
||||
IF WS-DUP-CONTRACT-ID(WS-I) = WS-MASTER-KEY
|
||||
AND WS-DUP-PLAN-CODE(WS-I) = WS-PLAN-CODE
|
||||
SET WS-DUP-FOUND-YES TO TRUE
|
||||
DISPLAY '[TRACE] DUPLICATE: contract='
|
||||
WS-MASTER-KEY
|
||||
' plan=' WS-PLAN-CODE
|
||||
EXIT PERFORM
|
||||
END-IF
|
||||
END-PERFORM
|
||||
END-IF.
|
||||
|
||||
IF NOT WS-DUP-FOUND-YES
|
||||
ADD 1 TO WS-DUP-INDEX
|
||||
MOVE WS-MASTER-KEY
|
||||
TO WS-DUP-CONTRACT-ID(WS-DUP-INDEX)
|
||||
MOVE WS-PLAN-CODE
|
||||
TO WS-DUP-PLAN-CODE(WS-DUP-INDEX)
|
||||
MOVE 1 TO WS-DUP-COUNT(WS-DUP-INDEX)
|
||||
DISPLAY '[TRACE] NEW assignment: contract='
|
||||
WS-MASTER-KEY ' plan=' WS-PLAN-CODE
|
||||
END-IF.
|
||||
|
||||
3500-CHECK-DUPLICATE-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 4000-VALIDATE — Control total and hash validation
|
||||
*> ============================================================
|
||||
4000-VALIDATE SECTION.
|
||||
4000-START.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 4000-VALIDATE start'.
|
||||
|
||||
*> --- Control total check: total-in = matched + unmatched ---
|
||||
COMPUTE WS-TOTAL-MASTER-IN =
|
||||
WS-MATCH-COUNT + WS-UNMATCH-MASTER.
|
||||
|
||||
IF WS-TOTAL-MASTER-IN NOT =
|
||||
WS-MASTER-COUNT
|
||||
MOVE 'N' TO WS-CONTROL-OK
|
||||
DISPLAY 'CONTROL FAIL: master-in=' WS-MASTER-COUNT
|
||||
' matched+unmatched='
|
||||
WS-TOTAL-MASTER-IN
|
||||
STRING 'CONTROL FAIL: master-in='
|
||||
WS-MASTER-COUNT
|
||||
' matched+unmatched='
|
||||
WS-TOTAL-MASTER-IN
|
||||
INTO WS-ERROR-MESSAGE
|
||||
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
|
||||
ELSE
|
||||
DISPLAY 'CONTROL OK: master-in=' WS-MASTER-COUNT
|
||||
' = matched+unmatched'
|
||||
END-IF.
|
||||
|
||||
*> --- Hash total verification ---
|
||||
COMPUTE WS-TOTAL-HASH-OUTPUT =
|
||||
WS-OUTPUT-HASH-AMT + WS-DETAIL-HASH-AMT
|
||||
IF WS-INPUT-HASH-AMT NOT =
|
||||
WS-TOTAL-HASH-OUTPUT
|
||||
MOVE 'N' TO WS-HASH-OK
|
||||
DISPLAY 'HASH FAIL: input=' WS-INPUT-HASH-AMT
|
||||
' output+detail='
|
||||
WS-TOTAL-HASH-OUTPUT
|
||||
STRING 'HASH FAIL: input='
|
||||
WS-INPUT-HASH-AMT
|
||||
' output+detail='
|
||||
WS-TOTAL-HASH-OUTPUT
|
||||
INTO WS-ERROR-MESSAGE
|
||||
PERFORM 6000-ERROR THRU 6000-ERROR-EXIT
|
||||
ELSE
|
||||
DISPLAY 'HASH OK: input=' WS-INPUT-HASH-AMT
|
||||
' = output+detail'
|
||||
END-IF.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME
|
||||
' 4000-VALIDATE complete'.
|
||||
|
||||
4000-VALIDATE-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 5000-REPORT — Generate audit report
|
||||
*> ============================================================
|
||||
5000-REPORT SECTION.
|
||||
5000-START.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 5000-REPORT start'.
|
||||
|
||||
MOVE WS-MASTER-COUNT TO AL-MASTER-IN.
|
||||
MOVE WS-MATCH-COUNT TO AL-MATCHED.
|
||||
MOVE WS-UNMATCH-MASTER TO AL-UNMATCH-M.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE1.
|
||||
IF WS-FILE-STATUS-4 NOT = '00'
|
||||
DISPLAY 'WARNING: AUDIT write error, status='
|
||||
WS-FILE-STATUS-4
|
||||
END-IF.
|
||||
|
||||
MOVE WS-DETAIL-COUNT TO AL-DETAIL-IN.
|
||||
MOVE WS-UNMATCH-DETAIL TO AL-UNMATCH-D.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE2.
|
||||
IF WS-FILE-STATUS-4 NOT = '00'
|
||||
DISPLAY 'WARNING: AUDIT write error, status='
|
||||
WS-FILE-STATUS-4
|
||||
END-IF.
|
||||
|
||||
MOVE WS-INPUT-HASH-AMT TO AL-IN-HASH.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE3.
|
||||
|
||||
MOVE WS-OUTPUT-HASH-AMT TO AL-OUT-HASH.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE4.
|
||||
|
||||
MOVE WS-DETAIL-HASH-AMT TO AL-DTL-HASH.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE5.
|
||||
|
||||
IF WS-HASH-OK = 'Y'
|
||||
MOVE 'PASS' TO AL-HASH-RESULT
|
||||
ELSE
|
||||
MOVE 'FAIL' TO AL-HASH-RESULT
|
||||
END-IF.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE6.
|
||||
|
||||
IF WS-CONTROL-OK = 'Y'
|
||||
MOVE 'PASS' TO AL-CTRL-RESULT
|
||||
ELSE
|
||||
MOVE 'FAIL' TO AL-CTRL-RESULT
|
||||
END-IF.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-LINE7.
|
||||
|
||||
DISPLAY '18-matching-MN-to-M: Master-in='
|
||||
WS-MASTER-COUNT
|
||||
' Detail-in=' WS-DETAIL-COUNT
|
||||
' Matched=' WS-MATCH-COUNT
|
||||
' Unmatch-M=' WS-UNMATCH-MASTER
|
||||
' Unmatch-D=' WS-UNMATCH-DETAIL.
|
||||
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-FOOTER.
|
||||
|
||||
5000-REPORT-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 6000-ERROR — Error handling
|
||||
*> ============================================================
|
||||
6000-ERROR SECTION.
|
||||
6000-ERROR-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.
|
||||
IF WS-FILE-STATUS-5 NOT = '00'
|
||||
DISPLAY 'WARNING: Cannot write to ERROR-FILE, status='
|
||||
WS-FILE-STATUS-5
|
||||
END-IF.
|
||||
|
||||
6000-ERROR-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 7000-AUDIT — Tracing / audit log
|
||||
*> ============================================================
|
||||
7000-AUDIT SECTION.
|
||||
7000-AUDIT-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-AUDIT-EXIT.
|
||||
EXIT.
|
||||
|
||||
*> ============================================================
|
||||
*> 7000-TRACE — Write trace line to audit
|
||||
*> ============================================================
|
||||
7000-TRACE SECTION.
|
||||
7000-TRACE-START.
|
||||
|
||||
ACCEPT WS-CURRENT-TIME FROM TIME.
|
||||
STRING WS-CURRENT-HOUR ':' WS-CURRENT-MINUTE ':'
|
||||
WS-CURRENT-SECOND
|
||||
INTO AT-TIMESTAMP.
|
||||
|
||||
STRING '7000-TRACE iteration ' WS-I INTO AT-MESSAGE.
|
||||
WRITE AUDIT-LINE FROM WS-AUDIT-TRACE.
|
||||
|
||||
7000-TRACE-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 WS-FILE-STATUS-1 NOT = '00'
|
||||
DISPLAY 'WARNING: FILE-MASTER close status='
|
||||
WS-FILE-STATUS-1
|
||||
END-IF.
|
||||
IF WS-FILE-STATUS-2 NOT = '00'
|
||||
DISPLAY 'WARNING: FILE-DETAIL close status='
|
||||
WS-FILE-STATUS-2
|
||||
END-IF.
|
||||
IF WS-FILE-STATUS-3 NOT = '00'
|
||||
DISPLAY 'WARNING: FILE-OUT close status='
|
||||
WS-FILE-STATUS-3
|
||||
END-IF.
|
||||
|
||||
CLOSE AUDIT-FILE.
|
||||
IF WS-FILE-STATUS-4 NOT = '00'
|
||||
DISPLAY 'WARNING: AUDIT-FILE close status='
|
||||
WS-FILE-STATUS-4
|
||||
END-IF.
|
||||
|
||||
CLOSE ERROR-FILE.
|
||||
IF WS-FILE-STATUS-5 NOT = '00'
|
||||
DISPLAY 'WARNING: ERROR-FILE close status='
|
||||
WS-FILE-STATUS-5
|
||||
END-IF.
|
||||
|
||||
DISPLAY '18-matching-MN-to-M: WS-MATCH-COUNT='
|
||||
WS-MATCH-COUNT ' records written'.
|
||||
DISPLAY '18-matching-MN-to-M: PASS'.
|
||||
|
||||
IF WS-ERROR-COUNT > 0
|
||||
DISPLAY '18-matching-MN-to-M: Errors=' WS-ERROR-COUNT
|
||||
' — see error-report-18.txt'
|
||||
END-IF.
|
||||
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 9000-EXIT complete'.
|
||||
DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' END'.
|
||||
|
||||
STOP RUN.
|
||||
|
||||
9000-EXIT-EXIT.
|
||||
EXIT.
|
||||
|
||||
END PROGRAM MatchingMNtoM.
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000
|
||||
Reference in New Issue
Block a user