409 lines
6.6 KiB
Markdown
409 lines
6.6 KiB
Markdown
# 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 |