Skip to content

Payment detail, events, and allocation

clsPaymentDetail implements IOnlinePayment and is the central record of a single electronic payment. Rather than a simple status column update, each state change is performed by a dedicated method (PostPending, RefundVendorRemitted, ReturnVendorRemitted, CancelVendorPending/DeclineVendorPending/ReplaceVendorPending via UpdateVendorPending, DeletePending, RemitPosted, CancelPayment) that updates the payment row and appends an immutable clsPaymentEvent audit record. Related bridge objects (clsPaymentAllocation, clsSessionTransfer, clsPaymentAuthorizationSessionTransfer) connect a payment to the accounting session(s) it was allocated from, and IAT/domestic payments trigger addenda creation (see Payment addenda).

Field Value
Operation ID OP-EFT-05
Trigger Caller calls NewPaymentDetail, or invokes a lifecycle method on a retrieved clsPaymentDetail
Inputs Bank account, payee, amount, ACH standard entry class code, IAT indicator, warehoused/non-warehoused indicator, allocation/session-transfer references
Outputs Persisted/updated PAYMENT_DETAIL row; one or more PAYMENT_EVENT audit rows per transition; PAYMENT_ALLOCATION/SESSION_TRANSFER/PAYMENT_AUTH_SESSION_TRANSFER rows; triggered addenda creation for IAT/standard payments
Primary components clsPaymentDetail (lifecycle methods, CreateIATAddenda, CreateStandardAddenda), clsPaymentDetailCollection (5 retrieval builders), clsPaymentAllocation/Collection, clsSessionTransfer, clsPaymentAuthorizationSessionTransfer, clsPaymentEvent/Collection/Code
Entry point Business\SAIF.Business.Payment.EFT\clsPaymentDetail.vb

Steps

  1. Create a new payment. NewPaymentDetail fetches the next sequence value (SQL-006, DUAL) and initializes bank account, amount, and status fields.
  2. Validate the ACH standard entry class code. ValidAchStdEntryClassCode requires a standard entry class code only when the linked bank account's banking network is ACH; non-ACH accounts (e.g., debit card) are exempt (BR-EFT-10).
  3. Insert. BeforeInsert/AfterInsert executes INSERT INTO PAYMENT_DETAIL (...) (SQL-018, PAYMENT_DETAIL).
  4. On failure (RowsAffected <> 1): adds an InsertError message (BR-EFT-05).
  5. Retrieve via one of five retrieval builders, dispatched by Criteria.RetrieveType: BuildSqlNormal (standard retrieval by PaymentDetailSeqNum), BuildSqlSeqNum (retrieval by an explicit sequence-number list), BuildSqlPend (payments still in a pending state, used by downstream batch processing), BuildPreNoteSql (prenote-only payments), and BuildPostedSql (already-posted/remitted payments). The SQL catalog documents these collectively under a single retrieval entry that joins PAYMENT_AUTHORIZATION and AUTHORIZATION_TYPE_CODE (SQL-059, PAYMENT_DETAIL); it does not enumerate each of the five builder variants as a separate SQL ID.*
  6. PostPending, RefundVendorRemitted, ReturnVendorRemitted, and UpdateVendorPending (Cancel/Decline/Replace). Each of these state-transition methods updates the payment row with its resulting status (SQL-085, PAYMENT_DETAIL) and appends a matching clsPaymentEvent row of the corresponding event code (SQL-019, PAYMENT_EVENT). ReturnVendorRemitted is distinct from the fuller Payment return handling flow, which additionally creates a PAYMENT_RETURN record for ACH-network returns.
  7. DeletePending. Removes a payment still in pending status; performs a physical delete on PAYMENT_DETAIL (SQL-096) and logs a DeletePending event (SQL-019, PAYMENT_EVENT).
  8. RemitPosted. Marks a posted payment as remitted (funds actually sent); updates the row (SQL-085) and logs a RemitPosted event (SQL-019).
  9. CancelPayment. Branches on payment source:
  10. If IsUSBankPayment, delegates the cancellation call to USBankAPIs.CancelPayment. > Origin: Delegated to SAIF.Business.EPay.USBank — see Recurring ACH authorization lifecycle.
  11. Otherwise, cancels the payment locally by updating the row (SQL-085) and logging a CancelPayment event directly (SQL-019).
  12. Trigger addenda creation. After certain state transitions (typically at insert/post time), IAT payments call CreateIATAddenda(), which creates 7 addenda records (type codes 10–16, using country codes rather than country names per the 2014 NACHA IAT format change) (SQL-005, SQL-015, PAYMENT_ADDENDA); non-IAT payments with addendum text call CreateStandardAddenda() to create a single addenda record. See Payment addenda for the full addenda lifecycle.
  13. Allocate a payment against a session. clsPaymentAllocation links a payment to a clsSessionTransfer via SessionTransferSeqNum; insert (SQL-016, PAYMENT_ALLOCATION), collection retrieval (SQL-057), update (SQL-084), and delete (SQL-095) follow the standard CRUD pattern. Aggregation properties on the collection compute both dynamically-calculated and GW/WCIS non-dynamic balance amounts across allocations.
  14. Session transfer bridge. clsSessionTransfer bridges clsPaymentDetail and clsPaymentAllocation; insert (SQL-021, SESSION_TRANSFER), retrieve (SQL-076), and update (SQL-087) follow the standard pattern. BeforeDelete enforces that the transfer is still in TransactionPending state and cascades a Save() of its child PaymentAllocations collection before allowing the delete to proceed (SQL-097).
  15. Auto-pay session scheduling. clsPaymentAuthorizationSessionTransfer is an insert (SQL-017) / retrieve (SQL-058) -only junction table (no update/delete) keyed by DueDate, used to schedule which session an auto-pay authorization's next payment will be drawn from (PAYMENT_AUTH_SESSION_TRANSFER).
  16. Immutable event log. clsPaymentEvent records are append-only: DeleteSQL is intentionally disabled and throws "This object never deletes events" if invoked (PAYMENT_EVENT); a single event can be retrieved by sequence number, joined with PAYMENT_EVENT_CODE and PAYMENT_RETURN_REASON_CODE descriptions (SQL-060), or all events for a payment detail can be retrieved as a collection (SQL-063); clsPaymentEventCode is a static, read-only lookup of the valid event-code values (see Code table lookups).

