Ringkasan Utama
Pada 2025, 85 persen perusahaan B2B menyediakan portal pelanggan online, naik dari 68 persen setahun sebelumnya, dan yang mengadopsi kanal B2B digital melaporkan kenaikan pendapatan penjualan rata-rata 41 persen. Portal baru memberi hasil itu jika membaca data stok, harga dan kredit dari ERP secara langsung.
Pada 2025, 85% perusahaan B2B menawarkan portal pelanggan online, naik dari 68% tahun sebelumnya. Perusahaan yang mengadopsi saluran B2B digital melaporkan rata-rata peningkatan pendapatan penjualan 41%. Untuk bisnis B2B Indonesia yang melayani klien korporat, portal pelanggan mengubah proses pemesanan via email dan telepon menjadi pengalaman swalayan yang berkembang tanpa pertumbuhan headcount yang proporsional.
Apa yang Benar-Benar Dibutuhkan Pelanggan B2B
Portal pelanggan B2B bukan toko ecommerce. Klien B2B membutuhkan: memesan berdasarkan daftar harga yang dinegosiasikan, melacak status pesanan dan pengiriman secara real-time, mengakses dan membayar faktur mereka, melihat riwayat transaksi mereka, dan berkomunikasi tentang pesanan tertentu.
Harga Khusus Pelanggan dan Batas Kredit
Dalam B2B Indonesia, setiap klien utama memiliki daftar harga yang dinegosiasikan. Portal ini membaca harga dari tabel customer_price_list ERP: setiap klien memiliki price list ID, dan ketika mereka menelusuri produk, mereka melihat harga kontrak mereka, bukan harga publik. Portal juga menampilkan batas kredit tersedia dan saldo outstanding mereka saat ini.
B2B Customer Portal Architecture
Customer (browser / mobile)
│
▼
┌─────────────────────────────────┐
│ Next.js Customer Portal │ (deployed: Vercel)
│ │
│ 🛒 Place Order (vs. price list)│
│ 📦 Track Shipment Status │
│ 🧾 View & Pay Invoices │
│ 📄 Download e-Faktur PDF │
└──────────────┬──────────────────┘
│ customer-scoped JWT
▼
┌─────────────────────────────────┐
│ NestJS API (shared) │
│ │
│ CustomerGuard → customer_id │
│ PostgreSQL RLS enforcement │
│ │
│ /pricing → customer_price_list │
│ /orders → sales_orders │
│ /invoices → ar_invoices │
│ /pay → Midtrans gateway │
└──────────────┬──────────────────┘
│
┌──────────────┴──────────────────┐
│ Internal ERP (Next.js) │
│ Sales Order sync ↔ portal │
│ Shipment updates → portal │
│ Invoice status → portal │
└─────────────────────────────────┘Dari pengalaman saya membangun sistem ERP sebagai konsultan ERP lepas: bangun pemeriksaan kredit di tingkat API, bukan hanya frontend. Saya memiliki implementasi awal di mana pemeriksaan batas kredit hanya ada di UI React — klien yang canggih dapat melewatinya dengan memanggil API langsung. Selalu paksakan aturan bisnis (batas kredit, minimum kuantitas pesanan, produk terbatas) di lapisan NestJS service.
Manajemen Pesanan dan Pelacakan Status Real-Time
Alur pesanan: pelanggan membuat pesanan di portal → pesanan disinkronkan ke ERP sebagai Sales Order → staf gudang ERP memilih dan mengirim → pembaruan pengiriman mengalir kembali ke portal → pelanggan melihat status real-time. Sinkronisasi bidireksional ini adalah tantangan integrasi inti.
Unduhan Dokumen — Faktur, DO, dan COA
Klien B2B perlu mengunduh dokumen: faktur pajak (PDF e-Faktur untuk rekonsiliasi PPN), Surat Jalan (untuk proses penerimaan barang mereka), dan Sertifikat Analisis untuk pemasok bahan baku. Semua ini dihasilkan di ERP dan disimpan dalam object storage dengan signed URL. Portal mengekspos pusat dokumen per pesanan dan per faktur.
// NestJS: Midtrans webhook handler (idempotent)
@Post('/webhooks/midtrans')
async handleMidtransWebhook(@Body() body: MidtransNotification) {
// 1. Validate Midtrans signature
const expectedSig = crypto
.createHash('sha512')
.update(body.order_id + body.status_code + body.gross_amount
+ process.env.MIDTRANS_SERVER_KEY)
.digest('hex');
if (expectedSig !== body.signature_key) {
throw new UnauthorizedException('Invalid webhook signature');
}
// 2. Idempotency check — skip if already processed
const alreadyProcessed = await this.paymentRepo.existsByMidtransId(
body.transaction_id
);
if (alreadyProcessed) {
return { message: 'Already processed — skipping' };
}
// 3. Only process successful payments
if (body.transaction_status === 'settlement'
|| body.transaction_status === 'capture') {
await this.arService.recordPayment({
invoiceId: body.order_id.replace('INV-', ''),
amount: parseFloat(body.gross_amount),
paymentDate: new Date(body.settlement_time),
reference: body.transaction_id,
method: body.payment_type,
});
}
return { message: 'OK' };
}Bagaimana Saya Mendekati Ini
Portal pelanggan adalah aplikasi Next.js terpisah yang diautentikasi melalui JWT khusus pelanggan. API NestJS memiliki konteks pelanggan yang membatasi setiap query ke data pelanggan yang terautentikasi — semua pesanan, faktur, dan pengiriman difilter berdasarkan customer_id di tingkat database menggunakan Row Level Security PostgreSQL.
Daftar harga pelanggan berubah — kontrak baru ditandatangani, harga promosi berakhir, biaya produk berubah. Jika Anda meng-cache daftar harga di lapisan aplikasi portal (misalnya di Redis untuk performa), Anda harus membatalkan cache ketika daftar harga diperbarui di ERP. Saya mengalami insiden memalukan di mana klien mendapat harga lama selama satu bulan penuh karena TTL cache diatur 24 jam. Untuk data harga, gunakan TTL yang jauh lebih pendek (maksimal 5 menit).
Integrasi Pembayaran Faktur Online
Saya mengintegrasikan Midtrans (payment gateway terkemuka Indonesia) untuk pembayaran faktur online. Klien dapat membayar faktur outstanding langsung dari portal. Alur pembayaran: klien memilih faktur yang akan dibayar → halaman pembayaran Midtrans terbuka → pada sukses, Midtrans mengirim webhook ke handler pembayaran NestJS → pembayaran dicatat di modul AR → status faktur diperbarui menjadi 'Dibayar'.
Adopsi dan Mengukur Keberhasilan
Setelah 6 bulan portal pelanggan di klien saya: 73% pesanan ditempatkan melalui portal (naik dari 0%), waktu pemrosesan pesanan rata-rata turun dari 4 jam menjadi 15 menit, dan panggilan layanan pelanggan turun 55%. Metrik yang penting untuk keberhasilan portal B2B: tingkat adopsi portal per akun pelanggan, pesanan melalui portal vs. saluran tradisional, tingkat pembayaran faktur secara online vs. transfer bank, dan waktu dari pesanan ke konfirmasi pesanan ERP.
