Initial import of AbelBirdNest Stock
This commit is contained in:
45
docs/project-spec/purchase-analysis-mapping.md
Normal file
45
docs/project-spec/purchase-analysis-mapping.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Purchase Analysis Mapping
|
||||
|
||||
Dokumen ini memetakan sheet analisis pembelian ke modul sistem.
|
||||
|
||||
## Letak proses
|
||||
|
||||
- `Purchases`: berat beli, kadar beli, harga referensi, modal barang awal.
|
||||
- `Receipts`: berat masuk, kadar masuk, perbandingan beli vs masuk.
|
||||
- `Lots / Sorting`: berat akhir, kadar akhir, rasio barang atas rata-rata.
|
||||
- `Purchase Analysis`: biaya operasional, valuasi market, laba rugi total, laba rugi agen.
|
||||
|
||||
## Mapping field
|
||||
|
||||
| Field sheet | Sumber utama | Implementasi |
|
||||
| --- | --- | --- |
|
||||
| Berat beli | Purchase lines | `purchase_lines.qty_ordered` atau override di `purchase_analyses.weight_buy` |
|
||||
| Berat masuk | Receipt lines | agregat `receipt_lines.qty_received` atau override di `purchase_analyses.weight_received` |
|
||||
| Berat akhir | Lots / sorting | agregat `inventory_lots.original_qty` atau override di `purchase_analyses.weight_final` |
|
||||
| Kadar beli | Purchase | rata-rata `purchase_lines.purchase_moisture_percent` atau override |
|
||||
| Kadar masuk | Receipt | rata-rata `receipt_lines.moisture_percent` atau override |
|
||||
| Kadar akhir | Lot final | rata-rata `inventory_lots.final_moisture_percent` atau override |
|
||||
| Barang atas rata-rata | QC / sorting | rata-rata `inventory_lots.above_average_ratio_percent` atau override |
|
||||
| Harga MK A/R | Purchasing / owner | `purchase_lines.market_reference_price` atau override |
|
||||
| Operasional | Costing | `purchase_analysis_cost_entries` |
|
||||
| Laba/rugi agen | Costing | `purchase_analyses.agent_profit_share_total` |
|
||||
|
||||
## Rumus sistem
|
||||
|
||||
- `berat_naik_percent = (berat_masuk - berat_beli) / berat_beli * 100`
|
||||
- `susut_tambah = berat_akhir - berat_masuk`
|
||||
- `modal_barang = sum(purchase_lines.subtotal)`
|
||||
- `operasional = sum(cost_entries.amount)`
|
||||
- `total_modal_beli = modal_barang + operasional`
|
||||
- `modal_beli_per_kg = modal_barang / berat_beli`
|
||||
- `modal_masuk_per_kg = modal_barang / berat_masuk`
|
||||
- `modal_jual_per_kg = modal_barang / berat_akhir`
|
||||
- `total_modal_mal = manual market valuation atau harga_mk_ar * berat_akhir`
|
||||
- `total_laba_rugi = total_modal_mal - total_modal_beli`
|
||||
- `laba_total_per_kg = (total_laba_rugi - laba_rugi_agen) / berat_akhir`
|
||||
- `laba_agen_per_kg = laba_rugi_agen / berat_akhir`
|
||||
|
||||
## Catatan
|
||||
|
||||
- Istilah `TOTAL MODAL MAL` di sheet sumber belum sepenuhnya baku. Di sistem, field ini diwakili sebagai `market valuation total`, supaya tetap fleksibel.
|
||||
- Semua angka hasil hitung tetap bisa dioverride lewat modul `Purchase Analysis` bila perusahaan ingin mengikuti angka manual owner.
|
||||
401
docs/project-spec/walet-alur-bisnis.html
Normal file
401
docs/project-spec/walet-alur-bisnis.html
Normal file
@ -0,0 +1,401 @@
|
||||
<!doctype html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Blueprint Alur Bisnis Sistem Inventory Sarang Burung Walet</title>
|
||||
<style>
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 2cm 1.8cm 2cm 1.8cm;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #222;
|
||||
font-size: 11pt;
|
||||
line-height: 1.55;
|
||||
}
|
||||
h1, h2, h3, h4 {
|
||||
color: #111;
|
||||
margin-top: 1.1em;
|
||||
margin-bottom: 0.45em;
|
||||
page-break-after: avoid;
|
||||
}
|
||||
h1 { font-size: 22pt; }
|
||||
h2 { font-size: 16pt; border-bottom: 1px solid #ddd; padding-bottom: 4px; }
|
||||
h3 { font-size: 13pt; }
|
||||
ul, ol { margin-top: 0.3em; }
|
||||
li { margin: 0.12em 0; }
|
||||
p { margin: 0.45em 0; }
|
||||
.muted { color: #666; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Blueprint Alur Bisnis Sistem Inventory Sarang Burung Walet</h1>
|
||||
|
||||
<h2>Ringkasan</h2>
|
||||
<p>Dokumen ini merangkum alur bisnis untuk sistem inventory sarang burung walet dengan karakter operasional berikut:</p>
|
||||
<ul>
|
||||
<li>proses dimulai dari pembelian</li>
|
||||
<li>satu pembelian bisa terdiri dari beberapa jenis barang</li>
|
||||
<li>setiap jenis bisa memiliki beberapa grade</li>
|
||||
<li>barang yang diterima bisa langsung terklasifikasi atau masih perlu sortasi internal</li>
|
||||
<li>stok disimpan berbasis lot atau batch</li>
|
||||
<li>satu penjualan dapat mengambil barang secara parsial dari beberapa lot berbeda</li>
|
||||
<li>seluruh pergerakan barang harus dapat ditelusuri untuk kebutuhan costing, traceability, audit, dan analisis penyusutan</li>
|
||||
</ul>
|
||||
<p>Sistem ini bukan inventory biasa. Sistem ini adalah <i>lot-based traceable inventory system</i> untuk perdagangan sarang burung walet.</p>
|
||||
|
||||
<h2>Tujuan Sistem</h2>
|
||||
<ul>
|
||||
<li>mencatat pembelian multi jenis dan multi grade</li>
|
||||
<li>mengelola penerimaan barang dan pembentukan batch atau lot</li>
|
||||
<li>mendukung sortasi, verifikasi ulang, dan regrade</li>
|
||||
<li>menyimpan stok per lot sekaligus menampilkan ringkasan stok per jenis-grade</li>
|
||||
<li>mendukung penjualan campuran dari beberapa lot</li>
|
||||
<li>menghitung HPP berdasarkan lot yang benar-benar dipakai</li>
|
||||
<li>mencatat susut, rusak, reject, dan adjustment per lot</li>
|
||||
<li>menyediakan traceability penuh dari supplier ke customer dan sebaliknya</li>
|
||||
<li>mendukung barcode atau QR untuk scan operasional</li>
|
||||
</ul>
|
||||
|
||||
<h2>Entitas Bisnis Utama</h2>
|
||||
<ul>
|
||||
<li>Supplier</li>
|
||||
<li>Customer</li>
|
||||
<li>Jenis Sarang</li>
|
||||
<li>Grade</li>
|
||||
<li>Gudang dan Lokasi Gudang</li>
|
||||
<li>Pembelian</li>
|
||||
<li>Penerimaan</li>
|
||||
<li>Lot Inventory</li>
|
||||
<li>Sortasi atau Reclassification</li>
|
||||
<li>Penjualan</li>
|
||||
<li>Sales Allocation</li>
|
||||
<li>Inventory Movement Ledger</li>
|
||||
<li>Stock Adjustment</li>
|
||||
<li>Return</li>
|
||||
<li>Barcode atau QR Label</li>
|
||||
</ul>
|
||||
|
||||
<h2>Prinsip Dasar Desain Stok</h2>
|
||||
<h3>1. Stock Summary</h3>
|
||||
<p>Ringkasan stok per:</p>
|
||||
<ul><li>jenis</li><li>grade</li><li>gudang</li></ul>
|
||||
<p>Digunakan untuk dashboard dan operasional cepat.</p>
|
||||
|
||||
<h3>2. Stock Lot</h3>
|
||||
<p>Detail stok per batch atau lot:</p>
|
||||
<ul>
|
||||
<li>kode lot</li>
|
||||
<li>supplier</li>
|
||||
<li>jenis</li>
|
||||
<li>grade</li>
|
||||
<li>qty awal</li>
|
||||
<li>qty sisa</li>
|
||||
<li>cost</li>
|
||||
<li>tanggal masuk</li>
|
||||
<li>parent lot jika hasil sortasi</li>
|
||||
</ul>
|
||||
<p>Digunakan untuk traceability dan costing.</p>
|
||||
|
||||
<h3>3. Stock Movement Ledger</h3>
|
||||
<p>Semua mutasi stok dicatat permanen:</p>
|
||||
<ul>
|
||||
<li>receiving</li>
|
||||
<li>sorting</li>
|
||||
<li>regrade</li>
|
||||
<li>transfer</li>
|
||||
<li>sales allocation</li>
|
||||
<li>shrinkage</li>
|
||||
<li>adjustment</li>
|
||||
<li>return</li>
|
||||
</ul>
|
||||
<p>Ledger ini menjadi sumber audit utama.</p>
|
||||
|
||||
<h2>Aktor Utama</h2>
|
||||
<h3>Admin Purchasing</h3>
|
||||
<ul><li>membuat pembelian</li><li>mengelola supplier</li><li>melihat histori harga beli</li></ul>
|
||||
<h3>Admin Gudang</h3>
|
||||
<ul><li>menerima barang</li><li>membuat lot</li><li>mengelola stok dan mutasi</li><li>melakukan opname dan adjustment</li></ul>
|
||||
<h3>Tim Sortasi / QC</h3>
|
||||
<ul><li>melakukan klasifikasi</li><li>memecah lot</li><li>menginput susut atau reject</li><li>melakukan regrade jika diperlukan</li></ul>
|
||||
<h3>Admin Sales</h3>
|
||||
<ul><li>membuat sales order</li><li>mengalokasikan stok dari lot</li><li>memproses picking dan invoice</li></ul>
|
||||
<h3>Owner / Manajemen</h3>
|
||||
<ul><li>memantau stok</li><li>memantau margin</li><li>melihat penyusutan</li><li>melihat traceability dan performa supplier</li></ul>
|
||||
|
||||
<h2>Alur Bisnis End-to-End</h2>
|
||||
<h3>Tahap 1. Master Setup</h3>
|
||||
<p>Sebelum transaksi berjalan, sistem harus memiliki data master:</p>
|
||||
<ul>
|
||||
<li>supplier</li>
|
||||
<li>customer</li>
|
||||
<li>jenis sarang</li>
|
||||
<li>grade</li>
|
||||
<li>gudang</li>
|
||||
<li>lokasi gudang</li>
|
||||
<li>satuan</li>
|
||||
<li>user dan role</li>
|
||||
<li>reason code adjustment dan shrinkage</li>
|
||||
<li>allocation policy</li>
|
||||
<li>costing policy</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 2. Pembelian</h3>
|
||||
<p>Admin membuat dokumen pembelian.</p>
|
||||
<p>Informasi pada header pembelian:</p>
|
||||
<ul>
|
||||
<li>nomor pembelian</li>
|
||||
<li>supplier</li>
|
||||
<li>tanggal pembelian</li>
|
||||
<li>referensi invoice supplier</li>
|
||||
<li>status</li>
|
||||
<li>catatan</li>
|
||||
</ul>
|
||||
<p>Pada detail pembelian, satu pembelian bisa memiliki banyak item:</p>
|
||||
<ul>
|
||||
<li>jenis</li>
|
||||
<li>grade, jika sudah diketahui</li>
|
||||
<li>qty atau berat</li>
|
||||
<li>harga beli</li>
|
||||
<li>subtotal</li>
|
||||
<li>status klasifikasi</li>
|
||||
</ul>
|
||||
<p>Kemungkinan kondisi pembelian:</p>
|
||||
<ol>
|
||||
<li>item sudah jelas jenis dan gradenya</li>
|
||||
<li>item masih campuran atau grade sementara</li>
|
||||
</ol>
|
||||
|
||||
<h3>Tahap 3. Penerimaan Barang</h3>
|
||||
<p>Saat barang datang:</p>
|
||||
<ul>
|
||||
<li>sistem memverifikasi pembelian</li>
|
||||
<li>barang ditimbang</li>
|
||||
<li>kualitas awal dicek</li>
|
||||
<li>selisih dicatat</li>
|
||||
<li>lot inventory dibuat</li>
|
||||
</ul>
|
||||
<p>Setiap lot yang tercipta menyimpan data:</p>
|
||||
<ul>
|
||||
<li>kode lot</li>
|
||||
<li>supplier asal</li>
|
||||
<li>referensi pembelian</li>
|
||||
<li>jenis</li>
|
||||
<li>grade</li>
|
||||
<li>qty diterima</li>
|
||||
<li>qty tersedia</li>
|
||||
<li>cost per unit</li>
|
||||
<li>tanggal masuk</li>
|
||||
<li>gudang dan lokasi</li>
|
||||
<li>status lot</li>
|
||||
<li>nilai barcode atau QR</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 4. Sortasi / Verifikasi / Reclassification</h3>
|
||||
<p>Jika barang datang masih campur atau perlu dicek ulang, dilakukan sesi sortasi.</p>
|
||||
<p>Contoh:</p>
|
||||
<ul>
|
||||
<li>lot masuk 50 kg</li>
|
||||
<li>hasil sortasi:
|
||||
<ul>
|
||||
<li>Jenis A Grade A = 20 kg</li>
|
||||
<li>Jenis A Grade B = 15 kg</li>
|
||||
<li>Jenis B Grade A = 10 kg</li>
|
||||
<li>Reject atau susut = 5 kg</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Hasil sortasi:</p>
|
||||
<ul>
|
||||
<li>lot sumber dikurangi atau ditutup</li>
|
||||
<li>child lot baru dibuat</li>
|
||||
<li>susut dicatat</li>
|
||||
<li>hubungan parent-child tersimpan</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 5. Penyimpanan dan Mutasi Gudang</h3>
|
||||
<p>Lot yang aktif disimpan di gudang atau lokasi tertentu.</p>
|
||||
<p>Aktivitas gudang yang didukung:</p>
|
||||
<ul>
|
||||
<li>pindah lokasi rak</li>
|
||||
<li>transfer antar gudang</li>
|
||||
<li>hold atau release lot</li>
|
||||
<li>stock opname</li>
|
||||
<li>adjustment stok</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 6. Penjualan</h3>
|
||||
<p>Saat customer melakukan pembelian:</p>
|
||||
<ul>
|
||||
<li>admin sales membuat sales order</li>
|
||||
<li>item dipilih berdasarkan jenis dan grade</li>
|
||||
<li>qty dimasukkan</li>
|
||||
<li>sistem menampilkan stok yang tersedia</li>
|
||||
</ul>
|
||||
<p>Satu sales line tidak harus dipenuhi dari satu lot.</p>
|
||||
<p>Contoh:</p>
|
||||
<ul>
|
||||
<li>Customer membeli Jenis A Grade A sebanyak 30 kg</li>
|
||||
<li>Alokasi bisa menjadi:
|
||||
<ul>
|
||||
<li>20 kg dari lot Supplier A</li>
|
||||
<li>10 kg dari lot Supplier B</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Karena itu sistem membutuhkan allocation detail per lot.</p>
|
||||
|
||||
<h3>Tahap 7. Picking dan Pengeluaran Barang</h3>
|
||||
<ul>
|
||||
<li>petugas scan QR atau barcode lot</li>
|
||||
<li>qty yang benar-benar diambil dikonfirmasi</li>
|
||||
<li>bila ada selisih timbang, selisih dicatat</li>
|
||||
<li>stok lot berkurang sesuai qty realisasi</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 8. Retur Penjualan</h3>
|
||||
<ul>
|
||||
<li>retur direferensikan ke penjualan</li>
|
||||
<li>jika memungkinkan, dikembalikan ke lot asal</li>
|
||||
<li>jika tidak, dibuat lot retur terpisah</li>
|
||||
<li>kondisi barang retur dicatat</li>
|
||||
<li>barang retur dapat dijual lagi, diregrade, atau direject</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 9. Retur Pembelian</h3>
|
||||
<ul>
|
||||
<li>barang diretur ke supplier</li>
|
||||
<li>sistem mengurangi lot asal</li>
|
||||
<li>nilai transaksi pembelian dapat dikoreksi</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 10. Shrinkage, Damage, Regrade, dan Adjustment</h3>
|
||||
<p>Sistem harus mendukung kejadian berikut pada level lot:</p>
|
||||
<ul>
|
||||
<li>susut timbang</li>
|
||||
<li>kerusakan</li>
|
||||
<li>kehilangan</li>
|
||||
<li>reject</li>
|
||||
<li>perubahan grade</li>
|
||||
<li>koreksi hasil stock opname</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tahap 11. Reporting dan Audit</h3>
|
||||
<p>Sistem harus dapat menjawab pertanyaan berikut:</p>
|
||||
<ul>
|
||||
<li>stok tersedia berapa per jenis-grade</li>
|
||||
<li>lot mana saja yang aktif</li>
|
||||
<li>lot tertentu berasal dari supplier siapa</li>
|
||||
<li>penjualan tertentu mengambil lot mana saja</li>
|
||||
<li>supplier tertentu telah menjual barangnya ke customer mana saja</li>
|
||||
<li>berapa susut per lot dan per supplier</li>
|
||||
<li>berapa margin per penjualan, per jenis, dan per grade</li>
|
||||
</ul>
|
||||
|
||||
<h2>Aturan Costing</h2>
|
||||
<p>Prinsip costing yang direkomendasikan:</p>
|
||||
<ul>
|
||||
<li>cost disimpan di level lot</li>
|
||||
<li>sales line dihitung berdasarkan allocation nyata ke lot</li>
|
||||
</ul>
|
||||
<p>Contoh:</p>
|
||||
<ul>
|
||||
<li>Lot A: 20 kg x 18 juta</li>
|
||||
<li>Lot B: 10 kg x 19 juta</li>
|
||||
</ul>
|
||||
<p>Maka total cost penjualan adalah penjumlahan biaya dari semua allocation.</p>
|
||||
<p>Metode alokasi yang didukung:</p>
|
||||
<ul>
|
||||
<li>FIFO</li>
|
||||
<li>FEFO jika dibutuhkan</li>
|
||||
<li>Manual allocation</li>
|
||||
<li>Hybrid, sistem memberi saran dan user bisa override</li>
|
||||
</ul>
|
||||
<p>Rekomendasi untuk MVP adalah Hybrid dengan default FIFO.</p>
|
||||
|
||||
<h2>Aturan Traceability</h2>
|
||||
<h3>Backward Trace</h3>
|
||||
<ul><li>dari penjualan ke lot</li><li>dari lot ke receipt</li><li>dari receipt ke purchase</li><li>dari purchase ke supplier</li></ul>
|
||||
<h3>Forward Trace</h3>
|
||||
<ul><li>dari supplier atau lot ke sales allocation</li><li>dari sales allocation ke customer</li></ul>
|
||||
<h3>Process Trace</h3>
|
||||
<ul>
|
||||
<li>asal pembelian</li>
|
||||
<li>hasil sortasi</li>
|
||||
<li>perubahan grade</li>
|
||||
<li>susut</li>
|
||||
<li>perpindahan gudang</li>
|
||||
<li>histori penjualan</li>
|
||||
</ul>
|
||||
|
||||
<h2>Aturan Barcode dan QR</h2>
|
||||
<p>Rekomendasi implementasi:</p>
|
||||
<ul>
|
||||
<li>SKU code untuk jenis-grade</li>
|
||||
<li>lot code untuk identitas lot</li>
|
||||
<li>QR code untuk scan operasional</li>
|
||||
</ul>
|
||||
<p>Contoh struktur kode:</p>
|
||||
<p><b>SKU:</b></p>
|
||||
<ul><li>MANGKOK-A</li><li>MANGKOK-B</li><li>SUDUT-A</li></ul>
|
||||
<p><b>Lot:</b></p>
|
||||
<ul><li>LOT-260428-SPA-001</li><li>LOT-260428-SPB-002</li><li>LOT-260428-SPA-001-S1 untuk hasil sortasi</li></ul>
|
||||
<p>Proses scan yang didukung:</p>
|
||||
<ul>
|
||||
<li>receiving</li>
|
||||
<li>sorting</li>
|
||||
<li>transfer gudang</li>
|
||||
<li>stock opname</li>
|
||||
<li>sales picking</li>
|
||||
<li>trace lookup</li>
|
||||
</ul>
|
||||
|
||||
<h2>Ringkasan Kebutuhan Menu Aplikasi</h2>
|
||||
<ul>
|
||||
<li>Dashboard</li>
|
||||
<li>Master Data</li>
|
||||
<li>Purchasing</li>
|
||||
<li>Receiving</li>
|
||||
<li>Sorting / Classification</li>
|
||||
<li>Inventory</li>
|
||||
<li>Sales</li>
|
||||
<li>Return</li>
|
||||
<li>Reports</li>
|
||||
<li>Barcode / QR</li>
|
||||
<li>Settings</li>
|
||||
</ul>
|
||||
|
||||
<h2>Ringkasan Layar Utama</h2>
|
||||
<ul>
|
||||
<li>Dashboard</li>
|
||||
<li>Purchase List</li>
|
||||
<li>Purchase Form</li>
|
||||
<li>Receipt Form</li>
|
||||
<li>Sorting Session Form</li>
|
||||
<li>Stock Summary</li>
|
||||
<li>Stock Lot List</li>
|
||||
<li>Lot Detail</li>
|
||||
<li>Sales Form</li>
|
||||
<li>Allocation Screen</li>
|
||||
<li>Picking Screen</li>
|
||||
<li>Adjustment Form</li>
|
||||
<li>Regrade Form</li>
|
||||
<li>Barcode Lookup</li>
|
||||
<li>Reports</li>
|
||||
</ul>
|
||||
|
||||
<h2>Kesimpulan</h2>
|
||||
<p>Sistem yang dibutuhkan adalah sistem inventory sarang burung walet berbasis lot atau batch dengan kemampuan:</p>
|
||||
<ul>
|
||||
<li>pembelian multi jenis dan multi grade</li>
|
||||
<li>sortasi dan reclassification</li>
|
||||
<li>partial sales dari banyak lot</li>
|
||||
<li>costing berdasarkan allocation nyata</li>
|
||||
<li>penyusutan per lot</li>
|
||||
<li>traceability dua arah</li>
|
||||
<li>barcode atau QR untuk scan operasional</li>
|
||||
</ul>
|
||||
<p>Dengan fondasi ini, bisnis dapat mengontrol stok, menjaga audit trail, menghitung HPP secara akurat, dan memantau kualitas supplier serta profitabilitas penjualan.</p>
|
||||
</body>
|
||||
</html>
|
||||
382
docs/project-spec/walet-alur-bisnis.md
Normal file
382
docs/project-spec/walet-alur-bisnis.md
Normal file
@ -0,0 +1,382 @@
|
||||
# Blueprint Alur Bisnis Sistem Inventory Sarang Burung Walet
|
||||
|
||||
## Ringkasan
|
||||
Dokumen ini merangkum alur bisnis untuk sistem inventory sarang burung walet dengan karakter operasional berikut:
|
||||
|
||||
- proses dimulai dari pembelian
|
||||
- satu pembelian bisa terdiri dari beberapa jenis barang
|
||||
- setiap jenis bisa memiliki beberapa grade
|
||||
- barang yang diterima bisa langsung terklasifikasi atau masih perlu sortasi internal
|
||||
- stok disimpan berbasis lot atau batch
|
||||
- satu penjualan dapat mengambil barang secara parsial dari beberapa lot berbeda
|
||||
- seluruh pergerakan barang harus dapat ditelusuri untuk kebutuhan costing, traceability, audit, dan analisis penyusutan
|
||||
|
||||
Sistem ini bukan inventory biasa. Sistem ini adalah lot-based traceable inventory system untuk perdagangan sarang burung walet.
|
||||
|
||||
## Tujuan Sistem
|
||||
Sistem dirancang untuk:
|
||||
|
||||
- mencatat pembelian multi jenis dan multi grade
|
||||
- mengelola penerimaan barang dan pembentukan batch atau lot
|
||||
- mendukung sortasi, verifikasi ulang, dan regrade
|
||||
- menyimpan stok per lot sekaligus menampilkan ringkasan stok per jenis-grade
|
||||
- mendukung penjualan campuran dari beberapa lot
|
||||
- menghitung HPP berdasarkan lot yang benar-benar dipakai
|
||||
- mencatat susut, rusak, reject, dan adjustment per lot
|
||||
- menyediakan traceability penuh dari supplier ke customer dan sebaliknya
|
||||
- mendukung barcode atau QR untuk scan operasional
|
||||
|
||||
## Entitas Bisnis Utama
|
||||
Sistem memiliki entitas bisnis utama berikut:
|
||||
|
||||
- Supplier
|
||||
- Customer
|
||||
- Jenis Sarang
|
||||
- Grade
|
||||
- Gudang dan Lokasi Gudang
|
||||
- Pembelian
|
||||
- Penerimaan
|
||||
- Lot Inventory
|
||||
- Sortasi atau Reclassification
|
||||
- Penjualan
|
||||
- Sales Allocation
|
||||
- Inventory Movement Ledger
|
||||
- Stock Adjustment
|
||||
- Return
|
||||
- Barcode atau QR Label
|
||||
|
||||
## Prinsip Dasar Desain Stok
|
||||
Sistem menggunakan tiga lapisan stok.
|
||||
|
||||
### 1. Stock Summary
|
||||
Ringkasan stok per:
|
||||
- jenis
|
||||
- grade
|
||||
- gudang
|
||||
|
||||
Digunakan untuk dashboard dan operasional cepat.
|
||||
|
||||
### 2. Stock Lot
|
||||
Detail stok per batch atau lot:
|
||||
- kode lot
|
||||
- supplier
|
||||
- jenis
|
||||
- grade
|
||||
- qty awal
|
||||
- qty sisa
|
||||
- cost
|
||||
- tanggal masuk
|
||||
- parent lot jika hasil sortasi
|
||||
|
||||
Digunakan untuk traceability dan costing.
|
||||
|
||||
### 3. Stock Movement Ledger
|
||||
Semua mutasi stok dicatat permanen:
|
||||
- receiving
|
||||
- sorting
|
||||
- regrade
|
||||
- transfer
|
||||
- sales allocation
|
||||
- shrinkage
|
||||
- adjustment
|
||||
- return
|
||||
|
||||
Ledger ini menjadi sumber audit utama.
|
||||
|
||||
## Aktor Utama
|
||||
Aktor yang akan berinteraksi dengan sistem:
|
||||
|
||||
### Admin Purchasing
|
||||
- membuat pembelian
|
||||
- mengelola supplier
|
||||
- melihat histori harga beli
|
||||
|
||||
### Admin Gudang
|
||||
- menerima barang
|
||||
- membuat lot
|
||||
- mengelola stok dan mutasi
|
||||
- melakukan opname dan adjustment
|
||||
|
||||
### Tim Sortasi / QC
|
||||
- melakukan klasifikasi
|
||||
- memecah lot
|
||||
- menginput susut atau reject
|
||||
- melakukan regrade jika diperlukan
|
||||
|
||||
### Admin Sales
|
||||
- membuat sales order
|
||||
- mengalokasikan stok dari lot
|
||||
- memproses picking dan invoice
|
||||
|
||||
### Owner / Manajemen
|
||||
- memantau stok
|
||||
- memantau margin
|
||||
- melihat penyusutan
|
||||
- melihat traceability dan performa supplier
|
||||
|
||||
## Alur Bisnis End-to-End
|
||||
|
||||
### Tahap 1. Master Setup
|
||||
Sebelum transaksi berjalan, sistem harus memiliki data master:
|
||||
- supplier
|
||||
- customer
|
||||
- jenis sarang
|
||||
- grade
|
||||
- gudang
|
||||
- lokasi gudang
|
||||
- satuan
|
||||
- user dan role
|
||||
- reason code adjustment dan shrinkage
|
||||
- allocation policy
|
||||
- costing policy
|
||||
|
||||
### Tahap 2. Pembelian
|
||||
Admin membuat dokumen pembelian.
|
||||
|
||||
Informasi pada header pembelian:
|
||||
- nomor pembelian
|
||||
- supplier
|
||||
- tanggal pembelian
|
||||
- referensi invoice supplier
|
||||
- status
|
||||
- catatan
|
||||
|
||||
Pada detail pembelian, satu pembelian bisa memiliki banyak item:
|
||||
- jenis
|
||||
- grade, jika sudah diketahui
|
||||
- qty atau berat
|
||||
- harga beli
|
||||
- subtotal
|
||||
- status klasifikasi
|
||||
|
||||
Kemungkinan kondisi pembelian:
|
||||
1. item sudah jelas jenis dan gradenya
|
||||
2. item masih campuran atau grade sementara
|
||||
|
||||
### Tahap 3. Penerimaan Barang
|
||||
Saat barang datang:
|
||||
- sistem memverifikasi pembelian
|
||||
- barang ditimbang
|
||||
- kualitas awal dicek
|
||||
- selisih dicatat
|
||||
- lot inventory dibuat
|
||||
|
||||
Setiap lot yang tercipta menyimpan data:
|
||||
- kode lot
|
||||
- supplier asal
|
||||
- referensi pembelian
|
||||
- jenis
|
||||
- grade
|
||||
- qty diterima
|
||||
- qty tersedia
|
||||
- cost per unit
|
||||
- tanggal masuk
|
||||
- gudang dan lokasi
|
||||
- status lot
|
||||
- nilai barcode atau QR
|
||||
|
||||
Jika satu pembelian terdiri dari banyak item, maka bisa terbentuk banyak lot.
|
||||
|
||||
### Tahap 4. Sortasi / Verifikasi / Reclassification
|
||||
Jika barang datang masih campur atau perlu dicek ulang, dilakukan sesi sortasi.
|
||||
|
||||
Contoh:
|
||||
- lot masuk 50 kg
|
||||
- hasil sortasi:
|
||||
- Jenis A Grade A = 20 kg
|
||||
- Jenis A Grade B = 15 kg
|
||||
- Jenis B Grade A = 10 kg
|
||||
- Reject atau susut = 5 kg
|
||||
|
||||
Hasil sortasi:
|
||||
- lot sumber dikurangi atau ditutup
|
||||
- child lot baru dibuat
|
||||
- susut dicatat
|
||||
- hubungan parent-child tersimpan
|
||||
|
||||
Dengan desain ini, sistem tetap tahu bahwa lot hasil sortasi berasal dari lot mana.
|
||||
|
||||
### Tahap 5. Penyimpanan dan Mutasi Gudang
|
||||
Lot yang aktif disimpan di gudang atau lokasi tertentu.
|
||||
|
||||
Aktivitas gudang yang didukung:
|
||||
- pindah lokasi rak
|
||||
- transfer antar gudang
|
||||
- hold atau release lot
|
||||
- stock opname
|
||||
- adjustment stok
|
||||
|
||||
Semua aktivitas ini masuk ke movement ledger.
|
||||
|
||||
### Tahap 6. Penjualan
|
||||
Saat customer melakukan pembelian:
|
||||
- admin sales membuat sales order
|
||||
- item dipilih berdasarkan jenis dan grade
|
||||
- qty dimasukkan
|
||||
- sistem menampilkan stok yang tersedia
|
||||
|
||||
Satu sales line tidak harus dipenuhi dari satu lot.
|
||||
|
||||
Contoh:
|
||||
Customer membeli Jenis A Grade A sebanyak 30 kg.
|
||||
Alokasi bisa menjadi:
|
||||
- 20 kg dari lot Supplier A
|
||||
- 10 kg dari lot Supplier B
|
||||
|
||||
Karena itu sistem membutuhkan allocation detail per lot.
|
||||
|
||||
### Tahap 7. Picking dan Pengeluaran Barang
|
||||
Setelah lot dialokasikan:
|
||||
- petugas scan QR atau barcode lot
|
||||
- qty yang benar-benar diambil dikonfirmasi
|
||||
- bila ada selisih timbang, selisih dicatat
|
||||
- stok lot berkurang sesuai qty realisasi
|
||||
|
||||
### Tahap 8. Retur Penjualan
|
||||
Jika barang dikembalikan customer:
|
||||
- retur direferensikan ke penjualan
|
||||
- jika memungkinkan, dikembalikan ke lot asal
|
||||
- jika tidak, dibuat lot retur terpisah
|
||||
- kondisi barang retur dicatat
|
||||
- barang retur dapat dijual lagi, diregrade, atau direject
|
||||
|
||||
### Tahap 9. Retur Pembelian
|
||||
Jika ada masalah dengan supplier:
|
||||
- barang diretur ke supplier
|
||||
- sistem mengurangi lot asal
|
||||
- nilai transaksi pembelian dapat dikoreksi
|
||||
|
||||
### Tahap 10. Shrinkage, Damage, Regrade, dan Adjustment
|
||||
Sistem harus mendukung kejadian berikut pada level lot:
|
||||
- susut timbang
|
||||
- kerusakan
|
||||
- kehilangan
|
||||
- reject
|
||||
- perubahan grade
|
||||
- koreksi hasil stock opname
|
||||
|
||||
Semua perubahan ini harus masuk ke ledger agar histori tetap utuh.
|
||||
|
||||
### Tahap 11. Reporting dan Audit
|
||||
Sistem harus dapat menjawab pertanyaan berikut:
|
||||
- stok tersedia berapa per jenis-grade
|
||||
- lot mana saja yang aktif
|
||||
- lot tertentu berasal dari supplier siapa
|
||||
- penjualan tertentu mengambil lot mana saja
|
||||
- supplier tertentu telah menjual barangnya ke customer mana saja
|
||||
- berapa susut per lot dan per supplier
|
||||
- berapa margin per penjualan, per jenis, dan per grade
|
||||
|
||||
## Aturan Costing
|
||||
Prinsip costing yang direkomendasikan:
|
||||
- cost disimpan di level lot
|
||||
- sales line dihitung berdasarkan allocation nyata ke lot
|
||||
|
||||
Contoh:
|
||||
- Lot A: 20 kg x 18 juta
|
||||
- Lot B: 10 kg x 19 juta
|
||||
|
||||
Maka total cost penjualan adalah penjumlahan biaya dari semua allocation.
|
||||
|
||||
### Metode alokasi yang didukung
|
||||
- FIFO
|
||||
- FEFO jika dibutuhkan
|
||||
- Manual allocation
|
||||
- Hybrid, sistem memberi saran dan user bisa override
|
||||
|
||||
Rekomendasi untuk MVP adalah Hybrid dengan default FIFO.
|
||||
|
||||
## Aturan Traceability
|
||||
Sistem wajib mendukung dua arah trace.
|
||||
|
||||
### Backward Trace
|
||||
Dari penjualan ke:
|
||||
- lot
|
||||
- receipt
|
||||
- purchase
|
||||
- supplier
|
||||
|
||||
### Forward Trace
|
||||
Dari supplier atau lot ke:
|
||||
- sales allocation
|
||||
- customer
|
||||
|
||||
### Process Trace
|
||||
Dari lot tertentu harus terlihat:
|
||||
- asal pembelian
|
||||
- hasil sortasi
|
||||
- perubahan grade
|
||||
- susut
|
||||
- perpindahan gudang
|
||||
- histori penjualan
|
||||
|
||||
## Aturan Barcode dan QR
|
||||
Rekomendasi implementasi:
|
||||
- SKU code untuk jenis-grade
|
||||
- lot code untuk identitas lot
|
||||
- QR code untuk scan operasional
|
||||
|
||||
### Contoh struktur kode
|
||||
SKU:
|
||||
- MANGKOK-A
|
||||
- MANGKOK-B
|
||||
- SUDUT-A
|
||||
|
||||
Lot:
|
||||
- LOT-260428-SPA-001
|
||||
- LOT-260428-SPB-002
|
||||
- LOT-260428-SPA-001-S1 untuk hasil sortasi
|
||||
|
||||
QR dapat menyimpan lot_code atau token unik. Aplikasi akan mengambil detail dari database saat discan.
|
||||
|
||||
### Proses scan yang didukung
|
||||
- receiving
|
||||
- sorting
|
||||
- transfer gudang
|
||||
- stock opname
|
||||
- sales picking
|
||||
- trace lookup
|
||||
|
||||
## Ringkasan Kebutuhan Menu Aplikasi
|
||||
Modul yang harus tersedia minimal:
|
||||
- Dashboard
|
||||
- Master Data
|
||||
- Purchasing
|
||||
- Receiving
|
||||
- Sorting / Classification
|
||||
- Inventory
|
||||
- Sales
|
||||
- Return
|
||||
- Reports
|
||||
- Barcode / QR
|
||||
- Settings
|
||||
|
||||
## Ringkasan Layar Utama
|
||||
Layar yang disarankan:
|
||||
- Dashboard
|
||||
- Purchase List
|
||||
- Purchase Form
|
||||
- Receipt Form
|
||||
- Sorting Session Form
|
||||
- Stock Summary
|
||||
- Stock Lot List
|
||||
- Lot Detail
|
||||
- Sales Form
|
||||
- Allocation Screen
|
||||
- Picking Screen
|
||||
- Adjustment Form
|
||||
- Regrade Form
|
||||
- Barcode Lookup
|
||||
- Reports
|
||||
|
||||
## Kesimpulan
|
||||
Sistem yang dibutuhkan adalah sistem inventory sarang burung walet berbasis lot atau batch dengan kemampuan:
|
||||
- pembelian multi jenis dan multi grade
|
||||
- sortasi dan reclassification
|
||||
- partial sales dari banyak lot
|
||||
- costing berdasarkan allocation nyata
|
||||
- penyusutan per lot
|
||||
- traceability dua arah
|
||||
- barcode atau QR untuk scan operasional
|
||||
|
||||
Dengan fondasi ini, bisnis dapat mengontrol stok, menjaga audit trail, menghitung HPP secara akurat, dan memantau kualitas supplier serta profitabilitas penjualan.
|
||||
BIN
docs/project-spec/walet-alur-bisnis.pdf
Normal file
BIN
docs/project-spec/walet-alur-bisnis.pdf
Normal file
Binary file not shown.
409
docs/project-spec/walet-api-spec.md
Normal file
409
docs/project-spec/walet-api-spec.md
Normal file
@ -0,0 +1,409 @@
|
||||
# API Spec Backend Sistem Inventory Walet
|
||||
|
||||
## 1. Prinsip API
|
||||
API berbasis REST JSON dengan fokus pada:
|
||||
- lot-based inventory
|
||||
- traceability
|
||||
- partial allocation
|
||||
- shrinkage and adjustment
|
||||
- barcode/QR lookup
|
||||
|
||||
Base path contoh:
|
||||
`/api/v1`
|
||||
|
||||
## 2. Auth
|
||||
### POST /auth/login
|
||||
Request:
|
||||
```json
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"password": "secret"
|
||||
}
|
||||
```
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"token": "jwt-token",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"name": "Admin",
|
||||
"role": "ADMIN"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Master Data
|
||||
### GET /suppliers
|
||||
### POST /suppliers
|
||||
Field penting supplier:
|
||||
- code
|
||||
- name
|
||||
- phone
|
||||
- email
|
||||
- bank_name
|
||||
- bank_account_number
|
||||
- address
|
||||
|
||||
### GET /suppliers/{id}
|
||||
### PUT /suppliers/{id}
|
||||
### DELETE /suppliers/{id}
|
||||
|
||||
### GET /customers
|
||||
### POST /customers
|
||||
Field penting customer:
|
||||
- code
|
||||
- name
|
||||
- phone
|
||||
- email
|
||||
- bank_name
|
||||
- bank_account_number
|
||||
- address
|
||||
### GET /item-types
|
||||
### POST /item-types
|
||||
### GET /item-grades
|
||||
### POST /item-grades
|
||||
### GET /warehouses
|
||||
### POST /warehouses
|
||||
### GET /warehouse-locations
|
||||
### POST /warehouse-locations
|
||||
### GET /adjustment-reasons
|
||||
### POST /adjustment-reasons
|
||||
|
||||
---
|
||||
|
||||
## 4. Purchasing
|
||||
### GET /purchases
|
||||
Filter:
|
||||
- supplier_id
|
||||
- status
|
||||
- date_from
|
||||
- date_to
|
||||
|
||||
### POST /purchases
|
||||
```json
|
||||
{
|
||||
"supplier_id": 1,
|
||||
"purchase_date": "2026-04-28",
|
||||
"supplier_invoice_no": "INV-8891",
|
||||
"notes": "Pembelian campuran",
|
||||
"lines": [
|
||||
{
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 1,
|
||||
"qty_ordered": 50,
|
||||
"unit_id": 1,
|
||||
"unit_price": 18000000,
|
||||
"classification_status": "FINAL"
|
||||
},
|
||||
{
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": null,
|
||||
"qty_ordered": 40,
|
||||
"unit_id": 1,
|
||||
"unit_price": 17500000,
|
||||
"classification_status": "PROVISIONAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /purchases/{id}
|
||||
### PUT /purchases/{id}
|
||||
### POST /purchases/{id}/submit
|
||||
### POST /purchases/{id}/cancel
|
||||
|
||||
---
|
||||
|
||||
## 5. Receiving
|
||||
### GET /receipts
|
||||
### POST /receipts
|
||||
```json
|
||||
{
|
||||
"purchase_id": 1,
|
||||
"supplier_id": 1,
|
||||
"receipt_date": "2026-04-28",
|
||||
"notes": "Barang diterima baik",
|
||||
"lines": [
|
||||
{
|
||||
"purchase_line_id": 1,
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 1,
|
||||
"qty_received": 50,
|
||||
"qty_accepted": 50,
|
||||
"qty_rejected": 0,
|
||||
"unit_id": 1,
|
||||
"unit_cost": 18000000,
|
||||
"warehouse_id": 1,
|
||||
"warehouse_location_id": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /receipts/{id}
|
||||
### POST /receipts/{id}/generate-lots
|
||||
Response contoh:
|
||||
```json
|
||||
{
|
||||
"receipt_id": 1,
|
||||
"lots": [
|
||||
{
|
||||
"id": 10,
|
||||
"lot_code": "LOT-260428-SPA-001",
|
||||
"qr_code_value": "LOT-260428-SPA-001"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Inventory Lots
|
||||
### GET /lots
|
||||
Filter:
|
||||
- supplier_id
|
||||
- item_type_id
|
||||
- item_grade_id
|
||||
- warehouse_id
|
||||
- status
|
||||
- keyword
|
||||
|
||||
### GET /lots/{id}
|
||||
### GET /lots/{id}/movements
|
||||
### GET /lots/{id}/trace
|
||||
### POST /lots/{id}/hold
|
||||
### POST /lots/{id}/release
|
||||
### POST /lots/{id}/transfer
|
||||
```json
|
||||
{
|
||||
"to_warehouse_id": 2,
|
||||
"to_location_id": 5,
|
||||
"qty": 10,
|
||||
"notes": "Pindah ke gudang cabang"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Sorting / Regrade
|
||||
### POST /sorting-sessions
|
||||
```json
|
||||
{
|
||||
"source_lot_id": 10,
|
||||
"sorting_date": "2026-04-28T15:00:00Z",
|
||||
"input_qty": 40,
|
||||
"shrinkage_qty": 3,
|
||||
"notes": "Sortasi batch campuran",
|
||||
"results": [
|
||||
{
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 1,
|
||||
"qty_result": 18,
|
||||
"unit_cost": 17500000
|
||||
},
|
||||
{
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 2,
|
||||
"qty_result": 12,
|
||||
"unit_cost": 17500000
|
||||
},
|
||||
{
|
||||
"item_type_id": 2,
|
||||
"item_grade_id": 1,
|
||||
"qty_result": 7,
|
||||
"unit_cost": 17500000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /sorting-sessions
|
||||
### GET /sorting-sessions/{id}
|
||||
|
||||
### POST /lots/{id}/regrade
|
||||
```json
|
||||
{
|
||||
"target_grade_id": 2,
|
||||
"qty": 5,
|
||||
"reason_id": 3,
|
||||
"notes": "Turun grade setelah QC"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Sales
|
||||
### GET /sales
|
||||
### POST /sales
|
||||
```json
|
||||
{
|
||||
"customer_id": 1,
|
||||
"sales_date": "2026-04-28",
|
||||
"notes": "Order customer X",
|
||||
"lines": [
|
||||
{
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 1,
|
||||
"qty_sold": 30,
|
||||
"unit_id": 1,
|
||||
"selling_price": 22000000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /sales/{id}
|
||||
### POST /sales/{id}/allocate
|
||||
```json
|
||||
{
|
||||
"lines": [
|
||||
{
|
||||
"sales_line_id": 1,
|
||||
"allocations": [
|
||||
{
|
||||
"inventory_lot_id": 10,
|
||||
"qty_allocated": 20
|
||||
},
|
||||
{
|
||||
"inventory_lot_id": 11,
|
||||
"qty_allocated": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### POST /sales/{id}/auto-allocate
|
||||
```json
|
||||
{
|
||||
"policy": "FIFO"
|
||||
}
|
||||
```
|
||||
|
||||
### POST /sales/{id}/confirm-picking
|
||||
```json
|
||||
{
|
||||
"lines": [
|
||||
{
|
||||
"sales_line_id": 1,
|
||||
"picked_allocations": [
|
||||
{
|
||||
"inventory_lot_id": 10,
|
||||
"qty_picked": 20
|
||||
},
|
||||
{
|
||||
"inventory_lot_id": 11,
|
||||
"qty_picked": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Adjustments & Shrinkage
|
||||
### POST /stock-adjustments
|
||||
```json
|
||||
{
|
||||
"inventory_lot_id": 11,
|
||||
"adjustment_type": "SHRINKAGE",
|
||||
"reason_id": 1,
|
||||
"qty_change": -1.2,
|
||||
"notes": "Selisih opname"
|
||||
}
|
||||
```
|
||||
|
||||
### GET /stock-adjustments
|
||||
|
||||
---
|
||||
|
||||
## 10. Returns
|
||||
### POST /sales-returns
|
||||
### POST /purchase-returns
|
||||
|
||||
### POST /sales-returns
|
||||
```json
|
||||
{
|
||||
"sales_id": 1,
|
||||
"customer_id": 1,
|
||||
"return_date": "2026-04-29",
|
||||
"lines": [
|
||||
{
|
||||
"sales_line_id": 1,
|
||||
"inventory_lot_id": 10,
|
||||
"item_type_id": 1,
|
||||
"item_grade_id": 1,
|
||||
"qty_returned": 2,
|
||||
"return_condition": "GOOD",
|
||||
"resolution": "RESTOCK"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Barcode / QR
|
||||
### GET /barcode/lookup/{value}
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"lot_id": 10,
|
||||
"lot_code": "LOT-260428-SPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"supplier_bank_name": "BCA",
|
||||
"supplier_bank_account_number": "1234567890",
|
||||
"item_type": "Jenis A",
|
||||
"grade": "Grade A",
|
||||
"available_qty": 30,
|
||||
"warehouse": "Gudang Pusat",
|
||||
"location": "Rak A1",
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
```
|
||||
|
||||
### POST /lots/{id}/print-label
|
||||
### GET /lots/{id}/labels
|
||||
|
||||
---
|
||||
|
||||
## 12. Reports
|
||||
### GET /reports/stock-summary
|
||||
### GET /reports/stock-lots
|
||||
### GET /reports/purchases
|
||||
### GET /reports/sales
|
||||
### GET /reports/margins
|
||||
### GET /reports/shrinkage
|
||||
### GET /reports/supplier-quality
|
||||
### GET /reports/traceability
|
||||
|
||||
Contoh:
|
||||
### GET /reports/traceability?sales_id=1
|
||||
### GET /reports/traceability?lot_id=10
|
||||
|
||||
---
|
||||
|
||||
## 13. Error Rules
|
||||
Format error:
|
||||
```json
|
||||
{
|
||||
"message": "Validation error",
|
||||
"errors": {
|
||||
"qty_allocated": ["qty allocated melebihi stok tersedia"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 14. Business Validation Rules
|
||||
- total allocation harus sama dengan qty sales line
|
||||
- qty allocation tidak boleh melebihi available qty lot
|
||||
- sorting result total + shrinkage tidak boleh melebihi input qty
|
||||
- lot hold tidak boleh dipakai untuk sales allocation
|
||||
- lot closed tidak boleh dipakai lagi
|
||||
- transfer dan adjustment harus menghasilkan movement ledger
|
||||
- receipt yang belum finalized tidak boleh dipakai untuk sales
|
||||
278
docs/project-spec/walet-backend-architecture.md
Normal file
278
docs/project-spec/walet-backend-architecture.md
Normal file
@ -0,0 +1,278 @@
|
||||
# Arsitektur Backend Sistem Inventory Walet
|
||||
|
||||
## 1. Tujuan
|
||||
Dokumen ini menjelaskan rancangan arsitektur backend untuk sistem inventory sarang burung walet berbasis lot, sorting, partial allocation, costing, dan traceability.
|
||||
|
||||
## 2. Prinsip Arsitektur
|
||||
- modular per domain bisnis
|
||||
- transaction-safe untuk operasi stok
|
||||
- audit trail wajib untuk semua mutasi lot
|
||||
- source of truth ada pada lot dan movement ledger
|
||||
- costing dihitung dari allocation aktual
|
||||
- siap dikembangkan bertahap dari MVP ke skala lebih besar
|
||||
|
||||
## 3. Modul Backend Utama
|
||||
### A. Auth & Access Control
|
||||
Tanggung jawab:
|
||||
- login
|
||||
- session/jwt
|
||||
- role permission
|
||||
- route guard
|
||||
- audit identity
|
||||
|
||||
### B. Master Data Module
|
||||
Tanggung jawab:
|
||||
- supplier
|
||||
- customer
|
||||
- item types
|
||||
- item grades
|
||||
- warehouses
|
||||
- locations
|
||||
- units
|
||||
- adjustment reasons
|
||||
|
||||
### C. Purchasing Module
|
||||
Tanggung jawab:
|
||||
- purchase header/lines
|
||||
- purchase workflow
|
||||
- histori harga beli
|
||||
|
||||
### D. Receiving Module
|
||||
Tanggung jawab:
|
||||
- receipt header/lines
|
||||
- qty accepted/rejected
|
||||
- create lot awal
|
||||
- generate label metadata
|
||||
|
||||
### E. Inventory Lot Module
|
||||
Tanggung jawab:
|
||||
- detail lot
|
||||
- stock summary
|
||||
- lot status
|
||||
- hold/release
|
||||
- transfer
|
||||
- location update
|
||||
|
||||
### F. Sorting & Regrade Module
|
||||
Tanggung jawab:
|
||||
- sorting session
|
||||
- child lot creation
|
||||
- shrinkage recording
|
||||
- regrade logic
|
||||
|
||||
### G. Sales Module
|
||||
Tanggung jawab:
|
||||
- sales header/lines
|
||||
- sales workflow
|
||||
- picking confirmation
|
||||
- finalize sales
|
||||
|
||||
### H. Allocation Engine Module
|
||||
Tanggung jawab:
|
||||
- manual allocation validation
|
||||
- FIFO suggestion
|
||||
- future FEFO/hybrid strategy
|
||||
- costing by allocation
|
||||
|
||||
### I. Inventory Movement Ledger Module
|
||||
Tanggung jawab:
|
||||
- record all inventory movements
|
||||
- balance validation
|
||||
- immutable movement history
|
||||
|
||||
### J. Adjustment & Return Module
|
||||
Tanggung jawab:
|
||||
- stock adjustment
|
||||
- shrinkage
|
||||
- purchase returns
|
||||
- sales returns
|
||||
- damage/reject flows
|
||||
|
||||
### K. Traceability Module
|
||||
Tanggung jawab:
|
||||
- backward trace
|
||||
- forward trace
|
||||
- lot lineage
|
||||
- trace report builder
|
||||
|
||||
### L. Reporting Module
|
||||
Tanggung jawab:
|
||||
- stock summary report
|
||||
- sales report
|
||||
- purchase report
|
||||
- margin report
|
||||
- shrinkage report
|
||||
- supplier quality report
|
||||
|
||||
### M. Barcode / QR Module
|
||||
Tanggung jawab:
|
||||
- label generation
|
||||
- reprint tracking
|
||||
- lookup by scanned value
|
||||
|
||||
## 4. Struktur Layer yang Disarankan
|
||||
```text
|
||||
src/
|
||||
modules/
|
||||
common/
|
||||
infrastructure/
|
||||
database/
|
||||
jobs/
|
||||
```
|
||||
|
||||
### Per module internal
|
||||
```text
|
||||
modules/
|
||||
purchases/
|
||||
controllers/
|
||||
services/
|
||||
repositories/
|
||||
dtos/
|
||||
entities/
|
||||
validators/
|
||||
```
|
||||
|
||||
## 5. Service Boundaries Penting
|
||||
### PurchaseService
|
||||
- createPurchase
|
||||
- updatePurchase
|
||||
- submitPurchase
|
||||
- cancelPurchase
|
||||
|
||||
### ReceiptService
|
||||
- createReceipt
|
||||
- finalizeReceipt
|
||||
- generateLotsFromReceipt
|
||||
|
||||
### LotService
|
||||
- getLotDetail
|
||||
- holdLot
|
||||
- releaseLot
|
||||
- transferLot
|
||||
- getStockSummary
|
||||
|
||||
### SortingService
|
||||
- createSortingSession
|
||||
- validateSortingBalance
|
||||
- createChildLots
|
||||
|
||||
### RegradeService
|
||||
- regradeLot
|
||||
- splitLotForRegrade
|
||||
|
||||
### SalesService
|
||||
- createSales
|
||||
- updateSales
|
||||
- finalizeSales
|
||||
- confirmPicking
|
||||
|
||||
### AllocationService
|
||||
- autoAllocateFIFO
|
||||
- validateManualAllocation
|
||||
- calculateAllocationCost
|
||||
|
||||
### MovementService
|
||||
- recordReceiptMovement
|
||||
- recordSortingMovement
|
||||
- recordSalesMovement
|
||||
- recordAdjustmentMovement
|
||||
- recordTransferMovement
|
||||
|
||||
### TraceService
|
||||
- traceBySales
|
||||
- traceByLot
|
||||
- buildLotLineage
|
||||
|
||||
## 6. Transaksi Database yang Wajib Atomic
|
||||
Operasi berikut wajib berada dalam database transaction:
|
||||
- finalize receipt + create lots + create movement
|
||||
- sorting submit + child lot creation + source lot reduction + movement insert
|
||||
- regrade + lot split + movement insert
|
||||
- sales allocation submit + costing update
|
||||
- picking confirm + lot quantity reduction + movement insert
|
||||
- stock adjustment + balance update + movement insert
|
||||
- returns + lot mutation + movement insert
|
||||
|
||||
Kalau tidak atomic, stok akan gampang kacau.
|
||||
|
||||
## 7. Source of Truth Rules
|
||||
- inventory_lots menyimpan posisi qty aktif saat ini
|
||||
- inventory_movements menyimpan histori mutasi yang tidak boleh hilang
|
||||
- sales_allocations menyimpan asal costing penjualan
|
||||
- sorting_results dan parent_lot relation menyimpan lineage hasil sortasi
|
||||
|
||||
## 8. Validasi Domain Penting
|
||||
### Receipt
|
||||
- qty accepted + qty rejected <= qty received
|
||||
|
||||
### Sorting
|
||||
- total result + shrinkage <= input qty
|
||||
|
||||
### Allocation
|
||||
- total allocation = qty sales line
|
||||
- lot status harus ACTIVE
|
||||
- available qty harus cukup
|
||||
|
||||
### Picking
|
||||
- qty picked tidak boleh melebihi qty allocated tanpa override rule
|
||||
|
||||
### Adjustment
|
||||
- qty_after tidak boleh negatif
|
||||
|
||||
### Regrade
|
||||
- qty regrade tidak boleh melebihi available qty lot sumber
|
||||
|
||||
## 9. Event / Hook Internal yang Disarankan
|
||||
Walau MVP belum perlu event bus besar, internal hooks bagus untuk:
|
||||
- afterReceiptFinalized
|
||||
- afterSortingCompleted
|
||||
- afterSalesAllocated
|
||||
- afterPickingConfirmed
|
||||
- afterAdjustmentCreated
|
||||
|
||||
Hook bisa dipakai untuk:
|
||||
- recalculation summary
|
||||
- audit log tambahan
|
||||
- notification
|
||||
- async report cache refresh
|
||||
|
||||
## 10. Caching Strategy
|
||||
- stock summary boleh dicache ringan
|
||||
- lot detail sebaiknya fresh atau cache sangat pendek
|
||||
- reports boleh async/precomputed bila sudah besar
|
||||
- traceability query perlu index bagus, jangan terlalu mengandalkan cache dulu
|
||||
|
||||
## 11. Database Index Priorities
|
||||
Index penting:
|
||||
- inventory_lots(item_type_id, item_grade_id, warehouse_id)
|
||||
- inventory_lots(status)
|
||||
- sales_allocations(sales_line_id)
|
||||
- sales_allocations(inventory_lot_id)
|
||||
- inventory_movements(inventory_lot_id, movement_date)
|
||||
- purchases(supplier_id, purchase_date)
|
||||
- sales(customer_id, sales_date)
|
||||
|
||||
## 12. Background Jobs yang Bisa Ditambahkan
|
||||
- nightly stock summary refresh
|
||||
- report materialization
|
||||
- aging recalculation
|
||||
- QR label batch generation
|
||||
- alert stok menipis
|
||||
|
||||
## 13. Security & Audit
|
||||
- semua endpoint protected
|
||||
- role permission check di service layer, bukan UI saja
|
||||
- audit log simpan user, waktu, aksi, reference
|
||||
- label reprint dan stock adjustment harus ekstra jelas auditnya
|
||||
|
||||
## 14. Rekomendasi Stack Backend
|
||||
Pilihan aman:
|
||||
- Node.js + NestJS / Express terstruktur
|
||||
- PostgreSQL
|
||||
- Prisma / TypeORM / Knex sesuai preferensi
|
||||
- Redis opsional untuk cache dan queue
|
||||
|
||||
Kalau mau lebih enterprise, NestJS cocok karena modular dan rapi.
|
||||
|
||||
## 15. Kesimpulan
|
||||
Backend sistem walet ini harus dibangun dengan fokus utama pada integritas transaksi stok. Modul paling kritis adalah inventory lot, allocation engine, movement ledger, sorting/regrade, dan traceability. Kalau lima bagian ini kuat, sisanya relatif mengikuti.
|
||||
277
docs/project-spec/walet-component-tree.md
Normal file
277
docs/project-spec/walet-component-tree.md
Normal file
@ -0,0 +1,277 @@
|
||||
# Component Tree Per Halaman Sistem Inventory Walet
|
||||
|
||||
## 1. Dashboard
|
||||
```text
|
||||
DashboardPage
|
||||
├── AppShell
|
||||
├── DashboardHeader
|
||||
├── MetricsGrid
|
||||
│ ├── TotalStockCard
|
||||
│ ├── InventoryValueCard
|
||||
│ ├── PurchaseThisMonthCard
|
||||
│ ├── SalesThisMonthCard
|
||||
│ └── ShrinkageThisMonthCard
|
||||
├── StockSummaryChart
|
||||
├── PurchaseVsSalesChart
|
||||
├── SupplierQualityChart
|
||||
├── AgingAlertPanel
|
||||
└── QuickActionPanel
|
||||
```
|
||||
|
||||
## 2. Purchase List
|
||||
```text
|
||||
PurchaseListPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── PurchaseFilterBar
|
||||
├── PurchaseToolbar
|
||||
└── PurchaseTable
|
||||
├── TableToolbar
|
||||
├── StatusBadge
|
||||
└── Pagination
|
||||
```
|
||||
|
||||
## 3. Purchase Form
|
||||
```text
|
||||
PurchaseFormPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── PurchaseHeaderForm
|
||||
│ ├── SupplierSelect
|
||||
│ ├── PurchaseDateInput
|
||||
│ ├── SupplierInvoiceInput
|
||||
│ └── NotesTextarea
|
||||
├── PurchaseLineEditor
|
||||
│ ├── PurchaseLineRow
|
||||
│ │ ├── ItemTypeSelect
|
||||
│ │ ├── ItemGradeSelect
|
||||
│ │ ├── QtyInput
|
||||
│ │ ├── UnitSelect
|
||||
│ │ ├── UnitPriceInput
|
||||
│ │ ├── ClassificationStatusSelect
|
||||
│ │ └── LineSubtotalCell
|
||||
│ └── AddLineButton
|
||||
├── PurchaseSummaryCard
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 4. Receipt Form
|
||||
```text
|
||||
ReceiptFormPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── ReceiptHeaderForm
|
||||
├── ReceiptLineTable
|
||||
│ ├── ReceiptLineRow
|
||||
│ │ ├── OrderedQtyCell
|
||||
│ │ ├── ReceivedQtyInput
|
||||
│ │ ├── AcceptedQtyInput
|
||||
│ │ ├── RejectedQtyInput
|
||||
│ │ ├── UnitCostInput
|
||||
│ │ ├── WarehouseSelect
|
||||
│ │ └── WarehouseLocationSelect
|
||||
├── GenerateLotPanel
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 5. Stock Lot List
|
||||
```text
|
||||
StockLotListPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── LotFilterBar
|
||||
├── LotToolbar
|
||||
└── LotTable
|
||||
├── StatusBadge
|
||||
├── AgingBadge
|
||||
├── LotQuickActionsMenu
|
||||
└── Pagination
|
||||
```
|
||||
|
||||
## 6. Lot Detail
|
||||
```text
|
||||
LotDetailPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── LotSummaryCard
|
||||
├── LotIdentitySection
|
||||
├── LotQuantitySection
|
||||
├── LotTraceSection
|
||||
│ ├── ParentLotCard
|
||||
│ ├── ChildLotsTable
|
||||
│ └── SourceReferenceCard
|
||||
├── LotMovementTimeline
|
||||
├── LotSalesUsageTable
|
||||
├── LotLabelPanel
|
||||
└── LotActionPanel
|
||||
├── HoldLotButton
|
||||
├── ReleaseLotButton
|
||||
├── TransferLotButton
|
||||
├── RegradeLotButton
|
||||
└── PrintLabelButton
|
||||
```
|
||||
|
||||
## 7. Sorting Session Form
|
||||
```text
|
||||
SortingSessionFormPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── SourceLotSelector
|
||||
├── SourceLotSummaryCard
|
||||
├── SortingResultEditor
|
||||
│ ├── SortingResultRow
|
||||
│ │ ├── ItemTypeSelect
|
||||
│ │ ├── ItemGradeSelect
|
||||
│ │ ├── QtyResultInput
|
||||
│ │ └── CostInput
|
||||
│ └── AddResultLineButton
|
||||
├── ShrinkageInputCard
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 8. Sales Form
|
||||
```text
|
||||
SalesFormPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── SalesHeaderForm
|
||||
│ ├── CustomerSelect
|
||||
│ ├── SalesDateInput
|
||||
│ └── NotesTextarea
|
||||
├── SalesLineEditor
|
||||
│ ├── SalesLineRow
|
||||
│ │ ├── ItemTypeSelect
|
||||
│ │ ├── ItemGradeSelect
|
||||
│ │ ├── QtyInput
|
||||
│ │ ├── UnitSelect
|
||||
│ │ ├── SellingPriceInput
|
||||
│ │ └── LineSubtotalCell
|
||||
│ └── AddLineButton
|
||||
├── SalesSummaryCard
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 9. Allocation Screen
|
||||
```text
|
||||
SalesAllocationPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── SalesLineSummaryCard
|
||||
├── AllocationToolbar
|
||||
│ ├── AutoAllocateButton
|
||||
│ ├── AllocationPolicySelect
|
||||
│ └── RefreshStockButton
|
||||
├── AvailableLotTable
|
||||
│ ├── LotRow
|
||||
│ │ ├── LotCodeCell
|
||||
│ │ ├── SupplierCell
|
||||
│ │ ├── AvailableQtyCell
|
||||
│ │ ├── UnitCostCell
|
||||
│ │ ├── FIFORecommendationBadge
|
||||
│ │ └── AllocateQtyInput
|
||||
├── AllocationSummaryCard
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 10. Picking Screen
|
||||
```text
|
||||
PickingPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── PickingSummaryCard
|
||||
├── QrScannerPanel
|
||||
├── PickingAllocationList
|
||||
│ ├── PickingAllocationRow
|
||||
│ │ ├── LotInfoCard
|
||||
│ │ ├── AllocatedQtyCell
|
||||
│ │ ├── PickedQtyInput
|
||||
│ │ └── VarianceBadge
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 11. Barcode Lookup
|
||||
```text
|
||||
BarcodeLookupPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── QrScannerPanel
|
||||
├── ManualBarcodeInput
|
||||
├── LookupResultCard
|
||||
├── TraceSummaryPanel
|
||||
└── QuickActionPanel
|
||||
```
|
||||
|
||||
## 12. Adjustment Form
|
||||
```text
|
||||
AdjustmentFormPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── LotSelector
|
||||
├── LotSnapshotCard
|
||||
├── AdjustmentForm
|
||||
│ ├── AdjustmentTypeSelect
|
||||
│ ├── ReasonSelect
|
||||
│ ├── QtyBeforeReadonly
|
||||
│ ├── QtyChangeInput
|
||||
│ ├── QtyAfterPreview
|
||||
│ ├── CostImpactPreview
|
||||
│ └── NotesTextarea
|
||||
└── StickyActionFooter
|
||||
```
|
||||
|
||||
## 13. Reports Page
|
||||
```text
|
||||
ReportPage
|
||||
├── AppShell
|
||||
├── PageHeader
|
||||
├── ReportFilterBar
|
||||
├── ReportSummaryCards
|
||||
├── ReportChartSection
|
||||
├── ReportTableSection
|
||||
└── ExportActionBar
|
||||
```
|
||||
|
||||
## 14. Shared Critical Components
|
||||
```text
|
||||
AppShell
|
||||
├── Sidebar
|
||||
├── Topbar
|
||||
├── Breadcrumb
|
||||
└── ContentWrapper
|
||||
|
||||
DataTable
|
||||
├── FilterBar
|
||||
├── ColumnVisibilityToggle
|
||||
├── ExportButton
|
||||
├── Pagination
|
||||
└── EmptyState
|
||||
|
||||
QrScannerPanel
|
||||
├── CameraPreview
|
||||
├── ScanOverlay
|
||||
├── ScanResultBadge
|
||||
└── ManualFallbackInput
|
||||
```
|
||||
|
||||
## 15. Prioritas Component Build
|
||||
Urutan komponen paling penting dibangun dulu:
|
||||
1. AppShell
|
||||
2. DataTable
|
||||
3. StatusBadge / AgingBadge
|
||||
4. Form primitives
|
||||
5. PurchaseLineEditor
|
||||
6. ReceiptLineTable
|
||||
7. LotTable
|
||||
8. LotSummaryCard
|
||||
9. LotMovementTimeline
|
||||
10. SalesLineEditor
|
||||
11. AvailableLotTable
|
||||
12. AllocationSummaryCard
|
||||
13. QrScannerPanel
|
||||
14. PickingAllocationList
|
||||
15. ReportFilterBar
|
||||
|
||||
## 16. Catatan
|
||||
- halaman lot detail dan allocation adalah pusat kompleksitas produk
|
||||
- QR scanner dan movement timeline adalah komponen pembeda
|
||||
- semua editor multi-line harus reusable agar purchase, receipt, sales, dan sorting lebih cepat dibangun
|
||||
441
docs/project-spec/walet-erd-dbml.dbml
Normal file
441
docs/project-spec/walet-erd-dbml.dbml
Normal file
@ -0,0 +1,441 @@
|
||||
Project walet_inventory {
|
||||
database_type: "PostgreSQL"
|
||||
Note: 'ERD importable schema for lot-based traceable walet inventory system'
|
||||
}
|
||||
|
||||
Table suppliers {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
phone varchar
|
||||
email varchar
|
||||
bank_name varchar
|
||||
bank_account_number varchar
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table customers {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
phone varchar
|
||||
email varchar
|
||||
bank_name varchar
|
||||
bank_account_number varchar
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table roles {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table users {
|
||||
id bigint [pk, increment]
|
||||
role_id bigint [not null]
|
||||
name varchar [not null]
|
||||
email varchar
|
||||
phone varchar
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table units {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table item_types {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
description text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table item_grades {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
rank_order int
|
||||
description text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table warehouses {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table warehouse_locations {
|
||||
id bigint [pk, increment]
|
||||
warehouse_id bigint [not null]
|
||||
code varchar [not null]
|
||||
name varchar [not null]
|
||||
location_type varchar
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
|
||||
indexes {
|
||||
(warehouse_id, code) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
Table adjustment_reasons {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
category varchar [not null]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchases {
|
||||
id bigint [pk, increment]
|
||||
purchase_no varchar [not null, unique]
|
||||
supplier_id bigint [not null]
|
||||
purchase_date date [not null]
|
||||
supplier_invoice_no varchar
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_lines {
|
||||
id bigint [pk, increment]
|
||||
purchase_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint
|
||||
qty_ordered decimal(18,3) [not null]
|
||||
unit_id bigint [not null]
|
||||
unit_price decimal(18,2) [not null]
|
||||
subtotal decimal(18,2) [not null]
|
||||
classification_status varchar [not null, default: 'FINAL']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table receipts {
|
||||
id bigint [pk, increment]
|
||||
receipt_no varchar [not null, unique]
|
||||
purchase_id bigint [not null]
|
||||
supplier_id bigint [not null]
|
||||
receipt_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
received_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table receipt_lines {
|
||||
id bigint [pk, increment]
|
||||
receipt_id bigint [not null]
|
||||
purchase_line_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint
|
||||
qty_received decimal(18,3) [not null]
|
||||
qty_accepted decimal(18,3) [not null]
|
||||
qty_rejected decimal(18,3) [not null, default: 0]
|
||||
unit_id bigint [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table inventory_lots {
|
||||
id bigint [pk, increment]
|
||||
lot_code varchar [not null, unique]
|
||||
parent_lot_id bigint
|
||||
source_type varchar [not null]
|
||||
source_ref_id bigint
|
||||
supplier_id bigint
|
||||
purchase_id bigint
|
||||
purchase_line_id bigint
|
||||
receipt_id bigint
|
||||
receipt_line_id bigint
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
warehouse_id bigint [not null]
|
||||
warehouse_location_id bigint
|
||||
original_qty decimal(18,3) [not null]
|
||||
available_qty decimal(18,3) [not null]
|
||||
reserved_qty decimal(18,3) [not null, default: 0]
|
||||
damaged_qty decimal(18,3) [not null, default: 0]
|
||||
shrinkage_qty decimal(18,3) [not null, default: 0]
|
||||
unit_id bigint [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
received_at timestamp [not null]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
qr_code_value varchar
|
||||
barcode_value varchar
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
|
||||
indexes {
|
||||
(item_type_id, item_grade_id, warehouse_id)
|
||||
(supplier_id, item_type_id, item_grade_id)
|
||||
}
|
||||
}
|
||||
|
||||
Table sorting_sessions {
|
||||
id bigint [pk, increment]
|
||||
sorting_no varchar [not null, unique]
|
||||
source_lot_id bigint [not null]
|
||||
sorting_date timestamp [not null]
|
||||
input_qty decimal(18,3) [not null]
|
||||
output_qty decimal(18,3) [not null]
|
||||
shrinkage_qty decimal(18,3) [not null, default: 0]
|
||||
notes text
|
||||
sorted_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sorting_results {
|
||||
id bigint [pk, increment]
|
||||
sorting_session_id bigint [not null]
|
||||
result_lot_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_result decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales {
|
||||
id bigint [pk, increment]
|
||||
sales_no varchar [not null, unique]
|
||||
customer_id bigint [not null]
|
||||
sales_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_lines {
|
||||
id bigint [pk, increment]
|
||||
sales_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_sold decimal(18,3) [not null]
|
||||
unit_id bigint [not null]
|
||||
selling_price decimal(18,2) [not null]
|
||||
subtotal decimal(18,2) [not null]
|
||||
costing_total decimal(18,2) [not null, default: 0]
|
||||
gross_margin decimal(18,2) [not null, default: 0]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_allocations {
|
||||
id bigint [pk, increment]
|
||||
sales_line_id bigint [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
qty_allocated decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
total_cost decimal(18,2) [not null]
|
||||
allocated_at timestamp [not null]
|
||||
allocated_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table inventory_movements {
|
||||
id bigint [pk, increment]
|
||||
movement_no varchar [not null, unique]
|
||||
movement_type varchar [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
related_lot_id bigint
|
||||
warehouse_id bigint [not null]
|
||||
warehouse_location_id bigint
|
||||
qty_in decimal(18,3) [not null, default: 0]
|
||||
qty_out decimal(18,3) [not null, default: 0]
|
||||
balance_after decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
reference_type varchar [not null]
|
||||
reference_id bigint [not null]
|
||||
reason_id bigint
|
||||
movement_date timestamp [not null]
|
||||
created_by bigint [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_returns {
|
||||
id bigint [pk, increment]
|
||||
sales_id bigint [not null]
|
||||
customer_id bigint [not null]
|
||||
return_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_return_lines {
|
||||
id bigint [pk, increment]
|
||||
sales_return_id bigint [not null]
|
||||
sales_line_id bigint [not null]
|
||||
inventory_lot_id bigint
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_returned decimal(18,3) [not null]
|
||||
return_condition varchar
|
||||
resolution varchar
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_returns {
|
||||
id bigint [pk, increment]
|
||||
purchase_id bigint [not null]
|
||||
supplier_id bigint [not null]
|
||||
return_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_return_lines {
|
||||
id bigint [pk, increment]
|
||||
purchase_return_id bigint [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
qty_returned decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table stock_adjustments {
|
||||
id bigint [pk, increment]
|
||||
adjustment_no varchar [not null, unique]
|
||||
inventory_lot_id bigint [not null]
|
||||
adjustment_type varchar [not null]
|
||||
reason_id bigint [not null]
|
||||
qty_before decimal(18,3) [not null]
|
||||
qty_change decimal(18,3) [not null]
|
||||
qty_after decimal(18,3) [not null]
|
||||
cost_impact decimal(18,2) [not null, default: 0]
|
||||
adjustment_date timestamp [not null]
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table lot_labels {
|
||||
id bigint [pk, increment]
|
||||
inventory_lot_id bigint [not null]
|
||||
label_type varchar [not null]
|
||||
label_value varchar [not null]
|
||||
printed_at timestamp
|
||||
printed_by bigint
|
||||
print_count int [not null, default: 0]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Ref: users.role_id > roles.id
|
||||
Ref: warehouse_locations.warehouse_id > warehouses.id
|
||||
Ref: purchases.supplier_id > suppliers.id
|
||||
Ref: purchases.created_by > users.id
|
||||
Ref: purchase_lines.purchase_id > purchases.id
|
||||
Ref: purchase_lines.item_type_id > item_types.id
|
||||
Ref: purchase_lines.item_grade_id > item_grades.id
|
||||
Ref: purchase_lines.unit_id > units.id
|
||||
Ref: receipts.purchase_id > purchases.id
|
||||
Ref: receipts.supplier_id > suppliers.id
|
||||
Ref: receipts.received_by > users.id
|
||||
Ref: receipt_lines.receipt_id > receipts.id
|
||||
Ref: receipt_lines.purchase_line_id > purchase_lines.id
|
||||
Ref: receipt_lines.item_type_id > item_types.id
|
||||
Ref: receipt_lines.item_grade_id > item_grades.id
|
||||
Ref: receipt_lines.unit_id > units.id
|
||||
Ref: inventory_lots.parent_lot_id > inventory_lots.id
|
||||
Ref: inventory_lots.supplier_id > suppliers.id
|
||||
Ref: inventory_lots.purchase_id > purchases.id
|
||||
Ref: inventory_lots.purchase_line_id > purchase_lines.id
|
||||
Ref: inventory_lots.receipt_id > receipts.id
|
||||
Ref: inventory_lots.receipt_line_id > receipt_lines.id
|
||||
Ref: inventory_lots.item_type_id > item_types.id
|
||||
Ref: inventory_lots.item_grade_id > item_grades.id
|
||||
Ref: inventory_lots.warehouse_id > warehouses.id
|
||||
Ref: inventory_lots.warehouse_location_id > warehouse_locations.id
|
||||
Ref: inventory_lots.unit_id > units.id
|
||||
Ref: sorting_sessions.source_lot_id > inventory_lots.id
|
||||
Ref: sorting_sessions.sorted_by > users.id
|
||||
Ref: sorting_results.sorting_session_id > sorting_sessions.id
|
||||
Ref: sorting_results.result_lot_id > inventory_lots.id
|
||||
Ref: sorting_results.item_type_id > item_types.id
|
||||
Ref: sorting_results.item_grade_id > item_grades.id
|
||||
Ref: sales.customer_id > customers.id
|
||||
Ref: sales.created_by > users.id
|
||||
Ref: sales_lines.sales_id > sales.id
|
||||
Ref: sales_lines.item_type_id > item_types.id
|
||||
Ref: sales_lines.item_grade_id > item_grades.id
|
||||
Ref: sales_lines.unit_id > units.id
|
||||
Ref: sales_allocations.sales_line_id > sales_lines.id
|
||||
Ref: sales_allocations.inventory_lot_id > inventory_lots.id
|
||||
Ref: sales_allocations.allocated_by > users.id
|
||||
Ref: inventory_movements.inventory_lot_id > inventory_lots.id
|
||||
Ref: inventory_movements.related_lot_id > inventory_lots.id
|
||||
Ref: inventory_movements.warehouse_id > warehouses.id
|
||||
Ref: inventory_movements.warehouse_location_id > warehouse_locations.id
|
||||
Ref: inventory_movements.reason_id > adjustment_reasons.id
|
||||
Ref: inventory_movements.created_by > users.id
|
||||
Ref: sales_returns.sales_id > sales.id
|
||||
Ref: sales_returns.customer_id > customers.id
|
||||
Ref: sales_return_lines.sales_return_id > sales_returns.id
|
||||
Ref: sales_return_lines.sales_line_id > sales_lines.id
|
||||
Ref: sales_return_lines.inventory_lot_id > inventory_lots.id
|
||||
Ref: sales_return_lines.item_type_id > item_types.id
|
||||
Ref: sales_return_lines.item_grade_id > item_grades.id
|
||||
Ref: purchase_returns.purchase_id > purchases.id
|
||||
Ref: purchase_returns.supplier_id > suppliers.id
|
||||
Ref: purchase_return_lines.purchase_return_id > purchase_returns.id
|
||||
Ref: purchase_return_lines.inventory_lot_id > inventory_lots.id
|
||||
Ref: stock_adjustments.inventory_lot_id > inventory_lots.id
|
||||
Ref: stock_adjustments.reason_id > adjustment_reasons.id
|
||||
Ref: stock_adjustments.created_by > users.id
|
||||
Ref: lot_labels.inventory_lot_id > inventory_lots.id
|
||||
Ref: lot_labels.printed_by > users.id
|
||||
442
docs/project-spec/walet-erd-schema.html
Normal file
442
docs/project-spec/walet-erd-schema.html
Normal file
@ -0,0 +1,442 @@
|
||||
<!doctype html><html><head><meta charset="utf-8"><style>@page { size:A4; margin:2cm 1.6cm; } body { font-family: Arial, Helvetica, sans-serif; font-size:11pt; line-height:1.5; } pre { white-space: pre-wrap; font-size:9pt; }</style></head><body><h1>ERD Schema Sistem Inventory Walet</h1><pre>Project walet_inventory {
|
||||
database_type: "PostgreSQL"
|
||||
Note: 'ERD importable schema for lot-based traceable walet inventory system'
|
||||
}
|
||||
|
||||
Table suppliers {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
phone varchar
|
||||
email varchar
|
||||
bank_name varchar
|
||||
bank_account_number varchar
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table customers {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
phone varchar
|
||||
email varchar
|
||||
bank_name varchar
|
||||
bank_account_number varchar
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table roles {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table users {
|
||||
id bigint [pk, increment]
|
||||
role_id bigint [not null]
|
||||
name varchar [not null]
|
||||
email varchar
|
||||
phone varchar
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table units {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table item_types {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
description text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table item_grades {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
rank_order int
|
||||
description text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table warehouses {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
address text
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table warehouse_locations {
|
||||
id bigint [pk, increment]
|
||||
warehouse_id bigint [not null]
|
||||
code varchar [not null]
|
||||
name varchar [not null]
|
||||
location_type varchar
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
|
||||
indexes {
|
||||
(warehouse_id, code) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
Table adjustment_reasons {
|
||||
id bigint [pk, increment]
|
||||
code varchar [not null, unique]
|
||||
name varchar [not null]
|
||||
category varchar [not null]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchases {
|
||||
id bigint [pk, increment]
|
||||
purchase_no varchar [not null, unique]
|
||||
supplier_id bigint [not null]
|
||||
purchase_date date [not null]
|
||||
supplier_invoice_no varchar
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_lines {
|
||||
id bigint [pk, increment]
|
||||
purchase_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint
|
||||
qty_ordered decimal(18,3) [not null]
|
||||
unit_id bigint [not null]
|
||||
unit_price decimal(18,2) [not null]
|
||||
subtotal decimal(18,2) [not null]
|
||||
classification_status varchar [not null, default: 'FINAL']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table receipts {
|
||||
id bigint [pk, increment]
|
||||
receipt_no varchar [not null, unique]
|
||||
purchase_id bigint [not null]
|
||||
supplier_id bigint [not null]
|
||||
receipt_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
received_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table receipt_lines {
|
||||
id bigint [pk, increment]
|
||||
receipt_id bigint [not null]
|
||||
purchase_line_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint
|
||||
qty_received decimal(18,3) [not null]
|
||||
qty_accepted decimal(18,3) [not null]
|
||||
qty_rejected decimal(18,3) [not null, default: 0]
|
||||
unit_id bigint [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table inventory_lots {
|
||||
id bigint [pk, increment]
|
||||
lot_code varchar [not null, unique]
|
||||
parent_lot_id bigint
|
||||
source_type varchar [not null]
|
||||
source_ref_id bigint
|
||||
supplier_id bigint
|
||||
purchase_id bigint
|
||||
purchase_line_id bigint
|
||||
receipt_id bigint
|
||||
receipt_line_id bigint
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
warehouse_id bigint [not null]
|
||||
warehouse_location_id bigint
|
||||
original_qty decimal(18,3) [not null]
|
||||
available_qty decimal(18,3) [not null]
|
||||
reserved_qty decimal(18,3) [not null, default: 0]
|
||||
damaged_qty decimal(18,3) [not null, default: 0]
|
||||
shrinkage_qty decimal(18,3) [not null, default: 0]
|
||||
unit_id bigint [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
received_at timestamp [not null]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
qr_code_value varchar
|
||||
barcode_value varchar
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
|
||||
indexes {
|
||||
(item_type_id, item_grade_id, warehouse_id)
|
||||
(supplier_id, item_type_id, item_grade_id)
|
||||
}
|
||||
}
|
||||
|
||||
Table sorting_sessions {
|
||||
id bigint [pk, increment]
|
||||
sorting_no varchar [not null, unique]
|
||||
source_lot_id bigint [not null]
|
||||
sorting_date timestamp [not null]
|
||||
input_qty decimal(18,3) [not null]
|
||||
output_qty decimal(18,3) [not null]
|
||||
shrinkage_qty decimal(18,3) [not null, default: 0]
|
||||
notes text
|
||||
sorted_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sorting_results {
|
||||
id bigint [pk, increment]
|
||||
sorting_session_id bigint [not null]
|
||||
result_lot_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_result decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales {
|
||||
id bigint [pk, increment]
|
||||
sales_no varchar [not null, unique]
|
||||
customer_id bigint [not null]
|
||||
sales_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_lines {
|
||||
id bigint [pk, increment]
|
||||
sales_id bigint [not null]
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_sold decimal(18,3) [not null]
|
||||
unit_id bigint [not null]
|
||||
selling_price decimal(18,2) [not null]
|
||||
subtotal decimal(18,2) [not null]
|
||||
costing_total decimal(18,2) [not null, default: 0]
|
||||
gross_margin decimal(18,2) [not null, default: 0]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_allocations {
|
||||
id bigint [pk, increment]
|
||||
sales_line_id bigint [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
qty_allocated decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
total_cost decimal(18,2) [not null]
|
||||
allocated_at timestamp [not null]
|
||||
allocated_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table inventory_movements {
|
||||
id bigint [pk, increment]
|
||||
movement_no varchar [not null, unique]
|
||||
movement_type varchar [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
related_lot_id bigint
|
||||
warehouse_id bigint [not null]
|
||||
warehouse_location_id bigint
|
||||
qty_in decimal(18,3) [not null, default: 0]
|
||||
qty_out decimal(18,3) [not null, default: 0]
|
||||
balance_after decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
reference_type varchar [not null]
|
||||
reference_id bigint [not null]
|
||||
reason_id bigint
|
||||
movement_date timestamp [not null]
|
||||
created_by bigint [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_returns {
|
||||
id bigint [pk, increment]
|
||||
sales_id bigint [not null]
|
||||
customer_id bigint [not null]
|
||||
return_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table sales_return_lines {
|
||||
id bigint [pk, increment]
|
||||
sales_return_id bigint [not null]
|
||||
sales_line_id bigint [not null]
|
||||
inventory_lot_id bigint
|
||||
item_type_id bigint [not null]
|
||||
item_grade_id bigint [not null]
|
||||
qty_returned decimal(18,3) [not null]
|
||||
return_condition varchar
|
||||
resolution varchar
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_returns {
|
||||
id bigint [pk, increment]
|
||||
purchase_id bigint [not null]
|
||||
supplier_id bigint [not null]
|
||||
return_date date [not null]
|
||||
status varchar [not null, default: 'DRAFT']
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table purchase_return_lines {
|
||||
id bigint [pk, increment]
|
||||
purchase_return_id bigint [not null]
|
||||
inventory_lot_id bigint [not null]
|
||||
qty_returned decimal(18,3) [not null]
|
||||
unit_cost decimal(18,2) [not null]
|
||||
notes text
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table stock_adjustments {
|
||||
id bigint [pk, increment]
|
||||
adjustment_no varchar [not null, unique]
|
||||
inventory_lot_id bigint [not null]
|
||||
adjustment_type varchar [not null]
|
||||
reason_id bigint [not null]
|
||||
qty_before decimal(18,3) [not null]
|
||||
qty_change decimal(18,3) [not null]
|
||||
qty_after decimal(18,3) [not null]
|
||||
cost_impact decimal(18,2) [not null, default: 0]
|
||||
adjustment_date timestamp [not null]
|
||||
notes text
|
||||
created_by bigint [not null]
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Table lot_labels {
|
||||
id bigint [pk, increment]
|
||||
inventory_lot_id bigint [not null]
|
||||
label_type varchar [not null]
|
||||
label_value varchar [not null]
|
||||
printed_at timestamp
|
||||
printed_by bigint
|
||||
print_count int [not null, default: 0]
|
||||
status varchar [not null, default: 'ACTIVE']
|
||||
created_at timestamp [not null]
|
||||
updated_at timestamp [not null]
|
||||
}
|
||||
|
||||
Ref: users.role_id > roles.id
|
||||
Ref: warehouse_locations.warehouse_id > warehouses.id
|
||||
Ref: purchases.supplier_id > suppliers.id
|
||||
Ref: purchases.created_by > users.id
|
||||
Ref: purchase_lines.purchase_id > purchases.id
|
||||
Ref: purchase_lines.item_type_id > item_types.id
|
||||
Ref: purchase_lines.item_grade_id > item_grades.id
|
||||
Ref: purchase_lines.unit_id > units.id
|
||||
Ref: receipts.purchase_id > purchases.id
|
||||
Ref: receipts.supplier_id > suppliers.id
|
||||
Ref: receipts.received_by > users.id
|
||||
Ref: receipt_lines.receipt_id > receipts.id
|
||||
Ref: receipt_lines.purchase_line_id > purchase_lines.id
|
||||
Ref: receipt_lines.item_type_id > item_types.id
|
||||
Ref: receipt_lines.item_grade_id > item_grades.id
|
||||
Ref: receipt_lines.unit_id > units.id
|
||||
Ref: inventory_lots.parent_lot_id > inventory_lots.id
|
||||
Ref: inventory_lots.supplier_id > suppliers.id
|
||||
Ref: inventory_lots.purchase_id > purchases.id
|
||||
Ref: inventory_lots.purchase_line_id > purchase_lines.id
|
||||
Ref: inventory_lots.receipt_id > receipts.id
|
||||
Ref: inventory_lots.receipt_line_id > receipt_lines.id
|
||||
Ref: inventory_lots.item_type_id > item_types.id
|
||||
Ref: inventory_lots.item_grade_id > item_grades.id
|
||||
Ref: inventory_lots.warehouse_id > warehouses.id
|
||||
Ref: inventory_lots.warehouse_location_id > warehouse_locations.id
|
||||
Ref: inventory_lots.unit_id > units.id
|
||||
Ref: sorting_sessions.source_lot_id > inventory_lots.id
|
||||
Ref: sorting_sessions.sorted_by > users.id
|
||||
Ref: sorting_results.sorting_session_id > sorting_sessions.id
|
||||
Ref: sorting_results.result_lot_id > inventory_lots.id
|
||||
Ref: sorting_results.item_type_id > item_types.id
|
||||
Ref: sorting_results.item_grade_id > item_grades.id
|
||||
Ref: sales.customer_id > customers.id
|
||||
Ref: sales.created_by > users.id
|
||||
Ref: sales_lines.sales_id > sales.id
|
||||
Ref: sales_lines.item_type_id > item_types.id
|
||||
Ref: sales_lines.item_grade_id > item_grades.id
|
||||
Ref: sales_lines.unit_id > units.id
|
||||
Ref: sales_allocations.sales_line_id > sales_lines.id
|
||||
Ref: sales_allocations.inventory_lot_id > inventory_lots.id
|
||||
Ref: sales_allocations.allocated_by > users.id
|
||||
Ref: inventory_movements.inventory_lot_id > inventory_lots.id
|
||||
Ref: inventory_movements.related_lot_id > inventory_lots.id
|
||||
Ref: inventory_movements.warehouse_id > warehouses.id
|
||||
Ref: inventory_movements.warehouse_location_id > warehouse_locations.id
|
||||
Ref: inventory_movements.reason_id > adjustment_reasons.id
|
||||
Ref: inventory_movements.created_by > users.id
|
||||
Ref: sales_returns.sales_id > sales.id
|
||||
Ref: sales_returns.customer_id > customers.id
|
||||
Ref: sales_return_lines.sales_return_id > sales_returns.id
|
||||
Ref: sales_return_lines.sales_line_id > sales_lines.id
|
||||
Ref: sales_return_lines.inventory_lot_id > inventory_lots.id
|
||||
Ref: sales_return_lines.item_type_id > item_types.id
|
||||
Ref: sales_return_lines.item_grade_id > item_grades.id
|
||||
Ref: purchase_returns.purchase_id > purchases.id
|
||||
Ref: purchase_returns.supplier_id > suppliers.id
|
||||
Ref: purchase_return_lines.purchase_return_id > purchase_returns.id
|
||||
Ref: purchase_return_lines.inventory_lot_id > inventory_lots.id
|
||||
Ref: stock_adjustments.inventory_lot_id > inventory_lots.id
|
||||
Ref: stock_adjustments.reason_id > adjustment_reasons.id
|
||||
Ref: stock_adjustments.created_by > users.id
|
||||
Ref: lot_labels.inventory_lot_id > inventory_lots.id
|
||||
Ref: lot_labels.printed_by > users.id
|
||||
</pre></body></html>
|
||||
BIN
docs/project-spec/walet-erd-schema.pdf
Normal file
BIN
docs/project-spec/walet-erd-schema.pdf
Normal file
Binary file not shown.
253
docs/project-spec/walet-figma-design-brief.md
Normal file
253
docs/project-spec/walet-figma-design-brief.md
Normal file
@ -0,0 +1,253 @@
|
||||
# Figma-Ready Design Brief
|
||||
## AbelBirdnest Stock
|
||||
|
||||
## 1. Tujuan Brief
|
||||
Dokumen ini dibuat agar tim UI/UX atau desainer Figma bisa langsung mulai mendesain tanpa harus membaca seluruh dokumen teknis dari nol.
|
||||
|
||||
Target desain:
|
||||
- desain aplikasi web responsive
|
||||
- prioritas pada operasional gudang, purchasing, sales, dan traceability
|
||||
- desain harus cepat dipakai, bukan sekadar cantik
|
||||
- mobile usability penting untuk flow scan, receiving, transfer, dan picking
|
||||
|
||||
## 2. Konteks Produk
|
||||
`AbelBirdnest Stock` adalah sistem inventory sarang burung walet berbasis lot/batch dengan kemampuan:
|
||||
- pembelian multi jenis dan multi grade
|
||||
- penerimaan barang dan pembentukan lot
|
||||
- sortasi / regrade
|
||||
- penjualan parsial dari banyak lot
|
||||
- costing berbasis allocation nyata
|
||||
- traceability supplier ke customer
|
||||
- barcode / QR lookup dan scan workflow
|
||||
|
||||
## 3. User Utama
|
||||
### Owner
|
||||
Tujuan:
|
||||
- melihat dashboard
|
||||
- melihat laporan, margin, shrinkage, traceability
|
||||
|
||||
### Admin Purchasing
|
||||
Tujuan:
|
||||
- membuat pembelian
|
||||
- mengelola supplier
|
||||
- melihat histori harga
|
||||
|
||||
### Admin Gudang
|
||||
Tujuan:
|
||||
- menerima barang
|
||||
- mengelola lot
|
||||
- transfer, hold, release, adjustment
|
||||
- scan QR/barcode
|
||||
|
||||
### Tim QC / Sortasi
|
||||
Tujuan:
|
||||
- sortasi lot
|
||||
- regrade
|
||||
- catat shrinkage dan reject
|
||||
|
||||
### Admin Sales
|
||||
Tujuan:
|
||||
- buat sales order
|
||||
- allocate lot
|
||||
- picking
|
||||
- cek trace sumber barang
|
||||
|
||||
## 4. Platform dan Breakpoints
|
||||
### Primary
|
||||
- Desktop web untuk office/admin tasks
|
||||
- Mobile web untuk gudang/scan tasks
|
||||
|
||||
### Breakpoints saran
|
||||
- Mobile: 360-480px
|
||||
- Tablet: 768px
|
||||
- Desktop: 1280px+
|
||||
|
||||
## 5. Design Principles
|
||||
- information dense but clear
|
||||
- focus on traceability and status visibility
|
||||
- minimize typing for operational workflows
|
||||
- prioritize fast actions and readable tables
|
||||
- destructive or high-risk actions must be explicit
|
||||
- quantity, cost, status, and lot identity must always stand out
|
||||
|
||||
## 6. Visual Direction
|
||||
### Tone
|
||||
- modern business app
|
||||
- clean, efficient, trustworthy
|
||||
- operational, not decorative
|
||||
|
||||
### Suggested look
|
||||
- neutral base colors
|
||||
- strong status color coding
|
||||
- lots of cards, tables, badges, and side panels
|
||||
- subtle but clear hierarchy
|
||||
|
||||
### Suggested color logic
|
||||
- Active: green
|
||||
- Hold: yellow/orange
|
||||
- Closed: gray
|
||||
- Rejected: red
|
||||
- Draft: blue-gray
|
||||
- Alert/shrinkage variance: red/orange
|
||||
|
||||
## 7. Typography Guidance
|
||||
- clear sans-serif
|
||||
- body 14-16px desktop
|
||||
- compact but readable table text 12-14px
|
||||
- headings should clearly separate sections
|
||||
|
||||
## 8. Core UX Priorities
|
||||
### A. Lot identity must be obvious
|
||||
Every lot-related screen should surface:
|
||||
- lot code
|
||||
- item type
|
||||
- grade
|
||||
- available qty
|
||||
- supplier
|
||||
- status
|
||||
- warehouse/location
|
||||
|
||||
### B. Allocation must feel safe
|
||||
Sales allocation UI must clearly show:
|
||||
- required qty
|
||||
- selected qty
|
||||
- remaining qty
|
||||
- cost impact
|
||||
- recommended FIFO lots
|
||||
|
||||
### C. Scan flow must be fast
|
||||
For mobile scan pages:
|
||||
- camera first
|
||||
- manual input fallback
|
||||
- instant lookup result
|
||||
- quick actions after scan
|
||||
|
||||
### D. Movement history must be readable
|
||||
Movement timeline should be understandable even by non-technical user.
|
||||
|
||||
## 9. Design Output Expected from UI/UX Team
|
||||
Minimal deliverables:
|
||||
- sitemap / screen map
|
||||
- low-fi wireframe cleanup
|
||||
- hi-fi UI for key screens
|
||||
- mobile variant for scan flows
|
||||
- clickable prototype for core flows
|
||||
- handoff specs for frontend team
|
||||
|
||||
## 10. Screen Priority for Hi-Fi Design
|
||||
Prioritas desain visual:
|
||||
1. Login
|
||||
2. Dashboard
|
||||
3. Purchase Form
|
||||
4. Receipt Form
|
||||
5. Stock Lot List
|
||||
6. Lot Detail
|
||||
7. Sales Form
|
||||
8. Allocation Screen
|
||||
9. Picking Screen
|
||||
10. Barcode Lookup
|
||||
11. Sorting Session Form
|
||||
12. Reports
|
||||
|
||||
## 11. Key Flows to Prototype
|
||||
### Flow 1. Purchase to Receipt
|
||||
- create purchase
|
||||
- receive goods
|
||||
- generate lot
|
||||
- view lot detail
|
||||
|
||||
### Flow 2. Lot to Sorting
|
||||
- select lot
|
||||
- create sorting session
|
||||
- create child lots
|
||||
- review results
|
||||
|
||||
### Flow 3. Sales Allocation
|
||||
- create sales order
|
||||
- choose item/grade
|
||||
- allocate from multiple lots
|
||||
- confirm costing
|
||||
- proceed to picking
|
||||
|
||||
### Flow 4. Scan Lookup
|
||||
- open scan page
|
||||
- scan QR
|
||||
- display lot data
|
||||
- navigate to lot detail or action page
|
||||
|
||||
## 12. Components that Need Design Attention
|
||||
- data table
|
||||
- filter bar
|
||||
- summary cards
|
||||
- status badges
|
||||
- qty editor
|
||||
- cost summary panel
|
||||
- movement timeline
|
||||
- QR scanner panel
|
||||
- traceability source panel
|
||||
- sticky action footer
|
||||
|
||||
## 13. Special UX Notes
|
||||
### A. Numbers
|
||||
Design must support large financial values and decimal quantities.
|
||||
|
||||
### B. Tables
|
||||
Many screens are data-heavy. Table readability is critical.
|
||||
|
||||
### C. Status
|
||||
Status should never rely on color only. Add badges/text.
|
||||
|
||||
### D. Bank fields
|
||||
Supplier and customer screens must include:
|
||||
- bank name
|
||||
- bank account number
|
||||
|
||||
### E. Audit-sensitive actions
|
||||
Actions like hold, release, regrade, adjustment, finalize should feel deliberate.
|
||||
|
||||
## 14. Suggested Figma File Structure
|
||||
```text
|
||||
AbelBirdnest Stock Design
|
||||
00 Cover
|
||||
01 Foundations
|
||||
- Colors
|
||||
- Typography
|
||||
- Spacing
|
||||
- Icons
|
||||
02 Components
|
||||
- Buttons
|
||||
- Inputs
|
||||
- Tables
|
||||
- Cards
|
||||
- Badges
|
||||
- Modals
|
||||
- Scanner
|
||||
03 Desktop Screens
|
||||
04 Mobile Screens
|
||||
05 Prototypes
|
||||
06 Dev Handoff
|
||||
```
|
||||
|
||||
## 15. Suggested Foundations
|
||||
### Components to define early
|
||||
- Button primary/secondary/destructive
|
||||
- Text field
|
||||
- Number field
|
||||
- Select field
|
||||
- Date picker
|
||||
- Badge status
|
||||
- Table row states
|
||||
- Card summary
|
||||
- Drawer/modal
|
||||
- Timeline item
|
||||
|
||||
## 16. Success Criteria for Design
|
||||
Design dianggap berhasil jika:
|
||||
- user bisa paham status lot dalam beberapa detik
|
||||
- sales allocation tidak membingungkan
|
||||
- scan flow cepat dipakai di HP
|
||||
- traceability tidak terasa kompleks walau datanya kaya
|
||||
- tabel tetap nyaman dibaca walau padat
|
||||
|
||||
## 17. Penutup
|
||||
Brief ini harus dipakai bersama dokumen wireframe, component tree, dan frontend structure. Fokus utama desain bukan sekadar estetika, tapi membuat proses inventory walet yang kompleks terasa jelas, aman, dan cepat dipakai.
|
||||
408
docs/project-spec/walet-frontend-structure.md
Normal file
408
docs/project-spec/walet-frontend-structure.md
Normal file
@ -0,0 +1,408 @@
|
||||
# Frontend Structure Sistem Inventory Walet
|
||||
|
||||
## 1. Tujuan
|
||||
Dokumen ini menjelaskan struktur frontend yang disarankan untuk aplikasi inventory sarang burung walet berbasis lot, traceability, sorting, partial allocation, dan QR/barcode workflow.
|
||||
|
||||
Target utamanya:
|
||||
- mudah dibangun bertahap
|
||||
- mudah dipahami tim frontend
|
||||
- mobile-friendly untuk flow gudang
|
||||
- scalable untuk modul traceability dan reporting
|
||||
|
||||
## 2. Rekomendasi Stack
|
||||
- Next.js / React
|
||||
- TypeScript
|
||||
- Tailwind CSS
|
||||
- shadcn/ui atau komponen serupa
|
||||
- TanStack Query untuk server state
|
||||
- Zustand atau Redux Toolkit untuk local workflow state yang kompleks
|
||||
- React Hook Form + Zod untuk form
|
||||
- Data table component untuk list/listing besar
|
||||
- QR scanner berbasis camera API di mobile web
|
||||
|
||||
## 3. Struktur Folder Tingkat Atas
|
||||
```text
|
||||
src/
|
||||
app/
|
||||
components/
|
||||
features/
|
||||
lib/
|
||||
hooks/
|
||||
services/
|
||||
types/
|
||||
store/
|
||||
utils/
|
||||
config/
|
||||
```
|
||||
|
||||
## 4. Struktur app/routes
|
||||
```text
|
||||
src/app/
|
||||
login/
|
||||
page.tsx
|
||||
dashboard/
|
||||
page.tsx
|
||||
suppliers/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
[id]/bank/page.tsx
|
||||
customers/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
[id]/bank/page.tsx
|
||||
item-types/
|
||||
page.tsx
|
||||
item-grades/
|
||||
page.tsx
|
||||
warehouses/
|
||||
page.tsx
|
||||
[id]/page.tsx
|
||||
purchases/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
[id]/edit/page.tsx
|
||||
receipts/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
lots/
|
||||
page.tsx
|
||||
[id]/page.tsx
|
||||
[id]/trace/page.tsx
|
||||
sorting/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
regrade/
|
||||
new/page.tsx
|
||||
sales/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
[id]/page.tsx
|
||||
[id]/allocation/page.tsx
|
||||
[id]/picking/page.tsx
|
||||
adjustments/
|
||||
page.tsx
|
||||
new/page.tsx
|
||||
returns/
|
||||
sales/page.tsx
|
||||
purchase/page.tsx
|
||||
barcode/
|
||||
scan/page.tsx
|
||||
lookup/page.tsx
|
||||
reports/
|
||||
stock-summary/page.tsx
|
||||
stock-lots/page.tsx
|
||||
purchases/page.tsx
|
||||
sales/page.tsx
|
||||
margins/page.tsx
|
||||
shrinkage/page.tsx
|
||||
traceability/page.tsx
|
||||
settings/
|
||||
page.tsx
|
||||
```
|
||||
|
||||
## 5. Struktur Features
|
||||
Setiap domain besar sebaiknya punya feature sendiri.
|
||||
|
||||
```text
|
||||
src/features/
|
||||
auth/
|
||||
dashboard/
|
||||
suppliers/
|
||||
customers/
|
||||
item-types/
|
||||
item-grades/
|
||||
warehouses/
|
||||
purchases/
|
||||
receipts/
|
||||
lots/
|
||||
sorting/
|
||||
regrade/
|
||||
sales/
|
||||
allocations/
|
||||
adjustments/
|
||||
returns/
|
||||
barcode/
|
||||
reports/
|
||||
```
|
||||
|
||||
## 6. Contoh Isi Tiap Feature
|
||||
Catatan domain tambahan:
|
||||
- feature suppliers dan customers perlu mendukung field `bank_name` dan `bank_account_number`
|
||||
- halaman detail supplier/customer sebaiknya punya section informasi pembayaran
|
||||
|
||||
Contoh feature purchases:
|
||||
|
||||
```text
|
||||
src/features/purchases/
|
||||
api/
|
||||
get-purchases.ts
|
||||
get-purchase-detail.ts
|
||||
create-purchase.ts
|
||||
update-purchase.ts
|
||||
components/
|
||||
purchase-form.tsx
|
||||
purchase-line-table.tsx
|
||||
purchase-status-badge.tsx
|
||||
purchase-filter.tsx
|
||||
hooks/
|
||||
use-purchase-form.ts
|
||||
use-purchases-query.ts
|
||||
schemas/
|
||||
purchase.schema.ts
|
||||
types/
|
||||
purchase.type.ts
|
||||
```
|
||||
|
||||
Contoh feature sales:
|
||||
|
||||
```text
|
||||
src/features/sales/
|
||||
api/
|
||||
get-sales.ts
|
||||
get-sales-detail.ts
|
||||
create-sales.ts
|
||||
allocate-sales.ts
|
||||
confirm-picking.ts
|
||||
components/
|
||||
sales-form.tsx
|
||||
sales-line-table.tsx
|
||||
allocation-panel.tsx
|
||||
picking-panel.tsx
|
||||
sales-summary-card.tsx
|
||||
hooks/
|
||||
use-sales-form.ts
|
||||
use-allocation.ts
|
||||
use-picking.ts
|
||||
schemas/
|
||||
sales.schema.ts
|
||||
types/
|
||||
sales.type.ts
|
||||
```
|
||||
|
||||
## 7. Shared Components
|
||||
```text
|
||||
src/components/
|
||||
ui/
|
||||
layout/
|
||||
app-shell.tsx
|
||||
sidebar.tsx
|
||||
topbar.tsx
|
||||
mobile-nav.tsx
|
||||
tables/
|
||||
data-table.tsx
|
||||
table-toolbar.tsx
|
||||
forms/
|
||||
form-field.tsx
|
||||
number-input.tsx
|
||||
date-picker.tsx
|
||||
select-async.tsx
|
||||
status/
|
||||
status-badge.tsx
|
||||
stock-badge.tsx
|
||||
cards/
|
||||
metric-card.tsx
|
||||
lot-card.tsx
|
||||
dialogs/
|
||||
confirm-dialog.tsx
|
||||
allocation-dialog.tsx
|
||||
trace-dialog.tsx
|
||||
scanners/
|
||||
qr-scanner.tsx
|
||||
barcode-input.tsx
|
||||
```
|
||||
|
||||
## 8. Services Layer
|
||||
Pisahkan akses API dari komponen.
|
||||
|
||||
```text
|
||||
src/services/
|
||||
api-client.ts
|
||||
auth.service.ts
|
||||
supplier.service.ts
|
||||
purchase.service.ts
|
||||
receipt.service.ts
|
||||
lot.service.ts
|
||||
sorting.service.ts
|
||||
sales.service.ts
|
||||
adjustment.service.ts
|
||||
report.service.ts
|
||||
```
|
||||
|
||||
## 9. Types Layer
|
||||
```text
|
||||
src/types/
|
||||
api.ts
|
||||
auth.ts
|
||||
supplier.ts
|
||||
customer.ts
|
||||
item.ts
|
||||
warehouse.ts
|
||||
purchase.ts
|
||||
receipt.ts
|
||||
lot.ts
|
||||
sorting.ts
|
||||
sales.ts
|
||||
report.ts
|
||||
```
|
||||
|
||||
## 10. State Management
|
||||
### Server state
|
||||
Gunakan TanStack Query untuk:
|
||||
- fetch list
|
||||
- detail view
|
||||
- mutation create/update
|
||||
- invalidate cache
|
||||
|
||||
### Local workflow state
|
||||
Gunakan Zustand/Redux untuk flow kompleks seperti:
|
||||
- sales allocation draft
|
||||
- picking workflow
|
||||
- sorting result draft
|
||||
- scanner temporary state
|
||||
|
||||
## 11. Halaman Paling Kritis
|
||||
### A. Stock Lot List
|
||||
Kebutuhan:
|
||||
- filter kuat
|
||||
- table cepat
|
||||
- klik ke lot detail
|
||||
- status warna
|
||||
|
||||
### B. Lot Detail
|
||||
Kebutuhan:
|
||||
- identitas lot jelas
|
||||
- parent-child relation
|
||||
- movement timeline
|
||||
- link ke sales/purchase/receipt
|
||||
- aksi cepat hold/release/regrade/transfer
|
||||
|
||||
### C. Allocation Screen
|
||||
Kebutuhan:
|
||||
- sales line summary di atas
|
||||
- list lot tersedia
|
||||
- qty allocation editor
|
||||
- auto allocate FIFO
|
||||
- kalkulasi total costing real-time
|
||||
- validasi total qty
|
||||
|
||||
### D. Picking Screen
|
||||
Kebutuhan:
|
||||
- scan QR
|
||||
- tampil lot teralokasi
|
||||
- input qty picked aktual
|
||||
- error warning jika beda dari alokasi
|
||||
|
||||
### E. Barcode Lookup Screen
|
||||
Kebutuhan:
|
||||
- buka cepat dari scan
|
||||
- tampil ringkas tapi informatif
|
||||
- tombol ke lot detail
|
||||
|
||||
## 12. Layout dan UX
|
||||
### Desktop
|
||||
Cocok untuk:
|
||||
- dashboard
|
||||
- purchasing
|
||||
- reports
|
||||
- stock table besar
|
||||
|
||||
### Mobile
|
||||
Cocok untuk:
|
||||
- scanning
|
||||
- receiving
|
||||
- picking
|
||||
- transfer lot
|
||||
- quick lot lookup
|
||||
|
||||
Saran:
|
||||
- gunakan responsive layout, bukan dua app terpisah dulu
|
||||
- fokus mobile-first pada layar operasional gudang
|
||||
|
||||
## 13. Form Strategy
|
||||
### Gunakan form section
|
||||
Untuk form besar seperti purchase, receipt, sales:
|
||||
- header section
|
||||
- detail lines section
|
||||
- summary section
|
||||
- actions footer sticky
|
||||
|
||||
### Untuk line items
|
||||
Gunakan editable table atau repeater row.
|
||||
|
||||
## 14. Component Priorities MVP
|
||||
Bangun komponen inti dulu:
|
||||
- app shell
|
||||
- data table
|
||||
- form field library
|
||||
- status badge
|
||||
- QR scanner
|
||||
- allocation panel
|
||||
- movement timeline
|
||||
- lot summary card
|
||||
|
||||
## 15. Flow Antar Halaman
|
||||
### Purchase to Receipt
|
||||
Purchase List -> Purchase Detail -> Create Receipt -> Receipt Detail -> Generate Lots -> Lot Detail
|
||||
|
||||
### Lot to Sorting
|
||||
Lot List -> Lot Detail -> Create Sorting -> Sorting Result -> Child Lot Detail
|
||||
|
||||
### Sales Flow
|
||||
Sales List -> Create Sales -> Allocation Screen -> Picking Screen -> Sales Detail
|
||||
|
||||
### Scan Flow
|
||||
Scan Page -> Lookup Result -> Lot Detail / Picking / Transfer
|
||||
|
||||
## 16. Permissions UI
|
||||
### Owner
|
||||
- read mostly all
|
||||
- no heavy transactional edit by default
|
||||
|
||||
### Purchasing
|
||||
- purchase pages
|
||||
|
||||
### Warehouse
|
||||
- receipt, lots, transfer, adjustment, barcode
|
||||
|
||||
### QC
|
||||
- sorting, regrade
|
||||
|
||||
### Sales
|
||||
- sales, allocation, picking
|
||||
|
||||
UI harus hide action sesuai role.
|
||||
|
||||
## 17. Frontend API Integration Pattern
|
||||
Untuk tiap feature:
|
||||
- query key per list/detail
|
||||
- mutation untuk create/update/action
|
||||
- central error handler
|
||||
- loading skeleton untuk page utama
|
||||
- toast notification untuk success/error
|
||||
|
||||
## 18. Frontend Deliverable yang Bisa Lanjut Dibuat
|
||||
Dari struktur ini, next bisa diturunkan menjadi:
|
||||
- route map detail
|
||||
- component tree per halaman
|
||||
- page-by-page wireframe detail
|
||||
- UI kit token
|
||||
- frontend task breakdown per sprint
|
||||
|
||||
## 19. Rekomendasi Eksekusi
|
||||
Urutan frontend yang paling masuk akal:
|
||||
1. layout + auth
|
||||
2. master data basic pages
|
||||
3. purchase & receipt
|
||||
4. stock lot & lot detail
|
||||
5. sales & allocation
|
||||
6. sorting & regrade
|
||||
7. scanner flow
|
||||
8. reports
|
||||
|
||||
## 20. Kesimpulan
|
||||
Frontend sistem walet ini sebaiknya dibangun modular per feature, dengan lot detail dan allocation flow sebagai pusat desain. Fokus utama harus pada kecepatan operasional gudang dan kejelasan traceability, bukan sekadar tampilan tabel stok biasa.
|
||||
127
docs/project-spec/walet-mock-responses.json
Normal file
127
docs/project-spec/walet-mock-responses.json
Normal file
@ -0,0 +1,127 @@
|
||||
{
|
||||
"login": {
|
||||
"token": "jwt-token-sample",
|
||||
"user": {
|
||||
"id": 5,
|
||||
"name": "Sales Walet",
|
||||
"role": "SALES"
|
||||
}
|
||||
},
|
||||
"lot_detail": {
|
||||
"id": 4,
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"supplier": {
|
||||
"id": 2,
|
||||
"code": "SUP-B",
|
||||
"name": "Supplier B",
|
||||
"bank_name": "Mandiri",
|
||||
"bank_account_number": "9876543210"
|
||||
},
|
||||
"item_type": {
|
||||
"id": 1,
|
||||
"code": "JNS-A",
|
||||
"name": "Jenis A"
|
||||
},
|
||||
"item_grade": {
|
||||
"id": 1,
|
||||
"code": "GRD-A",
|
||||
"name": "Grade A"
|
||||
},
|
||||
"original_qty": 18,
|
||||
"available_qty": 8,
|
||||
"reserved_qty": 0,
|
||||
"unit_cost": 17500000,
|
||||
"warehouse": {
|
||||
"id": 1,
|
||||
"name": "Gudang Pusat"
|
||||
},
|
||||
"location": {
|
||||
"id": 1,
|
||||
"name": "Rak A1"
|
||||
},
|
||||
"status": "ACTIVE",
|
||||
"qr_code_value": "LOT-260428-SUPB-001-S1"
|
||||
},
|
||||
"sales_detail": {
|
||||
"id": 1,
|
||||
"sales_no": "SLS-20260428-001",
|
||||
"customer": {
|
||||
"id": 1,
|
||||
"name": "Customer A",
|
||||
"bank_name": "BRI",
|
||||
"bank_account_number": "111222333444"
|
||||
},
|
||||
"sales_date": "2026-04-28",
|
||||
"status": "CONFIRMED",
|
||||
"lines": [
|
||||
{
|
||||
"id": 1,
|
||||
"item_type": "Jenis A",
|
||||
"item_grade": "Grade A",
|
||||
"qty_sold": 30,
|
||||
"selling_price": 22000000,
|
||||
"subtotal": 660000000,
|
||||
"costing_total": 550000000,
|
||||
"gross_margin": 110000000,
|
||||
"allocations": [
|
||||
{
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"qty_allocated": 20,
|
||||
"unit_cost": 18000000,
|
||||
"total_cost": 360000000
|
||||
},
|
||||
{
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"supplier": "Supplier B",
|
||||
"qty_allocated": 10,
|
||||
"unit_cost": 19000000,
|
||||
"total_cost": 190000000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"barcode_lookup": {
|
||||
"lot_id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"item_type": "Jenis A",
|
||||
"grade": "Grade A",
|
||||
"available_qty": 30,
|
||||
"warehouse": "Gudang Pusat",
|
||||
"location": "Rak A1",
|
||||
"status": "ACTIVE",
|
||||
"trace_summary": {
|
||||
"purchase_no": "PO-20260428-001",
|
||||
"used_in_sales": [
|
||||
"SLS-20260428-001"
|
||||
]
|
||||
}
|
||||
},
|
||||
"traceability_report": {
|
||||
"sales_no": "SLS-20260428-001",
|
||||
"customer": "Customer A",
|
||||
"lines": [
|
||||
{
|
||||
"item": "Jenis A / Grade A",
|
||||
"qty": 30,
|
||||
"sources": [
|
||||
{
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"qty": 20,
|
||||
"purchase_no": "PO-20260428-001"
|
||||
},
|
||||
{
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"supplier": "Supplier B",
|
||||
"qty": 10,
|
||||
"purchase_no": "PO-20260428-002",
|
||||
"parent_lot": "LOT-260428-SUPB-001"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
164
docs/project-spec/walet-notification-approval-flow.md
Normal file
164
docs/project-spec/walet-notification-approval-flow.md
Normal file
@ -0,0 +1,164 @@
|
||||
# Notification dan Approval Flow Sistem Inventory Walet
|
||||
|
||||
## 1. Tujuan
|
||||
Dokumen ini mendefinisikan event penting yang layak memicu notifikasi atau approval agar kontrol bisnis lebih baik tanpa membuat operasional terlalu lambat.
|
||||
|
||||
## 2. Prinsip
|
||||
- tidak semua transaksi perlu approval
|
||||
- approval dipakai untuk aksi berisiko tinggi
|
||||
- notifikasi dipakai untuk awareness dan respons cepat
|
||||
- approval tidak boleh menghambat proses gudang rutin yang volumenya tinggi
|
||||
|
||||
## 3. Event Notifikasi yang Direkomendasikan
|
||||
### A. Purchase Submitted
|
||||
Notifikasi ke:
|
||||
- Owner
|
||||
- Purchasing supervisor jika ada
|
||||
|
||||
Isi:
|
||||
- nomor pembelian
|
||||
- supplier
|
||||
- total nilai
|
||||
- jumlah line
|
||||
|
||||
### B. Receipt Finalized
|
||||
Notifikasi ke:
|
||||
- Owner opsional
|
||||
- Gudang lead
|
||||
- Purchasing
|
||||
|
||||
Isi:
|
||||
- nomor receipt
|
||||
- supplier
|
||||
- jumlah lot terbentuk
|
||||
- ada/tidak selisih
|
||||
|
||||
### C. Large Shrinkage / Adjustment
|
||||
Notifikasi ke:
|
||||
- Owner
|
||||
- Gudang lead
|
||||
- QC lead jika terkait kualitas
|
||||
|
||||
Trigger contoh:
|
||||
- shrinkage di atas threshold
|
||||
- cost impact di atas threshold
|
||||
|
||||
### D. Regrade Event
|
||||
Notifikasi ke:
|
||||
- Owner opsional
|
||||
- QC lead
|
||||
- Sales opsional jika pengaruh ke order aktif
|
||||
|
||||
### E. Sales Allocation Conflict
|
||||
Notifikasi ke:
|
||||
- Sales
|
||||
- Gudang
|
||||
|
||||
Trigger:
|
||||
- stok kurang
|
||||
- lot hold terpilih
|
||||
- qty dialokasikan bentrok
|
||||
|
||||
### F. Picking Variance
|
||||
Notifikasi ke:
|
||||
- Sales
|
||||
- Gudang
|
||||
|
||||
Trigger:
|
||||
- qty picked beda dari qty allocated
|
||||
|
||||
### G. Lot Hold / Release
|
||||
Notifikasi ke:
|
||||
- Gudang
|
||||
- QC
|
||||
- Sales jika lot terkait order aktif
|
||||
|
||||
## 4. Approval Flow yang Direkomendasikan
|
||||
### A. Purchase Approval
|
||||
Kapan perlu:
|
||||
- nilai pembelian di atas limit tertentu
|
||||
- supplier baru
|
||||
- harga beli di atas toleransi historis
|
||||
|
||||
Approver:
|
||||
- Owner
|
||||
- Purchasing manager
|
||||
|
||||
### B. Adjustment Approval
|
||||
Kapan perlu:
|
||||
- qty adjustment besar
|
||||
- cost impact besar
|
||||
- reason sensitif seperti loss/missing
|
||||
|
||||
Approver:
|
||||
- Gudang lead atau Owner
|
||||
|
||||
### C. Regrade Approval
|
||||
Kapan perlu:
|
||||
- downgrade signifikan bernilai besar
|
||||
- lot terkait order customer aktif
|
||||
|
||||
Approver:
|
||||
- QC lead / Owner
|
||||
|
||||
### D. Sales Override Approval
|
||||
Kapan perlu:
|
||||
- manual override dari policy FIFO
|
||||
- memakai lot non-prioritas
|
||||
- allow oversell draft exception
|
||||
|
||||
Approver:
|
||||
- Sales lead / Owner
|
||||
|
||||
## 5. Threshold yang Bisa Diatur
|
||||
Contoh parameter konfigurasi:
|
||||
- purchase_approval_amount_threshold
|
||||
- adjustment_qty_threshold
|
||||
- adjustment_cost_threshold
|
||||
- shrinkage_percent_threshold
|
||||
- regrade_qty_threshold
|
||||
- manual_override_requires_approval
|
||||
|
||||
## 6. Status Workflow Tambahan yang Bisa Dipakai
|
||||
### Purchase
|
||||
- DRAFT
|
||||
- PENDING_APPROVAL
|
||||
- SUBMITTED
|
||||
- APPROVED
|
||||
- CANCELLED
|
||||
|
||||
### Adjustment
|
||||
- DRAFT
|
||||
- PENDING_APPROVAL
|
||||
- APPROVED
|
||||
- POSTED
|
||||
- REJECTED
|
||||
|
||||
### Regrade
|
||||
- DRAFT
|
||||
- PENDING_APPROVAL
|
||||
- APPROVED
|
||||
- EXECUTED
|
||||
- REJECTED
|
||||
|
||||
## 7. UI Flow Sederhana
|
||||
### Purchase approval
|
||||
- purchasing submit purchase
|
||||
- jika melewati threshold -> status PENDING_APPROVAL
|
||||
- owner approve/reject
|
||||
- jika approve -> lanjut SUBMITTED
|
||||
|
||||
### Adjustment approval
|
||||
- gudang buat adjustment
|
||||
- jika kecil -> langsung POSTED
|
||||
- jika besar -> PENDING_APPROVAL
|
||||
- approver setujui -> POSTED
|
||||
|
||||
## 8. Notifikasi Channel
|
||||
MVP cukup dukung:
|
||||
- in-app notification
|
||||
- email optional
|
||||
- WhatsApp internal opsional nanti kalau dibutuhkan
|
||||
|
||||
## 9. Kesimpulan
|
||||
Approval dan notifikasi harus fokus ke transaksi berisiko tinggi, bukan semua transaksi. Dengan begitu sistem tetap lincah untuk operasional harian, tapi owner tetap punya kontrol di titik-titik penting.
|
||||
722
docs/project-spec/walet-openapi.yaml
Normal file
722
docs/project-spec/walet-openapi.yaml
Normal file
@ -0,0 +1,722 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Walet Inventory API
|
||||
version: 1.0.0
|
||||
description: API untuk sistem inventory sarang burung walet berbasis lot, traceability, sorting, dan partial sales allocation.
|
||||
servers:
|
||||
- url: /api/v1
|
||||
paths:
|
||||
/auth/login:
|
||||
post:
|
||||
summary: Login
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email, password]
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Login success
|
||||
/suppliers:
|
||||
get:
|
||||
summary: List suppliers
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
code: { type: string }
|
||||
name: { type: string }
|
||||
phone: { type: string }
|
||||
email: { type: string }
|
||||
bank_name: { type: string }
|
||||
bank_account_number: { type: string }
|
||||
address: { type: string }
|
||||
post:
|
||||
summary: Create supplier
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
bank_name:
|
||||
type: string
|
||||
bank_account_number:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/customers:
|
||||
get:
|
||||
summary: List customers
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
code: { type: string }
|
||||
name: { type: string }
|
||||
phone: { type: string }
|
||||
email: { type: string }
|
||||
bank_name: { type: string }
|
||||
bank_account_number: { type: string }
|
||||
address: { type: string }
|
||||
post:
|
||||
summary: Create customer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
bank_name:
|
||||
type: string
|
||||
bank_account_number:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/item-types:
|
||||
get:
|
||||
summary: List item types
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/item-grades:
|
||||
get:
|
||||
summary: List item grades
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/warehouses:
|
||||
get:
|
||||
summary: List warehouses
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/purchases:
|
||||
get:
|
||||
summary: List purchases
|
||||
parameters:
|
||||
- in: query
|
||||
name: supplier_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: status
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
post:
|
||||
summary: Create purchase
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreatePurchaseRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/purchases/{id}:
|
||||
get:
|
||||
summary: Purchase detail
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/receipts:
|
||||
get:
|
||||
summary: List receipts
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
post:
|
||||
summary: Create receipt
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateReceiptRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/receipts/{id}/generate-lots:
|
||||
post:
|
||||
summary: Generate lots from receipt
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Lots generated
|
||||
/lots:
|
||||
get:
|
||||
summary: List inventory lots
|
||||
parameters:
|
||||
- in: query
|
||||
name: supplier_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: item_type_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: item_grade_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: warehouse_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: status
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/lots/{id}:
|
||||
get:
|
||||
summary: Lot detail
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/lots/{id}/movements:
|
||||
get:
|
||||
summary: Lot movement history
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/lots/{id}/trace:
|
||||
get:
|
||||
summary: Lot traceability detail
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/lots/{id}/hold:
|
||||
post:
|
||||
summary: Hold lot
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Lot held
|
||||
/lots/{id}/release:
|
||||
post:
|
||||
summary: Release lot
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Lot released
|
||||
/lots/{id}/transfer:
|
||||
post:
|
||||
summary: Transfer lot
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
to_warehouse_id:
|
||||
type: integer
|
||||
to_location_id:
|
||||
type: integer
|
||||
qty:
|
||||
type: number
|
||||
notes:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Transfer success
|
||||
/sorting-sessions:
|
||||
get:
|
||||
summary: List sorting sessions
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
post:
|
||||
summary: Create sorting session
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateSortingSessionRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/lots/{id}/regrade:
|
||||
post:
|
||||
summary: Regrade lot
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [target_grade_id, qty, reason_id]
|
||||
properties:
|
||||
target_grade_id:
|
||||
type: integer
|
||||
qty:
|
||||
type: number
|
||||
reason_id:
|
||||
type: integer
|
||||
notes:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Regrade success
|
||||
/sales:
|
||||
get:
|
||||
summary: List sales
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
post:
|
||||
summary: Create sales order
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateSalesRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/sales/{id}:
|
||||
get:
|
||||
summary: Sales detail
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/sales/{id}/allocate:
|
||||
post:
|
||||
summary: Manual allocate lots to sales lines
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AllocateSalesRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Allocation success
|
||||
/sales/{id}/auto-allocate:
|
||||
post:
|
||||
summary: Auto allocate by policy
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
policy:
|
||||
type: string
|
||||
example: FIFO
|
||||
responses:
|
||||
'200':
|
||||
description: Auto allocation success
|
||||
/sales/{id}/confirm-picking:
|
||||
post:
|
||||
summary: Confirm picked quantities
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ConfirmPickingRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Picking confirmed
|
||||
/stock-adjustments:
|
||||
get:
|
||||
summary: List stock adjustments
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
post:
|
||||
summary: Create stock adjustment
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateStockAdjustmentRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/sales-returns:
|
||||
post:
|
||||
summary: Create sales return
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateSalesReturnRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/purchase-returns:
|
||||
post:
|
||||
summary: Create purchase return
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
/barcode/lookup/{value}:
|
||||
get:
|
||||
summary: Lookup lot by barcode or QR value
|
||||
parameters:
|
||||
- in: path
|
||||
name: value
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/stock-summary:
|
||||
get:
|
||||
summary: Stock summary report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/stock-lots:
|
||||
get:
|
||||
summary: Stock lots report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/purchases:
|
||||
get:
|
||||
summary: Purchases report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/sales:
|
||||
get:
|
||||
summary: Sales report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/margins:
|
||||
get:
|
||||
summary: Margin report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/shrinkage:
|
||||
get:
|
||||
summary: Shrinkage report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/supplier-quality:
|
||||
get:
|
||||
summary: Supplier quality report
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/reports/traceability:
|
||||
get:
|
||||
summary: Traceability report
|
||||
parameters:
|
||||
- in: query
|
||||
name: sales_id
|
||||
schema: { type: integer }
|
||||
- in: query
|
||||
name: lot_id
|
||||
schema: { type: integer }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
components:
|
||||
parameters:
|
||||
IdParam:
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
schemas:
|
||||
CreatePurchaseRequest:
|
||||
type: object
|
||||
required: [supplier_id, purchase_date, lines]
|
||||
properties:
|
||||
supplier_id:
|
||||
type: integer
|
||||
purchase_date:
|
||||
type: string
|
||||
format: date
|
||||
supplier_invoice_no:
|
||||
type: string
|
||||
notes:
|
||||
type: string
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [item_type_id, qty_ordered, unit_id, unit_price, classification_status]
|
||||
properties:
|
||||
item_type_id:
|
||||
type: integer
|
||||
item_grade_id:
|
||||
type: integer
|
||||
nullable: true
|
||||
qty_ordered:
|
||||
type: number
|
||||
unit_id:
|
||||
type: integer
|
||||
unit_price:
|
||||
type: number
|
||||
classification_status:
|
||||
type: string
|
||||
CreateReceiptRequest:
|
||||
type: object
|
||||
required: [purchase_id, supplier_id, receipt_date, lines]
|
||||
properties:
|
||||
purchase_id:
|
||||
type: integer
|
||||
supplier_id:
|
||||
type: integer
|
||||
receipt_date:
|
||||
type: string
|
||||
format: date
|
||||
notes:
|
||||
type: string
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [purchase_line_id, item_type_id, qty_received, qty_accepted, unit_id, unit_cost, warehouse_id]
|
||||
properties:
|
||||
purchase_line_id:
|
||||
type: integer
|
||||
item_type_id:
|
||||
type: integer
|
||||
item_grade_id:
|
||||
type: integer
|
||||
nullable: true
|
||||
qty_received:
|
||||
type: number
|
||||
qty_accepted:
|
||||
type: number
|
||||
qty_rejected:
|
||||
type: number
|
||||
unit_id:
|
||||
type: integer
|
||||
unit_cost:
|
||||
type: number
|
||||
warehouse_id:
|
||||
type: integer
|
||||
warehouse_location_id:
|
||||
type: integer
|
||||
CreateSortingSessionRequest:
|
||||
type: object
|
||||
required: [source_lot_id, sorting_date, input_qty, results]
|
||||
properties:
|
||||
source_lot_id:
|
||||
type: integer
|
||||
sorting_date:
|
||||
type: string
|
||||
format: date-time
|
||||
input_qty:
|
||||
type: number
|
||||
shrinkage_qty:
|
||||
type: number
|
||||
notes:
|
||||
type: string
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [item_type_id, item_grade_id, qty_result, unit_cost]
|
||||
properties:
|
||||
item_type_id:
|
||||
type: integer
|
||||
item_grade_id:
|
||||
type: integer
|
||||
qty_result:
|
||||
type: number
|
||||
unit_cost:
|
||||
type: number
|
||||
CreateSalesRequest:
|
||||
type: object
|
||||
required: [customer_id, sales_date, lines]
|
||||
properties:
|
||||
customer_id:
|
||||
type: integer
|
||||
sales_date:
|
||||
type: string
|
||||
format: date
|
||||
notes:
|
||||
type: string
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [item_type_id, item_grade_id, qty_sold, unit_id, selling_price]
|
||||
properties:
|
||||
item_type_id:
|
||||
type: integer
|
||||
item_grade_id:
|
||||
type: integer
|
||||
qty_sold:
|
||||
type: number
|
||||
unit_id:
|
||||
type: integer
|
||||
selling_price:
|
||||
type: number
|
||||
AllocateSalesRequest:
|
||||
type: object
|
||||
required: [lines]
|
||||
properties:
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [sales_line_id, allocations]
|
||||
properties:
|
||||
sales_line_id:
|
||||
type: integer
|
||||
allocations:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [inventory_lot_id, qty_allocated]
|
||||
properties:
|
||||
inventory_lot_id:
|
||||
type: integer
|
||||
qty_allocated:
|
||||
type: number
|
||||
ConfirmPickingRequest:
|
||||
type: object
|
||||
required: [lines]
|
||||
properties:
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [sales_line_id, picked_allocations]
|
||||
properties:
|
||||
sales_line_id:
|
||||
type: integer
|
||||
picked_allocations:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [inventory_lot_id, qty_picked]
|
||||
properties:
|
||||
inventory_lot_id:
|
||||
type: integer
|
||||
qty_picked:
|
||||
type: number
|
||||
CreateStockAdjustmentRequest:
|
||||
type: object
|
||||
required: [inventory_lot_id, adjustment_type, reason_id, qty_change]
|
||||
properties:
|
||||
inventory_lot_id:
|
||||
type: integer
|
||||
adjustment_type:
|
||||
type: string
|
||||
reason_id:
|
||||
type: integer
|
||||
qty_change:
|
||||
type: number
|
||||
notes:
|
||||
type: string
|
||||
CreateSalesReturnRequest:
|
||||
type: object
|
||||
required: [sales_id, customer_id, return_date, lines]
|
||||
properties:
|
||||
sales_id:
|
||||
type: integer
|
||||
customer_id:
|
||||
type: integer
|
||||
return_date:
|
||||
type: string
|
||||
format: date
|
||||
lines:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [sales_line_id, item_type_id, item_grade_id, qty_returned]
|
||||
properties:
|
||||
sales_line_id:
|
||||
type: integer
|
||||
inventory_lot_id:
|
||||
type: integer
|
||||
item_type_id:
|
||||
type: integer
|
||||
item_grade_id:
|
||||
type: integer
|
||||
qty_returned:
|
||||
type: number
|
||||
return_condition:
|
||||
type: string
|
||||
resolution:
|
||||
type: string
|
||||
notes:
|
||||
type: string
|
||||
363
docs/project-spec/walet-postman-collection.json
Normal file
363
docs/project-spec/walet-postman-collection.json
Normal file
@ -0,0 +1,363 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Walet Inventory API",
|
||||
"description": "Postman collection untuk sistem inventory sarang burung walet berbasis lot, traceability, sorting, dan allocation.",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"variable": [
|
||||
{
|
||||
"key": "baseUrl",
|
||||
"value": "http://localhost:3000/api/v1"
|
||||
},
|
||||
{
|
||||
"key": "token",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"item": [
|
||||
{
|
||||
"name": "Auth",
|
||||
"item": [
|
||||
{
|
||||
"name": "Login",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/auth/login",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"email\": \"admin@example.com\",\n \"password\": \"secret\"\n}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Master Data",
|
||||
"item": [
|
||||
{
|
||||
"name": "List Suppliers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/suppliers"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create Supplier",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/suppliers",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"code\": \"SUP-C\",\n \"name\": \"Supplier C\",\n \"phone\": \"081310000003\",\n \"email\": \"sup-c@walet.local\",\n \"bank_name\": \"BCA\",\n \"bank_account_number\": \"333444555666\",\n \"address\": \"Semarang\"\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Customers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/customers"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create Customer",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/customers",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"code\": \"CUST-C\",\n \"name\": \"Customer C\",\n \"phone\": \"081320000003\",\n \"email\": \"cust-c@walet.local\",\n \"bank_name\": \"Mandiri\",\n \"bank_account_number\": \"777888999000\",\n \"address\": \"Yogyakarta\"\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Item Types",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/item-types"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Item Grades",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/item-grades"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Purchasing",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Purchase",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/purchases",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"supplier_id\": 1,\n \"purchase_date\": \"2026-04-28\",\n \"supplier_invoice_no\": \"INV-8891\",\n \"notes\": \"Pembelian campuran\",\n \"lines\": [\n {\n \"item_type_id\": 1,\n \"item_grade_id\": 1,\n \"qty_ordered\": 50,\n \"unit_id\": 1,\n \"unit_price\": 18000000,\n \"classification_status\": \"FINAL\"\n },\n {\n \"item_type_id\": 1,\n \"item_grade_id\": null,\n \"qty_ordered\": 40,\n \"unit_id\": 1,\n \"unit_price\": 17500000,\n \"classification_status\": \"PROVISIONAL\"\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Purchases",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/purchases"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Receiving",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Receipt",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/receipts",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"purchase_id\": 1,\n \"supplier_id\": 1,\n \"receipt_date\": \"2026-04-28\",\n \"notes\": \"Barang diterima baik\",\n \"lines\": [\n {\n \"purchase_line_id\": 1,\n \"item_type_id\": 1,\n \"item_grade_id\": 1,\n \"qty_received\": 50,\n \"qty_accepted\": 50,\n \"qty_rejected\": 0,\n \"unit_id\": 1,\n \"unit_cost\": 18000000,\n \"warehouse_id\": 1,\n \"warehouse_location_id\": 1\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Generate Lots",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/receipts/1/generate-lots"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Inventory Lots",
|
||||
"item": [
|
||||
{
|
||||
"name": "List Lots",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/lots"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Lot Detail",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/lots/1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Lot Trace",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/lots/1/trace"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Sorting & Regrade",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Sorting Session",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/sorting-sessions",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"source_lot_id\": 10,\n \"sorting_date\": \"2026-04-28T15:00:00Z\",\n \"input_qty\": 40,\n \"shrinkage_qty\": 3,\n \"notes\": \"Sortasi batch campuran\",\n \"results\": [\n {\n \"item_type_id\": 1,\n \"item_grade_id\": 1,\n \"qty_result\": 18,\n \"unit_cost\": 17500000\n },\n {\n \"item_type_id\": 1,\n \"item_grade_id\": 2,\n \"qty_result\": 12,\n \"unit_cost\": 17500000\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Regrade Lot",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/lots/1/regrade",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"target_grade_id\": 2,\n \"qty\": 5,\n \"reason_id\": 3,\n \"notes\": \"Turun grade setelah QC\"\n}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Sales",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Sales Order",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/sales",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"customer_id\": 1,\n \"sales_date\": \"2026-04-28\",\n \"notes\": \"Order customer X\",\n \"lines\": [\n {\n \"item_type_id\": 1,\n \"item_grade_id\": 1,\n \"qty_sold\": 30,\n \"unit_id\": 1,\n \"selling_price\": 22000000\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Allocate Sales Lots",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/sales/1/allocate",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"lines\": [\n {\n \"sales_line_id\": 1,\n \"allocations\": [\n {\n \"inventory_lot_id\": 1,\n \"qty_allocated\": 20\n },\n {\n \"inventory_lot_id\": 4,\n \"qty_allocated\": 10\n }\n ]\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Auto Allocate Sales",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/sales/1/auto-allocate",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"policy\": \"FIFO\"\n}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Adjustment & Returns",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Stock Adjustment",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/stock-adjustments",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"inventory_lot_id\": 11,\n \"adjustment_type\": \"SHRINKAGE\",\n \"reason_id\": 1,\n \"qty_change\": -1.2,\n \"notes\": \"Selisih opname\"\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create Sales Return",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" },
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"url": "{{baseUrl}}/sales-returns",
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"sales_id\": 1,\n \"customer_id\": 1,\n \"return_date\": \"2026-04-29\",\n \"lines\": [\n {\n \"sales_line_id\": 1,\n \"inventory_lot_id\": 1,\n \"item_type_id\": 1,\n \"item_grade_id\": 1,\n \"qty_returned\": 2,\n \"return_condition\": \"GOOD\",\n \"resolution\": \"RESTOCK\"\n }\n ]\n}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Barcode & Reports",
|
||||
"item": [
|
||||
{
|
||||
"name": "Barcode Lookup",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/barcode/lookup/LOT-260428-SUPA-001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stock Summary Report",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/reports/stock-summary"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Traceability Report by Sales",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": "{{baseUrl}}/reports/traceability?sales_id=1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
105
docs/project-spec/walet-postman-environment.json
Normal file
105
docs/project-spec/walet-postman-environment.json
Normal file
@ -0,0 +1,105 @@
|
||||
{
|
||||
"id": "9d2b4d2e-0b58-4f8c-9c0e-walet-env-001",
|
||||
"name": "Walet Inventory Local",
|
||||
"values": [
|
||||
{
|
||||
"key": "baseUrl",
|
||||
"value": "http://localhost:3000/api/v1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "token",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "purchaseId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "receiptId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "lotId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "salesId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "salesLineId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "supplierId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "customerId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "warehouseId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "warehouseLocationId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "itemTypeId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "itemGradeId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "unitId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "reasonId",
|
||||
"value": "1",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "barcodeValue",
|
||||
"value": "LOT-260428-SUPA-001",
|
||||
"type": "text",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2026-04-28T16:13:00+07:00",
|
||||
"_postman_exported_using": "OpenClaw Joni"
|
||||
}
|
||||
293
docs/project-spec/walet-prd.html
Normal file
293
docs/project-spec/walet-prd.html
Normal file
@ -0,0 +1,293 @@
|
||||
<!doctype html><html><head><meta charset="utf-8"><style>@page { size:A4; margin:2cm 1.6cm; } body { font-family: Arial, Helvetica, sans-serif; font-size:11pt; line-height:1.55; } pre { white-space: pre-wrap; }</style></head><body><pre># PRD Sistem Inventory Sarang Burung Walet
|
||||
|
||||
## 1. Ringkasan Produk
|
||||
Produk ini adalah sistem inventory sarang burung walet berbasis lot atau batch untuk bisnis perdagangan yang dimulai dari pembelian, bukan produksi. Sistem harus mampu menangani pembelian multi jenis dan multi grade, sortasi internal, penyimpanan lot, penjualan parsial dari banyak lot, costing berbasis allocation nyata, penyusutan per lot, dan traceability penuh dengan dukungan barcode atau QR code.
|
||||
|
||||
## 2. Latar Belakang Masalah
|
||||
Bisnis sarang burung walet memiliki kompleksitas yang tidak bisa ditangani inventory biasa karena:
|
||||
|
||||
- satu pembelian bisa berisi banyak jenis dan grade
|
||||
- barang dari supplier bisa perlu diverifikasi atau disortir ulang
|
||||
- stok akhir harus ditrack per lot
|
||||
- satu penjualan bisa mengambil stok dari beberapa lot berbeda
|
||||
- HPP penjualan harus mengikuti lot yang benar-benar dipakai
|
||||
- penyusutan, kerusakan, regrade, dan retur harus tetap bisa ditelusuri
|
||||
- owner perlu tahu asal barang, margin, dan performa supplier
|
||||
|
||||
## 3. Tujuan Produk
|
||||
Tujuan produk ini:
|
||||
|
||||
- membuat pencatatan pembelian dan penerimaan barang lebih rapi
|
||||
- menjaga traceability dari supplier sampai customer
|
||||
- menghitung costing dan margin secara akurat
|
||||
- mengurangi kehilangan histori lot
|
||||
- memudahkan proses sortasi dan regrade
|
||||
- memberi visibilitas stok per jenis-grade dan per lot
|
||||
- mendukung operasional gudang dengan barcode atau QR scan
|
||||
|
||||
## 4. Ruang Lingkup
|
||||
### In Scope
|
||||
- master data supplier, customer, jenis, grade, gudang, user
|
||||
- pembelian dan penerimaan barang
|
||||
- pembuatan lot/batch
|
||||
- sortasi / klasifikasi / regrade
|
||||
- stok summary dan stok lot
|
||||
- sales order dan allocation lot
|
||||
- movement ledger
|
||||
- shrinkage / adjustment / damage / return
|
||||
- traceability report
|
||||
- barcode / QR label generation dan lookup
|
||||
|
||||
### Out of Scope untuk MVP
|
||||
- akuntansi umum penuh
|
||||
- integrasi marketplace
|
||||
- integrasi IoT
|
||||
- forecasting AI
|
||||
- multi currency kompleks
|
||||
- mobile app native terpisah, jika web mobile sudah cukup
|
||||
|
||||
## 5. User dan Role
|
||||
### Owner / Management
|
||||
Kebutuhan:
|
||||
- melihat dashboard
|
||||
- memantau stok, nilai inventory, margin, susut
|
||||
- melihat traceability dan performa supplier
|
||||
|
||||
### Admin Purchasing
|
||||
Kebutuhan:
|
||||
- membuat pembelian
|
||||
- melihat histori pembelian dan harga beli
|
||||
|
||||
### Admin Gudang
|
||||
Kebutuhan:
|
||||
- menerima barang
|
||||
- membuat dan memindahkan lot
|
||||
- opname dan adjustment
|
||||
- cetak label QR/barcode
|
||||
|
||||
### Tim Sortasi / QC
|
||||
Kebutuhan:
|
||||
- melakukan sortasi
|
||||
- mengubah satu lot menjadi beberapa lot hasil
|
||||
- mencatat susut/reject/regrade
|
||||
|
||||
### Admin Sales
|
||||
Kebutuhan:
|
||||
- membuat sales order
|
||||
- melihat stok tersedia
|
||||
- memilih atau menyesuaikan alokasi lot
|
||||
- memproses picking dan invoice
|
||||
|
||||
## 6. Problem Statement
|
||||
Bagaimana membuat sistem yang mampu mengelola stok sarang walet secara detail sampai level lot, sambil tetap mudah dipakai untuk operasional harian, serta menjaga costing dan traceability tetap akurat walaupun penjualan diambil dari campuran beberapa lot?
|
||||
|
||||
## 7. Product Principles
|
||||
- lot adalah unit traceability utama
|
||||
- stock summary hanya agregasi, bukan sumber kebenaran utama
|
||||
- semua perubahan stok harus masuk movement ledger
|
||||
- costing penjualan harus berbasis alokasi lot nyata
|
||||
- barcode atau QR membantu scan, tetapi sumber trace tetap pada model data
|
||||
- sistem harus mendukung override manual jika operasional lapangan membutuhkannya
|
||||
|
||||
## 8. Business Flow Summary
|
||||
1. master setup
|
||||
2. create purchase
|
||||
3. receive goods
|
||||
4. create lots
|
||||
5. sort or verify if needed
|
||||
6. store and move lots
|
||||
7. sell and allocate lots
|
||||
8. ship and confirm quantity
|
||||
9. handle returns, shrinkage, regrade, adjustment
|
||||
10. monitor reports and traceability
|
||||
|
||||
## 9. Functional Requirements
|
||||
|
||||
### 9.1 Master Data
|
||||
Sistem harus menyediakan CRUD untuk:
|
||||
- suppliers, termasuk data nomor rekening dan nama bank
|
||||
- customers, termasuk data nomor rekening dan nama bank
|
||||
- item types
|
||||
- item grades
|
||||
- warehouses
|
||||
- warehouse locations
|
||||
- users
|
||||
- roles
|
||||
- adjustment reasons
|
||||
- units
|
||||
|
||||
### 9.2 Purchasing
|
||||
Sistem harus bisa:
|
||||
- membuat dokumen pembelian
|
||||
- menyimpan banyak line dalam satu pembelian
|
||||
- menyimpan jenis, grade, qty, harga beli, subtotal
|
||||
- menandai line apakah final atau provisional
|
||||
- menyimpan nomor invoice supplier
|
||||
- menampilkan histori harga beli per jenis-grade
|
||||
|
||||
### 9.3 Receiving
|
||||
Sistem harus bisa:
|
||||
- menerima barang dari pembelian
|
||||
- membandingkan qty ordered vs qty received
|
||||
- mencatat qty accepted dan rejected
|
||||
- membuat lot per receipt line atau per hasil penerimaan
|
||||
- menyimpan cost lot
|
||||
- mencetak QR/barcode label
|
||||
|
||||
### 9.4 Inventory Lot
|
||||
Sistem harus bisa:
|
||||
- menampilkan stok per lot
|
||||
- menampilkan stok summary per jenis-grade
|
||||
- menandai lot aktif, hold, closed, rejected
|
||||
- menyimpan parent-child lot
|
||||
- menyimpan gudang dan lokasi simpan
|
||||
- menampilkan aging lot
|
||||
|
||||
### 9.5 Sorting / Classification / Regrade
|
||||
Sistem harus bisa:
|
||||
- membuat sorting session dari source lot
|
||||
- menghasilkan banyak lot baru dari satu lot asal
|
||||
- mencatat qty input, qty output, dan shrinkage
|
||||
- melakukan regrade dari satu grade ke grade lain
|
||||
- mencatat reject
|
||||
|
||||
### 9.6 Sales
|
||||
Sistem harus bisa:
|
||||
- membuat sales order
|
||||
- menambah sales lines per jenis-grade
|
||||
- menampilkan stok tersedia
|
||||
- mengalokasikan kebutuhan sales line ke satu atau banyak lot
|
||||
- mendukung alokasi otomatis dan manual
|
||||
- menghitung costing_total dan gross_margin
|
||||
|
||||
### 9.7 Allocation Engine
|
||||
Sistem harus bisa:
|
||||
- memberi rekomendasi lot berdasarkan FIFO
|
||||
- memungkinkan override manual
|
||||
- menghitung total cost dari setiap allocation
|
||||
- memastikan qty allocation tidak melebihi stok available
|
||||
|
||||
### 9.8 Inventory Movement Ledger
|
||||
Sistem harus mencatat semua mutasi:
|
||||
- receipt in
|
||||
- sorting out/in
|
||||
- sales out
|
||||
- return in/out
|
||||
- transfer in/out
|
||||
- shrinkage
|
||||
- adjustment
|
||||
- regrade out/in
|
||||
|
||||
### 9.9 Returns & Adjustments
|
||||
Sistem harus bisa:
|
||||
- mencatat retur pembelian
|
||||
- mencatat retur penjualan
|
||||
- mencatat adjustment stok
|
||||
- mencatat damage dan shrinkage
|
||||
- mengaitkan semua ke lot tertentu
|
||||
|
||||
### 9.10 Traceability
|
||||
Sistem harus menyediakan:
|
||||
- backward trace, dari sales ke supplier
|
||||
- forward trace, dari supplier/lot ke customer
|
||||
- histori proses lot, termasuk sorting, regrade, transfer, shrinkage, sales
|
||||
|
||||
### 9.11 Barcode / QR
|
||||
Sistem harus bisa:
|
||||
- generate label QR/barcode untuk lot
|
||||
- print ulang label
|
||||
- scan lot untuk lookup data
|
||||
- scan saat transfer, picking, dan stock opname
|
||||
|
||||
## 10. Non-Functional Requirements
|
||||
- web-based dan mobile-friendly
|
||||
- audit trail untuk transaksi penting
|
||||
- performa query stok dan lot harus cepat
|
||||
- akses berbasis role
|
||||
- histori tidak boleh hilang walau lot sudah closed
|
||||
- data harus siap diekspor
|
||||
|
||||
## 11. Costing Rules
|
||||
- unit cost utama disimpan per lot
|
||||
- costing sales line dihitung dari gabungan allocation nyata
|
||||
- default allocation policy adalah FIFO
|
||||
- sistem boleh mendukung FEFO/manual/hybrid
|
||||
- shrinkage mengurangi qty dan memengaruhi balance lot
|
||||
- regrade harus memindahkan qty dan histori cost dengan jelas
|
||||
|
||||
## 12. Traceability Rules
|
||||
### Backward Trace
|
||||
sales -> sales_allocations -> inventory_lots -> receipt_lines -> purchase_lines -> purchases -> suppliers
|
||||
|
||||
### Forward Trace
|
||||
suppliers -> purchases -> inventory_lots -> sales_allocations -> sales_lines -> sales -> customers
|
||||
|
||||
### Process Trace
|
||||
inventory_lots -> sorting_sessions -> sorting_results -> stock_adjustments -> inventory_movements
|
||||
|
||||
## 13. Key Screens
|
||||
- Dashboard
|
||||
- Purchase List
|
||||
- Purchase Detail/Form
|
||||
- Receipt Form
|
||||
- Receipt Detail
|
||||
- Stock Summary
|
||||
- Stock Lot List
|
||||
- Lot Detail
|
||||
- Sorting Session Form
|
||||
- Sales Form
|
||||
- Allocation Screen
|
||||
- Picking Screen
|
||||
- Adjustment Form
|
||||
- Regrade Form
|
||||
- Barcode Lookup
|
||||
- Reports
|
||||
|
||||
## 14. KPI / Success Metrics
|
||||
- akurasi stok per lot
|
||||
- kecepatan trace dari penjualan ke supplier
|
||||
- penurunan selisih opname
|
||||
- akurasi HPP penjualan
|
||||
- kecepatan receiving dan picking
|
||||
- visibilitas susut per lot dan supplier
|
||||
|
||||
## 15. MVP Recommendation
|
||||
### Phase 1
|
||||
- master data
|
||||
- purchasing
|
||||
- receiving
|
||||
- inventory lot
|
||||
- stock summary
|
||||
- sales
|
||||
- sales allocation
|
||||
- movement ledger
|
||||
- QR label dasar
|
||||
|
||||
### Phase 2
|
||||
- sorting
|
||||
- regrade
|
||||
- stock adjustment detail
|
||||
- transfer gudang
|
||||
- stock opname scan
|
||||
|
||||
### Phase 3
|
||||
- analytics supplier quality
|
||||
- analytics margin dan shrinkage
|
||||
- mobile scanner workflow lebih maju
|
||||
- smarter allocation engine
|
||||
|
||||
## 16. Risiko Implementasi
|
||||
- user ingin proses cepat tetapi model data kompleks
|
||||
- salah desain costing akan merusak laporan margin
|
||||
- jika lot discipline tidak dijaga, traceability rusak
|
||||
- jika QR hanya kosmetik tanpa lot discipline, manfaatnya kecil
|
||||
|
||||
## 17. Keputusan Produk yang Direkomendasikan
|
||||
- jadikan lot sebagai sumber kebenaran traceability
|
||||
- pakai stock summary hanya sebagai view agregat
|
||||
- gunakan FIFO default dengan override manual
|
||||
- pakai QR code di level lot
|
||||
- prioritaskan lot detail, allocation, dan movement ledger di fase awal
|
||||
|
||||
## 18. Kesimpulan
|
||||
Produk ini adalah sistem inventory walet yang berorientasi pada lot, costing akurat, dan traceability penuh. Dengan desain ini, bisnis dapat mengelola pembelian multi jenis-grade, sortasi, penjualan campuran, susut, dan audit histori secara jauh lebih aman dibanding inventory biasa.</pre></body></html>
|
||||
293
docs/project-spec/walet-prd.md
Normal file
293
docs/project-spec/walet-prd.md
Normal file
@ -0,0 +1,293 @@
|
||||
# PRD Sistem Inventory Sarang Burung Walet
|
||||
|
||||
## 1. Ringkasan Produk
|
||||
Produk ini adalah sistem inventory sarang burung walet berbasis lot atau batch untuk bisnis perdagangan yang dimulai dari pembelian, bukan produksi. Sistem harus mampu menangani pembelian multi jenis dan multi grade, sortasi internal, penyimpanan lot, penjualan parsial dari banyak lot, costing berbasis allocation nyata, penyusutan per lot, dan traceability penuh dengan dukungan barcode atau QR code.
|
||||
|
||||
## 2. Latar Belakang Masalah
|
||||
Bisnis sarang burung walet memiliki kompleksitas yang tidak bisa ditangani inventory biasa karena:
|
||||
|
||||
- satu pembelian bisa berisi banyak jenis dan grade
|
||||
- barang dari supplier bisa perlu diverifikasi atau disortir ulang
|
||||
- stok akhir harus ditrack per lot
|
||||
- satu penjualan bisa mengambil stok dari beberapa lot berbeda
|
||||
- HPP penjualan harus mengikuti lot yang benar-benar dipakai
|
||||
- penyusutan, kerusakan, regrade, dan retur harus tetap bisa ditelusuri
|
||||
- owner perlu tahu asal barang, margin, dan performa supplier
|
||||
|
||||
## 3. Tujuan Produk
|
||||
Tujuan produk ini:
|
||||
|
||||
- membuat pencatatan pembelian dan penerimaan barang lebih rapi
|
||||
- menjaga traceability dari supplier sampai customer
|
||||
- menghitung costing dan margin secara akurat
|
||||
- mengurangi kehilangan histori lot
|
||||
- memudahkan proses sortasi dan regrade
|
||||
- memberi visibilitas stok per jenis-grade dan per lot
|
||||
- mendukung operasional gudang dengan barcode atau QR scan
|
||||
|
||||
## 4. Ruang Lingkup
|
||||
### In Scope
|
||||
- master data supplier, customer, jenis, grade, gudang, user
|
||||
- pembelian dan penerimaan barang
|
||||
- pembuatan lot/batch
|
||||
- sortasi / klasifikasi / regrade
|
||||
- stok summary dan stok lot
|
||||
- sales order dan allocation lot
|
||||
- movement ledger
|
||||
- shrinkage / adjustment / damage / return
|
||||
- traceability report
|
||||
- barcode / QR label generation dan lookup
|
||||
|
||||
### Out of Scope untuk MVP
|
||||
- akuntansi umum penuh
|
||||
- integrasi marketplace
|
||||
- integrasi IoT
|
||||
- forecasting AI
|
||||
- multi currency kompleks
|
||||
- mobile app native terpisah, jika web mobile sudah cukup
|
||||
|
||||
## 5. User dan Role
|
||||
### Owner / Management
|
||||
Kebutuhan:
|
||||
- melihat dashboard
|
||||
- memantau stok, nilai inventory, margin, susut
|
||||
- melihat traceability dan performa supplier
|
||||
|
||||
### Admin Purchasing
|
||||
Kebutuhan:
|
||||
- membuat pembelian
|
||||
- melihat histori pembelian dan harga beli
|
||||
|
||||
### Admin Gudang
|
||||
Kebutuhan:
|
||||
- menerima barang
|
||||
- membuat dan memindahkan lot
|
||||
- opname dan adjustment
|
||||
- cetak label QR/barcode
|
||||
|
||||
### Tim Sortasi / QC
|
||||
Kebutuhan:
|
||||
- melakukan sortasi
|
||||
- mengubah satu lot menjadi beberapa lot hasil
|
||||
- mencatat susut/reject/regrade
|
||||
|
||||
### Admin Sales
|
||||
Kebutuhan:
|
||||
- membuat sales order
|
||||
- melihat stok tersedia
|
||||
- memilih atau menyesuaikan alokasi lot
|
||||
- memproses picking dan invoice
|
||||
|
||||
## 6. Problem Statement
|
||||
Bagaimana membuat sistem yang mampu mengelola stok sarang walet secara detail sampai level lot, sambil tetap mudah dipakai untuk operasional harian, serta menjaga costing dan traceability tetap akurat walaupun penjualan diambil dari campuran beberapa lot?
|
||||
|
||||
## 7. Product Principles
|
||||
- lot adalah unit traceability utama
|
||||
- stock summary hanya agregasi, bukan sumber kebenaran utama
|
||||
- semua perubahan stok harus masuk movement ledger
|
||||
- costing penjualan harus berbasis alokasi lot nyata
|
||||
- barcode atau QR membantu scan, tetapi sumber trace tetap pada model data
|
||||
- sistem harus mendukung override manual jika operasional lapangan membutuhkannya
|
||||
|
||||
## 8. Business Flow Summary
|
||||
1. master setup
|
||||
2. create purchase
|
||||
3. receive goods
|
||||
4. create lots
|
||||
5. sort or verify if needed
|
||||
6. store and move lots
|
||||
7. sell and allocate lots
|
||||
8. ship and confirm quantity
|
||||
9. handle returns, shrinkage, regrade, adjustment
|
||||
10. monitor reports and traceability
|
||||
|
||||
## 9. Functional Requirements
|
||||
|
||||
### 9.1 Master Data
|
||||
Sistem harus menyediakan CRUD untuk:
|
||||
- suppliers, termasuk data nomor rekening dan nama bank
|
||||
- customers, termasuk data nomor rekening dan nama bank
|
||||
- item types
|
||||
- item grades
|
||||
- warehouses
|
||||
- warehouse locations
|
||||
- users
|
||||
- roles
|
||||
- adjustment reasons
|
||||
- units
|
||||
|
||||
### 9.2 Purchasing
|
||||
Sistem harus bisa:
|
||||
- membuat dokumen pembelian
|
||||
- menyimpan banyak line dalam satu pembelian
|
||||
- menyimpan jenis, grade, qty, harga beli, subtotal
|
||||
- menandai line apakah final atau provisional
|
||||
- menyimpan nomor invoice supplier
|
||||
- menampilkan histori harga beli per jenis-grade
|
||||
|
||||
### 9.3 Receiving
|
||||
Sistem harus bisa:
|
||||
- menerima barang dari pembelian
|
||||
- membandingkan qty ordered vs qty received
|
||||
- mencatat qty accepted dan rejected
|
||||
- membuat lot per receipt line atau per hasil penerimaan
|
||||
- menyimpan cost lot
|
||||
- mencetak QR/barcode label
|
||||
|
||||
### 9.4 Inventory Lot
|
||||
Sistem harus bisa:
|
||||
- menampilkan stok per lot
|
||||
- menampilkan stok summary per jenis-grade
|
||||
- menandai lot aktif, hold, closed, rejected
|
||||
- menyimpan parent-child lot
|
||||
- menyimpan gudang dan lokasi simpan
|
||||
- menampilkan aging lot
|
||||
|
||||
### 9.5 Sorting / Classification / Regrade
|
||||
Sistem harus bisa:
|
||||
- membuat sorting session dari source lot
|
||||
- menghasilkan banyak lot baru dari satu lot asal
|
||||
- mencatat qty input, qty output, dan shrinkage
|
||||
- melakukan regrade dari satu grade ke grade lain
|
||||
- mencatat reject
|
||||
|
||||
### 9.6 Sales
|
||||
Sistem harus bisa:
|
||||
- membuat sales order
|
||||
- menambah sales lines per jenis-grade
|
||||
- menampilkan stok tersedia
|
||||
- mengalokasikan kebutuhan sales line ke satu atau banyak lot
|
||||
- mendukung alokasi otomatis dan manual
|
||||
- menghitung costing_total dan gross_margin
|
||||
|
||||
### 9.7 Allocation Engine
|
||||
Sistem harus bisa:
|
||||
- memberi rekomendasi lot berdasarkan FIFO
|
||||
- memungkinkan override manual
|
||||
- menghitung total cost dari setiap allocation
|
||||
- memastikan qty allocation tidak melebihi stok available
|
||||
|
||||
### 9.8 Inventory Movement Ledger
|
||||
Sistem harus mencatat semua mutasi:
|
||||
- receipt in
|
||||
- sorting out/in
|
||||
- sales out
|
||||
- return in/out
|
||||
- transfer in/out
|
||||
- shrinkage
|
||||
- adjustment
|
||||
- regrade out/in
|
||||
|
||||
### 9.9 Returns & Adjustments
|
||||
Sistem harus bisa:
|
||||
- mencatat retur pembelian
|
||||
- mencatat retur penjualan
|
||||
- mencatat adjustment stok
|
||||
- mencatat damage dan shrinkage
|
||||
- mengaitkan semua ke lot tertentu
|
||||
|
||||
### 9.10 Traceability
|
||||
Sistem harus menyediakan:
|
||||
- backward trace, dari sales ke supplier
|
||||
- forward trace, dari supplier/lot ke customer
|
||||
- histori proses lot, termasuk sorting, regrade, transfer, shrinkage, sales
|
||||
|
||||
### 9.11 Barcode / QR
|
||||
Sistem harus bisa:
|
||||
- generate label QR/barcode untuk lot
|
||||
- print ulang label
|
||||
- scan lot untuk lookup data
|
||||
- scan saat transfer, picking, dan stock opname
|
||||
|
||||
## 10. Non-Functional Requirements
|
||||
- web-based dan mobile-friendly
|
||||
- audit trail untuk transaksi penting
|
||||
- performa query stok dan lot harus cepat
|
||||
- akses berbasis role
|
||||
- histori tidak boleh hilang walau lot sudah closed
|
||||
- data harus siap diekspor
|
||||
|
||||
## 11. Costing Rules
|
||||
- unit cost utama disimpan per lot
|
||||
- costing sales line dihitung dari gabungan allocation nyata
|
||||
- default allocation policy adalah FIFO
|
||||
- sistem boleh mendukung FEFO/manual/hybrid
|
||||
- shrinkage mengurangi qty dan memengaruhi balance lot
|
||||
- regrade harus memindahkan qty dan histori cost dengan jelas
|
||||
|
||||
## 12. Traceability Rules
|
||||
### Backward Trace
|
||||
sales -> sales_allocations -> inventory_lots -> receipt_lines -> purchase_lines -> purchases -> suppliers
|
||||
|
||||
### Forward Trace
|
||||
suppliers -> purchases -> inventory_lots -> sales_allocations -> sales_lines -> sales -> customers
|
||||
|
||||
### Process Trace
|
||||
inventory_lots -> sorting_sessions -> sorting_results -> stock_adjustments -> inventory_movements
|
||||
|
||||
## 13. Key Screens
|
||||
- Dashboard
|
||||
- Purchase List
|
||||
- Purchase Detail/Form
|
||||
- Receipt Form
|
||||
- Receipt Detail
|
||||
- Stock Summary
|
||||
- Stock Lot List
|
||||
- Lot Detail
|
||||
- Sorting Session Form
|
||||
- Sales Form
|
||||
- Allocation Screen
|
||||
- Picking Screen
|
||||
- Adjustment Form
|
||||
- Regrade Form
|
||||
- Barcode Lookup
|
||||
- Reports
|
||||
|
||||
## 14. KPI / Success Metrics
|
||||
- akurasi stok per lot
|
||||
- kecepatan trace dari penjualan ke supplier
|
||||
- penurunan selisih opname
|
||||
- akurasi HPP penjualan
|
||||
- kecepatan receiving dan picking
|
||||
- visibilitas susut per lot dan supplier
|
||||
|
||||
## 15. MVP Recommendation
|
||||
### Phase 1
|
||||
- master data
|
||||
- purchasing
|
||||
- receiving
|
||||
- inventory lot
|
||||
- stock summary
|
||||
- sales
|
||||
- sales allocation
|
||||
- movement ledger
|
||||
- QR label dasar
|
||||
|
||||
### Phase 2
|
||||
- sorting
|
||||
- regrade
|
||||
- stock adjustment detail
|
||||
- transfer gudang
|
||||
- stock opname scan
|
||||
|
||||
### Phase 3
|
||||
- analytics supplier quality
|
||||
- analytics margin dan shrinkage
|
||||
- mobile scanner workflow lebih maju
|
||||
- smarter allocation engine
|
||||
|
||||
## 16. Risiko Implementasi
|
||||
- user ingin proses cepat tetapi model data kompleks
|
||||
- salah desain costing akan merusak laporan margin
|
||||
- jika lot discipline tidak dijaga, traceability rusak
|
||||
- jika QR hanya kosmetik tanpa lot discipline, manfaatnya kecil
|
||||
|
||||
## 17. Keputusan Produk yang Direkomendasikan
|
||||
- jadikan lot sebagai sumber kebenaran traceability
|
||||
- pakai stock summary hanya sebagai view agregat
|
||||
- gunakan FIFO default dengan override manual
|
||||
- pakai QR code di level lot
|
||||
- prioritaskan lot detail, allocation, dan movement ledger di fase awal
|
||||
|
||||
## 18. Kesimpulan
|
||||
Produk ini adalah sistem inventory walet yang berorientasi pada lot, costing akurat, dan traceability penuh. Dengan desain ini, bisnis dapat mengelola pembelian multi jenis-grade, sortasi, penjualan campuran, susut, dan audit histori secara jauh lebih aman dibanding inventory biasa.
|
||||
BIN
docs/project-spec/walet-prd.pdf
Normal file
BIN
docs/project-spec/walet-prd.pdf
Normal file
Binary file not shown.
165
docs/project-spec/walet-report-queries.sql
Normal file
165
docs/project-spec/walet-report-queries.sql
Normal file
@ -0,0 +1,165 @@
|
||||
-- 1. Stock summary per jenis-grade-gudang
|
||||
SELECT
|
||||
it.name AS item_type,
|
||||
ig.name AS item_grade,
|
||||
w.name AS warehouse,
|
||||
SUM(il.available_qty) AS qty_total,
|
||||
SUM(il.available_qty * il.unit_cost) AS inventory_value,
|
||||
COUNT(*) FILTER (WHERE il.status = 'ACTIVE') AS active_lot_count
|
||||
FROM inventory_lots il
|
||||
JOIN item_types it ON it.id = il.item_type_id
|
||||
JOIN item_grades ig ON ig.id = il.item_grade_id
|
||||
JOIN warehouses w ON w.id = il.warehouse_id
|
||||
WHERE il.status = 'ACTIVE'
|
||||
GROUP BY it.name, ig.name, w.name
|
||||
ORDER BY it.name, ig.name, w.name;
|
||||
|
||||
-- 2. Stock aging report
|
||||
SELECT
|
||||
il.lot_code,
|
||||
s.name AS supplier,
|
||||
it.name AS item_type,
|
||||
ig.name AS item_grade,
|
||||
il.available_qty,
|
||||
il.unit_cost,
|
||||
il.received_at,
|
||||
DATE_PART('day', NOW() - il.received_at) AS aging_days,
|
||||
il.status
|
||||
FROM inventory_lots il
|
||||
LEFT JOIN suppliers s ON s.id = il.supplier_id
|
||||
JOIN item_types it ON it.id = il.item_type_id
|
||||
JOIN item_grades ig ON ig.id = il.item_grade_id
|
||||
WHERE il.available_qty > 0
|
||||
ORDER BY aging_days DESC;
|
||||
|
||||
-- 3. Purchase history per supplier
|
||||
SELECT
|
||||
p.purchase_no,
|
||||
p.purchase_date,
|
||||
s.name AS supplier,
|
||||
COUNT(pl.id) AS total_lines,
|
||||
SUM(pl.subtotal) AS grand_total
|
||||
FROM purchases p
|
||||
JOIN suppliers s ON s.id = p.supplier_id
|
||||
JOIN purchase_lines pl ON pl.purchase_id = p.id
|
||||
GROUP BY p.id, p.purchase_no, p.purchase_date, s.name
|
||||
ORDER BY p.purchase_date DESC;
|
||||
|
||||
-- 4. Sales margin report
|
||||
SELECT
|
||||
sa.sales_no,
|
||||
sa.sales_date,
|
||||
c.name AS customer,
|
||||
SUM(sl.subtotal) AS sales_total,
|
||||
SUM(sl.costing_total) AS costing_total,
|
||||
SUM(sl.gross_margin) AS gross_margin
|
||||
FROM sales sa
|
||||
JOIN customers c ON c.id = sa.customer_id
|
||||
JOIN sales_lines sl ON sl.sales_id = sa.id
|
||||
GROUP BY sa.id, sa.sales_no, sa.sales_date, c.name
|
||||
ORDER BY sa.sales_date DESC;
|
||||
|
||||
-- 5. Supplier quality report berdasarkan hasil sortasi
|
||||
SELECT
|
||||
sup.name AS supplier,
|
||||
parent.lot_code AS source_lot,
|
||||
ss.input_qty,
|
||||
ss.output_qty,
|
||||
ss.shrinkage_qty,
|
||||
ROUND((ss.output_qty / NULLIF(ss.input_qty, 0)) * 100, 2) AS yield_percent
|
||||
FROM sorting_sessions ss
|
||||
JOIN inventory_lots parent ON parent.id = ss.source_lot_id
|
||||
LEFT JOIN suppliers sup ON sup.id = parent.supplier_id
|
||||
ORDER BY ss.sorting_date DESC;
|
||||
|
||||
-- 6. Shrinkage report
|
||||
SELECT
|
||||
sa.adjustment_no,
|
||||
il.lot_code,
|
||||
sup.name AS supplier,
|
||||
it.name AS item_type,
|
||||
ig.name AS item_grade,
|
||||
ar.name AS reason,
|
||||
sa.qty_before,
|
||||
sa.qty_change,
|
||||
sa.qty_after,
|
||||
sa.cost_impact,
|
||||
sa.adjustment_date
|
||||
FROM stock_adjustments sa
|
||||
JOIN inventory_lots il ON il.id = sa.inventory_lot_id
|
||||
LEFT JOIN suppliers sup ON sup.id = il.supplier_id
|
||||
JOIN item_types it ON it.id = il.item_type_id
|
||||
JOIN item_grades ig ON ig.id = il.item_grade_id
|
||||
JOIN adjustment_reasons ar ON ar.id = sa.reason_id
|
||||
ORDER BY sa.adjustment_date DESC;
|
||||
|
||||
-- 7. Traceability by sales
|
||||
SELECT
|
||||
s.sales_no,
|
||||
c.name AS customer,
|
||||
sl.id AS sales_line_id,
|
||||
it.name AS item_type,
|
||||
ig.name AS item_grade,
|
||||
sl.qty_sold,
|
||||
il.lot_code,
|
||||
sup.name AS supplier,
|
||||
sa.qty_allocated,
|
||||
sa.unit_cost,
|
||||
sa.total_cost,
|
||||
p.purchase_no
|
||||
FROM sales s
|
||||
JOIN customers c ON c.id = s.customer_id
|
||||
JOIN sales_lines sl ON sl.sales_id = s.id
|
||||
JOIN item_types it ON it.id = sl.item_type_id
|
||||
JOIN item_grades ig ON ig.id = sl.item_grade_id
|
||||
JOIN sales_allocations sa ON sa.sales_line_id = sl.id
|
||||
JOIN inventory_lots il ON il.id = sa.inventory_lot_id
|
||||
LEFT JOIN suppliers sup ON sup.id = il.supplier_id
|
||||
LEFT JOIN purchases p ON p.id = il.purchase_id
|
||||
ORDER BY s.sales_no, sl.id, il.lot_code;
|
||||
|
||||
-- 8. Forward trace by lot
|
||||
SELECT
|
||||
il.lot_code,
|
||||
sup.name AS supplier,
|
||||
s.sales_no,
|
||||
c.name AS customer,
|
||||
sa.qty_allocated,
|
||||
sa.total_cost,
|
||||
s.sales_date
|
||||
FROM inventory_lots il
|
||||
JOIN sales_allocations sa ON sa.inventory_lot_id = il.id
|
||||
JOIN sales_lines sl ON sl.id = sa.sales_line_id
|
||||
JOIN sales s ON s.id = sl.sales_id
|
||||
JOIN customers c ON c.id = s.customer_id
|
||||
LEFT JOIN suppliers sup ON sup.id = il.supplier_id
|
||||
ORDER BY il.lot_code, s.sales_date;
|
||||
|
||||
-- 9. Movement ledger per lot
|
||||
SELECT
|
||||
il.lot_code,
|
||||
im.movement_no,
|
||||
im.movement_type,
|
||||
im.qty_in,
|
||||
im.qty_out,
|
||||
im.balance_after,
|
||||
im.unit_cost,
|
||||
im.reference_type,
|
||||
im.reference_id,
|
||||
im.movement_date,
|
||||
u.name AS created_by
|
||||
FROM inventory_movements im
|
||||
JOIN inventory_lots il ON il.id = im.inventory_lot_id
|
||||
JOIN users u ON u.id = im.created_by
|
||||
ORDER BY il.lot_code, im.movement_date;
|
||||
|
||||
-- 10. Top customer by sales value
|
||||
SELECT
|
||||
c.name AS customer,
|
||||
SUM(sl.subtotal) AS total_sales,
|
||||
SUM(sl.gross_margin) AS total_margin
|
||||
FROM sales s
|
||||
JOIN customers c ON c.id = s.customer_id
|
||||
JOIN sales_lines sl ON sl.sales_id = s.id
|
||||
GROUP BY c.name
|
||||
ORDER BY total_sales DESC;
|
||||
159
docs/project-spec/walet-role-permission-matrix.md
Normal file
159
docs/project-spec/walet-role-permission-matrix.md
Normal file
@ -0,0 +1,159 @@
|
||||
# Role Permission Matrix Sistem Inventory Walet
|
||||
|
||||
## 1. Tujuan
|
||||
Dokumen ini mendefinisikan hak akses per role agar implementasi backend, frontend, dan audit trail konsisten.
|
||||
|
||||
## 2. Role Utama
|
||||
- Owner
|
||||
- Admin Purchasing
|
||||
- Admin Gudang
|
||||
- Tim Sortasi / QC
|
||||
- Admin Sales
|
||||
|
||||
## 3. Prinsip Akses
|
||||
- setiap aksi sensitif harus tercatat user-nya
|
||||
- role hanya boleh akses modul yang relevan
|
||||
- owner default lebih banyak read daripada write
|
||||
- aksi yang memengaruhi qty lot harus dibatasi ketat
|
||||
- traceability dan report penting minimal bisa dibaca owner
|
||||
|
||||
## 4. Matrix Hak Akses
|
||||
|
||||
| Modul / Aksi | Owner | Purchasing | Gudang | QC | Sales |
|
||||
|---|---|---|---|---|---|
|
||||
| Lihat Dashboard | Yes | Yes | Yes | Yes | Yes |
|
||||
| Lihat Master Data | Yes | Yes | Yes | Yes | Yes |
|
||||
| Buat/Edit Supplier | Yes | Yes | No | No | No |
|
||||
| Buat/Edit Customer | Yes | No | No | No | Yes |
|
||||
| Buat/Edit Jenis & Grade | Yes | Limited | No | Limited | No |
|
||||
| Buat/Edit Gudang & Lokasi | Yes | No | Yes | No | No |
|
||||
| Buat Pembelian | Yes | Yes | No | No | No |
|
||||
| Edit Draft Pembelian | Yes | Yes | No | No | No |
|
||||
| Submit Pembelian | Yes | Yes | No | No | No |
|
||||
| Cancel Pembelian | Yes | Yes | No | No | No |
|
||||
| Lihat Histori Harga Beli | Yes | Yes | No | No | No |
|
||||
| Buat Receipt | Yes | No | Yes | No | No |
|
||||
| Finalize Receipt | Yes | No | Yes | No | No |
|
||||
| Generate Lot | Yes | No | Yes | No | No |
|
||||
| Print/Reprint Label | Yes | No | Yes | Yes | No |
|
||||
| Lihat Stock Summary | Yes | Yes | Yes | Yes | Yes |
|
||||
| Lihat Stock Lot | Yes | No | Yes | Yes | Yes |
|
||||
| Lihat Lot Detail | Yes | No | Yes | Yes | Yes |
|
||||
| Hold/Release Lot | Yes | No | Yes | Limited | No |
|
||||
| Transfer Lot | Yes | No | Yes | No | No |
|
||||
| Stock Opname | Yes | No | Yes | No | No |
|
||||
| Stock Adjustment | Yes | No | Yes | Limited | No |
|
||||
| Buat Sorting Session | Yes | No | No | Yes | No |
|
||||
| Submit Hasil Sortasi | Yes | No | No | Yes | No |
|
||||
| Regrade Lot | Yes | No | No | Yes | No |
|
||||
| Lihat Traceability | Yes | Limited | Yes | Yes | Yes |
|
||||
| Buat Sales Order | Yes | No | No | No | Yes |
|
||||
| Edit Draft Sales | Yes | No | No | No | Yes |
|
||||
| Allocate Lot ke Sales | Yes | No | No | No | Yes |
|
||||
| Auto Allocate | Yes | No | No | No | Yes |
|
||||
| Confirm Picking | Yes | No | Yes | No | Yes |
|
||||
| Finalize Sales | Yes | No | No | No | Yes |
|
||||
| Buat Sales Return | Yes | No | Yes | No | Yes |
|
||||
| Buat Purchase Return | Yes | Yes | Yes | No | No |
|
||||
| Lihat Reports | Yes | Limited | Limited | Limited | Limited |
|
||||
| Export Reports | Yes | Limited | Limited | Limited | Limited |
|
||||
| Ubah Settings Sistem | Yes | No | No | No | No |
|
||||
| Kelola User & Role | Yes | No | No | No | No |
|
||||
|
||||
## 5. Keterangan Limited
|
||||
Limited berarti akses dibatasi konteks tertentu.
|
||||
|
||||
### Owner
|
||||
- full read
|
||||
- write untuk approval, oversight, dan kondisi pengecualian
|
||||
|
||||
### Purchasing limited pada jenis/grade
|
||||
- boleh usulkan / manage jika memang proses bisnis mengizinkan
|
||||
- idealnya tetap lewat owner/admin utama
|
||||
|
||||
### QC limited pada hold/release atau adjustment
|
||||
- QC bisa memberi rekomendasi
|
||||
- aksi final bisa dibatasi butuh approval gudang/owner jika diinginkan
|
||||
|
||||
### Reports limited
|
||||
Role non-owner hanya melihat laporan relevan:
|
||||
- Purchasing: pembelian, supplier quality sederhana
|
||||
- Gudang: stok, aging, shrinkage operasional
|
||||
- QC: sortasi, regrade, shrinkage
|
||||
- Sales: sales, margin dasar, trace per order
|
||||
|
||||
## 6. Rekomendasi Rule Akses Tambahan
|
||||
### Rule 1
|
||||
Lot CLOSED atau REJECTED tidak bisa dipakai untuk sales allocation.
|
||||
|
||||
### Rule 2
|
||||
Lot HOLD tidak bisa dipicking sampai dilepas.
|
||||
|
||||
### Rule 3
|
||||
Adjustment dengan dampak besar bisa diberi approval tambahan.
|
||||
|
||||
### Rule 4
|
||||
Reprint label harus tercatat siapa yang melakukan.
|
||||
|
||||
### Rule 5
|
||||
Finalize receipt, finalize sales, stock adjustment, regrade, dan sorting submit harus masuk audit log wajib.
|
||||
|
||||
## 7. Audit Log Minimum
|
||||
Aksi yang wajib tercatat:
|
||||
- create/update/cancel purchase
|
||||
- finalize receipt
|
||||
- generate lot
|
||||
- transfer lot
|
||||
- hold/release lot
|
||||
- stock adjustment
|
||||
- sorting submit
|
||||
- regrade
|
||||
- allocation submit
|
||||
- picking confirm
|
||||
- finalize sales
|
||||
- returns
|
||||
- label reprint
|
||||
|
||||
## 8. Frontend Visibility Rules
|
||||
### Owner
|
||||
Lihat semua menu.
|
||||
|
||||
### Purchasing
|
||||
Tampilkan:
|
||||
- dashboard
|
||||
- supplier
|
||||
- purchases
|
||||
- purchase returns
|
||||
- laporan pembelian
|
||||
|
||||
### Gudang
|
||||
Tampilkan:
|
||||
- dashboard
|
||||
- receipts
|
||||
- lots
|
||||
- transfer
|
||||
- stock adjustments
|
||||
- barcode
|
||||
- stock reports
|
||||
|
||||
### QC
|
||||
Tampilkan:
|
||||
- dashboard
|
||||
- lots
|
||||
- sorting
|
||||
- regrade
|
||||
- QC-related reports
|
||||
|
||||
### Sales
|
||||
Tampilkan:
|
||||
- dashboard
|
||||
- customers
|
||||
- sales
|
||||
- allocation
|
||||
- picking
|
||||
- sales returns
|
||||
- traceability lookup
|
||||
- sales reports
|
||||
|
||||
## 9. Kesimpulan
|
||||
Matrix ini menjaga agar sistem tetap aman, jelas, dan sesuai alur kerja nyata. Role paling sensitif terhadap integritas stok adalah Gudang, QC, dan Sales, sehingga semua aksi mereka harus terhubung ke audit trail yang kuat.
|
||||
76
docs/project-spec/walet-sample-transactions.html
Normal file
76
docs/project-spec/walet-sample-transactions.html
Normal file
@ -0,0 +1,76 @@
|
||||
<!doctype html><html lang="id"><head><meta charset="utf-8"><title>Contoh Transaksi End-to-End Walet</title><style>@page { size:A4; margin:2cm 1.6cm; } body { font-family: Arial, Helvetica, sans-serif; color:#222; font-size:11pt; line-height:1.55; } pre { white-space: pre-wrap; font-size:10pt; background:#f7f7f7; border:1px solid #ddd; padding:12px; }</style></head><body><pre># Contoh Transaksi End-to-End Sistem Inventory Walet
|
||||
|
||||
## Skenario 1. Pembelian Multi Jenis Multi Grade
|
||||
Supplier A mengirim:
|
||||
- Jenis A Grade A = 50 kg
|
||||
- Jenis A Grade B = 20 kg
|
||||
- Jenis B Grade A = 15 kg
|
||||
|
||||
Purchase dibuat dengan 3 line.
|
||||
Saat receiving, masing-masing line menjadi lot:
|
||||
- LOT-260428-SPA-001 = Jenis A Grade A 50 kg
|
||||
- LOT-260428-SPA-002 = Jenis A Grade B 20 kg
|
||||
- LOT-260428-SPA-003 = Jenis B Grade A 15 kg
|
||||
|
||||
## Skenario 2. Pembelian Butuh Sortasi
|
||||
Supplier B mengirim barang campur 40 kg.
|
||||
Masuk sebagai:
|
||||
- LOT-260428-SPB-001 = provisional
|
||||
|
||||
Setelah sortasi:
|
||||
- LOT-260428-SPB-001-S1 = Jenis A Grade A 18 kg
|
||||
- LOT-260428-SPB-001-S2 = Jenis A Grade B 12 kg
|
||||
- LOT-260428-SPB-001-S3 = Jenis B Grade A 7 kg
|
||||
- Susut/reject = 3 kg
|
||||
|
||||
## Skenario 3. Penjualan Campuran dari Banyak Lot
|
||||
Customer X membeli:
|
||||
- Jenis A Grade A = 30 kg
|
||||
|
||||
Sistem melihat stok:
|
||||
- LOT-260428-SPA-001 tersedia 50 kg
|
||||
- LOT-260428-SPB-001-S1 tersedia 18 kg
|
||||
|
||||
Allocation:
|
||||
- 20 kg dari LOT-260428-SPA-001
|
||||
- 10 kg dari LOT-260428-SPB-001-S1
|
||||
|
||||
Jika cost:
|
||||
- LOT-260428-SPA-001 = 18.000.000/kg
|
||||
- LOT-260428-SPB-001-S1 = 19.000.000/kg
|
||||
|
||||
HPP line:
|
||||
- 20 x 18.000.000 = 360.000.000
|
||||
- 10 x 19.000.000 = 190.000.000
|
||||
- Total cost = 550.000.000
|
||||
|
||||
## Skenario 4. Regrade
|
||||
Dari LOT-260428-SPA-001, setelah inspeksi ulang:
|
||||
- 5 kg turun dari Grade A menjadi Grade B
|
||||
|
||||
Maka:
|
||||
- lot Grade A dikurangi 5 kg
|
||||
- dibuat lot baru Grade B atau ditambahkan ke lot grade B aktif
|
||||
- ledger mencatat REGRADE_OUT dan REGRADE_IN
|
||||
|
||||
## Skenario 5. Shrinkage
|
||||
Saat stock opname, ditemukan selisih -1.2 kg pada LOT-260428-SPB-001-S2.
|
||||
|
||||
Sistem mencatat:
|
||||
- stock adjustment
|
||||
- reason: SHRINKAGE
|
||||
- qty_before
|
||||
- qty_after
|
||||
- cost impact
|
||||
|
||||
## Skenario 6. Traceability
|
||||
Untuk invoice SLS-001, sistem dapat menampilkan:
|
||||
- 20 kg berasal dari LOT-260428-SPA-001, Supplier A
|
||||
- 10 kg berasal dari LOT-260428-SPB-001-S1, Supplier B
|
||||
|
||||
Untuk LOT-260428-SPA-001, sistem dapat menampilkan:
|
||||
- asal purchase: PO-001
|
||||
- supplier: Supplier A
|
||||
- dipakai di invoice: SLS-001, SLS-004, SLS-006
|
||||
- pernah diregrade: ya/tidak
|
||||
- pernah adjustment: ya/tidak</pre></body></html>
|
||||
76
docs/project-spec/walet-sample-transactions.md
Normal file
76
docs/project-spec/walet-sample-transactions.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Contoh Transaksi End-to-End Sistem Inventory Walet
|
||||
|
||||
## Skenario 1. Pembelian Multi Jenis Multi Grade
|
||||
Supplier A mengirim:
|
||||
- Jenis A Grade A = 50 kg
|
||||
- Jenis A Grade B = 20 kg
|
||||
- Jenis B Grade A = 15 kg
|
||||
|
||||
Purchase dibuat dengan 3 line.
|
||||
Saat receiving, masing-masing line menjadi lot:
|
||||
- LOT-260428-SPA-001 = Jenis A Grade A 50 kg
|
||||
- LOT-260428-SPA-002 = Jenis A Grade B 20 kg
|
||||
- LOT-260428-SPA-003 = Jenis B Grade A 15 kg
|
||||
|
||||
## Skenario 2. Pembelian Butuh Sortasi
|
||||
Supplier B mengirim barang campur 40 kg.
|
||||
Masuk sebagai:
|
||||
- LOT-260428-SPB-001 = provisional
|
||||
|
||||
Setelah sortasi:
|
||||
- LOT-260428-SPB-001-S1 = Jenis A Grade A 18 kg
|
||||
- LOT-260428-SPB-001-S2 = Jenis A Grade B 12 kg
|
||||
- LOT-260428-SPB-001-S3 = Jenis B Grade A 7 kg
|
||||
- Susut/reject = 3 kg
|
||||
|
||||
## Skenario 3. Penjualan Campuran dari Banyak Lot
|
||||
Customer X membeli:
|
||||
- Jenis A Grade A = 30 kg
|
||||
|
||||
Sistem melihat stok:
|
||||
- LOT-260428-SPA-001 tersedia 50 kg
|
||||
- LOT-260428-SPB-001-S1 tersedia 18 kg
|
||||
|
||||
Allocation:
|
||||
- 20 kg dari LOT-260428-SPA-001
|
||||
- 10 kg dari LOT-260428-SPB-001-S1
|
||||
|
||||
Jika cost:
|
||||
- LOT-260428-SPA-001 = 18.000.000/kg
|
||||
- LOT-260428-SPB-001-S1 = 19.000.000/kg
|
||||
|
||||
HPP line:
|
||||
- 20 x 18.000.000 = 360.000.000
|
||||
- 10 x 19.000.000 = 190.000.000
|
||||
- Total cost = 550.000.000
|
||||
|
||||
## Skenario 4. Regrade
|
||||
Dari LOT-260428-SPA-001, setelah inspeksi ulang:
|
||||
- 5 kg turun dari Grade A menjadi Grade B
|
||||
|
||||
Maka:
|
||||
- lot Grade A dikurangi 5 kg
|
||||
- dibuat lot baru Grade B atau ditambahkan ke lot grade B aktif
|
||||
- ledger mencatat REGRADE_OUT dan REGRADE_IN
|
||||
|
||||
## Skenario 5. Shrinkage
|
||||
Saat stock opname, ditemukan selisih -1.2 kg pada LOT-260428-SPB-001-S2.
|
||||
|
||||
Sistem mencatat:
|
||||
- stock adjustment
|
||||
- reason: SHRINKAGE
|
||||
- qty_before
|
||||
- qty_after
|
||||
- cost impact
|
||||
|
||||
## Skenario 6. Traceability
|
||||
Untuk invoice SLS-001, sistem dapat menampilkan:
|
||||
- 20 kg berasal dari LOT-260428-SPA-001, Supplier A
|
||||
- 10 kg berasal dari LOT-260428-SPB-001-S1, Supplier B
|
||||
|
||||
Untuk LOT-260428-SPA-001, sistem dapat menampilkan:
|
||||
- asal purchase: PO-001
|
||||
- supplier: Supplier A
|
||||
- dipakai di invoice: SLS-001, SLS-004, SLS-006
|
||||
- pernah diregrade: ya/tidak
|
||||
- pernah adjustment: ya/tidak
|
||||
BIN
docs/project-spec/walet-sample-transactions.pdf
Normal file
BIN
docs/project-spec/walet-sample-transactions.pdf
Normal file
Binary file not shown.
366
docs/project-spec/walet-schema.html
Normal file
366
docs/project-spec/walet-schema.html
Normal file
@ -0,0 +1,366 @@
|
||||
<!doctype html><html><head><meta charset="utf-8"><style>@page { size:A4; margin:1.5cm; } body { font-family: Arial, Helvetica, sans-serif; font-size:9pt; line-height:1.4; } pre { white-space: pre-wrap; font-size:8pt; }</style></head><body><h1>SQL Schema Sistem Inventory Walet</h1><pre>CREATE TABLE roles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
role_id BIGINT NOT NULL REFERENCES roles(id),
|
||||
name VARCHAR(150) NOT NULL,
|
||||
email VARCHAR(150),
|
||||
phone VARCHAR(50),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE suppliers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
phone VARCHAR(50),
|
||||
email VARCHAR(150),
|
||||
bank_name VARCHAR(100),
|
||||
bank_account_number VARCHAR(100),
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE customers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
phone VARCHAR(50),
|
||||
email VARCHAR(150),
|
||||
bank_name VARCHAR(100),
|
||||
bank_account_number VARCHAR(100),
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE units (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(20) NOT NULL UNIQUE,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE item_types (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE item_grades (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
rank_order INT,
|
||||
description TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE warehouses (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE warehouse_locations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
code VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
location_type VARCHAR(50),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (warehouse_id, code)
|
||||
);
|
||||
|
||||
CREATE TABLE adjustment_reasons (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchases (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
purchase_date DATE NOT NULL,
|
||||
supplier_invoice_no VARCHAR(100),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id) ON DELETE CASCADE,
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT REFERENCES item_grades(id),
|
||||
qty_ordered NUMERIC(18,3) NOT NULL,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_price NUMERIC(18,2) NOT NULL,
|
||||
subtotal NUMERIC(18,2) NOT NULL,
|
||||
classification_status VARCHAR(20) NOT NULL DEFAULT 'FINAL',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE receipts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
receipt_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id),
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
receipt_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
received_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE receipt_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
receipt_id BIGINT NOT NULL REFERENCES receipts(id) ON DELETE CASCADE,
|
||||
purchase_line_id BIGINT NOT NULL REFERENCES purchase_lines(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT REFERENCES item_grades(id),
|
||||
qty_received NUMERIC(18,3) NOT NULL,
|
||||
qty_accepted NUMERIC(18,3) NOT NULL,
|
||||
qty_rejected NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE inventory_lots (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
lot_code VARCHAR(100) NOT NULL UNIQUE,
|
||||
parent_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
source_type VARCHAR(30) NOT NULL,
|
||||
source_ref_id BIGINT,
|
||||
supplier_id BIGINT REFERENCES suppliers(id),
|
||||
purchase_id BIGINT REFERENCES purchases(id),
|
||||
purchase_line_id BIGINT REFERENCES purchase_lines(id),
|
||||
receipt_id BIGINT REFERENCES receipts(id),
|
||||
receipt_line_id BIGINT REFERENCES receipt_lines(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
warehouse_location_id BIGINT REFERENCES warehouse_locations(id),
|
||||
original_qty NUMERIC(18,3) NOT NULL,
|
||||
available_qty NUMERIC(18,3) NOT NULL,
|
||||
reserved_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
damaged_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
shrinkage_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
received_at TIMESTAMP NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
qr_code_value VARCHAR(255),
|
||||
barcode_value VARCHAR(255),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_inventory_lots_item_grade_wh ON inventory_lots(item_type_id, item_grade_id, warehouse_id);
|
||||
CREATE INDEX idx_inventory_lots_supplier_item_grade ON inventory_lots(supplier_id, item_type_id, item_grade_id);
|
||||
|
||||
CREATE TABLE sorting_sessions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sorting_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
source_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
sorting_date TIMESTAMP NOT NULL,
|
||||
input_qty NUMERIC(18,3) NOT NULL,
|
||||
output_qty NUMERIC(18,3) NOT NULL,
|
||||
shrinkage_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
sorted_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sorting_results (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sorting_session_id BIGINT NOT NULL REFERENCES sorting_sessions(id) ON DELETE CASCADE,
|
||||
result_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_result NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
customer_id BIGINT NOT NULL REFERENCES customers(id),
|
||||
sales_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_id BIGINT NOT NULL REFERENCES sales(id) ON DELETE CASCADE,
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_sold NUMERIC(18,3) NOT NULL,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
selling_price NUMERIC(18,2) NOT NULL,
|
||||
subtotal NUMERIC(18,2) NOT NULL,
|
||||
costing_total NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
gross_margin NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_allocations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_line_id BIGINT NOT NULL REFERENCES sales_lines(id) ON DELETE CASCADE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
qty_allocated NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
total_cost NUMERIC(18,2) NOT NULL,
|
||||
allocated_at TIMESTAMP NOT NULL,
|
||||
allocated_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE inventory_movements (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
movement_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
movement_type VARCHAR(30) NOT NULL,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
related_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
warehouse_location_id BIGINT REFERENCES warehouse_locations(id),
|
||||
qty_in NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
qty_out NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
balance_after NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
reference_type VARCHAR(30) NOT NULL,
|
||||
reference_id BIGINT NOT NULL,
|
||||
reason_id BIGINT REFERENCES adjustment_reasons(id),
|
||||
movement_date TIMESTAMP NOT NULL,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_returns (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_id BIGINT NOT NULL REFERENCES sales(id),
|
||||
customer_id BIGINT NOT NULL REFERENCES customers(id),
|
||||
return_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_return_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_return_id BIGINT NOT NULL REFERENCES sales_returns(id) ON DELETE CASCADE,
|
||||
sales_line_id BIGINT NOT NULL REFERENCES sales_lines(id),
|
||||
inventory_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_returned NUMERIC(18,3) NOT NULL,
|
||||
return_condition VARCHAR(50),
|
||||
resolution VARCHAR(50),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_returns (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id),
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
return_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_return_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_return_id BIGINT NOT NULL REFERENCES purchase_returns(id) ON DELETE CASCADE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
qty_returned NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE stock_adjustments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
adjustment_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
adjustment_type VARCHAR(30) NOT NULL,
|
||||
reason_id BIGINT NOT NULL REFERENCES adjustment_reasons(id),
|
||||
qty_before NUMERIC(18,3) NOT NULL,
|
||||
qty_change NUMERIC(18,3) NOT NULL,
|
||||
qty_after NUMERIC(18,3) NOT NULL,
|
||||
cost_impact NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
adjustment_date TIMESTAMP NOT NULL,
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE lot_labels (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id) ON DELETE CASCADE,
|
||||
label_type VARCHAR(20) NOT NULL,
|
||||
label_value VARCHAR(255) NOT NULL,
|
||||
printed_at TIMESTAMP,
|
||||
printed_by BIGINT REFERENCES users(id),
|
||||
print_count INT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);</pre></body></html>
|
||||
BIN
docs/project-spec/walet-schema.pdf
Normal file
BIN
docs/project-spec/walet-schema.pdf
Normal file
Binary file not shown.
366
docs/project-spec/walet-schema.sql
Normal file
366
docs/project-spec/walet-schema.sql
Normal file
@ -0,0 +1,366 @@
|
||||
CREATE TABLE roles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
role_id BIGINT NOT NULL REFERENCES roles(id),
|
||||
name VARCHAR(150) NOT NULL,
|
||||
email VARCHAR(150),
|
||||
phone VARCHAR(50),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE suppliers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
phone VARCHAR(50),
|
||||
email VARCHAR(150),
|
||||
bank_name VARCHAR(100),
|
||||
bank_account_number VARCHAR(100),
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE customers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
phone VARCHAR(50),
|
||||
email VARCHAR(150),
|
||||
bank_name VARCHAR(100),
|
||||
bank_account_number VARCHAR(100),
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE units (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(20) NOT NULL UNIQUE,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE item_types (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE item_grades (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
rank_order INT,
|
||||
description TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE warehouses (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
address TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE warehouse_locations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
code VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
location_type VARCHAR(50),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (warehouse_id, code)
|
||||
);
|
||||
|
||||
CREATE TABLE adjustment_reasons (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchases (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
purchase_date DATE NOT NULL,
|
||||
supplier_invoice_no VARCHAR(100),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id) ON DELETE CASCADE,
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT REFERENCES item_grades(id),
|
||||
qty_ordered NUMERIC(18,3) NOT NULL,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_price NUMERIC(18,2) NOT NULL,
|
||||
subtotal NUMERIC(18,2) NOT NULL,
|
||||
classification_status VARCHAR(20) NOT NULL DEFAULT 'FINAL',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE receipts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
receipt_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id),
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
receipt_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
received_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE receipt_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
receipt_id BIGINT NOT NULL REFERENCES receipts(id) ON DELETE CASCADE,
|
||||
purchase_line_id BIGINT NOT NULL REFERENCES purchase_lines(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT REFERENCES item_grades(id),
|
||||
qty_received NUMERIC(18,3) NOT NULL,
|
||||
qty_accepted NUMERIC(18,3) NOT NULL,
|
||||
qty_rejected NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE inventory_lots (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
lot_code VARCHAR(100) NOT NULL UNIQUE,
|
||||
parent_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
source_type VARCHAR(30) NOT NULL,
|
||||
source_ref_id BIGINT,
|
||||
supplier_id BIGINT REFERENCES suppliers(id),
|
||||
purchase_id BIGINT REFERENCES purchases(id),
|
||||
purchase_line_id BIGINT REFERENCES purchase_lines(id),
|
||||
receipt_id BIGINT REFERENCES receipts(id),
|
||||
receipt_line_id BIGINT REFERENCES receipt_lines(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
warehouse_location_id BIGINT REFERENCES warehouse_locations(id),
|
||||
original_qty NUMERIC(18,3) NOT NULL,
|
||||
available_qty NUMERIC(18,3) NOT NULL,
|
||||
reserved_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
damaged_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
shrinkage_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
received_at TIMESTAMP NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
qr_code_value VARCHAR(255),
|
||||
barcode_value VARCHAR(255),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_inventory_lots_item_grade_wh ON inventory_lots(item_type_id, item_grade_id, warehouse_id);
|
||||
CREATE INDEX idx_inventory_lots_supplier_item_grade ON inventory_lots(supplier_id, item_type_id, item_grade_id);
|
||||
|
||||
CREATE TABLE sorting_sessions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sorting_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
source_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
sorting_date TIMESTAMP NOT NULL,
|
||||
input_qty NUMERIC(18,3) NOT NULL,
|
||||
output_qty NUMERIC(18,3) NOT NULL,
|
||||
shrinkage_qty NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
sorted_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sorting_results (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sorting_session_id BIGINT NOT NULL REFERENCES sorting_sessions(id) ON DELETE CASCADE,
|
||||
result_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_result NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
customer_id BIGINT NOT NULL REFERENCES customers(id),
|
||||
sales_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_id BIGINT NOT NULL REFERENCES sales(id) ON DELETE CASCADE,
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_sold NUMERIC(18,3) NOT NULL,
|
||||
unit_id BIGINT NOT NULL REFERENCES units(id),
|
||||
selling_price NUMERIC(18,2) NOT NULL,
|
||||
subtotal NUMERIC(18,2) NOT NULL,
|
||||
costing_total NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
gross_margin NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_allocations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_line_id BIGINT NOT NULL REFERENCES sales_lines(id) ON DELETE CASCADE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
qty_allocated NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
total_cost NUMERIC(18,2) NOT NULL,
|
||||
allocated_at TIMESTAMP NOT NULL,
|
||||
allocated_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE inventory_movements (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
movement_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
movement_type VARCHAR(30) NOT NULL,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
related_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
warehouse_id BIGINT NOT NULL REFERENCES warehouses(id),
|
||||
warehouse_location_id BIGINT REFERENCES warehouse_locations(id),
|
||||
qty_in NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
qty_out NUMERIC(18,3) NOT NULL DEFAULT 0,
|
||||
balance_after NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
reference_type VARCHAR(30) NOT NULL,
|
||||
reference_id BIGINT NOT NULL,
|
||||
reason_id BIGINT REFERENCES adjustment_reasons(id),
|
||||
movement_date TIMESTAMP NOT NULL,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_returns (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_id BIGINT NOT NULL REFERENCES sales(id),
|
||||
customer_id BIGINT NOT NULL REFERENCES customers(id),
|
||||
return_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE sales_return_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
sales_return_id BIGINT NOT NULL REFERENCES sales_returns(id) ON DELETE CASCADE,
|
||||
sales_line_id BIGINT NOT NULL REFERENCES sales_lines(id),
|
||||
inventory_lot_id BIGINT REFERENCES inventory_lots(id),
|
||||
item_type_id BIGINT NOT NULL REFERENCES item_types(id),
|
||||
item_grade_id BIGINT NOT NULL REFERENCES item_grades(id),
|
||||
qty_returned NUMERIC(18,3) NOT NULL,
|
||||
return_condition VARCHAR(50),
|
||||
resolution VARCHAR(50),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_returns (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL REFERENCES purchases(id),
|
||||
supplier_id BIGINT NOT NULL REFERENCES suppliers(id),
|
||||
return_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE purchase_return_lines (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
purchase_return_id BIGINT NOT NULL REFERENCES purchase_returns(id) ON DELETE CASCADE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
qty_returned NUMERIC(18,3) NOT NULL,
|
||||
unit_cost NUMERIC(18,2) NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE stock_adjustments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
adjustment_no VARCHAR(50) NOT NULL UNIQUE,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id),
|
||||
adjustment_type VARCHAR(30) NOT NULL,
|
||||
reason_id BIGINT NOT NULL REFERENCES adjustment_reasons(id),
|
||||
qty_before NUMERIC(18,3) NOT NULL,
|
||||
qty_change NUMERIC(18,3) NOT NULL,
|
||||
qty_after NUMERIC(18,3) NOT NULL,
|
||||
cost_impact NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
adjustment_date TIMESTAMP NOT NULL,
|
||||
notes TEXT,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE lot_labels (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
inventory_lot_id BIGINT NOT NULL REFERENCES inventory_lots(id) ON DELETE CASCADE,
|
||||
label_type VARCHAR(20) NOT NULL,
|
||||
label_value VARCHAR(255) NOT NULL,
|
||||
printed_at TIMESTAMP,
|
||||
printed_by BIGINT REFERENCES users(id),
|
||||
print_count INT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
532
docs/project-spec/walet-screen-ui-spec.md
Normal file
532
docs/project-spec/walet-screen-ui-spec.md
Normal file
@ -0,0 +1,532 @@
|
||||
# Screen-by-Screen UI Spec
|
||||
## Sistem Inventory Sarang Burung Walet
|
||||
|
||||
## 1. Login Screen
|
||||
### Tujuan
|
||||
Autentikasi user berdasarkan role.
|
||||
|
||||
### Section
|
||||
- logo / app name
|
||||
- email/phone field
|
||||
- password field
|
||||
- login button
|
||||
- error message area
|
||||
|
||||
### Notes
|
||||
- simple, fast, no clutter
|
||||
|
||||
---
|
||||
|
||||
## 2. Dashboard
|
||||
### Tujuan
|
||||
Memberi gambaran cepat kondisi bisnis.
|
||||
|
||||
### Layout
|
||||
- top header
|
||||
- metrics cards row
|
||||
- charts row
|
||||
- alerts row
|
||||
- quick actions panel
|
||||
|
||||
### Data utama
|
||||
- total stok aktif
|
||||
- nilai inventory
|
||||
- pembelian bulan ini
|
||||
- penjualan bulan ini
|
||||
- shrinkage bulan ini
|
||||
- lot aging alert
|
||||
|
||||
### CTA
|
||||
- buat pembelian
|
||||
- receipt baru
|
||||
- sales baru
|
||||
- scan lot
|
||||
|
||||
---
|
||||
|
||||
## 3. Supplier List
|
||||
### Tujuan
|
||||
Kelola data supplier.
|
||||
|
||||
### Layout
|
||||
- page header
|
||||
- filter/search bar
|
||||
- create supplier button
|
||||
- table list
|
||||
|
||||
### Kolom table
|
||||
- code
|
||||
- name
|
||||
- phone
|
||||
- email
|
||||
- bank_name
|
||||
- bank_account_number
|
||||
- status
|
||||
- actions
|
||||
|
||||
### Detail view supplier
|
||||
Section:
|
||||
- informasi umum
|
||||
- informasi pembayaran
|
||||
- histori pembelian
|
||||
|
||||
---
|
||||
|
||||
## 4. Customer List
|
||||
### Tujuan
|
||||
Kelola data customer.
|
||||
|
||||
### Layout
|
||||
- page header
|
||||
- filter/search bar
|
||||
- create customer button
|
||||
- table list
|
||||
|
||||
### Kolom table
|
||||
- code
|
||||
- name
|
||||
- phone
|
||||
- email
|
||||
- bank_name
|
||||
- bank_account_number
|
||||
- status
|
||||
- actions
|
||||
|
||||
### Detail view customer
|
||||
Section:
|
||||
- informasi umum
|
||||
- informasi pembayaran
|
||||
- histori penjualan
|
||||
|
||||
---
|
||||
|
||||
## 5. Purchase List
|
||||
### Tujuan
|
||||
Lihat seluruh purchase.
|
||||
|
||||
### Layout
|
||||
- filter bar
|
||||
- summary chips
|
||||
- purchase table
|
||||
|
||||
### Kolom
|
||||
- purchase no
|
||||
- supplier
|
||||
- purchase date
|
||||
- total
|
||||
- status
|
||||
- line count
|
||||
- actions
|
||||
|
||||
---
|
||||
|
||||
## 6. Purchase Form
|
||||
### Tujuan
|
||||
Membuat purchase multi-line.
|
||||
|
||||
### Header section
|
||||
- supplier select
|
||||
- bank info preview supplier
|
||||
- purchase date
|
||||
- invoice supplier
|
||||
- notes
|
||||
|
||||
### Lines section
|
||||
Kolom:
|
||||
- item type
|
||||
- grade
|
||||
- qty
|
||||
- unit
|
||||
- unit price
|
||||
- subtotal
|
||||
- classification status
|
||||
- note
|
||||
|
||||
### Summary section
|
||||
- total lines
|
||||
- grand total
|
||||
|
||||
### Actions
|
||||
- save draft
|
||||
- submit
|
||||
- cancel
|
||||
|
||||
---
|
||||
|
||||
## 7. Receipt List
|
||||
### Tujuan
|
||||
Melihat seluruh receipt.
|
||||
|
||||
### Kolom
|
||||
- receipt no
|
||||
- purchase no
|
||||
- supplier
|
||||
- receipt date
|
||||
- status
|
||||
- total lines
|
||||
- actions
|
||||
|
||||
---
|
||||
|
||||
## 8. Receipt Form
|
||||
### Tujuan
|
||||
Menerima barang dan membentuk lot.
|
||||
|
||||
### Header section
|
||||
- purchase ref
|
||||
- supplier
|
||||
- bank info supplier (readonly)
|
||||
- receipt date
|
||||
- receiver
|
||||
|
||||
### Lines section
|
||||
- item
|
||||
- ordered qty
|
||||
- received qty
|
||||
- accepted qty
|
||||
- rejected qty
|
||||
- unit cost
|
||||
- warehouse
|
||||
- location
|
||||
|
||||
### Actions
|
||||
- save receipt
|
||||
- finalize receipt
|
||||
- generate lot
|
||||
|
||||
---
|
||||
|
||||
## 9. Stock Summary
|
||||
### Tujuan
|
||||
Ringkasan stok per jenis-grade-gudang.
|
||||
|
||||
### Table columns
|
||||
- item type
|
||||
- grade
|
||||
- warehouse
|
||||
- qty total
|
||||
- inventory value
|
||||
- active lot count
|
||||
|
||||
---
|
||||
|
||||
## 10. Stock Lot List
|
||||
### Tujuan
|
||||
Melihat semua lot aktif/detail.
|
||||
|
||||
### Filter
|
||||
- supplier
|
||||
- item type
|
||||
- grade
|
||||
- warehouse
|
||||
- status
|
||||
- aging
|
||||
|
||||
### Table columns
|
||||
- lot code
|
||||
- supplier
|
||||
- item type
|
||||
- grade
|
||||
- available qty
|
||||
- unit cost
|
||||
- warehouse
|
||||
- location
|
||||
- aging
|
||||
- status
|
||||
- actions
|
||||
|
||||
---
|
||||
|
||||
## 11. Lot Detail
|
||||
### Tujuan
|
||||
Pusat traceability dan aksi lot.
|
||||
|
||||
### Section 1. Summary card
|
||||
- lot code
|
||||
- supplier
|
||||
- item type
|
||||
- grade
|
||||
- available qty
|
||||
- unit cost
|
||||
- status
|
||||
|
||||
### Section 2. Supplier info
|
||||
- supplier name
|
||||
- bank_name
|
||||
- bank_account_number
|
||||
|
||||
### Section 3. Quantity breakdown
|
||||
- original qty
|
||||
- available qty
|
||||
- reserved qty
|
||||
- damaged qty
|
||||
- shrinkage qty
|
||||
|
||||
### Section 4. Traceability
|
||||
- parent lot
|
||||
- child lots
|
||||
- purchase ref
|
||||
- receipt ref
|
||||
|
||||
### Section 5. Movement history
|
||||
- timeline/table of movements
|
||||
|
||||
### Section 6. Sales usage
|
||||
- invoice list
|
||||
- allocated qty
|
||||
- customer
|
||||
|
||||
### Actions
|
||||
- hold
|
||||
- release
|
||||
- transfer
|
||||
- regrade
|
||||
- print label
|
||||
|
||||
---
|
||||
|
||||
## 12. Sorting Session Form
|
||||
### Tujuan
|
||||
Pecah satu lot menjadi beberapa hasil.
|
||||
|
||||
### Section
|
||||
- source lot selector
|
||||
- source lot summary
|
||||
- results table
|
||||
- shrinkage input
|
||||
- reject input
|
||||
- notes
|
||||
|
||||
### Result columns
|
||||
- item type
|
||||
- grade
|
||||
- qty result
|
||||
- cost
|
||||
|
||||
---
|
||||
|
||||
## 13. Regrade Form
|
||||
### Tujuan
|
||||
Ubah sebagian qty lot ke grade baru.
|
||||
|
||||
### Fields
|
||||
- source lot
|
||||
- source grade
|
||||
- target grade
|
||||
- qty
|
||||
- reason
|
||||
- notes
|
||||
|
||||
### Preview
|
||||
- qty remaining source
|
||||
- target lot result
|
||||
|
||||
---
|
||||
|
||||
## 14. Sales List
|
||||
### Tujuan
|
||||
Lihat semua sales order.
|
||||
|
||||
### Kolom
|
||||
- sales no
|
||||
- customer
|
||||
- customer bank
|
||||
- sales date
|
||||
- grand total
|
||||
- costing total
|
||||
- gross margin
|
||||
- status
|
||||
- actions
|
||||
|
||||
---
|
||||
|
||||
## 15. Sales Form
|
||||
### Tujuan
|
||||
Membuat order penjualan.
|
||||
|
||||
### Header section
|
||||
- customer select
|
||||
- customer bank info preview
|
||||
- sales date
|
||||
- notes
|
||||
|
||||
### Line section
|
||||
- item type
|
||||
- grade
|
||||
- qty
|
||||
- unit
|
||||
- selling price
|
||||
- subtotal
|
||||
|
||||
### Summary
|
||||
- grand total
|
||||
|
||||
### Actions
|
||||
- save draft
|
||||
- continue to allocation
|
||||
|
||||
---
|
||||
|
||||
## 16. Allocation Screen
|
||||
### Tujuan
|
||||
Memecah kebutuhan sales line ke beberapa lot.
|
||||
|
||||
### Left panel
|
||||
- sales line summary
|
||||
- qty required
|
||||
- qty allocated
|
||||
- qty remaining
|
||||
|
||||
### Main table
|
||||
- lot code
|
||||
- supplier
|
||||
- available qty
|
||||
- unit cost
|
||||
- received at
|
||||
- FIFO badge
|
||||
- allocate qty input
|
||||
|
||||
### Bottom summary
|
||||
- total allocated
|
||||
- total cost
|
||||
- avg cost
|
||||
- validation state
|
||||
|
||||
### Actions
|
||||
- auto allocate
|
||||
- clear allocation
|
||||
- save allocation
|
||||
|
||||
---
|
||||
|
||||
## 17. Picking Screen
|
||||
### Tujuan
|
||||
Konfirmasi pengambilan aktual.
|
||||
|
||||
### Section
|
||||
- sales summary
|
||||
- QR scanner panel
|
||||
- allocation rows
|
||||
|
||||
### Row fields
|
||||
- lot code
|
||||
- allocated qty
|
||||
- picked qty
|
||||
- variance
|
||||
- status
|
||||
|
||||
### Actions
|
||||
- confirm picking
|
||||
- report variance
|
||||
|
||||
---
|
||||
|
||||
## 18. Barcode Lookup Screen
|
||||
### Tujuan
|
||||
Lookup cepat setelah scan.
|
||||
|
||||
### Section
|
||||
- scanner
|
||||
- manual input
|
||||
- result summary card
|
||||
- trace summary
|
||||
- quick actions
|
||||
|
||||
### Quick actions
|
||||
- open lot detail
|
||||
- transfer
|
||||
- hold/release
|
||||
- print label
|
||||
|
||||
---
|
||||
|
||||
## 19. Adjustment Form
|
||||
### Tujuan
|
||||
Input adjustment dan shrinkage.
|
||||
|
||||
### Fields
|
||||
- lot
|
||||
- lot snapshot
|
||||
- adjustment type
|
||||
- reason
|
||||
- qty before
|
||||
- qty change
|
||||
- qty after preview
|
||||
- cost impact preview
|
||||
- notes
|
||||
|
||||
### Actions
|
||||
- save draft
|
||||
- submit / post
|
||||
|
||||
---
|
||||
|
||||
## 20. Returns Screens
|
||||
### Sales Return
|
||||
- sales ref
|
||||
- customer
|
||||
- item lines
|
||||
- lot ref jika ada
|
||||
- qty return
|
||||
- condition
|
||||
- resolution
|
||||
|
||||
### Purchase Return
|
||||
- purchase ref
|
||||
- supplier
|
||||
- lot ref
|
||||
- qty return
|
||||
- cost
|
||||
- notes
|
||||
|
||||
---
|
||||
|
||||
## 21. Reports
|
||||
### Layout umum
|
||||
- report header
|
||||
- filter bar
|
||||
- summary cards
|
||||
- chart section
|
||||
- data table
|
||||
- export buttons
|
||||
|
||||
### Report yang perlu didesain
|
||||
- stock summary
|
||||
- stock lots
|
||||
- purchase history
|
||||
- sales margin
|
||||
- supplier quality
|
||||
- shrinkage
|
||||
- traceability
|
||||
|
||||
---
|
||||
|
||||
## 22. Mobile-Specific Screens
|
||||
Prioritas mobile:
|
||||
- barcode scan
|
||||
- receipt quick input
|
||||
- transfer lot
|
||||
- picking
|
||||
- lot lookup
|
||||
|
||||
### Design notes mobile
|
||||
- large touch targets
|
||||
- sticky action button
|
||||
- simplified data layout
|
||||
- bottom sheet for actions
|
||||
|
||||
---
|
||||
|
||||
## 23. UI States yang Harus Didukung
|
||||
Untuk semua screen penting, designer perlu siapkan:
|
||||
- empty state
|
||||
- loading state
|
||||
- error state
|
||||
- success toast/dialog
|
||||
- permission denied state
|
||||
- no result state
|
||||
|
||||
---
|
||||
|
||||
## 24. Penutup
|
||||
Dokumen ini dimaksudkan agar desainer bisa langsung membuat layout detail per screen di Figma, lengkap dengan section, field, table columns, dan interaction priority.
|
||||
125
docs/project-spec/walet-seed-data.sql
Normal file
125
docs/project-spec/walet-seed-data.sql
Normal file
@ -0,0 +1,125 @@
|
||||
INSERT INTO roles (code, name) VALUES
|
||||
('OWNER', 'Owner'),
|
||||
('PURCHASING', 'Admin Purchasing'),
|
||||
('WAREHOUSE', 'Admin Gudang'),
|
||||
('QC', 'Tim Sortasi'),
|
||||
('SALES', 'Admin Sales');
|
||||
|
||||
INSERT INTO users (role_id, name, email, phone) VALUES
|
||||
(1, 'Owner Walet', 'owner@walet.local', '081200000001'),
|
||||
(2, 'Purchasing Walet', 'purchasing@walet.local', '081200000002'),
|
||||
(3, 'Warehouse Walet', 'warehouse@walet.local', '081200000003'),
|
||||
(4, 'QC Walet', 'qc@walet.local', '081200000004'),
|
||||
(5, 'Sales Walet', 'sales@walet.local', '081200000005');
|
||||
|
||||
INSERT INTO units (code, name) VALUES
|
||||
('KG', 'Kilogram'),
|
||||
('PCS', 'Pieces');
|
||||
|
||||
INSERT INTO item_types (code, name, description) VALUES
|
||||
('JNS-A', 'Jenis A', 'Jenis sarang walet A'),
|
||||
('JNS-B', 'Jenis B', 'Jenis sarang walet B'),
|
||||
('JNS-C', 'Jenis C', 'Jenis sarang walet C');
|
||||
|
||||
INSERT INTO item_grades (code, name, rank_order, description) VALUES
|
||||
('GRD-A', 'Grade A', 1, 'Grade tertinggi'),
|
||||
('GRD-B', 'Grade B', 2, 'Grade menengah'),
|
||||
('GRD-C', 'Grade C', 3, 'Grade bawah'),
|
||||
('REJECT', 'Reject', 99, 'Tidak layak jual');
|
||||
|
||||
INSERT INTO warehouses (code, name, address) VALUES
|
||||
('WH-PUSAT', 'Gudang Pusat', 'Jl. Gudang Pusat'),
|
||||
('WH-CBG1', 'Gudang Cabang 1', 'Jl. Cabang 1');
|
||||
|
||||
INSERT INTO warehouse_locations (warehouse_id, code, name, location_type) VALUES
|
||||
(1, 'A1', 'Rak A1', 'RACK'),
|
||||
(1, 'A2', 'Rak A2', 'RACK'),
|
||||
(1, 'SORT', 'Area Sortasi', 'PROCESS'),
|
||||
(2, 'B1', 'Rak B1', 'RACK');
|
||||
|
||||
INSERT INTO adjustment_reasons (code, name, category) VALUES
|
||||
('SHRINK', 'Shrinkage', 'SHRINKAGE'),
|
||||
('DMG', 'Damage', 'DAMAGE'),
|
||||
('REGRADE', 'Regrade', 'REGRADE'),
|
||||
('OPNAME', 'Stock Opname Selisih', 'ADJUSTMENT');
|
||||
|
||||
INSERT INTO suppliers (code, name, phone, email, bank_name, bank_account_number, address) VALUES
|
||||
('SUP-A', 'Supplier A', '081310000001', 'sup-a@walet.local', 'BCA', '1234567890', 'Bogor'),
|
||||
('SUP-B', 'Supplier B', '081310000002', 'sup-b@walet.local', 'Mandiri', '9876543210', 'Bandung');
|
||||
|
||||
INSERT INTO customers (code, name, phone, email, bank_name, bank_account_number, address) VALUES
|
||||
('CUST-A', 'Customer A', '081320000001', 'cust-a@walet.local', 'BRI', '111222333444', 'Jakarta'),
|
||||
('CUST-B', 'Customer B', '081320000002', 'cust-b@walet.local', 'BNI', '555666777888', 'Surabaya');
|
||||
|
||||
INSERT INTO purchases (purchase_no, supplier_id, purchase_date, supplier_invoice_no, status, created_by)
|
||||
VALUES
|
||||
('PO-20260428-001', 1, '2026-04-28', 'INV-SUP-A-001', 'SUBMITTED', 2),
|
||||
('PO-20260428-002', 2, '2026-04-28', 'INV-SUP-B-001', 'SUBMITTED', 2);
|
||||
|
||||
INSERT INTO purchase_lines (purchase_id, item_type_id, item_grade_id, qty_ordered, unit_id, unit_price, subtotal, classification_status)
|
||||
VALUES
|
||||
(1, 1, 1, 50.000, 1, 18000000, 900000000, 'FINAL'),
|
||||
(1, 1, 2, 20.000, 1, 16000000, 320000000, 'FINAL'),
|
||||
(2, 1, NULL, 40.000, 1, 17500000, 700000000, 'PROVISIONAL');
|
||||
|
||||
INSERT INTO receipts (receipt_no, purchase_id, supplier_id, receipt_date, status, received_by)
|
||||
VALUES
|
||||
('RCV-20260428-001', 1, 1, '2026-04-28', 'FINALIZED', 3),
|
||||
('RCV-20260428-002', 2, 2, '2026-04-28', 'FINALIZED', 3);
|
||||
|
||||
INSERT INTO receipt_lines (receipt_id, purchase_line_id, item_type_id, item_grade_id, qty_received, qty_accepted, qty_rejected, unit_id, unit_cost)
|
||||
VALUES
|
||||
(1, 1, 1, 1, 50.000, 50.000, 0, 1, 18000000),
|
||||
(1, 2, 1, 2, 20.000, 20.000, 0, 1, 16000000),
|
||||
(2, 3, 1, NULL, 40.000, 40.000, 0, 1, 17500000);
|
||||
|
||||
INSERT INTO inventory_lots (
|
||||
lot_code, parent_lot_id, source_type, source_ref_id, supplier_id, purchase_id, purchase_line_id, receipt_id, receipt_line_id,
|
||||
item_type_id, item_grade_id, warehouse_id, warehouse_location_id, original_qty, available_qty, unit_id, unit_cost, received_at, status, qr_code_value, barcode_value
|
||||
) VALUES
|
||||
('LOT-260428-SUPA-001', NULL, 'PURCHASE', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50.000, 30.000, 1, 18000000, '2026-04-28 09:00:00', 'ACTIVE', 'LOT-260428-SUPA-001', 'LOT-260428-SUPA-001'),
|
||||
('LOT-260428-SUPA-002', NULL, 'PURCHASE', 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 20.000, 20.000, 1, 16000000, '2026-04-28 09:10:00', 'ACTIVE', 'LOT-260428-SUPA-002', 'LOT-260428-SUPA-002'),
|
||||
('LOT-260428-SUPB-001', NULL, 'PURCHASE', 3, 2, 2, 3, 2, 3, 1, 2, 1, 3, 40.000, 0.000, 1, 17500000, '2026-04-28 10:00:00', 'CLOSED', 'LOT-260428-SUPB-001', 'LOT-260428-SUPB-001'),
|
||||
('LOT-260428-SUPB-001-S1', 3, 'SORTING', 1, 2, 2, 3, 2, 3, 1, 1, 1, 1, 18.000, 8.000, 1, 17500000, '2026-04-28 11:00:00', 'ACTIVE', 'LOT-260428-SUPB-001-S1', 'LOT-260428-SUPB-001-S1'),
|
||||
('LOT-260428-SUPB-001-S2', 3, 'SORTING', 1, 2, 2, 3, 2, 3, 1, 2, 1, 2, 12.000, 12.000, 1, 17500000, '2026-04-28 11:00:00', 'ACTIVE', 'LOT-260428-SUPB-001-S2', 'LOT-260428-SUPB-001-S2'),
|
||||
('LOT-260428-SUPB-001-S3', 3, 'SORTING', 1, 2, 2, 3, 2, 3, 2, 1, 1, 2, 7.000, 7.000, 1, 17500000, '2026-04-28 11:00:00', 'ACTIVE', 'LOT-260428-SUPB-001-S3', 'LOT-260428-SUPB-001-S3');
|
||||
|
||||
INSERT INTO sorting_sessions (sorting_no, source_lot_id, sorting_date, input_qty, output_qty, shrinkage_qty, notes, sorted_by)
|
||||
VALUES
|
||||
('SRT-20260428-001', 3, '2026-04-28 11:00:00', 40.000, 37.000, 3.000, 'Sortasi batch campuran supplier B', 4);
|
||||
|
||||
INSERT INTO sorting_results (sorting_session_id, result_lot_id, item_type_id, item_grade_id, qty_result, unit_cost)
|
||||
VALUES
|
||||
(1, 4, 1, 1, 18.000, 17500000),
|
||||
(1, 5, 1, 2, 12.000, 17500000),
|
||||
(1, 6, 2, 1, 7.000, 17500000);
|
||||
|
||||
INSERT INTO sales (sales_no, customer_id, sales_date, status, created_by)
|
||||
VALUES
|
||||
('SLS-20260428-001', 1, '2026-04-28', 'CONFIRMED', 5);
|
||||
|
||||
INSERT INTO sales_lines (sales_id, item_type_id, item_grade_id, qty_sold, unit_id, selling_price, subtotal, costing_total, gross_margin)
|
||||
VALUES
|
||||
(1, 1, 1, 30.000, 1, 22000000, 660000000, 550000000, 110000000);
|
||||
|
||||
INSERT INTO sales_allocations (sales_line_id, inventory_lot_id, qty_allocated, unit_cost, total_cost, allocated_at, allocated_by)
|
||||
VALUES
|
||||
(1, 1, 20.000, 18000000, 360000000, '2026-04-28 13:00:00', 5),
|
||||
(1, 4, 10.000, 19000000, 190000000, '2026-04-28 13:00:00', 5);
|
||||
|
||||
INSERT INTO inventory_movements (movement_no, movement_type, inventory_lot_id, related_lot_id, warehouse_id, warehouse_location_id, qty_in, qty_out, balance_after, unit_cost, reference_type, reference_id, movement_date, created_by, notes)
|
||||
VALUES
|
||||
('MOV-0001', 'RECEIPT', 1, NULL, 1, 1, 50.000, 0.000, 50.000, 18000000, 'RECEIPT', 1, '2026-04-28 09:00:00', 3, 'Receipt lot supplier A grade A'),
|
||||
('MOV-0002', 'RECEIPT', 2, NULL, 1, 2, 20.000, 0.000, 20.000, 16000000, 'RECEIPT', 1, '2026-04-28 09:10:00', 3, 'Receipt lot supplier A grade B'),
|
||||
('MOV-0003', 'RECEIPT', 3, NULL, 1, 3, 40.000, 0.000, 40.000, 17500000, 'RECEIPT', 2, '2026-04-28 10:00:00', 3, 'Receipt lot provisional supplier B'),
|
||||
('MOV-0004', 'SORT_OUT', 3, NULL, 1, 3, 0.000, 40.000, 0.000, 17500000, 'SORTING', 1, '2026-04-28 11:00:00', 4, 'Lot sumber keluar untuk sortasi'),
|
||||
('MOV-0005', 'SORT_IN', 4, 3, 1, 1, 18.000, 0.000, 18.000, 17500000, 'SORTING', 1, '2026-04-28 11:00:00', 4, 'Hasil sortasi grade A'),
|
||||
('MOV-0006', 'SORT_IN', 5, 3, 1, 2, 12.000, 0.000, 12.000, 17500000, 'SORTING', 1, '2026-04-28 11:00:00', 4, 'Hasil sortasi grade B'),
|
||||
('MOV-0007', 'SORT_IN', 6, 3, 1, 2, 7.000, 0.000, 7.000, 17500000, 'SORTING', 1, '2026-04-28 11:00:00', 4, 'Hasil sortasi jenis B grade A'),
|
||||
('MOV-0008', 'SALE_OUT', 1, NULL, 1, 1, 0.000, 20.000, 30.000, 18000000, 'SALE', 1, '2026-04-28 13:00:00', 5, 'Alokasi penjualan dari lot supplier A'),
|
||||
('MOV-0009', 'SALE_OUT', 4, NULL, 1, 1, 0.000, 10.000, 8.000, 19000000, 'SALE', 1, '2026-04-28 13:00:00', 5, 'Alokasi penjualan dari lot hasil sortasi supplier B');
|
||||
|
||||
INSERT INTO lot_labels (inventory_lot_id, label_type, label_value, printed_at, printed_by, print_count, status)
|
||||
VALUES
|
||||
(1, 'QR', 'LOT-260428-SUPA-001', '2026-04-28 09:01:00', 3, 1, 'ACTIVE'),
|
||||
(4, 'QR', 'LOT-260428-SUPB-001-S1', '2026-04-28 11:01:00', 4, 1, 'ACTIVE');
|
||||
281
docs/project-spec/walet-sprint-breakdown.md
Normal file
281
docs/project-spec/walet-sprint-breakdown.md
Normal file
@ -0,0 +1,281 @@
|
||||
# Task Breakdown Per Sprint Sistem Inventory Walet
|
||||
|
||||
## Asumsi
|
||||
- Sprint 2 minggu
|
||||
- Tim kecil sampai menengah
|
||||
- Fokus awal ke fondasi backend + frontend operasional inti
|
||||
- Target awal: MVP usable untuk pembelian, receiving, stok lot, dan penjualan sederhana
|
||||
|
||||
## Sprint 0 - Foundation Setup
|
||||
### Backend
|
||||
- setup project structure
|
||||
- setup database PostgreSQL
|
||||
- implement auth dasar
|
||||
- implement migration system
|
||||
- import schema awal
|
||||
|
||||
### Frontend
|
||||
- setup Next.js + TypeScript
|
||||
- setup UI base, app shell, routing
|
||||
- setup TanStack Query, form library, state management
|
||||
|
||||
### DevOps
|
||||
- environment dev/staging
|
||||
- seed data awal
|
||||
- lint, formatting, pre-commit
|
||||
|
||||
### Deliverables
|
||||
- repo siap kerja
|
||||
- database hidup
|
||||
- login dasar
|
||||
- layout aplikasi hidup
|
||||
|
||||
---
|
||||
|
||||
## Sprint 1 - Master Data Core
|
||||
### Backend
|
||||
- API suppliers
|
||||
- API customers
|
||||
- API item types
|
||||
- API item grades
|
||||
- API warehouses dan locations
|
||||
- API adjustment reasons
|
||||
|
||||
### Frontend
|
||||
- halaman list/create/edit master data
|
||||
- reusable form dan table
|
||||
|
||||
### QA
|
||||
- validasi CRUD master data
|
||||
|
||||
### Deliverables
|
||||
- semua master data inti bisa dikelola
|
||||
|
||||
---
|
||||
|
||||
## Sprint 2 - Purchasing
|
||||
### Backend
|
||||
- API purchases
|
||||
- API purchase lines
|
||||
- status workflow draft/submitted/cancelled
|
||||
- histori harga beli dasar
|
||||
|
||||
### Frontend
|
||||
- purchase list
|
||||
- purchase form multi-line
|
||||
- purchase detail
|
||||
|
||||
### QA
|
||||
- test multi-line purchase
|
||||
- test status pembelian
|
||||
|
||||
### Deliverables
|
||||
- user bisa membuat pembelian multi jenis-grade
|
||||
|
||||
---
|
||||
|
||||
## Sprint 3 - Receiving dan Lot Creation
|
||||
### Backend
|
||||
- API receipts
|
||||
- API receipt lines
|
||||
- generate inventory lots
|
||||
- movement ledger untuk receiving
|
||||
- print label metadata
|
||||
|
||||
### Frontend
|
||||
- receipt form
|
||||
- receipt detail
|
||||
- generate lot action
|
||||
- lot list dasar
|
||||
|
||||
### QA
|
||||
- test qty ordered vs received
|
||||
- test lot terbentuk benar
|
||||
|
||||
### Deliverables
|
||||
- barang bisa diterima dan jadi lot
|
||||
|
||||
---
|
||||
|
||||
## Sprint 4 - Inventory Lot Management
|
||||
### Backend
|
||||
- API lot detail
|
||||
- API lot movement history
|
||||
- API hold/release
|
||||
- API transfer lot
|
||||
- stock summary endpoint
|
||||
|
||||
### Frontend
|
||||
- stock summary page
|
||||
- stock lot list
|
||||
- lot detail
|
||||
- transfer/hold action
|
||||
|
||||
### QA
|
||||
- test trace lot dasar
|
||||
- test lot status
|
||||
|
||||
### Deliverables
|
||||
- user bisa melihat dan mengelola lot
|
||||
|
||||
---
|
||||
|
||||
## Sprint 5 - Sales dan Allocation
|
||||
### Backend
|
||||
- API sales
|
||||
- API sales lines
|
||||
- API manual allocation
|
||||
- API auto allocation FIFO
|
||||
- costing by allocation
|
||||
- movement ledger untuk sales out
|
||||
|
||||
### Frontend
|
||||
- sales form
|
||||
- allocation screen
|
||||
- sales detail
|
||||
- costing preview
|
||||
|
||||
### QA
|
||||
- test sales dari satu lot
|
||||
- test sales dari banyak lot
|
||||
- test costing total
|
||||
|
||||
### Deliverables
|
||||
- penjualan campuran dari beberapa lot berjalan
|
||||
|
||||
---
|
||||
|
||||
## Sprint 6 - Picking dan Barcode Lookup
|
||||
### Backend
|
||||
- API confirm picking
|
||||
- API barcode lookup
|
||||
- API print/reprint label
|
||||
|
||||
### Frontend
|
||||
- picking screen
|
||||
- QR lookup page
|
||||
- scan-to-lot workflow
|
||||
|
||||
### QA
|
||||
- test scan lot
|
||||
- test picking actual qty
|
||||
|
||||
### Deliverables
|
||||
- gudang bisa picking pakai scan
|
||||
|
||||
---
|
||||
|
||||
## Sprint 7 - Sorting, Regrade, Shrinkage
|
||||
### Backend
|
||||
- API sorting session
|
||||
- API sorting results
|
||||
- parent-child lot relation
|
||||
- API regrade
|
||||
- API stock adjustment/shrinkage
|
||||
|
||||
### Frontend
|
||||
- sorting session form
|
||||
- regrade form
|
||||
- adjustment form
|
||||
- movement timeline update
|
||||
|
||||
### QA
|
||||
- test lot pecah jadi child lots
|
||||
- test shrinkage
|
||||
- test regrade
|
||||
|
||||
### Deliverables
|
||||
- sortasi dan regrade operasional berjalan
|
||||
|
||||
---
|
||||
|
||||
## Sprint 8 - Returns dan Traceability
|
||||
### Backend
|
||||
- API sales returns
|
||||
- API purchase returns
|
||||
- traceability report endpoint
|
||||
- forward trace dan backward trace
|
||||
|
||||
### Frontend
|
||||
- return pages
|
||||
- traceability report page
|
||||
- lot usage per sales
|
||||
- sales source per lot
|
||||
|
||||
### QA
|
||||
- test trace dari sales ke supplier
|
||||
- test trace dari supplier ke customer
|
||||
|
||||
### Deliverables
|
||||
- audit traceability end-to-end hidup
|
||||
|
||||
---
|
||||
|
||||
## Sprint 9 - Reporting dan Hardening
|
||||
### Backend
|
||||
- reports stock summary
|
||||
- stock lots
|
||||
- purchases
|
||||
- sales
|
||||
- margins
|
||||
- shrinkage
|
||||
- supplier quality
|
||||
|
||||
### Frontend
|
||||
- report pages
|
||||
- export actions
|
||||
- dashboard refinement
|
||||
|
||||
### QA
|
||||
- performance testing
|
||||
- data consistency testing
|
||||
- permission testing
|
||||
|
||||
### Deliverables
|
||||
- MVP lengkap dan siap UAT
|
||||
|
||||
---
|
||||
|
||||
## Sprint 10 - UAT & Stabilization
|
||||
### Fokus
|
||||
- bug fixing
|
||||
- UX refinement
|
||||
- validasi flow riil user
|
||||
- tuning laporan dan filter
|
||||
- training material awal
|
||||
|
||||
### Deliverables
|
||||
- versi siap pilot
|
||||
|
||||
---
|
||||
|
||||
## Jalur MVP paling ringkas kalau mau dipercepat
|
||||
Kalau Pak Wira ingin versi lebih cepat, bisa ambil jalur:
|
||||
1. Sprint 0
|
||||
2. Sprint 1
|
||||
3. Sprint 2
|
||||
4. Sprint 3
|
||||
5. Sprint 4
|
||||
6. Sprint 5
|
||||
|
||||
Artinya MVP cepat sudah mencakup:
|
||||
- master data
|
||||
- purchase
|
||||
- receipt
|
||||
- lot inventory
|
||||
- stock summary
|
||||
- sales allocation
|
||||
- costing dasar
|
||||
|
||||
Sortasi, regrade, return, dan trace report advanced bisa menyusul.
|
||||
|
||||
## Rekomendasi prioritas tertinggi
|
||||
Kalau tim terbatas, jangan mulai dari laporan dulu. Prioritas paling penting:
|
||||
1. lot model benar
|
||||
2. movement ledger benar
|
||||
3. sales allocation benar
|
||||
4. costing benar
|
||||
5. baru reporting dan polish
|
||||
|
||||
## Kesimpulan
|
||||
Task breakdown ini dibuat supaya tim bisa membangun sistem walet secara bertahap tanpa kehilangan fondasi. Pusat keberhasilan ada pada lot, allocation, movement ledger, dan traceability.
|
||||
455
docs/project-spec/walet-ui-data-contract.md
Normal file
455
docs/project-spec/walet-ui-data-contract.md
Normal file
@ -0,0 +1,455 @@
|
||||
# UI Data Contract Frontend-Backend Sistem Inventory Walet
|
||||
|
||||
## 1. Tujuan
|
||||
Dokumen ini menjelaskan kontrak data utama antara frontend dan backend agar implementasi UI tidak salah tafsir, terutama pada area lot, allocation, costing, sorting, dan traceability.
|
||||
|
||||
## 2. Prinsip Umum
|
||||
- backend adalah source of truth untuk data transaksi
|
||||
- frontend boleh menyimpan draft workflow lokal sebelum submit
|
||||
- angka quantity dan cost harus selalu dikirim dalam bentuk numerik
|
||||
- ID utama menggunakan integer/bigint
|
||||
- status harus dikirim dalam kode string yang konsisten
|
||||
- field read-only harus dibedakan jelas dari field editable
|
||||
|
||||
## 3. Format Response Umum
|
||||
Contoh standar response list:
|
||||
```json
|
||||
{
|
||||
"data": [],
|
||||
"meta": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Contoh standar response detail:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Contoh error:
|
||||
```json
|
||||
{
|
||||
"message": "Validation error",
|
||||
"errors": {
|
||||
"qty": ["qty harus lebih besar dari 0"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Purchase Contract
|
||||
### Purchase list item
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"purchase_no": "PO-20260428-001",
|
||||
"supplier": {
|
||||
"id": 1,
|
||||
"name": "Supplier A",
|
||||
"bank_name": "BCA",
|
||||
"bank_account_number": "1234567890"
|
||||
},
|
||||
"purchase_date": "2026-04-28",
|
||||
"status": "SUBMITTED",
|
||||
"line_count": 3,
|
||||
"grand_total": 1220000000
|
||||
}
|
||||
```
|
||||
|
||||
### Purchase detail
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"purchase_no": "PO-20260428-001",
|
||||
"supplier": {
|
||||
"id": 1,
|
||||
"name": "Supplier A",
|
||||
"bank_name": "BCA",
|
||||
"bank_account_number": "1234567890"
|
||||
},
|
||||
"purchase_date": "2026-04-28",
|
||||
"supplier_invoice_no": "INV-SUP-A-001",
|
||||
"status": "SUBMITTED",
|
||||
"notes": "Pembelian campuran",
|
||||
"lines": [
|
||||
{
|
||||
"id": 1,
|
||||
"item_type": { "id": 1, "name": "Jenis A" },
|
||||
"item_grade": { "id": 1, "name": "Grade A" },
|
||||
"qty_ordered": 50,
|
||||
"unit": { "id": 1, "code": "KG" },
|
||||
"unit_price": 18000000,
|
||||
"subtotal": 900000000,
|
||||
"classification_status": "FINAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Receipt Contract
|
||||
### Receipt detail
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"receipt_no": "RCV-20260428-001",
|
||||
"purchase": {
|
||||
"id": 1,
|
||||
"purchase_no": "PO-20260428-001"
|
||||
},
|
||||
"supplier": {
|
||||
"id": 1,
|
||||
"name": "Supplier A",
|
||||
"bank_name": "BCA",
|
||||
"bank_account_number": "1234567890"
|
||||
},
|
||||
"receipt_date": "2026-04-28",
|
||||
"status": "FINALIZED",
|
||||
"lines": [
|
||||
{
|
||||
"id": 1,
|
||||
"purchase_line_id": 1,
|
||||
"item_type": { "id": 1, "name": "Jenis A" },
|
||||
"item_grade": { "id": 1, "name": "Grade A" },
|
||||
"qty_received": 50,
|
||||
"qty_accepted": 50,
|
||||
"qty_rejected": 0,
|
||||
"unit_cost": 18000000,
|
||||
"warehouse": { "id": 1, "name": "Gudang Pusat" },
|
||||
"location": { "id": 1, "name": "Rak A1" }
|
||||
}
|
||||
],
|
||||
"generated_lots": [
|
||||
{
|
||||
"id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Lot Contract
|
||||
### Lot list item
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"item_type": "Jenis A",
|
||||
"item_grade": "Grade A",
|
||||
"original_qty": 50,
|
||||
"available_qty": 30,
|
||||
"unit_cost": 18000000,
|
||||
"warehouse": "Gudang Pusat",
|
||||
"location": "Rak A1",
|
||||
"aging_days": 3,
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
```
|
||||
|
||||
### Lot detail
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": {
|
||||
"id": 1,
|
||||
"name": "Supplier A",
|
||||
"bank_name": "BCA",
|
||||
"bank_account_number": "1234567890"
|
||||
},
|
||||
"item_type": {
|
||||
"id": 1,
|
||||
"name": "Jenis A"
|
||||
},
|
||||
"item_grade": {
|
||||
"id": 1,
|
||||
"name": "Grade A"
|
||||
},
|
||||
"original_qty": 50,
|
||||
"available_qty": 30,
|
||||
"reserved_qty": 0,
|
||||
"damaged_qty": 0,
|
||||
"shrinkage_qty": 0,
|
||||
"unit_cost": 18000000,
|
||||
"warehouse": {
|
||||
"id": 1,
|
||||
"name": "Gudang Pusat"
|
||||
},
|
||||
"location": {
|
||||
"id": 1,
|
||||
"name": "Rak A1"
|
||||
},
|
||||
"status": "ACTIVE",
|
||||
"parent_lot": null,
|
||||
"child_lots": [],
|
||||
"labels": [
|
||||
{
|
||||
"type": "QR",
|
||||
"value": "LOT-260428-SUPA-001"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Sales Contract
|
||||
### Sales list item
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"sales_no": "SLS-20260428-001",
|
||||
"customer": {
|
||||
"id": 1,
|
||||
"name": "Customer A",
|
||||
"bank_name": "BRI",
|
||||
"bank_account_number": "111222333444"
|
||||
},
|
||||
"sales_date": "2026-04-28",
|
||||
"status": "CONFIRMED",
|
||||
"grand_total": 660000000,
|
||||
"costing_total": 550000000,
|
||||
"gross_margin": 110000000
|
||||
}
|
||||
```
|
||||
|
||||
### Sales detail
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"sales_no": "SLS-20260428-001",
|
||||
"customer": {
|
||||
"id": 1,
|
||||
"name": "Customer A",
|
||||
"bank_name": "BRI",
|
||||
"bank_account_number": "111222333444"
|
||||
},
|
||||
"sales_date": "2026-04-28",
|
||||
"status": "CONFIRMED",
|
||||
"lines": [
|
||||
{
|
||||
"id": 1,
|
||||
"item_type": { "id": 1, "name": "Jenis A" },
|
||||
"item_grade": { "id": 1, "name": "Grade A" },
|
||||
"qty_sold": 30,
|
||||
"selling_price": 22000000,
|
||||
"subtotal": 660000000,
|
||||
"costing_total": 550000000,
|
||||
"gross_margin": 110000000,
|
||||
"allocations": [
|
||||
{
|
||||
"lot_id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"qty_allocated": 20,
|
||||
"unit_cost": 18000000,
|
||||
"total_cost": 360000000
|
||||
},
|
||||
{
|
||||
"lot_id": 4,
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"supplier": "Supplier B",
|
||||
"qty_allocated": 10,
|
||||
"unit_cost": 19000000,
|
||||
"total_cost": 190000000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Allocation Screen Contract
|
||||
### Available lots response
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"lot_id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"available_qty": 30,
|
||||
"unit_cost": 18000000,
|
||||
"received_at": "2026-04-28T09:00:00Z",
|
||||
"is_fifo_recommended": true,
|
||||
"status": "ACTIVE"
|
||||
},
|
||||
{
|
||||
"lot_id": 4,
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"supplier": "Supplier B",
|
||||
"available_qty": 8,
|
||||
"unit_cost": 19000000,
|
||||
"received_at": "2026-04-28T11:00:00Z",
|
||||
"is_fifo_recommended": false,
|
||||
"status": "ACTIVE"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Allocation submit payload
|
||||
```json
|
||||
{
|
||||
"lines": [
|
||||
{
|
||||
"sales_line_id": 1,
|
||||
"allocations": [
|
||||
{
|
||||
"inventory_lot_id": 1,
|
||||
"qty_allocated": 20
|
||||
},
|
||||
{
|
||||
"inventory_lot_id": 4,
|
||||
"qty_allocated": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Allocation summary response
|
||||
```json
|
||||
{
|
||||
"sales_line_id": 1,
|
||||
"qty_required": 30,
|
||||
"qty_allocated": 30,
|
||||
"costing_total": 550000000,
|
||||
"avg_cost": 18333333.33,
|
||||
"is_complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## 9. Sorting Contract
|
||||
### Sorting session detail
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"sorting_no": "SRT-20260428-001",
|
||||
"source_lot": {
|
||||
"id": 3,
|
||||
"lot_code": "LOT-260428-SUPB-001"
|
||||
},
|
||||
"input_qty": 40,
|
||||
"output_qty": 37,
|
||||
"shrinkage_qty": 3,
|
||||
"results": [
|
||||
{
|
||||
"lot_id": 4,
|
||||
"lot_code": "LOT-260428-SUPB-001-S1",
|
||||
"item_type": "Jenis A",
|
||||
"item_grade": "Grade A",
|
||||
"qty_result": 18
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 10. Barcode Lookup Contract
|
||||
```json
|
||||
{
|
||||
"lot_id": 1,
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"item_type": "Jenis A",
|
||||
"grade": "Grade A",
|
||||
"available_qty": 30,
|
||||
"warehouse": "Gudang Pusat",
|
||||
"location": "Rak A1",
|
||||
"status": "ACTIVE",
|
||||
"actions": {
|
||||
"can_hold": true,
|
||||
"can_release": false,
|
||||
"can_transfer": true,
|
||||
"can_pick": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11. Report Contract
|
||||
### Stock summary row
|
||||
```json
|
||||
{
|
||||
"item_type": "Jenis A",
|
||||
"item_grade": "Grade A",
|
||||
"warehouse": "Gudang Pusat",
|
||||
"qty_total": 38,
|
||||
"inventory_value": 730000000,
|
||||
"active_lot_count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### Traceability row
|
||||
```json
|
||||
{
|
||||
"sales_no": "SLS-20260428-001",
|
||||
"customer": "Customer A",
|
||||
"item": "Jenis A / Grade A",
|
||||
"qty_sold": 30,
|
||||
"sources": [
|
||||
{
|
||||
"lot_code": "LOT-260428-SUPA-001",
|
||||
"supplier": "Supplier A",
|
||||
"qty": 20,
|
||||
"purchase_no": "PO-20260428-001"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 12. Frontend Editable vs Readonly Rules
|
||||
### Editable examples
|
||||
- qty_received
|
||||
- qty_accepted
|
||||
- selling_price
|
||||
- qty_allocated draft
|
||||
- qty_picked actual
|
||||
- notes
|
||||
|
||||
### Readonly examples
|
||||
- lot_code
|
||||
- costing_total final hasil backend
|
||||
- gross_margin final hasil backend
|
||||
- parent_lot relation
|
||||
- source trace fields
|
||||
|
||||
## 13. Status Codes yang Harus Konsisten
|
||||
### Purchase
|
||||
- DRAFT
|
||||
- SUBMITTED
|
||||
- CANCELLED
|
||||
|
||||
### Receipt
|
||||
- DRAFT
|
||||
- FINALIZED
|
||||
|
||||
### Lot
|
||||
- ACTIVE
|
||||
- HOLD
|
||||
- CLOSED
|
||||
- REJECTED
|
||||
|
||||
### Sales
|
||||
- DRAFT
|
||||
- ALLOCATED
|
||||
- PICKED
|
||||
- CONFIRMED
|
||||
- CANCELLED
|
||||
|
||||
## 14. UI Validation Expectations
|
||||
Frontend harus validasi cepat untuk:
|
||||
- qty > 0
|
||||
- total allocation sama dengan qty line
|
||||
- qty result sorting tidak melebihi input
|
||||
- required fields tidak kosong
|
||||
|
||||
Namun final validation tetap di backend.
|
||||
|
||||
## 15. Kesimpulan
|
||||
Kontrak data ini dibuat agar frontend dan backend bicara bahasa yang sama, khususnya pada lot, allocation, sorting, traceability, dan costing yang merupakan inti sistem walet ini.
|
||||
331
docs/project-spec/walet-user-flow-visual-for-figma.md
Normal file
331
docs/project-spec/walet-user-flow-visual-for-figma.md
Normal file
@ -0,0 +1,331 @@
|
||||
# User Flow Visual untuk Figma
|
||||
## Sistem Inventory Sarang Burung Walet
|
||||
|
||||
Dokumen ini dibuat agar desainer bisa langsung menggambar user flow visual di Figma atau FigJam.
|
||||
|
||||
---
|
||||
|
||||
# 1. Node Legend yang Disarankan
|
||||
Gunakan standar shape berikut di Figma/FigJam:
|
||||
|
||||
- **Rectangle** = screen/page
|
||||
- **Rounded rectangle** = modal/drawer/panel aksi
|
||||
- **Diamond** = decision point
|
||||
- **Parallelogram** = input/scanning/manual entry
|
||||
- **Small tag/badge** = status atau note penting
|
||||
- **Arrow** = alur utama
|
||||
- **Dashed arrow** = alur alternatif / exception flow
|
||||
|
||||
Warna saran:
|
||||
- Biru = flow utama
|
||||
- Hijau = success path
|
||||
- Oranye = warning/manual override
|
||||
- Merah = error/blocked state
|
||||
- Ungu = traceability / lookup path
|
||||
|
||||
---
|
||||
|
||||
# 2. Sitemap Ringkas
|
||||
Susun dari kiri ke kanan:
|
||||
|
||||
```text
|
||||
Login
|
||||
-> Dashboard
|
||||
-> Master Data
|
||||
-> Suppliers
|
||||
-> Customers
|
||||
-> Item Types
|
||||
-> Item Grades
|
||||
-> Warehouses
|
||||
-> Purchases
|
||||
-> Receipts
|
||||
-> Lots
|
||||
-> Sorting
|
||||
-> Sales
|
||||
-> Adjustments
|
||||
-> Returns
|
||||
-> Barcode Lookup
|
||||
-> Reports
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 3. Flow 1. Purchase to Receipt to Lot
|
||||
## Tujuan
|
||||
Menggambarkan alur dari pembelian sampai lot terbentuk.
|
||||
|
||||
## Node urutan
|
||||
```text
|
||||
Dashboard
|
||||
-> Purchase List
|
||||
-> Purchase Form
|
||||
-> [Decision: Save Draft or Submit?]
|
||||
-> Save Draft -> Purchase Detail
|
||||
-> Submit -> Purchase Detail
|
||||
-> Create Receipt
|
||||
-> Receipt Form
|
||||
-> [Decision: Finalize Receipt?]
|
||||
-> No -> Draft Receipt Detail
|
||||
-> Yes -> Generate Lots
|
||||
-> Receipt Detail
|
||||
-> Lot Detail
|
||||
```
|
||||
|
||||
## Notes untuk designer
|
||||
- tampilkan supplier info termasuk bank info di purchase/receipt
|
||||
- receipt punya branch untuk accepted/rejected qty
|
||||
- setelah finalize, harus ada cabang ke lot result
|
||||
|
||||
---
|
||||
|
||||
# 4. Flow 2. Lot to Sorting / Regrade
|
||||
## Tujuan
|
||||
Menggambarkan alur perubahan lot setelah QC/sortasi.
|
||||
|
||||
## Node urutan
|
||||
```text
|
||||
Dashboard
|
||||
-> Lot List
|
||||
-> Lot Detail
|
||||
-> [Decision: Need Sorting or Regrade?]
|
||||
-> Sorting
|
||||
-> Sorting Session Form
|
||||
-> [Decision: Output valid?]
|
||||
-> No -> Error / revise rows
|
||||
-> Yes -> Child Lots Created
|
||||
-> Sorting Result Detail
|
||||
-> Child Lot Detail
|
||||
-> Regrade
|
||||
-> Regrade Form
|
||||
-> [Decision: Qty valid?]
|
||||
-> No -> Error
|
||||
-> Yes -> New Grade Lot / Updated Lot
|
||||
-> Lot Detail
|
||||
```
|
||||
|
||||
## Notes
|
||||
- decision node harus jelas memisahkan sorting dan regrade
|
||||
- gunakan warna oranye untuk warning jika qty tidak balance
|
||||
- gunakan node kecil untuk menandai shrinkage/reject
|
||||
|
||||
---
|
||||
|
||||
# 5. Flow 3. Sales Order to Allocation to Picking
|
||||
## Tujuan
|
||||
Ini flow paling penting untuk desain, karena inti kompleksitas sistem ada di sini.
|
||||
|
||||
## Node urutan
|
||||
```text
|
||||
Dashboard
|
||||
-> Sales List
|
||||
-> Sales Form
|
||||
-> Sales Detail
|
||||
-> Allocation Screen
|
||||
-> [Decision: Auto allocate or Manual allocate?]
|
||||
-> Auto Allocate FIFO
|
||||
-> Manual Select Lots
|
||||
-> [Decision: Allocation complete?]
|
||||
-> No -> Back to Allocation Screen
|
||||
-> Yes -> Save Allocation
|
||||
-> Picking Screen
|
||||
-> [Decision: Picked qty matches allocation?]
|
||||
-> Yes -> Confirm Picking
|
||||
-> No -> Variance Flow
|
||||
-> Sales Detail Final
|
||||
```
|
||||
|
||||
## Variance subflow
|
||||
```text
|
||||
Picking Screen
|
||||
-> Variance Warning
|
||||
-> [Decision: allow override?]
|
||||
-> No -> Back to Picking
|
||||
-> Yes -> Save Variance + Audit
|
||||
-> Sales Detail Final
|
||||
```
|
||||
|
||||
## Notes
|
||||
- allocation page perlu ditandai sebagai "critical workflow"
|
||||
- tampilkan alur campuran lot dari beberapa supplier
|
||||
- gunakan dashed flow untuk manual override
|
||||
|
||||
---
|
||||
|
||||
# 6. Flow 4. Barcode / QR Lookup
|
||||
## Tujuan
|
||||
Flow cepat untuk user gudang.
|
||||
|
||||
## Node urutan
|
||||
```text
|
||||
Dashboard
|
||||
-> Barcode Scan Page
|
||||
-> [Decision: Scan success?]
|
||||
-> No -> Manual Input
|
||||
-> Yes -> Lookup Result
|
||||
-> [Decision: What next?]
|
||||
-> Open Lot Detail
|
||||
-> Transfer Lot
|
||||
-> Hold/Release Lot
|
||||
-> Picking Context
|
||||
```
|
||||
|
||||
## Notes
|
||||
- flow ini sebaiknya punya versi mobile frame
|
||||
- scan success dan scan fail harus digambar
|
||||
|
||||
---
|
||||
|
||||
# 7. Flow 5. Stock Adjustment / Shrinkage
|
||||
## Tujuan
|
||||
Menggambarkan flow perubahan stok di luar transaksi normal.
|
||||
|
||||
## Node urutan
|
||||
```text
|
||||
Dashboard
|
||||
-> Lot Detail / Adjustment Menu
|
||||
-> Adjustment Form
|
||||
-> [Decision: Above approval threshold?]
|
||||
-> No -> Post Adjustment
|
||||
-> Yes -> Pending Approval
|
||||
-> Approver Review
|
||||
-> [Decision: Approve?]
|
||||
-> Reject -> Back to Draft/Cancelled
|
||||
-> Approve -> Post Adjustment
|
||||
-> Updated Lot Detail
|
||||
-> Movement Ledger Updated
|
||||
```
|
||||
|
||||
## Notes
|
||||
- cocok digambar dengan lane approval terpisah
|
||||
- gunakan merah untuk shrinkage/loss branch
|
||||
|
||||
---
|
||||
|
||||
# 8. Flow 6. Sales Return
|
||||
## Node urutan
|
||||
```text
|
||||
Sales Detail
|
||||
-> Create Sales Return
|
||||
-> Sales Return Form
|
||||
-> [Decision: Return linked to source lot?]
|
||||
-> Yes -> Return to existing lot / controlled flow
|
||||
-> No -> Create return lot
|
||||
-> [Decision: Condition good?]
|
||||
-> Yes -> Restock
|
||||
-> No -> Regrade / Reject
|
||||
-> Return Detail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 9. Flow 7. Purchase Return
|
||||
## Node urutan
|
||||
```text
|
||||
Purchase Detail / Lot Detail
|
||||
-> Create Purchase Return
|
||||
-> Purchase Return Form
|
||||
-> Confirm Return
|
||||
-> Lot Reduced
|
||||
-> Movement Ledger Updated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 10. Flow 8. Traceability Lookup
|
||||
## Tujuan
|
||||
Membantu designer memahami bagaimana user menelusuri asal barang.
|
||||
|
||||
## Backward trace
|
||||
```text
|
||||
Sales Detail
|
||||
-> Sales Line
|
||||
-> Allocation Rows
|
||||
-> Lot Detail
|
||||
-> Receipt Detail
|
||||
-> Purchase Detail
|
||||
-> Supplier Detail
|
||||
```
|
||||
|
||||
## Forward trace
|
||||
```text
|
||||
Supplier Detail
|
||||
-> Purchase List
|
||||
-> Purchase Detail
|
||||
-> Lots Created
|
||||
-> Sales Allocations
|
||||
-> Sales Detail
|
||||
-> Customer Detail
|
||||
```
|
||||
|
||||
## Notes
|
||||
- trace flow bisa diberi warna ungu
|
||||
- cocok dibuat sebagai separate flow map
|
||||
|
||||
---
|
||||
|
||||
# 11. Rekomendasi Layout Frame di Figma/FigJam
|
||||
## Board 1. Sitemap
|
||||
- high-level only
|
||||
|
||||
## Board 2. Core Transaction Flows
|
||||
- purchase -> receipt -> lot
|
||||
- lot -> sorting/regrade
|
||||
- sales -> allocation -> picking
|
||||
|
||||
## Board 3. Supporting Flows
|
||||
- scan lookup
|
||||
- adjustment
|
||||
- return
|
||||
- traceability
|
||||
|
||||
## Board 4. Role Overlay
|
||||
Tambahkan badge kecil pada node untuk role:
|
||||
- OWN
|
||||
- PUR
|
||||
- WH
|
||||
- QC
|
||||
- SAL
|
||||
|
||||
---
|
||||
|
||||
# 12. Rekomendasi Label per Screen
|
||||
Gunakan format:
|
||||
- `Screen: Purchase Form`
|
||||
- `Decision: Allocation complete?`
|
||||
- `Modal: Hold Lot Confirmation`
|
||||
- `Exception: Pick qty variance`
|
||||
|
||||
Ini bikin flow mudah dibaca saat handoff.
|
||||
|
||||
---
|
||||
|
||||
# 13. Rekomendasi untuk Prototype Link
|
||||
Untuk prototype yang perlu diklik duluan:
|
||||
1. Dashboard
|
||||
2. Purchase Form
|
||||
3. Receipt Form
|
||||
4. Lot Detail
|
||||
5. Sales Form
|
||||
6. Allocation Screen
|
||||
7. Picking Screen
|
||||
8. Barcode Scan
|
||||
|
||||
---
|
||||
|
||||
# 14. Deliverable yang Disarankan dari Designer
|
||||
Setelah menggambar flow ini, output minimal:
|
||||
- 1 figjam board user flow
|
||||
- 1 screen map desktop
|
||||
- 1 screen map mobile operasional
|
||||
- clickable prototype untuk sales allocation flow
|
||||
|
||||
---
|
||||
|
||||
# 15. Penutup
|
||||
Flow yang paling penting untuk digambar dulu adalah:
|
||||
- purchase -> receipt -> lot
|
||||
- lot -> sorting/regrade
|
||||
- sales -> allocation -> picking
|
||||
- scan -> lookup -> action
|
||||
|
||||
Kalau empat flow ini sudah jelas di Figma/FigJam, desainer akan jauh lebih cepat masuk ke desain screen detail.
|
||||
428
docs/project-spec/walet-wireframe.html
Normal file
428
docs/project-spec/walet-wireframe.html
Normal file
@ -0,0 +1,428 @@
|
||||
<!doctype html><html><head><meta charset="utf-8"><style>@page { size:A4; margin:2cm 1.6cm; } body { font-family: Arial, Helvetica, sans-serif; font-size:11pt; line-height:1.55; } pre { white-space: pre-wrap; }</style></head><body><pre># Wireframe Layar Aplikasi Sistem Inventory Walet
|
||||
|
||||
## 1. Dashboard
|
||||
### Tujuan
|
||||
Memberikan gambaran cepat kondisi bisnis.
|
||||
|
||||
### Komponen
|
||||
- Total stok aktif
|
||||
- Nilai inventory
|
||||
- Pembelian bulan ini
|
||||
- Penjualan bulan ini
|
||||
- Susut bulan ini
|
||||
- Top 5 supplier
|
||||
- Top 5 customer
|
||||
- Lot aging alert
|
||||
- Lot hold alert
|
||||
- Shortcut ke Purchase, Receiving, Sales, Inventory
|
||||
|
||||
### Widget utama
|
||||
- Stok per jenis-grade
|
||||
- Margin per periode
|
||||
- Grafik pembelian vs penjualan
|
||||
- Susut per supplier
|
||||
|
||||
---
|
||||
|
||||
## 2. Purchase List
|
||||
### Tujuan
|
||||
Melihat semua transaksi pembelian.
|
||||
|
||||
Catatan master terkait:
|
||||
- data supplier perlu menyimpan nama bank dan nomor rekening untuk kebutuhan pembayaran
|
||||
|
||||
### Komponen
|
||||
- Filter tanggal
|
||||
- Filter supplier
|
||||
- Filter status
|
||||
- Tombol buat pembelian baru
|
||||
- Tabel:
|
||||
- nomor pembelian
|
||||
- supplier
|
||||
- tanggal
|
||||
- total
|
||||
- status
|
||||
- jumlah line
|
||||
- aksi detail/edit
|
||||
|
||||
---
|
||||
|
||||
## 3. Purchase Form
|
||||
### Tujuan
|
||||
Membuat transaksi pembelian multi jenis dan multi grade.
|
||||
|
||||
### Header
|
||||
- Purchase no
|
||||
- Supplier
|
||||
- Tanggal pembelian
|
||||
- Invoice supplier
|
||||
- Catatan
|
||||
|
||||
### Detail line items
|
||||
Kolom:
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Satuan
|
||||
- Harga beli
|
||||
- Subtotal
|
||||
- Status klasifikasi
|
||||
- Catatan
|
||||
|
||||
### Aksi
|
||||
- Tambah baris
|
||||
- Simpan draft
|
||||
- Submit
|
||||
- Print
|
||||
|
||||
---
|
||||
|
||||
## 4. Receipt Form
|
||||
### Tujuan
|
||||
Menerima barang dari pembelian dan membuat lot.
|
||||
|
||||
### Header
|
||||
- Receipt no
|
||||
- Referensi purchase
|
||||
- Supplier
|
||||
- Tanggal terima
|
||||
- Petugas penerima
|
||||
|
||||
### Tabel line receiving
|
||||
- Item purchase
|
||||
- Qty ordered
|
||||
- Qty received
|
||||
- Qty accepted
|
||||
- Qty rejected
|
||||
- Unit cost
|
||||
- Status
|
||||
- Catatan
|
||||
|
||||
### Aksi
|
||||
- Generate lot
|
||||
- Print QR label
|
||||
- Simpan receipt
|
||||
|
||||
---
|
||||
|
||||
## 5. Receipt Detail
|
||||
### Tujuan
|
||||
Melihat hasil penerimaan dan lot yang terbentuk.
|
||||
|
||||
### Komponen
|
||||
- Ringkasan receipt
|
||||
- Daftar lot hasil receipt
|
||||
- Kode lot
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- QR status
|
||||
- Tombol print ulang label
|
||||
|
||||
---
|
||||
|
||||
## 6. Stock Summary
|
||||
### Tujuan
|
||||
Melihat stok ringkas per jenis-grade.
|
||||
|
||||
### Komponen
|
||||
- Filter gudang
|
||||
- Filter jenis
|
||||
- Filter grade
|
||||
- Tabel:
|
||||
- jenis
|
||||
- grade
|
||||
- qty total
|
||||
- nilai total
|
||||
- jumlah lot aktif
|
||||
|
||||
---
|
||||
|
||||
## 7. Stock Lot List
|
||||
### Tujuan
|
||||
Melihat stok detail berbasis lot.
|
||||
|
||||
### Tabel
|
||||
- Lot code
|
||||
- Supplier
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty awal
|
||||
- Qty tersedia
|
||||
- Unit cost
|
||||
- Tanggal masuk
|
||||
- Aging
|
||||
- Status
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- Aksi detail
|
||||
|
||||
### Filter
|
||||
- supplier
|
||||
- jenis
|
||||
- grade
|
||||
- status
|
||||
- gudang
|
||||
- aging
|
||||
|
||||
---
|
||||
|
||||
## 8. Lot Detail
|
||||
### Tujuan
|
||||
Menjadi pusat traceability satu lot.
|
||||
|
||||
### Section
|
||||
#### Informasi utama
|
||||
- Lot code
|
||||
- Supplier
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty awal
|
||||
- Qty available
|
||||
- Unit cost
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- Status
|
||||
|
||||
#### Parent-child relation
|
||||
- Parent lot
|
||||
- Child lots hasil sortasi/regrade
|
||||
|
||||
#### Movement history
|
||||
- receiving
|
||||
- sorting
|
||||
- adjustment
|
||||
- transfer
|
||||
- sales allocation
|
||||
- return
|
||||
|
||||
#### Sales usage
|
||||
- invoice mana saja yang memakai lot ini
|
||||
- qty per invoice
|
||||
|
||||
#### Aksi
|
||||
- print ulang label
|
||||
- hold lot
|
||||
- release lot
|
||||
- pindah lokasi
|
||||
- adjustment
|
||||
- regrade
|
||||
|
||||
---
|
||||
|
||||
## 9. Sorting Session Form
|
||||
### Tujuan
|
||||
Memecah satu lot menjadi beberapa lot hasil sortasi.
|
||||
|
||||
### Input utama
|
||||
- Source lot
|
||||
- Qty input
|
||||
- Tanggal sortasi
|
||||
- Operator
|
||||
- Catatan
|
||||
|
||||
### Hasil sortasi table
|
||||
- Jenis hasil
|
||||
- Grade hasil
|
||||
- Qty hasil
|
||||
- Cost
|
||||
- Catatan
|
||||
|
||||
### Additional
|
||||
- Qty shrinkage
|
||||
- Qty reject
|
||||
|
||||
### Aksi
|
||||
- Generate child lots
|
||||
- Simpan sesi
|
||||
|
||||
---
|
||||
|
||||
## 10. Regrade Form
|
||||
### Tujuan
|
||||
Memindahkan sebagian qty dari satu grade ke grade lain.
|
||||
|
||||
### Komponen
|
||||
- Source lot
|
||||
- Grade asal
|
||||
- Grade tujuan
|
||||
- Qty pindah
|
||||
- Alasan
|
||||
- Catatan
|
||||
|
||||
### Output
|
||||
- lot lama berkurang
|
||||
- lot baru terbentuk atau ditambah
|
||||
|
||||
---
|
||||
|
||||
## 11. Sales Form
|
||||
### Tujuan
|
||||
Membuat transaksi penjualan.
|
||||
|
||||
Catatan master terkait:
|
||||
- data customer perlu menyimpan nama bank dan nomor rekening untuk kebutuhan pembayaran/settlement
|
||||
|
||||
### Header
|
||||
- Sales no
|
||||
- Customer
|
||||
- Tanggal
|
||||
- Catatan
|
||||
|
||||
### Detail lines
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Satuan
|
||||
- Harga jual
|
||||
- Subtotal
|
||||
|
||||
### Aksi
|
||||
- Simpan draft
|
||||
- Lanjut ke allocation
|
||||
- Submit
|
||||
|
||||
---
|
||||
|
||||
## 12. Allocation Screen
|
||||
### Tujuan
|
||||
Mengalokasikan kebutuhan penjualan ke satu atau banyak lot.
|
||||
|
||||
### Layout
|
||||
#### Kiri
|
||||
- informasi sales line
|
||||
- jenis
|
||||
- grade
|
||||
- qty dibutuhkan
|
||||
|
||||
#### Kanan
|
||||
- daftar lot tersedia
|
||||
- lot code
|
||||
- supplier
|
||||
- qty available
|
||||
- unit cost
|
||||
- tanggal masuk
|
||||
- rekomendasi FIFO
|
||||
|
||||
### Interaksi
|
||||
- auto allocate
|
||||
- manual select qty per lot
|
||||
- validasi total allocation = qty line
|
||||
- tampil total costing hasil allocation
|
||||
|
||||
---
|
||||
|
||||
## 13. Picking Screen
|
||||
### Tujuan
|
||||
Memvalidasi pengambilan barang nyata dari lot teralokasi.
|
||||
|
||||
### Komponen
|
||||
- scan QR lot
|
||||
- tampil info lot
|
||||
- qty dialokasikan
|
||||
- qty diambil aktual
|
||||
- selisih jika ada
|
||||
- konfirmasi picking selesai
|
||||
|
||||
---
|
||||
|
||||
## 14. Transfer Form
|
||||
### Tujuan
|
||||
Memindahkan lot antar gudang atau lokasi.
|
||||
|
||||
### Komponen
|
||||
- scan/pilih lot
|
||||
- gudang asal
|
||||
- lokasi asal
|
||||
- gudang tujuan
|
||||
- lokasi tujuan
|
||||
- qty pindah
|
||||
- catatan
|
||||
|
||||
---
|
||||
|
||||
## 15. Stock Adjustment Form
|
||||
### Tujuan
|
||||
Mencatat perubahan stok selain transaksi normal.
|
||||
|
||||
### Komponen
|
||||
- lot
|
||||
- qty before
|
||||
- qty change
|
||||
- qty after
|
||||
- jenis adjustment
|
||||
- alasan
|
||||
- cost impact
|
||||
- catatan
|
||||
|
||||
---
|
||||
|
||||
## 16. Barcode / QR Lookup
|
||||
### Tujuan
|
||||
Lookup cepat dari hasil scan.
|
||||
|
||||
### Hasil scan menampilkan
|
||||
- lot code
|
||||
- supplier
|
||||
- jenis
|
||||
- grade
|
||||
- qty available
|
||||
- cost
|
||||
- lokasi
|
||||
- status
|
||||
- histori singkat
|
||||
|
||||
### Aksi cepat
|
||||
- buka detail lot
|
||||
- print label ulang
|
||||
- pindah lokasi
|
||||
- hold/release
|
||||
|
||||
---
|
||||
|
||||
## 17. Reports
|
||||
### Jenis laporan
|
||||
- Pembelian
|
||||
- Penerimaan
|
||||
- Stok summary
|
||||
- Stok lot
|
||||
- Aging
|
||||
- Sortasi
|
||||
- Sales
|
||||
- Margin
|
||||
- Shrinkage
|
||||
- Supplier quality
|
||||
- Traceability
|
||||
|
||||
### Filter umum
|
||||
- tanggal
|
||||
- supplier
|
||||
- customer
|
||||
- jenis
|
||||
- grade
|
||||
- gudang
|
||||
- status
|
||||
|
||||
---
|
||||
|
||||
## 18. Design Notes
|
||||
- halaman operasional harus mobile-friendly
|
||||
- allocation screen harus cepat, jangan terlalu penuh
|
||||
- lot detail harus jadi layar kunci karena pusat trace
|
||||
- scan workflow harus seminim mungkin input manual
|
||||
- warna status penting, misal active, hold, closed, rejected
|
||||
|
||||
## 19. Prioritas Wireframe MVP
|
||||
Urutan yang sebaiknya didesain dulu:
|
||||
1. Dashboard
|
||||
2. Purchase Form
|
||||
3. Receipt Form
|
||||
4. Stock Lot List
|
||||
5. Lot Detail
|
||||
6. Sales Form
|
||||
7. Allocation Screen
|
||||
8. Picking Screen
|
||||
9. Sorting Session Form
|
||||
10. Barcode Lookup</pre></body></html>
|
||||
428
docs/project-spec/walet-wireframe.md
Normal file
428
docs/project-spec/walet-wireframe.md
Normal file
@ -0,0 +1,428 @@
|
||||
# Wireframe Layar Aplikasi Sistem Inventory Walet
|
||||
|
||||
## 1. Dashboard
|
||||
### Tujuan
|
||||
Memberikan gambaran cepat kondisi bisnis.
|
||||
|
||||
### Komponen
|
||||
- Total stok aktif
|
||||
- Nilai inventory
|
||||
- Pembelian bulan ini
|
||||
- Penjualan bulan ini
|
||||
- Susut bulan ini
|
||||
- Top 5 supplier
|
||||
- Top 5 customer
|
||||
- Lot aging alert
|
||||
- Lot hold alert
|
||||
- Shortcut ke Purchase, Receiving, Sales, Inventory
|
||||
|
||||
### Widget utama
|
||||
- Stok per jenis-grade
|
||||
- Margin per periode
|
||||
- Grafik pembelian vs penjualan
|
||||
- Susut per supplier
|
||||
|
||||
---
|
||||
|
||||
## 2. Purchase List
|
||||
### Tujuan
|
||||
Melihat semua transaksi pembelian.
|
||||
|
||||
Catatan master terkait:
|
||||
- data supplier perlu menyimpan nama bank dan nomor rekening untuk kebutuhan pembayaran
|
||||
|
||||
### Komponen
|
||||
- Filter tanggal
|
||||
- Filter supplier
|
||||
- Filter status
|
||||
- Tombol buat pembelian baru
|
||||
- Tabel:
|
||||
- nomor pembelian
|
||||
- supplier
|
||||
- tanggal
|
||||
- total
|
||||
- status
|
||||
- jumlah line
|
||||
- aksi detail/edit
|
||||
|
||||
---
|
||||
|
||||
## 3. Purchase Form
|
||||
### Tujuan
|
||||
Membuat transaksi pembelian multi jenis dan multi grade.
|
||||
|
||||
### Header
|
||||
- Purchase no
|
||||
- Supplier
|
||||
- Tanggal pembelian
|
||||
- Invoice supplier
|
||||
- Catatan
|
||||
|
||||
### Detail line items
|
||||
Kolom:
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Satuan
|
||||
- Harga beli
|
||||
- Subtotal
|
||||
- Status klasifikasi
|
||||
- Catatan
|
||||
|
||||
### Aksi
|
||||
- Tambah baris
|
||||
- Simpan draft
|
||||
- Submit
|
||||
- Print
|
||||
|
||||
---
|
||||
|
||||
## 4. Receipt Form
|
||||
### Tujuan
|
||||
Menerima barang dari pembelian dan membuat lot.
|
||||
|
||||
### Header
|
||||
- Receipt no
|
||||
- Referensi purchase
|
||||
- Supplier
|
||||
- Tanggal terima
|
||||
- Petugas penerima
|
||||
|
||||
### Tabel line receiving
|
||||
- Item purchase
|
||||
- Qty ordered
|
||||
- Qty received
|
||||
- Qty accepted
|
||||
- Qty rejected
|
||||
- Unit cost
|
||||
- Status
|
||||
- Catatan
|
||||
|
||||
### Aksi
|
||||
- Generate lot
|
||||
- Print QR label
|
||||
- Simpan receipt
|
||||
|
||||
---
|
||||
|
||||
## 5. Receipt Detail
|
||||
### Tujuan
|
||||
Melihat hasil penerimaan dan lot yang terbentuk.
|
||||
|
||||
### Komponen
|
||||
- Ringkasan receipt
|
||||
- Daftar lot hasil receipt
|
||||
- Kode lot
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- QR status
|
||||
- Tombol print ulang label
|
||||
|
||||
---
|
||||
|
||||
## 6. Stock Summary
|
||||
### Tujuan
|
||||
Melihat stok ringkas per jenis-grade.
|
||||
|
||||
### Komponen
|
||||
- Filter gudang
|
||||
- Filter jenis
|
||||
- Filter grade
|
||||
- Tabel:
|
||||
- jenis
|
||||
- grade
|
||||
- qty total
|
||||
- nilai total
|
||||
- jumlah lot aktif
|
||||
|
||||
---
|
||||
|
||||
## 7. Stock Lot List
|
||||
### Tujuan
|
||||
Melihat stok detail berbasis lot.
|
||||
|
||||
### Tabel
|
||||
- Lot code
|
||||
- Supplier
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty awal
|
||||
- Qty tersedia
|
||||
- Unit cost
|
||||
- Tanggal masuk
|
||||
- Aging
|
||||
- Status
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- Aksi detail
|
||||
|
||||
### Filter
|
||||
- supplier
|
||||
- jenis
|
||||
- grade
|
||||
- status
|
||||
- gudang
|
||||
- aging
|
||||
|
||||
---
|
||||
|
||||
## 8. Lot Detail
|
||||
### Tujuan
|
||||
Menjadi pusat traceability satu lot.
|
||||
|
||||
### Section
|
||||
#### Informasi utama
|
||||
- Lot code
|
||||
- Supplier
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty awal
|
||||
- Qty available
|
||||
- Unit cost
|
||||
- Gudang
|
||||
- Lokasi
|
||||
- Status
|
||||
|
||||
#### Parent-child relation
|
||||
- Parent lot
|
||||
- Child lots hasil sortasi/regrade
|
||||
|
||||
#### Movement history
|
||||
- receiving
|
||||
- sorting
|
||||
- adjustment
|
||||
- transfer
|
||||
- sales allocation
|
||||
- return
|
||||
|
||||
#### Sales usage
|
||||
- invoice mana saja yang memakai lot ini
|
||||
- qty per invoice
|
||||
|
||||
#### Aksi
|
||||
- print ulang label
|
||||
- hold lot
|
||||
- release lot
|
||||
- pindah lokasi
|
||||
- adjustment
|
||||
- regrade
|
||||
|
||||
---
|
||||
|
||||
## 9. Sorting Session Form
|
||||
### Tujuan
|
||||
Memecah satu lot menjadi beberapa lot hasil sortasi.
|
||||
|
||||
### Input utama
|
||||
- Source lot
|
||||
- Qty input
|
||||
- Tanggal sortasi
|
||||
- Operator
|
||||
- Catatan
|
||||
|
||||
### Hasil sortasi table
|
||||
- Jenis hasil
|
||||
- Grade hasil
|
||||
- Qty hasil
|
||||
- Cost
|
||||
- Catatan
|
||||
|
||||
### Additional
|
||||
- Qty shrinkage
|
||||
- Qty reject
|
||||
|
||||
### Aksi
|
||||
- Generate child lots
|
||||
- Simpan sesi
|
||||
|
||||
---
|
||||
|
||||
## 10. Regrade Form
|
||||
### Tujuan
|
||||
Memindahkan sebagian qty dari satu grade ke grade lain.
|
||||
|
||||
### Komponen
|
||||
- Source lot
|
||||
- Grade asal
|
||||
- Grade tujuan
|
||||
- Qty pindah
|
||||
- Alasan
|
||||
- Catatan
|
||||
|
||||
### Output
|
||||
- lot lama berkurang
|
||||
- lot baru terbentuk atau ditambah
|
||||
|
||||
---
|
||||
|
||||
## 11. Sales Form
|
||||
### Tujuan
|
||||
Membuat transaksi penjualan.
|
||||
|
||||
Catatan master terkait:
|
||||
- data customer perlu menyimpan nama bank dan nomor rekening untuk kebutuhan pembayaran/settlement
|
||||
|
||||
### Header
|
||||
- Sales no
|
||||
- Customer
|
||||
- Tanggal
|
||||
- Catatan
|
||||
|
||||
### Detail lines
|
||||
- Jenis
|
||||
- Grade
|
||||
- Qty
|
||||
- Satuan
|
||||
- Harga jual
|
||||
- Subtotal
|
||||
|
||||
### Aksi
|
||||
- Simpan draft
|
||||
- Lanjut ke allocation
|
||||
- Submit
|
||||
|
||||
---
|
||||
|
||||
## 12. Allocation Screen
|
||||
### Tujuan
|
||||
Mengalokasikan kebutuhan penjualan ke satu atau banyak lot.
|
||||
|
||||
### Layout
|
||||
#### Kiri
|
||||
- informasi sales line
|
||||
- jenis
|
||||
- grade
|
||||
- qty dibutuhkan
|
||||
|
||||
#### Kanan
|
||||
- daftar lot tersedia
|
||||
- lot code
|
||||
- supplier
|
||||
- qty available
|
||||
- unit cost
|
||||
- tanggal masuk
|
||||
- rekomendasi FIFO
|
||||
|
||||
### Interaksi
|
||||
- auto allocate
|
||||
- manual select qty per lot
|
||||
- validasi total allocation = qty line
|
||||
- tampil total costing hasil allocation
|
||||
|
||||
---
|
||||
|
||||
## 13. Picking Screen
|
||||
### Tujuan
|
||||
Memvalidasi pengambilan barang nyata dari lot teralokasi.
|
||||
|
||||
### Komponen
|
||||
- scan QR lot
|
||||
- tampil info lot
|
||||
- qty dialokasikan
|
||||
- qty diambil aktual
|
||||
- selisih jika ada
|
||||
- konfirmasi picking selesai
|
||||
|
||||
---
|
||||
|
||||
## 14. Transfer Form
|
||||
### Tujuan
|
||||
Memindahkan lot antar gudang atau lokasi.
|
||||
|
||||
### Komponen
|
||||
- scan/pilih lot
|
||||
- gudang asal
|
||||
- lokasi asal
|
||||
- gudang tujuan
|
||||
- lokasi tujuan
|
||||
- qty pindah
|
||||
- catatan
|
||||
|
||||
---
|
||||
|
||||
## 15. Stock Adjustment Form
|
||||
### Tujuan
|
||||
Mencatat perubahan stok selain transaksi normal.
|
||||
|
||||
### Komponen
|
||||
- lot
|
||||
- qty before
|
||||
- qty change
|
||||
- qty after
|
||||
- jenis adjustment
|
||||
- alasan
|
||||
- cost impact
|
||||
- catatan
|
||||
|
||||
---
|
||||
|
||||
## 16. Barcode / QR Lookup
|
||||
### Tujuan
|
||||
Lookup cepat dari hasil scan.
|
||||
|
||||
### Hasil scan menampilkan
|
||||
- lot code
|
||||
- supplier
|
||||
- jenis
|
||||
- grade
|
||||
- qty available
|
||||
- cost
|
||||
- lokasi
|
||||
- status
|
||||
- histori singkat
|
||||
|
||||
### Aksi cepat
|
||||
- buka detail lot
|
||||
- print label ulang
|
||||
- pindah lokasi
|
||||
- hold/release
|
||||
|
||||
---
|
||||
|
||||
## 17. Reports
|
||||
### Jenis laporan
|
||||
- Pembelian
|
||||
- Penerimaan
|
||||
- Stok summary
|
||||
- Stok lot
|
||||
- Aging
|
||||
- Sortasi
|
||||
- Sales
|
||||
- Margin
|
||||
- Shrinkage
|
||||
- Supplier quality
|
||||
- Traceability
|
||||
|
||||
### Filter umum
|
||||
- tanggal
|
||||
- supplier
|
||||
- customer
|
||||
- jenis
|
||||
- grade
|
||||
- gudang
|
||||
- status
|
||||
|
||||
---
|
||||
|
||||
## 18. Design Notes
|
||||
- halaman operasional harus mobile-friendly
|
||||
- allocation screen harus cepat, jangan terlalu penuh
|
||||
- lot detail harus jadi layar kunci karena pusat trace
|
||||
- scan workflow harus seminim mungkin input manual
|
||||
- warna status penting, misal active, hold, closed, rejected
|
||||
|
||||
## 19. Prioritas Wireframe MVP
|
||||
Urutan yang sebaiknya didesain dulu:
|
||||
1. Dashboard
|
||||
2. Purchase Form
|
||||
3. Receipt Form
|
||||
4. Stock Lot List
|
||||
5. Lot Detail
|
||||
6. Sales Form
|
||||
7. Allocation Screen
|
||||
8. Picking Screen
|
||||
9. Sorting Session Form
|
||||
10. Barcode Lookup
|
||||
BIN
docs/project-spec/walet-wireframe.pdf
Normal file
BIN
docs/project-spec/walet-wireframe.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user