Skip to main content

Billing (libraries: billing, billfunc)

Purpose

The Billing domain produces periodic premium/fee bills for self-funded plan clients. A billing definition (bill_defs) names a set of client groups and a set of billing rules; each rule computes charges at one of three levels — per bill, per group, or per member — using effective-dated rate tables. A billing run (bill_runs + bill_run_defs) executes one or more definitions as of a bill date, writes charge detail to bill_charges, recalculates prior periods to generate retroactive adjustment charges, and assembles a printable group bill (invoice/statement) stored in the report tables. Receipts (payments) and manual charge adjustments are entered against a definition and appear on the next bill's balance-forward section.

  • Charge computation engine: billfunc/n_billproc ("Functions for billing process, including computing bill, group, and member rates").
  • Bill/invoice assembly: billfunc/n_bill_functions ("Global billing functions").
  • Set-based recalc/adjustment SQL and stored-procedure calls: billfunc/n_billproc_sql (calls Oracle package pkg_bills).
  • Screens (18 windows) live in billing; see the Screen catalog.

Actors

Evidenced by screens and menu entries (homersys/m_sys_frame Billing menu):

  • Billing administrator — maintains billing definitions, rules, rate tables and ranges (billing/w_bill_bill_def_maint, billing/w_bill_bill_rule_maint, billing/w_bill_bill_range_maint).
  • Billing operator — submits/re-submits/deletes billing runs (billing/w_bill_run_def_maint), views and prints finished bills (billing/w_bill_queue), runs exception reports (billing/w_bill_reports).
  • Accounts receivable clerk — enters receipts and manual charge adjustments (billing/w_bill_receipt_maint, billing/w_bill_adj_maint).
  • Batch process — an external batch application executes SUBMITTED runs by calling n_billproc.of_bill and n_bill_functions.of_report; a console/scheduler object (n_batch_scheduler) receives progress log lines (billfunc/n_billproc.of_registerconsole). The run screen's comments refer to this process as "SFPIBACK" (billing/w_bill_run_def_maint pfc_save comment); its executable is outside the extracted libraries.

Key workflows

1. Billing setup

  1. Define billing rules (bill_rules): code, description, bill level (BILL / GROUP / MEMBER, code key BLNGLEVEL per billing/dddw_billing_level), optional rate type (rate variables), default category and frequency (billing/w_bill_bill_rule_maint).
  2. Attach parameters (bill_rule_parms + bill_rule_parm_details) that decide which groups/members a rule applies to; sources are limited to ELECTIONS, GROUPS, GROUP_COVERAGES, GROUP_OPTION_VALS, MEMBER_CAT_VAL, MEMBER_ELIGIBILITIES and PLAN_PKGS (billfunc/n_billproc.of_ruleparmsql).
  3. Define rate tables per rule (bill_rate_tables, effective-dated from/thru) with rate amounts per rate item (bill_rate_amts), rounding codes (code keys BILLRATERN, BILLUNITRN per billing/dddw_bill_rate_rounding_cd, billing/dddw_bill_unit_rounding_cd) and vendor allocations (bill_rate_allocs, method PCT or AMT).
  4. Define bill ranges (bill_ranges + bill_range_items) — banded lookup tables (for example age bands) that map a computed value to a rate-item heading (billing/w_bill_bill_range_maint, billfunc/n_billproc.of_assemblerateitem).
  5. Create a billing definition (bill_defs): code, description, frequency, billing-year begin month, adjustment periods/logic, report formats, billing begin date, inactive date; attach groups (bill_def_groups), attach rules with per-definition category/frequency/rate-period and from/thru dates (bill_def_rules); set options (bill_def_option_vals) (billing/w_bill_bill_def_maint).

