Pasar software ERP mencapai $70 miliar pada 2025, didorong sebagian besar oleh permintaan pelaporan keuangan otomatis. Tim keuangan yang menggunakan otomasi laporan ERP melihat pengurangan waktu pembuatan laporan hingga 70%, dan Gartner memproyeksikan ERP canggih dengan AI dapat mempersingkat waktu penutupan keuangan hingga 30% pada 2028. Di UKM Indonesia, saya menemukan bahwa pelaporan keuangan biasanya merupakan modul bernilai tertinggi — yang dilihat CFO dan pemilik setiap minggu. Di Commsult, saya membangun mesin pelaporan keuangan yang menghasilkan Laba Rugi, Neraca, Arus Kas, dan laporan manajemen sepenuhnya dari buku besar umum.
Setiap laporan keuangan pada dasarnya adalah tampilan atas bagan akun (CoA) dan entri jurnal yang diposting terhadapnya. Sebelum menulis kode pelaporan apa pun, dapatkan struktur CoA yang benar. Kami menggunakan hierarki empat level: Kategori (Aset, Kewajiban, Ekuitas, Pendapatan, Beban) → Kelompok → Sub-kelompok → Akun.
Mesin jurnal kami menegakkan akuntansi double-entry di tingkat database: setiap entri jurnal harus memiliki total debit sama dengan total kredit, atau INSERT ditolak oleh batasan CHECK PostgreSQL. Setiap baris journal_entry memiliki header (tanggal, referensi, deskripsi, jenis) dan beberapa journal_lines (account_id, debit, kredit).
Financial Reporting Engine — NestJS + PostgreSQL
Chart of Accounts (4-level hierarchy)
├── ASSETS
│ ├── Current Assets
│ │ ├── Cash & Bank [11000–11999]
│ │ └── Accounts Receiv. [12000–12999]
│ └── Fixed Assets [15000–15999]
├── LIABILITIES
│ └── Accounts Payable [21000–21999]
├── EQUITY [30000–39999]
├── REVENUE [40000–49999]
└── EXPENSES [50000–59999]
journal_lines (the single source of truth)
┌─────────────────────────────────────────────────┐
│ id │ journal_id │ account_id │ debit │ credit │
│ ...│ ... │ 11001 │ 1000 │ 0 │ <- Cash receipt
│ ...│ ... │ 40001 │ 0 │ 1000 │ <- Revenue
└─────────────────────────────────────────────────┘
↓ Aggregated by NestJS ReportService
P&L Report Balance Sheet Cash Flow
Revenue: 500M Assets: 2.1B Operating: +400M
COGS: (300M) Liab: 800M Investing: (50M)
Gross: 200M Equity: 1.3B Financing: (20M)
Net: 150M Net: 330MDari pengalaman saya membangun sistem ERP di Commsult: selalu implementasikan fitur 'period lock'. Perusahaan Indonesia perlu menutup buku setiap bulan untuk pelaporan PPN dan setiap tahun untuk pajak penghasilan badan. Setelah periode dikunci, tidak ada entri jurnal baru yang dapat diposting — ini mencegah perubahan retroaktif yang akan membatalkan laporan pajak yang sudah diserahkan. Kunci diberlakukan di tingkat database dengan trigger.
Tiga laporan keuangan inti kami dibuat sesuai permintaan melalui endpoint NestJS. Endpoint L/R menerima rentang tanggal dan mengembalikan akun pendapatan yang dijumlahkan sebagai pemasukan, akun beban yang dijumlahkan sebagai biaya, dengan laba kotor dan laba bersih yang dihitung. Endpoint Neraca menghitung total aset, kewajiban, dan ekuitas pada tanggal tertentu.
Selain laporan wajib, manajemen menginginkan L/R per pusat biaya (berapa banyak yang dihabiskan setiap departemen?), profitabilitas proyek, dan analisis margin produk. Kami mendukung ini melalui cost_center_id dan project_id di setiap baris jurnal. CFO di klien kami mendapatkan email mingguan (dibuat secara otomatis setiap Senin pukul 06.00 WIB) dengan L/R per pusat biaya dilampirkan sebagai file Excel.
-- PostgreSQL: P&L report query
SELECT
coa.category,
coa.group_name,
coa.account_name,
coa.account_code,
SUM(jl.debit - jl.credit) AS net_amount
FROM journal_lines jl
JOIN journal_entries je ON jl.journal_id = je.id
JOIN chart_of_accounts coa ON jl.account_id = coa.id
WHERE
je.posted_at BETWEEN :start_date AND :end_date
AND je.status = 'posted'
AND coa.category IN ('REVENUE', 'EXPENSE')
AND (je.locked_period IS NULL OR je.locked_period >= :start_date)
GROUP BY coa.category, coa.group_name, coa.account_name, coa.account_code
ORDER BY coa.account_code;
-- Period lock enforcement (trigger)
CREATE OR REPLACE FUNCTION check_period_lock()
RETURNS TRIGGER AS $$
BEGIN
IF EXISTS (
SELECT 1 FROM period_locks
WHERE period_year = EXTRACT(YEAR FROM NEW.posting_date)
AND period_month = EXTRACT(MONTH FROM NEW.posting_date)
AND locked = TRUE
) THEN
RAISE EXCEPTION 'Period % is locked — no new entries allowed',
TO_CHAR(NEW.posting_date, 'YYYY-MM');
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_check_period_lock
BEFORE INSERT ON journal_entries
FOR EACH ROW EXECUTE FUNCTION check_period_lock();Mesin pelaporan kami adalah modul NestJS dengan empat service: JournalService (posting dan validasi), ReportService (query L/R, Neraca, Arus Kas), SegmentService (filter pusat biaya dan proyek), dan ExportService (PDF via Puppeteer, Excel via exceljs). Semua laporan di-cache di Redis dengan TTL 5 menit.
Jika klien Anda memiliki beberapa entitas legal atau bertransaksi dalam mata uang asing, pelaporan keuangan konsolidasi memerlukan translasi mata uang. Ini adalah sumber kesalahan umum saat ditangani secara manual. Kami menyimpan kurs tukar harian dan menerapkan kurs tanggal transaksi untuk item laporan laba rugi dan kurs akhir periode untuk item neraca, dengan PSAK 10 sebagai standar referensi.
Bisnis Indonesia harus mengajukan SPT Masa PPN bulanan melalui e-Faktur dan SPT Tahunan PPh. ERP kami menghubungkan setiap baris jurnal ke kode pajak opsional (PPN 11%, PPh 23 2%, dll.). Laporan PPN mengelompokkan berdasarkan masa pajak, menampilkan pajak masukan (pembelian) dan pajak keluaran (penjualan), dan menghitung utang pajak bersih atau kredit.
Untuk perusahaan Indonesia yang tunduk pada audit eksternal, setiap entri jurnal memerlukan dokumen pendukung. Sistem kami menghubungkan entri jurnal ke dokumen sumber — faktur AP, faktur AR, rekening koran, voucher pembayaran. Auditor dapat mengklik baris jurnal apa pun dan melihat dokumen aslinya. Kapabilitas 'drill-down ke sumber' ini yang membedakan ERP nyata dari spreadsheet canggih.