bysquare 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -61
- package/lib/generate.d.ts +15 -18
- package/lib/generate.js +79 -63
- package/lib/index.js +6 -1
- package/lib/parse.d.ts +6 -12
- package/lib/parse.js +122 -49
- package/lib/types.d.ts +119 -22
- package/lib/types.js +106 -37
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@ your implementation. See [examples](examples).
|
|
|
21
21
|
|
|
22
22
|

|
|
23
23
|
|
|
24
|
+
[build]: https://img.shields.io/github/workflow/status/xseman/bysquare/tests
|
|
25
|
+
[version]: https://img.shields.io/npm/v/bysquare
|
|
26
|
+
[license]: https://img.shields.io/github/license/xseman/bysquare
|
|
27
|
+
|
|
24
28
|
## Install
|
|
25
29
|
|
|
26
30
|
Node.js
|
|
@@ -37,10 +41,16 @@ npm install --global bysquare
|
|
|
37
41
|
|
|
38
42
|
## API
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
```ts
|
|
45
|
+
generate(model: Model): Promise<string>
|
|
46
|
+
parse(qr: string): Promise<ParsedModel>
|
|
47
|
+
detect(qr: string): Boolean
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**generate(model: Model): Promise\<string>**
|
|
41
51
|
|
|
42
52
|
```ts
|
|
43
|
-
import { generate, Model, parse } from "bysquare"
|
|
53
|
+
import { generate, Model, parse, PaymentOptions } from "bysquare"
|
|
44
54
|
|
|
45
55
|
const model: Model = {
|
|
46
56
|
IBAN: "SK9611000000002918599669",
|
|
@@ -48,35 +58,33 @@ const model: Model = {
|
|
|
48
58
|
CurrencyCode: "EUR",
|
|
49
59
|
VariableSymbol: "123",
|
|
50
60
|
Payments: 1,
|
|
51
|
-
PaymentOptions:
|
|
61
|
+
PaymentOptions: PaymentOptions.PaymentOrder,
|
|
52
62
|
BankAccounts: 1
|
|
53
63
|
}
|
|
54
64
|
|
|
55
|
-
generate(model).then((
|
|
56
|
-
// "0004G0005ES17OQ09C98Q7ME34TCR3V71LVKD2AE6EGHKR82DKS5NBJ3331VUFQIV0JGMR743UJCKSAKEM9QGVVVOIVH000"
|
|
65
|
+
generate(model).then((qr: string) => {
|
|
57
66
|
// your logic...
|
|
58
67
|
})
|
|
59
68
|
```
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
**parse(qr: string): Promise\<ParsedModel>**
|
|
62
71
|
|
|
63
72
|
```ts
|
|
64
|
-
import {
|
|
73
|
+
import { ParsedModel, parse } from "bysquare"
|
|
65
74
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
parse(qrString).then((model: Model) => {
|
|
75
|
+
const qr = "0004A00090IFU27IV0J6HGGLIOTIBVHNQQJQ6LAVGNBT363HR13JC6C75G19O246KTT5G8LTLM67HOIATP4OOG8F8FDLJ6T26KFCB1690NEVPQVSG0"
|
|
76
|
+
parse(qr).then((model: ParsedModel) => {
|
|
69
77
|
// your logic...
|
|
70
78
|
})
|
|
71
79
|
```
|
|
72
80
|
|
|
73
|
-
|
|
81
|
+
**detect(qr: string): Boolean**
|
|
74
82
|
|
|
75
83
|
```ts
|
|
76
84
|
import { detect } from "bysquare"
|
|
77
85
|
|
|
78
|
-
const
|
|
79
|
-
const isBysquare = detect(
|
|
86
|
+
const qr = "0004A00090IFU27IV0J6HGGLIOTIBVHNQQJQ6LAVGNBT363HR13JC6C75G19O246KTT5G8LTLM67HOIATP4OOG8F8FDLJ6T26KFCB1690NEVPQVSG0"
|
|
87
|
+
const isBysquare = detect(qr)
|
|
80
88
|
|
|
81
89
|
// your logic...
|
|
82
90
|
```
|
|
@@ -88,6 +96,7 @@ You can use json file with valid model to generate qr-string.
|
|
|
88
96
|
```sh
|
|
89
97
|
# example.json
|
|
90
98
|
# {
|
|
99
|
+
# "InvoiceID: "random-id",
|
|
91
100
|
# "IBAN": "SK9611000000002918599669",
|
|
92
101
|
# "Amount": 100.0,
|
|
93
102
|
# "CurrencyCode": "EUR",
|
|
@@ -98,13 +107,14 @@ You can use json file with valid model to generate qr-string.
|
|
|
98
107
|
# }
|
|
99
108
|
|
|
100
109
|
$ npx bysquare ./example.json
|
|
101
|
-
$
|
|
110
|
+
$ 0004A00090IFU27IV0J6HGGLIOTIBVHNQQJQ6LAVGNBT363HR13JC6C75G19O246KTT5G8LTLM67HOIATP4OOG8F8FDLJ6T26KFCB1690NEVPQVSG0
|
|
102
111
|
```
|
|
103
112
|
|
|
104
113
|
You can also use stdin.
|
|
105
114
|
|
|
106
115
|
```sh
|
|
107
116
|
$ bysquare <<< '{
|
|
117
|
+
"InvoiceID": "random-id",
|
|
108
118
|
"IBAN": "SK9611000000002918599669",
|
|
109
119
|
"Amount": 100.0,
|
|
110
120
|
"CurrencyCode": "EUR",
|
|
@@ -113,49 +123,10 @@ $ bysquare <<< '{
|
|
|
113
123
|
"PaymentOptions": 1,
|
|
114
124
|
"BankAccounts": 1
|
|
115
125
|
}'
|
|
116
|
-
$
|
|
126
|
+
$ 0004A00090IFU27IV0J6HGGLIOTIBVHNQQJQ6LAVGNBT363HR13JC6C75G19O246KTT5G8LTLM67HOIATP4OOG8F8FDLJ6T26KFCB1690NEVPQVSG0
|
|
117
127
|
```
|
|
118
128
|
|
|
119
|
-
##
|
|
120
|
-
|
|
121
|
-
| Option | Type | Required |
|
|
122
|
-
| --------------------------------- | -------- | -------- |
|
|
123
|
-
| InvoiceID | `string` | no |
|
|
124
|
-
| Payments | `number` | yes |
|
|
125
|
-
| PaymentOptions | `number` | yes |
|
|
126
|
-
| Amount | `number` | no |
|
|
127
|
-
| CurrencyCode | `string` | yes |
|
|
128
|
-
| PaymentDueDate | `string` | no |
|
|
129
|
-
| VariableSymbol | `string` | no |
|
|
130
|
-
| ConstantSymbol | `string` | no |
|
|
131
|
-
| SpecificSymbol | `string` | no |
|
|
132
|
-
| OriginatorsReferenceInformation | `string` | no |
|
|
133
|
-
| PaymentNote | `string` | no |
|
|
134
|
-
| BankAccounts | `number` | yes |
|
|
135
|
-
| IBAN | `string` | yes |
|
|
136
|
-
| BIC | `string` | no |
|
|
137
|
-
| StandingOrderExt | `number` | no |
|
|
138
|
-
| Day | `number` | no |
|
|
139
|
-
| Month | `number` | no |
|
|
140
|
-
| Periodicity | `string` | no |
|
|
141
|
-
| LastDate | `string` | no |
|
|
142
|
-
| LastDate | `string` | no |
|
|
143
|
-
| DirectDebitExt | `number` | no |
|
|
144
|
-
| DirectDebitScheme | `number` | no |
|
|
145
|
-
| DirectDebitType | `number` | no |
|
|
146
|
-
| VariableSymbol\_ | `string` | no |
|
|
147
|
-
| SpecificSymbol\_ | `string` | no |
|
|
148
|
-
| OriginatorsReferenceInformation\_ | `string` | no |
|
|
149
|
-
| MandateID | `string` | no |
|
|
150
|
-
| CreditorID | `string` | no |
|
|
151
|
-
| ContractID | `string` | no |
|
|
152
|
-
| MaxAmount | `number` | no |
|
|
153
|
-
| ValidTillDate | `string` | no |
|
|
154
|
-
| BeneficiaryName | `string` | no |
|
|
155
|
-
| BeneficiaryAddressLine1 | `string` | no |
|
|
156
|
-
| BeneficiaryAddressLine2 | `string` | no |
|
|
157
|
-
|
|
158
|
-
## Resources
|
|
129
|
+
## Related
|
|
159
130
|
|
|
160
131
|
- <https://bysquare.com/>
|
|
161
132
|
- <https://devel.cz/otazka/qr-kod-pay-by-square>
|
|
@@ -164,16 +135,12 @@ $ 0004G0005ES17OQ09C98Q7ME34TCR3V71LVKD2AE6EGHKR82DKS5NBJ3331VUFQIV0JGMR743UJCKS
|
|
|
164
135
|
- <https://www.sbaonline.sk/wp-content/uploads/2020/03/pay-by-square-specifications-1_1_0.pdf>
|
|
165
136
|
- <https://www.vutbr.cz/studenti/zav-prace/detail/78439>
|
|
166
137
|
|
|
167
|
-
<!-- Links -->
|
|
168
|
-
|
|
169
|
-
[build]: https://img.shields.io/github/workflow/status/xseman/bysquare/tests
|
|
170
|
-
[version]: https://img.shields.io/npm/v/bysquare
|
|
171
|
-
[license]: https://img.shields.io/github/license/xseman/bysquare
|
|
172
|
-
|
|
173
138
|
<!--
|
|
174
139
|
Versioning
|
|
175
140
|
----------
|
|
176
141
|
|
|
142
|
+
https://github.com/dherges/npm-version-git-flow
|
|
143
|
+
|
|
177
144
|
- Stash unfinished work
|
|
178
145
|
- Run tests and build app
|
|
179
146
|
- Run the `preversion` script
|
package/lib/generate.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Model } from "./index";
|
|
3
3
|
/**
|
|
4
|
+
* Returns a 2 byte buffer that represents the header of the bysquare
|
|
5
|
+
* specification
|
|
6
|
+
*
|
|
4
7
|
* ```
|
|
5
8
|
* | Attribute | Number of bits | Possible values | Note
|
|
6
9
|
* --------------------------------------------------------------------------------------------
|
|
@@ -10,38 +13,32 @@ import { Model } from "./index";
|
|
|
10
13
|
* | Reserved | 4 | 0-15 | bits reserved for future needs
|
|
11
14
|
* ```
|
|
12
15
|
*
|
|
13
|
-
* @see
|
|
16
|
+
* @see 3.5. by square header
|
|
14
17
|
*/
|
|
15
|
-
export declare function
|
|
18
|
+
export declare function makeHeaderBysquare(header?: [
|
|
16
19
|
bySquareType: number,
|
|
17
20
|
version: number,
|
|
18
21
|
documentType: number,
|
|
19
22
|
reserved: number
|
|
20
23
|
]): Buffer;
|
|
21
|
-
export declare function createChecksum(tabbedInput: string): Buffer;
|
|
22
24
|
/**
|
|
23
|
-
* Appending CRC32 checksum
|
|
24
|
-
*
|
|
25
|
-
* @see {spec 3.10.}
|
|
25
|
+
* @see 3.10 Appending CRC32 checksum
|
|
26
26
|
*/
|
|
27
|
-
export declare function
|
|
27
|
+
export declare function makeChecksum(tabbedInput: string): Buffer;
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* Transfer object to a tabbed string and append a CRC32 checksum
|
|
30
|
+
*
|
|
31
|
+
* @see 3.10. Appending CRC32 checksum
|
|
32
32
|
*/
|
|
33
|
-
export declare function
|
|
33
|
+
export declare function prepareForCompression(model: Model): Buffer;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
* characters
|
|
35
|
+
* Convert object to tab-separated fields according to the sequence specification
|
|
37
36
|
*
|
|
38
|
-
* @see
|
|
37
|
+
* @see Table 15 PAY by square sequence data model
|
|
39
38
|
*/
|
|
40
|
-
export declare
|
|
39
|
+
export declare function makeTabbed(model: Model): string;
|
|
41
40
|
/**
|
|
42
|
-
* Alphanumeric conversion using Base32hex
|
|
43
|
-
*
|
|
44
|
-
* @see {spec 3.13.}
|
|
41
|
+
* @see 3.13. Alphanumeric conversion using Base32hex
|
|
45
42
|
*/
|
|
46
43
|
export declare function alphanumericConversion(data: Buffer): string;
|
|
47
44
|
export declare function generate(model: Model): Promise<string>;
|
package/lib/generate.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -19,11 +23,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
23
|
return result;
|
|
20
24
|
};
|
|
21
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.generate = exports.alphanumericConversion = exports.
|
|
26
|
+
exports.generate = exports.alphanumericConversion = exports.makeTabbed = exports.prepareForCompression = exports.makeChecksum = exports.makeHeaderBysquare = void 0;
|
|
23
27
|
const lzma = __importStar(require("lzma-native"));
|
|
24
28
|
const index_1 = require("./index");
|
|
25
29
|
// echo "Hello" | xz --format=raw --lzma1=lc=3,lp=0,pb=2,dict=32KiB --stdout | hexdump -C
|
|
26
30
|
/**
|
|
31
|
+
* Returns a 2 byte buffer that represents the header of the bysquare
|
|
32
|
+
* specification
|
|
33
|
+
*
|
|
27
34
|
* ```
|
|
28
35
|
* | Attribute | Number of bits | Possible values | Note
|
|
29
36
|
* --------------------------------------------------------------------------------------------
|
|
@@ -33,11 +40,9 @@ const index_1 = require("./index");
|
|
|
33
40
|
* | Reserved | 4 | 0-15 | bits reserved for future needs
|
|
34
41
|
* ```
|
|
35
42
|
*
|
|
36
|
-
* @see
|
|
43
|
+
* @see 3.5. by square header
|
|
37
44
|
*/
|
|
38
|
-
function
|
|
39
|
-
// prettier-ignore
|
|
40
|
-
header = [
|
|
45
|
+
function makeHeaderBysquare(header = [
|
|
41
46
|
0b0000_0000, 0b0000_0000,
|
|
42
47
|
0b0000_0000, 0b0000_0000
|
|
43
48
|
]) {
|
|
@@ -45,83 +50,96 @@ header = [
|
|
|
45
50
|
if (!isValid) {
|
|
46
51
|
throw new Error("Header range of values must be <0,15>");
|
|
47
52
|
}
|
|
48
|
-
const [
|
|
53
|
+
const [bySquareType, version, documentType, reserved] = header;
|
|
49
54
|
/** Combine 4-nibbles to 2-bytes */
|
|
50
55
|
const headerBuffer = Buffer.from([
|
|
51
|
-
(
|
|
52
|
-
(
|
|
56
|
+
(bySquareType << 4) | (version << 0),
|
|
57
|
+
(documentType << 4) | (reserved << 0)
|
|
53
58
|
]);
|
|
54
59
|
return headerBuffer;
|
|
55
60
|
}
|
|
56
|
-
exports.
|
|
61
|
+
exports.makeHeaderBysquare = makeHeaderBysquare;
|
|
57
62
|
/**
|
|
58
|
-
* LZMA
|
|
63
|
+
* Allocates a new buffer of a 2 bytes that represents LZMA header which
|
|
64
|
+
* contains 16-bit unsigned integer (word, little-endian), which is the size of
|
|
65
|
+
* the decompressed data. Therefore the maximum size of compressed data is
|
|
66
|
+
* limited to 65535
|
|
59
67
|
*
|
|
60
|
-
* @see
|
|
68
|
+
* @see 3.11. LZMA Compression
|
|
61
69
|
*/
|
|
62
|
-
function
|
|
70
|
+
function makeHeaderLzma(decompressedData) {
|
|
71
|
+
const bytesCount = decompressedData.length;
|
|
72
|
+
if (bytesCount >= 2 ** 16) {
|
|
73
|
+
throw new Error("The maximum compressed data size has been reached");
|
|
74
|
+
}
|
|
63
75
|
const dataSize = Buffer.alloc(2);
|
|
64
|
-
dataSize.writeInt16LE(
|
|
76
|
+
dataSize.writeInt16LE(bytesCount);
|
|
65
77
|
return dataSize;
|
|
66
78
|
}
|
|
67
|
-
|
|
79
|
+
/**
|
|
80
|
+
* @see 3.10 Appending CRC32 checksum
|
|
81
|
+
*/
|
|
82
|
+
function makeChecksum(tabbedInput) {
|
|
68
83
|
// @ts-ignore: Wrong return type
|
|
69
84
|
const data = lzma.crc32(tabbedInput);
|
|
70
85
|
const crc32 = Buffer.alloc(4);
|
|
71
86
|
crc32.writeUInt32LE(data);
|
|
72
87
|
return crc32;
|
|
73
88
|
}
|
|
74
|
-
exports.
|
|
89
|
+
exports.makeChecksum = makeChecksum;
|
|
75
90
|
/**
|
|
76
|
-
*
|
|
91
|
+
* Transfer object to a tabbed string and append a CRC32 checksum
|
|
77
92
|
*
|
|
78
|
-
* @see
|
|
93
|
+
* @see 3.10. Appending CRC32 checksum
|
|
79
94
|
*/
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Buffer.from(tabbedString, "utf-8")
|
|
95
|
+
function prepareForCompression(model) {
|
|
96
|
+
const tabbed = makeTabbed(model);
|
|
97
|
+
return Buffer.concat([
|
|
98
|
+
makeChecksum(tabbed),
|
|
99
|
+
Buffer.from(tabbed, "utf-8")
|
|
86
100
|
]);
|
|
87
|
-
return merged;
|
|
88
101
|
}
|
|
89
|
-
exports.
|
|
102
|
+
exports.prepareForCompression = prepareForCompression;
|
|
90
103
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
104
|
+
* Convert object to tab-separated fields according to the sequence specification
|
|
105
|
+
*
|
|
106
|
+
* @see Table 15 PAY by square sequence data model
|
|
94
107
|
*/
|
|
95
|
-
function
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
acc[
|
|
108
|
+
function makeTabbed(model) {
|
|
109
|
+
const tabbed = Object.keys(model).reduce((acc, key) => {
|
|
110
|
+
const index = index_1.SequenceOrder[key];
|
|
111
|
+
acc[index] = String(model[key]);
|
|
99
112
|
return acc;
|
|
100
|
-
}, Array(33).fill(
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
}, Array(33).fill(undefined));
|
|
114
|
+
const notStandingOrder = tabbed[14] === undefined;
|
|
115
|
+
const notDirectDebit = tabbed[19] === undefined;
|
|
116
|
+
if (notStandingOrder) {
|
|
117
|
+
const attributesLength = 4;
|
|
118
|
+
tabbed[14] = String(0);
|
|
119
|
+
tabbed.splice(15, attributesLength);
|
|
120
|
+
if (notDirectDebit) {
|
|
121
|
+
tabbed[19 - attributesLength] = String(0);
|
|
122
|
+
tabbed.splice(20 - attributesLength, 10);
|
|
123
|
+
}
|
|
124
|
+
return tabbed.join("\t");
|
|
125
|
+
}
|
|
126
|
+
if (notDirectDebit) {
|
|
127
|
+
const attributesLength = 10;
|
|
128
|
+
tabbed[19] = String(0);
|
|
129
|
+
tabbed.splice(20, attributesLength);
|
|
130
|
+
}
|
|
131
|
+
return tabbed.join("\t");
|
|
103
132
|
}
|
|
104
|
-
exports.
|
|
105
|
-
/**
|
|
106
|
-
* The bit sequence is split into 5 bit chunks which are mapped onto the
|
|
107
|
-
* characters
|
|
108
|
-
*
|
|
109
|
-
* @see {spec 3.13. Table 9 – Encoding table}
|
|
110
|
-
*/
|
|
111
|
-
exports.SUBST = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
|
133
|
+
exports.makeTabbed = makeTabbed;
|
|
112
134
|
/**
|
|
113
|
-
* Alphanumeric conversion using Base32hex
|
|
114
|
-
*
|
|
115
|
-
* @see {spec 3.13.}
|
|
135
|
+
* @see 3.13. Alphanumeric conversion using Base32hex
|
|
116
136
|
*/
|
|
117
137
|
function alphanumericConversion(data) {
|
|
118
138
|
let paddedBinString = data.reduce((acc, byte) => acc + byte.toString(2).padStart(8, "0"), "");
|
|
119
139
|
let paddedLength = paddedBinString.length;
|
|
120
140
|
const remainder = paddedLength % 5;
|
|
121
141
|
if (remainder) {
|
|
122
|
-
paddedBinString += Array(5 - remainder)
|
|
123
|
-
.fill("0")
|
|
124
|
-
.join("");
|
|
142
|
+
paddedBinString += Array(5 - remainder).fill("0").join("");
|
|
125
143
|
paddedLength += 5 - remainder;
|
|
126
144
|
}
|
|
127
145
|
/**
|
|
@@ -136,14 +154,14 @@ function alphanumericConversion(data) {
|
|
|
136
154
|
const binEnd = 5 * i + 5;
|
|
137
155
|
const sliced = paddedBinString.slice(binStart, binEnd);
|
|
138
156
|
const key = parseInt(sliced, 2);
|
|
139
|
-
encoded +=
|
|
157
|
+
encoded += index_1.SUBST[key];
|
|
140
158
|
}
|
|
141
159
|
return encoded;
|
|
142
160
|
}
|
|
143
161
|
exports.alphanumericConversion = alphanumericConversion;
|
|
144
162
|
function generate(model) {
|
|
145
|
-
const
|
|
146
|
-
const
|
|
163
|
+
const data = prepareForCompression(model);
|
|
164
|
+
const compressedData = [];
|
|
147
165
|
return new Promise((resolve, reject) => {
|
|
148
166
|
const encoder = lzma.createStream("rawEncoder", {
|
|
149
167
|
synchronous: true,
|
|
@@ -152,21 +170,19 @@ function generate(model) {
|
|
|
152
170
|
});
|
|
153
171
|
encoder
|
|
154
172
|
.on("data", (chunk) => {
|
|
155
|
-
|
|
173
|
+
compressedData.push(chunk);
|
|
156
174
|
})
|
|
157
175
|
.on("error", reject)
|
|
158
176
|
.on("end", () => {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
headerCompression,
|
|
164
|
-
...dataChunks
|
|
177
|
+
const output = Buffer.concat([
|
|
178
|
+
makeHeaderBysquare(),
|
|
179
|
+
makeHeaderLzma(data),
|
|
180
|
+
...compressedData
|
|
165
181
|
]);
|
|
166
|
-
const
|
|
167
|
-
resolve(
|
|
182
|
+
const qr = alphanumericConversion(output);
|
|
183
|
+
resolve(qr);
|
|
168
184
|
})
|
|
169
|
-
.write(
|
|
185
|
+
.write(data, (error) => {
|
|
170
186
|
error && reject(error);
|
|
171
187
|
encoder.end();
|
|
172
188
|
});
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -11,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
11
15
|
};
|
|
12
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
17
|
exports.generate = exports.detect = exports.parse = void 0;
|
|
18
|
+
// Library exposed functions and types
|
|
14
19
|
var parse_1 = require("./parse");
|
|
15
20
|
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parse_1.parse; } });
|
|
16
21
|
Object.defineProperty(exports, "detect", { enumerable: true, get: function () { return parse_1.detect; } });
|
package/lib/parse.d.ts
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
2
|
+
import { ParsedModel } from "./index";
|
|
3
3
|
/**
|
|
4
|
-
* Generating by square Code
|
|
5
|
-
*
|
|
6
|
-
* @see {spec 3.14.}
|
|
4
|
+
* @see 3.14. Generating by square Code
|
|
7
5
|
*/
|
|
8
|
-
export declare function
|
|
6
|
+
export declare function assemble(tabbed: string): ParsedModel;
|
|
9
7
|
/**
|
|
10
|
-
* Decoding client data from QR Code 2005 symbol
|
|
11
|
-
*
|
|
12
|
-
* @see {spec 3.16.}
|
|
8
|
+
* @see 3.16. Decoding client data from QR Code 2005 symbol
|
|
13
9
|
*/
|
|
14
|
-
export declare function parse(qr: string): Promise<
|
|
10
|
+
export declare function parse(qr: string): Promise<ParsedModel>;
|
|
15
11
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @see {spec 3.13.}
|
|
12
|
+
* @see 3.13. Alphanumeric conversion using Base32hex
|
|
19
13
|
*/
|
|
20
14
|
export declare function inverseAlphanumericConversion(qr: string): Buffer;
|
|
21
15
|
/**
|
package/lib/parse.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -19,56 +23,128 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
23
|
return result;
|
|
20
24
|
};
|
|
21
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.detect = exports.inverseAlphanumericConversion = exports.parse = exports.
|
|
26
|
+
exports.detect = exports.inverseAlphanumericConversion = exports.parse = exports.assemble = void 0;
|
|
23
27
|
const lzma = __importStar(require("lzma-native"));
|
|
24
|
-
const
|
|
25
|
-
const
|
|
28
|
+
const index_1 = require("./index");
|
|
29
|
+
const FIELDS_INVOICE = 0;
|
|
30
|
+
const FIELDS_NUMBER_OF_PAYMENTS = 1;
|
|
31
|
+
const FIELDS_PAYMENT_OPTIONS = 2;
|
|
26
32
|
/**
|
|
27
|
-
* Generating by square Code
|
|
28
|
-
*
|
|
29
|
-
* @see {spec 3.14.}
|
|
33
|
+
* @see 3.14. Generating by square Code
|
|
30
34
|
*/
|
|
31
|
-
function
|
|
32
|
-
const
|
|
35
|
+
function assemble(tabbed) {
|
|
36
|
+
const fields = tabbed
|
|
33
37
|
.split("\t")
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
/** The end of the qr-string might contain a NULL-terminated string */
|
|
39
|
+
.map((entry) => entry.replace("\x00", ""));
|
|
40
|
+
const invoiceId = fields[FIELDS_INVOICE];
|
|
41
|
+
const output = {
|
|
42
|
+
invoiceId: !!invoiceId.length ? invoiceId : undefined,
|
|
43
|
+
payments: []
|
|
44
|
+
};
|
|
45
|
+
const paymentsCount = Number(fields[FIELDS_NUMBER_OF_PAYMENTS]);
|
|
46
|
+
const paymentOptions = Number(fields[FIELDS_PAYMENT_OPTIONS]);
|
|
47
|
+
for (let i = 0; i < paymentsCount; i++) {
|
|
48
|
+
const payment = fields.slice(3 + i, 11 + i);
|
|
49
|
+
const [ammount, currencyCode, paymentDueDate, variableSymbol, constantSymbol, specificSymbol, originatorsReferenceInformation, paymentNote] = payment;
|
|
50
|
+
output.payments.push({
|
|
51
|
+
amount: ammount.length ? Number(ammount) : undefined,
|
|
52
|
+
currencyCode: currencyCode,
|
|
53
|
+
paymentDueDate: paymentDueDate?.length ? paymentDueDate : undefined,
|
|
54
|
+
variableSymbol: variableSymbol?.length ? variableSymbol : undefined,
|
|
55
|
+
constantSymbol: constantSymbol?.length ? constantSymbol : undefined,
|
|
56
|
+
specificSymbol: specificSymbol?.length ? specificSymbol : undefined,
|
|
57
|
+
originatorsReferenceInformation: originatorsReferenceInformation?.length ? originatorsReferenceInformation : undefined,
|
|
58
|
+
paymentNote: paymentNote?.length ? paymentNote : undefined,
|
|
59
|
+
bankAccounts: []
|
|
60
|
+
});
|
|
61
|
+
const bankAccounts = fields.slice(11 + i, 15 + i);
|
|
62
|
+
const [bankAccountsCount, iban, bic] = bankAccounts;
|
|
63
|
+
if (bankAccountsCount?.length === 0) {
|
|
64
|
+
throw new Error("Missing bank accounts count");
|
|
39
65
|
}
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"PaymentOptions",
|
|
43
|
-
"Amount",
|
|
44
|
-
"BankAccounts",
|
|
45
|
-
"StandingOrderExt",
|
|
46
|
-
"Day",
|
|
47
|
-
"Month",
|
|
48
|
-
"DirectDebitExt",
|
|
49
|
-
"DirectDebitScheme",
|
|
50
|
-
"DirectDebitType",
|
|
51
|
-
"MaxAmount"
|
|
52
|
-
];
|
|
53
|
-
if (numericKeys.includes(key)) {
|
|
54
|
-
acc[key] = Number(value);
|
|
55
|
-
return acc;
|
|
66
|
+
if (iban?.length === 0) {
|
|
67
|
+
throw new Error("Missing IBAN");
|
|
56
68
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
for (let j = 0; j < Number(bankAccountsCount); j++) {
|
|
70
|
+
output.payments[i].bankAccounts.push({
|
|
71
|
+
iban: iban,
|
|
72
|
+
bic: bic?.length ? bic : undefined
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
switch (paymentOptions) {
|
|
76
|
+
case index_1.PaymentOptions.PaymentOrder:
|
|
77
|
+
break;
|
|
78
|
+
case index_1.PaymentOptions.StandingOrder:
|
|
79
|
+
const standingOrder = fields.slice(15 + i, 20 + i);
|
|
80
|
+
const [day, month, periodicity, lastDate] = standingOrder;
|
|
81
|
+
output.payments[i].standingOrder = {
|
|
82
|
+
day: day?.length ? Number(day) : undefined,
|
|
83
|
+
month: month?.length ? Number(month) : undefined,
|
|
84
|
+
periodicity: periodicity?.length ? periodicity : undefined,
|
|
85
|
+
lastDate: lastDate?.length ? lastDate : undefined
|
|
86
|
+
};
|
|
87
|
+
break;
|
|
88
|
+
case index_1.PaymentOptions.DirectDebit:
|
|
89
|
+
const directDebit = fields.slice(16 + i, 26 + i);
|
|
90
|
+
const [directDebitScheme, directDebitType, variableSymbol, specificSymbol, originatorsReferenceInformation, mandateId, creditorId, contractId, maxAmount, validTillDate,] = directDebit;
|
|
91
|
+
output.payments[i].directDebit = {
|
|
92
|
+
directDebitScheme: directDebitScheme.length ? Number(directDebitScheme) : undefined,
|
|
93
|
+
directDebitType: directDebitType.length ? Number(directDebitType) : undefined,
|
|
94
|
+
variableSymbol: variableSymbol.length ? variableSymbol : undefined,
|
|
95
|
+
specificSymbol: specificSymbol.length ? specificSymbol : undefined,
|
|
96
|
+
originatorsReferenceInformation: originatorsReferenceInformation.length ? originatorsReferenceInformation : undefined,
|
|
97
|
+
mandateId: mandateId.length ? mandateId : undefined,
|
|
98
|
+
creditorId: creditorId.length ? creditorId : undefined,
|
|
99
|
+
contractId: contractId.length ? contractId : undefined,
|
|
100
|
+
maxAmount: maxAmount.length ? Number(maxAmount) : undefined,
|
|
101
|
+
validTillDate: validTillDate.length ? validTillDate : undefined
|
|
102
|
+
};
|
|
103
|
+
default:
|
|
104
|
+
throw new Error("Unknown payment option");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Beneficiary list bysquare v1.1 */
|
|
108
|
+
for (let i = 0; i < paymentsCount; i++) {
|
|
109
|
+
let beneficiary = [];
|
|
110
|
+
switch (paymentOptions) {
|
|
111
|
+
case index_1.PaymentOptions.PaymentOrder:
|
|
112
|
+
beneficiary = fields.slice(16 + i, 20 + i);
|
|
113
|
+
break;
|
|
114
|
+
case index_1.PaymentOptions.StandingOrder:
|
|
115
|
+
beneficiary = fields.slice(20 + i, 24 + i);
|
|
116
|
+
break;
|
|
117
|
+
case index_1.PaymentOptions.DirectDebit:
|
|
118
|
+
beneficiary = fields.slice(25 + i, 29 + i);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (beneficiary.length === 0) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
const [name, addressLine1, addressLine2] = beneficiary;
|
|
125
|
+
/**
|
|
126
|
+
* The list of recipients is optional, if we find a missing record, the
|
|
127
|
+
* stream ends
|
|
128
|
+
*/
|
|
129
|
+
if (!name && !addressLine1 && !addressLine2) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
output.payments[i].beneficiary = {
|
|
133
|
+
name: name?.length ? name : undefined,
|
|
134
|
+
addressLine1: addressLine1?.length ? addressLine1 : undefined,
|
|
135
|
+
addressLine2: addressLine2?.length ? addressLine2 : undefined
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return output;
|
|
61
139
|
}
|
|
62
|
-
exports.
|
|
140
|
+
exports.assemble = assemble;
|
|
63
141
|
/**
|
|
64
|
-
* Decoding client data from QR Code 2005 symbol
|
|
65
|
-
*
|
|
66
|
-
* @see {spec 3.16.}
|
|
142
|
+
* @see 3.16. Decoding client data from QR Code 2005 symbol
|
|
67
143
|
*/
|
|
68
144
|
function parse(qr) {
|
|
69
145
|
const inversed = inverseAlphanumericConversion(qr);
|
|
70
|
-
const
|
|
71
|
-
const
|
|
146
|
+
const _headerBysquare = inversed.slice(0, 2);
|
|
147
|
+
const _headerCompression = inversed.slice(2, 4);
|
|
72
148
|
const compressedData = inversed.slice(4);
|
|
73
149
|
// @ts-ignore: Missing decored types
|
|
74
150
|
const decoder = lzma.createStream("rawDecoder", {
|
|
@@ -81,8 +157,8 @@ function parse(qr) {
|
|
|
81
157
|
.on("error", reject)
|
|
82
158
|
.on("data", (decompress) => {
|
|
83
159
|
const _crc32 = decompress.slice(0, 4);
|
|
84
|
-
const
|
|
85
|
-
const model =
|
|
160
|
+
const tabbed = decompress.slice(4).toString();
|
|
161
|
+
const model = assemble(tabbed);
|
|
86
162
|
resolve(model);
|
|
87
163
|
})
|
|
88
164
|
.write(compressedData, (error) => {
|
|
@@ -93,13 +169,11 @@ function parse(qr) {
|
|
|
93
169
|
}
|
|
94
170
|
exports.parse = parse;
|
|
95
171
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* @see {spec 3.13.}
|
|
172
|
+
* @see 3.13. Alphanumeric conversion using Base32hex
|
|
99
173
|
*/
|
|
100
174
|
function inverseAlphanumericConversion(qr) {
|
|
101
175
|
const binary = [...qr].reduce((acc, char) => {
|
|
102
|
-
acc +=
|
|
176
|
+
acc += index_1.SUBST.indexOf(char).toString(2).padStart(5, "0");
|
|
103
177
|
return acc;
|
|
104
178
|
}, "");
|
|
105
179
|
let bytes = [];
|
|
@@ -127,9 +201,8 @@ function detect(qr) {
|
|
|
127
201
|
return [...headerBysquare.toString("hex")]
|
|
128
202
|
.map((nibble) => parseInt(nibble, 16))
|
|
129
203
|
.every((nibble, index) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return nibble <= 2;
|
|
204
|
+
if (index === 1 /** version */) {
|
|
205
|
+
return 0 >= nibble && nibble <= 1;
|
|
133
206
|
}
|
|
134
207
|
return 0 <= nibble && nibble <= 15;
|
|
135
208
|
});
|
package/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bit sequence is split into 5 bit chunks which are mapped onto the
|
|
3
|
+
* characters
|
|
4
|
+
*
|
|
5
|
+
* @see {spec 3.13. Table 9 – Encoding table}
|
|
6
|
+
*/
|
|
7
|
+
export declare const SUBST = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
|
8
|
+
export declare enum PaymentOptions {
|
|
9
|
+
PaymentOrder = 1,
|
|
10
|
+
StandingOrder = 2,
|
|
11
|
+
DirectDebit = 3
|
|
12
|
+
}
|
|
13
|
+
export declare enum MonthClassifier {
|
|
14
|
+
January = 1,
|
|
15
|
+
February = 2,
|
|
16
|
+
March = 4,
|
|
17
|
+
April = 8,
|
|
18
|
+
May = 16,
|
|
19
|
+
June = 32,
|
|
20
|
+
July = 64,
|
|
21
|
+
August = 128,
|
|
22
|
+
September = 256,
|
|
23
|
+
October = 512,
|
|
24
|
+
November = 1024,
|
|
25
|
+
December = 2048
|
|
26
|
+
}
|
|
27
|
+
export declare enum PeriodicityClassifier {
|
|
28
|
+
Daily = "d",
|
|
29
|
+
Weekly = "w",
|
|
30
|
+
Biweekly = "b",
|
|
31
|
+
Monthly = "m",
|
|
32
|
+
Bimonthly = "B",
|
|
33
|
+
Quarterly = "q",
|
|
34
|
+
Semiannually = "s",
|
|
35
|
+
Annually = "a"
|
|
36
|
+
}
|
|
37
|
+
export declare enum DirectDebitType {
|
|
38
|
+
OneOff = 0,
|
|
39
|
+
Recurrent = 1
|
|
40
|
+
}
|
|
41
|
+
export declare enum DirectDebitScheme {
|
|
42
|
+
Other = 0,
|
|
43
|
+
Sepa = 1
|
|
44
|
+
}
|
|
1
45
|
/**
|
|
2
46
|
* Table 15. PAY by square sequence data model (page 30.)
|
|
3
47
|
*/
|
|
@@ -7,32 +51,28 @@ export interface Model {
|
|
|
7
51
|
*/
|
|
8
52
|
InvoiceID?: string;
|
|
9
53
|
/**
|
|
54
|
+
* Appendix E extended beneficiary fields
|
|
55
|
+
* Table 16 PAY by square extended fields for bulk payment order
|
|
56
|
+
*
|
|
10
57
|
* Number of payments
|
|
11
58
|
*/
|
|
12
59
|
Payments: number;
|
|
13
60
|
/**
|
|
14
61
|
* Max length 1
|
|
15
62
|
*/
|
|
16
|
-
PaymentOptions:
|
|
63
|
+
PaymentOptions: PaymentOptions;
|
|
17
64
|
/**
|
|
18
65
|
* Encoded with amount payable. This field is not required and can be left
|
|
19
66
|
* blank in cases payment amount is not known such as donations.
|
|
20
67
|
*
|
|
21
|
-
*
|
|
22
|
-
* Format #.########
|
|
68
|
+
* Decimal, max length 15
|
|
23
69
|
*/
|
|
24
70
|
Amount?: number;
|
|
25
71
|
/**
|
|
26
72
|
* 3 letter, payment currency code according to ISO 4217
|
|
27
|
-
*
|
|
28
|
-
* Max length 3
|
|
29
|
-
* Representation ISO 4217
|
|
30
73
|
*/
|
|
31
74
|
CurrencyCode: keyof typeof CurrencyCode;
|
|
32
75
|
/**
|
|
33
|
-
* Optional field
|
|
34
|
-
*
|
|
35
|
-
* Max length 8
|
|
36
76
|
* Format YYYYMMDD
|
|
37
77
|
*/
|
|
38
78
|
PaymentDueDate?: string;
|
|
@@ -77,7 +117,7 @@ export interface Model {
|
|
|
77
117
|
/**
|
|
78
118
|
* Max length 1
|
|
79
119
|
*/
|
|
80
|
-
StandingOrderExt?:
|
|
120
|
+
StandingOrderExt?: 0 | 1;
|
|
81
121
|
/**
|
|
82
122
|
* This is the payment day. It‘s meaning depends on the periodicity, meaning
|
|
83
123
|
* either day of the month (number between 1 and 31) or day of the week
|
|
@@ -93,7 +133,7 @@ export interface Model {
|
|
|
93
133
|
*
|
|
94
134
|
* Max length 4
|
|
95
135
|
*/
|
|
96
|
-
Month?:
|
|
136
|
+
Month?: MonthClassifier;
|
|
97
137
|
/**
|
|
98
138
|
* Periodicity of the payment. All valid options are „Daily“, „Weekly“,
|
|
99
139
|
* „Biweekly“, „Monthly“, „Bimonthly“, „Quarterly“, „Annually“,
|
|
@@ -102,33 +142,44 @@ export interface Model {
|
|
|
102
142
|
*
|
|
103
143
|
* Max length 1
|
|
104
144
|
*/
|
|
105
|
-
Periodicity?:
|
|
145
|
+
Periodicity?: PeriodicityClassifier;
|
|
106
146
|
/**
|
|
107
147
|
* Defines the day of the last payment of the standing order. After this
|
|
108
148
|
* date, standing order is cancelled.
|
|
109
149
|
*
|
|
110
|
-
* Max length 8
|
|
111
150
|
* Format YYYYMMDD
|
|
112
151
|
*/
|
|
113
152
|
LastDate?: string;
|
|
114
153
|
/**
|
|
115
154
|
* Max length 1
|
|
116
155
|
*/
|
|
117
|
-
DirectDebitExt?:
|
|
156
|
+
DirectDebitExt?: 0 | 1;
|
|
118
157
|
/**
|
|
119
|
-
*
|
|
120
|
-
* debit
|
|
158
|
+
* If DirectDebitScheme value is 1, which is „SEPA“ than encoded direct
|
|
159
|
+
* debit follows SEPA direct debit scheme which means that fields MandateID,
|
|
160
|
+
* CreditorID and optional ContractID are used. If direct debit scheme is 0,
|
|
161
|
+
* which is „OTHER“ this means no specific direct debit scheme and following
|
|
162
|
+
* rules do apply:
|
|
163
|
+
*
|
|
164
|
+
* a. Creditor is identified via bank accounts
|
|
165
|
+
*
|
|
166
|
+
* b. Contract between debtor and creditor is identified using one of the
|
|
167
|
+
* following two ways: 1. by two optional fields SpecificSymbol and
|
|
168
|
+
* VariableSymbol. 2. by one optional field OriginatorsReferenceInformation.
|
|
169
|
+
* If SpecificSymbol and VariableSymbol fields or
|
|
170
|
+
* OriginatorsReferenceInformation field is filled in DirectDebitExt then
|
|
171
|
+
* these fields do apply for the direct debit.
|
|
121
172
|
*
|
|
122
173
|
* Max length 1
|
|
123
174
|
*/
|
|
124
|
-
DirectDebitScheme?:
|
|
175
|
+
DirectDebitScheme?: DirectDebitScheme;
|
|
125
176
|
/**
|
|
126
177
|
* Can be „oneoff“ for one time debit or „recurrent“ for repeated debit
|
|
127
178
|
* until cancelled.
|
|
128
179
|
*
|
|
129
180
|
* Max length 1
|
|
130
181
|
*/
|
|
131
|
-
DirectDebitType?:
|
|
182
|
+
DirectDebitType?: DirectDebitType;
|
|
132
183
|
/**
|
|
133
184
|
* Max length 10
|
|
134
185
|
*/
|
|
@@ -155,10 +206,9 @@ export interface Model {
|
|
|
155
206
|
ContractID?: string;
|
|
156
207
|
/**
|
|
157
208
|
* Optional field. As most users prefer to set up some maximum amount for
|
|
158
|
-
* the direct debit, this can be pre
|
|
209
|
+
* the direct debit, this can be pre-filled for them.
|
|
159
210
|
*
|
|
160
|
-
*
|
|
161
|
-
* Format #.########
|
|
211
|
+
* Decimal, max length 15
|
|
162
212
|
*/
|
|
163
213
|
MaxAmount?: number;
|
|
164
214
|
/**
|
|
@@ -169,24 +219,71 @@ export interface Model {
|
|
|
169
219
|
*/
|
|
170
220
|
ValidTillDate?: string;
|
|
171
221
|
/**
|
|
222
|
+
* Belongs to the first payment
|
|
223
|
+
*
|
|
172
224
|
* Max length 70
|
|
173
225
|
*/
|
|
174
226
|
BeneficiaryName?: string;
|
|
175
227
|
/**
|
|
228
|
+
* Belongs to the first payment
|
|
229
|
+
*
|
|
176
230
|
* Max length 70
|
|
177
231
|
*/
|
|
178
232
|
BeneficiaryAddressLine1?: string;
|
|
179
233
|
/**
|
|
234
|
+
* Belongs to the first payment
|
|
235
|
+
*
|
|
180
236
|
* Max length 70
|
|
181
237
|
*/
|
|
182
238
|
BeneficiaryAddressLine2?: string;
|
|
183
239
|
}
|
|
240
|
+
export interface ParsedModel {
|
|
241
|
+
invoiceId: Model["InvoiceID"];
|
|
242
|
+
payments: Array<{
|
|
243
|
+
amount: Model["Amount"];
|
|
244
|
+
currencyCode: Model["CurrencyCode"];
|
|
245
|
+
paymentDueDate?: Model["PaymentDueDate"];
|
|
246
|
+
variableSymbol?: Model["VariableSymbol"];
|
|
247
|
+
constantSymbol?: Model["ConstantSymbol"];
|
|
248
|
+
specificSymbol?: Model["SpecificSymbol"];
|
|
249
|
+
originatorsReferenceInformation?: Model["OriginatorsReferenceInformation"];
|
|
250
|
+
paymentNote?: Model["PaymentNote"];
|
|
251
|
+
bankAccounts: Array<{
|
|
252
|
+
iban: Model["IBAN"];
|
|
253
|
+
bic?: Model["BIC"];
|
|
254
|
+
}>;
|
|
255
|
+
standingOrder?: {
|
|
256
|
+
day?: Model["Day"];
|
|
257
|
+
month?: Model["Month"];
|
|
258
|
+
periodicity?: Model["Periodicity"];
|
|
259
|
+
lastDate?: Model["LastDate"];
|
|
260
|
+
};
|
|
261
|
+
directDebit?: {
|
|
262
|
+
directDebitScheme?: Model["DirectDebitScheme"];
|
|
263
|
+
directDebitType?: Model["DirectDebitType"];
|
|
264
|
+
variableSymbol?: Model["VariableSymbol"];
|
|
265
|
+
specificSymbol?: Model["SpecificSymbol"];
|
|
266
|
+
originatorsReferenceInformation?: Model["OriginatorsReferenceInformation_"];
|
|
267
|
+
mandateId?: Model["MandateID"];
|
|
268
|
+
creditorId?: Model["CreditorID"];
|
|
269
|
+
contractId?: Model["ContractID"];
|
|
270
|
+
maxAmount?: Model["MaxAmount"];
|
|
271
|
+
validTillDate?: Model["ValidTillDate"];
|
|
272
|
+
};
|
|
273
|
+
beneficiary?: {
|
|
274
|
+
name?: Model["BeneficiaryName"];
|
|
275
|
+
addressLine1?: Model["BeneficiaryAddressLine1"];
|
|
276
|
+
addressLine2?: Model["BeneficiaryAddressLine2"];
|
|
277
|
+
};
|
|
278
|
+
}>;
|
|
279
|
+
}
|
|
184
280
|
/**
|
|
185
281
|
* Atributes must follow specific order
|
|
186
282
|
* Based on Table 15. PAY by square sequence data model (page 30.)
|
|
283
|
+
*
|
|
187
284
|
* @see{./docs/specification_v1.1.0.pdf}
|
|
188
285
|
*/
|
|
189
|
-
export declare enum
|
|
286
|
+
export declare enum SequenceOrder {
|
|
190
287
|
InvoiceID = 0,
|
|
191
288
|
Payments = 1,
|
|
192
289
|
PaymentOptions = 2,
|
package/lib/types.js
CHANGED
|
@@ -1,47 +1,116 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CurrencyCode = exports.
|
|
3
|
+
exports.CurrencyCode = exports.SequenceOrder = exports.DirectDebitScheme = exports.DirectDebitType = exports.PeriodicityClassifier = exports.MonthClassifier = exports.PaymentOptions = exports.SUBST = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The bit sequence is split into 5 bit chunks which are mapped onto the
|
|
6
|
+
* characters
|
|
7
|
+
*
|
|
8
|
+
* @see {spec 3.13. Table 9 – Encoding table}
|
|
9
|
+
*/
|
|
10
|
+
exports.SUBST = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
|
11
|
+
/**
|
|
12
|
+
* Mapping semantic version to encoded version number, header 4-bits
|
|
13
|
+
*
|
|
14
|
+
* It's a bit silly to limit the version number to 4-bit, if they keep
|
|
15
|
+
* increasing the version number, the latest possible mapped value is 16
|
|
16
|
+
*/
|
|
17
|
+
var Version;
|
|
18
|
+
(function (Version) {
|
|
19
|
+
/**
|
|
20
|
+
* 2013-02-22
|
|
21
|
+
* Created this document from original by square specifications
|
|
22
|
+
*/
|
|
23
|
+
Version[Version["1.0.0"] = 0] = "1.0.0";
|
|
24
|
+
/**
|
|
25
|
+
* 2015-06-24
|
|
26
|
+
* Added fields for beneficiary name and address
|
|
27
|
+
*/
|
|
28
|
+
Version[Version["1.1.0"] = 1] = "1.1.0";
|
|
29
|
+
})(Version || (Version = {}));
|
|
30
|
+
var PaymentOptions;
|
|
31
|
+
(function (PaymentOptions) {
|
|
32
|
+
PaymentOptions[PaymentOptions["PaymentOrder"] = 1] = "PaymentOrder";
|
|
33
|
+
PaymentOptions[PaymentOptions["StandingOrder"] = 2] = "StandingOrder";
|
|
34
|
+
PaymentOptions[PaymentOptions["DirectDebit"] = 3] = "DirectDebit";
|
|
35
|
+
})(PaymentOptions = exports.PaymentOptions || (exports.PaymentOptions = {}));
|
|
36
|
+
var MonthClassifier;
|
|
37
|
+
(function (MonthClassifier) {
|
|
38
|
+
MonthClassifier[MonthClassifier["January"] = 1] = "January";
|
|
39
|
+
MonthClassifier[MonthClassifier["February"] = 2] = "February";
|
|
40
|
+
MonthClassifier[MonthClassifier["March"] = 4] = "March";
|
|
41
|
+
MonthClassifier[MonthClassifier["April"] = 8] = "April";
|
|
42
|
+
MonthClassifier[MonthClassifier["May"] = 16] = "May";
|
|
43
|
+
MonthClassifier[MonthClassifier["June"] = 32] = "June";
|
|
44
|
+
MonthClassifier[MonthClassifier["July"] = 64] = "July";
|
|
45
|
+
MonthClassifier[MonthClassifier["August"] = 128] = "August";
|
|
46
|
+
MonthClassifier[MonthClassifier["September"] = 256] = "September";
|
|
47
|
+
MonthClassifier[MonthClassifier["October"] = 512] = "October";
|
|
48
|
+
MonthClassifier[MonthClassifier["November"] = 1024] = "November";
|
|
49
|
+
MonthClassifier[MonthClassifier["December"] = 2048] = "December";
|
|
50
|
+
})(MonthClassifier = exports.MonthClassifier || (exports.MonthClassifier = {}));
|
|
51
|
+
var PeriodicityClassifier;
|
|
52
|
+
(function (PeriodicityClassifier) {
|
|
53
|
+
PeriodicityClassifier["Daily"] = "d";
|
|
54
|
+
PeriodicityClassifier["Weekly"] = "w";
|
|
55
|
+
PeriodicityClassifier["Biweekly"] = "b";
|
|
56
|
+
PeriodicityClassifier["Monthly"] = "m";
|
|
57
|
+
PeriodicityClassifier["Bimonthly"] = "B";
|
|
58
|
+
PeriodicityClassifier["Quarterly"] = "q";
|
|
59
|
+
PeriodicityClassifier["Semiannually"] = "s";
|
|
60
|
+
PeriodicityClassifier["Annually"] = "a";
|
|
61
|
+
})(PeriodicityClassifier = exports.PeriodicityClassifier || (exports.PeriodicityClassifier = {}));
|
|
62
|
+
var DirectDebitType;
|
|
63
|
+
(function (DirectDebitType) {
|
|
64
|
+
DirectDebitType[DirectDebitType["OneOff"] = 0] = "OneOff";
|
|
65
|
+
DirectDebitType[DirectDebitType["Recurrent"] = 1] = "Recurrent";
|
|
66
|
+
})(DirectDebitType = exports.DirectDebitType || (exports.DirectDebitType = {}));
|
|
67
|
+
var DirectDebitScheme;
|
|
68
|
+
(function (DirectDebitScheme) {
|
|
69
|
+
DirectDebitScheme[DirectDebitScheme["Other"] = 0] = "Other";
|
|
70
|
+
DirectDebitScheme[DirectDebitScheme["Sepa"] = 1] = "Sepa";
|
|
71
|
+
})(DirectDebitScheme = exports.DirectDebitScheme || (exports.DirectDebitScheme = {}));
|
|
4
72
|
/**
|
|
5
73
|
* Atributes must follow specific order
|
|
6
74
|
* Based on Table 15. PAY by square sequence data model (page 30.)
|
|
75
|
+
*
|
|
7
76
|
* @see{./docs/specification_v1.1.0.pdf}
|
|
8
77
|
*/
|
|
9
|
-
var
|
|
10
|
-
(function (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})(
|
|
78
|
+
var SequenceOrder;
|
|
79
|
+
(function (SequenceOrder) {
|
|
80
|
+
SequenceOrder[SequenceOrder["InvoiceID"] = 0] = "InvoiceID";
|
|
81
|
+
SequenceOrder[SequenceOrder["Payments"] = 1] = "Payments";
|
|
82
|
+
SequenceOrder[SequenceOrder["PaymentOptions"] = 2] = "PaymentOptions";
|
|
83
|
+
SequenceOrder[SequenceOrder["Amount"] = 3] = "Amount";
|
|
84
|
+
SequenceOrder[SequenceOrder["CurrencyCode"] = 4] = "CurrencyCode";
|
|
85
|
+
SequenceOrder[SequenceOrder["PaymentDueDate"] = 5] = "PaymentDueDate";
|
|
86
|
+
SequenceOrder[SequenceOrder["VariableSymbol"] = 6] = "VariableSymbol";
|
|
87
|
+
SequenceOrder[SequenceOrder["ConstantSymbol"] = 7] = "ConstantSymbol";
|
|
88
|
+
SequenceOrder[SequenceOrder["SpecificSymbol"] = 8] = "SpecificSymbol";
|
|
89
|
+
SequenceOrder[SequenceOrder["OriginatorsReferenceInformation"] = 9] = "OriginatorsReferenceInformation";
|
|
90
|
+
SequenceOrder[SequenceOrder["PaymentNote"] = 10] = "PaymentNote";
|
|
91
|
+
SequenceOrder[SequenceOrder["BankAccounts"] = 11] = "BankAccounts";
|
|
92
|
+
SequenceOrder[SequenceOrder["IBAN"] = 12] = "IBAN";
|
|
93
|
+
SequenceOrder[SequenceOrder["BIC"] = 13] = "BIC";
|
|
94
|
+
SequenceOrder[SequenceOrder["StandingOrderExt"] = 14] = "StandingOrderExt";
|
|
95
|
+
SequenceOrder[SequenceOrder["Day"] = 15] = "Day";
|
|
96
|
+
SequenceOrder[SequenceOrder["Month"] = 16] = "Month";
|
|
97
|
+
SequenceOrder[SequenceOrder["Periodicity"] = 17] = "Periodicity";
|
|
98
|
+
SequenceOrder[SequenceOrder["LastDate"] = 18] = "LastDate";
|
|
99
|
+
SequenceOrder[SequenceOrder["DirectDebitExt"] = 19] = "DirectDebitExt";
|
|
100
|
+
SequenceOrder[SequenceOrder["DirectDebitScheme"] = 20] = "DirectDebitScheme";
|
|
101
|
+
SequenceOrder[SequenceOrder["DirectDebitType"] = 21] = "DirectDebitType";
|
|
102
|
+
SequenceOrder[SequenceOrder["VariableSymbol_"] = 22] = "VariableSymbol_";
|
|
103
|
+
SequenceOrder[SequenceOrder["SpecificSymbol_"] = 23] = "SpecificSymbol_";
|
|
104
|
+
SequenceOrder[SequenceOrder["OriginatorsReferenceInformation_"] = 24] = "OriginatorsReferenceInformation_";
|
|
105
|
+
SequenceOrder[SequenceOrder["MandateID"] = 25] = "MandateID";
|
|
106
|
+
SequenceOrder[SequenceOrder["CreditorID"] = 26] = "CreditorID";
|
|
107
|
+
SequenceOrder[SequenceOrder["ContractID"] = 27] = "ContractID";
|
|
108
|
+
SequenceOrder[SequenceOrder["MaxAmount"] = 28] = "MaxAmount";
|
|
109
|
+
SequenceOrder[SequenceOrder["ValidTillDate"] = 29] = "ValidTillDate";
|
|
110
|
+
SequenceOrder[SequenceOrder["BeneficiaryName"] = 30] = "BeneficiaryName";
|
|
111
|
+
SequenceOrder[SequenceOrder["BeneficiaryAddressLine1"] = 31] = "BeneficiaryAddressLine1";
|
|
112
|
+
SequenceOrder[SequenceOrder["BeneficiaryAddressLine2"] = 32] = "BeneficiaryAddressLine2";
|
|
113
|
+
})(SequenceOrder = exports.SequenceOrder || (exports.SequenceOrder = {}));
|
|
45
114
|
/**
|
|
46
115
|
* Currency codes based on ISO 4217
|
|
47
116
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bysquare",
|
|
3
3
|
"description": "It's a national standard for payment QR codes adopted by Slovak Banking Association (SBA)",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Filip Seman <filip.seman@protonmail.com>",
|
|
7
7
|
"keywords": [
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/lzma-native": "^4.0.1",
|
|
41
|
-
"@types/node": ">=
|
|
42
|
-
"typescript": "4.
|
|
41
|
+
"@types/node": ">=14",
|
|
42
|
+
"typescript": "~4.7.0",
|
|
43
43
|
"vitest": "0.22.0"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"main": "lib/index.js",
|
|
51
51
|
"types": "lib/index.d.ts",
|
|
52
52
|
"engines": {
|
|
53
|
-
"node": ">=14
|
|
54
|
-
"npm": ">=
|
|
53
|
+
"node": ">=14",
|
|
54
|
+
"npm": ">=7.0"
|
|
55
55
|
},
|
|
56
56
|
"os": [
|
|
57
57
|
"darwin",
|