*> ============================================================ *> 20-matching-MN-to-MxN : CDR详细清单 (CDR Detail M:N→M×N) *> Input : FILE-MASTER (master.dat: 合同), FILE-DETAIL (detail.dat: CDR) *> Output: FILE-OUT (output.dat: M×N笛卡尔积明细) *> Coverage: AM-N005, AM-R001 *> *> EXPANDED: Added SECTION structure, CDR-to-plan mapping validation, *> call type against plan allowance, excess usage tracking, detailed *> charge line generation, audit file, error file, control totals, *> hash totals, tracing, FILE STATUS checks. *> ============================================================ >>SOURCE FORMAT IS FREE IDENTIFICATION DIVISION. PROGRAM-ID. main-20-matching-MN-to-MxN. 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-20.txt" ORGANIZATION IS LINE SEQUENTIAL FILE STATUS IS FS-AUDIT. SELECT ERROR-FILE ASSIGN TO "error-report-20.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 *> ============================================================ 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). *> ============================================================ *> TABLE COUNTS *> ============================================================ 01 WS-MASTER-COUNT PIC 9(02) VALUE 0. 01 WS-DETAIL-COUNT PIC 9(02) VALUE 0. 01 WS-I PIC 9(02). 01 WS-J PIC 9(02). *> ============================================================ *> CONTROL TOTALS *> ============================================================ 01 WS-CONTROL-TOTALS. 05 WS-TOTAL-MASTERS PIC 9(09) VALUE 0. 05 WS-TOTAL-DETAILS PIC 9(09) VALUE 0. 05 WS-OUT-COUNT PIC 9(09) VALUE 0. 05 WS-MASTER-GROUPS PIC 9(09) VALUE 0. 05 WS-DETAIL-GROUPS PIC 9(09) VALUE 0. 05 WS-UNMATCH-MASTER PIC 9(09) VALUE 0. 05 WS-UNMATCH-DETAIL 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. *> ============================================================ *> MASTER TABLE *> ============================================================ 01 WS-MASTER-TABLE. 05 WS-MASTER-ENTRY OCCURS 10 TIMES. 10 WS-MST-KEY PIC X(10). 10 WS-MST-DATA1 PIC X(20). 10 WS-MST-DATA2 PIC 9(10). 10 WS-MST-DATA3 PIC S9(7)V99 COMP-3. *> ============================================================ *> DETAIL TABLE *> ============================================================ 01 WS-DETAIL-TABLE. 05 WS-DETAIL-ENTRY OCCURS 10 TIMES. 10 WS-DTL-KEY PIC X(10). 10 WS-DTL-DATA1 PIC X(20). 10 WS-DTL-DATA2 PIC 9(10). 10 WS-DTL-DATA3 PIC S9(7)V99 COMP-3. *> ============================================================ *> CDR-TO-PLAN MAPPING VALIDATION *> ============================================================ 01 WS-CDR-MAPPING. 05 WS-CDR-CALL-TYPE PIC X(02). 88 WS-CDR-VOICE-CALL VALUE 'VO'. 88 WS-CDR-DATA-CALL VALUE 'DA'. 88 WS-CDR-MESSAGE-CALL VALUE 'MS'. 88 WS-CDR-VIDEO-CALL VALUE 'VI'. 88 WS-CDR-ROAMING-CALL VALUE 'RO'. 05 WS-CDR-DURATION PIC 9(05). 05 WS-CDR-DATA-VOLUME PIC 9(09). 05 WS-CDR-TIMESTAMP PIC X(14). 05 WS-CDR-STATUS PIC X(01). 88 WS-CDR-VALID VALUE 'V'. 88 WS-CDR-INVALID VALUE 'I'. 88 WS-CDR-PENDING VALUE 'P'. *> ============================================================ *> PLAN ALLOWANCE FIELDS *> ============================================================ 01 WS-PLAN-ALLOWANCE. 05 WS-PLAN-VOICE-MIN PIC 9(05) VALUE 0. 05 WS-PLAN-DATA-MB PIC 9(09) VALUE 0. 05 WS-PLAN-MSG-COUNT PIC 9(05) VALUE 0. 05 WS-PLAN-PRICE-VOICE PIC 9(05)V99 VALUE 0. 05 WS-PLAN-PRICE-DATA PIC 9(05)V99 VALUE 0. 05 WS-PLAN-PRICE-MSG PIC 9(05)V99 VALUE 0. 05 WS-PLAN-EXCESS-VOICE PIC 9(05)V99 VALUE 0. 05 WS-PLAN-EXCESS-DATA PIC 9(09)V99 VALUE 0. 05 WS-PLAN-EXCESS-MSG PIC 9(05)V99 VALUE 0. *> ============================================================ *> EXCESS USAGE TRACKING *> ============================================================ 01 WS-EXCESS-USAGE. 05 WS-EXCESS-VOICE-MIN PIC 9(05) VALUE 0. 05 WS-EXCESS-DATA-MB PIC 9(09) VALUE 0. 05 WS-EXCESS-MSG-COUNT PIC 9(05) VALUE 0. 05 WS-EXCESS-AMOUNT PIC 9(09)V99 VALUE 0. *> ============================================================ *> CHARGE LINE GENERATION *> ============================================================ 01 WS-CHARGE-LINE. 05 WS-CL-CONTRACT PIC X(10). 05 WS-CL-CALL-TYPE PIC X(02). 05 WS-CL-USAGE PIC 9(09). 05 WS-CL-UNIT-PRICE PIC 9(05)V99. 05 WS-CL-LINE-TOTAL PIC 9(09)V99. 05 WS-CL-EXCESS-FLAG PIC X(01). 88 WS-CL-WITHIN-ALLOWANCE VALUE 'N'. 88 WS-CL-EXCESS 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(21) VALUE '20-matching-MN-to-MxN'. *> ============================================================ *> ERROR FIELDS *> ============================================================ 01 WS-ERROR-COUNT PIC 9(05) 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(42) VALUE '=== 20-matching-MN-to-MxN AUDIT REPORT ==='. 01 WS-AUDIT-FOOTER. 05 FILLER PIC X(50) VALUE '--- END OF 20-matching-MN-to-MxN AUDIT REPORT ---'. 01 WS-AUDIT-LINE1. 05 FILLER PIC X(20) VALUE 'Master Groups: '. 05 AL-MAST-GP PIC Z(9)9. 05 FILLER PIC X(16) VALUE ' Detail Groups: '. 05 AL-DTL-GP PIC Z(9)9. 05 FILLER PIC X(16) VALUE ' Output: '. 05 AL-OUT PIC Z(9)9. 01 WS-AUDIT-LINE2. 05 FILLER PIC X(20) VALUE 'Total Masters: '. 05 AL-TOT-MAST PIC Z(9)9. 05 FILLER PIC X(16) VALUE ' Total Details: '. 05 AL-TOT-DTL PIC Z(9)9. 01 WS-AUDIT-LINE3. 05 FILLER PIC X(20) VALUE 'Hash Master In: '. 05 AL-HASH-M PIC Z(14)9. 01 WS-AUDIT-LINE4. 05 FILLER PIC X(20) VALUE 'Hash Detail In: '. 05 AL-HASH-D PIC Z(14)9. 01 WS-AUDIT-LINE5. 05 FILLER PIC X(20) VALUE 'Hash Output: '. 05 AL-HASH-O 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(20) VALUE 'Excess Voice: '. 05 AL-EX-VOICE PIC Z(9)9. 05 FILLER PIC X(16) VALUE ' Excess Data: '. 05 AL-EX-DATA PIC Z(9)9. 05 FILLER PIC X(16) VALUE ' Excess Msg: '. 05 AL-EX-MSG PIC Z(9)9. 01 WS-AUDIT-LINE9. 05 FILLER PIC X(20) VALUE 'Excess Amount: '. 05 AL-EX-AMT PIC Z(11)9.99. 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-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-UNMATCH-MASTER-GRP PIC 9(09) VALUE 0. 01 WS-UNMATCH-DETAIL-GRP PIC 9(09) VALUE 0. 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-TOTAL-MASTERS MOVE 0 TO WS-TOTAL-DETAILS MOVE 0 TO WS-OUT-COUNT MOVE 0 TO WS-MASTER-GROUPS MOVE 0 TO WS-DETAIL-GROUPS MOVE 0 TO WS-UNMATCH-MASTER MOVE 0 TO WS-UNMATCH-DETAIL 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-EXCESS-VOICE-MIN MOVE 0 TO WS-EXCESS-DATA-MB MOVE 0 TO WS-EXCESS-MSG-COUNT MOVE 0 TO WS-EXCESS-AMOUNT MOVE 'Y' TO WS-CONTROL-OK MOVE 'Y' TO WS-HASH-OK MOVE 0 TO WS-UNMATCH-MASTER-GRP MOVE 0 TO WS-UNMATCH-DETAIL-GRP 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-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-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-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 *> ============================================================ 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 — output=' 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-EXIT END-IF. IF NOT EOF-MASTER ADD 1 TO WS-TOTAL-MASTERS 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-EXIT END-IF. IF NOT EOF-DETAIL ADD 1 TO WS-TOTAL-DETAILS 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: Cartesian product + validation *> ============================================================ 3300-PROCESS-MATCH SECTION. 3300-START. DISPLAY '[TRACE] MATCH group key=' WS-MASTER-KEY. MOVE WS-MASTER-KEY TO WS-KEY-HOLD. ADD 1 TO WS-MASTER-GROUPS. *> Load all master records for this key MOVE 0 TO WS-MASTER-COUNT. PERFORM UNTIL EOF-MASTER OR WS-MASTER-KEY NOT = WS-KEY-HOLD ADD 1 TO WS-MASTER-COUNT MOVE MASTER-REC TO WS-MASTER-ENTRY(WS-MASTER-COUNT) PERFORM 3100-READ-MASTER THRU 3100-READ-MASTER-EXIT END-PERFORM. DISPLAY '[TRACE] Masters loaded=' WS-MASTER-COUNT. *> Load all detail records for this key MOVE 0 TO WS-DETAIL-COUNT. PERFORM UNTIL EOF-DETAIL OR WS-DETAIL-KEY NOT = WS-KEY-HOLD ADD 1 TO WS-DETAIL-COUNT MOVE DETAIL-REC TO WS-DETAIL-ENTRY(WS-DETAIL-COUNT) PERFORM 3200-READ-DETAIL THRU 3200-READ-DETAIL-EXIT END-PERFORM. ADD 1 TO WS-DETAIL-GROUPS. DISPLAY '[TRACE] Details loaded=' WS-DETAIL-COUNT. *> For each master × detail, validate CDR and generate charge line PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > WS-MASTER-COUNT PERFORM VARYING WS-J FROM 1 BY 1 UNTIL WS-J > WS-DETAIL-COUNT *> Validate CDR-to-plan mapping PERFORM 3400-VALIDATE-CDR THRU 3400-VALIDATE-CDR-EXIT PERFORM 3500-CHECK-ALLOWANCE THRU 3500-CHECK-ALLOWANCE-EXIT *> Generate charge line with excess tracking PERFORM 3510-GENERATE-CHARGE THRU 3510-GENERATE-CHARGE-EXIT *> Write the output record MOVE WS-DETAIL-ENTRY(WS-J) 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-EXIT END-IF ADD 1 TO WS-OUT-COUNT MOVE WS-DTL-DATA2(WS-J) TO WS-AMOUNT-OUT ADD WS-AMOUNT-OUT TO WS-HASH-OUT END-PERFORM END-PERFORM. 3300-PROCESS-MATCH-EXIT. EXIT. *> ============================================================ *> 3400-VALIDATE-CDR — Validate CDR record fields *> ============================================================ 3400-VALIDATE-CDR SECTION. 3400-START. *> Extract CDR call type from detail DATA1 MOVE WS-DTL-DATA1(WS-J)(1:2) TO WS-CDR-CALL-TYPE. MOVE WS-DTL-DATA1(WS-J)(3:5) TO WS-CDR-DURATION. MOVE WS-DTL-DATA1(WS-J)(8:9) TO WS-CDR-DATA-VOLUME. MOVE WS-DTL-DATA1(WS-J)(17:1) TO WS-CDR-STATUS. DISPLAY '[TRACE] CDR type=' WS-CDR-CALL-TYPE ' dur=' WS-CDR-DURATION ' vol=' WS-CDR-DATA-VOLUME ' status=' WS-CDR-STATUS. *> Validate CDR status IF WS-CDR-INVALID DISPLAY '[TRACE] CDR INVALID — marking' ADD 1 TO WS-ERROR-COUNT END-IF. *> Determine call type and set default allowances MOVE 500 TO WS-PLAN-VOICE-MIN MOVE 1024 TO WS-PLAN-DATA-MB MOVE 1000 TO WS-PLAN-MSG-COUNT MOVE 0.05 TO WS-PLAN-PRICE-VOICE MOVE 0.01 TO WS-PLAN-PRICE-DATA MOVE 0.02 TO WS-PLAN-PRICE-MSG MOVE 0.10 TO WS-PLAN-EXCESS-VOICE MOVE 0.05 TO WS-PLAN-EXCESS-DATA MOVE 0.05 TO WS-PLAN-EXCESS-MSG. DISPLAY '[TRACE] Allowances: voice=' WS-PLAN-VOICE-MIN ' data=' WS-PLAN-DATA-MB ' msg=' WS-PLAN-MSG-COUNT. 3400-VALIDATE-CDR-EXIT. EXIT. *> ============================================================ *> 3500-CHECK-ALLOWANCE — Check CDR usage against plan allowance *> ============================================================ 3500-CHECK-ALLOWANCE SECTION. 3500-START. EVALUATE TRUE WHEN WS-CDR-VOICE-CALL IF WS-CDR-DURATION > WS-PLAN-VOICE-MIN COMPUTE WS-EXCESS-VOICE-MIN = WS-CDR-DURATION - WS-PLAN-VOICE-MIN COMPUTE WS-EXCESS-AMOUNT = WS-EXCESS-AMOUNT + (WS-EXCESS-VOICE-MIN * WS-PLAN-EXCESS-VOICE) DISPLAY '[TRACE] VOICE EXCESS: ' WS-EXCESS-VOICE-MIN ' min' END-IF WHEN WS-CDR-DATA-CALL IF WS-CDR-DATA-VOLUME > WS-PLAN-DATA-MB COMPUTE WS-EXCESS-DATA-MB = WS-CDR-DATA-VOLUME - WS-PLAN-DATA-MB COMPUTE WS-EXCESS-AMOUNT = WS-EXCESS-AMOUNT + (WS-EXCESS-DATA-MB * WS-PLAN-EXCESS-DATA) DISPLAY '[TRACE] DATA EXCESS: ' WS-EXCESS-DATA-MB ' MB' END-IF WHEN WS-CDR-MESSAGE-CALL IF WS-CDR-DURATION > WS-PLAN-MSG-COUNT COMPUTE WS-EXCESS-MSG-COUNT = WS-CDR-DURATION - WS-PLAN-MSG-COUNT COMPUTE WS-EXCESS-AMOUNT = WS-EXCESS-AMOUNT + (WS-EXCESS-MSG-COUNT * WS-PLAN-EXCESS-MSG) DISPLAY '[TRACE] MSG EXCESS: ' WS-EXCESS-MSG-COUNT ' msgs' END-IF WHEN WS-CDR-VIDEO-CALL DISPLAY '[TRACE] VIDEO call — special pricing' IF WS-CDR-DURATION > 100 COMPUTE WS-EXCESS-VOICE-MIN = WS-CDR-DURATION - 100 COMPUTE WS-EXCESS-AMOUNT = WS-EXCESS-AMOUNT + (WS-EXCESS-VOICE-MIN * 0.15) END-IF WHEN WS-CDR-ROAMING-CALL DISPLAY '[TRACE] ROAMING call — premium rate' COMPUTE WS-EXCESS-AMOUNT = WS-EXCESS-AMOUNT + (WS-CDR-DURATION * 0.25) WHEN OTHER DISPLAY '[TRACE] Unknown call type no allowance' ADD 1 TO WS-ERROR-COUNT END-EVALUATE. 3500-CHECK-ALLOWANCE-EXIT. EXIT. *> ============================================================ *> 3510-GENERATE-CHARGE — Build charge line entry *> ============================================================ 3510-GENERATE-CHARGE SECTION. 3510-START. *> Build a charge line record for audit/reporting MOVE WS-MST-KEY(WS-I) TO WS-CL-CONTRACT. MOVE WS-CDR-CALL-TYPE TO WS-CL-CALL-TYPE. EVALUATE TRUE WHEN WS-CDR-VOICE-CALL MOVE WS-CDR-DURATION TO WS-CL-USAGE MOVE WS-PLAN-PRICE-VOICE TO WS-CL-UNIT-PRICE WHEN WS-CDR-DATA-CALL MOVE WS-CDR-DATA-VOLUME TO WS-CL-USAGE MOVE WS-PLAN-PRICE-DATA TO WS-CL-UNIT-PRICE WHEN WS-CDR-MESSAGE-CALL MOVE WS-CDR-DURATION TO WS-CL-USAGE MOVE WS-PLAN-PRICE-MSG TO WS-CL-UNIT-PRICE WHEN OTHER MOVE 0 TO WS-CL-USAGE MOVE 0 TO WS-CL-UNIT-PRICE END-EVALUATE. COMPUTE WS-CL-LINE-TOTAL = WS-CL-USAGE * WS-CL-UNIT-PRICE. DISPLAY '[TRACE] CHARGE: contract=' WS-CL-CONTRACT ' type=' WS-CL-CALL-TYPE ' usage=' WS-CL-USAGE ' total=' WS-CL-LINE-TOTAL. 3510-GENERATE-CHARGE-EXIT. EXIT. *> ============================================================ *> 3610-SKIP-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. ADD 1 TO WS-UNMATCH-DETAIL-GRP. 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 *> ============================================================ 3620-SKIP-MASTER-GROUP SECTION. 3620-START. DISPLAY '[TRACE] SKIP-MASTER-GROUP key=' WS-MASTER-KEY. MOVE WS-MASTER-KEY TO WS-KEY-HOLD. ADD 1 TO WS-UNMATCH-MASTER-GRP. 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 — Control and hash validation *> ============================================================ 4000-VALIDATE SECTION. 4000-START. DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 4000-VALIDATE start'. *> Expected output = total-masters * total-details (groups only) COMPUTE WS-AMOUNT-OUT = WS-TOTAL-MASTERS * WS-TOTAL-DETAILS IF WS-OUT-COUNT NOT = WS-AMOUNT-OUT MOVE 'N' TO WS-CONTROL-OK MOVE 'Control FAIL: output count mismatch' TO WS-ERROR-MESSAGE PERFORM 6000-ERROR THRU 6000-EXIT DISPLAY 'CONTROL FAIL: out=' WS-OUT-COUNT ' expected masters*total: ' WS-TOTAL-MASTERS ' * ' WS-TOTAL-DETAILS ' = ' WS-AMOUNT-OUT ELSE DISPLAY 'CONTROL OK: output=' WS-OUT-COUNT ' = masters*details' END-IF. *> Hash check IF WS-HASH-MASTER-IN NOT = WS-HASH-DETAIL-IN MOVE 'N' TO WS-HASH-OK MOVE 'Hash FAIL: master/detail mismatch' TO WS-ERROR-MESSAGE PERFORM 6000-ERROR THRU 6000-EXIT DISPLAY 'HASH FAIL: master=' WS-HASH-MASTER-IN ' detail=' WS-HASH-DETAIL-IN ELSE DISPLAY 'HASH OK: master/detail balanced' END-IF. DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 4000-VALIDATE complete'. 4000-EXIT. EXIT. *> ============================================================ *> 5000-REPORT — Audit report generation *> ============================================================ 5000-REPORT SECTION. 5000-START. DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' 5000-REPORT start'. MOVE WS-MASTER-GROUPS TO AL-MAST-GP. MOVE WS-DETAIL-GROUPS TO AL-DTL-GP. MOVE WS-OUT-COUNT TO AL-OUT. WRITE AUDIT-LINE FROM WS-AUDIT-LINE1. MOVE WS-TOTAL-MASTERS TO AL-TOT-MAST. MOVE WS-TOTAL-DETAILS TO AL-TOT-DTL. WRITE AUDIT-LINE FROM WS-AUDIT-LINE2. MOVE WS-HASH-MASTER-IN TO AL-HASH-M. WRITE AUDIT-LINE FROM WS-AUDIT-LINE3. MOVE WS-HASH-DETAIL-IN TO AL-HASH-D. WRITE AUDIT-LINE FROM WS-AUDIT-LINE4. MOVE WS-HASH-OUT TO AL-HASH-O. 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. MOVE WS-EXCESS-VOICE-MIN TO AL-EX-VOICE. MOVE WS-EXCESS-DATA-MB TO AL-EX-DATA. MOVE WS-EXCESS-MSG-COUNT TO AL-EX-MSG. WRITE AUDIT-LINE FROM WS-AUDIT-LINE8. MOVE WS-EXCESS-AMOUNT TO AL-EX-AMT. WRITE AUDIT-LINE FROM WS-AUDIT-LINE9. *> Console summary DISPLAY '20-matching-MN-to-MxN: Masters=' WS-TOTAL-MASTERS ' Details=' WS-TOTAL-DETAILS ' Output=' WS-OUT-COUNT ' ExcessAmt=' WS-EXCESS-AMOUNT. 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-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 "20-matching-MN-to-MxN: PASS". IF WS-ERROR-COUNT > 0 DISPLAY '20-matching-MN-to-MxN: Errors=' WS-ERROR-COUNT ' — see error-report-20.txt' END-IF. DISPLAY '[TRACE] ' WS-PROGRAM-NAME ' END'. STOP RUN. 9000-EXIT-EXIT. EXIT. END PROGRAM main-20-matching-MN-to-MxN.