Skip to content

Parse callback and remittance XML

This operation covers four small, closely related types that all do the same job — turn inbound XML from US Bank into typed .NET values — without performing any SOAP calls or database access. RealTimePaymentConfirmation and RealTimeNonPaymentNotification parse individual callback payloads; RemittanceDocument parses a batch remittance file and yields a RemittedPayment per detail row. All four are pure, lazily-evaluated readers over an in-memory XElement/XDocument.

Field Value
Operation ID OP-EPAY-08
Trigger Caller constructs New RealTimePaymentConfirmation(xml), New RealTimeNonPaymentNotification(xml), or New RemittanceDocument(xDocument) from XML received from US Bank
Inputs Raw XML text (payment confirmation, nonpayment notification) or an XDocument (remittance document)
Outputs Typed, read-only properties: user ID, payment amount, policy number, transaction mode/frequency/duration/amount-type enums, confirmation ID, effective/business dates, product, payment network, card type (confirmation); user ID, policy number, product, unsuccessful-event description and timestamp (nonpayment notification); process date, biller ID, and a list of RemittedPayment rows (remittance document), each exposing confirmation ID, product, payment network, card type, amount, effective date, policy number, saved-balance ID, transaction type, user ID, and ACH return details
Primary components RealTimePaymentConfirmation (structure), RealTimeNonPaymentNotification (structure), RemittanceDocument, RemittedPayment
Entry point Business\SAIF.Business.EPay.USBank\RealTimePaymentConfirmation.vb

Steps

  1. Load the root element lazily. Both RealTimePaymentConfirmation and RealTimeNonPaymentNotification store the raw XML string in the constructor and defer parsing: the private Root property calls XElement.Load only the first time any property is read, caching the result for subsequent reads.
  2. Read simple scalar fields. Properties such as UserId, PaymentAmount, TransactionModeCode, BillerProductCode, and UnsuccessfulEvent read a single named child element's value directly off Root.
  3. Read parameter-style fields. PolicyNumber and SavedBalanceId (confirmation) and PolicyNumber (notification) search the Parameter child elements for one whose ParameterName matches, then return its ParameterValue; SavedBalanceId returns an empty string when no matching parameter exists instead of throwing.
  4. Classify the transaction mode. TransactionMode inspects the root element's local name (PaymentInfo vs. RecurringPaymentInfo) and maps the transaction-mode code to the matching enum member, defaulting to Other for any unrecognized combination.
  5. Derive recurring-specific fields. IsRecurring is true when the mode is StartRecurring, EditRecurring, or StopRecurring; ConfirmationId reads RecurringReferenceId when recurring or ConfirmationId otherwise; PaymentEffectiveDate reads FirstScheduledPaymentDate when recurring or PaymentEffectiveDate otherwise; Frequency and Duration are only meaningful (non-Other) when recurring.
  6. Derive biller identifiers from the confirmation ID. BillerGroupId and BillerId are computed by taking fixed-width substrings (first 3 characters, next 3 characters) of ConfirmationId.
  7. Resolve enums shared with the rest of the library. Product calls the shared ConvertEPaymentServiceProduct/GetSaifProductCode helpers (from Enums.vb) against the raw biller product code; PaymentNetwork calls ConvertPaymentNetwork; CardType maps a raw code string to the CardTypes enum, defaulting to Unknown.
  8. Parse fixed-format dates. ConvertYYYMMDDToDate/ConvertUSBankDateStringToDate slice a fixed-width YYYYMMDD-style string into year/month/day components and construct a Date.
  9. Load a remittance document. RemittanceDocument's constructor stores the caller-supplied XDocument; ProcessDate and BillerId are read from the Header element nested under Remittance.
  10. Enumerate remitted payments. RemittedPayments iterates every Detail element in the document and constructs one RemittedPayment per element, passing along the parsed BillerGroupId and BillerId from the header so each payment can compute its own confirmation-ID suffix.
  11. Read remitted-payment fields. Each RemittedPayment exposes the same category of typed accessors as the confirmation structure (product, payment network, card type, transaction type) plus ACH-specific fields (ACHReturnCode, ReturnReasonDescription, ReturnDate) and a computed ConfirmationIdWithoutBillerGroupAndBiller that strips the leading biller-group/biller prefix and parses the remainder as a decimal.

Process flow

The following diagram visualizes the lazy-parse pattern shared by the confirmation/notification structures and the remittance document's per-row expansion.

flowchart TD
    Start{Which payload?}
    Start -->|Payment confirmation| CLoad[Store XML string;<br>defer XElement.Load]
    CLoad --> CRead[Read scalar and parameter fields<br>on first property access]
    CRead --> CMode[Classify TransactionMode<br>from root name + code]
    CMode --> CDerive[Derive recurring flags,<br>confirmation ID, dates, enums]
    Start -->|Nonpayment notification| NLoad[Store XML string;<br>defer XElement.Load]
    NLoad --> NRead[Read scalar and parameter fields]
    Start -->|Remittance document| RLoad[Store XDocument]
    RLoad --> RHeader[Read ProcessDate, BillerId<br>from Header element]
    RHeader --> RLoop[For each Detail element:<br>construct a RemittedPayment]
    RLoop --> RFields[Expose typed fields<br>per remitted payment]
    CDerive --> Done([Typed values returned<br>to caller on demand])
    NRead --> Done
    RFields --> Done

Failure and edge-case behavior

  • All property reads assume the expected element is present; a missing element (other than the explicitly guarded SavedBalanceId and PaymentTypeAttempt/PaymentAmount cases) raises an unhandled null-reference-style exception from XElement navigation rather than a handled parsing error.*
  • SavedBalanceId on RealTimePaymentConfirmation and PaymentTypeAttempt/PaymentAmount on RealTimeNonPaymentNotification are the only fields with explicit missing-element handling, returning an empty string or zero instead of throwing.
  • RecurringRefId only reads a value when TransactionMode = Declined; for every other mode it returns an empty string without checking whether the underlying element exists.
  • Because Root is cached after first access, constructing one of these structures with malformed XML defers the parse failure until the first property is actually read, not at construction time.*
  • RemittedPayment's constructor is Friend, so instances can only be created by RemittanceDocument within this library — there is no public way to construct a RemittedPayment directly from a caller-supplied XML fragment.

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.EPay.USBank\RealTimePaymentConfirmation.vb
  • Business\SAIF.Business.EPay.USBank\RealTimeNonPaymentNotification.vb
  • Business\SAIF.Business.EPay.USBank\RemittanceDocument.vb
  • Business\SAIF.Business.EPay.USBank\RemittedPayment.vb
  • Business\SAIF.Business.EPay.USBank\Enums.vb