Disability activity tracking¶
Disability activity tracking covers two parallel entity families for a claim: disability status activity, which records the dates on which disability status changed, and disability authorization activity, which records time-loss authorization dates and reason codes. Both collections load newest-first, stamp the claim's injury context onto every item for cross-validation, enforce a non-decreasing date sequence, and persist through the usual insert, update, and delete lifecycle with row-count concurrency checks.
| Field | Value |
|---|---|
| Operation ID | OP-CM-07 |
| Trigger | Caller invokes clsClaimDisabilityActivityCollection.GetClaimDisabilityActivityCollection or clsDisabilityAuthActivityCollection.GetDisabilityAuthActivityCollection, edits or adds items, and calls Save() on the collection* |
| Inputs | ClaimID (Decimal, key for both families); DisabilityDate; DisabilityAuthReasonCode and DisabAuthActivityDate; the sequence keys DisabilityActivitySubNum and DisabAuthActivitySubNum; UpdateNum as the concurrency token on updates; the acting user from the data-portal info |
| Outputs | Inserted, updated, and deleted rows in the claim disability activity and disability authorization activity tables; in-memory latest item and current authorization, the history collection, the maximum disability date, and broken-rule messages |
| Primary components | clsClaimDisabilityActivity, clsClaimDisabilityActivityCollection (GetLatestRecord, GetInjuryDate, GetMaxDisabilityDate, UpdateHistoryCollections), clsDisabilityAuthActivity, clsDisabilityAuthActivityCollection (NewDisabilityAuthActivity, CurrentDisabAuth) |
| Entry point | Business\SAIF.Business.Claim.Maintenance\clsClaimDisabilityActivityCollection.vb |
Steps¶
- Retrieve the disability status history.
GetClaimDisabilityActivityCollection(dataPortal, claimID)builds a criteria and calls the portal's retrieve;BeforeRetrievebinds the claim identifier and the statement selects every row for the claim ordered by activity sub-number descending (SQL-043, CL_CLAIM_DISABILITY_ACTIVITY). - Materialize the status rows.
AfterRetrieveloops the reader, creates one activity object per row, callsLoadandFillto populate claim identifier, disability date, sub-number, and audit fields, re-attaches a criteria, and adds each item to the collection. - Fetch the injury context. When the cached injury date is still the minimum date,
GetInjuryDate()issues a separate request that reads the injury date and occupational-disease code for the claim into collection-level fields (SQL-042, CL_INJURY_CLAIM). - Stamp the injury context onto each item. Every loaded item receives the collection's injury date and occupational-disease code so it can self-validate.
- Determine the working "latest" row (
GetLatestRecord). - If the collection is empty, create a brand-new activity item whose claim identifier is set, whose sub-number and update number are zero, and whose disability date is the minimum date; mark it clean and add it as the latest item.
- Otherwise, sort descending by sub-number and take the first non-deleted item as the latest; if that item has already been saved, append a copy with the sub-number incremented by one so the caller gets a pre-seeded "add next status" row.
- Edit and validate a status item. Setting the disability date marks the item dirty; the item rules then require the date not to be in the future (checked only when the smart-date value was modified), require a date whenever the object is dirty, and forbid a date earlier than the injury date unless the claim is an occupational-disease claim.
- Enforce status chronology at the collection level. The collection rule sorts items descending by sub-number and rejects the set if any earlier-sequence item's date is less than a later one, so disability dates must be non-decreasing across the sequence; only items that are new and dirty or already saved take part.
- Save the disability status collection.
Save()applies the pending edit and the base save dispatches per item: - Insert: bind the disability date, acting user, claim identifier, and sub-number, then execute the insert; a rows-affected value other than one adds an insert error (SQL-003, CL_CLAIM_DISABILITY_ACTIVITY).
- Update: bind the disability date, update number, acting user, claim identifier, and sub-number and match on all three keys for optimistic concurrency; zero rows affected adds an update error carrying the DB contention message (SQL-088, CL_CLAIM_DISABILITY_ACTIVITY) (BR-CM-001).
- Delete: bind the claim identifier and sub-number; zero rows affected adds a delete error carrying the DB contention message (SQL-107, CL_CLAIM_DISABILITY_ACTIVITY) (BR-CM-001).
- Housekeeping after removal. Removing an item rebuilds the history collection from all list items except clean-new placeholders and re-sorts it descending by sub-number for grid display; the maximum-disability-date helper re-sorts and returns the first non-placeholder item's date, which is used to keep the claim's disability date in step.*
- Retrieve the disability authorization history.
GetDisabilityAuthActivityCollection(dataPortal, claimID)runs a statement that joins the authorization table to the claim on claim identifier and returns every authorization row plus the injury date, ordered by authorization sub-number descending (SQL-065, CL_DISABILITY_AUTH_ACTIVITY, CL_INJURY_CLAIM). - Materialize the authorization rows.
AfterRetrieveloads each row into an authorization object — claim identifier, reason code, activity date, sub-number, audit fields, and the joined injury date — tracks the highest sub-number seen, and sorts the collection descending. - Fall back to a separate injury-date read. If the injury date is still the minimum date after the join-based load, a scalar query supplies it, guarded by a date check before assignment (SQL-064, CL_INJURY_CLAIM).
- Add a new authorization activity.
NewDisabilityAuthActivity(claimID)increments the maximum-sequence counter, creates an empty item (claim identifier and acting user set, reason code defaulted to0, activity date empty, sub-number zero, marked new then clean), assigns the collection's injury date and the new sub-number, adds it, and re-sorts descending. - Edit and validate an authorization item. Setting the reason code or activity date marks the item dirty; the item rules forbid a date more than seven days in the future, require the date when the object is dirty, require a non-zero reason code when dirty, and forbid a date earlier than the injury date.
- Enforce authorization chronology at the collection level. The collection rule sorts descending by sub-number and rejects the set if any earlier-sequence date is less than a later one; unlike the status collection, it compares all rows rather than only dirty or saved ones.
- Save the authorization collection.
Save()applies the pending edit and the base save dispatches per item:- Insert: bind the activity date, acting user, claim identifier, reason code, and sub-number; zero rows affected adds an insert error (SQL-013, CL_DISABILITY_AUTH_ACTIVITY).
- Update: bind the reason code, activity date, update number, acting user, claim identifier, and sub-number, matching on claim, sub-number, and update number; zero rows affected adds an update error carrying the DB contention message (SQL-095, CL_DISABILITY_AUTH_ACTIVITY) (BR-CM-001).
- Delete: bind the claim identifier and sub-number; a rows-affected value other than one adds a delete error carrying the DB contention message (SQL-114, CL_DISABILITY_AUTH_ACTIVITY) (BR-CM-001).
- Expose the current authorization.
CurrentDisabAuthscans the list for the highest sub-number and, when the collection is empty, returns a transient empty authorization that is never added to the list, so bound consumers always receive a non-null object.
Process flow¶
The following diagram visualizes this operation's control flow across both entity families.
flowchart TD
Start([Caller requests disability data<br>for a claim]) --> Family{Which family?}
Family -->|Disability status| SRead[Select activity rows<br>ordered by sub-number desc]
SRead --> SLoad[Load one item per row]
SLoad --> SInj[Read injury date and<br>occupational disease code]
SInj --> SStamp[Stamp injury context<br>onto every item]
SStamp --> SLatest{Collection empty?}
SLatest -->|Yes| SNew[Create blank latest item]
SLatest -->|No| SCopy[Take newest item;<br>append incremented copy<br>if it was already saved]
SNew --> Edit
SCopy --> Edit
Family -->|Disability authorization| ARead[Select authorization rows<br>joined to the claim]
ARead --> ALoad[Load items; track max sequence;<br>sort desc]
ALoad --> AInj{Injury date resolved?}
AInj -->|No| AFall[Scalar injury date query<br>guarded by a date check]
AInj -->|Yes| ANew[NewDisabilityAuthActivity<br>seeds next sequence]
AFall --> ANew
ANew --> Edit[Caller edits item fields]
Edit --> Rules[Item rules: required, future date,<br>not before injury date]
Rules --> Seq[Collection rule: dates must be<br>non-decreasing by sequence]
Seq --> Ok{Rules pass?}
Ok -->|No| Invalid([Broken rules returned;<br>no persistence])
Ok -->|Yes| Save[Save applies edit,<br>dispatches per item]
Save --> Kind{Item state}
Kind -->|New| Ins[Insert row]
Kind -->|Modified| Upd[Update matching<br>claim, sub-number, update num]
Kind -->|Removed| Del[Delete by claim<br>and sub-number]
Ins --> Rows{Expected rows affected?}
Upd --> Rows
Del --> Rows
Rows -->|No| Err([Insert, update, or delete error;<br>DB contention message])
Rows -->|Yes| Done([Item marked old;<br>history collections rebuilt])
Failure and edge-case behavior¶
- Concurrency violations — another user updated or deleted the row first, so the update number no longer matches — surface as zero rows affected in the update and delete hooks for both entity families and produce a DB contention broken-rule message rather than a thrown exception (BR-CM-001).
- The two insert hooks disagree on the exact row-count test: one treats any count other than one as failure while the other treats only zero as failure. This is a source inconsistency, not a documented business distinction.*
- The two delete hooks are inconsistent in the same way, one testing for zero and the other for a count other than one.*
- The future-date rule on disability status runs only when the smart date's value was modified, so a loaded, unmodified date is never re-validated against today; the required and injury-date rules always evaluate when the object is dirty or a date is set.
- The injury-date cross-check on disability status is bypassed entirely for occupational-disease claims, allowing a disability date earlier than the injury date in that case.*
- If the latest non-deleted status item is itself new and never saved, no extra copy row is appended — the existing new item is reused, avoiding duplicate blank rows.
- The authorization collection's fallback injury-date query guards its scalar result with a date check, silently leaving the injury date at its default when the query returns no row or a non-date value.
- The maximum-date and history-rebuild helpers both special-case clean-new placeholder rows so the auto-generated blank entry does not pollute max-date lookups or the history grid.
- Statement properties that a given class does not use throw an invalid-statement application exception when invoked, guarding against use of the wrong data-access path.
- The two collections each enforce chronological ordering and injury-date cross-checks independently and do not coordinate with each other at the level shown in the source.*
Related documentation¶
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.Maintenance\clsClaimDisabilityActivity.vbBusiness\SAIF.Business.Claim.Maintenance\clsClaimDisabilityActivityCollection.vbBusiness\SAIF.Business.Claim.Maintenance\clsDisabilityAuthActivity.vbBusiness\SAIF.Business.Claim.Maintenance\clsDisabilityAuthActivityCollection.vb