Jump to content

Updating Items on Invoices


 Share

Recommended Posts

Hello, I wondered if you could help. I've recently been doing some work around updating invoices and credit notes using the API and have encountered a couple of issues when trying to remove or change items (products or services) for particular line items.

Issue 1

If I create a sales invoice (or purchase invoice or credit note) that includes a product or service for an invoice line, everything works fine.

Request to create sales invoice:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "99d52ca7060341a698a664d1737663c5",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO",
                "product_id": "d81d133b98164ec8a6fc47a756ada18a"
            }
        ]
    }
}

However, if I then attempt to remove the product for the line item using the update (PUT) endpoint it fails to remove it.

Request to update sales invoices, removing product_id:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "99d52ca7060341a698a664d1737663c5",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "id": "fdf3308e1db14cb99ec2ac3ddc64b374",
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO"
            }
        ]
    }
}

The response returns success but the invoice still contains the product after updating (see the product is still populated). Response:

"invoice_lines": [
        {
            "id": "fdf3308e1db14cb99ec2ac3ddc64b374",
            "displayed_as": "creating invoice",
            "description": "creating invoice",
            "product": {
                "id": "d81d133b98164ec8a6fc47a756ada18a",
                "displayed_as": "Lots of stuff",
                "$path": "/products/d81d133b98164ec8a6fc47a756ada18a",
                "created_at": "2020-05-15T11:38:49Z",
                "updated_at": "2021-07-15T11:48:36Z",
                "deletable": false,
                "deactivatable": false,
                "used_on_recurring_invoice": false,
                "item_code": "Stuff",
                "description": "Lots of stuff",
                "notes": "",
                "sales_ledger_account": {
                    "id": "9a994b92267a11e797950a57719b2edb",
                    "displayed_as": "Sales Type A (4000)",
                    "$path": "/ledger_accounts/9a994b92267a11e797950a57719b2edb"
                },
                "sales_tax_rate": {
                    "id": "GB_STANDARD",
                    "displayed_as": "Standard 20.00%",
                    "$path": "/tax_rates/GB_STANDARD"
                },
                "purchase_ledger_account": {
                    "id": "9a995955267a11e797950a57719b2edb",
                    "displayed_as": "Cost of sales - goods (5000)",
                    "$path": "/ledger_accounts/9a995955267a11e797950a57719b2edb"
                },
                "usual_supplier": null,
                "purchase_tax_rate": {
                    "id": "GB_STANDARD",
                    "displayed_as": "Standard 20.00%",
                    "$path": "/tax_rates/GB_STANDARD"
                },
                "cost_price": "10000.0",
                "sales_prices": [
                    {
                        "id": "7dae04f8274840c2893e84f92a82acf9",
                        "displayed_as": "Sales Price",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Sales Price",
                        "price": "1.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9aa528c0267a11e797950a57719b2edb",
                            "displayed_as": "Sales Price",
                            "$path": "/product_sales_price_types/9aa528c0267a11e797950a57719b2edb"
                        }
                    },
                    {
                        "id": "f21a28f61703473c9bf404573e369252",
                        "displayed_as": "Trade",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Trade",
                        "price": "0.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9aab371c267a11e797950a57719b2edb",
                            "displayed_as": "Trade",
                            "$path": "/product_sales_price_types/9aab371c267a11e797950a57719b2edb"
                        }
                    },
                    {
                        "id": "99c705b78633493b8f13d7b9cea1c35e",
                        "displayed_as": "Wholesale",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Wholesale",
                        "price": "0.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9ab1754b267a11e797950a57719b2edb",
                            "displayed_as": "Wholesale",
                            "$path": "/product_sales_price_types/9ab1754b267a11e797950a57719b2edb"
                        }
                    }
                ],
                "source_guid": null,
                "purchase_description": "",
                "active": true,
                "catalog_item_type": {
                    "id": "STOCK_ITEM",
                    "displayed_as": "Stock",
                    "$path": "/catalog_item_types/STOCK_ITEM"
                }
            },
            "service": null,
            "ledger_account": {
                "id": "9a994ff6267a11e797950a57719b2edb",
                "displayed_as": "Sale of Assets (4200)",
                "$path": "/ledger_accounts/9a994ff6267a11e797950a57719b2edb"
            },
            "trade_of_asset": false,
            "quantity": "1.0",
            "unit_price": "10.0",
            "net_amount": "10.0",
            "tax_rate": {
                "id": "GB_ZERO",
                "displayed_as": "Zero Rated 0.00%",
                "$path": "/tax_rates/GB_ZERO"
            },
            "tax_amount": "0.0",
            "tax_breakdown": [],
            "total_amount": "10.0",
            "base_currency_unit_price": "10.0",
            "unit_price_includes_tax": false,
            "base_currency_net_amount": "10.0",
            "base_currency_tax_amount": "0.0",
            "base_currency_tax_breakdown": [],
            "base_currency_total_amount": "10.0",
            "eu_goods_services_type": null,
            "discount_amount": "0.0",
            "base_currency_discount_amount": "0.0",
            "discount_percentage": "0.0",
            "eu_sales_description": null
        }
    ]

