Skip to content

Financial transaction and remark management

A financial transaction is the permanent, append-only ledger entry every payment, refund, and transfer in this library ultimately writes: a header row plus one or more detail lines and an optional remark. Almost every other operation in SAIF.Business.Claim.Payment ends by building one of these through clsPaymentBase, so this operation documents the shared object that all payee/payment flows delegate to for persistence.

Field Value
Operation ID OP-CP-01
Trigger clsFinancialTrans.NewFinancialTrans(dpi, claimData [, tranType]) (create), clsFinancialTrans.GetTransaction(dpi, tranID, tranType) or one of nine clsFinancialTransCollection factories (retrieve)
Inputs IDataPortalInfo, claim data or claim ID, transaction type code (Payment/Refund/Transfer), status, issue date, benefit sequence number, payment ID, payee/address data, detail amounts/dates/flags, remark code
Outputs Persisted CL_FINANCIAL_TRANS / CL_FINANCIAL_TRANS_DTL / remark rows; populated object graph; boolean save result; broken-rule/error messages
Primary components clsFinancialTrans.Create/SetHistory/ApplyValueChecks/ValidAddress, clsFinancialTransDtl, clsFinancialTransDtlCollection, clsFinancialTransCollection, clsFinancialTranRemark
Entry point Business\SAIF.Business.Claim.Payment\FinancialTransaction\clsFinancialTrans.vb

Steps

  1. Create a new transaction. NewFinancialTrans assigns ClaimFinancialTransSeqNum from a sequence, ClaimID from the criteria's claim data, and eagerly loads an (initially empty) detail collection and the child remark placeholder. Two ClaimID-only overloads are marked obsolete and internally resolve full claim data via clsClaimData (SAIF.Business.View.Claim, not yet migrated — see Payee management for the related note).
  2. Apply create defaults (BR-CP-007): status Released, medical/indemnity display code I, issue/entry date today, initiator the logged-on user. SetHistory() snapshots the claim's jurisdiction, status, type, coverage, injury date, policy, tail-coverage, preferred-worker, federal-benefit, NCE, HWR, and own-motion values onto the transaction row.
  3. Add a detail line. InsertTranDetail creates a clsFinancialTransDtl, assigns the transaction type code, and numbers it TranDetail.Count + 1 — a 1-based sub-number with no gap or uniqueness re-check.
  4. Apply value checks before insert (BR-CP-005, BR-CP-006). ApplyValueChecks sets each detail's reimbursement program (SD, then Retro Reserve, then NCE, in that precedence) and clears or sets the claim cost category based on chargeability, payee type, and reimbursable-program membership; an uncategorized detail is forced non-chargeable.
  5. Validate the payee address (BR-CP-004). ValidAddress runs as a level-one rule on AddressLine1 unless IgnoreBusinessRules is set or the object is an existing record whose address was already valid.
  6. Worker/Beneficiary payees require a previously validated address (delegated to clsPayeeBase/clsProviderAddress, SAIF.Business.View.Provider — not yet migrated).
  7. Attorney/Other/Medical Provider payees require address line 1, plus city and state unless the address is foreign.
  8. On failure: broken rule naming the payee ("Error: Worker/Beneficiary/Provider address is invalid \<PayeeFullName>").
  9. Insert the header. BeforeInsert normalizes blank special-handling codes and zero zip/provider-location values to NULL, and prefers the parent provider location when the payee's address is a parent location. The header insert itself has no catalogued SQL entry in this library's SQL index; it is described here from the traced stored-procedure call rather than linked.
  10. On a rows-affected value other than 1: "Insert Failed" error added; child detail and remark are not saved.
  11. Insert the detail line (SQL-020, CL_FINANCIAL_TRANS_DTL). Only runs after the header insert succeeds.
  12. On a rows-affected value other than 1: "Insert Failed" error added.
  13. Insert the remark, if any. When PayRemarkCode is blank the remark object is marked clean and no request is sent; otherwise it is inserted (SQL-054 covers the matching retrieve path; the remark insert/update/delete procedures were traced by name but have no distinct catalog entry beyond the retrieve).
  14. Update an existing transaction. Only PaymentMethodCode, PaymentID, and FinancialTransactionStatusCode may be changed after creation — every other field is insert-only, append-style history.
  15. On a rows-affected value other than 1: DBContentionError added (BR-CP-001).
  16. Update or delete the remark. Clearing PayRemarkCode to empty on an existing remark routes the save through the delete path instead of update (SQL-101 update, SQL-124 delete).
    • On a rows-affected value other than 1: DBContentionError added.
  17. Retrieve a transaction or transaction history. GetTransaction retrieves by sequence number and type; clsFinancialTransCollection exposes nine retrieval factories keyed by claim, issue date, benefit sequence, recovery eligibility, status, payment ID, or payment category, each backed by its own stored procedure (SQL-055, SQL-056, SQL-057, SQL-058, SQL-059, SQL-060, SQL-061, SQL-062, SQL-063, SQL-065, CL_FINANCIAL_TRANS).
    • If no row matches (single retrieve): the returned object is populated as a placeholder and a runtime-added rule reports "No valid transaction found for Id and Type supplied."
    • For ByStatus, ByStatusAndIssueDate, and ByClaim retrievals, detail lines for the whole result set are eagerly batch-loaded and grouped by transaction; other retrieval types load details lazily per transaction (N+1 pattern).
  18. Bulk status transition. updateFinancialTranStatus moves every matching transaction from one status to another for a claim/issue-date/payment-type in a single stored-procedure call (SQL-102) and returns the raw rows-affected count with no <> 1 check and no legal-transition validation of its own.
  19. Ad hoc aggregate queries. HasOverLapAmt sums detail amounts for a claim/category whose date range overlaps a proposed period; PreviousPaidAmt/PreviousPaidDays sum prior positive payments or refunds for an exact from/thru match (note: PreviousPaidDays must be read only after PreviousPaidAmt — an ordering dependency, not a rule); LatestPaymentDate finds the latest posted, non-8F, non-penalty transaction thru-date; GetLastPaymentThruDate builds its category list by string formatting rather than binding (low risk — values are enum-derived, not user input).
  20. First-payment determination (BR-CP-008). FirstPayment returns true only while none of the claim's transactions has reached Posted status.

