xero-node icon indicating copy to clipboard operation
xero-node copied to clipboard

Invoice creation fails for micro-transactions (< $0.01) with unitdp: 4

Open r0yfire opened this issue 6 months ago • 2 comments

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

  • xero-node version: 9.2.0
  • Node.js version: 16.20.2

Describe the bug When using unitdp: 4 with line items that have a total amount less than $0.01 and no tax, unexpected validation errors are thrown. This occurs even when the account code and tax type are valid.

☝️ Update: This condition appears to be triggered when the invoice status is set to AUTHORISED. If the invoice is set to DRAFT it is created as expected.

To Reproduce Steps to reproduce the behavior:

  1. Create a new invoice object with a line item that has the following shape:
{
  "description": "Email messages delivery",
  "quantity": 2,
  "unitAmount": 0.001,
  "accountCode": "40113",
  "taxType": "OUTPUT",
  "taxAmount": 0
}
  1. Submit the invoice using the createInvoices method and set unitdp: 4, like so:
const createdInvoicesResponse = await XeroClient.accountingApi.createInvoices(
        tenantId,
        {invoices},
        undefined,
        4,
        undefined,
        undefined,
    );
  1. Observe the following validation error returned:
{
  "Description": "Email messages delivery",
  "UnitAmount": 0.001,
  "TaxAmount": 0,
  "LineAmount": 0,
  "Tracking": [],
  "Quantity": 2,
  "LineItemID": "b5275db3-9817-40d9-9dd4-d50f22ed03d0",
  "ValidationErrors": [
    {
      "Message": "Account must be valid."
    },
    {
      "Message": "Tax rate must be valid."
    }
  ]
}

However, when I change the line item's unitAmount to be "0.1" it works as expected.

Expected behavior The Xero API and SDK should allow creation of invoices with line items having four decimal places, no tax, and total amounts less than $0.01, without throwing validation errors.

Additional context Here's a minimal, complete example that reproduces the issue:

import {Invoice} from 'xero-node';

const reproduceIssue = async () => {
    const {xero, tenantId} = await getXeroClient();
    const invoice = {
        type: Invoice.TypeEnum.ACCREC,
        contact: {contactID: 'VALID_CONTACT_ID'},
        lineItems: [{
            description: "Email messages delivery",
            quantity: 2,
            unitAmount: 0.001,
            accountCode: "40113",
            taxType: "OUTPUT",
            taxAmount: 0
        }],
        date: new Date().toISOString().split('T')[0],
        dueDate: new Date().toISOString().split('T')[0],
        status: Invoice.StatusEnum.AUTHORISED,
    };
    try {
        const response = await xero.accountingApi.createInvoices(
            tenantId,
            {invoices: [invoice]},
            undefined,
            4,
            undefined,
            undefined
        );
        console.log('Invoice created successfully:', response.body);
    } catch (error: any) {
        console.error('Error creating invoice:', error);
    }
};

(async () => {
    await reproduceIssue();
})();
  • I can provided the full API response, but I don't think it's needed.
  • I could not find similar issues here.
  • The account code 40113 is a "Sales" account type.

r0yfire avatar Aug 27 '24 12:08 r0yfire