# Modul Stock Adjustment (Sounding)

## Flow

1 shift = 1 record sounding = stok awal shift tersebut.

**Status:** sama persis dengan penjualan (Draft → Submitted → Approved → Locked, Recall, Unlock).
Approved = Locked: tidak bisa edit/upload foto/delete. Unlock butuh alasan.

**Formula Rekonsiliasi per Tangki per Shift:**
```
Stok Awal  = volume_final sounding shift ini
+ Penerimaan - Penjualan = Stok Teoritis
Stok Aktual = volume_final sounding shift berikutnya
Losses/Gain = Stok Aktual - Stok Teoritis
```

## Aturan

- `dipstick_digital_mm` **wajib** semua tangki aktif sebelum submit
- `dipstick_manual_mm` opsional (partial boleh)
- `volume_final_liter` = manual jika ada, fallback ke digital
- Kalibrasi: interpolasi linear via `app/utils/kalibrasi.py`. Input dalam **mm**. Di luar range → reject.
- Per-tank foto sounding (bukti stick): upload hanya saat status DRAFT
- Tabel kalibrasi tidak berubah saat produk berganti

## Schema

```sql
stock_adjustment (id, spbu_id, shift_id, tanggal, status,
                  submitted_by_id, submitted_at, reviewed_by_id, reviewed_at,
                  recalled_by_id, recalled_at, unlock_reason, unlocked_by_id, unlocked_at)
-- UniqueConstraint: (spbu_id, shift_id, tanggal)

stock_adjustment_item (id, stock_adjustment_id, tangki_id,
                       dipstick_digital_mm, volume_digital_liter,
                       dipstick_manual_mm, volume_manual_liter,
                       volume_final_liter)

stock_adjustment_item_foto (id, stock_adjustment_item_id, foto_url, tipe, keterangan)
```

## Files

- Router: `backend/app/routers/stock_adjustment.py`
- Service: `backend/app/services/stock_service.py`
- Frontend form: `frontend/src/components/forms/stock-form.tsx`
- Frontend page: `frontend/src/app/(dashboard)/stock/stock-client.tsx`
- API hooks: `frontend/src/lib/hooks/useStock.ts`
