# PANDUAN PENGUJIAN MANUAL 1 PROJECT (MASTER HUMAN QA HANDBOOK) ## Platform Omnichannel KeluargaMart (POS · B2B · ERP · Backend · NextReport) > **Tujuan Dokumen:** > Panduan ini disusun untuk penguji manusia (QA Engineer, Developer, Product Owner, dan Staf Operasional) agar dapat melakukan verifikasi manual end-to-end pada **seluruh modul sistem KeluargaMart**, memastikan tidak ada bug fungsional, salah hitung uang, dokumen anak yatim (*orphan*), kebocoran omnichannel, maupun "angka ghoib" yang lolos ke produksi. --- ## DAFTAR ISI 1. [Peta Akses Aplikasi, Port & Akun Uji](#1-peta-akses-aplikasi-port--akun-uji) 2. [Modul POS: Kasir Ritel, Struk, Scanner & Shift](#2-modul-pos-kasir-ritel-struk-scanner--shift) 3. [Modul B2B: Toko Online Grosir & Checkout Omnichannel](#3-modul-b2b-toko-online-grosir--checkout-omnichannel) 4. [Modul Pergudangan & Logistik (Fulfillment & Stok)](#4-modul-pergudangan--logistik-fulfillment--stok) 5. [Modul Pengadaan & Hutang Supplier (Purchasing & AP)](#5-modul-pengadaan--hutang-supplier-purchasing--ap) 6. [Modul Sales Force & Target Penjualan](#6-modul-sales-force--target-penjualan) 7. [Modul Akuntansi, Kas & Laporan Keuangan](#7-modul-akuntansi-kas--laporan-keuangan) 8. [Modul Multi-Toko, Master Data & Keamanan RBAC](#8-modul-multi-toko-master-data--keamanan-rbac) 9. [Modul NextReport: Cetak PDF & Struk](#9-modul-nextreport-cetak-pdf--struk) 10. [Audit Cepat 10 Query SQL untuk Menemukan Anomali](#10-audit-cepat-10-query-sql-untuk-menemukan-anomali) --- ## 1. PETA AKSES APLIKASI, PORT & AKUN UJI ### A. Matriks Port & URL Aplikasi (Lokal Container) | Aplikasi | URL | Deskripsi | |---|---|---| | **POS Kasir** | `http://localhost:3003` | Single Page Application (Vue 3 + Vite) untuk kasir register toko fisik | | **ERP Back-Office** | `http://localhost:3001` | Portal manajemen operasional, gudang, pembelian, akuntansi, dan master data | | **B2B Storefront** | `http://localhost:3002` | Toko e-commerce grosir (Nuxt 4 SSR) untuk pemesanan toko mitra & buyer | | **Go Backend REST** | `http://localhost:3004` | Chi Go REST API — *Single Source of Truth* untuk aturan bisnis & database | | **NextReport Engine**| `http://localhost:3005` | Mesin batch renderer PDF & dokumen accounting | | **PostgreSQL Database**| `localhost:5432` | DB: `erp`, User: `erp`, Password: `erp` | ### B. Matriks Akun Uji Peran (Role Persona) | Persona | Email Login | Password | Peran & Ruang Lingkup | |---|---|---|---| | **Super Admin / Owner** | `admin@keluargamart.local` | `Admin@1234` | Akses penuh ke seluruh menu ERP, POS, dan konfigurasi | | **Finance Manager** | `finance1@keluargamart.local` | `Finance@1234` | Akses Jurnal, Arus Kas, Neraca, Bayar Hutang PO, Approval Voucher | | **Staff Gudang / Logistik**| `warehouse1@keluargamart.local`| `Warehouse@1234`| Akses Packing Order, Surat Jalan (DO), Goods Receipt, Stock Opname | | **Kasir Toko 1 (Medan)** | `cashier1@keluargamart.local` | `Cashier@1234` | Kasir outlet Toko Medan (Shift, POS, Scan, Retur, Pickup) | | **Kasir Toko 2 (Binjai)**| `cashier2@keluargamart.local` | `Cashier@1234` | Kasir outlet Toko Binjai (Uji isolasi retur dan shift antar toko) | | **Sales Lapangan** | `sales1@keluargamart.local` | `Sales@1234` | Input Sales Order kanvasing, check-in kunjungan toko pelanggan | | **Pembeli B2B (Mitra Grosir)**| `buyer1@keluargamart.local`| `Buyer@1234` | Belanja grosir dus/karton, checkout pickup toko vs kirim alamat | --- ## 2. MODUL POS: KASIR RITEL, STRUK, SCANNER & SHIFT ### Skenario 2.1: Buka Shift Kasir & Penguncian Transaksi (Shift Guard) 1. Buka browser ke `http://localhost:3003`. 2. Login sebagai `cashier1@keluargamart.local`. 3. **Uji Penguncian (Fail-Closed):** Sebelum membuka shift, coba langsung klik produk atau tekan tombol Bayar. - **PASS:** Sistem menolak transaksi dan memunculkan dialog/peringatan *"Buka shift dahulu. Shift kasir wajib dibuka sebelum berjualan."* 4. Klik **Buka Shift**, masukkan Modal Kas Awal (misal: `Rp 200.000`), lalu klik konfirmasi. - **PASS:** Shift aktif, status di header menunjukkan *"Shift Dibuka"*, dan tombol kasir siap melayani. ### Skenario 2.2: Deteksi Scanner Hardware & Auto-Detect Tanpa Fokus 1. Pada halaman Kasir, **klik di sembarang tempat** (misal klik judul "Kasir" atau tombol kategori minuman) agar kotak input barcode **kehilangan fokus**. 2. Arahkan scanner barcode fisik ke produk (atau ketik cepat barcode produk misal `8997788990011` lalu tekan `Enter`). - **PASS:** Produk ("Kopi Susu Mantap") otomatis masuk ke keranjang belanja tanpa kasir perlu mengklik kotak barcode terlebih dahulu. - **PASS:** Kursor otomatis kembali berkedip di kotak input barcode agar siap scan barang berikutnya. 3. Klik tombol pencarian manual (`F2`), ketik `teh`, lalu **langsung scan barang lain**. - **PASS:** Karakter barcode tertangkap bersih, produk baru masuk ke keranjang, dan kolom pencarian tidak tercemar angka barcode. ### Skenario 2.3: Perhitungan Uang, Diskon Member & Multi-Metode Pembayaran 1. Tambahkan 2 produk ke keranjang. 2. Klik tombol **Pilih Pelanggan (`F4`)**, pilih pelanggan yang berstatus member (misal: `Member Gold`). - **PASS:** Muncul badge member dan potongan diskon member terhitung otomatis pada ringkasan subtotal. 3. Tekan **Bayar (`F6`)**: - Masukkan nominal uang tunai yang melebihi total (misal total Rp 15.000, bayar Rp 50.000). - **PASS:** Nilai Kembalian terhitung presisi (`Rp 35.000`). - Klik **Konfirmasi Pembayaran**. Transaksi berhasil tersimpan. ### Skenario 2.4: Kualitas Cetak Struk Kertas 58mm & Laci Kasir (Cash Drawer) 1. Pada popup sukses transaksi kasir, klik tombol **Cetak Struk** (atau **Cetak Thermal** via Cleanter). 2. Periksa hasil fisik / preview dialog cetak: - **Header:** Tulisan `KELUARGAMART` huruf kapital besar tebal. - **No. Transaksi:** Berawalan `TRX-` (contoh: `TRX-202611-000208`), berada dalam 1 baris (tidak patah). - **Garis Pemisah:** Garis lurus tipis solid (`─────────`), bukan blok kotak bergerigi (`▄▄▄▄`). - **Nama Barang:** Ditampilkan di baris pertama full-width rata kiri (`text-left`). Baris kedua menampilkan `1 x Rp 15.000` di kiri dan subtotal di kanan. **Tidak boleh saling bertumpuk**. - **Laci Uang (Cash Drawer):** Jika printer thermal terhubung ke laci via kabel RJ11, laci harus otomatis terbuka (*drawer kick*) saat struk selesai dicetak. ### Skenario 2.5: Retur Penjualan Independen Antar-Toko (Cabang) 1. Buka menu **Retur** di POS (`/returns`). 2. Masukkan nomor transaksi yang dibuat dari **Toko Binjai** (Toko 2), padahal Anda sedang login di **Toko Medan** (Toko 1). - **PASS:** Sistem menolak retur dengan pesan: *"Transaksi berasal dari toko lain. Retur hanya dapat dilakukan di toko asal transaksi."* 3. Masukkan nomor transaksi yang sah dari toko sendiri: - **PASS:** Barang transaksi muncul, kasir bisa memilih item yang diretur, dan struk retur tercetak valid. ### Skenario 2.6: Depot Air Minum Galon 1. Ubah mode kasir ke **Mode Galon (`F8`)**. 2. Pilih layanan: **Isi Ulang** atau **Pinjam Tabung** (dengan uang deposit). 3. Selesaikan transaksi: - **PASS:** Transaksi tercatat khusus dengan prefix galon, deposit tercatat di buku kasir, dan struk galon tercetak rapi. ### Skenario 2.7: Tutup Shift & Rekonsiliasi Kas Fisik 1. Klik avatar kasir → pilih **Tutup Shift**. 2. Sistem akan meminta kasir memasukkan **Jumlah Uang Fisik di Laci**. 3. Masukkan uang fisik: - Masukkan angka yang sama dengan perhitungan sistem: Selisih = `Rp 0`. - Masukkan angka yang kurang Rp 5.000: Sistem mencatat selisih kurang (*Shortage*) `Rp -5.000`. 4. Klik **Tutup Shift**: - **PASS:** Shift tertutup, riwayat shift tercatat permanen di ERP, dan kasir kembali ke layar login / terkunci. --- ## 3. MODUL B2B: TOKO ONLINE GROSIR & CHECKOUT OMNICHANNEL ### Skenario 3.1: Minimum Order (MOQ) & Tiering Harga Grosir 1. Buka browser ke `http://localhost:3002` (B2B Storefront). 2. Login sebagai `buyer1@keluargamart.local`. 3. Buka halaman detail produk grosir (misal: Minyak Goreng atau Wafer Superstar). 4. Masukkan jumlah 1 Pcs: - **PASS:** Sistem menampilkan harga satuan normal atau mengingatkan batas MOQ grosir. 5. Masukkan jumlah 1 Karton / 24 Pcs: - **PASS:** Harga otomatis turun ke harga tier grosir per karton. ### Skenario 3.2: Checkout Mode 1 — "Kirim ke Alamat" (Delivery Kurir) 1. Masukkan produk ke keranjang belanja, klik **Checkout**. 2. Pada pilihan pengiriman, pilih **"Kirim ke Alamat"**. Masukkan alamat pengantaran. 3. Pilih metode pembayaran: **Transfer Bank BCA**. 4. Klik **Buat Pesanan**: - **PASS (Konsistensi Omnichannel):** 1. Pesanan memiliki nomor order `SO-...`. 2. Di B2B detail pesanan, muncul stepper pengiriman kurir: *Menunggu Pembayaran → Diproses Gudang → Dikirim Kurir → Selesai*. 3. Muncul tombol *"Lacak Pengiriman"*. 4. **DI ERP GUDANG:** Pesanan ini **WAJIB MASUK** ke daftar antrean *Packing Order*. 5. **DI MESIN KASIR POS:** Pesanan ini **TIDAK BOLEH MUNCUL** di menu *Ambil Toko* kasir. ### Skenario 3.3: Checkout Mode 2 — "Ambil Sendiri di Toko" (Store Pickup) 1. Masukkan produk ke keranjang B2B, klik **Checkout**. 2. Pada pilihan pengiriman, pilih **"Ambil Sendiri di Toko (Pickup)"**. Pilih outlet toko tujuan (misal: Toko Medan). 3. Pilih metode pembayaran: **Bayar Tunai di Kasir (Cash on Pickup)**. 4. Klik **Buat Pesanan**: - **PASS (Konsistensi Omnichannel):** 1. Di B2B detail pesanan, stepper kurir **DISEMBUNYIKAN**. Tombol *"Lacak Pengiriman"* **TIDAK BOLEH MUNCUL**. 2. Menampilkan petunjuk: *"Tunjukkan No. Pesanan ini ke kasir Toko Medan untuk serah terima barang."* 3. **DI ERP GUDANG:** Pesanan ini **DILARANG MUNCUL** di daftar *Packing Order* gudang dan tidak boleh dibuatkan surat jalan delivery order otomatis! 4. **DI MESIN KASIR POS:** Pesanan ini **WAJIB MUNCUL** di menu *Ambil Toko* (`/pickup`) Toko Medan. ### Skenario 3.4: Uji Penyerahan Kasir Toko untuk Pesanan B2B Pickup 1. Buka POS Kasir Toko Medan (`http://localhost:3003/pickup`). 2. Cari nomor pesanan pickup dari Skenario 3.3 di atas. 3. Klik tombol **Serahkan Barang & Terima Pembayaran**: - **PASS:** Kasir menerima uang tunai, pesanan langsung beralih ke status `delivered / completed`. - **PASS:** Uang tunai otomatis masuk ke kas register kasir shift saat itu. - **PASS:** Tidak ada faktur piutang yang tertinggal atau status menggantung. --- ## 4. MODUL PERGUDANGAN & LOGISTIK (FULFILLMENT & STOK) ### Skenario 4.1: Gerbang Pembayaran Packing Order (Security Gate) 1. Login ke ERP (`http://localhost:3001`) sebagai Staff Gudang (`warehouse1@keluargamart.local`). 2. Buka menu **Gudang → Packing Order** (`/warehouse/packing`). 3. Cari pesanan delivery yang pembayarannya masih berstatus **Transfer Belum Lunas** (bukti belum diapprove finance). - **PASS:** Tombol packing terkunci / disable dengan tooltip *"Pesanan belum dibayar. Menunggu verifikasi pembayaran finance."* - **Kriteria Gagal (BUG):** Gudang bisa membungkus dan mengirim barang pesanan yang belum dibayar oleh pembeli transfer. ### Skenario 4.2: Cetak Packing Slip & Label Pengiriman 1. Pada pesanan delivery yang sudah lunas (`confirmed`), klik tombol **Mulai Packing**. 2. Centang barang yang dimasukkan ke kardus. 3. Klik tombol **Cetak Packing Slip**: - **PASS:** Lembar cetak berformat jelas dengan barcode nomor PO/SO, daftar item barang yang harus diambil, lokasi rak bin gudang, dan tanda tangan checker gudang. ### Skenario 4.3: Pembuatan Surat Jalan (Delivery Order) & Bukti Penerimaan (POD) 1. Setelah packing selesai, buat **Delivery Order (Surat Jalan)**. 2. Tunjuk driver / kurir armada internal. 3. Setelah kurir kembali dari pengiriman: - Buka Delivery Order terkait. - Klik **Konfirmasi Penerimaan (POD)**. - Masukkan nama penerima dan unggah foto bukti tanda terima (Foto POD). - **PASS:** Foto POD tersimpan di server dan muncul saat detail pengiriman dibuka kembali. Status pengiriman menjadi `Delivered`. ### Skenario 4.4: Mutasi Antar Gudang / Toko (Stock Transfer) 1. Buka menu **Gudang → Transfer Stok**. 2. Buat permintaan transfer: Dari *Gudang Pusat Medan* ke *Outlet Toko Binjai*, produk: *Kopi Susu Mantap (50 pcs)*. 3. Kirim transfer: - **PASS:** Stok di Gudang Pusat berkurang 50, dan status stok berpindah menjadi `In Transit` (Sedang dalam perjalanan). 4. Login sebagai kasir/staf Toko Binjai, buka menu Transfer Masuk, klik **Terima Barang**: - **PASS:** Status menjadi `Completed`. Stok di Toko Binjai bertambah 50 pcs. Tidak ada selisih stok yang hilang. ### Skenario 4.5: Stock Opname (Penyesuaian Fisik vs Sistem) 1. Buka menu **Gudang → Stock Opname**. 2. Buat sesi opname untuk kategori tertentu. 3. Masukkan jumlah perhitungan fisik (misal sistem: 100 pcs, fisik: 98 pcs, selisih -2 pcs). 4. Klik **Selesaikan Opname & Buat Penyesuaian**: - **PASS:** Stok sistem terkoreksi menjadi 98 pcs. - **PASS:** Sistem otomatis mencatat mutasi stok selisih opname dan memposting jurnal beban selisih persediaan ke buku besar akuntansi. --- ## 5. MODUL PENGADAAN & HUTANG SUPPLIER (PURCHASING & AP) ### Skenario 5.1: Alur Pembuatan & Persetujuan Purchase Order (PO) 1. Buka menu **Pembelian → Purchase Order** (`/purchasing/orders`). 2. Klik **Buat PO Baru**. Pilih supplier (misal: *PT Indofood Sukses Makmur*), pilih gudang penerima, tambahkan 2 item barang dan harga beli kesepakatan. 3. Simpan sebagai **Draft**: - **PASS:** PO berstatus `Draft`. Stok belum bertambah, hutang belum timbul. 4. Klik tombol **Setujui / Approve PO** (hanya akun manajer/admin yang memiliki tombol ini): - **PASS:** PO berstatus `Approved`. Lembar cetak PO resmi bertanda tangan dapat diunduh / dicetak. ### Skenario 5.2: Penerimaan Barang Supplier (Goods Receipt) & Barang Cacat 1. Saat truk supplier datang, buka menu **Pembelian → Penerimaan Barang (GR)**. 2. Klik **Terima Barang dari PO**. 3. Masukkan jumlah yang diterima: - Barang dipesan: 100 pcs. - Barang diterima bagus: 95 pcs. - Barang rusak/pecah (cacat): 5 pcs. 4. Klik **Konfirmasi Penerimaan**: - **PASS:** Stok gudang hanya bertambah 95 pcs. - **PASS:** Sistem otomatis mencatat 5 pcs barang retur/tolak dan mengurangi nilai tagihan supplier sebesar barang cacat tersebut. ### Skenario 5.3: Pengecekan Detail Hutang Supplier (`/purchasing/debts`) 1. Buka menu **Pembelian → Hutang Supplier**. 2. Halaman menampilkan daftar PO yang belum lunas pembayarannya. 3. Klik pada nomor PO atau tombol **Detail** (ikon mata): - **PASS:** Terbuka modal detail rincian hutang: 1. **Rangkuman Keuangan:** Total PO, Sudah Dibayar, Sisa Hutang, dan Nilai Retur/Cacat. 2. **Tab Item PO:** Menampilkan nama barang yang dibeli, SKU, qty dipesan, harga satuan, dan subtotal. 3. **Tab Penerimaan Barang (GR):** Menampilkan nomor GR penerimaan dan tanggal barang masuk. 4. **Tab Riwayat Pembayaran:** Menampilkan seluruh voucher yang pernah dibayarkan untuk PO tersebut. ### Skenario 5.4: Pembayaran Hutang Supplier via Voucher 1. Pada modal detail hutang (atau tabel hutang), klik tombol **Bayar**. 2. Masukkan jumlah pembayaran (misal bayar lunas, atau bayar sebagian). 3. Pilih Akun Kas/Bank sumber dana (misal: *1000.01.02 Kas Operasional* atau *Bank BCA*). 4. Klik **Bayar**: - **PASS:** Sisa hutang PO berkurang secara instan. - **PASS:** Sistem otomatis membuat voucher pengeluaran kas berstatus `Dibayar`. - **PASS:** Jurnal akuntansi kas keluar otomatis terposting (Debit: Hutang Dagang Supplier, Kredit: Kas/Bank). --- ## 6. MODUL SALES FORCE & TARGET PENJUALAN ### Skenario 6.1: Input Sales Order (Kanvasing Lapangan) 1. Login sebagai Sales Lapangan (`sales1@keluargamart.local`). 2. Buka menu **Kunjungan Sales → Check-in Toko Pelanggan**. 3. Buat Sales Order (SO) baru untuk toko langganan. 4. Simpan order: - **PASS:** Pesanan masuk ke sistem berstatus `pending_approval` agar diverifikasi oleh Supervisor/Admin. ### Skenario 6.2: Verifikasi Akurasi Target Sales (`/sales/targets`) 1. Buka menu **Penjualan → Target Sales**. 2. **Uji Penjumlahan Hirarki (Double Counting):** - Pilih filter **"Semua Tingkatan"**. - Perhatikan total target di kartu KPI teratas: - **PASS:** Total target mencerminkan target penjualan perusahaan yang benar (bukan penjumlahan kumulatif GM + BM + SPV + Sales yang berlipat ganda 4x). 3. **Uji Isolasi Status Order (Anti-Draft & Anti-Cancel):** - Catat angka pencapaian (*achievement*) sales hari ini. - Buat sales order baru berstatus `Draft` (belum disetujui). - Refresh halaman Target Sales: - **PASS:** Angka realisasi penjualan **TIDAK BERTAMBAH**. - Setujui order tersebut (`Confirmed`): - **PASS:** Angka realisasi penjualan baru bertambah sesuai nilai order sah. ### Skenario 6.3: Manajemen Piutang Pelanggan (Accounts Receivable / AR) 1. Buka menu **Penjualan → Piutang Pelanggan** (`/finance/receivables` atau `/sales/invoices`). 2. Filter berdasarkan toko atau jatuh tempo: - **PASS:** Menampilkan daftar faktur yang belum lunas lengkap dengan umur piutang (*Aging*: 1-30 hari, 31-60 hari, >90 hari). 3. Klik tombol **Catat Pembayaran Piutang**: - Masukkan nominal pembayaran dari pelanggan, pilih rekening bank penerima. - **PASS:** Sisa piutang pelanggan berkurang dan saldo piutang di profil pelanggan otomatis sinkron. --- ## 7. MODUL AKUNTANSI, KAS & LAPORAN KEUANGAN ### Skenario 7.1: Otomasi Jurnal Penjualan & Pembelian 1. Selesaikan 1 transaksi kasir di POS atau 1 pembayaran PO di ERP. 2. Buka menu **Akuntansi → Jurnal Umum** (`/accounting/journals`). 3. Cari nomor transaksi / nomor voucher tadi: - **PASS:** Jurnal otomatis terbentuk dengan format Debit = Kredit (Seimbang/Balance). - **PASS:** Nomor referensi jurnal mengarah tepat ke nomor transaksi asal. ### Skenario 7.2: Verifikasi Laporan Arus Kas (Pemberantasan Uang Ghoib) 1. Buka menu **Laporan → Laporan Arus Kas** (`/reports/cashflow-statement`). 2. Pilih rentang tahun berjalan (2026). 3. **Uji Integritas Penerimaan Kas Penjualan:** - Perhatikan baris *"Penerimaan Kas dari Pelanggan"*. - **PASS:** Nilai penerimaan kas mencerminkan penjualan operasional riil (puluhan juta rupiah). - **Kriteria Gagal (BUG BESAR):** Menampilkan angka Rp 2 Miliar yang berasal dari order testing Superstar Jumbo yang statusnya sudah dibatalkan (*cancelled*). 4. **Uji Klasifikasi Hutang Supplier:** - Periksa baris *"Pembayaran Kas kepada Pemasok / Supplier"*. - **PASS:** Masuk ke bagian **Arus Kas Aktivitas Operasi (Operating Activities)** sesuai standar PSAK 02 / IAS 7, **bukan** masuk ke Aktivitas Pendanaan (Financing). ### Skenario 7.3: Paritas Angka Dashboard vs Modal Rincian (Summary vs Drilldown) 1. Buka halaman utama **Dashboard ERP** (`/dashboard`). 2. Lihat kartu KPI (misal: *Net Cashflow*, *Total Piutang*, *Hutang Supplier Jatuh Tempo*). 3. Klik pada kartu KPI tersebut untuk membuka jendela popup modal rinciannya: - **PASS:** Jumlah baris dan total nominal di dalam popup modal **100% PERSIS SAMA** dengan angka yang tertera di kartu KPI luar. - **Kriteria Gagal (BUG):** Kartu luar menampilkan angka non-nol, tetapi saat diklik popup modalnya kosong (*blank* atau Rp 0). --- ## 8. MODUL MULTI-TOKO, MASTER DATA & KEAMANAN RBAC ### Skenario 8.1: Deaktivasi Outlet Toko yang Aman (Smart Store Deactivation) 1. Buka menu **Pengaturan → Toko & Cabang** (`/stores`). 2. Cari outlet toko yang saat ini masih memiliki **Shift Kasir Aktif**: - Coba klik tombol Nonaktifkan Toko. - **PASS:** Sistem menolak dengan pesan pencegahan: *"Toko tidak dapat dinonaktifkan karena masih memiliki shift kasir yang aktif. Harap tutup shift kasir terlebih dahulu."* 3. Cari toko tanpa shift aktif, lakukan nonaktifkan: - **PASS:** Toko menjadi nonaktif dan kasir di toko tersebut tidak dapat melakukan login baru. ### Skenario 8.2: Penegakan Hak Akses Fail-Closed (RBAC Enforcement) 1. Login menggunakan akun Kasir (`cashier1@keluargamart.local`). 2. Coba ketik manual URL halaman keuangan ERP di browser: `http://localhost:3001/accounting/general-ledger` atau `http://localhost:3001/reports/cashflow-statement`. - **PASS:** Layar menolak akses (redirect ke login atau menampilkan halaman *403 Forbidden / Tidak Memiliki Izin*). - **Kriteria Gagal (BUG):** Kasir bisa mengintip buku besar laba rugi perusahaan. ### Skenario 8.3: Pengaturan Harga Produk (Ritel POS vs Grosir B2B) 1. Buka menu **Produk → Daftar Produk** di ERP. 2. Edit satu produk, periksa pengaturan satuan multi-unit: - Satuan Utama: PCS (Harga Jual Ritel POS = Rp 15.000). - Satuan Grosir: DUS (Isi 24 PCS, Harga Grosir B2B = Rp 330.000). 3. Uji beli di POS (muncul harga Rp 15.000 per pcs) dan uji beli di B2B (muncul opsi harga dus Rp 330.000). --- ## 9. MODUL NEXTREPORT: CETAK PDF & STRUK ### Skenario 9.1: Lembar PO Resmi dengan Stempel Cetak Sekali (Print-Once Ledger) 1. Buka detail PO yang sudah disetujui di ERP. 2. Klik tombol **Cetak Dokumen PO (PDF)**: - **PASS:** Dokumen PDF terunduh rapi dengan kop resmi KeluargaMart, daftar barang bertabel presisi, nomor referensi, dan kotak tanda tangan. - **PASS:** Di backend tercatat stempel cetak: `PrintCount: 1`, dicetak oleh akun yang bersangkutan. ### Skenario 9.2: Lembar Invoice & Surat Jalan Gudang 1. Buka halaman faktur penjualan / surat jalan pengiriman. 2. Klik tombol **Cetak PDF**: - **PASS:** File PDF dibuat dalam tempo < 1 detik melalui NextReport tanpa halaman kosong di akhir (*no blank page*) dan ukuran kertas pas A4 / Continuous Form. --- ## 10. AUDIT CEPAT 10 QUERY SQL UNTUK MENEMUKAN ANOMALI Jalankan perintah ini di terminal server (`podman exec keluargamart-postgres psql -U erp -d erp -c "..."`) untuk mendeteksi bug database dalam hitungan detik: ```sql -- 1. Deteksi Uang Ghoib (Pembayaran mengambang dari order yang dibatalkan): SELECT so.so_number, so.status, p.payment_number, p.amount, p.created_at FROM payments p JOIN invoices inv ON inv.id = p.payable_id JOIN sales_orders so ON so.id = inv.sales_order_id WHERE so.status = 'cancelled'; -- 2. Deteksi Pembayaran Riil yang Lupa Diposting ke Jurnal Akuntansi: SELECT p.payment_number, p.amount, p.payment_date, p.payment_method FROM payments p LEFT JOIN journal_entries je ON je.reference_number = p.payment_number WHERE je.id IS NULL AND p.amount > 0; -- 3. Deteksi Selisih Piutang Pelanggan (Saldo Profil vs Rincian Faktur Terbuka): SELECT c.name, c.current_debt, COALESCE(SUM(inv.remaining_amount), 0) AS total_faktur FROM customers c LEFT JOIN invoices inv ON inv.customer_id = c.id AND inv.status <> 'paid' GROUP BY c.id, c.name, c.current_debt HAVING c.current_debt <> COALESCE(SUM(inv.remaining_amount), 0); -- 4. Deteksi Selisih Hutang Supplier (Total PO vs Saldo Pembayaran): SELECT po.po_number, po.total_amount, po.paid_amount, po.remaining_amount FROM purchase_orders po WHERE po.remaining_amount <> (po.total_amount - po.paid_amount); -- 5. Deteksi Pesanan Pickup Toko yang Nyasar ke Gudang Packing: SELECT so.so_number, so.shipping_address, so.status FROM sales_orders so WHERE so.shipping_address ILIKE '%[Ambil Sendiri di Toko]%' AND so.id IN (SELECT sales_order_id FROM delivery_orders); -- 6. Deteksi Stok Minus di Gudang / Toko: SELECT p.code, p.name, s.quantity, w.name AS gudang_toko FROM stocks s JOIN products p ON p.id = s.product_id JOIN warehouses w ON w.id = s.warehouse_id WHERE s.quantity < 0; -- 7. Deteksi Jurnal Akuntansi Tidak Seimbang (Debit != Kredit): SELECT je.id, je.entry_number, SUM(jl.debit) AS total_debit, SUM(jl.credit) AS total_kredit FROM journal_entries je JOIN journal_lines jl ON jl.journal_entry_id = je.id GROUP BY je.id, je.entry_number HAVING SUM(jl.debit) <> SUM(jl.credit); -- 8. Deteksi Transaksi Kasir POS Tanpa Shift Aktif: SELECT so.so_number, so.created_at FROM sales_orders so WHERE so.order_type = 'pos' AND so.shift_id IS NULL; -- 9. Deteksi Faktur yang Totalnya Berbeda dengan Penjumlahan Baris Item: SELECT so.so_number, so.total_amount, COALESCE(SUM(soi.subtotal), 0) AS sum_items FROM sales_orders so JOIN sales_order_items soi ON soi.sales_order_id = so.id GROUP BY so.id, so.so_number, so.total_amount HAVING ABS(so.total_amount - (COALESCE(SUM(soi.subtotal), 0) + so.tax_amount + so.shipping_cost - so.discount_amount)) > 0.05; -- 10. Deteksi Voucher Pembayaran Tanpa Nomor Akun Kas / Bank: SELECT id, voucher_number, amount, voucher_date FROM vouchers WHERE (cash_account_code IS NULL OR cash_account_code = '') AND amount > 0; ``` --- ## KESIMPULAN & TANDA SELESAI (DEFINITION OF DONE) Satu fitur atau modul dinyatakan **SELESAI dan BEBAS BUG** hanya jika: 1. Telah diuji oleh manusia mengikuti skenario di atas tanpa ada toast error yang tidak diharapkan. 2. Data yang ditampilkan di layar sesuai dengan data yang tertulis di tabel database. 3. Cetakan fisik struk thermal dan dokumen PDF tidak ada yang terpotong atau tumpang tindih. 4. Semua 10 query audit SQL di atas menghasilkan **0 anomali**.