94400d50d4
作为子目录纳入系统,与核心测试管道协同 Co-Authored-By: Claude <noreply@anthropic.com>
833 lines
32 KiB
COBOL
833 lines
32 KiB
COBOL
*> ============================================================
|
|
*> 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.
|