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 packagepkg_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_billandn_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_maintpfc_save comment); its executable is outside the extracted libraries.
Key workflows
1. Billing setup
- Define billing rules (
bill_rules): code, description, bill level (BILL / GROUP / MEMBER, code keyBLNGLEVELperbilling/dddw_billing_level), optional rate type (rate variables), default category and frequency (billing/w_bill_bill_rule_maint). - 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). - Define rate tables per rule (
bill_rate_tables, effective-dated from/thru) with rate amounts per rate item (bill_rate_amts), rounding codes (code keysBILLRATERN,BILLUNITRNperbilling/dddw_bill_rate_rounding_cd,billing/dddw_bill_unit_rounding_cd) and vendor allocations (bill_rate_allocs, method PCT or AMT). - 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). - 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_runsrow (key fromBILL_RUN_SEQ) withbill_dtanddue_dt, and onebill_run_defsrow per selected definition with statusSUBMITTED(orDELAYEDwhen "Delay Processing" is checked) (billing/w_bill_run_def_maintpfc_preupdate, pfc_addrow). - Deleting a run removes its charges and recalc rows (
pkg_bills.delete_bill_charges,pkg_bills.delete_recalc_chargesviabillfunc/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_maintpfc_save). - Re-submitting deletes the run's charges and voids its reports (status
VOID), then sets the run-definition status back toSUBMITTED(billing/w_bill_run_def_maintpfc_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_eligibilitiessubscriber 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_chargesrow per allocation entity, key fromBILL_CHARGE_SEQ, with charge typeNEW, 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):
- Recalculate the period with current data into
bill_recalc_charges_temp(charge typeRECALC), zeroing member key at GROUP level and member/group at BILL level. - 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 viaADJ-DROP(billfunc/n_billproc_sql.of_inserthistoricalcharges). - 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-RATEreversal (−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-CHANGEreversal and re-bill (billfunc/d_billproc_hist_adj_change,d_billproc_recalc_adj_change).
- in RECALC but not HISTORICAL →
- Recalc rows are persisted from temp to
bill_recalc_chargesviapkg_bills.move_temp_to_recalc; temp tables are truncated and indexes rebuilt viapkg_billsprocedures (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_keyequals this run. - Client adjustments = manual
bill_chargeswhosemanual_adj_run_sys_keyequals 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 forPLANYR, 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
MAXENROLLoption 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
BILLCOVRcode 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_periodsprior periods, stepping by the definition frequency, never beforeadj_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_maintpfc_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_maintdw_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_maintpfc_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_maintpfc_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_maintpfc_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_maintdw_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_maintpfc_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_queuepfc_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
| Level | Population | Units | Rate item | Rate |
|---|---|---|---|---|
| BILL | one charge per rule | 1 | first rate amount | single table amount (billfunc/n_billproc.of_billlevelrule) |
| GROUP | leaf groups passing rule parameters | 1 | FLAT only | flat table amount (billfunc/n_billproc.of_grouplevelrule) |
| MEMBER | eligible members passing rule parameters | 1, or election benefit amount when rate unit ≠ 1 | FLAT 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):
| Table | Role | Key columns (from schema.json) |
|---|---|---|
bill_defs | Billing definition | bill_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_groups | Groups per definition | bill_def_sys_key, group_id |
bill_def_rules | Rules 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_vals | Definition options (effective-dated typed values) | bill_option_cd, option_val_cd/char/dt/no, eff_dt, exp_dt |
bill_rules | Rule master | bill_rule_cd, bill_level, bill_rate_type_sys_key, default_bill_category, default_frequency |
bill_rule_parms / bill_rule_parm_details | Rule applicability criteria | parm_source, parm_connector, seq; parm_variable, parm_operator, parm_value, value_type_cd |
bill_rate_types / bill_rate_vars | Rate type and its variables | bill_level; seq, rate_source, rate_variable, rate_var_sql, code_key, bill_range_sys_key |
bill_ranges / bill_range_items | Banded lookup ranges | bill_range_cd, value_type_cd; heading, number_from/thru, char_from/thru |
bill_rate_tables | Effective-dated rate tables per rule | from_dt, thru_dt, rate_unit, rate_rounding_cd, unit_rounding_cd, alloc_method |
bill_rate_amts | Rate per rate item | rate_item, rate_amt |
bill_rate_allocs | Vendor split per rate amount | alloc_entity_sys_key, allocate_amt |
bill_runs / bill_run_defs | Run header / per-definition status | bill_dt, due_dt, status_cd; status_cd (SUBMITTED, DELAYED, COMPLETE, FAKE), total_billed_amt |
bill_charges | Charge 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_temp | Batch staging for charges and recalc comparison | mirror bill_charges plus charge_type HISTORICAL/RECALC, vendor_category |
bill_receipts | Payments received | bill_run_sys_key, bill_def_sys_key, receipt_amt, receipt_dt, check_number, group_id, member_sys_key, appearance_run_sys_key |
bill_reports | Link from run to stored report | report_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):
| Section | DataWindow | Notes |
|---|---|---|
| Mailing/remit page with balance summary | billfunc/d_billprt_rpt2_mailing_page | previous 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 detail | billfunc/d_billprt_rpt2_member_detail | per-group; misc columns per MISC_COL1/2 options |
| Age rate detail | billfunc/d_billprt_rpt2_age_rate_detail | option AGERATEDTL |
| Member adjustment detail | billfunc/d_billprt_rpt2_member_adj_detail | |
| Member bulk adjustments | billfunc/d_billprt_rpt2_member_bulk_adj | |
| Group charges | billfunc/d_billprt_rpt2_group_charges | |
| Category summary per group | billfunc/d_billprt_rpt2_category_summary | option CATSBYGRP |
| Bill-level charges | billfunc/d_billprt_rpt2_bill_charges | |
| Group summary | billfunc/d_billprt_rpt2_bill_group_summary | when billing combined |
| Overall category summary | billfunc/d_billprt_rpt2_category_group_summary | |
| Vendor disbursement summary | billfunc/d_billprt_rpt2_disbursement_summary | option DISB_SUMM |
| Final summary | billfunc/d_billprt_final_summary | |
| Client self-adjustment page | billfunc/d_billprt_client_adj_page | option 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-01treated as null date;12/31/2499/2500as open-ended dates. - Oracle-specific machinery: CONNECT BY group-hierarchy expansion
(
billfunc/d_bill_groups),pkg_billsstored procedures, dedicated rollback segmentBIGRBS(billfunc/n_billproc_sql.of_setrollback), sequences, RULE optimizer hints. - The adjustment comparison depends on exact equality of composite keys including
rate_itemstrings (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
- 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" inbilling/w_bill_run_def_maintcomments) is not in the extracted libraries. Where does it run, how is DELAYED handled differently, and what setsbill_run_defs.status_cdto COMPLETE? - 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_keyequal 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 (possiblypkg_billsor the batch app). bill_rule_def_delete_responsesemantics: 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_maintpfc_deleterow).- Adjustment logic default:
ls_adj_logicis initialized to null and never read frombill_defs.adj_logic_cdin the active code path, so the BILLYEAR/CALYEAR/BILLCAL limits appear dormant (billfunc/n_billproc.of_adjust_billsetsSetNull(ls_adj_logic)after reading definition fields). Was this intentional? - 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? bill_chargesadd/change/adj columns (add_amt,add_count,change_amt,adj_count,bill_amt,bill_count,bill_volumeetc. inschema.json) are not populated by the examined code paths — confirm whether any external process uses them.cm_billingis a case-management billing table used byum_cm/um_urlibraries, not by this domain (schema.json); confirm it is out of scope for premium billing migration.- 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.