Skip to content

CBACT04C

Source: cbl/CBACT04C.cbl

Type: Batch program

CBACT04C — Interest Calculator (Batch)

Purpose

This batch COBOL program calculates monthly interest on credit card account balances, based on the transaction category balances accumulated for each account. For each account, it determines the applicable interest rate from a disclosure group table, computes monthly interest per transaction category, updates the account's running balance, and writes an interest-charge transaction record to a transaction file for downstream processing. It is executed as job step INTCALC.STEP15.

How it works

The main control flow (Procedure Division, starting line 180) does the following:

  1. Startup: Opens all five files via 0000-TCATBALF-OPEN, 0100-XREFFILE-OPEN, 0200-DISCGRP-OPEN, 0300-ACCTFILE-OPEN, and 0400-TRANFILE-OPEN. Any file that fails to open (status ≠ '00') causes an immediate abend.

  2. Main loop: Reads the transaction category balance file (TCATBAL-FILE) sequentially via 1000-TCATBALF-GET-NEXT, one record per iteration, until end-of-file.

  3. When the account ID on the current record (TRANCAT-ACCT-ID) differs from the previous one (WS-LAST-ACCT-NUM), the program treats this as a new account:
    • If not the first account processed, it calls 1050-UPDATE-ACCOUNT to post the accumulated interest (WS-TOTAL-INT) to the previous account's balance and reset cycle credit/debit totals to zero.
    • It resets the running interest total, then looks up the new account's master record (1100-GET-ACCT-DATA) and its cross-reference record (1110-GET-XREF-DATA, keyed on account ID via the alternate key).
  4. For every category-balance record (regardless of whether the account changed), it looks up the interest rate for that account's disclosure group / transaction type / category via 1200-GET-INTEREST-RATE.
    • If the specific group is not found (DISCGRP-STATUS = '23'), it falls back to a hard-coded 'DEFAULT' group ID and re-reads via 1200-A-GET-DEFAULT-INT-RATE.
  5. If a non-zero interest rate (DIS-INT-RATE) is found, it computes interest (1300-COMPUTE-INTEREST) and calls a stubbed fee routine (1400-COMPUTE-FEES, currently a no-op — "To be implemented").
  6. 1300-COMPUTE-INTEREST computes monthly interest as (TRAN-CAT-BAL * DIS-INT-RATE) / 1200, adds it to the account's running total, and calls 1300-B-WRITE-TX to write a corresponding transaction record (type '01', category '05', source 'System') to the output transaction file, including a generated DB2-style timestamp (Z-GET-DB2-FORMAT-TIMESTAMP).
  7. When the category-balance file reaches end-of-file, the loop performs one final 1050-UPDATE-ACCOUNT to post interest for the last account.

  8. Shutdown: Closes all five files (90009400 paragraphs), again abending on any close error, and displays a completion message.

Any file-status error during open, read, rewrite, write, or close triggers 9910-DISPLAY-IO-STATUS (formats and displays the numeric/status code) followed by 9999-ABEND-PROGRAM, which calls CEE3ABD with abend code 999 to terminate the job forcibly.

Inputs & outputs

File / DD Select name Access Purpose
TCATBALF TCATBAL-FILE Indexed, sequential read Input driver file: transaction category balances per account (key: account ID + type code + category code). Drives the main processing loop.
XREFFILE XREF-FILE Indexed, random (by alternate key FD-XREF-ACCT-ID) Cross-reference lookup to get the card number associated with an account, used to populate the output transaction's card number.
ACCTFILE ACCOUNT-FILE Indexed, I-O (read and rewrite) Account master file — read to get current balance data, rewritten to post accumulated interest and reset cycle credit/debit.
DISCGRP DISCGRP-FILE Indexed, random Disclosure group table — provides the interest rate for a given account group / transaction type / category combination, with a fallback to a 'DEFAULT' group.
TRANSACT TRANSACT-FILE Sequential, output only Output file — new interest-charge transaction records are appended here, one per computed interest amount.

Copybooks CVACT01Y, CVACT03Y, CVTRA01Y, CVTRA02Y, CVTRA05Y define the working-storage record layouts (ACCOUNT-RECORD, CARD-XREF-RECORD, TRAN-CAT-BAL-RECORD, DIS-GROUP-RECORD, TRAN-RECORD) corresponding to these files. No CICS commands or SQL tables are used — this is a plain batch program. The program also accepts a linkage-section parameter PARM-DATE (10 bytes, from EXTERNAL-PARMS) used to build transaction IDs.

