Skip to content

Audit and audited services

An audit is the aggregate record of how a bill's services were reviewed: the audit header carries bill-level totals and flags, each service on the bill gets its own audited-service line, each audited-service line can carry one or more payment adjustments, and the audit as a whole can accumulate error, warning, and informational messages. All four record types share the same bill-scoped lifecycle and the same rows-affected concurrency contract, and they are saved together whenever the audit is saved — either directly by a caller or as a cascade from Bill CRUD.

Field Value
Operation ID OP-CB-02
Trigger clsBill.GenerateAudit() creates a new audit and its audited-service lines as part of a bill save; callers can also call clsAudit.NewAudit(...)/GetAudit(...) directly and edit the audited-service, adjustment, and message collections before calling Save()
Inputs BillID; audit header fields (ChargeableCostFlag, PrintEobFlag, AuditReceiptDate, SpecialHandlingCode, total amounts); per-service audited fields (service/provider/date/amount/diagnosis/prescriber); adjustment code and amount per audited service; message category and text
Outputs Populated clsAudit with its child collections on retrieve; persisted CBP_AUDIT, CBP_AUDITED_SERVICE, CBP_AUDITED_SERVICE_ADJUSTMENT, and CBP_AUDIT_MESSAGE rows on save; broken rules and DB-contention errors on failure
Primary components clsAudit.NewAudit, clsAudit.GetAudit, clsAudit.OnSave, clsAuditedServiceCollection.NewAuditedService, clsAuditedServiceAdjustmentCollection.NewServiceAdjustment, clsAuditMessageCollection.NewMessage, clsAuditMessage.NewErrorMessage/NewWarningMessage/NewInformationMessage
Entry point Business\SAIF.Business.Claim.Bill\Core\clsAudit.vb

Steps

  1. Create a new audit. clsAudit.Create() seeds BillID from the criteria and creates empty child collections: clsAuditMessageCollection.NewMessageCollection, clsAuditedServiceAdjustmentCollection.NewAuditedServiceAdjustmentCollection, and clsAuditedServiceCollection.NewAuditedServiceCollection.
  2. Retrieve an existing audit. GetAudit(...) builds a Criteria(BillID) and retrieves through MyCriteria.RetrieveSQL; AfterRetrieve loads the first row into the object, then MarkOld().
  3. Insert the audit header. BeforeInsert/AfterInsert write a single row into CBP_AUDIT with the bill ID, flags, receipt date, special-handling code, and total amounts (SQL-003, CBP_AUDIT).
  4. On a rows-affected value other than 1: add "Insert Failed" (BR-004).
  5. Update the audit header. BeforeUpdate/AfterUpdate update CBP_AUDIT by BILL_ID with optimistic concurrency on UPDATE_NUM (SQL-032, CBP_AUDIT).
  6. On a rows-affected value other than 1: add a DB-contention error (BR-004).
  7. Delete the audit header. BeforeDelete/AfterDelete delete the CBP_AUDIT row for the bill (SQL-042, CBP_AUDIT); child collections are cleared rather than saved when the parent is deleted.
  8. On a rows-affected value other than 1: add a DB-contention error (BR-004).
  9. Stamp update fields (OnSave). UpdateDate = Now and UpdateUser from the data-portal user are stamped on the header before every insert/update/delete.
  10. Add a new audited-service line. clsAuditedServiceCollection.NewAuditedService() auto-assigns the next ServiceID as Max(existing) + 1 (or 1). NewAuditedService(inServiceID) instead requires an explicit service ID and first checks the collection for a duplicate.
  11. If a line with that ServiceID already exists: throw "Attempt to generate new Audit Service Line for service #<id> failed. - Service already exists." (BR-005).
  12. Persist an audited-service line. clsAuditedService.Create() seeds DPI, BillID, ServiceID, and update user.
  13. Insert: writes the full audited-service row — service, provider, date, amount, diagnosis, and prescriber fields — into CBP_AUDITED_SERVICE (SQL-004, CBP_AUDITED_SERVICE).
  14. Update: updates nearly all service columns keyed by BILL_ID + AUDITEDSERVICE_ID + UPDATE_NUM (SQL-033, CBP_AUDITED_SERVICE).
  15. Delete: deletes by BillID and AuditedserviceID (SQL-043, CBP_AUDITED_SERVICE).
  16. Each path enforces the shared concurrency rule (BR-004).
  17. Reference fields (claim bill type, original-bill code, bill status, diagnosis type) resolve through mdlCBPSupportingData code maps, and service descriptions resolve through the linked service's description list.

