Skip to content

Maintain provider address

clsProviderAddress maintains dated address records (physical, mailing, etc.) per provider location. Every address type keeps its own effective/expiration timeline, addresses are normalized against USPS standards through CleanAddressHelper, and address changes for the current, unexpired record are synchronized to Contact Manager through clsAddressApi.

Field Value
Operation ID OP-PRV-04
Trigger Caller calls NewProviderAddress/GetProviderAddress, edits properties, and calls Save() or Delete()
Inputs ProviderLocationSeqNum, AddressTypeCode, EffDate/ExpDate, ForeignAddressFlag, address lines 1–3, CityName, StateCode, ZipCode/ZipCodeExt, CountryCode
Outputs Persisted PROVIDER_ADDRESS row; USPS-standardized address content; Contact Manager AddressDto sync
Primary components clsProviderAddress.Create, BeforeInsert/BeforeUpdate/BeforeDelete, CleanAddressHelper.DetermineAddressLinesToClean, clsAddressApi.Add/Update/RemoveAddress
Entry point Business\SAIF.Business.Provider\clsProviderAddress.vb

Steps

  1. Create. Create() assigns ProviderLocationSeqNum and a new ProviderAddressSeqNum via GetNextSeqNum("PROVIDER_ADDRESS_SEQ") when created from a location, or uses the criteria's address seq num directly for other construction paths.
  2. Retrieve. BeforeRetrieve/AfterRetrieve read PROVIDER_ADDRESS by PROVIDER_ADDRESS_SEQ_NUM (SQL-043); if the retrieved row is flagged foreign (ForeignAddressFlag = "Y"), StateCode is cleared in memory immediately after fill.
  3. Foreign/domestic toggling. Setting ForeignAddressFlag = "Y" clears StateCode as a side effect of the property setter, before save is even attempted.
  4. Validate dates and content before save.
  5. ValidateEffDate: hard error if the effective date is invalid, or (when modified) is before today.
  6. ValidateExpDate: hard error if the expiration date is today or in the future, or more than 30 years old; also blocks clearing an expiration date when a later same-type address already exists (BR-026).
  7. ValidateEffDateVsExpDate: hard error if the effective date is after the expiration date.
  8. ValidateExistingDates / ValidateEffOverlapingDates / ValidateExpOverlapingDates: hard errors that scan RelatedAddresses (same address type only) and reject a new open-ended address when another open-ended row of the same type exists, or when effective/expiration ranges overlap (BR-007).
  9. ValidateAddress/ValidateCity/ValidateState/ValidateZip/ValidateZipExt: hard errors requiring address line 1 always, and city/state (validated against the state code list)/ZIP (≥5 digits)/ZIP+4 (exactly 4 digits when present) only for domestic addresses (ForeignAddressFlag = "N") (BR-008).
  10. Normalize the address (warning-only). ValidateCleanAddress calls CleanAddressHelper:
  11. DetermineAddressLinesToClean() sends only two lines to the cleansing service — lines 2+3 if line 3 is populated, otherwise lines 1+2 — and calls service.CleanAddress(line1, line2, city, state, zip, zip4, True).
  12. If the service reports the address was cleaned: CheckForDroppedAddressLine() restores the original line 1 if the cleanser appears to have dropped it (detected by comparing the first three characters of the old line 2 against the old line 1), then UpdateAddressLines() writes the proper-cased, standardized lines/city/state/zip/zip4 back onto the object.
  13. The rule raises a warning either way: "Warning: Address has been updated to postal standards." when cleaned, or "Warning: Address may be incorrect." when the cleanser could not standardize it — neither blocks the save.
  14. Insert. BeforeInsert writes address type, dates, lines, city/state/zip/zip4/country, ForeignAddressFlag, and audit fields to PROVIDER_ADDRESS (SQL-019).
  15. FillAdressDto() builds AddressDto with resolved addressType description, providerNumber, and isPrimary (via clsProviderUtility).
  16. On success, AddContactManagerAddress() calls the API only if ExpDate = Date.MinValue (the address is current/effective); an expired address on creation is not synced.*
  17. Update. BeforeUpdate writes the same fields to PROVIDER_ADDRESS (SQL-067) with concurrency check WHERE PROVIDER_ADDRESS_SEQ_NUM = :ProviderAddressSeqNum AND UPDATE_NUM = :UpdateNum.
  18. UpdateContactManagerAddress() branches on the transition between the originally retrieved expiration date and the new one:
    • Was open-ended, now expired → calls RemoveContactManagerAddressApi().
    • Was open-ended, still open-ended → calls UpdateContactManagerAddressApi().
    • Was expired, now open-ended → calls AddContactManagerAddressApi().
    • Was expired, still expired → no API call.
  19. clsAddressApi routes: insert/update provider/{providerLocationSeqNumber}/address, delete provider/{providerLocationSeqNumber}/address/remove; exceptions are caught by CreateErrorMessage(), which logs the serialized DTO and adds an InsertError/UpdateError/DeleteError.
  20. Delete. BeforeDelete deletes the PROVIDER_ADDRESS row by ProviderAddressSeqNum (SQL-089); AfterDelete only checks rows affected and marks the object new — no Contact Manager remove call is made on delete, unlike the expiration-transition sync used during update.*

Process flow

flowchart TD
    Start([Caller edits address]) --> Domestic{Foreign or domestic?}
    Domestic -->|Domestic| ReqFields[Require line1, city, state, zip]
    Domestic -->|Foreign| SkipFields[Skip city/state/zip requirement;<br>state forced blank]
    ReqFields --> Overlap{Overlaps or duplicates<br>same-type open-ended address?}
    SkipFields --> Overlap
    Overlap -->|Yes| Fail([Overlapping effective period<br>blocks save])
    Overlap -->|No| Clean[Send 2 lines to CleanAddressHelper]
    Clean --> Cleaned{Standardized?}
    Cleaned -->|Yes| WarnClean([Warning: updated to postal standards])
    Cleaned -->|No| WarnBad([Warning: address may be incorrect])
    WarnClean --> Persist[Insert or update PROVIDER_ADDRESS]
    WarnBad --> Persist
    Persist --> Rows{RowsAffected = 1?}
    Rows -->|No| Contention([Insert Failed / DB contention error])
    Rows -->|Yes| ExpTransition{Expiration transition?}
    ExpTransition -->|Open to expired| ApiRemove[Contact Manager remove]
    ExpTransition -->|Expired to open| ApiAdd[Contact Manager add]
    ExpTransition -->|No material change| NoApi([No Contact Manager call])
    ApiRemove --> Done([Save complete])
    ApiAdd --> Done
    NoApi --> Done

Failure and edge-case behavior

  • Deleting an address never issues a Contact Manager removal call, so a deleted current address can remain visible in Contact Manager until a subsequent update elsewhere triggers a sync.*
  • USPS standardization always raises a warning (success or failure) but never blocks the save — an unrecognized address can still be persisted.
  • Overlap and duplicate-open-ended checks are scoped to addresses of the same type only; different address types on the same location do not interact.
  • Insert-time Contact Manager sync is skipped entirely for a brand-new address that is already expired.*

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\clsProviderAddress.vb
  • Business\SAIF.Business.Provider\CleanAddressHelper.vb
  • Business\SAIF.Business.Provider\Api\clsAddressApi.vb