[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:
- 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.
- Update baris Staging saat naik ke UAT. Ubah "Stage Saat Ini" di header menjadi STAGING.
- Update baris Production saat naik ke Prod. Ubah "Stage Saat Ini" di header menjadi PRODUCTION.
- Update entry di README.md setiap kali status berubah. -->
1. Informasi Tugas & Referensi Bisnis
Task ID / Nomor Referensi:
FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOADSumber 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):
- FEAT-SIMPONI-V3-ISOLATION — Isolasi protokol Simponi V3 dan standardisasi payload multi-satker
- TASK-SET-EXPIRED-BILLING-V3 — Manajemen status dan endpoint pembatalan / kedaluwarsa billing
- REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION — Deduplikasi controller dan orkestrator rekap tagihan
Modul Terkait:
Single BillingService / Repository:
single-billing-BEPIC 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, objekpayloadResponpada fungsi orkestratorprocessRekapTagihanOrchestratorhanya memetakanstatus,trx_id_insw, dan objekkode_billing, meskipun variabelexpiredDatetelah tersedia di dalam alur eksekusi. Perubahan ini menambahkan fieldexpired_date: expiredDatesecara 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: expiredDatepada respons skenario tagihan PNBP murni Simponi V3 - [x] Penambahan atribut
expired_date: expiredDatepada respons skenario BLU tunggal dan multi-satker BLU - [x] Penambahan atribut
expired_date: expiredDatepada respons skenario BUP - [x] Penambahan atribut
expired_date: expiredDatepada respons skenario kombinasi PNBP + BLU - [x] Penambahan atribut
expired_date: expiredDatepada respons skenario kombinasi PNBP + BUP - [x] Penjaminan keseragaman format tanggal kedaluwarsa (
YYYY-MM-DD HH:mm:ss) pada seluruh alur orkestrator rekap tagihan V3
- [x] Penambahan atribut
2. Deployment Lifecycle
| # | Environment | Tanggal & Waktu | PIC | Status | Catatan |
|---|---|---|---|---|---|
| 1 | Development | 2026-09-07 10:38 | Hermansyah Efendi | DEPLOYED | Branch: development |
| 2 | Staging (UAT) | 2026-10-14 13:00 | Hermansyah Efendi / QA | DEPLOYED | Release 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] |
| 3 | Production | 2026-10-14 20:06 | achmad fauzi | DEPLOYED | Branch: 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
| Tanggal | Environment | Perubahan | PIC |
|---|---|---|---|
| 2026-10-14 | Production | Status diupdate ke PRODUCTION (DEPLOYED, CLOSED), rilis Release v1.9.2 via MR !232 | Hermansyah Efendi |
| 2026-09-07 | Development | Inisialisasi draft audit log penambahan expired_date response rekap tagihan V3 (commit 4621366) | Hermansyah Efendi |
3. Analisis Teknis & Rincian Perubahan
Alur Logika & Bisnis:
- Menginjeksi properti
expired_date: expiredDateke dalam variabelpayloadResponpada fungsiprocessRekapTagihanOrchestratordiapp/helpers/tagihan_helper.js. - 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).
- Memastikan caller pada protokol V3 (
/api/v3/terima-rekap-tagihan) tidak lagi menerima nilaiexpired_date: undefinedketika menerima acknowledgement penerbitan billing, sehingga caller service dapat langsung menjalankan sinkronisasi countdown timer pembayaran.
- Menginjeksi properti
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" }
- Deskripsi: Menerima rekap data tagihan terpadu Simponi V3 (multi-satker / multi-K/L) dan mengembalikan kode billing beserta tanggal jatuh tempo kedaluwarsa (
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 ID | Branch | Author | Tanggal & Jam | Ringkasan Perubahan |
|---|---|---|---|---|
4621366 | development | Hermansyah Efendi | 2026-09-07 10:38 | feat(billing): add expired_date to rekap tagihan response payload |
Cuplikan Kode / Query Migration
// 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
// 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}$/);
});
}); 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_datepada response payload ketika penerbitan billing Simponi V3 sukses.
- Cakupan / Surface Pengujian:
API / Postman Only - Kebutuhan Akses / Role Akun: Token Bearer valid (
), Postman CollectionSingle 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)
Skenario 1 — Happy Path: Verifikasi Field
expired_datepada 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-tagihandengan bundle tagihan 7 Satker Hubla. - Ekspektasi Response: HTTP
200 OK, root response wajib memiliki fieldexpired_date(contoh:"2026-09-14 23:59:59"),status: 200,trx_id_insw, dan objekkode_billing. Fieldexpired_datetidak boleh kosong (""),null, atauundefined. - 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_hdrmencatat tanggalexpired_dateyang identik dengan response payload.
- Postman Request:
Skenario 2 — Happy Path: Verifikasi Field
expired_datepada 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-tagihandengan tagihan 1 satker tunggal (Satker287260- Disnav Samarinda). - Ekspektasi Response: HTTP
200 OK, response body mengembalikan atributexpired_dateyang 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_dateterisi dan sesuai pada record billing yang baru terbentuk.
- Postman Request:
Skenario 3 — Happy Path: Verifikasi Field
expired_datepada 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-tagihanmenggabungkan 2 Satker (Disnav Samarinda287260dan KSOP Samarinda287211). - Ekspektasi Response: HTTP
200 OK, root object respons menghasilkan atributexpired_datebersamaan dengankodeBillingIndukdankodeBillingPnbp. - 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_datetersimpan konsisten di database.
- Postman Request:
Bukti Response Verifikasi Staging (Diisi saat UAT)
{
"status": "PASSED",
"note": "Pengujian verifikasi UAT dan validasi integrasi berhasil lolos, rilis production v1.9.2 telah live."
}