XeroAPI / xero-node

Xero Node SDK for OAuth 2.0 generated from XeroAPI/Xero-OpenAPI
http://developer.xero.com/
MIT License
205 stars 162 forks source link

Xero accounting API issues with fractional values for invoicing! #592

Closed yagnesh-s-crest closed 2 years ago

yagnesh-s-crest commented 2 years ago

SDK you're using (please complete the following information):

Describe the bug When invoices are being created with more than 2 fraction points, Xero malfunctions internally.

To Reproduce Steps to reproduce the behavior:

  1. Create any invoices where line items has discountAmount in a way that generates discountRate to be more than 2 fraction points by internal calculations (detailed explanation in addition context)
  2. Open view invoice page (https://go.xero.com/AccountsReceivable/View.aspx?InvoiceID=id)
  3. Open edit invoice page (https://go.xero.com/AccountsReceivable/Edit.aspx?InvoiceID=id)
  4. Find the difference in total values.
  5. Try to authorize invoice using updateInvoice method which will fail with an error saying line total mismatch. The same approve will work from Xero account manually.

Expected behavior Xero Node client is expected to work properly for 4 fractional points when unitdp has been set to 4.

Screenshots View Page Screenshot Invoices Listing Screenshot Edit Page Screenshot

Additional context Here's a complete scenario that mentions the current issue in depth.

I'm using Xero API for quite some time to create an invoice, add payments, and credit notes, and create bills as well. Everything was working fine until invoices with fraction points in discount percentages have introduced. Now Xero is acting very weird and I can't think of a way to fix it. So here's my case! I have an invoice with 2 line items.

Line 1: First line has 24 quantity with 23.46 unit price. Total applied discount is 14.9705% thus total of first line is 478.75. Line 2: Second line has 26 quantity with 27.68 unit price. Total applied discount is 13.8047% thus total of first line is 620.33. Now, It's completely accurate in Xero as well because that's the exact value that I want to be honest with and what exists in my personal system. The same invoice shows the grand total of 1,099.08 on both the View Invoice page and the listing page. But now if I open the same invoice on the Edit page, The total abruptly becomes 1,099.11 because of the second line's total being 620.36 from 620.33. It's happening because of floating point ignorance in discounts.

Painful Issue: I was fine with that UI-only problem but it causing me a lot of trouble as I'm not unable to authorize the invoice using API (However manual approval works fine 🤦‍♂️) and unable to void any invoices because it abruptly throws me an error saying "The line total 620.33 does not match the expected line total 620.36"

RettBehrens commented 2 years ago

Hi @yagnesh-s-crest after discussing with API CX it sounds like this is an issue at the API level not specific to the Xero-Node SDK. Please contact api@xero.com and include the full payload used to create the invoice in your email.

yagnesh-s-crest commented 2 years ago

@RettBehrens, I've had a talk with official support and they provided two quick fixes so I'm sharing them as a reference below.

To provide some context, originally Xero only provided a discount rate option on invoice lines. The ability to use a discount amount was added later. When the discount amount is used the discount rate is also calculated. This has some unintended side-effects as you have seen.

In this case the main payload was omitted when the invoice was approved, as such it was inferred from what was on file for the invoice in question and the discount rate was incorrectly used (instead of the discount amount).

I shall raise a ticket with our product team to investigate a fix for this behaviour. In the meantime there are two potential workarounds that can be used.

The most simple would be to approve/authorise the invoices when they are created.

The second would be to retrieve the complete payload of the invoice prior to approving it, when making the update call to approve it you would remove the DiscountRate fields and pass the rest of the payload. The invoice will then pass validation.

I can very well confirm that second solution worked for me as I couldn't use first solution which was against our business requirement.