# SaveAdHocFieldDefinitionClaimType - Advanced Documentation ## Overview Creates or updates a single claim type ad hoc field definition, including its dropdown options and role-based view/edit permissions. The caller passes one field definition object per call. This is a long-running operation - it declares a `[LongRunningId] string ProcessID` parameter and is invoked through `ProcessStatus.Run`. If the field is already used by existing claim types, the operation regenerates the generated forms for each of those claim types before returning. ## Business Rules - The field definition is validated before any write: field label is required, must be a valid field name (cannot contain `,`, `"`, `#`), data type is required, and category is required (`ValidateFieldDefinition`) - The field label must be unique for the company across both ad hoc fields (`vwAdHocFieldDefinitionsClaimTypes`) and system claim fields (`vwClaimFieldsAllowedInSections`); a duplicate throws before any write occurs - When the field is already referenced by existing widget/intake fields (`Item.UsedBy` is non-empty), the definitions of those widget fields are recalculated before the save, by comparing current widget field data against the new definition (`GetUpdatedWidgetFieldsSqlBatch`) - New field definitions (`Item.ID < 1`) are assigned the next sort order, computed from the count of existing field-label rows found during the uniqueness check - Dropdown options, edit roles, and view roles are synced as Aptify sub-types (`AdHocFieldDefinitionsClaimTypeDropdownOptions`, `AdHocFieldDefinitionsClaimTypeEditRoles`, `AdHocFieldDefinitionsClaimTypeViewRoles`) - existing rows not present in the incoming lists are removed, and missing rows are added - The field definition is saved and the transaction is committed BEFORE form regeneration begins. Re-reading the definition immediately after the call confirms the write even while regeneration for used-by claim types is still running - Any updated widget field SQL from the used-by recalculation is executed inside the same transaction as the definition save, before commit - After commit, if the field has used-by claim types, the operation iterates the used-by collection and calls `ClaimDesigner.UpdateClaimTypeGeneratedForms` once per claim type ID - cost scales with the number of claim types in `Item.UsedBy` - The operation returns only after the used-by regeneration loop finishes - The ad hoc field cache for the company is cleared once before form regeneration begins (`ClearAdHocCache(AdHocFieldType.Claim, CompanyID)`, to ensure regeneration reads clean definitions) and again after the saved item's ID is set, at the end of the method - `IsSynced` marks this field for sync between companion claims ## Permissions & Security - Caller must be logged in (`curPerson.ID >= 1`) - Caller must have a company selected (`curCompany.ID >= 1`) - Caller must be a member of the current company (`IsPartOfCompany` check) - Caller must have the **ManageFirm** permission, checked inside the controller method (`Controllers.Role.Permissions.ManageFirm`) - The saved field definition is always scoped to the caller's current company (`CompanyID` is set from `_UnitOfWork.CurrentCompany.ID`, not from the incoming `Item`) ## Data Flow 1. Validate authentication, company membership, and ManageFirm permission (in the service method, before the controller is invoked) 2. Validate the field definition shape (`ValidateFieldDefinition`) 3. Query for an existing field label match across ad hoc and system claim fields for this company; throw if found 4. If `Item.UsedBy` is non-empty, compute the updated widget field SQL batch for currently dependent widget/intake fields 5. Get (or create) the `AdHocFieldDefinitionsClaimTypes` Aptify entity object for `Item.ID` and set its scalar fields 6. If this is a new field (`Item.ID < 1`), assign the computed sort order 7. Sync the dropdown options, edit roles, and view roles sub-types 8. Begin transaction 9. Save the entity object; throw if the save fails 10. Execute any updated widget field queries from step 4 11. Commit transaction 12. If the field has used-by claim types: clear the ad hoc field cache, get the intake setup, then call `ClaimDesigner.UpdateClaimTypeGeneratedForms` once per claim type ID in `Item.UsedBy` 13. Set `Item.ID` to the saved record's ID 14. Clear the ad hoc field cache again 15. Return the saved `Item` ## Side Effects - **Database write**: The `AdHocFieldDefinitionsClaimTypes` entity record is created or updated via Aptify - **Database writes**: Dropdown option, edit role, and view role sub-type rows are synced (added/removed) to match the incoming definition - **Database writes**: Widget field rows (`spSaveUpdatedWidgetFieldClaim` / `spSaveUpdatedWidgetFieldIntake`, selected by entity type) are updated for any dependent widget/intake fields whose calculated data no longer matches the new definition - **Database updates**: Claim type generated forms (HTML) are regenerated for every claim type in `Item.UsedBy` - **Cache invalidation**: Ad hoc field cache for claim type fields is cleared via `ClearAdHocCache(AdHocFieldType.Claim, CompanyID)`, once before regeneration and once at the end of the method ## Error Conditions - `RadoloException("You must be logged in to perform this action.")` - caller not authenticated - `RadoloException("You must have a company selected to perform this action.")` - no company context - `RadoloException("You can only perform this action for a company you are a member of.")` - cross-company attempt - `RadoloException("You do not have permission to save {claimLabel} type adhoc fields...")` - missing ManageFirm permission - `RadoloException("Field Label is required.")` - missing field label - `RadoloException("Field Label can not contain ',\",#.")` - invalid field label characters - `RadoloException("Data Type is required.")` - missing data type - `RadoloException("Category is required.")` - missing or invalid category - `RadoloException("An {Type} field with this field label[{FieldLabel}] already exists.")` - duplicate field label (ad hoc or system field) - `RadoloException("There was a problem saving this ad hoc field definition : {error}")` - Aptify entity save failed ## Usage Notes - This is a long-running operation wrapped in `ProcessStatus.Run` with a `[LongRunningId]` `ProcessID` parameter, but the controller method itself does not call `ProcessStatus.SetProcessStatus` at any point and has no `finally` block - progress is not reported mid-operation the way the delete operation does. - Because the save and commit happen before form regeneration starts, callers can re-read the field definition and see the persisted values while regeneration for used-by claim types is still in progress. - The operation does not return until the entire used-by regeneration loop completes, so response time scales with the number of claim types referencing the field. - The incoming `Item.CompanyID` is not trusted; the field is always saved under the caller's current company.