ERPNext v16 - Accounting (Versi BMP)

Semua penjelasan di level perilaku aplikasi, dengan jangkar codebase (branch version-16, erpnext/accounts/doctype/) supaya bisa diverifikasi; yang rawan bergeser ditandai ⚠️. Dokumen tersusun sebagai Chapter 0 (struktur & cross-check) + Chapter A-J: satu chapter per sub-workspace, plus satu chapter khusus Core Ledger - konsisten dengan diagram draw.io terlampir (grup teal = Core Ledger; 9 grup abu = sub-workspace).

Peta dokumen:

Urutan tulis mengikuti aliran bisnis: ledger → invoice → bayar → pajak → bank → lapor → rencana → aux → policy. Konvensi tiap chapter: Mesin apa → Perilaku per doctype → Lintas domain → Edge case, plus dua tambahan khusus Accounting: Delta v16 dan Catatan scope BMP.

Chapter 0 - Struktur & Cross-check

0.1 Nama modul

"Accounts" → Accounting - rename yang dulu diusulkan di issue #15155 dan terealisasi di v16.

0.2 Sembilan sub-workspace ↔ codebase ↔ dokumentasi

Catatan kaki:

0.3 Kesimpulan struktur

Kesembilan ikon cocok dengan codebase - tidak ada ikon "palsu". Tapi jantung ledger tidak ada di dialog ini: account, gl_entry, journal_entry, period_closing_voucher, ledger_health, repost_accounting_ledger, exchange_rate_revaluation hidup di workspace utama Accounting di belakang dialog ⚠️. Dialog ini hanya sub-area (pola "module home + sub-workspace" v16). Ini alasan Core Ledger mendapat chapter sendiri (A), bukan dilipat ke salah satu dari sembilan.

0.4 Register Delta v16 (level modul - sumber)

  1. Financial Report Templates - P&L dan Balance Sheet customizable, formula-driven via financial_report_row.
  2. Item Wise Tax Detail - field JSON lama → child table relasional; pajak per item kini first-class data.
  3. Tax Withholding (TDS) refactor - child table baru tax_withholding_entry.
  4. Bank Statement Import + Bank Reconciliation Tool diperkuat (MT940) - Banking naik dari "rekon manual" ke "import statement".
  5. Accounting Period - penutupan periode tidak boleh tanggal masa depan; periode jadi objek eksplisit.
  6. Transaction Logs (duplikat hash untuk Jerman) dihapus - pembersihan fitur compliance tanpa manfaat.
  7. Purchase Expense Booking - COGS terpisah dari service expense; stock accounting per Item/Item Group.
  8. Unlimited Accounting Dimensions, consolidated financial statement & trial balance multi-company, optimasi performa report.
  9. Payment Schedule dinamis - due date payment terms dihitung dari order dengan kondisi tersimpan.

(Subset yang relevan per chapter dinyatakan ulang di seksi "Delta v16" chapter tersebut.)

0.5 Bacaan perilaku (inti yang tetap sama v14→v16)

  1. Semua jalan ke gl_entry yang immutabel; journal_entry pintu manual; dokumen transaksi mem-posting sendiri.
  2. Report = proyeksi GL; v16 hanya menambah mesin template di atasnya, bukan mengubah sumber kebenaran.
  3. accounts_settings tetap single doctype policy (frozen date, perpetual inventory, dimensi default).

0.6 Diagram

Terlampir (draw.io XML): grup teal = Core Ledger (Chapter A); 9 grup abu = sub-workspace (Chapter B-J); node bertanda "(v16)" = baru/berubah.

Chapter A - Core Ledger

Mesin apa: satu buku besar yang menjadi single source of truth finansial. Setiap fakta finansial - dari mana pun asalnya - akhirnya menjadi baris debit/kredit di tabel yang sama (GL Entry); semua laporan hanyalah proyeksi dari tabel itu; dan hanya ada dua jalan masuk: Journal Entry (tangan manusia) dan dokumen transaksi (mesin).

Perilaku per doctype:

  1. Account (erpnext/accounts/doctype/account/) - tree per company (nested set, is_group). Dua atribut penentu perilaku: root_type (Asset / Liability / Equity / Income / Expense) menentukan di laporan mana akun tampil; account_type (Bank, Cash, Receivable, Payable, Stock, Tax, Round Off, dll.) menentukan perilaku sistem terhadapnya - Receivable/Payable mengaktifkan party link, Bank/Cash menjadi tujuan Payment Entry. Hanya leaf yang boleh menerima jurnal (group = agregasi); setiap company punya pohon CoA sendiri (suffix "− PSGA"); CoA lahir dari template negara saat company dibuat, atau via Chart of Accounts Importer. Flag frozen / disabled memblokir posting ⚠️.
  2. GL Entry - baris ledger immutabel: account, debit, credit, party_type/party, against_voucher, voucher_type/no, posting_date, fiscal_year, company, cost_center, is_opening, plus field dimensi akuntansi dinamis. Tidak ada UI edit/hapus; cancel = baris pembalik (reverse entry), jejak utuh; saldo = agregasi on-the-fly, tanpa kolom saldo yang dirawat manual. Perpetual inventory menulis GL langsung saat transaksi stok (stock-in-hand ↔ COGS/expense).
  3. Journal Entry - satu-satunya pintu manual ke ledger. Child table accounts (account + debit/credit + party + cost_center + dimensi). Validasi keras saat submit: total debit = total credit, gagal = tertolak. voucher_type (Journal Entry, Bank Entry, Cash Entry, Contra, Credit/Debit Note, Opening Entry, Inter-Company ⚠️) mengubah semantik default (Opening men-set is_opening, Contra memaksa Bank/Cash di dua sisi, dll.). Multi-currency: exchange rate per baris; selisih kurs mendarat di akun gain/loss yang dikonfigurasi.
  4. Fiscal Year - periode start/end; setiap posting divalidasi jatuh di dalam FY yang ada, jika tidak error eksplisit; penanda is_opening dan sumbu konsolidasi ⚠️. (Di UI v16 mungkin tampil di bawah Accounts Settings; kepemilikan konsep di sini.)
  5. Period Closing Voucher - penutupan periode: memindahkan saldo Income−Expense ke akun target (laba ditahan) lewat entry penutup; setelah tutup buku, laporan periode itu membaca snapshot, bukan menghitung ulang dari nol.
  6. Account Closing Balance - snapshot agregasi saldo saat closing; dipakai untuk performa report (Trial Balance/BS menghitung dari snapshot + delta setelahnya, bukan jutaan baris GL) ⚠️.
  7. Cost Center - tree per company (is_group) untuk melacak ke mana biaya/pendapatan berasal; child table alokasi memungkinkan satu baris jurnal dipecah persentase ke beberapa cost center ⚠️. (Catatan UI sama seperti butir 4.)
  8. Accounting Dimension - dimensi custom unlimited (jualan v16): membuat dimensi = sistem menambah field ke semua doctype transaksi + GL Entry (implementasinya via custom field ⚠️); dimensi lalu dipakai sebagai filter laporan dan sumbu laporan keuangan per dimensi. (Catatan UI sama seperti butir 4.)
  9. Exchange Rate Revaluation - DITOLAK (bukan opsional). Meskipun katalog Fragrance Oil dari supplier global (IFF, Givaudan, Mane, dll) menggunakan patokan USD (*USD-pegged local pricing*), seluruh transaksi komersial, faktur pajak, dan hutang usaha (Account Payable) dengan distributor lokal **100% terjadi dan dicatat dalam IDR**. Karena tidak ada saldo hutang/piutang dalam valuta asing (USD) yang mengendap di neraca, maka proses revaluasi kurs di akhir bulan **tidak diperlukan sama sekali**. Selisih kurs antara tanggal PO dan tanggal Invoice dibukukan langsung ke akun *Purchase Price Variance* saat Purchase Invoice diinput (Chapter B).
  10. Repost Accounting Ledger - koreksi GL untuk dokumen sudah submit tanpa cancel: daftar voucher di child items, berjalan di background, divalidasi tidak menyentuh periode tertutup/cancel ⚠️. Operasi berat - pola async yang sama dengan Chapter System.
  11. Ledger Health (v16) - monitor integritas: memindai anomali ledger (voucher tidak balance, party tak cocok, dll.) dan melaporkan "kesehatan" buku besar ⚠️. Pengakuan jujur bahwa ledger sebesar ini butuh check-up otomatis.

