33 min read

At 6:00 a.m. on the third Wednesday of every month, a COBOL batch job awakens at the Social Security Administration's data center in Woodlawn, Maryland. Over the next four hours, it will calculate and authorize benefit payments for approximately 67...

Chapter 35: Insurance and Government Systems

Part VII - COBOL in Financial Systems


Opening Vignette: The Quiet Engine of the Safety Net

At 6:00 a.m. on the third Wednesday of every month, a COBOL batch job awakens at the Social Security Administration's data center in Woodlawn, Maryland. Over the next four hours, it will calculate and authorize benefit payments for approximately 67 million Americans -- retirees drawing pensions they earned over decades of work, disabled individuals who depend on monthly checks for their survival, and surviving spouses and children of workers who died too young. The total: more than $100 billion in a single payment cycle. Every dollar must be calculated correctly. Every payment must reach the right account. Every deduction for Medicare premiums, tax withholding, and garnishments must be applied precisely as federal law requires.

Three hundred miles south, at a major property and casualty insurer's mainframe facility in Richmond, Virginia, the nightly batch cycle processes 400,000 auto insurance premium calculations. Each one involves dozens of rating factors: the driver's age, the vehicle's safety rating, the territory where the car is garaged, the policyholder's claims history over the past five years, multi-car discounts, good student discounts, and state-mandated minimum and maximum premium constraints. A single error in the rating algorithm could mean underpricing risk for an entire state, exposing the company to catastrophic losses, or overcharging policyholders in violation of the rates filed with the state insurance commissioner.

These two worlds -- insurance and government -- may seem different on the surface. One is a private industry driven by actuarial science and competitive markets; the other is a network of public agencies governed by statute and regulation. Yet they share a common technological foundation: massive COBOL systems that process enormous volumes of financial transactions with decimal precision, rigorous audit trails, and unwavering reliability.

Insurance companies and government agencies were among the earliest adopters of COBOL. The insurance industry needed a language that could handle complex premium calculations involving dozens of rating factors, table lookups, and rounding rules specified by state regulators. Government agencies needed a language that could process millions of benefit payments, tax returns, and eligibility determinations according to rules defined by thousands of pages of federal statute. COBOL delivered on both counts, and today, more than six decades after the language was created, it remains the backbone of both sectors.

In this chapter, you will learn how COBOL powers insurance policy administration systems, premium calculation engines, claims processing workflows, and actuarial computations. You will also explore how government agencies use COBOL for Social Security benefit administration, Medicare processing, tax computation, and regulatory compliance. By the end of this chapter, you will understand the data structures, processing patterns, and business logic that make these systems work, and you will be equipped to read, maintain, and extend the COBOL programs that millions of people depend on every day.


35.1 The Insurance Industry and COBOL

35.1.1 Why Insurance Runs on COBOL

The insurance industry processes staggering volumes of data. A large property and casualty insurer may maintain 30 million active policies, process 5 million claims annually, and calculate premiums using rating algorithms that involve hundreds of variables. A major life insurer may administer policies with coverage amounts totaling trillions of dollars, calculating reserves, cash values, and dividend allocations that must be accurate to the penny for regulatory reporting.

COBOL dominates insurance for several reasons that parallel those discussed in Chapter 34 for banking systems:

Decimal arithmetic precision: Insurance premiums, claim payments, reserves, and commissions all involve currency calculations where floating-point rounding errors are unacceptable. As covered in Chapter 33, COBOL's native support for packed decimal and display numeric data types eliminates the rounding errors that plague languages using IEEE 754 floating-point arithmetic. When a state insurance commissioner approves a rate of $347.52 per year for a particular coverage, the system must charge exactly $347.52 -- not $347.5199999999.

Table-driven processing: Insurance rating is fundamentally a table-lookup operation. Base rates vary by territory, coverage type, and policy form. Rating factors adjust for age, gender, claims history, vehicle type, building construction, and dozens of other variables. COBOL's table handling capabilities -- OCCURS clauses, INDEXED BY, SEARCH, and SEARCH ALL -- map naturally to these requirements.

High-volume batch processing: Insurance companies process enormous batch runs: nightly premium billing, monthly commission calculations, quarterly reserve valuations, and annual policy renewals. COBOL's sequential file processing, combined with SORT/MERGE and JCL-orchestrated job streams, handles these volumes efficiently.

Regulatory compliance: Insurance is regulated at the state level in the United States, meaning that a national insurer must comply with 50 different sets of rules. COBOL programs encode these rules explicitly in readable, auditable code that regulators and actuaries can review.

Long system lifetimes: An insurance policy can span decades. A whole life insurance policy purchased in 1975 may still be in force today, and the COBOL programs that administer it must faithfully execute business rules that were defined nearly fifty years ago while simultaneously applying current regulatory requirements. COBOL's backward compatibility makes this possible.

35.1.2 Insurance System Architecture

A typical insurance company's technology landscape includes the following core systems:

Policy Administration System (PAS): The system of record for all policies. It handles new business issuance, endorsements (mid-term changes), renewals, cancellations, and reinstatements. The PAS maintains the policy master file, which contains the definitive record of every policy the company has issued.

Rating Engine: The subsystem that calculates premiums. Given a set of risk characteristics (the "risk profile"), the rating engine applies base rates, rating factors, discounts, surcharges, and state-mandated limits to produce a premium. Rating engines may operate in batch mode (for renewal processing) or real-time mode (for online quoting).

Claims Processing System: Manages the lifecycle of insurance claims from first notice of loss through investigation, adjustment, payment, and closure. Claims systems are among the most complex applications in insurance, involving medical coding, litigation tracking, reserve estimation, and fraud detection.

Billing System: Generates premium invoices, processes payments, tracks delinquencies, and manages payment plans. Billing systems must handle multiple payment frequencies (annual, semi-annual, quarterly, monthly) and payment methods (direct bill, agency bill, payroll deduction, electronic funds transfer).

Reinsurance System: Manages the company's reinsurance treaties and facultative placements. When an insurer writes a policy with a coverage amount that exceeds its retention limit, it cedes a portion of the risk to reinsurers. The reinsurance system calculates ceded premiums, recoverable amounts on claims, and treaty balances.

Actuarial and Reserving Systems: Calculate the reserves that the company must hold to pay future claims. Reserve calculations involve complex actuarial formulas, loss development triangles, and statistical projections. These systems feed directly into regulatory filings and financial statements.


35.2 Insurance Policy Administration

Policy administration is the heart of an insurance company's operations. Every policy goes through a lifecycle: it is quoted, bound, issued, endorsed, renewed, and eventually cancelled or expired. The policy administration system manages each of these transitions, maintaining a complete history of every change.

35.2.1 The Policy Master Record

The policy master record is the most important data structure in an insurance system. It must store everything the company needs to know about a policy: who is insured, what is covered, when coverage begins and ends, how much premium is charged, who sold the policy, and how it has changed over time.

The following record layout, from Example 01 in this chapter's code directory, illustrates a typical policy master record for a multi-line insurance company. Notice how it uses level-88 condition names extensively to make the code self-documenting:

       01  POLICY-MASTER-RECORD.
           05  PM-POLICY-NUMBER          PIC X(12).
           05  PM-POLICY-STATUS-CODE     PIC X(02).
               88  PM-STATUS-ACTIVE      VALUE 'AC'.
               88  PM-STATUS-PENDING     VALUE 'PE'.
               88  PM-STATUS-CANCELLED   VALUE 'CA'.
               88  PM-STATUS-EXPIRED     VALUE 'EX'.
               88  PM-STATUS-LAPSED      VALUE 'LA'.
               88  PM-STATUS-SUSPENDED   VALUE 'SU'.
           05  PM-LINE-OF-BUSINESS       PIC X(03).
               88  PM-LOB-AUTO           VALUE 'AUT'.
               88  PM-LOB-HOME           VALUE 'HOM'.
               88  PM-LOB-LIFE           VALUE 'LIF'.
               88  PM-LOB-HEALTH         VALUE 'HLT'.
               88  PM-LOB-COMMERCIAL     VALUE 'COM'.
           05  PM-INSURED-INFO.
               10  PM-INSURED-SSN        PIC X(09).
               10  PM-INSURED-LAST-NAME  PIC X(25).
               10  PM-INSURED-FIRST-NAME PIC X(15).
               10  PM-INSURED-MI         PIC X(01).
               10  PM-INSURED-DOB        PIC 9(08).
               10  PM-INSURED-GENDER     PIC X(01).
               10  PM-INSURED-ADDRESS.
                   15  PM-STREET-ADDR    PIC X(30).
                   15  PM-CITY           PIC X(20).
                   15  PM-STATE          PIC X(02).
                   15  PM-ZIP-CODE       PIC X(05).
                   15  PM-ZIP-PLUS4      PIC 9(04).
           05  PM-POLICY-DATES.
               10  PM-EFFECTIVE-DATE     PIC 9(08).
               10  PM-EXPIRATION-DATE    PIC 9(08).
               10  PM-ORIG-ISSUE-DATE    PIC 9(08).
               10  PM-LAST-RENEWAL-DATE  PIC 9(08).
               10  PM-CANCEL-DATE        PIC 9(08).
           05  PM-COVERAGE-INFO.
               10  PM-COVERAGE-AMOUNT    PIC 9(09)V99.
               10  PM-DEDUCTIBLE-AMT     PIC 9(07)V99.
               10  PM-ANNUAL-PREMIUM     PIC 9(07)V99.
               10  PM-PREMIUM-FREQUENCY  PIC X(01).
                   88  PM-FREQ-ANNUAL    VALUE 'A'.
                   88  PM-FREQ-SEMI      VALUE 'S'.
                   88  PM-FREQ-QUARTERLY VALUE 'Q'.
                   88  PM-FREQ-MONTHLY   VALUE 'M'.
               10  PM-PAYMENT-METHOD     PIC X(01).
                   88  PM-PAY-DIRECT     VALUE 'D'.
                   88  PM-PAY-AGENCY     VALUE 'A'.
                   88  PM-PAY-PAYROLL    VALUE 'P'.
           05  PM-AGENT-INFO.
               10  PM-AGENT-CODE         PIC X(08).
               10  PM-AGENT-COMM-PCT     PIC 9V9999.
           05  PM-ENDORSEMENT-COUNT      PIC 9(03).
           05  PM-RENEWAL-COUNT          PIC 9(02).
           05  PM-CLAIMS-COUNT           PIC 9(03).
           05  PM-LAST-ACTIVITY-DATE     PIC 9(08).
           05  PM-UNDERWRITING-CLASS     PIC X(02).
               88  PM-UW-PREFERRED       VALUE 'PF'.
               88  PM-UW-STANDARD        VALUE 'ST'.
               88  PM-UW-SUBSTANDARD     VALUE 'SS'.
               88  PM-UW-DECLINED        VALUE 'DC'.
           05  PM-TERRITORY-CODE         PIC X(04).
           05  PM-RISK-SCORE             PIC 9(03).
           05  FILLER                    PIC X(169).

Several design decisions in this record layout deserve attention:

Policy number as primary key: The 12-character policy number (PM-POLICY-NUMBER) serves as the VSAM KSDS primary key. Insurance policy numbers typically encode information: the first two characters might indicate the line of business, the next two the state of issue, and the remaining eight a sequential number. This encoding allows range-based retrieval -- reading all auto policies issued in California, for example.

Alternate key on SSN: The Social Security number is defined as an alternate key WITH DUPLICATES, allowing the system to retrieve all policies for a given insured person. This is essential for household-level processing, cross-selling, and multi-policy discounts.

Status codes with condition names: The six status codes (AC, PE, CA, EX, LA, SU) cover the complete policy lifecycle. The level-88 condition names make PROCEDURE DIVISION logic readable: IF PM-STATUS-ACTIVE is far clearer than IF PM-POLICY-STATUS-CODE = 'AC'.

Separated date fields: Each date uses PIC 9(08) in YYYYMMDD format, which supports the FUNCTION INTEGER-OF-DATE intrinsic for date arithmetic. Keeping effective, expiration, original issue, last renewal, and cancellation dates as separate fields (rather than in an array) improves code readability and simplifies date validation.

FILLER for future expansion: The 169-byte FILLER at the end of the record reserves space for future fields without changing the record length. This is a standard practice in COBOL file design, as discussed in Chapter 12 on indexed files.

35.2.2 Transaction-Driven Policy Processing

Insurance policy administration follows a transaction-driven model. External events -- a new application, a change request, a renewal notice, a cancellation letter -- are encoded as transaction records and applied against the policy master file. The policy administration program in Example 01 demonstrates this pattern using an EVALUATE statement to dispatch transactions:

       2000-PROCESS-TRANSACTIONS.
           ADD 1 TO WS-TRANS-READ
           SET VALID-TRANS TO TRUE

           EVALUATE TRUE
               WHEN TR-CREATE
                   PERFORM 3000-CREATE-POLICY
               WHEN TR-MODIFY
                   PERFORM 4000-MODIFY-POLICY
               WHEN TR-RENEW
                   PERFORM 5000-RENEW-POLICY
               WHEN TR-CANCEL
                   PERFORM 6000-CANCEL-POLICY
               WHEN OTHER
                   MOVE 'INVALID TRANSACTION CODE'
                       TO WS-ERROR-MSG
                   PERFORM 8000-WRITE-ERROR
                   ADD 1 TO WS-ERRORS
           END-EVALUATE

           PERFORM 2100-READ-TRANSACTION
           .