Process flow

flowchart TD
    Start([Caller creates a payment]) --> Insert[INSERT PAYMENT_DETAIL]
    Insert --> IAT{IAT payment?}
    IAT -->|Yes| IATAddenda[CreateIATAddenda: 7 records]
    IAT -->|No addendum text| StdAddenda[CreateStandardAddenda: 1 record]
    IAT -->|No| Pending[Payment pending]
    IATAddenda --> Pending
    StdAddenda --> Pending
    Pending --> Transition{State transition}
    Transition -->|PostPending| Post[Update row; log event]
    Transition -->|CancelPayment| USBank{IsUSBankPayment?}
    Transition -->|DeletePending| DelPend[Physical delete; log event]
    Transition -->|RemitPosted| Remit[Update row; log event]
    USBank -->|Yes| Delegate[Delegate to USBankAPIs.CancelPayment]
    USBank -->|No| LocalCancel[Update row locally; log event]
    Post --> Return{Return/refund event?}
    Return -->|ReturnVendorRemitted| RVR[Update row; log event]
    Return -->|RefundVendorRemitted| RfVR[Update row; log event]
    Post --> Allocate[Allocate to session via<br>clsPaymentAllocation/clsSessionTransfer]
    Allocate --> Done([Lifecycle event logged])

Failure and edge-case behavior

  • Every state-transition method logs an immutable PAYMENT_EVENT row; events can never be deleted once created — clsPaymentEvent.DeleteSQL always throws.
  • ValidAchStdEntryClassCode only requires the entry class code for ACH-network bank accounts; debit-card and other non-ACH accounts are exempt, so a blank entry class code is valid in those cases (BR-EFT-10).
  • clsSessionTransfer.BeforeDelete refuses to delete unless the transfer is still TransactionPending, and always attempts to save its child PaymentAllocations first — a failure in the child save can block the parent delete.
  • CancelPayment behavior differs materially by payment source: US Bank payments are cancelled through an external API call (which may fail independently of local database state), while non-US-Bank payments are cancelled purely locally.
  • clsPaymentAuthorizationSessionTransfer supports insert and retrieve only — there is no update or delete path, so a scheduling mistake must be corrected by inserting a new row rather than modifying the existing one.*
  • The five clsPaymentDetailCollection retrieval builders are selected by an enum and are not interchangeable; calling the wrong RetrieveType for a given scenario (e.g., using BuildSqlPend to find posted payments) will return an empty or incorrect result set rather than raising an error.*

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.Payment.EFT\clsPaymentDetail.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentDetailCollection.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentAllocation.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentAllocationCollection.vb
  • Business\SAIF.Business.Payment.EFT\clsSessionTransfer.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentAuthorizationSessionTransfer.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentEvent.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentEventCollection.vb
  • Business\SAIF.Business.Payment.EFT\clsPaymentEventCode.vb