Lintas domain: semua modul bisnis (Selling, Buying, Stock, Payroll, Assets) menulis ke sini; Financial Reports (Chapter F) membaca dari sini; Payment Entry (Chapter C) bergantung pada account_type Bank/Cash; AR/AP bergantung pada Receivable/Payable; System scheduler menjalankan Period Closing, Revaluation, dan Repost.

Edge case:

  1. Salah root_type = laporan rusak tanpa error apa pun - validasi angka kuat, validasi struktur lemah.
  2. Leaf yang sudah punya entry tidak bisa bebas diubah jadi group; restrukturisasi tree dengan data = operasi hati-hati ⚠️.
  3. Dimensi yang dibuat belakangan tidak mengisi baris GL lama - laporan per dimensi harus sadar batas waktu ini.
  4. ~~Multi-currency tanpa revaluation akhir periode = Balance Sheet semu.~~ - **Tidak berlaku untuk BMP** karena tidak ada hutang valas; selisih kurs diperlakukan sebagai *Purchase Price Variance* (biaya/selisih harga), bukan *Exchange Gain/Loss*.
  5. Repost massal / closing pada periode besar = beban background; frozen date & periode tertutup membatasi keduanya.

Delta v16 (subset register Chapter 0.4): Accounting Period sebagai objek eksplisit; Account Category dengan root type; Ledger Health; Account Closing Balance untuk performa report; flag "Expenses Added To Stock" yang mem-posting GL beban masuk valuasi stok.

Catatan scope BMP:

  1. Adopsi penuh: GL immutabel (event-sourced), JE sebagai satu-satunya writer manual, CoA tree, period closing, cost center.
  2. Adaptasi: Accounting Dimension di BMP = kolom terdefinisi di kode per instalasi (kita menolak DDL runtime - "unlimited" menjadi "terbatas tapi terversioning"); snapshot closing = materialized view di SQLite.
  3. Opsional: Exchange Rate Revaluation - DITOLAK** - bukan opsional. BMP dirancang untuk ekosistem transaksi lokal IDR dengan katalog USD-pegged; tidak ada hutang valas yang perlu direvaluasi. Fitur ini di-hide permanen dari modul Accounting.

Chapter B - Invoicing

Mesin apa: tempat tagihan lahir - dokumen yang mengubah fakta bisnis (barang keluar/jasa diberikan, barang masuk/biaya terjadi) menjadi klaim uang (receivable/payable) dan baris ledger. Semua dokumen di chapter ini submittable; submit = momen GL ditulis, outstanding party berubah, dan jadwal tagihan (payment schedule) aktif.

Perilaku per doctype:

  1. Sales Invoice (erpnext/accounts/doctype/sales_invoice/) - dokumen piutang. Submit menulis GL: debit Receivable, kredit Income + pajak (bila ada); status lifecycle Draft → Unpaid → Paid/Overdue/Partly Paid → (Return/Credit Note Issued). Flag perilaku penting: update_stock - invoice bisa sekaligus menjadi bukti keluar stok (billing+delivery satu dokumen; favorit UMKM karena satu kertas cukup); is_pos - pembayaran langsung lewat child payments (mode of payment); is_return - credit note = GL terbalik, bisa dialokasikan ke invoice asli atau mengambang sebagai kredit. Deferred revenue ⚠️ menunda pengakuan income lewat akun penampung. Bisa lahir dari Sales Order (Selling), Subscription (Chapter I), atau timesheet project - di v16 penambahan timesheet via API menjadi panggilan terpisah.
  2. Purchase Invoice (erpnext/accounts/doctype/purchase_invoice/) - cermin utang: kredit Payable, debit Expense/Asset/Stock. update_stock = sekaligus bukti masuk stok; is_return = debit note. Dua perilaku khusus: tax withholding - bila supplier punya Tax Withholding Category, submit otomatis memotong dan menulis Tax Withholding Entry (Chapter D); dan budget check - baris expense dengan cost center divalidasi terhadap Budget (Chapter G) ⚠️. v16: aksi hold/unhold invoice diekspos sebagai document method ⚠️. **USD-Pegged Local Pricing (Domain Parfum):** Saat Purchase Invoice diinput, admin finance menginput nilai murni dalam IDR. Jika ada selisih antara nilai IDR di Purchase Order (hasil konversi katalog USD × kurs hari-PO) dan nilai IDR di Invoice akhir (akibat fluktuasi kurs atau kebijakan kurs distributor), selisih tersebut **tidak** dibukukan ke akun *Exchange Gain/Loss* (karena secara legal tidak ada hutang valas), melainkan ke akun **Purchase Price Variance** (Selisih Harga Pembelian). Laporan *Item-wise Purchase History* (Chapter D) akan menampilkan kolom referensi USD di samping realisasi IDR agar Owner/R&D bisa melihat tren harga global vs pengeluaran kas.
  3. POS Profile - konfigurasi layar kasir per user/company: warehouse sumber, akun write-off, daftar mode of payment, pajak default, grup item. Perilaku: menentukan seluruh perilaku POS tanpa menyentuh kode.
  4. POS Opening Entry - buka shift kasir dengan uang laci per mode pembayaran; status Open. Perilaku: tanpa opening, POS Invoice tidak bisa dibuat - shift adalah unit audit kasir.
  5. POS Invoice - Sales Invoice rasa kasir: pembayaran langsung (tunai/non-tunai), stok keluar seketika dari warehouse POS, pembulatan (round off) ke akun yang dikonfigurasi.
  6. POS Closing Entry - tutup shift: menghitung expected vs actual cash per mode; selisih mendarat di akun write-off; dan - ini kuncinya - mengonsolidasikan semua POS Invoice shift menjadi satu Sales Invoice konsolidasi ⚠️, sehingga ledger tidak kebanjiran ratusan invoice kasir per hari.
  7. Dunning - surat/tagihan denda atas invoice overdue: membawa dunning fee + bunga; menambah upaya penagihan ke timeline dan (⚠️) dapat mem-posting denda ke receivable lewat JE. Lahir dari invoice yang statusnya Overdue.
  8. Payment Terms Template - aturan cicilan/jatuh tempo sebagai master: persentase per termin + credit days/months, basis due date (tanggal invoice vs tanggal penerimaan barang). Dipasang di Customer/Supplier/Order; saat invoice submit, template men-generate child Payment Schedule.
  9. Payment Schedule - child table di invoice/order: due_date + payment_amount per termin; menggerakkan AR/AP aging buckets, status Overdue per termin, dan menjadi sasaran alokasi Payment Entry (Chapter C). v16: due date dinamis dengan kondisi tersimpan saat diambil dari order.
  10. Pricing Rule - mesin diskon/harga/gratis: kondisi (item/grup/brand/party/qty/minimal nilai/masa berlaku) → aksi (diskon %, rate, free item); prioritas menyelesaikan konflik bila beberapa rule cocok; diterapkan saat baris transaksi diambil (client) dan divalidasi server ⚠️. Promotional Scheme = induk beberapa rule ⚠️.
  11. **Selisih kurs vs kenaikan harga:** Selisih IDR antara PO dan PI bisa disebabkan oleh (a) fluktuasi kurs USD→IDR, atau (b) distributor mengubah harga USD. Admin finance harus paham pembeda ini - yang (a) masuk Purchase Price Variance, yang (b) adalah kenaikan harga nyata yang harus dilaporkan ke Owner untuk negosiasi/budgeting. Laporan Item-wise Purchase History dengan kolom USD referensi membantu memisahkan kedua kasus ini.