This is the classic COBOL transaction processing pattern: read a transaction, determine its type, dispatch to the appropriate processing paragraph, and read the next transaction. The EVALUATE TRUE construct with level-88 conditions (TR-CREATE, TR-MODIFY, TR-RENEW, TR-CANCEL) is the idiomatic COBOL equivalent of a switch statement, and it produces code that reads almost like English.

35.2.3 Policy Creation

Creating a new policy is the most data-intensive transaction. The create paragraph must validate that the policy does not already exist, populate every field in the master record, calculate the expiration date, and write the new record to the VSAM file. Here is the create logic from Example 01:

       3000-CREATE-POLICY.
      * Create a new policy from application data.
      * Validates that policy does not already exist.
           MOVE TR-POLICY-NUMBER TO PM-POLICY-NUMBER
           READ POLICY-MASTER
               INVALID KEY CONTINUE
               NOT INVALID KEY
                   MOVE 'POLICY ALREADY EXISTS - CANNOT CREATE'
                       TO WS-ERROR-MSG
                   PERFORM 8000-WRITE-ERROR
                   ADD 1 TO WS-ERRORS
                   GO TO 3000-EXIT
           END-READ

           INITIALIZE POLICY-MASTER-RECORD

           MOVE TR-POLICY-NUMBER      TO PM-POLICY-NUMBER
           SET  PM-STATUS-ACTIVE      TO TRUE
           MOVE TR-LINE-OF-BUSINESS   TO PM-LINE-OF-BUSINESS
           MOVE TR-INSURED-SSN        TO PM-INSURED-SSN
           MOVE TR-INSURED-LAST-NAME  TO PM-INSURED-LAST-NAME
           MOVE TR-INSURED-FIRST-NAME TO PM-INSURED-FIRST-NAME
           MOVE TR-INSURED-MI         TO PM-INSURED-MI
           MOVE TR-INSURED-DOB        TO PM-INSURED-DOB
           MOVE TR-INSURED-GENDER     TO PM-INSURED-GENDER
           MOVE TR-STREET-ADDR        TO PM-STREET-ADDR
           MOVE TR-CITY               TO PM-CITY
           MOVE TR-STATE              TO PM-STATE
           MOVE TR-ZIP-CODE           TO PM-ZIP-CODE
           MOVE TR-ZIP-PLUS4          TO PM-ZIP-PLUS4

           MOVE TR-EFFECTIVE-DATE     TO PM-EFFECTIVE-DATE
           MOVE TR-EFFECTIVE-DATE     TO PM-ORIG-ISSUE-DATE

      *    Calculate expiration date (1 year from effective)
           MOVE TR-EFFECTIVE-DATE     TO WS-DATE-WORK
           ADD 1 TO WS-WORK-YYYY
           STRING WS-WORK-YYYY WS-WORK-MM WS-WORK-DD
               DELIMITED BY SIZE
               INTO PM-EXPIRATION-DATE

           MOVE TR-COVERAGE-AMOUNT    TO PM-COVERAGE-AMOUNT
           MOVE TR-DEDUCTIBLE-AMT     TO PM-DEDUCTIBLE-AMT
           MOVE TR-ANNUAL-PREMIUM     TO PM-ANNUAL-PREMIUM
           MOVE TR-PREMIUM-FREQUENCY  TO PM-PREMIUM-FREQUENCY
           MOVE TR-AGENT-CODE         TO PM-AGENT-CODE
           MOVE 0.1000                TO PM-AGENT-COMM-PCT
           MOVE 0                     TO PM-ENDORSEMENT-COUNT
           MOVE 0                     TO PM-RENEWAL-COUNT
           MOVE 0                     TO PM-CLAIMS-COUNT
           MOVE WS-CURRENT-DATE       TO PM-LAST-ACTIVITY-DATE
           MOVE TR-UW-CLASS           TO PM-UNDERWRITING-CLASS
           MOVE TR-TERRITORY-CODE     TO PM-TERRITORY-CODE
           MOVE 500                   TO PM-RISK-SCORE

           WRITE POLICY-MASTER-RECORD
           IF WS-POLICY-STATUS = '00'
               ADD 1 TO WS-CREATES-OK
               MOVE 'CR'              TO WS-AD-TRANS-CODE
               MOVE PM-POLICY-NUMBER  TO WS-AD-POLICY-NUM
               MOVE 'CREATE'          TO WS-AD-ACTION
               MOVE PM-EFFECTIVE-DATE TO WS-AD-EFF-DATE
               MOVE PM-ANNUAL-PREMIUM TO WS-AD-PREMIUM
               MOVE 'ACTIVE'          TO WS-AD-STATUS
               MOVE 'NEW POLICY ISSUED'
                                      TO WS-AD-DESCRIPTION
               WRITE AUDIT-LINE FROM WS-AUDIT-DETAIL
           ELSE
               STRING 'WRITE ERROR ON POLICY CREATE: '
                      WS-POLICY-STATUS
                   DELIMITED BY SIZE INTO WS-ERROR-MSG
               PERFORM 8000-WRITE-ERROR
               ADD 1 TO WS-ERRORS
           END-IF
           .
       3000-EXIT.
           EXIT
           .

The duplicate-check pattern at the top is important: before writing a new record, the program attempts to read the policy number from the master file. If the read succeeds (NOT INVALID KEY), it means the policy already exists, and the create must be rejected. Only if the read fails (INVALID KEY) does the program proceed with the creation. This defensive pattern prevents the accidental overwriting of existing policies.

Note also the audit trail: every successful transaction writes a detail line to the audit report. In insurance systems, audit trails are not optional. State regulators and internal auditors require a complete record of every change to every policy, including who made the change, when, and why.

35.2.4 Endorsements and Policy Modifications

An endorsement is a mid-term change to a policy. Common endorsements include address changes, coverage increases or decreases, deductible changes, and the addition or removal of drivers or vehicles. The modification paragraph from Example 01 handles endorsements using a secondary EVALUATE:

       4000-MODIFY-POLICY.
      * Modify an existing policy (endorsement processing).
      * Supports address change, coverage change, deductible change.
           MOVE TR-POLICY-NUMBER TO PM-POLICY-NUMBER
           READ POLICY-MASTER
               INVALID KEY
                   MOVE 'POLICY NOT FOUND FOR MODIFY'
                       TO WS-ERROR-MSG
                   PERFORM 8000-WRITE-ERROR
                   ADD 1 TO WS-ERRORS
                   GO TO 4000-EXIT
           END-READ

           IF NOT PM-STATUS-ACTIVE
               MOVE 'POLICY NOT ACTIVE - CANNOT MODIFY'
                   TO WS-ERROR-MSG
               PERFORM 8000-WRITE-ERROR
               ADD 1 TO WS-ERRORS
               GO TO 4000-EXIT
           END-IF

           EVALUATE TRUE
               WHEN TR-MOD-ADDRESS
                   MOVE TR-STREET-ADDR  TO PM-STREET-ADDR
                   MOVE TR-CITY         TO PM-CITY
                   MOVE TR-STATE        TO PM-STATE
                   MOVE TR-ZIP-CODE     TO PM-ZIP-CODE
                   MOVE TR-ZIP-PLUS4    TO PM-ZIP-PLUS4
                   MOVE 'ADDRESS CHANGE ENDORSEMENT'
                       TO WS-AD-DESCRIPTION

               WHEN TR-MOD-COVERAGE
                   MOVE TR-COVERAGE-AMOUNT TO PM-COVERAGE-AMOUNT
                   MOVE TR-ANNUAL-PREMIUM  TO PM-ANNUAL-PREMIUM
                   MOVE 'COVERAGE CHANGE ENDORSEMENT'
                       TO WS-AD-DESCRIPTION

               WHEN TR-MOD-DEDUCTIBLE
                   MOVE TR-DEDUCTIBLE-AMT  TO PM-DEDUCTIBLE-AMT
                   MOVE TR-ANNUAL-PREMIUM  TO PM-ANNUAL-PREMIUM
                   MOVE 'DEDUCTIBLE CHANGE ENDORSEMENT'
                       TO WS-AD-DESCRIPTION

               WHEN OTHER
                   MOVE 'INVALID MODIFY FIELD CODE'
                       TO WS-ERROR-MSG
                   PERFORM 8000-WRITE-ERROR
                   ADD 1 TO WS-ERRORS
                   GO TO 4000-EXIT
           END-EVALUATE

           ADD 1 TO PM-ENDORSEMENT-COUNT
           MOVE WS-CURRENT-DATE TO PM-LAST-ACTIVITY-DATE

           REWRITE POLICY-MASTER-RECORD
           .

The dual validation -- first checking that the policy exists, then checking that it is active -- is characteristic of insurance processing. A policy that is cancelled, expired, lapsed, or suspended cannot be endorsed. The endorsement count is incremented on every successful modification, providing a running total that auditors can use to identify policies with unusual levels of activity.

35.2.5 Cancellation and Refund Calculation

Policy cancellation is more complex than it first appears, because the refund calculation depends on who initiated the cancellation. Insurance uses two refund methods:

Pro-rata cancellation: When the insured requests cancellation, they receive a refund proportional to the remaining days in the policy term. If a policyholder cancels a $1,200 annual policy six months into the term, the pro-rata refund is $600 (half the premium for half the remaining term).

Short-rate cancellation: When the company initiates the cancellation (for non-payment, underwriting reasons, or other cause), the company retains a penalty -- typically 10 percent of the unearned premium. Using the same example, the short-rate refund would be $540 ($600 pro-rata minus a 10 percent penalty).

No refund: Cancellations due to fraud result in no refund at all.

The refund calculation logic from Example 01 illustrates these rules:

       6100-CALCULATE-REFUND.
      * Calculate refund based on cancellation type.
      * Pro-rata: insured-requested cancellations
      * Short-rate: company-initiated cancellations
      * No refund: fraud cancellations
           MOVE 0 TO WS-REFUND-AMOUNT

           IF TR-CANCEL-FRAUD
               MOVE 0 TO WS-REFUND-AMOUNT
               GO TO 6100-EXIT
           END-IF

      *    Determine months used in term
           COMPUTE WS-DAYS-IN-TERM =
               FUNCTION INTEGER-OF-DATE(PM-EXPIRATION-DATE) -
               FUNCTION INTEGER-OF-DATE(PM-EFFECTIVE-DATE)

           COMPUTE WS-DAYS-USED =
               FUNCTION INTEGER-OF-DATE(TR-EFFECTIVE-DATE) -
               FUNCTION INTEGER-OF-DATE(PM-EFFECTIVE-DATE)

           IF WS-DAYS-USED >= WS-DAYS-IN-TERM
               MOVE 0 TO WS-REFUND-AMOUNT
               GO TO 6100-EXIT
           END-IF

           COMPUTE WS-DAYS-REMAINING =
               WS-DAYS-IN-TERM - WS-DAYS-USED

           IF TR-CANCEL-INSURED-REQ
      *        Pro-rata refund for insured-requested cancellation
               COMPUTE WS-REFUND-AMOUNT ROUNDED =
                   PM-ANNUAL-PREMIUM *
                   (WS-DAYS-REMAINING / WS-DAYS-IN-TERM)
           ELSE
      *        Short-rate refund (company keeps a penalty)
               COMPUTE WS-PRO-RATA-REFUND ROUNDED =
                   PM-ANNUAL-PREMIUM *
                   (WS-DAYS-REMAINING / WS-DAYS-IN-TERM)
      *        Apply 10% short-rate penalty
               COMPUTE WS-REFUND-AMOUNT ROUNDED =
                   WS-PRO-RATA-REFUND * 0.90
           END-IF
           .
       6100-EXIT.
           EXIT
           .

This code uses FUNCTION INTEGER-OF-DATE to convert YYYYMMDD dates into integer day numbers, enabling exact day-level arithmetic. The ROUNDED keyword ensures that the refund amount is properly rounded to the nearest penny, following the financial arithmetic principles covered in Chapter 33.


35.3 Premium Calculation Engines

35.3.1 The Rating Process

Premium calculation -- called "rating" in insurance terminology -- is the process of determining the price of an insurance policy. Rating is inherently a table-driven, factor-based computation. The basic formula is:

Final Premium = Base Rate
              x Age Factor
              x Vehicle Factor
              x Deductible Factor
              x Risk Class Factor
              - Discounts
              + Surcharges

Each factor is looked up from a table based on characteristics of the insured, the property being insured, or the coverage being purchased. The tables themselves are filed with state insurance regulators and must be applied exactly as filed. Any deviation -- even a rounding difference -- can result in regulatory penalties.

35.3.2 Table-Driven Rating in COBOL

Example 02 in this chapter's code directory implements a complete premium calculation engine for auto insurance. The program demonstrates several table structures that are representative of production rating systems.

The territory base rate table stores base rates for each combination of territory and coverage type:

       01  WS-TERRITORY-RATE-TABLE.
           05  WS-TERR-ENTRY OCCURS 20 TIMES
               INDEXED BY WS-TERR-IDX.
               10  WS-TERR-CODE         PIC X(04).
               10  WS-TERR-LI-RATE      PIC 9(05)V99.
               10  WS-TERR-CO-RATE      PIC 9(05)V99.
               10  WS-TERR-CP-RATE      PIC 9(05)V99.
               10  WS-TERR-MD-RATE      PIC 9(05)V99.
               10  WS-TERR-UM-RATE      PIC 9(05)V99.

