-
Notifications
You must be signed in to change notification settings - Fork 5
/
pay_by_square.py
117 lines (103 loc) · 3.01 KB
/
pay_by_square.py
1
2
3
4
5
6
7
8
9
10
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import lzma
import binascii
from typing import Optional
from datetime import datetime, date
def generate(
*,
amount: float,
iban: str,
swift: str = '',
date: Optional[date] = None,
beneficiary_name: str = '',
currency: str = 'EUR',
variable_symbol: str = '',
constant_symbol: str = '',
specific_symbol: str = '',
note: str = '',
beneficiary_address_1: str = '',
beneficiary_address_2: str = '',
) -> str:
'''Generate pay-by-square code that can by used to create QR code for
banking apps
When date is not provided current date will be used.
'''
if date is None:
date = datetime.now()
# 1) create the basic data structure
data = '\t'.join(
[
'',
'1', # payment
'1', # simple payment
f'{amount:.2f}',
currency,
date.strftime('%Y%m%d'),
variable_symbol,
constant_symbol,
specific_symbol,
'', # previous 3 entries in SEPA format, empty because already provided above
note,
'1', # to an account
iban,
swift,
'0', # not recurring
'0', # not 'inkaso'
beneficiary_name,
beneficiary_address_1,
beneficiary_address_2,
]
)
# 2) Add a crc32 checksum
checksum = binascii.crc32(data.encode()).to_bytes(4, 'little')
total = checksum + data.encode()
# 3) Run through XZ
compressed = lzma.compress(
total,
format=lzma.FORMAT_RAW,
filters=[
{
'id': lzma.FILTER_LZMA1,
'lc': 3,
'lp': 0,
'pb': 2,
'dict_size': 128 * 1024,
}
],
)
# 4) prepend length and convert to hex
compressed_with_length = b'\x00\x00' + len(total).to_bytes(2, 'little') + compressed
# 5) Convert to padded binary string
binary = ''.join(
[bin(single_byte)[2:].zfill(8) for single_byte in compressed_with_length]
)
# 6) Pad with zeros on the right up to a multiple of 5
length = len(binary)
remainder = length % 5
if remainder:
binary += '0' * (5 - remainder)
length += 5 - remainder
# 7) Substitute each quintet of bits with corresponding character
subst = '0123456789ABCDEFGHIJKLMNOPQRSTUV'
return ''.join(
[subst[int(binary[5 * i : 5 * i + 5], 2)] for i in range(length // 5)]
)
if __name__ == '__main__':
try:
import qrcode
except ImportError:
raise SystemExit('Install \'qrcode\' module to run demo')
code = generate(
amount=1,
iban='SK7700000000000000000000',
swift='FIOZSKBAXXX',
variable_symbol='11',
constant_symbol='22',
specific_symbol='33',
beneficiary_name='Foo',
beneficiary_address_1='address 1',
beneficiary_address_2='address 2',
note='bar',
)
print(code)
img = qrcode.make(code)
img.show()