There is also an issue if you try and change from a product to a service, where it gives an error.

Request updating from product to service:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "99d52ca7060341a698a664d1737663c5",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "id": "8972f9b97e194c1590dcd9e081d17eeb",
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO",
                "service_id": "bc41345c8b8f4ca6a7bceec1643738a8"
            }
        ]
    }
}

Error response, saying there can't be both a product and a service, even though only a service_id has been supplied:

[
    {
        "$severity": "error",
        "$dataCode": "RecordInvalid",
        "$message": "Cannot assign both product and service",
        "$source": "line_items.base"
    },
    {
        "$severity": "error",
        "$dataCode": "RecordInvalid",
        "$message": "Cannot assign both product and service",
        "$source": "line_items"
    }
]

I can actually work around this issue by not including the id for the line item and instead set it to null, which then works as expected, however this then causes another problem (Issue 2).

Request to update sales invoice with null id for invoice line:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "99d52ca7060341a698a664d1737663c5",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "id": null,
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO"
            }
        ]
    }
}

Which does then return a response to show the product is now null:

"invoice_lines": [
        {
            "id": "7a4e0c63b98b4575bb23daddb75b0bd0",
            "displayed_as": "creating invoice",
            "description": "creating invoice",
            "product": null,
            "service": null,
            "ledger_account": {
                "id": "9a994ff6267a11e797950a57719b2edb",
                "displayed_as": "Sale of Assets (4200)",
                "$path": "/ledger_accounts/9a994ff6267a11e797950a57719b2edb"
            },
            "trade_of_asset": false,
            "quantity": "1.0",
            "unit_price": "10.0",
            "net_amount": "10.0",
            "tax_rate": {
                "id": "GB_ZERO",
                "displayed_as": "Zero Rated 0.00%",
                "$path": "/tax_rates/GB_ZERO"
            },
            "tax_amount": "0.0",
            "tax_breakdown": [],
            "total_amount": "10.0",
            "base_currency_unit_price": "10.0",
            "unit_price_includes_tax": false,
            "base_currency_net_amount": "10.0",
            "base_currency_tax_amount": "0.0",
            "base_currency_tax_breakdown": [],
            "base_currency_total_amount": "10.0",
            "eu_goods_services_type": null,
            "discount_amount": "0.0",
            "base_currency_discount_amount": "0.0",
            "discount_percentage": "0.0",
            "eu_sales_description": null
        }
    ]

 

Issue 2

Following on the the above (using the "id": null workaround), if I create a sales invoice this time for an EU customer (France) I am required to set the eu_goods_services_type_id for each line item. If I first create a sales invoice with an invoice line with a product and set eu_goods_services_type_id to GOODS, everything works okay.

Request to create sales invoice for EU customer:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "979c5156ea0e45d9a9ea7b9d54775138",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO",
                "product_id": "d81d133b98164ec8a6fc47a756ada18a",
                "eu_goods_services_type_id": "GOODS"
            }
        ]
    }
}

Response shows invoice line with a product:

