# CHM-D-20260611-71 — Pindahkan Data NIE ke Kolom Merek

## Context

NIE (Nomor Izin Edar) sebelumnya disimpan per-barang di tabel `barangs`. Permintaan ini memindahkan ketiga field NIE (`jenis_nie`, `no_nie`, `masa_aktif_nie`) ke tabel `merek_barangs` sebagai sumber data tunggal (**Opsi A — single source of truth**).

Konsekuensi desain:
- NIE hanya disimpan di merek, tidak lagi di barang
- Kolom NIE di tabel `barangs` dihapus
- Form Tambah/Edit Barang menampilkan NIE read-only yang diambil live dari merek yang dipilih (tidak disimpan ke barangs)
- Jika merek NIE berubah, semua barang dengan merek tersebut otomatis mencerminkan data NIE terbaru

## Perubahan yang Dilakukan

### Migrations
| File | Keterangan |
|---|---|
| `2026_06_11_000001_add_nie_to_merek_barangs_table.php` | Tambah `jenis_nie`, `no_nie`, `masa_aktif_nie` ke `merek_barangs` |
| `2026_06_11_000002_drop_nie_from_barangs_table.php` | Drop kolom NIE dari `barangs` |

### Model
- `app/Models/MerekBarang.php` — tambah NIE ke `$fillable`, cast `masa_aktif_nie` sebagai date
- `app/Models/Barang.php` — hapus NIE dari `$fillable`

### Controller
- `app/Http/Controllers/DataInduk/MerekBarangController.php` — `data()`, `store()`, `update()` mencakup NIE
- `app/Http/Controllers/DataInduk/BarangController.php` — load `merekBarang` dengan kolom NIE, expose sebagai `merek_jenis_nie`, `merek_no_nie`, `merek_masa_aktif_nie`; hapus NIE dari validasi & save

### View
- `resources/views/data-induk/merek-barang.blade.php`
  - Form tambah/edit: urutan field = Nama Merek → section NIE (Jenis, No., Masa Aktif) → Catatan (paling bawah)
  - Tabel: kolom Jenis NIE, Nomor NIE, Masa Berlaku NIE (format dd-mm-yyyy) ditampilkan; kolom Catatan dihapus dari tabel
  - Modal detail: baris NIE ditampilkan
  - Flatpickr untuk Masa Aktif NIE
- `resources/views/data-induk/barang.blade.php` — NIE display-only (readonly) dari merek saat dipilih; `simpan()` tidak mengirim NIE; label "otomatis dari merek"

### Export / Template / Import
- `app/Exports/MerekBarangExport.php` — kolom Jenis NIE, No. NIE, Masa Aktif NIE
- `app/Exports/MerekBarangTemplateExport.php` — 5 kolom termasuk NIE
- `app/Imports/MerekBarangImport.php` — baca & simpan kolom NIE (konversi tanggal dd-mm-yyyy → Y-m-d)

---

## Pekerjaan 2 — Tampilkan Kode Referensi pada Cetakan PO

### Context
Cetakan PDF PO menampilkan `kode_barang` (kode internal sistem) di bawah nama barang. Diganti dengan `kode_ref` (kode referensi eksternal) agar supplier dapat mencocokkan dengan katalog mereka sendiri.

### Perubahan
- `app/Http/Controllers/Pengadaan/PurchaseOrderController.php` — `generatePdf()`: tambah eager load `items.barang:id,kode_ref`
- `resources/views/pengadaan/purchase-order/pdf.blade.php` — sub-info baris item: ganti `$item->kode_barang` → `$item->barang?->kode_ref ?? '-'`

### Catatan Desain
`kode_ref` tidak di-snapshot ke `purchase_order_items` (tidak ada migration), melainkan dibaca live dari relasi `barang`. Barang tanpa kode_ref menampilkan `-`.

---

---

## Pekerjaan 3 — Tambah Kolom U.P. di Data Supplier & Cetakan PO

### Context
Field "U.P." (Untuk Perhatian) ditambahkan ke master data supplier agar nama penerima/divisi tujuan PO dapat dicatat dan dicetak di cetakan PO tepat di bawah baris Telepon.

### Migration
`2026_06_11_000003_add_up_to_produsen_table.php` — tambah `up VARCHAR(150) NULLABLE` setelah kolom `telepon`