Origin: The reference-code resolution (GetClaimBillTypeCodeMap, GetOriginalBillCodeMap, GetBillStatusCodeMap, GetDiagnosisTypeCodeMap) is implemented by mdlCBPSupportingData in this same library; the service-description lookup is implemented by Service reference lookups (clsServiceInfo.ServiceDescriptions). 9. Validate and track dirtiness across the aggregate. clsAuditedService.IsValid() validates its own state together with its nested adjustment collection and returns ErrorCount = 0; IsDirty() folds in the adjustment collection's dirty state, so a dirty adjustment makes its parent audited-service line dirty too. 10. Add a new service-level adjustment. clsAuditedServiceAdjustmentCollection.NewServiceAdjustment(...) creates the child via clsAuditedServiceAdjustment.NewAuditedServiceAdjustment(...), sets the adjustment code and amount, and adds it to the list. clsAuditedServiceAdjustment.Create() seeds BillID and AuditServiceID. - Insert: writes the adjustment row into CBP_AUDITED_SERVICE_ADJUSTMENT (SQL-005, CBP_AUDITED_SERVICE_ADJUSTMENT). - Update: updates code/amount keyed by BILL_ID + AUDITSERVICE_ID + CODE + UPDATE_NUM (SQL-034, CBP_AUDITED_SERVICE_ADJUSTMENT). - Delete: by BillID, AuditServiceID, and adjustment code (SQL-044, CBP_AUDITED_SERVICE_ADJUSTMENT). - Each path enforces the shared concurrency rule (BR-004). - SettlementGroup, AdjustmentType, and AuditedAdjustmentCategory all resolve through mdlCBPSupportingData reference maps (SQL-011, SQL-013). 11. Add a new audit message. clsAuditMessageCollection.NewMessage(...) optionally creates a temporary read-only in-memory message (assigning the next local MessageID) before always replacing it with a persisted-style object created via NewWarningMessage, NewInformationMessage, or NewErrorMessage, which is then added to the collection. - Add(Item) on the collection is blocked directly and throws "Status can only be added via a Bill"* — the same guard text used by clsBillStatusCollection, so new messages can only be introduced through the factory methods. 12. Persist an audit message. clsAuditMessage.Create() assigns BillID, allocates MessageID through GetLegacyID(...) (legacy CBP sequence, CBPIDType.AuditError), sets the category, and sets the message text. - Insert: writes the message row into CBP_AUDIT_MESSAGE (SQL-006, CBP_AUDIT_MESSAGE). - Update: updates text/category keyed by MESSAGE_ID + BILL_ID + UPDATE_NUM (SQL-035, CBP_AUDIT_MESSAGE). - Delete: by MessageID and BillID (SQL-045, CBP_AUDIT_MESSAGE). - Each path enforces the shared concurrency rule (BR-004).

> **Origin**: `MessageID` allocation reuses the same `GetLegacyID` / `GetNextCBPSeqNum` sequence path as [Bill CRUD](bill-crud.md) step 1, calling the Oracle procedure `sp82385_get_next_bill_seqnum` with `CBP_AUDIT_ERROR`.
  1. Complete the save. OnSaveComplete() on the audit header saves the audited-service, adjustment, and message collections after the header itself is inserted, updated, or deleted; if the audit was deleted, the child collections are cleared instead of saved.

Process flow

The following diagram visualizes how an audit and its three child record types are validated and persisted together.

flowchart TD
    Start([Bill save triggers GenerateAudit,<br>or caller edits audit directly]) --> Header[Create/retrieve<br>Audit header]
    Header --> HeaderSave[Insert/Update/Delete CBP_AUDIT]
    HeaderSave --> Rows{RowsAffected = 1?}
    Rows -->|No| Contention([Contention error])
    Rows -->|Yes| Services[For each bill service:<br>NewAuditedService]
    Services --> Dup{ServiceID already<br>on audit?}
    Dup -->|Yes| DupErr([Duplicate-service exception])
    Dup -->|No| SaveService[Insert/Update/Delete<br>CBP_AUDITED_SERVICE]
    SaveService --> Adjust[Optional: NewServiceAdjustment<br>per audited service]
    Adjust --> SaveAdjust[Insert/Update/Delete<br>CBP_AUDITED_SERVICE_ADJUSTMENT]
    SaveService --> Messages[Optional: NewMessage<br>error / warning / information]
    Messages --> SaveMsg[Insert/Update/Delete<br>CBP_AUDIT_MESSAGE]
    SaveAdjust --> Done([Save returns success])
    SaveMsg --> Done

Failure and edge-case behavior

  • All four record types (audit header, audited service, adjustment, message) share the identical rows-affected concurrency contract; the caller cannot distinguish which table failed from the error text alone (BR-004).
  • Adding a duplicate ServiceID to an audit throws immediately rather than returning a broken-rule collection entry, so callers must catch the exception or pre-check for an existing line (BR-005).
  • Deleting the audit header clears rather than saves its child collections, so a deleted audit never leaves orphaned or stale audited-service, adjustment, or message rows from the same save cycle.
  • clsAuditMessageCollection.Add() reuses the exact guard message text from clsBillStatusCollection ("Status can only be added via a Bill"), which does not describe audit messages — this appears to be copied guard text rather than a message-specific string.*
  • clsAuditMessage field UpdateNumer (not UpdateNumber) is used in several places in source; this spelling is preserved here only to describe the code accurately, not as a documentation error.*

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\Core\clsAudit.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditCollection.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditedService.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditedServiceCollection.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditedServiceAdjustment.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditedServiceAdjustmentCollection.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditMessage.vb
  • Business\SAIF.Business.Claim.Bill\Core\clsAuditMessageCollection.vb
  • Business\SAIF.Business.Claim.Bill\AuditSupport\BillStatus.vb
  • Business\SAIF.Business.Claim.Bill\AuditSupport\BillType.vb
  • Business\SAIF.Business.Claim.Bill\AuditSupport\OriginalBills.vb
  • Business\SAIF.Business.Claim.Bill\AuditSupport\mdlCBPSupportingData.vb