# 📜 TRANSKRIP KONTEKS & CETAK BIRU ARSITEKTUR MIGRASI PENJUALAN
## Migrasi Tahap 2: Modul Penjualan CI3 (everest_refaktor) ➔ Laravel 13 DDD (everest_re)
**Waktu Penyusunan:** 8 September 2026  
**Status Dokumen:** SELESAI & DISEPAKATI (Siap Dilanjutkan Kapan Saja)  
**Tujuan Dokumen:** Membekukan seluruh hasil diskusi arsitektur, keputusan teknis, dan rancangan implementasi agar saat sesi berikutnya dibuka, agent/developer dapat langsung melanjutkan eksekusi tanpa kehilangan konteks sedikit pun.

---

## 1. 🧭 KOMPAS EVOLUSI SISTEM (THE ARCHITECTURAL PATH)

Garis besar perjalanan transformasi sistem telah disepakati bersama:

```
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ TAHAP 0: Controller-Centrik (Legacy As-Is CI3)                                          │
│ Mega-controllers (4.500 - 22.000 baris), $_SESSION sprawl acak, transport DOM iframe    │
└───────────────────────────────────────────┬─────────────────────────────────────────────┘
                                            │
                                            ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ TAHAP 1: Service & Pipeline di CI3 (SELESAI 100%)                                       │
│ Thin Controller, DTO eksplisit, Centralized Engines (Com*), Pipeline Engine,            │
│ Silsilah data (id_top, ids_prev, inv), AST balance = 0, Paritas 100% z:\everest_29agus │
└───────────────────────────────────────────┬─────────────────────────────────────────────┘
                                            │
                                            ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ TAHAP 2: Migrasikan ke Laravel 13 DDD Pragmatis (TOPIK SAAT INI)                         │
│ Memindahkan aturan bisnis murni yang sudah bersih ke dalam ekosistem Laravel modern:    │
│ Aggregate Roots, Native Pipelines, Database Locks, JSONB Snapshots, dan Domain Events   │
└─────────────────────────────────────────────────────────────────────────────────────────┘
```

---

## 2. 🛡️ KESEPAKATAN UTAMA: DEFINISI "DDD PRAGMATIS"

1.  **Anti-Pattern yang Ditolak**:
    *   **DILARANG** melakukan *copy-paste* mentah 50+ model COM dan array konfigurasi 10.724 baris (`coTransaksiCore.php`) ke dalam Laravel. Itu adalah anti-pattern *"Membangun CI3 di dalam tubuh Laravel"*.
2.  **Pola yang Disepakati (DDD Pragmatis)**:
    *   Mengekstrak **100% Aturan Bisnis (*Business Logic Rules*)** CI3 (rumus diskon, PPN Coretax floor, validasi stok, serial number, silsilah `id_top`).
    *   Menuangkannya ke dalam struktur taktis modern Laravel: **Aggregate Roots**, **Domain Services**, **Pipes**, **Form Requests**, dan **Domain Events**.
    *   Memisahkan tanggung jawab modul secara tegas (*Bounded Contexts*): Penjualan tidak boleh menulis langsung ke tabel jurnal GL atau mutasi stok fisik; komunikasi antar-modul wajib melalui Domain Events / Service Contract.

---

## 3. 📋 KEPUTUSAN ARSITEKTURAL DETAIL (HASIL DISKUSI)

### A. Pipeline Pattern: OPSI A (Laravel Native Pipeline `Illuminate\Pipeline`)
*   **Keputusan**: Menggunakan pipeline native bawaan Laravel dengan `SalesOrderContext` DTO.
*   **Alasan Teknis**:
    1.  *Maintainability*: Setiap langkah adalah kelas pipa tunggal (*Single Responsibility Principle*).
    2.  *Kemudahan Debugging*: *Stack trace* langsung menunjuk nomor baris spesifik (misal `ValidateStockPipe.php:42`), navigasi IDE bekerja 100% (`Ctrl + Klik`), MTTR < 5 menit.
    3.  *Kesesuaian Framework*: Idiomatik Laravel 13 & PHP 8.4 (*Strict Typing*, DI Container, *Constructor Property Promotion*).