Things to know

  • No SQL / CICS: Despite calculating interest for a "CardDemo" application, this program is pure batch COBOL with VSAM/indexed file I/O — no DB2 or CICS integration, though it generates a "DB2-format" timestamp string manually (Z-GET-DB2-FORMAT-TIMESTAMP) rather than obtaining it from an actual DB2 call.
  • Hard-coded values: Transaction type code '01', category code '05', and source 'System' are hard-coded for every generated interest transaction. The fallback disclosure group ID 'DEFAULT' is also hard-coded (line ~ in 1200-GET-INTEREST-RATE).
  • Fee calculation stub: 1400-COMPUTE-FEES is empty ("To be implemented") — it is called but currently performs no work. Any downstream expectation of fee transactions will not be met by this version.
  • Error handling is uniform but harsh: virtually every I/O operation checks file status and calls 9999-ABEND-PROGRAM on any non-success status (except tolerated cases: end-of-file '10' on the driver file, and '23'/not-found on the disclosure group lookup). There is no retry or partial-recovery logic — any unexpected file status abends the whole job via CALL 'CEE3ABD' with a fixed abend code of 999.
  • Transaction ID generation: TRAN-ID is built by concatenating PARM-DATE with an in-memory counter WS-TRANID-SUFFIX (6 digits, incremented per transaction, not reset across runs within the program) — uniqueness depends entirely on the caller supplying a distinct PARM-DATE per run; there's no persistence of this counter across runs.
  • Account-boundary logic risk: The "new account" detection compares TRANCAT-ACCT-ID to WS-LAST-ACCT-NUM and assumes the category-balance file is sorted by account ID. If the input file is not properly sorted, interest postings could be applied to the wrong account or split incorrectly.
  • Interest skipped silently when rate is zero: If DIS-INT-RATE is 0 for a category, no interest is computed or transaction written for that category — this is by design but could mask missing disclosure group configuration.
  • 1100-GET-ACCT-DATA / 1110-GET-XREF-DATA "not found" handling: These display a message on INVALID KEY but do not abend immediately on invalid key alone — they only abend if the resulting file status is not '00'. Since a not-found on a random read is typically a non-'00' status, this effectively still leads to an abend, but the flow is a bit indirect (display message from the INVALID KEY clause, followed by the generic status check triggering the abend).
  • Fixed 3-decimal-position style constants: Interest is computed by dividing by 1200 (12 months × 100 for percentage) — this assumes DIS-INT-RATE is stored as a whole-number percentage; misconfigured rate scaling would silently produce wrong interest amounts with no validation.

Files

Logical file DD name
TCATBAL-FILE TCATBALF
XREF-FILE XREFFILE
ACCOUNT-FILE ACCTFILE
DISCGRP-FILE DISCGRP
TRANSACT-FILE TRANSACT

Copybooks

CVACT01Y, CVACT03Y, CVTRA01Y, CVTRA02Y, CVTRA05Y

Calls

CEE3ABD

Executed by

INTCALC.STEP15

Paragraph flow