2. Billing run lifecycle

  • Submission writes a bill_runs row (key from BILL_RUN_SEQ) with bill_dt and due_dt, and one bill_run_defs row per selected definition with status SUBMITTED (or DELAYED when "Delay Processing" is checked) (billing/w_bill_run_def_maint pfc_preupdate, pfc_addrow).
  • Deleting a run removes its charges and recalc rows (pkg_bills.delete_bill_charges, pkg_bills.delete_recalc_charges via billfunc/n_billproc_sql), deletes the run's bill reports/report data, deletes its receipts, and detaches receipts and manual adjustments that only appeared on that bill back to the unassigned run (−100) (billing/w_bill_run_def_maint pfc_save).
  • Re-submitting deletes the run's charges and voids its reports (status VOID), then sets the run-definition status back to SUBMITTED (billing/w_bill_run_def_maint pfc_save).

3. Charge calculation (n_billproc.of_calculate_bill)

For the definition and bill date, the engine retrieves definition rules, rate tables, amounts, allocations, rate variables, ranges and parameter details as of the bill date (billfunc/n_billproc.of_billdataretrieve), plus the group tree of the definition (each bill_def_groups root expanded to leaf groups via the groups parent/child hierarchy — billfunc/d_bill_groups). Then per rule:

  • Frequency gate — ANNUAL rules bill only in their begin month; QUARTERLY rules in begin month +0/3/6/9; MONTHLY always; ONCE rules are skipped if a charge already exists for the rule in the from/thru window (of_calculate_bill).
  • BILL level — one charge with units fixed at 1 and the single rate amount of the effective rate table (of_billlevelrule).
  • GROUP level — for each leaf group where the rule's parameter SQL is satisfied (of_groupruleapplies), one flat-rate charge; only FLAT rates are supported at group level — any other rate type raises a fatal error (of_grouplevelrule).
  • MEMBER level — for each leaf group, the parameter SQL resolves the member population (active member_eligibilities subscriber rows as of the date, joined to elections/coverage where coverage-based — of_memberruleapplies, billfunc/d_bill_rule_members); each member gets a charge computed from the rate item (see below) (of_memberlevelrule).
  • Charge record — every charge is split across the rule's vendor allocations, one bill_charges row per allocation entity, key from BILL_CHARGE_SEQ, with charge type NEW, the bill period date, level, category, rate item, units, rate and election data (of_recordcharge, of_allocateamt, of_newkey).

Rate math (all levels): charge = round(units / rate_unit, unit_rounding) applied as (units ÷ rate_unit) × rate_amt, then rounded per the rate table's rate-rounding code; rounding codes are NEARxx / DOWNxx / UPxx with a default of round-to-nearest-cent (of_billlevelrule, of_memberlevelrule, of_round). For member rules with rate_unit ≠ 1, units come from the member's election coverage benefit amount (volume rating, e.g. per-$1000 life volume) (of_memberlevelrule).

Rate item resolution (of_assemblerateitem): if the rule's rate type has no rate variables the item is FLAT; otherwise each rate variable's SQL template (bill_rate_vars.rate_var_sql) is resolved by substituting :group_id, :member_sys_key, :bill_dt, :birth_dt, :gender_cd, :coverage_level, :coverage_amt and executing it (or reading the variable directly when the template is just a variable). If the variable references a bill range, the raw value is translated to the matching range-item heading (numeric ranges only). Results concatenate as SOURCE.VARIABLE=value;... and must match a bill_rate_amts.rate_item exactly.

Rate as-of date: a definition rule's rate_period_cd selects which rate table applies — CALYR uses Jan 1 of the bill year, PLANYR uses the group's STOPLOSS period start (group_periods via of_groupperiod), otherwise the bill date itself (of_billlevelrule, of_grouplevelrule, of_memberlevelrule).

4. Retroactive adjustments (n_billproc.of_adjust_bill)

