---
title: Bill edit validation
summary: Validates the bill header, diagnoses, and procedures in three ordered rule groups before the audit engine runs.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.Claim.Bill.AutomatedAudit
reference_type: package
operation_id: OP-AA-02
trigger: BillAuditEngine.AuditBill calls clsBillEditor.EditBill(Bill) after audit data has been generated
---

# Bill edit validation

`clsBillEditor.EditBill` runs the bill-header, diagnosis, and procedure rule groups in order, stopping as soon as any group produces a fatal error. Unlike the downstream audit engine, most of its rules only append audit messages to the bill; a small number of rules return `False` to `EditBill` and are treated as fatal, aborting the audit before any service-level work begins.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-AA-02 |
| **Trigger** | `BillAuditEngine.AuditBill` calls `clsBillEditor.EditBill(Bill)` after `GenerateAuditData` succeeds |
| **Inputs** | Populated `clsBillAudit` (header fields, diagnoses, procedures, resolved `Claim` and `BillingProvider`) |
| **Outputs** | Boolean pass/fail (`ErrorCount = 0`); audit messages appended to the bill via `GenerateError`/`GenerateWarning`; broken rules propagated to `BillAuditEngine` |
| **Primary components** | `clsBillEditor.EditBill`, `clsBillEditor.AddBusinessRules` |
| **Entry point** | `Business\SAIF.Business.Claim.Bill.AutomatedAudit\AuditUtilities\clsBillEditor.vb` |

## Steps

1. **Header group.** Start the `"Header"` rule group, clear broken rules, and run `CheckRules("Header")` ([BR-003](../business-rules.md#br-003-bill-edits-must-pass)):
   - `val_fe_CheckReceiptDateWithDOI` — fatal: if `Bill.MailRoomReceivedDate < Bill.Claim.InjuryDate`, generate error `"Bill data - received date is before date of injury"`.
   - `val_fe_CheckForNCE` — fatal: if `Bill.Claim.IsNCE`, generate error `"Bill data - claim is for non-compliant employer"`.
   - `val_fe_ClaimExists` — fatal: if `Bill.ClaimID = 0` or the claim is invalid, generate error `"Invalid claim number"` (with broken-rule data for `Claim`/`ClaimNumber`/`ClaimCheckValue`). If the claim is void and replaced, it re-resolves via `AuditEngine.GetClaim(Claim.ReplacedClaimID)` and errors with `"The merged claim is invalid"` if the replacement is also invalid; otherwise it updates `Bill.Claim` to the resolved claim.

     > **Origin**: The underlying claim lookup is implemented by [Retrieve claim summary data](../../saif-business-view-claim/operations/claim-summary-and-detail-retrieval.md) in `SAIF.Business.View.Claim`.
   - `val_fe_ValidateBillingProvider` — fatal: for a non-zero `ProviderLocationID`, requires a valid `BillingProvider`; if a bill-level `ProviderTaxID` is present, it must appear in the provider's tax-ID list or the rule fails with `"Bill data - invalid billing provider location"`. A zero `ProviderLocationID` is only an error unless `BillType = WorkerReimbursement`.

     > **Origin**: `Bill.BillingProvider` is resolved via [Retrieve provider location](../../saif-business-view-provider/operations/provider-location-retrieval.md) in `SAIF.BOF.Business.View.Provider`.
   - `val_fe_ValidAdjuster` — fatal: if `Bill.Claim.AdjusterMailID` is blank, generate error `"Bill data - missing responsible adjuster"`.
   - `val_me_BillTypeRequired` — message-only: for `InpatientHospital`/`OutpatientHospital` bills, the `UBBillTypeCode` must be at least 4 characters with numeric, non-zero characters in positions 2 and 3, else generate error `"Bill data - invalid type of bill"` (this rule always returns `True`, so it never aborts the group by itself).
   - `val_me_MissingAdmissionDate` / `val_me_MissingStatementFromDate` — for `InpatientHospital` bills, generate errors `"Bill data - missing admit date"` / `"Bill data - missing statement from date"` when the respective date is null.
   - `val_me_ValidAdmissionDate` — for `InpatientHospital` bills, error `"Bill data - admit date after received date"` if `MailRoomReceivedDate < AdmissionDate`.
   - `val_me_ValidDischargeDate` — for `InpatientHospital` bills, error `"Bill data - discharged before admitted"` if `DischargeDate < AdmissionDate`.
   - `val_me_ValidStatementFromDate` / `val_me_ValidStatementThruDate` — for `InpatientHospital` bills, error if the statement-from date precedes the admission date, or the statement-thru date precedes the statement-from date.
   - `val_me_ValidStatementFromThruDateSpan` — if the bill has diagnoses (or its billing provider type requires them), error `"Bill data - Statement from and thru dates cannot span over 10/01/15."` when the from/thru span crosses the hard-coded ICD-10 cutoff date of October 1, 2015, unless the bill is an inpatient institutional bill with a UB bill type prefix of `011`, `018`, `021`, or `032`.
   - `val_w_FederalClaimCheck` — warning-only: if `Bill.Claim.IsFederal`, generate warning `"Bill data - bill is for federal claim"`.
   - If `ErrorCount > 0` after the Header group, `EditBill` returns `False` immediately — Diagnoses and Procedures are never checked.
2. **Diagnoses group.** Start the `"Diagnoses"` group, clear broken rules, and run `CheckRules("Diagnoses")`. Registered diagnosis rules (`val_me_ValidDiagnosisCode`) generate an error per diagnosis whose code does not resolve, and a separate error `"Bill data - no diagnosis code"` when the billing provider type requires a diagnosis and none is present. If `ErrorCount > 0`, return `False` immediately.
3. **Procedures group.** Start the `"Procedures"` group, clear broken rules, and run `CheckRules("Procedures")`. Registered procedure rules (`val_me_ValidProcedureCode`) generate an error per procedure whose service does not resolve. If `ErrorCount > 0`, return `False`.
4. **Return overall result.** If all three groups completed without accumulating errors, return `True` (`ErrorCount = 0`).

## Process flow

```mermaid
flowchart TD
	Start([EditBill invoked]) --> Header[Header rule group:<br>DOI/NCE/claim/provider/adjuster,<br>admission/statement dates]
	Header --> HErr{ErrorCount > 0?}
	HErr -->|Yes| Fail([Return False])
	HErr -->|No| Diag[Diagnoses rule group]
	Diag --> DErr{ErrorCount > 0?}
	DErr -->|Yes| Fail
	DErr -->|No| Proc[Procedures rule group]
	Proc --> PErr{ErrorCount > 0?}
	PErr -->|Yes| Fail
	PErr -->|No| Pass([Return True])
```

## Failure and edge-case behavior

- Only the Header-group rules listed as fatal above can stop the pipeline; every other listed rule always returns `True` from its function even when it records an error message, so `EditBill` only fails when a Header-group fatal rule fires or a later group accumulates any generated error.*
- `val_me_BillTypeRequired` explicitly `Return True` even on a detected invalid bill type, so an invalid UB bill type code produces an audit message but does not, by itself, abort the Header group.
- The claim-merge resolution inside `val_fe_ClaimExists` can silently repoint `Bill.Claim` to a different claim mid-validation; subsequent rules in the same group see the updated claim.
- The October 1, 2015 ICD-10 span cutoff and its four UB bill-type-prefix exceptions are hard-coded in `clsBillEditor`, so any future exception codes require a code change rather than configuration.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts.

## Sources
- `Business\SAIF.Business.Claim.Bill.AutomatedAudit\AuditUtilities\clsBillEditor.vb`
