Purchase orders
Create grouped legacy supplier orders
/a/PurchaseOrders_createData
Create supplier-group Purchase Orders and their lines atomically.
When to use this endpoint
Use the CRM2 generic order widget’s grouped creation flow. This route delegates to the same checked creator as PurchaseOrder_createFromJob.
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 identity.
Requires Purchase Order View and Add on the singular/plural page; nested line creation also requires Edit. Supplier/form/target references and target record visibility are checked before saving.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
suppliers | Native array of objects | Yes | Groups {id:supplierID,formID:formID,purchaseOrderEntry:[mappedLine,...]}. Not decoded from a JSON string. Empty array creates nothing and returns an empty id list; duplicate supplier groups create separate headers. |
reference | Text | No | Defaults to blank. Maximum 32 Unicode characters; validated before persistence. |
container | Native value/object | Legacy ignored input | Not used by the creator. It is not required for target linking and does not allocate stock. |
target | Native {type,id} picker | No | Applied directly without a container gate. Validates type/ID, target View and scope. No Link and Warehouse use type 0/7 with ID zero. No specialized resource merge or allocation occurs. |
suppliers[].purchaseOrderEntry | Native mapped line array | No | Each row is passed to PurchaseOrderEntry_createData with poID replaced by the new header ID. Supply stock, quantity, cost and explicit line totals as needed. |
Example request
$result = FM_api('PurchaseOrders_createData', [
'suppliers'=>[[
'id'=>'42','formID'=>'5',
'purchaseOrderEntry'=>[[
'stock'=>['id'=>'0','type'=>'2','text'=>'Packing materials'],
'amt'=>'2','costNet'=>'10','totalNet'=>'20','totalTax'=>'4',
]],
]],
'reference'=>'Materials order',
]);
Example response
{
"ok": 1,
"id": [
1042
]
}
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: suppliers"} | suppliers is missing or is not a native list. Malformed groups/lines, unavailable suppliers/forms, inaccessible targets and invalid line values return errors. |
{"error":"permission denied"} | The required page permission is missing. Hidden/deleted records are omitted from collections; explicit parent readers reject an inaccessible parent. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Returns header IDs in supplier-group order. Empty suppliers returns an empty ID list; repeated supplier groups create separate orders.
- All groups and lines use one tenant-owner transaction, checked reference validation, reserved displayed numbering, initial availability, totals and creation/line history. A later child error rolls back all earlier groups.
- Supplied target is applied whether or not container is present. Destination allocation remains a separate OrderContainer_setAllocate call in CRM2.
- Does not send header creation notifications because the grouped creator disables that notification; successful child behavior is shared with PurchaseOrderEntry_createData. Deferred events/effects run after the owning commit.
Side effects
- Creates headers/lines, history, line totals and initial stock availability atomically. Does not email suppliers or allocate stock to a destination. A committed follow-up warning requires checking saved state before retrying.
See it in Fieldmotion
CRM1
No direct CRM1 literal caller was found in the searched client source. CRM1 uses PurchaseOrder_new and the legacy line editor.
CRM2
In CRM2’s generic stock/order widget, select materials and suppliers and create Purchase Orders; inspect PurchaseOrders_createData. The widget then issues separate OrderContainer_setAllocate calls for its destination.
Related endpoints
PurchaseOrder_createFromJob— Use checked atomic grouped creation.PurchaseOrderEntries_get— Read back the actual saved lines.