Skip to content

[FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD] Penambahan Atribut expired_date pada Response Payload Rekap Tagihan Single Billing V3 ​

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-BILLING-REKAP-EXPIRED-DATE-PAYLOAD

  • Sumber Instruksi: Kebutuhan Sinkronisasi Batas Waktu Pembayaran Billing pada Caller Services

  • Dokumen Referensi / Lampiran: Single Billing V3 - Multi Satker.postman_collection.json

  • Task / Dependensi Terkait (Cross-Service):

  • Modul Terkait: Single Billing

  • Service / Repository: single-billing-BE

  • PIC Pengembang: Hermansyah Efendi

  • Latar Belakang & Ringkasan Kebutuhan: Pada integrasi penerbitan billing antar-layanan (khususnya konsumsi oleh modul SSm Pengangkut), service pemanggil memerlukan kepastian informasi tanggal dan jam kedaluwarsa (expired_date) secara langsung pada response payload agar antarmuka pengguna dapat menampilkan batas akhir pembayaran (payment countdown) serta menyinkronkan status masa berlaku invoice tanpa harus melakukan round-trip query terpisah. Sebelumnya, objek payloadRespon pada fungsi orkestrator processRekapTagihanOrchestrator hanya memetakan status, trx_id_insw, dan objek kode_billing, meskipun variabel expiredDate telah tersedia di dalam alur eksekusi. Perubahan ini menambahkan field expired_date: expiredDate secara konsisten pada seluruh 7 percabangan respons sukses rekap tagihan pada protokol Single Billing V3 (POST /api/v3/terima-rekap-tagihan).

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

    • [x] Penambahan atribut expired_date: expiredDate pada respons skenario tagihan PNBP murni Simponi V3
    • [x] Penambahan atribut expired_date: expiredDate pada respons skenario BLU tunggal dan multi-satker BLU
    • [x] Penambahan atribut expired_date: expiredDate pada respons skenario BUP
    • [x] Penambahan atribut expired_date: expiredDate pada respons skenario kombinasi PNBP + BLU
    • [x] Penambahan atribut expired_date: expiredDate pada respons skenario kombinasi PNBP + BUP
    • [x] Penjaminan keseragaman format tanggal kedaluwarsa (YYYY-MM-DD HH:mm:ss) pada seluruh alur orkestrator rekap tagihan V3

2. Deployment Lifecycle ​

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-09-07 10:38Hermansyah EfendiDEPLOYEDBranch: development
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 penambahan expired_date response rekap tagihan V3 (commit 4621366)Hermansyah Efendi