### B. Numbering Counter Service: Paritas 100% & Database Pessimistic Lock
*   **Keputusan**:
    *   Struktur tabel counter asli (`counters_custom_number`, `counters_custom_content`, `counters_number`) **dipertahankan utuh 100% tanpa mengubah struktur tabel**.
    *   Format data `base64_encode(serialize(...))` dipertahankan agar kompatibel bolak-balik antara CI3 dan Laravel.
    *   Format penomoran nota (misal `stepCode|placeID|customerID|dtime`) menghasilkan format string yang identik dengan CI3.
*   **Penyempurnaan Concurrency**:
    *   Di Laravel, pembacaan baris counter menggunakan `lockForUpdate()` di dalam `DB::transaction()` untuk **melenyapkan risiko Race Condition (Nomor Kembar)** saat lonjakan transaksi multi-kasir.

### C. Pemetaan Alur Multi-Step 5822 ke Entitas Hukum Relasional
Alur multi-step `5822` dipetakan ke 3 entitas terisolasi:
1.  **Step 1 & 2 (`5822spo` & `5822so`)**: Dikelola oleh entitas **`SalesOrder`** (transisi status: `draft` $\rightarrow$ `confirmed`).
2.  **Step 3 & 4 (`5822pkd` & `5822spd`)**: Dikelola oleh entitas **`SalesDelivery`** (Pengiriman fisik / Surat Jalan, memotong stok fisik di gudang).
3.  **Step Faktur**: Dikelola oleh entitas **`SalesInvoice`** (Menimbulkan piutang dagang dan faktur komersial/pajak).

### D. Advance Opsi saat Otorisasi Sebagian (SO Confirmation)
Pada otorisasi Step 2 (`5822so`), jika kuantitas barang hanya disetujui sebagian, sistem menyediakan 2 opsi bagi sisa barang:
1.  **Tutup Sisa (*Close Remaining*)**:
    *   Kuantitas sisa ditandai `qty_closed`, komitmen booking stok dilepas, dan sisa **tidak akan pernah dikirimkan lagi**.
2.  **Outstanding / Backorder**:
    *   Kuantitas sisa ditandai `qty_outstanding`, status pesanan tetap memegang antrean *backorder*, dan otomatis muncul di daftar kebutuhan restock pengadaan untuk dipenuhi saat barang datang.

### E. Gerbang Pembayaran Kasir Sebelum Packing (*Payment Gatekeeper*)
Sebelum pesanan dapat dilanjutkan ke Langkah 3 (`5822pkd` / Prepacking & Packing List), sistem melakukan pengecekan ketat:
*   **Penjualan Tunai (*Cash/COD*)**: Uang **WAJIB SUDAH DITERIMA KASIR** (status pembayaran lunas / kas masuk tervalidasi). Jika belum, proses kemas gudang **terkunci**.
*   **Penjualan Kredit (*Term of Payment*)**: Memvalidasi batas plafon kredit (*credit limit*) dan status piutang jatuh tempo pelanggan.

### F. Trigger Otomatis Faktur Penjualan (PSAK 72 & UU PPN)
*   Transaksi `SalesInvoice` **otomatis ter-trigger saat barang dikeluarkan oleh bagian gudang** (*Goods Issued / Delivery Dispatched*).
*   Memenuhi kepatuhan mutlak: Tanggal Faktur Komersial = Tanggal Pelepasan Kendali Barang = Tanggal Faktur Pajak Coretax.

