Update besar apk finance

This commit is contained in:
Wian Drs
2026-09-11 16:03:00 +07:00
parent d42483b350
commit 4ef15c22ae
897 changed files with 98056 additions and 15979 deletions
+53
View File
@@ -0,0 +1,53 @@
# Finalisasi Budget Pengeluaran
## Ruang lingkup aktif
Modul ini mengelola budget berdasarkan **akun pengeluaran** saja. Dimensi cabang,
departemen, proyek, cost center, profit center, dan salesperson tidak digunakan
oleh UI maupun proses Budget pada versi ini.
Setiap dokumen Budget berlaku untuk satu perusahaan dan satu tahun fiskal. Nilai
tahunan merupakan akumulasi Januari sampai Desember. Pengguna dapat memasukkan
total setahun lalu membaginya rata ke 12 bulan, kemudian mengubah nominal setiap
bulan mengikuti perkembangan usaha.
## Alur dokumen
1. Buat Budget tahunan berstatus `draft`.
2. Pilih akun pengeluaran dan isi nominal per bulan.
3. Ajukan Budget menjadi `submitted`.
4. Penyetuju mengaktifkan atau menolak Budget.
5. Perubahan terhadap Budget aktif dibuat melalui revisi agar histori terjaga.
Hanya satu Budget berstatus `active` untuk kombinasi perusahaan dan tahun.
## Monitoring
- Budget: nominal akun pada Budget aktif sesuai rentang bulan.
- Realisasi: debit bersih akun pengeluaran dari jurnal posted/reversed.
- Komitmen: sisa nilai PO approved/diterima yang menggunakan akun budget dan
belum ditagihkan pada invoice supplier.
- Sisa: Budget dikurangi realisasi dan komitmen.
Budget bersifat monitoring. Proses pembuatan dan posting Jurnal tidak diubah atau
diblokir oleh Budget. Realisasi tetap dibaca dari jurnal yang telah ter-posting.
## Kompatibilitas database
Kolom dan tabel dimensi dari implementasi Tahap 13 tidak dihapus secara fisik.
Tujuannya menjaga kompatibilitas data Development/Production dan modul lain yang
mungkin telah menyimpan referensi tersebut. Modul Budget saat ini mengabaikan
kolom-kolom itu dan hanya memakai `account_id`. Bila dimensi diaktifkan kembali,
harus dibuat migration baru beserta rencana migrasi data dan pengujian akses.
## Pemeriksaan ringkas
Jalankan dari root aplikasi:
```bash
php index.php budgetcheck
php index.php budgetcheck workflow
```
Pemeriksaan workflow membuat data sementara, menguji Draft -> Submit -> Aktif ->
Revisi, lalu menghapus kembali data uji tersebut.
+78
View File
@@ -0,0 +1,78 @@
# Finalisasi Modul Aset Tetap
## Arsitektur kanonis
- Menu resmi: `Aset Tetap` → `/fixedassets`.
- Controller transaksi: `Fixedassets.php`.
- Aturan bisnis dan transaksi database: `FixedAssetService.php`.
- Query register, detail, lookup, opname, laporan: `FixedAssetModel.php`.
- `Asset.php` dan `Lokasiasset.php` hanya alias kompatibilitas. Keduanya tidak lagi boleh menulis stok, jurnal, atau aset.
## Alur perolehan
`Draft → Diajukan → Disetujui/Ditolak → Dikapitalisasi`
Dokumen pendukung wajib tersedia sebelum pengajuan. Pembuat dan approver dipisahkan, kecuali Master Admin yang memang memiliki seluruh kewenangan aplikasi.
### Input langsung
- `Buat jurnal kapitalisasi`: debit akun aset, kredit akun lawan yang dipilih.
- `Hubungkan jurnal posted`: tidak membuat jurnal kedua; jurnal sumber hanya boleh dipakai satu aset.
- `Saldo awal/tanpa jurnal baru`: khusus migrasi/saldo awal yang memang telah direkonsiliasi. Alasan dan dokumen wajib lengkap.
### Dari gudang
- Hanya item aktif dan barcode `available` yang dapat dipilih.
- Biaya berasal dari inventory ledger, bukan input manual.
- Kapitalisasi menggunakan transaksi database dan row locking.
- Otomatis membuat jurnal debit Aset / kredit Persediaan, inventory ledger keluar, stock log, item movement, dan memperbarui barcode serta cache stok.
- Barang `UNIT` selalu satu barcode untuk satu aset. Barang `QTY` dapat dikapitalisasi sebagian sesuai saldo tersedia.
## Siklus hidup
- Penyusutan bulanan/catch-up tidak boleh melewati nilai residu dan unik per aset-periode.
- Penambahan nilai, impairment, revaluasi, pelepasan/penjualan, hilang, dan rusak menghasilkan jurnal serta event immutable.
- Transfer lokasi, perubahan PIC, maintenance, dan opname tersimpan sebagai audit trail.
- Koreksi transaksi posted dilakukan melalui reversal event terakhir; histori tidak dihapus.
- Hasil opname `hilang/rusak` tidak otomatis menjurnal. Setelah opname diposting, lakukan mutasi resmi pada aset terkait agar user memverifikasi nilai dan akun sebelum posting.
## Dokumen dan laporan
- Kartu aset dan histori mutasi PDF.
- Label QR yang membuka identitas aset company-scoped.
- Berita acara opname PDF dengan pembuat, approver, dan poster.
- Daftar aset, jadwal penyusutan, maintenance, mutasi/audit, serta rekonsiliasi subledger ke buku besar tersedia dalam layar, PDF, dan Excel.
## Database produksi
Sebelum deploy:
1. Backup database dan file lampiran.
2. Jalankan migrasi berurutan sampai `20260906000900`.
3. Periksa mapping `inventory`, `asset_disposal_gain`, dan `asset_disposal_loss` untuk tiap perusahaan.
4. Lengkapi mapping akun default pada setiap kategori aset.
5. Tinjau aset legacy yang memakai mode `no_journal`, lalu rekonsiliasi saldo awal dengan GL.
6. Jalankan `php index.php fixedassetcheck` dan tindak lanjuti semua baris `[WARN]`.
7. Uji maker/approver dengan dua akun non-Admin dan satu Master Admin.
Migrasi `20260906000400` menambah workflow, company scope, histori, attachment scope, indeks, dan event immutable. Migrasi `20260906000500` mengubah nominal aset menjadi `DECIMAL` agar nilai setelah koma tidak hilang. Migrasi `20260906000600`–`20260906000700` menormalkan akun harga perolehan aset legacy: kategori yang semula menunjuk akun induk diarahkan ke akun detail yang dapat menerima posting. Migrasi `20260906000800` mengisi nilai draft aset gudang lama yang masih nol berdasarkan inventory ledger. Migrasi `20260906000900` melengkapi `stock_logs.company_id`, backfill dari master barang, dan indeks tenant untuk kapitalisasi/reversal aset gudang. Production wajib meninjau nama/kode akun detail dan nilai draft hasil migrasi bersama Finance sebelum go-live.
## Kontrol akses
- `can_view`: daftar, detail, lookup, dan laporan layar.
- `can_create`: membuat dan mengajukan draft perolehan/opname.
- `can_update`: mengubah draft/master, transfer, PIC, dan maintenance.
- `can_approve`: approve/reject perolehan dan opname.
- `can_post`: kapitalisasi, penyusutan, mutasi nilai, posting opname, dan reversal.
- `can_export`: PDF, Excel, kartu aset, dan berita acara.
## Checklist penerimaan
- Input langsung dan dari gudang berjalan sampai kapitalisasi.
- Posting gudang hanya sekali walaupun tombol diklik ulang.
- Debit dan kredit setiap jurnal aset seimbang.
- Barcode/qty, inventory ledger, stock log, item movement, dan stok item konsisten.
- Penyusutan periode yang sama tidak terduplikasi dan tidak di bawah residu.
- Periode tertutup menolak kapitalisasi, penyusutan, mutasi, dan reversal.
- Aset perusahaan lain tidak muncul pada register, lookup, detail, lampiran, atau laporan.
- Tugas utama dapat dilakukan pada laptop dan HP; modal menjadi layar penuh di HP.
+120
View File
@@ -0,0 +1,120 @@
# Finalisasi Modul Persediaan
Dokumen ini menjadi catatan implementasi development dan panduan penerapan ke production. Perubahan tidak menghapus jurnal, barcode, stock log, ledger, maupun histori transaksi lama.
## Fondasi yang digunakan
- `inventory_ledger` adalah sumber saldo dan nilai persediaan.
- `items.stok` hanya cache dan disinkronkan dari ledger setelah transaksi stok.
- `stock_logs` adalah jejak operasional/audit, bukan sumber saldo utama.
- Barcode menyimpan ketersediaan fisik per unit/kelompok. Stok yang `pending`, `installed`, `closed`, `returned`, atau `sold_out` tidak dapat dipilih sebagai stok operasional.
- Perpindahan barang ke teknisi tidak mengurangi nilai persediaan perusahaan. Barcode berstatus `installed` agar tidak dapat dialokasikan atau dikeluarkan dua kali; pengembalian mengaktifkannya kembali pada gudang asal.
- Dokumen posted tidak diedit atau dihapus. Koreksi dilakukan dengan dokumen reversal.
- Endpoint hapus master Gudang dan Jenis/Kode Barang dinonaktifkan secara permanen; perubahan ketersediaan master dilakukan melalui status aktif/nonaktif.
## Migration baru
1. `20260906000100_finalize_professional_inventory.php`
- melengkapi header/detail dokumen stok, sumber dokumen, approval, reversal, dan audit status;
- melengkapi company, status aktif, gudang, rak/bin, batch, reservasi, dan rekonsiliasi;
- membuat tabel histori dokumen serta reservasi;
- menambahkan indeks pencarian, status, tanggal, sumber, barcode, dan lampiran;
- melakukan backfill company secara konservatif.
2. `20260906000200_reconcile_inventory_company_and_cost.php`
- mengisi `company_id` yang masih kosong;
- mengisi biaya stock log dari ledger atau harga beli bila jejak lama memungkinkan;
- membuat snapshot histori status dokumen lama;
- tidak mengubah qty, saldo ledger, barcode, atau jurnal.
3. `20260906000300_harden_technician_inventory_custody.php`
- menambahkan `company_id` dan indeks pada penguasaan barang teknisi;
- menyelaraskan barcode assignment aktif lama dari `available` menjadi `installed` hanya bila tidak sedang direservasi;
- tidak mengubah qty persediaan atau membuat jurnal.
Status database development setelah migrasi: `20260906000300`. Pemeriksaan menunjukkan tidak ada item tanpa company dan tidak ada stock log tanpa unit cost.
## Alur operasional final
- Barang pembelian tetap masuk melalui Purchase Workflow dan penerimaan gudang.
- Barang berserial atau belum mempunyai harga jual masuk Barang Pending.
- Aktivasi berserial dapat dilakukan bertahap; unit yang belum lengkap tetap berada di Barang Pending.
- Barang aktif hanya dapat dilihat, ditelusuri stock card-nya, dan dicetak barcode. Pengeluaran menggunakan dokumen Operasional Stok.
- Operasional Stok mendukung multi-baris, draft, pengajuan, approval sesuai jenis, posting, reversal, sumber dokumen, lampiran, detail, PDF, dan audit status.
- Adjustment, selisih opname, rusak, dan hilang wajib approval. Mutasi biasa dan transfer mengikuti permission posting.
- Reservasi mendukung release sebagian/seluruhnya, consume, cancel, dan expired otomatis.
- Retur supplier tetap dikerjakan dari submenu Retur & Refund; penerimaan pembelian tidak diduplikasi sebagai input manual.
- Penjualan, penerimaan pembelian, retur supplier, aset, dan peralatan teknisi sudah menggunakan ledger atau adapter transaksi yang mempertahankan jejak dokumen.
## Hasil pemeriksaan development, 6 September 2026
Pemeriksaan integritas lulus:
- duplicate barcode: 0;
- duplicate ledger idempotency: 0;
- stok ledger negatif: 0;
- selisih qty ledger dengan stock log: 0;
- selisih cache `items.stok`: 0;
- reservasi barcode melebihi saldo: 0;
- release reservasi berlebih: 0;
- dokumen posted tanpa ledger: 0;
- trigger pencegahan stok negatif: aktif.
- assignment teknisi aktif dengan status barcode selain `installed`: 0 (satu metadata legacy telah diselaraskan tanpa mengubah qty/jurnal).
Rekonsiliasi nilai lama belum balance dan sengaja tidak dikoreksi otomatis:
- nilai inventory ledger: Rp268.920.950,00;
- nilai stock log: Rp275.369.950,00;
- nilai akun persediaan GL: Rp243.151.515,00;
- selisih ledger terhadap GL: Rp25.769.435,00.
Sumber selisih nilai ledger terhadap stock log yang teridentifikasi:
- `ONT-200526 - ONT TF525G`, Gudang Cikembar: ledger Rp57.836.670,00; stock log Rp64.305.670,00; selisih Rp-6.469.000,00;
- `ADP-260905120758-20 - Adpator 12 Volt`, Gudang Cikembar: ledger Rp180.000,00; stock log Rp160.000,00; selisih Rp20.000,00.
Terdapat tujuh posisi barcode legacy yang berbeda dari ledger:
- `FO1-010426`: +463 pada ledger;
- `ISK-140426`: -18 pada ledger;
- `KLB-120426`: -13 pada ledger;
- `JB24-010426`: +6 pada ledger;
- `ONT-260626`: -5 pada ledger;
- `PTC-270626`: -1 pada ledger;
- `F42-260903004514`: +1 pada ledger.
Angka tersebut tersedia pada Laporan Persediaan → Rekonsiliasi dan perintah `php index.php inventorycheck professional`. Koreksi hanya boleh dilakukan setelah dokumen sumber, stock opname fisik, dan saldo awal GL disepakati. Gunakan adjustment/opname beralasan dan approval; jangan mengedit tabel langsung.
## Hasil automated test
- PHP lint: 32 file inti Persediaan, integrasi Pembelian/Penjualan/Aset/Teknisi, migration, view, dan test lolos.
- PHPUnit: 24 test, 243 assertion, seluruhnya lulus.
- `stage17check`: seluruh kontrol accounting berstatus pass; terdapat warning 12 invoice legacy tanpa jurnal yang sudah dicatat untuk cut-over.
- `stage15check`: shell desktop/mobile, kesamaan sumber menu, breakpoint 360/390/768/1366, modal, local asset fallback, dan double-submit guard lulus.
- `stage16check`: tabel skalabilitas, cache, queue idempotent, dan database session lulus.
- `purchaseadjustmentcheck integrity/runtime`: seluruh invariant retur/refund serta query laporan lulus.
- Rekonsiliasi inventory terhadap GL sengaja menghasilkan exit code 1 karena selisih legacy Rp25.769.435,00 masih terbuka dan harus ditindaklanjuti, bukan ditutupi.
## Langkah wajib production
1. Backup database penuh dan folder `uploads/accounting` lalu uji restore-nya.
2. Terapkan pada staging yang merupakan salinan production; hentikan posting stok saat cut-over.
3. Deploy kode, lalu jalankan `php index.php migrate latest` dan pastikan `php index.php migrate status` menunjukkan `20260906000300` atau versi lebih baru.
4. Jalankan pemeriksaan berikut sebelum membuka transaksi:
```text
php index.php inventorycheck integrity
php index.php inventorycheck reconciliation
php index.php inventorycheck trigger_test
php index.php inventorycheck professional
php index.php inventorycheck anomalies
php index.php stage17check
php index.php purchaseadjustmentcheck integrity
php index.php purchaseadjustmentcheck runtime
```
5. Ekspor hasil rekonsiliasi, cocokkan dengan saldo awal, pembelian/penjualan legacy, dan lakukan stock opname untuk item yang berbeda.
6. Jangan menjalankan repair GL atau membuat jurnal penutup selisih sebelum penyebab dan otorisasinya terdokumentasi.
7. Uji permission Maker/Approver/Poster per perusahaan dan pastikan pengguna hanya melihat company aktif.
8. Uji smoke test pada laptop 1366×768, Full HD, Android kecil/besar, serta Safari iPhone: buat dokumen multi-item, preview PDF, scan barcode, reservasi, approval, posting, dan reversal.
9. Pantau query lambat, deadlock, ukuran ledger/log, dan job export setelah go-live.
Rollback migration finalisasi hanya melalui pemulihan backup karena menurunkan skema dapat menghilangkan metadata audit baru.
+73
View File
@@ -0,0 +1,73 @@
# Deployment Production — Retur & Refund Pembelian
Dokumen ini adalah checklist deployment. Jangan menyalin database Development ke Production.
## Migration wajib
Ambil backup penuh database dan folder `uploads/accounting` sebelum deployment, lalu jalankan migration secara berurutan:
1. `20260905000800_finalize_purchase_returns_refunds.php`
2. `20260905000900_add_purchase_adjustment_reversal_audit.php`
3. `20260905001000_reconcile_duplicate_purchase_receipt_ledger.php`
Migration terakhir tidak menghapus ledger. Jika mendeteksi penerimaan yang dahulu di-backfill lalu diposting ulang oleh PurchaseService, migration membuat mutasi kompensasi `data_reconciliation` yang dapat diaudit. Tinjau hasil deteksinya bersama Finance sebelum production. Migration sengaja tidak menyediakan rollback destruktif karena ledger transaksi bersifat immutable; pemulihan memakai backup atau dokumen reversal baru.
## Mapping COA yang wajib diverifikasi Finance
Pastikan mapping aktif, `allow_posting=1`, berada pada company yang tepat, dan menunjuk COA resmi Production:
- `inventory`
- `accounts_payable`
- `purchase_input_tax`
- `goods_in_transit`
- `supplier_advances`
- `supplier_refund_receivable`
- `purchase_return_adjustment`
- `bank_charge_expense`
- `purchase_price_variance`
Migration Development dapat membuat akun contoh untuk tiga mapping Retur/Refund. ID akun, kode akun contoh, dan mapping Development tidak boleh disalin mentah ke Production.
## Data yang tidak boleh disalin
- User, role, permission, session, dan token Development.
- Nomor sequence Development.
- PO, penerimaan, invoice, pembayaran, retur, refund, Debit Note, jurnal, serta lampiran uji.
- Akun contoh `Piutang Refund Supplier`, `Penyesuaian Retur Pembelian`, atau `Selisih Harga Pembelian` tanpa persetujuan Finance.
- Jurnal baseline/koreksi dengan referensi `DEV-*`.
## Rekonsiliasi sebelum deployment
1. Tutup input transaksi sementara dan ambil cut-off time.
2. Cocokkan PO, penerimaan posted, invoice supplier, pembayaran, dan saldo hutang.
3. Cocokkan qty `items`, `item_barcodes`, `stock_logs`, dan `inventory_ledger` per item/gudang.
4. Identifikasi penerimaan posted yang belum mempunyai invoice supplier. Nilainya merupakan reconciling item sementara pada implementasi existing, bukan alasan membuat jurnal dummy.
5. Cocokkan akun Persediaan, Hutang Usaha, Barang Dalam Perjalanan, Uang Muka Supplier, Pajak Masukan, dan Piutang Refund Supplier.
6. Pastikan tidak ada periode accounting yang salah status open/closed.
Pada Development tanggal 5 September 2026, koreksi duplicate receipt sebanyak 200 unit telah dibuat melalui migration `20260905001000`; kuantitas ledger, stock log, dan cache item sesudahnya sudah sama. Pemeriksaan terakhir menunjukkan reconciling item nilai Rp25.769.435. Rincian utamanya adalah penerimaan posted yang belum selesai menjadi invoice supplier, sehingga nilai fisik sudah masuk ledger tetapi pengakuan akuntansinya masih menunggu penyelesaian dokumen. Angka ini bersifat snapshot dan dapat berubah ketika transaksi development bertambah. Jangan membawa angka Development tersebut ke Production; Production harus dihitung ulang dari dokumen cut-off sendiri.
## Rekonsiliasi setelah deployment
Jalankan:
```powershell
php index.php migrate status
php index.php purchaseadjustmentcheck runtime
php index.php purchaseadjustmentcheck integrity
php index.php stage17check
php index.php payablecheck integrity
php index.php inventorycheck integrity
php index.php inventorycheck reconciliation
vendor\bin\phpunit --colors=never
```
Hasil yang harus nol: jurnal tidak balance, stok negatif, duplicate idempotency, refund melebihi klaim, saldo invoice negatif, orphan attachment/reference, dan kebocoran company. `inventorycheck reconciliation` hanya boleh disetujui jika selisih nol atau seluruh reconciling item penerimaan-belum-invoice mempunyai daftar dokumen dan persetujuan Finance.
## Uji akses dan operasional
1. Logout/login ulang seluruh role agar permission baru terbaca.
2. Uji Purchasing, Gudang, Finance, Approver, Auditor, dan Master Admin secara terpisah.
3. Uji satu retur `UNIT`, satu retur `QTY`, retur multi-item, pengganti parsial, refund parsial, Debit Note invoice terbuka, dan Debit Note invoice lunas.
4. Uji PDF iframe dan upload multi-file pada Chrome/Edge/Firefox serta HP.
5. Simpan hasil rekonsiliasi, screenshot approval, dan output QA sebagai bukti deployment.
+53
View File
@@ -0,0 +1,53 @@
# Deployment Database Production — Penjualan
## Sebelum deployment
1. Buat backup database dan folder `uploads/accounting`.
2. Pastikan seluruh migration sampai `20260906001100` sudah diterapkan.
3. Rekonsiliasi invoice lama, jurnal penjualan, `stock_logs`, `inventory_ledger`, dan status barcode. Tandai khusus invoice legacy yang sudah pernah mengurangi stok.
4. Pastikan mapping akun Penjualan lengkap untuk setiap company.
## Migration
Jalankan berurutan:
- `20260907000100_finalize_sales_invoice_workflow`
- `20260907000200_complete_sales_document_metadata`
- `20260907000300_expand_sales_return_barcode_status`
- `20260907000400_scope_document_numbering_by_company`
Migration bersifat additive dan tidak menghapus kolom/tabel lama. `company_id`, metadata invoice, tabel Surat Jalan, relasi multi-barcode, sumber pembayaran, pengakuan pendapatan, dan retur akan ditambahkan. Enum barcode mempertahankan seluruh status Pembelian/Persediaan yang sudah ada dan menambah `quarantine` serta `damaged`.
Migration keempat mengganti unique index nomor dokumen global menjadi per-company dan membuat sequence atomik per perusahaan. Struktur data transaksi tidak dihapus.
## Setelah deployment
1. Jalankan `php index.php salescheck`.
2. Uji satu invoice Development: pilih barcode → post Surat Jalan → ajukan → approve/post → bayar dengan bukti.
3. Bandingkan saldo invoice dengan akun Piutang dan saldo inventory ledger dengan akun Persediaan/Persediaan Dalam Penjualan.
4. Verifikasi permission per role dan isolasi company.
5. Pastikan folder `uploads/accounting/sales` dapat ditulis PHP tetapi eksekusi script diblokir oleh konfigurasi web server.
## Rollback
Jangan menjalankan `down()` pada data transaksi aktif. Rollback yang aman adalah mengembalikan backup database dan source secara bersamaan. Dokumen yang sudah posted harus direversal melalui workflow, bukan dihapus manual.
## Data yang perlu direkonsiliasi
- Invoice lama tanpa `company_id` yang customer-nya ambigu.
- Invoice dengan `stock_posted_at` tetapi tidak mempunyai inventory ledger yang sepadan.
- Satu barcode legacy pada `invoice_details.barcode_id` yang belum tercermin pada relasi multi-barcode.
- Pembayaran lama tanpa `payment_sources` atau bukti pembayaran.
- Jurnal lama dengan keterangan atau `ref_type/ref_id` yang tidak lengkap.
## Tambahan deployment editor invoice
Terapkan migration `20260907000500_finalize_invoice_editor` setelah `20260907000400`. Migration additive ini menambah idempotency/version header invoice, tipe dan idempotency baris invoice, indeks daftar/detail/pengelompokan Surat Jalan Draft, serta permission `can_submit` pada role terkait.
Lanjutkan dengan `20260907000600_finalize_sales_payment_permissions` untuk memberi `can_post` penerimaan pelanggan kepada role Finance yang memang memiliki hak posting Kas/Bank, sekaligus menambah indeks riwayat pembayaran dan alokasi invoice.
Setelah migration:
1. Jalankan `php index.php salescheck`.
2. Minta pengguna logout/login agar snapshot permission session memuat `can_submit` terbaru.
3. Uji alur singkat: buat header, tambah satu barang atau jasa, post Surat Jalan bila barang, ajukan, approve/post otomatis, lalu bayar dengan bukti.
4. Jangan mengaktifkan kembali mutasi legacy `Invoices::save/add_item/delete_item/bayar`.
+15
View File
@@ -0,0 +1,15 @@
# Checklist Production DB — Tahap 10–11
1. Backup dan uji restore, lalu jalankan migration `20260901001200`–`20260901001600` dalam maintenance window.
2. Buat role terpisah HR, Payroll Admin, Payroll Reviewer dan Payroll Approver; setelah itu ganti fallback Admin-only dengan permission granular.
3. Validasi riwayat efektif jabatan/departemen/cabang, kontrak, rekening, NPWP/status PTKP, BPJS dan benefit setiap karyawan.
4. Daftarkan serial mesin absensi dan secret; pastikan timezone dan mapping PIN karyawan benar.
5. Bersihkan duplikasi log sebelum lock absensi pertama. Koreksi harus diajukan dan disetujui sebelum periode dikunci.
6. Konfigurasikan seluruh formula, prorata, tarif lembur, unpaid leave, BPJS, PPh 21, THR dan mapping akun berdasarkan kebijakan/peraturan yang berlaku. Seed Development bukan perhitungan legal pajak.
7. Validasi mapping `payroll_expense`, `payroll_payable`, `payroll_tax_payable`, `payroll_bpjs_payable`, dan `employee_loan_receivable` terhadap COA Production.
8. Pisahkan hutang pajak/BPJS per komponen bila laporan perusahaan membutuhkannya sebelum payroll pertama diposting.
9. Konfigurasikan tax code per masa berlaku, inclusive/exclusive, akun input/output/withholding, dan nomor faktur pajak.
10. Rekonsiliasi tax register hasil backfill dengan invoice, tagihan supplier dan GL. Jangan membuat ulang jurnal historis.
11. Jalankan `php index.php stage1011check`; semua indikator mismatch/duplicate/missing harus nol.
Aturan pajak dan payroll dapat berubah. Nilai seed dan formula Development wajib ditinjau konsultan pajak/HR perusahaan sebelum Production.
+16
View File
@@ -0,0 +1,16 @@
# Checklist Production DB — Tahap 12–14
1. Backup dan uji restore; jalankan migration `20260901001700`–`20260901002100`.
2. Verifikasi seluruh data lama berada pada company `MAIN` dan setiap user memiliki tepat satu default company.
3. Jalankan `php index.php stage1214check`; `critical_rows_without_company`, `user_without_company`, `unbalanced_by_company`, dan `duplicate_rates` harus nol.
4. Jalankan migration `20260901002200` untuk memastikan `business_dimensions.company_id`, backfill tenant, dan unique key per perusahaan tersedia; kemudian petakan branch/departemen lama dan lengkapi project, cost center, profit center serta salesperson.
5. Isi dimensi default pada sumber transaksi agar journal detail baru tidak kosong. Data legacy tanpa dimensi tetap valid tetapi laporan dimensi akan masuk kelompok “tanpa dimensi”.
6. Petakan `budget_account_id` pada PO yang menjadi commitment. Uji warning/blocking sebelum budget diaktifkan.
7. Konfigurasikan worker export dan direktori `uploads/accounting/reports` di luar public access atau lindungi dengan authorization download.
8. Sebelum close, selesaikan closing checklist dan buat snapshot laporan utama.
9. Validasi mapping akun realized/unrealized FX gain/loss serta kurs sumber resmi.
10. Rekonsiliasi saldo foreign AR/AP ke base currency sebelum revaluasi pertama.
11. Jangan mengaktifkan perusahaan kedua untuk transaksi operasional sampai seluruh controller/model legacy diberi scope `company_id`. Prioritas: invoice, purchase, inventory, asset, cash/bank, HR/payroll, tax, dashboard dan generator PDF lama.
12. Setelah tenant audit lulus, ubah unique number/account/mapping/period indexes menjadi composite dengan `company_id` sesuai kebutuhan nomor terpisah per perusahaan.
Aktivasi multi-company Production wajib dilakukan sebagai cutover tersendiri. Migration menyiapkan fondasi dan memproteksi jalur baru, tetapi tidak otomatis membuat seluruh query legacy menjadi tenant-safe.
+44
View File
@@ -0,0 +1,44 @@
# Runbook Database Production — Tahap 5
## Preflight wajib
1. Full backup dan uji restore pada staging.
2. Bekukan pembuatan invoice/pembayaran selama migration.
3. Rekonsiliasi total invoice, pembayaran, piutang, jurnal, stock log, dan barcode.
4. Periksa nomor invoice duplikat:
```sql
SELECT no_invoice, COUNT(*), GROUP_CONCAT(id ORDER BY id)
FROM invoices GROUP BY no_invoice HAVING COUNT(*) > 1;
```
5. Periksa pembayaran tanpa invoice/customer, pembayaran melebihi invoice, jurnal hilang, dan detail stok ganda. Jangan mengoreksi otomatis sebelum Finance menyetujui mapping.
6. Tinjau akun kontrol: Piutang Usaha, Utang Pajak Penjualan, Uang Muka Pelanggan, Beban Kerugian Piutang, HPP, Persediaan, dan akun pendapatan.
## Migration
Jalankan berurutan: `20260831001000`, `20260831001100`, lalu `20260901000100`. Migration 010 berhenti aman jika nomor invoice duplikat ditemukan.
Migration membuat akun default berikut hanya bila kodenya belum ada:
- `2191` Utang Pajak Penjualan
- `2192` Uang Muka Pelanggan
- `6191` Beban Kerugian Piutang
Production wajib menyesuaikan `system_account_mappings` dengan chart of accounts resmi perusahaan. Jangan mengandalkan nama/kode default jika COA Production berbeda.
## Validasi setelah migration
```sql
SELECT workflow_status, status, COUNT(*) FROM invoices GROUP BY workflow_status,status;
SELECT COUNT(*) FROM payments p LEFT JOIN payment_allocations a ON a.payment_id=p.id WHERE a.id IS NULL;
SELECT no_invoice, COUNT(*) FROM invoices GROUP BY no_invoice HAVING COUNT(*)>1;
```
Uji pada staging: quotation→SO/invoice, submit→approve→post, partial dan multi-invoice payment, uang muka, credit note, write-off, refund, reversal, aging, statement, receipt, attachment, jurnal balance, serta stok/barcode berkurang tepat sekali.
Invoice historis tidak boleh diposting ulang otomatis. Jika flag legacy `posted` tidak sesuai jurnal sebenarnya, rekonsiliasi per invoice dan gunakan change script yang disetujui Finance/DBA.
## Operasional
Batasi endpoint credit note, refund, write-off, posting, dan reversal kepada role berwenang. Konfigurasikan provider reminder terpisah. Backup lampiran `uploads/accounting` bersama database dan terapkan malware scanning pada infrastruktur Production.
+11
View File
@@ -0,0 +1,11 @@
# Runbook Production DB — Tahap 6
1. Backup penuh dan uji restore di staging.
2. Rekonsiliasi stok, jurnal persediaan, daftar hutang supplier, dan invoice belum dibayar dari sistem lama.
3. Jalankan migration `20260901000300` lalu `20260901000400`.
4. Tinjau mapping `accounts_payable`, `purchase_input_tax`, `supplier_advances`, `payable_opening_balance`, dan `inventory` terhadap COA resmi Production.
5. Import master supplier terlebih dahulu. Saldo awal hanya boleh dimasukkan satu kali setelah Finance menyetujui daftar hutang per supplier dan tanggal cut-off berada pada periode open.
6. Jangan mengubah 1.547 movement pembelian legacy menjadi PO/receipt secara otomatis. Jika histori harus dimigrasikan, siapkan mapping supplier dan dokumen sumber yang ditandatangani Finance.
7. Uji PR/approval, PO/approval, dua receipt parsial, matching invoice, posting, dua pembayaran parsial, uang muka, retur, debit note, aging, statement, stok, dan jurnal balance.
Setelah go-live, hentikan jalur pembelian langsung pada menu barang untuk user biasa. Pembelian baru harus melalui workflow Tahap 6; jalur legacy hanya untuk koreksi terotorisasi sampai sepenuhnya dinonaktifkan.
+12
View File
@@ -0,0 +1,12 @@
# Runbook Production DB — Tahap 7
1. Bekukan seluruh mutasi stok, backup DB, dan uji restore.
2. Ekspor stok fisik per item/gudang/bin/barcode, saldo `stock_logs`, dan saldo akun Persediaan.
3. Cari barcode duplikat dan saldo negatif per gudang. Rekonsiliasi dengan dokumen fisik; jangan menjalankan `Inventoryrepair` Production.
4. Tentukan costing method per item (`average` default atau `fifo`) bersama Finance. Metode tidak boleh diubah setelah go-live tanpa prosedur revaluation.
5. Jalankan migration 005–008. Validasi backfill ledger per item/gudang terhadap stock log.
6. Selisih inventory ledger dengan GL harus diinvestigasi dan disetujui Finance. Jurnal baseline Production dibuat menggunakan change document sendiri, bukan nomor Development.
7. Isi minimum stock, reorder point, master bin, batch/expiry, dan reservation awal bila ada.
8. Uji dua request bersamaan untuk barcode yang sama, double submit dengan idempotency sama, transfer parsial, opname approval, FIFO/average, retur, rusak/hilang, negative stock, valuation, stock card, dan rekonsiliasi.
Setelah go-live, cabut akses mutasi langsung legacy secara bertahap dan arahkan seluruh mutasi ke Inventory Control. Monitor trigger rejection dan idempotency conflict di application log.
+14
View File
@@ -0,0 +1,14 @@
# Checklist Production DB — Tahap 8–9
1. Backup database dan uji restore; deploy kode dalam maintenance window.
2. Jalankan migration berurutan `20260901000900` sampai `20260901001100`.
3. Petakan setiap kategori/aset ke akun aset, akun akumulasi, dan akun beban penyusutan yang benar. Jangan mengandalkan child account legacy.
4. Validasi tanggal kapitalisasi, nilai perolehan, residu, masa manfaat, akumulasi dan nilai buku seluruh aset. Backfill tidak membuat jurnal baru.
5. Validasi akun laba/rugi pelepasan `4192/6193`; sesuaikan kode jika chart of accounts Production berbeda.
6. Lengkapi master rekening bank/kas, nomor rekening, mata uang, saldo awal dan tanggal saldo awal. Jangan memasukkan saldo awal jika sudah tercermin di GL.
7. Tetapkan `CASH_APPROVAL_THRESHOLD` dan approver sesuai kebijakan perusahaan.
8. Jalankan `php index.php stage89check`; seluruh nilai error/duplicate/orphan harus nol.
9. Rekonsiliasi asset register versus GL serta setiap rekening bank/kas versus rekening koran sebelum go-live.
10. Nonaktifkan cron penyusutan lama; gunakan endpoint yang kini diarahkan ke `FixedAssetService`, satu kali per hari dengan monitoring hasil.
Tidak ada koreksi saldo historis otomatis pada migration. Selisih Production harus dibuat sebagai jurnal rekonsiliasi yang disetujui dan terdokumentasi.
+41
View File
@@ -0,0 +1,41 @@
# Runbook Upgrade Database Production
Jangan arahkan `.env` development ke Production. Lakukan upgrade pada maintenance window dan gunakan salinan staging terbaru terlebih dahulu.
## Sebelum perubahan
1. Bekukan transaksi dan buat full backup database serta uji restore.
2. Catat versi migration Production dan bandingkan struktur, engine, charset, trigger, role, serta foreign key dengan staging.
3. Jalankan pemeriksaan berikut:
```sql
SELECT no_ref, COUNT(*) total, GROUP_CONCAT(id ORDER BY id) journal_ids
FROM journals GROUP BY no_ref HAVING COUNT(*) > 1;
SELECT r.id, r.nama_role, COUNT(u.id) users
FROM roles r LEFT JOIN users u ON u.role_id=r.id GROUP BY r.id, r.nama_role;
```
4. Rekonsiliasi setiap referensi duplikat terhadap dokumen sumber, invoice, stok, aset, dan bukti bank. Tentukan nomor koreksi bersama bagian Finance. Jangan menjalankan `accountingrepair duplicate_refs` di Production.
5. Pastikan role bernama `Admin` tersedia. Tentukan approver Production; seed default menggunakan role tersebut dan wajib ditinjau.
## Urutan deployment
1. Deploy kode dan backup kedua sesaat sebelum migration.
2. Jalankan migration 001–008.
3. Konfigurasi `approval_workflows` dan `approval_workflow_steps` sesuai matriks otorisasi perusahaan. Uji dengan akun non-pembuat.
4. Koreksi duplikat Production menggunakan change script yang telah disetujui dan menyimpan mapping nomor lama/baru.
5. Jalankan migration 009 untuk unique constraint `journals.no_ref`.
6. Jalankan `php index.php accountingcheck`, smoke test submit–approve–post–reverse, laporan, dan tutup/buka periode.
## Struktur baru yang wajib dipertahankan
`approval_workflows`, `approval_workflow_steps`, `approval_requests`, `approval_actions`, dan `immutable_audit_logs`; trigger `trg_immutable_audit_no_update`, `trg_immutable_audit_no_delete`, serta unique index `uq_journals_no_ref`.
Audit log adalah append-only. Koreksi dilakukan dengan event audit baru, bukan UPDATE/DELETE. Akses langsung database ke tabel audit harus dibatasi untuk user aplikasi; DBA darurat harus masuk prosedur change management.
Untuk perubahan invoice/piutang Tahap 5, lanjutkan dengan `PRODUCTION-DB-TAHAP-5.md` setelah seluruh langkah Tahap 4 selesai.
## Rollback
Rollback schema setelah transaksi baru masuk berisiko menghilangkan kontrol dan tidak disarankan. Jika smoke test gagal, hentikan transaksi, rollback kode, pertahankan tabel kontrol untuk investigasi, atau restore backup penuh setelah persetujuan Finance/DBA.
+40
View File
@@ -0,0 +1,40 @@
# Catatan Production — Penyatuan Workflow Pembelian
## Perubahan konsep
- `Barang Pending` hanya membuat master/rencana barang gudang dengan stok `0`.
- Tidak ada barcode, stock log, jurnal, atau pembayaran ketika master pending dibuat.
- Stok menjadi tersedia hanya setelah Goods Receipt untuk PO gudang diposting.
- Pembelian aset tidak masuk stok gudang; Goods Receipt membuat data pada asset register.
- Pembayaran dilakukan melalui tagihan supplier/hutang, bukan dari master barang.
## Migrasi wajib
Jalankan migration sampai versi `20260902000500` setelah backup dan uji staging. Migrasi menambah tujuan pembelian (`warehouse`/`asset`), metadata kapitalisasi aset, relasi receipt ke aset, serta kolom rencana pada `items`. Kolom item dan gudang pada detail transaksi terkait dibuat nullable agar pembelian aset tidak dipaksa mempunyai master barang gudang.
```bash
php index.php migrate latest
php index.php migrate status
```
## Pemeriksaan sebelum cut-over
1. Pastikan semua item berstatus `draft` mempunyai stok nol dan tidak digunakan pada penjualan.
2. Item draft legacy yang sudah mempunyai stok harus diklasifikasikan sebagai item aktif.
3. Pastikan mapping akun `inventory`, `accounts_payable`, dan `purchase_input_tax` aktif.
4. Pastikan akun aset dan lokasi aset tersedia sebelum membuat PO aset.
5. Uji satu siklus gudang dan satu siklus aset di staging: PR, approval, PO, approval, receipt, tagihan, posting hutang, lalu pembayaran.
6. Rekonsiliasi stock ledger dengan akun persediaan dan asset register dengan akun aset setelah cut-over.
Rollback migration ini tidak dilakukan dengan menghapus kolom pada database aktif. Gunakan backup terverifikasi apabila deployment harus dibatalkan.
## Biaya administrasi bank pada pembayaran
Migration `20260905000700` wajib dijalankan sebelum kode pembayaran terbaru digunakan. Migration ini menambahkan `bank_charge_amount`, `bank_charge_account_id`, dan `total_cash_out` pada `supplier_payments`, serta mapping `bank_charge_expense`.
Sebelum Production:
1. Cocokkan mapping `bank_charge_expense` dengan akun beban administrasi bank resmi pada COA perusahaan; jangan mengandalkan kode seed Development `6298` bila COA Production berbeda.
2. Pastikan `supplier_payments.amount` tetap diperlakukan sebagai pokok pembayaran yang mengurangi PO/invoice. `total_cash_out` adalah pokok ditambah biaya admin.
3. Rekonsiliasi total `purchase_payment_sources` dengan `supplier_payments.total_cash_out` dan alokasi invoice dengan `supplier_payments.amount`.
4. Uji masing-masing satu transaksi pembayaran awal/DP, pembayaran setelah penerimaan, dan pelunasan Hutang & Pembayaran dengan admin bank sebelum cut-over.
+10
View File
@@ -0,0 +1,10 @@
# Checklist Production — UI Tahap 15
1. Jalankan `php index.php stage15check` dan pastikan `failed` kosong.
2. Uji Admin dan setiap role non-Admin; menu desktop dan mobile harus identik setelah permission diterapkan.
3. Uji alur invoice, penerimaan, pembelian, pembayaran, inventory scan, aset, payroll, pajak, budget dan laporan pada 360 px serta laptop.
4. Verifikasi tidak ada POST ketika offline; setelah koneksi kembali pengguna harus mengirim ulang secara sadar.
5. Pastikan HTTPS aktif agar instalasi PWA, service worker, kamera dan scanner berjalan konsisten.
6. Konfigurasikan CSP dan sediakan salinan lokal Bootstrap Icons/SweetAlert/DataTables/Select2/QR bila Production harus tetap berfungsi tanpa CDN.
7. Pastikan direktori upload membatasi executable file dan kompresi server tetap dijalankan sebagai pertahanan kedua.
8. Setelah deploy, naikkan versi cache service worker bila asset statis berubah.
+64
View File
@@ -0,0 +1,64 @@
# Retur, Refund, Barang Pengganti, dan Debit Note
Modul pengecualian pembelian berada di **Pembelian → Retur & Refund**. Purchase Workflow tetap hanya menangani proses normal: PR, PO, Pembayaran Awal/DP, Penerimaan, dan Invoice Supplier.
## Alur operasional
### Retur barang
1. Purchasing membuat draft retur dari satu atau beberapa penerimaan milik supplier yang sama dan melampirkan bukti.
2. Pembuat draft mengajukan retur.
3. Approver menyetujui atau menolak. Approval hanya mereservasi barcode/batch; stok belum berkurang.
4. Gudang memilih **Post Pengeluaran**, mengisi tanggal, pengiriman, dan bukti. Pada titik ini stok, barcode, stock log, item movement, inventory ledger, jurnal terkait, dan audit trail diposting dalam satu transaksi.
5. Penyelesaian supplier dicatat sebagai barang pengganti, Debit Note, atau refund dana.
Retur `UNIT` wajib memilih satu barcode/serial per baris dengan qty satu. Retur `QTY` memilih batch/barcode dan mengisi jumlah. Sistem menolak barang yang tidak lagi berada di gudang, qty melebihi penerimaan neto, supplier campuran, atau posting ganda.
### Barang pengganti
Barang pengganti hanya dapat diterima dari retur yang telah dikirim. Penerimaan dapat parsial dan berulang. Barang `UNIT` dibuat per barcode; barang yang membutuhkan serial masuk status pending, sedangkan barang `QTY` mengikuti batch yang baru. Penerimaan pengganti tidak membentuk hutang baru.
### Refund supplier
1. Finance/Purchasing membuat klaim dari pembayaran, PO, retur, atau Debit Note yang masih mempunyai hak refund.
2. Klaim diajukan dan disetujui sesuai workflow Finance.
3. Dana dapat diterima beberapa kali. Setiap penerimaan wajib mempunyai akun Kas/Bank, tanggal, referensi bank, dan bukti.
4. Setelah seluruh dana diterima, Finance melakukan rekonsiliasi.
Jurnal hak refund adalah Debit Piutang Refund Supplier dan Kredit akun sumber yang dipetakan. Penerimaan dana adalah Debit Kas/Bank dan Kredit Piutang Refund Supplier. Biaya admin bank tidak dibalik otomatis.
Hak refund dikendalikan pada dua lapis: saldo setiap dokumen sumber dan plafon ekonomi per PO. Jika pembayaran sudah mempunyai dokumen pembayaran, sumber PO yang sama tidak ditampilkan kembali. Dengan demikian satu nilai pembayaran tidak dapat diklaim ulang melalui kombinasi sumber PO, pembayaran, retur, atau Debit Note.
### Debit Note
Debit Note mengurangi invoice supplier tanpa menghapus invoice asli. Saat invoice masih mempunyai saldo, Debit Note mengurangi Hutang Usaha. Bagian yang melebihi saldo hutang pada invoice lunas diarahkan menjadi Piutang Refund Supplier. Pajak masukan dibalik melalui mapping akun pajak.
### Retur sebelum Invoice Supplier
Retur yang telah dikirim sebelum Invoice Supplier dibuat mengurangi kuantitas yang dapat ditagihkan dan mengurangi total invoice sebesar harga PO beserta pajak baris yang diretur. Biaya tambahan PO tetap dipertahankan sampai terdapat dokumen koreksi supplier yang sah. Dengan demikian invoice berikutnya hanya mencatat barang neto tanpa mengubah histori PO atau penerimaan.
## Pembatalan dan reversal
- Draft/submitted/rejected/reserved dibatalkan dengan alasan; histori tidak dihapus.
- Dokumen posted hanya dapat direversal pada periode yang masih terbuka.
- Dokumen turunan harus direversal lebih dahulu. Contoh: penerimaan refund direversal sebelum klaim/Debit Note sumber.
- Reversal membuat jurnal dan mutasi stok lawan, tidak mengubah ledger lama.
## Dokumen dan pelaporan
Detail bukan JSON mentah. PDF Pengajuan Retur, Pengiriman Retur, Barang Pengganti, Refund, Penerimaan Refund, Debit Note, dan Ringkasan Penyelesaian dibuka melalui modal iframe. Laporan berikut tersedia pada Laporan Profesional:
- Laporan Retur Pembelian
- Laporan Refund Supplier
- Outstanding Refund Supplier
- Laporan Debit Note Supplier
Nomor dokumen pada laporan mengarah kembali ke detail Retur & Refund, sedangkan nomor jurnal mengarah ke detail jurnal.
## Permission
- `purchase_returns`: `can_view`, `can_create`, `can_update`, `can_approve`, `can_post`, `can_export`
- `purchase_refunds`: `can_view`, `can_create`, `can_update`, `can_approve`, `can_post`, `can_export`
- `supplier_debit_notes`: `can_view`, `can_create`, `can_post`, `can_export`
Master Admin tetap mempunyai seluruh akses. Menu, tab, button, endpoint, detail, dan PDF sama-sama divalidasi berdasarkan permission.
+21
View File
@@ -0,0 +1,21 @@
# Role dan permission aplikasi
| Role | Ruang lingkup utama |
|---|---|
| Admin | Seluruh modul, konfigurasi, company dan pengguna |
| Accounting Manager | Accounting, approval, closing, laporan, budget dan pajak |
| Finance & Treasury | Kas/bank, penerimaan, pembayaran dan posisi kas |
| AR / Sales Billing | Customer, penjualan, invoice dan piutang |
| AP / Purchasing | Supplier, pembelian dan hutang |
| Inventory & Warehouse | Persediaan, gudang, barcode dan stock opname |
| Asset Officer | Register dan seluruh siklus aset tetap |
| HR & Payroll | Karyawan, absensi dan payroll |
| Tax Officer | Master, transaksi dan laporan pajak |
| Auditor / Read Only | Baca lintas modul tanpa perubahan transaksi |
| Management Viewer | Dashboard, approval dan laporan manajemen |
`Keuangan` dan `Gudang` dipertahankan sebagai role legacy agar user production tidak kehilangan akses saat deployment. Untuk user baru gunakan `Finance & Treasury` dan `Inventory & Warehouse`.
Permission disimpan sebagai JSON pada `roles.permissions`. Perubahan role baru berlaku setelah user logout dan login kembali karena permission disalin ke session saat login.
Production wajib menjalankan migration `20260901002400`, memeriksa assignment user, lalu menguji minimal satu akun untuk setiap role sebelum go-live.
+39
View File
@@ -0,0 +1,39 @@
# Finalisasi Penjualan dan Invoice
## Arsitektur final
`SalesService` adalah sumber tunggal transaksi baru untuk invoice, reservasi barcode, Surat Jalan, posting stok, posting invoice, penerimaan pembayaran, pengakuan pendapatan, dan retur penjualan. `Sales` hanya menangani HTTP, permission, upload, JSON, dan PDF. Halaman lama Draft/Riwayat Invoice diarahkan ke workspace `sales`; penerimaan dari halaman Piutang juga memanggil `SalesService`.
## Alur
Penawaran tidak membuat jurnal atau stok. Penawaran yang diterima dapat dikonversi idempotent menjadi Sales Order. Sales Order diterima menjadi sumber invoice, tetapi gudang dan barcode tetap diverifikasi ulang.
Invoice mendukung `one_time` dan `running`. Baris yang ditambahkan ke Draft membuat Surat Jalan Draft dan mereservasi barcode. Invoice berjalan dapat ditambah lintas tanggal selama masih Draft. Surat Jalan posted mengurangi stok tepat sekali dan menjurnal Persediaan Dalam Penjualan terhadap Persediaan. Setelah semua pengiriman posted, invoice diajukan. Approval terakhir otomatis memposting invoice; tidak ada tombol Post kedua.
Metode Akrual mengakui pendapatan dan HPP saat invoice posted. Metode Setelah Pembayaran menampung nilai bersih pada Pendapatan Ditangguhkan, lalu mengakui pendapatan dan HPP secara proporsional pada setiap alokasi pembayaran. Ledger pengakuan memakai idempotency key.
Pembayaran dapat dialokasikan ke beberapa invoice dan berasal dari beberapa akun Kas/Bank. Kelebihan wajib menjadi uang muka. Bukti gambar/PDF wajib. Receipt tersedia sebagai PDF inline.
Retur memvalidasi dokumen pengiriman, barcode, dan saldo qty yang pernah dikirim. Workflow-nya Draft → Diajukan → Disetujui → Diterima/Diperiksa → Posted/Selesai. Posting menghasilkan jejak barcode, inventory ledger, stock log, item movement, credit note, dan jurnal tanpa membalik seluruh invoice.
## Dokumen dan laporan
Invoice PDF memisahkan halaman ringkasan dengan lampiran barcode. Surat Jalan, Retur, dan Bukti Penerimaan mempunyai PDF inline. Laporan Profesional menyediakan rekap penjualan, per customer, barang, barcode, invoice berjalan, retur, pengakuan pendapatan, Surat Jalan belum ditagihkan, serta rekonsiliasi piutang.
## Mapping akun
Tidak ada ID akun hardcoded. Mapping yang digunakan: `accounts_receivable`, `goods_revenue`, `deferred_revenue`, `inventory`, `inventory_in_sales`, `cost_of_goods_sold`, `sales_tax_payable`, dan `customer_advances`.
## Kompatibilitas legacy
Kolom legacy seperti `invoice_details.barcode_id` tetap dipertahankan. Transaksi lama tetap dapat dibaca. Data baru menggunakan `invoice_line_barcodes`, `sales_delivery_barcodes`, serta `revenue_recognition_ledger`. Invoice legacy yang pernah memposting stok langsung perlu direkonsiliasi sebelum dipindahkan ke workflow baru; sistem tidak membuat ulang ledger tersebut secara otomatis.
## Finalisasi editor 7 September 2026
- `Invoices` adalah controller utama daftar dan editor invoice melalui `/invoices`, `/invoices/create`, `/invoices/edit/{id}`, dan `/invoices/detail/{id}`.
- `SalesService` tetap menjadi pusat business logic. `Sales` menangani ringkasan, pengiriman, retur, upload, dan PDF; `Receivables` menangani UI pembayaran tetapi memposting melalui `SalesService`.
- Header disimpan lebih dahulu sebagai Draft. Barang/jasa kemudian ditambahkan satu per satu dan langsung tersimpan sehingga invoice akumulasi dapat dilanjutkan pada hari berikutnya.
- Baris persediaan hanya mereservasi barcode saat Draft. Stok fisik berkurang hanya ketika Surat Jalan diposting. Baris jasa tidak membuat Surat Jalan, stock log, inventory ledger, item movement, atau HPP.
- Daftar invoice/item memakai server-side pagination. Lookup customer, akun pendapatan, barang, gudang, barcode, dan Kas/Bank memakai AJAX pagination.
- Pembayaran customer memakai satu proses multi-invoice, multi-akun Kas/Bank, bukti wajib, uang muka terkontrol, receipt PDF, dan jurnal otomatis.
- Menu aktif disederhanakan. Data Penawaran/Sales Order tidak dihapus; navigasinya disembunyikan sampai dibutuhkan kembali.
+11
View File
@@ -0,0 +1,11 @@
# Standar Keterangan Jurnal Otomatis
Jurnal manual mempertahankan keterangan pengguna. Jurnal selain manual wajib diawali `[AUTO]` dan minimal memuat jenis transaksi, tanggal transaksi, serta sumber modul/referensi.
Jurnal yang melalui service accounting juga memuat nomor dokumen, customer/pihak, total nilai jurnal, dan rincian bisnis. Contoh:
`[AUTO] Posting Invoice Penjualan | Dokumen: INV-20260901-0001 | Pihak: PT Contoh | Tanggal transaksi: 2026-09-01 | Nilai jurnal: Rp 1.110.000,00 | Sumber: invoice#123 | Rincian: Posting Invoice INV-20260901-0001`
Trigger `trg_journals_auto_description` menjadi pengaman untuk modul legacy yang masih menulis langsung ke tabel jurnal. Jurnal baru sebaiknya selalu memakai `JournalService`/`PostingService` agar mendapat keterangan lengkap dan validasi accounting.
Backfill Development dijalankan dengan `php index.php journaldescriptionrepair run`. Untuk Production, jangan menjalankan command tersebut langsung: ekspor daftar perubahan, minta persetujuan Finance, backup, lalu jalankan dalam maintenance window karena keterangan jurnal posted akan berubah dan audit log akan bertambah.
+62
View File
@@ -0,0 +1,62 @@
# Tahap 0–1: Persiapan dan Keamanan
Dokumen ini adalah checklist deployment untuk fondasi keamanan `accounting_dev`.
## Sebelum deploy
1. Backup database dan folder `uploads`, lalu lakukan uji restore di staging.
2. Rotasi seluruh password database yang pernah tersimpan di repository/source lama.
3. Konfigurasikan environment berdasarkan `.env.example` melalui Apache `SetEnv`, virtual host, container, atau secret manager. File `.env` tidak dibaca otomatis oleh aplikasi.
4. Gunakan `CI_ENV=production`, URL HTTPS, `COOKIE_SECURE=true`, dan encryption key acak minimal 32 karakter pada production.
5. Isi `ATTENDANCE_ALLOWED_SERIALS` dengan serial mesin yang sah.
6. Biarkan `DBCOMPARE_ENABLED=false` kecuali saat diagnosis terkontrol oleh Admin.
7. Pastikan web server dapat menulis `application/logs`, folder session PHP, dan `uploads`, tetapi tidak dapat mengeksekusi PHP dari `uploads`.
Contoh konfigurasi Apache development:
```apache
SetEnv CI_ENV development
SetEnv APP_BASE_URL http://localhost/accounting_dev/
SetEnv APP_ENCRYPTION_KEY ganti-dengan-secret-acak-yang-panjang
SetEnv DB_HOST 127.0.0.1
SetEnv DB_PORT 3306
SetEnv DB_USERNAME accounting_app
SetEnv DB_PASSWORD secret
SetEnv DB_DATABASE accounting_dev
```
## Deployment dan rollback
1. Deploy ke staging dan jalankan `composer install --no-dev --optimize-autoloader` untuk build production.
2. Jalankan lint, dependency audit, login, logout, seluruh AJAX CRUD utama, upload, export, webhook, dan cron melalui CLI.
3. Ambil backup production tepat sebelum deployment.
4. Deploy source terlebih dahulu; migration baru hanya dijalankan setelah backup tervalidasi.
5. Jika smoke test gagal, kembalikan source release sebelumnya. Restore database hanya jika migration/transaksi deployment telah mengubah data.
## Aturan endpoint
- `Auth` adalah endpoint publik untuk login/logout.
- `AttendanceWebhook` publik khusus perangkat yang serialnya terdaftar dan dikecualikan dari CSRF.
- `Cronjob` hanya dapat dijalankan melalui PHP CLI.
- `Dbcompare` hanya untuk Admin, nonaktif secara default, dan seluruh koneksinya berasal dari environment.
- Controller bisnis harus mewarisi `MY_Controller`; controller admin penuh dapat mewarisi `MY_Admin_Controller`.
## Upload dan data pribadi
- File baru di `uploads/karyawan` dan background hasil upload tidak boleh ditambahkan ke Git.
- File lama yang sudah terlanjur tracked perlu dikeluarkan dari Git index pada perubahan repository terpisah, setelah backup dan pemeriksaan dampak deployment.
- Untuk production berskala besar, pindahkan upload ke private object storage dan berikan akses melalui endpoint terotorisasi.
## Database migration
Folder `application/migrations` telah disiapkan. Baseline migration harus dibuat dari schema production yang sudah diverifikasi dan tidak boleh dijalankan otomatis sebelum perbandingan staging selesai.
## Verifikasi minimum
- Request tanpa login ke controller bisnis menghasilkan redirect atau HTTP 401 untuk AJAX.
- Login gagal lima kali terkunci selama lima menit pada session tersebut.
- POST tanpa token CSRF ditolak.
- Cron melalui browser menghasilkan HTTP 403.
- Dbcompare nonaktif menghasilkan HTTP 404.
- Upload script ke folder upload tidak dapat dieksekusi.
- `composer audit --locked` tidak melaporkan advisory pada dependency production.
+27
View File
@@ -0,0 +1,27 @@
# Tahap 10–11 — HR/Payroll dan Pajak
## HR dan absensi
- Riwayat jabatan, departemen, cabang, status kerja, kontrak dan gaji efektif tersedia pada `employee_employment_history`.
- Data rekening, BPJS, NPWP/status pajak dan benefit profile berada pada master karyawan. Akses master dan payroll dibatasi Admin sampai role HR/Payroll khusus dibuat.
- Dokumen karyawan disimpan terpisah dengan `access_level`, nama file terenkripsi dan hash.
- Raw log mesin memiliki device whitelist, payload hash unik, status validasi dan relasi ke hasil absensi.
- Koreksi absensi, lembur dan approval memiliki subledger sendiri.
- Lock bulanan ditegakkan trigger database terhadap insert/update/delete absensi.
## Payroll
- Workflow: draft → reviewed → approved → final → posted → paid.
- Formula hanya menerima variabel yang diizinkan dan operator matematika dasar; tidak menggunakan `eval`.
- Komponen dasar: gaji pokok, lembur, unpaid leave, THR, bonus, BPJS, PPh 21 dan cicilan pinjaman.
- Prorata karyawan baru, snapshot variabel/formula, hash register, pemisahan reviewer/approver, final lock, jurnal otomatis dan slip individual.
- Tarif lembur Development default Rp25.000/jam dan dapat diatur dengan `PAYROLL_OVERTIME_RATE`; Production wajib mengikuti kebijakan perusahaan.
## Pajak
- Master kode pajak mempunyai jenis, inclusive/exclusive, tarif/formula, masa berlaku dan mapping akun.
- Tax register menyimpan pajak input, output dan withholding per dokumen/baris.
- Posting invoice dan supplier invoice otomatis mengisi tax register secara idempotent.
- Data historis pajak invoice/tagihan di-backfill tanpa jurnal baru.
- Periode pajak dapat open, reviewed, filed atau closed. Periode filed/closed menolak transaksi pajak baru.
- Register dapat diekspor CSV.
+26
View File
@@ -0,0 +1,26 @@
# Tahap 12–14 — Reporting, Budget, Multi-company, Multi-currency
## Laporan
- Menu Laporan Profesional menyediakan trial balance, general ledger, P&L, balance sheet, cash flow, changes in equity, journal register, account detail, komparatif bulan/tahun dan actual vs budget.
- Drill-down jurnal, tautan subledger, filter tanggal/akun/dimensi, CSV yang dapat dibuka Excel, print/PDF browser, saved filter, export queue dan snapshot closing tersedia.
- Background worker: `php index.php reportworker run`.
- Snapshot menyimpan payload dan hash filter sehingga laporan closing tidak berubah mengikuti transaksi periode berikutnya.
## Budget dan dimensi
- Dimensi branch, department, project, cost center, profit center dan salesperson tersedia di `journal_details`.
- Budget mendukung bulanan/tahunan, akun+dimensi, revision snapshot, approval, active version, actual vs budget, warning/blocking, dan commitment PO.
- Budget blocking diperiksa pada jalur `JournalService`; commitment hanya dihitung bila `purchase_order_lines.budget_account_id` terisi.
## Multi-company dan mata uang
- Company context berasal dari `user_companies`; user hanya dapat memilih perusahaan yang diberikan kepadanya.
- Data legacy dipindahkan ke perusahaan `MAIN`; seluruh baris kritis telah mempunyai `company_id`.
- Jurnal baru otomatis menerima company pada header dan detail. Laporan profesional selalu difilter company aktif.
- Mata uang, kurs harian, transaction/base amount, saldo foreign AR/AP, revaluasi belum terealisasi, akun gain/loss, serta struktur intercompany/elimination tersedia.
- Revaluasi menggunakan kurs terakhir yang tanggalnya tidak melebihi tanggal proses dan menghasilkan jurnal otomatis.
## Batas aktivasi
Menu legacy yang dibangun sebelum Tahap 14 belum semuanya memakai tenant filter di setiap query. Jangan aktifkan perusahaan kedua untuk transaksi operasional sebelum seluruh controller legacy pada checklist Production dinyatakan tenant-aware. Laporan profesional, budget, company context, journal core dan FX sudah tenant-aware.
+35
View File
@@ -0,0 +1,35 @@
# Tahap 15 — UI/UX Laptop dan HP
## Shell dan navigasi
- `NavigationService` adalah satu-satunya konfigurasi menu untuk desktop dan mobile; keduanya merender `partials/navigation_items` yang sama.
- Menu dan quick action difilter permission; Admin tetap memperoleh seluruh menu administrasi.
- Pencarian menu, badge approval, quick action, breadcrumb, mobile bottom action bar dan shortcut scanner tersedia.
- Link mati `Umum` dihapus. Identitas shell menggunakan Accounting tanpa identitas template lama.
## Mobile behavior
- Touch target minimum 44 px, modal fullscreen, numeric keyboard, lazy image, sticky action, collapsible/filter panel utility dan summary card utility.
- Tabel biasa diubah ke card/detail per baris menggunakan label header. DataTables tetap memakai responsive extension.
- Form POST menolak submit ganda dan menampilkan global loading. Posting offline selalu ditolak.
- Upload gambar di atas 350 KB dikompresi client-side ke maksimum 1600 px/JPEG 82% jika browser mendukung Canvas/DataTransfer.
- Laporan profesional tetap dapat dilihat sebagai HTML; PDF bukan satu-satunya jalur.
## Frontend dan PWA
- Bootstrap, DataTables, Select2, QR scanner dan SweetAlert dimuat berdasarkan halaman. SweetAlert duplikat pada login dihapus.
- Bootstrap dan jQuery memiliki fallback lokal. Aturan responsive kanonis berada di `app-final.css`; `app-responsive.min.css` dipertahankan hanya sebagai marker kompatibilitas cache PWA lama. JavaScript UI tetap menggunakan `app-ui.min.js`.
- PWA memakai ikon 192/512 yang benar. Service worker hanya cache `/assets/`; halaman dan respons transaksi tidak disimpan untuk penggunaan offline.
## Pengujian viewport
Headless Chrome diuji pada:
- 360×800
- 390×844
- 768×1024
- 1366×768
Artefak berada di `docs/ui-tests/`. Pemeriksaan regresi dapat dijalankan dengan `php index.php stage15check`.
Pengujian transaksi autentik tetap perlu dilakukan dengan akun per role pada perangkat fisik sebelum Production, terutama scanner/camera permission, keyboard mobile, upload foto, modal panjang dan proses approval.
+61
View File
@@ -0,0 +1,61 @@
# Tahap 16 — Skalabilitas database dan performa
## Implementasi
- Migration `20260902000100` menambahkan indeks query transaksi, database session, dashboard summary, queue, dead-letter, dan metrik database.
- Migration `20260902000200` menyediakan shared application cache.
- Migration `20260902000300` menyediakan arsip activity log.
- Session default menggunakan driver database (`ci_sessions`). Production dapat mengatur `SESSION_DRIVER=database`; Redis dapat dipilih setelah extension dan server Redis tersedia.
- Dashboard summary di-cache 5 menit per company. Chart dapat dikembangkan dengan pola cache yang sama bila volume jurnal sudah besar.
- Endpoint `lookups/search/{customer|item|account|employee|supplier}` memakai pencarian dan pagination maksimal 30 baris.
- Form penerimaan pelanggan telah berhenti memuat seluruh customer dan menggunakan AJAX lookup.
- Queue memiliki claim transaction/row lock, idempotency key, exponential retry, batas percobaan, dan dead-letter.
- Handler tersedia untuk report PDF/Excel/CSV, email/reminder, penyusutan, dan payroll calculation.
- Retention worker memindahkan activity log lama ke `activity_logs_archive` dalam batch, lalu membersihkan cache, session, dan completed job lama.
- DB monitor menyimpan latency koneksi/query, threads, slow query counter, dan ukuran database.
## Perintah operasional
Jalankan dari folder aplikasi melalui Task Scheduler/cron:
```text
php index.php queueworker run reports 20
php index.php queueworker run default 20
php index.php maintenanceworker retention 365 5000
php index.php dbmonitor run
php index.php scalabilitycheck index 20
php index.php stage16check
```
Saran jadwal: queue setiap menit, DB monitor setiap 5 menit, retention setiap malam, scalability check pada CI/staging.
## Baseline development 2 September 2026
- Database: 6.19 MB.
- Journal: 123 header / 388 detail.
- Activity log: 654.
- Latency koneksi: 16.926 ms.
- Latency query health check: 10.053 ms.
- Dashboard summary p95: 11.046 ms.
- Open receivables p95: 22.089 ms.
- General ledger berada jauh di bawah target 2 detik.
- Queue integration: idempotent dan berhasil menghasilkan file background.
Volume development masih kecil. Angka ini baseline fungsi, bukan bukti kapasitas production.
## Audit lanjutan untuk staging
- 29 view memakai DataTables; 13 sudah `serverSide:true`. Tabel master/transaksi yang tumbuh tanpa batas harus dimigrasikan bertahap ke server-side. Tabel referensi kecil boleh tetap client-side dengan hard limit.
- Jalankan load test menggunakan salinan data yang sudah dianonimkan: minimal 100 ribu jurnal, 50 ribu invoice, 25 ribu item/barcode, dan 1 juta stock/activity ledger.
- Uji 25, 50, lalu 100 virtual user untuk dashboard, pencarian, daftar transaksi, posting invoice, pembayaran, dan transfer stok.
- Gunakan akun serta session khusus staging; jangan melakukan load test transaksi pada production.
- Acceptance: daftar p95 <2 detik, dashboard p95 <3 detik, error <1%, tidak ada duplikasi nomor/stok/job.
## Catatan production
- Backup dan jalankan migration sampai `20260902000300`.
- Perubahan file-session ke database-session akan meminta user login kembali saat deploy.
- Jalankan worker hanya satu instance dahulu; tambah worker setelah memastikan locking MariaDB bekerja pada versi production.
- Konfigurasikan SMTP sebelum mengaktifkan job email/reminder.
- Pantau pertumbuhan `app_dead_letters`; setiap dead-letter harus mempunyai tindak lanjut dan mekanisme replay terkontrol.
- Aktifkan slow query log pada database production dan review query di atas ambang 500 ms.
+95
View File
@@ -0,0 +1,95 @@
# Tahap 2: Fondasi Arsitektur dan Transaksi
## Arsitektur baru
Controller menangani request dan response, model menangani akses data, sedangkan aturan bisnis berada di service:
```text
HTTP/CLI request
-> Controller
-> Domain Service
-> Domain Model
-> Database
```
Komponen yang tersedia:
- `JournalService`: validasi header, akun, baris, dan keseimbangan jurnal.
- `PostingService`: posting jurnal dari transaksi sumber dan pencegahan posting ganda.
- `NumberingService`: nomor dokumen atomic melalui `document_sequences`.
- `AccountMappingService`: mapping akun dari database dengan fallback konfigurasi.
- `TransactionService`: commit/rollback berbasis callback dan exception.
- `JournalModel`, `AccountModel`, `InvoiceModel`, dan `InventoryModel`.
- `BusinessException` dan helper response JSON konsisten.
## Integrasi yang sudah dilakukan
- Jurnal manual menggunakan `JournalService` dan `NumberingService`.
- Draft invoice menggunakan `InvoiceModel` dan penomoran terpusat.
- Posting item invoice menggunakan `PostingService`.
- Sinkronisasi stok dari invoice menggunakan `InventoryModel`.
- Nomor jurnal invoice dan pembayaran menggunakan `NumberingService`.
- Mapping akun invoice tidak lagi ditulis langsung pada controller.
- Penyusutan aset menggunakan mapping akun dan `PostingService`.
Proses jurnal lama pada modul Items, Asset manual, dan pembayaran invoice yang kompleks masih tetap kompatibel. Migrasinya ke service dilakukan bertahap setelah characterization test tersedia agar perilaku transaksi lama tidak berubah tanpa terdeteksi.
## Migration
Jalankan hanya melalui CLI:
```powershell
php index.php migrate latest
php index.php migrate status
```
Rollback ke version sebelumnya:
```powershell
php index.php migrate version 20260831000100
```
Jangan rollback migration pertama jika sequence sudah dipakai production, karena tabel sequence dan mapping akan dihapus oleh migration `down`.
## Pemeriksaan accounting
Pemeriksaan read-only:
```powershell
php index.php accountingcheck
```
Pemeriksaan mendeteksi:
- Tabel fondasi yang hilang.
- Mapping menuju akun yang tidak ada.
- Nomor jurnal duplikat.
- Jurnal debit/kredit tidak balance.
## Temuan data historis
Pada penerapan awal ditemukan lima nomor referensi jurnal yang sudah duplikat:
- `ADJ-20260609-87`
- `INV-20260610-0006`
- `INV-20260611-0001`
- `INV-20260722-0002`
- `INV-20260723-0006`
Data tersebut tidak diubah otomatis. Accounting perlu menentukan transaksi yang sah, kemudian referensi duplikat dikoreksi dengan audit trail. Setelah bersih, tambahkan unique index pada `journals.no_ref` melalui migration terpisah.
## Aturan penggunaan service
1. Controller baru tidak boleh insert langsung ke `journals` atau `journal_details`.
2. Mapping akun baru dibuat pada `system_account_mappings`, bukan ID pada controller.
3. Nomor dokumen baru harus melalui `NumberingService`.
4. Operasi multi-tabel harus memakai `TransactionService` atau transaksi eksplisit dengan penanganan exception.
5. Saat dipanggil di dalam transaksi yang sudah aktif, gunakan parameter `manageTransaction=false` pada service posting.
6. Untuk sumber yang boleh menghasilkan beberapa jurnal, nonaktifkan duplicate-source guard dan gunakan referensi unik per periode/transaksi.
## Langkah operasional berikutnya
1. Review delapan mapping akun bersama accounting.
2. Rekonsiliasi lima nomor jurnal historis yang duplikat.
3. Tambahkan characterization test untuk Items, Asset, dan pembayaran invoice.
4. Setelah test tersedia, pindahkan sisa direct journal insert ke `PostingService`.
+65
View File
@@ -0,0 +1,65 @@
# Tahap 3: Fondasi Accounting Profesional
## Tahun buku dan periode
- Tahun buku kalender dapat dibuat melalui menu Admin → Periode Accounting.
- Setiap tahun buku memiliki 12 periode bulanan.
- Status periode: `open`, `soft_closed`, dan `closed`.
- Soft close/close ditolak bila masih ada jurnal `draft`, `submitted`, atau `approved`.
- Membuka kembali periode wajib menyertakan alasan dan dicatat pada log periode.
- Trigger database menghubungkan journal legacy ke periode dan menolak insert pada periode non-open.
## Workflow jurnal
```text
draft -> submitted -> approved -> posted -> reversed
| |
+-> rejected<+
```
- Jurnal manual baru selalu dibuat sebagai `draft`.
- Submit hanya dapat dilakukan pembuat jurnal atau Admin.
- Approve, reject, post, dan reversal hanya tersedia bagi Admin pada implementasi saat ini.
- Opsi pemisahan pembuat dan approver dapat diaktifkan dengan `WORKFLOW_REQUIRE_SEPARATE_APPROVER=true`.
- Jurnal posted tidak dapat dihapus melalui menu Jurnal.
- Koreksi posted dilakukan dengan reversal yang menukar debit dan kredit.
- Setiap perubahan status dicatat pada `journal_status_histories`.
- Seluruh jurnal historis diberi status awal `posted` dan history migrasi tanpa mengubah nominal.
## Dampak laporan
Dashboard, buku besar, laba rugi, neraca, neraca saldo, dan generator PDF hanya menghitung status `posted` dan `reversed`. Draft, submitted, approved, serta rejected tidak memengaruhi laporan.
## Chart of accounts
- Kode akun unik pada database.
- Tersedia jenis akun header dan akun transaksi.
- Akun header tidak dapat menerima posting.
- Akun nonaktif tidak dapat menerima posting.
- Parent cycle dicegah.
- Akun yang mempunyai child, transaksi, atau mapping sistem tidak dapat dihapus.
- Akun yang sudah pernah digunakan sebagai akun posting dipertahankan sebagai akun transaksi saat migrasi.
## Migration
Version terakhir Tahap 3:
```text
20260831000700
```
Jalankan:
```powershell
php index.php migrate latest
php index.php migrate status
php index.php accountingcheck
```
## Catatan kompatibilitas
Beberapa modul legacy seperti Items, Asset manual, dan bagian tertentu Invoice masih membuat atau membersihkan jurnal sumber secara langsung. Insert-nya sudah dilindungi period trigger dan default `posted`, tetapi proses pembatalannya belum seluruhnya menggunakan reversal. Migrasi penuh proses tersebut dilakukan bersama penyempurnaan masing-masing subledger agar stok, invoice, aset, dan jurnal tidak terpisah.
## Temuan data lama
Lima nomor jurnal historis masih duplikat dan tidak diubah otomatis karena memerlukan keputusan accounting. Unique index `journals.no_ref` baru dapat ditambahkan setelah rekonsiliasi data tersebut.
+29
View File
@@ -0,0 +1,29 @@
# Tahap 4 — Approval dan Audit Trail
Tahap ini menambahkan kontrol internal tanpa mengubah jurnal historis yang telah posted.
## Fitur
- Workflow approval berbasis modul, jenis transaksi, rentang nilai, role atau user.
- Approval inbox yang responsif untuk laptop dan HP.
- Separation of duties: pembuat tidak dapat menyetujui pengajuannya sendiri.
- Snapshot transaksi pada saat diajukan.
- Riwayat setiap tindakan approval.
- Audit trail before/after dengan sensor password/token/secret dan hash berantai.
- Trigger database melarang UPDATE dan DELETE audit log.
- Nomor referensi jurnal wajib unik.
## Data development
Perintah berikut hanya boleh dijalankan sebelum migration 009 dan bukan di Production:
```bash
php index.php accountingrepair duplicate_refs
php index.php migrate latest
```
Referensi kedua dan berikutnya dalam kelompok duplikat diberi suffix `-D{id_jurnal}`. Setiap perubahan dicatat sebagai `development_repair` di `immutable_audit_logs`.
## Batas tahap
Workflow default baru diterapkan pada jurnal manual. Approval invoice, pembelian, pembayaran, stok, aset, dan payroll akan menggunakan engine yang sama saat subledger masing-masing ditingkatkan. Admin masih melakukan posting setelah approval; ini disengaja agar approval dan posting merupakan dua tindakan eksplisit.
+34
View File
@@ -0,0 +1,34 @@
# Tahap 5 — Invoice dan Piutang
## Cakupan yang diterapkan
- Quotation dan sales order, termasuk konversi menjadi draft invoice.
- Draft, submit, approval, posting, jatuh tempo, dan reversal invoice.
- Pajak dan diskon per item; ringkasan pajak pada invoice.
- Penerimaan pelanggan dengan cicilan/partial payment dan alokasi satu pembayaran ke banyak invoice.
- Kelebihan pembayaran hanya diterima jika ditandai sebagai uang muka pelanggan.
- Credit note, refund uang muka, dan bad debt/write-off dengan jurnal otomatis.
- Aging piutang, customer statement, credit limit/block, reminder queue, receipt, dan lampiran.
- Nomor invoice/pembayaran/dokumen unik dan audit trail.
- Stok/jurnal draft dinonaktifkan; keduanya hanya diposting satu kali saat invoice approved diposting.
## Perilaku data Development
Data lama dipertahankan. Invoice `paid`, `partial`, dan `unpaid` di-backfill sebagai `workflow_status=posted`, tetapi tidak dibuatkan jurnal atau mutasi stok ulang. Pembayaran lama diberi nomor `LEG-PAY-{id}` dan dialokasikan ke invoice asal di `payment_allocations`.
Invoice draft lama tetap draft. Stock log yang sudah pernah dibuat oleh alur lama ditandai pada detail agar posting baru tidak mengurangi stok dua kali.
## Menu
- Invoice → Penawaran & Sales Order
- Invoice → Piutang & Penerimaan
- Invoice → Draft/Riwayat Invoice
- Approval → persetujuan invoice
## Reminder
Tahap ini menyediakan antrean reminder. Pengiriman email/WhatsApp aktual memerlukan provider dan credential Production; worker pengiriman tidak mengirim otomatis sebelum provider disetujui.
## Lampiran
Jenis yang diterima: PDF, JPG, PNG, WEBP; maksimum 5 MB. File disimpan dengan nama acak, hash SHA-256, dan hanya dapat diunduh setelah login.
+20
View File
@@ -0,0 +1,20 @@
# Tahap 6 — Pembelian, Supplier, dan Hutang
## Alur baru
`Purchase Request → Approval → Purchase Order → Approval → Penerimaan parsial → Supplier Invoice/3-way match → Approval → Posting Hutang → Pembayaran`
Master supplier memuat termin, NPWP, rekening bank, kontak, alamat, status, dan saldo awal. Saldo awal membuat tagihan opening dan jurnal kontrol saat supplier pertama kali dibuat.
Kontrol utama:
- Receipt tidak dapat melebihi qty PO dan setiap stock log menyimpan referensi goods receipt.
- Supplier invoice hanya berasal dari receipt pada PO yang sama; qty invoice tidak dapat melebihi qty diterima.
- Nomor invoice supplier unik per supplier.
- Pembayaran mengunci tagihan, tidak boleh melebihi balance, dan satu pembayaran dapat dialokasikan ke beberapa tagihan.
- Selisih pembayaran hanya diterima sebagai uang muka supplier.
- Retur fisik mengurangi stok; debit note mengurangi hutang dan membuat jurnal otomatis.
- Aging hutang dan supplier statement tersedia.
- Seluruh jurnal memakai standar keterangan `[AUTO]` Tahap 5.
Data pembelian legacy (1.547 movement dan 17 jurnal) tidak dikonversi otomatis karena tidak memiliki identitas supplier/PO yang dapat dipercaya.
+23
View File
@@ -0,0 +1,23 @@
# Tahap 7 — Persediaan dan Gudang Profesional
## Fondasi
`inventory_ledger` menjadi ledger immutable untuk qty dan nilai. `stock_logs` tetap dimirror agar modul lama kompatibel. Qty item dan stock log telah diubah menjadi desimal.
Fitur mencakup opening, masuk, keluar, transfer, adjustment, opname dan approval selisih, retur, rusak/hilang, reservation, reorder point, batch, serial/barcode, bin, stock card API, Average/FIFO, valuation, slow/dead stock, serta rekonsiliasi GL.
## Kontrol concurrency
- Dokumen memiliki idempotency key unik.
- Ledger dan stock log memiliki idempotency unik.
- Posting mengunci dokumen, saldo/layer FIFO, dan barcode.
- Barcode memakai optimistic version; transaksi bersamaan kedua ditolak.
- Trigger DB menolak stock log keluar yang membuat saldo negatif dan mengunci baris item.
- Trigger barcode menolak qty negatif atau reserved melebihi qty.
- Inventory ledger tidak dapat di-update/delete.
## Penyesuaian Development
Backfill legacy menemukan KLEM KABEL -2 dan ISOLASI KABEL -3 di Gudang Cikembar. Dibuat dokumen opening correction untuk membawa keduanya ke nol, lengkap dengan jurnal dan audit. Selisih nilai awal inventory ledger vs GL sebesar Rp891.000 diselesaikan dengan jurnal baseline teridentifikasi `DEV-STAGE7-BASELINE`. Setelah koreksi, ledger dan GL sama-sama Rp154.400.950.
Koreksi Development ini tidak boleh disalin otomatis ke Production.
+18
View File
@@ -0,0 +1,18 @@
# Tahap 8–9 — Aset Tetap, Kas, Bank, dan Rekonsiliasi
## Yang diterapkan
- Subledger aset: kategori, sumber perolehan, kapitalisasi, residu, masa manfaat, metode, lokasi/PIC, QR, event immutable, maintenance, transfer, impairment, revaluation, disposal/hilang/rusak, opname, schedule dan rekonsiliasi GL.
- Penyusutan memiliki unique key `asset_id + period`, menggunakan row lock, memeriksa periode terbuka, mendukung catch-up, dan dibatasi sampai nilai residu.
- Penghapusan aset lama dinonaktifkan; pelepasan wajib melalui mutasi dan menghasilkan laba/rugi.
- Master kas/bank terhubung satu-ke-satu ke akun GL, cash ledger, kas masuk/keluar, transfer, petty cash, cash advance, reimbursement, biaya/bunga bank, posisi kas, impor CSV, matching, outstanding dan rekonsiliasi.
- Pembayaran keluar minimal `CASH_APPROVAL_THRESHOLD` (default Rp10.000.000) berstatus submitted dan wajib disetujui user berbeda.
- Semua posting otomatis memakai `PostingService`, periode fiskal, nomor unik, keterangan `[AUTO]` detail, serta idempotency key.
- Lampiran bukti tersedia melalui endpoint `accountingattachments/upload` untuk aset, maintenance, opname, transaksi kas, transfer, dan rekonsiliasi (PDF/gambar/CSV maksimum 5 MB, nama terenkripsi dan hash SHA-256).
## Catatan operasional
- CSV rekening koran: `tanggal,deskripsi,referensi,debit,kredit,saldo`.
- Matching otomatis hanya saran berdasarkan rekening, arah, nominal sama, rentang tanggal ±3 hari, dan referensi. Pengguna tetap mengonfirmasi.
- Cash forecast table telah tersedia untuk integrasi jadwal piutang/hutang; realisasi tidak dibuat otomatis agar tidak menggandakan transaksi.
- Perolehan dari PO/gudang tetap menyimpan `source_type/source_id`; transaksi historis hanya di-backfill sebagai event, tanpa jurnal baru.
+82
View File
@@ -0,0 +1,82 @@
# Finalisasi Peralatan Teknisi
## Ruang lingkup
Peralatan Teknisi adalah subledger operasional penguasaan fisik. Modul tidak membuat jurnal, tidak menulis `stock_logs`/`inventory_ledger`, serta tidak mengubah `qty_sisa`, harga, costing, atau nilai persediaan. Barang perusahaan tetap mengacu ke `items`, `kode_barang`, dan `item_barcodes`. `reserved_qty` dipakai untuk menahan kuantitas yang sedang berada di luar gudang agar tidak dapat dijual dua kali.
Barang customer disimpan terpisah dalam `customer_equipment_registry` dan tidak pernah diberi `item_id` atau `barcode_id` persediaan.
## Migration production
Jalankan setelah backup dan maintenance window:
```bash
php index.php migrate latest
php index.php migrate status
php index.php migrate equipment_audit
```
Migration yang harus terpasang berurutan:
1. `20260911000100_finalize_technician_equipment_operations.php`
2. `20260911000200_link_application_users_to_employees.php`
3. `20260911000300_add_customer_equipment_source_fields.php`
4. `20260911000400_add_technician_document_location.php`
5. `20260911000500_add_technician_condition_permission.php`
6. `20260911000600_document_technician_opening_balances.php`
7. `20260911000700_add_technician_attachment_permission.php`
Migration pertama membuat register barang customer, dokumen/header-detail, saldo custody, antrean pemeriksaan, indeks, permission awal, dan saldo awal dari `item_technician`. Migration tidak membuat ulang `item_movements` lama. Migration kedua menambah relasi opsional `users.employee_id` agar akun ber-role Teknisi dapat dibatasi pada barangnya sendiri. Migration ketiga menambah tanggal, nomor dokumen, dan alasan sumber barang customer/non-persediaan. Migration keempat menambah lokasi pemasangan pada dokumen operasional. Migration kelima memisahkan izin kondisi rusak/hilang. Migration keenam membuat dokumen immutable “Saldo Awal Migrasi” tanpa menggandakan movement lama. Migration ketujuh memisahkan izin melihat lampiran.
Setelah migration, buka Pengaturan → Pengguna dan tautkan setiap akun Teknisi ke Data Karyawan yang benar. Login ulang diperlukan agar permission baru masuk ke session.
## Alur final
1. Gudang → teknisi: pilih teknisi sekali, scan/cari banyak barang, lalu posting satu dokumen batch. Sistem menahan `reserved_qty`, mencatat `item_movements`, dan saldo custody per baris.
2. Teknisi → customer: pemasangan penuh/sebagian dan dokumen pemasangan.
3. Customer → teknisi: pelepasan dengan kondisi, customer asal, dan histori.
4. Teknisi → teknisi: pilih teknisi asal/tujuan sekali dan transfer banyak barang penuh/sebagian.
5. Teknisi → gudang: pengembalian banyak barang dalam satu dokumen dan satu bukti batch; seluruhnya masuk karantina dan belum available.
6. Pemeriksaan: hanya hasil layak yang melepaskan reservation dan membuat barang perusahaan available kembali.
7. Penggantian: pemasangan barang baru dan pelepasan barang lama berada dalam satu transaksi/dokumen.
8. Koreksi: membuat dokumen reversal baru; dokumen lama menjadi `reversed` dan tidak dihapus.
Pencarian menerima input scanner barcode USB/Bluetooth, barcode, serial number, kode barang, dan nama barang. Barang customer yang sudah terdaftar dipilih dari hasil scan/pencarian sehingga identitasnya tidak perlu dimasukkan ulang. PDF daftar posisi barang tersedia pada setiap teknisi.
## UNIT dan QTY
- `UNIT`: kuantitas selalu 1 dan hanya boleh mempunyai satu posisi aktif.
- `QTY`: mendukung perpindahan sebagian dan saldo per teknisi/customer/status. Setiap perubahan menggunakan transaksi, row lock, version check, validasi saldo, dan idempotency key.
## Permission
- `technician_equipment`: akses/register/export.
- `technician_equipment_all`: melihat seluruh teknisi.
- `technician_attachment`: melihat foto/dokumen lampiran.
- `technician_handover`: serah terima gudang.
- `technician_installation`: pemasangan, pelepasan, penggantian.
- `technician_transfer`: transfer antar teknisi.
- `technician_return`: pengembalian.
- `technician_inspection`: pemeriksaan gudang.
- `technician_condition`: menandai rusak, hilang, atau dihapuskan operasional.
- `technician_correction`: reversal.
Master Admin/Admin selalu mendapat seluruh kemampuan. Role Teknisi tanpa izin `technician_equipment_all` dibatasi memakai `users.employee_id`.
## Pemeriksaan development
Perintah smoke test menggunakan transaksi rollback dan tidak meninggalkan data:
```bash
php index.php migrate equipment_smoke
php index.php migrate equipment_qty_smoke
php index.php migrate equipment_replacement_smoke
php index.php migrate equipment_query_smoke
php index.php migrate equipment_batch_smoke
```
Jangan menjalankan metode smoke melalui HTTP; controller migration hanya menerima CLI.
## Tidak diubah
Alur pembelian, penerimaan, penjualan, invoice, aset tetap, payroll, laporan accounting, master barang, harga, costing, dan general ledger tidak diubah oleh finalisasi ini.
+59
View File
@@ -0,0 +1,59 @@
# Cutover database production lama ke V2
Proses ini bersifat **satu arah**: database lama hanya dibaca, sedangkan database V2 wajib kosong saat bootstrap. ID dan seluruh isi tabel lama dipertahankan, kemudian migration aplikasi dijalankan hanya pada database V2.
## Pengamanan
- Jalankan melalui CLI; endpoint web ditolak.
- Kredensial hanya melalui environment variable dan tidak disimpan di repository.
- Kedua koneksi diuji sebelum target ditulis.
- Bootstrap ditolak jika sumber dan target sama atau target sudah berisi objek.
- Snapshot memakai consistent read-only transaction.
- Backup dapat diberi SHA-256 agar file yang salah tidak dapat diimpor.
- Kode akun dinormalisasi menjadi tepat empat digit oleh migration aplikasi.
## Environment variable
```text
DBSYNC_ENABLED=true
DBSYNC_SOURCE_HOST=
DBSYNC_SOURCE_PORT=3306
DBSYNC_SOURCE_USERNAME=
DBSYNC_SOURCE_PASSWORD=
DBSYNC_SOURCE_DATABASE=
DBSYNC_TARGET_HOST=
DBSYNC_TARGET_PORT=3306
DBSYNC_TARGET_USERNAME=
DBSYNC_TARGET_PASSWORD=
DBSYNC_TARGET_DATABASE=
DBSYNC_BACKUP_DIRECTORY=C:\xampp\private_backups\accounting_dev
```
Opsional untuk memakai snapshot yang sudah tersedia:
```text
DBSYNC_BACKUP_FILE=C:\path\snapshot.sql
DBSYNC_BACKUP_SHA256=checksum_snapshot
DBSYNC_MYSQL_BIN=C:\xampp\mysql\bin\mysql.exe
```
## Perintah
```powershell
php index.php databasesync check
php index.php databasesync snapshot
php index.php databasesync bootstrap
php index.php databasesync verify
```
`bootstrap` otomatis membuat snapshot jika `DBSYNC_BACKUP_FILE` tidak diisi, mengimpor snapshot ke target kosong, menjalankan seluruh migration, dan melakukan audit akhir.
## Cutover production sebenarnya
1. Uji `check` dan pastikan target kosong.
2. Aktifkan maintenance/read-only pada aplikasi lama agar tidak ada transaksi baru selama snapshot akhir.
3. Jalankan `bootstrap` satu kali.
4. Pastikan `verify` berhasil: migration terbaru, semua kode akun empat digit, jurnal balance, dan tidak ada orphan utama.
5. Ubah konfigurasi aplikasi ke database V2, lakukan smoke test login/laporan/transaksi, lalu buka maintenance.
Cron sinkronisasi tabel-ke-tabel tidak digunakan karena struktur lama dan V2 berbeda dan berisiko menimpa hasil normalisasi. Jika downtime nol benar-benar diperlukan, siapkan CDC/outbox sebagai proyek terpisah; jangan menjalankan kedua aplikasi menulis ke database berbeda tanpa mekanisme konflik.
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB