---
title: Maintain provider MCO membership
summary: Persists a provider location's managed-care-organization membership periods and their negotiated rates, bounded by the parent MCO plan and any effective service contract.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Provider
reference_type: package
operation_id: OP-PRV-09
trigger: Caller creates or retrieves a clsProviderMCOMembership, edits properties, and calls Save() or Delete()
---

# Maintain provider MCO membership

`clsProviderMCOMembership` maintains a provider location's enrollment in an MCO plan for a given effective/expiration window, including per-membership admin-fee and specialty rate fields. The membership period must fit inside the parent plan's active dates and cannot expire before an effective service contract for the same plan/location, and every successful save or delete is synchronized to Contact Manager through `clsMembershipApi`.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-PRV-09 |
| **Trigger** | Caller calls `NewProviderMCOMembership`/`GetProviderMCOMembership`, edits properties, and calls `Save()` or `Delete()` |
| **Inputs** | `ProviderLocationSeqNum`, `MCOPlanID`, `EffDate`/`ExpDate`, `NewPatientsFlag`, `DirectoryFlag`, `AdminFeeFlag`/`AdminFeeRate`, `RatePtOtSt`, `RateRad`, `RateWcCtc`, `RateAsc` |
| **Outputs** | Persisted [MCO_PROVIDER](../database-tables.md#mco_provider) row; ContactManager `MembershipDto` sync |
| **Primary components** | `clsProviderMCOMembership.Create`, `BeforeInsert/BeforeUpdate/BeforeDelete`, `ActiveEffDate`, `BeforeContractExpDate`, `FillMembershipDto`, `clsMembershipApi.AddMembership/UpdateMembership/DeleteMembership` |
| **Entry point** | `Business\SAIF.Business.Provider\clsProviderMCOMembership.vb` |

## Steps

1. **Create with defaults.** `Create()` defaults `NewPatientsFlag`, `DirectoryFlag`, and `AdminFeeFlag` to `"Y"`, and `AdminFeeRate`, `RatePtOtSt`, `RateRad`, `RateWcCtc`, `RateAsc` to `1`; assigns a new seq num via `GetNextSeqNum("Mco_Provider_SEQ")`.
2. **Retrieve.** Reads [MCO_PROVIDER](../database-tables.md#mco_provider) by `PROVIDER_LOCATION_SEQ_NUM + MCO_PLAN_ID + EFF_DATE` ([SQL-054](../sql/SQL-054-retrieve-provider-m-c-o-membership.md)); `Fill(...)` also captures `m_OriginalMCOPlanID`/`m_OriginalEffDate` for use as the update/delete key, since the plan ID and effective date are themselves editable.
3. **Validate before save.**
   - `MissingMCOPlanID`, `MissingEffDate`: hard errors requiring the plan and effective date.
   - [BR-016](../business-rules.md#br-016-mco-membership-period-must-fall-within-the-mco-plans-active-date-range): `ActiveEffDate` requires the membership's effective/expiration window to fall entirely within `clsMCOPlan.GetMCOPlan(...).EffDate/ExpDate` (open-ended plan or membership expirations default to `Date.MaxValue`).
   - `LateExpDate`: hard error if `ExpDate` exceeds `Today + 10 years`.
   - [BR-017](../business-rules.md#br-017-mco-membership-expiration-cannot-precede-an-effective-service-contracts-expiration): `BeforeContractExpDate` — only when the object `IsDirty` and an `ExpDate` is set — runs `IsServiceContractEffective`, a scalar count query against [PROVIDER_SERVICE_CONTRACT](../database-tables.md#provider_service_contract) for the same location/plan whose expiration (`NVL(EXP_DATE, '31-Dec-2999')`) exceeds the proposed membership expiration; a nonzero count fails the rule.
   - `ValidEffExpDate`: hard error if `ExpDate` precedes `EffDate`.
   - [BR-018](../business-rules.md#br-018-mco-membership-admin-fee-flag-and-rate-must-be-mutually-consistent): `ValidAdminFeeRate` — if `AdminFeeFlag` is set, requires a nonblank rate no greater than `1.000`; if not set, requires the rate to be blank.
   - `ValidRatePtOtSt`, `ValidRateRad`, `ValidRateWcCtc`, `ValidRateAsc`: hard errors requiring each specialty rate to be present.
   - Warning-only checks: `EarlyEffDate`/`EarlyExpDate` (dates more than a year in the past), `LowAdminFeeRate`/`LowRatePtOtSt`/`LowRateRad`/`LowRateWcCtc`/`LowRateAsc` (rate below `.75`) — none of these block the save.
   - Overlapping-membership-period rules exist in source as commented-out code and are **not** currently enforced.*
4. **Insert.** Writes `MCO_PLAN_ID`, `PROVIDER_LOCATION_SEQ_NUM`, `EFF_DATE`/`EXP_DATE`, `NEW_PATIENTS_FLAG`, `DIRECTORY_FLAG`, `ADMIN_FEE_RATE`/`ADMIN_FEE_FLAG`, the four specialty rates, `MCO_PROVIDER_SEQ_NUM`, and audit fields to [MCO_PROVIDER](../database-tables.md#mco_provider) ([SQL-029](../sql/SQL-029-insert-provider-m-c-o-membership.md)).
   - `FillMembershipDto(MCOPlanID)` resolves `planName` via `clsProviderUtility.GetPlanNameByid`, `providerNumber` via `clsProviderUtility.GetProviderByProviderLocSeqNum`, and normalizes `mcoMembershipExpDate` to `Nothing` when `ExpDate = Date.MinValue`.
   - On success: `MarkOld()`, then call `clsMembershipApi.AddMembership(...)` against route `provider/{providerLocationSeqNumber}/membership`; API exceptions are JSON-logged and surfaced as `ApiInsertError`.
5. **Update.** Writes the same fields to [MCO_PROVIDER](../database-tables.md#mco_provider) ([SQL-077](../sql/SQL-077-update-provider-m-c-o-membership.md)) with concurrency check `WHERE PROVIDER_LOCATION_SEQ_NUM = :ProviderLocationSeqNum AND MCO_PLAN_ID = :OriginalMCOPlanID AND EFF_DATE = :OriginalEffDate AND UPDATE_NUM = :UpdateNum` — the row is located by the **original** plan ID and effective date even though those fields may have just changed.
   - `FillMembershipDto(m_OriginalMCOPlanID)` is used for the API call, so the synced `planName` reflects the original plan while dates reflect the current fields.*
   - On success: call `clsMembershipApi.UpdateMembership(...)`; API failure is logged and surfaced as `ApiUpdateError`.
6. **Delete.** Deletes from [MCO_PROVIDER](../database-tables.md#mco_provider) by `ProviderLocationSeqNum + OriginalMCOPlanID + OriginalEffDate` ([SQL-099](../sql/SQL-099-delete-provider-m-c-o-membership.md)) — **no `UPDATE_NUM` check on delete**.
   - The DTO for the API call is built using the original plan ID.
   - On success: call `clsMembershipApi.DeleteMembership(...)` against route `provider/{providerLocationSeqNumber}/membership/remove`; API failure is logged and surfaced as `ApiDeleteError`.

## Process flow

```mermaid
flowchart TD
	Start([Caller edits MCO membership]) --> PlanRange{Period within<br>MCO plan active dates?}
	PlanRange -->|No| Fail([Outside plan's active<br>date range blocks save])
	PlanRange -->|Yes| ContractCheck{Dirty, ExpDate set,<br>effective service contract outlives it?}
	ContractCheck -->|Yes| Fail2([Membership would expire<br>before contract blocks save])
	ContractCheck -->|No| AdminFee{Admin fee flag/rate consistent?}
	AdminFee -->|No| Fail3([Inconsistent admin<br>fee flag/rate blocks save])
	AdminFee -->|Yes| Rates{All specialty rates present?}
	Rates -->|No| Fail4([Broken rules returned])
	Rates -->|Yes| Persist[Insert/update/delete MCO_PROVIDER]
	Persist --> Rows{RowsAffected = 1?}
	Rows -->|No| Contention([Insert Failed / DB contention error])
	Rows -->|Yes| Api[Call clsMembershipApi Add/Update/Delete]
	Api --> Done([Save complete;<br>API failures logged, not blocking])
```

## Failure and edge-case behavior

- Update and delete locate the row by the **original** plan ID and effective date, so changing either field mid-edit relies on those original values being preserved correctly in memory; a stale original value would misdirect the SQL.*
- Delete has no `UPDATE_NUM` concurrency check, unlike insert/update, so a concurrent modification is not detected on delete.
- Overlapping-membership-period validation exists in source but is commented out, so a provider location can currently hold overlapping memberships in the same MCO plan.*
- Warning-only low-rate checks (below `.75`) never block a save, regardless of how far below the threshold the rate is.

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

## Sources

- `Business\SAIF.Business.Provider\clsProviderMCOMembership.vb`
- `Business\SAIF.Business.Provider\Api\clsMembershipApi.vb`
- `Business\SAIF.Business.Provider\clsMCOPlan.vb`
- `Business\SAIF.Business.Provider\clsProviderUtility.vb`
