---
title: DCBS reimbursement balancing
summary: Matches each DCBS reimbursement detail against the claim's unreconciled billed expenses, marks matched bills and expenses as reimbursed, and reconciles the remittance when the amounts agree.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.Claim.EAIP
reference_type: package
operation_id: OP-EAIP-08
trigger: Batch process calls clsBalanceDCBS.ProcessOneBatch for a DCBS posted date
---

# DCBS reimbursement balancing

DCBS remits money against SAIF's EAIP bills, but the remittance identifies claims by DCBS's own numbers and amounts by expense type — not by bill. This operation closes that gap. For every reimbursement posted on a given date it walks the detail rows, resolves each to a SAIF claim, and tries to find, among that claim's unreconciled billed expenses, a match for each expense-type amount. Matched administrative fees, wage subsidies, and purchases are stamped as reimbursed; when the matched total equals the detail total the detail reconciles, and when every detail's total equals the remittance amount the whole reimbursement reconciles. Each detail is processed in its own transaction, committed only if it reconciled.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-EAIP-08 |
| **Trigger** | Batch process constructs `clsBalanceDCBS` and calls `ProcessOneBatch(postedDate)`; `BalanceToDCBS(reimbursement)` can also be called for a single remittance |
| **Inputs** | A DCBS posted date; the reimbursements posted on it with their detail rows and expense-type amounts; each claim's unreconciled expense billings; the resolved claim data for name comparison |
| **Outputs** | Updated `EAIP_EXPENSE_BILLING` reimbursed amounts; wage subsidies and purchases moved to `Reimbursed` with the posted date as status date; the admin-fee reimbursement-detail link recorded on the bill; per-detail reconciled flags; the remittance's reconciled amount, reconciled date, and reconciled flag; counters for records read, reconciled, skipped, and name mismatches; warning and informational messages for unmatched claims, missing expenses, and name mismatches |
| **Primary components** | `clsBalanceDCBS` (`ProcessOneBatch`, `BalanceToDCBS`, counters), `dcbsMethods` (`GetDCBSWriteOff`), `clsReimbursementDetail`, `clsDetailAmount` (`MakeDirty`), `clsExpenseBilling`, `clsBilling`, `clsWageSubsidy`, `clsPurchase` |
| **Entry point** | `Business\SAIF.Business.Claim.EAIP\Reimbursement\clsBalanceDCBS.vb` |

## Steps