In production, this table would be loaded from an external file or a DB2 table at program initialization. The example loads rates from a sequential file during the initialization phase:

       1100-LOAD-RATE-TABLES.
      * Load territory base rates from external rate table file.
           MOVE 0 TO WS-TERR-COUNT

           PERFORM UNTIL WS-TBL-STATUS NOT = '00'
               READ RATE-TABLE-FILE
                   AT END
                       CONTINUE
                   NOT AT END
                       ADD 1 TO WS-TERR-COUNT
                       MOVE RATE-TABLE-RECORD(1:4)
                           TO WS-TERR-CODE(WS-TERR-COUNT)
                       MOVE RATE-TABLE-RECORD(5:9)
                           TO WS-TERR-LI-RATE(WS-TERR-COUNT)
                       MOVE RATE-TABLE-RECORD(14:9)
                           TO WS-TERR-CO-RATE(WS-TERR-COUNT)
                       MOVE RATE-TABLE-RECORD(23:9)
                           TO WS-TERR-CP-RATE(WS-TERR-COUNT)
                       MOVE RATE-TABLE-RECORD(32:9)
                           TO WS-TERR-MD-RATE(WS-TERR-COUNT)
                       MOVE RATE-TABLE-RECORD(41:9)
                           TO WS-TERR-UM-RATE(WS-TERR-COUNT)
               END-READ
           END-PERFORM
           .

The age rating factor table uses a threshold approach. Instead of storing a factor for every possible age, it stores age limits and applies the corresponding factor to any insured whose age falls at or below that threshold:

       01  WS-AGE-FACTOR-TABLE.
           05  FILLER PIC X(10) VALUE '016 1.7500'.
           05  FILLER PIC X(10) VALUE '017 1.6500'.
           05  FILLER PIC X(10) VALUE '018 1.5500'.
           05  FILLER PIC X(10) VALUE '019 1.4500'.
           05  FILLER PIC X(10) VALUE '020 1.3500'.
           05  FILLER PIC X(10) VALUE '021 1.2500'.
           05  FILLER PIC X(10) VALUE '025 1.1000'.
           05  FILLER PIC X(10) VALUE '030 1.0000'.
           05  FILLER PIC X(10) VALUE '040 0.9500'.
           05  FILLER PIC X(10) VALUE '050 0.9000'.
           05  FILLER PIC X(10) VALUE '055 0.9500'.
           05  FILLER PIC X(10) VALUE '060 1.0000'.
           05  FILLER PIC X(10) VALUE '065 1.1000'.
           05  FILLER PIC X(10) VALUE '070 1.2500'.
           05  FILLER PIC X(10) VALUE '075 1.4000'.
           05  FILLER PIC X(10) VALUE '999 1.5000'.
       01  WS-AGE-TBL REDEFINES WS-AGE-FACTOR-TABLE.
           05  WS-AGE-ENTRY OCCURS 16 TIMES
               INDEXED BY WS-AGE-IDX.
               10  WS-AGE-LIMIT         PIC 9(03).
               10  FILLER               PIC X(01).
               10  WS-AGE-RATE-FACTOR   PIC 9V9999.
               10  FILLER               PIC X(01).

This REDEFINES technique -- defining a table as FILLER values for readability and then redefining it as indexed entries for processing -- is a classic COBOL pattern that you will encounter in virtually every insurance rating system. The threshold approach is efficient because it avoids the need for a separate entry for every possible age from 16 to 100+. A 35-year-old driver falls into the "030-040" range and receives the 0.9500 factor.

35.3.3 The Multi-Step Rating Algorithm

The premium calculation in Example 02 follows a ten-step pipeline that is representative of production rating engines:

       2000-PROCESS-REQUESTS.
           ADD 1 TO WS-REQUESTS-READ
           INITIALIZE WS-CALC-FIELDS

      *    Step 1: Calculate insured age
           PERFORM 3000-CALCULATE-AGE

      *    Step 2: Look up territory base rate
           PERFORM 3100-LOOKUP-BASE-RATE

      *    Step 3: Apply age rating factor
           PERFORM 3200-APPLY-AGE-FACTOR

      *    Step 4: Apply vehicle symbol factor
           PERFORM 3300-APPLY-VEHICLE-FACTOR

      *    Step 5: Apply deductible factor
           PERFORM 3400-APPLY-DEDUCTIBLE-FACTOR

      *    Step 6: Apply risk class factor
           PERFORM 3500-APPLY-RISK-FACTOR

      *    Step 7: Calculate rated premium
           COMPUTE WS-COMBINED-FACTOR ROUNDED =
               WS-AGE-FACTOR *
               WS-VEHICLE-FACTOR *
               WS-DEDUCTIBLE-FACTOR *
               WS-RISK-FACTOR

           COMPUTE WS-RATED-PREMIUM ROUNDED =
               WS-BASE-PREMIUM * WS-COMBINED-FACTOR

      *    Step 8: Apply discounts
           PERFORM 3600-CALCULATE-DISCOUNTS

      *    Step 9: Apply surcharges
           PERFORM 3700-CALCULATE-SURCHARGES

      *    Step 10: Calculate final premium
           COMPUTE WS-FINAL-PREMIUM ROUNDED =
               WS-RATED-PREMIUM -
               WS-DISCOUNT-AMOUNT +
               WS-SURCHARGE-AMOUNT

      *    Step 11: Apply state min/max rules
           PERFORM 3800-APPLY-STATE-LIMITS

      *    Step 12: Write output
           PERFORM 4000-WRITE-OUTPUT
           .

Each step is isolated in its own paragraph, making the algorithm easy to trace, test, and modify. When a state regulator changes the age rating table, only the table data and the 3200-APPLY-AGE-FACTOR paragraph need to be reviewed. When a new discount is approved, only 3600-CALCULATE-DISCOUNTS needs to change.

35.3.4 Discounts and Surcharges

The discount calculation in Example 02 demonstrates a pattern where multiple independent discounts are accumulated and then capped at a maximum percentage:

       3600-CALCULATE-DISCOUNTS.
      * Apply applicable discounts with cap at maximum.
           MOVE 0 TO WS-DISCOUNT-AMOUNT
           MOVE 1 TO WS-FACTOR-POS
           MOVE SPACES TO WS-FACTORS-STRING

           IF RR-MULTI-CAR
               COMPUTE WS-DISCOUNT-AMOUNT ROUNDED =
                   WS-DISCOUNT-AMOUNT +
                   (WS-RATED-PREMIUM * WS-MULTI-CAR-DISC-PCT)
               STRING 'MC ' DELIMITED BY SIZE
                   INTO WS-FACTORS-STRING
                   WITH POINTER WS-FACTOR-POS
           END-IF

           IF RR-MULTI-POLICY
               COMPUTE WS-DISCOUNT-AMOUNT ROUNDED =
                   WS-DISCOUNT-AMOUNT +
                   (WS-RATED-PREMIUM * WS-MULTI-POL-DISC-PCT)
               STRING 'MP ' DELIMITED BY SIZE
                   INTO WS-FACTORS-STRING
                   WITH POINTER WS-FACTOR-POS
           END-IF

           IF RR-GOOD-STUDENT
               COMPUTE WS-DISCOUNT-AMOUNT ROUNDED =
                   WS-DISCOUNT-AMOUNT +
                   (WS-RATED-PREMIUM * WS-GOOD-STUDENT-DISC-PCT)
               STRING 'GS ' DELIMITED BY SIZE
                   INTO WS-FACTORS-STRING
                   WITH POINTER WS-FACTOR-POS
           END-IF

           IF RR-SAFE-DRIVER
               COMPUTE WS-DISCOUNT-AMOUNT ROUNDED =
                   WS-DISCOUNT-AMOUNT +
                   (WS-RATED-PREMIUM * WS-SAFE-DRIVER-DISC-PCT)
               STRING 'SD ' DELIMITED BY SIZE
                   INTO WS-FACTORS-STRING
                   WITH POINTER WS-FACTOR-POS
           END-IF

      *    Cap discount at maximum percentage
           IF WS-DISCOUNT-AMOUNT >
              (WS-RATED-PREMIUM * WS-MAX-DISCOUNT-PCT)
               COMPUTE WS-DISCOUNT-AMOUNT ROUNDED =
                   WS-RATED-PREMIUM * WS-MAX-DISCOUNT-PCT
           END-IF
           .

The discount cap is a regulatory requirement: insurance regulators typically limit the total discount that can be applied to prevent premiums from falling below actuarially sound levels. The WS-FACTORS-STRING field accumulates two-character codes (MC, MP, GS, SD) that record which discounts were applied. This provides an audit trail for regulatory examinations and makes it easy to explain to a policyholder why their premium is what it is.

35.3.5 State Minimum and Maximum Premiums

Every state sets minimum and maximum premiums for each line of insurance. These limits prevent insurers from charging too little (which would indicate insufficient rates to pay claims) or too much (which would constitute price gouging). The state limit enforcement from Example 02 is straightforward:

       3800-APPLY-STATE-LIMITS.
      * Enforce state minimum and maximum premium rules.
           MOVE 00000.00 TO WS-STATE-MIN
           MOVE 99999.99 TO WS-STATE-MAX

           PERFORM VARYING WS-ST-IDX FROM 1 BY 1
               UNTIL WS-ST-IDX > WS-NUM-STATE-ENTRIES
               IF WS-ST-CODE(WS-ST-IDX) = RR-STATE-CODE
                   MOVE WS-ST-MIN-PREM(WS-ST-IDX)
                       TO WS-STATE-MIN
                   MOVE WS-ST-MAX-PREM(WS-ST-IDX)
                       TO WS-STATE-MAX
                   SET WS-ST-IDX TO WS-NUM-STATE-ENTRIES
               END-IF
           END-PERFORM

           IF WS-FINAL-PREMIUM < WS-STATE-MIN
               MOVE WS-STATE-MIN TO WS-FINAL-PREMIUM
           END-IF

           IF WS-FINAL-PREMIUM > WS-STATE-MAX
               MOVE WS-STATE-MAX TO WS-FINAL-PREMIUM
           END-IF
           .

If the calculated premium falls below the state minimum, it is raised to the minimum. If it exceeds the state maximum, it is reduced to the maximum. These adjustments must be recorded in the audit trail, because regulators frequently review cases where minimum or maximum premiums were applied.


35.4 Claims Processing Workflows

35.4.1 The Claims Lifecycle

Claims processing is the most complex workflow in insurance. A claim begins when a policyholder reports a loss (a car accident, a house fire, a medical procedure) and progresses through multiple stages: first notice of loss, investigation, coverage verification, damage assessment, reserve estimation, negotiation, payment, and closure. Some claims close within days; complex liability claims may remain open for years.

The following COBOL data structure represents a typical claims master record:

       01  CLAIMS-MASTER-RECORD.
           05  CL-CLAIM-NUMBER           PIC X(15).
           05  CL-POLICY-NUMBER          PIC X(12).
           05  CL-CLAIM-STATUS           PIC X(02).
               88  CL-STATUS-OPEN        VALUE 'OP'.
               88  CL-STATUS-PENDING     VALUE 'PN'.
               88  CL-STATUS-APPROVED    VALUE 'AP'.
               88  CL-STATUS-DENIED      VALUE 'DN'.
               88  CL-STATUS-CLOSED      VALUE 'CL'.
               88  CL-STATUS-REOPENED    VALUE 'RO'.
               88  CL-STATUS-LITIGATION  VALUE 'LT'.
           05  CL-LINE-OF-BUSINESS       PIC X(03).
           05  CL-LOSS-DATE              PIC 9(08).
           05  CL-REPORT-DATE            PIC 9(08).
           05  CL-CLOSE-DATE             PIC 9(08).
           05  CL-LOSS-TYPE-CODE         PIC X(04).
           05  CL-LOSS-DESCRIPTION       PIC X(80).
           05  CL-CLAIMANT-INFO.
               10  CL-CLAIMANT-NAME      PIC X(40).
               10  CL-CLAIMANT-PHONE     PIC X(10).
               10  CL-CLAIMANT-RELATION  PIC X(02).
                   88  CL-INSURED         VALUE 'IN'.
                   88  CL-SPOUSE          VALUE 'SP'.
                   88  CL-THIRD-PARTY     VALUE 'TP'.
           05  CL-ADJUSTER-CODE          PIC X(08).
           05  CL-FINANCIAL-DATA.
               10  CL-RESERVE-AMOUNT     PIC 9(09)V99.
               10  CL-PAID-AMOUNT        PIC 9(09)V99.
               10  CL-RECOVERED-AMOUNT   PIC 9(09)V99.
               10  CL-DEDUCTIBLE-APPLIED PIC 9(07)V99.
               10  CL-COVERAGE-LIMIT     PIC 9(09)V99.
           05  CL-PAYMENT-COUNT          PIC 9(03).
           05  CL-LAST-ACTIVITY-DATE     PIC 9(08).
           05  CL-LITIGATION-FLAG        PIC X(01).
               88  CL-IN-LITIGATION      VALUE 'Y'.
           05  CL-FRAUD-FLAG             PIC X(01).
               88  CL-FRAUD-SUSPECTED    VALUE 'Y'.
           05  CL-CATASTROPHE-CODE       PIC X(06).
           05  FILLER                    PIC X(98).

