# Aturan Kerja & Pembelajaran Pasangan (User Learning Protocol)

## 1. Prinsip Utama: Proteksi Reputasi Klien & Context-Aware Audit
- **Reputasi Klien Adalah Utama:** Dilarang mengklaim "Sudah Oke" hanya berdasarkan asumsi atau kode yang tampak sekilas benar. Setiap klaim harus didukung oleh bukti empiris data session, query database, dan pengujian sintaks.
- **Memaknai Kondisi & Posisi (Business Context & Step Lifecycle):**
  - *Jangan membaca data secara buta (Blind Reading):* Setiap variabel di session dan database HARUS selalu dimaknai sesuai konteks bisnis dan posisi step-nya.
  - *Pahami Role & Hak Akses UI:* (Pre-PO, PO Approval, GRN Gudang, Finance).

## 2. Arti Perintah Spesifik dari User:

### A. Perintah "Cek Session"
- Lakukan **Deep Audit & Joint Analysis**: Ekstrak & bedah isi file session aktif (`C:/xampp/tmp/ci_session*`).
- Evaluasi **Backward Compatibility** dan keselarasan konteks posisi step UI dengan data backend.

### B. Perintah "Jalankan CLI Transaksi"
- **WAJIB LANGSUNG MENJALANKAN** method `CliTransaksi::run_cliTransaksi()`!
- **Mekanisme Eksekusi:**
  - Jalankan skrip runner CLI via `php.exe`:
    ```powershell
    c:\xampp\php\php.exe "c:\xampp\htdocs\new_san_variant\scratch\run_cli_via_argv.php"
    ```
  - Jika ada `tr_id` spesifik dari transaksi yang sedang diproses User di UI, set parameter `$_GET['tr_id'] = $trId` untuk dry-run/manual check.
  - Laporkan hasil eksekusi sub-komponen (`RekeningPembantuProdukRiil`, `ComJurnal`, `FifoProdukJadiVarian`, dll), durasi eksekusi, dan status pemrosesan di database.

## 3. Integritas Varian & MariaDB Typecasting Guardrail

### A. Gate Mapping `"extern_id" => "produk_id"`
- Dalam seluruh file `coTransaksiCore.php` di 28+ modul, komponen buku pembantu stok (`RekeningPembantuProduk`, `RekeningPembantuProdukRiil`, `RekeningPembantuProdukPpn`, dll) **WAJIB** dipetakan menggunakan `"extern_id" => "produk_id"` (integer ID produk murni).
- **DILARANG** menggunakan `"extern_id" => "id"` karena pada fitur varian, `$item['id']` berisi string cart key seperti `'variant:PID:VID'`. Memasukkan string awal huruf ke kolom `INT` MariaDB akan menyebabkan MariaDB secara implisit mengonversi nilai tersebut menjadi `0`, merusak buku pembantu stok secara diam-diam.

### B. Defense Filter Baris Hantu (*Ghost Row Prevention* di `transaksi_data`)
- Pada model utama `MdlTransaksi::writeDetailEntries()`, **WAJIB** dipasang filter penolak (*guard filter*) yang memeriksa apakah record memiliki ID item valid (`produk_id > 0`, `barang_id > 0`, dll) dan `qty > 0`.
- Apabila ditemukan item kosong (`produk_id = 0`, `qty = 0`, `nama = ''`), model harus me-return `null` dan menolak peng-insert-an ke tabel `transaksi_data`.

### C. Smart Extraction Cart Key di `writeDetailEntries()` & `FollowUp.php`
- Pada pengolahan cart item yang menggunakan string key berformat `'variant:PID:VID'`, `MdlTransaksi::writeDetailEntries()` dan `FollowUp.php` **WAJIB** mengekstrak `PID` murni untuk `produk_id` dan `VID` murni untuk `variant_id` sebelum melakukan peng-insert-an/update ke MariaDB.
- Hal ini menjamin bahwa tidak ada string `'variant:...'` yang terpotong menjadi integer `0` pada kolom `produk_id` atau `extern_id` MariaDB.

## 4. Invarian Model & Gateway Stok Varian (`MdlLockerStockVariant` & `LockerStockDualWrite`)

### A. Target Tabel & Nullability Filter `MdlLockerStockVariant`
- `MdlLockerStockVariant::$tableName` **WAJIB ALWAYS** bernilai `"stock_locker_variant"`, bukan `"stock_locker"`.
- Filter query stok varian **WAJIB** mendukung `(stock_locker_variant.jenis_locker = 'stock' OR stock_locker_variant.jenis_locker IS NULL OR stock_locker_variant.jenis_locker = '')` agar baris stok varian di database tidak pernah terabaikan dari tampilan modal UI.

