Files
cobol-java-v3/benchmark-programs/08-keybreak-aggregate/main-08-keybreak-aggregate.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

706 lines
28 KiB
COBOL

*> ============================================================
*> 08-keybreak-aggregate : 套餐统计 (Plan Statistics)
*> Input : FILE-IN.DAT (KEY PIC X(10), VALUE PIC 9(10), PLAN X(3))
*> Output: FILE-OUT.DAT (KEY组别统计: 件数,最小值,最大值,合计)
*> Report: REPORT-OUT.TXT (formatted 2-level key break report)
*> Audit: AUDIT-OUT.TXT (group-level audit trail)
*> Coverage: KB-N002, KB-N004~N006, KB-R001
*> 2-level key break: customer (IN-KEY) + plan (BILL-PLAN-CODE)
*> Statistics: count, min, max, total, avg, variance, std-dev
*> Hash totals for data integrity verification
*> ============================================================
IDENTIFICATION DIVISION.
PROGRAM-ID. KeyBreakAgg.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-IN
ASSIGN TO "FILE-IN.DAT"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-FILE-IN-STATUS.
SELECT FILE-OUT
ASSIGN TO "FILE-OUT.DAT"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-FILE-OUT-STATUS.
SELECT REPORT-OUT
ASSIGN TO "REPORT-OUT.TXT"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-REPORT-STATUS.
SELECT AUDIT-OUT
ASSIGN TO "AUDIT-OUT.TXT"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-AUDIT-STATUS.
DATA DIVISION.
FILE SECTION.
FD FILE-IN.
01 FILE-IN-REC.
05 IN-KEY PIC X(10).
05 IN-VALUE PIC 9(10).
05 BILL-PLAN-CODE PIC X(03).
05 FILLER PIC X(22).
FD FILE-OUT.
01 FILE-OUT-REC.
05 OUT-KEY PIC X(10).
05 FILLER PIC X VALUE SPACE.
05 OUT-COUNT PIC Z(05)9.
05 FILLER PIC X VALUE SPACE.
05 OUT-MIN PIC Z(09)9.
05 FILLER PIC X VALUE SPACE.
05 OUT-MAX PIC Z(09)9.
05 FILLER PIC X VALUE SPACE.
05 OUT-TOTAL PIC Z(09)9.
FD REPORT-OUT.
01 REPORT-OUT-REC PIC X(80).
FD AUDIT-OUT.
01 AUDIT-OUT-REC PIC X(80).
WORKING-STORAGE SECTION.
01 WS-TELECOM-REC.
COPY "telecom/TEL-BILLING.cpy".
*> Status flags
01 WS-STATUS.
05 WS-EOF-FLAG PIC X VALUE 'N'.
88 WS-EOF VALUE 'Y' FALSE 'N'.
05 WS-FIRST-REC PIC X VALUE 'Y'.
88 WS-FIRST VALUE 'Y' FALSE 'N'.
*> Key break fields
01 WS-PREV-KEY PIC X(10).
01 WS-CURRENT-KEY PIC X(10).
01 WS-PREV-PLAN PIC X(03).
01 WS-CURRENT-PLAN PIC X(03).
*> Customer-level accumulators (original augmented)
01 WS-ACCUMULATORS.
05 WS-GROUP-COUNT PIC 9(05) VALUE 0.
05 WS-GROUP-MIN PIC 9(10) VALUE 9999999999.
05 WS-GROUP-MAX PIC 9(10) VALUE 0.
05 WS-GROUP-TOTAL PIC 9(10) VALUE 0.
05 WS-GROUP-AVG PIC 9(10)V9(05) VALUE 0.
05 WS-SUM-SQUARES PIC 9(20) VALUE 0.
05 WS-GROUP-VAR PIC 9(10)V9(05) VALUE 0.
05 WS-GROUP-STDDEV PIC 9(10)V9(05) VALUE 0.
*> Plan-level accumulators
01 WS-PLAN-ACCUMULATORS.
05 WS-PLAN-COUNT PIC 9(05) VALUE 0.
05 WS-PLAN-MIN PIC 9(10) VALUE 9999999999.
05 WS-PLAN-MAX PIC 9(10) VALUE 0.
05 WS-PLAN-TOTAL PIC 9(10) VALUE 0.
05 WS-PLAN-AVG PIC 9(10)V9(05) VALUE 0.
05 WS-PLAN-SUM-SQUARES PIC 9(20) VALUE 0.
05 WS-PLAN-VAR PIC 9(10)V9(05) VALUE 0.
05 WS-PLAN-STDDEV PIC 9(10)V9(05) VALUE 0.
*> Overflow handling
01 WS-MAX-TOTAL PIC 9(10) VALUE 9999999999.
*> Report control
01 WS-LINE-COUNT PIC 9(02) VALUE 99.
01 WS-PAGE-LENGTH PIC 9(02) VALUE 60.
01 WS-PAGE-NUM PIC 9(03) VALUE 0.
*> Hash totals (data integrity)
01 WS-HASH-TOTAL-IN PIC 9(18) VALUE 0.
01 WS-HASH-TOTAL-OUT PIC 9(18) VALUE 0.
*> Batch counters
01 WS-GROUPS-WRITTEN PIC 9(05) VALUE 0.
01 WS-RECORDS-READ PIC 9(05) VALUE 0.
01 WS-VALUE-NUM PIC 9(10).
01 WS-HASH-VERIFIED PIC X(07) VALUE 'PASSED'.
*> File status fields
01 WS-FILE-IN-STATUS PIC X(02).
01 WS-FILE-OUT-STATUS PIC X(02).
01 WS-REPORT-STATUS PIC X(02).
01 WS-AUDIT-STATUS PIC X(02).
*> Error handling
01 WS-ERROR-MESSAGE PIC X(60).
01 WS-ERROR-SEVERITY PIC X(07).
88 WS-SEVERITY-WARNING VALUE 'WARNING'.
88 WS-SEVERITY-ERROR VALUE 'ERROR '.
88 WS-SEVERITY-FATAL VALUE 'FATAL '.
*> Overflow flag
01 WS-OVERFLOW-FLAG PIC X VALUE 'N'.
88 WS-OVERFLOW VALUE 'Y' FALSE 'N'.
*> Timestamp
01 WS-TIMESTAMP PIC X(19).
01 WS-CURRENT-DATE-DATA.
05 WS-CD-DATE PIC X(08).
05 WS-CD-TIME PIC X(06).
05 FILLER PIC X(09).
*> Report structures
01 WS-REPORT-HEADER.
05 FILLER PIC X(30)
05 FILLER PIC X(25) VALUE SPACES.
05 FILLER PIC X(06) VALUE 'PAGE: '.
05 WS-HDR-PAGE PIC Z(03)9.
05 FILLER PIC X(15) VALUE SPACES.
01 WS-DETAIL-LINE.
05 FILLER PIC X(05) VALUE SPACES.
05 WS-DL-KEY PIC X(10).
05 FILLER PIC X(03) VALUE SPACES.
05 FILLER PIC X(05) VALUE 'PLAN:'.
05 WS-DL-PLAN PIC X(03).
05 FILLER PIC X(03) VALUE SPACES.
05 FILLER PIC X(06) VALUE 'VALUE:'.
05 WS-DL-VALUE PIC Z(09)9.
05 FILLER PIC X(04) VALUE SPACES.
05 FILLER PIC X(06) VALUE 'CUMUL:'.
05 WS-DL-CUMUL PIC Z(09)9.
05 FILLER PIC X(24) VALUE SPACES.
01 WS-CUST-FOOTER.
05 FILLER PIC X(16) VALUE ' CUSTOMER TOTAL'.
05 FILLER PIC X(05) VALUE ': CNT='.
05 WS-CF-COUNT PIC Z(05)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'MIN: '.
05 WS-CF-MIN PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'MAX: '.
05 WS-CF-MAX PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(06) VALUE 'TOTAL:'.
05 WS-CF-TOTAL PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'AVG: '.
05 WS-CF-AVG PIC Z(09)9.
05 FILLER PIC X(20) VALUE SPACES.
01 WS-PLAN-FOOTER.
05 FILLER PIC X(14) VALUE ' PLAN-'.
05 WS-PF-PLAN PIC X(03).
05 FILLER PIC X(05) VALUE ': CNT='.
05 WS-PF-COUNT PIC Z(05)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'MIN: '.
05 WS-PF-MIN PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'MAX: '.
05 WS-PF-MAX PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(06) VALUE 'TOTAL:'.
05 WS-PF-TOTAL PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'AVG: '.
05 WS-PF-AVG PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'VAR: '.
05 WS-PF-VAR PIC Z(09)9.
05 FILLER PIC X(03) VALUE ' | '.
05 FILLER PIC X(05) VALUE 'STDEV:'.
05 WS-PF-STDDEV PIC Z(09)9.
05 FILLER PIC X(08) VALUE SPACES.
01 WS-GRAND-TOTAL-HEADER.
05 FILLER PIC X(25)
VALUE '=== GRAND TOTAL SUMMARY ==='.
05 FILLER PIC X(55) VALUE SPACES.
01 WS-GRAND-TOTAL-LINE.
05 FILLER PIC X(20)
VALUE ' Records read: '.
05 WS-GT-RECORDS PIC Z(05)9.
05 FILLER PIC X(53) VALUE SPACES.
01 WS-GT-HASH-LINE.
05 FILLER PIC X(20)
VALUE ' Hash IN: '.
05 WS-GT-HASH-IN PIC Z(17)9.
05 FILLER PIC X(43) VALUE SPACES.
01 WS-GT-HASH-LINE-OUT.
05 FILLER PIC X(20)
VALUE ' Hash OUT: '.
05 WS-GT-HASH-OUT PIC Z(17)9.
05 FILLER PIC X(43) VALUE SPACES.
01 WS-GT-VERIFY-LINE.
05 FILLER PIC X(20)
VALUE ' Verification: '.
05 WS-GT-VERIFY PIC X(07).
05 FILLER PIC X(53) VALUE SPACES.
*> Audit record structure
01 WS-AUDIT-LINE.
05 WS-AUDIT-TS PIC X(19).
05 FILLER PIC X VALUE SPACE.
05 WS-AUDIT-TYPE PIC X(08).
05 FILLER PIC X VALUE SPACE.
05 WS-AUDIT-DESC PIC X(51).
PROCEDURE DIVISION.
MAIN SECTION.
MAIN-PROCEDURE.
PERFORM 1000-INIT-SECTION
PERFORM 2000-OPEN-FILES-SECTION
PERFORM 3000-PROCESS-SECTION
PERFORM 4000-REPORT-SECTION
PERFORM 5000-AUDIT-SECTION
PERFORM 9000-EXIT-SECTION
STOP RUN.
*> 1000-INIT-SECTION
1000-INIT-SECTION.
PERFORM GET-TIMESTAMP
DISPLAY "[" WS-TIMESTAMP "] KeyBreakAgg START"
MOVE SPACES TO WS-PREV-PLAN
MOVE 0 TO WS-GROUPS-WRITTEN WS-RECORDS-READ
MOVE 0 TO WS-HASH-TOTAL-IN WS-HASH-TOTAL-OUT
MOVE 'N' TO WS-OVERFLOW-FLAG
MOVE 99 TO WS-LINE-COUNT
DISPLAY "Page length: " WS-PAGE-LENGTH
.
*> 2000-OPEN-FILES-SECTION
2000-OPEN-FILES-SECTION.
OPEN INPUT FILE-IN
IF WS-FILE-IN-STATUS NOT = '00'
STRING 'FILE-IN OPEN FAILED STATUS='
WS-FILE-IN-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'FATAL ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
DISPLAY "FILE-IN opened status=" WS-FILE-IN-STATUS
OPEN OUTPUT FILE-OUT
IF WS-FILE-OUT-STATUS NOT = '00'
STRING 'FILE-OUT OPEN FAILED STATUS='
WS-FILE-OUT-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'FATAL ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
DISPLAY "FILE-OUT opened status=" WS-FILE-OUT-STATUS
OPEN OUTPUT REPORT-OUT
IF WS-REPORT-STATUS NOT = '00'
STRING 'REPORT-OUT OPEN FAILED STATUS='
WS-REPORT-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'FATAL ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
DISPLAY "REPORT-OUT opened status=" WS-REPORT-STATUS
OPEN OUTPUT AUDIT-OUT
IF WS-AUDIT-STATUS NOT = '00'
STRING 'AUDIT-OUT OPEN FAILED STATUS='
WS-AUDIT-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'FATAL ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
DISPLAY "AUDIT-OUT opened status=" WS-AUDIT-STATUS
.
*> 3000-PROCESS-SECTION
3000-PROCESS-SECTION.
PERFORM 3100-READ-INPUT-SECTION
PERFORM UNTIL WS-EOF
PERFORM 3200-VALIDATE-SECTION
PERFORM 3300-APPLY-RULES-SECTION
PERFORM 3400-WRITE-OUTPUT-SECTION
PERFORM 3100-READ-INPUT-SECTION
END-PERFORM
IF WS-RECORDS-READ > 0
PERFORM WRITE-PLAN-AGGREGATE
PERFORM WRITE-GROUP-AGGREGATE
END-IF
.
*> 3100-READ-INPUT-SECTION
3100-READ-INPUT-SECTION.
READ FILE-IN INTO FILE-IN-REC
IF WS-FILE-IN-STATUS = '10'
SET WS-EOF TO TRUE
DISPLAY "FILE-IN EOF status=" WS-FILE-IN-STATUS
ELSE IF WS-FILE-IN-STATUS = '00'
ADD 1 TO WS-RECORDS-READ
MOVE IN-VALUE TO WS-VALUE-NUM
MOVE IN-KEY TO WS-CURRENT-KEY
MOVE BILL-PLAN-CODE OF FILE-IN-REC TO WS-CURRENT-PLAN
ADD WS-VALUE-NUM TO WS-HASH-TOTAL-IN
ELSE
STRING 'FILE-IN READ ERROR STATUS='
WS-FILE-IN-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'FATAL ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
.
*> 3200-VALIDATE-SECTION
3200-VALIDATE-SECTION.
IF WS-VALUE-NUM = 0
STRING 'Zero value encountered key='
WS-CURRENT-KEY INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'WARNING' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
IF WS-GROUP-TOTAL > WS-MAX-TOTAL
MOVE 'Y' TO WS-OVERFLOW-FLAG
STRING 'CUSTOMER TOTAL OVERFLOW key='
WS-CURRENT-KEY INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'ERROR ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
IF WS-GROUP-TOTAL + WS-VALUE-NUM > WS-MAX-TOTAL
STRING 'Would exceed MAX-TOTAL key='
WS-CURRENT-KEY INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'WARNING' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
.
*> 3300-APPLY-RULES-SECTION
3300-APPLY-RULES-SECTION.
IF WS-FIRST
MOVE WS-CURRENT-KEY TO WS-PREV-KEY
MOVE WS-CURRENT-PLAN TO WS-PREV-PLAN
MOVE WS-VALUE-NUM TO WS-GROUP-MIN
MOVE WS-VALUE-NUM TO WS-GROUP-MAX
MOVE WS-VALUE-NUM TO WS-PLAN-MIN
MOVE WS-VALUE-NUM TO WS-PLAN-MAX
MOVE 'N' TO WS-FIRST-REC
DISPLAY "First record key=" WS-CURRENT-KEY
" plan=" WS-CURRENT-PLAN
ELSE
IF WS-CURRENT-KEY NOT = WS-PREV-KEY
IF WS-PREV-PLAN NOT = SPACES
DISPLAY "CUST BREAK: " WS-PREV-KEY
" -> " WS-CURRENT-KEY
PERFORM WRITE-PLAN-AGGREGATE
END-IF
PERFORM WRITE-GROUP-AGGREGATE
MOVE WS-CURRENT-KEY TO WS-PREV-KEY
MOVE WS-CURRENT-PLAN TO WS-PREV-PLAN
MOVE 9999999999 TO WS-GROUP-MIN
MOVE 0 TO WS-GROUP-MAX
MOVE 0 TO WS-GROUP-COUNT
MOVE 0 TO WS-GROUP-TOTAL
MOVE 0 TO WS-GROUP-AVG
MOVE 0 TO WS-SUM-SQUARES
MOVE 0 TO WS-GROUP-VAR
MOVE 0 TO WS-GROUP-STDDEV
MOVE 9999999999 TO WS-PLAN-MIN
MOVE 0 TO WS-PLAN-MAX
MOVE 0 TO WS-PLAN-COUNT
MOVE 0 TO WS-PLAN-TOTAL
MOVE 0 TO WS-PLAN-AVG
MOVE 0 TO WS-PLAN-SUM-SQUARES
MOVE 0 TO WS-PLAN-VAR
MOVE 0 TO WS-PLAN-STDDEV
ELSE
IF WS-CURRENT-PLAN NOT = WS-PREV-PLAN
DISPLAY "PLAN BREAK: " WS-PREV-PLAN
" -> " WS-CURRENT-PLAN
PERFORM WRITE-PLAN-AGGREGATE
MOVE WS-CURRENT-PLAN TO WS-PREV-PLAN
MOVE 9999999999 TO WS-PLAN-MIN
MOVE 0 TO WS-PLAN-MAX
MOVE 0 TO WS-PLAN-COUNT
MOVE 0 TO WS-PLAN-TOTAL
MOVE 0 TO WS-PLAN-AVG
MOVE 0 TO WS-PLAN-SUM-SQUARES
MOVE 0 TO WS-PLAN-VAR
MOVE 0 TO WS-PLAN-STDDEV
END-IF
END-IF
END-IF
*> Customer-level accumulation (original logic preserved)
ADD 1 TO WS-GROUP-COUNT
ADD WS-VALUE-NUM TO WS-GROUP-TOTAL
COMPUTE WS-SUM-SQUARES = WS-SUM-SQUARES
+ (WS-VALUE-NUM * WS-VALUE-NUM)
IF WS-VALUE-NUM < WS-GROUP-MIN
MOVE WS-VALUE-NUM TO WS-GROUP-MIN
END-IF
IF WS-VALUE-NUM > WS-GROUP-MAX
MOVE WS-VALUE-NUM TO WS-GROUP-MAX
END-IF
*> Plan-level accumulation
ADD 1 TO WS-PLAN-COUNT
ADD WS-VALUE-NUM TO WS-PLAN-TOTAL
COMPUTE WS-PLAN-SUM-SQUARES = WS-PLAN-SUM-SQUARES
+ (WS-VALUE-NUM
* WS-VALUE-NUM)
IF WS-VALUE-NUM < WS-PLAN-MIN
MOVE WS-VALUE-NUM TO WS-PLAN-MIN
END-IF
IF WS-VALUE-NUM > WS-PLAN-MAX
MOVE WS-VALUE-NUM TO WS-PLAN-MAX
END-IF
.
*> 3400-WRITE-OUTPUT-SECTION
3400-WRITE-OUTPUT-SECTION.
MOVE IN-KEY TO WS-DL-KEY
MOVE BILL-PLAN-CODE OF FILE-IN-REC TO WS-DL-PLAN
MOVE IN-VALUE TO WS-DL-VALUE
MOVE WS-GROUP-TOTAL TO WS-DL-CUMUL
PERFORM WRITE-DETAIL-LINE
.
*> 4000-REPORT-SECTION
4000-REPORT-SECTION.
PERFORM WRITE-GRAND-TOTAL
.
*> 5000-AUDIT-SECTION
5000-AUDIT-SECTION.
PERFORM GET-TIMESTAMP
MOVE WS-TIMESTAMP TO WS-AUDIT-TS
MOVE 'SUMMARY' TO WS-AUDIT-TYPE
MOVE 'Batch processing complete' TO WS-AUDIT-DESC
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
IF WS-AUDIT-STATUS NOT = '00'
MOVE 'AUDIT-OUT WRITE ERROR' TO WS-ERROR-MESSAGE
MOVE 'WARNING' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
STRING 'Records read:' WS-RECORDS-READ
' Groups:' WS-GROUPS-WRITTEN
INTO WS-AUDIT-DESC
END-STRING
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
STRING 'Hash IN:' WS-HASH-TOTAL-IN
' OUT:' WS-HASH-TOTAL-OUT
' Verify:' WS-HASH-VERIFIED
INTO WS-AUDIT-DESC
END-STRING
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
IF WS-OVERFLOW
MOVE 'Overflow was set during processing'
TO WS-AUDIT-DESC
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
END-IF
MOVE 'END-OF-JOB' TO WS-AUDIT-DESC
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
.
*> 6000-ERROR-HANDLE-SECTION
6000-ERROR-HANDLE-SECTION.
DISPLAY "[" WS-ERROR-SEVERITY "] " WS-ERROR-MESSAGE
IF WS-SEVERITY-FATAL
PERFORM 9000-EXIT-SECTION
STOP RUN
END-IF
.
*> 9000-EXIT-SECTION
9000-EXIT-SECTION.
CLOSE FILE-IN
IF WS-FILE-IN-STATUS NOT = '00'
DISPLAY "FILE-IN CLOSE status=" WS-FILE-IN-STATUS
END-IF
CLOSE FILE-OUT
IF WS-FILE-OUT-STATUS NOT = '00'
DISPLAY "FILE-OUT CLOSE status=" WS-FILE-OUT-STATUS
END-IF
CLOSE REPORT-OUT
IF WS-REPORT-STATUS NOT = '00'
DISPLAY "REPORT-OUT CLOSE status=" WS-REPORT-STATUS
END-IF
CLOSE AUDIT-OUT
IF WS-AUDIT-STATUS NOT = '00'
DISPLAY "AUDIT-OUT CLOSE status=" WS-AUDIT-STATUS
END-IF
PERFORM GET-TIMESTAMP
DISPLAY "[" WS-TIMESTAMP "] === FINAL SUMMARY ==="
DISPLAY "Records read: " WS-RECORDS-READ
DISPLAY "Groups written: " WS-GROUPS-WRITTEN
DISPLAY "Hash total IN: " WS-HASH-TOTAL-IN
DISPLAY "Hash total OUT: " WS-HASH-TOTAL-OUT
DISPLAY "Hash verification: " WS-HASH-VERIFIED
DISPLAY "Overflow occurred: " WS-OVERFLOW-FLAG
DISPLAY "[" WS-TIMESTAMP "] KeyBreakAgg END"
.
*> SUPPORTING PARAGRAPHS
*> ------------------------------------------------------------
*> GET-TIMESTAMP : Populate WS-TIMESTAMP from system clock
*> ------------------------------------------------------------
GET-TIMESTAMP SECTION.
GET-TIMESTAMP-PROC.
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-DATA
STRING WS-CD-DATE(1:4) '-' WS-CD-DATE(5:2) '-'
WS-CD-DATE(7:2) ' ' WS-CD-TIME(1:2) ':'
WS-CD-TIME(3:2) ':' WS-CD-TIME(5:2)
INTO WS-TIMESTAMP
END-STRING
.
*> ------------------------------------------------------------
*> WRITE-GROUP-AGGREGATE — Original aggregate output (kept intact)
*> ------------------------------------------------------------
WRITE-GROUP-AGGREGATE SECTION.
WRITE-GROUP-AGGREGATE-PROC.
IF WS-GROUP-COUNT > 0
COMPUTE WS-GROUP-AVG =
WS-GROUP-TOTAL / WS-GROUP-COUNT
COMPUTE WS-GROUP-VAR =
(WS-SUM-SQUARES
- (WS-GROUP-TOTAL * WS-GROUP-TOTAL
/ WS-GROUP-COUNT))
/ WS-GROUP-COUNT
COMPUTE WS-GROUP-STDDEV =
FUNCTION SQRT(WS-GROUP-VAR)
ELSE
MOVE 0 TO WS-GROUP-AVG WS-GROUP-VAR WS-GROUP-STDDEV
END-IF
MOVE WS-PREV-KEY TO OUT-KEY
MOVE WS-GROUP-COUNT TO OUT-COUNT
MOVE WS-GROUP-MIN TO OUT-MIN
MOVE WS-GROUP-MAX TO OUT-MAX
MOVE WS-GROUP-TOTAL TO OUT-TOTAL
WRITE FILE-OUT-REC
IF WS-FILE-OUT-STATUS NOT = '00'
STRING 'FILE-OUT WRITE ERROR STATUS='
WS-FILE-OUT-STATUS INTO WS-ERROR-MESSAGE
END-STRING
MOVE 'ERROR ' TO WS-ERROR-SEVERITY
PERFORM 6000-ERROR-HANDLE-SECTION
END-IF
ADD 1 TO WS-GROUPS-WRITTEN
ADD WS-GROUP-TOTAL TO WS-HASH-TOTAL-OUT
DISPLAY " Group " WS-PREV-KEY ": count="
WS-GROUP-COUNT ", min=" WS-GROUP-MIN
", max=" WS-GROUP-MAX ", total=" WS-GROUP-TOTAL
*> Write customer footer to report
MOVE WS-GROUP-COUNT TO WS-CF-COUNT
MOVE WS-GROUP-MIN TO WS-CF-MIN
MOVE WS-GROUP-MAX TO WS-CF-MAX
MOVE WS-GROUP-TOTAL TO WS-CF-TOTAL
MOVE WS-GROUP-AVG TO WS-CF-AVG
MOVE WS-CUST-FOOTER TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
*> Write audit for customer group
PERFORM GET-TIMESTAMP
MOVE WS-TIMESTAMP TO WS-AUDIT-TS
MOVE 'CUST GRP' TO WS-AUDIT-TYPE
STRING 'Key ' WS-PREV-KEY ' count=' WS-GROUP-COUNT
' total=' WS-GROUP-TOTAL INTO WS-AUDIT-DESC
END-STRING
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
.
*> ------------------------------------------------------------
*> WRITE-PLAN-AGGREGATE — Plan-level aggregate output
*> ------------------------------------------------------------
WRITE-PLAN-AGGREGATE SECTION.
WRITE-PLAN-AGGREGATE-PROC.
IF WS-PLAN-COUNT = 0
EXIT SECTION
END-IF
COMPUTE WS-PLAN-AVG = WS-PLAN-TOTAL / WS-PLAN-COUNT
COMPUTE WS-PLAN-VAR =
(WS-PLAN-SUM-SQUARES
- (WS-PLAN-TOTAL * WS-PLAN-TOTAL / WS-PLAN-COUNT))
/ WS-PLAN-COUNT
COMPUTE WS-PLAN-STDDEV =
FUNCTION SQRT(WS-PLAN-VAR)
*> Write plan footer to report
MOVE WS-PREV-PLAN TO WS-PF-PLAN
MOVE WS-PLAN-COUNT TO WS-PF-COUNT
MOVE WS-PLAN-MIN TO WS-PF-MIN
MOVE WS-PLAN-MAX TO WS-PF-MAX
MOVE WS-PLAN-TOTAL TO WS-PF-TOTAL
MOVE WS-PLAN-AVG TO WS-PF-AVG
MOVE WS-PLAN-VAR TO WS-PF-VAR
MOVE WS-PLAN-STDDEV TO WS-PF-STDDEV
MOVE WS-PLAN-FOOTER TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
DISPLAY " Plan " WS-PREV-PLAN ": count="
WS-PLAN-COUNT ", total=" WS-PLAN-TOTAL
*> Write audit for plan group
PERFORM GET-TIMESTAMP
MOVE WS-TIMESTAMP TO WS-AUDIT-TS
MOVE 'PLAN GRP' TO WS-AUDIT-TYPE
STRING 'Plan ' WS-PREV-PLAN ' for key ' WS-PREV-KEY
' count=' WS-PLAN-COUNT ' total=' WS-PLAN-TOTAL
INTO WS-AUDIT-DESC
END-STRING
WRITE AUDIT-OUT-REC FROM WS-AUDIT-LINE
.
*> ------------------------------------------------------------
*> WRITE-REPORT-LINE : Write report line with page break control
*> ------------------------------------------------------------
WRITE-REPORT-LINE SECTION.
WRITE-REPORT-LINE-PROC.
IF WS-LINE-COUNT >= WS-PAGE-LENGTH
ADD 1 TO WS-PAGE-NUM
MOVE WS-PAGE-NUM TO WS-HDR-PAGE
MOVE WS-REPORT-HEADER TO REPORT-OUT-REC
WRITE REPORT-OUT-REC
MOVE 2 TO WS-LINE-COUNT
END-IF
WRITE REPORT-OUT-REC
ADD 1 TO WS-LINE-COUNT
.
*> ------------------------------------------------------------
*> WRITE-DETAIL-LINE : Write one detail record to report
*> ------------------------------------------------------------
WRITE-DETAIL-LINE SECTION.
WRITE-DETAIL-LINE-PROC.
MOVE WS-DETAIL-LINE TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
.
*> ------------------------------------------------------------
*> WRITE-GRAND-TOTAL : Grand total summary to report
*> ------------------------------------------------------------
WRITE-GRAND-TOTAL SECTION.
WRITE-GRAND-TOTAL-PROC.
IF WS-HASH-TOTAL-IN = WS-HASH-TOTAL-OUT
MOVE 'PASSED' TO WS-HASH-VERIFIED
ELSE
MOVE 'FAILED' TO WS-HASH-VERIFIED
END-IF
MOVE WS-RECORDS-READ TO WS-GT-RECORDS
MOVE WS-HASH-TOTAL-IN TO WS-GT-HASH-IN
MOVE WS-HASH-TOTAL-OUT TO WS-GT-HASH-OUT
MOVE WS-HASH-VERIFIED TO WS-GT-VERIFY
MOVE WS-GRAND-TOTAL-HEADER TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
MOVE SPACES TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
MOVE WS-GRAND-TOTAL-LINE TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
MOVE WS-GT-HASH-LINE TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
MOVE WS-GT-HASH-LINE-OUT TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
MOVE WS-GT-VERIFY-LINE TO REPORT-OUT-REC
PERFORM WRITE-REPORT-LINE
DISPLAY "Grand total: records=" WS-RECORDS-READ
" groups=" WS-GROUPS-WRITTEN
DISPLAY "Hash IN=" WS-HASH-TOTAL-IN
" OUT=" WS-HASH-TOTAL-OUT " " WS-HASH-VERIFIED
.