Skip to content

[FEAT-SIMPONI-V3-ISOLATION] Pembaruan Protokol API Simponi Kemenkeu & Isolasi Arsitektur V3 (Dukungan Multi-K/L & Multi-Satker) ​

Modul: Single Billing | Tipe: Feature | Stage Saat Ini: PRODUCTION | Tanggal Dokumen: 2026-09-07

PRODUCTION RELEASED

Dokumen ini telah berada dalam tahap PRODUCTION. Perubahan logika backend, migrasi skema/konfigurasi, dan rilis v1.9.2 telah diterapkan secara penuh di lingkungan Production via MR !232.

LIFECYCLE GUIDE — UPDATE BERTAHAP:

  1. Buat file ini saat selesai development. Isi semua section kecuali Staging & Production.
    • Tanggal Dokumen (Header) & Riwayat Update Log: Gunakan tanggal hari ini (pembuatan dokumen).
    • Baris Development (Lifecycle): Gunakan tanggal & jam commit terakhir terkait di branch development.
  2. Update baris Staging saat naik ke UAT. Ubah "Stage Saat Ini" di header menjadi STAGING.
  3. Update baris Production saat naik ke Prod. Ubah "Stage Saat Ini" di header menjadi PRODUCTION.
  4. Update entry di README.md setiap kali status berubah. -->

1. Informasi Tugas & Referensi Bisnis ​

  • Task ID / Nomor Referensi: FEAT-SIMPONI-V3-ISOLATION

  • Sumber Instruksi: Pembaruan Protokol API Simponi Kemenkeu & Isolasi Arsitektur V3

  • Dokumen Referensi / Lampiran:

  • Task / Dependensi Terkait (Cross-Service): -

  • Modul Terkait: Single Billing

  • Service / Repository: single-billing-BE

  • PIC Pengembang: Hermansyah Efendi

  • Latar Belakang & Ringkasan Kebutuhan: Pembaruan protokol API Simponi V3 Kemenkeu memperkenalkan kapabilitas krusial berupa dukungan Multi-K/L (Kemenhub & Kemenkes) serta Multi-Satker (Kantor Kesyahbandaran dan Otoritas Pelabuhan / KSOP serta Distrik Navigasi / Disnav) dalam satu transaksi bundle single billing terpadu. Pada implementasi Simponi V1/V2 sebelumnya, satu request penerbitan billing dibatasi hanya untuk 1 Satker tunggal. Protokol Simponi V3 mewajibkan format payload terstruktur simponi_req dengan detail 19 elemen (mencakup atribut kode_kl, kode_unit_riil, dan keterangan_detail), header 13 elemen, serta metadata agregasi information (billInfo 1-9) dan mekanisme respons JSON langsung. Hal ini memungkinkan tagihan PNBP dari satker Ditjen Hubla (Disnav Palembang, KSOP Pangkal Balam, KSOP Banjarmasin, KSOP Tanjung Emas, KSOP Teluk Palu, Disnav Ujung Pandang) dan satker Kemenkes (Balai Kekarantinaan Kesehatan / BKK) dikonsolidasikan dalam satu siklus billing code. Agar arsitektur baru ini tidak merusak (breaking change) alur Simponi V1/V2 eksisting yang sedang aktif beroperasi, integrasi Simponi V3 diisolasi secara modular pada rute /api/v3. Seluruh pengujian QA playbook dirancang untuk melakukan hit langsung ke gateway Simponi Kemenkeu (Live Gateway Sandbox, tanpa mock) guna memastikan validitas transaksi secara end-to-end sebelum rilis.

  • Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):

    • [x] Pembuatan modul routing /api/v3 di app/routes/v3/index.js dan mounting prefix di server.js (isolasi arsitektur)
    • [x] Penambahan skema validasi Joi schemasSimponiV3 untuk payload detail 19 elemen, header 13 elemen, dan validasi format multi-satker / multi-K/L
    • [x] Pembuatan controller rekapTagihanINSW_V3 dan request_billing_V3 berkemampuan agregasi invoice variasi Multi-Satker (KSOP & Disnav) serta Multi-K/L
    • [x] Penambahan fungsi helper komunikasi sendSingleBillingV3 dan sendInquiryBillingV3
    • [x] Implementasi mock handler handleSimponiMock hanya sebagai fallback lokal unit test DEV (dinonaktifkan pada eksekusi QA)
    • [x] Ekstraksi konstanta Simponi (SIMPONI_REQUEST_BILLING_METHOD, SIMPONI_KODE_SATKER, SIMPONI_KODE_KL, SIMPONI_KODE_ESELON_1)

