455 lines
8.5 KiB
Markdown
455 lines
8.5 KiB
Markdown
# 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. |