The financial fields in the claims record deserve explanation:

  • CL-RESERVE-AMOUNT: The estimated total cost of the claim. Reserves are set when a claim is opened and adjusted as more information becomes available. Aggregate reserves directly affect the company's financial statements.
  • CL-PAID-AMOUNT: The total amount paid to date on the claim, including all partial payments.
  • CL-RECOVERED-AMOUNT: Money recovered through subrogation (recovering from the at-fault party) or salvage (selling damaged property).
  • CL-DEDUCTIBLE-APPLIED: The portion of the loss borne by the policyholder.
  • CL-COVERAGE-LIMIT: The maximum the insurer will pay on this claim, drawn from the policy's coverage terms.

35.4.2 Claims Payment Processing

Claims payments are typically processed in batch, with payments accumulated during the day and released in a nightly payment run. The following program demonstrates a claims payment batch process:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  CLMPAYMT.
      *================================================================*
      * CLAIMS PAYMENT BATCH PROCESSING                                 *
      * Reads approved payment transactions, validates against          *
      * claims master and policy master, issues payments, and           *
      * updates reserves.                                               *
      *================================================================*

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  WS-PAYMENT-WORK.
           05  WS-NET-PAYMENT            PIC 9(09)V99.
           05  WS-REMAINING-RESERVE      PIC 9(09)V99.
           05  WS-TOTAL-PAID-TO-DATE     PIC 9(09)V99.
           05  WS-COVERAGE-REMAINING     PIC 9(09)V99.

       PROCEDURE DIVISION.

       3000-PROCESS-PAYMENT.
      *    Validate the claim exists and is open
           MOVE PT-CLAIM-NUMBER TO CL-CLAIM-NUMBER
           READ CLAIMS-MASTER
               INVALID KEY
                   MOVE 'CLAIM NOT FOUND' TO WS-ERROR-MSG
                   PERFORM 8000-WRITE-ERROR
                   GO TO 3000-EXIT
           END-READ

           IF NOT CL-STATUS-OPEN AND
              NOT CL-STATUS-APPROVED AND
              NOT CL-STATUS-REOPENED
               MOVE 'CLAIM NOT IN PAYABLE STATUS'
                   TO WS-ERROR-MSG
               PERFORM 8000-WRITE-ERROR
               GO TO 3000-EXIT
           END-IF

      *    Check coverage limit
           COMPUTE WS-TOTAL-PAID-TO-DATE =
               CL-PAID-AMOUNT + PT-PAYMENT-AMOUNT
           COMPUTE WS-COVERAGE-REMAINING =
               CL-COVERAGE-LIMIT - CL-PAID-AMOUNT

           IF PT-PAYMENT-AMOUNT > WS-COVERAGE-REMAINING
               MOVE WS-COVERAGE-REMAINING
                   TO WS-NET-PAYMENT
           ELSE
               MOVE PT-PAYMENT-AMOUNT
                   TO WS-NET-PAYMENT
           END-IF

      *    Apply deductible on first payment
           IF CL-PAYMENT-COUNT = 0 AND
              CL-DEDUCTIBLE-APPLIED = 0
               IF WS-NET-PAYMENT > PM-DEDUCTIBLE-AMT
                   SUBTRACT PM-DEDUCTIBLE-AMT
                       FROM WS-NET-PAYMENT
                   MOVE PM-DEDUCTIBLE-AMT
                       TO CL-DEDUCTIBLE-APPLIED
               ELSE
                   MOVE WS-NET-PAYMENT
                       TO CL-DEDUCTIBLE-APPLIED
                   MOVE 0 TO WS-NET-PAYMENT
               END-IF
           END-IF

      *    Update claim record
           ADD WS-NET-PAYMENT TO CL-PAID-AMOUNT
           ADD 1 TO CL-PAYMENT-COUNT

      *    Adjust reserve downward by payment amount
           IF CL-RESERVE-AMOUNT > WS-NET-PAYMENT
               SUBTRACT WS-NET-PAYMENT FROM CL-RESERVE-AMOUNT
           ELSE
               MOVE 0 TO CL-RESERVE-AMOUNT
           END-IF

           MOVE WS-CURRENT-DATE TO CL-LAST-ACTIVITY-DATE

           REWRITE CLAIMS-MASTER-RECORD
           .
       3000-EXIT.
           EXIT
           .

This payment processing logic enforces several business rules that are common across the insurance industry. The coverage limit check ensures that total payments on a claim never exceed the policy's coverage amount. The deductible is applied on the first payment, reducing the amount the insurer actually pays. The reserve is reduced by the payment amount, keeping the claim's financial picture accurate.


35.5 Actuarial Computations in COBOL

35.5.1 Loss Ratio Calculations

Actuaries evaluate the performance of an insurance portfolio by computing loss ratios -- the ratio of claims paid to premiums earned. A loss ratio above 1.0 means the company is paying more in claims than it is collecting in premiums, which is unsustainable.

The following COBOL code computes loss ratios by line of business:

       01  WS-LOSS-RATIO-TABLE.
           05  WS-LR-ENTRY OCCURS 5 TIMES.
               10  WS-LR-LOB            PIC X(03).
               10  WS-LR-EARNED-PREM    PIC 9(11)V99.
               10  WS-LR-INCURRED-LOSS  PIC 9(11)V99.
               10  WS-LR-LOSS-RATIO     PIC 9(01)V9999.
               10  WS-LR-EXPENSE-RATIO  PIC 9(01)V9999.
               10  WS-LR-COMBINED-RATIO PIC 9(01)V9999.

       5000-CALCULATE-LOSS-RATIOS.
           PERFORM VARYING WS-LR-IDX FROM 1 BY 1
               UNTIL WS-LR-IDX > 5
               IF WS-LR-EARNED-PREM(WS-LR-IDX) > 0
                   COMPUTE WS-LR-LOSS-RATIO(WS-LR-IDX) ROUNDED =
                       WS-LR-INCURRED-LOSS(WS-LR-IDX) /
                       WS-LR-EARNED-PREM(WS-LR-IDX)

                   COMPUTE WS-LR-COMBINED-RATIO(WS-LR-IDX)
                       ROUNDED =
                       WS-LR-LOSS-RATIO(WS-LR-IDX) +
                       WS-LR-EXPENSE-RATIO(WS-LR-IDX)
               ELSE
                   MOVE 0 TO WS-LR-LOSS-RATIO(WS-LR-IDX)
                   MOVE 0 TO WS-LR-COMBINED-RATIO(WS-LR-IDX)
               END-IF
           END-PERFORM
           .

The combined ratio -- loss ratio plus expense ratio -- is the single most important metric in property and casualty insurance. A combined ratio below 1.0 indicates underwriting profit; above 1.0 indicates underwriting loss. These calculations appear in quarterly financial statements, regulatory filings, and reinsurance treaty renewals.

35.5.2 Reserve Development Triangles

Loss reserve development is a core actuarial process. Actuaries track how reserves change over time using a triangular matrix where each row represents an accident year and each column represents a development period. COBOL is well-suited to constructing these triangles because of its two-dimensional table capabilities:

       01  WS-LOSS-TRIANGLE.
           05  WS-ACCIDENT-YEAR OCCURS 10 TIMES.
               10  WS-DEV-PERIOD OCCURS 10 TIMES.
                   15  WS-CUMULATIVE-PAID  PIC 9(11)V99.
                   15  WS-CUMULATIVE-INCUR PIC 9(11)V99.
                   15  WS-DEV-FACTOR       PIC 9(03)V9999.

       01  WS-TRIANGLE-WORK.
           05  WS-AY-IDX                 PIC 9(02).
           05  WS-DP-IDX                 PIC 9(02).
           05  WS-IBNR-RESERVE           PIC 9(11)V99.
           05  WS-ULTIMATE-LOSS          PIC 9(11)V99.

       5500-CALCULATE-DEVELOPMENT-FACTORS.
      *    Compute age-to-age development factors
           PERFORM VARYING WS-DP-IDX FROM 1 BY 1
               UNTIL WS-DP-IDX > 9
               MOVE 0 TO WS-FACTOR-SUM
               MOVE 0 TO WS-FACTOR-COUNT

               PERFORM VARYING WS-AY-IDX FROM 1 BY 1
                   UNTIL WS-AY-IDX > (10 - WS-DP-IDX)
                   IF WS-CUMULATIVE-PAID(WS-AY-IDX,
                      WS-DP-IDX) > 0
                       COMPUTE WS-DEV-FACTOR(WS-AY-IDX,
                           WS-DP-IDX) ROUNDED =
                           WS-CUMULATIVE-PAID(WS-AY-IDX,
                               WS-DP-IDX + 1) /
                           WS-CUMULATIVE-PAID(WS-AY-IDX,
                               WS-DP-IDX)
                       ADD WS-DEV-FACTOR(WS-AY-IDX,
                           WS-DP-IDX) TO WS-FACTOR-SUM
                       ADD 1 TO WS-FACTOR-COUNT
                   END-IF
               END-PERFORM
           END-PERFORM
           .

The development factor calculation is fundamental to actuarial science. By analyzing how claims develop over time (mature), actuaries can project the ultimate cost of claims that have been reported but not yet fully settled, and estimate reserves for claims that have been incurred but not yet reported (IBNR). These calculations, performed in COBOL batch programs, directly determine the reserves that appear on the company's balance sheet.


35.6 Batch Processing Patterns in Insurance

35.6.1 The Insurance Batch Cycle

Insurance companies rely on extensive batch processing to manage their operations. The typical nightly batch cycle includes:

  1. Transaction intake: Loading transactions from agents, web portals, and call centers
  2. Validation: Editing and validating all input transactions
  3. Policy processing: Applying new business, endorsements, renewals, and cancellations
  4. Premium billing: Generating invoices and processing payments
  5. Claims processing: Processing new claims, payments, and reserve changes
  6. Commission calculation: Computing agent commissions
  7. Reporting: Generating management reports and regulatory filings

The JCL for Example 01 shows a typical batch job stream for policy administration:

//POLIADMN JOB (ACCT),'POLICY ADMIN',CLASS=A,MSGCLASS=X,
//         MSGLEVEL=(1,1),NOTIFY=&SYSUID
//*================================================================*
//* INSURANCE POLICY ADMINISTRATION SYSTEM                          *
//* EXAMPLE 01 - CHAPTER 35                                         *
//*                                                                 *
//* STEP 1: SORT TRANSACTION FILE BY POLICY NUMBER                  *
//* STEP 2: BACKUP POLICY MASTER FILE                               *
//* STEP 3: RUN POLICY ADMINISTRATION PROGRAM                       *
//*================================================================*
//*
//*------------------------------------------------------------*
//* STEP 1: SORT TRANSACTIONS BY POLICY NUMBER                  *
//*------------------------------------------------------------*
//SORT     EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=INSUR.DAILY.TRANS.INPUT,DISP=SHR
//SORTOUT  DD DSN=&&SORTRANS,DISP=(NEW,PASS),
//            SPACE=(CYL,(5,2)),
//            DCB=(RECFM=FB,LRECL=300,BLKSIZE=27000)
//SORTWK01 DD SPACE=(CYL,(10,5))
//SORTWK02 DD SPACE=(CYL,(10,5))
//SORTWK03 DD SPACE=(CYL,(10,5))
//SYSIN    DD *
  SORT FIELDS=(3,12,CH,A)
  INCLUDE COND=(1,2,CH,EQ,C'CR',OR,
                1,2,CH,EQ,C'MD',OR,
                1,2,CH,EQ,C'RN',OR,
                1,2,CH,EQ,C'CN')
