# Booking Financial API – Frontend Integration Guide

This document describes the booking financial and surcharge changes for frontend implementation.

---

## 1. Overview of Changes

| Area | Change |
|------|--------|
| **Payment transactions** | New fields: `bank`, `terminal_type`, `installment_periods`, `is_invoice_exempt` |
| **Surcharge** | Configurable by bank + terminal + payment category + installment; optional manual amount/rate |
| **Line-item breakdown** | New `charges` array explains what makes up `total_receivable` |
| **Invoice exemption** | Transaction-level `is_invoice_exempt` overrides addon type setting |
| **Reference data** | Banks and surcharge rates come from API meta (DB-driven) |

---

## 2. GET Financial Summary

**Endpoint:** `GET /bookings/{bookingId}/financial-summary`

### 2.1 New / Updated Response Fields

| Field | Type | Description |
|-------|------|--------------|
| `surcharges_total` | number | Sum of all surcharge charges |
| `invoiceable_surcharges_total` | number | Surcharges that are invoiceable |
| `invoice_exempt_items` | array | All 免開發票 items in one list (see below) |
| `invoice_exempt_total` | number | Sum of amounts in `invoice_exempt_items` |
| `charges` | array | Line-item breakdown (see below) |
| `meta.banks` | array | Active banks (from DB) |
| `meta.terminal_types` | array | e.g. `["實體刷卡機", "線上刷卡機"]` |
| `meta.surcharge_rates` | object | Rate table for lookups (see below) |
| `meta.payment_methods` | array | **Booking-level** options (信用卡付款, 銀行轉帳, 現金付款) |
| `meta.transaction_payment_methods` | array | **Transaction-level** options (see below) |

### 2.2 `charges` Array

Each item describes one component of `total_receivable`:

```json
{
  "id": 1,
  "booking_id": 10,
  "traveler_id": 5,
  "charge_type": "base_price",
  "description": "基本團費",
  "amount": "40000.00",
  "percentage": null,
  "reference_amount": null,
  "booking_transaction_id": null
}
```

| `charge_type` | Meaning | `amount` |
|---------------|---------|----------|
| `base_price` | Trip base price per traveler | Positive |
| `addon_request` | Confirmed addon cost | Positive |
| `discount` | Discount | **Negative** |
| `surcharge` | Payment surcharge (e.g. card fee) | Positive |

**Rule:** `total_receivable = SUM(charges[].amount)`.

### 2.3 `invoice_exempt_items` (免開發票)

All invoice-exempt line items (addons, surcharges, payments) in one array. Each item has:

| Field | Type | Present when | Description |
|-------|------|---------------|-------------|
| `type` | string | always | `addon`, `surcharge`, or `payment` |
| `id` | number | always | Addon/charge/transaction ID |
| `amount` | number | always | Exempt amount |
| `description` | string | always | Display label (e.g. addon title, 訂金, 尾款, 手續費) |
| `traveler_id` | number \| null | addon, payment | Traveler when applicable |
| `request_number` | string \| null | addon | Addon request number |
| `booking_transaction_id` | number \| null | surcharge | Linked payment transaction |
| `payment_type` | string \| null | payment | deposit, balance, full, etc. |
| `payment_date` | string \| null | payment | Y-m-d |
| `payment_method` | string \| null | payment | 銀行轉帳, 國外信用卡, etc. |

Use this array to list all 免開發票 items in one section. `invoice_exempt_total` is the sum of `invoice_exempt_items[].amount`.

**Per-traveler:** Each object in `traveler_financials` includes:
- `surcharges_total`: that traveler’s share of all surcharges (so you can show and tally with payments).
- `total_receivable`: base + addons − discount + surcharges_total (same idea as booking `total_receivable`). Use this with `total_paid` so `balance_due = total_receivable - total_paid` and it does not go negative when surcharge is paid.
- `invoice_exempt_total`: the 免開發票 total for that traveler (exempt addons + exempt surcharges + exempt payments attributed to that traveler).

### 2.4 `meta.transaction_payment_methods`

Use this list for the **payment method** dropdown when adding/editing a **payment transaction** (not for the booking-level preference):

```json
["銀行轉帳", "現金付款", "國外信用卡", "國內信用卡"]
```

- **Booking-level** (`meta.payment_methods`): for the booking’s preferred payment method (e.g. on booking form).
- **Transaction-level** (`meta.transaction_payment_methods`): for each payment/refund record.

### 2.5 `meta.banks`

Array of bank objects (from `banks` table):

```json
[
  { "id": 1, "name": "台新", "name_en": "Taishin", "sort_order": 1, "is_active": true },
  { "id": 2, "name": "中信", "name_en": "CTBC", "sort_order": 2, "is_active": true }
]
```

Use for the **bank** dropdown when the user selects a credit card payment method.

### 2.6 `meta.surcharge_rates`

Nested structure for looking up the applicable surcharge rate:

