# 📋 Blueprint & Rancangan Final: Autopurchase FG Project (Modul `master_project`)

Dokumen ini merangkum rancangan arsitektur, skema database, dan alur logika teknis untuk implementasi **Autopurchase Finished Goods (FG) Proyek** berbasis standar ISO 9001:2015 pada framework CodeIgniter 3 (PHP 5.6).

---

## 1. Ringkasan Eksekutif & Prinsip Desain

| Parameter | Keputusan Desain | Rationale |
| :--- | :--- | :--- |
| **Tahap Pemicu (Trigger Stage)** | **Kickoff Project (Step 3: Started Project)** di `FollowUp.php` | Menjamin komposisi RAB sudah 100% terkunci dan terverifikasi (*zero risk of wrong specification*). |
| **Lingkup Barang** | **Hanya Finished Goods (FG)** (`jenis = 'produk'`) | Supplies & biaya dikelola via alur non-autopurchase. |
| **Metode Seleksi Item** | **Opsi 3 (Hybrid Inheritance)** | Default `allow_autopurchase` dari Master Produk $\rightarrow$ diwariskan ke RAB Proyek $\rightarrow$ dapat di-toggle di UI RAB. |
| **Sumber Data Barang** | **Tabel `project_komposisi` (Agregat Total)** | Menghasilkan total kuantitas bersih per barang untuk proyek tanpa duplikasi baris akibat pemecahan fase/work order. |
| **Modul Target Pengadaan** | **`pembelianfgproject` (Trjenis `1466`)** | Dokumen hasil trigger berupa wadah **Purchase Requisition (PR) / Pool Kebutuhan Belanja Project**. |

---

## 2. Diagram Alur Sistem (*End-to-End Workflow*)

```mermaid
sequenceDiagram
    autonumber
    actor Admin as Tim Master Data / PM
    actor PM as Project Manager
    participant MdlProj as master_project (MasterData.php)
    participant FollowUp as master_project (FollowUp.php)
    participant DB as MariaDB / Database
    actor Pur as Tim Purchasing
    participant ModulBeli as pembelianfgproject (1466)

    Admin->>DB: Set master produk FG: allow_autopurchase = 1/0
    PM->>MdlProj: Susun RAB Project (Workorder / Komposisi)
    MdlProj->>DB: Simpan komposisi & sync total ke project_komposisi (inherit allow_autopurchase)
    PM->>FollowUp: Eksekusi "KICKOFF PROJECT" (Step 3: Started Project)
    FollowUp->>DB: 1. Update project_start = 1 & project_start_id
    FollowUp->>DB: 2. Query project_komposisi (jenis='produk' & allow_autopurchase=1)
    FollowUp->>DB: 3. Insert ke project_purchase_pool (Status: WAITING_PO)
    Note over DB: Wadah PR Proyek terbentuk otomatis
    Pur->>ModulBeli: Buka Pembelian FG Project (1466)
    ModulBeli->>DB: Load item dari project_purchase_pool berdasarkan Project ID
    Pur->>ModulBeli: Pilih Supplier + Tentukan Harga + Terbitkan PO (1466)
    ModulBeli->>DB: Update pool status -> CLOSED / IN_PO
```

---

## 3. Perubahan Skema Database (*Database Schema Changes*)

### 3.1 Penambahan Kolom `allow_autopurchase`
Menambahkan kolom penanda pada 3 tabel terkait:

```sql
-- 1. Master Produk (Default setting per FG)
ALTER TABLE `produk` 
ADD COLUMN `allow_autopurchase` TINYINT(1) NOT NULL DEFAULT 0 
COMMENT '0 = Manual Purchase, 1 = Auto Purchase Project';

-- 2. Rekap Komposisi Proyek (Total agregat)
ALTER TABLE `project_komposisi` 
ADD COLUMN `allow_autopurchase` TINYINT(1) NOT NULL DEFAULT 0 
COMMENT 'Flag inheritance dari master produk';

-- 3. Detail Workorder Proyek (Pecahan per fase/sub-fase)
ALTER TABLE `project_komposisi_workoder` 
ADD COLUMN `allow_autopurchase` TINYINT(1) NOT NULL DEFAULT 0;

ALTER TABLE `project_komposisi_workoder_sub` 
ADD COLUMN `allow_autopurchase` TINYINT(1) NOT NULL DEFAULT 0;
```

