# SaveClaim - Advanced Documentation ## Overview Creates or updates a claim with staff assignments, contacts, ad hoc fields, notes, and privacy settings. Enforces field-level permissions, timestamp concurrency, and firm ownership. Generates calendar events for signup appointments, closes associated leads for new claims, and triggers JSON re-serialization. ## Business Rules - A `ClaimGroup` with a valid ID is required to save a claim. - New claims default `BillingBasis` to `"Contingency"`, set `CreatedBy` to the current person, and stamp `CreatedDate` with `DateTime.UtcNow`. - Existing claims cannot be updated by a user logged into a different firm than the claim's owning firm. - The claim's `IncidentDate` is always synced from `ClaimGroup.IncidentDate`. - Decision-dependent validation (same rules as SaveIntake): - **Stop Chase**: requires DecisionMaker and StopChaseReason. - **Accept**: requires DecisionMaker; if ContractDate is set, staff is required. - **Reject**: requires DecisionMaker and RejectionReason. - **Refer**: requires DecisionMaker, ReferralStatus, and ReferralContact. - If ClosedDate is set, ClosedNote is required. - Claim status is computed from state via `GetClaimStatus`. When status changes, the claim request cache for the firm is cleared. - FirmID changes on existing claims throw a critical error. - The claim group's `IncidentDate` and `Synopsis` are saved alongside the claim, with field-level permissions applied to claim group fields. - `EnforceFieldPermissions` is called on the claim entity with `ProtectedClaimFields` and the user's web groups, providing an additional layer of field-level protection beyond `RevertSystemFieldsWithPermissions`. - **Claim privacy**: `IsPrivate`, `ClaimAllowedStaff`, and `ClaimAllowedFirmRoles` sub-entities are synced. Changes to any of these flag the security info cache for clearing. - Staff assignments are synced via `ClaimStaffs` sub-entity; changes also flag the security cache. - Claim contacts (with their own ad hoc fields) are synced within the claim entity's `ClaimContacts` sub-entity. Each dirty claim contact gets a timestamp update. - Tags are synced via `ClaimTags`. - Ad hoc fields are synced with staff permission enforcement. - Review dates are updated via `SetLastReviewDates`. - Sticky note and estimated value changes auto-stamp metadata (same as SaveIntake). - If `SignUpAppointment` changes to a future date, decision is "Accept", and PersonInCharge is set, a signup calendar event is created and an email is sent. - For new claims with an associated lead, the lead is closed. - Timestamp is only updated for non-API users (API calls are assumed to be automated and re-runnable). - After commit, if the claim group was dirty, JSON re-serialization is forced for all claims in the group (skipping the current claim if it was also dirty, since it was already saved). - Claim color label is recalculated post-save. ## Permissions & Security - `ValidateCurrentPersonAndCompany` confirms authentication (no specific permission required beyond login). - All referenced person IDs are validated as firm members via `ValidatePersonWasPartOfFirm`. - For existing claims, security access is checked during validation (`HasSecurityAccessToClaim`). - Existing claims must have `FirmID` matching the current company. - Claim type must belong to the current firm. - `EnforceFieldPermissions` prevents modification of protected fields by users without the required web groups. - `RevertSystemFieldsWithPermissions` reverts unauthorized system field changes. - Privacy-related changes (IsPrivate, AllowedStaff, AllowedFirmRoles) trigger security cache invalidation. ## Data Flow 1. Null and ClaimGroup validation. 2. `ValidateCurrentPersonAndCompany` confirms authentication. 3. All referenced person IDs collected and validated against the firm. 4. New claim initialization (FirmID, CreatedBy, CreatedDate, BillingBasis) or firm ownership check for existing claims. 5. IncidentDate synced from ClaimGroup. 6. `Validate` checks required fields and decision rules. 7. Aptify generic entity loaded for the claim. 8. Timestamp concurrency check. 9. Status computed and set; cache cleared if status changed. 10. All scalar fields written to the entity. 11. Claim group entity loaded, `IncidentDate` and `Synopsis` set, field permissions applied, saved. 12. `EnforceFieldPermissions` applied to claim entity. 13. Privacy sub-entities (AllowedStaff, AllowedFirmRoles) synced. 14. Staff, claim contacts (with nested ad hoc fields), and tags synced. 15. System field permissions enforced (unauthorized changes reverted). 16. Claim ad hoc fields synced. 17. Review dates updated. 18. Transaction started. 19. Expected event tasks created if entity is dirty. 20. Timestamp updated (skipped for API users). 21. Linked events for removed ad hoc and system fields disconnected. 22. Claim saved via `SaveClaimGeAndEnsureName`. 23. Signup calendar event created if conditions met. 24. Linked calendar events updated if `SaveLinkedEvents` is true. 25. Transaction committed. 26. Security info cache cleared if privacy-related changes were made. 27. JSON re-serialization forced for claims in the group if the group was dirty. 28. "In charge" email sent if signup appointment triggered. 29. Lead closed for new claims with an associated lead. 30. Claim color label recalculated. 31. Correspondence email generated and claim returned. ## Side Effects - **Database writes**: Claim record, claim group, claim staff, claim contacts (with ad hoc fields), claim tags, claim ad hoc fields, expected event tasks, claim allowed staff/roles. - **Calendar events**: Signup appointment event created when conditions are met. - **Linked calendar events**: Updated post-transaction if `SaveLinkedEvents` is true. - **Email**: "In charge of claim" notification to PersonInCharge on signup appointment change. - **Lead closure**: Associated lead closed for new claims. - **Cache invalidation**: - Claim request cache cleared when claim status changes. - Security info cache cleared when privacy settings change. - Company and person caches are NOT directly cleared by this method. - **JSON re-serialization**: Forced for all claims in the claim group when the group is dirty (triggers background upload of claim JSON to storage). ## Error Conditions - `ArgumentNullException` if Claim is null. - `RadoloException("A ClaimGroup is required...")` if ClaimGroup is missing or has invalid ID. - `RadoloException("You cannot update a [claim] for a firm you are not logged into.")` if the current firm does not match the claim's FirmID on existing claims. - `RadoloException` from `Validate` for missing required fields or decision-dependent failures. - `RadoloException` from `ValidateTimestamp` for optimistic concurrency violations. - `RadoloException("The system is attempting to change the CompanyID...")` for FirmID tampering. - `RadoloException` from `ValidatePersonWasPartOfFirm` for invalid staff references. - `RadoloException("There was a problem saving the [claim] group...")` on claim group save failure. - `RadoloException("There was a problem saving this [claimant's] information...")` on claimant save failure. - Entity save failures include `LastError` details. - The SecureApi catch block attaches `ClaimID` to the exception data before publishing and rethrowing. ## Ad Hoc Fields Ad hoc fields are custom fields defined per claim type. They are passed as a list of `AdHocFieldInfo` objects on the claim. ### Setting Values **Critical: `FieldValue` is read-only.** It is a computed getter that returns the appropriate typed value as a string. Setting `FieldValue` does nothing. You must set the specific typed property that matches the field's `DataType`: | DataType | Property to Set | Notes | |----------|----------------|-------| | Number | `NumberValue` | Integer | | Decimal | `DecimalValue` | Decimal number | | TextShort | `TextShortValue` | Short text (single line) | | TextLong | `TextLongValue` | Long text (multi-line) | | Date | `DateValue` | Date only | | DateTime | `DateTimeValue` | Date and time | | Yes/No | `YesNoValue` | Boolean | | Dropdown | `DropdownValue` | Selected option text | | Document | `Document` | Document reference | | Contact | `BaboContact` | Contact reference | | Staff | `Staff` | Staff person reference | | Hyperlink | `TextShortValue` | URL stored as short text | | State | `DropdownValue` | US state stored as dropdown | ### Required Fields Each `AdHocFieldInfo` must include: - `AdHocFieldDefinitionID` - identifies which custom field this is - The appropriate typed value property for the field's DataType ### Permission Enforcement Ad hoc fields are synced via `SyncSubTypeToAdHocFieldValues`, which enforces role-based permissions: - **Edit permissions**: If the current user's roles do not include the field's `EditRoles`, the field value is preserved unchanged (the caller's value is ignored silently). - **View permissions**: Fields the user cannot view are filtered from the response. - **API users**: Bypass all edit/view restrictions - API callers can read and write all ad hoc fields regardless of role configuration. ### Nested Ad Hoc Fields on Claim Contacts SaveClaim also handles ad hoc fields on claim contacts (`ClaimContactInfo.AdHocFields`). Each claim contact can have its own set of ad hoc fields, which are synced within the `ClaimContacts` sub-entity. The same DataType rules and permission enforcement apply to these nested ad hoc fields. ### Calendar Event Linking Ad hoc fields of type Date or DateTime can be linked to calendar events. When `SaveLinkedEvents` is true (always true from SecureApi), linked calendar events are updated after the save. If an ad hoc field is removed, its linked calendar event is disconnected before save to avoid foreign key violations. ## Usage Notes - Unlike `SaveIntake`, this method does NOT save the claimant contact. The claimant must already exist. - Unlike `SaveIntake`, this method DOES handle claim privacy (IsPrivate, AllowedStaff, AllowedFirmRoles) and inline claim contacts. - The transaction starts later in the flow than SaveIntake -- after field validation, permission enforcement, and sub-entity syncing, but before the actual save. This reduces lock duration. - Timestamp updates happen only for the interactive login path (`curPerson.Origin == Origin.Login`); every other origin skips the update to avoid blocking UI users when automated processes are running. - The `SaveLinkedEvents` parameter is always `true` when called from the SecureApi. - Claim group fields (IncidentDate, Synopsis) are saved as part of this method, but the claim group's own ad hoc fields are not handled here.