2. Deployment Lifecycle ​

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-07-15 11:21Hermansyah EfendiDEPLOYEDBranch: development (Merged from feat/simponi-v3)
2Staging (UAT)2026-10-14 13:00Hermansyah Efendi / QADEPLOYEDRelease Candidate via MR Staging !229. Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]
3Production2026-10-14 20:06achmad fauziDEPLOYEDBranch: prod via MR !232 (Release v1.9.2). Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]

Riwayat Update Log ​

TanggalEnvironmentPerubahanPIC
2026-10-14ProductionStatus diupdate ke PRODUCTION (DEPLOYED, CLOSED), rilis Release v1.9.2 via MR !232Hermansyah Efendi
2026-09-07DevelopmentInisialisasi draft audit log dari context block backend (commit 086cd2a)Hermansyah Efendi
2026-09-07DevelopmentPembaruan dokumentasi kapabilitas Multi-Satker Hubla (KSOP & Disnav), pembersihan asosiasi entitas Wajib Bayar, dan penyelarasan QA Playbook berbasis Postman CollectionHermansyah Efendi
2026-09-07DevelopmentStandardisasi payload riil simponi_req (header 13 elemen, detail 19 elemen multi-K/L, metadata information) dan penegasan pengujian QA wajib Live Hit ke Gateway Simponi (tanpa mock)Hermansyah Efendi

