thai-bank-transfer-qr 0.1.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.
Files changed (3) hide show
  1. package/README.md +39 -0
  2. package/index.js +85 -0
  3. package/package.json +28 -0
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # thai-bank-transfer-qr
2
+
3
+ Minimal, dependency-free Thai bank transfer QR payload builder (PromptPay / Tag 29 + CRC16-CCITT).
4
+
5
+ - No merchant name or city tags (59/60) included.
6
+ - Privacy: never publish real bank account numbers.
7
+
8
+ ## Install
9
+
10
+ Use directly in a monorepo or publish to npm.
11
+
12
+ ## Usage
13
+
14
+ ```js
15
+ import buildThaiQRBankTransfer from "thai-bank-transfer-qr"
16
+
17
+ const payload = buildThaiQRBankTransfer({
18
+ bankCode: "004", // example only
19
+ accountNumber: "1234567890", // example only
20
+ amount: 10,
21
+ dynamic: false, // 11 static, 12 dynamic
22
+ })
23
+
24
+ console.log(payload)
25
+ ```
26
+
27
+ ## API
28
+
29
+ - buildThaiQRBankTransfer(options)
30
+ - bankCode: string (3 digits)
31
+ - accountNumber: string (digits only)
32
+ - amount: number|string (formatted to 2 decimals)
33
+ - dynamic?: boolean (default true)
34
+ - referenceId?: string (Tag 62 >> 05)
35
+
36
+ Also exports: `tlv`, `crc16CCITT`.
37
+
38
+ ## License
39
+ MIT
package/index.js ADDED
@@ -0,0 +1,85 @@
1
+ // Minimal, dependency-free Thai bank transfer QR payload builder
2
+ // Exports: buildThaiQRBankTransfer, tlv, crc16CCITT
3
+
4
+ /**
5
+ * Tag-Length-Value encoder
6
+ * @param {string} tag
7
+ * @param {string} value
8
+ * @returns {string}
9
+ */
10
+ export function tlv(tag, value) {
11
+ const len = value.length.toString().padStart(2, "0");
12
+ return `${tag}${len}${value}`;
13
+ }
14
+
15
+ /**
16
+ * CRC16-CCITT (poly 0x1021), init 0xFFFF, no XOR-out
17
+ * @param {string} input
18
+ * @returns {string} Uppercase hex (4 chars)
19
+ */
20
+ export function crc16CCITT(input) {
21
+ let crc = 0xffff;
22
+ for (let i = 0; i < input.length; i++) {
23
+ crc ^= input.charCodeAt(i) << 8;
24
+ for (let j = 0; j < 8; j++) {
25
+ crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
26
+ crc &= 0xffff;
27
+ }
28
+ }
29
+ return crc.toString(16).toUpperCase().padStart(4, "0");
30
+ }
31
+
32
+ /**
33
+ * Build Thai QR Bank Transfer payload (EMVCo + Thai spec)
34
+ * @param {Object} options
35
+ * @param {string} options.bankCode 3-digit Thai bank code (e.g. "004")
36
+ * @param {string} options.accountNumber Digits only
37
+ * @param {number|string} options.amount Fixed THB amount
38
+ * @param {boolean} [options.dynamic=true] Tag 01: 12=dynamic, 11=static
39
+ * @param {string} [options.merchantName]
40
+ * @param {string} [options.merchantCity]
41
+ * @param {string} [options.referenceId]
42
+ * @returns {string}
43
+ */
44
+ export function buildThaiQRBankTransfer({
45
+ bankCode,
46
+ accountNumber,
47
+ amount,
48
+ dynamic = true,
49
+ referenceId,
50
+ }) {
51
+ if (!/^\d{3}$/.test(bankCode))
52
+ throw new Error("bankCode must be 3 digits (e.g. 004)");
53
+ if (!/^\d+$/.test(accountNumber))
54
+ throw new Error("accountNumber must be digits only");
55
+
56
+ const amt = (
57
+ typeof amount === "number" ? amount : parseFloat(amount)
58
+ ).toFixed(2);
59
+ if (isNaN(Number(amt))) throw new Error("amount must be a number");
60
+
61
+ // Tag 29 (Bank transfer template) → 00=AID, 03=bankCode+accountNumber
62
+ const tag29 = tlv(
63
+ "29",
64
+ tlv("00", "A000000677010111") + tlv("03", `${bankCode}${accountNumber}`)
65
+ );
66
+
67
+ // Optional Tag 62 → 05=Reference ID
68
+ const tag62 = referenceId ? tlv("62", tlv("05", referenceId)) : "";
69
+
70
+ const withoutCRC =
71
+ tlv("00", "01") +
72
+ tlv("01", dynamic ? "12" : "11") +
73
+ tag29 +
74
+ tlv("52", "0000") +
75
+ tlv("53", "764") +
76
+ tlv("54", amt) +
77
+ tlv("58", "TH") +
78
+ tag62 +
79
+ "6304";
80
+
81
+ const crc = crc16CCITT(withoutCRC);
82
+ return withoutCRC + crc;
83
+ }
84
+
85
+ export default buildThaiQRBankTransfer;
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "thai-bank-transfer-qr",
3
+ "version": "0.1.0",
4
+ "description": "Thai bank transfer QR payload builder (PromptPay – Tag 29 + CRC16)",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
10
+ "keywords": [
11
+ "thai",
12
+ "promptpay",
13
+ "qr",
14
+ "emv",
15
+ "bank",
16
+ "transfer"
17
+ ],
18
+ "license": "MIT",
19
+ "author": "thunthup",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/thunthup/thai-bank-qr.git"
23
+ },
24
+ "homepage": "https://github.com/thunthup/thai-bank-qr#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/thunthup/thai-bank-qr/issues"
27
+ }
28
+ }