### G. Integrasi Modul Tax Standby (Coretax DJP)
Setiap `SalesInvoice` yang terbit otomatis mendaftarkan datanya ke modul `Taxes`:
*   **Penjualan Retail B2C / POS**: Standby sebagai **Faktur Pajak Gunggung** (Pedagang Eceran).
*   **Penjualan Grosir B2B**: Standby sebagai **Faktur Pajak Standar Coretax** (Lengkap dengan NPWP/NIK 16 digit, alamat, DPP, dan PPN 11% pembulatan ke bawah/*floor*).

### H. Penanganan Pengiriman Bertahap (*Partial Delivery*)
*   Tabel `sales_order_items` mencatat akumulasi `qty_terkirim`.
*   Jika pesanan 10 unit dan baru dikirim 6 unit, status SO menjadi `partially_shipped`. Sisa 4 unit tetap terbuka untuk Surat Jalan berikutnya.

### I. Snapshot Pembekuan Data Historis (*State Freeze*)
*   Menggunakan kolom native **`JSONB`** di PostgreSQL 16 pada header `sales_orders` dan `sales_invoices`.
*   Membekukan harga satuan, nama produk saat transaksi, dan tarif PPN secara permanen (*Immutable Audit Trail - ISO 27001*).

---

## 4. 🗂️ RANCANGAN STRUKTUR KODE DI LARAVEL (`Y:\everest_re\Modules\Penjualan`)

```
Y:\everest_re\Modules\Penjualan\app\
├── Domain\
│   ├── Contexts\
│   │   ├── SalesOrderContext.php              <-- DTO data input & lifecycle
│   │   └── SalesDeliveryContext.php
│   ├── Models\
│   │   ├── SalesOrder.php                     <-- Aggregate Root SO
│   │   ├── SalesOrderItem.php
│   │   ├── SalesDelivery.php                  <-- Aggregate Root DO / Surat Jalan
│   │   ├── SalesDeliveryItem.php
│   │   ├── SalesInvoice.php                   <-- Aggregate Root Faktur
│   │   └── SalesInvoiceItem.php
│   ├── Pipelines\
│   │   ├── Order\
│   │   │   ├── ValidateCustomerCreditPipe.php
│   │   │   ├── ValidateStockAvailabilityPipe.php
│   │   │   ├── ExtractSerialNumbersPipe.php
│   │   │   ├── CalculatePricingAndTaxPipe.php
│   │   │   ├── GenerateOrderNumberPipe.php    (Atomic Lock Counter)
│   │   │   ├── PersistSalesOrderPipe.php
│   │   │   └── FreezeSnapshotJsonbPipe.php
│   │   └── Delivery\
│   │       ├── VerifyPaymentGatePipe.php      (Kunci Kasir Tunai vs Kredit)
│   │       ├── DeductPhysicalStockPipe.php
│   │       └── PersistDeliveryOrderPipe.php
│   └── Services\
│       ├── PricingEngine.php                  (Diskon bertingkat + PPN 11% Coretax floor)
│       ├── StockEngine.php                    (Stok fisik vs booking vs minus)
│       ├── SerialNumberValidator.php          (Validasi nomor seri barang)
│       ├── NumberingCounterService.php        (Paritas counters_custom_number + lock)
│       ├── SalesOrderService.php              (Orchestrator SO)
│       ├── SalesDeliveryService.php           (Orchestrator Pengiriman)
│       └── SalesInvoiceService.php            (Orchestrator Penagihan & Coretax)
├── Events\
│   ├── SalesOrderConfirmed.php
│   ├── DeliveryDispatched.php                 <-- Trigger Auto Invoice & Tax Standby
│   └── SalesInvoiceIssued.php
└── Listeners\
    ├── AutoGenerateInvoiceListener.php
    └── RegisterTaxStandbyListener.php
```

---

## 5. 🚀 PANDUAN MELANJUTKAN PEKERJAAN (ROADMAP SESI BERIKUTNYA)

Saat sesi dibuka kembali, langsung fokus pada urutan eksekusi **Fase 1**:

1.  **Langkah 1.1**: Buat service domain kalkulasi murni di Laravel:
    *   [PricingEngine.php](file:///Y:/everest_re/Modules/Penjualan/app/Domain/Services/PricingEngine.php)
    *   [StockEngine.php](file:///Y:/everest_re/Modules/Penjualan/app/Domain/Services/StockEngine.php)
    *   [SerialNumberValidator.php](file:///Y:/everest_re/Modules/Penjualan/app/Domain/Services/SerialNumberValidator.php)
2.  **Langkah 1.2**: Buat [NumberingCounterService.php](file:///Y:/everest_re/Modules/Penjualan/app/Domain/Services/NumberingCounterService.php) dengan pembacaan tabel `counters_custom_number` menggunakan `lockForUpdate()`.
3.  **Langkah 1.3**: Buat migrasi penyesuaian kolom di PostgreSQL 16 (kolom `snapshot_payload` JSONB, kolom kuantitas otorisasi: `qty_approved`, `qty_outstanding`, `qty_closed`, `sisa_action`).
4.  **Langkah 1.4**: Susun rangkaian pipa (*Pipes*) dan sambungkan ke `SalesOrderService::createOrder()`.
5.  **Langkah 1.5**: Jalankan Unit Test kalkulasi finansial 0 selisih (`PricingEngineTest`).

---
*Dokumen ini disusun dan diverifikasi oleh Senior Enterprise Architect & Lead Financial Auditor untuk menjamin kesempurnaan migrasi Everest ERP ke Laravel.*