3. Analisis Teknis & Rincian Perubahan ​

  • Alur Logika & Bisnis:

    • Dukungan Multi-K/L & Multi-Satker: Single Billing V3 menerima bundle tagihan yang terdiri dari multi invoice lintas K/L (Kemenhub 022 dan Kemenkes 024) serta lintas Satker (Disnav Palembang 413293, KSOP Pangkal Balam 413262, KSOP Kelas I Banjarmasin 287171, KSOP Kelas I Tanjung Emas 412823, KSOP Kelas III Teluk Palu 287370, Disnav Ujung Pandang 287473, BKK Kemenkes 416108).
    • Struktur Payload Fisik Simponi V3 (simponi_req):
      • header (13 elemen): no_aju_layanan, dua hardcoded empty string "", expired_date, hardcoded "000", "00", "SB0001", jenis penerimaan "F" (PNBP), mata uang "1" (IDR), total_nominal, nama_wajib_bayar, npwp_wajib_bayar, dan keterangan_header.
      • detail (19 elemen per baris): hardcoded "", no_aju_layanan, expired_date, nama_wajib_bayar, npwp, kode_tarif_simponi, kode_pp_simponi, kode_akun, nominal_tarif_pnbp, volume, satuan_tarif, total_tarif_per_record, kode_lokasi, kode_kabkota, kode_satker_riil, fl_blu, kode_kl, kode_eselon_1, dan keterangan_detail.
      • information (billInfo 1–9): Metadata agregasi layanan (misal SSm Pengangkut Kedatangan vs Keberangkatan, nomor aju, nominal parsial, nomor PKK, nama kapal, dan pelabuhan).
    • Penegasan Pengujian QA (No Mock): Pada proses validasi QA dan UAT, pengetesan wajib melakukan koneksi langsung (live hit) ke Gateway Sandbox Simponi Kemenkeu untuk memvalidasi respons otentik dari sistem Simponi (termasuk verifikasi format satker, akun PNBP, dan penomoran billing 820xxxxxxx). Mock handler hanya difungsikan untuk isolasi unit test pada level internal development.
    • Penambahan Environment Gateway Simponi V3: Penambahan variabel lingkungan SIMPONI_BILLING_V3 sebagai URL gateway endpoint Simponi V3 resmi Kemenkeu pada container runtime backend.
    • Penghapusan Environment Variabel (Deprecated / Converted to Constants): Variabel lingkungan SIMPONI_BILLING_METHOD, SIMPONI_BILLING_METHOD_V2, dan SIMPONI_BILLING_METHOD_V3 telah dihapus (deprecated/removed) dari file environment dan digantikan sepenuhnya oleh konstanta internal SIMPONI_REQUEST_BILLING_METHOD (v1: 'single_billing', v2: 'single_billing_v2', v3: 'single_billing_v3') di app/helpers/simponi.js karena metode pemanggilan Simponi bersifat deterministik.
    • Isolasi Modular Rute: Rute V3 dipisahkan secara eksklusif pada app/routes/v3/index.js dan dimounting pada prefix /api/v3 di server.js guna menjamin zero-regression terhadap endpoint Simponi V1/V2 eksisting.
    • Daftar File yang Berubah:
      • app/routes/v3/index.js (API Route — isolasi rute v3)
      • app/controllers/tagihan_controller.js (Controller — handler rekap tagihan V3)
      • app/controllers/billing_controller.js (Controller — handler request billing V3)
      • app/models/tagihan_models.js (Validation / Schema — schema Joi V3 19 elemen & validasi multi-satker)
      • app/models/billing_models.js (Model / Query — query getDataDetailV3)
      • app/helpers/simponi.js (Helper / External Integration — client API Simponi V3 & mock handler)
      • server.js (Bootstrap — registrasi prefix /api/v3)
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada migration file yang terdeteksi — penambahan logic routing dan integrasi API.
  • Kontrak API & Response Payload:

    POST /api/v3/terima-rekap-tagihan ​

    • Deskripsi: Menerima rekap tagihan terpadu (mendukung Multi-K/L Kemenhub & Kemenkes serta Multi-Satker Hubla) dan meneruskannya ke Simponi V3, Inaportnet, dan Sinkarkes.
    • Autentikasi / Guard: Bearer Token (doIntrospection), validateSchemaSimponi(schemasSimponiV3.body)
    • Request Header / Content-Type:
      • Authorization: Bearer <token>
      • Content-Type: application/json
    • Request Body (Struktur Riil Simponi V3):
      jsonc
      {
        "simponi_req": {
          "method": "single_billing",
          "data": {
            "header": [
              "1020195BA8E65",                                                     // [0] no_aju_layanan
              "",                                                                  // [1] hardcode empty string
              "",                                                                  // [2] hardcode empty string
              "2026-09-11 23:59:59",                                               // [3] expired_date billing
              "000",                                                               // [4] hardcode "000" (spesifikasi Simponi V3)
              "00",                                                                // [5] hardcode "00" (spesifikasi Simponi V3)
              "SB0001",                                                            // [6] hardcode "SB0001" (kode prefix Single Billing)
              "F",                                                                 // [7] jenis_penerimaan ("F" = PNBP)
              "1",                                                                 // [8] mata_uang ("1" = IDR)
              53511808,                                                            // [9] total_nominal_billing (akumulasi detail)
              "PT LAYAR SENTOSA SHIPPING",                                         // [10] nama_wajib_bayar
              "0011358389631000",                                                  // [11] npwp_wajib_bayar (16 digit)
              "Single Billing SSm Pengangkut pada pelabuhan IDJKT - TANJUNG PRIOK" // [12] keterangan_header
            ],
            "detail": [
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan
                "2026-09-04",                     // [2] expired_date
                "MCABLEIDPGXPT BANGKA JAYA LINE", // [3] nama_wajib_bayar per item
                null,                             // [4] npwp_wajib_bayar (null jika tidak ada)
                "000899",                         // [5] kode_tarif_simponi
                "201615C",                        // [6] kode_pp_simponi
                "425517",                         // [7] kode_akun (PNBP Kenavigasian)
                0.6,                              // [8] nominal_tarif_pnbp
                12,                               // [9] volume / kuantitas
                "Per Kata",                       // [10] satuan_tarif
                51062,                            // [11] total_tarif_per_record
                "11",                             // [12] kode_lokasi
                "51",                             // [13] kode_kabkota
                "413293",                         // [14] kode_satker_riil (Disnav Palembang)
                "0",                              // [15] fl_blu (Flag BLU: "0" = Non-BLU)
                "022",                            // [16] kode_kl ("022" = Kemenhub)
                "04",                             // [17] kode_eselon_1 ("04" = Ditjen Hubla)
                ""                                // [18] keterangan_detail
              ],
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan
                "2026-09-04",                     // [2] expired_date
                "MCABLEIDPGXPT BANGKA JAYA LINE", // [3] nama_wajib_bayar
                null,                             // [4] npwp
                "000900",                         // [5] kode_tarif_simponi
                "201615C",                        // [6] kode_pp_simponi
                "425517",                         // [7] kode_akun
                0.15,                             // [8] nominal_tarif_pnbp
                12,                               // [9] volume
                "Per Kata",                       // [10] satuan_tarif
                12766,                            // [11] total_tarif_per_record
                "11",                             // [12] kode_lokasi
                "51",                             // [13] kode_kabkota
                "413293",                         // [14] kode_satker_riil (Disnav Palembang)
                "0",                              // [15] fl_blu
                "022",                            // [16] kode_kl (Kemenhub)
                "04",                             // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                // [18] keterangan_detail
              ],
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan
                "2026-09-04",                     // [2] expired_date
                "DNPUIDPGXPT BANGKA JAYA LINE",   // [3] nama_wajib_bayar
                null,                             // [4] npwp
                "000878",                         // [5] kode_tarif_simponi
                "201615C",                        // [6] kode_pp_simponi
                "425514",                         // [7] kode_akun (PNBP Kepelabuhanan)
                250,                              // [8] nominal_tarif_pnbp
                1483,                             // [9] volume
                "Per GT per 30 Hari",             // [10] satuan_tarif
                370750,                           // [11] total_tarif_per_record
                "30",                             // [12] kode_lokasi
                "02",                             // [13] kode_kabkota
                "413262",                         // [14] kode_satker_riil (KSOP Pangkal Balam)
                "0",                              // [15] fl_blu
                "022",                            // [16] kode_kl (Kemenhub)
                "04",                             // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                // [18] keterangan_detail
              ],
              [
                "",                                   // [0] hardcode empty string
                "1020195BA8E65",                      // [1] no_aju_layanan
                "2026-09-04",                         // [2] expired_date
                "LNPUIDBDJPT TERA LOGISTIC INDONESIA",// [3] nama_wajib_bayar
                null,                                 // [4] npwp
                "000877",                             // [5] kode_tarif_simponi
                "201615C",                            // [6] kode_pp_simponi
                "425514",                             // [7] kode_akun (PNBP Kepelabuhanan)
                0.034,                                // [8] nominal_tarif_pnbp
                45229,                                // [9] volume
                "Per GT per 30 Hari",                 // [10] satuan_tarif
                27815474,                             // [11] total_tarif_per_record
                "15",                                 // [12] kode_lokasi
                "51",                                 // [13] kode_kabkota
                "287171",                             // [14] kode_satker_riil (KSOP Kelas I Banjarmasin)
                "0",                                  // [15] fl_blu
                "022",                                // [16] kode_kl (Kemenhub)
                "04",                                 // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                    // [18] keterangan_detail
              ],
              [
                "",                                     // [0] hardcode empty string
                "1020195BA8E65",                        // [1] no_aju_layanan
                "2026-09-04",                           // [2] expired_date
                "LabuhPUPT SAMUDERA AGENCIES INDONESIA",// [3] nama_wajib_bayar
                null,                                   // [4] npwp
                "000395",                               // [5] kode_tarif_simponi
                "201615C",                              // [6] kode_pp_simponi
                "425513",                               // [7] kode_akun (PNBP Jasa Labuh)
                1452,                                   // [8] nominal_tarif_pnbp
                16856,                                  // [9] volume
                "Per GT/15 Hari",                       // [10] satuan_tarif
                24474912,                               // [11] total_tarif_per_record
                "03",                                   // [12] kode_lokasi
                "51",                                   // [13] kode_kabkota
                "412823",                               // [14] kode_satker_riil (KSOP Kelas I Tanjung Emas)
                "0",                                    // [15] fl_blu
                "022",                                  // [16] kode_kl (Kemenhub)
                "04",                                   // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                      // [18] keterangan_detail
              ],
              [
                "",                                         // [0] hardcode empty string
                "1020195BA8E65",                            // [1] no_aju_layanan
                "2026-09-04",                               // [2] expired_date
                "LabuhTuksPT PELAYARAN SURYA BINTANG TIMUR",// [3] nama_wajib_bayar
                null,                                       // [4] npwp
                "000447",                                   // [5] kode_tarif_simponi
                "201615C",                                  // [6] kode_pp_simponi
                "425513",                                   // [7] kode_akun (PNBP Jasa Labuh)
                84,                                         // [8] nominal_tarif_pnbp
                141,                                        // [9] volume
                "Per GT/15 Hari",                           // [10] satuan_tarif
                11844,                                      // [11] total_tarif_per_record
                "18",                                       // [12] kode_lokasi
                "02",                                       // [13] kode_kabkota
                "287370",                                   // [14] kode_satker_riil (KSOP Kelas III Teluk Palu)
                "0",                                        // [15] fl_blu
                "022",                                      // [16] kode_kl (Kemenhub)
                "04",                                       // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                          // [18] keterangan_detail
              ],
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan
                "2026-09-04",                     // [2] expired_date
                "VTSPUIDMAKPT MERATUS LINE",      // [3] nama_wajib_bayar
                null,                             // [4] npwp
                "000930",                         // [5] kode_tarif_simponi
                "201615C",                        // [6] kode_pp_simponi
                "425517",                         // [7] kode_akun (PNBP VTS)
                175000,                           // [8] nominal_tarif_pnbp
                1,                                // [9] volume
                "Per Kapal",                      // [10] satuan_tarif
                175000,                           // [11] total_tarif_per_record
                "19",                             // [12] kode_lokasi
                "51",                             // [13] kode_kabkota
                "287473",                         // [14] kode_satker_riil (Disnav Ujung Pandang)
                "0",                              // [15] fl_blu
                "022",                            // [16] kode_kl (Kemenhub)
                "04",                             // [17] kode_eselon_1 (Ditjen Hubla)
                ""                                // [18] keterangan_detail
              ],
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan (Kedatangan)
                "2026-09-04",                     // [2] expired_date
                "SAMUDERA SUKSES MAKMUR",         // [3] nama_wajib_bayar
                null,                             // [4] npwp
                "001744",                         // [5] kode_tarif_simponi
                "2019064",                        // [6] kode_pp_simponi
                "425314",                         // [7] kode_akun (PNBP Karantina Kesehatan)
                300000,                           // [8] nominal_tarif_pnbp
                1,                                // [9] volume
                "Per Pemeriksaan Kapal",          // [10] satuan_tarif
                300000,                           // [11] total_tarif_per_record
                "01",                             // [12] kode_lokasi
                "52",                             // [13] kode_kabkota
                "416108",                         // [14] kode_satker_riil (BKK Kemenkes)
                "0",                              // [15] fl_blu
                "024",                            // [16] kode_kl ("024" = Kemenkes)
                "05",                             // [17] kode_eselon_1 ("05" = Ditjen P2P)
                ""                                // [18] keterangan_detail
              ],
              [
                "",                               // [0] hardcode empty string
                "101018FB7DA54",                  // [1] no_aju_layanan (Keberangkatan)
                "2026-09-04",                     // [2] expired_date
                "SAMUDERA SUKSES MAKMUR",         // [3] nama_wajib_bayar
                null,                             // [4] npwp
                "001744",                         // [5] kode_tarif_simponi
                "2019064",                        // [6] kode_pp_simponi
                "425314",                         // [7] kode_akun (PNBP Karantina Kesehatan)
                300000,                           // [8] nominal_tarif_pnbp
                1,                                // [9] volume
                "Per Pemeriksaan Kapal",          // [10] satuan_tarif
                300000,                           // [11] total_tarif_per_record
                "01",                             // [12] kode_lokasi
                "52",                             // [13] kode_kabkota
                "416108",                         // [14] kode_satker_riil (BKK Kemenkes)
                "0",                              // [15] fl_blu
                "024",                            // [16] kode_kl ("024" = Kemenkes)
                "05",                             // [17] kode_eselon_1 ("05" = Ditjen P2P)
                ""                                // [18] keterangan_detail
              ]
            ]
          },
          "information": {
            "billInfo1": "SSm Pengangkut - Kedatangan",
            "billInfo2": "101018FB7DA54",
            "billInfo3": "300000",
            "billInfo4": "SSm Pengangkut - Keberangkatan",
            "billInfo5": "1020195BA8E65",
            "billInfo6": "53211808",
            "billInfo7": "PKK.LN.IDJKT.2411.000002",
            "billInfo8": "SPIL NITA",
            "billInfo9": "IDJKT - TANJUNG PRIOK"
          },
          "jenis_layanan": "8",
          "no_aju_layanan": "1020195BA8E65"
        }
      }
    Kamus Struktur Data Array Simponi V3: ​
    • Array Header (13 Elemen):

      • [0] no_aju_layanan: Nomor pengajuan dokumen layanan SSm Pengangkut
      • [1] empty_string: Hardcoded ""
      • [2] empty_string: Hardcoded ""
      • [3] expired_date: Batas akhir masa berlaku kode billing (YYYY-MM-DD HH:mm:ss)
      • [4] kode_aplikasi: Hardcoded "000" (spesifikasi teknis Simponi V3)
      • [5] kode_fungsi: Hardcoded "00" (spesifikasi teknis Simponi V3)
      • [6] kode_prefix: Hardcoded "SB0001" (prefix layanan Single Billing)
      • [7] jenis_penerimaan: "F" untuk Penerimaan Negara Bukan Pajak (PNBP)
      • [8] mata_uang: "1" untuk mata uang Rupiah (IDR)
      • [9] total_nominal: Total akumulasi tagihan (wajib sama dengan penjumlahan detail)
      • [10] nama_wajib_bayar: Nama wajib bayar induk / pemohon billing
      • [11] npwp_wajib_bayar: NPWP wajib bayar 16 digit angka
      • [12] keterangan_header: Deskripsi ringkas peruntukan billing layanan
    • Array Detail (19 Elemen per Baris):

      • [0] empty_string: Hardcoded ""
      • [1] no_aju_layanan: Nomor pengajuan transaksi layanan
      • [2] expired_date: Batas akhir tanggal pembayaran rincian tagihan (YYYY-MM-DD)
      • [3] nama_wajib_bayar: Nama wajib bayar sub-item tagihan
      • [4] npwp: NPWP sub-item (opsional / null jika tidak ada)
      • [5] kode_tarif_simponi: 6 digit kode tarif penerimaan Simponi
      • [6] kode_pp_simponi: 7 karakter kode Peraturan Pemerintah penetapan tarif
      • [7] kode_akun: 6 digit kode akun bagan akun standar (BAS) penerimaan
      • [8] nominal_tarif_pnbp: Tarif satuan per unit/volume
      • [9] volume: Kuantitas / volume layanan
      • [10] satuan_tarif: Satuan kuantitas (misal "Per Kata", "Per GT/15 Hari", "Per Kapal")
      • [11] total_tarif_per_record: Total nilai per baris tagihan
      • [12] kode_lokasi: 2 digit kode lokasi provinsi
      • [13] kode_kabkota: 2 digit kode kabupaten/kota
      • [14] kode_satker_riil: 6 digit kode Satker resmi penerima PNBP (UPT Hubla / BKK Kemenkes)
      • [15] fl_blu: Flag status instansi BLU ("0" = Non-BLU, "1" = BLU)
      • [16] kode_kl: 3 digit kode K/L ("022" = Kemenhub, "024" = Kemenkes)
      • [17] kode_eselon_1: 2 digit kode unit eselon I ("04" = Ditjen Hubla, "05" = Ditjen P2P)
      • [18] keterangan_detail: Informasi catatan tambahan spesifik tagihan (string kosong jika tidak ada)
    • Response Payload (200 OK):

      json
      {
        "status": 200,
        "trx_id_insw": "TRX-123456",
        "kode_billing": {
          "kodeBillingInduk": "820260729744850",
          "kodeBillingPnbp": "820260729744851"
        }
      }
    • Response Error (400 Bad Request):

      json
      {
        "status": 400,
        "message": "Validation Failed: Satker must be numeric / Total nominal header does not match detail sum"
      }

