# BLUEPRINT CETAK BIRU MODUL: PEMBATALAN
**Modul:** `pembatalan`  
**Workspace:** `new_san_variant`  
**Standard:** Single Variant Standard & Dual-Write Rollout  
**Tanggal Analisis:** 2026-07-29  

---

## 1. IDENTITAS MODUL

- **Nama Modul:** `pembatalan`
- **Pola Kompleksitas:** **Transaksi Kompleks** (Melibatkan Jurnal Pembalik Otomatis, Stock Locker Reversal / Dual-Write, Multi-Step Approval FollowUp, Reverting Registry Transaksi Asal, dan Dukungan Multi-Variant Item).
- **Jenis Transaksi (`jenisTr`):**
  - `9911` : Pembatalan Transaksi Jurnal Non-Stok / Reversal Transaksi Umum
  - `9912` : Pembatalan Transaksi Stok / Reversal Transaksi Barang & Persediaan
  - `9749` : Penghapusan Piutang (Bad Debt Write-off)

---

## 2. DAFTAR FUNGSI & LOGIKA BISNIS (REVERSE ENGINEERING)

### 2.1 Base Controller & Configuration

#### [Modul_Controller.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/Modul_Controller.php)
- **Fungsi `__construct()`**:
  - *Input (POST/GET/URI)*: `URI segment(4)` sebagai `$this->jenisTr`, `URI segment(1)` sebagai `$this->modul`.
  - *Validasi*: Session login `validateUserSession($this->session->login['id'])`.
  - *Config Loaded*: `coTransaksiUi`, `coTransaksiCore`, `coTransaksiLayout`, `coTransaksiValues`.
  - *Helper Loaded*: `he_access_right`, `he_session_replacer`, `he_url`.
  - *State & DB Schema Mapping*: Meng-inialisasi `$this->mongoTableList` (`transaksi`, `transaksi_values`, `transaksi_data`, `transaksi_data_values`, `transaksi_sign`, `transaksi_extstep`, `transaksi_registry`).

---

### 2.2 Entry Transaksi (Draft / Create)

#### [Create.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/Create.php)
- **Fungsi `index()`**:
  - *Input*: `GET/POST` parameters (filter nota, jenisTr).
  - *Validasi*: Memastikan session cart `_TR_[jenisTr]` terinisialisasi.
  - *Query*: Fetch data pendukung UI (cabang, gudang, user).
  - *Output*: View `transaksi_modul.php` / UI Step 1 (Pencarian & Pemilihan Nota Asal).
- **Fungsi `preview()`**:
  - *Input*: Data session cart `_TR_[jenisTr]` yang memuat nota pilihan.
  - *Validasi*: Memastikan item nota tidak kosong dan total kalkulasi pembatalan valid.
  - *Query*: MdlMongoMother / MdlTransaksi untuk kalkulasi simulasi jurnal pembalik.
  - *Output*: View `template/transaksi_extern.html` / UI Step 2 (Ringkasan Pembatalan & Preview Jurnal).
- **Fungsi `save()`**:
  - *Input*: `POST` form payload (catatan pembatalan, referenceNomer, ID transaksi asal).
  - *Validasi*: Check rule `referenceNomer` wajib diisi, nota asal belum pernah dibatalkan (`trash_4 = 0`).
  - *Query Database*:
    - `transaksi` (Insert header draf pembatalan).
    - `transaksi_data` (Insert rincian item nota yang dibatalkan).
    - `transaksi_values` (Insert total nilai reversal).
    - `transaksi_registry` (Record step registrasi draf).
  - *Output*: JSON response / Redirect ke halaman `FollowUp`.
- **Fungsi `doEdit()`**:
  - *Input*: `POST` data revisi draf pembatalan.
  - *Validasi*: Status transaksi masih draf (`status_next` = step 1).
  - *Query*: Update `transaksi_data` & `transaksi_values`.
  - *Output*: Response status success/error.
- **Fungsi `preCancelPackingPreview()` & `doPreCancelPacking()`**:
  - *Input*: `POST` ID transaksi pengiriman/packing.
  - *Validasi*: Verifikasi status packing gudang.
  - *Query*: Revert state stock locker active <-> hold.
  - *Output*: Preview / Execution result cancel packing.

---

### 2.3 Executing & Reversing (Approval / FollowUp)

#### [FollowUp.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/FollowUp.php)
- **Fungsi `index()`**:
  - *Input*: Filter datatable (status step approval, tanggal, cabang).
  - *Query*: `transaksi` where `jenisTr` = `9911`/`9912`/`9749` AND status step pending.
  - *Output*: View list transaksi pending approval.
