# Modul Rekonsiliasi

## Rekonsiliasi Harian (Sounding-Based)

❌ **Belum diimplementasikan** — tab UI = placeholder, model/router belum ada.

```
Per tangki: Stok Awal + Penerimaan + Pemindahan In - Penjualan - Pemindahan Out = Stok Teoritis
Losses/Gain = Stok Aktual - Stok Teoritis
```
Status: `Pending → Balanced → Approved`. Hanya bisa dijalankan jika semua shift hari itu sudah Submitted.

> Angka dari sounding bersifat **teoritis**. Untuk losses aktual, gunakan End-to-End.

## End-to-End Reconciliation (Losses Aktual)

Satu-satunya cara mengetahui losses aktual: siklus per tangki dari kosong ke kosong.

```
Losses Aktual = Total Masuk - Total Keluar - Selisih Dead Stock
Losses %      = Losses Aktual / Total Masuk × 100
```

- Status: `Open → Closed`
- Max 1 siklus Open per tangki
- Data penerimaan & penjualan diambil otomatis dari operasional

```sql
end_to_end_cycle (id, spbu_id, tangki_id, status,
                  tanggal_mulai, tanggal_selesai,
                  dead_stock_awal, dead_stock_akhir,
                  total_penerimaan, total_penjualan,
                  total_pemindahan_in, total_pemindahan_out,
                  losses_aktual, losses_pct, started_by_id, closed_by_id)
-- UniqueConstraint: (tangki_id, status='open')
```

## Files

- Router: `backend/app/routers/end_to_end.py`
- Frontend: `frontend/src/app/(dashboard)/rekonsiliasi/` (2 tab: Harian placeholder + E2E done)