### 3.2 Tabel Wadah Pool Permintaan Pembelian Proyek (`project_purchase_pool`)
Tabel baru untuk menampung seluruh item FG yang siap diproses oleh tim pembelian:

```sql
CREATE TABLE IF NOT EXISTS `project_purchase_pool` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `project_id` INT(11) NOT NULL COMMENT 'Relasi ke project_produk.id',
  `project_nama` VARCHAR(255) NOT NULL,
  `project_start_id` INT(11) DEFAULT 0 COMMENT 'ID transaksi Kickoff 588st',
  `project_start_nomer` VARCHAR(100) DEFAULT NULL,
  `cabang_id` INT(11) NOT NULL,
  `produk_id` INT(11) NOT NULL COMMENT 'ID barang FG (produk_dasar_id)',
  `produk_kode` VARCHAR(100) DEFAULT NULL,
  `produk_nama` VARCHAR(255) NOT NULL,
  `satuan_nama` VARCHAR(50) DEFAULT NULL,
  `qty_kebutuhan` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 'Qty total dari project_komposisi',
  `qty_po` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 'Qty yang sudah dibuatkan PO',
  `qty_sisa` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 'qty_kebutuhan - qty_po',
  `est_harga_beli` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 'Estimasi HPP/Nilai dari RAB',
  `status` ENUM('OPEN','PARTIAL','CLOSED','CANCELLED') NOT NULL DEFAULT 'OPEN',
  `created_dtime` DATETIME NOT NULL,
  `created_by_id` INT(11) NOT NULL,
  `created_by_nama` VARCHAR(100) NOT NULL,
  `last_updated_dtime` DATETIME DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_project_id` (`project_id`),
  KEY `idx_produk_id` (`produk_id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

---

## 4. Penyesuaian Modul & Kode Program (`master_project`)

### 4.1 Registrasi Field pada Model (`Mdls`)
1. **`application/models/Mdls/MdlProduk.php` & `MdlProduk2.php`**:
   - Daftarkan field `allow_autopurchase` ke dalam array `$fields` (Type: combo/checkbox).
2. **`application/models/Mdls/MdlProjectKomposisi.php`**:
   - Daftarkan field `allow_autopurchase`.
3. **`application/models/Mdls/MdlProjectKomposisiWorkorder.php` & `Sub`**:
   - Daftarkan field `allow_autopurchase`.

### 4.2 Pewarisan Nilai & UI di `MasterData.php`
1. **Fungsi `rebuildMasterKomposisi()` & `rebuildMasterKomposisiSub()`:**
   - Saat item FG dimasukkan ke workorder, sistem mengambil default `allow_autopurchase` dari tabel `produk`.
   - Pastikan field `allow_autopurchase` ikut tersimpan ke dalam `project_komposisi`.
2. **Tampilan RAB / Komposisi Project:**
   - Menampilkan status Autopurchase pada kolom tabel komposisi (Badge: *"Auto Purchase"* / *"Manual"*).

### 4.3 Pemicu Autopurchase saat Kickoff di `FollowUp.php`
Di dalam controller `FollowUp.php` pada `case 3:` (Step 3: `STARTED PROJECT`):

```php
// =========================================================================
// START OF AUTOPURCHASE POOL TRIGGER (KICKOFF PROJECT)
// =========================================================================

// 1. Validasi Idempotency: Pastikan pool belum pernah dibuat untuk project ini
$this->db->where("project_id", $idTargetProject);
$this->db->where("status <>", "CANCELLED");
$existingPoolCount = $this->db->count_all_results("project_purchase_pool");

if ($existingPoolCount == 0) {
    // 2. Query seluruh item FG yang diizinkan autopurchase dari project_komposisi
    $this->db->select("pk.*, pr.kode as produk_kode, pr.nama as produk_nama, pr.satuan as satuan_nama");
    $this->db->from("project_komposisi pk");
    $this->db->join("produk pr", "pk.produk_dasar_id = pr.id", "left");
    $this->db->where("pk.produk_id", $idTargetProject);
    $this->db->where("pk.jenis", "produk");              // Hanya FG
    $this->db->where("pk.allow_autopurchase", 1);        // Hanya yang diizinkan
    $this->db->where("pk.status", "1");
    $this->db->where("pk.trash", "0");
    $itemsAuto = $this->db->get()->result();

    if (!empty($itemsAuto)) {
        $insertBatch = array();
        $dateNow = date("Y-m-d H:i:s");
        $userId = $this->session->login['id'];
        $userNama = isset($this->session->login['nama']) ? $this->session->login['nama'] : $this->session->login['nama_login'];
        $projNama = isset($tempProdukMaster[0]->nama) ? $tempProdukMaster[0]->nama : "-";
        $cabangId = isset($tempProdukMaster[0]->cabang_id) ? $tempProdukMaster[0]->cabang_id : my_cabang_id();

        foreach ($itemsAuto as $rowItem) {
            $qtyKebutuhan = (float)$rowItem->jml;
            if ($qtyKebutuhan > 0) {
                $insertBatch[] = array(
                    "project_id"          => $idTargetProject,
                    "project_nama"        => $projNama,
                    "project_start_id"    => $insertID,
                    "project_start_nomer" => $tmpNomorNota2,
                    "cabang_id"           => $cabangId,
                    "produk_id"           => $rowItem->produk_dasar_id,
                    "produk_kode"         => $rowItem->produk_kode,
                    "produk_nama"         => $rowItem->produk_nama,
                    "satuan_nama"         => $rowItem->satuan_nama,
                    "qty_kebutuhan"       => $qtyKebutuhan,
                    "qty_po"              => 0.00,
                    "qty_sisa"            => $qtyKebutuhan,
                    "est_harga_beli"      => (float)$rowItem->nilai,
                    "status"              => "OPEN",
                    "created_dtime"       => $dateNow,
                    "created_by_id"       => $userId,
                    "created_by_nama"     => $userNama,
                    "last_updated_dtime"  => $dateNow,
                );
            }
        }

        if (!empty($insertBatch)) {
            $this->db->insert_batch("project_purchase_pool", $insertBatch);
        }
    }
}
// =========================================================================
// END OF AUTOPURCHASE POOL TRIGGER
// =========================================================================
```

---

## 5. Rencana Verifikasi & Pengujian (*Verification Plan*)

### 5.1 Skenario Uji Coba:
1. **Verifikasi Master Produk:**
   - Menandai Produk FG 1 dengan `allow_autopurchase = 1`, dan Produk FG 2 dengan `allow_autopurchase = 0`.
2. **Verifikasi Penyusunan RAB (`master_project`):**
   - Memasukkan FG 1, FG 2, Supplies, dan Biaya ke dalam RAB project baru.
   - Menyimpan BOM dan memverifikasi isi tabel `project_komposisi` (memastikan nilai `allow_autopurchase` terwariskan dengan tepat).
3. **Verifikasi Eksekusi Kickoff:**
   - Menjalankan otorisasi Step 3 (*Started Project / Kickoff*).
   - Memeriksa tabel `project_purchase_pool`:
     - ✅ FG 1 berhasil masuk ke pool dengan status `OPEN`.
     - ❌ FG 2 tidak masuk ke pool.
     - ❌ Supplies dan Biaya tidak masuk ke pool.
4. **Verifikasi Idempotency (Anti-Duplikasi):**
   - Merefresh halaman atau membuka kembali step Kickoff; memverifikasi pool data tidak terduplikasi.
