# Modul Discounts

File: [DiscountList.jsx](../../src/pages/discounts/DiscountList.jsx), [DiscountForm.jsx](../../src/pages/discounts/DiscountForm.jsx), [discountService.js](../../src/services/discountService.js)

Berbeda dari Products (5 endpoint berantai), Discount adalah CRUD **satu endpoint saja** — semua konfigurasi (target, jadwal, cabang) dikirim dalam satu payload `POST`/`PUT`.

## Field & Section

| Section | Field |
|---|---|
| Informasi Dasar | `name*`, `notes` (max 500) |
| Pengaturan | `type` (`percent`/`nominal`), `value*` (>0), `apply_to` (`all`/`product`/`category`/`modifier`), `max_amount` (cap nominal diskon, khusus berguna kalau `type=percent`), lalu multi-select kondisional sesuai `apply_to`: produk / kategori / modifier |
| Batas Pemakaian | `availability` (`unlimited`/`limited`) → kalau `limited`, `usage_limit*` (≥1) |
| Waktu Aktif | `time_range` (`forever`/`custom` dengan `active_from`/`active_until` tanggal), lalu per-hari (Senin–Minggu): toggle aktif + `allday` atau `custom` jam |
| Cabang | multi-select `branch_ids[]` |

## Validasi sebelum submit (manual, `handleSave`)

1. `name` kosong → toast "Nama diskon wajib diisi"
2. `value` kosong atau ≤0 → toast "Nilai diskon harus lebih dari 0"
3. Kalau `availability === 'limited'` dan (`usage_limit` kosong atau <1) → toast "Kuantitas diskon harus minimal 1"

## Transformasi payload sebelum dikirim

- `targets[]` dibangun dari `apply_to`: kalau `product` → `productIds.map(id => ({ target_type: 'product', target_id: id }))`, sama untuk `category`/`modifier`. Kalau `apply_to === 'all'` → `targets: []`.
- `schedules[]` dibangun dari hari yang toggle aktif: `{ day_of_week, start_time, end_time }`. Tipe "Berlaku tiap jam" → `00:00`–`23:59`.
- `max_amount`: dikirim `null` kalau kosong (bukan 0).
- `usage_limit`: dikirim `null` kalau `availability === 'unlimited'`.
- `active_from`/`active_until`: dikirim `null` kalau `time_range === 'forever'`.

## Endpoint

| Aksi | Method | Endpoint |
|---|---|---|
| List | GET | `/v1/discounts` |
| Detail | GET | `/v1/discounts/{id}` |
| Create | POST | `/v1/discounts` |
| Update | PUT | `/v1/discounts/{id}` |
| Delete | DELETE | `/v1/discounts/{id}` |

**Body create/update:**
```json
{
  "name": "...", "notes": "...",
  "type": "percent|nominal", "value": 0,
  "apply_to": "all|product|category|modifier",
  "max_amount": null,
  "targets": [{ "target_type": "product|category|modifier", "target_id": "..." }],
  "usage_limit": null,
  "active_from": null, "active_until": null,
  "branch_ids": ["..."],
  "schedules": [{ "day_of_week": 0, "start_time": "00:00", "end_time": "23:59" }]
}
```

**Expected response detail** (`GET /v1/discounts/{id}`) — bentuk balik yang dipakai untuk reconstruct form saat edit:
```json
{
  "data": {
    "name": "...", "notes": "...", "type": "...", "value": 0, "apply_to": "...", "max_amount": null,
    "targets": [{ "target_type": "...", "target_id": "..." }],
    "usage_limit": null, "active_from": "YYYY-MM-DD...", "active_until": "YYYY-MM-DD...",
    "branches": [{ "id": "..." }],
    "schedules": [{ "day_of_week": 0, "start_time": "HH:MM:SS", "end_time": "HH:MM:SS" }]
  }
}
```

## Error handling

`onError` di `saveMutation`: kalau ada `err.response.data.errors` (422 validation Laravel) → ambil field error pertama via `Object.values(errors).flat()[0]`. Kalau tidak → fallback `err.response.data.message` atau "Gagal menyimpan diskon".

## List

Tidak ada export/import di modul Discount (berbeda dari Branch/Category/Table/Product) — `discountService.js` hanya punya CRUD dasar, tanpa `exportExcel`/`exportPdf`/`importExcel`.
