# Feature: Sale Transaction

**Transaction Type:** Sale / Purchase
**Processor Class:** `TransactionProcessorImpl`
**Transaction Type Enum:** `TxnType.SALE`

---

## 1. Overview

A Sale transaction is a real-time online purchase where funds are debited from a cardholder's account. The POS terminal sends a financial request (MTI 0200) to the jPOS middleware, which translates it, forwards it to the bank acquirer (YSP or Fiserv), and returns the authorisation result to the terminal.

Sale is the most common transaction type. It supports all card entry modes: EMV chip (DE22=051), contactless (DE22=071), magnetic stripe (DE22=090), and manual key entry (DE22=011).

A receipt is generated in DE-63 (JSON format) when the rules engine returns `model_name_enabled = true`.

---

## 2. Flow Diagram

```
POS Terminal                  jPOS Middleware                  Bank Acquirer (YSP/Fiserv)
     |                               |                                      |
     |--- MTI 0200 (DE3=000000) ---->|                                      |
     |                               |-- validateAndStoreRequest()          |
     |                               |   (lookup DE41 -> POS terminal)      |
     |                               |-- preprocess()                       |
     |                               |   (check terminal busy / reversals)  |
     |                               |-- onboardRequest()                   |
     |                               |   (create pos_temp_transaction)      |
     |                               |-- evaluateRules() [HTTP]             |
     |                               |   (rules engine check)               |
     |                               |-- translator.toMessage()             |
     |                               |   (map to acquirer format)           |
     |                               |--- MTI 0200 (bank TID/MID) -------->|
     |                               |<-- MTI 0210 (DE39=00/other) --------|
     |                               |-- translator.fromMessage()           |
     |                               |   (map back to POS format)           |
     |                               |-- completeTransaction()              |
     |                               |   (move temp -> pos_transaction      |
     |                               |    or pos_failed_transaction)        |
     |                               |-- ReceiptGenerator.generateReceipt() |
     |                               |   (JSON -> DE63)                     |
     |<-- MTI 0210 (DE39, DE38, DE63)|                                      |
```

---

## 3. ISO-8583 Message Specification

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

| DE # | Field Name                          | Format        | M/C | Description / Example                               |
|------|-------------------------------------|---------------|-----|-----------------------------------------------------|
| MTI  | Message Type Indicator              | BCD F4        | M   | `0200`                                              |
| 2    | Primary Account Number (PAN)        | BCD LLVAR     | M   | Card number (masked in logs: `476134XXXXXX0047`)    |
| 3    | Processing Code                     | BCD F6        | M   | `000000` (Sale, default account)                    |
| 4    | Transaction Amount                  | BCD F12       | M   | `000000006500` = AED 65.00                          |
| 11   | System Trace Audit Number (STAN)    | BCD F6        | M   | `000257` (POS-generated, unique per session)        |
| 12   | Local Transaction Time              | BCD F6        | M   | `185628` (HHMMSS)                                   |
| 13   | Local Transaction Date              | BCD F4        | M   | `0414` (MMDD)                                       |
| 14   | Card Expiry Date                    | BCD F4        | C   | `YYMM` format, encrypted in transit                 |
| 19   | Acquiring Institution Country Code  | BCD F3        | M   | `784` (UAE)                                         |
| 22   | POS Entry Mode                      | BCD F3        | M   | `051` = EMV chip; `071` = contactless; `090` = swipe|
| 23   | PAN Sequence Number                 | BCD F3        | C   | `001` (from EMV chip)                               |
| 24   | Network International Identifier    | BCD F3        | C   | Set by middleware from acquirer config              |
| 25   | POS Condition Code                  | BCD F2        | M   | `00` = online purchase                              |
| 35   | Track 2 Data                        | BCD LLVAR     | M   | Encrypted swipe/chip equivalent Track 2             |
| 37   | Retrieval Reference Number (RRN)    | ASCII F12     | C   | `182856000257` (generated: YDDDHHSSSSSS)            |
| 41   | Card Acceptor Terminal ID (POS TID) | ASCII F8      | M   | `41448413` (POS terminal identifier)                |
| 42   | Card Acceptor Merchant ID (POS MID) | ASCII F15     | C   | POS merchant ID (mapped to bank MID internally)     |
| 49   | Transaction Currency Code           | BCD F3        | M   | `784` (AED)                                         |
| 52   | PIN Block Data                      | Binary F16    | C   | Present when PIN entered                            |
| 53   | Security Related Control Info (KSN) | ASCII LLVAR   | M   | `98250904730001000043` (20-digit KSN for DUKPT)     |
| 55   | EMV / Chip Data                     | Binary LLLVAR | C   | TLV-encoded ICC data (Tag 84, 9F26, 9F27, 95, etc.) |
| 62   | Information Data (Invoice No.)      | ASCII LLLVAR  | M   | `000001` (terminal invoice/batch number)            |
| 63   | PIN Encryption Key Info             | ASCII LLLVAR  | C   | Passed to acquirer as DE53; cleared in response     |

