---
title: SAIF.Business business rules
summary: Enumerated business rules with per-rule trigger, enforcement, and outcomes.
status: draft
owner: SAIF
last_reviewed: 2026-07-24
library: SAIF.Business
reference_type: package
---

# SAIF.Business business rules

This page captures business rules enforced by `SAIF.Business` and by the Oracle procedures it invokes.

## BR-SB-001: Employee leave requires investigator, reason, begin date, and end date

| Field | Value |
| --- | --- |
| **Statement** | Employee leave records require investigator, reason, begin date, and end date before they can be saved. |
| **Trigger** | Saving `clsEmployeeLeave`. |
| **Enforcement** | `AddBusinessRules()` attaches required-field rules. |
| **Outcome** | Invalid leave objects are not savable. |
| **Confidence** | Verified |
| **Tables** | [EMPLOYEE_LEAVE](database-tables.md#employee-leave) |
| **SQL** | [SQL-002](sql/SQL-002-pk82029-titan-insert-employee-leave.md), [SQL-046](sql/SQL-046-pk82029-titan-update-employee-leave.md) |
| **Source** | `Business\SAIF.Business\clsEmployeeLeave.vb`; `Business\SAIF.Business\CommonBusinessRules.vb` |

---

## BR-SB-002: Employee leave dates must stay within allowed ranges and ordering

| Field | Value |
| --- | --- |
| **Statement** | Employee leave begin and end dates must be after `01/01/1900`, within two years, and remain ordered so the end date does not precede the begin date or today. |
| **Trigger** | Saving a modified leave row. |
| **Enforcement** | `Rule_ValidBeginDate`, `Rule_ValidEndDate`, `Rule_ValidDates`, and `Rule_FutreThruDate`. |
| **Outcome** | Rule violations return user-facing errors and block persistence. |
| **Confidence** | Verified |
| **Tables** | [EMPLOYEE_LEAVE](database-tables.md#employee-leave) |
| **SQL** | [SQL-002](sql/SQL-002-pk82029-titan-insert-employee-leave.md), [SQL-046](sql/SQL-046-pk82029-titan-update-employee-leave.md) |
| **Source** | `Business\SAIF.Business\clsEmployeeLeave.vb` |

---

## BR-SB-003: Extended policy periods split only when the period exceeds one year plus sixteen days

| Field | Value |
| --- | --- |
| **Statement** | Extended policy periods split into two NCCI units only when the period exceeds one year plus sixteen days. |
| **Trigger** | Calling `GetUnitSplitDate` or `GetPolicyPeriodUnits`. |
| **Enforcement** | `UnitStatServices` date logic. |
| **Outcome** | One or two `DateRange` units are returned. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_MASTER](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [US_POLICY_UNIT](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-043](sql/SQL-043-unit-stat-lookup-family.md) |
| **Source** | `Business\SAIF.Business\UnitStatServices.vb` |

---

## BR-SB-004: Report valuation schedules switch from five to ten periods in 2002

| Field | Value |
| --- | --- |
| **Statement** | Report valuation schedules produce five periods before `01/01/2002` and ten periods on or after that date. |
| **Trigger** | Calling `GetReportValuationPeriods`. |
| **Enforcement** | `NumberOfReportPeriods = If(inUnitEffectiveDate < UREStartDate, 5, 10)`. |
| **Outcome** | Report-cycle count changes by effective date. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_MASTER](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [US_POLICY_UNIT](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-043](sql/SQL-043-unit-stat-lookup-family.md) |
| **Source** | `Business\SAIF.Business\UnitStatServices.vb` |

---

## BR-SB-005: Low-number policies validate against NON_EMPR_ACCT

| Field | Value |
| --- | --- |
| **Statement** | Policy numbers below 18 are validated against `NON_EMPR_ACCT`, not `POLICY`. |
| **Trigger** | Calling `PolicyServices.IsValidPolicy`. |
| **Enforcement** | Conditional SQL branch inside `PolicyServices`. |
| **Outcome** | Low-number policies use a different validation table. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | `Business\SAIF.Business\PolicyServices.vb` |

---

## BR-SB-006: Claims are externally viewable only when external view flag is Y

| Field | Value |
| --- | --- |
| **Statement** | Claims are externally viewable only when `external_view_flag = Y`. |
| **Trigger** | Calling `ClaimServices.IsClaimAvailableExternalView`. |
| **Enforcement** | SQL filter on `CL_INJURY_CLAIM`. |
| **Outcome** | Non-viewable claims return `False`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-021](sql/SQL-021-external-view-eligibility-query.md) |
| **Source** | `Business\SAIF.Business\ClaimServices.vb` |

---

## BR-SB-007: Production external-user queries hide test users

| Field | Value |
| --- | --- |
| **Statement** | Production external-user queries exclude test users. |
| **Trigger** | Calling `GetLastLogonsByCustomer` or `GetUsersByCustomer` when production is active. |
| **Enforcement** | `excludeTestUsers = AppGlobal.EnvironmentService.IsProduction`. |
| **Outcome** | Results exclude test accounts in production. |
| **Confidence** | Verified |
| **Tables** | [EXT_USER](database-tables.md#ext-user-ext-user-type), [EXT_USER_TYPE](database-tables.md#ext-user-ext-user-type) |
| **SQL** | [SQL-036](sql/SQL-036-external-user-last-logon-user-lookup-family.md) |
| **Source** | `Business\SAIF.Business\Services\ExternalUserServices.vb` |

---

## BR-SB-008: Bank-validation behavior changes by environment

| Field | Value |
| --- | --- |
| **Statement** | Bank-validation behavior changes by environment. |
| **Trigger** | Calling bank-validation helpers. |
| **Enforcement** | `GetApplicationEnvironment()` branches in `BankValidatorServices`. |
| **Outcome** | DEV bypasses live checks; Test, QA, and Production allow verified-routing behavior. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business\BankValidatorServices.vb` |

---

## BR-SB-009: SAIF output-address retrieval requires at least one LOCATION row for XSAIF

| Field | Value |
| --- | --- |
| **Statement** | `clsSAIFOutputAddress` is only valid when at least one `LOCATION` row exists for `XSAIF`. |
| **Trigger** | Retrieving SAIF output addresses. |
| **Enforcement** | `ValidObject` checks `m_AddressList.Count > 0`. |
| **Outcome** | Empty catalogs raise a validation error. |
| **Confidence** | Verified |
| **Tables** | [LOCATION](database-tables.md#location) |
| **SQL** | [SQL-033](sql/SQL-033-saif-output-address-retrieval.md) |
| **Source** | `Business\SAIF.Business\clsSAIFOutputAddress.vb` |

---

## BR-SB-010: Benefit-payment history checks map business context to payment-category filters

| Field | Value |
| --- | --- |
| **Statement** | Benefit-payment history checks map the requested benefit context to payment-category filters, and the DCS partial branch also requires amount and issue date.* |
| **Trigger** | Calling `ClaimServices.HasExistingBenefitPayment`. |
| **Enforcement** | Runtime SQL branch selection in `ClaimServices`. |
| **Outcome** | The query narrows payment-history matches to the applicable branch and filter set. |
| **Confidence** | Inferred* |
| **Tables** | [CL_FINANCIAL_TRANS](database-tables.md#cl-financial-trans-cl-financial-trans-dtl), [CL_FINANCIAL_TRANS_DTL](database-tables.md#cl-financial-trans-cl-financial-trans-dtl) |
| **SQL** | [SQL-012](sql/SQL-012-existing-benefit-payment-search.md) |
| **Source** | `Business\SAIF.Business\ClaimServices.vb` |

---

## BR-SB-011: Employee collection retrieval appends literal filter predicates

| Field | Value |
| --- | --- |
| **Statement** | Employee collection retrieval appends literal department, job-title, location, and active-only predicates to the shared employee query.* |
| **Trigger** | Calling `clsEmployeeDataCollection.Criteria.RetrieveSQL` with the corresponding retrieval mode. |
| **Enforcement** | Conditional SQL concatenation in `clsEmployeeDataCollection.Criteria`. |
| **Outcome** | The collection returns only rows matching the selected filter mode. |
| **Confidence** | Inferred* |
| **Tables** | [ADP_EMPLOYEE](database-tables.md#adp-employee) |
| **SQL** | [SQL-026](sql/SQL-026-employee-collection-retrieval.md) |
| **Source** | `Business\SAIF.Business\clsEmployeeDataCollection.vb` |

---

## BR-SB-012: NCCI policy numbers prefix voluntary policies with A and others with C

| Field | Value |
| --- | --- |
| **Statement** | NCCI policy-number generation prefixes voluntary policies with `A` and other policies with `C`. |
| **Trigger** | Calling `UnitStatServices.GetNCCIPolicyNumber`. |
| **Enforcement** | CASE expression in the `POLICY`/`POLICY_PERIOD_MASTER` lookup. |
| **Outcome** | The generated NCCI policy number encodes market type in its leading character. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_MASTER](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-043](sql/SQL-043-unit-stat-lookup-family.md) |
| **Source** | `Business\SAIF.Business\UnitStatServices.vb` |

---

## BR-SB-013: Employee leave updates expect single-row success

| Field | Value |
| --- | --- |
| **Statement** | Employee leave updates expect exactly one-row success from the persistence path. |
| **Trigger** | Calling `clsEmployeeLeave.BeforeUpdate`. |
| **Enforcement** | BOF persistence expectation documented in the DB cross-reference findings. |
| **Outcome** | Unexpected update counts indicate contention or failed persistence. |
| **Confidence** | Verified |
| **Tables** | [EMPLOYEE_LEAVE](database-tables.md#employee-leave) |
| **SQL** | [SQL-046](sql/SQL-046-pk82029-titan-update-employee-leave.md) |
| **Source** | `Business\SAIF.Business\clsEmployeeLeave.vb` |

---

## BR-SB-014: Employee leave deletes expect single-row success

| Field | Value |
| --- | --- |
| **Statement** | Employee leave deletes expect exactly one-row success from the persistence path. |
| **Trigger** | Calling `clsEmployeeLeave.BeforeDelete`. |
| **Enforcement** | BOF persistence expectation documented in the DB cross-reference findings. |
| **Outcome** | Unexpected delete counts indicate contention or failed persistence. |
| **Confidence** | Verified |
| **Tables** | [EMPLOYEE_LEAVE](database-tables.md#employee-leave) |
| **SQL** | [SQL-047](sql/SQL-047-pk82029-titan-delete-employee-leave.md) |
| **Source** | `Business\SAIF.Business\clsEmployeeLeave.vb` |

---

## PROC-RULE-001: Alert recipients are concatenated only while the output buffer remains under 4000 characters.

| Field | Value |
| --- | --- |
| **Statement** | Alert recipients are concatenated only while the output buffer remains under 4000 characters. |
| **Trigger** | `LENGTH(vreturn) < 4000` during task iteration. |
| **Enforcement** | `pk73101_image.who_was_alerted` |
| **Outcome** | Append `task_user` to the return string, prefixing later values with `, `. |
| **Confidence** | Verified |
| **Tables** | [RECORDING](database-tables.md#recording) |
| **SQL** | [SQL-038](sql/SQL-038-imaging-helper-sql-procedure-family.md) |
| **Source** | [pk73101_image](procedures/pk73101-image.md#business-rules) |

---

## PROC-RULE-002: Missing alert tasks produce an explicit not-found message.

| Field | Value |
| --- | --- |
| **Statement** | Missing alert tasks produce an explicit not-found message. |
| **Trigger** | `dummy = -1` after the task loop. |
| **Enforcement** | `pk73101_image.who_was_alerted` |
| **Outcome** | Return `No alerts found for the selected image.` |
| **Confidence** | Verified |
| **Tables** | [RECORDING](database-tables.md#recording) |
| **SQL** | [SQL-038](sql/SQL-038-imaging-helper-sql-procedure-family.md) |
| **Source** | [pk73101_image](procedures/pk73101-image.md#business-rules) |

---

## PROC-RULE-003: The result message uses singular or plural grammar based on alert count.

| Field | Value |
| --- | --- |
| **Statement** | The result message uses singular or plural grammar based on alert count. |
| **Trigger** | `vcounter = 1` versus more than one task. |
| **Enforcement** | `pk73101_image.who_was_alerted` |
| **Outcome** | Append `has been alerted...` for one user or `have been alerted...` for multiple users. |
| **Confidence** | Verified |
| **Tables** | [RECORDING](database-tables.md#recording) |
| **SQL** | [SQL-038](sql/SQL-038-imaging-helper-sql-procedure-family.md) |
| **Source** | [pk73101_image](procedures/pk73101-image.md#business-rules) |

---

## PROC-RULE-004: Claim image alerting is enabled only when at least one flagged legal case exists for the claim.

| Field | Value |
| --- | --- |
| **Statement** | Claim image alerting is enabled only when at least one flagged legal case exists for the claim. |
| **Trigger** | `v_cases > 0` after counting `LEGAL_CASE` rows with `claim_image_alerts_flag = 'Y'`. |
| **Enforcement** | `pk80001_LegalNet.alertlegalcase` |
| **Outcome** | Set `outAlertFlag` to `Y`; otherwise leave it as `N`. |
| **Confidence** | Verified |
| **Tables** | [LEGAL_CASE](database-tables.md#legal-case-legal-collection-investigation-cl-claim-support-order-conn) |
| **SQL** | [SQL-038](sql/SQL-038-imaging-helper-sql-procedure-family.md) |
| **Source** | [pk80001_LegalNet](procedures/pk80001-legalnet.md#business-rules) |

---

## PROC-RULE-005: The procedure uses the caller-supplied date when one is provided.

| Field | Value |
| --- | --- |
| **Statement** | The procedure uses the caller-supplied date when one is provided. |
| **Trigger** | `inDate IS NOT NULL`. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Convert `inDate` with `TO_DATE(inDate, 'MM/DD/YYYY')` and assign it to `v_date`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-006: Default correspondence address lookup falls back from guardian to mailing to home address.

| Field | Value |
| --- | --- |
| **Statement** | Default correspondence address lookup falls back from guardian to mailing to home address. |
| **Trigger** | `inAddrType = '1'`. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Test address existence for `G`, then `M`, then `H`, and use the first qualifying type. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-007: Default payment address lookup falls back from guardian to payment to mailing to home address.

| Field | Value |
| --- | --- |
| **Statement** | Default payment address lookup falls back from guardian to payment to mailing to home address. |
| **Trigger** | `inAddrType = '2'`. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Test address existence for `G`, then `P`, then `M`, then `H`, and use the first qualifying type. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-008: Explicit payment requests only use payment addresses.

| Field | Value |
| --- | --- |
| **Statement** | Explicit payment requests only use payment addresses. |
| **Trigger** | `inAddrType = 'P'` and the payment address exists. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Select address type `P`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-009: Other requests use the requested address type directly.

| Field | Value |
| --- | --- |
| **Statement** | Other requests use the requested address type directly. |
| **Trigger** | `inAddrType` is not `1`, `2`, or `P`, and `typeAddressExists_GW` returns true. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Keep the requested address type as `v_addresstypefound`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-010: Guardian correspondence resolves the guardian mailing address and inserts a `For:` line for the worker/beneficiary.

| Field | Value |
| --- | --- |
| **Statement** | Guardian correspondence resolves the guardian mailing address and inserts a `For:` line for the worker/beneficiary. |
| **Trigger** | `v_addrtype = 'G'` after address selection. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Resolve the guardian `person_id`, switch the address code to `M`, shift address lines, and populate `v_address_line1` with `For: <name>`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-011: Deceased people are addressed as estates.

| Field | Value |
| --- | --- |
| **Statement** | Deceased people are addressed as estates. |
| **Trigger** | `pra.death_date` is not null in the address lookup row. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Prefix the person name with `Estate of`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-012: Blank address lines are compacted upward to eliminate gaps.

| Field | Value |
| --- | --- |
| **Statement** | Blank address lines are compacted upward to eliminate gaps. |
| **Trigger** | Any of `v_address_line1` through `v_address_line4` is blank while later lines contain data. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Shift lower address lines into the first available blank slot. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-013: Addressee salutation is gender-based.

| Field | Value |
| --- | --- |
| **Statement** | Addressee salutation is gender-based. |
| **Trigger** | `v_gender = 'M'`, `v_gender = 'F'`, or any other value. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Set `v_addressee` to `Mr.`, `Ms.`, or `M.` plus the last name. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-014: An address is valid only when it has a person name, two populated address lines, and either foreign-address status or a city/state pair.

| Field | Value |
| --- | --- |
| **Statement** | An address is valid only when it has a person name, two populated address lines, and either foreign-address status or a city/state pair. |
| **Trigger** | `v_person_name`, `v_address_line1`, and `v_address_line2` are nonblank, plus `v_foreign_address_flag = 'Y'` or both `v_city_name` and `v_state_code` are nonblank. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Set `v_isvalidaddress` to `Y`. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-015: Requests with no qualifying address return no rows.

| Field | Value |
| --- | --- |
| **Statement** | Requests with no qualifying address return no rows. |
| **Trigger** | `v_addresstypefound <> v_addrtype`. |
| **Enforcement** | `pk82001_claim.getPersonAddress_GW` |
| **Outcome** | Open the `DUAL` cursor with `WHERE v_EMPTY = 'Y'` to return an empty result set. |
| **Confidence** | Verified |
| **Tables** | [CL_INJURY_CLAIM](database-tables.md#cl-injury-claim-cl-claim-responsibility) |
| **SQL** | [SQL-005](sql/SQL-005-pk82001-claim-getpersonaddress.md) |
| **Source** | [pk82001_claim](procedures/pk82001-claim.md#business-rules) |

---

## PROC-RULE-016: Pending-inclusive authorization checks bypass bank-account status and prenote gating.

| Field | Value |
| --- | --- |
| **Statement** | Pending-inclusive authorization checks bypass bank-account status and prenote gating. |
| **Trigger** | `inIncludePending = 'TRUE'`. |
| **Enforcement** | `pk82350_eft.isauthorizedforeft` |
| **Outcome** | Set `v_pending_flag = 1` before calling the shared authorization lookup. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-017: Non-pending authorization checks require an active bank account and successful prenote when prenote is required.

| Field | Value |
| --- | --- |
| **Statement** | Non-pending authorization checks require an active bank account and successful prenote when prenote is required. |
| **Trigger** | Shared `isauthforeft` path runs with `v_pending_flag = 0`. |
| **Enforcement** | `pk82350_eft.isauthorizedforeft` |
| **Outcome** | Match only `bank_account_status_code IN ('NEW','VALID')` rows where prenote is not required or `prenote_success_date` is populated. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-018: Beneficiary EFT authorizations must be effective, unreversed, and backed by an active bank account.

| Field | Value |
| --- | --- |
| **Statement** | Beneficiary EFT authorizations must be effective, unreversed, and backed by an active bank account. |
| **Trigger** | `trunc(auth_date) <= indate`, `revoke_date IS NULL`, and `bank_account_status_code IN ('NEW','VALID')`. |
| **Enforcement** | `pk82350_eft.isbeneficiaryauthforeft` |
| **Outcome** | Return the matching `payment_authorization_seq_num`; otherwise keep the default `-222`. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-019: Provider EFT authorization checks use the same pending-versus-active gating as person authorization checks.

| Field | Value |
| --- | --- |
| **Statement** | Provider EFT authorization checks use the same pending-versus-active gating as person authorization checks. |
| **Trigger** | `inIncludePending = 'TRUE'` or the default non-pending path. |
| **Enforcement** | `pk82350_eft.isproviderauthforeft` |
| **Outcome** | Either include pending rows or require `NEW`/`VALID` status plus a successful prenote when required. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-020: Active-authorization counts honor the same pending and prenote rules as sequence lookups.

| Field | Value |
| --- | --- |
| **Statement** | Active-authorization counts honor the same pending and prenote rules as sequence lookups. |
| **Trigger** | `inIncludePending = 'TRUE'` or the default non-pending path. |
| **Enforcement** | `pk82350_eft.ActiveAuthCountByPerson` |
| **Outcome** | Count all matching authorizations or only active/prenoted authorizations for the person and auth type. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-021: Only non-terminated debit card enrollments count as active enrollments.

| Field | Value |
| --- | --- |
| **Statement** | Only non-terminated debit card enrollments count as active enrollments. |
| **Trigger** | `card_term_date IS NULL`. |
| **Enforcement** | `pk82350_eft.CardEnrollmentCountByPerson` |
| **Outcome** | Include the enrollment row in the returned count. |
| **Confidence** | Verified |
| **Tables** | [PAYMENT_AUTHORIZATION](database-tables.md#payment-authorization) |
| **SQL** | [SQL-019](sql/SQL-019-pk82350-eft-isauthorizedforeft.md), [SQL-020](sql/SQL-020-pk82350-eft-isbeneficiaryauthforeft.md), [SQL-035](sql/SQL-035-eft-procedure-family.md) |
| **Source** | [pk82350_eft](procedures/pk82350-eft.md#business-rules) |

---

## PROC-RULE-022: UW312 and UW310 correspondence prefers the payroll mailing address before standard policy locations.

| Field | Value |
| --- | --- |
| **Statement** | UW312 and UW310 correspondence prefers the payroll mailing address before standard policy locations. |
| **Trigger** | `in_correspond_type = 'UW312'` or `in_correspond_type = 'UW310'`. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Query `special_loc` first, then fall back to `loc`, then `EXP`. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-023: Other correspondence uses the standard policy location first and then the latest eligible expired policy location.

| Field | Value |
| --- | --- |
| **Statement** | Other correspondence uses the standard policy location first and then the latest eligible expired policy location. |
| **Trigger** | Any other `in_correspond_type`. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Query `loc`, then `EXP`, and raise `no_policy_location` if neither cursor returns a row. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-024: Policy-location rows are filtered against either the policy effective date or the process date depending on whether processing is before or after the policy period start.

| Field | Value |
| --- | --- |
| **Statement** | Policy-location rows are filtered against either the policy effective date or the process date depending on whether processing is before or after the policy period start. |
| **Trigger** | `process_date < TO_DATE(in_pol_per_eff_date, 'DD-MON-YYYY')` versus `process_date >= TO_DATE(in_pol_per_eff_date, 'DD-MON-YYYY')`. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Apply the corresponding effective/expiration-date window in the `loc` and `special_loc` cursors. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-025: Barcode output switches to email address for UW560 correspondence.

| Field | Value |
| --- | --- |
| **Statement** | Barcode output switches to email address for UW560 correspondence. |
| **Trigger** | `in_correspond_type = 'UW560'`. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Set `bar_code` from `email_addr` instead of `usps_barcode`. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-026: Missing country codes default to the United States before country-name lookup.

| Field | Value |
| --- | --- |
| **Statement** | Missing country codes default to the United States before country-name lookup. |
| **Trigger** | `out_loc_country_cd IS NULL`. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Assign `v_country_cd := 'US'`. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-027: The DBA line is only emitted when the legal name differs from the policy name.

| Field | Value |
| --- | --- |
| **Statement** | The DBA line is only emitted when the legal name differs from the policy name. |
| **Trigger** | `out_legal_name = out_policy_name` versus different values. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Leave `out_dba_name` blank when they match; otherwise set `out_dba_name` to `DBA: <policy_name>`. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-028: Missing policy-location data is surfaced as an application error after blanking all output fields.

| Field | Value |
| --- | --- |
| **Statement** | Missing policy-location data is surfaced as an application error after blanking all output fields. |
| **Trigger** | `no_policy_location` exception is raised. |
| **Enforcement** | `sp62087_get_policy_address` |
| **Outcome** | Clear the output variables and raise `RAISE_APPLICATION_ERROR(-20001, 'No policy_location exists for this policy.')`. |
| **Confidence** | Verified |
| **Tables** | [POLICY](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit), [LOCATION](database-tables.md#location), [COUNTRY](database-tables.md#country) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [sp62087_get_policy_address](procedures/sp62087-get-policy-address.md#business-rules) |

---

## PROC-RULE-029: MAX mode returns the first day of the month 15 months after the effective date.

| Field | Value |
| --- | --- |
| **Statement** | MAX mode returns the first day of the month 15 months after the effective date. |
| **Trigger** | `UPPER(in_function_code) = 'MAX'`. |
| **Enforcement** | `SP72232_Calc_Policy_Exp_Date` |
| **Outcome** | Set `v_out_exp_date := TRUNC(ADD_MONTHS(in_pol_per_eff_date, 15), 'month')`. |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [SP72232_Calc_Policy_Exp_Date](procedures/sp72232-calc-policy-exp-date.md#business-rules) |

---

## PROC-RULE-030: Default mode uses a 13-month horizon for second-half effective dates and 12 months otherwise.

| Field | Value |
| --- | --- |
| **Statement** | Default mode uses a 13-month horizon for second-half effective dates and 12 months otherwise. |
| **Trigger** | `UPPER(in_function_code) <> 'MAX'` and `v_eff_day > 15` versus `v_eff_day <= 15`. |
| **Enforcement** | `SP72232_Calc_Policy_Exp_Date` |
| **Outcome** | Set `v_out_exp_date` to the first day of the month 13 or 12 months after the effective date. |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [SP72232_Calc_Policy_Exp_Date](procedures/sp72232-calc-policy-exp-date.md#business-rules) |

---

## PROC-RULE-031: AR policies snap the calculated expiration month to quarter boundaries.

| Field | Value |
| --- | --- |
| **Statement** | AR policies snap the calculated expiration month to quarter boundaries. |
| **Trigger** | `UPPER(in_fs) = 'AR'` and the derived `MMDD` falls into the defined quarter ranges. |
| **Enforcement** | `SP72232_Calc_Policy_Exp_Date` |
| **Outcome** | Adjust the output month to `04`, `07`, `10`, or `01`, incrementing the year after October. |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [SP72232_Calc_Policy_Exp_Date](procedures/sp72232-calc-policy-exp-date.md#business-rules) |

---

## PROC-RULE-032: Unhandled calculation failures are surfaced as application errors.

| Field | Value |
| --- | --- |
| **Statement** | Unhandled calculation failures are surfaced as application errors. |
| **Trigger** | `WHEN OTHERS` exception. |
| **Enforcement** | `SP72232_Calc_Policy_Exp_Date` |
| **Outcome** | Raise `RAISE_APPLICATION_ERROR(-20002, 'Error in sp72232: ' |
| **Confidence** | Verified |
| **Tables** | [POLICY_PERIOD_ALL](database-tables.md#policy-policy-period-all-policy-period-master-us-policy-unit) |
| **SQL** | [SQL-042](sql/SQL-042-policy-lookup-family.md) |
| **Source** | [SP72232_Calc_Policy_Exp_Date](procedures/sp72232-calc-policy-exp-date.md#business-rules) |

---

## PROC-RULE-033: Claim authorization exists only when the employee has a matching business-process/function-limit row with a sufficient maximum amount.

| Field | Value |
| --- | --- |
| **Statement** | Claim authorization exists only when the employee has a matching business-process/function-limit row with a sufficient maximum amount. |
| **Trigger** | A joined `ADP_EMPLOYEE` and `CL_CLAIM_EMP_BUS_FUNC_LIMIT` row matches `inMailId`, `inBusProcess`, `inAuthPurpose`, `inFunction`, and `inAmount <= MAX_AMOUNT`. |
| **Enforcement** | `sp82348_claim_authorization` |
| **Outcome** | Return the number of qualifying rows through `outCount`. |
| **Confidence** | Verified |
| **Tables** | [ADP_EMPLOYEE](database-tables.md#adp-employee) |
| **SQL** | [SQL-018](sql/SQL-018-sp82348-claim-authorization.md) |
| **Source** | [sp82348_claim_authorization](procedures/sp82348-claim-authorization.md#business-rules) |

---

## Stored procedure business rules

Rules sourced from Oracle stored procedures referenced by this library.

| Rule ID | Rule | Source | Link |
| --- | --- | --- | --- |
| [PROC-RULE-001](#proc-rule-001-alert-recipients-are-concatenated-only-while-the-output-buffer-remains-under-4000-characters) | Alert recipients are concatenated only while the output buffer remains under 4000 characters. | `pk73101_image` | [Details](procedures/pk73101-image.md#business-rules) |
| [PROC-RULE-002](#proc-rule-002-missing-alert-tasks-produce-an-explicit-not-found-message) | Missing alert tasks produce an explicit not-found message. | `pk73101_image` | [Details](procedures/pk73101-image.md#business-rules) |
| [PROC-RULE-003](#proc-rule-003-the-result-message-uses-singular-or-plural-grammar-based-on-alert-count) | The result message uses singular or plural grammar based on alert count. | `pk73101_image` | [Details](procedures/pk73101-image.md#business-rules) |
| [PROC-RULE-004](#proc-rule-004-claim-image-alerting-is-enabled-only-when-at-least-one-flagged-legal-case-exists-for-the-claim) | Claim image alerting is enabled only when at least one flagged legal case exists for the claim. | `pk80001_LegalNet` | [Details](procedures/pk80001-legalnet.md#business-rules) |
| [PROC-RULE-005](#proc-rule-005-the-procedure-uses-the-caller-supplied-date-when-one-is-provided) | The procedure uses the caller-supplied date when one is provided. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-006](#proc-rule-006-default-correspondence-address-lookup-falls-back-from-guardian-to-mailing-to-home-address) | Default correspondence address lookup falls back from guardian to mailing to home address. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-007](#proc-rule-007-default-payment-address-lookup-falls-back-from-guardian-to-payment-to-mailing-to-home-address) | Default payment address lookup falls back from guardian to payment to mailing to home address. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-008](#proc-rule-008-explicit-payment-requests-only-use-payment-addresses) | Explicit payment requests only use payment addresses. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-009](#proc-rule-009-other-requests-use-the-requested-address-type-directly) | Other requests use the requested address type directly. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-010](#proc-rule-010-guardian-correspondence-resolves-the-guardian-mailing-address-and-inserts-a-for-line-for-the-worker-beneficiary) | Guardian correspondence resolves the guardian mailing address and inserts a `For:` line for the worker/beneficiary. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-011](#proc-rule-011-deceased-people-are-addressed-as-estates) | Deceased people are addressed as estates. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-012](#proc-rule-012-blank-address-lines-are-compacted-upward-to-eliminate-gaps) | Blank address lines are compacted upward to eliminate gaps. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-013](#proc-rule-013-addressee-salutation-is-gender-based) | Addressee salutation is gender-based. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-014](#proc-rule-014-an-address-is-valid-only-when-it-has-a-person-name-two-populated-address-lines-and-either-foreign-address-status-or-a-city-state-pair) | An address is valid only when it has a person name, two populated address lines, and either foreign-address status or a city/state pair. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-015](#proc-rule-015-requests-with-no-qualifying-address-return-no-rows) | Requests with no qualifying address return no rows. | `pk82001_claim` | [Details](procedures/pk82001-claim.md#business-rules) |
| [PROC-RULE-016](#proc-rule-016-pending-inclusive-authorization-checks-bypass-bank-account-status-and-prenote-gating) | Pending-inclusive authorization checks bypass bank-account status and prenote gating. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-017](#proc-rule-017-non-pending-authorization-checks-require-an-active-bank-account-and-successful-prenote-when-prenote-is-required) | Non-pending authorization checks require an active bank account and successful prenote when prenote is required. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-018](#proc-rule-018-beneficiary-eft-authorizations-must-be-effective-unreversed-and-backed-by-an-active-bank-account) | Beneficiary EFT authorizations must be effective, unreversed, and backed by an active bank account. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-019](#proc-rule-019-provider-eft-authorization-checks-use-the-same-pending-versus-active-gating-as-person-authorization-checks) | Provider EFT authorization checks use the same pending-versus-active gating as person authorization checks. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-020](#proc-rule-020-active-authorization-counts-honor-the-same-pending-and-prenote-rules-as-sequence-lookups) | Active-authorization counts honor the same pending and prenote rules as sequence lookups. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-021](#proc-rule-021-only-non-terminated-debit-card-enrollments-count-as-active-enrollments) | Only non-terminated debit card enrollments count as active enrollments. | `pk82350_eft` | [Details](procedures/pk82350-eft.md#business-rules) |
| [PROC-RULE-022](#proc-rule-022-uw312-and-uw310-correspondence-prefers-the-payroll-mailing-address-before-standard-policy-locations) | UW312 and UW310 correspondence prefers the payroll mailing address before standard policy locations. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-023](#proc-rule-023-other-correspondence-uses-the-standard-policy-location-first-and-then-the-latest-eligible-expired-policy-location) | Other correspondence uses the standard policy location first and then the latest eligible expired policy location. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-024](#proc-rule-024-policy-location-rows-are-filtered-against-either-the-policy-effective-date-or-the-process-date-depending-on-whether-processing-is-before-or-after-the-policy-period-start) | Policy-location rows are filtered against either the policy effective date or the process date depending on whether processing is before or after the policy period start. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-025](#proc-rule-025-barcode-output-switches-to-email-address-for-uw560-correspondence) | Barcode output switches to email address for UW560 correspondence. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-026](#proc-rule-026-missing-country-codes-default-to-the-united-states-before-country-name-lookup) | Missing country codes default to the United States before country-name lookup. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-027](#proc-rule-027-the-dba-line-is-only-emitted-when-the-legal-name-differs-from-the-policy-name) | The DBA line is only emitted when the legal name differs from the policy name. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-028](#proc-rule-028-missing-policy-location-data-is-surfaced-as-an-application-error-after-blanking-all-output-fields) | Missing policy-location data is surfaced as an application error after blanking all output fields. | `sp62087_get_policy_address` | [Details](procedures/sp62087-get-policy-address.md#business-rules) |
| [PROC-RULE-029](#proc-rule-029-max-mode-returns-the-first-day-of-the-month-15-months-after-the-effective-date) | MAX mode returns the first day of the month 15 months after the effective date. | `SP72232_Calc_Policy_Exp_Date` | [Details](procedures/sp72232-calc-policy-exp-date.md#business-rules) |
| [PROC-RULE-030](#proc-rule-030-default-mode-uses-a-13-month-horizon-for-second-half-effective-dates-and-12-months-otherwise) | Default mode uses a 13-month horizon for second-half effective dates and 12 months otherwise. | `SP72232_Calc_Policy_Exp_Date` | [Details](procedures/sp72232-calc-policy-exp-date.md#business-rules) |
| [PROC-RULE-031](#proc-rule-031-ar-policies-snap-the-calculated-expiration-month-to-quarter-boundaries) | AR policies snap the calculated expiration month to quarter boundaries. | `SP72232_Calc_Policy_Exp_Date` | [Details](procedures/sp72232-calc-policy-exp-date.md#business-rules) |
| [PROC-RULE-032](#proc-rule-032-unhandled-calculation-failures-are-surfaced-as-application-errors) | Unhandled calculation failures are surfaced as application errors. | `SP72232_Calc_Policy_Exp_Date` | [Details](procedures/sp72232-calc-policy-exp-date.md#business-rules) |
| [PROC-RULE-033](#proc-rule-033-claim-authorization-exists-only-when-the-employee-has-a-matching-business-process-function-limit-row-with-a-sufficient-maximum-amount) | Claim authorization exists only when the employee has a matching business-process/function-limit row with a sufficient maximum amount. | `sp82348_claim_authorization` | [Details](procedures/sp82348-claim-authorization.md#business-rules) |

> **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
- [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)
- [Procedures](procedures/index.md)
- [API reference](api/index.md)
- [Security and authorization](security-authorization.md)
- [Configuration](configuration.md)

## Sources
- `Business\SAIF.Business\clsEmployeeLeave.vb`
- `Business\SAIF.Business\CommonBusinessRules.vb`
- `Business\SAIF.Business\UnitStatServices.vb`
- `Business\SAIF.Business\PolicyServices.vb`
- `Business\SAIF.Business\ClaimServices.vb`
- `Business\SAIF.Business\Services\ExternalUserServices.vb`
- `Business\SAIF.Business\BankValidatorServices.vb`
- `Business\SAIF.Business\clsSAIFOutputAddress.vb`
- `Business\SAIF.Business\ImageServices.vb`
- `Business\SAIF.Business\ObjectServices.vb`
