Midtrans-Middleware/docs/payment-link-e2e.md

7.4 KiB

Panduan QA End-to-End: Payment Link

Dokumen ini menjelaskan alur end-to-end Payment Link yang tersedia di proyek, mencakup konfigurasi, endpoint backend, format token, langkah QA dengan contoh request, hingga troubleshooting dan integrasi frontend.

Ringkasan Alur

  • ERP/eksternal membuat Payment Link via POST /createtransaksi dan menerima url serta token.
  • Frontend membuka halaman Pay di route pay/:token, lalu me-resolve token via GET /api/payment-links/:token.
  • Pengguna memilih metode pembayaran (sesuai allowed_methods dan toggle runtime), kemudian frontend memanggil POST /api/payments/charge.
  • Status pembayaran dapat dicek via GET /api/payments/:orderId/status dan disinkronkan via webhook POST /api/payments/webhook.

Prasyarat & Konfigurasi

  • Backend: jalankan node server/index.cjs (default port 8000).
  • Frontend: jalankan npm run dev (contoh dev port: 5175).
  • Penyesuaian environment penting:
    • EXTERNAL_API_KEY: API Key luar untuk POST /createtransaksi. Jika tidak diset, di dev akan diizinkan tanpa key.
    • PAYMENT_LINK_SECRET: secret untuk penandatanganan token Payment Link (HMAC SHA-256). Default dev: dev-secret.
    • PAYMENT_LINK_TTL_MINUTES: waktu kedaluwarsa token (default: 30).
    • PAYMENT_LINK_BASE: base URL untuk halaman Pay (default: http://localhost:5174/pay). Sesuaikan ke port frontend yang aktif (misal http://localhost:5175/pay).
    • PORT: port backend (default: 8000).
    • ERP_NOTIFICATION_URL, ERP_CLIENT_ID, ERP_MERCANT_ID, ERP_ENABLE_NOTIF: konfigurasi notifikasi ERP saat settlement.
    • Midtrans keys: Server Key dan Client Key harus tersedia untuk charge/status.
    • Frontend env: VITE_API_BASE_URL (contoh: http://localhost:8000/api), VITE_MIDTRANS_CLIENT_KEY.

Endpoint Backend

  • POST /createtransaksi

    • Header: X-API-KEY (opsional di dev jika EXTERNAL_API_KEY tidak diset).
    • Body: { item_id | order_id, nominal, customer?, allowed_methods? }
    • Respon: { url, token, order_id, nominal, expire_at }
    • Error: UNAUTHORIZED, BAD_REQUEST, ORDER_COMPLETED, ORDER_ACTIVE, CREATE_ERROR.
  • GET /api/payment-links/:token

    • Respon: { order_id, nominal, customer?, expire_at?, allowed_methods? }
    • Error: 410 TOKEN_EXPIRED, 400 INVALID_* (di dev ada fallback payload jika token invalid).
  • POST /api/payments/charge

    • Body: payload Midtrans (contoh di bawah). Diblokir jika method dimatikan oleh runtime toggles.
    • Error: PAYMENT_TYPE_DISABLED, CHARGE_ERROR.
  • GET /api/payments/:orderId/status

    • Respon: pass-through dari Midtrans (transaction status, VA, dll.).
  • POST /api/payments/webhook

    • Verifikasi signature: sha512(orderId + statusCode + grossAmount + serverKey).
    • Pada sukses (settlement atau capture+accept untuk kartu), backend kirim notifikasi ke ERP (jika diaktifkan) dan menandai order sebagai completed.
  • GET /api/health, GET/POST /api/config

    • Health: cek ketersediaan key dan environment.
    • Config: baca/ubah toggles (dev-only untuk POST).
  • Token adalah base64url(JSON) dengan fields minimal: { v, order_id, nominal, expire_at, sig, customer?, allowed_methods? }.
  • sig adalah HMAC SHA-256 dari string kanonik: "order_id|nominal|expire_at" menggunakan PAYMENT_LINK_SECRET.

Langkah QA (Contoh)

  1. Buat Payment Link

PowerShell (Windows):

$body = @{
  item_id = 'INV-PL-001';
  nominal = 150000;
  customer = @{ name='QA Tester'; phone='081234567890'; email='qa@example.com' };
  allowed_methods = @('bank_transfer','cstore','gopay','credit_card')
} | ConvertTo-Json -Depth 5;

Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/createtransaksi' -ContentType 'application/json' -Body $body | ConvertTo-Json -Depth 5

curl:

curl -X POST http://localhost:8000/createtransaksi \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: <jika-diperlukan>' \
  -d '{
    "item_id":"INV-PL-001",
    "nominal":150000,
    "customer": {"name":"QA Tester","phone":"081234567890","email":"qa@example.com"},
    "allowed_methods":["bank_transfer","cstore","gopay","credit_card"]
  }'
  1. Resolve Token
Invoke-RestMethod -Method GET -Uri "http://localhost:8000/api/payment-links/<token>" | ConvertTo-Json -Depth 5
  1. Buka Halaman Pay
  • Buka http://localhost:5175/pay/<token> (sesuaikan PAYMENT_LINK_BASE dengan port frontend).
  • Periksa daftar metode, panel, serta batasan dari allowed_methods dan runtime toggles.
  1. Charge Bank Transfer (BCA)
$bt = @{
  payment_type = 'bank_transfer';
  transaction_details = @{ order_id = 'INV-PL-001'; gross_amount = 150000 };
  bank_transfer = @{ bank = 'bca' }
} | ConvertTo-Json -Depth 5;

Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/api/payments/charge' -ContentType 'application/json' -Body $bt | ConvertTo-Json -Depth 5
  1. Charge GoPay/QR (opsional)
$qr = @{
  payment_type = 'gopay';
  transaction_details = @{ order_id = 'INV-PL-001'; gross_amount = 150000 };
  gopay = @{ enable_qr = $true }
} | ConvertTo-Json -Depth 5;

Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/api/payments/charge' -ContentType 'application/json' -Body $qr | ConvertTo-Json -Depth 5

Catatan: Bila 400 Bad Request, cek konfigurasi akun sandbox dan parameter GoPay/QRIS (lihat bagian troubleshooting).

  1. Status Check
Invoke-RestMethod -Method GET -Uri 'http://localhost:8000/api/payments/INV-PL-001/status' | ConvertTo-Json -Depth 5
  1. Webhook (uji manual)

Untuk uji manual, kirim payload menyerupai notifikasi Midtrans dengan signature_key yang valid. Signature dihitung:

// Node.js contoh perhitungan signature
const crypto = require('crypto')
function computeMidtransSignature(orderId, statusCode, grossAmount, secretKey) {
  const raw = String(orderId) + String(statusCode) + String(grossAmount) + String(secretKey)
  return crypto.createHash('sha512').update(raw).digest('hex')
}

Kemudian POST ke http://localhost:8000/api/payments/webhook dengan body berisi fields Midtrans (order_id, status_code, gross_amount, signature_key, dll.).

Troubleshooting

  • Frontend tidak sesuai PAYMENT_LINK_BASE (5174 vs 5175): set PAYMENT_LINK_BASE=http://localhost:5175/pay di backend agar URL link mengarah ke port yang benar.
  • 400 Bad Request untuk GoPay/QR:
    • Pastikan gopay payload memenuhi kebutuhan sandbox (mis. enable_qr, kadang perlu qr_black_white, atau callback_url).
    • Periksa toggles runtime (/api/config) dan ketersediaan Midtrans keys.
    • Beberapa merchant sandbox memiliki batasan; rujuk dokumentasi Midtrans untuk parameter terbaru.
  • UNAUTHORIZED saat createtransaksi: set header X-API-KEY sesuai EXTERNAL_API_KEY jika dikonfigurasi.
  • ORDER_ACTIVE atau ORDER_COMPLETED: backend menjaga activeOrders dan notifiedOrders untuk mencegah duplikasi; tunggu TTL atau gunakan order baru.

Integrasi Frontend

  • Route: pay/:token (lihat src/app/router.tsx).
  • Resolver: getPaymentLinkPayload(token) (lihat src/services/api.ts).
  • Toggle & Allowed Methods: PayPage menggabungkan runtimeCfg.paymentToggles dengan allowed_methods. Kunci metode: bank_transfer, credit_card, gopay, cstore, cpay.

Notifikasi ERP

  • Di settlement sukses, backend menghitung signature ERP (sha512) dan mengirim payload ke ERP_NOTIFICATION_URL jika ERP_ENABLE_NOTIF=true dan konfigurasi lengkap.

Postman Collection

  • Anda dapat mengimpor koleksi: docs/qa/payment-link.postman_collection.json untuk mencoba endpoint di atas.