# Naming Conventions

## Bahasa

| Konteks | Bahasa | Contoh |
|---------|--------|--------|
| UI label, menu, flash message | Indonesia | "DPB berhasil disimpan." |
| Nama tabel database | Indonesia snake_case | `stok_batch_obat`, `tagihan_pbf` |
| Enum/status di DB | Indonesia | `Belum Lunas`, `Menipis` |
| Kode PHP (class, method) | Inggris idiomatic | `PembelianService`, `kurangiStokFEFO` |
| Nama file PHP | Inggris PascalCase | `StokBatchObatController.php` |
| Route URL | Inggris/Indonesia campuran | `/pembelian`, `/stok/batch` |
| Route name | Inggris dot notation | `pembelian.index`, `stok.batch.koreksi` |
| CSS class custom | Prefix `siaga-` | `siaga-card`, `siaga-input` |

---

## Database

### Tabel

| Pola | Contoh |
|------|--------|
| Master data | `master_{entitas}` | `master_cabang`, `master_obat`, `master_pbf` |
| Dictionary | `master_{kategori}_obat` | `master_golongan_obat`, `master_satuan_obat` |
| Transaksi header | `{entitas}` singular | `pembelian`, `penjualan` |
| Transaksi detail | `detail_{entitas}` | `detail_pembelian`, `detail_penjualan` |
| Stok & audit | `{konsep}_{entitas}` | `stok_batch_obat`, `mutasi_stok`, `mutasi_kas` |
| Keuangan PBF | `{konsep}_pbf` | `tagihan_pbf`, `rencana_pembayaran_pbf` |

### Kolom

| Pola | Contoh |
|------|--------|
| Foreign key | `{entitas}_id` | `cabang_id`, `pbf_id`, `obat_id` |
| Tanggal | `tanggal_{konteks}` | `tanggal_terima`, `tanggal_expired` |
| Nomor dokumen | `nomor_{dokumen}` | `nomor_faktur`, `nomor_batch` |
| Jumlah kuantitas | `jumlah` atau `jumlah_{konteks}` | `jumlah_stok`, `jumlah_bayar` |
| Harga | `harga_{tipe}` | `harga_beli`, `harga_modal`, `harga_otc` |
| Harga satuan ecer | `harga_{tipe}_satuan` | `harga_modal_satuan`, `harga_reg_satuan` |
| Margin | `margin_{tier}` | `margin_otc`, `margin_reg`, `margin_vip` (% vs modal satuan) |
| Total | `total_{konteks}` | `total_faktur` (incl. PPN tagihan), `total_penjualan` |

### Istilah harga (kontrak nama)

| Nama kolom / istilah | Meaning tetap |
|----------------------|---------------|
| `harga_otc` | Harga jual **ecer** — jangan treat sebagai kemasan |
| `harga_reg` / `harga_vip` | Harga jual **kemasan utuh** |
| `harga_modal` | Modal **kemasan** (setelah diskon + PPN unit) |
| `harga_modal_satuan` | Modal **ecer** — dasar margin & acuan OTC |
| `harga_modal_terhitung` | Modal agregat kemasan (hasil `HargaModalService`) |
| `total_faktur` | Nilai tagihan PBF = DPP + PPN 11% |

Detail lengkap: [`pricing-dpb-rules.md`](pricing-dpb-rules.md).
| Status | `status_{konteks}` | `status_tagihan`, `status_stok` (virtual) |
| Nama entitas | `nama_{entitas}` | `nama_cabang`, `nama_obat`, `nama_pbf` |
| Kode | `kode_{entitas}` | `kode_obat`, `kode_pelanggan` |

### Index

- Nama deskriptif: `stok_batch_lookup` untuk composite index batch.

---

## Eloquent models

| Tabel | Model class | Catatan |
|-------|-------------|---------|
| `master_cabang` | `Cabang` | Tanpa prefix Master |
| `master_obat` | `Obat` | |
| `master_pbf` | `Pbf` | |
| `master_pelanggan` | `Pelanggan` | |
| `master_golongan_obat` | `GolonganObat` | |
| `stok_batch_obat` | `StokBatchObat` | |
| `tagihan_pbf` | `TagihanPbf` | |
| `pembayaran_tagihan_pbf` | `PembayaranTagihanPbf` | Histori bayar per peristiwa |
| `rencana_pembayaran_pbf` | `RencanaPembayaranPbf` | |
| `harga_jual_obat` | `HargaJualObat` | |
| `histori_harga_jual_obat` | `HistoriHargaJualObat` | |
| `harga_modal_perhitungan` | `HargaModalPerhitungan` | |

**Wajib** set `protected $table` jika nama tabel tidak mengikuti konvensi plural Laravel.

### Relasi

| Pola method | Return type | Contoh |
|-------------|-------------|--------|
| `belongsTo` singular | `BelongsTo` | `cabang()`, `pbf()`, `obat()` |
| `hasMany` plural | `HasMany` | `detail()`, `stokBatch()` |
| Nama relasi | camelCase Indonesia/Inggris | `golonganObat()`, `batchTerpakai()` |

---

## Controller

