Run distributor operations with stock, invoices, and profits in one place.
HJSys is a distributor management system for procurement, sales, finance, and owner oversight. It centralizes purchase orders, invoicing, payments, stock updates, overdue tracking, and gross profit and commission calculations so the team can work from one source of truth.
Procurement Admin Rina, 32 - Rina manages supplier orders and product stock for daily replenishment. She needs a fast way to create purchase orders, receive goods, and keep inventory accurate without spreadsheet work.
Finance Admin Dedi, 38 - Dedi handles invoicing, customer payments, and overdue accounts. He needs accurate totals, partial payment tracking, and reliable overdue flags to keep cash flow visible.
Owner Arman, 49 - Arman needs a clear view of profit, commissions, and operational health without digging into transaction details. He cares about decision-ready reports and control over all data.
Rina used to receive supplier deliveries in a spreadsheet, then manually update stock counts later in the day. That meant stock was often wrong during the busiest hours, and the sales team sometimes promised items that were already sold out.
With HJSys, she creates a purchase order, receives it in the system, and stock updates instantly. The sales and finance teams now see the same inventory data, so the owner gets cleaner reporting and fewer costly mistakes.
On the finance side, Dedi issues invoices with saved price snapshots, records partial payments, and lets the system mark overdue accounts automatically. Arman can open the dashboard and immediately see gross profit, commission liability, and outstanding receivables without asking for a manual recap.
Team & resourcing - Small team - 2 backend engineers, 1 UI/UX designer, part-time QA, part-time PM
Paste this into Cursor, Bolt, Lovable, or v0 to start building.
Build a distributor management web app called HJSys using Laravel 11, FilamentPHP v5, and MySQL 8. Create a production-ready admin system for procurement, finance, sales, and owner roles. Core modules: 1. Authentication and role-based authorization for super-admin, procurement, finance_sales, and salesman. 2. Master data CRUD for suppliers, clients, sales reps, and products. 3. Purchase orders with statuses draft, sent, received, cancelled. When a PO is marked received, increase product stock exactly once. 4. Sales invoices with statuses draft, invoiced, cancelled and payment statuses unpaid, partially_paid, paid, overdue. When invoiced, deduct stock exactly once. If an invoiced invoice is cancelled, restore stock exactly once. 5. Invoice items must store immutable buy_price_snapshot and sell_price_snapshot from products at entry time. Never recalculate historical invoices when product prices change. 6. Payments module that supports multiple payments per invoice and recalculates paid_amount and payment_status automatically. 7. Gross profit calculation per line and invoice, plus commission calculation only for fully paid invoices using sales rep commission_rate. 8. Daily scheduler job that marks unpaid or partially_paid invoices overdue when due_date has passed. 9. PDF generation for invoice, delivery note, and purchase order using DomPDF. Excel exports for sales recap, overdue aging, and commission reports using maatwebsite/excel. 10. Audit-friendly transaction history and role-specific dashboards. Primary screens: Dashboard, Suppliers, Clients, Sales Reps, Products, Purchase Orders, Sales Invoices, Payments, Reports, Users and Roles. Data model: users, suppliers, clients, sales_reps, products, purchase_orders, purchase_order_items, sales_invoices, sales_invoice_items, payments. Use proper foreign keys, timestamps, soft deletes where appropriate, and indexed columns for invoice_number, po_number, due_date, payment_status, and foreign keys. Implementation requirements: Use Laravel policies and middleware for access control. Use database transactions for all stock-impacting status changes. Make stock mutation idempotent. Add server-side validation for unique codes, required references, quantity > 0, and non-negative amounts. Use queued jobs for PDF generation and the overdue scheduler. Build responsive Filament resources with searchable tables, filters, status badges, and print/export actions. Include seeders for demo data and a clean, maintainable service layer for inventory and financial calculations. Default deployment target: Dockerized Laravel app on a single Ubuntu 22.04 VPS behind Nginx, with MySQL 8 and scheduled cron execution.
# PRODUCT REQUIREMENT DOCUMENT (PRD) ## 1. PROJECT OVERVIEW - **System Name:** HJSys (Harapan Jaya Management System) - **Target Tech Stack:** Laravel 11.x, FilamentPHP v5, MySQL 8.0 - **Target Infrastructure:** Single VPS Ubuntu 22.04 LTS (Dockerized / Coolify / Native Nginx) - **Objective:** Mengotomatiskan seluruh siklus administrasi distributor—mulai dari procurement (PO Masuk), penjualan (PO Keluar/Invoice), manajemen stok otomatis, pelacakan piutang overdue, hingga kalkulasi presisi untuk keuntungan kotor (*gross profit*) dan komisi sales. --- ## 2. USER ROLES & ACCESS CONTROL | Role ID | Role Name | Tanggung Jawab & Hak Akses | | :--- | :--- | :--- | | `super-admin` | Super Admin / Owner | Akses penuh ke seluruh data, laporan keuangan, komisi sales, margin keuntungan, dan manajemen pengguna. | | `procurement` | Admin Procurement | Mengelola Master Supplier, Master Produk, dan Transaksi PO Masuk (Purchase Order ke Supplier). | | `finance_sales` | Admin Finance & Sales | Mengelola Master Client, PO Keluar, Invoice Penjualan, Pencatatan Pembayaran, dan Pelacakan Overdue. | | `salesman` | Salesman | Access Read-only / Draf input untuk PO Keluar dan melihat estimasi komisi pribadi. | --- ## 3. FASE 1: FITUR WAJIB (MVP - MUST HAVE) ### 3.1. Master Data Management - **Master Supplier:** `code`, `name`, `phone`, `address`, `top_days` (Term of Payment default). - **Master Client:** `code`, `name`, `owner_name`, `phone`, `delivery_address`, `tax_address`, `tax_number`, `credit_limit`, `top_days`. - **Master Salesman:** `code`, `name`, `phone`, `commission_rate` (Persentase default, misal `2.00`%). - **Master Produk:** - `sku`, `name`, `unit` (Dus/Pack/Pcs), `buy_price`, `sell_price`, `stock`. ### 3.2. Procurement / PO Masuk (Purchase Order) - **Status Lifecycle:** `draft` -> `sent` -> `received` -> `cancelled`. - **Field Utama:** `po_number`, `supplier_id`, `order_date`, `tax_type` (`non_ppn`, `include_ppn`, `exclude_ppn`), `tax_amount`, `total_amount`, `notes`. - **Item Transaksi:** `product_id`, `qty`, `buy_price`, `subtotal`. - **Automated Stock Rule:** Saat status PO Masuk berubah menjadi `received`, stok barang di `products.stock` **otomatis bertambah**. ### 3.3. Penjualan & Invoicing (Sales Order & Invoicing) - **Pemisahan Status Transaksi & Pembayaran:** - **Status Invoice:** `draft` -> `invoiced` -> `cancelled`. - **Status Payment:** `unpaid` -> `partially_paid` -> `paid` -> `overdue`. - **Field Utama:** `invoice_number`, `client_id`, `sales_rep_id`, `invoice_date`, `due_date`, `invoice_status`, `payment_status`, `tax_type`, `subtotal_amount`, `tax_amount`, `discount_amount`, `total_amount`, `paid_amount`, `gross_profit_total`. - **Item Transaksi:** `product_id`, `qty`, `buy_price_snapshot`, `sell_price_snapshot`, `discount_item`, `subtotal`, `gross_profit`. - **CRITICAL BUSINESS RULES:** 1. **Price Snapshotting:** Saat item dimasukkan ke invoice, system **WAJIB** menyimpan `buy_price_snapshot` dan `sell_price_snapshot` dari tabel `products`. Perubahan harga master produk di masa depan tidak boleh mengubah data histori invoice lama. 2. **Automated Stock Rule:** - Saat `invoice_status` diubah menjadi `invoiced`, stok barang di `products.stock` **otomatis berkurang**. - Jika invoice berstatus `invoiced` diubah menjadi `cancelled`, stok barang wajib **dikembalikan (rollback)** secara otomatis. ### 3.4. Keuangan, Piutang & Overdue Tracking - **Pencatatan Pembayaran:** Menampung riwayat cicilan/pembayaran per invoice (`sales_invoice_id`, `payment_date`, `amount`, `payment_method` [transfer/cash/giro], `reference_number`). - **Update Status Tagihan:** - Jika `paid_amount` = 0 -> Status `unpaid`. - Jika `paid_amount` < `total_amount` -> Status `partially_paid`. - Jika `paid_amount` >= `total_amount` -> Status `paid`. - **Automated Overdue Check:** Scheduled task (Cron Job) berjalan harian (pukul 00:01). Mengidentifikasi invoice berstatus `invoiced` dengan `payment_status` `unpaid` / `partially_paid` yang mana `now() > due_date`, kemudian memperbarui `payment_status` menjadi `overdue`. ### 3.5. Kalkulasi Keuntungan & Komisi Sales - **Rumus Keuntungan Kotor (Gross Profit):** $$\text{Gross Profit Item} = (\text{sell\_price\_snapshot} - \text{buy\_price\_snapshot}) \times \text{qty} - \text{discount\_item}$$ $$\text{Gross Profit Invoice} = \sum(\text{Gross Profit Item}) - \text{discount\_amount\_invoice}$$ - **Rumus Komisi Sales:** Calculated **HANYA** dari invoice berstatus `invoiced` dengan `payment_status` = `paid` (lunas). $$\text{Nilai Komisi} = \text{Total Nominal Invoice Lunas} \times \left( \frac{\text{sales\_rep.commission\_rate}}{100} \right)$$ ### 3.6. Export & Document Generation - **PDF Generation (`barryvdh/laravel-dompdf`):** - Cetak Surat Jalan menggunakan `delivery_address`. - Cetak Invoice Tagihan menggunakan `tax_address` dan menampilkan `tax_number`. - Cetak Purchase Order. - **Excel Export (`maatwebsite/excel`):** Export Rekap Penjualan, Laporan Overdue, dan Rincian Komisi Sales. --- ## 4. FASE 2: ROADMAP PENGEMBANGAN MASA DEPAN 1. **WhatsApp API Gateway:** Send PDF Invoice & Auto Reminder H-3 / H+1 Overdue. 2. **Multi-Warehouse Support:** Pelacakan stok di beberapa gudang terpisah dan fitur Transfer Stok. 3. **Modul Retur & Credit Note:** Penanganan barang rusak/retur toko yang memotong sisa tagihan piutang. 4. **Enforcement Limit Kredit:** Penguncian otomatis pembuatan invoice baru jika piutang toko melebihi `credit_limit`. 5. **Salesman Mobile Portal (PWA):** Tampilan khusus *smartphone* untuk input order langsung dari lokasi toko. 6. **Pencatatan Giro Mundur:** Pengelolaan pencairan giro dengan tanggal kliring resmi. --- ## 5. DATABASE SCHEMA (DBML) ```dbml Table users { id bigint [pk, increment] name varchar email varchar [unique] password varchar role enum('super-admin', 'procurement', 'finance_sales', 'salesman') created_at timestamp updated_at timestamp } Table suppliers { id bigint [pk, increment] code varchar [unique] name varchar phone varchar address text top_days int [default: 0] created_at timestamp updated_at timestamp } Table clients { id bigint [pk, increment] code varchar [unique] name varchar owner_name varchar phone varchar delivery_address text tax_address text [null] tax_number varchar [null] credit_limit decimal [default: 0] top_days int [default: 30] created_at timestamp updated_at timestamp } Table sales_reps { id bigint [pk, increment] user_id bigint [null, ref: > users.id] code varchar [unique] name varchar phone varchar commission_rate decimal [default: 2.00] created_at timestamp updated_at timestamp } Table products { id bigint [pk, increment] sku varchar [unique] name varchar unit varchar [default: 'Pcs'] buy_price decimal [default: 0] sell_price decimal [default: 0] stock int [default: 0] created_at timestamp updated_at timestamp } Table purchase_orders { id bigint [pk, increment] po_number varchar [unique] supplier_id bigint [ref: > suppliers.id] order_date date status enum('draft', 'sent', 'received', 'cancelled') [default: 'draft'] tax_type enum('non_ppn', 'include_ppn', 'exclude_ppn') [default: 'non_ppn'] tax_amount decimal [default: 0] total_amount decimal [default: 0] notes text [null] created_at timestamp updated_at timestamp } Table purchase_order_items { id bigint [pk, increment] purchase_order_id bigint [ref: > purchase_orders.id] product_id bigint [ref: > products.id] qty int buy_price decimal subtotal decimal } Table sales_invoices { id bigint [pk, increment] invoice_number varchar [unique] client_id bigint [ref: > clients.id] sales_rep_id bigint [ref: > sales_reps.id] invoice_date date due_date date invoice_status enum('draft', 'invoiced', 'cancelled') [default: 'draft'] payment_status enum('unpaid', 'partially_paid', 'paid', 'overdue') [default: 'unpaid'] tax_type enum('non_ppn', 'include_ppn', 'exclude_ppn') [default: 'non_ppn'] subtotal_amount decimal [default: 0] tax_amount decimal [default: 0] discount_amount decimal [default: 0] total_amount decimal [default: 0] paid_amount decimal [default: 0] gross_profit_total decimal [default: 0] notes text [null] created_at timestamp updated_at timestamp } Table sales_invoice_items { id bigint [pk, increment] sales_invoice_id bigint [ref: > sales_invoices.id] product_id bigint [ref: > products.id] qty int buy_price_snapshot decimal sell_price_snapshot decimal discount_item decimal [default: 0] subtotal decimal gross_profit decimal } Table payments { id bigint [pk, increment] sales_invoice_id bigint [ref: > sales_invoices.id] payment_date date amount decimal payment_method enum('transfer', 'cash', 'giro') reference_number varchar [null] notes text [null] created_at timestamp updated_at timestamp }
Design by The Resonance | Powered by GPC – The AI Transformation Company