Goods returns
Create a legacy return note and deduct stock
/a/GoodsReturned_new
Create a return header, optionally insert positional return lines and deduct catalog stock.
When to use this endpoint
CRM1 starts with a supplier, then selects its goods-received note and quantities from GoodsReceivedEntries_get. Each chosen received line becomes a row in this request. This is the stock-changing creation path; GoodReturned_createData only inserts a header.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Session CSRF and account/IP restrictions still apply. These handlers add no goods-return, finance, department, owner or page-role permission check.
Records belong to the authenticated tenant. CRM1 shows this workflow when the employer features bit 262144 is enabled; CRM2 uses features2.goodsReturnedNotes. These are UI gates, not checks performed by these handlers.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
supplier_id | Integer | Yes | Positive whole integer; no supplier existence/on-hold/deletion or received-note ownership check. |
grn_id | Integer | Yes | Whole positive reference or legacy -1; no received-note existence/supplier ownership check. |
notes | String | No | Header notes, default empty string. |
rows | Native array of positional arrays | No | Native [receivedEntryID,stockType,item,quantity] arrays, exactly four positions. Type 1 uses catalog ID, type 2 a string up to 255 bytes. Whole non-negative quantities; zero skipped. JSON text is rejected. grne_id links are not relationship-validated. |
Example request
FM_api('GoodsReturned_new', ['supplier_id'=>84, 'grn_id'=>531, 'notes'=>'Damaged packaging', 'rows'=>[[733,1,1042,2]]]);
Example response
{"ok":1,"id":"642"}
Checked header insert ID, normally a numeric string. Header/line writes, catalog deductions and history commit atomically. A lost network response after commit is still uncertain: do not blindly repeat creation.
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":"goods return write failed"} | A primary write or history insert failed; the transaction is rolled back. |
{"error":"goods return read failed"} | A required locking read failed; no changes commit. |
{"error":"goods return transaction failed"} | Starting/committing the tenant transaction failed. |
{"error":"goods return operation failed"} | Unexpected database/JSON processing failure; no changes commit. |
{"error":"missing or invalid parameter: supplier_id"} | Not a positive whole supplier ID. |
{"error":"missing or invalid parameter: grn_id"} | Not a whole positive reference or legacy -1. |
{"error":"missing or invalid parameter: rows"} | Not native exact four-element positional rows. |
{"error":"missing or invalid parameter: qty"} | Negative, fractional, non-numeric or out-of-range quantity. |
{"error":"stock does not exist"} | Non-zero catalog rows refer to missing/deleted stock. |
{"error":"insufficient stock"} | Aggregated return quantities exceed locked catalog in_stock. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Native rows must have exactly [receivedEntryID,stockType,item,quantity]. Types 1/2 only; whole non-negative 32-bit quantities only. Zero quantities are skipped. JSON text, malformed rows, unsupported types, negatives and fractions are rejected.
- Catalog stock is locked in ascending ID order and repeated rows are summed before availability validation. Missing/deleted catalog items or insufficient stock reject the entire request.
- Type 2 descriptions are parameterized, including quotes and literal markup. CRM1 sends the description, not the catalog-ID slot, for free-text rows.
- Positive supplier_id and positive grn_id or legacy -1 are required. Supplier/received-note existence/ownership and received-entry relationships are still not validated.
- The legacy transaction subtracts catalog in_stock directly, without reconciling warehouse containers, updating received quantities, calculating totalNet or generating credit notes.
- All primary/history writes are checked in one tenant transaction. Database failure rolls back the entire request. No idempotency token: check for a saved note before retrying an uncertain client response.
Side effects
- Sets header/line timestamps and links. Catalog deductions also advance stock last_edited/edited_uuid for synchronization.
- Invalidates header/line/catalog caches and atomically records field history. No notification, PDF, accounting export or container movement.
See it in Fieldmotion
CRM1
pageGoodsReturned builds native rows from GoodsReceivedEntries_get: catalog rows send stock ID, free-text rows send the plain-text description. Invalid quantities and API save errors are shown without automatic retry.
CRM2
Current CRM2 layout creation goes through Layout_setValue to GoodReturned_createData. Older regression comments mention CRM2, but this legacy stock-changing route is not the current page’s create call.