### Perubahan
- `app/Models/Produsen.php` — tambah `up` ke `$fillable`
- `app/Http/Controllers/DataInduk/ProdusenController.php` — `rules()`, `fillableFields()`, `data()` mencakup `up`
- `resources/views/data-induk/produsen.blade.php` — field U.P. di Tab Umum (setelah Telepon), modal lihat, semua fungsi JS
- `resources/views/pengadaan/purchase-order/pdf.blade.php` — baris U.P. setelah Telepon (conditional, hanya muncul jika terisi)
- `app/Exports/ProdusenExport.php` — kolom U.P. di headings & map
- `app/Exports/ProdusenTemplateExport.php` — kolom U.P. di header & contoh baris (range A:M)
- `app/Imports/ProdusenImport.php` — baca kolom `up`

---

## Verifikasi

1. **Merek Barang** — tambah/edit merek dengan data NIE → tersimpan; export Excel → kolom NIE muncul; import Excel dengan kolom NIE → data masuk
2. **Barang** — pilih merek yang punya NIE → field NIE otomatis terisi & readonly; kosongkan merek → NIE hilang; simpan barang → NIE **tidak** tersimpan di barangs; modal detail barang → NIE tampil dari merek
3. Jalankan: `php8.2.26 artisan migrate`

---

## Pekerjaan 4 — Format Nama Gudang KSO

### Context
Gudang KSO dibuat otomatis saat faskes ditambahkan dengan `has_gudang_kso = true`. Nama gudang sebelumnya diawali kata "Gudang KSO " (contoh: "Gudang KSO RS Sehat"). Permintaan: nama gudang cukup menggunakan nama faskes langsung (contoh: "RS Sehat").

### Perubahan

**Controller** — `app/Http/Controllers/DataInduk/FaskesController.php`

`store()`: ubah `'nama' => 'Gudang KSO ' . $faskes->nama` → `'nama' => $faskes->nama`

`update()` — dua tempat:
- Saat gudang sudah ada: tambah `'nama' => $item->nama` pada array update (sebelumnya hanya update `is_active`)
- Saat create baru: ubah `'nama' => 'Gudang KSO ' . $item->nama` → `'nama' => $item->nama`

**Migration data fix** — `database/migrations/2026_06_11_000004_update_gudang_kso_nama.php`

Update semua record gudang dengan `tipe = 'faskes'` agar namanya mengikuti `faskes.nama` (menghapus prefix "Gudang KSO " dari data existing).

### Verifikasi
1. Jalankan migration → cek tabel `gudangs`, nama gudang tipe `faskes` = nama faskes saja
2. Tambah faskes baru dengan `has_gudang_kso = true` → gudang terbentuk dengan nama = nama faskes
3. Edit nama faskes → gudang KSO ikut berganti nama

---

## Pekerjaan 5 — Menu Mutasi Barang & Pengiriman Barang

### Context
Menu "Permintaan Mutasi" sebelumnya berada sebagai item langsung di bawah grup "Gudang". Permintaan:
1. Buat menu top-level baru bernama **"Mutasi Barang"**
2. Pindahkan halaman permintaan mutasi ke menu baru tersebut dengan nama **"Pengiriman Barang"**
3. Hapus item "Permintaan Mutasi" dari menu "Gudang"

Struktur menu hasil:
```
Gudang
  ├── Penerimaan Barang
  ├── Stok Barang
  └── ...

Mutasi Barang  ← top-level baru (icon bx-transfer)
  └── Pengiriman Barang  ← route: permintaan-pengeluaran.index
```

### Perubahan

**`config/menu.php`**
- Hapus item "Permintaan Mutasi" dari children "Gudang"
- Tambah grup top-level "Mutasi Barang" (setelah "Gudang", sebelum "Penjualan") dengan satu child "Pengiriman Barang" mengarah ke route `permintaan-pengeluaran.index`

**`resources/views/penjualan/permintaan-pengeluaran/index.blade.php`**
- Title: "Pengiriman Barang"
- Heading: "Pengiriman Barang"
- Breadcrumb: `Mutasi Barang → Pengiriman Barang`
- Tombol: "Buat Pengiriman"

**`resources/views/penjualan/permintaan-pengeluaran/form.blade.php`**
- Title: "Buat Pengiriman Barang" / "Edit Pengiriman Barang"
- Heading: sama
- Breadcrumb: `Mutasi Barang → Pengiriman Barang → Buat Baru/Edit`