| Pola | Contoh |
|------|--------|
| `{Entitas}Controller` | `PembelianController` |
| Method REST | `index`, `create`, `store`, `edit`, `update`, `destroy`, `show` |
| Method custom | Indonesia/Inggris deskriptif | `koreksiForm`, `koreksi` |

Route parameter custom:

```php
Route::resource('tagihan', TagihanPbfController::class)
    ->parameters(['tagihan' => 'tagihan']);
// URL: /tagihan/{tagihan} → variable $tagihan
```

---

## Service

| Pola | Contoh |
|------|--------|
| Class | `{Domain}Service` | `StokService`, `KasService` |
| Method simpan | `simpan($header, $detailItems)` | Pembelian, Penjualan |
| Method aksi | Bahasa Indonesia verb | `catatMasuk`, `catatKeluar`, `koreksiStok`, `kurangiStokFEFO` |
| Method query | `get{Apa}` | `getStokTotal`, `getStokAgregat`, `getSaldoTerakhir`, `getSaldoNetoPerCabang` |

---

## Routes

File: `routes/web.php`

| Pola URL | Route name | Controller |
|----------|------------|------------|
| `/cabang` | `cabang.index` | Resource |
| `/stok` | `stok.index` | Hub Stok Obat & Batch (`?tab=obat` / `batch`) |
| `/stok/obat` | `stok.obat.index` | Redirect → `stok.index?tab=obat` |
| `/stok/batch` | `stok.batch.index` | Redirect → `stok.index?tab=batch` |
| `/stok/mutasi` | `stok.mutasi.index` | Halaman Mutasi Stok |
| `/stok/batch/{stokBatch}/koreksi` | `stok.batch.koreksi` | Route model binding |
| `/laporan/penjualan` | `laporan.penjualan` | Group `laporan.` |

Query parameters untuk filter (bukan path):

- `?q=` — search
- `?cabang_id=` — filter cabang
- `?jenis=Medis` — filter penjualan
- `?rekening=tunai&arus=Medis` — filter kas (legacy `?sumber_kas=Kas Medis` masih di-map)
- `?status=aktif` — default daftar tagihan (Belum Lunas + Sebagian); `semua` / status tunggal juga didukung
- `?dari=&sampai=` — filter tanggal laporan / histori pembayaran

---

## Views

| Pola path | Contoh |
|-----------|--------|
| `{modul}/{action}.blade.php` | `obat/index.blade.php` |
| Layout | `layouts/app.blade.php` |
| Komponen | `components/button.blade.php` → `<x-button>` |

### Section yields

| Section | Isi |
|---------|-----|
| `title` | Judul tab browser |
| `page-title` | Judul di navbar |
| `content` | Isi utama |

---

## Enum & status values

Harus **persis** match antara migration, validation rule, dan tampilan UI:

### `jenis_penjualan`
`Medis`, `OTC`

### `jenis_harga` (pelanggan)
`OTC`, `REG`, `VIP`

### `sumber_kas` / `sumber_dana`
`Kas Medis`, `Kas OTC`, `BCA` — **dengan spasi dan kapitalisasi persis**

### `status_tagihan`
`Belum Lunas`, `Sebagian`, `Lunas`

### `status` rencana pembayaran
`Direncanakan`, `Dibayar`, `Batal`

### `jenis_mutasi` stok
`Pembelian`, `Penjualan`, `Koreksi`, `Retur`

### `jenis_mutasi` kas
`masuk`, `keluar` — **lowercase**

### `status_stok` (virtual, bukan kolom DB)
`Aman`, `Menipis`, `Habis`

---

## JavaScript

| Pola | Contoh |
|------|--------|
| File | kebab-case | `searchable-select.js` |
| Export function | camelCase | `initSearchableSelects` |
| Window global | PascalCase namespace | `window.SiagaSearchableSelect` |
| DOM id | kebab-case | `app-sidebar`, `sidebar-backdrop` |

---

## Config & env

| Key | Nilai default |
|-----|---------------|
| `APP_NAME` | `Siaga` |
| `APP_PORT` | `8080` |
| `APP_LOCALE` | `id` |
| `DB_DATABASE` | `siaga_app` |

---

## Git branch (agent)

```
feat/<modul>-<tujuan-kebab>
```

Contoh: `feat/penjualan-hub`, `feat/kas-dashboard-saldo`

Aturan:
- Selalu buat dari `main` terbaru (`git checkout main && git pull`).
- Satu branch = satu tujuan sempit; setelah PR merge, hapus branch lokal dan remote.
- Jangan biarkan feature branch hidup setelah merge (hindari tip “ahead” berisi hanya merge-sync).

---

## Anti-patterns penamaan

| Hindari | Gunakan |
|---------|---------|
| `medicines` | `obat` / `master_obat` |
| `branches` | `cabang` / `master_cabang` |
| `purchase_orders` | `pembelian` |
| `stock` (tabel) | `stok_batch_obat` |
| `paid` / `unpaid` | `Lunas` / `Belum Lunas` |
| `in` / `out` (stok) | `Pembelian` / `Penjualan` |
| Class `MasterCabang` | `Cabang` dengan `$table = 'master_cabang'` |
