├── .github ├── FUNDING.yml └── workflows │ └── coverage.yml ├── CHANGELOG.md ├── SECURITY.md ├── src ├── utils │ ├── to-tlv.ts │ ├── render-tags.ts │ ├── to-hex.ts │ └── to-base64.ts ├── index.ts ├── models │ ├── tag.ts │ └── invoice.ts └── internal │ └── internal.ts ├── jest.config.ts ├── .eslintrc.json ├── LICENSE ├── package.json ├── .gitignore ├── README.md ├── tests ├── invoice.test.ts └── tag.test.ts ├── CONTRIBUTING.md └── tsconfig.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [ihadabs] 2 | custom: ['https://www.buymeacoffee.com/axenda'] 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | > Heading Format:\ 4 | > Version - Year-Month-Day 5 | 6 | ## 1.0.0 - 2021-11-19 7 | 8 | - Support for (Fatoorah) QR Code phase 1 tags 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | For critical security issues, please send an e-mail to [dev@axenda.io](mailto:dev@axenda.io) instead of filing an issue 4 | here. 5 | -------------------------------------------------------------------------------- /src/utils/to-tlv.ts: -------------------------------------------------------------------------------- 1 | import { Tag } from '../models/tag'; 2 | 3 | /** 4 | * Converts a tags array to a TLV string 5 | * @param {Tag[]} tags 6 | * @return {string} 7 | */ 8 | export function toTlv(tags: Tag[]): string { 9 | return tags.map(tag => tag.toTlv()).join(''); 10 | } 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Invoice } from './models/invoice'; 2 | export { Tag } from './models/tag'; 3 | 4 | export { renderTags } from './utils/render-tags'; 5 | export { toBase64, tagsToBase64 } from './utils/to-base64'; 6 | export { toHex } from './utils/to-hex'; 7 | export { toTlv } from './utils/to-tlv'; 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/utils/render-tags.ts: -------------------------------------------------------------------------------- 1 | import { QRCodeToDataURLOptions, toDataURL } from 'qrcode'; 2 | import { Tag } from '../models/tag'; 3 | import { tagsToBase64 } from './to-base64'; 4 | 5 | export function renderTags(tags: Tag[], options?: QRCodeToDataURLOptions): Promise { 6 | const base64 = tagsToBase64(tags); 7 | return toDataURL(base64, options); 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/to-hex.ts: -------------------------------------------------------------------------------- 1 | import { Buffer } from 'buffer'; 2 | /** 3 | * Convert a string to a hex string encoded with UTF-8 4 | * @param {number} value 5 | * @return {string} 6 | */ 7 | export function toHex(value: number): string { 8 | let hex = value.toString(16); 9 | 10 | if ((hex.length % 2) > 0) { 11 | hex = '0' + hex; 12 | } 13 | 14 | return Buffer 15 | .from(hex, 'hex') 16 | .toString('utf-8'); 17 | } 18 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { InitialOptionsTsJest } from 'ts-jest/dist/types'; 2 | 3 | const jestConfig: InitialOptionsTsJest = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.(t|j)sx?$': 'ts-jest' 8 | }, 9 | testRegex: '(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', 10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 11 | collectCoverage: true, 12 | }; 13 | 14 | export default jestConfig; 15 | -------------------------------------------------------------------------------- /src/models/tag.ts: -------------------------------------------------------------------------------- 1 | import { toHex } from '../utils/to-hex'; 2 | 3 | /** 4 | * Tag class 5 | * 6 | */ 7 | export class Tag { 8 | constructor(private tag: number, private value: string) { 9 | } 10 | 11 | /** 12 | * Returns the tlv representation of the tag 13 | * @return {string} 14 | */ 15 | toTlv(): string { 16 | return toHex(this.tag) + toHex(this.getValueByteLength()) + this.value; 17 | } 18 | 19 | /** 20 | * Returns the byte length of the tag value 21 | * @return {number} 22 | */ 23 | private getValueByteLength(): number { 24 | return Buffer.byteLength(this.value); 25 | } 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/utils/to-base64.ts: -------------------------------------------------------------------------------- 1 | import { Tag } from '../models/tag'; 2 | import { toTlv } from './to-tlv'; 3 | import { Buffer } from 'buffer'; 4 | 5 | /** 6 | * Converts a tags array to a base64 string using the TLV encoding 7 | * @param {Tag[]} tags 8 | * @return {string} representing base64 of tags TLV 9 | */ 10 | export function tagsToBase64(tags: Tag[]): string { 11 | return Buffer.from(toTlv(tags)).toString('base64'); 12 | } 13 | 14 | /** 15 | * Converts a string with utf8 encoding to a base64 string 16 | * @param {string} value with utf8 encoding 17 | * @return {string} representing base64 18 | */ 19 | export function toBase64(value: string): string { 20 | return Buffer.from(value).toString('base64'); 21 | } 22 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": 13, 14 | "sourceType": "module" 15 | }, 16 | "plugins": [ 17 | "@typescript-eslint" 18 | ], 19 | "rules": { 20 | "comma-dangle": [ 21 | "error", 22 | "always-multiline" 23 | ], 24 | "indent": [ 25 | "error", 26 | "tab" 27 | ], 28 | "linebreak-style": [ 29 | "error", 30 | "unix" 31 | ], 32 | "quotes": [ 33 | "error", 34 | "single" 35 | ], 36 | "semi": [ 37 | "error", 38 | "always" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Running Code Coverage 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [ 10.x, 12.x, 14.x, 16.x ] 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v2 17 | with: 18 | fetch-depth: 2 19 | 20 | - name: Set up Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | 25 | - name: Install dependencies 26 | run: npm install 27 | 28 | - name: Run the tests 29 | run: npm test -- --coverage 30 | 31 | - name: Upload coverage to Codecov 32 | uses: codecov/codecov-action@v1 33 | with: 34 | token: ${{ secrets.CODECOV_TOKEN }} 35 | -------------------------------------------------------------------------------- /src/internal/internal.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a play area for internal stuff. 3 | * You can write code the way you like, 4 | * but it will not be part of the final build. 5 | */ 6 | 7 | import { Tag } from '../models/tag'; 8 | import { Invoice } from '../models/invoice'; 9 | import { tagsToBase64 } from '../utils/to-base64'; 10 | import { toHex } from '../utils/to-hex'; 11 | 12 | const tags: Tag[] = [ 13 | new Tag(1, 'Axenda'), 14 | new Tag(2, '1234567891'), 15 | new Tag(3, '2021-12-04T00:00:00Z'), 16 | new Tag(4, '100.00'), 17 | new Tag(5, '15.00'), 18 | ]; 19 | 20 | //toBase64(tlv); 21 | tagsToBase64(tags); 22 | //renderTags(tags); 23 | 24 | const invoice = new Invoice({ 25 | sellerName: 'Axenda', 26 | vatRegistrationNumber: '1234567891', 27 | invoiceTimestamp: '2021-12-04T00:00:00Z', 28 | invoiceTotal: '100.00', 29 | invoiceVatTotal: '15.00', 30 | }); 31 | 32 | invoice.toBase64(); 33 | //invoice.render().then((qrcode) => { 34 | // console.log(qrcode); 35 | //}); 36 | 37 | console.log('-------------------------'); 38 | 39 | toHex(1); 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Axenda 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/models/invoice.ts: -------------------------------------------------------------------------------- 1 | import { Tag } from './tag'; 2 | import { toTlv } from '../utils/to-tlv'; 3 | import { toBase64 } from '../utils/to-base64'; 4 | import { QRCodeToDataURLOptions, toDataURL } from 'qrcode'; 5 | 6 | /** 7 | * Invoice interface 8 | */ 9 | interface IInvoice { 10 | sellerName: string; 11 | vatRegistrationNumber: string; 12 | invoiceTimestamp: string; 13 | invoiceTotal: string; 14 | invoiceVatTotal: string; 15 | } 16 | 17 | /** 18 | * Invoice class 19 | */ 20 | export class Invoice { 21 | private readonly _tlv: string; 22 | 23 | constructor(invoice: IInvoice) { 24 | this._tlv = toTlv([ 25 | new Tag(1, invoice.sellerName), 26 | new Tag(2, invoice.vatRegistrationNumber), 27 | new Tag(3, invoice.invoiceTimestamp), 28 | new Tag(4, invoice.invoiceTotal), 29 | new Tag(5, invoice.invoiceVatTotal), 30 | ]); 31 | } 32 | 33 | /** 34 | * Returns the TLV representation of the invoice 35 | * @return {string} 36 | */ 37 | toTlv(): string { 38 | return this._tlv; 39 | } 40 | 41 | /** 42 | * Returns a base64 string representing the invoice 43 | * @return {string} 44 | */ 45 | toBase64(): string { 46 | return toBase64(this._tlv); 47 | } 48 | 49 | /** 50 | * Returns a QR code as base64 data image 51 | * @return {string} 52 | */ 53 | render(options?: QRCodeToDataURLOptions): Promise { 54 | return toDataURL(this.toBase64(), options); 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@axenda/zatca", 3 | "version": "1.0.4", 4 | "description": "", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "files": [ 8 | "lib", 9 | "src" 10 | ], 11 | "dependencies": { 12 | "qrcode": "^1.4.4" 13 | }, 14 | "devDependencies": { 15 | "@types/jest": "^27.0.2", 16 | "@types/node": "^14.14.44", 17 | "@types/qrcode": "^1.4.1", 18 | "@typescript-eslint/eslint-plugin": "^5.4.0", 19 | "@typescript-eslint/parser": "^5.4.0", 20 | "eslint": "^8.2.0", 21 | "jest": "^27.3.1", 22 | "nodemon": "^2.0.7", 23 | "ts-jest": "^27.0.7", 24 | "ts-node": "^10.7.0", 25 | "typescript": "^4.5.2" 26 | }, 27 | "scripts": { 28 | "setup": "npm install", 29 | "dev": "nodemon src/internal/internal.ts", 30 | "build": "rm -rf lib && tsc", 31 | "start": "node lib/index.js", 32 | "test": "jest", 33 | "lint": "eslint src", 34 | "format": "eslint src --fix", 35 | "prepublishOnly": "npm test && npm run lint", 36 | "preversion": "npm run lint", 37 | "version": "npm run format && git add -A src", 38 | "postversion": "git push && git push --tags", 39 | "prepare": "npm run build", 40 | "publish": "npm publish --access public" 41 | }, 42 | "homepage": "https://github.com/axenda/zatca#readme", 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/axenda/zatca" 46 | }, 47 | "bugs": { 48 | "url": "git+https://github.com/axenda/zatca/issues" 49 | }, 50 | "keywords": [ 51 | "zatca", 52 | "e-invoicing", 53 | "qr-code", 54 | "generation", 55 | "axenda", 56 | "typescript", 57 | "saudi-arabia", 58 | "fatoora" 59 | ], 60 | "publishConfig": { 61 | "registry": "https://registry.npmjs.org/" 62 | }, 63 | "author": "Hadi Albinsaad", 64 | "license": "MIT" 65 | } 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | .parcel-cache 79 | 80 | # Next.js build output 81 | .next 82 | out 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | dist 87 | 88 | # Gatsby files 89 | .cache/ 90 | # Comment in the public line in if your project uses Gatsby and not Next.js 91 | # https://nextjs.org/blog/next-9-1#public-directory-support 92 | # public 93 | 94 | # vuepress build output 95 | .vuepress/dist 96 | 97 | # Serverless directories 98 | .serverless/ 99 | 100 | # FuseBox cache 101 | .fusebox/ 102 | 103 | # DynamoDB Local files 104 | .dynamodb/ 105 | 106 | # TernJS port file 107 | .tern-port 108 | 109 | # Stores VSCode versions used for testing VSCode extensions 110 | .vscode-test 111 | 112 | # yarn v2 113 | .yarn/cache 114 | .yarn/unplugged 115 | .yarn/build-state.yml 116 | .yarn/install-state.gz 117 | .pnp.* 118 | 119 | .idea 120 | .vscode 121 | .DS_Store 122 | .vscodeignore 123 | .vsctest 124 | /lib 125 | .npmrc 126 | /coverage 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZATCA (Fatoorah) QR-Code Implementation 2 | 3 | [![NPM](https://nodei.co/npm/@axenda/zatca.png?mini=true)](https://npmjs.org/package/@axenda/zatca) 4 | 5 | ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/axenda/zatca/Running%20Code%20Coverage/main) 6 | [![codecov](https://codecov.io/gh/axenda/zatca/branch/main/graph/badge.svg?token=T52NJXGE0O)](https://codecov.io/gh/axenda/zatca) 7 | [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/user/project/master/LICENSE) 8 | 9 | An unofficial package to help developers implement ZATCA (Fatoora) QR code easily which is required for e-invoicing in 10 | Saudi Arabia. 11 | 12 | > ✨ You could use it in both frontend and backend Nodejs projects. 13 | 14 | > ✅ Validated to have the same output as ZATCA's SDK as of 18 November 2021. 15 | 16 | ## Installation 17 | 18 | To get started, install the package: 19 | 20 | ```bash 21 | npm i --save @axenda/zatca 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Summary 27 | 28 | Simple, all you need to generate a QR code is: 29 | 30 | ```typescript 31 | import { Invoice } from '@axenda/zatca'; 32 | 33 | const invoice = new Invoice({ 34 | sellerName: 'Axenda', 35 | vatRegistrationNumber: '1234567891', 36 | invoiceTimestamp: '2021-12-04T00:00:00Z', 37 | invoiceTotal: '100.00', 38 | invoiceVatTotal: '15.00', 39 | }); 40 | 41 | const imageData = await invoice.render(); 42 | 43 | // Read the following sections for more details. 44 | ``` 45 | 46 | ### Import 47 | 48 | First, import Invoice class or Tag class to represent an invoice QR code: 49 | 50 | ```typescript 51 | import { Invoice } from '@axenda/zatca'; 52 | // or 53 | import { Tag } from '@axenda/zatca'; 54 | ``` 55 | 56 | ### Representing an invoice QR code 57 | 58 | Second, create an instance of Invoice or an array of Tag class: 59 | 60 | ```typescript 61 | const invoice = new Invoice({ 62 | sellerName: 'Axenda', 63 | vatRegistrationNumber: '1234567891', 64 | invoiceTimestamp: '2021-12-04T00:00:00Z', 65 | invoiceTotal: '100.00', 66 | invoiceVatTotal: '15.00', 67 | }); 68 | // or 69 | const tags: Tag[] = [ 70 | new Tag(1, 'Axenda'), 71 | new Tag(2, '1234567891'), 72 | new Tag(3, '2021-12-04T00:00:00Z'), 73 | new Tag(4, '100.00'), 74 | new Tag(5, '15.00'), 75 | ]; 76 | ``` 77 | 78 | ### Generate TLV 79 | 80 | Now you can generate TLV string from the invoice or from the tags array: 81 | 82 | ```typescript 83 | invoice.toTlv(); 84 | 85 | // or using tags array 86 | 87 | import { toTlv } from '@axenda/zatca'; 88 | 89 | toTlv(tags) 90 | ``` 91 | 92 | ### Generate Base64 93 | 94 | You cloud generate Base64 string from the invoice or from the tags array: 95 | 96 | ```typescript 97 | invoice.toBase64(); 98 | 99 | // or using tags array 100 | 101 | import { tagsToBase64 } from '@axenda/zatca'; 102 | 103 | tagsToBase64(tags); 104 | ``` 105 | 106 | ### Render QR code 107 | 108 | You can generate image data (png) from base64 string and render it in browser: 109 | 110 | ```typescript 111 | await invoice.render(); 112 | 113 | // or using tags array 114 | 115 | import { renderTags } from '@axenda/zatca'; 116 | 117 | await renderTags(tags); 118 | ``` 119 | 120 | ### Use QR code image data 121 | 122 | Use the image data to display the QR code in browser: 123 | 124 | ```html 125 | 126 | Invoice QR Code 127 | 128 | 129 | 130 | ``` 131 | 132 | ## Tests 133 | 134 | To run test suites, first install dependencies, then run `npm test`: 135 | 136 | ```bash 137 | npm install 138 | npm test 139 | ``` 140 | 141 | ## Package roadmap 142 | 143 | - [x] Support ZATCA invoice QR code phase 1 144 | - [ ] Review package API consistency 145 | - [ ] Support ZATCA invoice QR code phase 2 146 | 147 | ## Contributing 148 | 149 | We welcome [contributions](https://github.com/axenda/zatca/graphs/contributors) of all kinds from anyone. Please take a 150 | moment to review the [guidelines for contributing](CONTRIBUTING.md). 151 | 152 | * [Bug reports](https://github.com/axenda/zatca/issues/new) 153 | * [Feature requests](CONTRIBUTING.md#-feature-requests) 154 | * [Pull requests](CONTRIBUTING.md#-pull-requests) 155 | 156 | ## License 157 | 158 | The MIT License (MIT). Please see [License File](LICENSE) for more information. 159 | -------------------------------------------------------------------------------- /tests/invoice.test.ts: -------------------------------------------------------------------------------- 1 | import { Invoice, toBase64 } from '../src'; 2 | 3 | test('Invoice.toTlv() returns a valid base64 string using toBase64()', () => { 4 | const invoice = new Invoice({ 5 | sellerName: 'Axenda', 6 | vatRegistrationNumber: '1234567891', 7 | invoiceTimestamp: '2021-12-04T00:00:00Z', 8 | invoiceTotal: '100.00', 9 | invoiceVatTotal: '15.00', 10 | }); 11 | 12 | expect(toBase64(invoice.toTlv())) 13 | .toBe('AQZBeGVuZGECCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 14 | }); 15 | 16 | test('Invoice.toBase64() returns a valid base64 string', () => { 17 | const invoice = new Invoice({ 18 | sellerName: 'Axenda', 19 | vatRegistrationNumber: '1234567891', 20 | invoiceTimestamp: '2021-12-04T00:00:00Z', 21 | invoiceTotal: '100.00', 22 | invoiceVatTotal: '15.00', 23 | }); 24 | 25 | expect(invoice.toBase64()) 26 | .toBe('AQZBeGVuZGECCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 27 | }); 28 | 29 | test('Invoice.toBase64() returns a valid base64 string using arabic seller name', () => { 30 | const invoice = new Invoice({ 31 | sellerName: 'اكسندا', 32 | vatRegistrationNumber: '1234567891', 33 | invoiceTimestamp: '2021-12-04T00:00:00Z', 34 | invoiceTotal: '100.00', 35 | invoiceVatTotal: '15.00', 36 | }); 37 | 38 | expect(invoice.toBase64()) 39 | .toBe('AQzYp9mD2LPZhtiv2KcCCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 40 | }); 41 | 42 | test('Invoice.render() generates a valid qr code use arabic seller name', async () => { 43 | const invoice = new Invoice({ 44 | sellerName: 'اكسندا', 45 | vatRegistrationNumber: '1234567891', 46 | invoiceTimestamp: '2021-12-04T00:00:00Z', 47 | invoiceTotal: '100.00', 48 | invoiceVatTotal: '15.00', 49 | }); 50 | 51 | const imageData = await invoice.render(); 52 | 53 | expect(imageData) 54 | .toBe('data:image/png;base64,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'); 55 | }); 56 | -------------------------------------------------------------------------------- /tests/tag.test.ts: -------------------------------------------------------------------------------- 1 | import { renderTags, Tag, tagsToBase64, toBase64, toHex, toTlv } from '../src'; 2 | import { Buffer } from 'buffer'; 3 | 4 | test('tagsToBase64() generates a valid base64 string from tags', () => { 5 | const tags: Tag[] = [ 6 | new Tag(1, 'Axenda'), 7 | new Tag(2, '1234567891'), 8 | new Tag(3, '2021-12-04T00:00:00Z'), 9 | new Tag(4, '100.00'), 10 | new Tag(5, '15.00'), 11 | ]; 12 | expect(tagsToBase64(tags)) 13 | .toBe('AQZBeGVuZGECCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 14 | }); 15 | 16 | test('toBase64() generates a valid base64 string from tags using toTlv()', () => { 17 | const tags: Tag[] = [ 18 | new Tag(1, 'Axenda'), 19 | new Tag(2, '1234567891'), 20 | new Tag(3, '2021-12-04T00:00:00Z'), 21 | new Tag(4, '100.00'), 22 | new Tag(5, '15.00'), 23 | ]; 24 | expect(toBase64(toTlv(tags))) 25 | .toBe('AQZBeGVuZGECCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 26 | }); 27 | 28 | test('toHex() generates a valid hex string utf-8 encoded', () => { 29 | const hexStrInUtf8 = toHex(23); 30 | const hexStrInHex = Buffer 31 | .from(hexStrInUtf8, 'utf-8') 32 | .toString('hex'); 33 | 34 | expect(parseInt(hexStrInHex, 16)) 35 | .toBe(23); 36 | }); 37 | 38 | test('tagsToBase64() generates a valid base64 string from tags using arabic seller name', () => { 39 | const tags: Tag[] = [ 40 | new Tag(1, 'اكسندا'), 41 | new Tag(2, '1234567891'), 42 | new Tag(3, '2021-12-04T00:00:00Z'), 43 | new Tag(4, '100.00'), 44 | new Tag(5, '15.00'), 45 | ]; 46 | expect(tagsToBase64(tags)) 47 | .toBe('AQzYp9mD2LPZhtiv2KcCCjEyMzQ1Njc4OTEDFDIwMjEtMTItMDRUMDA6MDA6MDBaBAYxMDAuMDAFBTE1LjAw'); 48 | }); 49 | 50 | test('renderTags() generates a valid qr code use arabic seller name', async () => { 51 | const tags: Tag[] = [ 52 | new Tag(1, 'اكسندا'), 53 | new Tag(2, '1234567891'), 54 | new Tag(3, '2021-12-04T00:00:00Z'), 55 | new Tag(4, '100.00'), 56 | new Tag(5, '15.00'), 57 | ]; 58 | 59 | const imageData = await renderTags(tags); 60 | 61 | expect(imageData) 62 | .toBe('data:image/png;base64,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'); 63 | }); 64 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the package 2 | 3 | ## 🐛 Bug reports 4 | 5 | If you noticed a bug, please [open a new issue](https://github.com/axenda/zatca/issues/new) describing how to reproduce 6 | the bug. 7 | 8 | ## 🦾 Involvement 9 | 10 | - [ ] Review package API consistency 11 | - [ ] Support ZATCA invoice QR code phase 2 12 | - [ ] Improve documentation ([README](README.md), [CONTRIBUTING](CONTRIBUTING.md), etc.) 13 | 14 | Fork, close, fix and resolve [issues](https://github.com/axenda/zatca/issues) 15 | 16 | ## 🆕 Feature requests 17 | 18 | Feature requests are welcome, please [open a new issue](https://github.com/axenda/zatca/issues/new) describing your 19 | request. 20 | 21 | 22 | 23 | ## 🤝 Pull requests 24 | 25 | Good pull requests - patches, improvements, new features - are a fantastic help. 26 | 27 | **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), 28 | otherwise you risk spending a lot of time working on something that the project's developers might not want to merge 29 | into the project. 30 | 31 | Please adhere to the coding conventions used throughout a project (indentation, accurate comments, etc.) and any other 32 | requirements (such as test coverage). 33 | 34 | Adhering to the following this process is the best way to get your work included in the project: 35 | 36 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: 37 | 38 | ```bash 39 | # Clone your fork of the repo into the current directory 40 | git clone https://github.com//zatca 41 | # Navigate to the newly cloned directory 42 | cd zatca 43 | # Assign the original repo to a remote called "upstream" 44 | git remote add upstream https://github.com/axenda/zatca 45 | ``` 46 | 47 | 2. If you cloned a while ago, get the latest changes from upstream: 48 | 49 | ```bash 50 | git checkout main 51 | git pull upstream main 52 | ``` 53 | 54 | 3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix: 55 | 56 | ```bash 57 | git checkout -b 58 | ``` 59 | 60 | 4. Make sure to update, or add to the tests when appropriate. Patches and features will not be accepted without tests. 61 | Run `npm test` to check that all tests pass after you've made changes. 62 | 63 | 5. Commit your changes in logical chunks. Please adhere to 64 | these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 65 | or your code is unlikely be merged into the main project. Use Git's 66 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 67 | feature to tidy up your commits before making them public. 68 | 69 | 6. Locally merge (or rebase) the upstream development branch into your topic branch: 70 | 71 | ```bash 72 | git pull [--rebase] upstream main 73 | ``` 74 | 75 | 7. Push your topic branch up to your fork: 76 | 77 | ```bash 78 | git push origin 79 | ``` 80 | 81 | 8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 82 | with a clear title and description. 83 | 84 | 9. If you are asked to amend your changes before they can be merged in, please use `git commit --amend` (or rebasing for 85 | multi-commit Pull Requests) and force push to your remote feature branch. You may also be asked to squash commits. 86 | 87 | 10. If you are asked to squash your commits, then please use `git rebase -i main`. It will ask you to pick your commits 88 | - pick the major commits and squash the rest. 89 | 90 | **IMPORTANT**: By submitting a patch, you agree to license your work under the same license as that used by the project. 91 | 92 | 93 | 94 | ## Maintainers 95 | 96 | If you have commit access, please follow this process for merging patches and cutting new releases. 97 | 98 | ### Reviewing changes 99 | 100 | 1. Check that a change is within the scope and philosophy of the project. 101 | 2. Check that a change has any necessary tests and a proper, descriptive commit message. 102 | 3. Checkout the change and test it locally. 103 | 4. If the change is good, and authored by someone who cannot commit to 104 | `main`, please try to avoid using GitHub's merge button. Apply the change to `main` locally (feel free to amend any 105 | minor problems in the author's original commit if necessary). 106 | 5. If the change is good, and authored by another maintainer/collaborator, give them a "Ship it!" comment and let them 107 | handle the merge. 108 | 109 | ### Submitting changes 110 | 111 | 1. All non-trivial changes should be put up for review using GitHub Pull Requests. 112 | 2. Your change should not be merged into `main` (or another feature branch), without at least one "Ship it!" comment 113 | from another maintainer/collaborator on the project. "Looks good to me" is not the same as "Ship it!". 114 | 3. Try to avoid using GitHub's merge button. Locally rebase your change onto 115 | `main` and then push to GitHub. 116 | 4. Once a feature branch has been merged into its target branch, please delete the feature branch from the remote 117 | repository. 118 | 119 | ### Releasing a new version 120 | 121 | 1. Include all new functional changes in the CHANGELOG. 122 | 2. Use a dedicated commit to increment the version. The version needs to be added to the `CHANGELOG.md` (inc. date) and 123 | the `package.json`. 124 | 3. The commit message must be of `v0.0.0` format. 125 | 4. Create an annotated tag for the version: `git tag -m "v0.0.0" v0.0.0`. 126 | 5. Push the changes and tags to GitHub: `git push --tags origin main`. 127 | 6. Publish the new version to npm: `npm publish`. 128 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src" 4 | ], 5 | "exclude": [ 6 | "node_modules", 7 | "tests" 8 | ], 9 | "compilerOptions": { 10 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 11 | 12 | /* Projects */ 13 | // "incremental": true, /* Enable incremental compilation */ 14 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 15 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 16 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 17 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 18 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 19 | 20 | /* Language and Environment */ 21 | "target": "es5", 22 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 23 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 24 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 25 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 26 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 27 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 28 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 29 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 30 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 31 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 32 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 33 | 34 | /* Modules */ 35 | "module": "commonjs", 36 | /* Specify what module code is generated. */ 37 | // "rootDir": "./", /* Specify the root folder within your source files. */ 38 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 39 | "baseUrl": ".", 40 | /* Specify the base directory to resolve non-relative module names. */ 41 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 42 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 43 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 44 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 45 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 46 | // "resolveJsonModule": true, /* Enable importing .json files */ 47 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 48 | 49 | /* JavaScript Support */ 50 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 51 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 52 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 53 | 54 | /* Emit */ 55 | "declaration": true, 56 | /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 57 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 58 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 59 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 60 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 61 | "outDir": "./lib", 62 | /* Specify an output folder for all emitted files. */ 63 | // "removeComments": true, /* Disable emitting comments. */ 64 | // "noEmit": true, /* Disable emitting files from a compilation. */ 65 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 66 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 67 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 68 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 69 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 70 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 71 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 72 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 73 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 74 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 75 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 76 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 77 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 78 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 79 | 80 | /* Interop Constraints */ 81 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 82 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 83 | "esModuleInterop": true, 84 | /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 85 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 86 | "forceConsistentCasingInFileNames": true, 87 | /* Ensure that casing is correct in imports. */ 88 | 89 | /* Type Checking */ 90 | "strict": true, 91 | /* Enable all strict type-checking options. */ 92 | "noImplicitAny": true, 93 | /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 94 | "strictNullChecks": true, 95 | /* When type checking, take into account `null` and `undefined`. */ 96 | "strictFunctionTypes": true, 97 | /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 98 | "strictBindCallApply": true, 99 | /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 100 | "strictPropertyInitialization": true, 101 | /* Check for class properties that are declared but not set in the constructor. */ 102 | "noImplicitThis": true, 103 | /* Enable error reporting when `this` is given the type `any`. */ 104 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 105 | "alwaysStrict": true, 106 | /* Ensure 'use strict' is always emitted. */ 107 | "noUnusedLocals": true, 108 | /* Enable error reporting when a local variables aren't read. */ 109 | "noUnusedParameters": true, 110 | /* Raise an error when a function parameter isn't read */ 111 | "exactOptionalPropertyTypes": true, 112 | /* Interpret optional property types as written, rather than adding 'undefined'. */ 113 | "noImplicitReturns": true, 114 | /* Enable error reporting for codepaths that do not explicitly return in a function. */ 115 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 116 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 117 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 118 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 119 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 120 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 121 | 122 | /* Completeness */ 123 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 124 | "skipLibCheck": true 125 | /* Skip type checking all .d.ts files. */ 126 | } 127 | } 128 | --------------------------------------------------------------------------------