Files
cobol-java-v3/benchmark-programs/20-matching-MN-to-MxN/main-20-matching-MN-to-MxN.cbl
T
NB-076 94400d50d4 feat: add benchmark-programs — 58 telecom COBOL test programs
作为子目录纳入系统,与核心测试管道协同

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-25 09:53:21 +08:00

893 lines
34 KiB
COBOL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
*> ============================================================
*> 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.