diff --git a/package.json b/package.json index c34bc9f..443a8cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pixeldrive/peppol-toolkit", - "version": "0.8.1", + "version": "0.8.2", "description": "A TypeScript toolkit for building and reading peppol UBL documents", "keywords": [ "peppol", diff --git a/src/builder/DocumentBuilder.ts b/src/builder/DocumentBuilder.ts index 1fada09..85c7b4a 100644 --- a/src/builder/DocumentBuilder.ts +++ b/src/builder/DocumentBuilder.ts @@ -4,6 +4,7 @@ import { CurrencyCode, Invoice, partySchema, CreditNote } from '../documents'; import XMLAttributes from '../helpers/XMLAttributes'; import getDateString from '../helpers/getDateString'; import { z } from 'zod'; +import { isNullish } from '../helpers/isNullish'; const DEFAULT_CUSTOMIZATION_ID = 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0'; @@ -766,7 +767,8 @@ export class DocumentBuilder { ...this.__buildAmount( 'PayableAmount', total.payableAmount, - total.payableAmountCurrency ?? currency + total.payableAmountCurrency ?? currency, + true ), }; } @@ -774,9 +776,11 @@ export class DocumentBuilder { private __buildAmount( name: string, amount: number | undefined, - currency: CurrencyCode + currency: CurrencyCode, + generateOnZero = false ) { - if (!amount) return {}; + if (isNullish(amount)) return {}; + if (!amount && !generateOnZero) return {}; return { [`cbc:${name}`]: { '#text': amount.toFixed(2), diff --git a/src/helpers/isNullish.ts b/src/helpers/isNullish.ts new file mode 100644 index 0000000..702affb --- /dev/null +++ b/src/helpers/isNullish.ts @@ -0,0 +1,2 @@ +export const isNullish = (value: any): value is null | undefined => + value === null || value === undefined; diff --git a/tests/builder-creditnote.test.ts b/tests/builder-creditnote.test.ts index a6515a7..3e87a3a 100644 --- a/tests/builder-creditnote.test.ts +++ b/tests/builder-creditnote.test.ts @@ -66,6 +66,42 @@ describe('Creditnote Builder', () => { ); }); + it('should always include payable amount even when it is zero', () => { + const creditNoteXML = toolkit.creditNoteToPeppolUBL({ + ...basicCreditNote, + legalMonetaryTotal: { + ...basicCreditNote.legalMonetaryTotal, + payableAmount: 0, + }, + }); + + expect(creditNoteXML).toContain( + '0.00' + ); + }); + + it('should omit other zero monetary amounts when generateOnZero is false', () => { + const creditNoteXML = toolkit.creditNoteToPeppolUBL({ + ...basicCreditNote, + legalMonetaryTotal: { + ...basicCreditNote.legalMonetaryTotal, + payableAmount: 0, + prepaidAmount: 0, + allowanceTotalAmount: 0, + chargeTotalAmount: 0, + payableRoundingAmount: 0, + }, + }); + + expect(creditNoteXML).toContain( + '0.00' + ); + expect(creditNoteXML).not.toContain(' { const creditNoteXML = toolkit.creditNoteToPeppolUBL({ ...basicCreditNote, diff --git a/tests/builder-invoice.test.ts b/tests/builder-invoice.test.ts index a6992c0..45ef67d 100644 --- a/tests/builder-invoice.test.ts +++ b/tests/builder-invoice.test.ts @@ -66,6 +66,42 @@ describe('Invoices Builder', () => { ); }); + it('should always include payable amount even when it is zero', () => { + const invoiceXML = toolkit.invoiceToPeppolUBL({ + ...basicInvoice, + legalMonetaryTotal: { + ...basicInvoice.legalMonetaryTotal, + payableAmount: 0, + }, + }); + + expect(invoiceXML).toContain( + '0.00' + ); + }); + + it('should omit other zero monetary amounts when generateOnZero is false', () => { + const invoiceXML = toolkit.invoiceToPeppolUBL({ + ...basicInvoice, + legalMonetaryTotal: { + ...basicInvoice.legalMonetaryTotal, + payableAmount: 0, + prepaidAmount: 0, + allowanceTotalAmount: 0, + chargeTotalAmount: 0, + payableRoundingAmount: 0, + }, + }); + + expect(invoiceXML).toContain( + '0.00' + ); + expect(invoiceXML).not.toContain(' { const invoiceXML = toolkit.invoiceToPeppolUBL({ ...basicInvoice,