> **Middleware translation note:** DE41 and DE42 are overwritten with bank TID (`39360312`) and bank MID (`000362511456113`) before forwarding to the acquirer. The original POS TID (`41448413`) is restored in the response.

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

| DE # | Field Name                       | Format        | M/C | Description / Example                                      |
|------|----------------------------------|---------------|-----|------------------------------------------------------------|
| MTI  | Message Type Indicator           | BCD F4        | M   | `0210`                                                     |
| 2    | PAN                              | BCD LLVAR     | C   | Echoed back (sensitive fields stripped before POS return)  |
| 3    | Processing Code                  | BCD F6        | M   | `000000` (echoed)                                          |
| 4    | Transaction Amount               | BCD F12       | M   | `000000006500` (echoed)                                    |
| 11   | STAN                             | BCD F6        | M   | `000257` (POS STAN restored)                               |
| 12   | Local Transaction Time           | BCD F6        | M   | Transaction time from bank                                 |
| 13   | Local Transaction Date           | BCD F4        | M   | Transaction date from bank                                 |
| 37   | Retrieval Reference Number (RRN) | ASCII F12     | M   | `182856000257` (used in receipt and void matching)         |
| 38   | Authorization Code               | ASCII F6      | M   | `123456` (approval code from issuer)                       |
| 39   | Response Code                    | ASCII F2      | M   | `00` = Approved                                            |
| 41   | Card Acceptor Terminal ID        | ASCII F8      | M   | `41448413` (POS TID restored by translator)                |
| 42   | Card Acceptor Merchant ID        | ASCII F15     | C   | POS MID restored by translator                             |
| 55   | EMV Response Data                | Binary LLLVAR | C   | Issuer script / response data for card update              |
| 60   | Bank Transaction Details (JSON)  | ASCII LLLVAR  | C   | `{"BankStan":"000168","BankTerminalId":"39360312","BankMerchantId":"000362511456113","BankTxnRefNumber":"182856000257","BankBatchNumber":"000001","BankTxnTime":"125856","BankTxnDate":"0414","BankResponseCode":"00","BankResponseMessage":"APPROVED AND COMPLETED SUCCESSFUL"}` |
| 63   | Receipt JSON                     | ASCII LLLVAR  | C   | JSON receipt document (when rules engine enables it)       |

---

## 4. Processing Codes

| Processing Code | Meaning                                                                  |
|-----------------|--------------------------------------------------------------------------|
| `000000`        | Sale, default account                                                    |
| `000001`        | Sale (normalised to `000000` by middleware — see `getSaleMsg()`)         |
| `000100`        | Sale, savings account                                                    |
| `000200`        | Sale, checking account                                                   |

---

## 5. Response Codes

| DE39 | Meaning                  | Middleware Handling                                     |
|------|--------------------------|---------------------------------------------------------|
| `00` | Approved                 | Move temp -> `pos_transaction`; generate receipt in DE63|
| `10` | Partially Approved       | Treated as success (`isPaymentSuccessful()`)            |
| `11` | Approved VIP             | Treated as success                                      |
| `05` | Do Not Honor             | Move temp -> `pos_failed_transaction`                   |
| `12` | Invalid Transaction      | Move temp -> `pos_failed_transaction`                   |
| `51` | Insufficient Funds       | Move temp -> `pos_failed_transaction`                   |
| `76` | Invalid Terminal Mapping | Returned by middleware if DE41 lookup fails             |
| `83` | Acquirer Timeout         | Middleware initiates auto-reversal (MTI 0400)           |
| `96` | System Malfunction       | Returned on DB error or unhandled exception             |

---

## 6. Rules Engine

The rules engine is invoked via `EvaluateRules.prepare()` after `onboardRequest()` and before the acquirer call. It is an HTTP POST to the configured `rules.engine.endpoint`.

**Inputs sent to rules engine:**
- DE-41 (Terminal ID — POS TID)
- DE-42 (Merchant ID — POS MID)
- DE-4  (Transaction Amount)
- DE-11 (STAN)
- DE-49 (Currency Code)

**Outputs consumed by middleware:**
- `RULES_DECISION`: `ALLOW` -> proceed; `DECLINE` -> return `generateFailedMsg()`
- `RULES_HEADER_MERCHANT_NAME`, `RULES_HEADER_MERCHANT_ADDRESS`, `RULES_HEADER_LOGO`
- `RULES_FOOTER_MESSAGE`, `RULES_FOOTER_DESCRIPTION`
- `RULES_MODEL_NAME_ENABLED`: `true` -> generate JSON receipt in DE-63

