# Payment API

> **Prefix:** `/api/v1/payment`, `/api/v1/subscription-payment`  
> **Supported Gateways:** `mellat` (Mellat Bank SOAP) | `sep` (SEP REST)

---

## GET `/api/v1/payment/config`

دریافت تنظیمات عمومی پرداخت — برای نمایش وضعیت درگاه آزمایشی در frontend.

**Permission:** `IS_AUTHENTICATED_FULLY`

### Response `200`
```json
{
  "success": true,
  "data": {
    "test_mode": true
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `test_mode` | boolean | `true` = درگاه آزمایشی فعال است — backend از MockGateway استفاده می‌کند و پول واقعی کسر نمی‌شود |

**نکته:** این endpoint هیچ اطلاعات حساسی (terminal_id، password، ...) را expose نمی‌کند. تنها یک boolean برای مصرف frontend است.

---

## GET `/api/v1/my/payments`

List the **authenticated user's own** payments (derived from the token — there is no userId in the URL). Used by the public dashboard's transactions tab.

**Permission:** `IS_AUTHENTICATED_FULLY`

### Query Parameters
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | integer | 1 | Page number |
| `limit` | integer | 20 | Items per page (max 100) |
| `status` | string | — | Optional filter: `pending` / `success` / `failed` / `cancelled` / `refunded` |

### Response `200` (paginated)
```json
{
  "success": true,
  "data": [
    {
      "uuid": "pay-uuid-...",
      "order_id": "ORD-84FB82E12A4A45CE",
      "amount_rials": 590000,
      "status": "success",
      "gateway": "mellat",
      "type": "appointment",
      "reference_id": "...",
      "appointment_uuid": "appt-uuid-...",
      "created_at": 1781521834
    }
  ],
  "meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 }
}
```

> Items at `data` (flat array), total at `meta.totalRecords`. Ordered by `created_at` DESC.

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |

---

## POST `/api/v1/payment/appointment`

Initiate payment for an appointment. Returns a redirect URL to the payment gateway.

**Permission:** `AUTH` — must be the appointment owner (patient)

### Request Body (`application/json`)
```json
{
  "appointment_uuid": "appt-uuid-...",
  "gateway": "mellat",
  "frontend_address": "https://myapp.com/payment/result"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `appointment_uuid` | string (UUID) | ✅ | Appointment to pay for |
| `gateway` | string | ✅ | `"mellat"` or `"sep"` |
| `frontend_address` | string | ❌ | Redirect URL after payment (overrides default) |

### Response `200`
```json
{
  "success": true,
  "data": {
    "payment_uuid": "pay-uuid-...",
    "redirect_url": "https://bpm.shaparak.ir/pgwchannel/...",
    "order_id": "CLINICPRO-1717000000-ABC123"
  }
}
```

> **On successful callback** for an appointment payment, the booking is transitioned `pending → confirmed` (its 15-minute `expires_at` is cleared) and a confirmation SMS is dispatched to the patient's mobile. If the booking already lapsed to `expired` before payment confirmed, it is **not** re-confirmed (the transition is rejected) — handle refund out of band.

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_FORBIDDEN_001` | 403 | Not the patient |
| `ERR_PAYMENT_003` | 422 | Appointment not in payable state |
| `ERR_PAYMENT_002` | 422 | Invalid amount |
| `ERR_PAYMENT_001` | 503 | Payment gateway unavailable |

---

## POST `/api/v1/payment/callback/{gateway}`
## GET `/api/v1/payment/callback/{gateway}`

Payment gateway callback. Called by the bank after user completes (or cancels) payment.

**Permission:** `PUBLIC` — called by the gateway, not the user

### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
| `gateway` | string | `mellat` or `sep` |

### Request (varies by gateway)
**Mellat POST fields:**
```
ResCode=0&SaleOrderId=...&SaleReferenceId=...&RefId=...
```

**SEP POST fields:**
```
Status=2&RRN=...&RefNum=...&TerminalId=...&TraceNo=...
```

### Response
- If `ResCode=0` (success): appointment confirmed, redirect to `frontend_address?success=1&uuid=...`
- If failed: redirect to `frontend_address?success=0&error=...`

### Notes
- On success: appointment status → `confirmed`, wallet credited with doctor's share
- Payment record stored with: `order_id`, `amount_rials`, `status`, `gateway`, `ref_id`

---

## POST `/api/v1/subscription-payment`

Initiate a subscription / wallet top-up payment (not tied to a specific appointment).

**Permission:** `AUTH`

### Request Body
```json
{
  "gateway": "mellat",
  "amount_rials": 1000000,
  "frontend_address": "https://myapp.com/wallet/result"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `gateway` | string | ✅ | `"mellat"` or `"sep"` |
| `amount_rials` | integer | ✅ | Amount in Rials (min: 10,000) |
| `frontend_address` | string | ❌ | Redirect URL after payment |

### Response `200`
```json
{
  "success": true,
  "data": {
    "payment_uuid": "pay-uuid-...",
    "redirect_url": "https://bpm.shaparak.ir/pgwchannel/...",
    "order_id": "CLINICPRO-SUB-1717000000-XYZ"
  }
}
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_PAYMENT_002` | 422 | Invalid amount |
| `ERR_PAYMENT_001` | 503 | Gateway unavailable |

---

## POST/GET `/api/v1/subscription-payment/callback/{gateway}`

Callback for subscription payments. Same behavior as appointment callback but credits wallet instead.

**Permission:** `PUBLIC`

---

## GET `/api/v1/payment/{uuid}`

Get payment status and details.

**Permission:** `AUTH` — must be the payment owner or `ROLE_ADMIN`

### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
| `uuid` | string (UUID) | Payment UUID |

### Response `200`
```json
{
  "success": true,
  "data": {
    "uuid": "pay-uuid-...",
    "order_id": "CLINICPRO-1717000000-ABC123",
    "amount_rials": 500000,
    "status": "paid",
    "gateway": "mellat",
    "ref_id": "123456789",
    "appointment_uuid": "appt-uuid-...",
    "created_at": 1717000000,
    "paid_at": 1717000120
  }
}
```

**Payment Status Values:**
| Value | Description |
|-------|-------------|
| `pending` | Created, not paid yet |
| `paid` | Successfully paid |
| `failed` | Gateway returned failure |
| `cancelled` | User cancelled at gateway |
| `refunded` | Refunded |

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_FORBIDDEN_001` | 403 | Not the owner |
| `ERR_NOT_FOUND_001` | 404 | Payment not found |
