📐 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 = expression

Contoh Sederhana

nilai_akhir = pokok * (1 + bunga / 100)
total = pokok + setoran

Pemisah Antar Formula

Pemisah antar formula mendukung dua cara (bisa dicampur):

PemisahContoh
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

TipeKeteranganContoh
numberAngka biasaperiode = 10
currencyMata uang (Rp)harga_rumah = 500000000
percentagePersentase (%)bunga = 7.5
selectPilihan dengan optionsmode = 1
yearTahuntenor = 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

OperatorArti
==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 true atau 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:

FungsiDeskripsiContoh
round(x)Pembulatan ke integer terdekatround(3.7) → 4
floor(x)Pembulatan ke bawahfloor(3.7) → 3
ceil(x)Pembulatan ke atasceil(3.2) → 4
abs(x)Nilai absolutabs(-5) → 5
pow(x, y)Pangkat (x^y)pow(2, 3) → 8
sqrt(x)Akar kuadratsqrt(16) → 4
log(x)Logaritma naturallog(2.718) → 1
max(x, y)Nilai maksimummax(5, 10) → 10
min(x, y)Nilai minimummin(5, 10) → 5

ProFungsi Lanjutan (Pro)

Pengguna tier Kreator Pro dan Tim Keuangan memiliki akses ke logika kompleks dan fungsi finansial tingkat lanjut:

FungsiDeskripsiContoh
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_pekerjaanmultiplierKeterangan
16Lajang (6× pengeluaran)
29Menikah (9× pengeluaran)
3+12Freelance/Wiraswasta (12× pengeluaran)

Contoh penggunaan:

{{dana_darurat}} = {{pengeluaran_bulanan}} * multiplier

Built-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):

KodeStatusNilai PTKP
1TK/0 — Tidak KawinRp 54.000.000
2TK/1 — Tidak Kawin, 1 TanggunganRp 58.500.000
3TK/2 — Tidak Kawin, 2 TanggunganRp 63.000.000
4TK/3 — Tidak Kawin, 3 TanggunganRp 67.500.000
5K/0 — KawinRp 58.500.000
6K/1 — Kawin, 1 TanggunganRp 63.000.000
7K/2 — Kawin, 2 TanggunganRp 67.500.000
8K/3 — Kawin, 3 TanggunganRp 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:

  1. Input field mode type: "select" dengan options numerik
  2. Conditional fields — tampilkan field berdasarkan mode
  3. 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

ErrorPenyebabSolusi
division by zeroPembagi bernilai 0Gunakan max(pembagi, 0.000001)
not a valid numberHasil NaN/Inf (0/0, akar negatif)Cek input, pastikan tidak ada operasi invalid
duplicate result keyDua baris pakai key LHS yang samaPastikan 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) / 100

2. Dana Darurat

{{dana}} = round({{pengeluaran_bulanan}} * multiplier); {{bulan_cadangan}} = multiplier

3. 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 saveinput + hasil kalkulasi disimpan bersama
Saat lihat riwayathasil yang ditampilkan = hasil saat perhitungan dibuat
5 tahun kemudianaturan pajak berubah → riwayat lama tetap sama

Panduan Singkat (Cheat Sheet)

Formatkey = expression
Pemisahenter (newline) atau ;
Variable{{nama}} (wajib pakai {{ }})
Pembagian: atau / (dua-duanya bisa)
Pangkat^ atau pow(x, y)
Kondisionalkondisi ? true : false
Fungsiround, floor, ceil, abs, pow, sqrt, log, max, min
Fungsi spesialptkp(kode_numerik)
Variable built-inmultiplier (dari status_pekerjaan)
Condition ops==, !=, ||, &&
Select optionsvalue numerik, label deskriptif
Immutablehasil save tidak berubah meski aturan update