**Fail-mode:** `OPEN` (allow on rules engine failure). Timeout: 500 ms. Retries: 1.

---

## 7. Receipt Generation (DE-63)

When `RULES_MODEL_NAME_ENABLED = true`, `ReceiptGenerator.generateReceipt()` produces a JSON document placed in DE-63. Receipt is not generated for MTI 0400 or 0800.

| Block       | Content                                                                    |
|-------------|----------------------------------------------------------------------------|
| Logo        | `lg.url` — merchant logo URL from rules engine or default                  |
| Header      | Merchant name, address (from rules engine response)                        |
| TID/MID     | Bank TID (from `BankTerminalId` metadata) and bank MID                     |
| Date/Time   | From DE-13 (MMDD) and DE-12 (HHMMSS)                                       |
| Scheme/Entry| Card scheme (from EMV AID Tag 84 or PAN BIN) + entry mode label           |
| TxnType     | `"Sale"` or `"Sale-Tip"` (bold)                                            |
| Masked PAN  | Last 4 digits: `************NNNN`                                           |
| Batch/STAN  | Batch number and STAN from DE-62 / DE-11                                   |
| RRN         | Retrieval Reference Number (DE-37)                                          |
| Amount      | `AED xx.xx` (centred, large, bold) — DE-4 / 100                           |
| Status      | `"APPROVAL CODE: NNNNNN"` + `"PLEASE DEBIT MY ACCOUNT"`                   |
| CVM         | PIN Verified / Signature / No CVM (from EMV Tag 9F34/9F6C)                |
| Footer      | Footer message + description from rules; app version from DE-56            |

**Declined receipt:** If `RULES_MODEL_NAME_ENABLED = true` and transaction is declined, `generateFailedMsg()` still calls `ReceiptGenerator` and sets DE-63 with `"MW - DECLINED- Tran not Permitted"` as status.

---

## 8. Error Handling

| Scenario                         | Behaviour                                                                  |
|----------------------------------|----------------------------------------------------------------------------|
| DE-41 not mapped in DB           | `errorCode = INVALID_POS_TERMINAL`, DE39=`76` returned immediately         |
| No acquirer connection           | `errorCode = INVALID_POS_ACQUIRER`, DE39=`77`                              |
| Terminal busy / reversal pending | `errorCode = TERMINAL_BUSY` / `REVERSAL_PENDING`, DE39=`80`/`81`          |
| Rules engine decline             | `cleanupTransaction()` called; `generateFailedMsg()` with possible DE-63   |
| `SocketTimeoutException`         | `handleResponseTimeout()` -> creates `PosTransactionReversal` (MTI 0400)   |
| Null acquirer response           | `handleConnectionLoss()` -> MTI 0400 reversal initiated                    |
| DB error in `completeTransaction` | `handleDatabaseError()` -> reversal initiated; DE39=`82` to POS           |

**Reversal parameters:**
- Max retries: 3
- Retry delay: 60 seconds
- Stale temp threshold: 45 seconds
- Successful reversal response codes: `00`, `21`, `56`

---

## 9. BDD Scenarios

### Scenario 1: Approved EMV Sale

```
Given a POS terminal with TID=41448413 is mapped to bank TID=39360312, MID=000362511456113
And the rules engine returns ALLOW with model_name_enabled=true
When the terminal sends MTI 0200 with DE3=000000, DE4=000000006500, DE22=051, DE41=41448413
Then the middleware forwards MTI 0200 to the acquirer with bank TID=39360312
And the acquirer responds MTI 0210 with DE39=00, DE38=123456, DE37=182856000257
And the temp transaction moves from pos_temp_transaction to pos_transaction
And the response MTI 0210 is returned to POS with DE38=123456, DE39=00
And DE-63 contains a JSON receipt with "APPROVAL CODE: 123456" and "PLEASE DEBIT MY ACCOUNT"
```

### Scenario 2: Declined — Insufficient Funds

```
Given a POS terminal is mapped and rules engine returns ALLOW
When the terminal sends MTI 0200 with DE4=000000500000 (AED 5,000.00)
And the acquirer responds MTI 0210 with DE39=51
Then the temp transaction moves to pos_failed_transaction
And the response MTI 0210 is returned with DE39=51
And DE-63 contains "MW - DECLINED- Tran not Permitted" if model_name_enabled=true
```

### Scenario 3: Declined by Rules Engine

```
Given the rules engine returns DECLINE for terminal TID=41448413
When the terminal sends MTI 0200 with DE4=000000006500
Then cleanupTransaction() is called to remove the temp record
And the middleware returns MTI 0210 with a declined response code
And no message is forwarded to the bank acquirer
```

