Stock Transfer
Location: dg_smart_pos_api/modules/StockTransfer (no space in the directory name, unlike an earlier draft of this page). Owns two related but distinct workflows: a store directly pushing stock to another store, and a store asking another store for stock which is then approved or rejected. Both ultimately move stock via App\Models\Store-scoped quantities in store_stocks; the module depends on Inventory for the stock items themselves (Modules\Inventory\Models\NewStock) and is in turn a listed dependency of Inventory in config/modules.php.
Data model
Section titled “Data model”StockRequest(stock_requeststable) - a pull-model ask:requesting_storewantsrequested_quantityof a stock item fromfulfilling_store. Nostatuscolumn; status is always computed from quantities viacomputeStatus()(pending,partially_fulfilled,fulfilled,rejected,cancelled).TransferHistory(transfer_historiestable) - an actual movement record:origin_storetodestination_store,transferred_quantityvsreceived_quantityvsreturned_to_origin_quantity. Status is likewise computed, not stored, viaquantityInTransit()(in_transit,partially_received,fully_received,settled).
Approving a StockRequest creates/updates a TransferHistory under the hood (StockRequestController::approve doc comment: “moves stock via StockTransferService”) - a request is the ask, a transfer is the actual stock movement.
Stock requests (pull model)
Section titled “Stock requests (pull model)”StockRequestController against StockRequest:
index- lists requests for a store, filterable bytype(outgoing/incoming),status,from_date/to_date. “Incoming” includes requests aimed at any warehouse the store owns (Store::warehouseIdsOwnedBy), since a warehouse has no logins of its own to act on its own requests.store(StockRequestCreateRequest) -fulfilling_store(required),lines(array ofstock_id/requested_quantity/optionalsuggested_serials),notes. Rejects requesting from your own store.approve(StockRequestApproveRequest) - fully or partially approves, moving stock viaStockTransferService. Requiresinventory:transferspecifically (stricter than read/create).reject(StockRequestRejectRequest) - closes the remaining open quantity with a reason. Sameinventory:transfer-only gate as approve.cancel- requester-side cancellation of the remaining open quantity. Allowed under the broader read/create permission set.getPendingApprovals/getPendingApprovalCount- incoming requests still awaiting a decision at this store.getAllPendingApprovals- every pending request tenant-wide, gated by a separateinventory:resolve-any-requestpermission; visibility only, approving/rejecting still goes through the store-scoped routes above.
Direct transfers (push model)
Section titled “Direct transfers (push model)”StockTransferController against TransferHistory:
store(StockTransferCreateRequest) -stock_to_transfer(array ofid/transfer_quantity/optionalserials),to_store. Note the field names differ from the request flow above (id/transfer_quantityhere vsstock_id/requested_quantitythere). Gated byinventory:transfer|inventory:addplus astock.write.adminmiddleware that additionally blocks warehouse-origin transfers forinventory:add-only users unless the store’scashier_can_transfer_from_warehousesetting allows it.index/show- filterable bytype(transfer/receive),status, date range.receive(StockTransferReceiveRequest) - receives a quantity of a specific transfer’s stock at the destination.reverse(StockTransferReverseRequest) - reverses a quantity of a transfer, optionally scoped to specific serials.getPendingReceived,getTransferred,getReceived- convenience list endpoints.deliveryNote- metadata for client-side thermal/PDF delivery notes, addressed either byids=1,2,3or a sharedbatch=transfer batch number.exportPdf- A4 PDF export of the filtered transfer list (same filters asindex).
Admin cross-store dashboard
Section titled “Admin cross-store dashboard”AdminStockTransferController (not store-scoped): dashboard (summary cards plus per-shop-pair breakdown), transfers (paginated, filtered list across every store), exportPdf (same, as a PDF). All three require inventory:transfer.
Route surface
Section titled “Route surface”Registered as a tenant route module (StockTransfer is in ModulesServiceProvider::TENANT_ROUTE_MODULES), required once each from routes/tenant.php (no duplicate registration, unlike Sales):
Stock requests - auth:sanctum, prefix stock-requests/stores/{store} (from modules/StockTransfer/Routes/stockRequest.php):
| Method | Path | Controller method |
|---|---|---|
| GET | requests/pending-approvals |
getPendingApprovals |
| GET | requests/pending-approval-count |
getPendingApprovalCount |
| GET | requests |
index |
| GET | requests/{stockRequest} |
show |
| POST | requests |
store |
| POST | requests/{stockRequest}/cancel |
cancel |
| POST | requests/{stockRequest}/approve |
approve |
| POST | requests/{stockRequest}/reject |
reject |
| GET | stock-requests/pending-approvals/all (no {store}) |
getAllPendingApprovals |
Stock transfers - auth:sanctum, prefix stock-transfer/stores/{store} (from modules/StockTransfer/Routes/transfer.php):
| Method | Path | Controller method |
|---|---|---|
| GET | transfers/delivery-note |
deliveryNote |
| GET | transfers/export-pdf |
exportPdf |
| GET | transfers |
index |
| GET | transfers/{transferHistory} |
show |
| POST | transfers |
store |
| POST | transfers/{transferHistory}/receive |
receive |
| POST | transfers/{transferHistory}/reverse |
reverse |
| GET | transfer/pending/received |
getPendingReceived |
| GET | transfer/sent |
getTransferred |
| GET | transfer/received |
getReceived |
Admin - auth:sanctum, prefix stock-transfer/admin:
| Method | Path | Controller method |
|---|---|---|
| GET | dashboard |
AdminStockTransferController::dashboard |
| GET | transfers |
AdminStockTransferController::transfers |
| GET | transfers/export-pdf |
AdminStockTransferController::exportPdf |
Response shape
Section titled “Response shape”A stock transfer list item (StockTransferListResource):
{ "id": 1, "transfer_batch_no": "TB-000001", "stock_id": 5, "stock_name": "Widget 500ml", "origin_store_name": "Main Branch", "destination_store_name": "Warehouse A", "transfer_date": "2026-01-01", "transferred_quantity": 10, "received_quantity": 4, "returned_to_origin_quantity": 0, "in_transit_quantity": 6, "status": "partially_received", "transferred_by_name": "Jane Doe", "cost_snapshot": 250.5, "transfer_value": 2505}A stock request list item (StockRequestListResource) additionally carries remaining_quantity, available_at_fulfilling_store (only populated when the viewing store is the request’s own fulfilling_store, null otherwise so a requester can’t infer the other store’s stock), and a computed status.