- **Fungsi `followupPrePreview()` & `followupPreview()`**:
  - *Input*: `GET/POST` ID transaksi pembatalan.
  - *Query*: Fetch detail transaksi `transaksi_data` + jurnal pembalik yang akan dibentuk.
  - *Output*: View modal/halaman approval.
- **Fungsi `doFollowup()`** *(Core Execution Reversal)*:
  - *Input*: `POST` ID transaksi pembatalan + keputusan approval (Approve/Reject).
  - *Validasi*: User access level (`he_access_right`), lock transaksi agar tidak terksekusi ganda.
  - *Query & Model Executed*:
    1. **Status Update**: Update `transaksi` state menjadi `completed`/`canceled`.
    2. **Jurnal Pembalik**: Panggil `ComTransaksi_jurnal_revert::pair()` untuk membalikkan (swap Debit <-> Kredit) semua entri akun dari transaksi asal ke `com_jurnal`.
    3. **Stock Reversal (Dual-Write)**: Jika `jenisTr = 9912`, panggil `ComLockerStockDualWrite::pair()` untuk mengembalikan stok barang & stok varian ke gudang asal (dengan sentinel `variant_id=1` untuk barang non-variant `variant_id=0`).
    4. **Registry Update**: Update `transaksi_registry` pada transaksi asal untuk menandai status transaksi lama sebagai `REVERTED` / `CANCELED`.
  - *Output*: JSON status success + auto print receipt option.
- **Fungsi `doRevert()` & `doRevertAll()`**:
  - *Input*: `POST` ID transaksi.
  - *Logic*: Membatalkan proses pembatalan (Rollback step ke draf/reject).
  - *Query*: Restore status `transaksi_registry`.
- **Fungsi `doCancelPacking()`**:
  - *Input*: `POST` ID packing.
  - *Logic*: Revert status pengiriman barang di gudang.

---

### 2.4 Cart & Item Selection Engine

#### [_shoppingCart.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/_shoppingCart.php)
- **Fungsi `viewCart()`**: Render tabel item keranjang nota yang dibatalkan.
- **Fungsi `reset()`**:
  - *Logic Dual-Write Stock*: Melepaskan hold locker stok yang dikunci sementara saat memilih item nota, menggunakan `ComLockerStockDualWrite::pair()` untuk sinkronisasi `stock_locker` dan `stock_locker_variant`.
- **Fungsi `recordFieldElement()`, `recordItemColumn()`, `recordPairedItem()`**:
  - *Input*: `POST` field name, value, item key.
  - *Logic*: Real-time update AJAX ke session array `_TR_[jenisTr]`.

#### [_processSelectNota.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/_processSelectNota.php) & [_processSelectNotaRevert.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/_processSelectNotaRevert.php)
- **Fungsi `select()`**:
  - *Input*: `POST` ID Nota / Nomor Transaksi (`referenceNomer`).
  - *Validasi*: Memastikan nota asal belum pernah dibatalkan (`trash_4 = 0`) dan transaksi asal berstatus `completed`.
  - *Query*: Fetch data header & detail transaksi asal dari `transaksi` / `MdlNotaItem`.
  - *Logic*: Memindahkan seluruh item transaksi asal ke keranjang `_TR_[jenisTr]`.
- **Fungsi `remove()`**: Menghapus nota terpilih dari session cart.
- **Fungsi `updateValues()`**: Kalkulasi ulang total nilai piutang/hutang/stok yang dibatalkan.

#### [_processSelectProduct.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/_processSelectProduct.php)
- **Fungsi `select()`, `multiSelect()`, `remove()`**:
  - *Logic*: Mengelola pembatalan parsial per-item barang.
  - *Stock Locker*: Memanggil `ComLockerStockDualWrite::pair()` untuk hold/active stock adjustment.

---

### 2.5 Reporting, Printing & Detail Views

#### [Transaksi.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/Transaksi.php)
- **Fungsi `index()`**: Datatable list transaksi pembatalan (filters: cabang, range tanggal, status).
- **Fungsi `validate()`**: AJAX endpoint untuk cek validitas nota sebelum dimasukkan ke form pembatalan.

#### [ActivityReport.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/ActivityReport.php) & [History.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/History.php)
- **Fungsi `viewMonthly()`, `viewDaily()`, `viewHistory()`**: Render laporan rekapitulasi transaksi pembatalan dalam format bulanan/harian/grid.