```json
{
  "實體刷卡機": {
    "台新": [
      { "payment_category": "國内", "installment_periods": null, "rate": 1.66 },
      { "payment_category": "國内", "installment_periods": 3, "rate": 1.7 },
      { "payment_category": "國内", "installment_periods": 6, "rate": 1.72 },
      { "payment_category": "國外", "installment_periods": null, "rate": 3.2 }
    ],
    "中信": [ ... ]
  },
  "線上刷卡機": { ... }
}
```

- **payment_category:** `國内` | `國外` | `銀聯`
- **installment_periods:** `null` = 未分期, or number (3, 6, 12, 24, etc.)
- **rate:** percentage (e.g. 1.66 = 1.66%)

**Mapping from UI to category:**

| User selects payment_method | payment_category |
|-----------------------------|------------------|
| 國內信用卡 | 國内 |
| 國外信用卡 | 國外 |
| (銀聯 – if you add it later) | 銀聯 |

**Lookup:** Given `terminal_type`, `bank` (name), `payment_category`, and `installment_periods`:

1. Find the row with the same `payment_category` and **exact** `installment_periods`.
2. If none, use the row with that `payment_category` and `installment_periods: null` (未分期).
3. If still none, there is no rate for that combination → show a warning and optionally let the user enter a manual amount or rate.

**Frontend warning:** When the user selects an installment period (e.g. 24) and there is **no exact match** in `surcharge_rates` for that bank/terminal/category, show a message like:  
「此分期期數無對應手續費率，將以未分期費率計算，或可手動輸入手續費金額/費率。」

---

## 3. Add Payment

**Endpoint:** `POST /bookings/{bookingId}/payments`

### 3.1 Request Body (new/updated fields)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `payment_method` | string | No | One of: 銀行轉帳, 現金付款, 國外信用卡, 國內信用卡 |
| `bank` | string | No | Bank **name** (e.g. 台新). Use when payment_method is credit card. |
| `terminal_type` | string | No | 實體刷卡機 or 線上刷卡機. Use for surcharge lookup. |
| `installment_periods` | integer | No | 1, 3, 6, 12, 24, 36, etc. null/omit = 未分期. |
| `is_invoice_exempt` | boolean | No | If true, this payment is excluded from invoiceable amount. **Overrides** addon type’s invoice exemption for allocations. |
| `surcharge_amount` | number | No | Manual surcharge amount (overrides any auto rate). |
| `surcharge_rate` | number | No | Manual surcharge % (e.g. 1.5). Backend multiplies by payment `amount` to get surcharge. |

**Surcharge behaviour (backend priority):**

1. If `surcharge_amount` is sent → use that exact amount (no rate calculation).
2. Else if `surcharge_rate` is sent → calculate `amount × (surcharge_rate / 100)`.
3. Else → auto lookup from `surcharge_rates` table using `terminal_type` + `bank` + payment_category + `installment_periods` (with fallback to 未分期).
4. Else → **default fallback**: 1.5% for 國外信用卡, no surcharge for 國內信用卡.
5. If final result is 0 or missing, no surcharge is created.

This means: even if `bank` or `terminal_type` are not provided, a 國外信用卡 payment will still get a 1.5% surcharge by default. To **skip** the surcharge entirely, send `surcharge_amount: 0`.

**Example (auto surcharge):**

```json
{
  "amount": 40000,
  "payment_date": "2025-03-15",
  "payment_type": "full",
  "payment_method": "國外信用卡",
  "bank": "台新",
  "terminal_type": "實體刷卡機",
  "status": "paid",
  "is_invoice_exempt": false
}
```

**Example (manual surcharge amount):**

```json
{
  "amount": 40000,
  "payment_date": "2025-03-15",
  "payment_type": "full",
  "payment_method": "國外信用卡",
  "surcharge_amount": 600,
  "status": "paid"
}
```

**Example (manual surcharge rate):**

```json
{
  "amount": 40000,
  "payment_date": "2025-03-15",
  "payment_type": "full",
  "payment_method": "國外信用卡",
  "surcharge_rate": 1.5,
  "status": "paid"
}
```

### 3.2 Response

Payment object now includes (when present): `bank`, `terminal_type`, `installment_periods`, `is_invoice_exempt`. If a surcharge was created, the payment will have a related `surcharge_charge` and a separate surcharge transaction (same as before).

---

## 4. Update Payment

**Endpoint:** `PUT /bookings/{bookingId}/payments/{paymentId}`

Same body fields as Add Payment (all optional for update). Surcharge is recalculated when amount, payment_method, bank, terminal_type, installment_periods, `surcharge_amount`, or `surcharge_rate` change.

---

## 5. Add / Update Refund

**Endpoint:** `POST /bookings/{bookingId}/refunds` and `PUT /bookings/{bookingId}/refunds/{refundId}`

Refunds accept the same optional fields for consistency: `bank`, `terminal_type`, `installment_periods`, `is_invoice_exempt`. No surcharge is created for refunds.

---

## 6. Payment / Refund Object Shape (in `details.payments` / `details.refunds`)

Each payment or refund can now include:

| Field | Type | Description |
|-------|------|--------------|
| `payment_method` | string | 銀行轉帳, 現金付款, 國外信用卡, 國內信用卡 |
| `bank` | string \| null | e.g. 台新 |
| `terminal_type` | string \| null | 實體刷卡機, 線上刷卡機 |
| `installment_periods` | integer \| null | 未分期 = null |
| `is_invoice_exempt` | boolean | Default false |