Process flow

flowchart TD
    Start([Payment workflow or caller<br>requests a transaction]) --> Which{Create or retrieve?}
    Which -->|Create| New[NewFinancialTrans:<br>seed header, snapshot claim data]
    New --> Detail[Add detail line]
    Detail --> Checks[Apply value checks:<br>reimbursement program,<br>cost category]
    Checks --> AddrRule{Payee address valid?}
    AddrRule -->|No| Blocked([Broken rule added;<br>save blocked])
    AddrRule -->|Yes| InsHeader[Insert header]
    InsHeader --> Rows1{RowsAffected = 1?}
    Rows1 -->|No| Fail1([Insert Failed;<br>children not saved])
    Rows1 -->|Yes| InsDetail[Insert detail line]
    InsDetail --> InsRemark{Remark code blank?}
    InsRemark -->|Yes| SkipRemark[No remark row created]
    InsRemark -->|No| InsRemarkRow[Insert remark row]
    Which -->|Retrieve| Retr[Select factory by<br>claim / status / issue date / etc.]
    Retr --> Found{Row(s) found?}
    Found -->|No| Placeholder([Placeholder object;<br>not-found rule added])
    Found -->|Yes| Loaded([Populated transaction<br>or collection returned])
    SkipRemark --> Done([Save complete])
    InsRemarkRow --> Done

Failure and edge-case behavior

  • Detail-line update always throws ApplicationException(InvalidSQLProperty) because clsFinancialTransDtl.Criteria.UpdateSQL is not implemented — detail lines are effectively insert-only in practice.
  • Detail-line delete uses an inline statement with unbound literal placeholders and a mismatched column name (claim_financial_trans_id instead of claim_financial_trans_seq_num); it is very likely a dead/non-functional path.
  • clsFinancialTransDtlCollection.Remove and clsFinancialTransCollection.Remove are self-recursive — calling either with a matching item causes a stack overflow rather than removing it.
  • A missing remark on retrieve is not an error; a clean, empty placeholder remark object is returned instead.
  • Static code-map caches (RecoveryTypeCodes, FinancialTransTypeCodes) are process-wide and only refresh when explicitly requested.
  • GetTransaction sets IgnoreBusinessRules = True on the returned object, which suppresses the address-validity rule but not the runtime-added not-found rule.
  • The header insert/update/retrieve stored procedures were traced from source but have no distinct entry in this library's SQL catalog separate from the collection-level entries cited above; they are described in prose rather than linked to avoid citing a non-existent SQL ID.

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.Claim.Payment\FinancialTransaction\clsFinancialTrans.vb
  • Business\SAIF.Business.Claim.Payment\FinancialTransaction\clsFinancialTransCollection.vb
  • Business\SAIF.Business.Claim.Payment\FinancialTransaction\clsFinancialTransDtl.vb
  • Business\SAIF.Business.Claim.Payment\FinancialTransaction\clsFinancialTransDtlCollection.vb
  • Business\SAIF.Business.Claim.Payment\FinancialTransaction\clsFinancialTranRemark.vb