4. Bukti Teknis (Technical Proof & Audit Trail) ​

  • Repository: single-billing-BE
  • Branch Utama: development
  • Merge Request / PR: !232 (Release v1.9.2 — Merged to prod) | Staging: !229

Daftar Commit Terkait (Multi-Commit Trail) ​

Commit IDBranchAuthorTanggal & JamRingkasan Perubahan
d8c6e35feat/simponi-v3Hermansyah Efendi2026-05-25 10:12feat(simponi-v3): isolate simponi v3 integration under /api/v3 routes
925037dfeat/simponi-v3Hermansyah Efendi2026-05-25 10:36refactor(simponi): implement reusable mock handler for DEV environment
6acadbfdevelopmentHermansyah Efendi2026-07-14 13:29refactor(simponi): use constants instead of env for billing methods
2200580developmentHermansyah Efendi2026-07-14 13:40refactor(simponi): extract simponi v3 metadata to constants
086cd2adevelopmentHermansyah Efendi2026-07-15 11:21fix(simponi): replace Math.random with crypto.randomInt in mock handler

Cuplikan Kode / Query Migration ​

javascript
// app/helpers/simponi.js
const handleSimponiMock = () => {
  if (process.env.STATUS_APP !== 'DEV') {
    return null;
  }
  const mockMode = process.env.MOCK_MODE;
  if (!mockMode) {
    return null;
  }
  if (mockMode === 'true') {
    return {
      response: {
        code: "00",
        message: "Sukses",
        data: [
          `820${crypto.randomInt(100000000, 1000000000)}`,
          `820${crypto.randomInt(1000000, 10000000)}`,
          moment().format('YYYY-MM-DD HH:mm:ss'),
          moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss')
        ]
      }
    };
  }
  const errors = [
    { code: "IX", message: "Satker Layanan dengan Satker Riil tidak ada keterkaitan." },
    { code: "IN", message: "Nama wajib bayar tidak boleh mengandung karakter khusus seperti !@#$%^&" },
    { code: "IR", message: "Kode Satker Riil tidak valid." },
    { code: "ID", message: "Tanggal tidak valid." },
    { code: "M2", message: "Proses pengiriman data billing ke MPN gagal." },
    { code: "IM", message: "Satker Riil dengan Akun Penerimaan tidak ada keterkaitan." },
    { code: "IS", message: "Kode Satker Layanan tidak valid." }
  ];
  if (mockMode === 'error') {
    const randomError = errors[crypto.randomInt(0, errors.length)];
    return {
      response: {
        code: randomError.code,
        message: randomError.message,
        data: []
      }
    };
  }
  return null;
};