1. **Load the batch.** `ProcessOneBatch(postedDate)` retrieves every reimbursement posted on the given date through the posted-date reader ([Details](../procedures/pk82500_eaip.md#getreimbbyposteddate)), then processes each one in turn, saving the collection afterwards when it is valid. Retrieval and the structure of a remittance are covered by [Reimbursement recording](reimbursement-recording.md).
2. **Walk the detail rows.** `BalanceToDCBS(reimb)` iterates the remittance's detail rows, incrementing the records-read counter for each and resetting the running reconciled total for the remittance.
3. **Relax validation for the batch user.** When the acting user identifier is `BATCH`, the detail's rules are cleared before processing. This is what allows a detail whose DCBS claim number cannot be resolved to be saved with its outcome recorded instead of blocking the batch.
4. **Skip details already reconciled.** A detail already flagged reconciled is not reprocessed; its total is simply added to the running remittance total so the header arithmetic still balances on a re-run.
5. **Bracket each detail in its own transaction.** Any pending transaction is ended before a new one is begun for the current detail. The commit decision is deferred to the end of the detail — a detail that fails to reconcile rolls back its own partial matching without affecting details already committed.
6. **Skip unresolvable claims.** The detail's claim identifier is read from the resolved claim data. If the claim data is invalid, the records-skipped counter is incremented and a warning "Claim not found:" naming the DCBS claim number is emitted; the detail is abandoned without any matching attempt.
   > **Origin**: Claim resolution and the formatted worker name compared later in this operation are implemented by `clsClaimData` in `SAIF.Business.View.Claim` 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-claim/operations-processes.md) in the `SAIF.Business.View.Claim` documentation set.
7. **Load the claim's unreconciled billings.** For a resolvable claim, the non-reconciled expense billings are loaded — the bills for that claim whose billed amount still differs from the reimbursed amount ([SQL-018](../sql/SQL-018.md), [Details](../procedures/pk82500_eaip.md#getbillingsbyclaim)). Everything the detail can possibly match must come from this set.
8. **Match the administrative fee (type `A`).** For an admin-fee amount, the run looks for a bill whose billed amount equals the detail total, whose admin fee is positive, whose admin-fee reimbursement-detail link is either unset or already points at this detail, and whose admin fee equals the amount DCBS reimbursed. If nothing matches, a second pass repeats the search without the billed-amount condition, so a fee reimbursed alongside other content on the same bill can still be found. The matched bill's admin-fee reimbursement-detail link is set to this detail, which is what prevents the same fee being claimed twice by two remittances.
9. **Match wage subsidies (type `W`).** For a wage amount, the run loads the wage subsidy behind each candidate expense billing. If the loaded object comes back new — meaning the expense no longer exists — a warning "wage subsidy not found" naming the expense is emitted and the candidate is passed over. Otherwise the wage subsidy is moved to `Reimbursed` unless it is already `Amended` (an amended expense keeps its amended status so the amendment can still be billed), its status date is set to the reimbursement's posted date, and it is saved.
10. **Apply the DCBS write-off to wage subsidies.** The matched billing line's reimbursed amount is set to its billed amount plus the DCBS write-off for the claim. `dcbsMethods.GetDCBSWriteOff(dpi, claimID)` runs an inline query across the expense, expense-billing, and billing tables that returns the largest absolute non-zero write-off amount, signed negative when the largest negative write-off exceeds the largest positive one, and zero when there is none; it matches on either the expense identifier or the original-expense identifier so an amendment's write-off is found through its original. Note that the claim identifier is concatenated into the statement text rather than bound as a parameter.*
11. **Match other expense types.** Any other expense-type amount follows the wage-subsidy pattern against purchases: load the purchase behind the candidate expense billing, warn when it comes back new, otherwise move it to `Reimbursed` unless already `Amended`, set the status date to the posted date, save it, and set the billing line's reimbursed amount to its billed amount. No write-off adjustment is applied on this path.
12. **Record each match.** Every matched detail amount is explicitly marked dirty through `MakeDirty()` so the save cascade writes it back even though none of its own fields changed, and its reimbursed amount is added to the detail's running reconciled total.
13. **Compare the worker names.** The resolved claim's formatted worker name is compared with the DCBS-supplied worker name after both are upper-cased and trimmed. On a match the detail's matching-name flag is set; on a mismatch the name-mismatch counter is incremented and an informational reconciliation message naming both spellings is emitted. A mismatch is reported, never fatal — the money still reconciles.
14. **Save the matched bills and expenses.** The billing collection and the expense-billing collection are saved when valid, writing the new reimbursed amounts and the admin-fee link back through the billing update statements ([SQL-028](../sql/SQL-028.md), [SQL-029](../sql/SQL-029.md), [Details](../procedures/pk82500_eaip.md#eaip_expense_billing_update)).
15. **Decide whether the detail reconciled.** When the detail's total amount equals the total matched, the detail is flagged reconciled and the records-reconciled counter is incremented ([BR-PROC-012](../business-rules.md#br-proc-012-a-reimbursement-detail-reconciles-only-when-amounts-match-the-detail-total)). Otherwise the records-skipped counter is incremented and a warning "Not Reconciled:" naming the detail is emitted. Either way the detail's total is added to the remittance's running total.
16. **Commit or roll back the detail.** The detail's transaction is ended with a commit flag equal to the detail's reconciled flag. A detail that did not reconcile therefore discards every status change, reimbursed amount, and admin-fee link it made, leaving the claim exactly as it was for the next attempt.
17. **Reconcile the remittance.** After the last detail, the remittance's reconciled amount is set to the accumulated total. When that equals the reimbursement amount, the reconciled date is set to today and the remittance is flagged reconciled. When the accumulated total is zero, it is instead stored as `0.01` — a sentinel whose stated purpose in the code is to make the next batch skip the remittance rather than reprocess a remittance that matched nothing.*
18. **Save the batch.** Control returns to `ProcessOneBatch`, which saves the reimbursement collection when it is valid, persisting the reconciled flags, dates, and amounts through the reimbursement update statement ([SQL-035](../sql/SQL-035.md), [Details](../procedures/pk82500_eaip.md#eaip_reimbursement_update)). The four counters are left on the balancing object for the batch report.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Batch starts for a posted date]) --> Load[Load reimbursements<br>posted on that date]
	Load --> Det[Next detail row;<br>RecordsRead + 1]
	Det --> Batch{User is BATCH?}
	Batch -->|Yes| Clear[Clear the detail's rules]
	Batch -->|No| Recon
	Clear --> Recon{Already reconciled?}
	Recon -->|Yes| Add[Add total to remittance running total]
	Recon -->|No| Txn[End any pending transaction;<br>begin a transaction for this detail]
	Txn --> Claim{Claim data valid?}
	Claim -->|No| Skip[RecordsSkipped + 1;<br>warn Claim not found]
	Claim -->|Yes| Bills[Load the claim's<br>unreconciled expense billings]
	Bills --> Type{Detail amount type}
	Type -->|A admin fee| Fee[Match bill on admin fee, link,<br>and amount; retry without<br>billed-amount condition]
	Type -->|W wages| Wage[Load wage subsidy; set Reimbursed<br>unless Amended; add DCBS write-off]
	Type -->|other| Purch[Load purchase; set Reimbursed<br>unless Amended]
	Fee --> Mark[MakeDirty on the detail amount;<br>accumulate matched total]
	Wage --> Mark
	Purch --> Mark
	Mark --> More{More detail amounts?}
	More -->|Yes| Type
	More -->|No| Name[Compare claim worker name<br>with DCBS worker name]
	Name --> SaveB[Save billing and<br>expense-billing collections]
	SaveB --> Bal{Detail total = matched total?}
	Bal -->|Yes| Ok[IsReconciled = true;<br>RecordsReconciled + 1]
	Bal -->|No| Not[RecordsSkipped + 1;<br>warn Not Reconciled]
	Ok --> End[End transaction, commit =<br>detail reconciled flag]
	Not --> End
	Skip --> End
	End --> Next{More details?}
	Next -->|Yes| Det
	Add --> Next
	Next -->|No| Head[ReconciledAmount = running total]
	Head --> Eq{Equals reimbursement amount?}
	Eq -->|Yes| Done[ReconciledDate = today;<br>IsReconciled = true]
	Eq -->|No, and total is zero| Sent[Store 0.01 sentinel<br>so the next batch skips it]
	Eq -->|No| SaveR
	Done --> SaveR[Save the reimbursement collection]
	Sent --> SaveR
	SaveR --> Fin([Counters reported to the batch])
```

## Failure and edge-case behavior

- A detail that does not reconcile rolls back everything it did, including valid partial matches. The next run therefore starts that detail from scratch rather than continuing where it stopped.
- The `0.01` reconciled-amount sentinel makes an entirely unmatched remittance look partly reconciled in the data. Any report summing reconciled amounts will be off by one cent per such remittance.*
- Clearing the rules for the `BATCH` user disables the claim-number validation on the detail, so a detail with an unresolvable claim number is saved with a warning rather than rejected.
- The claim identifier is concatenated directly into the write-off query text instead of being bound. The value comes from resolved claim data rather than user input, but the pattern is unsafe.*
- The admin-fee second pass drops the billed-amount condition, which widens matching to any bill on the claim with a positive admin fee and an unclaimed link. On a claim with several such bills the first candidate in the loaded order wins.*
- An expense that has been deleted since billing yields a new object rather than an error; the run emits a "not found" warning and leaves the corresponding amount unmatched, which usually means the detail then fails to reconcile.
- An expense already in `Amended` status is deliberately not moved to `Reimbursed`, so the amendment can still flow through [DCBS bill generation and billing records](dcbs-bill-generation.md).
- The write-off adjustment is claim-wide, not expense-specific: the single largest absolute write-off on the claim is applied to whichever wage-subsidy billing line is being matched. On a claim with several written-off expenses this can credit the wrong line.*
- A name mismatch never blocks reconciliation; it only raises the counter and an informational message for manual review.

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.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.EAIP\Reimbursement\clsBalanceDCBS.vb`
- `Business\SAIF.Business.Claim.EAIP\Reimbursement\dcbsMethods.vb`
- `Business\SAIF.Business.Claim.EAIP\Reimbursement\clsReimbursement.vb`
- `Business\SAIF.Business.Claim.EAIP\Reimbursement\clsReimbursementDetail.vb`
- `Business\SAIF.Business.Claim.EAIP\Reimbursement\clsDetailAmount.vb`
- `Business\SAIF.Business.Claim.EAIP\Billing\clsBilling.vb`
- `Business\SAIF.Business.Claim.EAIP\Billing\clsExpenseBilling.vb`
- `Business\SAIF.Business.Claim.EAIP\Period\clsWageSubsidy.vb`
- `Business\SAIF.Business.Claim.EAIP\Period\clsPurchase.vb`
