# Feature: Refund Transaction

**Transaction Type:** Refund / Return / Credit
**Processor Class:** `TransactionProcessorImpl`
**Transaction Type Enum:** `TxnType.REFUND`

---

## 1. Overview

A Refund credits funds back to a cardholder's account. Unlike a Void (which cancels an unsettled transaction in the same batch), a Refund can apply across batch boundaries and is processed as an independent financial advice (MTI 0220 with DE3=`200000`).

The middleware does not require the original transaction to be present in `pos_transaction` — the refund is treated as a new standalone transaction. The cardholder's card must be present and a new authorisation is obtained from the acquirer.

> **Acquirer MTI note:** `JposYspTranslator.getRefundMsg()` maps the incoming MTI 0220 to MTI **0200** when sending to YSP. The POS terminal receives MTI 0230 as the response.

---

## 2. Flow Diagram

```
POS Terminal                  jPOS Middleware                     Bank Acquirer
     |                               |                                    |
     |--- MTI 0220 (DE3=200000) ---->|                                    |
     |                               |-- validateAndStoreRequest()        |
     |                               |   (lookup DE41 -> POS terminal)    |
     |                               |-- preprocess()                     |
     |                               |   (clearReversal + clearTemp;      |
     |                               |    NO check for original txn)      |
     |                               |-- onboardRequest()                 |
     |                               |   (create pos_temp_transaction)    |
     |                               |-- evaluateRules() [HTTP]           |
     |                               |-- translator.toMessage()           |
     |                               |   getRefundMsg() -> MTI 0200       |
     |                               |--- MTI 0200 (DE3=200000) -------->|
     |                               |<-- MTI 0210 (DE39=00) ------------|
     |                               |-- completeTransaction()            |
     |<-- MTI 0230 (DE39=00) --------|                                    |
```

---

## 3. ISO-8583 Message Specification

### 3.1 Request Fields (POS Terminal -> Middleware)

| DE # | Field Name                          | Format        | M/C | Description / Example                               |
|------|-------------------------------------|---------------|-----|-----------------------------------------------------|
| MTI  | Message Type Indicator              | BCD F4        | M   | `0220`                                              |
| 2    | Primary Account Number (PAN)        | BCD LLVAR     | M   | Full card PAN (cardholder must be present)          |
| 3    | Processing Code                     | BCD F6        | M   | `200000` (Refund, default account)                  |
| 4    | Transaction Amount                  | BCD F12       | M   | `000000001200` = AED 12.00 (amount to be refunded)  |
| 11   | STAN                                | BCD F6        | M   | `000003` (new STAN for refund)                      |
| 12   | Local Transaction Time              | BCD F6        | M   | `095757` (HHMMSS)                                   |
| 13   | Local Transaction Date              | BCD F4        | M   | `0212` (MMDD)                                       |
| 14   | Card Expiry Date                    | BCD F4        | M   | `YYMM` format, encrypted in transit                 |
| 19   | Acquiring Institution Country Code  | BCD F3        | M   | `784`                                               |
| 22   | POS Entry Mode                      | BCD F3        | M   | `011` = manual key entry                            |
| 23   | PAN Sequence Number                 | BCD F3        | C   | Present if chip card                                |
| 24   | NII                                 | BCD F3        | C   | Set by middleware                                   |
| 25   | POS Condition Code                  | BCD F2        | M   | `00` = online                                       |
| 35   | Track 2 Data                        | BCD LLVAR     | C   | Present if card swiped/dipped                       |
| 41   | Card Acceptor Terminal ID           | ASCII F8      | M   | `41448413`                                          |
| 42   | Card Acceptor Merchant ID           | ASCII F15     | C   | POS merchant ID                                     |
| 49   | Transaction Currency Code           | BCD F3        | M   | `784`                                               |
| 52   | PIN Block Data                      | Binary F16    | C   | Present when PIN entered                            |
| 53   | Security Related Control Info (KSN) | ASCII LLVAR   | M   | 20-digit DUKPT KSN                                  |
| 55   | EMV / Chip Data                     | Binary LLLVAR | C   | TLV-encoded ICC data (present for chip refunds)     |
| 62   | Information Data (Invoice No.)      | ASCII LLLVAR  | M   | `000001`                                            |
| 63   | PIN Encryption Key Info             | ASCII LLLVAR  | C   | Mapped to DE53 for acquirer                         |

### 3.2 Acquirer Request Fields (Middleware -> Acquirer, MTI 0200 for YSP)

`getRefundMsg()` clones the POS request, sets MTI to `0200`, replaces TID/MID with bank values, generates DE37 (RRN), and moves DE63 to DE53.

