From 05fd16a9130af9812683cec02f696e0c66d6d643 Mon Sep 17 00:00:00 2001 From: ribbery009 Date: Sat, 3 Feb 2024 15:12:08 +0100 Subject: [PATCH 1/4] Add adjustment invoice feature to Invoice class --- lib/Invoice.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Invoice.js b/lib/Invoice.js index 912dfe8..085092b 100644 --- a/lib/Invoice.js +++ b/lib/Invoice.js @@ -33,6 +33,8 @@ export class Invoice { this._options.paid = options.paid this._options.comment = options.comment this._options.logoImage = options.logoImage + this._options.adjustmentInvoice = options.adjustmentInvoice || false + this._options.adjustmentInvoiceNumber = options.adjustmentInvoiceNumber this._options.prepaymentInvoice = options.prepaymentInvoice || false } @@ -66,6 +68,8 @@ export class Invoice { assert(Array.isArray(this._options.items), 'Valid Items array missing from invoice options') + assert(!(this._options.adjustmentInvoice === true && typeof this._options.adjustmentInvoiceNumber === 'undefined'), 'If adjustmentInvoice is true, adjustmentInvoiceNumber must be specified.'); + let o = wrapWithElement('fejlec', [ [ 'keltDatum', this._options.issueDate ], [ 'teljesitesDatum', this._options.fulfillmentDate ], @@ -78,6 +82,8 @@ export class Invoice { [ 'arfolyam', this._options.exchangeRate ], [ 'rendelesSzam', this._options.orderNumber ], [ 'elolegszamla', this._options.prepaymentInvoice ], + [ 'helyesbitoszamla', this._options.adjustmentInvoice ], + [ 'helyesbitettSzamlaszam', this._options.adjustmentInvoiceNumber ], [ 'dijbekero', this._options.proforma ], [ 'logoExtra', this._options.logoImage ], [ 'szamlaszamElotag', this._options.invoiceIdPrefix ], From 0b4092471786333b53b2c44c56fe4f84772bf603 Mon Sep 17 00:00:00 2001 From: ribbery009 Date: Sun, 4 Feb 2024 00:51:51 +0100 Subject: [PATCH 2/4] Add adjustment invoice number to Invoice constructor and remove adjustmentInvoice bool --- README.md | 1 + lib/Invoice.js | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 93750cf..eb7bd2d 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ let invoice = new Invoice({ buyer: buyer, // the buyer, required items: [ soldItem1, soldItem2 ], // the sold items, required prepaymentInvoice: false // prepayment/deposit invoice should be issued, optional, default: false + adjustmentInvoiceNumber: 'ORIGINAL-INVOICE-NUMBER', // optional, only required for creating a correcting invoice }) ``` diff --git a/lib/Invoice.js b/lib/Invoice.js index 085092b..e9c71ce 100644 --- a/lib/Invoice.js +++ b/lib/Invoice.js @@ -33,7 +33,6 @@ export class Invoice { this._options.paid = options.paid this._options.comment = options.comment this._options.logoImage = options.logoImage - this._options.adjustmentInvoice = options.adjustmentInvoice || false this._options.adjustmentInvoiceNumber = options.adjustmentInvoiceNumber this._options.prepaymentInvoice = options.prepaymentInvoice || false } @@ -68,7 +67,12 @@ export class Invoice { assert(Array.isArray(this._options.items), 'Valid Items array missing from invoice options') - assert(!(this._options.adjustmentInvoice === true && typeof this._options.adjustmentInvoiceNumber === 'undefined'), 'If adjustmentInvoice is true, adjustmentInvoiceNumber must be specified.'); + + if (this._options.adjustmentInvoiceNumber !== null && this._options.adjustmentInvoiceNumber !== undefined) { + assert(typeof this._options.adjustmentInvoiceNumber === 'string', '"adjustmentInvoiceNumber" should be a string') + assert(this._options.adjustmentInvoiceNumber.length > 0, '"adjustmentInvoiceNumber" should be minimum 1 character') + this._options.adjustmentInvoice = true + } let o = wrapWithElement('fejlec', [ [ 'keltDatum', this._options.issueDate ], From bb41e773390a64c114996b907a937b10a53e523f Mon Sep 17 00:00:00 2001 From: ribbery009 Date: Sun, 4 Feb 2024 09:43:04 +0100 Subject: [PATCH 3/4] Add tests for adjustmentInvoiceNumber property --- tests/invoice.spec.js | 60 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/tests/invoice.spec.js b/tests/invoice.spec.js index 30fac93..31095eb 100644 --- a/tests/invoice.spec.js +++ b/tests/invoice.spec.js @@ -72,6 +72,60 @@ describe('Invoice', function () { it('should have `tetelek` node', function () { expect(obj).to.have.property('tetelek') }) - }) - }) -}) + + // START- New test suite for adjustmentInvoiceNumber property + describe('adjustmentInvoiceNumber validation', function () { + it('should not include adjustmentInvoiceNumber when it is null', function (done) { + invoice._options.adjustmentInvoiceNumber = null; + parser.parseString('' + invoice._generateXML() + '', function (err, result) { + expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitettSzamlaszam'); + done(); + }); + }); + + it('should not include adjustmentInvoiceNumber when it is undefined', function (done) { + delete invoice._options.adjustmentInvoiceNumber; + parser.parseString('' + invoice._generateXML() + '', function (err, result) { + expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitettSzamlaszam'); + done(); + }); + }); + + it('should throw an error when adjustmentInvoiceNumber is an empty string', function () { + expect(() => { + invoice._options.adjustmentInvoiceNumber = ''; + invoice._generateXML(); + }).to.throw(); + }); + + it('should throw an error when adjustmentInvoiceNumber is not a string', function () { + const invalidTypes = [new Date(), 123, true]; + invalidTypes.forEach(type => { + expect(() => { + invoice._options.adjustmentInvoiceNumber = type; + invoice._generateXML(); + }).to.throw(); + }); + }); + + it('should not throw an error when adjustmentInvoiceNumber is a non-empty string', function () { + expect(() => { + invoice._options.adjustmentInvoiceNumber = '12345'; + invoice._generateXML(); + }).to.not.throw(); + }); + + it('should include adjustmentInvoiceNumber when it is a non-empty string', function (done) { + invoice._options.adjustmentInvoiceNumber = '12345'; + parser.parseString('' + invoice._generateXML() + '', function (err, result) { + expect(result.wrapper.fejlec[0].helyesbitettSzamlaszam[0]).to.equal('12345'); + done(); + }); + }); + + }); + // END - New test suite for adjustmentInvoiceNumber property + + }); + }); +}); \ No newline at end of file From 0eee22253b0c12159afc0cd2520ad222a1b6ed66 Mon Sep 17 00:00:00 2001 From: ribbery009 Date: Sun, 4 Feb 2024 14:36:06 +0100 Subject: [PATCH 4/4] Refactor code formatting and add validation for adjustmentInvoiceNumber --- tests/invoice.spec.js | 133 +++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 26 deletions(-) diff --git a/tests/invoice.spec.js b/tests/invoice.spec.js index 31095eb..0a6abd3 100644 --- a/tests/invoice.spec.js +++ b/tests/invoice.spec.js @@ -2,10 +2,11 @@ import xml2js from 'xml2js' const parser = new xml2js.Parser() -import {expect} from 'chai' +import { expect } from 'chai' -import {Buyer, Invoice, Item, Seller} from '../index.js' -import {createSeller, createBuyer, createSoldItemNet, createSoldItemGross, createInvoice} from './resources/setup.js' +import { Buyer, Invoice, Item, Seller } from '../index.js' +import { createSeller, createBuyer, createSoldItemNet, createSoldItemGross, createInvoice } from './resources/setup.js' +import { Currency, Language, PaymentMethod } from "../lib/Constants.js" describe('Invoice', function () { let seller @@ -19,7 +20,7 @@ describe('Invoice', function () { buyer = createBuyer(Buyer) soldItem1 = createSoldItemNet(Item) soldItem2 = createSoldItemGross(Item) - invoice = createInvoice(Invoice, seller, buyer, [ soldItem1, soldItem2 ]) + invoice = createInvoice(Invoice, seller, buyer, [soldItem1, soldItem2]) }) describe('constructor', function () { @@ -36,7 +37,8 @@ describe('Invoice', function () { }) it('should set items', function () { - expect(invoice._options).to.have.property('items').that.is.an('array')}) + expect(invoice._options).to.have.property('items').that.is.an('array') + }) }) describe('_generateXML', function () { it('should return valid XML', function (done) { @@ -72,57 +74,136 @@ describe('Invoice', function () { it('should have `tetelek` node', function () { expect(obj).to.have.property('tetelek') }) - + // START- New test suite for adjustmentInvoiceNumber property describe('adjustmentInvoiceNumber validation', function () { it('should not include adjustmentInvoiceNumber when it is null', function (done) { - invoice._options.adjustmentInvoiceNumber = null; + const invoice = new Invoice({ + adjustmentInvoiceNumber: null, + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + }); + parser.parseString('' + invoice._generateXML() + '', function (err, result) { expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitettSzamlaszam'); - done(); + expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitoszamla'); + done(err); }); }); it('should not include adjustmentInvoiceNumber when it is undefined', function (done) { - delete invoice._options.adjustmentInvoiceNumber; + const invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + }); + parser.parseString('' + invoice._generateXML() + '', function (err, result) { expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitettSzamlaszam'); - done(); + expect(result.wrapper).to.not.have.deep.property('fejlec.helyesbitoszamla'); + done(err); }); }); it('should throw an error when adjustmentInvoiceNumber is an empty string', function () { expect(() => { - invoice._options.adjustmentInvoiceNumber = ''; + invoice = new Invoice({ + adjustmentInvoiceNumber: '', + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + }); + invoice._generateXML(); + }).to.throw(/"adjustmentInvoiceNumber" should be minimum 1 character/); + }); + + it('should throw an error when adjustmentInvoiceNumber is a Date object', function () { + + expect(() => { + invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + adjustmentInvoiceNumber: new Date() + }); invoice._generateXML(); - }).to.throw(); + }).to.throw(/"adjustmentInvoiceNumber" should be a string/); }); - it('should throw an error when adjustmentInvoiceNumber is not a string', function () { - const invalidTypes = [new Date(), 123, true]; - invalidTypes.forEach(type => { - expect(() => { - invoice._options.adjustmentInvoiceNumber = type; - invoice._generateXML(); - }).to.throw(); + it('should throw an error when adjustmentInvoiceNumber is a number', function () { + invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + adjustmentInvoiceNumber: 123 }); + expect(() => { + invoice._generateXML(); + }).to.throw(/"adjustmentInvoiceNumber" should be a string/); + }); + + it('should throw an error when adjustmentInvoiceNumber is a boolean', function () { + const invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + adjustmentInvoiceNumber: true + }); + expect(() => { + invoice._generateXML(); + }).to.throw(/"adjustmentInvoiceNumber" should be a string/); }); it('should not throw an error when adjustmentInvoiceNumber is a non-empty string', function () { expect(() => { - invoice._options.adjustmentInvoiceNumber = '12345'; - invoice._generateXML(); + const invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + adjustmentInvoiceNumber: '12345' + }); + invoice._generateXML(); }).to.not.throw(); - }); + }); it('should include adjustmentInvoiceNumber when it is a non-empty string', function (done) { - invoice._options.adjustmentInvoiceNumber = '12345'; + const invoice = new Invoice({ + paymentMethod: PaymentMethod.BankTransfer, + currency: Currency.Ft, + language: Language.Hungarian, + seller: seller, + buyer: buyer, + items: [soldItem1, soldItem2], + adjustmentInvoiceNumber: '12345' + }); parser.parseString('' + invoice._generateXML() + '', function (err, result) { - expect(result.wrapper.fejlec[0].helyesbitettSzamlaszam[0]).to.equal('12345'); - done(); + expect(result.wrapper.fejlec[0].helyesbitettSzamlaszam[0]).to.equal('12345'); + expect(result.wrapper.fejlec[0].helyesbitoszamla[0]).to.equal('true'); + done(err); }); }); - }); // END - New test suite for adjustmentInvoiceNumber property