# Variant Cutover Playbook

Dokumen ini menjelaskan cara transisi produk reguler menjadi produk varian tanpa merusak audit trail transaksi dan stok.

## Keputusan Utama

- `Open docs legacy` tidak boleh dipetakan otomatis ke variant.
- `Stok parent legacy` tidak boleh dibagi ke variant dengan SQL manual.
- Jalur resmi cutover stok adalah modul [`application/modules/konversi_varian`](W:/san_varian/application/modules/konversi_varian).
- Flow yang dipakai:
  - `7881` untuk pusat di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L311)
  - `881` branch di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L5) sudah di-hardening mengikuti pola `7881`, tetapi masih `UAT pending`

## Kenapa Dipilih `konversi_varian`

- Source stock masih dibaca dari locker parent product melalui `MdlLockerStock` dan `MdlProduk2` di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L32)
- Target variant dibaca dari `MdlProdukVarian` di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L34)
- Controller konversi memang memuat daftar variant saat product `has_variants = 1` di [_processSelectProductConvertion.php](W:/san_varian/application/modules/konversi_varian/controllers/_processSelectProductConvertion.php#L43)
- Save path-nya sudah membawa `variant_id` ke komponen stok variant seperti `LockerStockVarian` dan `LockerStockMutasiVarian` di [coTransaksiCore.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiCore.php#L1289)
- Flow `7881` memang diset sebagai transaksi `place = center` di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L314)
- Flow `881` memang berlabel `branch`, dan setelah hardening target core-nya sudah diarahkan ke stok varian seperti pola `7881`

## Hasil Audit dan Hardening `881` Cabang

- `881` memang sudah mengenal produk yang punya varian di source selector.
  - `selectorSrcModelVarian = MdlProdukVarian` ada di [coTransaksiUi.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiUi.php#L34)
  - controller juga sudah memuat daftar varian ke session `items2` saat `has_variants = 1` di [_processSelectProductConvertion.php](W:/san_varian/application/modules/konversi_varian/controllers/_processSelectProductConvertion.php#L43)
- Hardening yang sudah diterapkan:
  - `881` sekarang memakai `lockerCheck`, `editHandlerMethod2 = recordItemColumnVarian`, dan `shoppingCartPairedItemVarian`, sehingga grid input qty per varian ikut aktif seperti `7881`
  - source row `881` sekarang menampilkan `current_stok`, `distribute`, dan `sisa_distribute`
  - target row `881` sekarang menampilkan `sku` dan `header_varian`
  - request step `881r` sekarang memakai pola hold yang sama dengan `7881r`, agar tidak double-deduct stok source
  - target approval `881` sekarang membawa `varian_id => variant_id` ke `FifoAverage`, `FifoProdukJadiVarian`, `LockerStockVarian`, dan `LockerStockMutasiVarian`
  - `ComLockerStockVarian` sudah dibetulkan agar menulis ke `stock_locker_varian`, bukan kembali ke locker parent
  - komponen `ComLockerStockMutasiVarian` sudah disiapkan untuk audit trail mutasi stok varian
- Sebaliknya `7881` sudah lengkap untuk target varian:
  - input qty varian lewat `recordItemColumnVarian` di [_shoppingCart.php](W:/san_varian/application/modules/konversi_varian/controllers/_shoppingCart.php#L3366)
  - target approval menulis `variant_id` ke `LockerStockVarian`, `LockerStockMutasiVarian`, dan `FifoProdukJadiVarian` di [coTransaksiCore.php](W:/san_varian/application/modules/konversi_varian/config/coTransaksiCore.php#L1336)

Kesimpulan status:
- `881` bukan flow yang salah modul.
- Hardening utama sudah diterapkan agar pola cabang mendekati `7881`.
- Tetapi statusnya tetap `belum siap produksi` sampai UAT cabang membuktikan:
  - hold source stock tidak dobel
  - total qty varian = qty source
  - stok target benar-benar masuk ke `stock_locker_varian`
  - mutasi target tercatat di `stock_locker_mutasi_varian`
  - layer FIFO target tercatat di `rek_cache_persediaan_produk_varian_fifo`
  - jurnal/HPP/mutasi tidak regress

## Rule Operasional

- Produk hanya boleh diaktifkan menjadi varian jika:
  - open docs pembelian dan penjualan untuk parent product sudah beres, atau
  - bisnis secara sadar memutuskan dokumen lama diselesaikan sebagai `legacy parent item`
- Jika parent stock masih ada:
  - wajib dilakukan `stock cutover`
  - tidak boleh ada transaksi baru untuk produk tersebut selama proses cutover
- Setelah cutover:
  - source of truth stok operasional pindah ke variant
  - parent stock hanya menjadi rollup/reporting

## Jalur Cek Stok Legacy

- Cek pertama:
  - `stock_locker`
  - berguna untuk melihat state operasional seperti `active`, `hold`, `distribute`, `returned`, `moved`
- Cek kedua:
  - `_rek_pembantu_produk_cache` periode `forever`
  - ini dipakai juga oleh engine kalkulasi stock melalui [MdlProdukCalcStock.php](W:/san_varian/application/models/Mdls/MdlProdukCalcStock.php#L325)
  - lebih cocok sebagai `second opinion` apakah parent product masih punya saldo stock tersedia
- Interpretasi yang disarankan:
  - `active` dan `hold` = blocker keras
  - `distribute`, `returned`, `moved` = perlu audit tambahan; jangan langsung diabaikan
  - jika locker menunjukkan state transisi tetapi cache `forever` sudah `0`, kemungkinan ada residual/anomali locker yang perlu dibersihkan
  - jika `active` masih positif, produk tetap dianggap masih punya parent stock legacy dan tidak layak langsung diaktifkan sebagai varian
- Catatan lokasi:
  - `cabang_id = -1` dan `gudang_id = -1` adalah lokasi valid pusat / DC, bukan otomatis data invalid

## Urutan Cutover Yang Disarankan

1. Finalisasi master variant.
   Pastikan daftar variant, SKU, dan atribut sudah final di master produk.

2. Cek dokumen open.
   Cek minimal `PRE-PO`, `PO`, `GRN`, `SO`, delivery, invoice, retur, dan movement stock lain yang masih berjalan.

3. Tentukan mode transisi.
   Pilihan aman:
   - semua dokumen lama diselesaikan dulu, baru aktivasi varian
   Pilihan terbatas:
   - dokumen lama tetap dianggap parent legacy
   - transaksi baru setelah cutover wajib variant-aware

4. Freeze transaksi untuk product tersebut.
   Jangan izinkan pembelian, penjualan, atau movement stock baru saat stok parent sedang dipindahkan.

5. Hitung stok parent aktual per gudang.
   Hasil hitung ini menjadi dasar alokasi stok ke masing-masing variant.

6. Tentukan alokasi stok awal per variant.
   Alokasi harus diputuskan user bisnis/gudang, bukan ditebak sistem.

7. Jalankan `konversi_varian`.
   - pusat: flow `7881`
   - cabang: flow `881` hanya boleh dipakai setelah UAT cabang selesai
   Konversikan stok parent ke variant sesuai alokasi yang disetujui.

   Infrastruktur minimum yang harus sudah ada sebelum UAT:
   - `stock_locker_varian`
   - `stock_locker_mutasi_varian`
   - `rek_cache_persediaan_produk_varian_fifo`
   SQL manual tersedia di [20260406_stock_locker_varian.sql](W:/san_varian/docs/sql/20260406_stock_locker_varian.sql) dan [20260408_variant-stock-support.sql](W:/san_varian/docs/sql/20260408_variant-stock-support.sql).

8. Verifikasi hasil cutover.
   Pastikan:
   - stok parent lama menjadi `0`
   - stok setiap variant sesuai alokasi
   - history mutasi tercatat

9. Buka kembali transaksi operasional.
   Setelah verifikasi lolos, transaksi baru boleh berjalan dengan variant.

## Yang Tidak Boleh Dilakukan

- Tidak boleh membagi stok parent ke variant dengan query `UPDATE/INSERT` manual tanpa transaksi operasional.
- Tidak boleh menebak variant untuk dokumen lama yang tidak punya `variant_id`.
- Tidak boleh membiarkan parent stock dan variant stock sama-sama aktif untuk barang yang sama tanpa keputusan cutover yang jelas.

## Checklist Verifikasi

- [ ] Master variant final
- [ ] Open docs legacy sudah nol atau sudah diputuskan tetap legacy
- [ ] Freeze transaksi sudah dilakukan
- [ ] Stok parent aktual sudah dihitung per gudang
- [ ] Alokasi ke variant sudah disetujui user bisnis
- [ ] Konversi dilakukan lewat modul `konversi_varian`
- [ ] Jika cutover dilakukan di pusat, gunakan flow `7881`
- [ ] Jika stok ada di cabang, pastikan flow `881` sudah lulus UAT sebelum dipakai
- [ ] Tabel `stock_locker_mutasi_varian` sudah tersedia
- [ ] Tabel `rek_cache_persediaan_produk_varian_fifo` sudah tersedia
- [ ] Parent stock menjadi nol setelah cutover
- [ ] Variant stock sesuai hasil alokasi
- [ ] Transaksi baru sesudah cutover sudah memakai variant

## Catatan Implementasi

- Modul ini cocok untuk `stock cutover`, bukan untuk memigrasikan dokumen pembelian/penjualan lama.
- Open docs tetap harus ditangani di jalur transaksi masing-masing.
- Jika nanti dibutuhkan, validasi aktivasi varian di master produk sebaiknya mengecek:
  - open docs legacy
  - stok parent yang masih tersisa
  - status cutover stock per product
- Jika cabang perlu ikut cutover, hardening kode `881` sudah diterapkan.
- Migration helper yang tersedia:
  - `MigrateMaster/add_variant_stock_locker_table`
  - `MigrateMaster/add_variant_stock_support_tables`
- Langkah berikutnya bukan tambah patch besar lagi, tetapi `UAT cabang end-to-end` sebelum dibuka ke user.