3. Analisis Teknis & Rincian Perubahan ​

  • Alur Logika & Bisnis:

    1. Menginjeksi properti expired_date: expiredDate ke dalam variabel payloadRespon pada fungsi processRekapTagihanOrchestrator di app/helpers/tagihan_helper.js.
    2. Pengisian mencakup seluruh 7 variasi percabangan sukses pembentukan billing V3 (PNBP murni, BLU murni, BUP murni, kombinasi PNBP+BLU, kombinasi PNBP+BUP, serta varian multi-satker).
    3. Memastikan caller pada protokol V3 (/api/v3/terima-rekap-tagihan) tidak lagi menerima nilai expired_date: undefined ketika menerima acknowledgement penerbitan billing, sehingga caller service dapat langsung menjalankan sinkronisasi countdown timer pembayaran.
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada migration file yang terdeteksi. Perubahan hanya pada layer helper payload respons API.
  • Kontrak API & Response Payload:

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

    • Deskripsi: Menerima rekap data tagihan terpadu Simponi V3 (multi-satker / multi-K/L) dan mengembalikan kode billing beserta tanggal jatuh tempo kedaluwarsa (expired_date).
    • 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-14 23:59:59",                                               // [3] expired_date billing
              "000",                                                               // [4] hardcode "000"
              "00",                                                                // [5] hardcode "00"
              "SB0001",                                                            // [6] hardcode "SB0001"
              "F",                                                                 // [7] jenis_penerimaan ("F" = PNBP)
              "1",                                                                 // [8] mata_uang ("1" = IDR)
              53511808,                                                            // [9] total_nominal_billing
              "PT LAYAR SENTOSA SHIPPING",                                         // [10] nama_wajib_bayar
              "0011358389631000",                                                  // [11] npwp_wajib_bayar
              "Single Billing SSm Pengangkut pada pelabuhan IDJKT - TANJUNG PRIOK" // [12] keterangan_header
            ],
            "detail": [
              [
                "",                               // [0] hardcode empty string
                "1020195BA8E65",                  // [1] no_aju_layanan
                "2026-09-14",                     // [2] expired_date
                "MCABLEIDPGXPT BANGKA JAYA LINE", // [3] nama_wajib_bayar per item
                null,                             // [4] npwp_wajib_bayar
                "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
                "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
                "022",                            // [16] kode_kl ("022" = Kemenhub)
                "04",                             // [17] kode_eselon_1 ("04" = Ditjen Hubla)
                ""                                // [18] keterangan_detail
              ]
            ]
          },
          "information": {
            "billInfo1": "SSm Pengangkut - Kedatangan",
            "billInfo2": "1020195BA8E65",
            "billInfo3": "53511808",
            "billInfo7": "PKK.LN.IDJKT.2411.000002",
            "billInfo8": "SPIL NITA",
            "billInfo9": "IDJKT - TANJUNG PRIOK"
          },
          "jenis_layanan": "8",
          "no_aju_layanan": "1020195BA8E65"
        }
      }
    • Response Payload Sukses (200 OK):
      json
      {
        "status": 200,
        "trx_id_insw": "TRX-123456",
        "expired_date": "2026-09-14 23:59:59",
        "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
4621366developmentHermansyah Efendi2026-09-07 10:38feat(billing): add expired_date to rekap tagihan response payload

Cuplikan Kode / Query Migration ​

javascript
// app/helpers/tagihan_helper.js (processRekapTagihanOrchestrator)
@@ -684,6 +684,7 @@
         payloadRespon = {
           status: status.success,
           trx_id_insw: trxIdInsw,
+          expired_date: expiredDate,
           kode_billing: {
             kodeBillingPnbp: kodeBillingPnbp
           },
@@ -836,6 +837,7 @@
         payloadRespon = {
           status: status.success,
           trx_id_insw: trxIdInsw,
+          expired_date: expiredDate,
           kode_billing: {
             kodeBillingInduk: kodeBillingInduk,
             kodeBillingPnbp: kodeBillingPnbp,

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

A. Verifikasi Unit Test (Development Stage) ​

  • Test Suite File: tests/helpers/tagihan_helper.test.js
  • Status Eksekusi CLI: PASSED
javascript
// tests/helpers/tagihan_helper.test.js
describe('processRekapTagihanOrchestrator - payload verification', () => {
  it('should return expired_date in payloadRespon for valid billing request', async () => {
    // Verifikasi field expired_date mengembalikan format tanggal valid YYYY-MM-DD HH:mm:ss
    const response = await processRekapTagihanOrchestrator(mockReq, mockRes, mockNext, 'v3');
    expect(response).toHaveProperty('expired_date');
    expect(response.expired_date).toMatch(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
  });
});
text
 RUN  v4.1.11 D:/WORK/LNSW/single-billing-BE
 ✓ tests/helpers/tagihan_helper.test.js (13 tests) 24ms
 Test Files  1 passed (1)
      Tests  13 passed (13)
   Start at  12:06:16
   Duration  423ms (transform 119ms, setup 88ms, import 95ms, tests 24ms, environment 0ms)

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

Disesuaikan secara komprehensif berdasarkan Postman Collection: Single Billing V3 - Multi Satker.postman_collection.json.Fokus Pengujian: Memastikan ketersediaan dan keabsahan field expired_date pada response payload ketika penerbitan billing Simponi V3 sukses.

  • Cakupan / Surface Pengujian: API / Postman Only
  • Kebutuhan Akses / Role Akun: Token Bearer valid (), Postman Collection Single Billing V3 - Multi Satker.postman_collection.json
  • Hasil Pengujian UAT: PASSED
  • Catatan QA: Verifikasi response expired_date pada alur rekap tagihan V3 berhasil lolos pengujian UAT.
Skenario Pengujian QA (Test Scenarios) ​
  1. Skenario 1 — Happy Path: Verifikasi Field expired_date pada Response Tagihan Multi-Satker Hubla:

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 1
    • Pre-kondisi: Environment DEV/Staging aktif, Token Bearer valid, payload bundle multi-satker valid.
    • Trigger / Request: POST /api/v3/terima-rekap-tagihan dengan bundle tagihan 7 Satker Hubla.
    • Ekspektasi Response: HTTP 200 OK, root response wajib memiliki field expired_date (contoh: "2026-09-14 23:59:59"), status: 200, trx_id_insw, dan objek kode_billing. Field expired_date tidak boleh kosong (""), null, atau undefined.
    • Postman Test Script Assertion:
      javascript
      pm.test("Status code is 200", function () {
          pm.response.to.have.status(200);
      });
      pm.test("Response contains expired_date on success", function () {
          var jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property('expired_date');
          pm.expect(jsonData.expired_date).to.be.a('string');
          pm.expect(jsonData.expired_date).to.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
      });
    • Verifikasi Database / Log: Tabel billing.subbiller_hdr mencatat tanggal expired_date yang identik dengan response payload.
  2. Skenario 2 — Happy Path: Verifikasi Field expired_date pada Response Tagihan Single Satker V3:

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 2
    • Pre-kondisi: Environment DEV/Staging aktif, Token Bearer valid.
    • Trigger / Request: POST /api/v3/terima-rekap-tagihan dengan tagihan 1 satker tunggal (Satker 287260 - Disnav Samarinda).
    • Ekspektasi Response: HTTP 200 OK, response body mengembalikan atribut expired_date yang valid selaras dengan batas kedaluwarsa billing Simponi.
    • Postman Test Script Assertion:
      javascript
      pm.test("Response contains expired_date on success", function () {
          var jsonData = pm.response.json();
          pm.expect(jsonData.expired_date).to.not.be.oneOf([null, undefined, ""]);
          pm.expect(jsonData.expired_date).to.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
      });
    • Verifikasi Database / Log: Kolom expired_date terisi dan sesuai pada record billing yang baru terbentuk.
  3. Skenario 3 — Happy Path: Verifikasi Field expired_date pada Tagihan Kombinasi Disnav & KSOP:

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 3
    • Pre-kondisi: Environment DEV/Staging aktif, Token Bearer valid.
    • Trigger / Request: POST /api/v3/terima-rekap-tagihan menggabungkan 2 Satker (Disnav Samarinda 287260 dan KSOP Samarinda 287211).
    • Ekspektasi Response: HTTP 200 OK, root object respons menghasilkan atribut expired_date bersamaan dengan kodeBillingInduk dan kodeBillingPnbp.
    • Postman Test Script Assertion:
      javascript
      pm.test("Response contains expired_date on success", function () {
          var jsonData = pm.response.json();
          pm.expect(jsonData.expired_date).to.be.a('string');
          pm.expect(jsonData.expired_date).to.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
      });
    • Verifikasi Database / Log: Nilai expired_date tersimpan konsisten di database.
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