Forum Discussion

daniel_bcd's avatar
daniel_bcd
Contributing User
3 days ago

PUT Sale/Invoice/Item returns 37006 "Cannot update order on existing invoice" for any invoice converted from an order

Product: AccountRight (cloud company file), AccountRight API v2 (x-myobapi-version: v2)

Endpoint: PUT /accountright/{cf}/Sale/Invoice/Item/{uid}?returnBody=true

Goal: set CustomerPurchaseOrderNumber on paid invoices, nothing else changed

 

The PUT works on invoices that were entered or imported directly as invoices

(Order is null on GET). It fails on every invoice that was created by converting

a sales order in the AccountRight desktop app. Exact response, captured from the

API today:

 

HTTP 400

{

"Errors": [{

"Name": "CannotUpdateOrderOnExistingInvoice",

"Message": "Cannot update order on existing invoice",

"AdditionalDetails": "Order.UID",

"ErrorCode": 37006,

"Severity": "Error"

}]

}

 

What GET returns for one of these invoices:

- InvoiceType "Item", Status "Closed", BalanceDueAmount 0

- "Order": { "UID": "<guid>", "Number": "00030351", "URI": ".../Sale/Order/<guid>" }

 

The linked order:

- GET /Sale/Order?$filter=Number eq '00030351' returns it with

Status "ConvertedToInvoice" and OrderType "Service", although the invoice

is Item layout and the order was keyed with items.

- GET /Sale/Order/Item/<guid> returns 404.

- GET /Sale/Order/Service/<guid> returns it, with description-only lines

(no Item on any line).

- Every converted order in this file shows as Service the same way.

 

Payloads tried on the invoice, each built from a fresh GET with the current RowVersion:

1. Order exactly as returned (UID, Number, URI) -> 37006

2. The entire GET body sent back with nothing changed -> 37006

3. Order omitted -> 37006

4. "Order": null -> 37006

5. "Order": { "UID": "<guid>" } -> 37006

6. "Order": { "UID": "<guid>", "Number": "00030351" } -> 37006

7. "Order": { "UID": "<guid>", "URI": "<uri>" } -> 37006

8. "Order": { "Number": "00030351" } -> 400 "Order is required"

9. "Order": { "URI": "<uri>" } -> 400 "Order is required"

10. "Order": { "Number": "00030351", "URI": "<uri>" } -> 400 "Order is required"

11. "Order": {} -> 400 "Order is required"

12. "Order": { "UID": null } -> 400 validation errors

Control: payload 2 on an invoice with no order link -> 200 OK

 

So with the UID present the API says the order cannot be updated, and without

it the API says the order is required. Number and URI make no difference, the

UID alone is evaluated. There is no payload that satisfies both rules.

 

Editing the same invoices in the AccountRight desktop or browser UI works fine.

 

Questions:

1. Is this a known limitation for invoices converted from orders in the desktop app?

2. Is there a supported payload or endpoint for updating such an invoice via the API?

3. Would an invoice converted from an order through the API (POST Sale/Invoice/Item

with Order.UID) or through the browser "Convert to invoice" be updatable afterwards?

4. Why does the retained converted order appear as Service layout when the original

order and the invoice are Item layout?

 

Happy to supply the company file ID, invoice and order UIDs and request timestamps

privately.

