# Arsitektur & Spesifikasi Pipeline Transaksi Follow-Up Sales Order (CI3 Edition)

> **Dokumen Teknis Enterprise ERP**  
> **Modul**: Penjualan / Sales Order (`5822`)  
> **Standar Kepatuhan**: ISO 9001 (Mutu), ISO 27001 (Audit Trail), PSAK/IFRS, ACID DB Transactions  
> **Status Refaktor**: 100% Faithful Baseline Execution (`executeFollowupAsIs` Alignment)

---

## 1. Ringkasan Eksekutif

Dokumen ini menjelaskan rancangan arsitektur, siklus hidup data (*data lifecycle*), dan pipeline eksekusi transaksi **Follow-Up (Step 1 SPO $\rightarrow$ Step 2 SO / Approval)** pada modul penjualan framework CodeIgniter 3. 

Refaktorisasi memisahkan tanggung jawab dari monolitik legacy controller menjadi dua domain service terstruktur:
1. **`ComSalesOrderFollowupService`**: Mengorkestrasi aturan bisnis, validasi guard, kalkulasi DPP/PPN, penomoran nota, penulisan entri master, detail item, dan snapshot registri 49-key.
2. **`ComTransactionPipelineEngine`**: Mesin modular yang mengeksekusi sub/main GL components (Jurnal Buku Besar), alokasi payment sources (multi-valas, kas/bank, pajak PPh/PPN, uang muka), dan post-processors (LockerStock & mutasi stok).

---

## 2. Diagram Alur Transaksi End-to-End (Mermaid Diagram)

```mermaid
flowchart TD
    %% Layer 1: Presentation & Ingestion
    subgraph L1["1. CONTROLLER LAYER (FollowUp.php)"]
        A["HTTP Request / URL:<br>/penjualan/FollowUp/doFollowup/{jenisTr}/{refId}/{targetStep}/{currStep}"] --> B["Mengekstrak State Session & Konfigurasi Modul<br>(coTransaksiUi, coTransaksiCore, coTransaksiLayout)"]
        B --> C["Memanggil Domain Service:<br><b>ComSalesOrderFollowupService::processSalesOrderFollowup()</b>"]
    end

    %% Layer 2: Pre-Persistence & Calculations
    subgraph L2["2. INGESTION & KALKULASI DATA (Pre-DB Write)"]
        C --> D["<b>Step 1-2: Security Guards & Hydration</b><br>- Cek Maintenance & State Locker (state='hold')<br>- Hydrate Data Referensi Induk ($refId)"]
        D --> E["<b>Step 3-4: Pricing & DPP Pembulatan</b><br>- Rekonsiliasi DPP, PPN & Grand Total<br>- Injeksi Replacer {total_dpp}, {total_ppn}"]
        E --> F["<b>Step 5: Pre-Processors</b><br>- Eksekusi preProcessor (he_value_builder)"]
        F --> G["<b>Step 6-7: Dynamic Counter & Replacers</b><br>- CustomCounter('transaksi') -> Nomor Nota (5822so.1.16.2)<br>- build_global_counter() -> Global Counter (5822so.20260817.1.16.2.22486)<br>- Terapkan array group masterReplacers & addValues via foreach<br>- Hitung unpaidList (tagihan, terbayar, sisa)"]
    end

    %% Layer 3: Persistence Database (ACID START)
    subgraph L3["3. TRANSACTION PERSISTENCE (ACID DB Transaction)"]
        G --> H["<b>Step 8: Write Main Entry (Master Header)</b><br>- INSERT INTO `transaksi`<br>- Menghasilkan: <b>$insertID</b>"]
        H --> I["<b>Step 9: Master Auxiliaries & Signature</b><br>- writeMainEntries_entryPoint ($epID)<br>- INSERT `transaksi_sign` (Audit Otorisasi User)<br>- writeMainValues (grand_total, tagihan, dpp, ppn)<br>- writeMainFields & writeMainElements<br>- ids_his Blob History Tracking per-step<br>- writeDueDate & indexing_main_values blob"]
        I --> J["<b>Step 10: Detail Items & Valid Qty Deduction</b><br>- INSERT `transaksi_data` (Rincian Item)<br>- writeDetailValues ($insertID & $epID)<br>- Pemotongan `valid_qty` pada transaksi referensi sebelumnya<br>- INSERT `items_child` & `items_child_seri`<br>- Update indexing_details & indexing_detail_values"]
    end

    %% Layer 4: Snapshot & Financial Engine
    subgraph L4["4. STATE SNAPSHOT & FINANCIAL PIPELINE"]
        J --> K["<b>Step 11: 49-Key Data Registries Snapshot</b><br>- $tr->writeDataRegistries($insertID, $baseRegistries)<br>- Merekam freeze snapshot 49 key (items, config, layout)"]
        K --> L["<b>Step 12: GL Accounting & Payment Pipeline</b><br>- <b>executeSubComponents</b>: Komponen rincian<br>- <b>executeMainComponents</b>: Posting Jurnal GL Buku Besar<br>- <b>processPaymentSources</b>: multi-valas, pajak (PPh/PPN), kas/bank<br>- <b>uangMuka</b> & <b>MdlTransaksiLaporan</b><br>- <b>executePostProcessors</b>: detail, sub_detail (LockerStock), master"]
    end

    %% Layer 5: External Sync & ACID Complete
    subgraph L5["5. EXTERNAL SYNC & COMMIT"]
        L --> M["<b>Step 13: External Sync & Lockers</b><br>- MdlLockerTransaksi::execLocker()<br>- Validasi CB_ID_PUSAT (cabangValidator)<br>- Replikasi Inter-Branch (connectTo)"]
        M --> N["<b>Step 14: ACID Commit</b><br>- $this->db->trans_complete()<br>- Validasi $this->db->trans_status()"]
        N --> O["Return Standardized Result JSON / Redirection View"]
    end

    classDef controller fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
    classDef calc fill:#fff3e0,stroke:#f57c00,stroke-width:2px;
    classDef db fill:#e8f5e9,stroke:#388e3c,stroke-width:2px;
    classDef finance fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px;
    classDef commit fill:#efebe9,stroke:#5d4037,stroke-width:2px;

    class A,B,C controller;
    class D,E,F,G calc;
    class H,I,J db;
    class K,L finance;
    class M,N,O commit;
```

