---
title: Medical bill retrieval
summary: Loads a single medical bill or a security-filtered collection of medical bills through the medical billing API, applying worker-name confidentiality masking, pending-bill total suppression, and print-link/employee-flag propagation.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.Claim.MedicalBill
reference_type: package
operation_id: OP-MB-01
trigger: Caller invokes clsMedicalBill.GetMedicalBill(billID) for a single bill, or clsMedicalBillCollection.GetMedicalBills(searchCriteria[, security]) for a search
---

# Medical bill retrieval

Medical bill retrieval loads bill data from the medical billing web API rather than directly from Oracle. A caller either retrieves one bill by identifier or retrieves a collection using a `MedicalBillSearchRequest`. Collection retrieval additionally applies AD-resource authorization checks, builds print links for completed bills, and propagates a SAIF-employee flag; every returned bill computes worker-name masking, pending-bill total suppression, and lazily-loaded audit/EOB/adjustment data on demand.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MB-01 |
| **Trigger** | `clsMedicalBill.GetMedicalBill(dataportal, billID)` for a single bill; `clsMedicalBillCollection.GetMedicalBills(dataportal, searchCriteria[, security])` for a search |
| **Inputs** | `billID` (single retrieval); `MedicalBillSearchRequest` and, for the non-`IsMedicalBillSearch` overload, a `clsSecurityPrincipal` (collection retrieval) |
| **Outputs** | Populated `clsMedicalBill` or `clsMedicalBillCollection`; print link on completed bills; `IsSaifEmployee` flag; masked or unmasked `WorkerName`; suppressed or computed `TotalPaidAmt` |
| **Primary components** | `clsMedicalBill.GetMedicalBill`, `clsMedicalBill.BeforeRetrieve`, `clsMedicalBill.AfterRetrieve`, `clsMedicalBillCollection.GetMedicalBills`, `clsMedicalBillCollection.BeforeRetrieve`, `clsMedicalBillCollection.AfterRetrieve`, `clsMedicalBillCollection.BuildPrintLink`, `clsMedicalBill.WorkerName`, `clsMedicalBill.TotalPaidAmt` |
| **Entry point** | `Business\SAIF.Business.Claim.MedicalBill\clsMedicalBill.vb`, `Business\SAIF.Business.Claim.MedicalBill\clsMedicalBillCollection.vb` |

## Steps

1. **Single-bill retrieval.** The caller invokes `clsMedicalBill.GetMedicalBill(dataportal, billID)`. `BeforeRetrieve` formats the API route to `ROUTE_MEDICALBILL_RETRIEVE_BY_BILL_ID` (`v2/Integration/GetMedicalBillData/{billID}`); `AfterRetrieve` deserializes a `MedicalBillSingleResult` and calls the private `Fill` method with the returned `MedicalBillData` row when present.
   - If the API returns no data row: the object is returned unfilled (no explicit not-found error is raised).*
2. **Collection retrieval — external/authorized search.** The caller invokes `clsMedicalBillCollection.GetMedicalBills(dataportal, searchCriteria, security)`. `BeforeRetrieve` formats the route to `ROUTE_MEDICALBILL_RETRIEVE_BY_SEARCH_CRITERIA` (`v2/Integration/GetMedicalBillData`, POST) and sets the request body to the search criteria.
3. **Collection retrieval — medical-bill-search overload.** The parameterless-security overload `GetMedicalBills(dataportal, searchCriteria)` only issues the retrieval when `searchCriteria.IsMedicalBillSearch` is true; otherwise it returns `Nothing` without calling the API.
4. **Deserialize and load each row.** `AfterRetrieve` reads a `MedicalBillResult` and, for each `MedicalBillData` item, constructs a new `clsMedicalBill` and calls its internal `Load` method, which fills the object and marks it as an existing (non-new) instance.
5. **Apply print link and employee flag for non-search retrievals.** When `searchCriteria.IsMedicalBillSearch` is false, `AfterRetrieve` calls `BuildPrintLink` and sets `IsSaifEmployee` on the loaded bill:
   - `BuildPrintLink` sets `PrintLink` to a `PrintEOB(...)` JavaScript anchor only when `BillStatusType = Completed`; pending bills get no print link.
   - `IsSaifEmployee` is set from the collection's own `IsSAIFEmployee` check, which compares `SecurityPrincipal.Domain` to `"SAIF"` ([BR-MB-003](../business-rules.md#br-mb-003-saif-employee-status-affects-data-visibility)).
   - For an `IsMedicalBillSearch` retrieval, neither the print link nor the employee flag is set on the returned bills.*
