Purchase orders
Patch mapped order line fields
/a/PurchaseOrderEntry_updateData
Change selected mapped line values under the existing-line approval wrapper.
When to use this endpoint
Use for explicit mapped patches of existing line IDs. Parent totals, history, approval and compatible availability now share the same checked transaction; CRM2’s full spreadsheet uses atomic replacement instead.
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 |
|---|---|---|---|
id | Positive scalar, native or JSON ID array | Yes | Existing local header/line IDs. Every selected row is checked and all writes share one transaction; later failure rolls back the entire request. |
poID / po_id | Positive integer or digit string | No | When supplied, must match every selected line’s real parent. poID is mapped; po_id is a guard/control input. |
stock | Native picker object | No | {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. |
cDate / lastEdited | Date-time | No | Creation defaults cDate to server now; lastEdited is automatically stamped when omitted. Layout read-only flags do not make these mapped columns immutable. |
roID | Integer-compatible | Legacy alias | Compatibility parent alias; it must match the actual owner, even when poID is also supplied. |
Example request
$result = FM_api('PurchaseOrderEntry_updateData', [
'id'=>'2081','poID'=>'1042',
'amt'=>'2.5','costNet'=>'10','totalNet'=>'25','totalTax'=>'5',
]);
Example response
{
"ok": 1
}
A shared no-op can return {"warning":"No Change."}; a multi-ID update can return {"ok":1}. No error result is a committed-prefix signal: the whole request is transactional.
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": "purchase order entry belongs to another order"} | A supplied canonical parent differs from the selected line’s owner. |
{"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
- Positive scalar/native/JSON line IDs are normalized. Every selected line must belong to an active visible parent. poID, po_id and roID must each agree with the actual owner; aliases cannot reparent a line.
- Only supplied mapped fields change. Validates supplied stock picker/type, nonnegative finite quantities/cost/totals and text length; nominal input is normalized. Supplied line monetary totals remain authoritative.
- Supplier, carriage and changed line data clear approval and require approval again. Exact no-op saves retain approval. Non-administrators with crm_access bit 8192 cannot make financial changes to approved orders.
- Changed lines refresh parent totals including carriage, timestamp/cache, checked line history and an edit event in the same transaction. Initial availability follows changed identities/quantities.
- Existing allocation destinations are preserved. Changing stock identity/quantity after allocation or receipt is rejected and rolled back; financial/cost changes with unchanged quantities can still require approval again.
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 mapped lines, parent financial state, compatible initial availability and checked history atomically. No supplier email or inventory receipt is created.
See it in Fieldmotion
CRM1
No direct CRM1 caller was found; the editor uses PurchaseOrderEntry_save.
CRM2
The purchaseOrderEntry layout map declares this update route, but the main spreadsheet save saves a matched replacement set atomically. Do not infer in-place line updates from the visible spreadsheet.
Related endpoints
PurchaseOrder_recalculateTotal— Refresh stale header totals after a line patch.PurchaseOrderEntry_getRequestedDetails— Read the mapped line back.