tappay 0.5.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.
- tappay/__init__.py +16 -0
- tappay/client.py +303 -0
- tappay/exceptions.py +19 -0
- tappay/models.py +50 -0
- tappay-0.5.0.dist-info/METADATA +130 -0
- tappay-0.5.0.dist-info/RECORD +9 -0
- tappay-0.5.0.dist-info/WHEEL +5 -0
- tappay-0.5.0.dist-info/licenses/LICENSE.txt +24 -0
- tappay-0.5.0.dist-info/top_level.txt +1 -0
tappay/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
__version__ = "0.5.0"
|
|
3
|
+
|
|
4
|
+
from tappay.client import Client
|
|
5
|
+
from tappay.models import Models
|
|
6
|
+
from tappay.exceptions import Exceptions, Error, ClientError, ServerError, AuthenticationError
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Client",
|
|
10
|
+
"Models",
|
|
11
|
+
"Exceptions",
|
|
12
|
+
"Error",
|
|
13
|
+
"ClientError",
|
|
14
|
+
"ServerError",
|
|
15
|
+
"AuthenticationError",
|
|
16
|
+
]
|
tappay/client.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from platform import python_version
|
|
4
|
+
from typing import Optional, Dict, Any, Union
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from tappay.models import Models
|
|
9
|
+
from tappay.exceptions import Exceptions
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
# We need to access __version__ from somewhere, commonly from a package level or hardcoded here then imported.
|
|
14
|
+
# For now I will hardcode it here or pass it in.
|
|
15
|
+
# Better yet, I will define __version__ in __init__.py and import it here? No, circular import.
|
|
16
|
+
# I will put __version__ in a separate file or keep it in __init__ and pass it to Client if needed,
|
|
17
|
+
# or just duplicate/move it.
|
|
18
|
+
# Let's define it in client.py for now to avoid circular dependency if __init__ imports client.
|
|
19
|
+
# Actually, the original code used it in User-Agent.
|
|
20
|
+
VERSION = "0.5.0"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Client:
|
|
24
|
+
"""Client for interacting with the TapPay API."""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
is_sandbox: bool,
|
|
29
|
+
partner_key: Optional[str] = None,
|
|
30
|
+
merchant_id: Optional[str] = None,
|
|
31
|
+
app_name: Optional[str] = None,
|
|
32
|
+
app_version: Optional[str] = None,
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Create a Client object to start making calls to TapPay APIs.
|
|
36
|
+
|
|
37
|
+
:param bool is_sandbox: Define runtime environment (sandbox or production)
|
|
38
|
+
:param str partner_key: Your TapPay partner key (optional)
|
|
39
|
+
:param str merchant_id: Your TapPay merchant ID (optional)
|
|
40
|
+
:param str app_name: This optional value is added to the user-agent header
|
|
41
|
+
:param str app_version: This optional value is added to the user-agent header
|
|
42
|
+
"""
|
|
43
|
+
if not isinstance(is_sandbox, bool):
|
|
44
|
+
raise TypeError(
|
|
45
|
+
f"expected bool for parameter `is_sandbox`, {type(is_sandbox)} found"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self.partner_key = partner_key or os.environ.get("TAPPAY_PARTNER_KEY")
|
|
49
|
+
self.merchant_id = merchant_id or os.environ.get("TAPPAY_MERCHANT_ID")
|
|
50
|
+
|
|
51
|
+
if self.partner_key is None:
|
|
52
|
+
raise ValueError("Missing required value for `partner_key`")
|
|
53
|
+
if self.merchant_id is None:
|
|
54
|
+
raise ValueError("Missing required value for `merchant_id`")
|
|
55
|
+
|
|
56
|
+
subdomain = "sandbox" if is_sandbox else "prod"
|
|
57
|
+
self.api_host = f"{subdomain}.tappaysdk.com"
|
|
58
|
+
|
|
59
|
+
user_agent = f"tappay-python/{VERSION} python/{python_version()}"
|
|
60
|
+
|
|
61
|
+
if app_name and app_version:
|
|
62
|
+
user_agent += f" {app_name}/{app_version}"
|
|
63
|
+
|
|
64
|
+
self.headers = {
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
"User-Agent": user_agent,
|
|
67
|
+
"x-api-key": self.partner_key,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
def pay_by_prime(
|
|
71
|
+
self,
|
|
72
|
+
prime: str,
|
|
73
|
+
amount: int,
|
|
74
|
+
details: str,
|
|
75
|
+
card_holder_data: Models.CardHolderData,
|
|
76
|
+
**kwargs: Any,
|
|
77
|
+
) -> Dict[str, Any]:
|
|
78
|
+
"""
|
|
79
|
+
Make a payment using "prime" obtained from TapPay frontend SDK
|
|
80
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/back.html#pay-by-prime-api
|
|
81
|
+
"""
|
|
82
|
+
if not isinstance(card_holder_data, Models.CardHolderData):
|
|
83
|
+
raise TypeError(
|
|
84
|
+
f"expected `CardHolderData` type for parameter `card_holder_data`, {type(card_holder_data)} found"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
params = {
|
|
88
|
+
"prime": prime,
|
|
89
|
+
"amount": amount,
|
|
90
|
+
"currency": Models.Currencies.TWD,
|
|
91
|
+
"details": details,
|
|
92
|
+
"cardholder": card_holder_data.to_dict(),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if kwargs:
|
|
96
|
+
params.update(**kwargs)
|
|
97
|
+
|
|
98
|
+
return self.__post_with_partner_key_and_merchant_id(
|
|
99
|
+
"/tpc/payment/pay-by-prime", params
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def pay_by_token(
|
|
103
|
+
self,
|
|
104
|
+
card_key: str,
|
|
105
|
+
card_token: str,
|
|
106
|
+
amount: int,
|
|
107
|
+
details: str,
|
|
108
|
+
**kwargs: Any,
|
|
109
|
+
) -> Dict[str, Any]:
|
|
110
|
+
"""
|
|
111
|
+
Make a payment using previously obtained card secrets (key & token)
|
|
112
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/back.html#pay-by-card-token-api
|
|
113
|
+
"""
|
|
114
|
+
params = {
|
|
115
|
+
"card_key": card_key,
|
|
116
|
+
"card_token": card_token,
|
|
117
|
+
"amount": amount,
|
|
118
|
+
"currency": Models.Currencies.TWD,
|
|
119
|
+
"details": details,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if kwargs:
|
|
123
|
+
params.update(**kwargs)
|
|
124
|
+
|
|
125
|
+
return self.__post_with_partner_key_and_merchant_id(
|
|
126
|
+
"/tpc/payment/pay-by-token", params
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def refund(
|
|
130
|
+
self, rec_trade_id: str, amount: int, **kwargs: Any
|
|
131
|
+
) -> Dict[str, Any]:
|
|
132
|
+
"""
|
|
133
|
+
Refund a payment
|
|
134
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/back.html#refund-api
|
|
135
|
+
"""
|
|
136
|
+
params = {
|
|
137
|
+
"rec_trade_id": rec_trade_id,
|
|
138
|
+
"amount": amount,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if kwargs:
|
|
142
|
+
params.update(**kwargs)
|
|
143
|
+
|
|
144
|
+
return self.__post_with_partner_key("/tpc/transaction/refund", params)
|
|
145
|
+
|
|
146
|
+
def get_records(
|
|
147
|
+
self,
|
|
148
|
+
filters_dict: Dict[str, Any],
|
|
149
|
+
page: int = 0,
|
|
150
|
+
records_per_page: int = 50,
|
|
151
|
+
order_by_dict: Optional[Dict[str, Any]] = None,
|
|
152
|
+
) -> Dict[str, Any]:
|
|
153
|
+
"""
|
|
154
|
+
Query historical records
|
|
155
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/back.html#record-api
|
|
156
|
+
"""
|
|
157
|
+
params = {
|
|
158
|
+
"records_per_page": records_per_page,
|
|
159
|
+
"page": page,
|
|
160
|
+
"filters": filters_dict,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if order_by_dict:
|
|
164
|
+
params["order_by"] = order_by_dict
|
|
165
|
+
|
|
166
|
+
return self.__post_with_partner_key("/tpc/transaction/query", params)
|
|
167
|
+
|
|
168
|
+
def capture_today(self, rec_trade_id: str) -> Dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
Capture specific payment record
|
|
171
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#cap-today-api
|
|
172
|
+
"""
|
|
173
|
+
params = {
|
|
174
|
+
"rec_trade_id": rec_trade_id,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return self.__post_with_partner_key("/tpc/transaction/cap", params)
|
|
178
|
+
|
|
179
|
+
def cancel_capture(self, rec_trade_id: str) -> Dict[str, Any]:
|
|
180
|
+
"""
|
|
181
|
+
Cancel a specific capture
|
|
182
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#cap-cancel-api
|
|
183
|
+
"""
|
|
184
|
+
params = {
|
|
185
|
+
"rec_trade_id": rec_trade_id,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return self.__post_with_partner_key("/tpc/transaction/cap/cancel", params)
|
|
189
|
+
|
|
190
|
+
def get_trade_history(self, rec_trade_id: str) -> Dict[str, Any]:
|
|
191
|
+
"""
|
|
192
|
+
Get record and status of a specific transaction
|
|
193
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#trade-history-api
|
|
194
|
+
"""
|
|
195
|
+
params = {
|
|
196
|
+
"rec_trade_id": rec_trade_id,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return self.__post_with_partner_key(
|
|
200
|
+
"/tpc/transaction/trade-history", params
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def bind_card(
|
|
204
|
+
self,
|
|
205
|
+
prime: str,
|
|
206
|
+
card_holder_data: Models.CardHolderData,
|
|
207
|
+
**kwargs: Any,
|
|
208
|
+
) -> Dict[str, Any]:
|
|
209
|
+
"""
|
|
210
|
+
Bind new credit card
|
|
211
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#bind-card-api
|
|
212
|
+
"""
|
|
213
|
+
if not isinstance(card_holder_data, Models.CardHolderData):
|
|
214
|
+
raise TypeError(
|
|
215
|
+
f"expected `CardHolderData` type for parameter `card_holder_data`, {type(card_holder_data)} found"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
params = {
|
|
219
|
+
"prime": prime,
|
|
220
|
+
"currency": Models.Currencies.TWD,
|
|
221
|
+
"cardholder": card_holder_data.to_dict(),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if kwargs:
|
|
225
|
+
params.update(**kwargs)
|
|
226
|
+
|
|
227
|
+
return self.__post_with_partner_key_and_merchant_id(
|
|
228
|
+
"/tpc/card/bind", params
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def remove_card(self, card_key: str, card_token: str) -> Dict[str, Any]:
|
|
232
|
+
"""
|
|
233
|
+
Remove bound credit card
|
|
234
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#remove-card-api
|
|
235
|
+
"""
|
|
236
|
+
params = {
|
|
237
|
+
"card_key": card_key,
|
|
238
|
+
"card_token": card_token,
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return self.__post_with_partner_key("/tpc/card/remove", params)
|
|
242
|
+
|
|
243
|
+
def cancel_refund(
|
|
244
|
+
self, rec_trade_id: str, **kwargs: Any
|
|
245
|
+
) -> Dict[str, Any]:
|
|
246
|
+
"""
|
|
247
|
+
Cancel a single refund
|
|
248
|
+
Ref: https://docs.tappaysdk.com/tutorial/zh/advanced.html#refund-cancel-api
|
|
249
|
+
"""
|
|
250
|
+
params = {
|
|
251
|
+
"rec_trade_id": rec_trade_id,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if kwargs:
|
|
255
|
+
params.update(**kwargs)
|
|
256
|
+
|
|
257
|
+
return self.__post_with_partner_key(
|
|
258
|
+
"/tpc/transaction/refund/cancel", params
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
def __post_with_partner_key(
|
|
262
|
+
self, request_uri: str, params: Dict[str, Any]
|
|
263
|
+
) -> Dict[str, Any]:
|
|
264
|
+
params = dict(params, partner_key=self.partner_key)
|
|
265
|
+
return self.__post(request_uri, params)
|
|
266
|
+
|
|
267
|
+
def __post_with_partner_key_and_merchant_id(
|
|
268
|
+
self, request_uri: str, params: Dict[str, Any]
|
|
269
|
+
) -> Dict[str, Any]:
|
|
270
|
+
params = dict(params, merchant_id=self.merchant_id)
|
|
271
|
+
return self.__post_with_partner_key(request_uri, params)
|
|
272
|
+
|
|
273
|
+
def __post(self, request_uri: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
274
|
+
uri = f"https://{self.api_host}{request_uri}"
|
|
275
|
+
params = dict(params)
|
|
276
|
+
|
|
277
|
+
logger.debug(f"POST to: {uri}")
|
|
278
|
+
logger.debug(f"POST headers: {self.headers}")
|
|
279
|
+
logger.debug(f"POST params: {params}")
|
|
280
|
+
|
|
281
|
+
response = requests.post(uri, json=params, headers=self.headers)
|
|
282
|
+
return self.__parse(response)
|
|
283
|
+
|
|
284
|
+
def __parse(self, response: requests.Response) -> Optional[Dict[str, Any]]:
|
|
285
|
+
logger.debug(f"response status: {response.status_code}")
|
|
286
|
+
logger.debug(f"response content: {response.content}")
|
|
287
|
+
|
|
288
|
+
if response.status_code == 401:
|
|
289
|
+
raise Exceptions.AuthenticationError
|
|
290
|
+
elif response.status_code == 204:
|
|
291
|
+
return None
|
|
292
|
+
elif 200 <= response.status_code < 300:
|
|
293
|
+
return response.json()
|
|
294
|
+
elif 400 <= response.status_code < 500:
|
|
295
|
+
message = f"{response.status_code} response from {self.api_host}"
|
|
296
|
+
raise Exceptions.ClientError(message)
|
|
297
|
+
elif 500 <= response.status_code < 600:
|
|
298
|
+
message = f"{response.status_code} response from {self.api_host}"
|
|
299
|
+
raise Exceptions.ServerError(message)
|
|
300
|
+
|
|
301
|
+
# Fallback for unexpected status codes
|
|
302
|
+
message = f"Unexpected status code {response.status_code} from {self.api_host}"
|
|
303
|
+
raise Exceptions.ServerError(message)
|
tappay/exceptions.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
class Error(Exception):
|
|
3
|
+
"""Base exception for all TapPay errors."""
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ClientError(Error):
|
|
8
|
+
"""Error raised when the client sends an invalid request."""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ServerError(Error):
|
|
13
|
+
"""Error raised when the TapPay server encounters an issue."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AuthenticationError(ClientError):
|
|
18
|
+
"""Error raised when authentication fails."""
|
|
19
|
+
pass
|
tappay/models.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import Optional, Dict, Any
|
|
2
|
+
|
|
3
|
+
class Models:
|
|
4
|
+
"""Namespace for TapPay models."""
|
|
5
|
+
|
|
6
|
+
class Currencies:
|
|
7
|
+
"""Currency constants."""
|
|
8
|
+
TWD = "TWD"
|
|
9
|
+
|
|
10
|
+
class CardHolderData:
|
|
11
|
+
"""Card holder data model."""
|
|
12
|
+
|
|
13
|
+
phone_number: Optional[str] = None
|
|
14
|
+
name: Optional[str] = None
|
|
15
|
+
email: Optional[str] = None
|
|
16
|
+
zip_code: Optional[str] = None
|
|
17
|
+
address: Optional[str] = None
|
|
18
|
+
national_id: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
phone_number: str,
|
|
23
|
+
name: str,
|
|
24
|
+
email: str,
|
|
25
|
+
zip_code: Optional[str] = None,
|
|
26
|
+
address: Optional[str] = None,
|
|
27
|
+
national_id: Optional[str] = None,
|
|
28
|
+
):
|
|
29
|
+
self.phone_number = phone_number
|
|
30
|
+
self.name = name
|
|
31
|
+
self.email = email
|
|
32
|
+
self.zip_code = zip_code
|
|
33
|
+
self.address = address
|
|
34
|
+
self.national_id = national_id
|
|
35
|
+
|
|
36
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
37
|
+
result_dict = {
|
|
38
|
+
"phone_number": self.phone_number,
|
|
39
|
+
"name": self.name,
|
|
40
|
+
"email": self.email,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if self.zip_code:
|
|
44
|
+
result_dict["zip_code"] = self.zip_code
|
|
45
|
+
if self.address:
|
|
46
|
+
result_dict["address"] = self.address
|
|
47
|
+
if self.national_id:
|
|
48
|
+
result_dict["national_id"] = self.national_id
|
|
49
|
+
|
|
50
|
+
return result_dict
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tappay
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: TapPay Client Library for Python
|
|
5
|
+
Author-email: Shih Wei Chris Lo <shihwei@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/shihweilo/tappay-python
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/shihweilo/tappay-python/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE.txt
|
|
22
|
+
Requires-Dist: requests>=2.4.2
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# TapPay Python SDK
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
[](https://badge.fury.io/py/tappay)
|
|
30
|
+
[](https://pypi.org/project/tappay/)
|
|
31
|
+
[](https://github.com/psf/black)
|
|
32
|
+
[](https://opensource.org/licenses/MIT)
|
|
33
|
+
|
|
34
|
+
> [!IMPORTANT]
|
|
35
|
+
> **Python 2 Support Dropped**: As of version 0.5.0, this library no longer supports Python 2.7. Please use Python 3.8 or newer.
|
|
36
|
+
|
|
37
|
+
This is the unofficial Python client library for TapPay's Backend API. To use it you'll need a TapPay account. Sign up at [tappaysdk.com](https://www.tappaysdk.com).
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Install using pip:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install tappay
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### Initialization
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import tappay
|
|
53
|
+
|
|
54
|
+
# Initialize the client
|
|
55
|
+
client = tappay.Client(
|
|
56
|
+
is_sandbox=True,
|
|
57
|
+
partner_key="YOUR_PARTNER_KEY",
|
|
58
|
+
merchant_id="YOUR_MERCHANT_ID"
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For production, you can set `TAPPAY_PARTNER_KEY` and `TAPPAY_MERCHANT_ID` environment variables and omit them in the constructor:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
client = tappay.Client(is_sandbox=False)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Pay by Prime
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# Create cardholder data
|
|
72
|
+
card_holder = tappay.Models.CardHolderData(
|
|
73
|
+
phone_number="0912345678",
|
|
74
|
+
name="Wang Xiao Ming",
|
|
75
|
+
email="test@example.com"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Make payment
|
|
79
|
+
response = client.pay_by_prime(
|
|
80
|
+
prime="prime_token_from_frontend",
|
|
81
|
+
amount=100,
|
|
82
|
+
details="Order #123",
|
|
83
|
+
card_holder_data=card_holder
|
|
84
|
+
)
|
|
85
|
+
print(response)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Pay by Token
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
response = client.pay_by_token(
|
|
92
|
+
card_key="card_key",
|
|
93
|
+
card_token="card_token",
|
|
94
|
+
amount=100,
|
|
95
|
+
details="Subscription"
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Refunds
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
response = client.refund(
|
|
103
|
+
rec_trade_id="rec_trade_id",
|
|
104
|
+
amount=100
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For more API details, please refer to the [TapPay Backend API Documentation](https://docs.tappaysdk.com/tutorial/zh/back.html).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
### Setup
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git clone https://github.com/shihweilo/tappay-python.git
|
|
116
|
+
cd tappay-python
|
|
117
|
+
pip install -e ".[dev]"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Testing
|
|
121
|
+
|
|
122
|
+
Run tests using pytest:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pytest
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Contributing
|
|
129
|
+
|
|
130
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
tappay/__init__.py,sha256=CFV-ZoZJR5DKe-vfABPMQOTLYQaYEfaJyOGZFpyqGV0,324
|
|
2
|
+
tappay/client.py,sha256=8j_1yCGK5ZF3Eaqb1bn78dqgDw54As861HrRfNSVbbE,10131
|
|
3
|
+
tappay/exceptions.py,sha256=_kfkoAuvsLVehkIZ4ucOu8zVWCB4PBTikmm8YgBmcik,389
|
|
4
|
+
tappay/models.py,sha256=F364tteyUNB3ZBnBKgOOPwMv26BxVNoUOXQlaRIWS54,1461
|
|
5
|
+
tappay-0.5.0.dist-info/licenses/LICENSE.txt,sha256=CpgTk30a7F04kGiQypkY-PXWUWAKwbzrE7qTO93roxE,1084
|
|
6
|
+
tappay-0.5.0.dist-info/METADATA,sha256=4hVfermPUwkV7sWk6PKYEgOqmIhRoBv4AfgGBdxhR1E,3324
|
|
7
|
+
tappay-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
+
tappay-0.5.0.dist-info/top_level.txt,sha256=GZaMpi1PiPG4IbGyB3mN0M0L-pNZDuaUTP3-5u8QQ3E,7
|
|
9
|
+
tappay-0.5.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Shih Wei Chris Lo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
|
6
|
+
obtaining a copy of this software and associated documentation
|
|
7
|
+
files (the "Software"), to deal in the Software without
|
|
8
|
+
restriction, including without limitation the rights to use,
|
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the
|
|
11
|
+
Software is furnished to do so, subject to the following
|
|
12
|
+
conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be
|
|
15
|
+
included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tappay
|