Skip to content

Audit bill comparison

clsAuditCompare.CompareBills is a standalone diagnostic utility, independent of the BillAuditEngine.AuditBill pipeline, that compares two clsBillAudit snapshots — typically a pre- and post-audit copy of the same bill — across header fields, status, audit totals, messages, adjustments, and audited-service lines, and reports every mismatch as a comparison error.

Field Value
Operation ID OP-AA-06
Trigger Caller invokes clsAuditCompare.CompareBills(inAudit1, inAudit2, Optional ForceCompare As Boolean = False)
Inputs Two clsBillAudit instances; optional ForceCompare flag to bypass the matching-BillID precondition
Outputs Boolean match result (True when no compare errors were added); collection of comparison error messages describing each mismatched field
Primary components clsAuditCompare.CompareBills, clsAuditCompare.CompareField
Entry point Business\SAIF.Business.Claim.Bill.AutomatedAudit\AuditUtilities\clsAuditCompare.vb

Steps

  1. Store inputs. CompareBills stores the two supplied clsBillAudit objects.
  2. Check matching bill identity. Unless ForceCompare = True, the two bills must share the same BillID; otherwise add error "Bills do not have matching ID's - Compare Cancelled." and the comparison for identity stops here (other sections below still run against the given inputs).
  3. Compare bill header properties. Compare BillTotalAmount, StatementFromDate, StatementThruDate, ClaimID, DRGCode, ClaimNumber, and ClaimCheckValue using CompareField (see step 8 for field-specific comparison rules).
  4. Compare latest status records. Select each bill's latest status row by UpdateDate descending and compare StatusCode and ResponsiblePartyID. If either bill has no status record, add error "Could not determine matching Status Records".
  5. Compare audit-level properties. Compare AuditReceiptDate, ChargeableCostFlag, PrintEobFlag, SpecialHandlingCode, TotalAllowedAmount, TotalChargedAmount, and TotalMcoAdminFeeAmount.
  6. Compare audit messages. If the message counts differ, add a non-match result with message "Comparison of Message Text and Category cancelled." Otherwise, sort both message collections by category/text and compare MessageText and MessageCategory pairwise.
  7. Compare adjustments. If the adjustment counts differ, add a non-match result with message "Comparison of property elements cancelled." Otherwise, sort both adjustment collections by AuditServiceID and code and compare AuditAdjustmentAmount, AuditAdjustmentCode, and AuditServiceID pairwise.
  8. Compare audited services. If the service counts differ, add a non-match result with message "Property comparison has been cancelled for this service." Otherwise, compare a broad set of audited-service fields by matching ServiceID. CompareField applies type-specific rules:
  9. MessageText — compares letters case-insensitively, then digits (excluding zeroes), then punctuation, with distinct mismatch messages: "Values do not have the same letters.", "Values do not have the same digits.", "Values do not have the same punctuation marks."
  10. String fields such as DRGCode, McoEligibilityStatusCode, service modifiers, and ServiceCode — trimmed string comparison.
  11. Decimal *Amount fields — numeric comparison, displayed as currency in the mismatch message.
  12. DateTime fields — exact comparison.
  13. All other fields — case-insensitive string comparison.
  14. On any exception while comparing a field, add error "<Class>/<Key>-<Prop>: Could not be compared - <exception>" rather than allowing the exception to propagate.
  15. Return overall result. CompareBills returns True only if no comparison errors were added across steps 2–8.

Process flow

flowchart TD
    Start([CompareBills invoked]) --> IDCheck{ForceCompare or<br>BillID matches?}
    IDCheck -->|No| IDError[Add error:<br>IDs do not match]
    IDCheck -->|Yes| Header[Compare bill header fields]
    IDError --> Header
    Header --> Status[Compare latest status records]
    Status --> Audit[Compare audit-level totals/flags]
    Audit --> Messages{Message counts match?}
    Messages -->|No| MsgCancelled[Add: comparison cancelled]
    Messages -->|Yes| MsgCompare[Compare sorted message pairs]
    MsgCancelled --> Adjustments
    MsgCompare --> Adjustments{Adjustment counts match?}
    Adjustments -->|No| AdjCancelled[Add: comparison cancelled]
    Adjustments -->|Yes| AdjCompare[Compare sorted adjustment pairs]
    AdjCancelled --> Services
    AdjCompare --> Services{Service counts match?}
    Services -->|No| SvcCancelled[Add: comparison cancelled]
    Services -->|Yes| SvcCompare[Compare matched service fields<br>via CompareField]
    SvcCancelled --> Done
    SvcCompare --> Done([Return True if no errors added])

Failure and edge-case behavior

  • A count mismatch in messages, adjustments, or services cancels field-by-field comparison for that section entirely and reports a single cancellation message rather than identifying which specific rows differ.
  • ForceCompare = True allows comparing two bills with different BillID values; all subsequent sections still run against whatever data each bill contains, which can produce a large number of unrelated mismatches.
  • Exceptions during an individual field compare are caught and reported as comparison errors rather than aborting the whole comparison, so a single malformed field does not prevent the rest of the comparison from completing.
  • This operation is not invoked anywhere in the BillAuditEngine.AuditBill pipeline traced in Automated bill audit orchestration; it is a standalone tool for callers who need to verify audit results independently.*
  • Source contains a commented-out Oracle-vs-DB2 DispenseAsWrittenCode normalization branch that is excluded from this operation's behavior as dead code.

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\clsAuditCompare.vb