---
title: Loss summary maintenance
summary: Creates, retrieves, updates, and deletes US_LOSS_SUMMARY rows, deriving totals from category offsets and the Claim Financial API.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.UnitStat.Claim
reference_type: package
operation_id: OP-USC-03
trigger: Caller invokes clsLossSummary.NewLossSummary / GetLossSummary, then Save() or Delete()
---

# Loss summary maintenance

`clsLossSummary` is the persisted record of a claim's reportable loss totals. Beyond plain CRUD, it derives its medical and indemnity totals from the sum of its child `LossCategories` (each an `US_LOSS_CATEGORY` row with `US_LOSS_CATEGORY_OFFSET` children), applies a settlement/third-party-prediction floor to indemnity amounts, and determines whether a claim counts as "Part B only" by delegating to coverage-combination and claim-data lookups. Persisted totals always reflect the derived values rather than any raw amount a caller might otherwise set.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-USC-03 |
| **Trigger** | `NewLossSummary(dpi, claimID)` to create, `GetLossSummary(dpi, claimID)` to retrieve, followed by `Save()` or `Delete()` |
| **Inputs** | `ClaimID`, `ValueDate` (optional override), child `LossCategories` collection |
| **Outputs** | Persisted or retrieved `US_LOSS_SUMMARY` row with derived `TotalIncurredMedicalAmount`, `TotalIncurredIndemnityAmount`, `TotalPaidMedicalAmount`, `TotalPaidIndemnityAmount` |
| **Primary components** | `clsLossSummary`, `clsLossSummaryCollection` |
| **Entry point** | `Business\SAIF.Business.UnitStat.Claim\Loss Summary\clsLossSummary.vb`, `Business\SAIF.Business.UnitStat.Claim\Loss Summary\clsLossSummaryCollection.vb` |

## Steps

1. **Value-date resolution.** `clsLossSummary` exposes a `ValueDate` property that defaults to the current retrieval/valuation date but can be overridden by the caller before a valuation pass — the override lookup allows callers (chiefly [loss valuation orchestration](loss-valuation-orchestration.md)) to value a summary as of an arbitrary historical date rather than "now".
2. **Coverage/claim delegation.** `CoverageCode` and `IsOnlyClaimPartB` are computed by delegating to same-library helpers and an external claim-data object:
   - `IsOnlyClaimPartB` calls `clsCoverageCombination.IsNotCoverageCombinationPartA` (see [Coverage combination management](coverage-combination-management.md)) to determine whether the claim is excluded from being a Part-A member, then inspects the claim's coverage code.
   - The underlying claim coverage code and related claim attributes are retrieved via `clsClaimData`.

     > **Origin:** `clsClaimData` is implemented in `SAIF.Business.View.Claim`, which is documented in its previous (pre-migration) format and has no corresponding per-operation anchor for this specific lookup. See [SAIF.Business.View.Claim operations and processes](../../saif-business-view-claim/operations-processes.md).
