thunder-solution-sdk 1.0.0__py3-none-any.whl
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.
- thunder_slip/__init__.py +12 -0
- thunder_slip/_base_error.py +8 -0
- thunder_slip/_codec.py +102 -0
- thunder_slip/_transport.py +282 -0
- thunder_slip/client.py +860 -0
- thunder_slip/errors.py +367 -0
- thunder_slip/files.py +59 -0
- thunder_slip/models.py +600 -0
- thunder_slip/py.typed +0 -0
- thunder_slip/webhook.py +26 -0
- thunder_slip/webhooks.py +25 -0
- thunder_solution_sdk-1.0.0.dist-info/METADATA +452 -0
- thunder_solution_sdk-1.0.0.dist-info/RECORD +16 -0
- thunder_solution_sdk-1.0.0.dist-info/WHEEL +5 -0
- thunder_solution_sdk-1.0.0.dist-info/licenses/LICENSE +21 -0
- thunder_solution_sdk-1.0.0.dist-info/top_level.txt +1 -0
thunder_slip/models.py
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"""Typed request and response models from the shared wire contract."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import base64
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
from typing import Any, Literal, TypeAlias
|
|
8
|
+
from ._codec import UNSET, UnsetType, encode
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
AccountType: TypeAlias = Literal["NATURAL", "JURISTIC"]
|
|
12
|
+
QrType: TypeAlias = Literal["PROMPTPAY", "BILL_PAYMENT", "KSHOP", "MAE_MANEE", "TUNGNGERN"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(kw_only=True)
|
|
16
|
+
class Model:
|
|
17
|
+
"""Wire model; metadata is excluded from representation and JSON."""
|
|
18
|
+
|
|
19
|
+
meta: ResponseMeta | None = field(
|
|
20
|
+
default=None, init=False, repr=False, compare=False, metadata={"ignore": True}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> Any:
|
|
24
|
+
"""Return wire JSON with absent fields omitted."""
|
|
25
|
+
return encode(self)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(kw_only=True)
|
|
29
|
+
class Info(Model):
|
|
30
|
+
"""Info wire fields. Unknown enum strings are preserved."""
|
|
31
|
+
|
|
32
|
+
application: InfoApplication = field(metadata={"wire": "application"})
|
|
33
|
+
branch: InfoBranch = field(metadata={"wire": "branch"})
|
|
34
|
+
account: InfoAccount = field(metadata={"wire": "account"})
|
|
35
|
+
product: InfoProduct = field(metadata={"wire": "product"})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(kw_only=True)
|
|
39
|
+
class InfoApplication(Model):
|
|
40
|
+
"""InfoApplication wire fields. Unknown enum strings are preserved."""
|
|
41
|
+
|
|
42
|
+
name: str = field(metadata={"wire": "name"})
|
|
43
|
+
auto_renew: AutoRenew = field(metadata={"wire": "autoRenew"})
|
|
44
|
+
quota: ApplicationQuota = field(metadata={"wire": "quota"})
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(kw_only=True)
|
|
48
|
+
class AutoRenew(Model):
|
|
49
|
+
"""AutoRenew wire fields. Unknown enum strings are preserved."""
|
|
50
|
+
|
|
51
|
+
expired: bool = field(metadata={"wire": "expired"})
|
|
52
|
+
quota: bool = field(metadata={"wire": "quota"})
|
|
53
|
+
created_at: str = field(metadata={"wire": "createdAt"})
|
|
54
|
+
expires_at: str = field(metadata={"wire": "expiresAt"})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(kw_only=True)
|
|
58
|
+
class ApplicationQuota(Model):
|
|
59
|
+
"""ApplicationQuota wire fields. Unknown enum strings are preserved."""
|
|
60
|
+
|
|
61
|
+
used: int = field(metadata={"wire": "used"})
|
|
62
|
+
max: int | None = field(metadata={"wire": "max"})
|
|
63
|
+
remaining: int | None = field(metadata={"wire": "remaining"})
|
|
64
|
+
total_used: int = field(metadata={"wire": "totalUsed"})
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(kw_only=True)
|
|
68
|
+
class InfoBranch(Model):
|
|
69
|
+
"""InfoBranch wire fields. Unknown enum strings are preserved."""
|
|
70
|
+
|
|
71
|
+
name: str = field(metadata={"wire": "name"})
|
|
72
|
+
is_active: bool = field(metadata={"wire": "isActive"})
|
|
73
|
+
quota: BranchQuota = field(metadata={"wire": "quota"})
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(kw_only=True)
|
|
77
|
+
class BranchQuota(Model):
|
|
78
|
+
"""BranchQuota wire fields. Unknown enum strings are preserved."""
|
|
79
|
+
|
|
80
|
+
used: int = field(metadata={"wire": "used"})
|
|
81
|
+
total_used: int = field(metadata={"wire": "totalUsed"})
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(kw_only=True)
|
|
85
|
+
class InfoAccount(Model):
|
|
86
|
+
"""InfoAccount wire fields. Unknown enum strings are preserved."""
|
|
87
|
+
|
|
88
|
+
email: str = field(metadata={"wire": "email"})
|
|
89
|
+
credit: float = field(metadata={"wire": "credit"})
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass(kw_only=True)
|
|
93
|
+
class InfoProduct(Model):
|
|
94
|
+
"""InfoProduct wire fields. Unknown enum strings are preserved."""
|
|
95
|
+
|
|
96
|
+
name: str = field(metadata={"wire": "name"})
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass(kw_only=True)
|
|
100
|
+
class BankSlipResult(Model):
|
|
101
|
+
"""BankSlipResult wire fields. Unknown enum strings are preserved."""
|
|
102
|
+
|
|
103
|
+
remark: str | UnsetType = field(metadata={"wire": "remark"}, default=UNSET)
|
|
104
|
+
is_duplicate: bool | UnsetType = field(metadata={"wire": "isDuplicate"}, default=UNSET)
|
|
105
|
+
matched_account: MatchedAccount | None | UnsetType = field(
|
|
106
|
+
metadata={"wire": "matchedAccount"}, default=UNSET
|
|
107
|
+
)
|
|
108
|
+
amount_in_order: float | UnsetType = field(metadata={"wire": "amountInOrder"}, default=UNSET)
|
|
109
|
+
amount_in_slip: float = field(metadata={"wire": "amountInSlip"})
|
|
110
|
+
is_amount_matched: bool | UnsetType = field(metadata={"wire": "isAmountMatched"}, default=UNSET)
|
|
111
|
+
raw_slip: BankSlip = field(metadata={"wire": "rawSlip"})
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass(kw_only=True)
|
|
115
|
+
class TrueWalletResult(Model):
|
|
116
|
+
"""TrueWalletResult wire fields. Unknown enum strings are preserved."""
|
|
117
|
+
|
|
118
|
+
remark: str | UnsetType = field(metadata={"wire": "remark"}, default=UNSET)
|
|
119
|
+
is_duplicate: bool | UnsetType = field(metadata={"wire": "isDuplicate"}, default=UNSET)
|
|
120
|
+
matched_account: MatchedAccount | None | UnsetType = field(
|
|
121
|
+
metadata={"wire": "matchedAccount"}, default=UNSET
|
|
122
|
+
)
|
|
123
|
+
amount_in_order: float | UnsetType = field(metadata={"wire": "amountInOrder"}, default=UNSET)
|
|
124
|
+
amount_in_slip: float = field(metadata={"wire": "amountInSlip"})
|
|
125
|
+
is_amount_matched: bool | UnsetType = field(metadata={"wire": "isAmountMatched"}, default=UNSET)
|
|
126
|
+
raw_slip: TrueWalletSlip = field(metadata={"wire": "rawSlip"})
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@dataclass(kw_only=True)
|
|
130
|
+
class BankSlip(Model):
|
|
131
|
+
"""BankSlip wire fields. Unknown enum strings are preserved."""
|
|
132
|
+
|
|
133
|
+
payload: str = field(metadata={"wire": "payload"})
|
|
134
|
+
trans_ref: str = field(metadata={"wire": "transRef"})
|
|
135
|
+
date: str = field(metadata={"wire": "date"})
|
|
136
|
+
country_code: str = field(metadata={"wire": "countryCode"})
|
|
137
|
+
amount: SlipAmount = field(metadata={"wire": "amount"})
|
|
138
|
+
fee: float | UnsetType = field(metadata={"wire": "fee"}, default=UNSET)
|
|
139
|
+
ref1: str | UnsetType = field(metadata={"wire": "ref1"}, default=UNSET)
|
|
140
|
+
ref2: str | UnsetType = field(metadata={"wire": "ref2"}, default=UNSET)
|
|
141
|
+
ref3: str | UnsetType = field(metadata={"wire": "ref3"}, default=UNSET)
|
|
142
|
+
sender: SlipParty = field(metadata={"wire": "sender"})
|
|
143
|
+
receiver: SlipReceiver = field(metadata={"wire": "receiver"})
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass(kw_only=True)
|
|
147
|
+
class SlipAmount(Model):
|
|
148
|
+
"""SlipAmount wire fields. Unknown enum strings are preserved."""
|
|
149
|
+
|
|
150
|
+
amount: float = field(metadata={"wire": "amount"})
|
|
151
|
+
local: LocalAmount = field(metadata={"wire": "local"})
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass(kw_only=True)
|
|
155
|
+
class LocalAmount(Model):
|
|
156
|
+
"""LocalAmount wire fields. Unknown enum strings are preserved."""
|
|
157
|
+
|
|
158
|
+
amount: float | UnsetType = field(metadata={"wire": "amount"}, default=UNSET)
|
|
159
|
+
currency: str | UnsetType = field(metadata={"wire": "currency"}, default=UNSET)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@dataclass(kw_only=True)
|
|
163
|
+
class SlipReceiver(Model):
|
|
164
|
+
"""SlipReceiver wire fields. Unknown enum strings are preserved."""
|
|
165
|
+
|
|
166
|
+
bank: SlipReceiverBank | UnsetType = field(metadata={"wire": "bank"}, default=UNSET)
|
|
167
|
+
account: SlipReceiverAccount = field(metadata={"wire": "account"})
|
|
168
|
+
merchant_id: str | None | UnsetType = field(metadata={"wire": "merchantId"}, default=UNSET)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@dataclass(kw_only=True)
|
|
172
|
+
class SlipReceiverBank(Model):
|
|
173
|
+
"""SlipReceiverBank wire fields. Unknown enum strings are preserved."""
|
|
174
|
+
|
|
175
|
+
id: str | UnsetType = field(metadata={"wire": "id"}, default=UNSET)
|
|
176
|
+
name: str | UnsetType = field(metadata={"wire": "name"}, default=UNSET)
|
|
177
|
+
short: str | UnsetType = field(metadata={"wire": "short"}, default=UNSET)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass(kw_only=True)
|
|
181
|
+
class SlipReceiverAccount(Model):
|
|
182
|
+
"""SlipReceiverAccount wire fields. Unknown enum strings are preserved."""
|
|
183
|
+
|
|
184
|
+
name: SlipReceiverAccountName = field(metadata={"wire": "name"})
|
|
185
|
+
bank: AccountNumber | UnsetType = field(metadata={"wire": "bank"}, default=UNSET)
|
|
186
|
+
proxy: AccountNumber | UnsetType = field(metadata={"wire": "proxy"}, default=UNSET)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@dataclass(kw_only=True)
|
|
190
|
+
class SlipReceiverAccountName(Model):
|
|
191
|
+
"""SlipReceiverAccountName wire fields. Unknown enum strings are preserved."""
|
|
192
|
+
|
|
193
|
+
th: str | UnsetType = field(metadata={"wire": "th"}, default=UNSET)
|
|
194
|
+
en: str | UnsetType = field(metadata={"wire": "en"}, default=UNSET)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass(kw_only=True)
|
|
198
|
+
class SlipParty(Model):
|
|
199
|
+
"""SlipParty wire fields. Unknown enum strings are preserved."""
|
|
200
|
+
|
|
201
|
+
bank: SlipBank | UnsetType = field(metadata={"wire": "bank"}, default=UNSET)
|
|
202
|
+
account: SlipAccount = field(metadata={"wire": "account"})
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@dataclass(kw_only=True)
|
|
206
|
+
class SlipBank(Model):
|
|
207
|
+
"""SlipBank wire fields. Unknown enum strings are preserved."""
|
|
208
|
+
|
|
209
|
+
id: str | UnsetType = field(metadata={"wire": "id"}, default=UNSET)
|
|
210
|
+
name: str | UnsetType = field(metadata={"wire": "name"}, default=UNSET)
|
|
211
|
+
short: str | UnsetType = field(metadata={"wire": "short"}, default=UNSET)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass(kw_only=True)
|
|
215
|
+
class SlipAccount(Model):
|
|
216
|
+
"""SlipAccount wire fields. Unknown enum strings are preserved."""
|
|
217
|
+
|
|
218
|
+
name: AccountName = field(metadata={"wire": "name"})
|
|
219
|
+
bank: AccountNumber | UnsetType = field(metadata={"wire": "bank"}, default=UNSET)
|
|
220
|
+
proxy: AccountNumber | UnsetType = field(metadata={"wire": "proxy"}, default=UNSET)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@dataclass(kw_only=True)
|
|
224
|
+
class AccountName(Model):
|
|
225
|
+
"""AccountName wire fields. Unknown enum strings are preserved."""
|
|
226
|
+
|
|
227
|
+
th: str | UnsetType = field(metadata={"wire": "th"}, default=UNSET)
|
|
228
|
+
en: str | UnsetType = field(metadata={"wire": "en"}, default=UNSET)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@dataclass(kw_only=True)
|
|
232
|
+
class AccountNumber(Model):
|
|
233
|
+
"""AccountNumber wire fields. Unknown enum strings are preserved."""
|
|
234
|
+
|
|
235
|
+
type: str = field(metadata={"wire": "type"})
|
|
236
|
+
account: str = field(metadata={"wire": "account"})
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@dataclass(kw_only=True)
|
|
240
|
+
class MatchedAccount(Model):
|
|
241
|
+
"""MatchedAccount wire fields. Unknown enum strings are preserved."""
|
|
242
|
+
|
|
243
|
+
bank: MatchedBank = field(metadata={"wire": "bank"})
|
|
244
|
+
name_th: str = field(metadata={"wire": "nameTh"})
|
|
245
|
+
name_en: str = field(metadata={"wire": "nameEn"})
|
|
246
|
+
type: str = field(metadata={"wire": "type"})
|
|
247
|
+
bank_number: str = field(metadata={"wire": "bankNumber"})
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@dataclass(kw_only=True)
|
|
251
|
+
class MatchedBank(Model):
|
|
252
|
+
"""MatchedBank wire fields. Unknown enum strings are preserved."""
|
|
253
|
+
|
|
254
|
+
name_th: str | UnsetType = field(metadata={"wire": "nameTh"}, default=UNSET)
|
|
255
|
+
name_en: str | UnsetType = field(metadata={"wire": "nameEn"}, default=UNSET)
|
|
256
|
+
code: str | UnsetType = field(metadata={"wire": "code"}, default=UNSET)
|
|
257
|
+
short_code: str | UnsetType = field(metadata={"wire": "shortCode"}, default=UNSET)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@dataclass(kw_only=True)
|
|
261
|
+
class TrueWalletSlip(Model):
|
|
262
|
+
"""TrueWalletSlip wire fields. Unknown enum strings are preserved."""
|
|
263
|
+
|
|
264
|
+
transaction_id: str = field(metadata={"wire": "transactionId"})
|
|
265
|
+
date: str = field(metadata={"wire": "date"})
|
|
266
|
+
amount: float = field(metadata={"wire": "amount"})
|
|
267
|
+
sender: TrueWalletSender = field(metadata={"wire": "sender"})
|
|
268
|
+
receiver: TrueWalletReceiver = field(metadata={"wire": "receiver"})
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@dataclass(kw_only=True)
|
|
272
|
+
class TrueWalletSender(Model):
|
|
273
|
+
"""TrueWalletSender wire fields. Unknown enum strings are preserved."""
|
|
274
|
+
|
|
275
|
+
name: str = field(metadata={"wire": "name"})
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@dataclass(kw_only=True)
|
|
279
|
+
class TrueWalletReceiver(Model):
|
|
280
|
+
"""TrueWalletReceiver wire fields. Unknown enum strings are preserved."""
|
|
281
|
+
|
|
282
|
+
name: str = field(metadata={"wire": "name"})
|
|
283
|
+
phone: str = field(metadata={"wire": "phone"})
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass(kw_only=True)
|
|
287
|
+
class Bank(Model):
|
|
288
|
+
"""Bank wire fields. Unknown enum strings are preserved."""
|
|
289
|
+
|
|
290
|
+
code: str = field(metadata={"wire": "code"})
|
|
291
|
+
name_th: str = field(metadata={"wire": "nameTh"})
|
|
292
|
+
name_en: str = field(metadata={"wire": "nameEn"})
|
|
293
|
+
short_code: str = field(metadata={"wire": "shortCode"})
|
|
294
|
+
swift_code: str = field(metadata={"wire": "swiftCode"})
|
|
295
|
+
extra_verify: list[ExtraVerifyOption] | None = field(metadata={"wire": "extraVerify"})
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@dataclass(kw_only=True)
|
|
299
|
+
class ExtraVerifyOption(Model):
|
|
300
|
+
"""ExtraVerifyOption wire fields. Unknown enum strings are preserved."""
|
|
301
|
+
|
|
302
|
+
value: str = field(metadata={"wire": "value"})
|
|
303
|
+
label: str = field(metadata={"wire": "label"})
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@dataclass(kw_only=True)
|
|
307
|
+
class BankAccount(Model):
|
|
308
|
+
"""BankAccount wire fields. Unknown enum strings are preserved."""
|
|
309
|
+
|
|
310
|
+
id: int = field(metadata={"wire": "id"})
|
|
311
|
+
bank_code: str = field(metadata={"wire": "bankCode"})
|
|
312
|
+
bank_number: str = field(metadata={"wire": "bankNumber"})
|
|
313
|
+
name_th: str = field(metadata={"wire": "nameTh"})
|
|
314
|
+
name_en: str = field(metadata={"wire": "nameEn"})
|
|
315
|
+
type: str = field(metadata={"wire": "type"})
|
|
316
|
+
extra_verify: str | None = field(metadata={"wire": "extraVerify"})
|
|
317
|
+
match_mode: str | None = field(metadata={"wire": "matchMode"})
|
|
318
|
+
created_at: str = field(metadata={"wire": "createdAt"})
|
|
319
|
+
updated_at: str = field(metadata={"wire": "updatedAt"})
|
|
320
|
+
deleted_at: str | None = field(metadata={"wire": "deletedAt"})
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@dataclass(kw_only=True)
|
|
324
|
+
class BankAccountPage(Model):
|
|
325
|
+
"""BankAccountPage wire fields. Unknown enum strings are preserved."""
|
|
326
|
+
|
|
327
|
+
items: list[BankAccount] = field(metadata={"wire": "items"})
|
|
328
|
+
total: int = field(metadata={"wire": "total"})
|
|
329
|
+
page: int = field(metadata={"wire": "page"})
|
|
330
|
+
limit: int = field(metadata={"wire": "limit"})
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@dataclass(kw_only=True)
|
|
334
|
+
class LinkResult(Model):
|
|
335
|
+
"""LinkResult wire fields. Unknown enum strings are preserved."""
|
|
336
|
+
|
|
337
|
+
linked: bool = field(metadata={"wire": "linked"})
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
@dataclass(kw_only=True)
|
|
341
|
+
class UnlinkResult(Model):
|
|
342
|
+
"""UnlinkResult wire fields. Unknown enum strings are preserved."""
|
|
343
|
+
|
|
344
|
+
unlinked: bool = field(metadata={"wire": "unlinked"})
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
@dataclass(kw_only=True)
|
|
348
|
+
class JobSubmission(Model):
|
|
349
|
+
"""JobSubmission wire fields. Unknown enum strings are preserved."""
|
|
350
|
+
|
|
351
|
+
job_id: str = field(metadata={"wire": "jobId"})
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@dataclass(kw_only=True)
|
|
355
|
+
class BatchSubmission(Model):
|
|
356
|
+
"""BatchSubmission wire fields. Unknown enum strings are preserved."""
|
|
357
|
+
|
|
358
|
+
batch_id: str = field(metadata={"wire": "batchId"})
|
|
359
|
+
jobs: list[BatchJob] = field(metadata={"wire": "jobs"})
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@dataclass(kw_only=True)
|
|
363
|
+
class BatchJob(Model):
|
|
364
|
+
"""BatchJob wire fields. Unknown enum strings are preserved."""
|
|
365
|
+
|
|
366
|
+
job_id: str = field(metadata={"wire": "jobId"})
|
|
367
|
+
index: int = field(metadata={"wire": "index"})
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@dataclass(kw_only=True)
|
|
371
|
+
class Job(Model):
|
|
372
|
+
"""Job wire fields. Unknown enum strings are preserved."""
|
|
373
|
+
|
|
374
|
+
job_id: str = field(metadata={"wire": "jobId"})
|
|
375
|
+
batch_id: str | UnsetType = field(metadata={"wire": "batchId"}, default=UNSET)
|
|
376
|
+
status: str = field(metadata={"wire": "status"})
|
|
377
|
+
result: JobResult | UnsetType = field(metadata={"wire": "result"}, default=UNSET)
|
|
378
|
+
error: JobError | UnsetType = field(metadata={"wire": "error"}, default=UNSET)
|
|
379
|
+
attempts: int = field(metadata={"wire": "attempts"})
|
|
380
|
+
created_at: str = field(metadata={"wire": "createdAt"})
|
|
381
|
+
updated_at: str = field(metadata={"wire": "updatedAt"})
|
|
382
|
+
branch_id: int | UnsetType = field(metadata={"wire": "branchId"}, default=UNSET)
|
|
383
|
+
service_id: int | UnsetType = field(metadata={"wire": "serviceId"}, default=UNSET)
|
|
384
|
+
callback_event_id: str | UnsetType = field(metadata={"wire": "callbackEventId"}, default=UNSET)
|
|
385
|
+
callback_protocol: int | UnsetType = field(metadata={"wire": "callbackProtocol"}, default=UNSET)
|
|
386
|
+
callback_delivery: CallbackDelivery | UnsetType = field(
|
|
387
|
+
metadata={"wire": "callbackDelivery"}, default=UNSET
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
@dataclass(kw_only=True)
|
|
392
|
+
class JobResult(Model):
|
|
393
|
+
"""JobResult wire fields. Unknown enum strings are preserved."""
|
|
394
|
+
|
|
395
|
+
status: str = field(metadata={"wire": "status"})
|
|
396
|
+
data: BankSlipResult | None = field(metadata={"wire": "data"})
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@dataclass(kw_only=True)
|
|
400
|
+
class JobError(Model):
|
|
401
|
+
"""JobError wire fields. Unknown enum strings are preserved."""
|
|
402
|
+
|
|
403
|
+
code: str | UnsetType = field(metadata={"wire": "code"}, default=UNSET)
|
|
404
|
+
message: str | UnsetType = field(metadata={"wire": "message"}, default=UNSET)
|
|
405
|
+
webhook: str | UnsetType = field(metadata={"wire": "webhook"}, default=UNSET)
|
|
406
|
+
url: str | UnsetType = field(metadata={"wire": "url"}, default=UNSET)
|
|
407
|
+
status: int | UnsetType = field(metadata={"wire": "status"}, default=UNSET)
|
|
408
|
+
at: str | UnsetType = field(metadata={"wire": "at"}, default=UNSET)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@dataclass(kw_only=True)
|
|
412
|
+
class CallbackDelivery(Model):
|
|
413
|
+
"""CallbackDelivery wire fields. Unknown enum strings are preserved."""
|
|
414
|
+
|
|
415
|
+
state: str | None = field(metadata={"wire": "state"})
|
|
416
|
+
http_status: int | None = field(metadata={"wire": "httpStatus"})
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
@dataclass(kw_only=True)
|
|
420
|
+
class WebhookEvent(Model):
|
|
421
|
+
"""WebhookEvent wire fields. Unknown enum strings are preserved."""
|
|
422
|
+
|
|
423
|
+
job_id: str = field(metadata={"wire": "jobId"})
|
|
424
|
+
batch_id: str | None = field(metadata={"wire": "batchId"})
|
|
425
|
+
status: str = field(metadata={"wire": "status"})
|
|
426
|
+
data: BankSlipResult | None = field(metadata={"wire": "data"})
|
|
427
|
+
error: WebhookError | UnsetType = field(metadata={"wire": "error"}, default=UNSET)
|
|
428
|
+
timestamp: str = field(metadata={"wire": "timestamp"})
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
@dataclass(kw_only=True)
|
|
432
|
+
class WebhookError(Model):
|
|
433
|
+
"""WebhookError wire fields. Unknown enum strings are preserved."""
|
|
434
|
+
|
|
435
|
+
code: str = field(metadata={"wire": "code"})
|
|
436
|
+
message: str = field(metadata={"wire": "message"})
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
@dataclass(kw_only=True)
|
|
440
|
+
class V1Me(Model):
|
|
441
|
+
"""V1Me wire fields. Unknown enum strings are preserved."""
|
|
442
|
+
|
|
443
|
+
application: str = field(metadata={"wire": "application"})
|
|
444
|
+
used_quota: int = field(metadata={"wire": "usedQuota"})
|
|
445
|
+
max_quota: int | None = field(metadata={"wire": "maxQuota"})
|
|
446
|
+
remaining_quota: int | None = field(metadata={"wire": "remainingQuota"})
|
|
447
|
+
expired_at: str | None = field(metadata={"wire": "expiredAt"})
|
|
448
|
+
current_credit: float = field(metadata={"wire": "currentCredit"})
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
@dataclass(kw_only=True)
|
|
452
|
+
class QrCode(Model):
|
|
453
|
+
"""QrCode wire fields. Unknown enum strings are preserved."""
|
|
454
|
+
|
|
455
|
+
image: str = field(metadata={"wire": "image"})
|
|
456
|
+
mime: str = field(metadata={"wire": "mime"})
|
|
457
|
+
payload: str = field(metadata={"wire": "payload"})
|
|
458
|
+
|
|
459
|
+
def image_bytes(self) -> bytes:
|
|
460
|
+
"""Decode the base64 PNG image."""
|
|
461
|
+
return base64.b64decode(self.image, validate=True)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@dataclass(kw_only=True)
|
|
465
|
+
class VerifyOptions(Model):
|
|
466
|
+
"""VerifyOptions wire fields. Unknown enum strings are preserved."""
|
|
467
|
+
|
|
468
|
+
remark: str | UnsetType = field(metadata={"wire": "remark"}, default=UNSET)
|
|
469
|
+
match_account: bool | UnsetType = field(metadata={"wire": "matchAccount"}, default=UNSET)
|
|
470
|
+
match_amount: float | UnsetType = field(metadata={"wire": "matchAmount"}, default=UNSET)
|
|
471
|
+
check_duplicate: bool | UnsetType = field(metadata={"wire": "checkDuplicate"}, default=UNSET)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
@dataclass(kw_only=True)
|
|
475
|
+
class CreateBankAccountParams(Model):
|
|
476
|
+
"""CreateBankAccountParams wire fields. Unknown enum strings are preserved."""
|
|
477
|
+
|
|
478
|
+
bank_code: str = field(metadata={"wire": "bankCode"})
|
|
479
|
+
bank_number: str = field(metadata={"wire": "bankNumber"})
|
|
480
|
+
name_th: str = field(metadata={"wire": "nameTh"})
|
|
481
|
+
name_en: str = field(metadata={"wire": "nameEn"})
|
|
482
|
+
type: AccountType = field(metadata={"wire": "type"})
|
|
483
|
+
extra_verify: str | UnsetType = field(metadata={"wire": "extraVerify"}, default=UNSET)
|
|
484
|
+
match_mode: str | UnsetType = field(metadata={"wire": "matchMode"}, default=UNSET)
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
@dataclass(kw_only=True)
|
|
488
|
+
class UpdateBankAccountParams(Model):
|
|
489
|
+
"""UpdateBankAccountParams wire fields. Unknown enum strings are preserved."""
|
|
490
|
+
|
|
491
|
+
bank_code: str | UnsetType = field(metadata={"wire": "bankCode"}, default=UNSET)
|
|
492
|
+
bank_number: str | UnsetType = field(metadata={"wire": "bankNumber"}, default=UNSET)
|
|
493
|
+
name_th: str | UnsetType = field(metadata={"wire": "nameTh"}, default=UNSET)
|
|
494
|
+
name_en: str | UnsetType = field(metadata={"wire": "nameEn"}, default=UNSET)
|
|
495
|
+
type: AccountType | UnsetType = field(metadata={"wire": "type"}, default=UNSET)
|
|
496
|
+
extra_verify: str | None | UnsetType = field(metadata={"wire": "extraVerify"}, default=UNSET)
|
|
497
|
+
match_mode: str | UnsetType = field(metadata={"wire": "matchMode"}, default=UNSET)
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
@dataclass(kw_only=True)
|
|
501
|
+
class BatchSlip(Model):
|
|
502
|
+
"""BatchSlip wire fields. Unknown enum strings are preserved."""
|
|
503
|
+
|
|
504
|
+
remark: str | UnsetType = field(metadata={"wire": "remark"}, default=UNSET)
|
|
505
|
+
match_account: bool | UnsetType = field(metadata={"wire": "matchAccount"}, default=UNSET)
|
|
506
|
+
match_amount: float | UnsetType = field(metadata={"wire": "matchAmount"}, default=UNSET)
|
|
507
|
+
check_duplicate: bool | UnsetType = field(metadata={"wire": "checkDuplicate"}, default=UNSET)
|
|
508
|
+
payload: str = field(metadata={"wire": "payload"})
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
@dataclass(kw_only=True)
|
|
512
|
+
class AsyncVerifyOptions(Model):
|
|
513
|
+
"""AsyncVerifyOptions wire fields. Unknown enum strings are preserved."""
|
|
514
|
+
|
|
515
|
+
remark: str | UnsetType = field(metadata={"wire": "remark"}, default=UNSET)
|
|
516
|
+
match_account: bool | UnsetType = field(metadata={"wire": "matchAccount"}, default=UNSET)
|
|
517
|
+
match_amount: float | UnsetType = field(metadata={"wire": "matchAmount"}, default=UNSET)
|
|
518
|
+
check_duplicate: bool | UnsetType = field(metadata={"wire": "checkDuplicate"}, default=UNSET)
|
|
519
|
+
callback_url: str | UnsetType = field(metadata={"wire": "callbackUrl"}, default=UNSET)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
@dataclass(kw_only=True)
|
|
523
|
+
class BatchOptions(Model):
|
|
524
|
+
"""BatchOptions wire fields. Unknown enum strings are preserved."""
|
|
525
|
+
|
|
526
|
+
callback_url: str | UnsetType = field(metadata={"wire": "callbackUrl"}, default=UNSET)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@dataclass(kw_only=True)
|
|
530
|
+
class V1VerifyOptions(Model):
|
|
531
|
+
"""V1VerifyOptions wire fields. Unknown enum strings are preserved."""
|
|
532
|
+
|
|
533
|
+
check_duplicate: bool | UnsetType = field(metadata={"wire": "checkDuplicate"}, default=UNSET)
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@dataclass(kw_only=True)
|
|
537
|
+
class ListBankAccountsParams(Model):
|
|
538
|
+
"""ListBankAccountsParams wire fields. Unknown enum strings are preserved."""
|
|
539
|
+
|
|
540
|
+
type: AccountType | UnsetType = field(metadata={"wire": "type"}, default=UNSET)
|
|
541
|
+
bank_code: str | UnsetType = field(metadata={"wire": "bankCode"}, default=UNSET)
|
|
542
|
+
page: int | UnsetType = field(metadata={"wire": "page"}, default=UNSET)
|
|
543
|
+
limit: int | UnsetType = field(metadata={"wire": "limit"}, default=UNSET)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
@dataclass(kw_only=True)
|
|
547
|
+
class QrRequest(Model):
|
|
548
|
+
"""QrRequest wire fields. Unknown enum strings are preserved.
|
|
549
|
+
|
|
550
|
+
One flat model for every `type`; the API checks the combinations. With `biller_id`, `ref1`
|
|
551
|
+
is optional and `ref2` needs `ref1`. KSHOP `ref1` is the shop id KB + 12 digits, MAE_MANEE
|
|
552
|
+
`ref1` the 15-digit shop id. TUNGNGERN needs `merchant_name`, the English shop name. Fields
|
|
553
|
+
are sent as given.
|
|
554
|
+
"""
|
|
555
|
+
|
|
556
|
+
type: QrType = field(metadata={"wire": "type"})
|
|
557
|
+
msisdn: str | UnsetType = field(metadata={"wire": "msisdn"}, default=UNSET)
|
|
558
|
+
nat_id: str | UnsetType = field(metadata={"wire": "natId"}, default=UNSET)
|
|
559
|
+
e_wallet_id: str | UnsetType = field(metadata={"wire": "eWalletId"}, default=UNSET)
|
|
560
|
+
biller_id: str | UnsetType = field(metadata={"wire": "billerId"}, default=UNSET)
|
|
561
|
+
ref1: str | UnsetType = field(metadata={"wire": "ref1"}, default=UNSET)
|
|
562
|
+
ref2: str | UnsetType = field(metadata={"wire": "ref2"}, default=UNSET)
|
|
563
|
+
amount: float | UnsetType = field(metadata={"wire": "amount"}, default=UNSET)
|
|
564
|
+
merchant_name: str | UnsetType = field(metadata={"wire": "merchantName"}, default=UNSET)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
@dataclass(kw_only=True)
|
|
568
|
+
class RateLimit(Model):
|
|
569
|
+
"""RateLimit wire fields. Unknown enum strings are preserved."""
|
|
570
|
+
|
|
571
|
+
limit: int = field(metadata={"wire": "limit"})
|
|
572
|
+
remaining: int = field(metadata={"wire": "remaining"})
|
|
573
|
+
reset: int = field(metadata={"wire": "reset"})
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
@dataclass(kw_only=True)
|
|
577
|
+
class ResponseMeta(Model):
|
|
578
|
+
"""ResponseMeta wire fields. Unknown enum strings are preserved."""
|
|
579
|
+
|
|
580
|
+
status: int = field(metadata={"wire": "status"})
|
|
581
|
+
request_id: str | None = field(metadata={"wire": "requestId"})
|
|
582
|
+
message: str | None = field(metadata={"wire": "message"})
|
|
583
|
+
rate_limit: RateLimit | None = field(metadata={"wire": "rateLimit"})
|
|
584
|
+
headers: dict[str, str] = field(metadata={"wire": "headers"})
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@dataclass(kw_only=True)
|
|
588
|
+
class BankList(Model):
|
|
589
|
+
"""Iterable bank catalog, serialized as a plain array."""
|
|
590
|
+
|
|
591
|
+
items: list[Bank]
|
|
592
|
+
|
|
593
|
+
def __iter__(self) -> Iterator[Bank]:
|
|
594
|
+
return iter(self.items)
|
|
595
|
+
|
|
596
|
+
def __len__(self) -> int:
|
|
597
|
+
return len(self.items)
|
|
598
|
+
|
|
599
|
+
def to_dict(self) -> list[Any]:
|
|
600
|
+
return [encode(item) for item in self.items]
|
thunder_slip/py.typed
ADDED
|
File without changes
|
thunder_slip/webhook.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Raw-body signature primitives; typed webhook models follow the shared spec."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import hmac
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def verify_signature(raw_body: bytes | str, signature: str | None, secret: str) -> bool:
|
|
10
|
+
"""Verify a sha256= hexadecimal HMAC over the exact raw UTF-8 body."""
|
|
11
|
+
if not secret or not signature or not signature.startswith("sha256="):
|
|
12
|
+
return False
|
|
13
|
+
digest = signature[7:]
|
|
14
|
+
if len(digest) != 64 or any(c not in "0123456789abcdef" for c in digest):
|
|
15
|
+
return False
|
|
16
|
+
body = raw_body.encode("utf8") if isinstance(raw_body, str) else raw_body
|
|
17
|
+
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
|
|
18
|
+
return hmac.compare_digest(expected, digest)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_webhook(raw_body: bytes) -> dict[str, Any]:
|
|
22
|
+
"""Decode an object; verify its raw signature before trusting it."""
|
|
23
|
+
value: Any = json.loads(raw_body)
|
|
24
|
+
if not isinstance(value, dict):
|
|
25
|
+
raise ValueError("Webhook body must be an object")
|
|
26
|
+
return value
|
thunder_slip/webhooks.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Standalone webhook authentication and typed event parsing."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from .webhook import verify_signature as verify_signature
|
|
5
|
+
from ._codec import DecodeError, decode
|
|
6
|
+
from .models import WebhookEvent
|
|
7
|
+
from .errors import InputError, WebhookSignatureError
|
|
8
|
+
|
|
9
|
+
SIGNATURE_HEADER: str = "X-Thunder-Signature"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parse_event(raw_body: bytes | str) -> WebhookEvent:
|
|
13
|
+
"""Parse the original UTF-8 body without verifying its signature."""
|
|
14
|
+
try:
|
|
15
|
+
return decode(WebhookEvent, json.loads(raw_body))
|
|
16
|
+
except (json.JSONDecodeError, UnicodeDecodeError, DecodeError):
|
|
17
|
+
pass
|
|
18
|
+
raise InputError("INVALID_ARGUMENT", "Webhook body must be a valid event JSON object")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def construct_event(raw_body: bytes | str, signature: str | None, secret: str) -> WebhookEvent:
|
|
22
|
+
"""Verify HMAC before parsing, or raise WebhookSignatureError."""
|
|
23
|
+
if not verify_signature(raw_body, signature, secret):
|
|
24
|
+
raise WebhookSignatureError("Invalid webhook signature")
|
|
25
|
+
return parse_event(raw_body)
|