# 📖 ATURAN & PROTOKOL FORENSIK PEMBACAAN DATA DISKON PEMBELIAN
**Sistem:** Everest ERP (CodeIgniter 3.1.8 / PHP 5.6 / MariaDB 10)  
**Dokumen Referensi:** Aturan Standar Forensik 3-Way Matching & 5W+1H  
**Target Analisis:** Rekonsiliasi Hulu (PO/Registry) &rarr; Fisik (Stock Locker) &rarr; Hilir (Buku Pembantu Akuntansi & Klaim)  
**Terakhir Diperbarui:** 30 September 2026  

---

## 📌 DAFTAR ISI
1. [Prinsip Dasar 3-Way Matching](#1-prinsip-dasar-3-way-matching)
2. [Aturan Pilar 1: Hulu PO & Registry Dokumen](#2-aturan-pilar-1-hulu-po--registry-dokumen)
3. [Aturan Pilar 2: Fisik Slot Locker (`stock_locker_diskon`)](#3-aturan-pilar-2-fisik-slot-locker-stock_locker_diskon)
4. [Aturan Pilar 3: Hilir Buku Pembantu Akuntansi (`1010020030`)](#4-aturan-pilar-3-hilir-buku-pembantu-akuntansi-1010020030)
5. [Aturan Transaksi Pemotong (Klaim 3333 & Retur 9911)](#5-aturan-transaksi-pemotong-klaim-3333--retur-9911)
6. [Aturan Penanganan Rangkaian Pengiriman Parsial PO](#6-aturan-penanganan-rangkaian-pengiriman-parsial-po)
7. [Protokol Validasi & Kueri Database Aman (Query Safety)](#7-protokol-validasi--kueri-database-aman-query-safety)
8. [Log Klarifikasi Temuan Data Live](#8-log-klarifikasi-temuan-data-live)

---

## 1. Prinsip Dasar 3-Way Matching

Rekonsiliasi diskon pembelian **tidak boleh** hanya mengandalkan satu sumber tabel. Sistem menggunakan kerangka kerja 3 Pilar:

```
[PILAR 1: HULU]               [PILAR 2: FISIK]               [PILAR 3: HILIR]
Purchase Order (466)    ───►   GRN Fisik Locker (467)   ───►  Buku Pembantu Piutang
- items4_sum / items5_sum       - stock_locker_diskon          - Subpiutang 1010020030
- stock_locker_pre_diskon       - Kolom nilai (bukan semu)     - GL Jurnal Finansial
- Komitmen & Kontrak Diskon     - Hak Terbit Riil Gudang       - Realisasi Klaim 3333
```

Setiap GRN dinyatakan **Sehat / Selaras Sempurna** HANYA JIKA:
1. `Hak Seharusnya (Pilar 1) == Total Terbit Locker (Pilar 2)` (toleransi diskrepansi rounding $\le$ Rp 100).
2. `Total Terbit Locker (Pilar 2) == Debet Jurnal Piutang (Pilar 3)`.
3. `Total Locker Diklaim == Kredit Jurnal Realisasi (Klaim 3333)`.

---

## 2. Aturan Pilar 1: Hulu PO & Registry Dokumen

### 2.1 Dekoder Data Blob Registry (`items4_sum` & `items5_sum`)
- Seluruh rincian tarif diskon per barang disimpan dalam format serialized PHP yang di-base64 pada kolom `transaksi.items4_sum` (diskon nominal/persen) dan `transaksi.items5_sum` (diskon hadiah barang / promo free produk).
- **Aturan Dekoder PHP 5.6 Safe:** Unserialize bawaan PHP 5.6 pada arsitektur tertentu sering gagal (*corrupted payload*) jika ada integer 64-bit (`i:10000000000;`). WAJIB dilakukan normalisasi regex sebelum unserialize:
  ```php
  $rawFixed = preg_replace_callback('/i:(\d{10,});/', function($m){
      return 's:' . strlen($m[1]) . ':"' . $m[1] . '";';
  }, base64_decode($blob));
  $data = @unserialize($rawFixed);
  ```

### 2.2 Hak Seharusnya (Expected Discount)
- Dihitung dari akumulasi item barang yang benar-benar diterima pada dokumen penerimaan fisik (`qty * tarif_diskon`).
- **Diskon 7 (Free Produk / Hadiah):** Jika PO memiliki bonus barang, bonus tersebut umumnya hanya diserahkan pada salah satu pengiriman GRN pertama, bukan dipecah proporsional di seluruh GRN parsial.

---

## 3. Aturan Pilar 2: Fisik Slot Locker (`stock_locker_diskon`)

### 3.1 Kolom `nilai` vs Kolom `nilai_unit` (Nilai Semu)
- **KOLOM `nilai` ADALAH SALDO RIIL:** Kolom `nilai` pada tabel `stock_locker_diskon` merepresentasikan hak diskon aktif yang sah dan tersisa untuk dapat dipotong.
- **KOLOM `nilai_unit` ADALAH NILAI SEMU:** Jangan pernah menggunakan `nilai_unit` sebagai saldo hak! Pada masa lalu, terdapat proses repair/reset data yang menolkan kolom `nilai = 0`, namun membiarkan kolom `nilai_unit` terisi angka lama. Nilai ini tidak boleh diakui sebagai saldo aktif.

### 3.2 Formula Baku Agregasi Locker
Untuk menghitung saldo fisik pada suatu GRN:
```sql
Total Terbit = SUM((nilai + IFNULL(nilai_diklaim, 0)) * IF(jumlah < 0, -1, 1))
Sisa Saldo   = SUM(nilai * IF(jumlah < 0, -1, 1))
Total Klaim  = SUM(IFNULL(nilai_diklaim, 0) * IF(jumlah < 0, -1, 1))
```

### 3.3 Relasi Kunci Dokumen (`transaksi_id` OR `nomer`)
- Pada database live, data lama atau data hasil migrasi terkadang tidak mengisi kolom `transaksi_id` dengan ID transaksi baru, melainkan mencatat nomor dokumen fisik pada kolom `nomer`.
- **Aturan Kueri:** Pencarian slot locker WAJIB menggunakan klausa ganda:
  ```sql
  WHERE (transaksi_id = $grnId OR nomer = '$grnNomer')
  ```

---

## 4. Aturan Pilar 3: Hilir Buku Pembantu Akuntansi (`1010020030`)

### 4.1 Deteksi Tabel Sharded Buku Pembantu
- Sistem menggunakan skema partisi sharding nama tabel berakhiran COA: `__rek_pembantu_subpiutangsuppliertrans__1010020030`.
- **Aturan Fallback:** Jika tabel sharded tidak ditemukan di database target, sistem wajib otomatis fallback ke tabel master un-sharded `_rek_pembantu_subpiutangsuppliertrans`, dan jika mutasi bernilai 0, cek rek_cache `_rek_pembantu_subpiutangsuppliertrans_cache` dengan `periode = 'forever'`.

### 4.2 Aturan Pembukuan Debet & Kredit
- **Debet (Pengakuan Piutang Diskon):** GRN mendebet rekening `1010020030` sebagai pengakuan hak klaim ke supplier atas barang yang telah masuk gudang.
- **Kredit (Pencairan / Pelunasan):** Terjadi saat dokumen klaim diskon (`3333`) diterbitkan ke kasir/supplier atau saat terjadi pembatalan retur pembelian (`9911`).

---

## 5. Aturan Transaksi Pemotong (Klaim 3333 & Retur 9911)

### 5.1 Realisasi Klaim Diskon Supplier (`3333`)
- Mengurangi saldo `nilai` pada `stock_locker_diskon` dan menambahkan nilai yang sama ke kolom `nilai_diklaim`.
- Menjurnal mutasi KREDIT pada buku pembantu piutang supplier `1010020030`.
- Berelasi ke GRN asal via `reference_id = grn.id` ATAU `reference_nomer = grn.nomer`.

### 5.2 Pembatalan / Retur Pembelian (`9911` / `trash_4 = 1`)
- Jika suatu GRN dibatalkan atau diretur, status dokumen pada tabel `transaksi` ditandai dengan `trash_4 = 1`.
- **Baris Pembalik Kontra (Negative Locker):** Sistem mencatatkan baris pembalik kontra dengan `jumlah = -1` dan `nilai = -X` untuk menolkan saldo fisik.
- **Eksklusi dari Audit Anomali:** GRN yang memiliki `trash_4 = 1` WAJIB dieksklusi dari kueri anomali aktif (`WHERE (t.trash_4 = 0 OR t.trash_4 IS NULL)`), karena piutang akuntansinya sudah dikreditkan kembali menjadi Rp 0.

---

## 6. Aturan Penanganan Rangkaian Pengiriman Parsial PO

### 6.1 Fenomena Over-Debet Jurnal PO Parsial
- **Penyebab:** Pada pengiriman bertahap (1 PO dipecah menjadi beberapa GRN), modul pembelian lawas mencatat seluruh nilai komitmen diskon PO utuh pada penerimaan GRN parsial pertama (*in-advance lump-sum recognition*).
- **Indikasi Forensik:**
  - GRN ke-1: Debet jurnal akuntansi jauh lebih besar dari fisik locker (`debet_jurnal > 1.2 * total_locker`).
  - GRN ke-2, ke-3, dst: Fisik locker terbit sesuai barang, namun debet jurnal = Rp 0 (karena sudah dijurnal di muka).
- **Aturan Evaluasi:** Kondisi ini **bukan kehilangan uang riil**, melainkan diskrepansi waktu pengakuan (*timing difference*). Analisis wajib dilakukan secara kumulatif pada level PO (`Pengelompokan: Per Induk PO`).

---

## 7. Protokol Validasi & Kueri Database Aman (Query Safety)

### 7.1 Larangan Komentar PHP di Dalam String SQL Double-Quotes
- **KRITIKAL:** DILARANG menempatkan komentar PHP single-line `// ...` di dalam blok string SQL PHP (`$sql = " ... ";`).
- **Alasan:** PHP tidak mengabaikan `//` di dalam tanda kutip string, sehingga `//` terkirim sebagai teks mentah ke MariaDB dan memicu syntax error **1064**, yang menyebabkan kueri mengembalikan nilai `FALSE` dan seluruh indikator KPI menjadi `0 GRN`.
- **Standar Penulisan:** Jika ingin menulis komentar di dalam string SQL, gunakan format komentar SQL standar MariaDB: `-- komentar` atau `/* komentar */`.

### 7.2 Multi-Database Host (DB 5.10 vs DB 5.17)
- **DB 5.10 (`everest_26sep`):** Database operasional utama harian.
- **DB 5.17 (`run_everest_modul`):** Database replika / staging AI analitik.
- Parameter switcher URL wajib mendukung format `?source=517` maupun `?source=5.17` secara agnostik.

---

## 8. Log Klarifikasi Temuan Data Live

| Tanggal | ID / Nomer Kasus | Temuan Lapangan | Klarifikasi & Resolusi Aturan |
|---|---|---|---|
| **29 Sep 2026** | `GRN.-1.2496` | Debet jurnal Rp 24,6 Jt padahal nilai barang hanya Rp 12 Jt. | **Over-Debet PO Parsial:** Debet mengambil plafon total PO `PO.-1.1849` utuh pada parsial pertama. Rekonsiliasi wajib ditarik ke grup PO. |
| **29 Sep 2026** | `GRN.-1.2496` | Diskon 1 tidak terbit di locker, hanya Diskon 2 & 3. | **Plafon Pre-Locker 0:** Kueri validasi PO memeriksa `pre_diskon`. Jika bernilai 0, slot fisik dilewati. |
| **30 Sep 2026** | Dokumen Retur `9911` | Saldo piutang buku pembantu sudah 0, tetapi locker fisik masih tercatat utuh. | **Retur Menggantung:** Ditambahkan logika pembalik kontra (`jumlah = -1`) dan filter `trash_4 = 0` pada dashboard. |
| **30 Sep 2026** | Dashboard 5.17 | KPI menampilkan 0 GRN pada seluruh metrik. | **SQL Syntax Error:** Marker komentar boundary `//` berada di dalam kutip kueri SQL. Telah dibersihkan dan verifikasi live sukses (4.985 GRN sehat, 428 anomali). |