---

## 3. Matriks Transformasi State Data (*Data State Evolution*)

| Tahap | Parameter Data | Sumber Input | Hasil / State Baru | Tabel Basis Data |
| :--- | :--- | :--- | :--- | :--- |
| **A. Hydration** | `$orderHeader`, `$refData` | Session & DB Ref (`$refId`) | State awal referensi (SPO/Approval) | Memori PHP |
| **B. Countering** | `$tmpNomorNota`, `$tmpNomorNota2` | `CustomCounter` & `formatNota` | `5822so.1.16.2` & `5822so.20260817.1.16.2.22486` | `transaksi_counters` |
| **C. Header Write** | `$tableIn_master` | Payload Master Header | Record Header Transaksi Baru (`$insertID`) | `transaksi` |
| **D. Sign & EntryPoint** | `$epID`, `transaksi_sign` | User Login & Metadata Step | Catatan Audit Otorisasi & Relasi EntryPoint | `transaksi`, `transaksi_sign` |
| **E. Item & Valid Qty** | `$orderItems` | Keranjang Belanja | Detail Item Baru & Pengurangan Kuota Item Lama | `transaksi_data`, `transaksi_data_values` |
| **F. Child Items** | `items_child`, `items_child_seri` | Sub-Item / Paket Racikan | Rincian Komposisi & Serial Number | `transaksi_data_child`, `transaksi_data_child_seri` |
| **G. Registry Freeze** | `$baseRegistries` (49 Key) | 100% Parameter Snapshot | State Snapshot Permanen (Audit/Revert Safe) | `transaksi_registries` |
| **H. GL Journal** | `$jurnalResult` | `masterComponentsConfig` | Double-entry GL (Debit = Kredit) | Jurnal / Ledger GL |
| **I. Payment & Tax** | `$arrPymSrc`, `uangMuka` | `payment_source`, `uang_muka` | Piutang/Utang, Multi-Valas, Faktur Pajak | `payment_source`, `transaksi_uang_muka` |
| **J. Post-Processors** | `LockerStock`, Sub-Detail | `postProcConfig` | Mutasi Stok & Kunci Transaksi | `locker_stock`, `transaksi_laporan` |

---

## 4. Struktur 49-Key Immutable Data Registries Snapshot

Tabel `transaksi_registries` membekukan kondisi utuh keranjang belanja dan layout pada saat transaksi di-approve:

