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