Lintas domain: submit invoice = menulis ke Core Ledger (Chapter A); pajak dibaca dari Chapter D; Payment Schedule dikonsumsi Chapter C (alokasi & aging); update_stock menyentuh Stock (warehouse, valuation, COGS pada perpetual); item & price list dari Selling/Stock; Budget (Chapter G) memvalidasi PI; Subscription (Chapter I) melahirkan SI berulang.

Edge case:

  1. update_stock + Delivery Note/Purchase Receipt untuk fakta yang sama = stok bergerak dua kali - user harus memilih satu jalur; sumber kebingungan klasik.
  2. Status Overdue dihitung dari due date vs hari ini; tanpa recomputation (akses/scheduled) status bisa basi ⚠️.
  3. Credit note yang tidak dialokasikan = kredit mengambang (advance) - butuh reconciliation (Chapter C) agar tidak jadi "uang hantu".
  4. POS: opening salah → closing ikut salah; selisih kas kecil yang rutin di-write-off bisa menyembunyikan kebocoran bila akun write-off tidak pernah diaudit.
  5. Payment terms diubah setelah submit tidak meregenerasi schedule ⚠️ - koreksi termin = koreksi manual per baris.
  6. Pricing rule yang cocok diam-diam = harga "tiba-tiba diskon"; admin butuh detail rule di form untuk memahami kenapa (debuggability).

Delta v16 (subset register Chapter 0.4): Payment Schedule due date dinamis; Item Wise Tax Detail (child table) merapikan rincian pajak per baris invoice; timesheet billing via API terpisah; hold/unhold PI sebagai document method; penanganan negative grand total.

Catatan scope BMP:

  1. Adopsi penuh: Sales/Purchase Invoice submittable dengan update_stock (satu dokumen untuk UMKM), is_return, payment terms/schedule, status lifecycle.
  2. Adaptasi: Pricing Rule → versi sederhana dulu (daftar diskon per item/party + masa berlaku); mesin free-item & prioritas kompleks = fase lanjut.
  3. Tunda: keluarga POS (Profile/Opening/Invoice/Closing) - kandidat fase 2; UMKM non-retail tidak membutuhkannya, dan shift-kasir menambah permukaan audit yang besar.
  4. Opsional: Dunning - penagihan UMKM terjadi di WhatsApp, bukan surat formal; biarkan mati sampai ada permintaan nyata.

Chapter C - Payments

Mesin apa: sisi kas dari buku besar - tempat uang benar-benar bergerak masuk/keluar dan klaim (receivable/payable) dilunasi, dialokasikan, atau dibatalkan alokasinya. Jika Chapter B menciptakan klaim, Chapter C menutupnya; dan karena akurasi AR/AP tidak boleh bergantung pada GL semata, chapter ini punya ledger kedua khusus pembayaran (Payment Ledger).

Perilaku per doctype:

  1. Payment Entry (erpnext/accounts/doctype/payment_entry/) - dokumen pembayaran inti. payment_type: Receive (uang masuk: debit Bank/Cash, kredit Receivable), Pay (kebalikan), Internal Transfer (Bank→Bank dalam company yang sama). Child table references mengalokasikan pembayaran ke invoice/JE tertentu (allocated_amount); sisa yang tidak dialokasikan otomatis menjadi advance milik party. Child deductions menampung bank charge/write-off/selisih kurs ke akun yang ditunjuk. Multi-currency: exchange rate per sisi; gain/loss kurs diposting otomatis. Submit menulis GL dan Payment Ledger, memperbarui outstanding invoice + paid_amount di Payment Schedule ⚠️. Akun tujuan Bank/Cash diambil dari default Mode of Payment per company.
  2. Payment Request - permintaan bayar sebagai dokumen: Inward (menagih customer - bisa mengirim link/email pembayaran via payment gateway; sukses di gateway = Payment Entry tercipta otomatis ⚠️) atau Outward (mengajukan pembayaran supplier, biasanya berlanjut ke Payment Order/Entry). Status lifecycle Requested → Initiated → Paid/Failed ⚠️.
  3. Payment Order - batch pembayaran keluar untuk diproses bank/integrasi: kumpulan reference dalam satu dokumen; jembatan ke file bank/transfer massal ⚠️. Pola enterprise: satu persetujuan untuk banyak pembayaran.
  4. Payment Reconciliation - alat mencocokkan pembayaran tak beralokasi (advance atau pembayaran berdiri sendiri) dengan invoice yang masih terbuka per party. Perilaku: dua daftar (unallocated payments vs unpaid invoices) → user memilih pasangan → alokasi tercipta. Ini penyelamat untuk alur "transfer masuk dulu, invoice menyusul" yang sangat umum di UMKM.
  5. Unreconcile Payment - kebalikan #4: membatalkan alokasi yang sudah terjadi - pembayaran kembali menjadi unallocated, outstanding invoice pulih ⚠️. Koreksi kesalahan pasang tanpa cancel dokumen.
  6. Advance Payment Ledger Entry - ledger khusus panjar/DP: tercipta saat pembayaran menjadi advance, terkonsumsi saat advance dialokasikan ke invoice. Membuat "berapa DP customer/supplier kita" menjadi angka yang bisa dilaporkan, bukan tebakan.
  7. Payment Ledger Entry - ledger paralel GL khusus relasi pembayaran ↔ klaim: setiap posting invoice dan pembayaran menulis di sini; AR/AP aging & outstanding membaca dari ledger ini, bukan agregasi GL ⚠️. Alasan keberadaannya: di GL, pembayaran dan invoice sulit dipasangkan secara andal; PLE menyimpan pasangan itu secara eksplisit (against_voucher).
  8. Mode of Payment - master cara bayar: type (Cash / Bank / Wallet / dll. ⚠️) + default account per company (child accounts). Perilaku: menentukan akun GL tujuan di Payment Entry, POS, dan pembayaran is_pos pada invoice - satu master mengendalikan ke mana semua uang "mendarat".

