paymentsgate 1.4.9__py3-none-any.whl → 1.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.
Potentially problematic release.
This version of paymentsgate might be problematic. Click here for more details.
- paymentsgate/client.py +117 -54
- paymentsgate/enums.py +57 -22
- paymentsgate/exceptions.py +2 -2
- paymentsgate/mappers.py +4 -0
- paymentsgate/models.py +144 -113
- paymentsgate/transport.py +5 -8
- paymentsgate/types.py +9 -0
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.0.dist-info}/METADATA +1 -1
- paymentsgate-1.5.0.dist-info/RECORD +15 -0
- paymentsgate-1.4.9.dist-info/RECORD +0 -13
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.0.dist-info}/LICENSE +0 -0
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.0.dist-info}/WHEEL +0 -0
paymentsgate/client.py
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import logging
|
|
3
|
-
from dataclasses import dataclass, is_dataclass, field, asdict
|
|
3
|
+
# from dataclasses import dataclass, is_dataclass, field, asdict
|
|
4
4
|
import json
|
|
5
5
|
from urllib.parse import urlencode
|
|
6
|
+
from pydantic import Field, BaseModel
|
|
6
7
|
|
|
7
|
-
from
|
|
8
|
+
from .types import TokenResponse
|
|
9
|
+
from .tokens import (
|
|
8
10
|
AccessToken,
|
|
9
11
|
RefreshToken
|
|
10
12
|
)
|
|
11
|
-
from
|
|
13
|
+
from .exceptions import (
|
|
12
14
|
APIResponseError,
|
|
13
15
|
APIAuthenticationError
|
|
14
16
|
)
|
|
15
|
-
from
|
|
17
|
+
from .models import (
|
|
16
18
|
Credentials,
|
|
17
19
|
GetQuoteModel,
|
|
18
20
|
GetQuoteResponseModel,
|
|
@@ -20,36 +22,35 @@ from paymentsgate.models import (
|
|
|
20
22
|
PayInResponseModel,
|
|
21
23
|
PayOutModel,
|
|
22
24
|
PayOutResponseModel,
|
|
23
|
-
InvoiceModel
|
|
25
|
+
InvoiceModel,
|
|
26
|
+
GetQuoteTlv,
|
|
27
|
+
PayOutTlvRequest,
|
|
28
|
+
QuoteTlvResponse,
|
|
24
29
|
)
|
|
25
|
-
from
|
|
26
|
-
from
|
|
30
|
+
from .enums import ApiPaths
|
|
31
|
+
from .transport import (
|
|
27
32
|
Request,
|
|
28
33
|
Response
|
|
29
34
|
)
|
|
30
|
-
from
|
|
31
|
-
from
|
|
35
|
+
from .logger import Logger
|
|
36
|
+
from .cache import (
|
|
32
37
|
AbstractCache,
|
|
33
38
|
DefaultCache
|
|
34
39
|
)
|
|
35
40
|
|
|
36
41
|
import requests
|
|
37
42
|
|
|
38
|
-
@dataclass
|
|
39
|
-
class ApiClient:
|
|
40
|
-
baseUrl: str = field(default="", init=False)
|
|
41
|
-
timeout: int = field(default=180, init=True)
|
|
42
|
-
logger: Logger = Logger
|
|
43
|
-
cache: AbstractCache = field(default_factory=DefaultCache)
|
|
44
|
-
config: Credentials = field(default_factory=dict, init=False)
|
|
45
|
-
|
|
46
|
-
REQUEST_DEBUG: bool = False
|
|
47
|
-
RESPONSE_DEBUG: bool = False
|
|
48
43
|
|
|
44
|
+
class ApiClient:
|
|
49
45
|
def __init__(self, config: Credentials, baseUrl: str, debug: bool=False):
|
|
50
46
|
self.config = config
|
|
51
47
|
self.cache = DefaultCache()
|
|
52
48
|
self.baseUrl = baseUrl
|
|
49
|
+
|
|
50
|
+
self.REQUEST_DEBUG = False
|
|
51
|
+
self.RESPONSE_DEBUG = False
|
|
52
|
+
self.timeout = 180
|
|
53
|
+
|
|
53
54
|
if debug:
|
|
54
55
|
logging.basicConfig(level=logging.DEBUG)
|
|
55
56
|
|
|
@@ -65,7 +66,7 @@ class ApiClient:
|
|
|
65
66
|
|
|
66
67
|
# Handle response
|
|
67
68
|
response = self._send_request(request)
|
|
68
|
-
self.
|
|
69
|
+
self.log(request, response)
|
|
69
70
|
if (response.success):
|
|
70
71
|
return response.cast(PayInResponseModel, APIResponseError)
|
|
71
72
|
else:
|
|
@@ -84,16 +85,34 @@ class ApiClient:
|
|
|
84
85
|
|
|
85
86
|
# Handle response
|
|
86
87
|
response = self._send_request(request)
|
|
87
|
-
self.
|
|
88
|
+
self.log(request, response)
|
|
88
89
|
if (response.success):
|
|
89
90
|
return response.cast(PayOutResponseModel, APIResponseError)
|
|
90
91
|
else:
|
|
91
92
|
raise APIResponseError(response)
|
|
92
93
|
|
|
94
|
+
def PayOutTlv(self, request: PayOutTlvRequest) -> PayOutResponseModel:
|
|
95
|
+
request = Request(
|
|
96
|
+
method="post",
|
|
97
|
+
path=ApiPaths.invoices_payout_tlv,
|
|
98
|
+
content_type='application/json',
|
|
99
|
+
noAuth=False,
|
|
100
|
+
signature=False,
|
|
101
|
+
body=request
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Handle response
|
|
105
|
+
response = self._send_request(request)
|
|
106
|
+
self.log(request, response)
|
|
107
|
+
if not response.success:
|
|
108
|
+
raise APIResponseError(response)
|
|
109
|
+
|
|
110
|
+
return response.cast(PayOutResponseModel, APIResponseError)
|
|
111
|
+
|
|
93
112
|
def Quote(self, params: GetQuoteModel) -> GetQuoteResponseModel:
|
|
94
113
|
# Prepare request
|
|
95
114
|
request = Request(
|
|
96
|
-
method="
|
|
115
|
+
method="post",
|
|
97
116
|
path=ApiPaths.fx_quote,
|
|
98
117
|
content_type='application/json',
|
|
99
118
|
noAuth=False,
|
|
@@ -103,12 +122,30 @@ class ApiClient:
|
|
|
103
122
|
|
|
104
123
|
# Handle response
|
|
105
124
|
response = self._send_request(request)
|
|
106
|
-
self.
|
|
125
|
+
self.log(request, response)
|
|
107
126
|
if not response.success:
|
|
108
127
|
raise APIResponseError(response)
|
|
109
128
|
|
|
110
129
|
return response.cast(GetQuoteResponseModel, APIResponseError)
|
|
111
130
|
|
|
131
|
+
def QuoteQr(self, params: GetQuoteTlv) -> QuoteTlvResponse:
|
|
132
|
+
request = Request(
|
|
133
|
+
method="post",
|
|
134
|
+
path=ApiPaths.fx_quote_tlv,
|
|
135
|
+
content_type='application/json',
|
|
136
|
+
noAuth=False,
|
|
137
|
+
signature=False,
|
|
138
|
+
body=params
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Handle response
|
|
142
|
+
response = self._send_request(request)
|
|
143
|
+
self.log(request, response)
|
|
144
|
+
if not response.success:
|
|
145
|
+
raise APIResponseError(response)
|
|
146
|
+
|
|
147
|
+
return response.cast(QuoteTlvResponse, APIResponseError)
|
|
148
|
+
|
|
112
149
|
def Status(self, id: str) -> InvoiceModel:
|
|
113
150
|
# Prepare request
|
|
114
151
|
request = Request(
|
|
@@ -121,7 +158,7 @@ class ApiClient:
|
|
|
121
158
|
|
|
122
159
|
# Handle response
|
|
123
160
|
response = self._send_request(request)
|
|
124
|
-
self.
|
|
161
|
+
self.log(request, response)
|
|
125
162
|
if not response.success:
|
|
126
163
|
raise APIResponseError(response)
|
|
127
164
|
|
|
@@ -130,23 +167,25 @@ class ApiClient:
|
|
|
130
167
|
@property
|
|
131
168
|
def token(self) -> AccessToken | None:
|
|
132
169
|
# First check if valid token is cached
|
|
133
|
-
token = self.cache.get_token('
|
|
134
|
-
refresh = self.cache.get_token('
|
|
170
|
+
token = self.cache.get_token('AccessToken')
|
|
171
|
+
refresh = self.cache.get_token('RefreshToken')
|
|
172
|
+
|
|
135
173
|
if token is not None and not token.is_expired:
|
|
136
174
|
return token
|
|
137
175
|
else:
|
|
138
176
|
# try to refresh token
|
|
139
177
|
if refresh is not None and not refresh.is_expired:
|
|
140
|
-
refreshed = self._refresh_token()
|
|
178
|
+
refreshed = self._refresh_token(token, refresh)
|
|
141
179
|
|
|
142
180
|
if (refreshed.success):
|
|
143
181
|
access = AccessToken(
|
|
144
|
-
|
|
182
|
+
refreshed.json_body["access_token"]
|
|
145
183
|
)
|
|
146
184
|
refresh = RefreshToken(
|
|
147
|
-
|
|
148
|
-
int(
|
|
185
|
+
refreshed.json_body["refresh_token"],
|
|
186
|
+
int(refreshed.json_body["expires_in"]),
|
|
149
187
|
)
|
|
188
|
+
|
|
150
189
|
self.cache.set_token(access)
|
|
151
190
|
self.cache.set_token(refresh)
|
|
152
191
|
|
|
@@ -157,12 +196,13 @@ class ApiClient:
|
|
|
157
196
|
if response.success:
|
|
158
197
|
|
|
159
198
|
access = AccessToken(
|
|
160
|
-
response.
|
|
199
|
+
response.json_body["access_token"]
|
|
161
200
|
)
|
|
162
201
|
refresh = RefreshToken(
|
|
163
|
-
response.
|
|
164
|
-
int(response.
|
|
202
|
+
response.json_body["refresh_token"],
|
|
203
|
+
int(response.json_body["expires_in"]),
|
|
165
204
|
)
|
|
205
|
+
|
|
166
206
|
self.cache.set_token(access)
|
|
167
207
|
self.cache.set_token(refresh)
|
|
168
208
|
|
|
@@ -174,7 +214,8 @@ class ApiClient:
|
|
|
174
214
|
"""
|
|
175
215
|
Send a specified Request to the GoPay REST API and process the response
|
|
176
216
|
"""
|
|
177
|
-
body = asdict(request.body) if is_dataclass(request.body) else request.body
|
|
217
|
+
# body = asdict(request.body) if is_dataclass(request.body) else request.body
|
|
218
|
+
body = request.body
|
|
178
219
|
# Add Bearer authentication to headers if needed
|
|
179
220
|
headers = request.headers or {}
|
|
180
221
|
if not request.noAuth:
|
|
@@ -184,35 +225,48 @@ class ApiClient:
|
|
|
184
225
|
|
|
185
226
|
if (request.method == 'get'):
|
|
186
227
|
params = urlencode(body)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
228
|
+
try:
|
|
229
|
+
r = requests.request(
|
|
230
|
+
method=request.method,
|
|
231
|
+
url=f"{self.baseUrl}{request.path}?{params}",
|
|
232
|
+
headers=headers,
|
|
233
|
+
timeout=self.timeout
|
|
234
|
+
)
|
|
235
|
+
except:
|
|
236
|
+
print('Error')
|
|
237
|
+
pass
|
|
193
238
|
else:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
239
|
+
try:
|
|
240
|
+
r = requests.request(
|
|
241
|
+
method=request.method,
|
|
242
|
+
url=f"{self.baseUrl}{request.path}",
|
|
243
|
+
headers=headers,
|
|
244
|
+
json=body,
|
|
245
|
+
timeout=self.timeout
|
|
246
|
+
)
|
|
247
|
+
except KeyError:
|
|
248
|
+
print('Error')
|
|
249
|
+
pass
|
|
250
|
+
|
|
251
|
+
# if r == None:
|
|
201
252
|
|
|
202
253
|
# Build Response instance, try to decode body as JSON
|
|
203
|
-
response = Response(raw_body=r.content,
|
|
254
|
+
response = Response(raw_body=r.content, json_body={}, status_code=r.status_code)
|
|
204
255
|
|
|
205
256
|
if (self.REQUEST_DEBUG):
|
|
206
257
|
print(f"{request.method} => {self.baseUrl}{request.path} => {response.status_code}")
|
|
207
258
|
|
|
208
259
|
try:
|
|
209
|
-
response.
|
|
260
|
+
response.json_body = r.json()
|
|
210
261
|
except json.JSONDecodeError:
|
|
211
262
|
pass
|
|
212
263
|
|
|
213
|
-
self.
|
|
264
|
+
self.log(request, response)
|
|
214
265
|
return response
|
|
215
266
|
|
|
267
|
+
def log(self, request: Request, response: Response):
|
|
268
|
+
Logger(self, request, response)
|
|
269
|
+
|
|
216
270
|
def _get_token(self) -> Response:
|
|
217
271
|
# Prepare request
|
|
218
272
|
request = Request(
|
|
@@ -224,18 +278,27 @@ class ApiClient:
|
|
|
224
278
|
)
|
|
225
279
|
# Handle response
|
|
226
280
|
response = self._send_request(request)
|
|
227
|
-
self.
|
|
281
|
+
self.log(request, response)
|
|
228
282
|
return response
|
|
229
283
|
|
|
230
|
-
def _refresh_token(self) -> Response:
|
|
284
|
+
def _refresh_token(self, access: AccessToken, refresh: RefreshToken) -> Response:
|
|
231
285
|
# Prepare request
|
|
232
286
|
request = Request(
|
|
233
287
|
method="post",
|
|
234
288
|
path=ApiPaths.token_refresh,
|
|
235
289
|
content_type='application/json',
|
|
236
|
-
|
|
290
|
+
noAuth=True,
|
|
291
|
+
headers={"Authorization": f"Bearer {access.token}" },
|
|
292
|
+
body={"refresh_token": refresh.token},
|
|
237
293
|
)
|
|
238
294
|
# Handle response
|
|
239
295
|
response = self._send_request(request)
|
|
240
|
-
self.
|
|
296
|
+
self.log(request, response)
|
|
241
297
|
return response
|
|
298
|
+
|
|
299
|
+
def loadToken(self, params: TokenResponse):
|
|
300
|
+
access = AccessToken(params.access_token)
|
|
301
|
+
refresh = RefreshToken(params.refresh_token, int(params.expires_in))
|
|
302
|
+
self.cache.set_token(access)
|
|
303
|
+
self.cache.set_token(refresh)
|
|
304
|
+
|
paymentsgate/enums.py
CHANGED
|
@@ -16,6 +16,7 @@ class ApiPaths(StrEnum):
|
|
|
16
16
|
token_validate = "/auth/token/validate"
|
|
17
17
|
invoices_payin = "/deals/payin"
|
|
18
18
|
invoices_payout = "/deals/payout"
|
|
19
|
+
invoices_payout_tlv = "/deals/tlv"
|
|
19
20
|
invoices_info = "/deals/:id"
|
|
20
21
|
invoices_credentials = "/deals/:id/credentials"
|
|
21
22
|
assets_list = "/wallet"
|
|
@@ -25,6 +26,7 @@ class ApiPaths(StrEnum):
|
|
|
25
26
|
appel_list = "/support/list"
|
|
26
27
|
appel_stat = "/support/statistic"
|
|
27
28
|
fx_quote = "/fx/calculatenew"
|
|
29
|
+
fx_quote_tlv = "/fx/tlv"
|
|
28
30
|
|
|
29
31
|
class Currencies(StrEnum):
|
|
30
32
|
USDT = "USDT"
|
|
@@ -57,14 +59,16 @@ class Currencies(StrEnum):
|
|
|
57
59
|
AMD = "AMD"
|
|
58
60
|
|
|
59
61
|
class Languages(StrEnum):
|
|
60
|
-
EN = "EN"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
EN = "EN",
|
|
63
|
+
AZ = "AZ",
|
|
64
|
+
UZ = "UZ",
|
|
65
|
+
GE = "GE",
|
|
66
|
+
TR = "TR",
|
|
67
|
+
AE = "AE",
|
|
68
|
+
RU = "RU",
|
|
69
|
+
IN = "IN",
|
|
70
|
+
AR = "AR",
|
|
71
|
+
KG = "KG"
|
|
68
72
|
|
|
69
73
|
|
|
70
74
|
class Statuses(StrEnum):
|
|
@@ -118,14 +122,42 @@ class InvoiceTypes(StrEnum):
|
|
|
118
122
|
vodafonecash = "vodafonecash"
|
|
119
123
|
razn = "razn"
|
|
120
124
|
rtjs = "rtjs"
|
|
121
|
-
|
|
125
|
+
sberpay = "sberpay",
|
|
126
|
+
tpay = "tpay",
|
|
127
|
+
opay = "opay",
|
|
128
|
+
moniepoint = "moniepoint",
|
|
129
|
+
palmpay = "palmpay",
|
|
130
|
+
wave = "wave",
|
|
131
|
+
orangemoney = "orangemoney",
|
|
132
|
+
moovmoney = "moovmoney",
|
|
133
|
+
rtjscard = "rtjscard",
|
|
134
|
+
ruzs = "ruzs",
|
|
135
|
+
amobile = "amobile",
|
|
136
|
+
payid = "payid",
|
|
137
|
+
baridi = "baridi",
|
|
138
|
+
multiwidget = "multiwidget",
|
|
139
|
+
attijari = "attijari",
|
|
140
|
+
cih = "cih",
|
|
141
|
+
cashplus = "cashplus",
|
|
142
|
+
elqr = "elqr",
|
|
143
|
+
odengi = "odengi"
|
|
144
|
+
|
|
145
|
+
class EELQRBankALias(StrEnum):
|
|
146
|
+
bakai = 'bakai',
|
|
147
|
+
mbank = 'mbank',
|
|
148
|
+
optima = 'optima',
|
|
149
|
+
kicb = 'kicb',
|
|
150
|
+
odengi = 'odengi',
|
|
151
|
+
demir = 'demir',
|
|
152
|
+
megapay = 'megapay',
|
|
122
153
|
|
|
123
154
|
class CredentialsTypes(StrEnum):
|
|
124
|
-
iban = "iban"
|
|
125
|
-
phone = "phone"
|
|
126
|
-
card = "card"
|
|
127
|
-
fps = "fps"
|
|
128
|
-
|
|
155
|
+
iban = "iban",
|
|
156
|
+
phone = "phone",
|
|
157
|
+
card = "card",
|
|
158
|
+
fps = "fps",
|
|
159
|
+
qr = "qr",
|
|
160
|
+
account = "account",
|
|
129
161
|
custom = "custom"
|
|
130
162
|
|
|
131
163
|
|
|
@@ -137,12 +169,13 @@ class RiskScoreLevels(StrEnum):
|
|
|
137
169
|
|
|
138
170
|
|
|
139
171
|
class CancellationReason(StrEnum):
|
|
140
|
-
NO_MONEY = "NO_MONEY"
|
|
141
|
-
CREDENTIALS_INVALID = "CREDENTIALS_INVALID"
|
|
142
|
-
EXPIRED = "EXPIRED"
|
|
143
|
-
PRECHARGE_GAP_UPPER_LIMIT = "PRECHARGE_GAP_UPPER_LIMIT"
|
|
144
|
-
CROSS_BANK_TFF_LESS_THAN_3K = "CROSS_BANK_TFF_LESS_THAN_3K"
|
|
145
|
-
CROSS_BANK_UNSUPPORTED = "CROSS_BANK_UNSUPPORTED"
|
|
172
|
+
NO_MONEY = "NO_MONEY",
|
|
173
|
+
CREDENTIALS_INVALID = "CREDENTIALS_INVALID",
|
|
174
|
+
EXPIRED = "EXPIRED",
|
|
175
|
+
PRECHARGE_GAP_UPPER_LIMIT = "PRECHARGE_GAP_UPPER_LIMIT",
|
|
176
|
+
CROSS_BANK_TFF_LESS_THAN_3K = "CROSS_BANK_TFF_LESS_THAN_3K",
|
|
177
|
+
CROSS_BANK_UNSUPPORTED = "CROSS_BANK_UNSUPPORTED",
|
|
178
|
+
ACCOUNT_NUMBER_BLACKLISTED = "ACCOUNT_NUMBER_BLACKLISTED"
|
|
146
179
|
|
|
147
180
|
|
|
148
181
|
class FeesStrategy(StrEnum):
|
|
@@ -151,8 +184,10 @@ class FeesStrategy(StrEnum):
|
|
|
151
184
|
|
|
152
185
|
|
|
153
186
|
class InvoiceDirection(StrEnum):
|
|
154
|
-
F2C = "F2C"
|
|
155
|
-
C2F = "C2F"
|
|
187
|
+
F2C = "F2C",
|
|
188
|
+
C2F = "C2F",
|
|
189
|
+
FIAT_IN = "FIAT_IN",
|
|
190
|
+
FIAT_OUT = "FIAT_OUT"
|
|
156
191
|
|
|
157
192
|
|
|
158
193
|
class TTLUnits(StrEnum):
|
paymentsgate/exceptions.py
CHANGED
|
@@ -31,8 +31,8 @@ class APIError(PaymentsgateError):
|
|
|
31
31
|
|
|
32
32
|
class APIResponseError(APIError):
|
|
33
33
|
def __init__(self, response: Response) -> None:
|
|
34
|
-
super().__init__(response.
|
|
34
|
+
super().__init__(response.json_body.get('error'), response.json_body.get('message'), response.json_body.get('data'), response.json_body.get('details'), response.status_code)
|
|
35
35
|
|
|
36
36
|
class APIAuthenticationError(APIError):
|
|
37
37
|
def __init__(self, response: Response) -> None:
|
|
38
|
-
super().__init__(response.
|
|
38
|
+
super().__init__(response.json_body.get('error'), response.json_body.get('message'), response.json_body.get('data'), response.json_body.get('details'), response.status_code)
|
paymentsgate/mappers.py
ADDED
paymentsgate/models.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from dataclasses import dataclass
|
|
3
2
|
import datetime
|
|
4
3
|
import json
|
|
5
4
|
from typing import Optional, List
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
from paymentsgate.enums import (
|
|
8
9
|
Currencies,
|
|
@@ -16,36 +17,29 @@ from paymentsgate.enums import (
|
|
|
16
17
|
CredentialsTypes
|
|
17
18
|
)
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
self.merchant_id = merchant_id
|
|
33
|
-
self.project_id = project_id
|
|
34
|
-
self.private_key = private_key
|
|
35
|
-
self.public_key = public_key
|
|
20
|
+
class BaseRequestModel(BaseModel):
|
|
21
|
+
model_config = ConfigDict(extra='forbid')
|
|
22
|
+
|
|
23
|
+
class BaseResponseModel(BaseModel):
|
|
24
|
+
model_config = ConfigDict(extra='ignore')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Credentials(BaseModel):
|
|
28
|
+
account_id: str
|
|
29
|
+
public_key: str
|
|
30
|
+
private_key: Optional[str] = Field(default=None)
|
|
31
|
+
merchant_id: Optional[str] = Field(default=None)
|
|
32
|
+
project_id: Optional[str] = Field(default=None)
|
|
36
33
|
|
|
37
34
|
@classmethod
|
|
38
35
|
def fromFile(cls, filename):
|
|
39
36
|
data = json.load(open(filename))
|
|
40
|
-
return cls(data
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
data.get('private_key'),
|
|
44
|
-
data.get('public_key'))
|
|
37
|
+
return cls(**data)
|
|
38
|
+
|
|
39
|
+
model_config = ConfigDict(extra='ignore')
|
|
45
40
|
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
class PayInFingerprintBrowserModel:
|
|
42
|
+
class PayInFingerprintBrowserModel(BaseRequestModel):
|
|
49
43
|
acceptHeader: str
|
|
50
44
|
colorDepth: int
|
|
51
45
|
language: str
|
|
@@ -57,8 +51,7 @@ class PayInFingerprintBrowserModel:
|
|
|
57
51
|
windowHeight: int
|
|
58
52
|
windowWidth: int
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
class PayInFingerprintModel:
|
|
54
|
+
class PayInFingerprintModel(BaseRequestModel):
|
|
62
55
|
fingerprint: str
|
|
63
56
|
ip: str
|
|
64
57
|
country: str
|
|
@@ -67,143 +60,146 @@ class PayInFingerprintModel:
|
|
|
67
60
|
zip: str
|
|
68
61
|
browser: Optional[PayInFingerprintBrowserModel]
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
amount: float
|
|
63
|
+
class PayInModel(BaseRequestModel):
|
|
64
|
+
amount: float # decimals: 2
|
|
73
65
|
currency: Currencies
|
|
66
|
+
country: Optional[str] # Country iso code
|
|
74
67
|
invoiceId: Optional[str] # idempotent key
|
|
75
|
-
clientId: Optional[str]
|
|
76
|
-
type: InvoiceTypes
|
|
77
|
-
bankId: Optional[str]
|
|
68
|
+
clientId: Optional[str] # uniq client ref
|
|
69
|
+
type: InvoiceTypes # Invoice subtype, see documentation
|
|
70
|
+
bankId: Optional[str] # ID from bank list or NSPK id
|
|
78
71
|
trusted: Optional[bool]
|
|
79
72
|
successUrl: Optional[str]
|
|
80
73
|
failUrl: Optional[str]
|
|
81
74
|
backUrl: Optional[str]
|
|
82
75
|
clientCard: Optional[str]
|
|
76
|
+
clientName: Optional[str]
|
|
83
77
|
fingerprint: Optional[PayInFingerprintModel]
|
|
84
78
|
lang: Optional[Languages]
|
|
79
|
+
sync: Optional[bool] # sync h2h scheme, see documentation
|
|
80
|
+
multiWidgetOptions: Optional[PayInMultiWidgetOptions]
|
|
81
|
+
theme: Optional[str] # personalized widget theme
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
class PayInResponseModel:
|
|
83
|
+
class PayInResponseModel(BaseResponseModel):
|
|
88
84
|
id: str
|
|
89
85
|
status: Statuses
|
|
90
86
|
type: InvoiceTypes
|
|
91
|
-
url: str
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
87
|
+
url: Optional[str]
|
|
88
|
+
deeplink: Optional[str]
|
|
89
|
+
m10: Optional[str]
|
|
90
|
+
cardholder: Optional[str]
|
|
91
|
+
account: Optional[str]
|
|
92
|
+
bankId: Optional[str]
|
|
93
|
+
accountSubType: Optional[str]
|
|
94
|
+
|
|
95
|
+
class PayOutRecipientModel(BaseRequestModel):
|
|
96
|
+
account_number: str # IBAN, Phone, Card, local bank account number, wallet number, etc'
|
|
97
|
+
account_owner: Optional[str] # FirstName LastName or FirstName MiddleName LastName
|
|
98
|
+
account_iban: Optional[str] # use only cases where iban is't primary account id
|
|
99
|
+
account_swift: Optional[str] # for swift transfers only
|
|
100
|
+
account_phone: Optional[str] # additional recipient phone number, use only cases where phone is't primary account id
|
|
101
|
+
account_bic: Optional[str] # recipient bank id
|
|
102
|
+
account_ewallet_name: Optional[str] # additional recipient wallet provider info
|
|
103
|
+
account_email: Optional[str] # additional recipient email, use only cases where email is't primary account id
|
|
104
|
+
account_bank_id: Optional[str] # recipient bankId (from API banks or RU NSPK id)
|
|
105
|
+
account_internal_client_number: Optional[str] # Bank internal identifier used for method banktransferphp (Philippines)
|
|
106
|
+
type: Optional[CredentialsTypes] # primary credential type
|
|
107
|
+
|
|
108
|
+
class PayOutModel(BaseRequestModel):
|
|
108
109
|
currency: Optional[Currencies] # currency from, by default = usdt
|
|
109
|
-
currencyTo:Currencies
|
|
110
|
-
amount: float
|
|
110
|
+
currencyTo: Optional[Currencies] # currency to, fiat only, if use quoteId - not required
|
|
111
|
+
amount: Optional[float] # decimals: 2, if use quoteId - not required
|
|
111
112
|
invoiceId: Optional[str] # idempotent key
|
|
112
|
-
clientId: Optional[str]
|
|
113
|
+
clientId: Optional[str] # uniq client ref
|
|
113
114
|
ttl: Optional[int]
|
|
114
115
|
ttl_unit: Optional[TTLUnits]
|
|
115
|
-
finalAmount: Optional[float]
|
|
116
|
-
sender_name: Optional[str]
|
|
116
|
+
finalAmount: Optional[float] # Optional, for pre-charge rate lock
|
|
117
|
+
sender_name: Optional[str] # sender personal short data
|
|
118
|
+
sender_personal: Optional[PayOutSenderModel]
|
|
117
119
|
baseCurrency: Optional[CurrencyTypes]
|
|
118
120
|
feesStrategy: Optional[FeesStrategy]
|
|
119
121
|
recipient: PayOutRecipientModel
|
|
120
122
|
quoteId: Optional[str]
|
|
123
|
+
src_amount: Optional[str] # Optional, source amount in local currency for 2phase payout
|
|
124
|
+
type: Optional[InvoiceTypes] # payout transaction scheme hint
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
class PayOutResponseModel:
|
|
126
|
+
class PayOutResponseModel(BaseResponseModel):
|
|
124
127
|
id: str
|
|
125
128
|
status: Statuses
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
class GetQuoteModel:
|
|
130
|
+
class GetQuoteModel(BaseRequestModel):
|
|
129
131
|
currency_from: Currencies
|
|
130
132
|
currency_to: Currencies
|
|
131
133
|
amount: float
|
|
132
|
-
subtype: InvoiceTypes
|
|
134
|
+
subtype: Optional[InvoiceTypes]
|
|
135
|
+
currency_original: Optional[Currencies]
|
|
133
136
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
currency_to: CurrencyModel
|
|
137
|
+
class QuoteEntity(BaseResponseModel):
|
|
138
|
+
currencyFrom: Currencies
|
|
139
|
+
currencyTo: Currencies
|
|
138
140
|
pair: str
|
|
139
141
|
rate: float
|
|
140
142
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
expiredAt: Optional[datetime.datetime] = None
|
|
143
|
+
class GetQuoteResponseModel(BaseResponseModel):
|
|
144
|
+
id: str
|
|
145
|
+
finalAmount: float
|
|
146
|
+
direction: InvoiceDirection
|
|
147
|
+
fullRate: float
|
|
148
|
+
fullRateReverse: float
|
|
149
|
+
fees: float
|
|
150
|
+
fees_percent: float
|
|
151
|
+
quotes: List[QuoteEntity]
|
|
152
|
+
expiredAt: Optional[datetime.datetime] = Field(default=None)
|
|
152
153
|
|
|
153
154
|
#deprecated
|
|
154
|
-
currency_from: Optional[CurrencyModel] = None
|
|
155
|
-
currency_to: Optional[CurrencyModel] = None
|
|
156
|
-
currency_middle: Optional[CurrencyModel] = None
|
|
157
|
-
rate1: Optional[float] = None
|
|
158
|
-
rate2: Optional[float] = None
|
|
159
|
-
rate3: Optional[float] = None
|
|
160
|
-
net_amount: Optional[float] = None
|
|
161
|
-
metadata: Optional[object] = None
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
class DepositAddressResponseModel:
|
|
155
|
+
currency_from: Optional[CurrencyModel] = Field(default=None)
|
|
156
|
+
currency_to: Optional[CurrencyModel] = Field(default=None)
|
|
157
|
+
currency_middle: Optional[CurrencyModel] = Field(default=None)
|
|
158
|
+
rate1: Optional[float] = Field(default=None)
|
|
159
|
+
rate2: Optional[float] = Field(default=None)
|
|
160
|
+
rate3: Optional[float] = Field(default=None)
|
|
161
|
+
net_amount: Optional[float] = Field(default=None)
|
|
162
|
+
metadata: Optional[object] = Field(default=None)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class DepositAddressResponseModel(BaseResponseModel):
|
|
165
166
|
currency: Currencies
|
|
166
167
|
address: str
|
|
167
|
-
expiredAt: datetime
|
|
168
|
+
expiredAt: datetime.datetime
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
class CurrencyModel:
|
|
170
|
+
|
|
171
|
+
class CurrencyModel(BaseResponseModel):
|
|
171
172
|
_id: str
|
|
172
173
|
type: CurrencyTypes
|
|
173
174
|
code: Currencies
|
|
174
175
|
symbol: str
|
|
175
|
-
label: Optional[str]
|
|
176
|
+
label: Optional[str] = Field(default=None)
|
|
176
177
|
decimal: int
|
|
177
|
-
countryCode: Optional[str]
|
|
178
|
-
countryName: Optional[str]
|
|
178
|
+
countryCode: Optional[str] = Field(default=None)
|
|
179
|
+
countryName: Optional[str] = Field(default=None)
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
class BankModel:
|
|
181
|
+
class BankModel(BaseResponseModel):
|
|
182
182
|
name: str
|
|
183
183
|
title: str
|
|
184
184
|
currency: Currencies
|
|
185
185
|
fpsId: str
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
class InvoiceStatusModel:
|
|
187
|
+
class InvoiceStatusModel(BaseResponseModel):
|
|
189
188
|
name: Statuses
|
|
190
|
-
createdAt: datetime
|
|
191
|
-
updatedAt: datetime
|
|
189
|
+
createdAt: datetime.datetime
|
|
190
|
+
updatedAt: datetime.datetime
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
class InvoiceAmountModel:
|
|
192
|
+
class InvoiceAmountModel(BaseResponseModel):
|
|
195
193
|
crypto: float
|
|
196
194
|
fiat: float
|
|
197
195
|
fiat_net: float
|
|
198
196
|
|
|
199
|
-
|
|
200
|
-
class InvoiceMetadataModel:
|
|
197
|
+
class InvoiceMetadataModel(BaseResponseModel):
|
|
201
198
|
invoiceId: Optional[str]
|
|
202
199
|
clientId: Optional[str]
|
|
203
200
|
fiatAmount: Optional[float]
|
|
204
201
|
|
|
205
|
-
|
|
206
|
-
class InvoiceModel:
|
|
202
|
+
class InvoiceModel(BaseResponseModel):
|
|
207
203
|
_id: str
|
|
208
204
|
orderId: str
|
|
209
205
|
projectId: str
|
|
@@ -216,18 +212,53 @@ class InvoiceModel:
|
|
|
216
212
|
metadata: InvoiceMetadataModel
|
|
217
213
|
receiptUrls: List[str]
|
|
218
214
|
isExpired: bool
|
|
219
|
-
createdAt: datetime
|
|
220
|
-
updatedAt: datetime
|
|
221
|
-
expiredAt: datetime
|
|
215
|
+
createdAt: datetime.datetime
|
|
216
|
+
updatedAt: datetime.datetime
|
|
217
|
+
expiredAt: datetime.datetime
|
|
222
218
|
|
|
223
|
-
|
|
224
|
-
class AssetsAccountModel:
|
|
219
|
+
class AssetsAccountModel(BaseResponseModel):
|
|
225
220
|
currency: CurrencyModel;
|
|
226
221
|
total: float
|
|
227
222
|
pending: float
|
|
228
223
|
available: float
|
|
229
224
|
|
|
230
|
-
|
|
231
|
-
class AssetsResponseModel:
|
|
225
|
+
class AssetsResponseModel(BaseResponseModel):
|
|
232
226
|
assets: List[AssetsAccountModel]
|
|
233
227
|
|
|
228
|
+
class PayInMultiWidgetOptions(BaseRequestModel):
|
|
229
|
+
offerAmount: Optional[bool] # show amount select from best offers
|
|
230
|
+
elqrBanks: Optional[str] # elqr bank list
|
|
231
|
+
|
|
232
|
+
class PayOutSenderModel(BaseRequestModel):
|
|
233
|
+
name: Optional[str]
|
|
234
|
+
birthday: Optional[str]
|
|
235
|
+
phone: Optional[str]
|
|
236
|
+
passport: Optional[str]
|
|
237
|
+
|
|
238
|
+
class PayOutTlvRequestModel(BaseRequestModel):
|
|
239
|
+
quoteId: str # ID from /fx/tlv response
|
|
240
|
+
invoiceId: Optional[str]
|
|
241
|
+
clientId: Optional[str]
|
|
242
|
+
sender_personal: Optional[PayOutSenderModel]
|
|
243
|
+
|
|
244
|
+
class GetQuoteTlv(BaseRequestModel):
|
|
245
|
+
data: str
|
|
246
|
+
|
|
247
|
+
class QuoteTlvResponse(BaseResponseModel):
|
|
248
|
+
id: str
|
|
249
|
+
amount: float # fiat local amount
|
|
250
|
+
amountCrypto: float # total crypto amount inc. fees
|
|
251
|
+
currencyCode: Currencies # local currency
|
|
252
|
+
feeInCrypto: float # total fee in crypto
|
|
253
|
+
feePercent: float # fee percent
|
|
254
|
+
qrVersion: int # qr code version, 1 - nspk, 2 - tlv encoded, 3 - tlv plain
|
|
255
|
+
rate: float # exchange rate
|
|
256
|
+
merchant: Optional[str] = Field(default=None) # merchant title
|
|
257
|
+
logo: Optional[str] = Field(default=None) # merchant logo
|
|
258
|
+
|
|
259
|
+
class PayOutTlvRequest(BaseRequestModel):
|
|
260
|
+
quoteId: str # quote.id ref
|
|
261
|
+
invoiceId: Optional[str] = Field(default=None)
|
|
262
|
+
clientId: Optional[str] = Field(default=None)
|
|
263
|
+
src_amount: Optional[float] = Field(default=None)
|
|
264
|
+
sender_personal: Optional[PayOutSenderModel] = Field(default=None)
|
paymentsgate/transport.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
class Request:
|
|
4
|
+
class Request(BaseModel):
|
|
6
5
|
method: str
|
|
7
6
|
path: str
|
|
8
7
|
content_type: str = 'application/json'
|
|
@@ -11,11 +10,9 @@ class Request:
|
|
|
11
10
|
noAuth: bool | None = False
|
|
12
11
|
signature: bool | None = False
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class Response:
|
|
13
|
+
class Response(BaseModel):
|
|
17
14
|
raw_body: bytes
|
|
18
|
-
|
|
15
|
+
json_body: dict
|
|
19
16
|
status_code: int
|
|
20
17
|
|
|
21
18
|
@property
|
|
@@ -24,8 +21,8 @@ class Response:
|
|
|
24
21
|
|
|
25
22
|
def cast(self, model: BaseModel, error: dict):
|
|
26
23
|
if self.success:
|
|
27
|
-
return model(**self.
|
|
28
|
-
return error(self.
|
|
24
|
+
return model(**self.json_body)
|
|
25
|
+
return error(self.json_body.get('error'), self.json_body.get('message'), self.json_body.get('data'), self.json_body.get('status'));
|
|
29
26
|
|
|
30
27
|
def __str__(self) -> str:
|
|
31
28
|
return self.raw_body.decode("utf-8")
|
paymentsgate/types.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
paymentsgate/__init__.py,sha256=53DrE7IRD2NFQshE2EGYQ28jLr-ro45iFei28ZMOezI,336
|
|
2
|
+
paymentsgate/cache.py,sha256=w3xB3iaYPxVEZbeWxpWM1PQT-JctspoI5qC9bv6Xmts,1002
|
|
3
|
+
paymentsgate/client.py,sha256=0brT3_ZTt52lBIKHoBIPzybGJ_uv_taAelxmdKLkeC0,9338
|
|
4
|
+
paymentsgate/enums.py,sha256=kLK3xfw8zckTK6wbEA7RH9R98VaD2eF7asT9mzyLDBI,4201
|
|
5
|
+
paymentsgate/exceptions.py,sha256=-ZzMvzyViBQCf4LsbAFXwizDHF_0Axyn705n2FBJ17I,1346
|
|
6
|
+
paymentsgate/logger.py,sha256=QY6upavgb2y9dRQG05NwF_OTxP7bPspZR5QdpCjJULI,221
|
|
7
|
+
paymentsgate/mappers.py,sha256=ruXJ3I5VY89wbvJP7aJY8xws2LRXFj3eOMreXkrJ7g8,163
|
|
8
|
+
paymentsgate/models.py,sha256=kRTWo_velRP8pQ76-yc5vZp5OJP2pw-K8mMn3dB06Qg,8072
|
|
9
|
+
paymentsgate/tokens.py,sha256=qdvCQJ9jYIRKSxlmm5gip-nMAQWH8_EHys9zwel4oaU,916
|
|
10
|
+
paymentsgate/transport.py,sha256=VgVkWBCphrUtHeA79ExhlWo-FyidzHeUkxKIx8nnsh4,814
|
|
11
|
+
paymentsgate/types.py,sha256=UQ6RRcTcK-TXYPjwDP6DnSSYtHsw4Fmt2f34q6O_msg,172
|
|
12
|
+
paymentsgate-1.5.0.dist-info/LICENSE,sha256=4xWMZLmqNJ6602DZLEg0A9v03uT4xMq_-XSIxvXvfYM,1075
|
|
13
|
+
paymentsgate-1.5.0.dist-info/WHEEL,sha256=bbU3AyvhQ312rVm7zzRQjs6axI1UYWC3nmFA2E6FFSI,88
|
|
14
|
+
paymentsgate-1.5.0.dist-info/METADATA,sha256=5DVm2gm1jSZXaLNnLpDDXukEPgB7j-dI6ef97PX1dgU,4020
|
|
15
|
+
paymentsgate-1.5.0.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
paymentsgate/__init__.py,sha256=53DrE7IRD2NFQshE2EGYQ28jLr-ro45iFei28ZMOezI,336
|
|
2
|
-
paymentsgate/cache.py,sha256=w3xB3iaYPxVEZbeWxpWM1PQT-JctspoI5qC9bv6Xmts,1002
|
|
3
|
-
paymentsgate/client.py,sha256=xawYI252rRY1Yi3QKpTdWCDjHdu2uBRBUvKtNoryrmI,7566
|
|
4
|
-
paymentsgate/enums.py,sha256=wvDeVQvSO5WPPSWd1XKOh-8vgI1gsK2wyfMi7P8vay0,3311
|
|
5
|
-
paymentsgate/exceptions.py,sha256=fQniUSQp8XkWXPCITHDUbVNcDwSPA8rJpwbbhJ8wfNQ,1306
|
|
6
|
-
paymentsgate/logger.py,sha256=QY6upavgb2y9dRQG05NwF_OTxP7bPspZR5QdpCjJULI,221
|
|
7
|
-
paymentsgate/models.py,sha256=LEwaoy2rkdA-2BLJoV85aKBlDMDu4NETZ0thCrBIV1g,5017
|
|
8
|
-
paymentsgate/tokens.py,sha256=qdvCQJ9jYIRKSxlmm5gip-nMAQWH8_EHys9zwel4oaU,916
|
|
9
|
-
paymentsgate/transport.py,sha256=pOmvDZh06uIGIUWTFi0vgf8pAgQT1f96ArcJNycU2Ks,785
|
|
10
|
-
paymentsgate-1.4.9.dist-info/LICENSE,sha256=4xWMZLmqNJ6602DZLEg0A9v03uT4xMq_-XSIxvXvfYM,1075
|
|
11
|
-
paymentsgate-1.4.9.dist-info/WHEEL,sha256=bbU3AyvhQ312rVm7zzRQjs6axI1UYWC3nmFA2E6FFSI,88
|
|
12
|
-
paymentsgate-1.4.9.dist-info/METADATA,sha256=iOdFgWAzkyAwCYTriGi2AW0svSwVgV79NgXiS-EvocE,4020
|
|
13
|
-
paymentsgate-1.4.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|