Jobs: forms and resources
Replace job stock usage and adjust legacy quantities
/a/Job_setStock
Replace resource stock rows and adjust legacy warehouse/container quantities for direct job usage.
When to use this endpoint
Use for the CRM1 Resources stock widget’s complete desired state, after reading Job_getStock and resolving source IDs.
Do not confuse this with Job_setStockUsed: that endpoint modifies usage rows without adjusting warehouse/container levels.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. The handler performs no additional page or role-permission check.
Job and form IDs refer to the authenticated account. Cross-account writes occur only through the stored outsourcing relationship on the routes that explicitly mirror changes.
The dispatcher also applies account/user and IP restrictions. A CRM session carrying a CSRF token must supply it through X-FMCSRF or _csrf; missing/incorrect tokens can be rejected before this handler runs.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer string | Yes | Positive physical job ID. |
val | JSON array string | No | Full desired direct stock list, plus optional table-linked entries. Defaults to blank, which clears direct usage; use [] explicitly to clear. Rows use id, amt and source, optionally cost/price. No numeric amount/stock existence/availability validation is enforced. |
val[].source | String | Per row | 0 denotes legacy warehouse stock; encoded type_ID selects a legacy stock_container (1=user, 2=vehicle, 3=location). Source IDs are integer-converted. Tokens without an underscore are treated as warehouse for quantity adjustment; use canonical tokens. |
val[].linkMethod | Object inside val JSON | No | Absent or method=linkToJob keeps a direct row. method=table queues an addressed table cell using table_id/table_row/table_column; other methods are removed from the direct list without a table update. |
val[].cost / val[].price | Numbers inside val JSON | No | Explicit snapshots are preserved. Missing values use stock average cost and the resolved customer’s price band. Customer resolution follows asset owner/location chains with cycle protection. |
Example request
$result = FM_api('Job_setStock', [
'id'=>'1042',
'val'=>json_encode([['id'=>'205','amt'=>'2','source'=>'0']]),
]);
Example response
{"ok":1}
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"missing or invalid parameter: id"} | Nonpositive ID. |
{"error":"job does not exist"} | No active job is read. |
{"error":"Unable to save job stock"} | The primary database save failed. Successful-save history and subsequent follow-ups are not run. Stock quantity/usage database changes are rolled back together. |
{"error":"invalid parameter: val"} | Nonempty stock input does not decode to an array. Blank input still clears direct usage. |
{"ok":1,"warning":"Job saved; follow-up incomplete. Inspect saved state before retrying.","warnings":["Job_updateCosts: Unable to save job"],"saved":1} | The primary save succeeded, but a recalculation, asset rebuild, notification or outsourced mirror failed. warnings identifies the failed follow-up; any normal response fields remain present. A benign no-change result from a follow-up is not a failure. Read saved state before retrying. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Aggregates old/new direct quantities by source and stock ID and applies old-minus-new deltas. Zero-amount direct rows are removed. Existing rows lacking source may use their containers key only when exactly one container is present; unidentifiable old rows are skipped.
- An old item removed from a source is returned even when other requested items still use that source. Unchanged retained items have no quantity delta.
- Main form meta.do_not_update_stock_levels disables warehouse/container quantity adjustments, but does not prevent usage saves, table-cell edits or cost recalculation.
- Table-linked entries replace each addressed cell with an encoded version-2 stock object (stock entries with id/amt/containers and v=2). Other cells survive. These entries are excluded from the direct quantity delta; this path does not itself deduct stock for those cell changes.
- Missing cost/price snapshots are enriched; relative customer bands multiply/round base price, absolute bands use a stock-specific band price when present. Existing explicit price, including zero, is retained.
- Malformed truthy JSON is rejected as invalid parameter: val. No positive-stock/availability check, deduplication of stored rows, amount bound, paging or batch limit is provided.
Side effects
- Locks the active job before reading usage, then updates warehouse stock.in_stock or stock_container.amt and saves usage in one tenant database transaction. Failed quantity/app-sync/job writes roll back the transaction. Missing containers are inserted. This is not the newer stock-inventory movement workflow.
- After a successful commit, crossing a configured amt_trigger downward can queue threshold email to its configured recipient; mail failure produces a saved-state warning. Container changes mark users, vehicles or locations edited for app synchronization. Vehicle source IDs are coerced to integers, so UUID-based sources do not retain that identity.
- Checked active-job stock_used/subform_values/timestamp/edit-marker UPDATE and meetings-cache invalidation. Records generic job history only after commit, then calls Job_updateCosts and Job_updatePrices (costs already invokes prices); failures produce saved-state warnings. No outsourced mirror is made.
See it in Fieldmotion
CRM1
Open a job’s Resources/Costs stock table and edit rows or quantities. pageJobCosts.js sends the full JSON list to Job_setStock. The job editor also calls it immediately when deleting a saved resource row.
CRM2
No direct canonical or legacy caller was found in CRM2’s source. Its layout-driven resource editing is a separate save contract. No direct Job_setStock request was found in its resource editor.
Related endpoints
Job_getStockreads the job’s direct and field-specific stock usage before a resource edit.Job_setStockUsedadjusts usage rows without moving inventory.Job_updateCostsrefreshes cost/resource snapshots and invokes the price follow-up.