Lintas domain: menutup klaim dari Chapter B (invoice & Payment Schedule); menulis ke Core Ledger (Chapter A) + Payment Ledger; akun Bank/Cash & statement dari Chapter E (Banking); payment gateway dari Integrations; advance mengalir ke AR/AP aging (Chapter F); Mode of Payment dipakai POS (Chapter B).

Edge case:

  1. Pembayaran beda valuta dari invoice → gain/loss kurs harus diposting; rate salah = margin terdistorsi diam-diam (v16: rate amount diterima kini memakai posting date Payment Entry).
  2. Alokasi melebihi outstanding invoice diblokir atau melimpah jadi advance tergantung konfigurasi ⚠️ - sumber kejutan "kok jadi DP?".
  3. Internal Transfer menuntut kedua akun Bank/Cash satu company; pembayaran antar company = jalur Inter-Company Journal Entry (Chapter A), bukan Payment Entry biasa ⚠️.
  4. Unreconcile pada periode yang sudah tertutup/frozen harus diblokir - membatalkan alokasi di periode terkunci = merusak laporan yang sudah ditutup ⚠️.
  5. Cancel Payment Entry yang sudah mengalokasi = alokasi balik, invoice "hidup" lagi sebagai unpaid; status harus direkomputasi atau list AR basi.
  6. Advance yang tidak pernah direkonsiliasi = "kredit hantu" di laporan - sama dengan edge case Chapter B #3, kini punya ledger sendiri yang membuatnya terlihat (dan bisa diaudit).

Delta v16 (subset register Chapter 0.4): Unreconcile Payment sebagai alat koreksi first-class; exchange rate amount diterima mengikuti posting date Payment Entry; permission fixes pada Payment Reconciliation & alat rekonsiliasi.

Catatan scope BMP:

  1. Adopsi penuh: Payment Entry (Receive/Pay/Internal Transfer + references + deductions + advance), Mode of Payment, dan Payment Ledger sebagai sumber kebenaran outstanding/aging - akurasi AR/AP adalah nyawa UMKM.
  2. Adopsi: Payment Reconciliation + Unreconcile - alur "transfer dulu, invoice menyusul" dan "salah pasang" adalah keseharian UMKM; keduanya harus ada dan harus sederhana (dua daftar → pasang/batalkan).
  3. Tunda: Payment Request + Payment Order + payment gateway - UMKM membayar/menagih via transfer bank manual; batch payment order = kebutuhan enterprise. Masuk fase lanjut bersama POS.

Chapter D - Taxes

Mesin apa: lapisan yang menempel di atas transaksi - mengubah baris pajak dari "ketikan manual" menjadi kalkulasi beraturan: template memberi baris default, rule memilih template otomatis, item bisa menimpa rate, dan withholding memotong pembayaran sebelum uang keluar. Semua baris pajak akhirnya menulis GL ke akun pajak saat dokumen submit (Chapter A).

Perilaku per doctype:

  1. Sales Taxes & Charges Template (erpnext/accounts/doctype/sales_taxes_and_charges_template/) - master baris pajak sisi jual, per company. Child taxes (Sales Taxes & Charges): account_head (akun pajak), rate, dan charge_type yang menentukan cara hitung: On Net Total (persen dari dasar), On Previous Row Amount / Total (pajak berjenjang/komposit - bergantung urutan baris), Actual (nominal tetap, mis. bea), On Item Quantity ⚠️. Perilaku: saat template dipasang ke invoice/order, barisnya disalin ke transaksi (bukan referensi) - setelah itu transaksi mandiri; template berubah tidak mengubah dokumen lama. Pajak inklusif (harga sudah termasuk pajak) didukung lewat flag inklusif ⚠️ - mengubah arah kalkulasi dasar.
  2. Purchase Taxes & Charges Template - cermin sisi beli; struktur dan perilaku sama. Di sisi beli baris Actual sering dipakai untuk ongkir/bea yang kemudian bisa ditarik ke valuasi stok lewat Landed Cost (Stock) ⚠️.
  3. Item Tax Template - override rate per item: pasangan (account_head → rate). Dipasang di Item atau dipilih per transaksi. Perilaku: baris pajak transaksi tetap dari template company, tapi rate-nya ditimpa untuk item yang punya template - satu invoice bisa mencampur PPN 11% dan 0% per item. Override hanya berlaku bila account_head cocok dengan baris pajak transaksi; tidak cocok = diam-diam diabaikan ⚠️.
  4. Tax Category - label klasifikasi untuk determinasi pajak: mis. "Dalam Negeri", "Luar Negeri", "Ekspor", "Kawasan Berikat". Melekat di Customer/Supplier/alamat/transaksi. Perilaku: sendiri tidak menghitung apa-apa - dia input bagi Tax Rule.
  5. Tax Rule - pemetaan otomatis: kondisi (tax_category, party/grup, company, rentang tanggal, alamat tagirim ⚠️) → template mana yang dipakai. Perilaku: invoice baru memilih template tanpa dipilih manusia - pola yang sama dengan Pricing Rule (Chapter B) tapi untuk pajak. Konflik dua rule yang cocok diselesaikan prioritas/first-match ⚠️.
  6. Tax Withholding Category - mesin potong pajak di sumber (PPh-style): rate, akun withholding payable, threshold tunggal & kumulatif, periode. Dipasang di Supplier. Perilaku: saat Purchase Invoice submit dan threshold terlampaui, sistem memotong: GL withholding tercipta, supplier berhak dibayar netto, dan Payment Entry (Chapter C) menghormati potongan itu. Threshold kumulatif berarti invoice ke-N dalam periode bisa terpotong sebagian saat melewati batas ⚠️. **Konteks Domain Parfum:** Di pabrik parfum, PPh 23 paling sering diterapkan pada **supplier jasa** (ekspedisi lokal, maintenance mesin, cleaning service). Supplier bahan baku (Alkohol, Fragrance Oil, Packaging) biasanya adalah PKP yang dikenakan PPN 11% tanpa withholding. Admin purchasing wajib memastikan field *Tax Withholding Category* di master Supplier **diisi dengan benar** untuk supplier jasa - jika terlewat, Purchase Invoice akan full tanpa potongan pajak, dan koreksi akhir tahun sangat menyakitkan (ini edge case paling mahal di modul Purchase, terdokumentasi di Purchase Chapter C)
  7. Tax Withholding Entry (v16) - record detail per peristiwa potong: voucher, jumlah kena pajak, jumlah potong, rentang tanggal kategori. Perilaku: membuat audit "kenapa invoice ini dipotong segini" bisa dijawab per baris, bukan rekonstruksi - hasil refactor TDS v16.
  8. Item Wise Tax Detail (v16) - child table pengganti field JSON lama: rincian pajak per item (item, rate, amount) sebagai data relasional. Perilaku: register pajak per item (dasar laporan GST/kompliance) kini queryable dan first-class - bukan string JSON yang harus diparse ⚠️.

