📐 Dokumentasi Formula Template
Dokumentasi lengkap syntax formula template untuk kalkulator dinamis di KalKuu.
Struktur Dasar
Formula template terdiri dari satu atau lebih baris expression. Setiap baris memiliki format:
result_key = expressionContoh Sederhana
nilai_akhir = pokok * (1 + bunga / 100)
total = pokok + setoranPemisah Antar Formula
Pemisah antar formula mendukung dua cara (bisa dicampur):
| Pemisah | Contoh |
|---|---|
| Enter (newline) | Satu formula per baris |
Titik koma (;) | nilai_akhir = pokok * bunga; total = pokok + setoran |
💡 Cara kerja backend: Semua \n di-convert ke ; terlebih dahulu, lalu di-split by ;. Jadi keduanya setara.
Penulisan Variabel {{ }}
Semua variable wajib menggunakan {{ }}. Backend otomatis men-strip {{ dan }} sebelum evaluasi.
{{nilai_akhir}} = {{pokok}} * pow(1 + {{bunga}}/100, {{periode}}) // ✅ standard
{{total}} = {{pokok}} + {{setoran}} // ✅ standard📌 Konvensi baku Kalkuu: Selalu gunakan {{ }} — ini memudahkan identifikasi mana variable dan mana fungsi/keyword.
Chaining (Variabel Berantai)
Hasil dari baris sebelumnya bisa digunakan di baris berikutnya:
{{pkp_tahunan}} = {{penghasilan}} * 12 - ptkp({{status_ptkp}})
{{pph_terutang}} = {{pkp_tahunan}} * 0.05
{{pph_periode}} = {{pph_terutang}} / 12⚠️ Urutan penting. Variabel harus didefinisikan dulu sebelum dipakai.
Variabel & Input Field
Variable dari Input
Variable input berasal dari name di inputFields. Semua variable input otomatis tersedia di environment formula.
// inputFields — CMS admin panel
[
{ "name": "pokok", "type": "currency", "label": "Jumlah Awal" },
{ "name": "bunga", "type": "percentage", "label": "Suku Bunga" },
{ "name": "periode", "type": "number", "label": "Jangka Waktu" }
]// Di formula, langsung pakai nama field:
{{nilai_akhir}} = {{pokok}} * pow(1 + {{bunga}}/100, {{periode}})Tipe Input Field
| Tipe | Keterangan | Contoh |
|---|---|---|
number | Angka biasa | periode = 10 |
currency | Mata uang (Rp) | harga_rumah = 500000000 |
percentage | Persentase (%) | bunga = 7.5 |
select | Pilihan dengan options | mode = 1 |
year | Tahun | tenor = 15 |
Select Field & Opsi
Field select punya options — array { value, label }. Value yang dikirim ke formula:
{
"name": "mode",
"type": "select",
"label": "Mode Perhitungan",
"options": [
{ "value": "1", "label": "PPh 21 Karyawan" },
{ "value": "2", "label": "PPh 21 Freelance" },
{ "value": "3", "label": "Karyawan+Freelance" }
]
}💡 Value harus numerik supaya bisa langsung dipakai di formula. "1" akan di-parse jadi 1.0.
📌 Segmented Pill: Jika type="select" dan name="mode", frontend otomatis render sebagai segmented pill (bukan dropdown).
Field Hasil (Output)
Key di sisi kiri (LHS) harus cocok dengan key di resultFields:
// resultFields
[
{ "key": "nilai_akhir", "label": "Nilai Akhir", "format": "currency" },
{ "key": "total_bunga", "label": "Total Bunga", "format": "currency" }
]
{{nilai_akhir}} = {{pokok}} * pow(1 + {{bunga}}/100, {{periode}}) // ✅
{{total_bunga}} = {{nilai_akhir}} - {{pokok}} // ✅Input Kondisional
Field input bisa punya condition — field hanya muncul jika kondisi terpenuhi.
Syntax Condition
| Operator | Arti |
|---|---|
== | Sama dengan |
!= | Tidak sama dengan |
|| | OR |
&& | AND |
{
"name": "penghasilan",
"type": "currency",
"label": "Gaji Karyawan/Bulan",
"condition": "mode==1||mode==3" // muncul hanya di mode 1 dan 3
}📌 Jika field disembunyikan (condition false), variable tetap dikirim ke formula dengan nilai 0.
Perilaku di Frontend
- • Field dengan condition
false→ hidden (opacity-0,max-h-0) - • Field dengan condition
trueatau tanpa condition → selalu visible - • Transisi smooth antar mode
Konversi Otomatis
: → / (Indonesian Division)
Karena banyak pengguna Indonesia mengetik : untuk pembagian, backend otomatis mengkonversi : menjadi /.
{{nilai_akhir}} = {{pokok}} * (1 + {{bunga}} : 100) // ditulis pakai :
{{nilai_akhir}} = {{pokok}} * (1 + {{bunga}} / 100) // dievaluasi sebagai /⚠️ Ternary ? : tetap aman. Backend mendeteksi ? sebelum :, jadi ternary operator tidak ikut terkonversi.
^ → pow() (Power Operator)
{{nilai_akhir}} = {{pokok}} * (1 + {{bunga}}/100) ^ {{periode}}
// Dikonversi menjadi:
{{nilai_akhir}} = {{pokok}} * pow(1 + {{bunga}}/100, {{periode}})Fungsi Bawaan
Semua fungsi berikut tersedia di dalam formula:
| Fungsi | Deskripsi | Contoh |
|---|---|---|
round(x) | Pembulatan ke integer terdekat | round(3.7) → 4 |
floor(x) | Pembulatan ke bawah | floor(3.7) → 3 |
ceil(x) | Pembulatan ke atas | ceil(3.2) → 4 |
abs(x) | Nilai absolut | abs(-5) → 5 |
pow(x, y) | Pangkat (x^y) | pow(2, 3) → 8 |
sqrt(x) | Akar kuadrat | sqrt(16) → 4 |
log(x) | Logaritma natural | log(2.718) → 1 |
max(x, y) | Nilai maksimum | max(5, 10) → 10 |
min(x, y) | Nilai minimum | min(5, 10) → 5 |
ProFungsi Lanjutan (Pro)
Pengguna tier Kreator Pro dan Tim Keuangan memiliki akses ke logika kompleks dan fungsi finansial tingkat lanjut:
| Fungsi | Deskripsi | Contoh |
|---|---|---|
IF(cond, trueVal, falseVal) | Percabangan logika (If-Else) | IF(umur > 17, 1000, 0) |
pmt(rate, nper, pv) | Hitung cicilan pinjaman (bunga tetap) | pmt(0.01, 12, 100000000) |
tax_pph21(pkp) | Pajak progresif PPh 21 (aturan 2024) | tax_pph21(600000000) → pajak_terutang |
Variabel Bawaan
multiplier
Nilai pengali untuk Dana Darurat, diturunkan dari status_pekerjaan:
| status_pekerjaan | multiplier | Keterangan |
|---|---|---|
1 | 6 | Lajang (6× pengeluaran) |
2 | 9 | Menikah (9× pengeluaran) |
3+ | 12 | Freelance/Wiraswasta (12× pengeluaran) |
Contoh penggunaan:
{{dana_darurat}} = {{pengeluaran_bulanan}} * multiplierBuilt-in Function: ptkp(kode)
Mengembalikan nilai PTKP (Penghasilan Tidak Kena Pajak) tahunan berdasarkan kode numerik. Input status_ptkp di CMS harus pakai value angka (1-8):
| Kode | Status | Nilai PTKP |
|---|---|---|
1 | TK/0 — Tidak Kawin | Rp 54.000.000 |
2 | TK/1 — Tidak Kawin, 1 Tanggungan | Rp 58.500.000 |
3 | TK/2 — Tidak Kawin, 2 Tanggungan | Rp 63.000.000 |
4 | TK/3 — Tidak Kawin, 3 Tanggungan | Rp 67.500.000 |
5 | K/0 — Kawin | Rp 58.500.000 |
6 | K/1 — Kawin, 1 Tanggungan | Rp 63.000.000 |
7 | K/2 — Kawin, 2 Tanggungan | Rp 67.500.000 |
8 | K/3 — Kawin, 3 Tanggungan | Rp 72.000.000 |
📌 Setup CMS: Input field status_ptkp harus type: "select" dengan options value 1-8 (bukan string kode seperti "tk0"), supaya formula bisa langsung pakai ptkp(1), ptkp(6), dst.
{{pkp}} = max(0, {{penghasilan}} * 12 - ptkp({{status_ptkp}}))Formula Multi-Mode
Untuk kalkulator dengan beberapa mode, gunakan:
- Input field
mode—type: "select"dengan options numerik - Conditional fields — tampilkan field berdasarkan mode
- Ternary di formula — branching berdasarkan nilai
mode
Contoh: PPh 21 (3 Mode)
// ═══ Mode 1: Karyawan ═══
{{pkp_karyawan}} = round(max(0, {{penghasilan}} * 12 - ptkp({{status_ptkp}}) - {{iuran_pensiun}} * 12))
// ═══ Mode 2: Freelance (tahunan) ═══
{{neto_freelance}} = round({{penghasilan_bruto_tahunan}} * {{persentase_nppn}} / 100)
{{pkp_freelance}} = round(max(0, {{neto_freelance}} - ptkp(1)))
// ═══ Mode 3: Kombinasi ═══
{{biaya_jabatan}} = min(round({{penghasilan}} * 12 * 0.05), 6000000)
{{net_employment}} = round(max(0, {{penghasilan}} * 12 - {{biaya_jabatan}} - {{iuran_pensiun}} * 12))
{{net_freelance}} = round({{penghasilan_bruto_tahunan}} * {{persentase_nppn}} / 100)
{{total_net}} = {{net_employment}} + {{net_freelance}}
{{pkp_combined}} = round(max(0, {{total_net}} - ptkp({{status_ptkp}})))
// ═══ Switch Mode ═══
{{pkp_tahunan}} = round({{mode}} == 1 ? {{pkp_karyawan}} : ({{mode}} == 2 ? {{pkp_freelance}} : {{pkp_combined}}))
// ═══ Tarif Progresif ═══
{{pph_terutang}} = round({{pkp_tahunan}} <= 60000000 ? {{pkp_tahunan}} * 0.05 : ({{pkp_tahunan}} <= 250000000 ? 3000000 + ({{pkp_tahunan}} - 60000000) * 0.15 : ({{pkp_tahunan}} <= 500000000 ? 3000000 + 28500000 + ({{pkp_tahunan}} - 250000000) * 0.25 : ({{pkp_tahunan}} <= 5000000000 ? 3000000 + 28500000 + 62500000 + ({{pkp_tahunan}} - 500000000) * 0.30 : 3000000 + 28500000 + 62500000 + 1350000000 + ({{pkp_tahunan}} - 5000000000) * 0.35))))
// ═══ Hasil: Mode 1 & 3 bulanan, Mode 2 tahunan ═══
{{pph_periode}} = round({{mode}} == 2 ? {{pph_terutang}} : {{pph_terutang}} / 12)
{{take_home_pay}} = round({{mode}} == 1 ? {{penghasilan}} - {{pph_periode}} - {{iuran_pensiun}} : ({{mode}} == 2 ? {{penghasilan_bruto_tahunan}} - {{pph_periode}} : {{penghasilan}} + {{penghasilan_bruto_tahunan}} / 12 - {{pph_periode}} - {{iuran_pensiun}}))
{{tarif_efektif}} = {{pkp_tahunan}} > 0 ? round({{pph_terutang}} / {{pkp_tahunan}} * 100 * 100) / 100 : 0.0💡 Ternary pattern: mode == 1 ? hasil_mode_1 : (mode == 2 ? hasil_mode_2 : hasil_mode_3)
Penanganan Error
| Error | Penyebab | Solusi |
|---|---|---|
division by zero | Pembagi bernilai 0 | Gunakan max(pembagi, 0.000001) |
not a valid number | Hasil NaN/Inf (0/0, akar negatif) | Cek input, pastikan tidak ada operasi invalid |
duplicate result key | Dua baris pakai key LHS yang sama | Pastikan setiap key unik |
missing '=' | Baris formula tidak punya = | Format harus key = expression |
Contoh Lengkap
1. Bunga Majemuk
{{nilai_akhir}} = round({{pokok}} * pow(1 + {{bunga}}/100/12, {{periode}}*12) + {{setoran}} * ((pow(1 + {{bunga}}/100/12, {{periode}}*12) - 1) / max({{bunga}}/100/12, 0.000001)))
{{total_investasi}} = round({{pokok}} + {{setoran}} * 12 * {{periode}})
{{total_bunga}} = round({{nilai_akhir}} - {{total_investasi}})
{{roi_persen}} = round(({{nilai_akhir}} - {{total_investasi}}) / {{total_investasi}} * 100 * 100) / 1002. Dana Darurat
{{dana}} = round({{pengeluaran_bulanan}} * multiplier); {{bulan_cadangan}} = multiplier3. KPR Syariah
{{pembiayaan}} = {{harga_rumah}} - {{uang_muka}}
{{cicilan_bulanan}} = round(({{pembiayaan}} + {{pembiayaan}} * {{margin_persen}}/100 * {{tenor_tahun}}) / ({{tenor_tahun}} * 12))
{{total_pembayaran}} = round({{cicilan_bulanan}} * {{tenor_tahun}} * 12)
{{total_margin}} = round({{total_pembayaran}} - {{pembiayaan}})Perhitungan Saya (Immutable)
Hasil kalkulasi yang disimpan di Perhitungan Saya bersifat immutable — tidak berubah meskipun formula atau aturan diperbarui di kemudian hari.
| Saat save | input + hasil kalkulasi disimpan bersama |
| Saat lihat riwayat | hasil yang ditampilkan = hasil saat perhitungan dibuat |
| 5 tahun kemudian | aturan pajak berubah → riwayat lama tetap sama |
Panduan Singkat (Cheat Sheet)
| Format | key = expression |
| Pemisah | enter (newline) atau ; |
| Variable | {{nama}} (wajib pakai {{ }}) |
| Pembagian | : atau / (dua-duanya bisa) |
| Pangkat | ^ atau pow(x, y) |
| Kondisional | kondisi ? true : false |
| Fungsi | round, floor, ceil, abs, pow, sqrt, log, max, min |
| Fungsi spesial | ptkp(kode_numerik) |
| Variable built-in | multiplier (dari status_pekerjaan) |
| Condition ops | ==, !=, ||, && |
| Select options | value numerik, label deskriptif |
| Immutable | hasil save tidak berubah meski aturan update |