```php
$baseRegistries = array(
    'main'                            => $transactionPayload['main'],
    'items'                           => $transactionPayload['items'],
    'items2'                          => $transactionPayload['items2'],
    'items2_sum'                      => $transactionPayload['items2_sum'],
    'itemSrc'                         => $transactionPayload['itemSrc'],
    'itemSrc_sum'                     => $transactionPayload['itemSrc_sum'],
    'items3'                          => $transactionPayload['items3'],
    'items3_sum'                      => $transactionPayload['items3_sum'],
    'items4'                          => $transactionPayload['items4'],
    'items4_sum'                      => $transactionPayload['items4_sum'],
    'items5_sum'                      => $transactionPayload['items5_sum'],
    'items6_sum'                      => $transactionPayload['items6_sum'],
    'items6'                          => $transactionPayload['items6'],
    'items7'                          => $transactionPayload['items7'],
    'items7_sum'                      => $transactionPayload['items7_sum'],
    'items8_sum'                      => $transactionPayload['items8_sum'],
    'items9_sum'                      => $transactionPayload['items9_sum'],
    'items10_sum'                     => $transactionPayload['items10_sum'],
    'items_noapprove'                 => $transactionPayload['items_noapprove'],
    'rsltItems'                       => $transactionPayload['rsltItems'],
    'rsltItems2'                      => $transactionPayload['rsltItems2'],
    'rsltItems3'                      => $transactionPayload['rsltItems3'],
    'tableIn_master'                  => $transactionPayload['tableIn_master'],
    'tableIn_detail'                  => $transactionPayload['tableIn_detail'],
    'tableIn_detail2_sum'             => $transactionPayload['tableIn_detail2_sum'],
    'tableIn_detail_rsltItems'        => $transactionPayload['tableIn_detail_rsltItems'],
    'tableIn_detail_rsltItems2'       => $transactionPayload['tableIn_detail_rsltItems2'],
    'tableIn_master_values'           => $transactionPayload['tableIn_master_values'],
    'tableIn_detail_values'           => $transactionPayload['tableIn_detail_values'],
    'tableIn_detail_values_rsltItems' => $transactionPayload['tableIn_detail_values_rsltItems'],
    'tableIn_detail_values_rsltItems2'=> $transactionPayload['tableIn_detail_values_rsltItems2'],
    'tableIn_detail_values2_sum'      => $transactionPayload['tableIn_detail_values2_sum'],
    'main_add_values'                 => $transactionPayload['main_add_values'],
    'main_add_fields'                 => $transactionPayload['main_add_fields'],
    'main_elements'                   => $transactionPayload['main_elements'],
    'main_inputs'                     => $transactionPayload['main_inputs'],
    'main_inputs_orig'                => $transactionPayload['main_inputs'],
    'receiptDetailFields'             => $customConfig['configLayout'][$jenisTr]['receiptDetailFields'][$stepNumTarget],
    'receiptSumFields'                => $customConfig['configLayout'][$jenisTr]['receiptSumFields'][$stepNumTarget],
    'receiptDetailFields2'            => $customConfig['configLayout'][$jenisTr]['receiptDetailFields2'][$stepNumTarget],
    'receiptSumFields2'               => $customConfig['configLayout'][$jenisTr]['receiptSumFields2'][$stepNumTarget],
    'receiptDetailSrcFields'          => $customConfig['configLayout'][$jenisTr]['receiptDetailSrcFields'][$stepNumTarget],
    'jurnal_index'                    => $customConfig['configCore'][$jenisTr]['components'][$stepCodeTarget],
    'preProcessor'                    => $customConfig['configCore'][$jenisTr]['preProcessor'][$stepCodeTarget],
    'postProcessor'                   => $customConfig['configCore'][$jenisTr]['postProcessor'][$stepCodeTarget],
    'revert'                          => $transactionPayload['revert'],
    'items_komposisi'                 => $transactionPayload['items_komposisi'],
    'componentsBuilder'               => $transactionPayload['componentsBuilder'],
    'jurnalItems'                     => $transactionPayload['jurnalItems'],
);
```

---

## 5. Standar Kepatuhan Akuntansi & Keamanan Enterprise

1. **ACID Transaction Guarantee**:
   - Seluruh mutasi keuangan dibungkus dalam blok native `$this->db->trans_start()` dan `$this->db->trans_complete()`.
   - Kegagalan di sub-komponen mana pun akan memicu *automatic rollback* menyeluruh untuk mencegah korupsi data.
2. **Immutable Audit Trail (ISO 27001 & ISA)**:
   - Dilarang melakukan `UPDATE` atau `DELETE` pada mutasi buku besar.
   - Perubahan step dicatat secara berurutan (*append-only*) pada `transaksi_sign`, `ids_his`, dan snapshot permanen `transaksi_registries`.
3. **Pemberlakuan Zero Inline Comments**:
   - Seluruh dokumentasi peran agen diisolasi pada blok docstring `/** [AGENT_LOG] ... [/AGENT_LOG] */` sebelum fungsi dimulai.
   - Baris kode logika bersih dari *noise* tracking.