Lintas domain: baris pajak menulis GL ke akun Tax (Chapter A) saat submit; Tax Rule membaca Tax Category dari party/alamat (Selling/Buying); Item Tax Template melekat di Item (Stock); withholding mengubah jumlah yang boleh dibayar Payment Entry (Chapter C); Item Wise Tax Detail memberi bahan register & laporan (Chapter F) dan - penting untuk Indonesia - fondasi data bagi integrasi e-Faktur eksternal nanti.

Edge case:

  1. Inklusif vs eksklusif salah set = margin terdistorsi diam-diam (harga dikira belum termasuk pajak padahal sudah).
  2. Urutan baris komposit (On Previous Row…) menentukan hasil - memindah baris mengubah angka tanpa peringatan.
  3. Item Tax Template yang account_head-nya tidak cocok baris pajak transaksi = override silent ignore ⚠️ - item "kok tetap 11%?" padahal templatenya 0%.
  4. Cancel invoice yang sudah ter-withhold harus membalik Tax Withholding Entry + GL - alur cancel yang paling rumit di modul ini ⚠️.
  5. Konflik Tax Rule = template terpilih diam-diam; user butuh visibility rule mana yang menang (debuggability, pola sama dengan Pricing Rule).
  6. Pembulatan pajak per baris vs total → selisih receh harus mendarat di akun Round Off; tanpa itu grand total ≠ jumlah GL.

