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.