# 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