flowchart TD
    0000_TCATBALF_OPEN["0000-TCATBALF-OPEN"]
    0100_XREFFILE_OPEN["0100-XREFFILE-OPEN"]
    0200_DISCGRP_OPEN["0200-DISCGRP-OPEN"]
    0300_ACCTFILE_OPEN["0300-ACCTFILE-OPEN"]
    0400_TRANFILE_OPEN["0400-TRANFILE-OPEN"]
    1000_TCATBALF_GET_NEXT["1000-TCATBALF-GET-NEXT"]
    1050_UPDATE_ACCOUNT["1050-UPDATE-ACCOUNT"]
    1100_GET_ACCT_DATA["1100-GET-ACCT-DATA"]
    1110_GET_XREF_DATA["1110-GET-XREF-DATA"]
    1200_GET_INTEREST_RATE["1200-GET-INTEREST-RATE"]
    1200_A_GET_DEFAULT_INT_RATE["1200-A-GET-DEFAULT-INT-RATE"]
    1300_COMPUTE_INTEREST["1300-COMPUTE-INTEREST"]
    1300_B_WRITE_TX["1300-B-WRITE-TX"]
    1400_COMPUTE_FEES["1400-COMPUTE-FEES"]
    9000_TCATBALF_CLOSE["9000-TCATBALF-CLOSE"]
    9100_XREFFILE_CLOSE["9100-XREFFILE-CLOSE"]
    9200_DISCGRP_CLOSE["9200-DISCGRP-CLOSE"]
    9300_ACCTFILE_CLOSE["9300-ACCTFILE-CLOSE"]
    9400_TRANFILE_CLOSE["9400-TRANFILE-CLOSE"]
    Z_GET_DB2_FORMAT_TIMESTAMP["Z-GET-DB2-FORMAT-TIMESTAMP"]
    9999_ABEND_PROGRAM["9999-ABEND-PROGRAM"]
    9910_DISPLAY_IO_STATUS["9910-DISPLAY-IO-STATUS"]
    0000_TCATBALF_OPEN --> 9910_DISPLAY_IO_STATUS
    0000_TCATBALF_OPEN --> 9999_ABEND_PROGRAM
    0100_XREFFILE_OPEN --> 9910_DISPLAY_IO_STATUS
    0100_XREFFILE_OPEN --> 9999_ABEND_PROGRAM
    0200_DISCGRP_OPEN --> 9910_DISPLAY_IO_STATUS
    0200_DISCGRP_OPEN --> 9999_ABEND_PROGRAM
    0300_ACCTFILE_OPEN --> 9910_DISPLAY_IO_STATUS
    0300_ACCTFILE_OPEN --> 9999_ABEND_PROGRAM
    0400_TRANFILE_OPEN --> 9910_DISPLAY_IO_STATUS
    0400_TRANFILE_OPEN --> 9999_ABEND_PROGRAM
    1000_TCATBALF_GET_NEXT --> 9910_DISPLAY_IO_STATUS
    1000_TCATBALF_GET_NEXT --> 9999_ABEND_PROGRAM
    1050_UPDATE_ACCOUNT --> 9910_DISPLAY_IO_STATUS
    1050_UPDATE_ACCOUNT --> 9999_ABEND_PROGRAM
    1100_GET_ACCT_DATA --> 9910_DISPLAY_IO_STATUS
    1100_GET_ACCT_DATA --> 9999_ABEND_PROGRAM
    1110_GET_XREF_DATA --> 9910_DISPLAY_IO_STATUS
    1110_GET_XREF_DATA --> 9999_ABEND_PROGRAM
    1200_A_GET_DEFAULT_INT_RATE --> 9910_DISPLAY_IO_STATUS
    1200_A_GET_DEFAULT_INT_RATE --> 9999_ABEND_PROGRAM
    1200_GET_INTEREST_RATE --> 1200_A_GET_DEFAULT_INT_RATE
    1200_GET_INTEREST_RATE --> 9910_DISPLAY_IO_STATUS
    1200_GET_INTEREST_RATE --> 9999_ABEND_PROGRAM
    1300_B_WRITE_TX --> 9910_DISPLAY_IO_STATUS
    1300_B_WRITE_TX --> 9999_ABEND_PROGRAM
    1300_B_WRITE_TX --> Z_GET_DB2_FORMAT_TIMESTAMP
    1300_COMPUTE_INTEREST --> 1300_B_WRITE_TX
    9000_TCATBALF_CLOSE --> 9910_DISPLAY_IO_STATUS
    9000_TCATBALF_CLOSE --> 9999_ABEND_PROGRAM
    9100_XREFFILE_CLOSE --> 9910_DISPLAY_IO_STATUS
    9100_XREFFILE_CLOSE --> 9999_ABEND_PROGRAM
    9200_DISCGRP_CLOSE --> 9910_DISPLAY_IO_STATUS
    9200_DISCGRP_CLOSE --> 9999_ABEND_PROGRAM
    9300_ACCTFILE_CLOSE --> 9910_DISPLAY_IO_STATUS
    9300_ACCTFILE_CLOSE --> 9999_ABEND_PROGRAM
    9400_TRANFILE_CLOSE --> 9910_DISPLAY_IO_STATUS
    9400_TRANFILE_CLOSE --> 9999_ABEND_PROGRAM

Paragraphs

Paragraph Line Performs
0000-TCATBALF-OPEN 234 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
0100-XREFFILE-OPEN 252 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
0200-DISCGRP-OPEN 270 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
0300-ACCTFILE-OPEN 289 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
0400-TRANFILE-OPEN 307 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1000-TCATBALF-GET-NEXT 325 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1050-UPDATE-ACCOUNT 350 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1100-GET-ACCT-DATA 372 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1110-GET-XREF-DATA 393 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1200-GET-INTEREST-RATE 415 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM, 1200-A-GET-DEFAULT-INT-RATE
1200-A-GET-DEFAULT-INT-RATE 443 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1300-COMPUTE-INTEREST 462 1300-B-WRITE-TX
1300-B-WRITE-TX 473 Z-GET-DB2-FORMAT-TIMESTAMP, 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
1400-COMPUTE-FEES 518
9000-TCATBALF-CLOSE 522 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
9100-XREFFILE-CLOSE 541 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
9200-DISCGRP-CLOSE 559 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
9300-ACCTFILE-CLOSE 577 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
9400-TRANFILE-CLOSE 595 9910-DISPLAY-IO-STATUS, 9999-ABEND-PROGRAM
Z-GET-DB2-FORMAT-TIMESTAMP 613
9999-ABEND-PROGRAM 628
9910-DISPLAY-IO-STATUS 635