Initial import of AbelBirdNest Stock
This commit is contained in:
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.
|
||||
Reference in New Issue
Block a user