Mengotomatiskan Piutang Usaha dalam ERP Kustom: Pengingat, Laporan Aging, dan Pelacakan Pembayaran

Foto oleh Unsplash

Foto oleh Unsplash
Di sebagian besar UKM Indonesia, manajemen piutang usaha ditangani melalui kombinasi spreadsheet Excel dan follow-up WhatsApp manual. Ketika saya membangun modul AR untuk ERP kustom Commsult Indonesia, tujuannya adalah mengotomatiskan seluruh siklus hidup piutang — dari pembuatan invoice hingga eskalasi keterlambatan — sehingga tim keuangan dapat fokus pada pengecualian daripada follow-up rutin.
Otomatisasi AR yang lengkap mencakup empat tahap: pembuatan dan pengiriman invoice, pengingat pembayaran otomatis pada interval yang ditentukan, deteksi dan eskalasi keterlambatan, dan pencatatan pembayaran dengan rekonsiliasi.
Langkah pertama adalah menghasilkan invoice PDF yang profesional dan mengirimkannya ke pelanggan melalui email. Dalam implementasi NestJS kami, kami menggunakan Puppeteer untuk me-render template HTML ke PDF. PDF yang dihasilkan disimpan di Google Cloud Storage dan tautan unduhan disertakan dalam email pengiriman.
Jadwal pengingat dapat dikonfigurasi per syarat pembayaran pelanggan. Untuk pelanggan NET_30: pengingat ramah di T-7, pengingat lebih tegas di T-3, pemberitahuan keterlambatan di T+0, tindak lanjut di T+7, dan notifikasi credit hold di T+30 keterlambatan.
Accounts Receivable Automation Flow
Invoice Created
│
▼
┌──────────────────┐
│ Generate PDF │◄── NestJS PDF service (Puppeteer)
│ & Send Email │──► Customer inbox
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Due Date T-7 │──► Reminder email #1 (automated)
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Due Date T-3 │──► Reminder email #2 (escalation tone)
└────────┬─────────┘
│
▼
┌──────────────────┐ ┌─────────────────────┐
│ Due Date T+0 │─────►│ Mark as OVERDUE │
└────────┬─────────┘ │ Notify AR Manager │
│ └─────────────────────┘
▼
┌──────────────────┐
│ T+7 Overdue │──► Manual follow-up flag
│ T+30 Overdue │──► Credit hold trigger
└──────────────────┘Selalu sertakan tautan pembayaran langsung dalam email pengingat. Kami mengintegrasikan dengan payment gateway lokal (Midtrans) sehingga pelanggan dapat membayar langsung dari email. Invoice dengan tautan pembayaran dibayar 40% lebih cepat.
Modul @nestjs/schedule NestJS menyediakan scheduler berbasis cron yang berjalan di dalam proses aplikasi. Kami menjalankan tugas pengingat AR setiap pagi pukul 08.00 WIB (UTC+7). Tugas ini melakukan kueri untuk invoice yang jatuh tempo dalam 7, 3, dan 0 hari, serta untuk invoice yang sudah terlambat.
Laporan aging mengkategorikan semua invoice yang belum dibayar berdasarkan seberapa terlambatnya: lancar (belum jatuh tempo), 1–30 hari, 31–60 hari, 61–90 hari, dan 90+ hari. Kami membuat laporan ini secara on-demand dan juga pra-komputasi snapshot harian untuk performa.
// NestJS: AR automated reminder scheduler
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThanOrEqual, In } from 'typeorm';
import { Invoice } from './invoice.entity';
import { EmailService } from '../email/email.service';
import { addDays, startOfDay } from 'date-fns';
@Injectable()
export class ArReminderService {
private readonly logger = new Logger(ArReminderService.name);
constructor(
@InjectRepository(Invoice)
private invoiceRepo: Repository<Invoice>,
private emailService: EmailService,
) {}
@Cron(CronExpression.EVERY_DAY_AT_8AM)
async sendReminders() {
const today = startOfDay(new Date());
// T-7: first reminder
const upcomingInvoices = await this.invoiceRepo.find({
where: {
dueDate: addDays(today, 7),
status: In(['SENT', 'PARTIALLY_PAID']),
},
relations: ['customer'],
});
for (const invoice of upcomingInvoices) {
await this.emailService.sendArReminder(invoice, 'REMINDER_7_DAYS');
this.logger.log(`Sent T-7 reminder for invoice ${invoice.invoiceNumber}`);
}
// T+0: mark overdue
const overdueInvoices = await this.invoiceRepo.find({
where: {
dueDate: LessThanOrEqual(today),
status: In(['SENT', 'PARTIALLY_PAID']),
},
relations: ['customer'],
});
for (const invoice of overdueInvoices) {
await this.invoiceRepo.update(invoice.id, { status: 'OVERDUE' });
await this.emailService.sendArReminder(invoice, 'OVERDUE_NOTICE');
}
this.logger.log(
`Processed ${upcomingInvoices.length} reminders, ${overdueInvoices.length} overdue`
);
}
}Ketika pelanggan melakukan pembayaran, staf keuangan mencatatnya di ERP terhadap invoice. Sistem mendukung pembayaran parsial. Ketika invoice mencapai saldo nol, secara otomatis beralih ke status DIBAYAR dan kuitansi dikirim melalui email ke pelanggan.
Berhati-hatilah dengan penanganan zona waktu di scheduler. Indonesia memiliki tiga zona waktu (WIB, WITA, WIT) dan waktu server sering UTC. Selalu simpan tanggal jatuh tempo sebagai DATE (bukan TIMESTAMP) di PostgreSQL dan secara eksplisit konversi ke zona waktu pelanggan saat menghitung status keterlambatan.
Modul AR berkontribusi ke dashboard keuangan dengan tiga metrik utama: Days Sales Outstanding (DSO), tingkat penagihan per periode, dan jumlah terlambat per tier pelanggan. DSO yang meningkat menandakan masalah penagihan sebelum menjadi krisis arus kas.
Setelah menjalankan sistem AR otomatis di produksi di Commsult Indonesia selama 6 bulan: waktu follow-up manual turun 70%, tingkat keterlambatan turun dari 45% ke 22%, dan waktu penagihan rata-rata meningkat dari 38 hari menjadi 26 hari.