---
title: BillValidator
summary: API reference for BillValidator.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-24
library: SAIF.Services
reference_type: package
---

# BillValidator

Validates a `Bill` aggregate before persistence, requiring a total amount and bill type, bounding the DRG code's length, and — for three optional fields that may be blank — deferring to `IClaimQueryProvider` or format checks only when a value is actually supplied: a SAIF claim number must resolve to an existing claim via `IClaimQueryProvider.IsValidClaim`, a UB bill type code must be purely numeric, and a CBP admission type code must be one of a fixed allow-list of single digits.

## Purpose
- Requires `BillTotalAmount` and `BillTypeCode` to be non-null; limits `DrgCode` to at most 3 characters.
- When `SaifClaimNumber` is supplied (non-null/non-empty), requires it to resolve to an existing claim via `IClaimQueryProvider.IsValidClaim`; blank values are treated as valid (skip the check).
- When `UbBillTypeCode` is supplied, requires it to contain only numeric characters via `ContainsOnlyNumericCharacters()`; blank values are treated as valid.
- When `CBPAdmissionTypeCode` is supplied, requires it to be one of the allow-listed values `1`, `2`, `3`, `4`, `5`, `9`; blank values are treated as valid.

## Context
- Namespace: `SAIF.Services.Claims.Bills.Validators`
- Assembly/package: `SAIF.Services` (packaged inside the `SAIF.SAIFCode.Core` NuGet package)

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| BillValidator | `BillValidator(IClaimQueryProvider claimQueryProvider)` | Wires required/length rules for `BillTotalAmount`, `BillTypeCode`, `DrgCode`, plus conditional `Must` predicates for `SaifClaimNumber` (claim existence lookup), `UbBillTypeCode` (numeric-only format), and `CBPAdmissionTypeCode` (fixed allow-list).* |

## Inherited members
`BillValidator` inherits its full public surface from FluentValidation's `AbstractValidator<Bill>` base class (`FluentValidation.AbstractValidator<T>`), which is declared in the external FluentValidation NuGet package and is not otherwise documented in this repository. The table below gives the full signature and purpose of each inherited public member actually used to build the rule set in the constructor, so the type remains self-contained without requiring the reader to consult the FluentValidation package directly.

| Member | Signature | Purpose |
| --- | --- | --- |
| `RuleFor` | `IRuleBuilderInitial<Bill, TProperty> RuleFor<TProperty>(Expression<Func<Bill, TProperty>> expression)` | Begins a validation rule chain for a specific property of the `Bill` instance being validated; used here for `BillTotalAmount`, `BillTypeCode`, `DrgCode`, `SaifClaimNumber`, `UbBillTypeCode`, and `CBPAdmissionTypeCode`.* |
| `NotNull` | `IRuleBuilderOptions<Bill, TProperty> NotNull()` | Fails validation when the property value is null; used for `BillTotalAmount` and `BillTypeCode`.* |
| `MaximumLength` | `IRuleBuilderOptions<Bill, string> MaximumLength(int maximumLength)` | Fails validation when a string property exceeds the given character length; bounds `DrgCode` to 3 characters.* |
| `Must` | `IRuleBuilderOptions<Bill, TProperty> Must(Func<Bill, TProperty, bool> predicate)` | Fails validation when the supplied predicate returns false for the current `Bill` and property value; used for the claim-existence, numeric-format, and allow-list checks on `SaifClaimNumber`, `UbBillTypeCode`, and `CBPAdmissionTypeCode`.* |
| `When` | `IRuleBuilderOptions<Bill, TProperty> When(Func<Bill, bool> predicate, Action action)` | Applies the rules registered inside `action` only when `predicate` evaluates true for the current `Bill`, letting the conditional fields skip validation when blank.* |
| `Validate` | `ValidationResult Validate(Bill instance)` | Runs every configured rule against `instance` synchronously and returns a `ValidationResult` listing any failures; the primary entry point callers invoke.* |
| `ValidateAsync` | `Task<ValidationResult> ValidateAsync(Bill instance, CancellationToken cancellation = default)` | Runs every configured rule against `instance` asynchronously, required when a rule performs async work such as the `SaifClaimNumber` claim-existence lookup.* |

## Behavioral notes
- Validation is enforced via FluentValidation's `AbstractValidator<T>` base.*
- The `SaifClaimNumber`, `UbBillTypeCode`, and `CBPAdmissionTypeCode` rules each use an inline null/empty short-circuit (via `IsNullOrEmpty()`) inside the `Must` predicate so the field is only actively checked when a value is present; each treats a blank value as valid.*
- The `SaifClaimNumber` rule performs a live existence lookup against `IClaimQueryProvider`, so validation outcome depends on external claim data at validation time rather than only the request's own fields.*

## Constraints and usage notes
- Requires an `IClaimQueryProvider` implementation to be supplied via constructor injection for the claim-existence check.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- Services/SAIF.Services/Claims/Bills/Validators/BillValidator.cs
