diff --git a/packages/payment_qr_codes/package.json b/packages/payment_qr_codes/package.json new file mode 100644 index 000000000..f0acf2598 --- /dev/null +++ b/packages/payment_qr_codes/package.json @@ -0,0 +1,42 @@ +{ + "name": "@apify/payment_qr_codes", + "version": "0.0.1", + "description": "Tools for creating payment QR codes.", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "keywords": [ + "apify" + ], + "author": { + "name": "Apify", + "email": "support@apify.com", + "url": "https://apify.com" + }, + "contributors": [ + "Matej Hamas " + ], + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/apify/apify-shared-js" + }, + "bugs": { + "url": "https://github.com/apify/apify-shared-js/issues" + }, + "homepage": "https://apify.com", + "scripts": { + "build": "npm run clean && npm run compile && npm run copy", + "clean": "rimraf ./dist", + "compile": "tsc -p tsconfig.build.json", + "copy": "ts-node -T ../../scripts/copy.ts" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "qrcode": "^1.4.4" + }, + "devDependencies": { + "@types/qrcode": "^1.4.1" + } +} diff --git a/packages/payment_qr_codes/src/czk_payment_qr_codes.ts b/packages/payment_qr_codes/src/czk_payment_qr_codes.ts new file mode 100644 index 000000000..3270d57cc --- /dev/null +++ b/packages/payment_qr_codes/src/czk_payment_qr_codes.ts @@ -0,0 +1,27 @@ +import qrcode from 'qrcode'; + +interface CzkQRCodeInputData { + iban: string; + amount: number; + currencyCode: string; // 3 letter currency code + message: string; // e.g. invoice number + beneficiaryName: string; +} +/* + * This function encodes provided data into a single string complying with CZK QR code payment protocol. + * The protocol is issued by Czech Bank Association and can be found + * at https://cbaonline.cz/upload/1645-standard-qr-v1-2-cerven-2021.pdf + */ +export function encodeInputDataToRawQrCodeInputString(data: CzkQRCodeInputData): string { + const { iban, amount, currencyCode, message, beneficiaryName } = data; + return `SPD*1.0*RN:${beneficiaryName}*ACC:${iban}*AM:${amount}*CC:${currencyCode.toUpperCase()}*MSG:${message}`; +} + +/** + * This function generates CZK QR code that can be used for domestic QR code payment. + * It returns the QR code encoded as data URL that can be directly viewed in browser or used in tag. + */ +export async function generateCzkPaymentQrCodeDataUrl(data: CzkQRCodeInputData): Promise { + const code = qrcode.create(encodeInputDataToRawQrCodeInputString(data), {}); + return qrcode.toDataURL(code.segments); +} diff --git a/packages/payment_qr_codes/src/index.ts b/packages/payment_qr_codes/src/index.ts new file mode 100644 index 000000000..0a0f22ac4 --- /dev/null +++ b/packages/payment_qr_codes/src/index.ts @@ -0,0 +1 @@ +export * from './czk_payment_qr_codes'; diff --git a/packages/payment_qr_codes/tsconfig.build.json b/packages/payment_qr_codes/tsconfig.build.json new file mode 100644 index 000000000..856db0f21 --- /dev/null +++ b/packages/payment_qr_codes/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src/**/*"] +} diff --git a/packages/payment_qr_codes/tsconfig.json b/packages/payment_qr_codes/tsconfig.json new file mode 100644 index 000000000..52d43eaaa --- /dev/null +++ b/packages/payment_qr_codes/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*"] +} diff --git a/test/__snapshots__/czk_payment_qr_codes.test.ts.snap b/test/__snapshots__/czk_payment_qr_codes.test.ts.snap new file mode 100644 index 000000000..1587f7720 --- /dev/null +++ b/test/__snapshots__/czk_payment_qr_codes.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CZK payment QR code generation test 1`] = `"data:image/png;base64,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"`; diff --git a/test/czk_payment_qr_codes.test.ts b/test/czk_payment_qr_codes.test.ts new file mode 100644 index 000000000..f49131dbd --- /dev/null +++ b/test/czk_payment_qr_codes.test.ts @@ -0,0 +1,35 @@ +import { + encodeInputDataToRawQrCodeInputString, + generateCzkPaymentQrCodeDataUrl, +} from '@apify/payment_qr_codes'; + +describe('CZK payment QR code generation', () => { + it('can encode payment data to QR cod estring', () => { + expect(encodeInputDataToRawQrCodeInputString({ + iban: 'CZ6508000000192000145399', // testing IBAN from https://www.cnb.cz/cs/platebni-styk/iban/iban-mezinarodni-format-cisla-uctu/ + amount: 123.45, + currencyCode: 'czk', + message: 'Test message', + beneficiaryName: 'John Doe', + })).toBe('SPD*1.0*RN:John Doe*ACC:CZ6508000000192000145399*AM:123.45*CC:CZK*MSG:Test message'); + + expect(encodeInputDataToRawQrCodeInputString({ + iban: 'CZ6508000000192000145399', // testing IBAN from https://www.cnb.cz/cs/platebni-styk/iban/iban-mezinarodni-format-cisla-uctu/ + amount: 123.45, + currencyCode: 'EUR', + message: 'Test message', + beneficiaryName: 'John Doe', + })).toBe('SPD*1.0*RN:John Doe*ACC:CZ6508000000192000145399*AM:123.45*CC:EUR*MSG:Test message'); + }); + + it('test', async () => { + const code = await generateCzkPaymentQrCodeDataUrl({ + iban: 'CZ6508000000192000145399', // testing IBAN from https://www.cnb.cz/cs/platebni-styk/iban/iban-mezinarodni-format-cisla-uctu/ + amount: 123.45, + currencyCode: 'czk', + message: 'Test message', + beneficiaryName: 'John Doe', + }); + expect(code).toMatchSnapshot(); + }); +});