"invoice_lines": [
        {
            "id": "b1d671312ece42f1ad078b2a4bea9206",
            "displayed_as": "creating invoice",
            "description": "creating invoice",
            "product": {
                "id": "d81d133b98164ec8a6fc47a756ada18a",
                "displayed_as": "Lots of stuff",
                "$path": "/products/d81d133b98164ec8a6fc47a756ada18a",
                "created_at": "2020-05-15T11:38:49Z",
                "updated_at": "2021-07-15T11:58:45Z",
                "deletable": false,
                "deactivatable": false,
                "used_on_recurring_invoice": false,
                "item_code": "Stuff",
                "description": "Lots of stuff",
                "notes": "",
                "sales_ledger_account": {
                    "id": "9a994b92267a11e797950a57719b2edb",
                    "displayed_as": "Sales Type A (4000)",
                    "$path": "/ledger_accounts/9a994b92267a11e797950a57719b2edb"
                },
                "sales_tax_rate": {
                    "id": "GB_STANDARD",
                    "displayed_as": "Standard 20.00%",
                    "$path": "/tax_rates/GB_STANDARD"
                },
                "purchase_ledger_account": {
                    "id": "9a995955267a11e797950a57719b2edb",
                    "displayed_as": "Cost of sales - goods (5000)",
                    "$path": "/ledger_accounts/9a995955267a11e797950a57719b2edb"
                },
                "usual_supplier": null,
                "purchase_tax_rate": {
                    "id": "GB_STANDARD",
                    "displayed_as": "Standard 20.00%",
                    "$path": "/tax_rates/GB_STANDARD"
                },
                "cost_price": "10000.0",
                "sales_prices": [
                    {
                        "id": "7dae04f8274840c2893e84f92a82acf9",
                        "displayed_as": "Sales Price",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Sales Price",
                        "price": "1.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9aa528c0267a11e797950a57719b2edb",
                            "displayed_as": "Sales Price",
                            "$path": "/product_sales_price_types/9aa528c0267a11e797950a57719b2edb"
                        }
                    },
                    {
                        "id": "f21a28f61703473c9bf404573e369252",
                        "displayed_as": "Trade",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Trade",
                        "price": "0.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9aab371c267a11e797950a57719b2edb",
                            "displayed_as": "Trade",
                            "$path": "/product_sales_price_types/9aab371c267a11e797950a57719b2edb"
                        }
                    },
                    {
                        "id": "99c705b78633493b8f13d7b9cea1c35e",
                        "displayed_as": "Wholesale",
                        "created_at": "2020-05-15T11:38:49Z",
                        "updated_at": "2020-05-15T11:38:49Z",
                        "price_name": "Wholesale",
                        "price": "0.0",
                        "price_includes_tax": false,
                        "product_sales_price_type": {
                            "id": "9ab1754b267a11e797950a57719b2edb",
                            "displayed_as": "Wholesale",
                            "$path": "/product_sales_price_types/9ab1754b267a11e797950a57719b2edb"
                        }
                    }
                ],
                "source_guid": null,
                "purchase_description": "",
                "active": true,
                "catalog_item_type": {
                    "id": "STOCK_ITEM",
                    "displayed_as": "Stock",
                    "$path": "/catalog_item_types/STOCK_ITEM"
                }
            },
            "service": null,
            "ledger_account": {
                "id": "9a994ff6267a11e797950a57719b2edb",
                "displayed_as": "Sale of Assets (4200)",
                "$path": "/ledger_accounts/9a994ff6267a11e797950a57719b2edb"
            },
            "trade_of_asset": false,
            "quantity": "1.0",
            "unit_price": "10.0",
            "net_amount": "10.0",
            "tax_rate": {
                "id": "GB_ZERO",
                "displayed_as": "Zero Rated 0.00%",
                "$path": "/tax_rates/GB_ZERO"
            },
            "tax_amount": "0.0",
            "tax_breakdown": [],
            "total_amount": "10.0",
            "base_currency_unit_price": "10.0",
            "unit_price_includes_tax": false,
            "base_currency_net_amount": "10.0",
            "base_currency_tax_amount": "0.0",
            "base_currency_tax_breakdown": [],
            "base_currency_total_amount": "10.0",
            "eu_goods_services_type": {
                "id": "GOODS",
                "displayed_as": "Goods (and related services)",
                "$path": "/eu_goods_services_types/GOODS"
            },
            "discount_amount": "0.0",
            "base_currency_discount_amount": "0.0",
            "discount_percentage": "0.0",
            "eu_sales_description": null
        }
    ]

However, if I then try and change the product to a service (or remove the product) having set the line "id" to null to workaround the first issue, and change the eu_goods_services_type_id to SERVICES to reflect this, it returns an error saying the goods and services type need to be the same, even though there is only one item.

Request to update sales invoice, changing product to service, and eu good and services type to SERVICES:

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "979c5156ea0e45d9a9ea7b9d54775138",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "id": null,
                "description": "creating invoice",
                "ledger_account_id": "9a994ff6267a11e797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO",
                "service_id": "bc41345c8b8f4ca6a7bceec1643738a8",
                "eu_goods_services_type_id": "SERVICES"
            }
        ]
    }
}