3. **Derived totals.** `TotalIncurredMedicalAmount` and `TotalPaidMedicalAmount` sum the corresponding amounts across all child `LossCategories`. `TotalIncurredIndemnityAmount` and `TotalPaidIndemnityAmount` do the same but additionally compute a floor from any `SETL`-category child offset whose `OffsetTypeCode` is `TPN` (third-party-prediction, non-lien): if the summed category total is below that floor, the floor is used instead; the final result is then clamped to a minimum of zero ([BR-006](../business-rules.md#br-006-indemnity-totals-are-floored-by-settlement-third-party-prediction-offsets-and-cannot-go-negative)).
4. **Retrieve.** `BeforeRetrieve` binds `ClaimID` and executes ([SQL-011](../sql/sql-011-select.md), [DUAL](../database-tables.md#dual) — the retrieval select is built from `dual` plus inline package-function calls rather than a direct table join):
   ```sql
   Select ... From dual Where ClaimID = :ClaimID
   ```
   - `AfterRetrieve`: loads the returned columns, retrieves the child `LossCategories` collection, and calls `MarkOld()`.
5. **Insert / update.** `BeforeInsert` ([SQL-006](../sql/sql-006-insert.md)) and `BeforeUpdate` ([SQL-021](../sql/sql-021-update.md)) against [US_LOSS_SUMMARY](../database-tables.md#us_loss_summary) both bind the four **derived** total properties — `TotalIncurredMedicalAmount`, `TotalIncurredIndemnityAmount`, `TotalPaidMedicalAmount`, `TotalPaidIndemnityAmount` — as the parameter values for `INCURRED_MEDICAL_AMOUNT`, `INCURRED_INDEMNITY_AMOUNT`, `PAID_MEDICAL_AMOUNT`, and `PAID_INDEMNITY_AMOUNT` respectively, rather than any raw backing-field amount a caller might have set directly ([BR-007](../business-rules.md#br-007-loss-summary-persistence-binds-derived-totals-not-raw-in-memory-amounts)).
   - `AfterInsert`/`AfterUpdate`: standard rows-affected check; on success cascades `Save()` to the child `LossCategories` collection and calls `MarkOld()`.
6. **Delete.** `BeforeDelete` executes ([SQL-026](../sql/sql-026-delete.md), [US_LOSS_SUMMARY](../database-tables.md#us_loss_summary)):
   ```sql
   DELETE us_loss_summary Where Claim_ID = :ClaimID
   ```
   - `AfterDelete`: standard rows-affected check; on success calls `MarkNew()`.
7. **Validity quirk.** `clsLossSummary.IsValid` **overwrites** rather than combines its base validity: it executes `Valid = MyBase.IsValid` followed immediately by `Valid = IsChildValid(LossCategories)`, so the object's final validity reflects only the child-collection check — the base class's own broken-rules result is computed but then discarded rather than being AND-combined with the child result.*

## Process flow

```mermaid
flowchart TD
	Start([Caller requests loss-summary operation]) --> Which{Create, retrieve,<br>update, or delete?}
	Which -->|Retrieve| Ret[Select via dual + package functions]
	Ret --> LoadCat[Retrieve child LossCategories]
	LoadCat --> Loaded([clsLossSummary populated])
	Which -->|Insert or Update| Derive[Compute derived totals from LossCategories]
	Derive --> Floor{Indemnity total below<br>SETL/TPN floor?}
	Floor -->|Yes| Clamp[Raise to floor, then clamp to >= 0]
	Floor -->|No| ClampOnly[Clamp to >= 0]
	Clamp --> Bind[Bind derived totals to SQL parameters]
	ClampOnly --> Bind
	Bind --> Exec[Execute insert or update]
	Exec --> CascadeSave[Cascade Save to LossCategories]
	CascadeSave --> Done([Persisted])
	Which -->|Delete| Del[Delete by ClaimID]
	Del --> DelDone([Deleted; marked new])
```

## Failure and edge-case behavior
- `IsValid` discarding the base-class validity result means any broken business rules registered directly against `clsLossSummary` itself (as opposed to its children) do not block a save through the normal validity gate; this is a real quirk in the object's dirty/valid tracking rather than intentional design, based on how the assignment sequence overwrites rather than combines results.*
- The indemnity floor/clamp logic runs on every property read, not only at save time, so any UI or caller reading `TotalIncurredIndemnityAmount` mid-edit sees the same floored/clamped value that will ultimately be persisted.*
- A rows-affected value other than `1` on insert, update, or delete adds the framework's standard error/broken-rule entry rather than throwing, consistent with the pattern used elsewhere in this library.*

## 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. Statements
> marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- `Business\SAIF.Business.UnitStat.Claim\Loss Summary\clsLossSummary.vb`
- `Business\SAIF.Business.UnitStat.Claim\Loss Summary\clsLossSummaryCollection.vb`
