# Dev Jurnal - Upgrade BI Graph Sales to 10-Mode Analytics

## [2026-07-03] Implementasi 10-Mode Sales Analytics & Perbaikan Nilai 0

### Masalah
- Fungsi  iewGraphSales() sebelumnya menampilkan grafik bulanan statis tanpa pilihan mode analisis dan tanpa visualisasi data tabel.
- Data 
ugilaba tahun 2023-2026 menggunakan kode numeric (4010/5010/6010) bukan teks literal, mengakibatkan nilai 0 pada query pencarian nama rekening mentah.

### Solusi & Perubahan
1. **Database View (`vw_bi_sales_monthly`)**: 
   - Membuat/mengupdate view dengan pemetaan query gabungan (`penjualan` -> `rekening IN ('penjualan', '4010')`, `hpp` -> `rekening IN ('hpp', '5010')`, dan `total_biaya` -> `kategori='biaya'`).
   - Menyertakan filter default model `status=1` dan `trash=0`.
   - **Query SQL View:**
     ```sql
     CREATE OR REPLACE VIEW vw_bi_sales_monthly AS
     SELECT
         thn                                                                                         AS `year`,
         bln                                                                                         AS `month`,
         CONCAT(thn, '-', LPAD(bln, 2, '0'))                                                         AS periode,

         -- ========== PENGHASILAN / PENJUALAN ==========
         SUM(CASE WHEN rekening IN ('penjualan', 'penjualan projek', '4010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS penjualan,
         SUM(CASE WHEN rekening = 'return penjualan'        
                  THEN kredit - debet ELSE 0 END)                                                    AS return_penjualan,
         SUM(CASE WHEN rekening = 'jasa kirim'              
                  THEN kredit - debet ELSE 0 END)                                                    AS jasa_kirim,
         SUM(CASE WHEN rekening = 'laba lain lain'          
                  THEN kredit - debet ELSE 0 END)                                                    AS laba_lain_lain,
         SUM(CASE WHEN rekening = 'keutungan kurs'          
                  THEN kredit - debet ELSE 0 END)                                                    AS keuntungan_kurs,

         -- ========== HPP ==========
         SUM(CASE WHEN rekening IN ('hpp', 'hpp projek', '5010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS hpp,

         -- ========== BIAYA OPERASIONAL ==========
         SUM(CASE WHEN (kategori = 'biaya' AND rekening NOT IN ('hpp', 'hpp projek', '5010', 'return penjualan'))
                  THEN kredit - debet ELSE 0 END)                                                    AS total_biaya,

         -- ========== DERIVED: Penjualan Netto ==========
         SUM(CASE WHEN rekening IN ('penjualan', 'penjualan projek', '4010', 'return penjualan', 'jasa kirim') 
                  THEN kredit - debet ELSE 0 END)                                                    AS penjualan_net,

         -- ========== DERIVED: Total HPP ==========
         SUM(CASE WHEN rekening IN ('hpp', 'hpp projek', '5010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS total_hpp

     FROM rugilaba
     WHERE periode  = 'bulanan'
       AND status   = 1
       AND trash    = 0
       AND thn      > 0
       AND bln      > 0
     GROUP BY thn, bln
# Dev Jurnal - Upgrade BI Graph Sales to 10-Mode Analytics

## [2026-07-03] Implementasi 10-Mode Sales Analytics & Perbaikan Nilai 0

### Masalah
- Fungsi  iewGraphSales() sebelumnya menampilkan grafik bulanan statis tanpa pilihan mode analisis dan tanpa visualisasi data tabel.
- Data 
ugilaba tahun 2023-2026 menggunakan kode numeric (4010/5010/6010) bukan teks literal, mengakibatkan nilai 0 pada query pencarian nama rekening mentah.

### Solusi & Perubahan
1. **Database View (`vw_bi_sales_monthly`)**: 
   - Membuat/mengupdate view dengan pemetaan query gabungan (`penjualan` -> `rekening IN ('penjualan', '4010')`, `hpp` -> `rekening IN ('hpp', '5010')`, dan `total_biaya` -> `kategori='biaya'`).
   - Menyertakan filter default model `status=1` dan `trash=0`.
   - **Query SQL View:**
     ```sql
     CREATE OR REPLACE VIEW vw_bi_sales_monthly AS
     SELECT
         thn                                                                                         AS `year`,
         bln                                                                                         AS `month`,
         CONCAT(thn, '-', LPAD(bln, 2, '0'))                                                         AS periode,

         -- ========== PENGHASILAN / PENJUALAN ==========
         SUM(CASE WHEN rekening IN ('penjualan', 'penjualan projek', '4010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS penjualan,
         SUM(CASE WHEN rekening = 'return penjualan'        
                  THEN kredit - debet ELSE 0 END)                                                    AS return_penjualan,
         SUM(CASE WHEN rekening = 'jasa kirim'              
                  THEN kredit - debet ELSE 0 END)                                                    AS jasa_kirim,
         SUM(CASE WHEN rekening = 'laba lain lain'          
                  THEN kredit - debet ELSE 0 END)                                                    AS laba_lain_lain,
         SUM(CASE WHEN rekening = 'keutungan kurs'          
                  THEN kredit - debet ELSE 0 END)                                                    AS keuntungan_kurs,

         -- ========== HPP ==========
         SUM(CASE WHEN rekening IN ('hpp', 'hpp projek', '5010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS hpp,

         -- ========== BIAYA OPERASIONAL ==========
         SUM(CASE WHEN (kategori = 'biaya' AND rekening NOT IN ('hpp', 'hpp projek', '5010', 'return penjualan'))
                  THEN kredit - debet ELSE 0 END)                                                    AS total_biaya,

         -- ========== DERIVED: Penjualan Netto ==========
         SUM(CASE WHEN rekening IN ('penjualan', 'penjualan projek', '4010', 'return penjualan', 'jasa kirim') 
                  THEN kredit - debet ELSE 0 END)                                                    AS penjualan_net,

         -- ========== DERIVED: Total HPP ==========
         SUM(CASE WHEN rekening IN ('hpp', 'hpp projek', '5010') 
                  THEN kredit - debet ELSE 0 END)                                                    AS total_hpp

     FROM rugilaba
     WHERE periode  = 'bulanan'
       AND status   = 1
       AND trash    = 0
       AND thn      > 0
       AND bln      > 0
     GROUP BY thn, bln
     ORDER BY thn ASC, bln ASC;
     ```
2. **Model (`MdlRugilaba.php`)**:
   - Menambahkan method query view getSalesMonthly(), getSalesAllMonthly(), dan getSalesDistinctYears().
3. **Controller (Bi.php)**:
   - Menambahkan navigasi parameter GET ?mode=... dan merutekannya ke 10 metode analisis performa (Monthly, Yearly, YTD, QTD, Rolling 12, MoM, YoY, Margin, dan Running Total).
4. **View ( i_graph_sales.php)**:
   - Menambahkan navigasi tab 10-mode, filter tahun/bulan dinamis, integrasi Highcharts terformat Rupiah, dan integrasi library DataTable dengan tombol cetak & ekspor Excel.

---

## [2026-07-05] Implementasi Laporan Pivot Aktivitas Personil (Agent 7 — Focus: Penjualan)

### Latar Belakang
Blueprint `blue-print-laporan-person.md` dianalisis. Sistem perlu menampilkan keterlibatan setiap personil dalam setiap step transaksi penjualan, bersumber dari field `counters_intext` di tabel `transaksi` yang berformat output `print_r` PHP.

### Masalah Ditemukan & Diperbaiki

#### 1. Bug Regex Double-Count (blueprint asli)
- **Masalah:** Regex original `/\[(.*?)\|olehID\]/s` bersifat greedy dan mencocokkan dari bracket `[` pertama yang berbeda sub-array (`stepCode|placeID` → `stepCode|olehID`), menyebabkan parsing ganda dan double-counting.
- **Solusi:** Regex diubah menjadi `/\[([^\]]+)\|olehID\]/` (non-bracket `[^\]]+`) sehingga hanya mencocokkan key tepat di dalam satu level bracket.
- **Tambahan filter:** ETL hanya memproses block dengan key prefix **tepat** `stepCode` (bukan `stepCode|placeID|olehID`) untuk menghindari duplikasi per dimensi.

#### 2. Bug Stored Procedure YEAR/MONTH/QUARTER Group By
- **Masalah:** SP versi pertama menggunakan `@date_group` sebagai string yang di-CONCAT setelah `SUM(...)`, menyebabkan kolom `tahun` tidak dikenali karena tidak ada di proyeksi SELECT.
- **Solusi:** SP di-refactor agar setiap mode (DAY/MONTH/QUARTER/YEAR) membangun query SELECT sendiri dengan kolom tanggal dideklarasikan langsung di SELECT clause.

#### 3. MariaDB @variable di WHERE Clause
- **Masalah:** `SET @filter_clause = '...'` kemudian digunakan sebagai `WHERE ... AND @filter_clause` — ini tidak berfungsi di MariaDB (variabel user tidak di-evaluate sebagai ekspresi SQL).
- **Solusi:** Menggunakan `@filter_jenis` dengan prefix `AND ` kemudian di-embed via `CONCAT` ke dalam `@q_steps` dan `@sql_main`.

### File yang Dibuat / Dimodifikasi

| File | Aksi | Keterangan |
|------|------|-----------|
| `application/models/Activity_model.php` | **BARU** | ETL parser dengan regex fix + `get_pivot_data()` memanggil SP |
| `application/controllers/eusvc/LaporanApi.php` | **MODIFY** | Tambah endpoint `activity_pivot()` dan `run_etl()` |
| `bi_reports/index.html` | **MODIFY** | Tambah section card "Aktivitas Personil Penjualan" + filter + ETL button |
| `bi_reports/assets/app.js` | **MODIFY** | Tambah `fetchPersonnel()`, `renderPersonnel()` (kolom dinamis), `runEtl()`, event listeners |
| `scratch/setup_activity_db.php` | **BARU** | Script DDL untuk tabel, views, dan SP |

### Database Objects Dibuat di `san_13mar`

| Objek | Tipe | Keterangan |
|-------|------|-----------|
| `dim_person` | TABLE | Dimensi personil (id, nama) |
| `trx_activity_raw` | TABLE | Tabel materialized hasil ETL parsing `counters_intext` |
| `vw_activity_detail` | VIEW | Join `trx_activity_raw` + `dim_person` + mapping modul_label |
| `vw_activity_daily` | VIEW | Agregasi harian per person, step_code, jenis_master |
| `SP_GET_PIVOT_ACTIVITY` | PROCEDURE | Pivot dinamis dengan filter modul & group by DAY/MONTH/QUARTER/YEAR |

### Hasil Verifikasi ETL
- **Total baris diproses:** 95,162 aktivitas dari 96,915 transaksi
- **Jumlah personil:** 73 orang unik
- **Step codes penjualan ditemukan:** `582spo`, `582so`, `582pkd`, `582spd`, `582`, `982`, `982r`, `982g`, `382spo`, `382so`, `382pkd`, `382spd`, `382`, `1582spo`
- **SP Pivot**: Semua 4 mode (DAY, MONTH, QUARTER, YEAR) berfungsi dengan benar ✅

---

## [2026-07-06] Implementasi UI Hybrid (Hover Detail Kontribusi Cabang pada Semua Kolom Tabel & Grafik)

### Latar Belakang
User meluruskan bahwa hover detail yang diinginkan adalah **rincian kontribusi nominal dari masing-masing cabang** untuk setiap metrik keuangan (Net Penjualan, HPP, Efisiensi, Laba Kotor, Total Biaya, Selisih Kurs, Selisih Opname, Jasa Kirim, Lain-Lain Net, Laba Bersih), serta mengembalikan kolom tabel ke struktur aslinya (12 kolom lengkap) agar tidak ada penggabungan.

### Solusi & Perubahan
1. **Restorasi 12 Kolom Tabel**:
   - Mengembalikan kolom tabel ke struktur penuh yang mencakup Selisih Kurs, Selisih Opname, Jasa Kirim, dan Lain-Lain Net secara terpisah.
2. **Kalkulasi Data Multi-Dimensi Cabang**:
   - Memodifikasi method model `getSalesBranchBreakdown()` di `MdlRugilaba.php` agar mengembalikan array asosiatif seluruh metrik keuangan per cabang, per tahun, dan per bulan.
3. **Hover Rincian Cabang untuk Semua Kolom Tabel**:
   - Membuat helper method private `_branchCell()` dan `_cumBranchCell()` di `Bi.php` untuk memformat nilai sel tabel secara otomatis, mencari kontribusi cabang dari data breakdown, mengurutkannya dari yang terbesar, dan menyematkan detailnya ke dalam atribut `title` HTML.
   - P&L multiplier (faktor `-1` untuk HPP dan Total Biaya) disesuaikan agar tanda minus/plus pada hover cabang sinkron dengan nilai yang tampil di kolom tabel.
4. **Hover Rincian Cabang pada Grafik Highcharts**:
   - Data series `Laba Bersih` di grafik dikirimkan beserta array asosiatif kontribusi cabang (`branches`). Formatter Highcharts (`tooltip.formatter`) di view membaca data ini dan me-render rincian sumbangsih cabang di pop-up tooltip grafik.

### File yang Dimodifikasi
- `application/models/Mdls/MdlRugilaba.php` — getSalesBranchBreakdown() ditingkatkan untuk merinci semua kolom P&L per cabang.
- `application/controllers/Bi.php` — Implementasi helper `_branchCell()` & `_cumBranchCell()` serta refactor 10 mode BI Sales untuk memasang hover cabang pada seluruh kolom.
- `application/views/bi_graph_sales.php` — Penyesuaian formatter Highcharts tooltip untuk membaca dan menampilkan array cabang.

---

## [2026-07-07] Perbaikan Bug Double-Counting & Mismatch Data Cabang di `getSalesBranchBreakdown` (Agent 7)

### Masalah
- Terdapat selisih data yang masif hingga **7,6 Miliar Rupiah** pada periode Juni 2026 antara data grafik/tabel utama (`vw_bi_sales_monthly` / `vw_consolidate_monthly`) dengan data rincian kontribusi cabang (`getSalesBranchBreakdown` di `MdlRugilaba.php`).
- **Penyebab Utama:**
  1. Akun biaya operasional (`rekening LIKE '6%'`) ditambahkan secara ganda (*double-counted*) baik di kolom `total_biaya` maupun `lain_lain_netto` karena query `lain_lain_netto` tidak mengecualikan `rekening LIKE '6%'` ketika memfilter `kategori = 'biaya'`.
  2. Akun non-operasional `7020020` (selisih opname) dimasukkan ke `total_biaya` karena bertipe `kategori = 'biaya'`, padahal seharusnya masuk ke metrik `selisih_opname`.
  3. Kolom `penjualan_net` pada breakdown menyertakan `'jasa kirim'`, padahal `'jasa kirim'` sudah dihitung secara terpisah di kolom `jasa_kirim`, mengakibatkan penghitungan ganda.

### Solusi & Perubahan
1. **Penyelarasan Query SQL Breakdown (`MdlRugilaba.php`)**:
   - Memperbarui query SELECT di dalam method `getSalesBranchBreakdown()` agar logic CASE-nya **100% konsisten** dengan views (`vw_bi_sales_monthly`).
   - `total_biaya` dibatasi hanya untuk `rekening LIKE '6%'` (ditambah penanganan `kategori = 'biaya'` untuk kompatibilitas data lama) serta mengecualikan rekening non-operasional.
   - `lain_lain_netto` diubah untuk memfilter rentang rekening `7%`, `8%`, `9%`, atau `3%` dan mengecualikan rekening-rekening yang sudah masuk metrik khusus lainnya.
   - `penjualan_net` dibersihkan dari `'jasa kirim'` karena `'jasa kirim'` sudah memiliki metrik sendiri.

### File yang Dimodifikasi
- `application/models/Mdls/MdlRugilaba.php` — query `getSalesBranchBreakdown()` diselaraskan sepenuhnya dengan views.

### Hasil UAT / Verifikasi
- Perbedaan nilai/selisih antara view utama dan branch breakdown berkurang dari **7,6 Miliar Rupiah** menjadi **tepat 0 (0.00)** untuk semua periode transaksi.