| DE # | Field Name               | Format        | Notes                                                  |
|------|--------------------------|---------------|--------------------------------------------------------|
| MTI  |                          | BCD F4        | `0200` (YSP requires financial request for refund)     |
| 3    | Processing Code          | BCD F6        | `200000`                                               |
| 4    | Amount                   | BCD F12       | Refund amount                                          |
| 11   | STAN                     | BCD F6        | Bank-assigned STAN (from `StanBatchNumberService`)     |
| 12   | Local Time               | BCD F6        | From `tempTransaction.bTidTime`                        |
| 13   | Local Date               | BCD F4        | From `tempTransaction.bTidDate` (last 4 chars)         |
| 37   | RRN                      | ASCII F12     | Generated: `generateDE37(stan)`                        |
| 41   | TID                      | ASCII F8      | Bank TID                                               |
| 42   | MID                      | ASCII F15     | Bank MID                                               |
| 53   | KSN                      | ASCII LLVAR   | From original DE63                                     |

### 3.3 Response Fields (Acquirer -> Middleware -> POS Terminal)

| DE # | Field Name               | Format        | M/C | Description                                         |
|------|--------------------------|---------------|-----|-----------------------------------------------------|
| MTI  |                          | BCD F4        | M   | `0230` (advice response to POS)                     |
| 3    | Processing Code          | BCD F6        | M   | `200000`                                            |
| 11   | STAN                     | BCD F6        | M   | POS STAN restored                                   |
| 37   | RRN                      | ASCII F12     | M   | From acquirer                                       |
| 38   | Authorization Code       | ASCII F6      | C   | Refund auth code from issuer                        |
| 39   | Response Code            | ASCII F2      | M   | `00` = Refund approved                              |
| 41   | Terminal ID              | ASCII F8      | M   | POS TID restored                                    |
| 63   | Receipt JSON             | ASCII LLLVAR  | C   | Receipt with type `"Refund"` and `"PLEASE CREDIT MY ACCOUNT"` |

---

## 4. Processing Codes

| Processing Code | Meaning                         |
|-----------------|---------------------------------|
| `200000`        | Refund, default account         |
| `200100`        | Refund, savings account         |
| `200200`        | Refund, checking account        |

---

## 5. Response Codes

| DE39 | Meaning                | Middleware Handling                       |
|------|------------------------|-------------------------------------------|
| `00` | Approved               | Move temp -> `pos_transaction`            |
| `05` | Do Not Honor           | Move temp -> `pos_failed_transaction`     |
| `57` | Txn Not Permitted      | Refunds not allowed for this terminal     |
| `76` | Invalid Terminal       | DE41 not mapped in DB                     |
| `83` | Acquirer Timeout       | Auto-reversal (MTI 0400)                  |
| `96` | System Malfunction     | Unhandled exception                       |

---

## 6. Rules Engine

Identical to Sale. The rules engine receives POS TID/MID (not bank TID/MID). Merchant name, address, and logo for receipt header come from the rules engine response. Fail-mode: `OPEN`. Timeout: 500 ms.

---

## 7. Receipt Generation (DE-63)

When `RULES_MODEL_NAME_ENABLED = true`, receipt type is set to `"Refund"`. The status block shows `"PLEASE CREDIT MY ACCOUNT"`. The amount block shows the refund amount in AED format (centred, large, bold).

---

## 8. Error Handling

| Scenario                  | Behaviour                                                   |
|---------------------------|-------------------------------------------------------------|
| Terminal not found        | DE39=`76`; no bank call                                     |
| Terminal busy             | DE39=`81`                                                   |
| Rules engine decline      | `cleanupTransaction()`; failed msg returned                 |
| Acquirer timeout          | `handleResponseTimeout()` -> MTI 0400 reversal              |
| Connection lost           | `handleConnectionLoss()` -> MTI 0400 reversal               |
| DB error                  | `handleDatabaseError()` -> DE39=`82`                        |

---

## 9. BDD Scenarios

### Scenario 1: Approved Refund — Manual Key Entry

```
Given a POS terminal TID=41448413 is mapped to bank TID=39360312
And the rules engine returns ALLOW with model_name_enabled=true
When the terminal sends MTI 0220 with DE3=200000, DE4=000000001200, DE22=011
Then the middleware calls getRefundMsg() and forwards MTI 0200 with DE3=200000
And the acquirer responds with DE39=00, DE38=055371
And the temp record moves to pos_transaction
And the POS receives MTI 0230 with DE39=00
And DE-63 contains a receipt showing "PLEASE CREDIT MY ACCOUNT"
```

