Purchase orders
Create a mapped order line
/a/PurchaseOrderEntry_createData
Append a mapped line, its initial Purchase stock container and refreshed parent totals.
When to use this endpoint
Use the CRM2 spreadsheet replacement flow, or append a fully populated line to an existing header. Supply explicit monetary totals; use Entry_new followed by Entry_save for the legacy blank-line workflow.
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 line IDs are checked against their active, visible parent orders. A supplied po_id must match the line’s owner. These are tenant-local record IDs, not displayed order numbers.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
poID | Positive integer or digit string | Yes | Active visible parent. Canonical poID and compatibility po_id are normalized; any supplied roID must agree. |
stock | Native picker object | Yes on creation | {type:1,id:42} for catalogue stock; {type:2,id:0,text:"Delivery materials"} for miscellaneous text. This route expects the native nested object, not a JSON string. |
stockType / stockID / stockText | Integer-compatible / text | No | Mapped stock components; type 1 catalogue, 2 miscellaneous, text up to 255 Unicode characters. Creation still needs the native stock picker; supplied catalogue selections must be available. |
amt | Numeric-compatible | No | Quantity; mapped as float, so fractions are preserved. Omission does not derive a quantity from the Job or stock record. |
costNet / totalNet / totalTax | Numeric-compatible | No | Nonnegative finite unit cost and supplied line totals. Four-decimal unit cost requires an upgraded tenant; final monetary totals use currency storage. No server row formula runs. |
nominal_id / nominal_code / nominalCode | Local ID / stored code / legacy value | No | Local nominal ID, stored text code or legacy selection. Canonical adapter rejects conflicting resolvable IDs/codes and stores the code. |
taxTypeID / taxType | Text / native picker | No | Stored tax code, or picker {id:"T1",nominalID:localNominalID}. This selects accounting metadata; it does not calculate totalTax. |
sortNumber | Integer-compatible | No | Display order. Creation assigns the next positive number when absent or below 1; explicit positive values are accepted without renumbering the other lines. |
roID | Integer-compatible | Legacy alias | Legacy parent-column alias. Must equal the canonical poID/po_id; it cannot change ownership. |
cDate / lastEdited | Date-time | Legacy controls | Creation defaults cDate to server now; lastEdited is automatically stamped when omitted. Layout read-only flags do not make these mapped columns immutable. |
Example request
$result = FM_api('PurchaseOrderEntry_createData', [
'poID'=>'1042',
'stock'=>['type'=>'2','id'=>'0','text'=>'Packing materials'],
'amt'=>'1.5','costNet'=>'10',
'totalNet'=>'15','totalTax'=>'3',
]);
Example response
{
"ok": 1,
"id": 2081
}
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. |
{"error": "missing or invalid parameter: stock"} | The required native stock picker is missing. |
{"error": "Unable to create record"} | Mapped row insertion failed; the wrapper rolls back this line operation. |
{"error":"Cannot change stock quantities or identity on an allocated or received Purchase Order"} | The change would invalidate existing allocations or receipts; the transaction rolls back. |
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 an existing active visible parent and a native stock picker. The canonical parent is poID; po_id is accepted and normalized. The roID compatibility alias must agree and cannot move the new line to another header.
- Validates stock type 1/2, available catalogue selections, finite nonnegative quantity/cost/totals and the 255-Unicode-character text limit. Nominal account input resolves to its canonical stored code. Supplied totals are stored; layout formulas are not executed.
- Absent/nonpositive sortNumber selects the next positive line position. When quantity is supplied, creates initial Purchase availability (order_type 1, source type 16/id=parent), using container type 0 for catalogue and 1 for miscellaneous. Fractions survive.
- Direct creation refreshes parent totals including carriage, timestamp/cache and line history, and clears approval. Non-administrators with bit 8192 cannot create lines on approved orders.
- During Layout_setValue replacement, availability/totals/approval are finalized once against the complete old/new line sets. Exact financial replacement preserves approval and compatible allocations; the whole layout rolls back on an invalid later row.
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.
- Inserts the mapped line, canonical initial availability and checked history. No inventory receipt or supplier email is created.
See it in Fieldmotion
CRM1
No direct CRM1 caller was found. CRM1 uses PurchaseOrder_new and the legacy PurchaseOrderEntry_new/save line editor instead.
CRM2
In CRM2 Purchase Order details, save the line spreadsheet and inspect Layout_setValue. The Purchase Order layout saves the complete spreadsheet atomically, updates matched lines in place to retain receipt references, creates new lines and removes only omitted lines.
Related endpoints
PurchaseOrder_createData— Create the parent header first.PurchaseOrderEntry_save— Compare the legacy line workflow.