Finance & Accounting Skill
Skill universal untuk membangun fitur keuangan, kalkulasi akuntansi, dan laporan finansial — berlaku untuk semua jenis usaha.
Konsep Dasar Akuntansi
Persamaan Dasar
Aset = Kewajiban + Modal
Laba = Pendapatan - Beban
Jenis Akun
| Kategori |
Contoh |
Saldo Normal |
| Aset |
Kas, Piutang, Persediaan, Peralatan |
Debit |
| Kewajiban |
Hutang Usaha, Hutang Bank, Pendapatan Diterima Dimuka |
Kredit |
| Modal |
Modal Pemilik, Laba Ditahan |
Kredit |
| Pendapatan |
Penjualan, Jasa, Pendapatan Lain |
Kredit |
| Beban |
Bahan/Material, Gaji, Sewa, Utilitas, Penyusutan |
Debit |
HPP / COGS (Harga Pokok)
HPP berlaku berbeda tergantung jenis usaha:
Per Jenis Usaha
| Jenis Usaha |
Komponen HPP |
| Produksi (kue, makanan, manufaktur) |
Bahan baku + tenaga kerja langsung + overhead pabrik |
| Dagang (toko, retail, reseller) |
Harga beli barang + ongkos kirim masuk |
| Jasa (salon, bengkel, konsultan) |
Bahan habis pakai + tenaga kerja langsung |
| F&B (restoran, kafe, catering) |
Bahan makanan + kemasan + food cost |
Rumus HPP
Usaha Produksi:
HPP = Bahan Baku Terpakai + Tenaga Kerja Langsung + Overhead Produksi
Bahan Baku Terpakai = Persediaan Awal + Pembelian - Persediaan Akhir
Usaha Dagang:
HPP = Persediaan Awal + Pembelian Bersih - Persediaan Akhir
Pembelian Bersih = Pembelian - Retur Pembelian - Potongan Pembelian + Ongkir Masuk
Usaha Jasa:
HPP = Bahan Habis Pakai + Upah Langsung
Metode Penilaian Persediaan
| Metode |
Cara Hitung |
Cocok Untuk |
| FIFO (First In First Out) |
Stok masuk pertama dihitung keluar duluan |
Bahan perishable, makanan, obat |
| Rata-rata Tertimbang |
(Total nilai stok) ÷ (total qty) |
Barang homogen, harga fluktuatif |
| Harga Terakhir |
Pakai harga pembelian paling baru |
UMKM simple, stok kecil |
| Specific Identification |
Track harga per batch/lot |
Barang unik, mahal (perhiasan, kendaraan) |
Implementasi HPP (Generic)
const hitungHPP = (items, inventaris, metode = 'terakhir') => {
return items.reduce((total, item) => {
const barang = inventaris.find(b => b.id === item.itemId)
if (!barang) return total
let hargaPerUnit
switch (metode) {
case 'terakhir':
hargaPerUnit = barang.hargaTerakhir / (barang.konversi || 1)
break
case 'rata-rata':
hargaPerUnit = barang.rataRataHarga / (barang.konversi || 1)
break
case 'fifo':
hargaPerUnit = getFIFOPrice(barang.id, item.jumlah)
break
default:
hargaPerUnit = barang.hargaTerakhir / (barang.konversi || 1)
}
return total + (hargaPerUnit * item.jumlah)
}, 0)
}
HPP + Overhead
HPP Total = HPP Material + Tenaga Kerja Langsung + Overhead
Overhead contoh per jenis usaha:
- Produksi: gas, listrik mesin, penyusutan alat produksi
- F&B: gas dapur, kemasan, sarung tangan
- Bengkel: listrik, oli mesin, alat habis pakai
- Salon: listrik, produk treatment habis pakai
Pricing & Margin
Rumus Universal
Harga Jual = HPP × (1 + Markup%)
Margin% = ((Harga Jual - HPP) / Harga Jual) × 100
Markup% = ((Harga Jual - HPP) / HPP) × 100
Target Margin per Industri (rekomendasi UMKM Indonesia)
| Industri |
Margin Kotor |
Markup |
| F&B / Makanan |
30-50% |
43-100% |
| Retail / Toko |
20-40% |
25-67% |
| Fashion / Pakaian |
40-60% |
67-150% |
| Jasa / Service |
50-70% |
100-233% |
| Digital Product |
70-90% |
233-900% |
| Furniture / Kerajinan |
40-60% |
67-150% |
| Pertanian / Agribisnis |
20-35% |
25-54% |
| Bengkel / Otomotif |
30-50% |
43-100% |
Break-Even Point
BEP (unit) = Biaya Tetap ÷ (Harga Jual - HPP per Unit)
BEP (rupiah) = Biaya Tetap ÷ Contribution Margin Ratio
CMR = (Harga Jual - HPP) / Harga Jual
Contoh biaya tetap: sewa, gaji tetap, asuransi, depresiasi
Contoh biaya variabel: bahan baku, kemasan, komisi sales
ROI (Return on Investment)
ROI = (Laba Bersih ÷ Total Investasi) × 100%
Payback Period = Total Investasi ÷ Laba Bersih per Bulan
Laporan Laba Rugi
Struktur Universal
PENDAPATAN
Penjualan / Jasa Kotor xxx
(-) Diskon, Retur, Potongan (xxx)
──────────────────────────────────
Pendapatan Bersih xxx
HARGA POKOK (HPP/COGS)
Material / Barang Terjual xxx
Tenaga Kerja Langsung xxx
Overhead Produksi xxx
──────────────────────────────────
Total HPP (xxx)
──────────────────────────────────
LABA KOTOR (Gross Profit) xxx
BEBAN OPERASIONAL
Gaji & Upah Tetap xxx
Sewa Tempat xxx
Utilitas (Listrik, Air, Internet) xxx
Transportasi & Pengiriman xxx
Marketing & Promosi xxx
Penyusutan Peralatan xxx
Administrasi & Lain-lain xxx
──────────────────────────────────
Total Beban Operasional (xxx)
──────────────────────────────────
LABA OPERASIONAL (EBIT) xxx
PENDAPATAN/BEBAN LAIN
Pendapatan Bunga xxx
Beban Bunga Pinjaman (xxx)
──────────────────────────────────
LABA SEBELUM PAJAK (EBT) xxx
Pajak (xxx)
──────────────────────────────────
LABA BERSIH (Net Profit) xxx
Implementasi (Generic)
const hitungLabaRugi = (transaksi, pengeluaran, periode) => {
const penjualan = transaksi
.filter(t => t.status === 'selesai' && inPeriode(t.createdAt, periode))
const pendapatanKotor = penjualan.reduce((sum, t) => sum + t.subtotal, 0)
const totalDiskon = penjualan.reduce((sum, t) => sum + (t.diskon || 0), 0)
const totalRetur = penjualan.reduce((sum, t) => sum + (t.retur || 0), 0)
const pendapatanBersih = pendapatanKotor - totalDiskon - totalRetur
const beban = pengeluaran
.filter(p => inPeriode(p.tanggal, periode))
.reduce((acc, p) => {
acc[p.kategori] = (acc[p.kategori] || 0) + p.jumlah
return acc
}, {})
const totalHPP = Object.entries(beban)
.filter(([k]) => ['bahan', 'material', 'kemasan', 'barang'].includes(k))
.reduce((sum, [, v]) => sum + v, 0)
const labaKotor = pendapatanBersih - totalHPP
const totalBebanOps = Object.entries(beban)
.filter(([k]) => ['gaji', 'sewa', 'operasional', 'marketing', 'transport', 'admin'].includes(k))
.reduce((sum, [, v]) => sum + v, 0)
const labaBersih = labaKotor - totalBebanOps
return {
pendapatanKotor, totalDiskon, totalRetur, pendapatanBersih,
totalHPP, labaKotor,
totalBebanOps, labaBersih,
marginKotor: pendapatanBersih ? (labaKotor / pendapatanBersih * 100) : 0,
marginBersih: pendapatanBersih ? (labaBersih / pendapatanBersih * 100) : 0,
}
}
Neraca (Balance Sheet)
Struktur
ASET
Aset Lancar
Kas & Bank xxx
Piutang Usaha xxx
Persediaan Barang/Bahan xxx
Biaya Dibayar Dimuka xxx
Total Aset Lancar xxx
Aset Tetap
Peralatan & Mesin xxx
Kendaraan xxx
(-) Akumulasi Penyusutan (xxx)
Total Aset Tetap xxx
──────────────────────────────────
TOTAL ASET xxx
KEWAJIBAN & MODAL
Kewajiban Lancar
Hutang Usaha (Supplier) xxx
Hutang Bank (jatuh tempo <1th) xxx
Pendapatan Diterima Dimuka (DP) xxx
Total Kewajiban Lancar xxx
Kewajiban Jangka Panjang
Hutang Bank (>1 tahun) xxx
Total Kewajiban Jangka Panjang xxx
Modal
Modal Pemilik xxx
Laba Ditahan xxx
Laba Periode Berjalan xxx
Total Modal xxx
──────────────────────────────────
TOTAL KEWAJIBAN & MODAL xxx
Cash Flow (Arus Kas)
3 Aktivitas
1. OPERASIONAL
(+) Penerimaan penjualan / jasa
(+) Penerimaan piutang
(-) Pembayaran supplier / bahan
(-) Gaji karyawan
(-) Biaya operasional
2. INVESTASI
(-) Pembelian peralatan / mesin
(-) Renovasi tempat usaha
(+) Penjualan aset
3. PENDANAAN
(+) Pinjaman bank
(+) Tambahan modal pemilik
(-) Pembayaran cicilan
(-) Penarikan prive
ARUS KAS BERSIH = Operasional + Investasi + Pendanaan
SALDO AKHIR = Saldo Awal + Arus Kas Bersih
Piutang & Hutang
Aging Piutang
| Kategori |
Hari |
Status |
Tindakan |
| Lancar |
0-30 |
Hijau |
Reminder otomatis |
| Kurang Lancar |
31-60 |
Kuning |
Follow-up personal |
| Diragukan |
61-90 |
Orange |
Negosiasi / cicilan |
| Macet |
>90 |
Merah |
Penagihan / write-off |
Implementasi Piutang (Generic)
const hitungPiutang = (transaksi) => {
return transaksi
.filter(t => t.status !== 'batal')
.reduce((total, t) => {
const terbayar = (t.dp || 0) + (t.pelunasan || 0)
const sisa = t.total - terbayar
return total + Math.max(0, sisa)
}, 0)
}
const agingPiutang = (transaksi) => {
const now = new Date()
return transaksi
.filter(t => t.status !== 'batal')
.map(t => {
const sisa = t.total - (t.dp || 0) - (t.pelunasan || 0)
if (sisa <= 0) return null
const hari = Math.floor((now - new Date(t.createdAt)) / 86400000)
let kategori = 'lancar'
if (hari > 90) kategori = 'macet'
else if (hari > 60) kategori = 'diragukan'
else if (hari > 30) kategori = 'kurangLancar'
return { ...t, sisa, hari, kategori }
})
.filter(Boolean)
}
Invoice / Tagihan
Format Nomor (Customizable)
{PREFIX}-{TAHUN}-{NOMOR_URUT}
Contoh per jenis usaha:
- Toko: INV-2024-001
- Bengkel: WO-2024-001 (Work Order)
- Salon: RCP-2024-001 (Receipt)
- Konsultan: INV-2024-001/KNS
- Kafe: BIL-2024-001 (Bill)
Komponen Invoice Universal
┌──────────────────────────────────────┐
│ LOGO NAMA USAHA │
│ Alamat │
│ Telp / WA / Email │
├──────────────────────────────────────┤
│ No. Invoice: INV-2024-001 │
│ Tanggal: 24 Mar 2024 │
│ Jatuh Tempo: 07 Apr 2024 │
│ Kepada: Nama Pelanggan / Klien │
├──────────────────────────────────────┤
│ No │ Item/Jasa │ Qty │ Harga │ Sub│
│ 1 │ Produk A │ 2 │ xx.000│xxx│
│ 2 │ Jasa B │ 1 │ xx.000│xxx│
├──────────────────────────────────────┤
│ Subtotal: xxx.000│
│ Diskon: -xx.000│
│ PPN 11%: xx.000│ ← opsional
│ Ongkir: xx.000│ ← opsional
│ TOTAL: xxx.000│
│ Terbayar:-xxx.000│
│ SISA: xxx.000│
├──────────────────────────────────────┤
│ Pembayaran ke: │
│ Bank BCA - 1234567890 │
│ a/n Nama Usaha │
│ │
│ Syarat & Ketentuan: │
│ - Pembayaran dalam 14 hari │
│ - Transfer = konfirmasi via WA │
└──────────────────────────────────────┘
Pajak Indonesia
PPh Final UMKM (PP 55/2022)
Omzet ≤ Rp 500 juta/tahun → BEBAS pajak
Omzet > Rp 500 juta → PPh Final 0.5% dari omzet kotor
Berlaku untuk: WP OP (7 tahun) dan WP Badan (4 tahun)
PPN (Pajak Pertambahan Nilai)
Wajib PKP jika omzet > Rp 4.8 miliar/tahun
Tarif PPN: 11% (per April 2022)
PPN Terutang = PPN Keluaran - PPN Masukan
PPh 21 (Karyawan)
Gaji ≤ Rp 4.5 juta/bulan → PTKP, tidak kena pajak
Gaji > Rp 4.5 juta/bulan → Tarif progresif:
0 - 60 juta : 5%
60 - 250 juta : 15%
250 - 500 juta : 25%
500 juta - 5 M : 30%
> 5 M : 35%
Implementasi Pajak UMKM
const hitungPajakUMKM = (omzetBulanan) => {
const omzetTahunan = omzetBulanan.reduce((sum, o) => sum + o, 0)
const BATAS_BEBAS = 500_000_000
if (omzetTahunan <= BATAS_BEBAS) {
return { pajak: 0, status: 'Bebas PPh (omzet ≤ 500 juta)' }
}
const omzetKenaPajak = omzetTahunan - BATAS_BEBAS
const pajak = omzetKenaPajak * 0.005
return {
omzetTahunan, omzetKenaPajak, pajak,
pajakPerBulan: pajak / 12,
status: `PPh Final 0.5% dari ${formatRp(omzetKenaPajak)}`,
}
}
Penyusutan Aset (Depreciation)
Metode
| Metode |
Rumus |
Cocok Untuk |
| Garis Lurus |
(Harga Beli - Nilai Sisa) ÷ Umur Ekonomis |
Peralatan umum |
| Saldo Menurun |
Nilai Buku × (2 ÷ Umur Ekonomis) |
Aset cepat usang (komputer, HP) |
| Unit Produksi |
(Harga Beli - Nilai Sisa) × (Produksi Aktual ÷ Kapasitas Total) |
Mesin produksi |
Umur Ekonomis (pedoman pajak)
| Kelompok |
Umur |
Contoh |
| Kelompok 1 |
4 tahun |
Komputer, HP, peralatan kecil |
| Kelompok 2 |
8 tahun |
Mesin produksi, perabotan |
| Kelompok 3 |
16 tahun |
Kendaraan, mesin berat |
| Kelompok 4 |
20 tahun |
Bangunan permanen |
Format Angka (Indonesia)
Helper Functions
export const formatRp = (n) =>
new Intl.NumberFormat('id-ID', {
style: 'currency', currency: 'IDR', maximumFractionDigits: 0,
}).format(n || 0)
export const formatPersen = (n, desimal = 1) =>
`${(n * 100).toFixed(desimal).replace('.', ',')}%`
export const formatRibuan = (n) => {
if (Math.abs(n) >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1).replace('.', ',')} M`
if (Math.abs(n) >= 1_000_000) return `${(n / 1_000_000).toFixed(1).replace('.', ',')} jt`
if (Math.abs(n) >= 1_000) return `${(n / 1_000).toFixed(0)} rb`
return n.toString()
}
Multi-Currency Support
export const formatCurrency = (n, currency = 'IDR') => {
const locales = { IDR: 'id-ID', USD: 'en-US', SGD: 'en-SG', MYR: 'ms-MY' }
return new Intl.NumberFormat(locales[currency] || 'id-ID', {
style: 'currency', currency, maximumFractionDigits: currency === 'IDR' ? 0 : 2,
}).format(n || 0)
}
KPI Dashboard Keuangan
Metrik Universal
| KPI |
Rumus |
Benchmark Sehat |
| Margin Kotor |
Laba Kotor ÷ Pendapatan |
Tergantung industri (lihat tabel margin) |
| Margin Bersih |
Laba Bersih ÷ Pendapatan |
> 10% |
| Rasio HPP |
HPP ÷ Pendapatan |
< 60% |
| DSO |
(Piutang ÷ Pendapatan) × 30 |
< 30 hari |
| Current Ratio |
Aset Lancar ÷ Kewajiban Lancar |
> 1.5 |
| Inventory Turnover |
HPP ÷ Rata-rata Persediaan |
> 6x/tahun (tergantung industri) |
| ROI |
Laba Bersih ÷ Total Investasi |
> 15%/tahun |
| Revenue Growth |
(Bulan Ini - Bulan Lalu) ÷ Bulan Lalu |
Positif & konsisten |
Grafik yang Direkomendasikan
- Line Chart: Trend pendapatan harian/mingguan/bulanan
- Stacked Bar: Pendapatan vs pengeluaran per periode
- Pie/Donut: Komposisi pengeluaran atau sumber pendapatan
- Area Chart: Arus kas kumulatif
- Progress Bar: Target omzet / KPI pencapaian
- Heatmap: Penjualan per hari per jam (untuk retail/F&B)
- Waterfall Chart: Breakdown dari pendapatan ke laba bersih
Aturan Keuangan
- Semua angka uang wajib pakai formatter — jangan tampilkan raw number
- Gunakan
Intl.NumberFormat — jangan hardcode titik/koma
- Jangan bulatkan di tengah kalkulasi — bulatkan hanya saat tampilkan ke user
- Simpan nilai dalam satuan terkecil (Rupiah penuh, sen untuk USD)
- Validasi: harga > 0, qty > 0, diskon ≤ subtotal, DP ≤ total
- Audit trail wajib untuk setiap transaksi keuangan
- Periode tutup buku: jangan izinkan edit transaksi periode yang sudah ditutup
- Backup data keuangan secara berkala
- Pisahkan keuangan pribadi dan usaha