For each of the definition's adj_periods prior periods (stepping back one month, quarter, or year according to definition frequency), bounded below by adj_beg_dt (default: 5 years back) and by adjustment logic (adj_logic_cd: BILLYEAR = not before billing-year start, CALYEAR = not before Jan 1, BILLCAL = combination):

  1. Recalculate the period with current data into bill_recalc_charges_temp (charge type RECALC), zeroing member key at GROUP level and member/group at BILL level.
  2. Summarize history: insert the surviving net historical charges for that period into the same temp table (charge type HISTORICAL) — summing all prior-run charge amounts per member/group/category/rule/allocation entity, carrying rate details from the latest prior charge, and excluding items already fully dropped via ADJ-DROP (billfunc/n_billproc_sql.of_inserthistoricalcharges).
  3. Compare RECALC vs HISTORICAL and emit adjustment charges into bill_charges (of_recordadjustment):
    • in RECALC but not HISTORICAL → ADJ-ADD (positive) (billfunc/d_billproc_adj_add);
    • in HISTORICAL but not RECALC → ADJ-DROP (amounts negated) (billfunc/d_billproc_adj_drop);
    • same member/group/category but different rule or allocation entity → paired ADJ-RATE reversal (−historical) and re-bill (+recalc) (billfunc/d_billproc_hist_adj_rate, d_billproc_recalc_adj_rate);
    • same rule/entity but changed election level, election benefit amount, or rate item → paired ADJ-CHANGE reversal and re-bill (billfunc/d_billproc_hist_adj_change, d_billproc_recalc_adj_change).
  4. Recalc rows are persisted from temp to bill_recalc_charges via pkg_bills.move_temp_to_recalc; temp tables are truncated and indexes rebuilt via pkg_bills procedures (billfunc/n_billproc_sql).

5. Bill/statement production (n_bill_functions.of_report)

For the run/definition, definition groups are resolved to active eligibility-level groups as of the bill date (billfunc/d_billprt_elig_groups); depending on option BILL_EACH one combined bill or one bill per group is produced (of_report). Each bill is a composite report assembled from sub-reports (of_create_bill2): mailing/remit page with balance summary, member detail, optional age-rate detail, member adjustment detail, member bulk adjustments, group charges, optional per-group category summaries, bill-level charges, group summary, overall category summary, optional vendor disbursement summary, final summary, and an optional client self-adjustment page. The finished report is stored via n_report_data.of_InsertReportData with category BILL (errors as BILLERR / BILLPRTERR) and linked to the run in bill_reports (of_savebill, n_billproc.of_bill).

