paymentsgate 1.4.9__py3-none-any.whl → 1.5.1__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.
- paymentsgate/__init__.py +14 -14
- paymentsgate/cache.py +9 -7
- paymentsgate/client.py +293 -70
- paymentsgate/enums.py +67 -31
- paymentsgate/exceptions.py +29 -12
- paymentsgate/logger.py +0 -1
- paymentsgate/mappers.py +3 -0
- paymentsgate/models.py +280 -224
- paymentsgate/signature.py +91 -0
- paymentsgate/tokens.py +7 -4
- paymentsgate/transport.py +14 -11
- paymentsgate/types.py +7 -0
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.1.dist-info}/METADATA +5 -4
- paymentsgate-1.5.1.dist-info/RECORD +16 -0
- paymentsgate-1.4.9.dist-info/RECORD +0 -13
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.1.dist-info}/LICENSE +0 -0
- {paymentsgate-1.4.9.dist-info → paymentsgate-1.5.1.dist-info}/WHEEL +0 -0
paymentsgate/__init__.py
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
from paymentsgate.client import ApiClient
|
|
2
2
|
from paymentsgate.enums import (
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
AuthenticationRealms,
|
|
4
|
+
ApiPaths,
|
|
5
|
+
Currencies,
|
|
6
|
+
Languages,
|
|
7
|
+
Statuses,
|
|
8
|
+
CurrencyTypes,
|
|
9
|
+
InvoiceTypes,
|
|
10
|
+
CredentialsTypes,
|
|
11
|
+
RiskScoreLevels,
|
|
12
|
+
CancellationReason,
|
|
13
|
+
FeesStrategy,
|
|
14
|
+
InvoiceDirection,
|
|
15
|
+
TTLUnits,
|
|
16
16
|
)
|
|
17
|
-
from paymentsgate.models import Credentials
|
|
17
|
+
from paymentsgate.models import Credentials
|
paymentsgate/cache.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
|
|
4
|
-
from paymentsgate.tokens import
|
|
5
|
-
|
|
6
|
-
RefreshToken
|
|
7
|
-
)
|
|
4
|
+
from paymentsgate.tokens import AccessToken, RefreshToken
|
|
5
|
+
|
|
8
6
|
|
|
9
7
|
class AbstractCache(ABC):
|
|
10
8
|
"""
|
|
@@ -19,15 +17,19 @@ class AbstractCache(ABC):
|
|
|
19
17
|
...
|
|
20
18
|
|
|
21
19
|
@abstractmethod
|
|
22
|
-
def set_token(self,token: AccessToken | RefreshToken) -> None:
|
|
20
|
+
def set_token(self, token: AccessToken | RefreshToken) -> None:
|
|
23
21
|
"""
|
|
24
22
|
Save the token to the cache under the specified key
|
|
25
23
|
"""
|
|
26
24
|
...
|
|
27
|
-
|
|
25
|
+
|
|
26
|
+
|
|
28
27
|
@dataclass
|
|
29
28
|
class DefaultCache(AbstractCache):
|
|
30
|
-
tokens: dict[str, AccessToken | RefreshToken] = field(
|
|
29
|
+
tokens: dict[str, AccessToken | RefreshToken] = field(
|
|
30
|
+
default_factory=dict, init=False
|
|
31
|
+
)
|
|
32
|
+
|
|
31
33
|
def get_token(self, key: str) -> AccessToken | RefreshToken | None:
|
|
32
34
|
return self.tokens.get(key)
|
|
33
35
|
|
paymentsgate/client.py
CHANGED
|
@@ -1,58 +1,261 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import logging
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import json
|
|
5
5
|
from urllib.parse import urlencode
|
|
6
|
+
from pydantic import Field, BaseModel
|
|
6
7
|
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
GetQuoteModel,
|
|
18
|
-
GetQuoteResponseModel,
|
|
19
|
-
PayInModel,
|
|
20
|
-
PayInResponseModel,
|
|
21
|
-
PayOutModel,
|
|
8
|
+
from .types import TokenResponse
|
|
9
|
+
from .tokens import AccessToken, RefreshToken
|
|
10
|
+
from .exceptions import APIResponseError, APIAuthenticationError
|
|
11
|
+
from .models import (
|
|
12
|
+
Credentials,
|
|
13
|
+
GetQuoteModel,
|
|
14
|
+
GetQuoteResponseModel,
|
|
15
|
+
PayInModel,
|
|
16
|
+
PayInResponseModel,
|
|
17
|
+
PayOutModel,
|
|
22
18
|
PayOutResponseModel,
|
|
23
|
-
InvoiceModel
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Request,
|
|
28
|
-
Response
|
|
29
|
-
)
|
|
30
|
-
from paymentsgate.logger import Logger
|
|
31
|
-
from paymentsgate.cache import (
|
|
32
|
-
AbstractCache,
|
|
33
|
-
DefaultCache
|
|
19
|
+
InvoiceModel,
|
|
20
|
+
GetQuoteTlv,
|
|
21
|
+
PayOutTlvRequest,
|
|
22
|
+
QuoteTlvResponse,
|
|
34
23
|
)
|
|
24
|
+
from .enums import ApiPaths
|
|
25
|
+
from .transport import Request, Response
|
|
26
|
+
from .logger import Logger
|
|
27
|
+
from .cache import AbstractCache, DefaultCache
|
|
35
28
|
|
|
36
|
-
import
|
|
29
|
+
import httpx
|
|
37
30
|
|
|
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
31
|
|
|
46
|
-
|
|
47
|
-
RESPONSE_DEBUG: bool = False
|
|
32
|
+
class BaseClient:
|
|
48
33
|
|
|
49
|
-
def __init__(self, config: Credentials, baseUrl: str, debug: bool=False):
|
|
34
|
+
def __init__(self, config: Credentials, baseUrl: str, timeout: int = 20, debug: bool=False):
|
|
50
35
|
self.config = config
|
|
51
36
|
self.cache = DefaultCache()
|
|
52
37
|
self.baseUrl = baseUrl
|
|
38
|
+
self.timeout = timeout
|
|
53
39
|
if debug:
|
|
54
40
|
logging.basicConfig(level=logging.DEBUG)
|
|
55
41
|
|
|
42
|
+
|
|
43
|
+
class ApiAsyncClient(BaseClient):
|
|
44
|
+
async def PayIn(self, request: PayInModel) -> PayInResponseModel:
|
|
45
|
+
# Prepare request
|
|
46
|
+
request = Request(
|
|
47
|
+
method="post",
|
|
48
|
+
path=ApiPaths.invoices_payin,
|
|
49
|
+
content_type='application/json',
|
|
50
|
+
noAuth=False,
|
|
51
|
+
body=request.model_dump(exclude_none=True),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Handle response
|
|
55
|
+
response = await self._send_request(request)
|
|
56
|
+
if (response.success):
|
|
57
|
+
return response.cast(PayInResponseModel, APIResponseError)
|
|
58
|
+
else:
|
|
59
|
+
raise APIResponseError(response)
|
|
60
|
+
|
|
61
|
+
async def PayOut(self, request: PayOutModel) -> PayOutResponseModel:
|
|
62
|
+
# Prepare request
|
|
63
|
+
request = Request(
|
|
64
|
+
method="post",
|
|
65
|
+
path=ApiPaths.invoices_payout,
|
|
66
|
+
content_type='application/json',
|
|
67
|
+
noAuth=False,
|
|
68
|
+
signature=True,
|
|
69
|
+
body=request.model_dump(exclude_none=True)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Handle response
|
|
73
|
+
response = await self._send_request(request)
|
|
74
|
+
if (response.success):
|
|
75
|
+
return response.cast(PayOutResponseModel, APIResponseError)
|
|
76
|
+
else:
|
|
77
|
+
raise APIResponseError(response)
|
|
78
|
+
|
|
79
|
+
async def PayOutTlv(self, request: PayOutTlvRequest) -> PayOutResponseModel:
|
|
80
|
+
request = Request(
|
|
81
|
+
method="post",
|
|
82
|
+
path=ApiPaths.invoices_payout_tlv,
|
|
83
|
+
content_type="application/json",
|
|
84
|
+
noAuth=False,
|
|
85
|
+
signature=False,
|
|
86
|
+
body=request.model_dump(exclude_none=True),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Handle response
|
|
90
|
+
response = await self._send_request(request)
|
|
91
|
+
if not response.success:
|
|
92
|
+
raise APIResponseError(response)
|
|
93
|
+
|
|
94
|
+
return response.cast(PayOutResponseModel, APIResponseError)
|
|
95
|
+
|
|
96
|
+
async def Quote(self, params: GetQuoteModel) -> GetQuoteResponseModel:
|
|
97
|
+
# Prepare request
|
|
98
|
+
request = Request(
|
|
99
|
+
method="get",
|
|
100
|
+
path=ApiPaths.fx_quote,
|
|
101
|
+
content_type='application/json',
|
|
102
|
+
noAuth=False,
|
|
103
|
+
signature=False,
|
|
104
|
+
body=params.model_dump(exclude_none=True)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Handle response
|
|
108
|
+
response = await self._send_request(request)
|
|
109
|
+
if not response.success:
|
|
110
|
+
raise APIResponseError(response)
|
|
111
|
+
|
|
112
|
+
return response.cast(GetQuoteResponseModel, APIResponseError)
|
|
113
|
+
|
|
114
|
+
async def QuoteQr(self, params: GetQuoteTlv) -> QuoteTlvResponse:
|
|
115
|
+
request = Request(
|
|
116
|
+
method="post",
|
|
117
|
+
path=ApiPaths.fx_quote_tlv,
|
|
118
|
+
content_type="application/json",
|
|
119
|
+
noAuth=False,
|
|
120
|
+
signature=False,
|
|
121
|
+
body=params.model_dump(exclude_none=True),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Handle response
|
|
125
|
+
response = await self._send_request(request)
|
|
126
|
+
if not response.success:
|
|
127
|
+
raise APIResponseError(response)
|
|
128
|
+
|
|
129
|
+
return response.cast(QuoteTlvResponse, APIResponseError)
|
|
130
|
+
|
|
131
|
+
async def Status(self, id: str) -> InvoiceModel:
|
|
132
|
+
# Prepare request
|
|
133
|
+
request = Request(
|
|
134
|
+
method="get",
|
|
135
|
+
path=ApiPaths.invoices_info.replace(':id', id),
|
|
136
|
+
content_type='application/json',
|
|
137
|
+
noAuth=False,
|
|
138
|
+
signature=False,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Handle response
|
|
142
|
+
response = await self._send_request(request)
|
|
143
|
+
if not response.success:
|
|
144
|
+
raise APIResponseError(response)
|
|
145
|
+
return response.cast(InvoiceModel, APIResponseError)
|
|
146
|
+
|
|
147
|
+
async def get_token(self) -> AccessToken | None:
|
|
148
|
+
# First check if valid token is cached
|
|
149
|
+
token = self.cache.get_token("AccessToken")
|
|
150
|
+
refresh = self.cache.get_token("RefreshToken")
|
|
151
|
+
|
|
152
|
+
if token is not None and not token.is_expired:
|
|
153
|
+
return token
|
|
154
|
+
else:
|
|
155
|
+
# try to refresh token
|
|
156
|
+
if refresh is not None and not refresh.is_expired:
|
|
157
|
+
refreshed = await self._refresh_token(token, refresh)
|
|
158
|
+
|
|
159
|
+
if refreshed.success:
|
|
160
|
+
access = AccessToken(refreshed.json_body["access_token"])
|
|
161
|
+
refresh = RefreshToken(
|
|
162
|
+
refreshed.json_body["refresh_token"],
|
|
163
|
+
int(refreshed.json_body["expires_in"]),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
self.cache.set_token(access)
|
|
167
|
+
self.cache.set_token(refresh)
|
|
168
|
+
|
|
169
|
+
return access
|
|
170
|
+
|
|
171
|
+
# try to issue token
|
|
172
|
+
response = await self._fetch_token()
|
|
173
|
+
if response.success:
|
|
174
|
+
access = AccessToken(response.json_body["access_token"])
|
|
175
|
+
refresh = RefreshToken(
|
|
176
|
+
response.json_body["refresh_token"],
|
|
177
|
+
int(response.json_body["expires_in"]),
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
self.cache.set_token(access)
|
|
181
|
+
self.cache.set_token(refresh)
|
|
182
|
+
|
|
183
|
+
return access
|
|
184
|
+
else:
|
|
185
|
+
raise APIAuthenticationError(response)
|
|
186
|
+
|
|
187
|
+
async def _send_request(self, request: Request) -> Response:
|
|
188
|
+
"""
|
|
189
|
+
Send a specified Request to the GoPay REST API and process the response
|
|
190
|
+
"""
|
|
191
|
+
dict_factory = lambda l: {k: v for k, v in l if v is not None}
|
|
192
|
+
body = request.body
|
|
193
|
+
# Add Bearer authentication to headers if needed
|
|
194
|
+
headers = request.headers or {}
|
|
195
|
+
if not request.noAuth:
|
|
196
|
+
auth = await self.get_token()
|
|
197
|
+
if auth is not None:
|
|
198
|
+
headers["Authorization"] = f"Bearer {auth.token}"
|
|
199
|
+
|
|
200
|
+
client = httpx.AsyncClient(timeout=self.timeout)
|
|
201
|
+
if request.method == 'get':
|
|
202
|
+
url = f'{self.baseUrl}{request.path}'
|
|
203
|
+
if body:
|
|
204
|
+
params = urlencode(body)
|
|
205
|
+
url = f'{url}?{params}'
|
|
206
|
+
r = await client.request(
|
|
207
|
+
method=request.method,
|
|
208
|
+
url=url,
|
|
209
|
+
headers=headers,
|
|
210
|
+
timeout=self.timeout
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
r = await client.request(
|
|
214
|
+
method=request.method,
|
|
215
|
+
url=f"{self.baseUrl}{request.path}",
|
|
216
|
+
headers=headers,
|
|
217
|
+
json=body,
|
|
218
|
+
timeout=self.timeout
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Build Response instance, try to decode body as JSON
|
|
222
|
+
response = Response(raw_body=r.content, json={}, status_code=r.status_code)
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
response.json_body = r.json()
|
|
226
|
+
except json.JSONDecodeError:
|
|
227
|
+
pass
|
|
228
|
+
|
|
229
|
+
return response
|
|
230
|
+
|
|
231
|
+
async def _fetch_token(self) -> Response:
|
|
232
|
+
# Prepare request
|
|
233
|
+
request = Request(
|
|
234
|
+
method="post",
|
|
235
|
+
path=ApiPaths.token_issue,
|
|
236
|
+
content_type='application/json',
|
|
237
|
+
noAuth=True,
|
|
238
|
+
body={"account_id": self.config.account_id, "public_key": self.config.public_key},
|
|
239
|
+
)
|
|
240
|
+
# Handle response
|
|
241
|
+
response = await self._send_request(request)
|
|
242
|
+
return response
|
|
243
|
+
|
|
244
|
+
async def _refresh_token(self) -> Response:
|
|
245
|
+
# Prepare request
|
|
246
|
+
request = Request(
|
|
247
|
+
method="post",
|
|
248
|
+
path=ApiPaths.token_refresh,
|
|
249
|
+
content_type='application/json',
|
|
250
|
+
body={"refresh_token": self.refreshToken},
|
|
251
|
+
)
|
|
252
|
+
# Handle response
|
|
253
|
+
response = await self._send_request(request)
|
|
254
|
+
return response
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class ApiClient(BaseClient):
|
|
258
|
+
|
|
56
259
|
def PayIn(self, request: PayInModel) -> PayInResponseModel:
|
|
57
260
|
# Prepare request
|
|
58
261
|
request = Request(
|
|
@@ -60,12 +263,11 @@ class ApiClient:
|
|
|
60
263
|
path=ApiPaths.invoices_payin,
|
|
61
264
|
content_type='application/json',
|
|
62
265
|
noAuth=False,
|
|
63
|
-
body=request,
|
|
266
|
+
body=request.model_dump(exclude_none=True),
|
|
64
267
|
)
|
|
65
268
|
|
|
66
269
|
# Handle response
|
|
67
270
|
response = self._send_request(request)
|
|
68
|
-
self.logger(request, response)
|
|
69
271
|
if (response.success):
|
|
70
272
|
return response.cast(PayInResponseModel, APIResponseError)
|
|
71
273
|
else:
|
|
@@ -79,17 +281,32 @@ class ApiClient:
|
|
|
79
281
|
content_type='application/json',
|
|
80
282
|
noAuth=False,
|
|
81
283
|
signature=True,
|
|
82
|
-
body=request
|
|
284
|
+
body=request.model_dump(exclude_none=True)
|
|
83
285
|
)
|
|
84
286
|
|
|
85
287
|
# Handle response
|
|
86
288
|
response = self._send_request(request)
|
|
87
|
-
self.logger(request, response)
|
|
88
289
|
if (response.success):
|
|
89
290
|
return response.cast(PayOutResponseModel, APIResponseError)
|
|
90
291
|
else:
|
|
91
292
|
raise APIResponseError(response)
|
|
92
293
|
|
|
294
|
+
def PayOutTlv(self, request: PayOutTlvRequest) -> PayOutResponseModel:
|
|
295
|
+
request = Request(
|
|
296
|
+
method="post",
|
|
297
|
+
path=ApiPaths.invoices_payout_tlv,
|
|
298
|
+
content_type="application/json",
|
|
299
|
+
noAuth=False,
|
|
300
|
+
signature=False,
|
|
301
|
+
body=request.model_dump(exclude_none=True),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Handle response
|
|
305
|
+
response = self._send_request(request)
|
|
306
|
+
if not response.success:
|
|
307
|
+
raise APIResponseError(response)
|
|
308
|
+
return response.cast(PayOutResponseModel, APIResponseError)
|
|
309
|
+
|
|
93
310
|
def Quote(self, params: GetQuoteModel) -> GetQuoteResponseModel:
|
|
94
311
|
# Prepare request
|
|
95
312
|
request = Request(
|
|
@@ -98,17 +315,33 @@ class ApiClient:
|
|
|
98
315
|
content_type='application/json',
|
|
99
316
|
noAuth=False,
|
|
100
317
|
signature=False,
|
|
101
|
-
body=params
|
|
318
|
+
body=params.model_dump(exclude_none=True)
|
|
102
319
|
)
|
|
103
320
|
|
|
104
321
|
# Handle response
|
|
105
322
|
response = self._send_request(request)
|
|
106
|
-
self.logger(request, response)
|
|
107
323
|
if not response.success:
|
|
108
324
|
raise APIResponseError(response)
|
|
109
325
|
|
|
110
326
|
return response.cast(GetQuoteResponseModel, APIResponseError)
|
|
111
|
-
|
|
327
|
+
|
|
328
|
+
def QuoteQr(self, params: GetQuoteTlv) -> QuoteTlvResponse:
|
|
329
|
+
request = Request(
|
|
330
|
+
method="post",
|
|
331
|
+
path=ApiPaths.fx_quote_tlv,
|
|
332
|
+
content_type="application/json",
|
|
333
|
+
noAuth=False,
|
|
334
|
+
signature=False,
|
|
335
|
+
body=params.model_dump(exclude_none=True),
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# Handle response
|
|
339
|
+
response = self._send_request(request)
|
|
340
|
+
if not response.success:
|
|
341
|
+
raise APIResponseError(response)
|
|
342
|
+
|
|
343
|
+
return response.cast(QuoteTlvResponse, APIResponseError)
|
|
344
|
+
|
|
112
345
|
def Status(self, id: str) -> InvoiceModel:
|
|
113
346
|
# Prepare request
|
|
114
347
|
request = Request(
|
|
@@ -121,14 +354,12 @@ class ApiClient:
|
|
|
121
354
|
|
|
122
355
|
# Handle response
|
|
123
356
|
response = self._send_request(request)
|
|
124
|
-
self.logger(request, response)
|
|
125
357
|
if not response.success:
|
|
126
358
|
raise APIResponseError(response)
|
|
127
359
|
|
|
128
360
|
return response.cast(InvoiceModel, APIResponseError)
|
|
129
361
|
|
|
130
|
-
|
|
131
|
-
def token(self) -> AccessToken | None:
|
|
362
|
+
def get_token(self) -> AccessToken | None:
|
|
132
363
|
# First check if valid token is cached
|
|
133
364
|
token = self.cache.get_token('access')
|
|
134
365
|
refresh = self.cache.get_token('refresh')
|
|
@@ -141,27 +372,27 @@ class ApiClient:
|
|
|
141
372
|
|
|
142
373
|
if (refreshed.success):
|
|
143
374
|
access = AccessToken(
|
|
144
|
-
response.
|
|
375
|
+
response.json_body["access_token"]
|
|
145
376
|
)
|
|
146
377
|
refresh = RefreshToken(
|
|
147
|
-
response.
|
|
148
|
-
int(response.
|
|
378
|
+
response.json_body["refresh_token"],
|
|
379
|
+
int(response.json_body["expires_in"]),
|
|
149
380
|
)
|
|
150
381
|
self.cache.set_token(access)
|
|
151
382
|
self.cache.set_token(refresh)
|
|
152
383
|
|
|
153
384
|
return access
|
|
154
385
|
|
|
155
|
-
# try to issue token
|
|
156
|
-
response = self.
|
|
386
|
+
# try to issue token
|
|
387
|
+
response = self._fetch_token()
|
|
157
388
|
if response.success:
|
|
158
389
|
|
|
159
390
|
access = AccessToken(
|
|
160
|
-
response.
|
|
391
|
+
response.json_body["access_token"]
|
|
161
392
|
)
|
|
162
393
|
refresh = RefreshToken(
|
|
163
|
-
response.
|
|
164
|
-
int(response.
|
|
394
|
+
response.json_body["refresh_token"],
|
|
395
|
+
int(response.json_body["expires_in"]),
|
|
165
396
|
)
|
|
166
397
|
self.cache.set_token(access)
|
|
167
398
|
self.cache.set_token(refresh)
|
|
@@ -174,24 +405,23 @@ class ApiClient:
|
|
|
174
405
|
"""
|
|
175
406
|
Send a specified Request to the GoPay REST API and process the response
|
|
176
407
|
"""
|
|
177
|
-
body = asdict(request.body) if is_dataclass(request.body) else request.body
|
|
178
408
|
# Add Bearer authentication to headers if needed
|
|
179
409
|
headers = request.headers or {}
|
|
180
410
|
if not request.noAuth:
|
|
181
|
-
auth = self.
|
|
411
|
+
auth = self.get_token()
|
|
182
412
|
if auth is not None:
|
|
183
413
|
headers["Authorization"] = f"Bearer {auth.token}"
|
|
184
414
|
|
|
185
415
|
if (request.method == 'get'):
|
|
186
416
|
params = urlencode(body)
|
|
187
|
-
r =
|
|
417
|
+
r = httpx.request(
|
|
188
418
|
method=request.method,
|
|
189
419
|
url=f"{self.baseUrl}{request.path}?{params}",
|
|
190
420
|
headers=headers,
|
|
191
421
|
timeout=self.timeout
|
|
192
422
|
)
|
|
193
423
|
else:
|
|
194
|
-
r =
|
|
424
|
+
r = httpx.request(
|
|
195
425
|
method=request.method,
|
|
196
426
|
url=f"{self.baseUrl}{request.path}",
|
|
197
427
|
headers=headers,
|
|
@@ -202,18 +432,13 @@ class ApiClient:
|
|
|
202
432
|
# Build Response instance, try to decode body as JSON
|
|
203
433
|
response = Response(raw_body=r.content, json={}, status_code=r.status_code)
|
|
204
434
|
|
|
205
|
-
if (self.REQUEST_DEBUG):
|
|
206
|
-
print(f"{request.method} => {self.baseUrl}{request.path} => {response.status_code}")
|
|
207
|
-
|
|
208
435
|
try:
|
|
209
|
-
response.
|
|
436
|
+
response.json_body = r.json()
|
|
210
437
|
except json.JSONDecodeError:
|
|
211
438
|
pass
|
|
212
|
-
|
|
213
|
-
self.logger(request, response)
|
|
214
439
|
return response
|
|
215
440
|
|
|
216
|
-
def
|
|
441
|
+
def _fetch_token(self) -> Response:
|
|
217
442
|
# Prepare request
|
|
218
443
|
request = Request(
|
|
219
444
|
method="post",
|
|
@@ -224,9 +449,8 @@ class ApiClient:
|
|
|
224
449
|
)
|
|
225
450
|
# Handle response
|
|
226
451
|
response = self._send_request(request)
|
|
227
|
-
self.logger(request, response)
|
|
228
452
|
return response
|
|
229
|
-
|
|
453
|
+
|
|
230
454
|
def _refresh_token(self) -> Response:
|
|
231
455
|
# Prepare request
|
|
232
456
|
request = Request(
|
|
@@ -237,5 +461,4 @@ class ApiClient:
|
|
|
237
461
|
)
|
|
238
462
|
# Handle response
|
|
239
463
|
response = self._send_request(request)
|
|
240
|
-
self.logger(request, response)
|
|
241
464
|
return response
|