diff --git a/README.md b/README.md index b6c68cf..a14ce5e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ With SwissQRBill you can easily generate the new QR Code payment slips which will be introduced on 30 June 2020 in switzerland. +[](https://github.com/Rogerrrrrrrs/SwissQRBill/blob/master/assets/qrbill.pdf) + + ## Contents * [Features](#features) @@ -11,21 +14,24 @@ With SwissQRBill you can easily generate the new QR Code payment slips which wil * [Usage](#Usage) * [API](#API) + ## Features - Generates PDF with scalable vector graphics - Supports german, english, italian and french invoices - Supports A4 invoices as well as A6/5 (QR Bill only) - - Supports empty fields as defined in the [specifications](https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-de.pdf) + - Supports empty fields as defined in the [specifications](https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-en.pdf) - Allows you to add other content above the invoice using [PDFKit](https://github.com/foliojs/pdfkit) - Easy to use - Free and open source + ## Installation ``` npm i swissqrbill --save ``` + ## Usage ```js @@ -34,7 +40,7 @@ const SwissQRBill = require("swissqrbill"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", @@ -55,13 +61,14 @@ const data = { const bill = new SwissQRBill.PDF(data, "qrbill.pdf"); ``` -This will generate the following PDF file +This will generate the above PDF. -[](https://github.com/Rogerrrrrrrs/SwissQRBill/blob/master/assets/qrbill.pdf) ## API + ### Methods + - Constructor - [SwissQRBill.PDF(data, outputPath[, options])](#swissqrbillpdfdata-outputpath-options) - Methods @@ -70,38 +77,50 @@ This will generate the following PDF file - [addQRBill()](#addqrbill) - [mmToPoints(mm)](#mmtopointsmm) + #### SwissQRBill.PDF(data, outputPath[, options]) + - data - object containing all relevant billing data. - outputPath - string output path for the generated PDF file. - options - object containing settings, optional. - - Returns a new instance of SwissQRBill.PDF. + + + Returns a new instance of SwissQRBill.PDF Available options: - language - string: Either `"DE" | "EN" | "IT" | "FR"`. Default `"DE"`. - size - string: Either `"A4" | "A6/5"`. Default `"A6/5"`. - scissors - boolean: Whether you want to show the scissor icons or the text `Separate before paying in`. Default `true`. - - autoGenerate - boolean: Whether you want to atomatically finalize the PDF. When set to false you are able to add your own content to the PDF using PDFKit. Default `true`. + - autoGenerate - boolean: Whether you want to automatically finalize the PDF. When set to false you are able to add your own content to the PDF using PDFKit. Default `true`. + #### addPage() + Adds a new page to the PDF. + #### end() + Finalizes the PDF document, after this command you are no longer able to edit the PDF. Note: This function is automatically called when the option autoGenerate is set to true. + #### addQRBill() + Adds the QR Bill to the bottom of the current page. Note: This function is automatically called when the option autoGenerate is set to true. + #### mmToPoints(mm) + - mm - number containg the millimeters you want to convert to points. Converts milimeters to points which are used in the PDF file. Returns a number containing the converted millimeters in points. ## PDFKit -This module uses [PDFKit](https://github.com/foliojs/pdfkit) to generate PDF files. You are able to generate a comlete bill using PDFKit methods and then add the QR Bill to the bottom using `addQRBill()` when the option `autoGenerate` is set to `false`. + +This module uses [PDFKit](https://github.com/foliojs/pdfkit) to generate PDF files. You are able to generate a complete bill using PDFKit methods and then add the QR Bill to the bottom using `addQRBill()` when the option `autoGenerate` is set to `false`. The documentation for PDFKit can be found [here](http://pdfkit.org/docs/getting_started.html). @@ -113,7 +132,7 @@ const SwissQRBill = require("swissqrbill"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/assets/qrbill.pdf b/assets/qrbill.pdf index 049875f..2d4802a 100644 Binary files a/assets/qrbill.pdf and b/assets/qrbill.pdf differ diff --git a/assets/qrbill.png b/assets/qrbill.png index 45cf579..3468af7 100644 Binary files a/assets/qrbill.png and b/assets/qrbill.png differ diff --git a/example/a4.js b/example/a4.js new file mode 100644 index 0000000..7457a38 --- /dev/null +++ b/example/a4.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/a4.pdf", { size: "A4" }); \ No newline at end of file diff --git a/example/a6.js b/example/a6.js index 3888323..77bbdd4 100644 --- a/example/a6.js +++ b/example/a6.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/example/multipage.js b/example/multipage.js index c03afb5..4dc9186 100644 --- a/example/multipage.js +++ b/example/multipage.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/example/normal-iban-creditor-reference.js b/example/normal-iban-creditor-reference.js new file mode 100644 index 0000000..8c92b34 --- /dev/null +++ b/example/normal-iban-creditor-reference.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "RF18539007547034", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH5800791123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/normal-iban-creditor-reference.pdf"); \ No newline at end of file diff --git a/example/normal-iban-no-reference.js b/example/normal-iban-no-reference.js new file mode 100644 index 0000000..9be82d0 --- /dev/null +++ b/example/normal-iban-no-reference.js @@ -0,0 +1,23 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH5800791123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/normal-iban-no-reference.pdf"); \ No newline at end of file diff --git a/example/qr-iban.js b/example/qr-iban.js new file mode 100644 index 0000000..69fd0df --- /dev/null +++ b/example/qr-iban.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/qr-iban.pdf"); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0ab412b..ee309ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "swissqrbill", - "version": "1.0.5", + "version": "1.0.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -131,17 +131,6 @@ } } }, - "@typescript-eslint/experimental-utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz", - "integrity": "sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.21.0", - "eslint-scope": "^5.0.0" - } - }, "@typescript-eslint/parser": { "version": "2.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.22.0.tgz", @@ -188,38 +177,6 @@ } } }, - "@typescript-eslint/typescript-estree": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz", - "integrity": "sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", diff --git a/package.json b/package.json index 622efa2..a612eaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swissqrbill", - "version": "1.0.5", + "version": "1.0.6", "description": "Swiss QR Bill generation in node.js ", "main": "./index.js", "types": "./lib/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 842169a..ce8268f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -138,38 +138,53 @@ export namespace SwissQRBill { this._data = data; - //-- Validate data + //-- Validate IBAN + + if(this._data.creditor.account === undefined){ + throw new Error("You must provide an IBAN or QR-IBAN number."); + } + if(this._data.creditor.account.replace(/ /g, "").length !== 21){ + throw new Error(`The provided IBAN number '${this._data.creditor.account}' is either too long or too short.`); + } if(IBAN.isValid(this._data.creditor.account) === false){ throw new Error(`The provided IBAN number '${this._data.creditor.account}' is not valid.`); } if(this._data.creditor.account.substr(0, 2) !== "CH" && this._data.creditor.account.substr(0, 2) !== "LI"){ - throw new Error("Only CH and LI IBAN numbers are allowed"); + throw new Error("Only CH and LI IBAN numbers are allowed."); } - if(this._isQRIBAN(this._data.creditor.account)){ - this._referenceType = "QRR"; + //-- Validate reference + + if(this._isQRIBAN(this._data.creditor.account)){ if(this._data.reference === undefined){ - throw new Error("QR-IBAN numbers must have a reference"); + throw new Error("If there is no reference, a conventional IBAN must be used."); } + if(this._isQRReference(this._data.reference)){ + this._referenceType = "QRR"; + } else { + throw new Error("QR reference requires the use of a QR-IBAN (and vice versa)."); + } + + } else { if(this._data.reference === undefined){ this._referenceType = "NON"; } else { - this._referenceType = "SCOR"; + if(this._isQRReference(this._data.reference)){ + throw new Error("Creditor Reference requires the use of a conventional IBAN."); + } else { + this._referenceType = "SCOR"; + } } } - if(this._data.creditor.name.length > 70){ - throw new Error("Creditor name can be a maximum of 70 characters"); - } - if(options !== undefined){ if(options.language !== undefined){ this._language = options.language; @@ -621,177 +636,331 @@ export namespace SwissQRBill { let qrString = ""; - qrString += "SPC\n"; // Swiss Payments Code - qrString += "0200\n"; // Version - qrString += "1\n"; // Coding Type UTF-8 - qrString += this._formatIBAN(this._data.creditor.account)??this._data.creditor.account + "\n"; // IBAN + //-- Swiss Payments Code + + qrString += "SPC\n"; + + + //-- Version + + qrString += "0200\n"; + + + //-- Coding Type UTF-8 + + qrString += "1\n"; + + + //-- IBAN + + qrString += this._data.creditor.account.replace(/ /g, "")+ "\n" ?? "\n"; + if(this._data.creditor.houseNumber !== undefined){ - qrString += "S\n"; // Adress Type - if(this._data.creditor.name.length > 70){ - throw new Error("Creditor name must be a maximum of 70 characters"); - } - qrString += this._data.creditor.name + "\n"; // Name + //-- Adress Type - if(this._data.creditor.address.length > 70){ - throw new Error("Creditor address must be a maximum of 70 characters"); - } - qrString += this._data.creditor.address + "\n"; // Address + qrString += "S\n"; - if(this._data.creditor.address.length > 16){ - throw new Error("Creditor house number can be a maximum of 16 characters"); - } - qrString += this._data.creditor.houseNumber + "\n"; // House number - if(this._data.creditor.address.length > 16){ - throw new Error("Creditor zip must be a maximum of 16 characters"); - } - qrString += this._data.creditor.zip + "\n"; // Zip code + //-- Name + + if(this._data.creditor.name === undefined){ throw new Error("Creditor name cannot be undefined."); } + if(this._data.creditor.name.length > 70){ throw new Error("Creditor name must be a maximum of 70 characters."); } + qrString += this._data.creditor.name + "\n"; + - if(this._data.creditor.address.length > 35){ - throw new Error("Creditor city must be a maximum of 35 characters"); + //-- Address + + if(this._data.creditor.address === undefined){ throw new Error("Creditor address cannot be undefined."); } + if(this._data.creditor.address.length > 70){ throw new Error("Creditor address must be a maximum of 70 characters."); } + qrString += this._data.creditor.address + "\n"; + + + //-- House number + + if(this._data.creditor.houseNumber.length > 16){ + throw new Error("Creditor house number can be a maximum of 16 characters."); } - qrString += this._data.creditor.city + "\n"; // City + qrString += this._data.creditor.houseNumber + "\n"; + + + //-- Zip + + if(this._data.creditor.zip === undefined){ throw new Error("Creditor zip cannot be undefined."); } + if(this._data.creditor.zip.toString().length > 16){ throw new Error("Creditor zip must be a maximum of 16 characters."); } + qrString += this._data.creditor.zip + "\n"; + + if(this._data.creditor.city === undefined){ throw new Error("Creditor city cannot be undefined."); } + if(this._data.creditor.city.length > 35){ throw new Error("Creditor city must be a maximum of 35 characters."); } + qrString += this._data.creditor.city + "\n"; } else { - qrString += "K\n"; // Adress Type - if(this._data.creditor.name.length > 70){ - throw new Error("Creditor name must be a maximum of 70 characters"); - } - qrString += this._data.creditor.name + "\n"; // Name + //-- Adress Type - if(this._data.creditor.address.length > 70){ - throw new Error("Creditor address must be a maximum of 70 characters"); - } - qrString += this._data.creditor.address + "\n"; // Address + qrString += "K\n"; - if((this._data.creditor.zip + " " + this._data.creditor.city).length > 70){ - throw new Error("Creditor zip plus city must be a maximum of 70 characters"); - } - qrString += this._data.creditor.zip + " " + this._data.creditor.city + "\n"; // Zip code + city - } + //-- Name + + if(this._data.creditor.name === undefined){ throw new Error("Creditor name cannot be undefined."); } + if(this._data.creditor.name.length > 70){ throw new Error("Creditor name must be a maximum of 70 characters."); } + qrString += this._data.creditor.name + "\n"; + + + //-- Address + + if(this._data.creditor.address === undefined){ throw new Error("Creditor address cannot be undefined."); } + if(this._data.creditor.address.length > 70){ throw new Error("Creditor address must be a maximum of 70 characters."); } + qrString += this._data.creditor.address + "\n"; + + + //-- Zip + city + + + if(this._data.creditor.zip === undefined || this._data.creditor.city === undefined){ throw new Error("Creditor zip and city cannot be undefined."); } + if((this._data.creditor.zip + " " + this._data.creditor.city).length > 70){ throw new Error("Creditor zip plus city must be a maximum of 70 characters."); } + qrString += this._data.creditor.zip + " " + this._data.creditor.city + "\n"; + + + //-- Empty zip field + + qrString += "\n"; + + + //-- Empty city field + + qrString += "\n"; - if(this._data.creditor.country.length !== 2){ - throw new Error("Creditor country must be 2 characters"); } - qrString += this._data.creditor.country + "\n"; // Country + + if(this._data.creditor.country === undefined){ throw new Error("Creditor country cannot be undefined."); } + if(this._data.creditor.country.length !== 2){ throw new Error("Creditor country must be 2 characters."); } + qrString += this._data.creditor.country + "\n"; //-- 7 x empty - qrString += "\n"; // 1 - qrString += "\n"; // 2 - qrString += "\n"; // 3 - qrString += "\n"; // 4 - qrString += "\n"; // 5 - qrString += "\n"; // 6 - qrString += "\n"; // 7 + qrString += "\n"; // 1 + qrString += "\n"; // 2 + qrString += "\n"; // 3 + qrString += "\n"; // 4 + qrString += "\n"; // 5 + qrString += "\n"; // 6 + qrString += "\n"; // 7 + + + //-- Amount if(this._data.amount !== undefined){ if(this._data.amount.toString().length > 12){ - throw new Error("Creditor country must be 2 characters"); + throw new Error("Creditor country must be 2 characters."); } } - qrString += (this._data.amount ?? "") + "\n"; // Amount - qrString += this._data.currency + "\n"; // Currency + qrString += (this._data.amount ?? "") + "\n"; + + + //-- Currency + + if(this._data.currency === undefined){ throw new Error("Currency cannot be undefined."); } + qrString += this._data.currency + "\n"; + + + //-- Debitor if(this._data.debitor !== undefined){ if(this._data.debitor.houseNumber !== undefined){ - qrString += "S\n"; // Adress Type - if(this._data.debitor.name.length > 70){ - throw new Error("Debitor name must be a maximum of 70 characters"); - } - qrString += this._data.debitor.name + "\n"; // Name + //-- Address type + + qrString += "S\n"; + + + //-- Name + + if(this._data.debitor.name === undefined){ throw new Error("Debitor name cannot be undefined if the debitor object is available."); } + if(this._data.debitor.name.length > 70){ throw new Error("Debitor name must be a maximum of 70 characters."); } + qrString += this._data.debitor.name + "\n"; + + //-- Address + + if(this._data.debitor.address === undefined){ throw new Error("Debitor address cannot be undefined if the debitor object is available."); } if(this._data.debitor.address.length > 70){ - throw new Error("Debitor address must be a maximum of 70 characters"); + throw new Error("Debitor address must be a maximum of 70 characters."); } - qrString += this._data.debitor.address + "\n"; // Address + qrString += this._data.debitor.address + "\n"; - if(this._data.debitor.address.length > 16){ - throw new Error("Debitor house number can be a maximum of 16 characters"); - } - qrString += this._data.debitor.houseNumber + "\n"; // House number - if(this._data.debitor.address.length > 16){ - throw new Error("Debitor zip must be a maximum of 16 characters"); + //-- House number + + if(this._data.debitor.houseNumber.length > 16){ + throw new Error("Debitor house number can be a maximum of 16 characters."); } - qrString += this._data.debitor.zip + "\n"; // Zip code + qrString += this._data.debitor.houseNumber + "\n"; + + + //-- Zip - if(this._data.debitor.address.length > 35){ - throw new Error("Debitor city must be a maximum of 35 characters"); + if(this._data.debitor.zip === undefined){ throw new Error("Debitor zip cannot be undefined if the debitor object is available."); } + if(this._data.debitor.zip.toString().length > 16){ + throw new Error("Debitor zip must be a maximum of 16 characters."); } - qrString += this._data.debitor.city + "\n"; // City + qrString += this._data.debitor.zip + "\n"; + + + //-- City + + if(this._data.debitor.city === undefined){ throw new Error("Debitor city cannot be undefined if the debitor object is available."); } + if(this._data.debitor.city.length > 35){ throw new Error("Debitor city must be a maximum of 35 characters."); } + qrString += this._data.debitor.city + "\n"; } else { - qrString += "K\n"; // Adress Type - if(this._data.debitor.name.length > 70){ - throw new Error("Debitor name must be a maximum of 70 characters"); - } - qrString += this._data.debitor.name + "\n"; // Name + //-- Address type - if(this._data.debitor.address.length > 70){ - throw new Error("Debitor address must be a maximum of 70 characters"); - } - qrString += this._data.debitor.address + "\n"; // Address + qrString += "K\n"; + + + //-- Name + + if(this._data.debitor.name === undefined){ throw new Error("Debitor name cannot be undefined if the debitor object is available."); } + if(this._data.debitor.name.length > 70){ throw new Error("Debitor name must be a maximum of 70 characters."); } + qrString += this._data.debitor.name + "\n"; + + + //-- Address + + if(this._data.debitor.address === undefined){ throw new Error("Debitor address cannot be undefined if the debitor object is available."); } + if(this._data.debitor.address.length > 70){ throw new Error("Debitor address must be a maximum of 70 characters."); } + qrString += this._data.debitor.address + "\n"; + + + //-- Zip + city + + if(this._data.debitor.zip === undefined || this._data.debitor.city === undefined){ throw new Error("Debitor zip and city cannot be undefined if the debitor object is available."); } + if((this._data.debitor.zip + " " + this._data.debitor.city).length > 70){ throw new Error("Debitor zip plus city must be a maximum of 70 characters."); } + qrString += this._data.debitor.zip + " " + this._data.debitor.city + "\n"; - if((this._data.debitor.zip + " " + this._data.debitor.city).length > 70){ - throw new Error("Debitor zip plus city must be a maximum of 70 characters"); - } - qrString += this._data.debitor.zip + " " + this._data.debitor.city + "\n"; // Zip code + city + + //-- Empty field zip + + qrString += "\n"; + + + //-- Empty field city + + qrString += "\n"; } - qrString += this._data.debitor.country + "\n"; // Country + + if(this._data.debitor.country === undefined){ throw new Error("Debitor country cannot be undefined if the debitor object is available."); } + if((this._data.debitor.country).length !== 2){ throw new Error("Debitor country must be 2 characters."); } + qrString += this._data.debitor.country + "\n"; + + } else { + + + //-- Empty field type + + qrString += "\n"; + + + //-- Empty field name + + qrString += "\n"; + + + //-- Empty field address + + qrString += "\n"; + + + //-- Empty field house number + + qrString += "\n"; + + + //-- Empty field zip + + qrString += "\n"; + + + //-- Empty field city + + qrString += "\n"; + + + //-- Empty field country + + qrString += "\n"; + } - qrString += this._referenceType + "\n"; // Referencetype + + //-- Reference type + + qrString += this._referenceType + "\n"; + + + //-- Reference if(this._data.reference !== undefined){ - if(this._data.reference.replace(/ /g, "").length > 27){ - throw new Error("Reference must be a maximum of 27 characters"); - } - qrString += this._data.reference + "\n"; // Reference + qrString += this._data.reference.replace(/ /g, "") + "\n"; } else { - qrString += "" + "\n"; // Reference + qrString += "\n"; } + + //-- Unstructured message + if(this._data.message !== undefined){ - if(this._data.message.length > 140){ - throw new Error("Message must be a maximum of 140 characters"); - } - qrString += this._data.message + "\n"; // Unstructured message + if(this._data.message.length > 140){ throw new Error("Message must be a maximum of 140 characters."); } + qrString += this._data.message + "\n"; + } else { + qrString += "\n"; } - qrString += "EPD" + "\n"; // End Payment Data + //-- End Payment Data + + qrString += "EPD" + "\n"; + + + //-- Additional information if(this._data.additionalInformation !== undefined){ - if(this._data.additionalInformation.length > 140){ - throw new Error("AdditionalInfromation must be a maximum of 27 characters"); - } - qrString += this._data.additionalInformation + "\n"; // Bill infromation + if(this._data.additionalInformation.length > 140){ throw new Error("AdditionalInfromation must be a maximum of 140 characters."); } + qrString += this._data.additionalInformation + "\n"; + } else { + qrString += "\n"; } + + //-- AV1 + if(this._data.av1 !== undefined){ - if(this._data.av1.length > 100){ - throw new Error("AV1 must be a maximum of 27 characters"); + + if(this._data.av1.length > 100){ throw new Error("AV1 must be a maximum of 100 characters."); } + if(this._data.av1.substr(0, 5) !== "eBill"){ + throw new Error("AV1 must begin with eBill"); } - qrString += this._data.av1 + "\n"; // AV1 + qrString += this._data.av1 + "\n"; + } if(this._data.av2 !== undefined){ - if(this._data.av2.length > 100){ - throw new Error("AV2 must be a maximum of 27 characters"); + + if(this._data.av2.length > 100){ throw new Error("AV2 must be a maximum of 100 characters."); } + if(this._data.av2.substr(0, 5) !== "eBill"){ + throw new Error("AV2 must begin with eBill"); } - qrString += this._data.av2 + "\n"; // AV2 + qrString += this._data.av2; + } const qrcodeString = new QRCode({ @@ -799,7 +968,8 @@ export namespace SwissQRBill { join: true, width: this.mmToPoints(46), height: this.mmToPoints(46), - padding: 0 + padding: 0, + ecl: "M" }).svg(); let svgPath = this._getSVGPathFromQRCodeString(qrcodeString); @@ -1001,16 +1171,17 @@ export namespace SwissQRBill { private _formatReference(reference: string): string { reference = this._removeLinebreaks(reference); + reference = reference.replace(/ /g, ""); let referenceArray: RegExpMatchArray = []; if(this._referenceType === "QRR"){ - const match = reference.replace(/ /g, "").split("").reverse().join("").match(/.{1,5}/g); + const match = reference.split("").reverse().join("").match(/.{1,5}/g); if(match !== null){ referenceArray = match.reverse(); } } else if(this._referenceType === "SCOR"){ - const match = reference.replace(/ /g, "").match(/.{1,4}/g); + const match = reference.match(/.{1,4}/g); if(match !== null){ referenceArray = match; } @@ -1035,6 +1206,7 @@ export namespace SwissQRBill { private _formatIBAN(iban: string): string | undefined { iban = this._removeLinebreaks(iban); + iban = iban.replace(/ /g, ""); const ibanArray = iban.replace(/ /g, "").match(/.{1,4}/g); @@ -1065,6 +1237,35 @@ export namespace SwissQRBill { } + /** + * Checks if the provided reference matches a QR reference + * + * @private + * @param {string} reference string containing the reference number + * @returns {boolean} boolean if the reference is a QR reference + * @memberof PDF + */ + + private _isQRReference(reference: string): boolean { + + reference = this._removeLinebreaks(reference); + reference = reference.replace(/ /g, ""); + + if(reference.length === 27){ + if(!isNaN(+reference)){ + return true; + } + } + + if(reference.replace(/ /g, "").length <= 25){ + return false; + } + + throw new Error("Reference is not valid."); + + } + + /** * Draws a rectangle which is used when data is to be filled in by hand. * diff --git a/tests/a4.js b/tests/a4.js index 988251d..7457a38 100644 --- a/tests/a4.js +++ b/tests/a4.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/a6-5-housenumber.js b/tests/a6-5-housenumber.js new file mode 100644 index 0000000..fa8dff5 --- /dev/null +++ b/tests/a6-5-housenumber.js @@ -0,0 +1,27 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac", + houseNumber: 1268, + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse", + houseNumber: 28, + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + + +const bill = new SwissQRBill.PDF(data, "./output/a6-5-housenumber.pdf"); \ No newline at end of file diff --git a/tests/a6-5.js b/tests/a6-5.js new file mode 100644 index 0000000..b84ed22 --- /dev/null +++ b/tests/a6-5.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/a6-5.pdf", { size: "A6/5" }); \ No newline at end of file diff --git a/tests/av1av2.js b/tests/av1av2.js index 1f14b07..da5354b 100644 --- a/tests/av1av2.js +++ b/tests/av1av2.js @@ -3,9 +3,9 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", - av1: "UV;UltraPay005;12345", - av2: "XY;XYService;54321", + reference: "210000000003139471430009017", + av1: "eBillUV;UltraPay005;12345", + av2: "eBillXY;XYService;54321", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/english.js b/tests/english.js index 82799b9..7cbdb2f 100644 --- a/tests/english.js +++ b/tests/english.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/euro.js b/tests/euro.js index 7e2aa6c..cef08c3 100644 --- a/tests/euro.js +++ b/tests/euro.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "EUR", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/french.js b/tests/french.js index 1bf2446..2b403a9 100644 --- a/tests/french.js +++ b/tests/french.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/italian.js b/tests/italian.js index 709f8cf..00a4931 100644 --- a/tests/italian.js +++ b/tests/italian.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/multipage.js b/tests/multipage.js index 6f9b662..11cc6bf 100644 --- a/tests/multipage.js +++ b/tests/multipage.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/no-amount.js b/tests/no-amount.js index 63b014b..bf9f68c 100644 --- a/tests/no-amount.js +++ b/tests/no-amount.js @@ -2,7 +2,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/no-debitor-no-amount.js b/tests/no-debitor-no-amount.js index 97ce481..e18870e 100644 --- a/tests/no-debitor-no-amount.js +++ b/tests/no-debitor-no-amount.js @@ -2,7 +2,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", - reference: "21 00000 00003 13947 14300 09017", + reference: "RF18539007547034", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/no-debitor-no-reference.js b/tests/no-debitor-no-reference.js index fa19a7c..7d08b0d 100644 --- a/tests/no-debitor-no-reference.js +++ b/tests/no-debitor-no-reference.js @@ -1,7 +1,7 @@ const SwissQRBill = require("../"); const data = { - currency: "EUR", + currency: "CHF", amount: 1199.95, creditor: { name: "Robert Schneider AG", diff --git a/tests/no-debitor.js b/tests/no-debitor.js index 8042137..d2a4984 100644 --- a/tests/no-debitor.js +++ b/tests/no-debitor.js @@ -3,13 +3,13 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "RF18539007547034", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", zip: 2501, city: "Biel", - account: "CH4431999123000889012", + account: "CH5800791123000889012", country: "CH" } }; diff --git a/tests/normal-iban.js b/tests/normal-iban-creditor-reference.js similarity index 90% rename from tests/normal-iban.js rename to tests/normal-iban-creditor-reference.js index de64582..d01d09c 100644 --- a/tests/normal-iban.js +++ b/tests/normal-iban-creditor-reference.js @@ -3,7 +3,6 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/normal-iban-no-reference.js b/tests/normal-iban-no-reference.js new file mode 100644 index 0000000..715a4da --- /dev/null +++ b/tests/normal-iban-no-reference.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "RF18539007547034", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH5800791123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/normal-iban.pdf"); \ No newline at end of file diff --git a/tests/qr-iban.js b/tests/qr-iban.js new file mode 100644 index 0000000..69fd0df --- /dev/null +++ b/tests/qr-iban.js @@ -0,0 +1,24 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const bill = new SwissQRBill.PDF(data, "./output/qr-iban.pdf"); \ No newline at end of file diff --git a/tests/run.sh b/tests/run.sh index c68c993..f9d7148 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -1,6 +1,14 @@ #!/bin/sh +echo "ts" +tsc ts.ts + node ts + rm ts.js echo "a4" node a4 +echo "a6-5" + node a6-5 +echo "a6-5-housenmuber" + node a6-5-housenumber echo "av1av2" node av1av2 echo "english" @@ -23,11 +31,11 @@ echo "no-debitor-no-amount-no-reference" node no-debitor-no-amount-no-reference echo "no-debitor-no-reference" node no-debitor-no-reference -echo "normal-iban" - node normal-iban +echo "normal-iban-creditor-reference" + node normal-iban-creditor-reference +echo "normal-iban-no-reference" + node normal-iban-no-reference +echo "qr-iban" + node qr-iban echo "separate" - node separate -echo "ts" -tsc ts.ts - node ts - rm ts.js \ No newline at end of file + node separate \ No newline at end of file diff --git a/tests/separate.js b/tests/separate.js index e3227bb..8f63af8 100644 --- a/tests/separate.js +++ b/tests/separate.js @@ -3,7 +3,7 @@ const SwissQRBill = require("../"); const data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", diff --git a/tests/ts.ts b/tests/ts.ts index 0618c1b..e03b5bd 100644 --- a/tests/ts.ts +++ b/tests/ts.ts @@ -1,9 +1,9 @@ import { SwissQRBill } from "../lib/index"; -const sampleObject: SwissQRBill.data = { +const data: SwissQRBill.data = { currency: "CHF", amount: 1199.95, - reference: "21 00000 00003 13947 14300 09017", + reference: "210000000003139471430009017", creditor: { name: "Robert Schneider AG", address: "Rue du Lac 1268", @@ -21,4 +21,4 @@ const sampleObject: SwissQRBill.data = { } }; -const bill = new SwissQRBill.PDF(sampleObject, "./output/ts.pdf"); \ No newline at end of file +const bill = new SwissQRBill.PDF(data, "./output/ts.pdf"); \ No newline at end of file