5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification) ​

A. Verifikasi Unit Test (Development Stage) ​

  • Test Suite File: tests/helpers/simponi.test.js
  • Status Eksekusi CLI: PASSED
javascript
describe("mock mode via sendSingleBilling", () => {
  it("ignores MOCK_MODE when STATUS_APP is not DEV", async () => {
    process.env.STATUS_APP = "PROD";
    process.env.MOCK_MODE = "true";
    process.env.SIMPONI_BILLING_V1 = "http://v1";
    axios.mockResolvedValueOnce({ data: '{"response":{"code":"00"}}' });
    const result = await sendSingleBilling("x");
    expect(axios).toHaveBeenCalledTimes(1);
    expect(result).toEqual({ response: { code: "00" } });
  });
});
text
 RUN  v4.1.11 D:/WORK/LNSW/single-billing-BE
 ✓ tests/helpers/simponi.test.js (28 tests) 23ms
 Test Files  1 passed (1)
      Tests  28 passed (28)
   Start at  10:59:53
   Duration  388ms (transform 74ms, setup 78ms, import 83ms, tests 23ms, environment 0ms)

B. Panduan Pengujian QA & Verifikasi Staging (QA Playbook) ​

Disesuaikan secara komprehensif berdasarkan Postman Collection: Single Billing V3 - Multi Satker.postman_collection.json.PRINSIP QA: Live Gateway Simponi (Tanpa Mock). Seluruh eksekusi QA wajib melakukan koneksi langsung ke sandbox Simponi Kemenkeu untuk memastikan sistem eksternal Simponi merespons sukses.

  • Cakupan / Surface Pengujian: API / Postman Only (Direct Single Billing API & Live Gateway Simponi Sandbox)
  • Kebutuhan Akses / Role Akun: Token Bearer valid (), Postman Environment Dev/Staging dengan konfigurasi direct live hit ke endpoint Simponi Kemenkeu (MOCK_MODE=off).
  • Hasil Pengujian UAT: PASSED
  • Catatan QA: Seluruh 10 skenario pengujian QA multi-satker dan isolasi Simponi V3 via Live Gateway Simponi Sandbox berhasil lolos validasi UAT.
