---
title: Payment return handling
summary: Records an ACH payment return, classifies it against NACHA return reason codes with culture-aware descriptions, and creates backout/refund events without ever revoking the related authorization.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.Payment.EFT
reference_type: package
operation_id: OP-EFT-08
trigger: Batch/reconciliation process retrieves a returned-payment notice and creates a clsPaymentReturn record referencing the original clsPaymentDetail
---

# Payment return handling

`clsPaymentReturn` records that a previously-issued electronic payment was returned by the receiving bank, along with the NACHA return reason. It joins to `PAYMENT_RETURN_REASON_GCODE` for a culture-aware description of the reason and can create a backout or vendor-refund `clsPaymentEvent` once a returned payment has been reviewed. Returns are permanent, append-mostly records: `DeleteSQL` is intentionally disabled.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-EFT-08 |
| **Trigger** | Reconciliation process creates a `clsPaymentReturn` referencing the original `PaymentDetailSeqNum` and the bank-reported return reason code |
| **Inputs** | `PaymentDetailSeqNum`, return type code, return reason code, return date |
| **Outputs** | Persisted `PAYMENT_RETURN` row; culture-aware return-reason description; `PAYMENT_EVENT` row of type `BackoutEvent` or `VendorRefund` once reviewed |
| **Primary components** | `clsPaymentReturn.BeforeCreate/Insert/Retrieve`, `MarkReviewed`, `CreateBackoutPaymentEvent`; `clsPaymentReturnReasonCode`(+Collection); `clsReturnStatusCode`; `clsReturnTypeCode` |
| **Entry point** | `Business\SAIF.Business.Payment.EFT\clsPaymentReturn.vb` |

## Steps

1. **Create a new return record.** `NewPaymentReturn` fetches the next sequence value ([SQL-008](../sql/SQL-008-saif-business-payment-eft.md), [DUAL](../database-tables.md#dual)) and links it to the original `PaymentDetailSeqNum` from [Payment detail, events, and allocation](payment-detail-and-allocation.md).
2. **Classify the return using NACHA reference codes.** The return reason code is validated against `clsPaymentReturnReasonCode`/`Collection` ([SQL-066](../sql/SQL-066-saif-business-payment-eft.md), [SQL-067](../sql/SQL-067-saif-business-payment-eft.md)) and classified per [BR-EFT-03](../business-rules.md#br-eft-03-returned-eft-payment-classified-by-nacha-return-reason-code); return status and return type are validated against `clsReturnStatusCode` ([SQL-070](../sql/SQL-070-saif-business-payment-eft.md), [SQL-071](../sql/SQL-071-saif-business-payment-eft.md)) and `clsReturnTypeCode` ([SQL-072](../sql/SQL-072-saif-business-payment-eft.md), [SQL-073](../sql/SQL-073-saif-business-payment-eft.md)) respectively (see [Code table lookups](code-table-lookups.md)).
3. **Insert.** `BeforeInsert`/`AfterInsert` executes `INSERT INTO PAYMENT_RETURN (...)` ([SQL-020](../sql/SQL-020-saif-business-payment-eft.md), [PAYMENT_RETURN](../database-tables.md#payment_return)).
   - On failure (`RowsAffected <> 1`): adds an `InsertError` message ([BR-EFT-05](../business-rules.md#br-eft-05-insertupdate-operations-require-exactly-one-affected-row)).
4. **Retrieve with culture-aware return-reason description.** The single-record retrieval query joins `PAYMENT_RETURN_REASON_GCODE` on the current session's culture/language so the return-reason description text is presented in the caller's language rather than a single hard-coded locale ([SQL-064](../sql/SQL-064-saif-business-payment-eft.md), [PAYMENT_RETURN](../database-tables.md#payment_return), [BR-EFT-07](../business-rules.md#br-eft-07-return-reason-description-is-culture-aware)).
5. **Collection retrieval.** `clsPaymentReturnCollection` retrieves multiple returns using the same culture-aware join, for reconciliation reporting ([SQL-065](../sql/SQL-065-saif-business-payment-eft.md)).
6. **Mark as reviewed.** `MarkReviewed` updates the return row's status once an operator has reviewed and acted on it ([SQL-086](../sql/SQL-086-saif-business-payment-eft.md), [PAYMENT_RETURN](../database-tables.md#payment_return)).
7. **Create a backout or vendor-refund event.** `CreateBackoutPaymentEvent` creates a `clsPaymentEvent` of type `BackoutEvent` (internal accounting reversal) or `VendorRefund` (funds returned to the vendor), depending on the return's classification, using the same immutable event-insert mechanism documented in [Payment detail, events, and allocation](payment-detail-and-allocation.md) ([SQL-019](../sql/SQL-019-saif-business-payment-eft.md), [PAYMENT_EVENT](../database-tables.md#payment_event)).
8. **Update.** Further updates to the return record (e.g., correcting the reason code before final processing) use the same standard `UPDATE PAYMENT_RETURN` statement as the review step ([SQL-086](../sql/SQL-086-saif-business-payment-eft.md)).
9. **No cross-reference to authorization revocation.** `clsPaymentReturn` never reads from or writes to `clsEFTAuthorization` beyond the read-only culture-aware description join above — a payment return does **not** automatically revoke the customer's [EFT authorization / consent](eft-authorization-consent.md); revocation, if warranted, is a separate, manually-initiated action.
10. **Deletion is disabled.** `DeleteSQL` is overridden to always throw, with the source comment indicating a payment return "should not be deleted once created" — returns are a permanent audit record.

## Process flow

```mermaid
flowchart TD
	Start([Bank reports a returned payment]) --> Create[Create PaymentReturn record]
	Create --> Classify[Classify by NACHA return reason code]
	Classify --> Insert[INSERT PAYMENT_RETURN]
	Insert --> Rows{RowsAffected = 1?}
	Rows -->|No| Err([InsertError added])
	Rows -->|Yes| Retrieve[Retrieve with culture-aware<br>reason description]
	Retrieve --> Review{Reviewed?}
	Review -->|No| Pending([Awaiting operator review])
	Review -->|Yes| Mark[MarkReviewed]
	Mark --> Event[CreateBackoutPaymentEvent:<br>BackoutEvent or VendorRefund]
	Event --> NoRevoke([Authorization NOT revoked<br>automatically])
	NoRevoke --> Done([Return processing complete])
```

## Failure and edge-case behavior

- Because `clsPaymentReturn` never revokes the related `clsEFTAuthorization`, a recurring pattern of returns for the same customer/bank account will not automatically stop future auto-pay attempts unless a separate process explicitly calls `RevokeAuthorization` in [EFT authorization / consent](eft-authorization-consent.md).*
- `DeleteSQL` always throws — a return record, once inserted, is permanent and can only be corrected via update, never removed.
- The culture-aware reason-description join depends on the caller's active session culture; if no matching localized row exists in `PAYMENT_RETURN_REASON_GCODE`, the description may render blank or fall back to a default language row ([BR-EFT-07](../business-rules.md#br-eft-07-return-reason-description-is-culture-aware)).*

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **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\clsPaymentReturn.vb`
- `Business\SAIF.Business.Payment.EFT\clsPaymentReturnCollection.vb`
- `Business\SAIF.Business.Payment.EFT\clsPaymentReturnReasonCode.vb`
- `Business\SAIF.Business.Payment.EFT\clsReturnStatusCode.vb`
- `Business\SAIF.Business.Payment.EFT\clsReturnTypeCode.vb`
