# Laporan Analisis & Resolusi Bug Loker Stok (Shopping Cart)

**Tanggal:** 23 Juli 2026
**Lingkup:** Modul Inventori dengan fitur `locker stock` aktif (15 Modul)
**Konteks:** Rollout Single Variant Standard (Dual-Write Locker)

## Gejala (Symptom)
User melaporkan dua kejanggalan utama saat memanipulasi kuantitas produk dari *Shopping Cart*:
1. **Stok Tidak Cukup (Error Hold Minus):** Ketika user memanipulasi jumlah (*qty*) produk Varian dari dalam *shopping cart* yang menyebabkan penurunan jumlah (misal dari 5 menjadi 3, sehingga *hold* harus dikurangi 2), sistem melemparkan pesan error *"Stok tidak cukup"*.
2. **Kuantitas Mentok di 1:** Ketika produk (khususnya Varian Baru) yang belum pernah dimasukkan ke dalam keranjang di-input dengan *newQty* tertentu (contoh: 23), jumlah yang tercatat di keranjang tetap `1`. Namun, jika produk sudah ada di keranjang sebelumnya, perubahan kuantitas berjalan normal.

---

## Analisis Akar Masalah (Root Cause)

### 1. Masalah "Stok Tidak Cukup" (Variant Leakage)
Pada saat sistem menerima perintah untuk mengurangi jumlah barang di keranjang, sistem harus memindahkan selisih angka tersebut dari status `hold` (booking) kembali ke status `active`.
Namun, di ke-147 *file controller* `_processSelect*.php` yang menggunakan integrasi pelindung baru `ComLockerStockDualWrite`, **sistem alpa meneruskan identitas `variant_id` ke dalam perisai pelindung (`static`)**. 

Akibatnya, fungsi pelindung Varian (`ComLockerStockVariant`) mengira bahwa produk yang sedang diubah adalah produk non-varian. Sistem kemudian mendaratkan perintah minus (`-2`) secara buta ke produk Induk (`variant_id = 1`). Karena produk induk tersebut nilai *hold*-nya kosong (*null*), penambahan angka minus terdeteksi sebagai tindakan ilegal sehingga membangkitkan fungsi penolak otomatis: *"Stok tidak cukup"*.

### 2. Masalah Kuantitas Produk Baru Mentok di 1 (Hardcode `tmpJml = 1`)
Setiap kali produk dimasukkan ke dalam sesi *shopping cart*, sistem menginisialisasi parameter `jml` menggunakan variabel bayangan bernama `$tmpJml`. 
Pada baris awal kode (sebelum validasi loker), variabel ini diatur dengan cara di-*hardcode*:
```php
$tmpJml = 1;
```

Normalnya, di bawah baris tersebut terdapat validasi ke database `stock_locker` fisik. Apabila barang memiliki riwayat *active* stok, sistem akan me-*replace* angka `1` ini menjadi angka dari inputan pengguna (e.g. `23`):
```php
$tmpJml = $jml_diperlukan;
```

Namun, karena produk Varian Baru **benar-benar belum memiliki jejak fisik stok yang "active"** di `stock_locker` lama, blok pencarian mengembalikan hasil kosong (0 baris). Kondisi ini menyebabkan blok penugasan `$tmpJml = $jml_diperlukan` dilompati (tidak pernah tereksekusi). Alhasil, saat eksekusi mencapai pembuatan sesi keranjang, sistem mendaftarkan barang tersebut menggunakan angka `1` dari nilai inisialisasi paksa tersebut, mengabaikan angka `23` yang diketik oleh pengguna. Berbeda dengan saat *update* keranjang (produk sudah ada), yang jalurnya secara langsung menembak `$_GET['newQty']` sehingga terlihat normal.

---

## Solusi (Resolusi Kode)

### 1. Penambalan Kebocoran Varian (Variant Injection)
Skrip otomatis (`patch_variant_leak.php`) telah dijalankan pada **39 *file*** yang memiliki blok pengolah *dual write* `ComLockerStockDualWrite->pair()`. 
Properti pendeteksi Varian yang responsif secara paksa disuntikkan:

**[Sebelum]**
```php
"cabang_id"   => $this->session->login['cabang_id'],
"gudang_id"   => $this->session->login['gudang_id'],
```

**[Sesudah]**
```php
"cart_key"    => isset($cartKey) ? $cartKey : (isset($id) ? $id : 0),
"variant_id"  => (isset($_GET['variant_id']) ? $_GET['variant_id'] : (isset($variant_id) ? $variant_id : ((isset($cartKey) && strpos($cartKey, 'variant:') === 0) ? explode(':', $cartKey)[2] : 1))),
"cabang_id"   => $this->session->login['cabang_id'],
"gudang_id"   => $this->session->login['gudang_id'],
```

### 2. Penghapusan Hardcode (Dynamic `tmpJml`)
Skrip otomatis (`patch_tmpjml.php`) telah dijalankan pada **51 *file*** pengolah seleksi produk lintas modul. Nilai paksa `1` telah dihapuskan dari inisialisasi awal dan digantikan oleh tangkapan parameter cerdas:

**[Sebelum]**
```php
$tmpJml = 1;
```

**[Sesudah]**
```php
$tmpJml = isset($jml) ? $jml : 1;
```
Dengan perbaikan ini, sebelum kode mencapai blok *locker* (ada atau tidaknya barang di database fisik lama), sistem telah memegang kuantitas target (e.g., `23`) dan tidak akan lagi memenggalnya menjadi `1`.

---

## Status Pengujian
Seluruh file terdampak (total 147 *file controller* `_processSelect*.php`) telah di-verifikasi bebas dari kerusakaan kode (*Syntax Check* / `php -l` lulus 100%). Kuantitas yang diinput dari URL kini secara utuh diteruskan hingga mendarat dengan selamat di tabel proteksi stok (`stock_locker_variant`).