Returns the error that all eu goods and services need to be the same, but there is only one line:

[
    {
        "$severity": "error",
        "$dataCode": "RecordInvalid",
        "$message": "All items on this Sales Invoice must have the same EU Goods/Services type.",
        "$source": "base"
    }
]

This error goes away if I change the id from null to the actual line item Id, but then I am back to Issue 1 where the product isn't removed and cannot be changed. This happens for sales invoices, purchase invoices, sales credit notes. The only one I haven't checked is purchase credit notes.

Is this a bug with the API or is there something I'm missing or not doing correctly? I've tried various combinations of things but haven't been able to get it to work how I expect it to.

Thanks a lot for your help.

Christian.

Link to comment
Share on other sites

  • Administrators

Hi Christian,

Thanks for all of the detail. 

I've tested this myself using a UK VAT registered business using your initial sales_invoice example, and updating my contact, ledger account and product ids.

{
    "sales_invoice": {
        "date": "2021-07-15",
        "due_date": "2021-07-20",
        "currency_id": "GBP",
        "contact_id": "85b732ca9cda4c28ac580bb2c21c01e2",
        "exchange_rate": 1,
        "invoice_lines": [
            {
                "description": "creating invoice",
                "ledger_account_id": "bf15fce94a9112f797950a57719b2edb",
                "quantity": 1,
                "unit_price": 10,
                "tax_amount": 0,
                "tax_rate_id": "GB_ZERO",
                "product_id": "92b7697e4a9211e7979i9a57719b2edb"
            }
        ]
    }
}

The above posted as you'd expect, so I removed the product_id as you have and made a PUT request using the generated id of the sales_invoice https://api.accounting.sage.com/v3.1/sales_invoices/1b57cc6c911045ca8c35f0d4ca5d19d2

which resulted in:
 

"invoice_lines": [
        {
            "id": "37e25ac4623647b2af7bc3e9d1075738",
            "displayed_as": "creating invoice",
            "description": "creating invoice",
            "product": null,
            "service": null,
            "ledger_account": {
                "id": "bf15fce94a9112f797950a57719b2edb",
                "displayed_as": "Sales - Products (4000)",
                "$path": "/ledger_accounts/bf15fce94a9112f797950a57719b2edb"
            },
            "trade_of_asset": false,
...

I've verified this in the UI, and where there was a product listed, now isn't successfully - however this is a UK Business and a UK Contact.

I've discussed this with my colleague and we believe that this may be a bug thats been introduced during the EU VAT Reform changes made for 1st July 2021. 

We will investigate this further and let you know what we can find out.

 

Ben

Link to comment
Share on other sites

Hi Ben,

Thanks a lot for looking at this for me. Yes it sounds like it could be something around the EU VAT as it does seem to error with EU customers when trying to change from a product to service and changing the eu_goods_services_type_id from GOODS to SERVICES to match (or the other way around).

For your successful request that removed the product, it looks like you made the PUT without the id of the invoice line within the body. Do you get the same result if you include that id? Including that line id for me works around the issue with the EU customer encounter, but then results in the product not being removed. Perhaps it's not advised to use this id in PUT operations?

Christian.

Link to comment
Share on other sites

  • Administrators

Hi Christian,

Yeah, I didn't specify the id for the invoice line as when making a PUT as I view it that you are essentially re-posting a revised version of the invoice, as if it were new, so you wouldn't know the id of the line anyway. Ideally we could use a PATCH request (which we don't have available unfortunately), where as I'm sure you are already aware,  you could only include the details you want to update.

I get the same issue as you when including the invoice line id, the product is not removed. So, with that in mind I'd essentially write the request body for your PUT as if it were a POST, but with the altered values. 

That being said, the EU customer issue looks to be a bug and after some investigation my colleague Mark has logged two tickets for investigation by the engineering API team which for your records the ticket numbers are AC-6232 and AC-6234.  I don't have an ETA on when these will be looked at but will update you as soon as I can. 

Hope thats ok,

Ben

Link to comment
Share on other sites

Hi Ben,

Yes that makes sense regarding not specifying the id of the invoice line and treating it as if it were a POST.

Thanks for looking into the EU customer issue and raising the tickets for investigation; I appreciate it.

Christian.

  • Like 1
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...