Purchase orders
Copy ordered stock into a Job
/a/PurchaseOrder_setLinkToJob
Merge order lines into a Job’s stock usage and allocate catalogue stock before storing the Job link.
When to use this endpoint
Use the CRM2 post-save Job link follow-up when ordered resources should appear on the Job. For a header-only link, use PurchaseOrder_setLink.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Session requests use dispatcher CSRF protection when configured. API keys use their owner’s permissions.
Requires explicit View on Purchase Order or Purchase Orders, plus Edit on either page. Non-administrators with legacy Purchase Orders visibility disabled (crm_access bit 256) are denied.
Explicit order IDs must identify active, visible records in the authenticated tenant. TeamAccess follows linked Contracts, Customers, Jobs, Quotes and Departments; legacy department filtering follows Customer, Quote-customer and ordinary customer-Job links. Scoped users cannot read unlinked or Warehouse orders through this check.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Positive integer or digit string | Yes | Local Purchase Order ID; not po_num. Missing, malformed or inaccessible IDs fail. |
jobID | Positive integer or digit string | Yes | Active Job ID visible to the user. Requires Job View and Edit in addition to Purchase Order rights. |
Example request
$result = FM_api('PurchaseOrder_setLinkToJob', ['id'=>'1042','jobID'=>'87']);
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": "permission denied"} | Page/action rights or the legacy visibility setting deny access. |
{"error": "purchase order does not exist"} | An explicit parent/header ID is absent, deleted or outside the caller’s scope. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Requires the Job’s View/Edit and active record scope. Locks the owner, Purchase Order and destination Job; copies catalogue type-1 lines into Job type-0 resources and miscellaneous type-2 lines into Job type-1 resources.
- Preserves unrelated existing Job resource rows, including legacy rows with no source. Replaces resources sourced from this order with every saved order line, retaining duplicate miscellaneous descriptions as separate rows with stable per-line link IDs.
- New catalogue prices use customer-aware Stocks_getPrice. Miscellaneous price follows cost unless pageGlobal.poMakeJobMiscPriceSameAsCost is exactly boolean false, in which case it is 0. Repeated linking refreshes the order’s own quantities/costs/prices without duplicating rows.
- Computes stock_cost and price over the complete resulting resource list; awaiting-stock rows do not terminate the totals pass. Existing dispatched rows with oldSource from this order must be returned before relinking.
- When autoupdate-job-substatus is blank or 1, Purchase/Requisition sources select Awaiting Stock. With stockTracking enabled, the remaining precedence is Needs Dispatched (Job source), Stock Not Yet Allocated (None), then Dispatched (outbound Job/User/Vehicle source).
- Allocates exact order quantities to Job destination type 7. Missing/short availability, receipt incompatibility or a different destination fails atomically. An exact replay counts existing destination quantities; it does not duplicate allocations.
Side effects
- Writes use the tenant-owner lock and a transaction or caller savepoint. A rejected operation rolls back its local writes and checked history. Earlier separate API requests remain committed.
- Edit events, notifications and form follow-ups run after the owning commit. A saved/no-replay warning identifies committed data with a failed follow-up; inspect the saved state rather than repeating creation or sending.
- Updates Job stock_used, complete stock totals, configured substatus, timestamps and stock containers together with the header link/history. Job form synchronization follows commit; a follow-up failure reports a no-replay warning.
See it in Fieldmotion
CRM1
No direct CRM1 caller was found. CRM1’s header linking does not establish this stock-copy contract.
CRM2
In CRM2 Purchase Order details, save an editable Job-linked order; after totals refresh the page invokes PurchaseOrder_setLinkToJob. Completing a Job-linked order through mapped updateData can also call it when poCopyStockToJobOnComplete is enabled.
Related endpoints
PurchaseOrder_setLink— Link the header without copying Job resources.PurchaseOrder_updateData— Completion can trigger this follow-up.