feat: add benchmark-programs — 58 telecom COBOL test programs

作为子目录纳入系统,与核心测试管道协同

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
NB-076
2026-06-25 09:53:21 +08:00
parent 50f9f0f52f
commit 94400d50d4
278 changed files with 44125 additions and 0 deletions
@@ -0,0 +1,37 @@
# 20-matching-MN-to-MxN
## 电信业务场景
CDR详细清单M:N→M×N。多个合同×多个通话明细的笛卡尔积组合,输出完整的CDR详细清单(M×N件)。
**M:N matching — Cartesian product output (M x N records per matching key).**
Tests the scenario where both input files may contain duplicate keys and
every combination of matching master and detail records must be output
(the full Cartesian product).
## Test data
| File | Records | Keys |
|-------------|---------|------------------------------------------|
| master.dat | 5 | KEY00001 (x2), KEY00002 (x1), KEY00003 (x2) |
| detail.dat | 7 | KEY00001 (x3), KEY00003 (x2), KEY00004 (x2) |
- **KEY00001:** 2 masters x 3 details = 6 output records
- **KEY00003:** 2 masters x 2 details = 4 output records
- **Total output:** 10 records
- **Unmatched:** KEY00002 (master only), KEY00004 (detail only)
## Algorithm
1. Read both files synchronously (both assumed sorted by key).
2. When keys match: read all master records for that key into a table,
read all detail records for that key into a table, then write M x N
output records covering every combination.
3. Unmatched groups are skipped via the standard key-comparison logic.
## Expected output
- **output.dat:** 10 records x 45 bytes = 450 bytes
- Program displays: `20-matching-MN-to-MxN: PASS`
- Script displays: `20-matching-MN-to-MxN: ALL TESTS PASSED`
@@ -0,0 +1,12 @@
=== 20-matching-MN-to-MxN AUDIT REPORT ===
Master Groups: 3 Detail Groups: 3 Output: 2
Total Masters: 2 Total Details: 2
Hash Master In: 1002
Hash Detail In: 1002
Hash Output: 1002
Hash Check: PASS
Control Check: FAIL
Excess Voice: 0 Excess Data: 0 Excess Msg: 0
Excess Amount: 0.00
--- END OF 20-matching-MN-to-MxN AUDIT REPORT ---
[TRACE] 16:35:21 7000-AUDIT entry
@@ -0,0 +1 @@
E000000001F00000000000000000010000000501000000601E000000002F00000000000000000020000000502000000602E000000003F00000000000000000030000000503000000603E000000004F00000000000000000040000000504000000604E000000005F00000000000000000050000000505000000605E000000006F00000000000000000060000000506000000606E000000007F00000000000000000070000000507000000607E000000008F00000000000000000080000000508000000608E000000009F00000000000000000090000000509000000609E000000010F00000000000000000100000000510000000610E000000011F00000000000000000110000000511000000611E000000012F00000000000000000120000000512000000612E000000013F00000000000000000130000000513000000613E000000014F00000000000000000140000000514000000614E000000015F00000000000000000150000000515000000615E000000016F00000000000000000160000000516000000616E000000017F00000000000000000170000000517000000617E000000018F00000000000000000180000000518000000618E000000019F00000000000000000190000000519000000619E000000020F00000000000000000200000000520000000620E000000021F00000000000000000210000000521000000621E000000022F00000000000000000220000000522000000622E000000023F00000000000000000230000000523000000623E000000024F00000000000000000240000000524000000624E000000025F00000000000000000250000000525000000625E000000026F00000000000000000260000000526000000626E000000027F00000000000000000270000000527000000627E000000028F00000000000000000280000000528000000628E000000029F00000000000000000290000000529000000629E000000030F00000000000000000300000000530000000630E000000031F00000000000000000310000000531000000631E000000032F00000000000000000320000000532000000632E000000033F00000000000000000330000000533000000633E000000034F00000000000000000340000000534000000634E000000035F00000000000000000350000000535000000635E000000036F00000000000000000360000000536000000636E000000037F00000000000000000370000000537000000637E000000038F00000000000000000380000000538000000638E000000039F00000000000000000390000000539000000639E000000040F00000000000000000400000000540000000640E000000041F00000000000000000410000000541000000641E000000042F00000000000000000420000000542000000642E000000043F00000000000000000430000000543000000643E000000044F00000000000000000440000000544000000644E000000045F00000000000000000450000000545000000645E000000046F00000000000000000460000000546000000646E000000047F00000000000000000470000000547000000647E000000048F00000000000000000480000000548000000648E000000049F00000000000000000490000000549000000649E000000050F00000000000000000500000000550000000650E000000051F00000000000000000510000000551000000651E000000052F00000000000000000520000000552000000652E000000053F00000000000000000530000000553000000653E000000054F00000000000000000540000000554000000654E000000055F00000000000000000550000000555000000655E000000056F00000000000000000560000000556000000656E000000057F00000000000000000570000000557000000657E000000058F00000000000000000580000000558000000658E000000059F00000000000000000590000000559000000659E000000060F00000000000000000600000000560000000660E000000061F00000000000000000610000000561000000661E000000062F00000000000000000620000000562000000662E000000063F00000000000000000630000000563000000663E000000064F00000000000000000640000000564000000664E000000065F00000000000000000650000000565000000665E000000066F00000000000000000660000000566000000666E000000067F00000000000000000670000000567000000667E000000068F00000000000000000680000000568000000668E000000069F00000000000000000690000000569000000669E000000070F00000000000000000700000000570000000670E000000071F00000000000000000710000000571000000671E000000072F00000000000000000720000000572000000672E000000073F00000000000000000730000000573000000673E000000074F00000000000000000740000000574000000674
@@ -0,0 +1,4 @@
ERROR # 3: ERROR reading FILE-MASTER, status=
ERROR # 4: ERROR reading FILE-DETAIL, status=
ERROR # 6: Control FAIL: output count mismatch
ERROR # 7: Control FAIL: output count mismatch
@@ -0,0 +1,892 @@
*> ============================================================
*> 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.
@@ -0,0 +1 @@
E000000001F00000000000000000010000000501000000601E000000002F00000000000000000020000000502000000602E000000003F00000000000000000030000000503000000603E000000004F00000000000000000040000000504000000604E000000005F00000000000000000050000000505000000605E000000006F00000000000000000060000000506000000606E000000007F00000000000000000070000000507000000607E000000008F00000000000000000080000000508000000608E000000009F00000000000000000090000000509000000609E000000010F00000000000000000100000000510000000610E000000011F00000000000000000110000000511000000611E000000012F00000000000000000120000000512000000612E000000013F00000000000000000130000000513000000613E000000014F00000000000000000140000000514000000614E000000015F00000000000000000150000000515000000615E000000016F00000000000000000160000000516000000616E000000017F00000000000000000170000000517000000617E000000018F00000000000000000180000000518000000618E000000019F00000000000000000190000000519000000619E000000020F00000000000000000200000000520000000620E000000021F00000000000000000210000000521000000621E000000022F00000000000000000220000000522000000622E000000023F00000000000000000230000000523000000623E000000024F00000000000000000240000000524000000624E000000025F00000000000000000250000000525000000625E000000026F00000000000000000260000000526000000626E000000027F00000000000000000270000000527000000627E000000028F00000000000000000280000000528000000628E000000029F00000000000000000290000000529000000629E000000030F00000000000000000300000000530000000630E000000031F00000000000000000310000000531000000631E000000032F00000000000000000320000000532000000632E000000033F00000000000000000330000000533000000633E000000034F00000000000000000340000000534000000634E000000035F00000000000000000350000000535000000635E000000036F00000000000000000360000000536000000636E000000037F00000000000000000370000000537000000637E000000038F00000000000000000380000000538000000638E000000039F00000000000000000390000000539000000639E000000040F00000000000000000400000000540000000640E000000041F00000000000000000410000000541000000641E000000042F00000000000000000420000000542000000642E000000043F00000000000000000430000000543000000643E000000044F00000000000000000440000000544000000644E000000045F00000000000000000450000000545000000645E000000046F00000000000000000460000000546000000646E000000047F00000000000000000470000000547000000647E000000048F00000000000000000480000000548000000648E000000049F00000000000000000490000000549000000649E000000050F00000000000000000500000000550000000650E000000051F00000000000000000510000000551000000651E000000052F00000000000000000520000000552000000652E000000053F00000000000000000530000000553000000653E000000054F00000000000000000540000000554000000654E000000055F00000000000000000550000000555000000655E000000056F00000000000000000560000000556000000656E000000057F00000000000000000570000000557000000657E000000058F00000000000000000580000000558000000658E000000059F00000000000000000590000000559000000659E000000060F00000000000000000600000000560000000660E000000061F00000000000000000610000000561000000661E000000062F00000000000000000620000000562000000662E000000063F00000000000000000630000000563000000663E000000064F00000000000000000640000000564000000664E000000065F00000000000000000650000000565000000665E000000066F00000000000000000660000000566000000666E000000067F00000000000000000670000000567000000667E000000068F00000000000000000680000000568000000668E000000069F00000000000000000690000000569000000669E000000070F00000000000000000700000000570000000670E000000071F00000000000000000710000000571000000671E000000072F00000000000000000720000000572000000672E000000073F00000000000000000730000000573000000673E000000074F00000000000000000740000000574000000674
@@ -0,0 +1 @@
E000000001F00000000000000000010000000501000000601000001F0000000000000000001000000050100000