# Modul Penebusan & Penerimaan BBM

## Penebusan

**Status:** `Draft → Submitted → Partially Received → Fully Received`
- Bisa diinput sebelum SO keluar (status: `WAITING_SO`)
- Penerimaan hanya bisa dicatat setelah SO ada
- 1 DO bisa multi-produk. 1 penerimaan bisa link ke lebih dari 1 DO.

```sql
penebusan (id, spbu_id, tanggal, no_do, no_so, status, is_manual,
           pdf_do_url, pdf_bukti_bayar_url)
penebusan_item (id, penebusan_id, produk_id, volume_pesan, nilai)
```

## Penerimaan

- Link ke Penebusan (DO/SO)
- Per item: dipstick manual **sebelum & sesudah** + ATG digital **sebelum & sesudah** (ATG opsional)
- Volume diterima = dipstick sesudah - dipstick sebelum (manual)
- ATG hanya untuk perbandingan — dikonversi via tabel kalibrasi yang sama
- Volume live-computed on-blur: `GET /penerimaan/calculate-volume?tangki_id&height_mm`
- Summary per item: **Received Manual** vs **Received Digital** vs `volume_pesan`
  - Shortage > `losses_threshold_penerimaan_pct` → badge merah
  - Excess → badge biru; shortage ≤ threshold → badge kuning (normal losses)
- Foto: truck photos + per-item dipstick/ATG; diupload setelah record tersimpan
- **Foto upload hanya bisa dilakukan saat status = DRAFT.** Submit/approved → upload/delete foto diblok.

## Status Flow

```
Draft → Submitted → Approved (= Locked)
                        ↓
                    Rejected → edit → Re-submit
                                          ↑
                         Unlock (by approver, wajib isi alasan)
```

- **Tidak ada Recall** di penerimaan (beda dari penjualan/stock)
- **Unlock**: approver unlock dari approved → draft (alasan wajib)

## BAST PDF

✅ `GET /api/v1/spbus/{spbu_id}/penerimaan/{id}/bast-pdf` — tersedia setelah approved.

## Schema

```sql
penerimaan (id, spbu_id, penebusan_id, tanggal, tgl_jam_keluar_terminal, jam_tiba, jam_berangkat,
            no_polisi, shipment_no, nama_pengemudi, no_lo,
            density_obs, temp_obs, density_ons, temp_ons, catatan,
            -- Approval audit
            status,                    -- draft | submitted | approved | rejected
            submitted_by_id, submitted_at,
            reviewed_by_id, reviewed_at, catatan_review,
            unlocked_by_id, unlocked_at, unlock_reason,
            created_by_id, created_at)

penerimaan_item (id, penerimaan_id, penebusan_item_id, produk_id, tangki_id,
                 dipstick_sebelum_mm, volume_sebelum,
                 dipstick_sesudah_mm, volume_sesudah, volume_diterima,
                 atg_sebelum_mm, atg_sesudah_mm)

penerimaan_foto (id, penerimaan_id, penerimaan_item_id [nullable], tipe, url)
-- tipe: truck|stick_t3|compartment_buka|compartment_kosong|surat_jalan
--       stick_awal|stick_akhir|dipstick_sebelum|dipstick_sesudah|atg_sebelum|atg_sesudah
```

**Migration:** `g1j2k3l4m5n6` — tambah `StatusPenerimaan` enum + 9 kolom audit.

## API Endpoints

```
GET/POST  /api/v1/spbus/{spbu_id}/penerimaan
GET       /api/v1/spbus/{spbu_id}/penerimaan/{id}
DELETE    /api/v1/spbus/{spbu_id}/penerimaan/{id}
POST      /api/v1/spbus/{spbu_id}/penerimaan/{id}/fotos    ← tipe via query param
DELETE    /api/v1/spbus/{spbu_id}/penerimaan/{id}/fotos/{foto_id}
GET       /api/v1/spbus/{spbu_id}/penerimaan/calculate-volume
POST      /api/v1/spbus/{spbu_id}/penerimaan/{id}/submit
POST      /api/v1/spbus/{spbu_id}/penerimaan/{id}/review   ← { action: approve|reject, catatan? }
POST      /api/v1/spbus/{spbu_id}/penerimaan/{id}/unlock   ← { alasan: string }
GET       /api/v1/spbus/{spbu_id}/penerimaan/{id}/bast-pdf
```

## Files

- Router: `backend/app/routers/penebusan.py`, `backend/app/routers/penerimaan.py`
- Model: `backend/app/models/penerimaan.py` — `Penerimaan`, `PenerimaanItem`, `PenerimaanFoto`, `StatusPenerimaan`
- Frontend: `frontend/src/app/(dashboard)/penebusan/`, `frontend/src/app/(dashboard)/penerimaan/`
- Hooks: `frontend/src/lib/hooks/usePenerimaan.ts`
