Skip to content

Provider bank account retrieval

clsProviderBankAccountCollection.GetProviderBankAccounts finds every bank account linked to a provider through that provider's locations' payment authorizations, excluding deleted accounts. Each returned clsProviderBankAccount is a thin wrapper that only carries a BankAccountSeqNum; its nickname, routing number, account number, and masked account number are resolved lazily, one property access at a time, from the shared clsBankAccount object. Both the collection query and the per-account field resolution are documented together because the second only exists to serve callers of the first.

Field Value
Operation ID OP-PP-06
Trigger clsProviderBankAccountCollection.GetProviderBankAccounts(dpi, providerID)
Inputs ProviderSeqNum
Outputs Populated clsProviderBankAccountCollection of clsProviderBankAccount (sequence number only); decrypted/masked field values on subsequent property access
Primary components clsProviderBankAccountCollection.GetProviderBankAccounts, clsProviderBankAccount.BankAccountNickName, clsProviderBankAccount.BankRoutingNumber, clsProviderBankAccount.BankAccountNumber, clsProviderBankAccount.MaskedBankAccountNumber, clsProviderBankAccount.BankAccount
Entry point Business\SAIF.Business.Provider.PaymentPreference\clsProviderBankAccounts.vb

Steps

  1. Query candidate accounts. GetProviderBankAccounts(dpi, providerID) selects BANK_ACCOUNT_SEQ_NUM from BANK_ACCOUNT where the account is not status DELET (BR-14) and its sequence number appears in PAYMENT_AUTHORIZATION rows whose customer_id matches one of the provider's location sequence numbers (SQL-004, BANK_ACCOUNT, PAYMENT_AUTHORIZATION, PROVIDER_LOCATION).
  2. The query does not filter on revoke_date is null — a commented-out line in source shows this filter was considered and removed, so bank accounts tied to a revoked payment authorization are still returned by this query.*
  3. Load and mark each row. Each matched row is loaded into a clsProviderBankAccount carrying only BankAccountSeqNum, and the object is marked Old on load — there is no create/update/delete path on this class; it is read-only.
  4. Resolve the underlying bank account on demand. The private BankAccount property calls clsBankAccount.GetBankAccount(MyCriteria.DataPortalInfo, BankAccountSeqNum) every time it is accessed — it is not cached on the object. Each of the four public properties below independently triggers this call:
  5. BankAccountNickName returns BankAccount.BankAccountNickName unmodified.
  6. BankRoutingNumber returns SAIF.Security.clsSecureEncrypt.DecryptString(BankAccount.BankRoutingNumber) — the routing number is decrypted from its stored encrypted form before being returned.
  7. BankAccountNumber returns SAIF.Security.clsSecureEncrypt.DecryptString(BankAccount.BankAccountNumber) — likewise decrypted.
  8. MaskedBankAccountNumber returns BankAccount.MaskedBankAccountNumber — pre-masked by the underlying object, not decrypted.

Origin: clsBankAccount and its GetBankAccount/masking logic are implemented in SAIF.Business.Payment.EFT and executed on behalf of this operation. That library is documented in the previous format, so no per-operation page exists; see Bank account management in the SAIF.Business.Payment.EFT documentation set. Decryption itself is performed by SAIF.Security.clsSecureEncrypt, delivered via the local SAIFEncrypt.dll per this library's dependency documentation.

Process flow

flowchart TD
    Start([Caller requests provider bank accounts]) --> Query[Select BANK_ACCOUNT_SEQ_NUM<br>where status <> DELET and linked via<br>PAYMENT_AUTHORIZATION to a provider location]
    Query --> Load[Load each row as clsProviderBankAccount,<br>MarkOld]
    Load --> Collection([Populated clsProviderBankAccountCollection])
    Collection --> Access{Caller reads a field?}
    Access -->|BankAccountNickName| Fetch1[GetBankAccount lookup] --> Nick([Return nickname])
    Access -->|BankRoutingNumber| Fetch2[GetBankAccount lookup] --> Decrypt1[DecryptString] --> Routing([Return routing number])
    Access -->|BankAccountNumber| Fetch3[GetBankAccount lookup] --> Decrypt2[DecryptString] --> AcctNum([Return account number])
    Access -->|MaskedBankAccountNumber| Fetch4[GetBankAccount lookup] --> Masked([Return masked number])

Failure and edge-case behavior

  • Each of the four field properties calls clsBankAccount.GetBankAccount independently and without caching; reading all four properties for the same object issues four separate underlying lookups rather than one, a potential N+1-style performance cost when iterating a large collection.*
  • The class's Criteria.CreateSQL/RetrieveSQL/InsertSQL/UpdateSQL/DeleteSQL properties all throw ApplicationException(InvalidSQLProperty) when accessed. Since clsProviderBankAccount is only ever populated via Load() from the collection's inline SQL (never through the standard DataPortal Fetch/BeforeRetrieve/Create/Update/Delete path in normal use), BeforeRetrieve/AfterRetrieve on the individual object and all of these criteria SQL properties are effectively unreachable in the traced code paths.*
  • Because the DELET status filter is the only exclusion applied, a bank account whose payment authorization has been revoked (see EFT payment location assignment) can still be returned by this query and have its fields resolved normally.*

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.PaymentPreference\clsProviderBankAccounts.vb