Skenario Pengujian QA (Test Scenarios) ​
  1. Skenario 1 — Happy Path: Agregasi Multi-Satker Ekstrem (7 Satker Hubla Lintas Wilayah):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 1
    • Pre-kondisi: Environment DEV/Staging terhubung langsung ke Live Gateway Simponi Sandbox (Mock dinonaktifkan), Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan membawa bundle 7 tagihan dari 7 Satker Hubla (KSOP dan Distrik Navigasi) yang berbeda secara simultan:
      • Satker 413293: Distrik Navigasi (Disnav) Palembang
      • Satker 413262: KSOP Pangkal Balam
      • Satker 287171: KSOP Kelas I Banjarmasin
      • Satker 412823: KSOP Kelas I Tanjung Emas (Semarang)
      • Satker 287370: KSOP Kelas III Teluk Palu
      • Satker 287473: Distrik Navigasi (Disnav) Ujung Pandang (Makassar)
      • Satker 412801: Distrik Navigasi (Disnav) Tanjung Priok
    • Ekspektasi Response: HTTP 200 OK langsung dari Gateway Simponi, response body memuat code: "00" dan mengembalikan kode billing konsolidasi (820xxxxxxx) tanpa terjadi error penolakan relasi antar-satker.
    • Verifikasi Database / Log: Seluruh 7 data tagihan tersimpan dengan asosiasi kode satker riil masing-masing dan status disposisi billing aktif.
  2. Skenario 2 — Happy Path: Baseline Single Satker (1 Satker Tunggal):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 2 & Uji Multisatker - Tagihan Kemenhub 4
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan membawa tagihan yang seluruhnya berasal dari 1 Satker yang sama (misal Satker 287260 [Distrik Navigasi Samarinda / Balikpapan] atau 287211 [KSOP Samarinda]).
    • Ekspektasi Response: HTTP 200 OK, code: "00", membuktikan backward compatibility terhadap alur penerbitan billing single-satker reguler di Gateway Simponi.
  3. Skenario 3 — Happy Path: Agregasi Multi-Satker Moderat (Kombinasi 2 Satker Berbeda):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 3
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan menggabungkan tagihan dari 2 Satker berbeda: Satker 287260 (Disnav Samarinda) dan Satker 287211 (KSOP Samarinda).
    • Ekspektasi Response: HTTP 200 OK, code: "00", kode billing diterbitkan secara sukses untuk kedua entitas satker dari Gateway Simponi.
  4. Skenario 4 — Happy Path: Agregasi Multi-Satker Kompleks (9 Tagihan Lintas 7 Satker Hubla):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 5
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan membawa 9 tagihan yang mencakup variasi Satker Hubla:
      • Satker 413591: KSOP Kuala Tungkal
      • Satker 412879: Distrik Navigasi Semarang
      • Satker 412823: KSOP Kelas I Tanjung Emas (Semarang)
      • Satker 413293: Distrik Navigasi Palembang
      • Satker 413256: KSOP Palembang
      • Satker 287260: Distrik Navigasi Samarinda
      • Satker 287228: KSOP Balikpapan
    • Ekspektasi Response: HTTP 200 OK, code: "00", gateway Simponi berhasil menerima dan memproses seluruh array detail 19 elemen dari 9 tagihan tersebut.
  5. Skenario 5 — Negative Test: Penolakan Nilai Nominal Negatif (Minus):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub (Minus)
    • Pre-kondisi: Payload sengaja dikonfigurasi dengan nominal minus pada total header (-63828) dan baris detail (-0.6, -51062).
    • Trigger / Request: POST /api/pengangkut/tagihan
    • Ekspektasi Response: HTTP 400 Bad Request, validasi Joi memblokir request dan mengembalikan pesan error validasi sebelum request diteruskan ke gateway Simponi.
  6. Skenario 6 — Negative Test: Penolakan Kode Satker Alphanumeric pada Header:

    • Postman Request: Uji Multisatker - Tagihan Kemenhub (Satker Alhpanumeric - Header)
    • Pre-kondisi: Elemen satker pada header berisi karakter alphanumeric (4132X3).
    • Trigger / Request: POST /api/pengangkut/tagihan
    • Ekspektasi Response: HTTP 400 Bad Request, sistem menolak format kode satker yang tidak strictly numeric.
  7. Skenario 7 — Negative Test: Penolakan Karakter Alphanumeric pada Detail:

    • Postman Request: Uji Multisatker - Tagihan Kemenhub (Satker Alhpanumeric - Header Detail)
    • Pre-kondisi: Kode akun penerimaan pada baris detail memuat karakter non-angka (42X517, 425X17).
    • Trigger / Request: POST /api/pengangkut/tagihan
    • Ekspektasi Response: HTTP 400 Bad Request, skema validasi schemasSimponiV3 menggagalkan proses dengan rincian field akun invalid.
  8. Skenario 8 — Negative Test: Integritas Nilai Mismatch (Header vs Detail):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub (Nominal Tidak Sesuai Detail)
    • Pre-kondisi: Header mencatat total nilai 63827, sedangkan hasil penjumlahan matematis detail adalah 63828 (51062 + 12766).
    • Trigger / Request: POST /api/pengangkut/tagihan
    • Ekspektasi Response: HTTP 400 Bad Request, sistem mendeteksi diskrepansi akumulasi dan menolak transaksi demi mencegah ketidaksesuaian pembukuan PNBP Simponi.
  9. Skenario 9 — Integration / Error Handling: Penanganan Penolakan Riil Gateway Simponi:

    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, dikirimkan request dengan relasi satker/akun yang tidak terdaftar di Simponi Kemenkeu.
    • Trigger / Request: POST /api/v3/terima-rekap-tagihan
    • Ekspektasi Response: Gateway Simponi merespons dengan kode penolakan resmi (seperti kode IX [Satker Layanan & Riil tidak terkait], IR [Kode Satker Riil tidak valid], IM [Satker Riil & Akun tidak terkait], IS [Kode Satker Layanan tidak valid]) dan service Single Billing meneruskan respons error terstruktur ke caller tanpa crash.
  10. Skenario 10 — Integration: Pelunasan Pembayaran Billing DJA (activeinquiry_v2):

    • Postman Request: Uji Multisatker - Kirim Payment
    • Pre-kondisi: Kode billing aktif telah terbentuk di sistem Single Billing dan terdaftar di Simponi.
    • Trigger / Request: POST https://dev-backend.insw.go.id/single-billing/dja/activeinquiry_v2 membawa payload pelunasan DJA (termasuk nomor billing 820260729744850 dan NTPN).
    • Ekspektasi Response: HTTP 200 OK, status pembayaran billing berhasil diperbarui menjadi lunas (fl_paid = true).
Bukti Response Verifikasi Staging (Diisi saat UAT) ​
json
{
  "status": "PASSED",
  "note": "Pengujian verifikasi UAT dan validasi integrasi berhasil lolos, rilis production v1.9.2 telah live."
}

Single Source of Truth (SSOT) Arsitektur & Perubahan Teknis Backend