Statement balance section (of_mailingpage, billfunc/d_billprt_def_balance_info):

  • Previous balance = all prior-run charges (excluding this run's manual adjustments) minus all prior receipts (excluding those first appearing on this run), limited to runs on/after the definition's bill_beg_dt.
  • Payments = receipts whose appearance_run_sys_key equals this run.
  • Client adjustments = manual bill_charges whose manual_adj_run_sys_key equals this run.
  • Current billed = NEW + ADJ-ADD/DROP/CHANGE/RATE totals by level (member, group, other/bill) (billfunc/d_billprt_charge_total).
  • Current due = previous balance − payments + client adjustments + current billed.

6. Receipts and manual adjustments

  • Receipts are entered per definition against a specific COMPLETE billed run (and group or member when the definition bills per group/member), with amount, date, check number, description; new receipts get appearance_run_sys_key = -100 (unassigned) and can be edited or deleted only while unassigned (billing/w_bill_receipt_maint, billing/w_bill_receipt_response, billing/d_bill_receipt_view).
  • Manual adjustments are add/drop charge entries per definition: "drop" reverses selected existing NEW charges (negated amounts, charge type ADJ-DROP, manual_adj_run_sys_key = -100); manual entries can be deleted only while still unassigned (billing/w_bill_adj_maint).

Business rules

Each statement is testable; citations are library/object.

  • BIL-1 A billing run/definition combination that already has charges must not be billed again; the run aborts with a fatal error (billfunc/n_billproc.of_bill).
  • BIL-2 A run must not be billed when a later-dated bill already exists for the definition, nor when a bill has already been produced for the same calendar month (billfunc/n_billproc.of_bill).
  • BIL-3 ANNUAL rules generate charges only when the bill month equals the rule's begin month; QUARTERLY rules only when the bill month is the begin month plus 0, 3, 6 or 9 (mod 12); MONTHLY rules always; unrecognized frequencies are fatal errors (billfunc/n_billproc.of_calculate_bill).
  • BIL-4 A ONCE-frequency rule is skipped when any charge already exists for that rule/definition/run within the rule's from/thru date window (billfunc/n_billproc.of_calculate_bill).
  • BIL-5 Rule level must be BILL, GROUP, or MEMBER; any other level is a fatal error (billfunc/n_billproc.of_calculate_bill).
  • BIL-6 The rate table used is the one effective for the rate as-of date, which is Jan 1 of the bill year for rate period CALYR, the group's STOPLOSS plan-year start for PLANYR, and the bill date otherwise; a missing rate table is a fatal error (billfunc/n_billproc.of_billlevelrule, of_grouplevelrule, of_memberlevelrule).
  • BIL-7 A bill-level rule uses a single rate amount with units fixed at 1; multiple rate amounts on a bill-level rule produce a warning and the first is used (billfunc/n_billproc.of_billlevelrule).
  • BIL-8 Group-level rules support only FLAT rate amounts; a non-flat rate type at group level is a fatal error (billfunc/n_billproc.of_grouplevelrule).
  • BIL-9 Charge amount = (units ÷ rate unit) × rate amount, with units and result rounded per the rate table's unit- and rate-rounding codes; rounding codes are NEARn (nearest n), DOWNn (truncate), UPn (ceiling), defaulting to nearest cent (billfunc/n_billproc.of_round, of_memberlevelrule).
  • BIL-10 When a member-level rate table's rate unit is not 1, billing units are the member's election coverage benefit amount; a member missing this amount is a fatal error (billfunc/n_billproc.of_memberlevelrule).
  • BIL-11 For non-flat member rates, the rate item is assembled from the rule's rate variables (resolved per member via SQL substitution of group, member, bill date, birth date, gender, coverage level and coverage amount) and must match a rate amount's rate item exactly; no match is a fatal error (billfunc/n_billproc.of_assemblerateitem, of_memberlevelrule).
  • BIL-12 A rate variable tied to a bill range translates the computed value to the range item heading whose numeric from/thru brackets contain it (billfunc/n_billproc.of_assemblerateitem).
  • BIL-13 A member is in a rule's population only while holding an active subscriber eligibility row in the group as of the member date, excluding members with life status 'Fake' or 'PCS' (billfunc/d_bill_rule_members).
  • BIL-14 When a definition carries the MAXENROLL option date, member selection is as of the earlier of the bill date and that option date (billfunc/n_billproc.of_memberruleapplies).
  • BIL-15 For coverage-based member rules, the election used for billing is the one matching the coverage-type parameter with the lowest BILLCOVR code display sequence among the member's active elections (billfunc/n_billproc.of_ruleparmsql).
  • BIL-16 Rule parameter sources are restricted to ELECTIONS, GROUPS, GROUP_COVERAGES, GROUP_OPTION_VALS (GROUP_OPTIONS is auto-corrected to GROUP_OPTION_VALS), MEMBER_CAT_VAL, MEMBER_ELIGIBILITIES and PLAN_PKGS; any other source is a fatal error (billfunc/n_billproc.of_ruleparmsql).
  • BIL-17 For GROUP_OPTION_VALS and MEMBER_CAT_VAL parameters, the parameter variable is a code (option/category code), and the compared column is selected by that code's value type (NUMBER/DATE/CODE/CHAR); an unexpected value type is a fatal error (billfunc/n_billproc.of_ruleparmsql).
  • BIL-18 Parameter details connected by OR start a new union branch in which the fixed source-join criteria are repeated, so OR alternatives each still satisfy the base joins (billfunc/n_billproc.of_ruleparmsql).
  • BIL-19 A charge is recorded only when its amount, election benefit amount, or election level is non-zero/non-empty (billfunc/n_billproc.of_recordcharge).
  • BIL-20 Every recorded charge is split into one row per allocation entity of its rate amount; percentage allocations must total exactly 100% (under- or over-allocation is a fatal error, except a single-entity allocation which takes the full amount with a warning); amount allocations must reconcile to the rate amount, with the final entity absorbing rounding remainder (billfunc/n_billproc.of_allocateamt, of_recordcharge).
  • BIL-21 Adjustment processing recalculates at most adj_periods prior periods, stepping by the definition frequency, never before adj_beg_dt, never more than 5 years back, further limited by adjustment logic BILLYEAR (billing-year start), CALYEAR (Jan 1), or BILLCAL (billfunc/n_billproc.of_adjust_bill).
  • BIL-22 The historical baseline for a period is the net sum of all prior-run charges per member/group/category/rule/allocation entity, excluding combinations whose charges already net to zero at a prior ADJ-DROP (billfunc/n_billproc_sql.of_inserthistoricalcharges).
  • BIL-23 Adjustment charge types and signs: ADJ-ADD (+), ADJ-DROP (−), ADJ-RATE (−historical, +recalculated), ADJ-CHANGE (−historical, +recalculated); ADJ-CHANGE is triggered by differences in election level, election benefit amount, or rate item (billfunc/n_billproc.of_recordadjustment, billfunc/d_billproc_hist_adj_change).
  • BIL-24 For ADJ-CHANGE the reversing negative entry must be committed before the positive entry with a lower charge key, because election info is taken from the greatest historical charge key (comment in billfunc/n_billproc.of_adjustbill).
  • BIL-25 Submitting runs assigns a new run key to all newly selected definitions with the entered bill date (also used as due date) and status SUBMITTED, or DELAYED when delay processing is chosen (billing/w_bill_run_def_maint pfc_preupdate, pfc_addrow).
  • BIL-26 Only a definition's latest run appears in the run-maintenance lists, and only definitions active (not inactive) as of the bill date are offered (billing/d_bill_run_def_maint).
  • BIL-27 A definition row cannot be selected for submission when its latest bill date is later than the entered bill date (billing/w_bill_run_def_maint dw_bill_def_list clicked/doubleclicked).
  • BIL-28 Removing a previously submitted run deletes its charges and recalc rows, deletes its bill reports/report objects/report data, deletes its receipts (after user confirmation when receipts exist), and re-points receipts and manual adjustments that appeared on it back to the unassigned run (−100); re-submission instead deletes charges and voids reports (billing/w_bill_run_def_maint pfc_save, pfc_deleterow).
  • BIL-29 Every billing definition owns a permanent "unassigned" run (bill_run_sys_key = -100, status FAKE) used to hold receipts and manual adjustments before they appear on a real bill (billing/w_bill_bill_def_maint pfc_preupdate).
  • BIL-30 Each definition rule must have a billing category and a from date before the definition can be saved; a definition must have a definition code (billing/w_bill_bill_def_maint pfc_preupdate).
  • BIL-31 Receipts can be created only against billed runs dated on/after the definition's billing begin date; earlier bills are historical only (billing/w_bill_receipt_maint dw_receipt_view ue_enter).
  • BIL-32 Receipts and manual adjustment charges can be edited or deleted only while unassigned (appearance/manual-adjustment run = −100), i.e. before they appear on a bill (billing/w_bill_receipt_maint, billing/w_bill_adj_maint pfc_deleterow).
  • BIL-33 Only NEW charges may be manually dropped; dropping creates reversing ADJ-DROP rows (negated charge and election benefit amounts) attached to the unassigned run, with a warning when the selection appears already dropped (billing/w_bill_adj_maint.wf_dropcharges).
  • BIL-34 Statement current-due = previous balance − payments + client adjustments + current billed, where previous balance counts only runs on/after the definition's billing begin date (billfunc/n_bill_functions.of_mailingpage, billfunc/d_billprt_def_balance_info).
  • BIL-35 With definition option BILL_EACH = GROUP, a separate bill is produced per eligible group (groups without charges are skipped with a warning); otherwise a single combined bill is produced (billfunc/n_bill_functions.of_report).
  • BIL-36 Bill content options come from bill_def_option_vals: ALLOW_ADJ (client self-adjustment page), DISB_SUMM (vendor disbursement summary), AGERATEDTL (age-rate premium detail), CATSBYGRP (category summaries by group), MISC_COL1/MISC_COL2 (member-detail miscellaneous columns, defaults EFF_DT and HCN), PAYABLE_TO, BILL_EACH, MAXENROLL (billfunc/n_bill_functions.of_create_bill2, of_mailingpage, billfunc/n_billproc.of_memberruleapplies).
  • BIL-37 Bill processing errors are aggregated (duplicates counted, not repeated) into an error report saved with the run under category BILLERR (calculation) or BILLPRTERR (print); fatal errors stop the run (billfunc/n_billproc.of_reporterror, of_bill, billfunc/n_bill_functions.of_savebill).
  • BIL-38 Printing a voided report requires explicit confirmation; printed reports are marked with status PRINT, and the queue can filter to unprinted (no status) and non-void reports (billing/w_bill_queue pfc_print, ue_filter).
  • BIL-39 The definition group list is stored at any level of the group hierarchy but billing always expands it to leaf-level groups (those with no child groups) for charge processing (billfunc/d_bill_groups).
  • BIL-40 A definition rule may be restricted to specific groups of the definition via a MEMBER_ELIGIBILITIES.GROUP_ID rule parameter; when present, group- and member-level processing skips groups not in that list (billfunc/d_bill_bill_def_rules, billfunc/n_billproc.of_calculate_bill).

Rate/charge computation summary

LevelPopulationUnitsRate itemRate
BILLone charge per rule1first rate amountsingle table amount (billfunc/n_billproc.of_billlevelrule)
GROUPleaf groups passing rule parameters1FLAT onlyflat table amount (billfunc/n_billproc.of_grouplevelrule)
MEMBEReligible members passing rule parameters1, or election benefit amount when rate unit ≠ 1FLAT or assembled from rate variables (age, gender, coverage level, member category, ranges)matched bill_rate_amts.rate_amt (billfunc/n_billproc.of_memberlevelrule)

Elections drive member premiums three ways: the election's coverage type selects the rule (parameters, BILLCOVR priority), its coverage level / benefit amount feed the rate item and units, and the election's values are stored on the charge (election_level, election_benefit_amt) so later recalcs can detect changes (billfunc/n_billproc.of_memberlevelrule, of_recordcharge, billfunc/d_billproc_hist_adj_change).

Vendor allocation links billing to funding/disbursement: every charge row carries an alloc_entity_sys_key resolved from bill_rate_allocs, and the disbursement summary reports charge totals by vendor (billfunc/n_billproc.of_allocateamt, billing/d_billprt_disbursement_division_summary, billfunc/d_billprt_rpt2_disbursement_summary).

Data

Core tables (see schema.json CRUD: billing and billfunc both read/write most of these):

TableRoleKey columns (from schema.json)
bill_defsBilling definitionbill_def_cd, description, frequency, beg_month, adj_periods, adj_beg_dt, adj_beg_month, adj_logic_cd, bill_beg_dt, inactive_dt, bill_rpt_fmt_sys_key, alloc_rpt_fmt_sys_key
bill_def_groupsGroups per definitionbill_def_sys_key, group_id
bill_def_rulesRules per definition (effective-dated)bill_def_sys_key, bill_rule_sys_key, from_dt, thru_dt, bill_category, frequency, beg_month, rate_period_cd
bill_def_options / bill_def_option_valsDefinition options (effective-dated typed values)bill_option_cd, option_val_cd/char/dt/no, eff_dt, exp_dt
bill_rulesRule masterbill_rule_cd, bill_level, bill_rate_type_sys_key, default_bill_category, default_frequency
bill_rule_parms / bill_rule_parm_detailsRule applicability criteriaparm_source, parm_connector, seq; parm_variable, parm_operator, parm_value, value_type_cd
bill_rate_types / bill_rate_varsRate type and its variablesbill_level; seq, rate_source, rate_variable, rate_var_sql, code_key, bill_range_sys_key
bill_ranges / bill_range_itemsBanded lookup rangesbill_range_cd, value_type_cd; heading, number_from/thru, char_from/thru
bill_rate_tablesEffective-dated rate tables per rulefrom_dt, thru_dt, rate_unit, rate_rounding_cd, unit_rounding_cd, alloc_method
bill_rate_amtsRate per rate itemrate_item, rate_amt
bill_rate_allocsVendor split per rate amountalloc_entity_sys_key, allocate_amt
bill_runs / bill_run_defsRun header / per-definition statusbill_dt, due_dt, status_cd; status_cd (SUBMITTED, DELAYED, COMPLETE, FAKE), total_billed_amt
bill_chargesCharge detail (one row per allocation entity)bill_run/def/rule/rate_amt keys, bill_period_dt, bill_level, bill_category, charge_type (NEW, ADJ-ADD, ADJ-DROP, ADJ-RATE, ADJ-CHANGE), charge_amt, rate_item, rate_amt, bill_units, election_level, election_benefit_amt, alloc_entity_sys_key, member_sys_key, group_id, manual_adj_run_sys_key, bill_receipt_sys_key
bill_charges_temp, bill_recalc_charges, bill_recalc_charges_tempBatch staging for charges and recalc comparisonmirror bill_charges plus charge_type HISTORICAL/RECALC, vendor_category
bill_receiptsPayments receivedbill_run_sys_key, bill_def_sys_key, receipt_amt, receipt_dt, check_number, group_id, member_sys_key, appearance_run_sys_key
bill_reportsLink from run to stored reportreport_data_sys_key, status_cd (PRINT, VOID)

External reads: groups, group_periods, group_coverages, group_option_vals, member_eligibilities, members, elections, member_cat_val, plan_pkgs, codes, vendors/alloc_entities, report_data/report_objects (billfunc/n_billproc.of_ruleparmsql, billfunc/d_bill_rule_members, billing/dddw_bill_vendors, billing/d_bill_report_data).

Database sequences: BILL_RUN_SEQ, BILL_CHARGE_SEQ, BILL_RECEIPT_SEQ, plus a generic per-table sequence helper (billfunc/n_bill_functions.of_getbillsequence). Oracle package pkg_bills provides: move_temp_to_recalc, move_temp_to_charges, truncate_temp_charges, truncate_temp_recalc, delete_recalc_charges, build_temp_recalc_ix, delete_bill_charges (billfunc/n_billproc_sql).

Invoice/statement outputs

Composite group bill assembled per run/definition (billfunc/n_bill_functions.of_create_bill2):

SectionDataWindowNotes
Mailing/remit page with balance summarybillfunc/d_billprt_rpt2_mailing_pageprevious balance, payments, client adjustments, member/group/other charges and adjustments, current billed/due; remit address from group contacts or letter header, PAYABLE_TO option
Member detailbillfunc/d_billprt_rpt2_member_detailper-group; misc columns per MISC_COL1/2 options
Age rate detailbillfunc/d_billprt_rpt2_age_rate_detailoption AGERATEDTL
Member adjustment detailbillfunc/d_billprt_rpt2_member_adj_detail
Member bulk adjustmentsbillfunc/d_billprt_rpt2_member_bulk_adj
Group chargesbillfunc/d_billprt_rpt2_group_charges
Category summary per groupbillfunc/d_billprt_rpt2_category_summaryoption CATSBYGRP
Bill-level chargesbillfunc/d_billprt_rpt2_bill_charges
Group summarybillfunc/d_billprt_rpt2_bill_group_summarywhen billing combined
Overall category summarybillfunc/d_billprt_rpt2_category_group_summary
Vendor disbursement summarybillfunc/d_billprt_rpt2_disbursement_summaryoption DISB_SUMM
Final summarybillfunc/d_billprt_final_summary
Client self-adjustment pagebillfunc/d_billprt_client_adj_pageoption ALLOW_ADJ

Stored reports are browsed and printed from the Bill Report Queue (billing/w_bill_queue, list billing/d_bill_bill_reports_list). Standalone reports: disbursement summary by division (billing/w_billprt_disbursement_division_summary), flex charge billing for Depcare/Medreim elections (billing/w_billrpt_flex_charges), billing exception and definition-rate reports (billing/w_bill_reports, billing/n_verify_bill).

Migration notes

  • The rule-parameter and rate-variable engines store fragments of Oracle SQL in data (bill_rule_parm_details.parm_value, bill_rate_vars.rate_var_sql) and build/execute dynamic SQL with string substitution at run time (billfunc/n_billproc.of_ruleparmsql, of_assemblerateitem). A migration should replace this with a declarative criteria/rating model; the value space actually used must be inventoried from production data.
  • Charge rows are denormalized per allocation entity; totals per charge exist only as sums. Preserve this grain or introduce a charge header/allocation split.
  • Sentinel values are load-bearing: run −100 = "unassigned" bucket for receipts and manual adjustments (billing/w_bill_bill_def_maint, billing/w_bill_adj_maint); 1900-01-01 treated as null date; 12/31/2499/2500 as open-ended dates.
  • Oracle-specific machinery: CONNECT BY group-hierarchy expansion (billfunc/d_bill_groups), pkg_bills stored procedures, dedicated rollback segment BIGRBS (billfunc/n_billproc_sql.of_setrollback), sequences, RULE optimizer hints.
  • The adjustment comparison depends on exact equality of composite keys including rate_item strings (up to 2000 chars); formatting changes to rate items would generate spurious ADJ-CHANGE churn (billfunc/d_billproc_hist_adj_change).
  • Reports are persisted as serialized PowerBuilder report objects in report tables (n_report_data); a migration needs a replacement rendering/archive strategy for historical bills.
  • The commented-out in-memory adjustment algorithm (of_adjustbill) was superseded by the temp-table version (of_adjust_bill); only the latter is called (billfunc/n_billproc.of_bill).

Open questions

  1. Batch executor: the process that picks up SUBMITTED/DELAYED runs and calls n_billproc.of_bill / n_bill_functions.of_report (referred to as "SFPIBACK" in billing/w_bill_run_def_maint comments) is not in the extracted libraries. Where does it run, how is DELAYED handled differently, and what sets bill_run_defs.status_cd to COMPLETE?
  2. Attachment of receipts/adjustments to a run: receipts and manual adjustments are created against run −100 and the balance queries read them by appearance_run_sys_key / manual_adj_run_sys_key equal to the current run (billfunc/d_billprt_def_balance_info), and run deletion resets them to −100 (billing/w_bill_run_def_maint), but the code that flips −100 to the live run at bill time was not found in these libraries (possibly pkg_bills or the batch app).
  3. bill_rule_def_delete_response semantics: the response window offers Re-submit vs Remove; confirm business meaning of re-submitting DELAYED runs (status is preserved as DELAYED — billing/w_bill_run_def_maint pfc_deleterow).
  4. Adjustment logic default: ls_adj_logic is initialized to null and never read from bill_defs.adj_logic_cd in the active code path, so the BILLYEAR/CALYEAR/BILLCAL limits appear dormant (billfunc/n_billproc.of_adjust_bill sets SetNull(ls_adj_logic) after reading definition fields). Was this intentional?
  5. Group-level rate variables: explicitly unimplemented ("Requirements have not been defined … only flat rates will be allowed at the group level" — billfunc/n_billproc.of_grouplevelrule). Is group-level variable rating needed in the target system?
  6. bill_charges add/change/adj columns (add_amt, add_count, change_amt, adj_count, bill_amt, bill_count, bill_volume etc. in schema.json) are not populated by the examined code paths — confirm whether any external process uses them.
  7. cm_billing is a case-management billing table used by um_cm/um_ur libraries, not by this domain (schema.json); confirm it is out of scope for premium billing migration.
  8. Flex billing report hard-codes coverage types 'Depcare' and 'Medreim' and a manually entered rate (billing/d_billrpt_flex_charges, billing/w_billrpt_flex_charges); confirm whether flex billing should become a normal billing definition in the target system.