tingee-sdk 0.4.0__tar.gz
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.
- tingee_sdk-0.4.0/PKG-INFO +146 -0
- tingee_sdk-0.4.0/README.md +129 -0
- tingee_sdk-0.4.0/pyproject.toml +31 -0
- tingee_sdk-0.4.0/setup.cfg +4 -0
- tingee_sdk-0.4.0/src/tingee_sdk/__init__.py +53 -0
- tingee_sdk-0.4.0/src/tingee_sdk/bank_constants.py +92 -0
- tingee_sdk-0.4.0/src/tingee_sdk/client.py +76 -0
- tingee_sdk-0.4.0/src/tingee_sdk/generated_methods.py +593 -0
- tingee_sdk-0.4.0/src/tingee_sdk/http.py +109 -0
- tingee_sdk-0.4.0/src/tingee_sdk/models.py +1522 -0
- tingee_sdk-0.4.0/src/tingee_sdk/py.typed +0 -0
- tingee_sdk-0.4.0/src/tingee_sdk/response.py +17 -0
- tingee_sdk-0.4.0/src/tingee_sdk/signature.py +209 -0
- tingee_sdk-0.4.0/src/tingee_sdk/version.py +2 -0
- tingee_sdk-0.4.0/src/tingee_sdk.egg-info/PKG-INFO +146 -0
- tingee_sdk-0.4.0/src/tingee_sdk.egg-info/SOURCES.txt +17 -0
- tingee_sdk-0.4.0/src/tingee_sdk.egg-info/dependency_links.txt +1 -0
- tingee_sdk-0.4.0/src/tingee_sdk.egg-info/top_level.txt +1 -0
- tingee_sdk-0.4.0/tests/test_signature.py +185 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tingee-sdk
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Tingee Open API SDK for Python
|
|
5
|
+
Author-email: Tingee <developer@heno.vn>
|
|
6
|
+
License: ISC
|
|
7
|
+
Project-URL: Homepage, https://developers.tingee.vn
|
|
8
|
+
Project-URL: Documentation, https://developers.tingee.vn/docs/sdk
|
|
9
|
+
Project-URL: Repository, https://github.com/tingeehub/tingee-python
|
|
10
|
+
Project-URL: Issues, https://github.com/tingeehub/tingee-python/issues
|
|
11
|
+
Keywords: tingee,sdk,payment,api
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# tingee-sdk (Python)
|
|
19
|
+
|
|
20
|
+
> SDK chính thức tích hợp **Tingee Open API** cho Python
|
|
21
|
+
|
|
22
|
+
Python ≥ 3.8, không phụ thuộc thư viện ngoài.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Cài đặt
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install tingee-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Bắt đầu nhanh
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import os
|
|
38
|
+
from tingee_sdk import TingeeClient, is_success_response
|
|
39
|
+
|
|
40
|
+
client = TingeeClient(
|
|
41
|
+
secret_key=os.environ["TINGEE_SECRET_KEY"],
|
|
42
|
+
client_id=os.environ["TINGEE_CLIENT_ID"],
|
|
43
|
+
environment="uat", # hoặc "production" (mặc định)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
result = client.bank.get_banks()
|
|
47
|
+
if is_success_response(result):
|
|
48
|
+
print(result["data"])
|
|
49
|
+
|
|
50
|
+
result = client.bank.generate_viet_qr({
|
|
51
|
+
"bankName": "OCB",
|
|
52
|
+
"accountNumber": "0123456789",
|
|
53
|
+
"amount": 100000,
|
|
54
|
+
"content": "Thanh toan don hang",
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Method được nhóm theo path: `/v1/bank/create-va` → `client.bank.create_va(body)`, `/v1/deep-link/generate` → `client.deep_link.generate(body)`.
|
|
59
|
+
- Body và query truyền dạng `dict`, tên field giữ nguyên như API (camelCase). Kiểu DTO (TypedDict) nằm trong `tingee_sdk.models`.
|
|
60
|
+
- SDK tự ký request (`x-signature`, `x-request-timestamp`, `x-client-id`).
|
|
61
|
+
|
|
62
|
+
> **Lưu ý:** SDK trả về `dict` có `code` và `message`. Kiểm tra `code == "00"` hoặc `is_success_response(result)` để xác định thành công — SDK **không tự raise** khi `code != "00"`. Lỗi HTTP (non-2xx), lỗi mạng và timeout raise `TingeeHttpError`.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Xác thực Webhook
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Flask
|
|
70
|
+
from flask import Flask, request
|
|
71
|
+
|
|
72
|
+
app = Flask(__name__)
|
|
73
|
+
|
|
74
|
+
@app.post("/webhook/tingee")
|
|
75
|
+
def tingee_webhook():
|
|
76
|
+
result = client.verify_webhook_signature(
|
|
77
|
+
request.headers.get("x-signature"),
|
|
78
|
+
request.headers.get("x-request-timestamp"),
|
|
79
|
+
request.get_data(), # raw body
|
|
80
|
+
)
|
|
81
|
+
if result["code"] != "00":
|
|
82
|
+
return {"error": result["message"]}, 401
|
|
83
|
+
|
|
84
|
+
body = request.get_json()
|
|
85
|
+
# Xử lý giao dịch...
|
|
86
|
+
return {"received": True}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Hoặc dùng hàm `verify_webhook_signature(secret_token, signature, timestamp, body)` với secret token riêng.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Xác thực URL webhook
|
|
94
|
+
|
|
95
|
+
Khi lưu URL webhook trên Tingee, hệ thống gửi một request xác thực vào URL đó:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{ "event": "url-validation", "plainToken": "<chuỗi ngẫu nhiên>", "timestamp": 1730000000000 }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Endpoint phải trả về HTTP 200 với `{ "plainToken": "...", "encryptedToken": "..." }`, trong đó `encryptedToken = HMAC-SHA256(secretToken, plainToken)` dạng hex. `secretToken` là secret của **API Key loại Xác thực webhook** đang bật (tạo trong mục API Credentials).
|
|
102
|
+
|
|
103
|
+
SDK làm sẵn bước này: hàm trả về body cần phản hồi, hoặc `None` nếu không phải request xác thực. Gọi **trước** khi verify chữ ký, vì body xác thực không có các trường giao dịch.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from tingee_sdk import create_url_validation_response
|
|
107
|
+
|
|
108
|
+
@app.post("/webhook/tingee")
|
|
109
|
+
def tingee_webhook():
|
|
110
|
+
validation = create_url_validation_response(os.environ["TINGEE_WEBHOOK_SECRET"], request.get_data())
|
|
111
|
+
if validation is not None:
|
|
112
|
+
return validation
|
|
113
|
+
|
|
114
|
+
# Verify chữ ký & xử lý giao dịch như bình thường...
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Nếu dùng chung khóa với client: `client.create_url_validation_response(request.get_data())`.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Bank Constants
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from tingee_sdk import BankNameEnum, get_bank_code, get_bank_short_name, get_bank_bin
|
|
125
|
+
|
|
126
|
+
get_bank_code("970436") # BankNameEnum.VCB
|
|
127
|
+
get_bank_short_name("970436") # 'Vietcombank'
|
|
128
|
+
get_bank_bin(BankNameEnum.VCB) # '970436'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Liên hệ & Hỗ trợ
|
|
134
|
+
|
|
135
|
+
📧 **Email:** [developer@heno.vn](mailto:developer@heno.vn)
|
|
136
|
+
💬 **Telegram:** [@tingeesupport](https://t.me/tingeesupport)
|
|
137
|
+
🌐 **Website:** [tingee.vn](https://tingee.vn)
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Xem thêm
|
|
142
|
+
|
|
143
|
+
- [CHANGELOG](./CHANGELOG.md)
|
|
144
|
+
- [Tài liệu Tingee Open API](https://open-api.tingee.vn)
|
|
145
|
+
- [Tài liệu Tingee Developer](https://developers.tingee.vn)
|
|
146
|
+
- [Trang chủ Tingee](https://tingee.vn)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# tingee-sdk (Python)
|
|
2
|
+
|
|
3
|
+
> SDK chính thức tích hợp **Tingee Open API** cho Python
|
|
4
|
+
|
|
5
|
+
Python ≥ 3.8, không phụ thuộc thư viện ngoài.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Cài đặt
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install tingee-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Bắt đầu nhanh
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import os
|
|
21
|
+
from tingee_sdk import TingeeClient, is_success_response
|
|
22
|
+
|
|
23
|
+
client = TingeeClient(
|
|
24
|
+
secret_key=os.environ["TINGEE_SECRET_KEY"],
|
|
25
|
+
client_id=os.environ["TINGEE_CLIENT_ID"],
|
|
26
|
+
environment="uat", # hoặc "production" (mặc định)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
result = client.bank.get_banks()
|
|
30
|
+
if is_success_response(result):
|
|
31
|
+
print(result["data"])
|
|
32
|
+
|
|
33
|
+
result = client.bank.generate_viet_qr({
|
|
34
|
+
"bankName": "OCB",
|
|
35
|
+
"accountNumber": "0123456789",
|
|
36
|
+
"amount": 100000,
|
|
37
|
+
"content": "Thanh toan don hang",
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Method được nhóm theo path: `/v1/bank/create-va` → `client.bank.create_va(body)`, `/v1/deep-link/generate` → `client.deep_link.generate(body)`.
|
|
42
|
+
- Body và query truyền dạng `dict`, tên field giữ nguyên như API (camelCase). Kiểu DTO (TypedDict) nằm trong `tingee_sdk.models`.
|
|
43
|
+
- SDK tự ký request (`x-signature`, `x-request-timestamp`, `x-client-id`).
|
|
44
|
+
|
|
45
|
+
> **Lưu ý:** SDK trả về `dict` có `code` và `message`. Kiểm tra `code == "00"` hoặc `is_success_response(result)` để xác định thành công — SDK **không tự raise** khi `code != "00"`. Lỗi HTTP (non-2xx), lỗi mạng và timeout raise `TingeeHttpError`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Xác thực Webhook
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# Flask
|
|
53
|
+
from flask import Flask, request
|
|
54
|
+
|
|
55
|
+
app = Flask(__name__)
|
|
56
|
+
|
|
57
|
+
@app.post("/webhook/tingee")
|
|
58
|
+
def tingee_webhook():
|
|
59
|
+
result = client.verify_webhook_signature(
|
|
60
|
+
request.headers.get("x-signature"),
|
|
61
|
+
request.headers.get("x-request-timestamp"),
|
|
62
|
+
request.get_data(), # raw body
|
|
63
|
+
)
|
|
64
|
+
if result["code"] != "00":
|
|
65
|
+
return {"error": result["message"]}, 401
|
|
66
|
+
|
|
67
|
+
body = request.get_json()
|
|
68
|
+
# Xử lý giao dịch...
|
|
69
|
+
return {"received": True}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Hoặc dùng hàm `verify_webhook_signature(secret_token, signature, timestamp, body)` với secret token riêng.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Xác thực URL webhook
|
|
77
|
+
|
|
78
|
+
Khi lưu URL webhook trên Tingee, hệ thống gửi một request xác thực vào URL đó:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{ "event": "url-validation", "plainToken": "<chuỗi ngẫu nhiên>", "timestamp": 1730000000000 }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Endpoint phải trả về HTTP 200 với `{ "plainToken": "...", "encryptedToken": "..." }`, trong đó `encryptedToken = HMAC-SHA256(secretToken, plainToken)` dạng hex. `secretToken` là secret của **API Key loại Xác thực webhook** đang bật (tạo trong mục API Credentials).
|
|
85
|
+
|
|
86
|
+
SDK làm sẵn bước này: hàm trả về body cần phản hồi, hoặc `None` nếu không phải request xác thực. Gọi **trước** khi verify chữ ký, vì body xác thực không có các trường giao dịch.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from tingee_sdk import create_url_validation_response
|
|
90
|
+
|
|
91
|
+
@app.post("/webhook/tingee")
|
|
92
|
+
def tingee_webhook():
|
|
93
|
+
validation = create_url_validation_response(os.environ["TINGEE_WEBHOOK_SECRET"], request.get_data())
|
|
94
|
+
if validation is not None:
|
|
95
|
+
return validation
|
|
96
|
+
|
|
97
|
+
# Verify chữ ký & xử lý giao dịch như bình thường...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Nếu dùng chung khóa với client: `client.create_url_validation_response(request.get_data())`.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Bank Constants
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from tingee_sdk import BankNameEnum, get_bank_code, get_bank_short_name, get_bank_bin
|
|
108
|
+
|
|
109
|
+
get_bank_code("970436") # BankNameEnum.VCB
|
|
110
|
+
get_bank_short_name("970436") # 'Vietcombank'
|
|
111
|
+
get_bank_bin(BankNameEnum.VCB) # '970436'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Liên hệ & Hỗ trợ
|
|
117
|
+
|
|
118
|
+
📧 **Email:** [developer@heno.vn](mailto:developer@heno.vn)
|
|
119
|
+
💬 **Telegram:** [@tingeesupport](https://t.me/tingeesupport)
|
|
120
|
+
🌐 **Website:** [tingee.vn](https://tingee.vn)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Xem thêm
|
|
125
|
+
|
|
126
|
+
- [CHANGELOG](./CHANGELOG.md)
|
|
127
|
+
- [Tài liệu Tingee Open API](https://open-api.tingee.vn)
|
|
128
|
+
- [Tài liệu Tingee Developer](https://developers.tingee.vn)
|
|
129
|
+
- [Trang chủ Tingee](https://tingee.vn)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tingee-sdk"
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "Tingee Open API SDK for Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "ISC" }
|
|
12
|
+
authors = [{ name = "Tingee", email = "developer@heno.vn" }]
|
|
13
|
+
keywords = ["tingee", "sdk", "payment", "api"]
|
|
14
|
+
dependencies = []
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://developers.tingee.vn"
|
|
23
|
+
Documentation = "https://developers.tingee.vn/docs/sdk"
|
|
24
|
+
Repository = "https://github.com/tingeehub/tingee-python"
|
|
25
|
+
Issues = "https://github.com/tingeehub/tingee-python/issues"
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src"]
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.package-data]
|
|
31
|
+
tingee_sdk = ["py.typed"]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tingee SDK for Python
|
|
3
|
+
|
|
4
|
+
Official SDK for Tingee Open API. DTO types are in ``tingee_sdk.models``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .bank_constants import (
|
|
8
|
+
BANKS,
|
|
9
|
+
BANKS_OBJECT,
|
|
10
|
+
BankAccountTypeEnum,
|
|
11
|
+
BankBinEnum,
|
|
12
|
+
BankNameEnum,
|
|
13
|
+
get_bank_bin,
|
|
14
|
+
get_bank_code,
|
|
15
|
+
get_bank_short_name,
|
|
16
|
+
)
|
|
17
|
+
from .client import ENVIRONMENT_URLS, TingeeClient, TingeeEnvironment
|
|
18
|
+
from .http import TingeeHttpError
|
|
19
|
+
from .response import TingeeApiResponse, is_error_response, is_success_response
|
|
20
|
+
from .signature import (
|
|
21
|
+
URL_VALIDATION_EVENT,
|
|
22
|
+
create_url_validation_response,
|
|
23
|
+
format_timestamp,
|
|
24
|
+
generate_signature,
|
|
25
|
+
verify_webhook_signature,
|
|
26
|
+
)
|
|
27
|
+
from .version import SDK_VERSION
|
|
28
|
+
|
|
29
|
+
__version__ = SDK_VERSION
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"TingeeClient",
|
|
33
|
+
"TingeeEnvironment",
|
|
34
|
+
"ENVIRONMENT_URLS",
|
|
35
|
+
"TingeeHttpError",
|
|
36
|
+
"TingeeApiResponse",
|
|
37
|
+
"is_success_response",
|
|
38
|
+
"is_error_response",
|
|
39
|
+
"generate_signature",
|
|
40
|
+
"format_timestamp",
|
|
41
|
+
"verify_webhook_signature",
|
|
42
|
+
"create_url_validation_response",
|
|
43
|
+
"URL_VALIDATION_EVENT",
|
|
44
|
+
"BankNameEnum",
|
|
45
|
+
"BankBinEnum",
|
|
46
|
+
"BankAccountTypeEnum",
|
|
47
|
+
"BANKS",
|
|
48
|
+
"BANKS_OBJECT",
|
|
49
|
+
"get_bank_code",
|
|
50
|
+
"get_bank_short_name",
|
|
51
|
+
"get_bank_bin",
|
|
52
|
+
"SDK_VERSION",
|
|
53
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Bank constants (same as the other SDKs)."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Dict, List, Optional, TypedDict
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"BankNameEnum",
|
|
8
|
+
"BankBinEnum",
|
|
9
|
+
"BankAccountTypeEnum",
|
|
10
|
+
"BankInfo",
|
|
11
|
+
"BANKS_OBJECT",
|
|
12
|
+
"BANKS",
|
|
13
|
+
"get_bank_code",
|
|
14
|
+
"get_bank_short_name",
|
|
15
|
+
"get_bank_bin",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BankNameEnum(str, Enum):
|
|
20
|
+
OCB = "OCB"
|
|
21
|
+
BIDV = "BIDV"
|
|
22
|
+
MBB = "MBB"
|
|
23
|
+
ACB = "ACB"
|
|
24
|
+
VPB = "VPB"
|
|
25
|
+
PGB = "PGB"
|
|
26
|
+
VIB = "VIB"
|
|
27
|
+
STB = "STB"
|
|
28
|
+
CTG = "CTG"
|
|
29
|
+
VCB = "VCB"
|
|
30
|
+
AGRIBANK = "AGRIBANK"
|
|
31
|
+
SHINHAN = "SHINHAN"
|
|
32
|
+
COB = "COB"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BankBinEnum(str, Enum):
|
|
36
|
+
OCB = "970448"
|
|
37
|
+
BIDV = "970418"
|
|
38
|
+
MBB = "970422"
|
|
39
|
+
ACB = "970416"
|
|
40
|
+
VPB = "970432"
|
|
41
|
+
PGB = "970430"
|
|
42
|
+
VIB = "970441"
|
|
43
|
+
STB = "970403"
|
|
44
|
+
CTG = "970415"
|
|
45
|
+
VCB = "970436"
|
|
46
|
+
AGRIBANK = "970405"
|
|
47
|
+
SHINHAN = "970424"
|
|
48
|
+
COB = "970446"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BankAccountTypeEnum(str, Enum):
|
|
52
|
+
PersonalAccount = "personal-account"
|
|
53
|
+
BusinessAccount = "business-account"
|
|
54
|
+
BusinessHouseHoldAccount = "business-household-account"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class BankInfo(TypedDict):
|
|
58
|
+
code: BankNameEnum
|
|
59
|
+
name: str
|
|
60
|
+
shortName: str
|
|
61
|
+
bin: str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
BANKS_OBJECT: Dict[BankNameEnum, BankInfo] = {
|
|
65
|
+
BankNameEnum.VCB: {"code": BankNameEnum.VCB, "name": "Ngân hàng TMCP Ngoại Thương Việt Nam", "bin": "970436", "shortName": "Vietcombank"},
|
|
66
|
+
BankNameEnum.CTG: {"code": BankNameEnum.CTG, "name": "Ngân hàng TMCP Công thương Việt Nam", "bin": "970415", "shortName": "VietinBank"},
|
|
67
|
+
BankNameEnum.BIDV: {"code": BankNameEnum.BIDV, "name": "Ngân hàng TMCP Đầu tư và Phát triển Việt Nam", "bin": "970418", "shortName": "BIDV"},
|
|
68
|
+
BankNameEnum.AGRIBANK: {"code": BankNameEnum.AGRIBANK, "name": "Ngân hàng Nông nghiệp và Phát triển Nông thôn Việt Nam", "bin": "970405", "shortName": "Agribank"},
|
|
69
|
+
BankNameEnum.MBB: {"code": BankNameEnum.MBB, "name": "Ngân hàng TMCP Quân đội", "bin": "970422", "shortName": "MB Bank"},
|
|
70
|
+
BankNameEnum.ACB: {"code": BankNameEnum.ACB, "name": "Ngân hàng TMCP Á Châu", "bin": "970416", "shortName": "ACB"},
|
|
71
|
+
BankNameEnum.OCB: {"code": BankNameEnum.OCB, "name": "Ngân hàng TMCP Phương Đông", "bin": "970448", "shortName": "OCB Bank"},
|
|
72
|
+
BankNameEnum.VPB: {"code": BankNameEnum.VPB, "name": "Ngân hàng TMCP Việt Nam Thịnh Vượng", "bin": "970432", "shortName": "VPBank"},
|
|
73
|
+
BankNameEnum.STB: {"code": BankNameEnum.STB, "name": "Ngân hàng TMCP Sài Gòn Thương Tín", "bin": "970403", "shortName": "Sacombank"},
|
|
74
|
+
BankNameEnum.VIB: {"code": BankNameEnum.VIB, "name": "Ngân hàng TMCP Quốc tế Việt Nam", "bin": "970441", "shortName": "VIB"},
|
|
75
|
+
BankNameEnum.PGB: {"code": BankNameEnum.PGB, "name": "Ngân Hàng TMCP Thịnh vượng và Phát triển", "bin": "970430", "shortName": "PGBank"},
|
|
76
|
+
BankNameEnum.SHINHAN: {"code": BankNameEnum.SHINHAN, "name": "Ngân hàng TNHH MTV Shinhan Việt Nam", "bin": "970424", "shortName": "Shinhan Bank"},
|
|
77
|
+
BankNameEnum.COB: {"code": BankNameEnum.COB, "name": "Ngân hàng Hợp tác Xã Việt Nam", "bin": "970446", "shortName": "Co-opBank"},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
BANKS: List[BankInfo] = list(BANKS_OBJECT.values())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_bank_code(bank_bin: str) -> Optional[BankNameEnum]:
|
|
84
|
+
return next((x["code"] for x in BANKS if x["bin"] == bank_bin), None)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_bank_short_name(bank_bin: str) -> Optional[str]:
|
|
88
|
+
return next((x["shortName"] for x in BANKS if x["bin"] == bank_bin), None)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_bank_bin(bank_name: BankNameEnum) -> Optional[str]:
|
|
92
|
+
return next((x["bin"] for x in BANKS if x["code"] == bank_name), None)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from typing import Any, Dict, Literal, Optional, Union
|
|
2
|
+
|
|
3
|
+
from .generated_methods import GeneratedMethods
|
|
4
|
+
from .http import TingeeHttpClient
|
|
5
|
+
from .signature import create_url_validation_response, verify_webhook_signature
|
|
6
|
+
|
|
7
|
+
__all__ = ["TingeeClient", "TingeeEnvironment", "ENVIRONMENT_URLS"]
|
|
8
|
+
|
|
9
|
+
TingeeEnvironment = Literal["production", "uat"]
|
|
10
|
+
|
|
11
|
+
ENVIRONMENT_URLS: Dict[str, str] = {
|
|
12
|
+
"production": "https://open-api.tingee.vn",
|
|
13
|
+
"uat": "https://uat-open-api.tingee.vn",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TingeeClient(GeneratedMethods):
|
|
18
|
+
"""
|
|
19
|
+
Tingee Open API client.
|
|
20
|
+
|
|
21
|
+
Example::
|
|
22
|
+
|
|
23
|
+
client = TingeeClient(secret_key="...", client_id="...", environment="uat")
|
|
24
|
+
result = client.bank.get_banks()
|
|
25
|
+
if result["code"] == "00":
|
|
26
|
+
print(result["data"])
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
secret_key: str,
|
|
32
|
+
client_id: str,
|
|
33
|
+
environment: TingeeEnvironment = "production",
|
|
34
|
+
timeout: float = 90,
|
|
35
|
+
base_url: Optional[str] = None,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
:param secret_key: Secret key for generating request signature
|
|
39
|
+
:param client_id: Client ID for API authentication
|
|
40
|
+
:param environment: ``production`` (default) or ``uat``
|
|
41
|
+
:param timeout: Request timeout in seconds (default 90)
|
|
42
|
+
:param base_url: Custom base URL (overrides environment)
|
|
43
|
+
"""
|
|
44
|
+
if not secret_key:
|
|
45
|
+
raise ValueError("secret_key is required")
|
|
46
|
+
if not client_id:
|
|
47
|
+
raise ValueError("client_id is required")
|
|
48
|
+
if environment not in ENVIRONMENT_URLS and not base_url:
|
|
49
|
+
raise ValueError("environment must be one of: {0}".format(", ".join(ENVIRONMENT_URLS)))
|
|
50
|
+
|
|
51
|
+
self._secret_key = secret_key
|
|
52
|
+
self._base_url = base_url or ENVIRONMENT_URLS[environment]
|
|
53
|
+
super().__init__(TingeeHttpClient(self._base_url, secret_key, client_id, timeout))
|
|
54
|
+
|
|
55
|
+
def get_base_url(self) -> str:
|
|
56
|
+
return self._base_url
|
|
57
|
+
|
|
58
|
+
def verify_webhook_signature(
|
|
59
|
+
self,
|
|
60
|
+
signature: Optional[str],
|
|
61
|
+
timestamp: Optional[str],
|
|
62
|
+
body: Union[Dict[str, Any], str, bytes, None],
|
|
63
|
+
) -> Dict[str, str]:
|
|
64
|
+
"""Verify an incoming Tingee webhook signature using this client's secret_key."""
|
|
65
|
+
return verify_webhook_signature(self._secret_key, signature, timestamp, body)
|
|
66
|
+
|
|
67
|
+
def create_url_validation_response(
|
|
68
|
+
self,
|
|
69
|
+
body: Union[Dict[str, Any], str, bytes, None],
|
|
70
|
+
secret_token: Optional[str] = None,
|
|
71
|
+
) -> Optional[Dict[str, str]]:
|
|
72
|
+
"""
|
|
73
|
+
Build the response for a webhook URL validation request, ``None`` if body is not one.
|
|
74
|
+
Pass ``secret_token`` when your "Webhook verification" credential differs from this client's.
|
|
75
|
+
"""
|
|
76
|
+
return create_url_validation_response(secret_token or self._secret_key, body)
|