You will be able to hold a part in more than one place, move it between places, receive new stock, and record each use. A part's on-hand figure is the sum of what sits in each location, and no location goes below zero.
Before you start #
- You need a role that handles parts: owner, manager, advisor or technician.
- The write calls sit under
/fleet, so they needdispatch_fleetin the licence. Reading stays open. Seefleet-without-the-licence. - Parts come from the parts catalogue; see
shop-stock-and-parts.
Steps #
- Add a location with
POST /fleet/stock-locations, giving acodeof up to 20 characters and aname. A code that already exists answersconflict. Every account has a location with the codemain. - Receive stock with
POST /fleet/parts/{id}/receive, givingqty(a whole number from 1 to 100000) and, when you want one,location_id. Without it the stock goes intomain. - Move stock with
POST /fleet/parts/{id}/transfer, givingqty,from_location_idandto_location_id. The two locations must differ. The move happens in one step, so the total stays the same. - Record a use with
POST /fleet/parts/{id}/consume, givingqtyand optionallylocation_id,asset_idandjob_id. The location's stock drops byqty. - See where a part sits with
GET /fleet/parts/{id}/stock. The answer listson_handand the quantity at each location.
Resale or internal use #
Each use announces part.consumed with the SKU, the quantity, the location_id, the asset_ref and a purpose.
resalemeans the part was sold on a job.internalmeans the business used it up, which counts as repair and maintenance expense instead of cost of sales.
Set purpose yourself, or leave it out. When you leave it out, a part used on a vehicle your business operates defaults to internal, and every other use defaults to resale. Any other value answers validation_failed.
Older stock #
Stock recorded before locations existed moves into main the first time you touch the part, so the sum never changes. The older stock adjustment at POST /shop/parts/{id}/adjust lands in main too. Adjust and receive work on main unless you choose another location.
Technical details
- Quantities sit in
part_stock, one row for each part and location. Database triggers keepshop_parts.on_handequal to the sum of those rows. - A change that would take a location below zero writes nothing and answers
conflictwith the quantity on hand. - Every write adds an audit entry.
part.consumeddata:sku,qty,job_id,at,location_id,asset_ref,purpose. Ids are strings. Delivery to other systems arrives in Phase 9; seefleet-api-and-events.
If something goes wrong #
conflict(409): "Only N on hand" at that location. Receive more or transfer stock in first.not_found(404): the part, location, asset or job does not exist.validation_failed(422):qtyis outside 1 to 100000, the two transfer locations match, orpurposeis neitherresalenorinternal.feature_not_licensed(403) orlicence_read_only(403): seefleet-without-the-licence.