When to use this endpoint

Use after separately saving line values, including after a mapped layout save. Supply already-calculated line totals; this call does not derive them from quantities and unit costs.

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

ParameterTypeRequiredDescription
idPositive integer or digit stringYesLocal Purchase Order ID; not po_num. Missing, malformed or inaccessible IDs fail.

Example request

$result = FM_api('PurchaseOrder_recalculateTotal', ['id'=>'1042']);

Example response

{
  "ok": 1
}

Errors and unusual responses

ResponseCondition
{"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

  • Runs under the checked Edit wrapper and owner/order lock. Sums saved line total_net/total_tax and adds delivery_net/delivery_tax; it does not calculate line amounts from quantity/cost or a tax-code label.
  • A numeric difference above 0.00001 updates persisted delivery-inclusive totals, clears approval and stamps last_edited. Equal totals preserve approval. The response contains no amounts; read the header afterwards.
  • The approved-edit restriction blocks a changed recalculation for non-administrators with crm_access bit 8192. Failure rolls back the totals and approval together.
  • No container reconciliation, receipt creation, supplier email or independent line-formula repair is performed.

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.
  • Persists changed totals/approval/timestamp and checked total-change history. No history row is added for an unchanged snapshot.

See it in Fieldmotion

CRM1

No direct literal CRM1 caller was found; the legacy line save/delete handlers recalculate totals themselves.

CRM2

In CRM2 Purchase Order details, Save runs display.save followed by PurchaseOrder_recalculateTotal, before the optional specialized Job/Quote link follow-up.

Related endpoints