QA manual untuk tagihan langganan HaloRT yang dibayar lewat QRIS dinamis dari merchant GoPay HaloRT, dengan konfirmasi manual oleh operator. Proses rilis: Testing/Testing Mechanism. Alur gateway lama (Duitku / Doit.id): Testing/Duitku SaaS Billing.

Ini hanya untuk invoice SaaS (hrt…). Iuran warga tidak pernah memakai QRIS ini — tetap Doit.id / Duitku / bukti transfer (Features/Iuran Managed HaloRT).

Cara kerja singkat

  1. Pengurus / operator klik Bayar → API membuat invoice pending dengan kode unik yang ditambahkan ke harga paket. Kode diambil dari slot terkecil yang masih kosong — 1–9 dulu, lalu 10–99, lalu 100–999 — jadi biasanya pembayar hanya lebih bayar beberapa rupiah (contoh Rp 99.000 → Rp 99.001).
  2. API menyusun QRIS dinamis dari QR statis merchant (tag 54 = nominal bayar, CRC baru) dan mengarahkan browser ke app.halort.com/bayar/{merchantOrderId}?t=….
  3. Pembayar scan QR dengan e-wallet / m-banking apa pun. Nominal sudah terisi.
  4. Email [HaloRT] QRIS Rp … — {tenant} dikirim ke ops.
  5. Operator mencocokkan mutasi GoPay Merchant dengan nominal tepat di admin.halort.com/transactions → Konfirmasi lunas → langganan diperpanjang, email invoice paid terkirim.

Nominal bayar unik di antara invoice QRIS pending yang belum kedaluwarsa, jadi satu nominal = satu invoice.

Persiapan

  1. halort-platform, halort-platform-web, halort-admin sudah deploy dari main (GitHub Actions → Argo CD). Kolom baru platform_invoices (provider, unique_code, payable_amount, qris_payload, expires_at, confirmed_by_email, confirmation_note) dibuat otomatis saat API start (prisma db push di startup) — tidak perlu db:push manual.
  2. Secret halort-platform-runtime-env berisi PAYMENT_PROVIDER_SAAS=qris, QRIS_STATIC_PAYLOAD, QRIS_TOKEN_SECRET (lihat Ops/Secrets Overview). Isi di halort-infra/.env lalu make sync-platform-secrets.
  3. QRIS_STATIC_PAYLOAD = string mentah hasil decode QR statis GoPay Merchant (diawali 000201, diakhiri 6304 + 4 hex). Jika CRC tidak valid, API log peringatan dan QRIS dianggap belum dikonfigurasi — pembuatan invoice SaaS ditolak sampai payload diperbaiki atau PAYMENT_PROVIDER_SAAS dihapus.
  4. Akses dashboard / app GoPay Merchant untuk melihat mutasi masuk.
  5. Tenant uji: gp2. Catat paket dan jatuh tempo sebelum bayar.

A — Buat invoice

#LangkahExpected
A1Pengurus gp2 → /admin/settings/layanan → pilih Starter, Bulanan → BayarRedirect ke app.halort.com/bayar/hrt…?t=…
A2Operator → Tenant Control → edit gp2 → BayarSama seperti A1
A3Cek email opsSubjek [HaloRT] QRIS Rp 99.xxx — {tenant}, tautan ke halaman transaksi QRIS pending
A4Buat 2 invoice berturut-turut dengan paket & durasi samaNominal bayar berbeda: kode unik 1 lalu 2 (slot terkecil yang kosong)
A5Tandai kedaluwarsa invoice kode 1, lalu buat invoice baru dengan paket samaKode 1 dipakai lagi

B — Halaman checkout (/bayar/…)

