# Jurnal Pengembangan (Dev-Journal) - Modul Konversi

Modul ini mendokumentasikan seluruh riwayat perbaikan bug, penyesuaian fungsionalitas, dan stabilisasi sistem yang dilakukan pada modul konversi dalam rangka mendukung transisi ke arsitektur **Single Variant Standard**.

---

## 1. Daftar Perubahan Sesi Ini

### A. Migrasi Dual-Write Stock Locker ke ComLockerStockDualWrite
* **Masalah:** Penulisan stok sebelumnya hanya mengarah ke tabel `stock_locker` secara langsung atau terpisah untuk varian, yang menyebabkan risiko ketidaksinkronan data antara level parent (`stock_locker`) dan level variant (`stock_locker_variant`).
* **Perbaikan:**
  * Mengintegrasikan `ComLockerStockDualWrite::pair()` untuk menjamin penulisan ganda (*dual-write*) yang atomik ke `stock_locker` dan `stock_locker_variant` secara bersamaan dalam satu transaksi database.
  * **Berkas yang Diperbarui:**
    * [_shoppingCart.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_shoppingCart.php) - Modifikasi pada method `reset()` untuk jalur produk varian dan non-varian.
    * [_processSelectProductConvertion.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_processSelectProductConvertion.php) - Modifikasi pada method `select()`, `reserveVariantLockerForSelect()`, dan `releaseVariantLockerOnRemove()`.
    * [_processSelectProductConvertionSatuan.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_processSelectProductConvertionSatuan.php) - Penerapan Dual-Write pada saat pemilihan produk konversi satuan.
    * [_processSelectSupplies.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_processSelectSupplies.php) - Penerapan Dual-Write pada penanganan stok supplies.
    * [_processSelectSuppliesConvertion.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_processSelectSuppliesConvertion.php) - Penerapan Dual-Write pada pemrosesan konversi supplies.
    * [Create.php](file:///w:/new_san_variant/application/modules/konversi/controllers/Create.php) - Pembersihan mutasi stok manual dan mengarahkannya ke model Dual-Write.

### B. Registrasi FIFO Dual-Write (FifoProdukJadiVarian)
* **Masalah:** Antrean HPP FIFO untuk produk varian belum tercatat secara otomatis ketika transaksi konversi selesai diproses.
* **Perbaikan:**
  * Mendaftarkan komponen `FifoProdukJadiVarian` pada file konfigurasi transaksi core modul konversi setelah entri `FifoProdukJadi` tipe 1.
  * Menerapkan filter sentinel pada `FifoProdukJadiVarian` agar:
    * `variant_id < 0` &rarr; di-skip.
    * `variant_id == 0` &rarr; diubah menjadi `1` (sentinel standard).
    * `variant_id >= 1` &rarr; diproses langsung.
  * **Berkas yang Diperbarui:**
    * [coTransaksiCore.php](file:///w:/new_san_variant/application/modules/konversi/config/coTransaksiCore.php) - Pendaftaran class `FifoProdukJadiVarian` di 4 entri transaksi tipe 1.

---

## 2. Status UAT (User Acceptance Testing) — Sesi Dual-Write
* **Status Penyimpanan Database:** Sukses (0 Mismatch terdeteksi antara tabel parent `stock_locker` dan `stock_locker_variant`).
* **Status Tampilan Lembar Cetak (Printing):** Sukses (Format cetak nota konversi berjalan normal).
* **Status Fungsional Aksi Lain:** Sukses (Aksi hold dan release loker saat memilih/menghapus produk di keranjang belanja bekerja dengan benar).

---

## 3. Perbaikan Selector Produk dengan Variant Picker (Sesi 2026-06-26)

### A. Selector Menampilkan Baris Duplikat per Varian

* **Masalah (Bug):** Ketika user mencari produk di selector (contoh: "b28"), produk yang memiliki varian muncul **beberapa baris** (1 baris per entry `stock_locker`). Contoh: "ALPEN B28D" muncul 2 baris dengan jumlah 220 dan 55. Seharusnya hanya **1 baris produk master**.
* **Analisis Penyebab:**
  * `MdlLockerStock::lookupByKeyword()` melakukan query ke tabel `stock_locker` **tanpa `GROUP BY produk_id`**, sehingga jika ada beberapa entry stock_locker untuk produk yang sama (dari dual-write per variant atau perbedaan gudang), muncul baris duplikat.
  * Fungsi `selector_uses_variant_rows()` hanya mengenali `MdlProduk` dan `MdlProduk2`, sehingga ketika `selectorModel = "MdlLockerStock"` (konfigurasi konversi), fungsi ini mengembalikan `false` dan `collapse_variant_rows_for_picker()` **tidak pernah dipanggil**.
  * Path variant terpisah (`MdlProdukVarian->search_selector_rows()`) **tidak bisa dipakai** karena method `search_selector_rows` tidak ada di model `MdlProdukVarian`.
* **Solusi Perbaikan:**
  * Menambahkan `GROUP BY stock_locker.produk_id` dan `SUM(jumlah)` di `lookupByKeyword()` agar pasti 1 baris per produk master.
  * Menyederhanakan `get_selector_rows()` agar selalu menggunakan `lookupByKeyword()` (path variant terpisah dihapus karena broken).
  * Menghapus panggilan `collapse_variant_rows_for_picker()` setelah fetch (tidak diperlukan lagi karena `GROUP BY` sudah handle di level SQL).
* **Berkas yang Diubah:**
  * [MdlLockerStock.php](file:///w:/new_san_variant/application/models/Mdls/MdlLockerStock.php) — Rewrite `lookupByKeyword()`: `GROUP BY produk_id`, `SUM(jumlah)`, subquery `has_variants`, `ORDER BY has_variants DESC`.
  * [_selectorItem.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_selectorItem.php) — Simplifikasi `get_selector_rows()` dan hapus `collapse` call.

---

### B. Variant Picker Popup Tidak Muncul (Langsung Masuk Cart)

* **Masalah (Bug):** Produk "ALPEN B28D" memiliki varian aktif, tetapi saat diklik di selector **langsung masuk ke cart sebagai produk master** tanpa menampilkan popup `variantPicker`. User tidak bisa memilih varian mana yang ingin diproses.
* **Analisis Penyebab:**
  * Subquery `has_variants` menghitung `COUNT(*)` dari `var_product_variants` — jika produk punya **2 atau lebih varian**, nilainya bisa `2`, `3`, `5`, dst.
  * Pengecekan di kode menggunakan **`=== 1` (exact match)**, sehingga produk dengan lebih dari 1 varian **gagal match** dan blok variant picker dilewati.
  * Terdapat 3 lokasi yang menggunakan pengecekan salah ini.
* **Solusi Perbaikan:**
  * Mengganti semua `(int)$row->has_variants === 1` menjadi `(int)$row->has_variants > 0` di 3 lokasi:
    1. `collapse_variant_rows_for_picker()` (baris 46)
    2. Variant picker URL override di `selectItem()` (baris 481)
    3. `preLocker` bypass di `selectItem()` (baris 494)
* **Berkas yang Diubah:**
  * [_selectorItem.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_selectorItem.php) — Fix 3 pengecekan `has_variants`.

---

### C. Produk Varian Stok 0 Tidak Muncul di Selector

* **Masalah (Bug):** Jika stok produk master = 0 (misalnya belum ada transaksi masuk), produk tersebut **tidak muncul** di selector. Padahal produk ini memiliki varian yang mungkin memiliki stok, sehingga harus tetap bisa dipilih.
* **Analisis Penyebab:**
  * Blok `$preLocker` di `selectItem()` mengecek `$valLocker > 0` untuk semua produk. Produk dengan stok master = 0 langsung difilter keluar tanpa mempertimbangkan apakah produk tersebut memiliki varian.
* **Solusi Perbaikan:**
  * Menambahkan bypass pada blok `$preLocker`: jika `has_variants > 0`, produk langsung lolos ke `$items[]` tanpa pengecekan stok. Pengecekan stok per varian dilakukan di popup `variantPicker`.
* **Berkas yang Diubah:**
  * [_selectorItem.php](file:///w:/new_san_variant/application/modules/konversi/controllers/_selectorItem.php) — Tambah bypass `$isVariantProduct` di blok `$preLocker`.

---

### D. Backfill Migration Stok Varian Salah (Stok Terduplikasi)

* **Masalah (Bug):** Script `Backfilllockervariant.php` mendistribusikan stok parent ke **setiap** entry variant di `stock_locker_variant`. Contoh: produk master stok 55 → 4 varian masing-masing mendapat stok 55 → total 275 (seharusnya 55). Stok menjadi invalid/terduplikasi.
* **Analisis Penyebab:**
  * Script lama menggunakan `$row->jumlah` (stok parent) untuk field `jumlah` di kedua entry (parent dan variant).
  * Script juga menggunakan `ComLockerStockDualWrite::pair()` yang menulis ulang ke parent — menggandakan entry parent yang sudah ada.
* **Solusi Perbaikan:**
  * Rewrite script backfill dengan aturan:
    * **Produk tanpa varian** → sentinel `variant_id = 1` dengan `jumlah = stok parent` (match parent karena satu-satunya entry).
    * **Produk dengan varian** → setiap varian mendapat `jumlah = 0`. Stok diisi melalui transaksi nyata.
    * Insert langsung ke `stock_locker_variant` tanpa `ComLockerStockDualWrite::pair()` (parent sudah ada).
  * Menambahkan method `reset()` untuk truncate & backfill ulang.
* **Berkas yang Diubah:**
  * [Backfilllockervariant.php](file:///w:/new_san_variant/application/controllers/Backfilllockervariant.php) — Rewrite total.

---

### E. Dokumentasi Blueprint Selector Variant Picker

* **Tujuan:** Menyediakan blueprint agar modul lain (pembelian, penjualan, distribusi, produksi, dll) bisa mengadaptasi selector variant-aware dengan mudah.
* **Isi:** Arsitektur alur data, komponen yang terlibat, konfigurasi `coTransaksiUi.php`, checklist implementasi, dan daftar kesalahan umum.
* **Berkas yang Dibuat:**
  * [blueprint-selector-variant-picker.md](file:///w:/new_san_variant/docs/blueprint-selector-variant-picker.md) — Blueprint lengkap.

---

## 4. Ringkasan Berkas yang Diubah — Sesi 2026-06-26

| No | Berkas | Aksi | Deskripsi |
|----|--------|------|-----------|
| 1 | `application/models/Mdls/MdlLockerStock.php` | MODIFY | GROUP BY produk_id, SUM(jumlah), has_variants subquery |
| 2 | `application/modules/konversi/controllers/_selectorItem.php` | MODIFY | Fix selector: 1 baris per produk, has_variants > 0, preLocker bypass, get_selector_rows simplified |
| 3 | `application/controllers/Backfilllockervariant.php` | REWRITE | Variant stok = 0, sentinel = stok parent, tanpa DualWrite |
| 4 | `docs/blueprint-selector-variant-picker.md` | NEW | Blueprint untuk modul lain |

---

## 5. Status UAT — Sesi Selector Variant Picker
* **Selector 1 baris per produk:** ✅ Sukses — hanya 1 baris produk master muncul di selector.
* **Variant Picker popup:** ✅ Sukses — popup muncul saat klik produk yang memiliki varian, menampilkan daftar varian dengan stok dan input qty.
* **Produk varian stok 0 tetap muncul:** ✅ Sukses — produk master dengan stok 0 tetap muncul di selector jika memiliki varian aktif.
* **Backfill migration:** ✅ Sukses — variant entry mendapat stok 0, sentinel mendapat stok parent. Tidak ada duplikasi stok.

---

## 6. Referensi Silang (Doc-Sync)

Dokumen-dokumen berikut juga diperbarui sebagai bagian dari sinkronisasi dokumentasi:

| Dokumen | Lokasi | Isi yang Ditambahkan |
|---------|--------|----------------------|
| Jurnal Bulanan Proyek | [2026-06.md](file:///w:/new_san_variant/docs/dev-journal/2026-06.md) | Entri sesi 2026-06-26: selector variant picker |
| Progress Tracker | [blueprint-progress-tracker.md](file:///w:/new_san_variant/docs/dev-journal/blueprint-progress-tracker.md) | Update status konversi + daily sync |
| Blueprint Selector | [blueprint-selector-variant-picker.md](file:///w:/new_san_variant/docs/blueprint-selector-variant-picker.md) | Blueprint baru untuk referensi modul lain |

> **Catatan:** Dokumentasi `AGENT_GLOBAL` (blueprint produksi existing) **TIDAK diperbarui** untuk fitur variant.
> AGENT_GLOBAL baru di-update setelah fitur variant di-merge ke production,
> agar tidak membingungkan agent lain yang bekerja di workspace produksi.