Delta v16 (subset register Chapter 0.4): Item Wise Tax Detail JSON → child table relasional (#2); Tax Withholding Entry sebagai child table pelacakan detail + refactor TDS (#3).

Catatan scope BMP:

  1. Adopsi penuh: mesin baris pajak di transaksi (charge_type + kaskade), template per company, Item Tax Template - UMKM Indonesia tetap butuh PPN (11% / 0% ekspor) dan pencatatan pajak keluaran/masukan.
  2. Adopsi: Tax Withholding Category + Entry - PPh 23/4(2) atas jasa/sewa adalah keseharian B2B; threshold kumulatif wajib ada agar taat aturan tanpa spreadsheet samping.
  3. Adaptasi/sederhanakan: Tax Category + Tax Rule → fase pertama cukup default template per company + override per party; mesin rule penuh menyusul bila kombinasi tarif benar-benar banyak.
  4. Catatan strategis: Item Wise Tax Detail dipertahankan walau tanpa paket kompliance - karena dialah fondasi data integrasi e-Faktur pihak ketiga di masa depan (core menyediakan data, kompliance = app eksternal; konsisten dengan filosofi kurasi kita).

Chapter E - Banking

Mesin apa: jembatan antara catatan bank di dunia nyata dan catatan bank di ledger. Bank di luar sistem tahu uang masuk/keluar lebih dulu atau berbeda dari sistem; chapter ini menutup selisih itu: statement masuk sebagai Bank Transaction, lalu direkonsiliasi - dipasangkan - dengan Payment Entry/JE yang sudah ada (atau dibuat baru untuk baris yang tak punya pasangan, seperti biaya bank). Hasil akhirnya: saldo GL akun Bank = saldo bank sesungguhnya, dan setiap baris statement punya penjelasan.

Perilaku per doctype:

  1. Bank (erpnext/accounts/doctype/bank/) - master paling sederhana: nama bank + kode SWIFT ⚠️. Hanya pemberi identitas bagi Bank Account.
  2. Bank Account - dua rasa dalam satu doctype: akun company (tautan Bank + GL Account bertipe Bank + nomor akun; target rekonsiliasi dan integrasi) dan akun party (rekening customer/supplier untuk tujuan pembayaran ⚠️). Perilaku: akun company menentukan pasangan GL account yang saldonya akan diuji kebenaran; akun party mengalir ke detail pembayaran di Payment Entry (Chapter C). v16: API pembuat bank account party dihapus - kini lewat jalur new_doc standar.
  3. Bank Transaction - satu baris statement = satu record: tanggal, deposit/withdrawal, reference number, deskripsi, tebakan party, status Unreconciled → Reconciled ⚠️, plus child table alokasi (Payment Entry/JE mana yang menyerap baris ini, berapa allocated_amount). Perilaku kunci: record ini tidak menulis GL sendiri - dia hanya menunjuk dokumen pembayaran yang menulis GL; rekonsiliasi = memasang penunjukan itu.
  4. Bank Statement Import - wizard impor statement (CSV terpetakan kolom, atau MT940 dengan mapping reference per transaksi di v16) → menciptakan Bank Transaction massal. Perilaku: deduplikasi berbasis reference/hash agar impor ulang tidak menggandakan baris ⚠️ - tapi bank dengan reference lemah tetap rawan duplikat.
  5. Bank Reconciliation Tool - cockpit harian akuntan: dua daftar berdampingan untuk satu Bank Account + periode - Bank Transaction unreconciled vs Payment Entry/JE sistem. Aksi per baris: match ke pembayaran yang ada (bisa split satu baris ke beberapa pembayaran), atau create on the spot (baris biaya bank → JE baru dibuat saat itu juga). Perilaku: match = alokasi tercipta + status Reconciled; selisih kecil bisa langsung di-write-off ⚠️. Alat ini yang mengubah "transfer masuk misterius" menjadi piutang yang lunas terdokumentasi.
  6. Bank Clearance - pola lama yang lebih sempit: untuk akun Bank, daftar pembayaran/cek sistem diberi clearance date saat terbukti lolos bank ⚠️. Bukan matching statement, melainkan penandaan "cek saya sudah cair". Masih hidup berdampingan dengan Reconciliation Tool - warisan era cek.

Lintas domain: Bank Account menuntut GL Account bertipe Bank (Chapter A); rekonsiliasi mengalokasikan Payment Entry (Chapter C) atau melahirkan JE (Chapter A) untuk biaya/bunga; statement import memakai pola wizard impor yang sama dengan Data Import (Framework); akun party memberi tujuan transfer di Payment Entry; hasil rekonsiliasi = kepercayaan angka kas di Financial Reports (Chapter F).

Edge case:

  1. Impor statement duplikat saat reference bank lemah = Bank Transaction kembar; dedup bukan jaminan ⚠️.
  2. Satu transfer gabungan melunasi tiga invoice → alokasi wajib split; alat harus mendukung multi-alokasi per baris, kalau tidak user mengakali lewat JE manual.
  3. Baris biaya bank/bunga/admin tanpa pasangan sistem: bila tidak di-create-on-the-spot, menumpuk sebagai unreconciled abadi - "sampah" yang merusak kepercayaan daftar.
  4. Tebakan party dari deskripsi bank = heuristik; salah tebak + user tidak cek = alokasi salah yang sah secara sistem.
  5. Dua alat tumpang tindih (Clearance warisan vs Reconciliation modern) = kebingungan "pakai yang mana" ⚠️ - admin lama setia Clearance, admin baru belajar Reconciliation.
  6. Cancel Payment Entry yang sudah di-match = Bank Transaction kembali Unreconciled; status harus direkomputasi atau daftar rekonsiliasi basi.

Delta v16 (subset register Chapter 0.4): Bank Statement Import diperkuat - MT940 memetakan reference per transaksi (:61 customer_reference) sehingga narasi baris lebih akurat (#4); permission fixes pada Reconciliation Tool & fungsi whitelisted; penghapusan API make_bank_account.

Catatan scope BMP:

  1. Adopsi penuh: Bank, Bank Account (company + party), Bank Transaction, Statement Import, dan Reconciliation Tool dengan tiga aksi (match / split / create-on-the-spot). Alur "mutasi bank dulu, dokumen menyusul" adalah keseharian UMKM - rekonsiliasi yang mudah adalah pembeda hidup-mati kepercayaan angka kas.
  2. Adaptasi: impor CSV dulu (format bank Indonesia bervariasi; mapping kolom fleksibel), MT940/ISO camt menyusul bila relevan; tebakan party sederhana (cocok nama/amount) dengan konfirmasi eksplisit, bukan auto-allocate.
  3. Tunda/tolak: auto-sync integrasi bank (API bank terbuka untuk UMKM Indonesia praktis belum ada - manual CSV adalah realitas) dan Bank Clearance warisan cek (cek hampir mati di UMKM; Reconciliation Tool menutup kebutuhannya). Satu alat rekonsiliasi, bukan dua.

Chapter F - Financial Reports

Mesin apa: tidak ada "data laporan" - semua laporan adalah proyeksi on-the-fly dari dua ledger: GL (untuk posisi & kinerja) dan Payment Ledger (untuk piutang/utang). Laporan = agregasi dengan dimensi (company, periode, cost center, dimensi akuntansi, pohon akun). v16 mengubah mesin ini dari layout tetap menjadi formula-driven: pernyataan keuangan bisa didefinisikan sendiri lewat template. Konsekuensi prinsipilnya: laporan tidak pernah "salah hitung" - tapi mereka mewarisi diam-diam semua kesalahan struktur di Chapter A.

Perilaku per laporan/mesin:

  1. General Ledger - laporan paling atomik: semua baris GL per akun/periode dengan saldo berjalan + saldo awal. Filter: akun, periode, cost center, dimensi, party, voucher. Perilaku kunci: drill-down auditor - dari angka mana pun di BS/P&L → baris GL → voucher sumber → dokumen operasional. Navigasi "angka → bukti" ini yang membuat pembukuan bisa diaudit tanpa ekspor spreadsheet.
  2. Trial Balance - per akun: total debit/kredit + saldo awal/akhir; leaf di-roll up ke group mengikuti pohon akun. Perilaku: cek pertama "debit = kredit"; versi consolidated multi-company ada di v16. Bila Trial Balance tidak balance, sesuatu rusak di ledger - laporan ini adalah alarm paling dini.
  3. Balance Sheet - posisi pada satu tanggal; seksi per root_type Asset/Liability/Equity. Perilaku performa: membaca snapshot closing (Account Closing Balance) + delta setelah tanggal closing, bukan menghitung jutaan baris GL dari nol ⚠️. Filter dimensi/cost center/company tersedia; bisa konsolidasi.
  4. Profit & Loss - kinerja per periode; seksi Income/Expense per root_type + baris laba bersih. Perilaku: periode vs tanggal posting (bukan tanggal dokumen) menentukan baris masuk ke periode mana baris; bisa dipotong per dimensi/cost center/project - laporan P&L per proyek/cabang lahir dari sini.
  5. Cash Flow - diturunkan dari gerakan GL akun Bank/Cash, diklasifikasikan Operating/Investing/Financing lewat pemetaan kategori ⚠️. Bukan statement tersimpan - maka kejujurannya bergantung pada kebenaran pemetaan kategori, bukan pada mesinnya.
  6. AR / AP Aging - membaca Payment Ledger Entry (Chapter C), bukan GL - karena pasangan pembayaran↔invoice hanya andal di sana. Bucket umur jatuh tempo configurable (0-30, 31-60, dst.); per party dan per invoice. Perilaku: laporan yang paling "hidup" bagi UMKM - siapa nợ berapa dan seberapa basi; v16 membuatnya configurable (kolom/bucket/range) ⚠️.
  7. Financial Report Template + financial_report_row (v16) - mesin baru: baris laporan didefinisikan sebagai formula yang merujuk akun/group/baris lain (rasio custom, seksi custom, urutan custom). Perilaku: P&L/BS berubah dari "layout bawaan" menjadi "pernyataan yang kamu rancang sendiri" tanpa kode - evolusi terbesar mesin report sejak awal, dan alasan v16 menyebutnya customizable, formula-driven statements.

Lintas domain: membaca GL (Chapter A) dan Payment Ledger (Chapter C); dimensi & cost center dari Chapter A; periode/frozen date dari Chapter J; aging memberi bahan prioritas ke Dunning (Chapter B) dan rekonsiliasi (Chapter C); semua laporan bisa dijadwalkan & di-email via Auto Email Report (Framework) dan di-export xlsx - pola output yang sama dengan modul lain.

Edge case:

  1. Salah root_type (Chapter A) tampil di sini sebagai "salah seksi" di BS/P&L tanpa error - laporan mewarisi kesalahan struktur secara diam-diam.
  2. Snapshot vs Repost: bila Repost Accounting Ledger mengubah entry sebelum tanggal closing setelah snapshot dibangun, snapshot menjadi basi - laporan salah sampai snapshot direkomputasi ⚠️.
  3. Filter dimensi/cost center yang dalam bisa mem-bypass snapshot dan menghantam GL mentah → lambat di data besar; momen "kenapa laporan ini lama" biasanya ini.
  4. Konsolidasi multi-company tanpa eliminasi transaksi inter-company = omzet/aset double counting ⚠️.
  5. Mengubah bucket aging = mereklasifikasi sejarah - membandingkan aging bulan ini vs bulan lalu jadi apel-ke-jeruk bila bucket ikut diubah.
  6. Klasifikasi Cash Flow berbasis pemetaan manual: akun salah kategori = statement menyesatkan walau angkanya "benar" ⚠️.

Delta v16 (subset register Chapter 0.4): Financial Report Templates formula-driven via financial_report_row (#1); consolidated trial balance & consolidated financial statements (#8); configurable receivables/payables reports (#8); optimasi performa report (#8).

Catatan scope BMP:

  1. Adopsi penuh: GL drill-down (angka→voucher→dokumen), Trial Balance, Balance Sheet, P&L, AR/AP aging dari Payment Ledger, Cash Flow (klasifikasi sederhana). Ini inti "kepercayaan angka" BMP.
  2. Adaptasi: mesin template formula-driven = fase 2; UMKM cukup statement standar dulu - tapi arsitektur "report = proyeksi + definisi baris" dipertahankan sejak awal supaya template bisa ditambah tanpa rombak mesin.
  3. Adopsi (pola Framework): semua laporan export xlsx + schedulable + auto-email - laporan yang tidak bisa dikirim terjadwal tidak akan dipakai UMKM.
  4. Keunggulan BMP yang disengaja: snapshot closing = materialized view SQLite (keputusan Chapter A) - performa BS/Trial Balance tanpa mengorbankan immutability.

Chapter G - Budget

Mesin apa: pengendali boleh tidaknya uang direncanakan/dikeluarkan - bukan penghitung. Budget memasang pagar di sekitar cost center untuk satu fiscal year; transaksi yang menyentuh akun ter-budget diperiksa terhadap pagar itu pada beberapa titik (komitmen & realisasi), dan melanggar pagar bisa berarti diblokir, diperingatkan, atau dibiarkan - tergantung kebijakan yang dipilih.

Perilaku per doctype:

  1. Budget (erpnext/accounts/doctype/budget/) - record submittable: budget_against (Cost Center, atau Project ⚠️) + fiscal year + child accounts (akun ter-budget + budget_amount). Dua pasang kebijakan inti: aksi bila anggaran tahunan terlampaui dan aksi bila anggaran bulanan kumulatif terlampaui, masing-masing bernilai Stop / Warn / Ignore; plus flag terpisah per titik cek (Material Request / Purchase Order / booking aktual ⚠️). Perilaku saat transaksi submit (MR/PO/PI): sistem membandingkan kumulatif belanja akun+cost center terhadap budget dan mengeksekusi aksi - Stop = error eksplisit yang memblokir, Warn = lolos dengan peringatan, Ignore = senyap. Bila monthly_distribution terpasang, pagarnya per bulan mengikuti persentase distribusi, bukan rata 12.
  2. Monthly Distribution - master proration: child months (bulan + percentage_allocation, wajib total 100 ⚠️). Perilaku: mengubah budget tahunan menjadi pagar bulanan yang tidak rata - berguna untuk bisnis musiman (lebaran, panen, tahun ajaran).
  3. Budget Variance Report - selisih rencana vs kenyataan: per akun, per periode (bulan/kuartal/tahun), membaca actual dari GL (Chapter A) dan membandingkannya dengan record Budget; variance = actual − budget. Perilaku: laporan ini yang mengubah Budget dari "polisi" menjadi "alat belajar" - di mana pagar selalu tertabrak, di sana budgetnya salah atau disiplinnya bocor.

Lintas domain: Budget berdiri di atas Cost Center & Fiscal Year (Chapter A); titik ceknya hidup di Buying (Material Request, Purchase Order) dan Invoicing (Chapter B) (Purchase Invoice); actual dibaca dari GL (Chapter A); keluarganya laporan (Chapter F) meski workspace-nya Budget.

Edge case:

  1. Dua titik cek (komitmen PO vs realisasi PI) bisa saling kejutan: PO lolos pagar, tapi saat PI masuk budget sudah habis - perilaku tergantung flag titik cek mana yang aktif; misconfig = blokir yang terasa "tiba-tiba".
  2. Warn yang terlalu sering = warn fatigue; semua orang belajar menekan OK tanpa membaca - pagar lunak yang tak dibaca sama dengan tidak ada.
  3. Belanja tanpa cost center lolos budgeting sama sekali - lubang cakupan; budget hanya sekuat disiplin pengisian cost center.
  4. Persentase Monthly Distribution ≠ 100 = validasi error atau pagar bulanan yang menyesatkan ⚠️.
  5. Revisi budget tengah tahun = cancel + buat baru (atau amend ⚠️) - riwayat pagar lama harus tetap terbaca agar variance periode lalu tidak berubah makna.
  6. Budget per company mengikuti company milik cost center; consolidated budgeting lintas company tidak native ⚠️.

Delta v16 (subset register Chapter 0.4): "enhanced budgeting" ⚠️ (detail fitur masih umum di sumber); perbaikan pesan error validasi budget assignment yang sebelumnya ambigu (dari commit branch v16) - kecil tapi penting: pesan Stop yang jelas ("sisa budget Rp X") adalah separuh kegunaan fitur ini.

Catatan scope BMP:

  1. Adopsi: Budget per cost center + fiscal year dengan trio Stop/Warn/Ignore dan titik cek di PO + PI - kontrol belanja sederhana adalah kebutuhan UMKM multi-cabang/departemen, dan trio aksi memberi keluwesan tanpa memaksa birokrasi.
  2. Adaptasi: Monthly Distribution opsional dengan default rata 1/12 bila kosong; pesan Stop wajib menyertakan angka sisa budget (konsisten prinsip "error yang bisa ditindaklanjuti").
  3. Tunda: budget against Project (Project = fase 2) dan budgeting multi-dimensi - kompleksitas yang tidak sebanding dengan profil UMKM awal.

Chapter H - Auxiliary Domains (Share Management & Subscription)

Mesin apa: dua mesin pembantu yang melayani model bisnis spesifik dan jarang dipakai oleh UMKM murni. Share Management mengelola ekuitas berbasis saham (cap table, perpindahan kepemilikan) yang relevan untuk PT tertutup/terbuka. Subscription mengelola tagihan berulang (SaaS, retainer, sewa) dengan men-generate invoice secara periodik. Keduanya berdiri di tepi modul Accounting: yang satu menyentuh Equity di CoA, yang lain melahirkan Sales Invoice.

Perilaku per doctype:

A. Share Management

  1. Shareholder (erpnext/accounts/doctype/shareholder/) - master pemegang saham (bisa individu atau entitas); membawa detail kontak dan nomor identifikasi.
  2. Share Type - kelas saham (mis. Equity, Preference) beserta nominal value per lembar. Perilaku: mendefinisikan "mata uang" ekuitas perusahaan.
  3. Share Transfer - dokumen submittable yang memindahkan sejumlah lembar dari satu Shareholder ke Shareholder lain (atau dari perusahaan ke pemegang saham saat penerbitan awal). Perilaku: memvalidasi bahwa pengirim memiliki saldo lembar yang cukup; submit = memperbarui Share Balance.
  4. Share Balance - bukan doctype yang diisi manual, melainkan view / agregasi dari riwayat Share Transfer; menampilkan berapa lembar tiap tipe saham yang dipegang tiap Shareholder saat ini.

B. Subscription 5. Subscription Plan - master paket langganan: item/jasa yang dijual, harga, dan siklus billing (bulanan/kuartalan/tahunan) + jumlah hari sebelum due date invoice dibuat. 6. Subscription - record langganan aktif per Customer + Plan. Perilaku: memiliki start_date, next_schedule_date, dan status (Active/Trialling/Cancelled/Completed). Scheduler (Framework) memeriksa record Active setiap hari; jika next_schedule_date tercapai, sistem men-generate Sales Invoice (Chapter B) baru dan menggeser tanggal jadwal berikutnya. 7. Subscription Settings (single) - policy global: apakah invoice yang di-generate otomatis langsung di-submit atau dibiarkan draft menunggu review manusia; akun pendapatan default; penanganan prorate ⚠️.

Lintas domain: Subscription adalah produsen Sales Invoice (Chapter B) yang kemudian memukul GL (Chapter A) dan memengaruhi AR Aging (Chapter F). Share Management berdiri mandiri tetapi ujung-ujungnya memetakan nilai ke akun Equity di CoA (Chapter A). Keduanya sangat bergantung pada Scheduler (Framework Chapter 3) untuk berjalan otomatis.

Edge case:

  1. Subscription yang induknya di-cancel atau Customer-nya di-disable, tapi schedulernya jalan = invoice hantu terus tercipta setiap bulan (bug klasik yang diperbaiki di v16).
  2. Subscription yang diubah Plan-nya di tengah periode = prorate calculation yang rumit dan sering salah hitung bila tidak dikonfigurasi hati-hati ⚠️.
  3. Share Transfer yang di-cancel = saldo lembar harus dikembalikan; bila ada transfer berantai (A→B→C) dan yang A→B di-cancel, saldo B dan C bisa menjadi negatif atau error.
  4. Cap table (Share Balance) di ERP sering tidak sinkron dengan akta notaris di dunia nyata karena admin lupa menginput transfer sekunder - membuat laporan ini berbahaya bila dijadikan rujukan legal tunggal.

Delta v16 (subset register Chapter 0.4): Perbaikan bug kritis di Subscription - sistem kini divalidasi untuk tidak mengaktifkan kembali (reactivate) subscription yang sudah di-cancel saat scheduler berjalan.

Catatan scope BMP:

  1. Tolak / Tunda (Share Management): Target BMP = UMKM (CV, Firma, UD, PT Perorangan) yang tidak mengelola cap table atau perdagangan saham di dalam ERP. Manajemen saham mereka ada di tangan notaris dan spreadsheet. Memasukkan ini hanya menambah beban kognitif dan permukaan UI tanpa ROI.
  2. Tolak / Adaptasi Ringan (Subscription): Model bisnis berlangganan murni (SaaS) jarang menjadi inti UMKM tradisional (toko, manufaktur, distributor). Untuk tagihan berulang sederhana (mis. sewa ruko, retainer jasa), BMP cukup mengandalkan Auto Repeat (Framework Chapter 4) yang men-duplicate dokumen invoice apa adanya. Mesin Subscription yang kompleks (prorate, trial period, plan upgrade) ditunda ke fase enterprise.

Chapter I - Accounts Settings

Mesin apa: ruang policy modul - single doctype (plus tiga pendamping) yang tidak menyimpan transaksi, tapi menentukan perilaku semua transaksi di Chapter A-H: kapan posting boleh terjadi, bagaimana stok berbicara dengan ledger, ke mana panjar dicatat, dan bagaimana CoA lahir saat setup. Pola yang sama dengan System Settings di Framework - dan pola yang sama dengan modul "Administration" BMP kita nanti.

Perilaku per doctype:

  1. Accounts Settings (erpnext/accounts/doctype/accounts_settings/) - single doctype policy; kelompok perilakunya:
  2. Accounting Period (v16) - objek periode eksplisit: start/end + status closed; menutup periode tanggal masa depan ditolak (validasi v16); periode closed memblokir posting & repost ke dalamnya - governance yang lebih granular daripada satu frozen date global.
  3. Chart of Accounts Importer - alat setup: impor CoA custom dari file terstruktur → menciptakan pohon Account massal dengan validasi root_type/account_type. Perilaku: jalan bagi company yang tidak cocok template negara - dan sumber kesalahan struktur bila file inputnya sembrono (echo edge case Chapter A #1).
  4. Account Category (v16) - lapisan klasifikasi di atas akun dengan root type ⚠️; bahan baku bagi Financial Report Templates (Chapter F) - kategori = sumbu custom untuk pernyataan keuangan custom.

Lintas domain: policy di sini menggerbangi semua penulis GL (Chapter A-E): frozen date & accounting period memblokir posting; sakelar stok-ledger menentukan apakah Stock menulis GL; flag panjar mengubah bentuk AR/AP (Chapter C/F); Importer memberi makan CoA (Chapter A); Account Category memberi makan template laporan (Chapter F).

Edge case:

  1. Frozen date dipasang saat masih ada dokumen tertahan = blokir mendadak; tanpa role pengecualian yang tepat, akuntan justru terkunci dari pekerjaannya sendiri.
  2. Perpetual vs periodic yang diganti setelah ada data = inkonsistensi valuasi-GL yang praktis tak bisa dirapikan lagi - keputusan satu arah ⚠️.
  3. Periode closed tapi koreksi wajib (audit menemukan kesalahan) = harus reopen - dan reopen harus diperlakukan sebagai peristiwa governance (siapa, kenapa, kapan), bukan klik biasa ⚠️.
  4. Impor CoA dengan root_type salah = laporan rusak berminggu-minggu kemudian tanpa error (pola yang sama berulang: validasi angka kuat, validasi struktur lemah).
  5. Mengubah flag policy (mis. panjar) = laporan sebelum/sesudah berbeda bentuk; user menyebutnya "angka berubah", padahal ledger tidak berubah - butuh komunikasi, bukan kode.
  6. Immutable Ledger ON mengubah perilaku laporan: efek pembatalan mendarat di periode tanggal pembatalan, bukan periode dokumen asli, dan entri batal tetap terlihat di laporan (sebagai pembatalan). Finance wajib paham - ini perilaku jujur, bukan bug; komunikasikan saat menutup buku.
  7. Supplier invoice uniqueness ON dapat menolak credit/debit note yang memakai nomor sama dengan invoice dalam fiscal year yang sama - bila supplier menerbitkan dokumen koreksi bernomor identik, admin mencatat nomor unik (mis. suffix) di field Supplier Invoice No.

Delta v16 (subset register Chapter 0.4): Accounting Period sebagai objek eksplisit dengan validasi anti-masa-depan (#5); flag Expenses Added To Stock (#7); Account Category ber-root-type (penopang #1).

Catatan scope BMP:

  1. Adopsi penuh: frozen date + role pengecualian, objek periode closed, CoA importer (alat setup), dan pola single doctype policy per modul - ini persis wujud modul Administration BMP kita.
  2. Keputusan desain BMP: perpetual inventory default ON dan tidak ditawarkan sebagai toggle - satu model mental (stok selalu menulis GL) mengalahkan fleksibilitas yang hanya menghasilkan inkonsistensi; UMKM tidak butuh periodic inventory.
  3. Adaptasi: reopen periode di BMP wajib meninggalkan jejak audit (siapa/kapan/alasan) - menutup celah governance yang di ERPNext hanya berupa flag ⚠️→keputusan.
  4. Keputusan desain BMP (terverifikasi UI v16): enable_immutable_ledger = ON (satu arah, approval Owner); check_supplier_invoice_number_uniqueness = ON; delete … on deletion = OFF permanen.
  5. Catatan navigasi: Accounts Settings dapat dicapai dari dua pintu (workspace "ERPNext Settings" dan "Invoicing → Settings") - satu record, dua tautan, bukan redundansi data. Chinese Wall: pembatasan menempel di doctype, bukan di pintu; write access Accounts Settings hanya Owner/Finance.

Chapter I tertutup - dokumen ERPNext_v16 - Accounting (Versi BMP) selesai: Chapter 0 (struktur & cross-check) + A-I, seluruh sub-workspace terbedah dengan konvensi seragam, register Delta v16 sebagai sumber tunggal, dan catatan scope BMP di tiap bab yang bersama-sama membentuk register adopsi/adaptasi/tolak untuk BMP.

Ringkasan posisi BMP setelah bab ini: ledger immutabel + JE + CoA + period closing diadopsi penuh; Payment Ledger & rekonsiliasi bank diadopsi; POS, Payment Order, Subscription, Share Management, mesin template formula, dan rule-engine penuh ditunda/ditolak sesuai profil UMKM.

Modul berikutnya yang mau dibedah dengan pola yang sama - Stock/Inventory (pasangan alami Accounting lewat perpetual inventory), Buying, atau Selling?