Files
cobol-java-v3/benchmark-programs/34-sort/main-34-sort.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

1445 lines
56 KiB
COBOL

IDENTIFICATION DIVISION.
PROGRAM-ID. Main34Sort.
*> ============================================================
*> 34-sort : CDR排序 (CDR Sorting before Billing)
*> Input : sort-input.dat (未排序CDR明细)
*> Output: sort-output.dat (按客户/时间排序CDR)
*> Summary: sort-summary.txt (排序结果汇总)
*> Stats : sort-stats.txt (排序统计)
*> Audit : sort-audit.txt (审计跟踪)
*> Report : sort-report.txt (多层断点汇总报告)
*> Coverage: SR-N001~N015
*> ============================================================
*> CDR SORT processing program for telecom billing
*> Tests: USING/GIVING, INPUT/OUTPUT PROCEDURE,
*> multi-key sort, stable sort, 0/1 record sort,
*> enhanced validation, multi-level keybreak,
*> audit trail, hash totals, FILE STATUS checks
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INPUT-FILE ASSIGN TO "sort-input.dat"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-INPUT.
SELECT OUTPUT-FILE ASSIGN TO "sort-output.dat"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-OUTPUT.
SELECT WORK-FILE ASSIGN TO "sort-work.tmp"
FILE STATUS IS FS-WORK.
SELECT SUMMARY-FILE ASSIGN TO "sort-summary.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-SUMMARY.
SELECT SORT-STATS-FILE ASSIGN TO "sort-stats.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-STATS.
SELECT AUDIT-FILE ASSIGN TO "sort-audit.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-AUDIT.
SELECT REPORT-FILE ASSIGN TO "sort-report.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS FS-REPORT.
SELECT WORK-FILE2 ASSIGN TO "sort-work2.tmp"
FILE STATUS IS FS-WORK2.
DATA DIVISION.
FILE SECTION.
FD INPUT-FILE.
01 INPUT-REC.
05 IN-KEY PIC X(10).
05 IN-DATA PIC X(20).
05 IN-VALUE PIC 9(05).
FD OUTPUT-FILE.
01 OUTPUT-REC.
05 OUT-KEY PIC X(10).
05 OUT-DATA PIC X(20).
05 OUT-VALUE PIC 9(05).
SD WORK-FILE.
01 WORK-REC.
05 WR-KEY PIC X(10).
05 WR-DATA PIC X(20).
05 WR-VALUE PIC 9(05).
SD WORK-FILE2.
01 WORK2-REC.
05 W2R-KEY PIC X(10).
05 W2R-CUSTOMER PIC X(11).
05 W2R-PLAN PIC X(05).
05 W2R-CALL-TYPE PIC X(02).
05 W2R-DATE PIC 9(08).
05 W2R-DURATION PIC 9(09).
FD SUMMARY-FILE.
01 SUMMARY-REC PIC X(80).
FD SORT-STATS-FILE.
01 STATS-REC PIC X(80).
FD AUDIT-FILE.
01 AUDIT-REC PIC X(80).
FD REPORT-FILE.
01 REPORT-REC PIC X(80).
WORKING-STORAGE SECTION.
01 WS-CDR-REF.
COPY "telecom/TEL-CDR.cpy".
*> FILE STATUS fields
01 FS-INPUT PIC X(02).
88 FS-INPUT-OK VALUE "00".
88 FS-INPUT-EOF VALUE "10".
01 FS-OUTPUT PIC X(02).
88 FS-OUTPUT-OK VALUE "00".
01 FS-WORK PIC X(02).
01 FS-SUMMARY PIC X(02).
88 FS-SUMMARY-OK VALUE "00".
01 FS-STATS PIC X(02).
88 FS-STATS-OK VALUE "00".
01 FS-AUDIT PIC X(02).
88 FS-AUDIT-OK VALUE "00".
01 FS-REPORT PIC X(02).
88 FS-REPORT-OK VALUE "00".
01 FS-WORK2 PIC X(02).
*> Original WS fields (preserved for existing tests)
01 WS-EOF PIC X(01) VALUE "N".
88 WS-EOF-Y VALUE "Y".
01 WS-RECORD-COUNT PIC 9(02) VALUE 0.
01 WS-TOTAL-VALUE PIC 9(07) VALUE 0.
01 WS-GROUP-COUNT PIC 9(02) VALUE 0.
01 WS-GROUP-VALUE PIC 9(07) VALUE 0.
01 WS-PREV-KEY PIC X(10).
01 WS-HEADER-LINE.
05 FILLER PIC X(10) VALUE "KEY ".
05 FILLER PIC X(22) VALUE "DATA ".
05 FILLER PIC X(10) VALUE "VALUE ".
01 WS-DETAIL-LINE.
05 DL-KEY PIC X(10).
05 FILLER PIC X(02) VALUE SPACES.
05 DL-DATA PIC X(20).
05 FILLER PIC X(02) VALUE SPACES.
05 DL-VALUE PIC Z(9)9.
01 WS-SUMMARY-LINE.
05 FILLER PIC X(20) VALUE "Group key: ".
05 SL-KEY PIC X(10).
05 FILLER PIC X(10) VALUE " Count: ".
05 SL-COUNT PIC Z(9).
05 FILLER PIC X(10) VALUE " Total: ".
05 SL-TOTAL PIC Z(9)9.
*> CDR test data (phone numbers + call durations)
01 TEST-DATA-AREA.
05 TEST-DATA OCCURS 9 TIMES.
10 TD-KEY PIC X(10).
10 TD-DATA PIC X(20).
10 TD-VALUE PIC 9(05).
01 TEST-DATA-VALUES.
05 FILLER PIC X(35) VALUE
"CDRB00000113800138001 00100".
05 FILLER PIC X(35) VALUE
"CDRA00000113900139001 00500".
05 FILLER PIC X(35) VALUE
"CDRC00000113700137001 00200".
05 FILLER PIC X(35) VALUE
"CDRA00000213600136001 00300".
05 FILLER PIC X(35) VALUE
"CDRB00000213500135001 00400".
05 FILLER PIC X(35) VALUE
"CDRA00000313400134001 00150".
05 FILLER PIC X(35) VALUE
"CDRC00000213300133001 00250".
05 FILLER PIC X(35) VALUE
"CDRB00000313200132001 00350".
05 FILLER PIC X(35) VALUE
"CDRA00000413100131001 00200".
01 TEST-DATA-REDEF REDEFINES TEST-DATA-VALUES.
05 TEST-DATA-ENTRY OCCURS 9 TIMES.
10 TDE-KEY PIC X(10).
10 TDE-DATA PIC X(20).
10 TDE-VALUE PIC 9(05).
01 IDX PIC 9(02).
*> ============================================================
*> New WS fields for enhanced telecom billing processing
*> ============================================================
*> Current timestamp from FUNCTION CURRENT-DATE (21 chars)
01 WS-CURRENT-DATE-TIME.
05 WS-CDT-DATE PIC 9(08).
05 WS-CDT-TIME PIC 9(06).
05 WS-CDT-MS PIC 9(02).
05 WS-CDT-OFFSET PIC 9(04).
05 WS-CDT-SIGN PIC X(01).
*> Batch control totals
01 WS-BATCH-CTL.
05 WS-BCT-INPUT-COUNT PIC 9(09) VALUE 0.
05 WS-BCT-SORTED-COUNT PIC 9(09) VALUE 0.
05 WS-BCT-FILTERED-COUNT PIC 9(09) VALUE 0.
05 WS-BCT-DUP-COUNT PIC 9(09) VALUE 0.
05 WS-BCT-INVALID-COUNT PIC 9(09) VALUE 0.
05 WS-BCT-HASH-TOTAL PIC 9(15) VALUE 0.
*> Sort statistics
01 WS-SORT-STATS.
05 WS-SS-INPUT-COUNT PIC 9(09) VALUE 0.
05 WS-SS-OUTPUT-COUNT PIC 9(09) VALUE 0.
05 WS-SS-FILTERED PIC 9(09) VALUE 0.
05 WS-SS-DUPLICATE-COUNT PIC 9(09) VALUE 0.
05 WS-SS-TOTAL-DURATION PIC 9(15) VALUE 0.
*> Audit message buffer
01 WS-AUDIT-MESSAGE PIC X(55).
*> Audit entry
01 WS-AUDIT-LINE.
05 FILLER PIC X(01) VALUE SPACE.
05 WS-AL-DATE PIC 9(08).
05 FILLER PIC X(01) VALUE SPACE.
05 WS-AL-TIME PIC 9(06).
05 FILLER PIC X(01) VALUE SPACE.
05 WS-AL-SEVERITY PIC X(01).
05 FILLER PIC X(02) VALUE SPACE.
05 WS-AL-MESSAGE PIC X(55).
01 WS-ERROR-SEVERITY PIC X(01).
88 WS-ERR-INFO VALUE "I".
88 WS-ERR-WARN VALUE "W".
88 WS-ERR-ERROR VALUE "E".
88 WS-ERR-FATAL VALUE "F".
*> Multi-level keybreak fields
01 WS-BREAK-CUSTOMER.
05 WS-BR-CUSTOMER PIC X(11).
05 WS-BR-CUST-COUNT PIC 9(09) VALUE 0.
05 WS-BR-CUST-DUR PIC 9(09) VALUE 0.
01 WS-BREAK-PLAN.
05 WS-BR-PLAN PIC X(05).
05 WS-BR-PLAN-COUNT PIC 9(09) VALUE 0.
05 WS-BR-PLAN-DUR PIC 9(09) VALUE 0.
01 WS-BREAK-CALL-TYPE.
05 WS-BR-CALL-TYPE PIC X(02).
05 WS-BR-CT-COUNT PIC 9(09) VALUE 0.
05 WS-BR-CT-DUR PIC 9(09) VALUE 0.
01 WS-PREV-W2R-KEY PIC X(10).
01 WS-PREV-CUSTOMER PIC X(11).
01 WS-PREV-PLAN PIC X(05).
01 WS-PREV-CALLTYPE PIC X(02).
01 WS-PREV-DATE PIC 9(08).
*> Enriched CDR field buffers
01 WS-ECDR-ID PIC X(10).
01 WS-ECDR-CUSTOMER PIC X(11).
01 WS-ECDR-PLAN PIC X(05).
01 WS-ECDR-CALL-TYPE PIC X(02).
01 WS-ECDR-DATE PIC 9(08).
01 WS-ECDR-DURATION PIC 9(09).
*> Enriched detail line for display
01 WS-ENH-DETAIL-LINE.
05 FILLER PIC X(02) VALUE SPACE.
05 EDL-ID PIC X(10).
05 FILLER PIC X(01) VALUE SPACE.
05 EDL-CUSTOMER PIC X(11).
05 FILLER PIC X(01) VALUE SPACE.
05 EDL-PLAN PIC X(05).
05 FILLER PIC X(01) VALUE SPACE.
05 EDL-CALL-TYPE PIC X(02).
05 FILLER PIC X(01) VALUE SPACE.
05 EDL-DATE PIC 9(08).
05 FILLER PIC X(01) VALUE SPACE.
05 EDL-DURATION PIC Z(9)9.
*> Report line templates
01 WS-RPT-HEADER1.
05 FILLER PIC X(30) VALUE
"TELECOM SORT REPORT - RUN AT ".
05 RPT1-DATE PIC 9(08).
05 FILLER PIC X(01) VALUE SPACE.
05 RPT1-TIME PIC 9(06).
01 WS-RPT-HEADER2.
05 FILLER PIC X(80) VALUE ALL "=".
01 WS-RPT-KEYBREAK-CUST.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(18) VALUE "CUSTOMER: ".
05 RPT-CUST-ID PIC X(11).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(08) VALUE "COUNT: ".
05 RPT-CUST-COUNT PIC Z(9)9.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(10) VALUE "DURATION: ".
05 RPT-CUST-DUR PIC Z(9)9.
01 WS-RPT-KEYBREAK-PLAN.
05 FILLER PIC X(08) VALUE SPACES.
05 FILLER PIC X(15) VALUE " PLAN: ".
05 RPT-PLAN-ID PIC X(05).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(08) VALUE "COUNT: ".
05 RPT-PLAN-COUNT PIC Z(9)9.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(10) VALUE "DURATION: ".
05 RPT-PLAN-DUR PIC Z(9)9.
01 WS-RPT-KEYBREAK-CT.
05 FILLER PIC X(12) VALUE SPACES.
05 FILLER PIC X(13) VALUE "CALL TYPE: ".
05 RPT-CALL-TYPE PIC X(02).
05 FILLER PIC X(03) VALUE SPACES.
05 RPT-CALL-TYPE-NAME PIC X(15).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(08) VALUE "COUNT: ".
05 RPT-CT-COUNT PIC Z(9)9.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(10) VALUE "DURATION: ".
05 RPT-CT-DUR PIC Z(9)9.
01 WS-RPT-GRAND-TOTAL.
05 FILLER PIC X(25) VALUE
"GRAND TOTAL RECORDS: ".
05 RPT-GRAND-COUNT PIC Z(9)9.
05 FILLER PIC X(10) VALUE SPACES.
05 FILLER PIC X(15) VALUE "TOTAL DURATION: ".
05 RPT-GRAND-DUR PIC Z(9)9.
*> Enhanced CDR test data (telecom format)
*> Layout: 10-id + 11-customer + 11-callee + 5-plan + 2-type + 8-date + 9-dur = 56
*> We align to WORK2-REC fields: key(10)+cust(11)+plan(5)+type(2)+date(8)+dur(9) = 45
*> Store as concatenated 45-char strings
01 ENH-TEST-VALUES.
05 FILLER PIC X(45) VALUE
"CDR1000001186139000138001PSTDMO20260601000060000".
05 FILLER PIC X(45) VALUE
"CDR1000002186139000138001PSTDMO20260601000120000".
05 FILLER PIC X(45) VALUE
"CDR1000003186139000138001PRMMO20260602000300000".
05 FILLER PIC X(45) VALUE
"CDR1000004186138000139001PRMMO20260601000050000".
05 FILLER PIC X(45) VALUE
"CDR1000005186138000139001ECOMO20260601000100000".
05 FILLER PIC X(45) VALUE
"CDR1000006186138000139001PSTDMO20260603000350000".
05 FILLER PIC X(45) VALUE
"CDR1000007186140000138001PSTDMO20260601000450000".
05 FILLER PIC X(45) VALUE
"CDR1000008186139000139001PRMMO20260603000200000".
05 FILLER PIC X(45) VALUE
"CDR2000001186141000138001ECOMO20260601001500000".
05 FILLER PIC X(45) VALUE
"CDR2000002186141000138001ECOMO20260602002500000".
01 ENH-TEST-REDEF REDEFINES ENH-TEST-VALUES.
05 ENH-TEST-ENTRY OCCURS 10 TIMES.
10 ETE-ID PIC X(10).
10 ETE-CUSTOMER PIC X(11).
10 ETE-PLAN PIC X(05).
10 ETE-CALL-TYPE PIC X(02).
10 ETE-DATE PIC 9(08).
10 ETE-DURATION PIC 9(09).
01 ENH-IDX PIC 9(02).
*> Hash total work fields
01 WS-HASH-TOTAL PIC 9(15) VALUE 0.
01 WS-DURATION-HASH PIC 9(15) VALUE 0.
01 WS-DURATION-CHECK PIC 9(15) VALUE 0.
*> Duplicate test data
01 DUP-VALUES.
05 FILLER PIC X(45) VALUE
"CDR-DUP00113800138001PSTDMO20260601000100000".
05 FILLER PIC X(45) VALUE
"CDR-DUP00213800138001PSTDMO20260602000200000".
05 FILLER PIC X(45) VALUE
"CDR-DUP00313800138001PSTDMO20260601000100000".
05 FILLER PIC X(45) VALUE
"CDR-DUP00413900139001PRMMT20260601000300000".
05 FILLER PIC X(45) VALUE
"CDR-DUP00513900139001PRMMT20260601000300000".
01 DUP-REDEF REDEFINES DUP-VALUES.
05 DUP-ENTRY OCCURS 5 TIMES.
10 DE-ID PIC X(10).
10 DE-CUSTOMER PIC X(11).
10 DE-PLAN PIC X(05).
10 DE-CALL-TYPE PIC X(02).
10 DE-DATE PIC 9(08).
10 DE-DURATION PIC 9(09).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
*> ========================================
*> Test SR-N001: Basic ascending sort
*> ========================================
PERFORM INIT-INPUT-FILE.
DISPLAY "=== SR-N001: Ascending SORT USING/GIVING ===".
SORT WORK-FILE ON ASCENDING KEY WR-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> ========================================
*> Test SR-N002: Descending sort
*> ========================================
PERFORM INIT-INPUT-FILE.
DISPLAY "=== SR-N002: Descending SORT ===".
SORT WORK-FILE ON DESCENDING KEY WR-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> ========================================
*> Test SR-N003: Multi-key sort (KEY1 ASC, KEY2 DESC)
*> ========================================
PERFORM INIT-INPUT-FILE.
DISPLAY "=== SR-N003: Multi-key ASC + DESC ===".
SORT WORK-FILE ON ASCENDING KEY WR-KEY
DESCENDING KEY WR-VALUE
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> ========================================
*> Test SR-N004: INPUT PROCEDURE (filter)
*> ========================================
PERFORM INIT-INPUT-FILE.
DISPLAY "=== SR-N004: INPUT PROCEDURE (filter) ===".
SORT WORK-FILE ON ASCENDING KEY WR-KEY
INPUT PROCEDURE IS FILTER-INPUT
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> ========================================
*> Test SR-N005: OUTPUT PROCEDURE (summary)
*> ========================================
PERFORM INIT-INPUT-FILE.
DISPLAY "=== SR-N005: OUTPUT PROCEDURE (summary) ===".
SORT WORK-FILE ON ASCENDING KEY WR-KEY
USING INPUT-FILE
OUTPUT PROCEDURE IS SUMMARIZE-OUTPUT.
PERFORM DISPLAY-OUTPUT.
CLOSE SUMMARY-FILE.
DISPLAY "Summary written to sort-summary.txt".
*> ========================================
*> Test SR-N006: 0 record sort
*> ========================================
DISPLAY "=== SR-N006: Empty file sort ===".
OPEN OUTPUT INPUT-FILE.
CLOSE INPUT-FILE.
SORT WORK-FILE ON ASCENDING KEY WR-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE.
DISPLAY " 0 record sort completed".
PERFORM INIT-INPUT-FILE.
*> ========================================
*> Test SR-N007: 1 record sort
*> ========================================
DISPLAY "=== SR-N007: Single record sort ===".
OPEN OUTPUT INPUT-FILE.
MOVE "CDR-S00001" TO IN-KEY.
MOVE "SINGLE-CDR-RECORD " TO IN-DATA.
MOVE 00100 TO IN-VALUE.
WRITE INPUT-REC.
CLOSE INPUT-FILE.
SORT WORK-FILE ON ASCENDING KEY WR-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> Restore full input
PERFORM INIT-INPUT-FILE.
*> ========================================
*> Test SR-N008: INPUT/OUTPUT PROCEDURE with editing
*> ========================================
DISPLAY "=== SR-N008: INPUT/OUTPUT PROCEDURE edit ===".
SORT WORK-FILE ON ASCENDING KEY WR-KEY
INPUT PROCEDURE IS EDIT-INPUT
OUTPUT PROCEDURE IS SUMMARIZE-OUTPUT.
PERFORM DISPLAY-OUTPUT.
*> ========================================
*> Test SR-N009: Duplicate key sort (stable)
*> ========================================
DISPLAY "=== SR-N009: Duplicate key sort ===".
OPEN OUTPUT INPUT-FILE.
MOVE "CDR-DUP001" TO IN-KEY.
MOVE "DUP-CDR-FIRST-001 " TO IN-DATA.
MOVE 00100 TO IN-VALUE.
WRITE INPUT-REC.
MOVE "CDR-DUP001" TO IN-KEY.
MOVE "DUP-CDR-SECOND-002 " TO IN-DATA.
MOVE 00200 TO IN-VALUE.
WRITE INPUT-REC.
MOVE "CDR-DUP001" TO IN-KEY.
MOVE "DUP-CDR-THIRD-003 " TO IN-DATA.
MOVE 00300 TO IN-VALUE.
WRITE INPUT-REC.
CLOSE INPUT-FILE.
SORT WORK-FILE ON ASCENDING KEY WR-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
PERFORM INIT-INPUT-FILE.
*> ========================================
*> Test SR-N010: Descending multi-key
*> ========================================
DISPLAY "=== SR-N010: Descending multi-key ===".
SORT WORK-FILE ON DESCENDING KEY WR-KEY
ASCENDING KEY WR-VALUE
USING INPUT-FILE
GIVING OUTPUT-FILE.
PERFORM DISPLAY-OUTPUT.
*> ================================================================
*> SR-N011: Multi-key sort with 3+ keys (customer, date, duration)
*> Using WORK-FILE2 with INPUT PROCEDURE for data generation
*> ================================================================
DISPLAY "=== SR-N011: Enhanced multi-key sort (3 keys) ===".
PERFORM 1000-INIT.
SORT WORK-FILE2 ON ASCENDING KEY W2R-CUSTOMER
ASCENDING KEY W2R-DATE
DESCENDING KEY W2R-DURATION
INPUT PROCEDURE IS BUILD-ENH-RECORDS
OUTPUT PROCEDURE IS DISPLAY-ENH-OUTPUT.
PERFORM 5000-AUDIT.
DISPLAY " SR-N011: Enhanced multi-key sort complete".
*> ================================================================
*> SR-N012: INPUT PROCEDURE with CDR validation, filtering,
*> field enrichment
*> ================================================================
DISPLAY "=== SR-N012: Enhanced INPUT PROCEDURE ===".
PERFORM 1000-INIT.
PERFORM INIT-INPUT-FILE-FROM-ENH.
SORT WORK-FILE2 ON ASCENDING KEY W2R-CUSTOMER
ASCENDING KEY W2R-DATE
DESCENDING KEY W2R-DURATION
INPUT PROCEDURE IS 3100-VALIDATE
OUTPUT PROCEDURE IS DISPLAY-ENH-OUTPUT.
DISPLAY " SR-N012: Enhanced INPUT PROCEDURE complete".
*> ================================================================
*> SR-N013: Enhanced OUTPUT PROCEDURE with multi-level keybreak
*> (customer, plan, call type) + report
*> ================================================================
DISPLAY "=== SR-N013: Enhanced keybreak report ===".
PERFORM 1000-INIT.
PERFORM INIT-INPUT-FILE-FROM-ENH.
SORT WORK-FILE2 ON ASCENDING KEY W2R-CUSTOMER
ASCENDING KEY W2R-PLAN
ASCENDING KEY W2R-CALL-TYPE
ASCENDING KEY W2R-DATE
INPUT PROCEDURE IS 3200-CALCULATE
OUTPUT PROCEDURE IS 4000-REPORT.
MOVE "SR-N013: Multi-level keybreak report generated"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
DISPLAY " SR-N013: Keybreak report complete".
*> ================================================================
*> SR-N014: Duplicate key handling with statistics
*> ================================================================
DISPLAY "=== SR-N014: Duplicate key with statistics ===".
PERFORM 1000-INIT.
PERFORM INIT-DUP-ENH-FILE.
SORT WORK-FILE2 ON ASCENDING KEY W2R-CUSTOMER
ASCENDING KEY W2R-DATE
INPUT PROCEDURE IS 3100-VALIDATE
OUTPUT PROCEDURE IS 4000-REPORT.
PERFORM WRITE-STATS.
MOVE "SR-N014: Duplicate keys detected and counted"
TO WS-AUDIT-MESSAGE.
MOVE "W" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
DISPLAY " SR-N014: Duplicate key handling complete".
*> ================================================================
*> SR-N015: Full pipeline with audit trail and hash totals
*> ================================================================
DISPLAY "=== SR-N015: Full pipeline with audit trail ===".
PERFORM 1000-INIT.
PERFORM INIT-INPUT-FILE-FROM-ENH.
SORT WORK-FILE2 ON ASCENDING KEY W2R-CUSTOMER
ASCENDING KEY W2R-DATE
DESCENDING KEY W2R-DURATION
INPUT PROCEDURE IS 3100-VALIDATE
OUTPUT PROCEDURE IS 4000-REPORT.
PERFORM WRITE-STATS.
PERFORM WRITE-HASH-TOTAL.
CLOSE SORT-STATS-FILE.
CLOSE AUDIT-FILE.
CLOSE REPORT-FILE.
MOVE "SR-N015: Full pipeline completed with audit"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
MOVE "SR-N015: Hash total verified OK"
TO WS-AUDIT-MESSAGE.
PERFORM 5000-AUDIT.
DISPLAY "=== ALL SR-N001 through SR-N015 tests complete ===".
STOP RUN.
*> ================================================================
*> Existing paragraphs (preserved exactly from original)
*> ================================================================
INIT-INPUT-FILE.
OPEN OUTPUT INPUT-FILE.
PERFORM VARYING IDX FROM 1 BY 1 UNTIL IDX > 9
MOVE TDE-KEY(IDX) TO IN-KEY
MOVE TDE-DATA(IDX) TO IN-DATA
MOVE TDE-VALUE(IDX) TO IN-VALUE
WRITE INPUT-REC
END-PERFORM.
CLOSE INPUT-FILE.
DISPLAY-OUTPUT.
OPEN INPUT OUTPUT-FILE.
MOVE 0 TO WS-RECORD-COUNT.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ OUTPUT-FILE INTO OUTPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
ADD 1 TO WS-RECORD-COUNT
MOVE OUT-KEY TO DL-KEY
MOVE OUT-DATA TO DL-DATA
MOVE OUT-VALUE TO DL-VALUE
DISPLAY " " WS-DETAIL-LINE
END-READ
END-PERFORM.
DISPLAY " Total records: " WS-RECORD-COUNT.
CLOSE OUTPUT-FILE.
FILTER-INPUT SECTION.
*> Only pass records where VALUE > 200
OPEN INPUT INPUT-FILE.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ INPUT-FILE INTO INPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
IF IN-VALUE > 200
MOVE INPUT-REC TO WORK-REC
RELEASE WORK-REC
END-IF
END-READ
END-PERFORM.
CLOSE INPUT-FILE.
SUMMARIZE-OUTPUT SECTION.
*> Key break summary
OPEN OUTPUT OUTPUT-FILE.
OPEN OUTPUT SUMMARY-FILE.
MOVE "N" TO WS-EOF.
MOVE 0 TO WS-TOTAL-VALUE.
MOVE SPACES TO WS-PREV-KEY.
PERFORM UNTIL WS-EOF-Y
RETURN WORK-FILE INTO WORK-REC
AT END
MOVE "Y" TO WS-EOF
PERFORM WRITE-SUMMARY-LINE
NOT AT END
IF WR-KEY NOT = WS-PREV-KEY
IF WS-PREV-KEY NOT = SPACES
PERFORM WRITE-SUMMARY-LINE
END-IF
MOVE WR-KEY TO WS-PREV-KEY
MOVE 0 TO WS-GROUP-COUNT
MOVE 0 TO WS-GROUP-VALUE
END-IF
MOVE WORK-REC TO OUTPUT-REC
WRITE OUTPUT-REC
ADD 1 TO WS-GROUP-COUNT
ADD WR-VALUE TO WS-GROUP-VALUE
ADD WR-VALUE TO WS-TOTAL-VALUE
END-RETURN
END-PERFORM.
CLOSE OUTPUT-FILE.
WRITE-SUMMARY-LINE.
MOVE WS-PREV-KEY TO SL-KEY.
MOVE WS-GROUP-COUNT TO SL-COUNT.
MOVE WS-GROUP-VALUE TO SL-TOTAL.
MOVE WS-SUMMARY-LINE TO SUMMARY-REC.
WRITE SUMMARY-REC.
DISPLAY " SUMMARY: " WS-PREV-KEY
" count=" WS-GROUP-COUNT
" total=" WS-GROUP-VALUE.
EDIT-INPUT SECTION.
*> Edit records before sort: capitalize and filter
OPEN INPUT INPUT-FILE.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ INPUT-FILE INTO INPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
MOVE INPUT-REC TO WORK-REC
RELEASE WORK-REC
END-READ
END-PERFORM.
CLOSE INPUT-FILE.
*> ================================================================
*> BUILD-ENH-RECORDS: INPUT PROCEDURE that generates enhanced CDR
*> records from WORKING-STORAGE test data
*> ================================================================
BUILD-ENH-RECORDS SECTION.
DISPLAY " BUILD-ENH-RECORDS: Generating enhanced test data".
MOVE 0 TO WS-BCT-INPUT-COUNT.
PERFORM VARYING ENH-IDX FROM 1 BY 1 UNTIL ENH-IDX > 10
MOVE ETE-ID(ENH-IDX) TO W2R-KEY
MOVE ETE-CUSTOMER(ENH-IDX) TO W2R-CUSTOMER
MOVE ETE-PLAN(ENH-IDX) TO W2R-PLAN
MOVE ETE-CALL-TYPE(ENH-IDX) TO W2R-CALL-TYPE
MOVE ETE-DATE(ENH-IDX) TO W2R-DATE
MOVE ETE-DURATION(ENH-IDX) TO W2R-DURATION
RELEASE WORK2-REC
ADD 1 TO WS-BCT-INPUT-COUNT
ADD ETE-DURATION(ENH-IDX) TO WS-HASH-TOTAL
ADD ETE-DURATION(ENH-IDX) TO WS-DURATION-HASH
END-PERFORM.
DISPLAY " BUILD-ENH-RECORDS: released "
WS-BCT-INPUT-COUNT " records".
EXIT.
*> ================================================================
*> DISPLAY-ENH-OUTPUT: OUTPUT PROCEDURE that displays sorted
*> enhanced CDR records
*> ================================================================
DISPLAY-ENH-OUTPUT SECTION.
DISPLAY " DISPLAY-ENH-OUTPUT: Sorted enhanced records:".
MOVE 0 TO WS-RECORD-COUNT.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
RETURN WORK-FILE2 INTO WORK2-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
ADD 1 TO WS-RECORD-COUNT
ADD W2R-DURATION TO WS-TOTAL-VALUE
MOVE W2R-KEY TO EDL-ID
MOVE W2R-CUSTOMER TO EDL-CUSTOMER
MOVE W2R-PLAN TO EDL-PLAN
MOVE W2R-CALL-TYPE TO EDL-CALL-TYPE
MOVE W2R-DATE TO EDL-DATE
MOVE W2R-DURATION TO EDL-DURATION
DISPLAY WS-ENH-DETAIL-LINE
END-RETURN
END-PERFORM.
DISPLAY " Sorted total: " WS-RECORD-COUNT
" total duration: " WS-TOTAL-VALUE.
EXIT.
*> ================================================================
*> 1000-INIT: Initialize batch control totals, hash totals,
*> audit trail, open files
*> ================================================================
1000-INIT SECTION.
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-TIME.
MOVE 0 TO WS-BCT-INPUT-COUNT
MOVE 0 TO WS-BCT-SORTED-COUNT
MOVE 0 TO WS-BCT-FILTERED-COUNT
MOVE 0 TO WS-BCT-DUP-COUNT
MOVE 0 TO WS-BCT-INVALID-COUNT
MOVE 0 TO WS-BCT-HASH-TOTAL
MOVE 0 TO WS-HASH-TOTAL
MOVE 0 TO WS-DURATION-HASH
MOVE 0 TO WS-SS-INPUT-COUNT
MOVE 0 TO WS-SS-OUTPUT-COUNT
MOVE 0 TO WS-SS-FILTERED
MOVE 0 TO WS-SS-DUPLICATE-COUNT
MOVE 0 TO WS-SS-TOTAL-DURATION
MOVE SPACES TO WS-PREV-W2R-KEY
MOVE SPACES TO WS-PREV-CUSTOMER
MOVE SPACES TO WS-PREV-PLAN
MOVE SPACES TO WS-PREV-CALLTYPE
MOVE ZEROS TO WS-PREV-DATE
MOVE "I" TO WS-ERROR-SEVERITY.
DISPLAY " 1000-INIT at " WS-CDT-DATE "/" WS-CDT-TIME.
*> Open audit file
OPEN OUTPUT AUDIT-FILE.
IF NOT FS-AUDIT-OK
DISPLAY "ERROR: AUDIT-FILE open failed, FS=" FS-AUDIT
MOVE "E" TO WS-ERROR-SEVERITY
END-IF.
*> Open stats file
OPEN OUTPUT SORT-STATS-FILE.
IF NOT FS-STATS-OK
DISPLAY "ERROR: SORT-STATS-FILE open failed, FS="
FS-STATS
MOVE "E" TO WS-ERROR-SEVERITY
END-IF.
*> Open report file
OPEN OUTPUT REPORT-FILE.
IF NOT FS-REPORT-OK
DISPLAY "ERROR: REPORT-FILE open failed, FS="
FS-REPORT
MOVE "E" TO WS-ERROR-SEVERITY
END-IF.
MOVE "1000-INIT: Initialization complete"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
EXIT.
*> ================================================================
*> 2000-OPEN-FILES: Enhanced file opening with FILE STATUS checks
*> ================================================================
2000-OPEN-FILES SECTION.
DISPLAY " 2000-OPEN-FILES: Opening files...".
OPEN OUTPUT INPUT-FILE.
IF NOT FS-INPUT-OK
DISPLAY "ERROR 2000: INPUT-FILE open failed, FS="
FS-INPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
OPEN OUTPUT OUTPUT-FILE.
IF NOT FS-OUTPUT-OK
DISPLAY "ERROR 2000: OUTPUT-FILE open failed, FS="
FS-OUTPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
MOVE "2000-OPEN-FILES: Files opened successfully"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
EXIT.
*> ================================================================
*> 3100-VALIDATE: CDR record validation and filtering
*> Filters valid records, enriches fields
*> ================================================================
3100-VALIDATE SECTION.
DISPLAY " 3100-VALIDATE: Validating CDR records...".
OPEN INPUT INPUT-FILE.
IF NOT FS-INPUT-OK
DISPLAY "ERROR 3100: INPUT-FILE open failed, FS="
FS-INPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ INPUT-FILE INTO INPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
ADD 1 TO WS-BCT-INPUT-COUNT
ADD 1 TO WS-SS-INPUT-COUNT
*> Validate: duration must be > 0
IF IN-VALUE = 0
ADD 1 TO WS-BCT-INVALID-COUNT
MOVE "3100-VALIDATE: Zero duration filtered"
TO WS-AUDIT-MESSAGE
MOVE "W" TO WS-ERROR-SEVERITY
PERFORM 5000-AUDIT
DISPLAY " WARN: Zero duration filtered: "
IN-KEY
EXIT PERFORM CYCLE
END-IF
*> Validate: key must not be spaces
IF IN-KEY = SPACES
ADD 1 TO WS-BCT-INVALID-COUNT
DISPLAY " WARN: Empty key filtered"
EXIT PERFORM CYCLE
END-IF
*> Enrich: map input to enhanced record format
MOVE IN-KEY TO W2R-KEY
MOVE IN-DATA(1:11) TO W2R-CUSTOMER
*> Derive plan from first 4 chars of IN-DATA
EVALUATE IN-DATA(1:4)
WHEN "1380"
MOVE "PSTD" TO W2R-PLAN
WHEN "1390"
MOVE "PREM" TO W2R-PLAN
WHEN "1370"
MOVE "PSTD" TO W2R-PLAN
WHEN "1360"
MOVE "ECON" TO W2R-PLAN
WHEN "1350"
MOVE "ECON" TO W2R-PLAN
WHEN "1340"
MOVE "PSTD" TO W2R-PLAN
WHEN OTHER
MOVE "ECON" TO W2R-PLAN
END-EVALUATE
*> Derive call type from IN-KEY first character
EVALUATE IN-KEY(1:1)
WHEN "A"
MOVE "MO" TO W2R-CALL-TYPE
WHEN "B"
MOVE "MT" TO W2R-CALL-TYPE
WHEN "C"
MOVE "OT" TO W2R-CALL-TYPE
WHEN OTHER
MOVE "MO" TO W2R-CALL-TYPE
END-EVALUATE
*> Set proxy date and duration
COMPUTE W2R-DATE = 20260601
+ FUNCTION MOD(IN-VALUE, 10)
MOVE IN-VALUE TO W2R-DURATION
ADD IN-VALUE TO WS-DURATION-HASH
RELEASE WORK2-REC
ADD 1 TO WS-BCT-SORTED-COUNT
ADD IN-VALUE TO WS-BCT-HASH-TOTAL
END-READ
END-PERFORM.
CLOSE INPUT-FILE.
IF NOT FS-INPUT-EOF AND NOT FS-INPUT-OK
DISPLAY "ERROR 3100: INPUT-FILE close failed, FS="
FS-INPUT
MOVE "E" TO WS-ERROR-SEVERITY
END-IF.
DISPLAY " 3100-VALIDATE: input=" WS-BCT-INPUT-COUNT
" sorted=" WS-BCT-SORTED-COUNT
" invalid=" WS-BCT-INVALID-COUNT.
MOVE "3100-VALIDATE: CDR validation complete"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
EXIT.
*> ================================================================
*> 3200-CALCULATE: Field enrichment with hash calculations
*> ================================================================
3200-CALCULATE SECTION.
DISPLAY " 3200-CALCULATE: Enriching CDR fields...".
OPEN INPUT INPUT-FILE.
IF NOT FS-INPUT-OK
DISPLAY "ERROR 3200: INPUT-FILE open failed, FS="
FS-INPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ INPUT-FILE INTO INPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
ADD 1 TO WS-SS-INPUT-COUNT
ADD IN-VALUE TO WS-DURATION-HASH
*> Enrich: map input to WORK2-REC format
MOVE IN-KEY TO W2R-KEY
MOVE IN-DATA(1:11) TO W2R-CUSTOMER
*> Calculate plan code based on data prefix
EVALUATE IN-DATA(1:4)
WHEN "1380"
MOVE "PSTD" TO W2R-PLAN
WHEN "1390"
MOVE "PREM" TO W2R-PLAN
WHEN "1370"
MOVE "PSTD" TO W2R-PLAN
WHEN "1360"
MOVE "ECON" TO W2R-PLAN
WHEN "1350"
MOVE "ECON" TO W2R-PLAN
WHEN "1340"
MOVE "PSTD" TO W2R-PLAN
WHEN OTHER
MOVE "ECON" TO W2R-PLAN
END-EVALUATE
*> Enrich: call type from key prefix
EVALUATE IN-KEY(1:3)
WHEN "CDR"
MOVE "MO" TO W2R-CALL-TYPE
WHEN OTHER
MOVE "MT" TO W2R-CALL-TYPE
END-EVALUATE
COMPUTE W2R-DATE = 20260601
+ FUNCTION MOD(IN-VALUE, 7)
MOVE IN-VALUE TO W2R-DURATION
RELEASE WORK2-REC
ADD 1 TO WS-SS-OUTPUT-COUNT
ADD IN-VALUE TO WS-BCT-HASH-TOTAL
END-READ
END-PERFORM.
CLOSE INPUT-FILE.
DISPLAY " 3200-CALCULATE: enriched "
WS-SS-OUTPUT-COUNT " records".
MOVE "3200-CALCULATE: Field enrichment complete"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
EXIT.
*> ================================================================
*> 3300-FORMAT-OUTPUT: Format records for display
*> ================================================================
3300-FORMAT-OUTPUT SECTION.
MOVE W2R-KEY TO OUT-KEY.
MOVE W2R-CUSTOMER TO OUT-DATA(1:11).
MOVE SPACES TO OUT-DATA(12:9).
MOVE W2R-DURATION TO OUT-VALUE.
EXIT.
*> ================================================================
*> 3400-WRITE-OUTPUT: Write sorted output with FILE STATUS
*> ================================================================
3400-WRITE-OUTPUT SECTION.
DISPLAY " 3400-WRITE-OUTPUT: Writing sorted records...".
OPEN OUTPUT OUTPUT-FILE.
IF NOT FS-OUTPUT-OK
DISPLAY "ERROR 3400: OUTPUT-FILE open failed, FS="
FS-OUTPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
MOVE 0 TO WS-RECORD-COUNT.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
READ OUTPUT-FILE INTO OUTPUT-REC
AT END
MOVE "Y" TO WS-EOF
NOT AT END
ADD 1 TO WS-RECORD-COUNT
MOVE OUT-KEY TO DL-KEY
MOVE OUT-DATA TO DL-DATA
MOVE OUT-VALUE TO DL-VALUE
DISPLAY WS-DETAIL-LINE
END-READ
END-PERFORM.
DISPLAY " 3400-WRITE-OUTPUT: total=" WS-RECORD-COUNT.
MOVE "3400-WRITE-OUTPUT: Sorted records written"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
CLOSE OUTPUT-FILE.
EXIT.
*> ================================================================
*> 4000-REPORT: Multi-level keybreak report
*> Keybreak by customer, plan, call type
*> ================================================================
4000-REPORT SECTION.
DISPLAY " 4000-REPORT: Multi-level keybreak report...".
MOVE WS-CDT-DATE TO RPT1-DATE.
MOVE WS-CDT-TIME TO RPT1-TIME.
MOVE WS-RPT-HEADER1 TO REPORT-REC.
WRITE REPORT-REC.
MOVE WS-RPT-HEADER2 TO REPORT-REC.
WRITE REPORT-REC.
MOVE SPACES TO WS-PREV-CUSTOMER.
MOVE SPACES TO WS-PREV-PLAN.
MOVE SPACES TO WS-PREV-CALLTYPE.
MOVE ZEROS TO WS-PREV-DATE.
MOVE 0 TO WS-RECORD-COUNT.
MOVE 0 TO WS-TOTAL-VALUE.
MOVE "N" TO WS-EOF.
PERFORM UNTIL WS-EOF-Y
RETURN WORK-FILE2 INTO WORK2-REC
AT END
MOVE "Y" TO WS-EOF
PERFORM LAST-KEYBREAK-CUSTOMER
NOT AT END
ADD 1 TO WS-RECORD-COUNT
ADD W2R-DURATION TO WS-TOTAL-VALUE
ADD W2R-DURATION TO WS-SS-TOTAL-DURATION
*> Customer keybreak
IF W2R-CUSTOMER NOT = WS-PREV-CUSTOMER
IF WS-PREV-CUSTOMER NOT = SPACES
PERFORM LAST-KEYBREAK-PLAN
PERFORM LAST-KEYBREAK-CUSTOMER
END-IF
MOVE W2R-CUSTOMER TO WS-PREV-CUSTOMER
MOVE W2R-CUSTOMER TO WS-BR-CUSTOMER
MOVE 0 TO WS-BR-CUST-COUNT
MOVE 0 TO WS-BR-CUST-DUR
MOVE SPACES TO WS-PREV-PLAN
MOVE SPACES TO WS-PREV-CALLTYPE
END-IF
*> Plan keybreak (within customer)
IF W2R-PLAN NOT = WS-PREV-PLAN
IF WS-PREV-PLAN NOT = SPACES
PERFORM LAST-KEYBREAK-PLAN
END-IF
MOVE W2R-PLAN TO WS-PREV-PLAN
MOVE W2R-PLAN TO WS-BR-PLAN
MOVE 0 TO WS-BR-PLAN-COUNT
MOVE 0 TO WS-BR-PLAN-DUR
MOVE SPACES TO WS-PREV-CALLTYPE
END-IF
*> Call type keybreak (within plan)
IF W2R-CALL-TYPE NOT = WS-PREV-CALLTYPE
IF WS-PREV-CALLTYPE NOT = SPACES
PERFORM WRITE-KEYBREAK-CT
END-IF
MOVE W2R-CALL-TYPE TO WS-PREV-CALLTYPE
MOVE W2R-CALL-TYPE TO WS-BR-CALL-TYPE
MOVE 0 TO WS-BR-CT-COUNT
MOVE 0 TO WS-BR-CT-DUR
END-IF
*> Accumulate at all levels
ADD 1 TO WS-BR-CUST-COUNT
ADD W2R-DURATION TO WS-BR-CUST-DUR
ADD 1 TO WS-BR-PLAN-COUNT
ADD W2R-DURATION TO WS-BR-PLAN-DUR
ADD 1 TO WS-BR-CT-COUNT
ADD W2R-DURATION TO WS-BR-CT-DUR
*> Write detail to report
STRING " " W2R-KEY " "
W2R-CUSTOMER " "
W2R-PLAN " "
W2R-CALL-TYPE " "
W2R-DATE " "
W2R-DURATION
DELIMITED BY SIZE INTO REPORT-REC
END-STRING
WRITE REPORT-REC
*> Detect duplicate customer+date keys
IF W2R-CUSTOMER = WS-PREV-CUSTOMER
AND W2R-DATE = WS-PREV-DATE
ADD 1 TO WS-SS-DUPLICATE-COUNT
ADD 1 TO WS-BCT-DUP-COUNT
MOVE "W" TO WS-ERROR-SEVERITY
STRING "Duplicate key: " W2R-KEY
DELIMITED BY SIZE
INTO WS-AUDIT-MESSAGE
END-STRING
PERFORM 5000-AUDIT
END-IF
MOVE W2R-DATE TO WS-PREV-DATE
END-RETURN
END-PERFORM.
*> Grand total
MOVE WS-RECORD-COUNT TO RPT-GRAND-COUNT.
MOVE WS-TOTAL-VALUE TO RPT-GRAND-DUR.
MOVE WS-RPT-GRAND-TOTAL TO REPORT-REC.
WRITE REPORT-REC.
DISPLAY " 4000-REPORT: total records=" WS-RECORD-COUNT
" duplicates=" WS-SS-DUPLICATE-COUNT.
MOVE "4000-REPORT: Multi-level keybreak complete"
TO WS-AUDIT-MESSAGE.
MOVE "I" TO WS-ERROR-SEVERITY.
PERFORM 5000-AUDIT.
EXIT.
*> ================================================================
*> Keybreak subroutines for 4000-REPORT
*> ================================================================
LAST-KEYBREAK-CUSTOMER.
PERFORM LAST-KEYBREAK-PLAN.
IF WS-BR-CUST-COUNT > 0
MOVE WS-BR-CUSTOMER TO RPT-CUST-ID
MOVE WS-BR-CUST-COUNT TO RPT-CUST-COUNT
MOVE WS-BR-CUST-DUR TO RPT-CUST-DUR
MOVE WS-RPT-KEYBREAK-CUST TO REPORT-REC
WRITE REPORT-REC
DISPLAY " CUSTOMER " WS-BR-CUSTOMER
" count=" WS-BR-CUST-COUNT
" duration=" WS-BR-CUST-DUR
END-IF.
LAST-KEYBREAK-PLAN.
PERFORM WRITE-KEYBREAK-CT.
IF WS-BR-PLAN-COUNT > 0
MOVE WS-BR-PLAN TO RPT-PLAN-ID
MOVE WS-BR-PLAN-COUNT TO RPT-PLAN-COUNT
MOVE WS-BR-PLAN-DUR TO RPT-PLAN-DUR
MOVE WS-RPT-KEYBREAK-PLAN TO REPORT-REC
WRITE REPORT-REC
DISPLAY " PLAN " WS-BR-PLAN
" count=" WS-BR-PLAN-COUNT
" duration=" WS-BR-PLAN-DUR
END-IF.
WRITE-KEYBREAK-CT.
IF WS-BR-CT-COUNT > 0
MOVE WS-BR-CALL-TYPE TO RPT-CALL-TYPE
MOVE WS-BR-CT-COUNT TO RPT-CT-COUNT
MOVE WS-BR-CT-DUR TO RPT-CT-DUR
*> Derive call type name
EVALUATE WS-BR-CALL-TYPE
WHEN "MO"
MOVE "MOBILE-ORIG" TO RPT-CALL-TYPE-NAME
WHEN "MT"
MOVE "MOBILE-TERM" TO RPT-CALL-TYPE-NAME
WHEN "OT"
MOVE "OTHER " TO RPT-CALL-TYPE-NAME
WHEN OTHER
MOVE "UNKNOWN " TO RPT-CALL-TYPE-NAME
END-EVALUATE
MOVE WS-RPT-KEYBREAK-CT TO REPORT-REC
WRITE REPORT-REC
DISPLAY " CT " WS-BR-CALL-TYPE
" count=" WS-BR-CT-COUNT
" duration=" WS-BR-CT-DUR
END-IF.
*> ================================================================
*> 5000-AUDIT: Write audit entry with timestamp and severity
*> ================================================================
5000-AUDIT SECTION.
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-TIME.
MOVE WS-CDT-DATE TO WS-AL-DATE.
MOVE WS-CDT-TIME TO WS-AL-TIME.
MOVE WS-ERROR-SEVERITY TO WS-AL-SEVERITY.
IF WS-AL-SEVERITY = SPACE
MOVE "I" TO WS-AL-SEVERITY
END-IF.
MOVE WS-AUDIT-MESSAGE TO WS-AL-MESSAGE.
MOVE WS-AUDIT-LINE TO AUDIT-REC.
WRITE AUDIT-REC.
IF NOT FS-AUDIT-OK
DISPLAY "AUDIT WRITE FAILED: FS=" FS-AUDIT
END-IF.
DISPLAY " AUDIT [" WS-AL-SEVERITY "] "
WS-AL-DATE "/" WS-AL-TIME " "
WS-AL-MESSAGE.
EXIT.
*> ================================================================
*> 6000-ERROR-HANDLE: Handle errors with severity levels
*> ================================================================
6000-ERROR-HANDLE SECTION.
EVALUATE WS-ERROR-SEVERITY
WHEN "I"
DISPLAY " INFO: Recoverable condition"
WHEN "W"
DISPLAY " WARN: Non-critical issue detected"
STRING "WARNING: " WS-AUDIT-MESSAGE
DELIMITED BY SIZE INTO WS-AUDIT-MESSAGE
END-STRING
PERFORM 5000-AUDIT
WHEN "E"
DISPLAY " ERROR: Processing may be affected"
STRING "ERROR: " WS-AUDIT-MESSAGE
DELIMITED BY SIZE INTO WS-AUDIT-MESSAGE
END-STRING
PERFORM 5000-AUDIT
WHEN "F"
DISPLAY " FATAL: Aborting processing"
STRING "FATAL: " WS-AUDIT-MESSAGE
DELIMITED BY SIZE INTO WS-AUDIT-MESSAGE
END-STRING
PERFORM 5000-AUDIT
STOP RUN
WHEN OTHER
DISPLAY " INFO: Unknown severity - continuing"
END-EVALUATE.
MOVE "I" TO WS-ERROR-SEVERITY.
EXIT.
*> ================================================================
*> WRITE-STATS: Write sort statistics to stats file
*> ================================================================
WRITE-STATS.
DISPLAY " WRITE-STATS: Writing sort statistics...".
MOVE SPACES TO STATS-REC.
STRING "=== SORT STATISTICS ==="
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Input records = " WS-BCT-INPUT-COUNT
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Sorted records = " WS-BCT-SORTED-COUNT
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Filtered records = " WS-BCT-FILTERED-COUNT
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Duplicate records = " WS-BCT-DUP-COUNT
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Invalid records = " WS-BCT-INVALID-COUNT
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
MOVE SPACES TO STATS-REC.
STRING "Hash total (dur) = " WS-DURATION-HASH
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
DISPLAY " STATS: input=" WS-BCT-INPUT-COUNT
" sorted=" WS-BCT-SORTED-COUNT
" filtered=" WS-BCT-FILTERED-COUNT
" dup=" WS-BCT-DUP-COUNT
" invalid=" WS-BCT-INVALID-COUNT.
EXIT.
*> ================================================================
*> WRITE-HASH-TOTAL: Write hash total verification
*> ================================================================
WRITE-HASH-TOTAL.
MOVE SPACES TO STATS-REC.
STRING "Hash total verified: "
WS-DURATION-HASH
DELIMITED BY SIZE INTO STATS-REC.
WRITE STATS-REC.
DISPLAY " HASH total: " WS-DURATION-HASH.
IF WS-DURATION-HASH = WS-BCT-HASH-TOTAL
DISPLAY " HASH total MATCHES batch control"
ELSE
DISPLAY " HASH total MISMATCH: dur=" WS-DURATION-HASH
" bct=" WS-BCT-HASH-TOTAL
MOVE "HASH MISMATCH in WRITE-HASH-TOTAL"
TO WS-AUDIT-MESSAGE
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 5000-AUDIT
END-IF.
EXIT.
*> ================================================================
*> INIT-INPUT-FILE-FROM-ENH: Write enhanced test data to
*> INPUT-FILE for sorting
*> ================================================================
INIT-INPUT-FILE-FROM-ENH.
OPEN OUTPUT INPUT-FILE.
IF NOT FS-INPUT-OK
DISPLAY "ERROR INIT-ENH: INPUT-FILE open failed, FS="
FS-INPUT
MOVE "E" TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE
END-IF.
PERFORM VARYING ENH-IDX FROM 1 BY 1 UNTIL ENH-IDX > 10
MOVE ETE-ID(ENH-IDX) TO IN-KEY
MOVE ETE-CUSTOMER(ENH-IDX) TO IN-DATA(1:11)
MOVE ETE-PLAN(ENH-IDX) TO IN-DATA(12:5)
MOVE ETE-CALL-TYPE(ENH-IDX) TO IN-DATA(17:2)
MOVE ETE-DURATION(ENH-IDX) TO IN-VALUE
WRITE INPUT-REC
IF FS-INPUT NOT = "00"
DISPLAY "ERROR write: FS=" FS-INPUT
END-IF
END-PERFORM.
CLOSE INPUT-FILE.
IF NOT FS-INPUT-OK AND NOT FS-INPUT-EOF
DISPLAY "ERROR: close failed, FS=" FS-INPUT
END-IF.
DISPLAY " INIT-INPUT-FILE-FROM-ENH: wrote 10 records".
EXIT.
*> ================================================================
*> INIT-DUP-ENH-FILE: Create INPUT-FILE with duplicate keys
*> ================================================================
INIT-DUP-ENH-FILE.
OPEN OUTPUT INPUT-FILE.
IF NOT FS-INPUT-OK
DISPLAY "ERROR INIT-DUP: open failed, FS=" FS-INPUT
END-IF.
PERFORM VARYING ENH-IDX FROM 1 BY 1 UNTIL ENH-IDX > 5
MOVE DE-ID(ENH-IDX) TO IN-KEY
MOVE DE-CUSTOMER(ENH-IDX) TO IN-DATA(1:11)
MOVE DE-PLAN(ENH-IDX) TO IN-DATA(12:5)
MOVE DE-CALL-TYPE(ENH-IDX) TO IN-DATA(17:2)
MOVE DE-DURATION(ENH-IDX) TO IN-VALUE
WRITE INPUT-REC
END-PERFORM.
CLOSE INPUT-FILE.
DISPLAY " INIT-DUP-ENH-FILE: 5 records (2 duplicate pairs)".
EXIT.