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,63 @@
# 02-matching-1-N: 1:N Matching (one master matches N details by key)
## 电信业务场景
合同↔通话明细关联。读取合同文件(CONTRACT)和通话明细文件(CDR),按合同ID进行1:N关联。一个合同可关联多条CDR,未关联的记录输出到异常文件。
## Description
Tests one-to-many matching where one master record can match multiple detail
records sharing the same STD-KEY. The program reads a master, then reads all
consecutive details with the same key, writing one output record per matching
detail. Unmatched master and detail records are silently skipped.
## Record Layout
| Field | Type | Length | Description |
|------------|-----------------|--------|---------------------------|
| STD-KEY | PIC X | 10 | Record key |
| STD-DATA-1 | PIC X | 20 | Description text |
| STD-DATA-2 | PIC 9 | 10 | Numeric data (display) |
| STD-DATA-3 | PIC S9(7)V99 | 05 | Numeric data (COMP-3) |
Total record length: 45 bytes.
## Files
| File | Purpose |
|-----------------------------|-----------------------------------|
| main-02-matching-1-N.cbl | Main COBOL program (fixed format) |
| data-gen.sh | Generate test data files |
| run.sh | Compile, run, verify |
| README.md | This file |
## Data
- **master.dat**: 2 records — KEY00001 (has 3 matching details),
KEY00004 (unmatched master)
- **detail.dat**: 4 records — KEY00001 x3 (3 details for KEY00001),
KEY00005 (unmatched detail)
## Matching Logic
1. Read master, then advance detail cursor to find matching key.
2. For each detail with the same key, write one output record (from master).
3. When details run out or key changes, read next master.
4. Skip unmatched masters (master key < detail key).
5. Skip unmatched details (detail key < master key).
## Test
| Check | Expected |
|------------------------|---------------------------|
| Output records | 3 (1 master x 3 details) |
| Output file size | 135 bytes (3 x 45) |
| Unmatched master | 1 (KEY00004) |
| Unmatched detail | 1 (KEY00005) |
## Usage
```bash
cd 02-matching-1-N
bash run.sh
```
@@ -0,0 +1,31 @@
================================================
02-MATCHING-1-N AUDIT REPORT
Program Version: V2.00
Run Date: 20260622 Time: 16452669
================================================
RECORD COUNT SUMMARY:
Master (contract) records : 00002
Detail (CDR) records : 00003
Matched (output) records : 00000
Unmatched contracts : 00000
Unmatched CDRs : 00003
Duplicate CDRs detected : 00000
Avg CDRs per contract : N/A (no division)
HASH TOTAL RECONCILIATION:
Input hash (contract) : 000000006060606
Output hash : 000000000000000
Error hash : 000000000000000
** HASH MISMATCH ** Diff: 00000000606060v
ERROR SUMMARY:
Key format errors : 00005
Duplicate CDRs : 00000
Expired contracts : 00000
CDR date outside rng : 00000
Warnings : 00010
Fatal errors : 00000
================================================
END OF AUDIT REPORT
Generated: 20260622 16452669
@@ -0,0 +1 @@
0000000000000000000
Binary file not shown.
@@ -0,0 +1,791 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. Main02Matching1N.
*> ============================================================
*> 02-matching-1-N : 合同↔通话明细匹配 (Contract↔CDR 1:N)
*> Input : master.dat (合同文件: 按CONTRACT-ID排序)
*> detail.dat (通话明细: 按CONTRACT-ID排序)
*> Output: output.dat (合同关联的通话明细清单)
*> error.dat (未关联CDR/合同)
*> audit-report.txt (审计报告: 处理统计)
*> Coverage: MT-N002, MT-N004, MT-N005, MT-R001
*> contract validity period, CDR date range, dup detection
*> ============================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-MASTER ASSIGN TO 'master.dat'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-MASTER-STATUS.
SELECT FILE-DETAIL ASSIGN TO 'detail.dat'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-DETAIL-STATUS.
SELECT FILE-OUT ASSIGN TO 'output.dat'
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-OUT-STATUS.
SELECT FILE-ERR ASSIGN TO 'error.dat'
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-ERR-STATUS.
SELECT AUDIT-FILE ASSIGN TO 'audit-report.txt'
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-AUDIT-STATUS.
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 FILE-ERR.
01 ERR-REC.
05 ERR-TYPE PIC X(10).
05 ERR-KEY PIC X(10).
05 ERR-DATA PIC X(20).
05 ERR-AMOUNT PIC 9(10).
05 ERR-FILLER PIC X(30).
FD AUDIT-FILE.
01 AUDIT-REC PIC X(120).
WORKING-STORAGE SECTION.
01 WS-TELECOM-CONTRACT.
COPY "telecom/TEL-BILLING.cpy".
01 WS-TELECOM-CDR.
COPY "telecom/TEL-CDR.cpy".
*> File status fields
01 WS-MASTER-STATUS PIC X(02).
01 WS-DETAIL-STATUS PIC X(02).
01 WS-OUT-STATUS PIC X(02).
01 WS-ERR-STATUS PIC X(02).
01 WS-AUDIT-STATUS PIC X(02).
*> EOF and status flags
01 WS-FLAGS.
05 WS-MASTER-EOF PIC X VALUE 'N'.
88 WS-MASTER-END VALUE 'Y' FALSE 'N'.
05 WS-DETAIL-EOF PIC X VALUE 'N'.
88 WS-DETAIL-END VALUE 'Y' FALSE 'N'.
05 WS-HAVE-MAST PIC X VALUE 'N'.
88 WS-HAVE-MAST-Y VALUE 'Y' FALSE 'N'.
*> Key area for contract matching
01 WS-KEY-AREA.
05 WS-MASTER-KEY PIC X(10).
05 WS-DETAIL-KEY PIC X(10).
05 WS-GROUP-KEY PIC X(10).
05 WS-PREV-DETL-KEY PIC X(10).
05 WS-PREV-MAST-KEY PIC X(10).
*> Counter accumulators
01 WS-COUNTERS.
05 WS-MATCH-COUNT PIC 9(05) VALUE 0.
05 WS-MAST-READ-COUNT PIC 9(05) VALUE 0.
05 WS-DETL-READ-COUNT PIC 9(05) VALUE 0.
05 WS-UNMATCH-MAST-COUNT PIC 9(05) VALUE 0.
05 WS-UNMATCH-DETL-COUNT PIC 9(05) VALUE 0.
05 WS-DUP-CDR-COUNT PIC 9(05) VALUE 0.
05 WS-ERROR-COUNT PIC 9(05) VALUE 0.
05 WS-WARN-COUNT PIC 9(05) VALUE 0.
05 WS-FATAL-COUNT PIC 9(05) VALUE 0.
05 WS-SEQ-ERR-COUNT PIC 9(05) VALUE 0.
05 WS-KEY-FMT-ERR-COUNT PIC 9(05) VALUE 0.
*> Hash totals for batch control
01 WS-HASH-TOTALS.
05 WS-INPUT-HASH-MAST PIC 9(15) VALUE 0.
05 WS-INPUT-HASH-DETL PIC 9(15) VALUE 0.
05 WS-OUTPUT-HASH PIC 9(15) VALUE 0.
05 WS-ERROR-HASH PIC 9(15) VALUE 0.
05 WS-HASH-DIFF PIC S9(15) VALUE 0.
*> Date and timestamp areas
01 WS-DATE-TIME.
05 WS-PROC-DATE PIC 9(08).
05 WS-PROC-TIME PIC 9(08).
05 WS-TIMESTAMP.
10 WS-TS-DATE PIC X(08).
10 WS-TS-SPACE PIC X VALUE ' '.
10 WS-TS-TIME PIC X(08).
*> Validation accumulators
01 WS-VALIDATION.
05 WS-PREV-CONTRACT-KEY PIC X(10).
05 WS-PREV-CDR-KEY PIC X(10).
05 WS-CDR-DUP-FLAG PIC X VALUE 'N'.
88 WS-CDR-DUP-FOUND VALUE 'Y' FALSE 'N'.
05 WS-VALID-KEY-CHARS PIC X(36) VALUE
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.
05 WS-KEY-CHAR PIC X.
05 WS-CHAR-OK PIC X VALUE 'N'.
88 WS-CHAR-IS-OK VALUE 'Y' FALSE 'N'.
05 WS-IDX PIC 9(02).
05 WS-KEY-INVALID-FLAG PIC X VALUE 'N'.
88 WS-KEY-INVALID VALUE 'Y' FALSE 'N'.
05 WS-CDR-ID-SAVE PIC X(10).
05 WS-CDR-ID-PREV PIC X(10).
*> Contract validity date check
01 WS-CONTRACT-VALIDITY.
05 WS-CONTRACT-MONTH PIC 9(06).
05 WS-CURRENT-MONTH PIC 9(06).
05 WS-CONTRACT-ACTIVE PIC X VALUE 'Y'.
88 WS-CONTRACT-IS-ACTIVE VALUE 'Y' FALSE 'N'.
05 WS-CONTRACT-EXPIRED-COUNT PIC 9(05) VALUE 0.
*> CDR date range validation
01 WS-CDR-DATE-CHECK.
05 WS-CDR-MONTH PIC 9(06).
05 WS-CDR-DATE-FLAG PIC X VALUE 'Y'.
88 WS-CDR-DATE-OK VALUE 'Y' FALSE 'N'.
05 WS-CDR-OUTSIDE-COUNT PIC 9(05) VALUE 0.
*> Amount comparison area
01 WS-AMOUNT-AREAS.
05 WS-MAST-AMT-NUM PIC 9(10).
05 WS-DETL-AMT-NUM PIC 9(10).
05 WS-OUT-AMT-NUM PIC 9(10).
05 WS-ERR-AMT-NUM PIC 9(10).
*> Error message areas
01 WS-ERR-MSG PIC X(60).
01 WS-ERR-DETAIL PIC X(80).
*> Program phase tracking
01 WS-PGM-PHASE PIC X(20).
PROCEDURE DIVISION.
*> ============================================================
*> MAIN SECTION
*> ============================================================
MAIN SECTION.
MB-PROCESS.
*> Initialize and open files
PERFORM 1000-INITIALIZE
PERFORM 2000-OPEN-FILES
*> Read first master record
PERFORM 3100-READ-MASTER
*> MAIN MATCHING LOOP (original 1:N algorithm preserved)
PERFORM UNTIL WS-MASTER-END
IF NOT WS-HAVE-MAST-Y
EXIT PERFORM
END-IF
MOVE STD-KEY OF MASTER-REC TO WS-MASTER-KEY
ADD 1 TO WS-MAST-READ-COUNT
PERFORM 4000-VALIDATE-MASTER
*> Advance master to next record (original logic)
PERFORM 3100-READ-MASTER
*> Process all detail records matching this master (original inner loop)
PERFORM UNTIL WS-DETAIL-END
IF STD-KEY OF DETAIL-REC
NOT = WS-MASTER-KEY
EXIT PERFORM
END-IF
ADD 1 TO WS-DETL-READ-COUNT
PERFORM 4100-VALIDATE-DETAIL
*> Check for duplicate CDR within batch
PERFORM 4400-CHECK-DUP-CDR
*> Write output (original logic)
MOVE MASTER-REC TO OUT-REC
WRITE OUT-REC
ADD 1 TO WS-MATCH-COUNT
PERFORM 5100-ACCUMULATE-OUTPUT
PERFORM 3200-READ-DETAIL
END-PERFORM
*> If detail key advanced past master key, master is unmatched
IF STD-KEY OF DETAIL-REC > WS-MASTER-KEY
AND NOT WS-DETAIL-END
ADD 1 TO WS-UNMATCH-MAST-COUNT
PERFORM 5300-WRITE-MAST-UNMATCH
END-IF
END-PERFORM.
*> Drain remaining detail records (original logic)
PERFORM UNTIL WS-DETAIL-END
ADD 1 TO WS-UNMATCH-DETL-COUNT
ADD 1 TO WS-DETL-READ-COUNT
PERFORM 4100-VALIDATE-DETAIL
PERFORM 5400-WRITE-DETL-UNMATCH
PERFORM 3200-READ-DETAIL
END-PERFORM
*> Close files and write audit
CLOSE FILE-MASTER
CLOSE FILE-DETAIL
CLOSE FILE-OUT
CLOSE FILE-ERR
PERFORM 7000-AUDIT-TRAIL
PERFORM 8000-FINALIZE
DISPLAY '02-matching-1-N: PASS'
STOP RUN
.
*> ============================================================
*> 1000-INITIALIZE
*> ============================================================
1000-INITIALIZE.
MOVE FUNCTION CURRENT-DATE (1:8) TO WS-PROC-DATE
MOVE FUNCTION CURRENT-DATE (9:8) TO WS-PROC-TIME
MOVE FUNCTION CURRENT-DATE (1:8) TO WS-TS-DATE
MOVE FUNCTION CURRENT-DATE (9:8) TO WS-TS-TIME
DISPLAY "============================================"
DISPLAY "02-MATCHING-1-N Contract-CDR Matching"
DISPLAY "Version V2.00"
DISPLAY "Run date: " WS-PROC-DATE " " WS-PROC-TIME
DISPLAY "============================================"
INITIALIZE WS-COUNTERS
INITIALIZE WS-HASH-TOTALS
INITIALIZE WS-VALIDATION
INITIALIZE WS-CONTRACT-VALIDITY
INITIALIZE WS-CDR-DATE-CHECK
.
*> ============================================================
*> 2000-OPEN-FILES
*> ============================================================
2000-OPEN-FILES.
MOVE '2000-OPEN-FILES' TO WS-PGM-PHASE
DISPLAY "[" WS-TS-DATE " " WS-TS-TIME
"] 02-MATCHING: Opening files..."
OPEN INPUT FILE-MASTER
IF WS-MASTER-STATUS NOT = '00'
STRING "FATAL: Cannot open master.dat, status "
WS-MASTER-STATUS
INTO WS-ERR-MSG
END-STRING
PERFORM 6000-FATAL-ERROR
END-IF
OPEN INPUT FILE-DETAIL
IF WS-DETAIL-STATUS NOT = '00'
STRING "FATAL: Cannot open detail.dat, status "
WS-DETAIL-STATUS
INTO WS-ERR-MSG
END-STRING
PERFORM 6000-FATAL-ERROR
END-IF
OPEN OUTPUT FILE-OUT
IF WS-OUT-STATUS NOT = '00'
STRING "FATAL: Cannot open output.dat, status "
WS-OUT-STATUS
INTO WS-ERR-MSG
END-STRING
PERFORM 6000-FATAL-ERROR
END-IF
OPEN OUTPUT FILE-ERR
IF WS-ERR-STATUS NOT = '00'
STRING "FATAL: Cannot open error.dat, status "
WS-ERR-STATUS
INTO WS-ERR-MSG
END-STRING
PERFORM 6000-FATAL-ERROR
END-IF
OPEN OUTPUT AUDIT-FILE
IF WS-AUDIT-STATUS NOT = '00'
DISPLAY "WARNING: Cannot open audit-report.txt, "
"status " WS-AUDIT-STATUS
ADD 1 TO WS-WARN-COUNT
END-IF
PERFORM 7010-WRITE-AUDIT-HEADER
.
*> ============================================================
*> 3100-READ-MASTER — Read next master record (original helper)
*> ============================================================
3100-READ-MASTER.
READ FILE-MASTER
AT END
MOVE 'Y' TO WS-MASTER-EOF
MOVE 'N' TO WS-HAVE-MAST
NOT AT END
MOVE 'Y' TO WS-HAVE-MAST
END-READ
.
*> ============================================================
*> 3200-READ-DETAIL — Read next detail record
*> ============================================================
3200-READ-DETAIL.
READ FILE-DETAIL
AT END MOVE 'Y' TO WS-DETAIL-EOF
END-READ
.
*> ============================================================
*> 4000-VALIDATE-MASTER — Validate master record
*> ============================================================
4000-VALIDATE-MASTER.
*> Check key format
MOVE 'N' TO WS-KEY-INVALID-FLAG
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > 10 OR WS-KEY-INVALID
MOVE STD-KEY OF MASTER-REC(WS-IDX:1) TO WS-KEY-CHAR
MOVE 'N' TO WS-CHAR-OK
IF WS-KEY-CHAR >= 'A' AND WS-KEY-CHAR <= 'Z'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF WS-KEY-CHAR >= '0' AND WS-KEY-CHAR <= '9'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF WS-KEY-CHAR = '-'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF NOT WS-CHAR-IS-OK
MOVE 'Y' TO WS-KEY-INVALID-FLAG
END-IF
END-PERFORM
IF WS-KEY-INVALID
ADD 1 TO WS-KEY-FMT-ERR-COUNT
ADD 1 TO WS-WARN-COUNT
STRING "WARN: Invalid key format in master: "
STD-KEY OF MASTER-REC
INTO WS-ERR-MSG
END-STRING
PERFORM 6100-WARNING-ERROR
END-IF
*> Accumulate input hash total
MOVE STD-DATA-3 OF MASTER-REC TO WS-MAST-AMT-NUM
ADD WS-MAST-AMT-NUM TO WS-INPUT-HASH-MAST
*> Check contract validity period
MOVE STD-DATA-2 OF MASTER-REC TO WS-CONTRACT-MONTH
MOVE WS-PROC-DATE(1:6) TO WS-CURRENT-MONTH
IF WS-CONTRACT-MONTH > WS-CURRENT-MONTH
ADD 1 TO WS-CONTRACT-EXPIRED-COUNT
ADD 1 TO WS-WARN-COUNT
STRING "WARN: Contract period invalid key="
STD-KEY OF MASTER-REC
INTO WS-ERR-MSG
END-STRING
PERFORM 6100-WARNING-ERROR
END-IF
.
*> ============================================================
*> 4100-VALIDATE-DETAIL — Validate detail (CDR) record
*> ============================================================
4100-VALIDATE-DETAIL.
*> Check key format
MOVE 'N' TO WS-KEY-INVALID-FLAG
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > 10 OR WS-KEY-INVALID
MOVE STD-KEY OF DETAIL-REC(WS-IDX:1) TO WS-KEY-CHAR
MOVE 'N' TO WS-CHAR-OK
IF WS-KEY-CHAR >= 'A' AND WS-KEY-CHAR <= 'Z'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF WS-KEY-CHAR >= '0' AND WS-KEY-CHAR <= '9'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF WS-KEY-CHAR = '-'
MOVE 'Y' TO WS-CHAR-OK
END-IF
IF NOT WS-CHAR-IS-OK
MOVE 'Y' TO WS-KEY-INVALID-FLAG
END-IF
END-PERFORM
IF WS-KEY-INVALID
ADD 1 TO WS-KEY-FMT-ERR-COUNT
ADD 1 TO WS-WARN-COUNT
STRING "WARN: Invalid key format in detail: "
STD-KEY OF DETAIL-REC
INTO WS-ERR-MSG
END-STRING
PERFORM 6100-WARNING-ERROR
END-IF
*> Accumulate input hash from CDR duration/amount
MOVE STD-DATA-3 OF DETAIL-REC TO WS-DETL-AMT-NUM
ADD WS-DETL-AMT-NUM TO WS-INPUT-HASH-DETL
*> CDR date range validation
MOVE STD-DATA-2 OF DETAIL-REC TO WS-CDR-MONTH
MOVE WS-PROC-DATE(1:6) TO WS-CURRENT-MONTH
IF WS-CDR-MONTH > WS-CURRENT-MONTH
ADD 1 TO WS-CDR-OUTSIDE-COUNT
ADD 1 TO WS-WARN-COUNT
STRING "WARN: CDR date outside range key="
STD-KEY OF DETAIL-REC
INTO WS-ERR-MSG
END-STRING
PERFORM 6100-WARNING-ERROR
END-IF
.
*> ============================================================
*> 4400-CHECK-DUP-CDR — Check for duplicate CDR within batch
*> ============================================================
4400-CHECK-DUP-CDR.
*> STD-DATA-1 contains CDR-ID in TEL-CDR mapping
MOVE STD-DATA-1 OF DETAIL-REC(1:10) TO WS-CDR-ID-SAVE
IF WS-CDR-ID-SAVE = WS-CDR-ID-PREV
ADD 1 TO WS-DUP-CDR-COUNT
ADD 1 TO WS-WARN-COUNT
STRING "WARN: Duplicate CDR detected: "
WS-CDR-ID-SAVE
INTO WS-ERR-MSG
END-STRING
PERFORM 6100-WARNING-ERROR
END-IF
MOVE WS-CDR-ID-SAVE TO WS-CDR-ID-PREV
.
*> ============================================================
*> 5100-ACCUMULATE-OUTPUT — Accumulate output hash
*> ============================================================
5100-ACCUMULATE-OUTPUT.
MOVE STD-DATA-3 OF OUT-REC TO WS-OUT-AMT-NUM
ADD WS-OUT-AMT-NUM TO WS-OUTPUT-HASH
.
*> ============================================================
*> 5300-WRITE-MAST-UNMATCH — Write unmatched master to error
*> ============================================================
5300-WRITE-MAST-UNMATCH.
MOVE 'MAST-UNMTC' TO ERR-TYPE
MOVE STD-KEY OF MASTER-REC TO ERR-KEY
MOVE STD-DATA-1 OF MASTER-REC(1:20) TO ERR-DATA
MOVE STD-DATA-3 OF MASTER-REC TO WS-MAST-AMT-NUM
MOVE WS-MAST-AMT-NUM TO ERR-AMOUNT
WRITE ERR-REC
.
*> ============================================================
*> 5400-WRITE-DETL-UNMATCH — Write unmatched detail to error
*> ============================================================
5400-WRITE-DETL-UNMATCH.
MOVE 'DETL-UNMTC' TO ERR-TYPE
MOVE STD-KEY OF DETAIL-REC TO ERR-KEY
MOVE STD-DATA-1 OF DETAIL-REC(1:20) TO ERR-DATA
MOVE STD-DATA-3 OF DETAIL-REC TO WS-DETL-AMT-NUM
MOVE WS-DETL-AMT-NUM TO ERR-AMOUNT
WRITE ERR-REC
.
*> ============================================================
*> 6000-FATAL-ERROR — Fatal error, terminates program
*> ============================================================
6000-FATAL-ERROR.
ADD 1 TO WS-FATAL-COUNT
DISPLAY "FATAL [" WS-TS-DATE " " WS-TS-TIME "] "
WS-ERR-MSG
MOVE 16 TO RETURN-CODE
STOP RUN
.
*> ============================================================
*> 6100-WARNING-ERROR — Warning handler
*> ============================================================
6100-WARNING-ERROR.
ADD 1 TO WS-WARN-COUNT
DISPLAY "WARNING [" WS-TS-DATE " " WS-TS-TIME "] "
WS-ERR-MSG
.
*> ============================================================
*> 7000-AUDIT-TRAIL — Write audit summary report
*> ============================================================
7000-AUDIT-TRAIL.
MOVE '7000-AUDIT-TRAIL' TO WS-PGM-PHASE
DISPLAY "[" WS-TS-DATE " " WS-TS-TIME
"] 02-MATCHING: Writing audit report..."
PERFORM 7020-WRITE-AUDIT-SUMMARY
PERFORM 7030-WRITE-HASH-DETAIL
PERFORM 7040-WRITE-ERROR-SUMMARY
PERFORM 7060-WRITE-AUDIT-FOOTER
CLOSE AUDIT-FILE
.
*> ============================================================
*> 7010-WRITE-AUDIT-HEADER
*> ============================================================
7010-WRITE-AUDIT-HEADER.
MOVE SPACES TO AUDIT-REC
STRING "================================================"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "02-MATCHING-1-N AUDIT REPORT"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "Program Version: V2.00"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "Run Date: " WS-PROC-DATE " Time: " WS-PROC-TIME
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "================================================"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
.
*> ============================================================
*> 7020-WRITE-AUDIT-SUMMARY
*> ============================================================
7020-WRITE-AUDIT-SUMMARY.
MOVE SPACES TO AUDIT-REC
STRING "RECORD COUNT SUMMARY:"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Master (contract) records : " WS-MAST-READ-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Detail (CDR) records : " WS-DETL-READ-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Matched (output) records : " WS-MATCH-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Unmatched contracts : "
WS-UNMATCH-MAST-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Unmatched CDRs : "
WS-UNMATCH-DETL-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Duplicate CDRs detected : " WS-DUP-CDR-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Avg CDRs per contract : N/A (no division)"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
.
*> ============================================================
*> 7030-WRITE-HASH-DETAIL
*> ============================================================
7030-WRITE-HASH-DETAIL.
MOVE SPACES TO AUDIT-REC
STRING " "
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "HASH TOTAL RECONCILIATION:"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Input hash (contract) : " WS-INPUT-HASH-MAST
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Output hash : " WS-OUTPUT-HASH
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Error hash : " WS-ERROR-HASH
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
ADD WS-OUTPUT-HASH TO WS-ERROR-HASH
GIVING WS-HASH-DIFF
SUBTRACT WS-INPUT-HASH-MAST FROM WS-HASH-DIFF
IF WS-HASH-DIFF NOT = 0
MOVE SPACES TO AUDIT-REC
STRING " ** HASH MISMATCH ** Diff: " WS-HASH-DIFF
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
ELSE
MOVE SPACES TO AUDIT-REC
STRING " Hash total: VERIFIED"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
END-IF
.
*> ============================================================
*> 7040-WRITE-ERROR-SUMMARY
*> ============================================================
7040-WRITE-ERROR-SUMMARY.
MOVE SPACES TO AUDIT-REC
STRING " "
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "ERROR SUMMARY:"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Key format errors : " WS-KEY-FMT-ERR-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Duplicate CDRs : " WS-DUP-CDR-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Expired contracts : "
WS-CONTRACT-EXPIRED-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " CDR date outside rng : "
WS-CDR-OUTSIDE-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Warnings : " WS-WARN-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING " Fatal errors : " WS-FATAL-COUNT
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
.
*> ============================================================
*> 7060-WRITE-AUDIT-FOOTER
*> ============================================================
7060-WRITE-AUDIT-FOOTER.
MOVE SPACES TO AUDIT-REC
STRING " "
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "================================================"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "END OF AUDIT REPORT"
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
MOVE SPACES TO AUDIT-REC
STRING "Generated: " WS-PROC-DATE " " WS-PROC-TIME
INTO AUDIT-REC
END-STRING
WRITE AUDIT-REC
.
*> ============================================================
*> 8000-FINALIZE — Display final summary
*> ============================================================
8000-FINALIZE.
MOVE '8000-FINALIZE' TO WS-PGM-PHASE
DISPLAY "============================================"
DISPLAY "02-MATCHING-1-N Processing Summary"
DISPLAY "============================================"
DISPLAY "Contract records read : " WS-MAST-READ-COUNT
DISPLAY "CDR records read : " WS-DETL-READ-COUNT
DISPLAY "Matched records : " WS-MATCH-COUNT
DISPLAY "Unmatched contracts : " WS-UNMATCH-MAST-COUNT
DISPLAY "Unmatched CDRs : " WS-UNMATCH-DETL-COUNT
DISPLAY "Duplicate CDRs : " WS-DUP-CDR-COUNT
DISPLAY "Expired contracts : "
WS-CONTRACT-EXPIRED-COUNT
DISPLAY "--------------------------------------------"
DISPLAY "Key format errors : " WS-KEY-FMT-ERR-COUNT
DISPLAY "Warnings : " WS-WARN-COUNT
DISPLAY "Fatal errors : " WS-FATAL-COUNT
DISPLAY "============================================"
ADD WS-OUTPUT-HASH TO WS-ERROR-HASH
GIVING WS-HASH-DIFF
SUBTRACT WS-INPUT-HASH-MAST FROM WS-HASH-DIFF
IF WS-HASH-DIFF NOT = 0
DISPLAY "WARNING: Hash total mismatch! Diff="
WS-HASH-DIFF
ELSE
DISPLAY "Hash totals: VERIFIED"
END-IF
DISPLAY "Audit report written to audit-report.txt"
DISPLAY "============================================"
.
END PROGRAM Main02Matching1N.
@@ -0,0 +1,155 @@
*> ============================================================
*> main-matching-1-N : 合同↔通话明细匹配 (Contract↔CDR 1:N)
*> Input : FILE-MAST (MASTER.DAT: 合同), FILE-DETL (DETAIL.DAT: CDR)
*> Output: FILE-OUT (OUTPUT.DAT: 一致), FILE-ERR (ERROR.DAT: 不一致)
*> Coverage: MT-N002, MT-N004, MT-N005, MT-R001
*> ============================================================
IDENTIFICATION DIVISION.
PROGRAM-ID. MATCHING-1N.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-MAST ASSIGN TO "MASTER.DAT"
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-FS1.
SELECT FILE-DETL ASSIGN TO "DETAIL.DAT"
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-FS2.
SELECT FILE-OUT ASSIGN TO "OUTPUT.DAT"
ORGANIZATION IS SEQUENTIAL.
SELECT FILE-ERR ASSIGN TO "ERROR.DAT"
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD FILE-MAST RECORD CONTAINS 40 CHARACTERS.
01 MAST-REC.
05 M-KEY PIC X(10).
05 M-NAME PIC X(20).
05 M-AMOUNT PIC 9(10).
FD FILE-DETL RECORD CONTAINS 40 CHARACTERS.
01 DETL-REC.
05 D-KEY PIC X(10).
05 D-NAME PIC X(20).
05 D-AMOUNT PIC 9(10).
FD FILE-OUT RECORD CONTAINS 60 CHARACTERS.
01 OUT-REC.
05 O-M-KEY PIC X(10).
05 O-M-NAME PIC X(20).
05 O-D-NAME PIC X(20).
05 O-AMOUNT PIC 9(10).
FD FILE-ERR RECORD CONTAINS 40 CHARACTERS.
01 ERR-REC PIC X(40).
WORKING-STORAGE SECTION.
01 WS-FS1 PIC X(2).
01 WS-FS2 PIC X(2).
01 WS-EOF1 PIC X(1) VALUE 'N'.
88 WS-EOF1-Y VALUE 'Y' FALSE 'N'.
01 WS-EOF2 PIC X(1) VALUE 'N'.
88 WS-EOF2-Y VALUE 'Y' FALSE 'N'.
01 WS-MAST-COUNT PIC 9(10).
01 WS-DETL-COUNT PIC 9(10).
01 WS-MATCH-COUNT PIC 9(10).
01 WS-MAST-REMAIN PIC 9(10).
01 WS-DETL-REMAIN PIC 9(10).
01 WS-MAST-KEY PIC X(10).
01 WS-MAST-NAME PIC X(20).
01 WS-MAST-AMT PIC 9(10).
01 WS-HAVE-MAST PIC X(1) VALUE 'N'.
88 WS-HAVE-MAST-Y VALUE 'Y' FALSE 'N'.
PROCEDURE DIVISION.
MAIN.
DISPLAY "MATCHING-1N: Starting 1:N matching"
OPEN INPUT FILE-MAST FILE-DETL.
OPEN OUTPUT FILE-OUT FILE-ERR.
IF WS-FS1 NOT = "00" OR WS-FS2 NOT = "00"
DISPLAY "OPEN FAIL: MAST=" WS-FS1 " DETL=" WS-FS2
STOP RUN RETURNING 1
END-IF.
PERFORM READ-MASTER.
PERFORM UNTIL WS-EOF1-Y
IF NOT WS-HAVE-MAST-Y
EXIT PERFORM
END-IF
MOVE M-KEY TO WS-MAST-KEY
MOVE M-NAME TO WS-MAST-NAME
MOVE M-AMOUNT TO WS-MAST-AMT
ADD 1 TO WS-MAST-COUNT
PERFORM READ-MASTER
PERFORM UNTIL WS-EOF2-Y
IF D-KEY NOT = WS-MAST-KEY
EXIT PERFORM
END-IF
MOVE WS-MAST-KEY TO O-M-KEY
MOVE WS-MAST-NAME TO O-M-NAME
MOVE D-NAME TO O-D-NAME
MOVE D-AMOUNT TO O-AMOUNT
WRITE OUT-REC
ADD 1 TO WS-MATCH-COUNT
ADD 1 TO WS-DETL-COUNT
READ FILE-DETL INTO DETL-REC
AT END SET WS-EOF2-Y TO TRUE
END-READ
END-PERFORM
IF D-KEY > WS-MAST-KEY AND NOT WS-EOF2-Y
ADD 1 TO WS-MAST-REMAIN
STRING "MAST-REMAIN " WS-MAST-KEY
DELIMITED BY SIZE INTO ERR-REC
END-STRING
WRITE ERR-REC
END-IF
END-PERFORM.
PERFORM UNTIL WS-EOF2-Y
ADD 1 TO WS-DETL-REMAIN WS-DETL-COUNT
STRING "DETL-REMAIN " D-KEY
DELIMITED BY SIZE INTO ERR-REC
END-STRING
WRITE ERR-REC
READ FILE-DETL INTO DETL-REC
AT END SET WS-EOF2-Y TO TRUE
END-READ
END-PERFORM.
CLOSE FILE-MAST FILE-DETL FILE-OUT FILE-ERR.
DISPLAY "MATCH-1N: MASTER=" WS-MAST-COUNT
" DETL=" WS-DETL-COUNT
DISPLAY "MATCH-1N: MATCHED=" WS-MATCH-COUNT
" M-REMAIN=" WS-MAST-REMAIN
" D-REMAIN=" WS-DETL-REMAIN
IF WS-MATCH-COUNT > 0
DISPLAY "MATCHING-1N: PASS"
STOP RUN RETURNING 0
ELSE
DISPLAY "MATCHING-1N: FAIL"
STOP RUN RETURNING 1
END-IF
.
READ-MASTER.
READ FILE-MAST INTO MAST-REC
AT END
SET WS-EOF1-Y TO TRUE
MOVE 'N' TO WS-HAVE-MAST
NOT AT END
SET WS-HAVE-MAST TO TRUE
END-READ
.
END PROGRAM MATCHING-1N.
@@ -0,0 +1 @@
0000000000000000000