6. **Authorization checks (lazy, per-collection).** `HasExposureAccess` and `HasHealthIssueAccess` lazily resolve and cache `SecurityPrincipal.IsAuthorized("ExposureClaim")` and `SecurityPrincipal.IsAuthorized("CollateralHealthClaim")` respectively ([BR-MB-001](../business-rules.md#br-mb-001-exposure-claims-require-exposureclaim-ad-resource-authorization), [BR-MB-002](../business-rules.md#br-mb-002-collateral-health-claims-require-collateralhealthclaim-ad-resource-authorization)). These properties are exposed for callers to apply filtering; the retrieval itself does not filter rows based on them.*
7. **Worker-name confidentiality masking.** Reading `clsMedicalBill.WorkerName` returns `** Confidential **` instead of the formatted name when the caller is internal (or the bill's `IsSaifEmployee` flag is set) and `ClaimSecurity.IsWorkerConflict` is true ([BR-MB-021](../business-rules.md#br-mb-021-worker-name-is-masked-for-confidential-claims)).
   - `ClaimSecurity` is lazily resolved via `clsClaimSecurity.GetClaimSecurity(dataPortalInfo, ClaimID)`.

   > **Origin**: `clsClaimSecurity` and its claim-security data (including `IsWorkerConflict` and `WorkerNameFormatted`) are implemented in `SAIF.Business` and executed on behalf of this operation. See [Claim information and authorization support](../../saif-business/operations/claim-information-and-authorization-support.md) (`OP-SB-07`) in the `SAIF.Business` documentation set. Note: this operation calls the direct `clsClaimSecurity.GetClaimSecurity(dpi, claimID)` overload rather than the CCClaimData API route described as the primary path on that operation page; behavior is expected to be equivalent but was not independently re-verified against that page's documented steps.*
8. **Provider location resolution (lazy).** Reading `clsMedicalBill.ProviderLocation` lazily resolves `Provider.clsProviderLocation.GetProviderLocation(dataPortalInfo, ProviderLocationID)`, used by `ProviderRegisteredName` and `ProviderBusinessName`.

   > **Origin**: `Provider.clsProviderLocation.GetProviderLocation` is implemented in `SAIF.BOF.Business.View.Provider` and executed on behalf of this operation. That library is documented in the previous format, so no per-operation page exists; see [Operations and processes](../../saif-business-view-provider/operations/provider-location-retrieval.md) in the `SAIF.BOF.Business.View.Provider` documentation set.
9. **Pending-bill total suppression.** Reading `TotalPaidAmt` returns a null value instead of `TotalAllowedAmt - TotalMCOAdminFeeAmt` when the bill is `Pending`, has a parent collection, and that parent's originating search criteria has `IsMedicalBillSearch = True` ([BR-MB-019](../business-rules.md#br-mb-019-pending-bill-payment-totals-are-suppressed-during-a-medical-bill-search)).
10. **Bulk audit-detail suppression.** Setting `clsMedicalBillCollection.SuppresAuditDetail = True` propagates `SuppressAuditDetail = True` to every bill in the collection, which in turn skips the lazy loads described in [Audit service and adjustment retrieval](audit-service-and-adjustment-retrieval.md) and [EOB note retrieval](eob-note-retrieval.md) ([BR-MB-020](../business-rules.md#br-mb-020-audit-and-eob-detail-retrieval-is-suppressed-for-bulk-print-views)).
11. **Aggregate adjustment descriptions.** `clsMedicalBillCollection.AuditDescriptions` walks every non-suppressed bill's audit services and their adjustments, builds a deduplicated `clsAdjustmentCodeCollection` (delegating each code lookup to [Adjustment code lookup](adjustment-code-lookup.md)), and sorts the result by `Code`.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Caller requests bill data]) --> Which{Single bill or search?}
	Which -->|Single bill| SingleRoute[Route: GetMedicalBillData/{billID}]
	SingleRoute --> SingleFill[Fill bill from MedicalBillSingleResult]
	Which -->|Search| SearchType{IsMedicalBillSearch?}
	SearchType -->|Yes, no security overload| SearchRouteA[POST GetMedicalBillData<br>no print link / employee flag applied]
	SearchType -->|No, with security| SearchRouteB[POST GetMedicalBillData<br>BuildPrintLink + IsSaifEmployee applied]
	SearchRouteA --> LoadEach[Load each MedicalBillData row]
	SearchRouteB --> LoadEach
	SingleFill --> Compute[Compute WorkerName masking,<br>TotalPaidAmt suppression on read]
	LoadEach --> Compute
	Compute --> Done([Bill or collection returned to caller])
```

## Failure and edge-case behavior

- A single-bill retrieval with no matching row returns an unfilled `clsMedicalBill` rather than raising a not-found error.*
- The `GetMedicalBills(dataportal, searchCriteria)` overload silently returns `Nothing` when `IsMedicalBillSearch` is false, so callers relying on this overload for a non-medical-bill-search must use the security-parameter overload instead.
- Worker-name masking and pending-bill total suppression are computed on every read, not cached, so they always reflect the current `Parent`/`ClaimSecurity` state at access time.
- `AuditDescriptions` on both the bill and the collection silently skip bills with `SuppressAuditDetail = True`, which can make aggregate adjustment totals appear incomplete for bulk-print collections.

## 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.MedicalBill\clsMedicalBill.vb`
- `Business\SAIF.Business.Claim.MedicalBill\clsMedicalBillCollection.vb`
- `Business\SAIF.Business.Claim.MedicalBill\MedicalBillSearchRequest.vb`
- `Business\SAIF.Business.Claim.MedicalBill\MedicalBillResult.vb`