/*
//*
//*------------------------------------------------------------*
//* STEP 2: BACKUP POLICY MASTER BEFORE PROCESSING              *
//*------------------------------------------------------------*
//BACKUP   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  REPRO INFILE(INDD) OUTFILE(OUTDD)
/*
//INDD     DD DSN=INSUR.POLICY.MASTER,DISP=SHR
//OUTDD    DD DSN=INSUR.POLICY.MASTER.BACKUP,
//            DISP=(NEW,CATLG,DELETE),
//            SPACE=(CYL,(50,10)),
//            DCB=(RECFM=FB,LRECL=500,BLKSIZE=27500)
//*
//*------------------------------------------------------------*
//* STEP 3: RUN POLICY ADMINISTRATION PROGRAM                   *
//*------------------------------------------------------------*
//POLIADM  EXEC PGM=POLIADMN,REGION=64M
//STEPLIB  DD DSN=INSUR.PROD.LOADLIB,DISP=SHR
//POLMAST  DD DSN=INSUR.POLICY.MASTER,DISP=OLD
//TRANSIN  DD DSN=&&SORTRANS,DISP=(OLD,DELETE)
//AUDITRPT DD DSN=INSUR.DAILY.POLIADM.AUDIT,
//            DISP=(NEW,CATLG,DELETE),
//            SPACE=(CYL,(2,1)),
//            DCB=(RECFM=FB,LRECL=132,BLKSIZE=27984)
//ERRRPT   DD DSN=INSUR.DAILY.POLIADM.ERRORS,
//            DISP=(NEW,CATLG,DELETE),
//            SPACE=(CYL,(1,1)),
//            DCB=(RECFM=FB,LRECL=132,BLKSIZE=27984)
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//*
//*------------------------------------------------------------*
//* STEP 4: PRINT AUDIT REPORT                                  *
//*------------------------------------------------------------*
//PRINT    EXEC PGM=IEBGENER
//SYSUT1   DD DSN=INSUR.DAILY.POLIADM.AUDIT,DISP=SHR
//SYSUT2   DD SYSOUT=*,DCB=(RECFM=FBA,LRECL=133)
//SYSIN    DD DUMMY
//SYSPRINT DD SYSOUT=*
//

This JCL stream illustrates several important batch processing practices discussed in Chapter 28:

Pre-sort of transactions: The SORT step sorts transactions by policy number and filters for valid transaction types. Sorting by policy number is essential when the COBOL program accesses the VSAM master file in key sequence, which provides optimal I/O performance.

Backup before update: The IDCAMS REPRO step creates a complete backup of the policy master file before any updates are applied. If the update job fails halfway through, the backup allows the operations team to restore the master file to its pre-run state and reprocess.

DISP=OLD for exclusive access: The POLMAST DD statement specifies DISP=OLD, which grants the job exclusive access to the policy master file. This prevents any other job from reading or writing the file during processing, ensuring data integrity.

Temporary dataset for sorted transactions: The sorted transaction file uses a temporary dataset name (&&SORTRANS), which is automatically deleted when the job completes. This avoids cluttering the catalog with intermediate files.

35.6.2 Checkpoint and Restart

Long-running batch jobs in insurance often implement checkpoint and restart logic. If a job that is processing 500,000 renewal transactions fails after processing 300,000, the operations team should be able to restart at transaction 300,001 rather than reprocessing the entire file. The following pattern shows a basic checkpoint mechanism:

       01  WS-CHECKPOINT-FIELDS.
           05  WS-CHECKPOINT-INTERVAL    PIC 9(05) VALUE 10000.
           05  WS-RECORDS-SINCE-CKPT     PIC 9(05) VALUE 0.
           05  WS-LAST-KEY-PROCESSED     PIC X(12).
           05  WS-CHECKPOINT-COUNT       PIC 9(03) VALUE 0.

       2000-PROCESS-TRANSACTIONS.
           ADD 1 TO WS-RECORDS-SINCE-CKPT

           IF WS-RECORDS-SINCE-CKPT >= WS-CHECKPOINT-INTERVAL
               PERFORM 2500-TAKE-CHECKPOINT
               MOVE 0 TO WS-RECORDS-SINCE-CKPT
           END-IF

           MOVE TR-POLICY-NUMBER TO WS-LAST-KEY-PROCESSED
           .

       2500-TAKE-CHECKPOINT.
           ADD 1 TO WS-CHECKPOINT-COUNT
           DISPLAY 'CHECKPOINT ' WS-CHECKPOINT-COUNT
                   ' AT RECORD ' WS-TRANS-READ
                   ' KEY: ' WS-LAST-KEY-PROCESSED

      *    In production, this would write a checkpoint
      *    record to a VSAM file or DB2 table and
      *    commit any pending database changes.
           .

Every 10,000 records, the program records the last key processed. On restart, the program reads the checkpoint file, positions the input file to the next record after the checkpoint, and resumes processing. This pattern is critical for large-scale insurance batch processing where job windows are tight and reruns are expensive.


35.7 Government Benefits Administration

35.7.1 The Scale of Government Systems

The federal government operates some of the largest COBOL systems in the world. The Social Security Administration processes benefits for over 70 million Americans. The Internal Revenue Service processes more than 150 million individual tax returns annually. The Centers for Medicare and Medicaid Services administers health coverage for over 150 million people. State governments run their own massive COBOL systems for unemployment insurance, motor vehicle registration, and vital records.

These systems share characteristics that make COBOL an ideal fit:

  • Rule-based processing: Government benefits are determined by statutes that encode complex eligibility rules. COBOL's verbose, explicit syntax maps naturally to statutory language.
  • Audit requirements: Government systems must maintain complete audit trails. Every decision -- why a benefit was approved, denied, or adjusted -- must be documented and traceable.
  • Massive volumes: Government agencies process transactions measured in the hundreds of millions. Batch processing with COBOL and JCL is the proven approach for these volumes.
  • Extreme reliability: Government payment systems cannot fail. Missing a Social Security payment can leave a retiree unable to pay rent. These systems must run without interruption, month after month, year after year.

35.7.2 Social Security Benefit Calculation

Social Security benefits are calculated using a formula defined by federal law. The computation involves determining a worker's Average Indexed Monthly Earnings (AIME) based on their highest 35 years of earnings, then applying a progressive benefit formula to produce the Primary Insurance Amount (PIA).

The following COBOL program demonstrates the PIA calculation:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  SSACALC.
      *================================================================*
      * SOCIAL SECURITY BENEFIT CALCULATION                             *
      * Computes Primary Insurance Amount (PIA) from earnings history.  *
      * Implements the SSA benefit formula with bend points.            *
      *================================================================*

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  WS-EARNINGS-HISTORY.
           05  WS-ANNUAL-EARNINGS OCCURS 45 TIMES.
               10  WS-EARN-YEAR          PIC 9(04).
               10  WS-EARN-AMOUNT        PIC 9(07)V99.
               10  WS-EARN-INDEX-FACTOR  PIC 9(02)V9999.
               10  WS-INDEXED-EARNINGS   PIC 9(09)V99.
           05  WS-YEARS-OF-EARNINGS      PIC 9(02).

       01  WS-BENEFIT-CALCULATION.
           05  WS-TOP-35-TOTAL           PIC 9(11)V99.
           05  WS-AIME                   PIC 9(05)V99.
           05  WS-PIA-AMOUNT             PIC 9(05)V99.
           05  WS-MONTHLY-BENEFIT        PIC 9(05)V99.

      *    2024 Bend Points (adjusted annually for wage growth)
       01  WS-BEND-POINTS.
           05  WS-BEND-POINT-1           PIC 9(05)V99
                                          VALUE 01174.00.
           05  WS-BEND-POINT-2           PIC 9(05)V99
                                          VALUE 07078.00.
           05  WS-PIA-FACTOR-1           PIC 9V9999
                                          VALUE 0.9000.
           05  WS-PIA-FACTOR-2           PIC 9V9999
                                          VALUE 0.3200.
           05  WS-PIA-FACTOR-3           PIC 9V9999
                                          VALUE 0.1500.

       01  WS-SORT-WORK.
           05  WS-SORT-TEMP              PIC 9(09)V99.
           05  WS-SORT-I                 PIC 9(02).
           05  WS-SORT-J                 PIC 9(02).
           05  WS-SORTED-EARNINGS        PIC 9(09)V99
                                          OCCURS 45 TIMES.

       01  WS-PIA-WORK.
           05  WS-PIA-TIER-1             PIC 9(05)V99.
           05  WS-PIA-TIER-2             PIC 9(05)V99.
           05  WS-PIA-TIER-3             PIC 9(05)V99.
           05  WS-REMAINING-AIME         PIC 9(05)V99.

       PROCEDURE DIVISION.

       1000-CALCULATE-PIA.
      *    Step 1: Index earnings to account for wage growth
           PERFORM 1100-INDEX-EARNINGS

      *    Step 2: Select highest 35 years of indexed earnings
           PERFORM 1200-SELECT-TOP-35

      *    Step 3: Calculate AIME
           COMPUTE WS-AIME ROUNDED =
               WS-TOP-35-TOTAL / 420
      *        (35 years x 12 months = 420 months)

      *    Step 4: Apply PIA formula with bend points
           PERFORM 1300-APPLY-BEND-POINTS

      *    Step 5: Round PIA down to next lower dime
           COMPUTE WS-PIA-AMOUNT =
               FUNCTION INTEGER(WS-PIA-AMOUNT * 10) / 10

           MOVE WS-PIA-AMOUNT TO WS-MONTHLY-BENEFIT
           .

       1100-INDEX-EARNINGS.
      *    Multiply each year's earnings by the indexing factor
      *    to adjust for wage growth since that year.
           PERFORM VARYING WS-SORT-I FROM 1 BY 1
               UNTIL WS-SORT-I > WS-YEARS-OF-EARNINGS
               COMPUTE WS-INDEXED-EARNINGS(WS-SORT-I) ROUNDED =
                   WS-EARN-AMOUNT(WS-SORT-I) *
                   WS-EARN-INDEX-FACTOR(WS-SORT-I)
           END-PERFORM
           .

       1200-SELECT-TOP-35.
      *    Sort indexed earnings in descending order
      *    and sum the top 35 years.
           PERFORM VARYING WS-SORT-I FROM 1 BY 1
               UNTIL WS-SORT-I > WS-YEARS-OF-EARNINGS
               MOVE WS-INDEXED-EARNINGS(WS-SORT-I)
                   TO WS-SORTED-EARNINGS(WS-SORT-I)
           END-PERFORM

      *    Simple bubble sort (small table)
           PERFORM VARYING WS-SORT-I FROM 1 BY 1
               UNTIL WS-SORT-I >= WS-YEARS-OF-EARNINGS
               PERFORM VARYING WS-SORT-J FROM 1 BY 1
                   UNTIL WS-SORT-J >=
                       WS-YEARS-OF-EARNINGS
                   IF WS-SORTED-EARNINGS(WS-SORT-J) <
                      WS-SORTED-EARNINGS(WS-SORT-J + 1)
                       MOVE WS-SORTED-EARNINGS(WS-SORT-J)
                           TO WS-SORT-TEMP
                       MOVE WS-SORTED-EARNINGS(
                           WS-SORT-J + 1)
                           TO WS-SORTED-EARNINGS(WS-SORT-J)
                       MOVE WS-SORT-TEMP
                           TO WS-SORTED-EARNINGS(
                               WS-SORT-J + 1)
                   END-IF
               END-PERFORM
           END-PERFORM

      *    Sum the top 35 years
           MOVE 0 TO WS-TOP-35-TOTAL
           PERFORM VARYING WS-SORT-I FROM 1 BY 1
               UNTIL WS-SORT-I > 35 OR
                     WS-SORT-I > WS-YEARS-OF-EARNINGS
               ADD WS-SORTED-EARNINGS(WS-SORT-I)
                   TO WS-TOP-35-TOTAL
           END-PERFORM
           .

       1300-APPLY-BEND-POINTS.
      *    The PIA formula is progressive:
      *    90% of AIME up to first bend point
      *    32% of AIME between first and second bend points
      *    15% of AIME above second bend point

           MOVE 0 TO WS-PIA-TIER-1
                     WS-PIA-TIER-2
                     WS-PIA-TIER-3

           IF WS-AIME <= WS-BEND-POINT-1
               COMPUTE WS-PIA-TIER-1 ROUNDED =
                   WS-AIME * WS-PIA-FACTOR-1
           ELSE
               COMPUTE WS-PIA-TIER-1 ROUNDED =
                   WS-BEND-POINT-1 * WS-PIA-FACTOR-1

               COMPUTE WS-REMAINING-AIME =
                   WS-AIME - WS-BEND-POINT-1

               IF WS-REMAINING-AIME <=
                  (WS-BEND-POINT-2 - WS-BEND-POINT-1)
                   COMPUTE WS-PIA-TIER-2 ROUNDED =
                       WS-REMAINING-AIME *
                       WS-PIA-FACTOR-2
               ELSE
                   COMPUTE WS-PIA-TIER-2 ROUNDED =
                       (WS-BEND-POINT-2 -
                        WS-BEND-POINT-1) *
                       WS-PIA-FACTOR-2
                   COMPUTE WS-PIA-TIER-3 ROUNDED =
                       (WS-AIME - WS-BEND-POINT-2) *
                       WS-PIA-FACTOR-3
               END-IF
           END-IF

           COMPUTE WS-PIA-AMOUNT ROUNDED =
               WS-PIA-TIER-1 +
               WS-PIA-TIER-2 +
               WS-PIA-TIER-3
           .

The Social Security PIA formula is a classic example of government-mandated computation that must be implemented exactly as specified in law. The three-tier progressive formula -- 90 percent of the first $1,174 of AIME, 32 percent of AIME between $1,174 and $7,078, and 15 percent of AIME above $7,078 (using 2024 bend points) -- cannot be approximated or rounded differently than the statute prescribes. The final PIA is rounded down to the next lower dime, not rounded to the nearest cent. This kind of specific rounding rule is common in government systems and is naturally expressed in COBOL.

35.7.3 Benefits Eligibility Determination

Government benefit programs require complex eligibility logic. A typical program must evaluate income, family size, age, disability status, citizenship, residency, and dozens of other criteria. The following code illustrates eligibility determination for a government benefits program:

       01  WS-ELIGIBILITY-RECORD.
           05  WS-ELIG-APPLICANT-ID      PIC X(10).
           05  WS-ELIG-AGE               PIC 9(03).
           05  WS-ELIG-HOUSEHOLD-SIZE    PIC 9(02).
           05  WS-ELIG-MONTHLY-INCOME    PIC 9(07)V99.
           05  WS-ELIG-ASSETS            PIC 9(09)V99.
           05  WS-ELIG-CITIZENSHIP       PIC X(01).
               88  WS-US-CITIZEN         VALUE 'C'.
               88  WS-LEGAL-RESIDENT     VALUE 'R'.
               88  WS-NON-CITIZEN        VALUE 'N'.
           05  WS-ELIG-DISABILITY-FLAG   PIC X(01).
               88  WS-DISABLED           VALUE 'Y'.
           05  WS-ELIG-VETERAN-FLAG      PIC X(01).
               88  WS-VETERAN            VALUE 'Y'.
           05  WS-ELIG-STATE-CODE        PIC X(02).

       01  WS-ELIG-RESULT.
           05  WS-ELIGIBLE-FLAG          PIC X(01).
               88  WS-IS-ELIGIBLE        VALUE 'Y'.
               88  WS-NOT-ELIGIBLE       VALUE 'N'.
           05  WS-DENIAL-REASON          PIC X(04).
               88  WS-DENY-INCOME        VALUE 'INC '.
               88  WS-DENY-ASSETS        VALUE 'ASST'.
               88  WS-DENY-CITIZEN       VALUE 'CTZN'.
               88  WS-DENY-AGE           VALUE 'AGE '.
           05  WS-BENEFIT-AMOUNT         PIC 9(05)V99.

      *    Federal Poverty Level table (monthly, by household size)
       01  WS-FPL-TABLE.
           05  FILLER PIC 9(07)V99 VALUE 01255.00.
           05  FILLER PIC 9(07)V99 VALUE 01703.33.
           05  FILLER PIC 9(07)V99 VALUE 02151.67.
           05  FILLER PIC 9(07)V99 VALUE 02600.00.
           05  FILLER PIC 9(07)V99 VALUE 03048.33.
           05  FILLER PIC 9(07)V99 VALUE 03496.67.
           05  FILLER PIC 9(07)V99 VALUE 03945.00.
           05  FILLER PIC 9(07)V99 VALUE 04393.33.
       01  WS-FPL-TBL REDEFINES WS-FPL-TABLE.
           05  WS-FPL-AMOUNT PIC 9(07)V99 OCCURS 8 TIMES.

       01  WS-INCOME-LIMIT              PIC 9(07)V99.
       01  WS-ASSET-LIMIT               PIC 9(09)V99
                                          VALUE 2000.00.
       01  WS-ASSET-LIMIT-DISABLED      PIC 9(09)V99
                                          VALUE 3500.00.

       4000-DETERMINE-ELIGIBILITY.
           SET WS-IS-ELIGIBLE TO TRUE
           MOVE SPACES TO WS-DENIAL-REASON

      *    Rule 1: Citizenship requirement
           IF WS-NON-CITIZEN
               SET WS-NOT-ELIGIBLE TO TRUE
               SET WS-DENY-CITIZEN TO TRUE
               GO TO 4000-EXIT
           END-IF

      *    Rule 2: Income test (130% of Federal Poverty Level)
           IF WS-ELIG-HOUSEHOLD-SIZE > 0 AND
              WS-ELIG-HOUSEHOLD-SIZE <= 8
               COMPUTE WS-INCOME-LIMIT ROUNDED =
                   WS-FPL-AMOUNT(WS-ELIG-HOUSEHOLD-SIZE)
                   * 1.30
           ELSE
               COMPUTE WS-INCOME-LIMIT ROUNDED =
                   WS-FPL-AMOUNT(8) +
                   ((WS-ELIG-HOUSEHOLD-SIZE - 8) *
                    448.33 * 1.30)
           END-IF

           IF WS-ELIG-MONTHLY-INCOME > WS-INCOME-LIMIT
               SET WS-NOT-ELIGIBLE TO TRUE
               SET WS-DENY-INCOME TO TRUE
               GO TO 4000-EXIT
           END-IF

      *    Rule 3: Asset test
           IF WS-DISABLED
               IF WS-ELIG-ASSETS > WS-ASSET-LIMIT-DISABLED
                   SET WS-NOT-ELIGIBLE TO TRUE
                   SET WS-DENY-ASSETS TO TRUE
                   GO TO 4000-EXIT
               END-IF
           ELSE
               IF WS-ELIG-ASSETS > WS-ASSET-LIMIT
                   SET WS-NOT-ELIGIBLE TO TRUE
                   SET WS-DENY-ASSETS TO TRUE
                   GO TO 4000-EXIT
               END-IF
           END-IF

      *    Rule 4: Calculate benefit amount
           PERFORM 4100-CALCULATE-BENEFIT
           .
       4000-EXIT.
           EXIT
           .

       4100-CALCULATE-BENEFIT.
      *    Benefit amount is the difference between the
      *    income limit and the household's countable income,
      *    divided by a state-specific factor.
           COMPUTE WS-BENEFIT-AMOUNT ROUNDED =
               (WS-INCOME-LIMIT - WS-ELIG-MONTHLY-INCOME)
               * 0.30

           IF WS-BENEFIT-AMOUNT < 23.00
               MOVE 23.00 TO WS-BENEFIT-AMOUNT
           END-IF
           .

This eligibility determination code demonstrates several patterns common in government COBOL systems. The rules are applied in a specific order, with early exits for disqualifying conditions. The Federal Poverty Level table is used to calculate income limits that vary by household size. Asset limits differ for disabled and non-disabled applicants. The minimum benefit amount of $23.00 is a statutory floor. Every one of these rules traces directly to a section of federal or state law, and COBOL's explicit, self-documenting style makes it straightforward for policy analysts and auditors to verify that the program correctly implements the statute.


35.8 Tax Processing Systems

35.8.1 Tax Calculation in COBOL

The Internal Revenue Service and state tax agencies use COBOL extensively for tax return processing. Tax computation involves bracket-based calculations, deduction phaseouts, credit limitations, and alternative minimum tax computations. The following code demonstrates a federal income tax calculation using the bracket structure:

       01  WS-TAX-BRACKETS.
           05  WS-BRACKET OCCURS 7 TIMES.
               10  WS-BRACKET-LOW        PIC 9(07)V99.
               10  WS-BRACKET-HIGH       PIC 9(07)V99.
               10  WS-BRACKET-RATE       PIC 9V9999.
               10  WS-BRACKET-BASE-TAX   PIC 9(07)V99.

       01  WS-TAX-WORK.
           05  WS-TAXABLE-INCOME         PIC 9(09)V99.
           05  WS-GROSS-TAX              PIC 9(09)V99.
           05  WS-TAX-IN-BRACKET         PIC 9(09)V99.
           05  WS-INCOME-IN-BRACKET      PIC 9(09)V99.
           05  WS-BRACKET-IDX            PIC 9(01).

       5000-CALCULATE-FEDERAL-TAX.
           MOVE 0 TO WS-GROSS-TAX

           PERFORM VARYING WS-BRACKET-IDX FROM 1 BY 1
               UNTIL WS-BRACKET-IDX > 7
               IF WS-TAXABLE-INCOME >
                  WS-BRACKET-LOW(WS-BRACKET-IDX)

                   IF WS-TAXABLE-INCOME <=
                      WS-BRACKET-HIGH(WS-BRACKET-IDX)
      *                Income falls within this bracket
                       COMPUTE WS-INCOME-IN-BRACKET =
                           WS-TAXABLE-INCOME -
                           WS-BRACKET-LOW(WS-BRACKET-IDX)
                   ELSE
      *                Income exceeds this bracket
                       COMPUTE WS-INCOME-IN-BRACKET =
                           WS-BRACKET-HIGH(WS-BRACKET-IDX) -
                           WS-BRACKET-LOW(WS-BRACKET-IDX)
                   END-IF

                   COMPUTE WS-TAX-IN-BRACKET ROUNDED =
                       WS-INCOME-IN-BRACKET *
                       WS-BRACKET-RATE(WS-BRACKET-IDX)

                   ADD WS-TAX-IN-BRACKET TO WS-GROSS-TAX
               END-IF
           END-PERFORM
           .

The progressive tax bracket computation iterates through each bracket, calculating the tax owed on the portion of income that falls within that bracket. This pattern parallels the Social Security PIA calculation -- both are progressive formulas mandated by law. The use of ROUNDED on the tax-in-bracket computation ensures proper cent-level precision, a requirement for tax processing as discussed in Chapter 33.

35.8.2 Withholding and Reporting

Government agencies also process employer-submitted W-2 and 1099 forms, matching reported income against tax returns. This matching program pattern is a classic batch COBOL application:

       01  WS-MATCH-COUNTERS.
           05  WS-RETURNS-READ           PIC 9(09) VALUE 0.
           05  WS-W2S-READ              PIC 9(09) VALUE 0.
           05  WS-MATCHED                PIC 9(09) VALUE 0.
           05  WS-UNMATCHED-RETURNS      PIC 9(09) VALUE 0.
           05  WS-UNMATCHED-W2S          PIC 9(09) VALUE 0.
           05  WS-INCOME-DISCREPANCIES   PIC 9(09) VALUE 0.

       01  WS-TOLERANCE-AMOUNT          PIC 9(05)V99
                                          VALUE 50.00.

       6000-MATCH-RETURNS-TO-W2S.
      *    Both files are sorted by SSN.
      *    Classic sequential match-merge pattern.

           EVALUATE TRUE
               WHEN RT-SSN = W2-SSN
      *            Match found - compare income amounts
                   COMPUTE WS-INCOME-DIFF =
                       FUNCTION ABS(
                           RT-WAGES-REPORTED -
                           W2-WAGES-REPORTED)
                   IF WS-INCOME-DIFF > WS-TOLERANCE-AMOUNT
                       ADD 1 TO WS-INCOME-DISCREPANCIES
                       PERFORM 6100-WRITE-DISCREPANCY
                   END-IF
                   ADD 1 TO WS-MATCHED
                   PERFORM 6200-READ-RETURN
                   PERFORM 6300-READ-W2

               WHEN RT-SSN < W2-SSN
      *            Return with no matching W2
                   ADD 1 TO WS-UNMATCHED-RETURNS
                   PERFORM 6400-WRITE-UNMATCHED-RETURN
                   PERFORM 6200-READ-RETURN

               WHEN RT-SSN > W2-SSN
      *            W2 with no matching return
                   ADD 1 TO WS-UNMATCHED-W2S
                   PERFORM 6500-WRITE-UNMATCHED-W2
                   PERFORM 6300-READ-W2
           END-EVALUATE
           .

This sequential match-merge is a foundational batch processing pattern. Both files must be sorted by the same key (SSN in this case). The program compares keys from each file, advances the file with the lower key, and identifies matches, unmatched returns, and unmatched W-2 forms. The IRS uses this technique to identify tax returns where reported income does not match the income reported by employers, triggering correspondence and potential audits. This merge-matching pattern was also covered in the context of banking reconciliation in Chapter 34.


35.9 Regulatory Compliance Reporting

35.9.1 Insurance Regulatory Filings

Insurance companies must file extensive reports with state insurance departments and the National Association of Insurance Commissioners (NAIC). The most important filing is the Annual Statement, a standardized financial report that includes:

  • Balance sheet (assets, liabilities, surplus)
  • Income statement (premiums, losses, expenses)
  • Schedule of investments
  • Loss development triangles by line of business
  • Reinsurance summaries
  • Risk-based capital calculations

COBOL batch programs extract data from policy, claims, billing, and financial systems and format it according to NAIC specifications. The following excerpt shows how a regulatory report line is constructed:

       01  WS-NAIC-SCHEDULE-P.
           05  WS-SP-LINE OCCURS 25 TIMES.
               10  WS-SP-LOB-CODE        PIC X(03).
               10  WS-SP-YEAR            PIC 9(04).
               10  WS-SP-PREM-WRITTEN    PIC S9(11)V99.
               10  WS-SP-PREM-EARNED     PIC S9(11)V99.
               10  WS-SP-LOSS-PAID       PIC S9(11)V99.
               10  WS-SP-LOSS-RESERVE    PIC S9(11)V99.
               10  WS-SP-LOSS-INCURRED   PIC S9(11)V99.
               10  WS-SP-EXPENSE         PIC S9(11)V99.

       7000-GENERATE-SCHEDULE-P.
           PERFORM VARYING WS-SP-IDX FROM 1 BY 1
               UNTIL WS-SP-IDX > 25
               COMPUTE WS-SP-LOSS-INCURRED(WS-SP-IDX) =
                   WS-SP-LOSS-PAID(WS-SP-IDX) +
                   WS-SP-LOSS-RESERVE(WS-SP-IDX)

               MOVE WS-SP-LOB-CODE(WS-SP-IDX)
                   TO WS-RPT-LOB
               MOVE WS-SP-YEAR(WS-SP-IDX)
                   TO WS-RPT-YEAR
               MOVE WS-SP-PREM-EARNED(WS-SP-IDX)
                   TO WS-RPT-EARNED-PREM
               MOVE WS-SP-LOSS-INCURRED(WS-SP-IDX)
                   TO WS-RPT-INCURRED-LOSS

      *        Calculate loss ratio for this line/year
               IF WS-SP-PREM-EARNED(WS-SP-IDX) > 0
                   COMPUTE WS-RPT-LOSS-RATIO ROUNDED =
                       WS-SP-LOSS-INCURRED(WS-SP-IDX) /
                       WS-SP-PREM-EARNED(WS-SP-IDX)
               END-IF

               PERFORM 7100-WRITE-SCHEDULE-P-LINE
           END-PERFORM
           .

Note the use of signed numeric fields (S9(11)V99) in the regulatory report. Incurred losses can be negative in cases where reserves are reduced or subrogation recoveries exceed paid losses. The signed PICTURE clause ensures that negative values are properly represented in the output.

35.9.2 Government Compliance Standards

Government agencies maintain their own extensive compliance frameworks. Programs processing tax data must comply with IRS Publication 1075, which governs the safeguarding of Federal Tax Information (FTI). Programs processing health data must comply with HIPAA. Programs processing benefits data must comply with the Privacy Act of 1974. Each of these frameworks imposes requirements on how data is stored, accessed, transmitted, and logged.

From a COBOL programming perspective, compliance requirements manifest in several concrete coding practices:

Access logging: Every access to a sensitive record must be logged with the user ID, timestamp, record accessed, and action taken. COBOL programs achieve this by writing to an audit file or calling a logging subprogram after every file I/O operation on protected data.

Data masking: When displaying or printing sensitive data, programs must mask all but the last four digits of Social Security numbers, all but the last four digits of account numbers, and all but the last four characters of policy numbers. The following utility paragraph demonstrates this pattern:

       8500-MASK-SSN.
      *    Mask SSN for display: 123-45-6789 -> ***-**-6789
           MOVE '***-**-' TO WS-MASKED-SSN(1:7)
           MOVE WS-RAW-SSN(6:4) TO WS-MASKED-SSN(8:4)
           .

Encryption at rest: Sensitive fields in COBOL files may be encrypted using calls to system encryption services. On z/OS, this typically involves calling the Integrated Cryptographic Service Facility (ICSF) through a COBOL CALL statement.


35.10 HIPAA and Data Privacy Considerations

35.10.1 HIPAA in Insurance Systems

The Health Insurance Portability and Accountability Act (HIPAA) imposes strict requirements on any system that processes Protected Health Information (PHI). Health insurance COBOL systems must comply with both the Privacy Rule (who can access PHI) and the Security Rule (how PHI must be protected).

In COBOL programs, HIPAA compliance affects system design at multiple levels:

Transaction code sets: HIPAA mandates the use of standard electronic transaction formats for health insurance claims (837), remittance advice (835), eligibility inquiries (270/271), and claim status inquiries (276/277). These are ANSI X12 EDI transactions that COBOL programs must generate and parse. A typical 837 claim transaction might contain hundreds of segments, each with specific formatting rules:

       01  WS-837-CLAIM-SEGMENT.
           05  WS-837-SEGMENT-ID         PIC X(03).
           05  WS-837-ELEMENT-SEP        PIC X(01) VALUE '*'.
           05  WS-837-CLAIM-ID           PIC X(20).
           05  WS-837-CHARGE-AMOUNT      PIC 9(07)V99.
           05  WS-837-PLACE-OF-SERVICE   PIC X(02).
           05  WS-837-DIAGNOSIS-CODE     PIC X(08).
           05  WS-837-PROCEDURE-CODE     PIC X(05).
           05  WS-837-MODIFIER           PIC X(02).
           05  WS-837-SERVICE-DATE       PIC 9(08).
           05  WS-837-PROVIDER-NPI       PIC X(10).

       9000-BUILD-837-CLM-SEGMENT.
           MOVE 'CLM' TO WS-837-SEGMENT-ID
           STRING
               WS-837-SEGMENT-ID
               WS-837-ELEMENT-SEP
               WS-837-CLAIM-ID
               WS-837-ELEMENT-SEP
               WS-837-CHARGE-AMOUNT
               WS-837-ELEMENT-SEP
               WS-837-PLACE-OF-SERVICE
               DELIMITED BY SIZE
               INTO WS-OUTPUT-SEGMENT
           .

Minimum necessary standard: HIPAA requires that programs access only the minimum PHI necessary to perform their function. In practice, this means that a COBOL billing program should not read diagnostic codes or treatment details that are irrelevant to billing. System designers enforce this through separate copybooks: a billing copybook exposes only billing-relevant fields, while clinical fields are defined in a separate copybook used only by claims adjudication programs.

Audit trail requirements: HIPAA requires that every access to PHI be logged. Insurance COBOL systems typically implement this through a centralized audit logging subprogram:

       8800-LOG-PHI-ACCESS.
           MOVE WS-USER-ID       TO AL-USER-ID
           MOVE WS-PROGRAM-ID    TO AL-PROGRAM-ID
           MOVE WS-CURRENT-TS    TO AL-TIMESTAMP
           MOVE CL-CLAIM-NUMBER  TO AL-RECORD-KEY
           MOVE 'READ'           TO AL-ACTION-TYPE
           MOVE 'CLAIMS-MASTER'  TO AL-FILE-NAME
           CALL 'AUDITLOG' USING AUDIT-LOG-RECORD
           .

35.10.2 Data Retention and Disposal

Both insurance and government systems must comply with data retention requirements. Insurance policies and claims must be retained for periods ranging from five to thirty years, depending on the line of business and the jurisdiction. Government records have their own retention schedules mandated by the National Archives and Records Administration (NARA).

COBOL batch programs that purge expired records must verify retention requirements before deleting data. A typical purge program checks the record date against the retention period for that record type and writes purged records to an archive file before deletion:

       01  WS-RETENTION-TABLE.
           05  WS-RET-ENTRY OCCURS 10 TIMES.
               10  WS-RET-RECORD-TYPE    PIC X(02).
               10  WS-RET-YEARS          PIC 9(02).

       7500-CHECK-RETENTION.
           PERFORM VARYING WS-RET-IDX FROM 1 BY 1
               UNTIL WS-RET-IDX > 10
               IF WS-RET-RECORD-TYPE(WS-RET-IDX) =
                  WS-RECORD-TYPE
                   COMPUTE WS-RETAIN-UNTIL =
                       FUNCTION INTEGER-OF-DATE(
                           WS-RECORD-DATE) +
                       (WS-RET-YEARS(WS-RET-IDX) * 365)
                   IF FUNCTION INTEGER-OF-DATE(
                       WS-CURRENT-DATE) > WS-RETAIN-UNTIL
                       SET WS-OK-TO-PURGE TO TRUE
                   ELSE
                       SET WS-NOT-OK-TO-PURGE TO TRUE
                   END-IF
                   SET WS-RET-IDX TO 10
               END-IF
           END-PERFORM
           .

35.11 Real-Time Policy Queries

35.11.1 CICS Online Inquiry

While the batch processing described in previous sections handles the high-volume operations, insurance companies also need real-time access to policy and claims information. Customer service representatives, agents, and adjusters need to look up policy details, check claim status, and verify coverage in real time. As discussed in Chapters 24 and 25, CICS provides the online transaction processing environment for these inquiries.

The following CICS program demonstrates a real-time policy inquiry:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  POLINQ.
      *================================================================*
      * ONLINE POLICY INQUIRY - CICS TRANSACTION                        *
      * Retrieves policy information for display on a 3270 terminal     *
      * or a web service request.                                       *
      *================================================================*

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  WS-COMMAREA.
           05  WS-CA-POLICY-NUMBER       PIC X(12).
           05  WS-CA-RETURN-CODE         PIC 9(02).
               88  WS-CA-SUCCESS         VALUE 00.
               88  WS-CA-NOT-FOUND       VALUE 10.
               88  WS-CA-ERROR           VALUE 99.

       01  WS-POLICY-DISPLAY.
           05  WS-PD-POLICY-NUM          PIC X(12).
           05  WS-PD-STATUS              PIC X(10).
           05  WS-PD-INSURED-NAME        PIC X(41).
           05  WS-PD-LOB                 PIC X(12).
           05  WS-PD-EFF-DATE            PIC X(10).
           05  WS-PD-EXP-DATE            PIC X(10).
           05  WS-PD-COVERAGE            PIC $$$,$$$,MATH1$,$$$,$$9.99.
           05  WS-PD-DEDUCTIBLE          PIC $$$,$$9.99.
           05  WS-PD-AGENT              PIC X(08).
           05  WS-PD-CLAIMS-COUNT        PIC ZZ9.

       PROCEDURE DIVISION.

       0000-MAIN.
           EXEC CICS READ
               DATASET('POLMAST')
               INTO(POLICY-MASTER-RECORD)
               RIDFLD(WS-CA-POLICY-NUMBER)
               RESP(WS-CICS-RESP)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   PERFORM 1000-FORMAT-DISPLAY
                   SET WS-CA-SUCCESS TO TRUE
               WHEN DFHRESP(NOTFND)
                   SET WS-CA-NOT-FOUND TO TRUE
               WHEN OTHER
                   SET WS-CA-ERROR TO TRUE
           END-EVALUATE

           EXEC CICS RETURN
               TRANSID('POLQ')
               COMMAREA(WS-COMMAREA)
           END-EXEC
           .

       1000-FORMAT-DISPLAY.
           MOVE PM-POLICY-NUMBER TO WS-PD-POLICY-NUM

           EVALUATE TRUE
               WHEN PM-STATUS-ACTIVE
                   MOVE 'ACTIVE' TO WS-PD-STATUS
               WHEN PM-STATUS-CANCELLED
                   MOVE 'CANCELLED' TO WS-PD-STATUS
               WHEN PM-STATUS-EXPIRED
                   MOVE 'EXPIRED' TO WS-PD-STATUS
               WHEN OTHER
                   MOVE PM-POLICY-STATUS-CODE
                       TO WS-PD-STATUS
           END-EVALUATE

           STRING PM-INSURED-FIRST-NAME DELIMITED BY '  '
                  ' ' DELIMITED BY SIZE
                  PM-INSURED-LAST-NAME DELIMITED BY '  '
               INTO WS-PD-INSURED-NAME

           EVALUATE TRUE
               WHEN PM-LOB-AUTO
                   MOVE 'AUTOMOBILE' TO WS-PD-LOB
               WHEN PM-LOB-HOME
                   MOVE 'HOMEOWNERS' TO WS-PD-LOB
               WHEN PM-LOB-LIFE
                   MOVE 'LIFE'       TO WS-PD-LOB
               WHEN PM-LOB-HEALTH
                   MOVE 'HEALTH'     TO WS-PD-LOB
               WHEN PM-LOB-COMMERCIAL
                   MOVE 'COMMERCIAL' TO WS-PD-LOB
           END-EVALUATE

           MOVE PM-COVERAGE-AMOUNT TO WS-PD-COVERAGE
           MOVE PM-ANNUAL-PREMIUM  TO WS-PD-PREMIUM
           MOVE PM-DEDUCTIBLE-AMT  TO WS-PD-DEDUCTIBLE
           MOVE PM-AGENT-CODE      TO WS-PD-AGENT
           MOVE PM-CLAIMS-COUNT    TO WS-PD-CLAIMS-COUNT
           .

This CICS program illustrates how the same policy master record used in batch processing (section 35.2) is also accessed in real time. The VSAM file is shared between batch and CICS, with CICS using READ-ONLY access during online hours and batch jobs running during off-peak windows. The display formatting logic translates internal codes into human-readable text -- converting 'AUT' to 'AUTOMOBILE' and 'AC' to 'ACTIVE' -- so that customer service representatives can quickly understand the policy's status.


35.12 Government Payment Processing

35.12.1 Payment File Generation

Government agencies generate massive payment files that are transmitted to the Treasury Department for disbursement. Social Security payments, tax refunds, veterans' benefits, and federal employee salaries all flow through similar payment processing pipelines. The following code demonstrates the generation of an ACH payment file for government benefit disbursements:

       01  WS-ACH-BATCH-HEADER.
           05  WS-ACH-REC-TYPE          PIC X(01) VALUE '5'.
           05  WS-ACH-SERVICE-CODE      PIC X(03) VALUE '220'.
           05  WS-ACH-COMPANY-NAME      PIC X(16).
           05  WS-ACH-COMPANY-ID        PIC X(10).
           05  WS-ACH-ENTRY-CLASS       PIC X(03) VALUE 'PPD'.
           05  WS-ACH-DESCRIPTION       PIC X(10).
           05  WS-ACH-EFF-DATE          PIC X(06).
           05  WS-ACH-SETTLE-DATE       PIC X(03) VALUE SPACES.
           05  WS-ACH-ORIGINATOR-CODE   PIC X(01) VALUE '1'.
           05  WS-ACH-ORIGIN-DFI        PIC X(08).
           05  WS-ACH-BATCH-NUMBER      PIC 9(07).

       01  WS-ACH-ENTRY-DETAIL.
           05  WS-ACH-DET-REC-TYPE      PIC X(01) VALUE '6'.
           05  WS-ACH-DET-TRANS-CODE    PIC X(02) VALUE '22'.
           05  WS-ACH-DET-ROUTING       PIC X(09).
           05  WS-ACH-DET-ACCOUNT       PIC X(17).
           05  WS-ACH-DET-AMOUNT        PIC 9(10).
           05  WS-ACH-DET-INDIV-ID      PIC X(15).
           05  WS-ACH-DET-INDIV-NAME    PIC X(22).
           05  WS-ACH-DET-DISC-DATA     PIC X(02) VALUE SPACES.
           05  WS-ACH-DET-ADDENDA-IND   PIC X(01) VALUE '0'.
           05  WS-ACH-DET-TRACE-NUM     PIC X(15).

       01  WS-PAYMENT-TOTALS.
           05  WS-PAY-ENTRY-COUNT        PIC 9(08) VALUE 0.
           05  WS-PAY-TOTAL-AMOUNT       PIC 9(12)V99 VALUE 0.
           05  WS-PAY-HASH-TOTAL         PIC 9(10) VALUE 0.

       8000-GENERATE-ACH-PAYMENT.
           MOVE BEN-ROUTING-NUMBER
               TO WS-ACH-DET-ROUTING
           MOVE BEN-ACCOUNT-NUMBER
               TO WS-ACH-DET-ACCOUNT
      *    ACH amounts are in cents, no decimal
           COMPUTE WS-ACH-DET-AMOUNT =
               BEN-PAYMENT-AMOUNT * 100
           MOVE BEN-SSN TO WS-ACH-DET-INDIV-ID
           MOVE BEN-NAME TO WS-ACH-DET-INDIV-NAME

           ADD 1 TO WS-PAY-ENTRY-COUNT
           ADD BEN-PAYMENT-AMOUNT TO WS-PAY-TOTAL-AMOUNT
      *    Hash total is sum of routing numbers (for validation)
           ADD BEN-ROUTING-NUM-9
               TO WS-PAY-HASH-TOTAL

           WRITE ACH-RECORD FROM WS-ACH-ENTRY-DETAIL
           .

The ACH payment format is standardized by NACHA (the National Automated Clearing House Association) and follows a precise fixed-length record layout -- exactly the kind of fixed-format data that COBOL handles naturally. The hash total, computed as the sum of all routing numbers in the batch, provides a simple but effective validation mechanism: if the receiving bank computes a different hash, the file has been corrupted or tampered with. This pattern mirrors the ACH processing described for the banking context in Chapter 34, but applied here to government benefit disbursement.

35.12.2 Case Management Systems

Government agencies use case management systems to track the lifecycle of individual cases -- benefit applications, tax audits, disability determinations, and appeals. These systems maintain a case record that accumulates activity over time:

       01  WS-CASE-RECORD.
           05  CS-CASE-NUMBER            PIC X(12).
           05  CS-CASE-TYPE              PIC X(02).
               88  CS-TYPE-NEW-CLAIM     VALUE 'NC'.
               88  CS-TYPE-REVIEW        VALUE 'RV'.
               88  CS-TYPE-APPEAL        VALUE 'AP'.
               88  CS-TYPE-OVERPAYMENT   VALUE 'OP'.
           05  CS-CASE-STATUS            PIC X(02).
               88  CS-STATUS-OPEN        VALUE 'OP'.
               88  CS-STATUS-PENDING     VALUE 'PD'.
               88  CS-STATUS-DECIDED     VALUE 'DC'.
               88  CS-STATUS-CLOSED      VALUE 'CL'.
               88  CS-STATUS-APPEALED    VALUE 'AP'.
           05  CS-APPLICANT-SSN          PIC X(09).
           05  CS-APPLICANT-NAME         PIC X(40).
           05  CS-OPEN-DATE              PIC 9(08).
           05  CS-DECISION-DATE          PIC 9(08).
           05  CS-CLOSE-DATE             PIC 9(08).
           05  CS-ASSIGNED-EXAMINER      PIC X(08).
           05  CS-PRIORITY-CODE          PIC X(01).
               88  CS-PRIORITY-HIGH      VALUE 'H'.
               88  CS-PRIORITY-NORMAL    VALUE 'N'.
               88  CS-PRIORITY-LOW       VALUE 'L'.
           05  CS-DAYS-OPEN              PIC 9(04).
           05  CS-ACTION-COUNT           PIC 9(03).
           05  CS-DECISION-CODE          PIC X(02).
               88  CS-APPROVED           VALUE 'AP'.
               88  CS-DENIED             VALUE 'DN'.
               88  CS-PARTIAL            VALUE 'PT'.
           05  CS-BENEFIT-AMOUNT         PIC 9(07)V99.
           05  CS-NOTES-COUNT            PIC 9(03).
           05  FILLER                    PIC X(50).

Case management programs generate aging reports that track how long cases have been open. Government agencies are often required by law to make decisions within specified timeframes -- the Social Security Administration, for example, must process initial disability claims within a target period. The aging report helps managers identify cases that are approaching their deadline:

       8200-CALCULATE-CASE-AGING.
           COMPUTE CS-DAYS-OPEN =
               FUNCTION INTEGER-OF-DATE(WS-CURRENT-DATE) -
               FUNCTION INTEGER-OF-DATE(CS-OPEN-DATE)

           EVALUATE TRUE
               WHEN CS-DAYS-OPEN > 180
                   ADD 1 TO WS-OVER-180-COUNT
                   PERFORM 8210-FLAG-OVERDUE
               WHEN CS-DAYS-OPEN > 90
                   ADD 1 TO WS-OVER-90-COUNT
               WHEN CS-DAYS-OPEN > 60
                   ADD 1 TO WS-OVER-60-COUNT
               WHEN CS-DAYS-OPEN > 30
                   ADD 1 TO WS-OVER-30-COUNT
               WHEN OTHER
                   ADD 1 TO WS-UNDER-30-COUNT
           END-EVALUATE
           .

35.13 Medicare and Health Benefits Processing

35.13.1 Medicare Claims Adjudication

Medicare claims processing is one of the largest COBOL applications in the world. The Centers for Medicare and Medicaid Services (CMS) processes over 1 billion claims per year through a network of Medicare Administrative Contractors (MACs), all running COBOL-based claims adjudication systems.

Medicare claims adjudication involves matching procedure codes against coverage rules, applying fee schedules, checking for duplicate claims, coordinating benefits with other insurance, and applying patient cost-sharing (deductibles, coinsurance, and copayments):

       01  WS-MEDICARE-CLAIM.
           05  MC-CLAIM-NUMBER           PIC X(15).
           05  MC-BENEFICIARY-HIC        PIC X(12).
           05  MC-PROVIDER-NPI           PIC X(10).
           05  MC-SERVICE-DATE           PIC 9(08).
           05  MC-PROCEDURE-CODE         PIC X(05).
           05  MC-DIAGNOSIS-CODES.
               10  MC-DIAG-CODE PIC X(08)
                   OCCURS 12 TIMES.
           05  MC-BILLED-AMOUNT          PIC 9(07)V99.
           05  MC-ALLOWED-AMOUNT         PIC 9(07)V99.
           05  MC-DEDUCTIBLE-APPLIED     PIC 9(05)V99.
           05  MC-COINSURANCE-AMOUNT     PIC 9(05)V99.
           05  MC-MEDICARE-PAYS          PIC 9(07)V99.

       01  WS-PART-B-DEDUCTIBLE         PIC 9(05)V99
                                          VALUE 00240.00.
       01  WS-PART-B-COINSURANCE        PIC 9V99
                                          VALUE 0.20.
       01  WS-YTD-DEDUCTIBLE-MET        PIC 9(05)V99.

       9200-ADJUDICATE-PART-B-CLAIM.
      *    Look up allowed amount from fee schedule
           PERFORM 9210-LOOKUP-FEE-SCHEDULE

      *    Apply deductible (if not yet met for the year)
           IF WS-YTD-DEDUCTIBLE-MET < WS-PART-B-DEDUCTIBLE
               COMPUTE MC-DEDUCTIBLE-APPLIED =
                   FUNCTION MIN(
                       MC-ALLOWED-AMOUNT,
                       (WS-PART-B-DEDUCTIBLE -
                        WS-YTD-DEDUCTIBLE-MET))
               ADD MC-DEDUCTIBLE-APPLIED
                   TO WS-YTD-DEDUCTIBLE-MET
           ELSE
               MOVE 0 TO MC-DEDUCTIBLE-APPLIED
           END-IF

      *    Calculate coinsurance (20% of allowed amount
      *    after deductible)
           COMPUTE MC-COINSURANCE-AMOUNT ROUNDED =
               (MC-ALLOWED-AMOUNT - MC-DEDUCTIBLE-APPLIED)
               * WS-PART-B-COINSURANCE

      *    Medicare payment = Allowed - Deductible - Coinsurance
           COMPUTE MC-MEDICARE-PAYS ROUNDED =
               MC-ALLOWED-AMOUNT -
               MC-DEDUCTIBLE-APPLIED -
               MC-COINSURANCE-AMOUNT

           IF MC-MEDICARE-PAYS < 0
               MOVE 0 TO MC-MEDICARE-PAYS
           END-IF
           .

This adjudication logic implements the standard Medicare Part B payment formula: the allowed amount (determined by a fee schedule) minus the annual deductible (if not yet met) minus 20 percent coinsurance. The FUNCTION MIN intrinsic ensures that the deductible applied does not exceed the allowed amount -- if a claim's allowed amount is $50 and the beneficiary has $100 of deductible remaining, only $50 of deductible is applied to that claim. These calculations, applied to over a billion claims per year, must be exact to the penny.


35.14 Connecting the Concepts

35.14.1 Shared Patterns Across Insurance and Government

Throughout this chapter, you have encountered several patterns that recur in both insurance and government COBOL systems:

Table-driven processing: Both premium rating (section 35.3) and tax bracket computation (section 35.8) use tables to drive calculations. This approach separates business rules (the table data) from processing logic (the table lookup code), making it easy to update rules without modifying programs.

Progressive formulas: The Social Security PIA formula (section 35.7) and the federal tax bracket computation (section 35.8) both apply different rates to different tiers of a base amount. This progressive structure appears throughout government and insurance systems.

Sequential match-merge: The tax return matching program (section 35.8) uses the same sorted-file match-merge pattern that appears in banking reconciliation (Chapter 34) and insurance claims processing.

Audit trail generation: Every program in this chapter writes audit records. In insurance, audit trails satisfy regulatory examiners. In government, they satisfy both internal auditors and public accountability requirements.

Checkpoint and restart: Long-running batch jobs in both sectors implement checkpoint logic to enable efficient restart after failures, as discussed in section 35.6.

35.14.2 Cross-References to Other Chapters

The topics in this chapter build directly on concepts from earlier chapters:

  • Chapter 33 (Financial Calculations): The decimal arithmetic principles, rounding rules, and COMPUTE statement usage demonstrated throughout this chapter follow directly from the financial calculation techniques covered in Chapter 33. Premium calculations, benefit computations, and tax bracket logic all depend on the precise decimal arithmetic that COBOL provides natively.

  • Chapter 34 (Banking and Payment Systems): The ACH payment generation in section 35.12 uses the same NACHA file format described in Chapter 34. The sequential match-merge pattern used for tax return matching is the same technique used for bank reconciliation. The VSAM file handling patterns in the policy administration system mirror the account master file techniques from banking.

  • Chapter 28 (Batch Processing): The JCL job streams, checkpoint/restart logic, and batch processing patterns in section 35.6 apply the batch processing principles covered in Chapter 28 to the specific requirements of insurance and government systems.

  • Chapters 24-25 (CICS): The online policy inquiry program in section 35.11 applies CICS concepts from Chapters 24 and 25 to the insurance domain, demonstrating how the same data structures serve both batch and online processing.


What You Have Learned

This chapter has covered the extensive use of COBOL in insurance companies and government agencies -- two sectors where the language's strengths in decimal arithmetic, batch processing, and regulatory compliance are indispensable. Here is a summary of the key concepts and skills you have acquired:

Insurance Policy Administration: You learned how policy master records are structured using VSAM KSDS files with indexed access, how transactions drive the policy lifecycle (creation, endorsement, renewal, and cancellation), and how audit trails are maintained for every policy change. You saw how level-88 condition names make policy status checking readable and how the EVALUATE statement dispatches different transaction types to appropriate processing paragraphs.

Premium Calculation Engines: You studied the table-driven rating approach that is the foundation of insurance premium computation. You learned how base rates are looked up by territory and coverage type, how rating factors for age, vehicle, deductible, and risk class are applied multiplicatively, how discounts and surcharges are accumulated with regulatory caps, and how state minimum and maximum premiums are enforced. You saw how the REDEFINES clause enables readable table initialization while supporting efficient indexed access.

Claims Processing: You examined the claims master record structure, the claims payment workflow with coverage limit enforcement and deductible application, and how reserve amounts are adjusted as payments are made. You learned that claims processing involves the most complex business logic in insurance, combining coverage verification, damage assessment, and payment authorization.

Actuarial Computations: You explored loss ratio calculations and reserve development triangles -- two fundamental actuarial tools that COBOL programs compute in batch. You learned how two-dimensional COBOL tables represent development triangles and how age-to-age factors are calculated to project ultimate losses.

Batch Processing Patterns: You studied the insurance batch cycle, including the JCL job stream for policy administration with pre-sort, backup, processing, and reporting steps. You learned the checkpoint and restart pattern that enables recovery from mid-job failures without reprocessing the entire file.

Government Benefits Administration: You implemented the Social Security PIA formula with its three-tier progressive structure and earnings indexing. You built an eligibility determination program that applies income tests, asset tests, and citizenship requirements according to statutory rules. You saw how the Federal Poverty Level table drives income limit calculations.

Tax Processing: You learned how progressive tax bracket computations work in COBOL, iterating through brackets and accumulating tax amounts. You studied the sequential match-merge pattern used to compare tax returns against W-2 forms for income verification.

Regulatory Compliance Reporting: You examined how COBOL programs generate NAIC regulatory filings for insurance companies, including Schedule P loss development data with signed numeric fields for negative values.

HIPAA and Data Privacy: You learned how HIPAA requirements affect COBOL program design in health insurance systems, including ANSI X12 EDI transaction generation, minimum necessary data access through separate copybooks, PHI access audit logging, and data masking for sensitive identifiers.

Real-Time Policy Queries: You saw how CICS programs provide online access to the same policy master records used in batch processing, formatting internal codes into human-readable displays for customer service representatives.

Government Payment Processing: You studied ACH payment file generation for government benefit disbursements, including the fixed-format record layouts mandated by NACHA, hash total validation, and the payment control totals that ensure every dollar is accounted for.

Case Management: You examined government case tracking systems with aging report logic that helps agencies meet statutory decision deadlines.

These insurance and government systems represent some of the most critical COBOL applications in operation today. They process trillions of dollars annually, serve hundreds of millions of people, and must operate with absolute precision and reliability. The patterns you have learned in this chapter -- table-driven rating, progressive benefit formulas, transaction-driven master file updates, batch processing with checkpoint/restart, regulatory compliance reporting, and real-time inquiry -- form the foundation of COBOL programming in these vital sectors. In Chapter 36, you will turn to another major domain of COBOL in financial systems: accounting and general ledger processing, where you will see how the double-entry bookkeeping principles that underpin all financial reporting are implemented in COBOL programs that produce the financial statements on which businesses and regulators depend.