*> ============================================================ *> 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.