#### [ViewDetails.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/ViewDetails.php)
- **Fungsi `nomer()`, `item_report()`**:
  - *Multi-Variant Fix*: Menggunakan unique row key indexing (`{produk_id}_{variant_id}`) untuk mencegah overwrite data saat transaksi memuat barang yang sama dengan varian berbeda.
  - *Variant Label*: Menampilkan badge label varian (`variant_label` / `variant_nama`).

#### [Printing.php](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/controllers/Printing.php)
- **Fungsi `viewReceipt()`, `viewProformaReceipt()`, `viewReceiptCashIn()`**: Render template cetak nota bukti pembatalan transaksi.

---

## 3. IDENTIFIKASI PERBEDAAN DENGAN MOCKUP GLOBAL

Berikut adalah fitur, komponen unik, dan query spesifik pada modul `pembatalan` yang **TIDAK ADA** pada mockup CRUD / Transaksi Standar:

| No | Komponen / Fitur Unik | Deskripsi & Perbedaannya dengan Mockup Standar |
|:--:|:----------------------|:------------------------------------------------|
| 1 | **Reversal Engine (`ComTransaksi_jurnal_revert`)** | Menggunakan model khusus yang otomatis membaca entri jurnal lama dari transaksi asal dan secara simetris membalik akun Debit <-> Kredit ke `com_jurnal`. |
| 2 | **Process Handler Nota Revert (`_processSelectNotaRevert`)** | Handler khusus yang mengecek keterikatan transaksi turunan (misal: faktur penjualan yang sudah dilunasi tidak bisa dibatalkan sebelum pembayaran dibatalkan). |
| 3 | **Dual-Write Stock Locker Reversal** | Menggunakan `ComLockerStockDualWrite::pair()` untuk mengembalikan stok ke `stock_locker` dan `stock_locker_variant` secara sinkron, dengan aturan sentinel (`variant_id=0` -> `1`). |
| 4 | **Live Edit FollowUp (`_followupLiveEdit.php`)** | Memungkinkan pengubahan atribut transaksi secara live saat transaksi berada di tangan supervisor/approver di halaman FollowUp. |
| 5 | **Registry Cross-Referencing (`transaksi_registry`)** | Penulisan log status khusus untuk menandai transaksi asal sebagai `REVERTED`/`CANCELED` secara permanen sehingga tidak dapat dibatalkan dua kali. |
| 6 | **Multi-Variant Unique Key Indexing in `ViewDetails`** | Penanganan khusus key indexing `{produk_id}_{variant_id}` agar tampilan rincian barang tidak tumpang tindih untuk produk yang memiliki varian berbeda dalam 1 nota. |

---

## 4. ARSITEKTUR KODE BARU (THE BLUEPRINT)

### 4.1 Struktur Controller & Service Layer Baru

Untuk menjaga *Clean Architecture* dan kemudahan maintenance, Controller baru modul `pembatalan` dibagi secara modular:

```
application/modules/pembatalan/
├── config/
│   ├── coTransaksiCore.php
│   ├── coTransaksiUi.php
│   ├── coTransaksiLayout.php
│   └── coTransaksiValues.php
├── controllers/
│   ├── Modul_Controller.php       # Base controller (session & config loader)
│   ├── Create.php                 # Step 1 & Step 2 Entry Pembatalan
│   ├── FollowUp.php               # Approval & Execution Reversal
│   ├── Transaksi.php              # Grid List & Status Validation
│   ├── ActivityReport.php         # Laporan Aktivitas Pembatalan
│   ├── History.php                # Riwayat Transaksi
│   ├── Printing.php               # Cetak Nota Bukti Pembatalan
│   ├── ViewDetails.php            # Modal Detail Transaksi (Multi-Variant Safe)
│   ├── _shoppingCart.php          # Cart Session Manager & Locker Release
│   ├── _processSelectNotaRevert.php # Selector & Validator Nota Asal
│   └── _processSelectProduct.php   # Partial Product Selector (Dual-Write Stock)
└── views/
    ├── transaksi_modul.php        # UI Shell
    ├── shoppingCart.php           # Table Cart Render
    ├── transaksi.php              # Datatable List
    ├── activityReports.php        # Laporan View
    └── printing.php               # Print Template
```

---

### 4.2 Payload Data & State Management (JSON / AJAX API)

#### A. State Cart Session (`_TR_9911` / `_TR_9912`)
```json
{
  "header": {
    "nomer": "TR-BATAL-202607-0001",
    "referenceNomer": "FJ-202607-0089",
    "transaksi_id_asal": "60d5ec...",
    "dtime": "2026-07-29 11:45:00",
    "oleh_id": 12,
    "cabang_id": 1,
    "alasan_batal": "Kesalahan input barang oleh kasir"
  },
  "items": [
    {
      "cart_key": "prod_105_variant_2",
      "produk_id": 105,
      "variant_id": 2,
      "variant_nama": "Ukuran L - Merah",
      "nama": "Lemari Besi High Safety",
      "satuan": "Unit",
      "jumlah": 1.0,
      "harga": 5000000.0,
      "subtotal": 5000000.0
    }
  ],
  "values": {
    "total_reversal_nilai": 5000000.0,
    "total_reversal_stok": 1.0
  }
}
```