Surcharge transactions (auto-created, `payment_type: "surcharge"`) also have these fields; they are system-managed and should not be edited/deleted by the user.

---

## 7. Invoice Exemption Priority

- For **addon requests** paid by a transaction:  
  **Transaction `is_invoice_exempt` overrides** the addon request type’s `is_invoice_exempt`.  
  If the transaction has `is_invoice_exempt: true`, that payment (and its addon allocations) is treated as exempt even if the addon type is normally invoiceable.
- For **surcharges:**  
  The surcharge is invoice-exempt if the **main payment** that triggered it has `is_invoice_exempt: true`.

Response fields `invoiceable_addons_total`, `invoiceable_surcharges_total`, `invoiceable_total_receivable`, and the single list `invoice_exempt_items` (with `invoice_exempt_total`) reflect this priority. Use `invoice_exempt_items` to display all 免開發票 items in one section.

---

## 8. payment_type Values

Allowed for payments/refunds:

- `deposit`
- `balance`
- `full`
- `addon_request`
- `surcharge` (system-only; do not send from frontend for new payments)
- `other`

---

## 9. Suggested Frontend Flows

### 9.1 Add/Edit Payment Form

1. **Payment method**  
   Dropdown: `meta.transaction_payment_methods` (銀行轉帳, 現金付款, 國外信用卡, 國內信用卡).

2. **If 國內信用卡 or 國外信用卡:**  
   - Show **Bank** dropdown: `meta.banks` (use `name` as value).  
   - Show **Terminal type**: `meta.terminal_types` (實體刷卡機, 線上刷卡機).  
   - Show **Installment periods**: free input (number) or dropdown (e.g. 未分期, 3, 6, 12, 24, 36). Send `null` or omit for 未分期.

3. **Surcharge**  
   - Optional: Call a helper that uses `meta.surcharge_rates` + current form values to compute suggested rate and amount.  
   - If no rate found for the chosen installment, show warning and optionally pre-fill a manual `surcharge_amount` or `surcharge_rate` field.  
   - Send either `surcharge_amount` or `surcharge_rate` only when the user explicitly overrides; otherwise omit and let backend auto-calculate.

4. **Invoice exempt**  
   Checkbox: `is_invoice_exempt` (default false). Explain that it overrides addon type setting for this payment.

### 9.2 Displaying Charges Breakdown

Use `charges` to render a line-item list:

- Group or label by `charge_type` (base_price, addon_request, discount, surcharge).
- For discounts, show `amount` as negative or as a positive “discount” value.
- Sum of all `charges[].amount` should equal `total_receivable`.

### 9.3 Surcharge Rate Lookup Helper (pseudo-code)

```text
function getSuggestedSurcharge(terminalType, bankName, paymentMethod, installmentPeriods, meta) {
  const category = paymentMethod === '國外信用卡' ? '國外' : paymentMethod === '國內信用卡' ? '國内' : null;
  if (!category || !meta.surcharge_rates[terminalType]?.[bankName]) return { rate: null, warning: null };

  const rows = meta.surcharge_rates[terminalType][bankName];
  const exact = rows.find(r => r.payment_category === category && r.installment_periods === installmentPeriods);
  const fallback = rows.find(r => r.payment_category === category && r.installment_periods === null);

  const rate = exact?.rate ?? fallback?.rate ?? null;
  const warning = (installmentPeriods && !exact && fallback) 
    ? '此分期期數無對應手續費率，將以未分期費率計算。' 
    : (!rate && (paymentMethod === '國外信用卡' || paymentMethod === '國內信用卡')) 
      ? '無此組合之手續費率，請手動輸入金額或費率。' 
      : null;
  return { rate, warning };
}
```

Use `rate` to show suggested surcharge and optionally pre-fill; show `warning` in the UI when non-null.

---

## 10. Summary Checklist for Frontend

- [ ] Use `meta.transaction_payment_methods` for payment method in add/edit payment (not `meta.payment_methods`).
- [ ] Use `meta.banks` for bank dropdown when payment method is credit card.
- [ ] Use `meta.terminal_types` and free input for installment periods (e.g. 3, 6, 12, 24, 36).
- [ ] Implement surcharge lookup from `meta.surcharge_rates` with fallback to 未分期 and show warning when no exact installment match.
- [ ] Allow optional manual `surcharge_amount` or `surcharge_rate` when no rate or user override.
- [ ] Add `is_invoice_exempt` to payment form and send it in POST/PUT.
- [ ] Display `charges` as the breakdown of `total_receivable`.
- [ ] Use `invoice_exempt_items` (and `invoice_exempt_total`) as the single section to list all 免開發票 items; each item has `type` (`addon` \| `surcharge` \| `payment`), `id`, `amount`, `description`, and type-specific fields.
- [ ] Include `bank`, `terminal_type`, `installment_periods`, `is_invoice_exempt` in payment/refund display and in any edit payloads.