### Scenario 2: Declined Refund — Do Not Honor

```
Given a valid terminal mapping exists
When the terminal sends a refund for AED 5,000.00 (DE4=000000500000)
And the issuer responds DE39=05
Then the temp record moves to pos_failed_transaction
And the POS receives MTI 0230 with DE39=05
```

### Scenario 3: Refund — EMV Chip Card

```
Given the cardholder dips their chip card at the terminal
When MTI 0220 with DE3=200000, DE22=051, DE55=<TLV data> is received
Then DE55 is forwarded to the acquirer
And the receipt card scheme is detected from EMV AID Tag 84
And the receipt entry mode shows "CHIP"
```

### Scenario 4: Refund — Acquirer Connection Lost

```
Given a refund is forwarded to the acquirer
And the TCP connection is lost before a response is received
Then lifecycleService.handleConnectionLoss() is called
And a MTI 0400 reversal is initiated for the refund amount
And the POS terminal receives DE39=83
```

### Scenario 5: Refund — No Original Transaction Required

```
Given a Sale transaction is from a prior closed batch (not in pos_transaction)
When the terminal sends MTI 0220 with DE3=200000 with the card present
Then the middleware processes the refund without checking pos_transaction
And the refund proceeds as a new standalone transaction to the acquirer
```

---

## 10. Business Requirements

### BR-REFUND-01 — Purpose
The system shall support Refund transactions that credit funds back to a cardholder's account, applicable within the current batch or across prior settled batches.

### BR-REFUND-02 — No Original Transaction Required
The system shall process a Refund as a standalone transaction. It shall not require the original Sale to be present in `pos_transaction`. The cardholder's card must be physically present at the terminal.

### BR-REFUND-03 — Distinction from Void
A Refund shall be used when the original transaction has already been settled or is in a prior batch. A Void shall be used to cancel an unsettled transaction in the current batch. The system shall distinguish the two by processing code: Refund uses DE3=`200000`; Void uses DE3=`020000`.

### BR-REFUND-04 — Terminal Registration
The system shall reject any Refund request where DE41 is not registered in the terminal database, returning DE39=`76` without contacting the acquirer.

### BR-REFUND-05 — Terminal Busy Check
The system shall reject a Refund request if the terminal already has an active transaction in progress, returning DE39=`81`.

### BR-REFUND-06 — Pending Reversal Housekeeping
Before processing a Refund, the system shall dispatch any pending reversals and clear any stale orphaned temp transactions for the requesting terminal.

### BR-REFUND-07 — Rules Engine Evaluation
The system shall evaluate each Refund through the rules engine using the POS TID/MID. If the rules engine returns `DECLINE`, the Refund shall be rejected without a bank call. If the rules engine is unreachable, the system shall allow the Refund (fail-mode: `OPEN`).

### BR-REFUND-08 — Acquirer MTI Mapping
The system shall send MTI `0200` (Financial Request) to the YSP acquirer for a Refund, regardless of the MTI `0220` received from the POS terminal. The POS terminal shall receive MTI `0230` as the response.

### BR-REFUND-09 — TID/MID Mapping
The system shall replace the POS TID/MID with the bank-mapped TID/MID before forwarding to the acquirer. The original POS TID shall be restored in the response returned to the terminal.

### BR-REFUND-10 — Transaction Persistence
The system shall create a `pos_temp_transaction` record before contacting the acquirer. On approval (DE39=`00`), it shall be promoted to `pos_transaction`. On decline, it shall be moved to `pos_failed_transaction`.

### BR-REFUND-11 — Supported Entry Modes
The system shall accept Refund requests for all card entry modes including manual key entry (DE22=`011`), EMV chip (DE22=`051`), contactless (DE22=`071`), and magnetic stripe (DE22=`090`).

### BR-REFUND-12 — EMV Data Passthrough
The system shall forward DE-55 (EMV chip data) from the POS request to the acquirer unchanged when present.

### BR-REFUND-13 — Receipt Generation
When `model_name_enabled = true` is returned by the rules engine, the system shall generate a receipt in DE-63 of the response. The receipt type shall be `"Refund"` and the status block shall read `"PLEASE CREDIT MY ACCOUNT"`.

### BR-REFUND-14 — Acquirer Timeout and Auto-Reversal
If the acquirer does not respond within the configured timeout, the system shall:
- Return DE39=`83` to the POS terminal immediately
- Automatically initiate a reversal (MTI 0400) for the refund amount
- Retry up to 3 times at 60-second intervals

### BR-REFUND-15 — Success Criteria
A Refund is considered approved when the acquirer returns DE39=`00`. All other response codes are treated as declined.