#### B. AJAX Datatable Response (`Transaksi.php` / `History.php`)
```json
{
  "draw": 1,
  "recordsTotal": 45,
  "recordsFiltered": 45,
  "data": [
    {
      "id": "60d5ec...",
      "nomer": "TR-BATAL-202607-0001",
      "referenceNomer": "FJ-202607-0089",
      "dtime": "2026-07-29",
      "oleh_nama": "Budi Admin",
      "transaksi_nilai": "Rp 5.000.000",
      "status_next": "completed",
      "action_tools": "<a class='btn btn-sm btn-info'>Detail</a>"
    }
  ]
}
```

---

### 4.3 Panduan Langkah-demi-Langkah Developer (Step-by-Step Implementation Guide)

Agent developer yang mengeksekusi refactoring wajib mengikuti alur berikut agar **TIDAK ADA FITUR LAMA YANG HILANG**:

1. **Langkah 1: Verifikasi Integrasi Config (`coTransaksiCore.php`)**
   - Pastikan seluruh `jenisTr` (`9911`, `9912`, `9749`) terdaftar lengkap dengan gateway component (`ComTransaksi_jurnal_revert`, `ComLockerStockDualWrite`).

2. **Langkah 2: Terapkan Dual-Write Stock Locker di `_shoppingCart.php` & `_processSelectProduct.php`**
   - Wajib memanggil `ComLockerStockDualWrite::pair()` untuk setiap perubahan state locker stok (`hold` -> `active` / `release`).
   - Pastikan aturan sentinel varian berlaku: jika `variant_id == 0`, konversikan menjadi `1` sebelum menulis ke `stock_locker_variant`.

3. **Langkah 3: Perbaikan Multi-Variant Indexing di `ViewDetails.php`**
   - Pastikan pengaksesan item nota menggunakan key paduan `produk_id` dan `variant_id` (contoh: `$itemKey = $row['produk_id'] . '_' . $row['variant_id'];`) untuk menghindari tabrakan key pada item barang sejenis dengan beda varian.

4. **Langkah 4: Validasi Integritas Jurnal Pembalik di `FollowUp.php`**
   - Saat metode `doFollowup()` dieksekusi, pastikan `ComTransaksi_jurnal_revert::pair()` dipanggil di dalam transaksi database (`$this->db->trans_start()` ... `$this->db->trans_complete()`).
   - Verifikasi bahwa `transaksi_registry` pada nota asal diperbarui secara atomik.

5. **Langkah 5: Pengujian Syntax PHP 5.6 & UAT Checklist**
   - Jalankan perintah CLI `C:\xampp\php\php.exe -l [path_file]` pada setiap controller/view yang dimodifikasi untuk memastikan tidak ada kesalahan sintaks PHP 5.6.
   - Update file `docs/uat-checklist.md` menandai item pekerjaan yang telah diselesaikan.

---

### 5. KESIMPULAN & STATUS EKSEKUSI

- 🟢 **Pekerjaan Selesai (Completed & Verified)**:
  1. Analisis Reverse Engineering penuh pada modul `pembatalan` (Controller, Config, View, Schema DB).
  2. Pemetaan alur transaksi reversal, jurnal pembalik `ComTransaksi_jurnal_revert`, dan `ComLockerStockDualWrite`.
  3. Pembuatan dokumen Blueprint `blueprint_pembatalan.md` sesuai dengan struktur 4 poin wajib.
  4. Penyimpanan dokumen Blueprint di direktori utama project dan direktori dokumen modul.

- 🔍 **Status Verifikasi Sintaks / Modul**:
  - `blueprint_pembatalan.md` telah berhasil dibuat dan diverifikasi di:
    - [blueprint_pembatalan.md](file:///c:/xampp/htdocs/new_san_variant/blueprint_pembatalan.md)
    - [blueprint_pembatalan.md (Modul Docs)](file:///c:/xampp/htdocs/new_san_variant/application/modules/pembatalan/docs/blueprint_pembatalan.md)

---
*Dokumen Blueprint ini dibuat secara otomatis oleh Agent 7 untuk memandu proses refactoring modul Pembatalan di workspace `new_san_variant`.*
