﻿---
title: SAIF.Business.Policy.Premium business rules
summary: Enumerated business rules with triggers, enforcement points, and outcomes.
status: draft
owner: Technical Writer
last_reviewed: 2026-07-31
library: SAIF.Business.Policy.Premium
reference_type: package
---

# SAIF.Business.Policy.Premium business rules

This page captures business rules enforced by this library.

## BR-001: Manual class number is required

| Field | Value |
| --- | --- |
| **Statement** | A class coverage must have a manual class number. |
| **Trigger** | Validation of a class coverage |
| **Enforcement** | `clsClassCoverageBase.AddBusinessRules (clsClassCoverageBase.vb:790-803) — TextRequired on ManualClassNumber` |
| **Outcome** | Error: "Error: Class is required." |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-002: Manual class number must resolve

| Field | Value |
| --- | --- |
| **Statement** | The manual class number must resolve to a valid manual class detail. If the number is blank the rule passes, to avoid a duplicate failure with [BR-001](business-rules.md#br-001-manual-class-number-is-required); otherwise HasManualClassDetail AndAlso ManualClassDetail.IsValid must hold. |
| **Trigger** | Validation of a class coverage |
| **Enforcement** | `ValidManualClassNumber rule, clsClassCoverageBase.vb` |
| **Outcome** | Error: "Error: {0} is not a valid class number." |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-003: Manual class usage code is required

| Field | Value |
| --- | --- |
| **Statement** | A manual class usage code is required (check level two). |
| **Trigger** | Validation of a class coverage |
| **Enforcement** | `TextRequired on ManualClassUsageCode, clsClassCoverageBase.vb` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-004: Class and usage must match rating period

| Field | Value |
| --- | --- |
| **Statement** | The manual class number combined with its usage code must be available for the rating period (check level two). |
| **Trigger** | Validation of a class coverage |
| **Enforcement** | `ValidManualClassBase rule registered on both ManualClassNumber and ManualClassUsageCode` |
| **Outcome** | Error: "Error: Class {0} with usage code {1} is not available for this rating period." |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-005: Employee and rate type codes are required

| Field | Value |
| --- | --- |
| **Statement** | Employee rating type code, manual class type code and rate type code are required (check level three). |
| **Trigger** | Validation of a class coverage |
| **Enforcement** | `TextRequired rules, clsClassCoverageBase.vb` |
| **Outcome** | Validation errors |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-006: FELA classes are blocked on assigned-risk periods

| Field | Value |
| --- | --- |
| **Statement** | FELA class types are not permitted on assigned-risk periods. |
| **Trigger** | Validation of a class coverage (level three) |
| **Enforcement** | `ValidFELA — fails when PeriodRatingInfo.IsAssignedRisk And IsClassTypeFELA` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-007: Manual class type must match the base class

| Field | Value |
| --- | --- |
| **Statement** | The manual class type code must be consistent with the base: a Regular base allows Regular or USLH; otherwise the type must equal the base's type. |
| **Trigger** | Validation of a class coverage (level three) |
| **Enforcement** | `ValidManualClassTypeCode, clsClassCoverageBase.vb` |
| **Outcome** | Error message beginning "Error: Jurisdiction code…" |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb` |

---
## BR-008: Duplicate manual classes are not allowed

| Field | Value |
| --- | --- |
| **Statement** | A class coverage collection may not contain duplicate manual classes (check level two). |
| **Trigger** | Validation of a class coverage collection |
| **Enforcement** | `clsClassCoverageBaseCollection.vb:345 — DuplicateManualClass rule, IsDuplicate performs an O(n²) scan` |
| **Outcome** | Error: "Error: Duplicate class ({0})." |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverageBaseCollection.vb` |

---
## BR-009: OCCPAP factor must stay between zero and one

| Field | Value |
| --- | --- |
| **Statement** | An OCCPAP factor must be greater than 0 and less than 1. |
| **Trigger** | Validation of a policy period OCCPAP |
| **Enforcement** | `clsPolicyPeriodOccpap.vb:428 — IsValidFactor` |
| **Outcome** | Error: "Error: OCCPAP Factor must be between .01 and .99" |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_OCCPAP](database-tables.md#policy_period_occpap) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodOccpap.vb` |

---
## BR-010: OCCPAP requires a policy period effective date

| Field | Value |
| --- | --- |
| **Statement** | A policy period OCCPAP must have a policy period effective date (not Date.MinValue). |
| **Trigger** | Validation of a policy period OCCPAP |
| **Enforcement** | `ValidPolicyPeriodOCCPAP, clsPolicyPeriodOccpap.vb` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_OCCPAP](database-tables.md#policy_period_occpap) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodOccpap.vb` |

---
## BR-011: Premium adjustment type code must be valid

| Field | Value |
| --- | --- |
| **Statement** | A premium adjustment type code must be a valid code. |
| **Trigger** | Validation of a premium adjustment type code |
| **Enforcement** | `clsPremiumAdjustmentTypeCode.vb:607 — ValidPremiumAdjustmentTypeCode on Code` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [PREM_ADJUSTMENT_TYPE_CODE](database-tables.md#prem_adjustment_type_code) |
| **Source** | `Business\SAIF.Business.Policy.Premium\Rating\clsPremiumAdjustmentTypeCode.vb` |

---
## BR-012: Rating plan factor must fit the selected plan

| Field | Value |
| --- | --- |
| **Statement** | A non-rated plan must have a null rating plan factor; any other plan's factor must fall within one of the configured ValidRatingPlanFactors ranges. |
| **Trigger** | Validation of a policy period rating plan |
| **Enforcement** | `clsPolicyPeriodRatingPlan.vb:711-713 — ValidRatingPlanFactor` |
| **Outcome** | Error message enumerating the valid ranges |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_RATING_PLAN](database-tables.md#policy_period_rating_plan) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodRatingPlan.vb` |

---
## BR-012a: SARAP factor is limited to assigned-risk experience plans

| Field | Value |
| --- | --- |
| **Statement** | A SARAP factor is allowed only when RatingPlan = Experience And PeriodRatingInfo.MarketType = AssignedRisk; otherwise it must be null. |
| **Trigger** | Validation of a policy period rating plan |
| **Enforcement** | `ValidSARAPFactor / AllowSARAPFactor (clsPolicyPeriodRatingPlan.vb ~:733)` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_RATING_PLAN](database-tables.md#policy_period_rating_plan) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodRatingPlan.vb` |

---
## BR-012b: Rating plan dates must form a valid range

| Field | Value |
| --- | --- |
| **Statement** | A policy period rating plan's effective/expiration dates must form a valid range. |
| **Trigger** | Validation of a policy period rating plan |
| **Enforcement** | `ValidDateRange → IsValidDateRange` |
| **Outcome** | Validation error |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_RATING_PLAN](database-tables.md#policy_period_rating_plan) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodRatingPlan.vb` |

---
## BR-012c: Renewal rating plans require all core fields

| Field | Value |
| --- | --- |
| **Statement** | A policy renewal rating plan requires a non-zero policy number, an effective date greater than DateTime.MinValue, an expiration date greater than the effective date, and a non-empty plan code. |
| **Trigger** | Validation of a policy renewal rating plan |
| **Enforcement** | `clsPolicyRenewalRatingPlan.vb:590-593 — IsValidPolicyNumber, IsValidEffectiveDate, IsValidExpirationDate, IsValidPlan` |
| **Outcome** | Validation errors |
| **Confidence** | Verified |
| **Tables** | [POLICY_RENEWAL_RATING_PLAN](database-tables.md#policy_renewal_rating_plan) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPolicyRenewalRatingPlan.vb` |

---
## BR-013: Subtotals must use one rating rule master

| Field | Value |
| --- | --- |
| **Statement** | A set of premium summary adjustments being sub-totalled must all belong to a single rating rule master. |
| **Trigger** | Sub-total computation (OP-004) |
| **Enforcement** | `iPremiumSummaryAdjustment.vb — GetSingleRatingRuleMaster` |
| **Outcome** | Throws ApplicationException |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\iPremiumSummaryAdjustment.vb` |

---
## BR-014: Per-period subtotal eligibility is filtered by rule metadata

| Field | Value |
| --- | --- |
| **Statement** | A premium adjustment type participates in per-period sub-totalling only when it has a rating rule priority, a non-zero rating rule master ID, all adjustment SQLs null, and a rating rule function of Addition, IncreasedLimitsMinimumPremium, Multiplication or PremiumPeriodProcessing. |
| **Trigger** | Sub-total computation |
| **Enforcement** | `SubTotalPremiumSummaryAdjustment.vb` |
| **Outcome** | Type included in per-period sub-totals |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\SubTotalPremiumSummaryAdjustment.vb` |

---
## BR-015: Whole-term subtotal eligibility is filtered by rule metadata

| Field | Value |
| --- | --- |
| **Statement** | A premium adjustment type participates in overall (whole-term) sub-totalling when the same first three conditions hold and the rating rule function is DCBSSplitProcessing or ProcessLater. |
| **Trigger** | Sub-total computation |
| **Enforcement** | `SubTotalPremiumSummaryAdjustment.vb` |
| **Outcome** | Type included in the overall min-effective → max-expiration sub-total |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\SubTotalPremiumSummaryAdjustment.vb` |

---
## BR-016: NEAP uses base amounts instead of difference amounts

| Field | Value |
| --- | --- |
| **Statement** | Premium amounts are summed from DifferenceAmount, except NEAP amounts which are summed from BaseAmount. |
| **Trigger** | Premium amount query (OP-005) |
| **Enforcement** | `PremiumAmountProviderExtensions.PremiumAmount (iPremiumAmountProvider.vb)` |
| **Outcome** | Returned amount |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\iPremiumAmountProvider.vb` |

---
## BR-017: Discount equals discounted minus standard premium

| Field | Value |
| --- | --- |
| **Statement** | The discount premium amount equals the discounted amount minus the standard amount. |
| **Trigger** | Premium amount query |
| **Enforcement** | `PremiumAmountProviderExtensions` |
| **Outcome** | Returned discount |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\iPremiumAmountProvider.vb` |

---
## BR-018: DCBS descriptions switch between percentage and based-on text

| Field | Value |
| --- | --- |
| **Statement** | For a DCBS adjustment with no splits (DCBSSplitCount = 0), the description shows a percentage computed as Math.Abs(1 - Adjustment) * 100; when splits exist, it shows "based on" instead. |
| **Trigger** | Document description build (OP-006) |
| **Enforcement** | `clsPremiumSummaryAdjustment.vb:729-762` |
| **Outcome** | Description text |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-019: Adjusted-rate DCBS descriptions use subject premium when ELCB applies

| Field | Value |
| --- | --- |
| **Statement** | The DCBS description basis is the literal "subject premium" when the adjustment is adjusted-rate and ELCB applies; otherwise it is the formatted BaseAmount ($###,##0.00). |
| **Trigger** | Document description build |
| **Enforcement** | `clsPremiumSummaryAdjustment.vb:729-762` |
| **Outcome** | Description text |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_EMP_LIAB](database-tables.md#policy_period_emp_liab) |
| **SQL** | [SQL-116](sql/SQL-116-saif-business-policy-premium.md) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-020: NEAP descriptions replace the normal adjustment text

| Field | Value |
| --- | --- |
| **Statement** | A NEAP adjustment's document description replaces any built text with "Total [Estimated ]Policy Premium Including DCBS Assessment". |
| **Trigger** | Document description build |
| **Enforcement** | `clsPremiumSummaryAdjustment.vb:729-762` |
| **Outcome** | Description text |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-021: ELCB applies when liability rows span a non-zero range

| Field | Value |
| --- | --- |
| **Statement** | ELCB applies to a policy period when at least one POLICY_PERIOD_EMP_LIAB row exists whose premium adjustment effective and expiration dates differ. |
| **Trigger** | ELCB determination (OP-008) |
| **Enforcement** | `clsPremiumSummaryAdjustment.vb:525-548` |
| **Outcome** | HasELCB set true/false |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_EMP_LIAB](database-tables.md#policy_period_emp_liab) |
| **SQL** | [SQL-117](sql/SQL-117-saif-business-policy-premium.md) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-022: Null statistical class becomes an empty string

| Field | Value |
| --- | --- |
| **Statement** | When the NCCI stat class procedure returns DBNull, the stat class is an empty string. |
| **Trigger** | Stat class determination (OP-009) |
| **Enforcement** | `clsPremiumSummaryAdjustment.vb:549-580` |
| **Outcome** | Empty string returned |
| **Confidence** | Verified |
| **SQL** | [SQL-119](sql/SQL-119-saif-business-policy-premium.md) |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-023: Renewal plans join the merged list only when policy number exists

| Field | Value |
| --- | --- |
| **Statement** | The renewal rating plan is included in the merged plan list only when its PolicyNumber <> 0; the merged list is ordered by effective date descending. |
| **Trigger** | Plan merge (OP-012) |
| **Enforcement** | `PolicyPeriodRatingPlans.GetPlans (iPolicyRatingPlan.vb)` |
| **Outcome** | Merged, ordered plan list |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_RATING_PLAN](database-tables.md#policy_period_rating_plan), [POLICY_RENEWAL_RATING_PLAN](database-tables.md#policy_renewal_rating_plan) |
| **Source** | `Business\SAIF.Business.Policy.Premium\iPolicyRatingPlan.vb` |

---
## BR-024: Premium summary adjustments do not support updates

| Field | Value |
| --- | --- |
| **Statement** | The UpdateSQL property of the premium summary adjustment criteria is not supported; attempting to use it is an error.* |
| **Trigger** | Any attempt to update a premium summary adjustment through the criteria |
| **Enforcement** | `clsPremiumSummaryAdjustment.Criteria.UpdateSQL` |
| **Outcome** | Throws ApplicationException(BOC.Messages.InvalidSQLProperty) — premium summary adjustments are insert-only* |
| **Confidence** | Inferred* |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb` |

---
## BR-025: Rows affected must equal one for persistence success

| Field | Value |
| --- | --- |
| **Statement** | A persistence statement that affects a number of rows other than exactly one is treated as a concurrency failure. |
| **Trigger** | Insert/update/delete completion |
| **Enforcement** | `After* handlers across the entity set — RowsAffected <> 1 → AddErrorMessage(..., BOC.Messages.DBContentionError)` |
| **Outcome** | Error added to the object |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Policy.Premium\clsClassCoverage.vb` |

---
## BR-026: Weighted claim frequency uses payroll-weighted averaging

| Field | Value |
| --- | --- |
| **Statement** | Weighted claim frequency for a set of class coverages equals Σ(claim frequency × payroll) ÷ total payroll. |
| **Trigger** | Claim frequency computation |
| **Enforcement** | `iClassCoverage.vb — WeightedClaimFrequency extension` |
| **Outcome** | Computed decimal |
| **Confidence** | Verified |
| **Tables** | [PREM_HIST_CLASS_COVERAGE](database-tables.md#prem_hist_class_coverage) |
| **Source** | `Business\SAIF.Business.Policy.Premium\iClassCoverage.vb` |

---

## Inherited business rules

Rules in this section originate from base classes or services provided by dependency framework libraries. They are enforced by inherited behavior, not by code in this library.

### From `clsBusinessBase` (`SAIF.Framework.Core`)

#### INH-001: BOF rules manager records and surfaces broken rules

| Field | Value |
| --- | --- |
| **Statement** | `clsBusinessBase` owns a `clsRulesManager` that records failed rule checks and exposes broken-rule state through the object surface.† |
| **Trigger** | Derived business objects call `Rules.CheckRules(...)` during validation or property updates.† |
| **Enforcement** | `clsRulesManager` locates registered handlers and stores failures for the derived object.† |
| **Outcome** | BOF-derived types in this library surface rule failures consistently through the inherited rules manager and IDataErrorInfo support.† |
| **Origin** | `SAIF.Framework.Core` — `clsBusinessBase` / `clsRulesManager` |
| **Source** | Retrieved framework documentation |

## Notes
- [BR-024](business-rules.md#br-024-premium-summary-adjustments-do-not-support-updates) is marked inferred because the insert-only behavior is concluded from the unsupported `UpdateSQL` path.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [API reference](api/index.md)

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

## Sources
- `Business\SAIF.Business.Policy.Premium\Rating\clsPremiumAdjustmentTypeCode.vb`
- `Business\SAIF.Business.Policy.Premium\SubTotalPremiumSummaryAdjustment.vb`
- `Business\SAIF.Business.Policy.Premium\clsClassCoverage.vb`
- `Business\SAIF.Business.Policy.Premium\clsClassCoverageBase.vb`
- `Business\SAIF.Business.Policy.Premium\clsClassCoverageBaseCollection.vb`
- `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodOccpap.vb`
- `Business\SAIF.Business.Policy.Premium\clsPolicyPeriodRatingPlan.vb`
- `Business\SAIF.Business.Policy.Premium\clsPolicyRenewalRatingPlan.vb`
- `Business\SAIF.Business.Policy.Premium\clsPremiumSummaryAdjustment.vb`
- `Business\SAIF.Business.Policy.Premium\iClassCoverage.vb`
- `Business\SAIF.Business.Policy.Premium\iPolicyRatingPlan.vb`
- `Business\SAIF.Business.Policy.Premium\iPremiumAmountProvider.vb`
- `Business\SAIF.Business.Policy.Premium\iPremiumSummaryAdjustment.vb`