### Scenario 4: Acquirer Timeout — Auto-Reversal Triggered

```
Given a Sale request is sent to the acquirer
And the acquirer connection times out with SocketTimeoutException
Then lifecycleService.handleResponseTimeout() is called
And a PosTransactionReversal record is created with reason=RESPONSE_TIMEOUT
And a MTI 0400 reversal is sent to the bank
And the POS terminal receives DE39=83 (ACQUIRER_TIMED_OUT)
```

### Scenario 5: Contactless (NFC) Sale

```
Given the POS terminal sends DE22=071 (contactless)
And DE55 contains EMV tag 84=A0000000031010 (VISA AID)
When the middleware processes the Sale
Then the receipt card scheme is identified as "VISA"
And the entry mode label is "CONTACTLESS"
```

### Scenario 6: PIN-Based Magnetic Stripe Sale

```
Given the POS terminal sends DE22=021 (magnetic stripe with PIN)
And DE52 PIN Block is present with encrypted PIN data
And DE53 contains the 20-digit KSN
When the Sale is processed
Then the request is forwarded with DE52 and DE53 to the acquirer
And the receipt CVM block shows "PIN Verified"
```

---

## 10. Business Requirements

### BR-SALE-01 — Purpose
The system shall support real-time online Sale transactions that debit funds from a cardholder's account and return an authorisation result to the POS terminal.

### BR-SALE-02 — Supported Entry Modes
The system shall accept Sale requests for all card entry modes:
- EMV chip (DE22=`051`)
- Contactless / NFC (DE22=`071`)
- Magnetic stripe (DE22=`090`)
- Magnetic stripe with PIN (DE22=`021`)
- Manual key entry (DE22=`011`)
- Fallback from chip to swipe (DE22=`800`)

### BR-SALE-03 — Terminal Registration
The system shall reject any Sale request where DE41 (Terminal ID) is not registered in the terminal database, returning DE39=`76` without contacting the acquirer.

### BR-SALE-04 — Terminal Busy Check
The system shall reject a Sale request if the terminal already has an active transaction in progress, returning DE39=`81`. The terminal must wait and retry.

### BR-SALE-05 — Pending Reversal Check
The system shall reject a Sale request if a pending reversal exists for the terminal, returning DE39=`80`. Pending reversals must be resolved before a new Sale is accepted.

### BR-SALE-06 — Rules Engine Evaluation
Before forwarding to the acquirer, the system shall evaluate each Sale through the rules engine. If the rules engine returns `DECLINE`, the transaction shall be rejected without a bank call. If the rules engine is unreachable, the system shall allow the transaction (fail-mode: `OPEN`).

### BR-SALE-07 — TID/MID Mapping
The system shall replace the POS Terminal ID (DE41) and Merchant ID (DE42) with the bank-mapped TID and MID before forwarding to the acquirer. The original POS TID and MID shall be restored in the response returned to the terminal.

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

### BR-SALE-09 — Partial Approval
The system shall treat DE39=`10` (Partially Approved) as a successful transaction, promoting the record to `pos_transaction` and returning the approval to the POS terminal.

### BR-SALE-10 — 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) to the acquirer
- Retry the reversal up to 3 times at 60-second intervals
- Escalate to `MANUAL_REVIEW` status if all retries fail

### BR-SALE-11 — Receipt Generation
When the rules engine returns `model_name_enabled = true`, the system shall generate a JSON receipt and place it in DE-63 of the response. The receipt shall include merchant name/logo, transaction details, masked PAN, amount, approval code, and cardholder verification method.

### BR-SALE-12 — Declined Receipt
When `model_name_enabled = true` and the transaction is declined (by the acquirer or rules engine), the system shall still generate a receipt in DE-63 with status `"MW - DECLINED- Tran not Permitted"`.

### BR-SALE-13 — Bank Transaction Details
The system shall populate DE-60 of the response with bank-side transaction details in JSON format, including bank STAN, bank TID/MID, RRN, batch number, transaction date/time, response code, and response message.

### BR-SALE-14 — EMV Data Passthrough
The system shall forward DE-55 (EMV chip data) from the POS request to the acquirer unchanged. Any issuer script or EMV response data returned in DE-55 by the acquirer shall be passed back to the POS terminal.

### BR-SALE-15 — PIN Security
The system shall forward DE-52 (PIN block) and DE-53 (KSN) from the POS request to the acquirer unchanged. PIN data shall not be logged or stored at any point in the middleware.

### BR-SALE-16 — Amount Validation
The system shall reject any Sale request where DE-4 (Transaction Amount) is absent or zero, returning DE39=`12` without contacting the acquirer.

### BR-SALE-17 — Success Criteria
A Sale is considered approved when the acquirer returns DE39=`00`, `10`, or `11`. All other response codes are treated as declined.