### B. Pengisian `jenis_locker` & Smart Extraction `variant_id`
- Model `ComLockerStockVariant` **WAJIB** memasukkan `"jenis_locker" => "stock"` untuk setiap penulisan baris stok varian baru (`new`).
- Model stok (`ComLockerStockDualWrite`, `ComLockerStockVariant`, `ComLockerStock`) **WAJIB** mengekstrak `variant_id` secara otomatis dari string cart key (`'variant:PID:VID'`) jika `variant_id` tidak disertakan di static config.
- Pendaftaran komponen stok di `coTransaksiCore.php` **WAJIB** menggunakan `LockerStockDualWrite` dengan menyertakan pemetaan `variant_id` dan `variant2_id`.

### C. Invarian Dual-Write Konfigurasi GRN & Mutasi Stok (`coTransaksiCore.php`)
- Seluruh transaksi yang berdampak pada stok fisik (termasuk GRN `467`, Mutasi, dan Penjualan) **WAJIB** dikonfigurasi menggunakan `ComLockerStockDualWrite` dengan pemetaan eksplisit `"variant_id" => "variant_id"` dan `"variant2_id" => "variant2_id"`.
- **DILARANG** menggunakan `LockerStock` tunggal pada transaksi yang mendukung varian produk agar stok varian di `stock_locker_variant` selalu terupdate secara otomatis dan akurat.

### D. Penanganan Filter Raw SQL dengan Kurung/OR di `MdlMother::fetchCriteria()`
- Dalam `MdlMother::fetchCriteria()`, setiap filter yang memiliki ekspresi raw SQL berkurung `(` atau klausa `OR` **WAJIB** dialokasikan secara eksplisit ke `$this->criteria2` sebagai string raw murni, bukan di-explode oleh tanda `=`.
- Hal ini mencegah CodeIgniter Query Builder meng-escape tanda kutip tunggal secara salah (`'stock\'`) yang dapat menimbulkan MariaDB Syntax Error 1064 pada query `UPDATE`.

### E. Penanganan Filter Raw SQL dengan Kurung/OR di `MdlMother::addData()`
- Dalam `MdlMother::addData()`, ekspresi filter raw SQL yang mengandung `(` atau klausa `OR`/`or` **WAJIB** dilewati (`continue;`) pada perulangan `$this->filters`.
- Hal ini mencegah string kueri filter ter-explode menjadi nama kolom invalid pada kueri `INSERT` yang memicu SQL Error 1064.

### F. HQ Fallback di `MdlLockerStockVariant::cekLoker()`
- Pada `MdlLockerStockVariant::cekLoker()`, apabila stok varian tidak ditemukan di `cabang_id` & `gudang_id` spesifik login user, sistem **WAJIB** melakukan *fallback lookup* ke HQ / Gudang Utama (`cabang_id = -1, gudang_id = -1`).
- Hal ini menjamin bahwa seluruh stok varian fisik hasil GRN atau penerimaan pusat dapat langsung terakses oleh UI Picker di seluruh cabang.

## 5. Protokol Mandatory 3-Way / Multi-Tabel Cross-Checking Audit

### A. 4-Layer Audit Protocol
Dilarang mengklaim hasil verifikasi hanya berdasarkan 1-2 tabel. Setiap pengujian transaksi / stok **WAJIB** mengeksekusi audit 4-layer simultan:
1. **Layer 1 (Input Detail Transaksi):** Tabel `transaksi_data` (Qty & Variant ID).
2. **Layer 2 (Buku Pembantu & Mutasi):** Tabel `_rek_pembantu_produk_cache` & `__rek_pembantu_produk_riil__*` (Saldo Awal, Mutasi GRN, Saldo Akhir).
3. **Layer 3 (Stok Fisik Gudang):** Tabel `stock_locker_variant` & `stock_locker` (Active Stock per Variant & Parent).
4. **Layer 4 (Tampilan UI Modal):** Output `variantPicker` (`_selectorItem.php`).

### B. Invarian Akumulasi Stok Fisik
- Penerimaan barang baru (GRN) untuk varian **DILARANG HARAM** mengurangi stok master non-varian (`variant_id = 1`) yang sudah ada sebelumnya.
- Rumus Total Akumulasi Stok Fisik:
  $$\text{Total Akumulasi Stok} = \text{Saldo Awal Stok Master} + \text{Penerimaan GRN Varian Baru}$$

## 6. Prinsip Pemisahan Arsitektur Akuntansi vs Stok Varian (SAK & ISO 9001:2015 Standard)
- **Layer 1 — Akuntansi Finansial (`RekeningPembantuProduk` / `_rek_pembantu_produk_cache`):**
  Mengikhtisarkan saldo nilai uang (Rupiah) dan HPP pada level **Master Produk (`produk_id`)** untuk menjaga kerapian struktur COA & Laporan Keuangan Neraca sesuai Standar Akuntansi Keuangan (PSAK 14 / IFRS).
- **Layer 2 — Operasional Stok Gudang & FIFO Varian (`stock_locker_variant` & `rek_cache_persediaan_produk_varian_fifo`):**
  Melacak kuantitas fisik dan HPP spesifik per **Variant ID (`variant_id`)** sesuai standar Manajemen Mutu & Traceability ISO 9001:2015 (Klausul 8.5.2) melalui `ComLockerStockDualWrite` dan `FifoProdukJadiVarian`.
