# Modul Penyetoran

## Konsep (Per-Shift Model)

Penyetoran **auto-created** saat laporan_shift disimpan via `_upsert_penyetoran()` di `operational_service.py`.
Linked ke `laporan_shift_id` (UniqueConstraint). Operator tidak perlu input manual.

**Amounts yang dihitung otomatis:**
- `jumlah_kas` = total pecahan tunai dari kas fields laporan_shift
- `jumlah_non_kas` = kartu + QR + instansi dari laporan_shift
- `total_penjualan` = total_nilai laporan_shift

Auto-update amounts **hanya jika penyetoran masih DRAFT**. Sudah submitted/approved → amounts tidak diubah.

## Status Flow

**Penyetoran individual:** `draft → submitted → approved`

**PenyetoranBatch:**
```
[Operator]
1. Buka halaman penyetoran, filter date range
2. Centang shift-shift yang mau disubmit (status: draft)
3. Klik "Kirim ke Manager" → POST /penyetoran/batches
   → Penyetoran items set ke SUBMITTED
   → Batch dibuat dengan status DRAFT

[Operator/Admin]
4. Submit batch ke manager → POST /batches/{id}/submit
   → Batch status: SUBMITTED, set submitted_by_id/at

[Manager/Approver]
5. Approve batch → POST /batches/{id}/review (action: approve)
   → Semua penyetoran items → APPROVED
   → Batch → APPROVED (= Locked)
```

Approved = Locked. Unlock butuh alasan, oleh user dengan `penyetoran:approve`.

## BAST PDF

✅ `GET /api/v1/spbus/{spbu_id}/penyetoran/batches/{batch_id}/bast-pdf` — tersedia setelah batch approved.

## Schema

```sql
penyetoran (id, laporan_shift_id, spbu_id, tanggal, shift_id,
            jumlah_kas, jumlah_non_kas, total_penjualan, catatan,
            batch_id,           -- FK ke penyetoran_batch (nullable)
            status,             -- draft | submitted | approved
            bukti_url,
            created_by_id, created_at, updated_at)
-- UniqueConstraint: (laporan_shift_id)

penyetoran_batch (id, spbu_id, tanggal_from, tanggal_to, total_amount, catatan,
                  status,                   -- draft | submitted | approved
                  submitted_by_id, submitted_at,
                  reviewed_by_id, reviewed_at, catatan_review,
                  unlocked_by_id, unlocked_at, unlock_reason,
                  created_at, updated_at)
```

**Migration:** `e7h8i9j0k1l2` — redesign penyetoran (per-shift) + tambah penyetoran_batch.

## API Endpoints

```
-- Penyetoran items (read-only, auto-created)
GET   /api/v1/spbus/{spbu_id}/penyetoran              ← list, params: tanggal_from, tanggal_to
GET   /api/v1/spbus/{spbu_id}/penyetoran/summary/{tanggal}  ← daily summary
GET   /api/v1/spbus/{spbu_id}/penyetoran/{id}
PATCH /api/v1/spbus/{spbu_id}/penyetoran/{id}         ← update catatan saja
POST  /api/v1/spbus/{spbu_id}/penyetoran/{id}/bukti   ← upload bukti setor

-- Batch
GET/POST /api/v1/spbus/{spbu_id}/penyetoran/batches
GET      /api/v1/spbus/{spbu_id}/penyetoran/batches/{id}
POST     /api/v1/spbus/{spbu_id}/penyetoran/batches/{id}/submit
POST     /api/v1/spbus/{spbu_id}/penyetoran/batches/{id}/review  ← { action: approve, catatan_review? }
GET      /api/v1/spbus/{spbu_id}/penyetoran/batches/{id}/bast-pdf
```

## Files

- Model: `backend/app/models/penyetoran.py` — `Penyetoran`, `PenyetoranBatch`, `StatusPenyetoran`, `StatusPenyetoranBatch`
- Router: `backend/app/routers/penyetoran.py`
- Service: `backend/app/services/penyetoran_service.py`
- Auto-upsert: `backend/app/services/operational_service._upsert_penyetoran()`
- Frontend: `frontend/src/app/(dashboard)/penyetoran/penyetoran-client.tsx`
- Hooks: `frontend/src/lib/hooks/usePenyetoran.ts`
