---
title: User type management
summary: Creates, validates, and saves external-user type rows together with provider and policy helper checks.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.External.Users
reference_type: package
operation_id: OP-EU-06
trigger: Caller loads or saves `clsUserType` objects, asks for type definitions, or runs policy/provider helper checks.
---

# User type management

This operation covers the `EXT_USER_TYPE` layer that hangs beneath a user account. It persists the user's roles, validates role-level business constraints, saves the related customer and access-group children, and exposes helper methods that support provider EFT administration and policyholder registration checks.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-EU-06 |
| **Trigger** | User-type load, save, delete, or policy/provider helper request |
| **Inputs** | User type ID, user ID, customer ID, source-system identifiers, credentials, access groups, policy number, provider email |
| **Outputs** | Persisted `EXT_USER_TYPE` row, saved child groups, helper booleans, and EFT-related updates |
| **Primary components** | `clsUserType.FillUserType`, `clsUserType.OnSave`, `clsUserTypeCollection.GetUserTypesByUserID`, `mdlCodeMaps.GetUserTypes`, `mdlCodeMaps.GetStatusTypes` |
| **Entry point** | `Business\SAIF.Business.External.Users\clsUserType.vb` |

## Steps

1. **Create or retrieve a user-type row.** New rows allocate `EXT_USER_TYPE_SEQ`; existing rows retrieve the user type by sequence number and fill the persisted fields from `EXT_USER_TYPE` joined to its code tables ([SQL-009](../sql/SQL-009-saif-business-external-users.md), [SQL-030](../sql/SQL-030-saif-business-external-users.md), [EXT_USER_TYPE](../database-tables.md#ext_user_type)).
2. **Load the type and status code maps.** `mdlCodeMaps.GetUserTypes` caches the `EXT_USER_TYPE_CODE` map, while `mdlCodeMaps.GetStatusTypes` caches and orders the `EXT_USER_STATUS_CODE` map used by the broader user aggregate ([SQL-038](../sql/SQL-038-saif-business-external-users.md), [SQL-039](../sql/SQL-039-saif-business-external-users.md), [EXT_USER_TYPE_CODE](../database-tables.md#ext_user_type_code), [EXT_USER_STATUS_CODE](../database-tables.md#ext_user_status_code)).
3. **Load all user-type definitions for selection UIs when needed.** `GetAllUserTypes` reads the type code and prompt tables into placeholder rows that describe the required source-system inputs for each type ([SQL-031](../sql/SQL-031-saif-business-external-users.md), [EXT_USER_TYPE_CODE](../database-tables.md#ext_user_type_code)).
4. **Load a user's role assignments through the API projection.** `GetUserTypesByUserID` calls `ExternalLogin/UserTypesByUserId/{id}`, then `FillUserType` hydrates each API record into a `clsUserType`, rehydrates access groups, and sets `IsSteward` from the steward access-group selection.
5. **Validate source-system and collection rules before save.**
   - New rows require `CustomerID > 0`.
   - Collection rules allow only one primary type, only one steward, and only one row for the same user type and source-system group.
   - Policyholder rows require a numeric policy number.
   - Agency steward rows cannot also select ARP Agency or Producer access.
6. **Validate policyholder access helpers when access groups are chosen.** `ValidateStateAgencyAccess` requires entity code `50` before the state-agency group can be selected, and `ValidateWrapUpAccess` requires the policy to be the wrap-up parent before Wrap-Up Online can be selected.
7. **Insert or update the `EXT_USER_TYPE` row.** `BeforeInsert` and `BeforeUpdate` bind user, customer, role, and source-system fields into `EXT_USER_TYPE`; update uses the `UPDATE_NUM` concurrency pattern ([BR-EU-05](../business-rules.md#br-eu-05-optimistic-concurrency-via-update_num), [SQL-009](../sql/SQL-009-saif-business-external-users.md), [SQL-050](../sql/SQL-050-saif-business-external-users.md), [EXT_USER_TYPE](../database-tables.md#ext_user_type)).
8. **Delete the row when the user type is removed.** `BeforeDelete` removes the `EXT_USER_TYPE` row by sequence number ([SQL-056](../sql/SQL-056-saif-business-external-users.md), [EXT_USER_TYPE](../database-tables.md#ext_user_type)).
9. **Save child objects around the row change.** `OnSave` always saves the related customer, deselects and saves all access groups when the row is being deleted, and saves provider EFT child objects when they were loaded. `OnSaveComplete` saves the access-group collection after the root insert or update.
10. **Support provider EFT admin handoffs.** `UpdateAdminUserEmail` finds the current admin user type for a provider and reassigns matching provider EFT rows to the current user type ([SQL-032](../sql/SQL-032-saif-business-external-users.md), [EXT_USER_TYPE](../database-tables.md#ext_user_type)).
11. **Update authorization-contact emails for active provider EFT rows.** `UpdateEftAuthorizationEmail` loads the provider EFT collection for the source-system group and updates active `PAYMENT_AUTHORIZATION` rows with the new email and audit stamp ([SQL-051](../sql/SQL-051-saif-business-external-users.md), [PAYMENT_AUTHORIZATION](../database-tables.md#payment_authorization)).
12. **Run policy/provider helper checks used by registration paths.**
   - `IsQuotedPolicyExpired`, `IsBillingPlanEstablished`, and `IsBillingPlanSCInstallments` invoke Oracle package functions for policyholder registration checks ([SQL-033](../sql/SQL-033-saif-business-external-users.md), [SQL-034](../sql/SQL-034-saif-business-external-users.md), [SQL-035](../sql/SQL-035-saif-business-external-users.md)).
   - `IsUserEobOwner` checks whether the AD user owns any provider EOB interface rows ([SQL-036](../sql/SQL-036-saif-business-external-users.md), [PROVIDER_EOB_INTERFACE](../database-tables.md#provider_eob_interface)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
    Start([User-type request]) --> Load[Create or load user type]
    Load --> Maps[Load code maps and access groups]
    Maps --> Validate[Run role, policy, and collection validation]
    Validate --> Action{Save, delete, or helper check?}
    Action -->|Save| Persist[Insert or update user type and children]
    Action -->|Delete| Remove[Delete row and clear groups]
    Action -->|Helper| Helpers[Run policy or provider helper logic]
    Persist --> Done([Return user-type result])
    Remove --> Done
    Helpers --> Done
```

## Failure and edge-case behavior

- Primary-type and steward uniqueness are enforced at the in-memory collection layer before the database row is written.
- State-agency and wrap-up access checks depend on live policy data; a policy that no longer meets those conditions cannot keep the corresponding access selection.
- Provider EFT email updates only touch rows whose expiration date is blank or still current.
- The Oracle package bodies behind the policy helper calls are not present in this repository, so database-side decision details remain unknown.**

> **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.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

## Sources
- `Business\SAIF.Business.External.Users\clsUserType.vb`
- `Business\SAIF.Business.External.Users\mdlCodeMaps.vb`
