-
-
Save mauris/44877098c672075265dcad9cf1950756 to your computer and use it in GitHub Desktop.
SG PayNow QR Code Generator Sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String.prototype.padLeft = function (n, str) { | |
if (n < String(this).length) { | |
return this.toString(); | |
} | |
else { | |
return Array(n - String(this).length + 1).join(str || '0') + this; | |
} | |
} | |
function crc16(s) { | |
var crcTable = [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, | |
0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, | |
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, | |
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, | |
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, | |
0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, | |
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, | |
0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, | |
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, | |
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, | |
0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, | |
0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, | |
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, | |
0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, | |
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, | |
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, | |
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, | |
0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, | |
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, | |
0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, | |
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, | |
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, | |
0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, | |
0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, | |
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, | |
0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, | |
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, | |
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, | |
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, | |
0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, | |
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, | |
0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, | |
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, | |
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, | |
0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, | |
0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, | |
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, | |
0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, | |
0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, | |
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, | |
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, | |
0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, | |
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0]; | |
var crc = 0xFFFF; | |
var j, i; | |
for (i = 0; i < s.length; i++) { | |
c = s.charCodeAt(i); | |
if (c > 255) { | |
throw new RangeError(); | |
} | |
j = (c ^ (crc >> 8)) & 0xFF; | |
crc = crcTable[j] ^ (crc << 8); | |
} | |
return ((crc ^ 0) & 0xFFFF).toString(16).toUpperCase(); | |
} | |
function generatePayNowStr( opts ) { | |
const p = [ | |
{ id: '00', value: '01' }, // ID 00: Payload Format Indicator (Fixed to '01') | |
{ id: '01', value: '12' }, // ID 01: Point of Initiation Method 11: static, 12: dynamic | |
{ | |
id: '26', value: // ID 26: Merchant Account Info Template | |
[{ id: '00', value: 'SG.PAYNOW' }, | |
{ id: '01', value: '2' }, // 0 for mobile, 2 for UEN. 1 is not used. | |
{ id: '02', value: opts.uen }, // PayNow UEN (Company Unique Entity Number) | |
{ id: '03', value: opts.editable.toString() }, // 1 = Payment amount is editable, 0 = Not Editable | |
{ id: '04', value: opts.expiry }] // Expiry date (YYYYMMDD) | |
}, | |
{ id: '52', value: '0000' }, // ID 52: Merchant Category Code (not used) | |
{ id: '53', value: '702' }, // ID 53: Currency. SGD is 702 | |
{ id: '54', value: opts.amount.toString() }, // ID 54: Transaction Amount | |
{ id: '58', value: 'SG' }, // ID 58: 2-letter Country Code (SG) | |
{ id: '59', value: 'COMPANY NAME' }, // ID 59: Company Name | |
{ id: '60', value: 'Singapore' }, // ID 60: Merchant City | |
{ | |
id: '62', value: [{ // ID 62: Additional data fields | |
id: '01', value: opts.refNumber // ID 01: Bill Number | |
}] | |
} | |
] | |
let str = p.reduce((final, current) => { | |
if (Array.isArray(current.value)) { //nest loop | |
current.value = current.value.reduce((f, c) => { | |
f += c.id + c.value.length.toString().padLeft(2) + c.value; | |
return f | |
}, "") | |
} | |
final += current.id + current.value.length.toString().padLeft(2) + current.value; | |
return final | |
}, "") | |
// Here we add "6304" to the previous string | |
// ID 63 (Checksum) 04 (4 characters) | |
// Do a CRC16 of the whole string including the "6304" | |
// then append it to the end. | |
str += '6304' + crc16(str + '6304'); | |
return str; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment