Pencatatan Investasi & Hitung Untung-Rugi Otomatis
Mencatat berbagai aset investasi (saham, reksa dana, emas, kripto) dan menghitung otomatis harga modal rata-rata serta estimasi keuntungan atau kerugian saat aset dijual.
Mencatat berbagai aset investasi (saham, reksa dana, emas, kripto) dan menghitung otomatis harga modal rata-rata serta estimasi keuntungan atau kerugian saat aset dijual.
Tantangan & Kebutuhan Pengguna
Pencatatan investasi seperti saham, emas, kripto, atau reksa dana tidak bisa disamakan dengan belanja konsumtif biasa. Ketika pengguna membeli aset yang sama secara bertahap (top-up / dollar-cost averaging) di harga yang berfluktuasi, sistem harus menghitung ulang Harga Pokok Pembelian (HPP) per unit secara akurat. Selain itu, pembelian aset harus memotong saldo kas tabungan, dan penjualan aset harus mengembalikan uang ke saldo kas sekaligus menghitung laba/rugi bersih (*realized P/L*).
Dana yang dibelikan aset investasi tidak lenyap dari pembukuan kas; ia bertransformasi menjadi unit kepemilikan dengan nilai HPP rata-rata tertimbang yang terus bergerak.
Solusi & Cara Kerja
Modul investasi dirancang dengan arsitektur tiga tabel yang saling terhubung: `investment` (menyimpan posisi kepemilikan aktif dan `avg_price`), `investment_tx` (menyimpan histori mutasi `buy` dan `sell`), serta tabel arus kas (`cashflowexpense` dan `cashflowincome`). Saat pengguna melakukan top-up pembelian, server menghitung HPP baru dengan rumus rata-rata tertimbang `((oldQty * oldAvg) + safeTotalNum) / newQty`. Saat pengguna menjual sebagian atau seluruh unitnya, server menghitung `hpp = avg_price * qty_jual`, mencari selisihnya terhadap nilai jual bersih (`pl = total_jual - hpp`), menyisipkan dana masuk ke `cashflowincome`, dan otomatis mengubah status aset menjadi `'closed'` apabila sisa unit mencapai `0`.
Berikut adalah implementasi perhitungan HPP Moving Average saat top-up di `src/app/api/investment/route.ts` dan kalkulasi Realized P/L saat penjualan di `src/app/api/investment/[uuid]/sell/route.ts`:
Detail & Hal yang Diperhatikan
- Guardrail Prasyarat Anggaran (HTTP 422): Pembelian aset ditolak jika kantong belum memiliki anggaran pengeluaran berkategori `'Investasi'`, dan penjualan ditolak jika belum memiliki sumber pendapatan bertipe `'Investasi'` agar integritas laporan anggaran terjaga.
- Presisi Kuantitas Desimal Gaya Indonesia: Mendukung input pecahan dengan koma (misal `4,5` gram emas atau unit kripto) yang divalidasi dengan regex `/^[0-9]*(,[0-9]*)?$/`, dikonversi ke titik desimal standar, dan dikirim sebagai string ke MySQL agar tidak terpotong pembulatan integer.
- Validasi Kepemilikan Maksimum: Endpoint penjualan menolak transaksi jika `safeQtyNum > Number(inv.qty)` untuk mencegah saldo unit bernilai negatif (*short selling* tidak disengaja).