### Verifikasi
1. Sidebar → "Mutasi Barang" muncul di antara Gudang dan Penjualan
2. Klik "Pengiriman Barang" → halaman terbuka dengan judul & breadcrumb benar
3. Tombol "Buat Pengiriman" → form create terbuka dengan judul benar

---

## Pekerjaan 6 — Filter Stok Kecuali Gudang Pusat

### Context
Halaman Stok Barang (`/gudang/stok`) sudah memiliki filter Gudang (pilih satu gudang tertentu). Permintaan: tambah opsi **"Kecualikan Gudang Pusat"** berupa checkbox yang ketika dicentang akan menghilangkan semua data stok dari gudang bertipe `pusat` di kedua tab (Rekap Stok & Detail Stok).

Gudang model memiliki kolom `tipe` dengan nilai `'pusat'` atau `'faskes'`, sehingga filter cukup dengan `WHERE gudangs.tipe != 'pusat'`.

### Perubahan

**1. `resources/views/gudang/stok/index.blade.php`**

Di kedua filter card (tab Rekap dan tab Detail), tambah checkbox setelah baris filter Gudang, sebelum tombol Filter:
```html
<div class="col-md-auto d-flex align-items-end pb-1">
    <div class="form-check mb-0">
        <input class="form-check-input" type="checkbox" id="chkKecualiPusat" value="1">
        <label class="form-check-label small" for="chkKecualiPusat">Kecualikan Gudang Pusat</label>
    </div>
</div>
```
(Tab Detail: `id="chkKecualiPusat2"`)

Di fungsi `data` masing-masing DataTable, tambah parameter:
```js
d.kecuali_pusat = $('#chkKecualiPusat').is(':checked') ? 1 : '';
```

**2. `app/Http/Controllers/Gudang/StokController.php`**

Di method `rekap()` dan `detail()`, tambah kondisi after filter gudang yang sudah ada:
```php
->when($request->kecuali_pusat, fn($q) => $q->where('gudangs.tipe', '!=', 'pusat'))
```

### Verifikasi
1. Buka Stok Barang → tab Rekap → centang "Kecualikan Gudang Pusat" → klik Filter → kolom Gudang tidak ada yang bertipe pusat
2. Ulangi di tab Detail
3. Kombinasi dengan filter Gudang spesifik tetap berjalan normal
4. Uncheck → data Gudang Pusat muncul kembali

---

## Pekerjaan 7 — Batasan Karakter Nama Barang

### Context
Saat ini field Nama Barang memiliki batas `max:255` di controller dan `maxlength="255"` di view — batas generik yang belum mencerminkan kebutuhan bisnis. Permintaan: tetapkan batas yang lebih ketat dan tambahkan counter karakter agar user tahu sisa karakter yang tersedia.

Batas yang ditetapkan: **48 karakter** (cukup untuk nama produk medis, mencegah nama terlalu panjang yang merusak tampilan tabel/cetakan).

Kolom `nama` di tabel `barangs` adalah `VARCHAR(255)` — tidak perlu migration karena 150 < 255.

### Perubahan

**`app/Http/Controllers/DataInduk/BarangController.php`**

Di method `store()` dan `update()`, ubah rule:
```php
// Sebelum:
'nama' => 'required|string|max:255',
// Sesudah:
'nama' => 'required|string|max:48',
```

**`resources/views/data-induk/barang.blade.php`**

1. Ubah `maxlength="255"` → `maxlength="150"` pada `#formNama`
2. Tambah counter di bawah input (`#counterNama`) dalam wrapper `d-flex justify-content-between`
3. Fungsi `updateNamaCounter(val)`:
   - 0–39 karakter: abu-abu (normal)
   - 40–47 karakter: kuning + bold (peringatan)
   - 48 karakter: merah + bold (batas tercapai)
4. Event `#formNama input` memanggil `updateNamaCounter()`
5. `resetBarangForm()` memanggil `updateNamaCounter('')` → reset ke `0 / 150`
6. `openEdit()` memanggil `updateNamaCounter(d.nama)` → set counter sesuai nilai existing

### Verifikasi
1. Buka form Tambah Barang → counter menampilkan `0 / 150`
2. Ketik nama → counter bertambah real-time; kuning mulai 130, merah di 150
3. Paste teks > 150 karakter → terpotong di 150
4. Buka Edit Barang → counter langsung menampilkan jumlah karakter nama yang ada
5. Submit nama 49+ karakter via API langsung → backend tolak dengan error max:48