#LangkahExpected
B1Buka tautan di desktop dan HPNominal besar, rincian harga paket + kode unik, QR tampil, nama merchant sesuai QR statis
B2Salin nominalNominal tanpa titik tersalin ke clipboard
B3Scan QR dengan GoPay / m-banking (jangan bayar dulu)Nominal terisi otomatis = nominal bayar; nama merchant cocok
B4Ubah / hapus parameter ?t=“Tagihan tidak ditemukan” (404)
B5Biarkan halaman terbukaStatus di-poll tiap ~15 detik; Cek status memuat ulang manual
B6View source / header respons APICache-Control: no-store, X-Robots-Tag: noindex

C — Bayar & konfirmasi (uang sungguhan, nominal kecil)

Gunakan paket termurah; ini transaksi production ke merchant HaloRT.

#LangkahExpected
C1Bayar QR dari B3Mutasi masuk di GoPay Merchant dengan nominal tepat
C2admin.halort.com → Transaksi → chip Menunggu konfirmasi QRISInvoice tampil; kolom Nominal bayar menyorot kode unik
C3Isi Nominal tepat (Rp) dengan nominal mutasiHanya invoice itu yang muncul
C4Konfirmasi lunas → nominal sudah terisi → isi referensi (ID transaksi GoPay) → simpanStatus paid; kolom dikonfirmasi oleh = email operator
C5Cek tenant gp2Jatuh tempo +1 bulan, paket sesuai, status ACTIVE
C6Halaman /bayar/… pembayarBerganti ke layar Lunas; QR tidak ditampilkan lagi
C7Email pengurusInvoice paid, PDF memuat baris Kode Unik QRIS dan total = nominal bayar
C8Ulangi POST …/confirm untuk invoice yang sudah paidDikembalikan apa adanya; tidak menambah bulan dua kali

D — Kasus khusus

SkenarioExpected
Pembayar transfer nominal berbeda (mis. tanpa kode unik)Modal konfirmasi wajib catatan; tetap bisa dikonfirmasi setelah dicocokkan manual
Invoice lewat QRIS_EXPIRY_HOURS (default 24 jam)Status expired; halaman bayar menampilkan “Tagihan ditutup”; tidak ada QR
Uang masuk setelah expiredOperator tetap bisa Konfirmasi lunas (peringatan kedaluwarsa tampil); catatan audit tersimpan
Tandai kedaluwarsa pada invoice pendingStatus expired; nominal bayar bebas dipakai invoice baru
Invoice Doit.id / DuitkuTombol Konfirmasi / Tandai kedaluwarsa tidak muncul; API menolak (400)
Iuran warga (hri…)Tidak pernah memakai QRIS, walau PAYMENT_PROVIDER_SAAS=qris
PAYMENT_PROVIDER_SAAS=qris tapi QRIS_STATIC_PAYLOAD / QRIS_TOKEN_SECRET kosong atau CRC rusakTombol bayar error “QRIS belum dikonfigurasi” (503); tidak ada invoice QRIS dibuat
PAYMENT_PROVIDER_SAAS dihapusPembayaran SaaS kembali ke Doit.id / Duitku (rollback)

Cek cepat API:

GET https://api.halort.com/api/payments/qris/{merchantOrderId}?t={token}
POST https://api.halort.com/api/platform/invoices/{merchantOrderId}/confirm   { "paid_amount": 99137, "reference": "…", "note": "…" }
POST https://api.halort.com/api/platform/invoices/{merchantOrderId}/expire    { "note": "…" }

Endpoint /api/platform/* butuh sesi operator platform.

Laporan issue

Format Testing/Testing Mechanism:

Scenario: QRIS B3 / C4 / D-expired
Device + OS: Chrome macOS / GoPay Android
Tenant: gp2
merchantOrderId: hrt…
Nominal bayar: Rp …
Steps: …
Expected: …
Actual: …
Screenshot: halaman /bayar + mutasi GoPay Merchant (sensor data pribadi)

Terkait

Testing/Duitku SaaS Billing · Guides/Platform/Super Admin Platform · Surfaces/Platform API · Ops/Secrets Overview · Testing/Web Admin Checklist