6 Replies

  • ROC_MYOB's avatar
    ROC_MYOB
    MYOB Moderator
    3 days ago

    Hi daniel_bcd​ ,

    Thanks for the thorough write-up — the matrix of payloads (including a no-change GET→PUT) and the Item invoice / Service order mismatch is exactly what we needed.


    What I can see with early investigation is error **37006** (`CannotUpdateOrderOnExistingInvoice`) is documented behaviour for changing an invoice’s linked order after create: the API will not let you add, remove, or retarget `Order.UID` on an existing invoice. See [API Errors & Warnings](https://developer.myob.com/api/myob-business-api/api-overview/error-messages/) (“Cannot update Order.UID on existing Invoice”).

    On a normal converted invoice, a PUT that **keeps the same** `Order.UID` from GET (and only changes fields like `CustomerPurchaseOrderNumber`) is expected to succeed. Your control case (invoice with `Order: null`) matching that pattern confirms the rest of the payload is fine.

    What you are hitting looks like a **data/layout edge case on the linked order**, not a supported “you cannot update converted invoices” rule:

    - The invoice is Item and correctly linked to an order.

    - That order is exposed as `OrderType: Service`, with `/Sale/Order/Item/{uid}` 404 and `/Sale/Order/Service/{uid}` returning description-only lines.

    - That pattern (Item sales living under Service after import / conversion / missing layout metadata) has been reported before.

    In that situation the update path can fail the order-link check even when you send back the same `Order` object GET returned — so there is **no supported PUT payload** that unblocks these invoices today. Editing the same invoices in desktop/browser works because that path does not go through this API validation.

    Options I can think of:

    1. Set or correct `CustomerPurchaseOrderNumber` in AccountRight (desktop or browser) for the affected invoices.
    2. For **new** work: prefer converting a healthy Item order via `POST /Sale/Invoice/Item` with `Order.UID` (or convert in product from an order that still appears under `/Sale/Order/Item`), and set `CustomerPurchaseOrderNumber` on create/convert where you can.
    3. We are treating the “GET Order echoes back but PUT 37006” case on Service-misclassified converted orders as a product defect to investigate — if you can share company file ID and one invoice/order UID privately (support / DM), that will speed confirmation on a clone.

    The answers to your questions:

    1. Not a documented “desktop convert = read-only via API” limitation; it is unexpected failure of a same-`Order.UID` update when the retained order is misclassified as Service.
    2. No alternate endpoint for patching only `CustomerPurchaseOrderNumber` on invoices — PUT on the layout endpoint is the supported update, and it is failing here.
    3. Invoices converted via API (or browser) from a correct Item order are expected to allow later PUT with the same `Order.UID`. We would not expect the Service/404/Item mismatch on those. Worth a small repro on a test file if you can.
    4. The retained order showing as Service while the invoice is Item is a known class of layout-metadata issues (import / conversion / missing layout property). It is related to why the PUT fails, not a separate cosmetic quirk.

    Happy to follow up on the thread once I have a clearer fix/workaround from engineering.

    Thanks Roc

  • daniel_bcd's avatar
    daniel_bcd
    Contributing User
    3 days ago

    Thanks Roc,  feel free to DM me and I'll provide details you are after.

     

     

    I've don these on a test customer, all through the API:

     

    1. POST /Sale/Order/Item, one line, qty 1, $0 -> 201, order 00030356, Status Open

    2. GET /Sale/Order/Item/{uid} -> 200, Item line present

    3. POST /Sale/Invoice/Item with "Order": { "UID": "<order uid>" } and the same line

    -> 201, invoice 00030357, linked to 00030356

    4. GET /Sale/Order/Item/{uid} after conversion -> 200, Status "ConvertedToInvoice",

    OrderType "Item", item line intact

    5. GET /Sale/Invoice/Item/{invoice uid} -> Order link present

    6. PUT the invoice with the Order object exactly as returned and

    CustomerPurchaseOrderNumber changed -> 200, RowVersion advanced

     

    So an order converted through the API stays a healthy Item order and the invoice

    updates normally. The failing invoices in this file were all converted with

    "Change to Invoice" in the AccountRight desktop app (every converted order in the

    file since 2020 shows as Service with the Item path returning 404). That points at

    the desktop conversion as the step that leaves the retained order without its

    layout metadata.

     

    Two things I noticed that may help engineering:

     

    - The API conversion assigned a new invoice number (00030357 for order 00030356).

    The desktop conversion kept the order number on the invoice. The file has

    "Retain original invoice number on change of status" behaviour in the desktop app.

    - With "Order": {} on one of the broken invoices the API returns "Order is

    required", so it does expect a link on those invoices, then rejects the only

    UID it returns for them.

     

    I will send the company file ID and the UIDs for both pairs privately: the

    failing invoice 00030351 with its order, and the passing 00030357 with order

    00030356, so you can compare them on a clone.

     

    A questions while engineering looks at it:

    On an API conversion, can the invoice be given the order's number by setting

    "Number" on the POST, or is a new number always assigned?

     

    Thanks again,

    Daniel

  • ROC_MYOB's avatar
    ROC_MYOB
    MYOB Moderator
    3 days ago

    Thanks — that API vs desktop isolation is exactly what I needed. It matches what we were seeing in the update path: healthy Item orders (layout metadata intact) accept a same-`Order.UID` PUT; the desktop-converted orders that land as Service / Item 404 do not. We’ll use the CFID and both UID pairs on a clone when you DM them.

     

    On invoice Number during API conversion

     

    You can keep the order’s number by setting `Number` on the `POST /Sale/Invoice/Item` body (same value as the order). The convert guidance sample does that explicitly:

     

    https://apisupport.myob.com/hc/en-us/articles/360001247376-Convert-a-Sales-Quote-Order-to-an-Invoice

     

    If you omit `Number` (or leave it blank), the API assigns the next invoice number — which is what you saw (00030356 → 00030357). That is expected API behaviour and is separate from the desktop retain-on-status-change preference.

     

    If you set `Number` to the order number, check for duplicates if that number already exists as an invoice in the file.

     

    For the historical desktop-converted invoices, the UI remains the practical workaround until we have a fix/data remediation path. Appreciate the thorough repro.

  • daniel_bcd's avatar
    daniel_bcd
    Contributing User
    2 hours ago

    Hi Roc, an update with new findings. The file ID and UIDs are going to you privately.

     

    Since my last post I have been able to watch the client do the import on screen and check each record through the API as he went. The short version: the Service classification is created by the desktop import itself, not by Change to Invoice.

     

    What the client does

     

    The sales file comes from a B2B portal in the standard AccountRight Item sales import layout (31 columns, Co./Last Name through to Sale Status, tab delimited). He imports it with File > Import/Export Assistant > Sales > Item, Match All, with every field matched one to one and Sale Status set to I. When that invoice import is rejected (insufficient stock on a line), he changes Sale Status to O, imports the same file as an order, adjusts the quantity in AccountRight, then uses Change to Invoice.

     

    What the API shows, checked within minutes of each step

     

    1. Order imported from the file, still Open, nothing converted. The /Sale/Order list reports OrderType Service with a /Sale/Order/Service URI. GET on the Service path returns one line with the item name as the Description, an income account, no Item and no ShipQuantity. GET on /Sale/Order/Item/{uid} returns 404. In AccountRight the same order shows the Item Number column with the item on it.

    2. Change to Invoice on that order. The invoice is an Item invoice (/Sale/Invoice/Item) with an Order link to the order above, and the order is now ConvertedToInvoice, still Service. This is the same shape as the invoice from my first post, so PUT is expected to fail with 37006 (not tested on this one).

    3. Same file imported with Sale Status Q. The quote is reported as QuoteType Service with a /Sale/Quote/Service URI, and /Sale/Quote/Item/{uid} returns 404.

    4. Same file imported as an order a second time. Service again.

     

    So three desktop imports in a row (order, quote, order) from a compliant Item sales file, all shown as Service by the API while the product shows them as Item sales. For comparison, an order created with POST /Sale/Order/Item on the same file stays Item, converts cleanly through POST /Sale/Invoice/Item with Order.UID, and the resulting invoice accepts PUT. Every converted order in this file since 2020 (230 of them) is reported as Service, so this has been happening for a long time.

     

    One side observation: the imported order and quote both come back with ShippingMethod blank even though the file has a Ship Via value on every row, and the invoice converted from the order is also blank. I have not yet confirmed what the product shows for Ship Via on those records.

     

    Questions

     

    1. Does this narrow the defect to the Import Assistant writing Item sales with missing layout metadata? If so, is there an import setting, a file field, or a version of AccountRight where the imported order is exposed as Item?

    2. Is a fix planned, and is there a way to repair the existing records so their invoices accept PUT?

    3. Until then, is POST /Sale/Invoice/Item with Order.UID against one of these Service-exposed orders expected to work, or does it need a healthy Item order as the source?

     

    The private message with the file ID and the UIDs for the order, quote, converted invoice and the clean API pair is on its way.