Skip to content

Commit

Permalink
fix: tax calculation (#775)
Browse files Browse the repository at this point in the history
  • Loading branch information
leoslr committed Feb 16, 2022
1 parent 6773e0c commit d1281e6
Show file tree
Hide file tree
Showing 2 changed files with 330 additions and 1 deletion.
35 changes: 35 additions & 0 deletions packages/data-format/src/format/rnf_invoice/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,38 @@ export const getInvoiceLineTotal = (item: InvoiceItem): BigNumber => {
),
);
};

export const getInvoiceTotalWithoutTax = (invoice: Invoice): BigNumber => {
return invoice.invoiceItems.reduce(
(acc, item) => acc.add(getInvoiceLineTotalWithoutTax(item)),
BigNumber.from(0),
);
};

export const getInvoiceLineTotalWithoutTax = (item: InvoiceItem): BigNumber => {
const discount = item.discount ? BigNumber.from(item.discount) : BigNumber.from(0);

return BigNumber.from(
// Removes the resulting decimal (.0)
Number(
FixedNumber.from(item.unitPrice)
// accounts for floating quantities
.mulUnsafe(FixedNumber.fromString(item.quantity.toString()))
.subUnsafe(FixedNumber.from(discount))
.round(0)
.toString(),
),
);
};

export const getInvoiceTaxTotal = (invoice: Invoice): BigNumber => {
const invoiceTotalWithoutTax = invoice.invoiceItems.reduce(
(acc, item) => acc.add(getInvoiceLineTotalWithoutTax(item)),
BigNumber.from(0),
);
const invoiceTotal = invoice.invoiceItems.reduce(
(acc, item) => acc.add(getInvoiceLineTotal(item)),
BigNumber.from(0),
);
return invoiceTotal.sub(invoiceTotalWithoutTax);
};
296 changes: 295 additions & 1 deletion packages/data-format/test/rnf_invoice/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { getInvoiceTotal } from '../../src/format/rnf_invoice';
import {
getInvoiceTotal,
getInvoiceTotalWithoutTax,
getInvoiceTaxTotal,
} from '../../src/format/rnf_invoice';

const baseInvoiceItem = {
name: 'test 1',
Expand Down Expand Up @@ -193,3 +197,293 @@ describe('getInvoiceTotal', () => {
).toEqual('4000');
});
});

describe('getInvoiceTotalWithoutTax', () => {
it('supports single items', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [baseInvoiceItem],
}).toString(),
).toEqual('1000');
});

it('supports single items with quantity', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [{ ...baseInvoiceItem, quantity: 2 }],
}).toString(),
).toEqual('2000');
});

it('supports multiple items', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [
{ ...baseInvoiceItem, unitPrice: '1000' },
{ ...baseInvoiceItem, unitPrice: '500' },
],
}).toString(),
).toEqual('1500');
});

it('supports single item with discount', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
discount: '1000000',
},
],
}).toString(),
).toEqual('500000');
});

it('supports floating quantity', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '3333',
quantity: 0.3333,
},
],
}).toString(),
).toEqual('1111');
});

it('supports several items with floating quantity', () => {
expect(
getInvoiceTotalWithoutTax({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '3333',
quantity: 0.3333,
},
{
...baseInvoiceItem,
unitPrice: '3333',
quantity: 0.3333,
},
],
}).toString(),
).toEqual('2222');
});
});

describe('getInvoiceTaxTotal', () => {
it('supports single items', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [baseInvoiceItem],
}).toString(),
).toEqual('0');
});

it('supports single items with quantity', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [{ ...baseInvoiceItem, quantity: 2 }],
}).toString(),
).toEqual('0');
});

it('supports multiple items', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{ ...baseInvoiceItem, unitPrice: '1000' },
{ ...baseInvoiceItem, unitPrice: '500' },
],
}).toString(),
).toEqual('0');
});

it('supports rnf_invoice 0.0.2 items with taxPercent tax', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
meta: {
format: 'rnf_invoice',
version: '0.0.2',
},
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
quantity: 1,
taxPercent: 10,
},
],
}).toString(),
).toEqual('150000');
});

it('supports single items with fixed tax', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
tax: { amount: '500000', type: 'fixed' },
},
],
}).toString(),
).toEqual('500000');
});

it('supports single item with percentage discount', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
discount: '1000000',
},
],
}).toString(),
).toEqual('0');
});

it('supports single item with tax', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
tax: { amount: '12', type: 'percentage' },
},
],
}).toString(),
).toEqual('180000');
});

it('supports single item with tax and percentage discount', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
discount: '1000000',
tax: { amount: '12', type: 'percentage' },
},
],
}).toString(),
).toEqual('60000');
});

it('supports single item with fixed tax and discount', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
discount: '1000000',
tax: { amount: '500000', type: 'fixed' },
},
],
}).toString(),
).toEqual('500000');
});

it('supports floating quantity', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
quantity: 0.333,
},
],
}).toString(),
).toEqual('0');
});

it('supports floating tax', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '1500000',
tax: {
type: 'percentage',
amount: '1.011',
},
},
],
}).toString(),
).toEqual('15165');
});

it('rounds the total correctly', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '3333',
tax: {
type: 'percentage',
amount: '20',
},
},
],
}).toString(),
).toEqual('667');
});

it('supports several items with taxes & floating quantity', () => {
expect(
getInvoiceTaxTotal({
...baseInvoice,
invoiceItems: [
{
...baseInvoiceItem,
unitPrice: '3333',
quantity: 0.3333,
tax: {
type: 'percentage',
amount: '10',
},
},
{
...baseInvoiceItem,
unitPrice: '3333',
quantity: 0.3333,
tax: {
type: 'percentage',
amount: '10',
},
},
],
}).toString(),
).toEqual('222');
});
});

0 comments on commit d1281e6

Please sign in to comment.