payme-pkg 3.0.24__py3-none-any.whl → 3.0.28__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 payme-pkg might be problematic. Click here for more details.
- payme/admin.py +1 -1
- payme/classes/cards.py +1 -1
- payme/classes/client.py +11 -9
- payme/classes/initializer.py +5 -10
- payme/classes/receipts.py +71 -67
- payme/exceptions/webhook.py +36 -25
- payme/migrations/0004_alter_paymetransactions_account_id.py +18 -0
- payme/models.py +1 -1
- payme/types/response/cards.py +13 -3
- payme/types/response/receipts.py +54 -30
- payme/types/response/webhook.py +24 -14
- payme/views.py +14 -10
- {payme_pkg-3.0.24.dist-info → payme_pkg-3.0.28.dist-info}/METADATA +14 -5
- payme_pkg-3.0.28.dist-info/RECORD +33 -0
- {payme_pkg-3.0.24.dist-info → payme_pkg-3.0.28.dist-info}/WHEEL +1 -1
- payme_pkg-3.0.24.dist-info/RECORD +0 -32
- {payme_pkg-3.0.24.dist-info → payme_pkg-3.0.28.dist-info/licenses}/LICENSE.txt +0 -0
- {payme_pkg-3.0.24.dist-info → payme_pkg-3.0.28.dist-info}/top_level.txt +0 -0
payme/admin.py
CHANGED
|
@@ -8,7 +8,7 @@ class PaymeTransactionsUI(admin.ModelAdmin):
|
|
|
8
8
|
"""
|
|
9
9
|
Custom admin interface for PaymeTransactions model.
|
|
10
10
|
"""
|
|
11
|
-
list_display = ('
|
|
11
|
+
list_display = ('pk', 'state', 'cancel_reason', 'created_at')
|
|
12
12
|
list_filter = ('state', 'cancel_reason', 'created_at')
|
|
13
13
|
search_fields = ('transaction_id', 'account_id')
|
|
14
14
|
ordering = ('-created_at',)
|
payme/classes/cards.py
CHANGED
|
@@ -19,7 +19,7 @@ class Cards:
|
|
|
19
19
|
services. It allows you to create new cards and retrieve verification
|
|
20
20
|
codes for existing cards.
|
|
21
21
|
"""
|
|
22
|
-
def __init__(self, url: str, payme_id: str) ->
|
|
22
|
+
def __init__(self, url: str, payme_id: str) -> None:
|
|
23
23
|
"""
|
|
24
24
|
Initialize the Cards client.
|
|
25
25
|
|
payme/classes/client.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import Union
|
|
1
|
+
import typing as t
|
|
3
2
|
|
|
4
3
|
from payme.const import Networks
|
|
5
4
|
from payme.classes.cards import Cards
|
|
@@ -11,14 +10,14 @@ class Payme:
|
|
|
11
10
|
"""
|
|
12
11
|
The payme class provides a simple interface
|
|
13
12
|
"""
|
|
13
|
+
|
|
14
14
|
def __init__(
|
|
15
15
|
self,
|
|
16
16
|
payme_id: str,
|
|
17
|
-
fallback_id:
|
|
18
|
-
payme_key:
|
|
19
|
-
is_test_mode: bool = False
|
|
20
|
-
):
|
|
21
|
-
|
|
17
|
+
fallback_id: t.Optional[str] = None,
|
|
18
|
+
payme_key: t.Optional[str] = None,
|
|
19
|
+
is_test_mode: bool = False,
|
|
20
|
+
) -> None:
|
|
22
21
|
# initialize payme network
|
|
23
22
|
url = Networks.PROD_NET.value
|
|
24
23
|
|
|
@@ -26,5 +25,8 @@ class Payme:
|
|
|
26
25
|
url = Networks.TEST_NET.value
|
|
27
26
|
|
|
28
27
|
self.cards = Cards(url=url, payme_id=payme_id)
|
|
29
|
-
self.initializer = Initializer(
|
|
30
|
-
|
|
28
|
+
self.initializer = Initializer(
|
|
29
|
+
payme_id=payme_id, fallback_id=fallback_id, is_test_mode=is_test_mode
|
|
30
|
+
)
|
|
31
|
+
if payme_key:
|
|
32
|
+
self.receipts = Receipts(url=url, payme_id=payme_id, payme_key=payme_key)
|
payme/classes/initializer.py
CHANGED
|
@@ -13,17 +13,14 @@ class Initializer:
|
|
|
13
13
|
The Payme ID associated with your account
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
def __init__(
|
|
16
|
+
def __init__(
|
|
17
|
+
self, payme_id: str = None, fallback_id: str = None, is_test_mode: bool = False
|
|
18
|
+
) -> None:
|
|
17
19
|
self.payme_id = payme_id
|
|
18
20
|
self.fallback_id = fallback_id
|
|
19
21
|
self.is_test_mode = is_test_mode
|
|
20
22
|
|
|
21
|
-
def generate_pay_link(
|
|
22
|
-
self,
|
|
23
|
-
id: int,
|
|
24
|
-
amount: int,
|
|
25
|
-
return_url: str
|
|
26
|
-
) -> str:
|
|
23
|
+
def generate_pay_link(self, id: int, amount: int, return_url: str) -> str:
|
|
27
24
|
"""
|
|
28
25
|
Generate a payment link for a specific order.
|
|
29
26
|
|
|
@@ -52,9 +49,7 @@ class Initializer:
|
|
|
52
49
|
https://developer.help.paycom.uz/initsializatsiya-platezhey/
|
|
53
50
|
"""
|
|
54
51
|
amount = amount * 100 # Convert amount to the smallest currency unit
|
|
55
|
-
params =
|
|
56
|
-
f'm={self.payme_id};ac.{settings.PAYME_ACCOUNT_FIELD}={id};a={amount};c={return_url}'
|
|
57
|
-
)
|
|
52
|
+
params = f"m={self.payme_id};ac.{settings.PAYME_ACCOUNT_FIELD}={id};a={amount};c={return_url}"
|
|
58
53
|
params = base64.b64encode(params.encode("utf-8")).decode("utf-8")
|
|
59
54
|
|
|
60
55
|
if self.is_test_mode is True:
|
payme/classes/receipts.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from urllib.parse import parse_qs
|
|
2
4
|
|
|
3
5
|
from payme.classes.cards import Cards
|
|
4
6
|
from payme.classes.http import HttpClient
|
|
@@ -13,6 +15,7 @@ ALLOWED_METHODS = {
|
|
|
13
15
|
"receipts.check": response.CheckResponse,
|
|
14
16
|
"receipts.get": response.GetResponse,
|
|
15
17
|
"receipts.get_all": response.GetAllResponse,
|
|
18
|
+
"receipts.set_fiscal_data": response.SetFiscalDataResponse,
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
|
|
@@ -20,7 +23,8 @@ class Receipts:
|
|
|
20
23
|
"""
|
|
21
24
|
The Receipts class provides methods to interact with the Payme Receipts.
|
|
22
25
|
"""
|
|
23
|
-
|
|
26
|
+
|
|
27
|
+
def __init__(self, payme_id: str, payme_key: str, url: str) -> None:
|
|
24
28
|
"""
|
|
25
29
|
Initialize the Receipts client.
|
|
26
30
|
|
|
@@ -32,25 +36,25 @@ class Receipts:
|
|
|
32
36
|
|
|
33
37
|
headers = {
|
|
34
38
|
"X-Auth": f"{payme_id}:{payme_key}",
|
|
35
|
-
"Content-Type": "application/json"
|
|
39
|
+
"Content-Type": "application/json",
|
|
36
40
|
}
|
|
37
41
|
self.http = HttpClient(url, headers)
|
|
38
42
|
|
|
39
43
|
def create(
|
|
40
44
|
self,
|
|
41
45
|
account: dict,
|
|
42
|
-
amount: Union[float, int],
|
|
43
|
-
description: Optional[str] = None,
|
|
44
|
-
detail: Optional[
|
|
45
|
-
timeout: int = 10
|
|
46
|
+
amount: t.Union[float, int],
|
|
47
|
+
description: t.Optional[str] = None,
|
|
48
|
+
detail: t.Optional[t.Dict] = None,
|
|
49
|
+
timeout: int = 10,
|
|
46
50
|
) -> response.CreateResponse:
|
|
47
51
|
"""
|
|
48
52
|
Create a new receipt.
|
|
49
53
|
|
|
50
54
|
:param account: The account details for the receipt.
|
|
51
55
|
:param amount: The amount of the receipt.
|
|
52
|
-
:param description: Optional description for the receipt.
|
|
53
|
-
:param detail: Optional additional details for the receipt.
|
|
56
|
+
:param description: t.Optional description for the receipt.
|
|
57
|
+
:param detail: t.Optional additional details for the receipt.
|
|
54
58
|
:param timeout: The request timeout duration in seconds (default 10).
|
|
55
59
|
"""
|
|
56
60
|
method = "receipts.create"
|
|
@@ -58,7 +62,7 @@ class Receipts:
|
|
|
58
62
|
"amount": amount,
|
|
59
63
|
"account": account,
|
|
60
64
|
"description": description,
|
|
61
|
-
"detail": detail
|
|
65
|
+
"detail": detail,
|
|
62
66
|
}
|
|
63
67
|
return self._post_request(method, params, timeout)
|
|
64
68
|
|
|
@@ -74,10 +78,7 @@ class Receipts:
|
|
|
74
78
|
The request timeout duration in seconds (default is 10).
|
|
75
79
|
"""
|
|
76
80
|
method = "receipts.pay"
|
|
77
|
-
params = {
|
|
78
|
-
"id": receipts_id,
|
|
79
|
-
"token": token
|
|
80
|
-
}
|
|
81
|
+
params = {"id": receipts_id, "token": token}
|
|
81
82
|
return self._post_request(method, params, timeout)
|
|
82
83
|
|
|
83
84
|
def send(
|
|
@@ -91,15 +92,10 @@ class Receipts:
|
|
|
91
92
|
:param timeout: The request timeout duration in seconds (default 10).
|
|
92
93
|
"""
|
|
93
94
|
method = "receipts.send"
|
|
94
|
-
params = {
|
|
95
|
-
"id": receipts_id,
|
|
96
|
-
"phone": phone
|
|
97
|
-
}
|
|
95
|
+
params = {"id": receipts_id, "phone": phone}
|
|
98
96
|
return self._post_request(method, params, timeout)
|
|
99
97
|
|
|
100
|
-
def cancel(
|
|
101
|
-
self, receipts_id: str, timeout: int = 10
|
|
102
|
-
) -> response.CancelResponse:
|
|
98
|
+
def cancel(self, receipts_id: str, timeout: int = 10) -> response.CancelResponse:
|
|
103
99
|
"""
|
|
104
100
|
Cancel the receipt.
|
|
105
101
|
|
|
@@ -107,14 +103,10 @@ class Receipts:
|
|
|
107
103
|
:param timeout: The request timeout duration in seconds (default 10).
|
|
108
104
|
"""
|
|
109
105
|
method = "receipts.cancel"
|
|
110
|
-
params = {
|
|
111
|
-
"id": receipts_id
|
|
112
|
-
}
|
|
106
|
+
params = {"id": receipts_id}
|
|
113
107
|
return self._post_request(method, params, timeout)
|
|
114
108
|
|
|
115
|
-
def check(
|
|
116
|
-
self, receipts_id: str, timeout: int = 10
|
|
117
|
-
) -> response.CheckResponse:
|
|
109
|
+
def check(self, receipts_id: str, timeout: int = 10) -> response.CheckResponse:
|
|
118
110
|
"""
|
|
119
111
|
Check the status of a cheque.
|
|
120
112
|
|
|
@@ -122,14 +114,10 @@ class Receipts:
|
|
|
122
114
|
:param timeout: The request timeout duration in seconds (default 10).
|
|
123
115
|
"""
|
|
124
116
|
method = "receipts.check"
|
|
125
|
-
params = {
|
|
126
|
-
"id": receipts_id
|
|
127
|
-
}
|
|
117
|
+
params = {"id": receipts_id}
|
|
128
118
|
return self._post_request(method, params, timeout)
|
|
129
119
|
|
|
130
|
-
def get(
|
|
131
|
-
self, receipts_id: str, timeout: int = 10
|
|
132
|
-
) -> response.GetResponse:
|
|
120
|
+
def get(self, receipts_id: str, timeout: int = 10) -> response.GetResponse:
|
|
133
121
|
"""
|
|
134
122
|
Get the details of a specific cheque.
|
|
135
123
|
|
|
@@ -137,29 +125,52 @@ class Receipts:
|
|
|
137
125
|
:param timeout: The request timeout duration in seconds (default 10).
|
|
138
126
|
"""
|
|
139
127
|
method = "receipts.get"
|
|
140
|
-
params = {
|
|
141
|
-
"id": receipts_id
|
|
142
|
-
}
|
|
128
|
+
params = {"id": receipts_id}
|
|
143
129
|
return self._post_request(method, params, timeout)
|
|
144
130
|
|
|
145
131
|
def get_all(
|
|
146
132
|
self, count: int, from_: int, to: int, offset: int, timeout: int = 10
|
|
147
133
|
) -> response.GetAllResponse:
|
|
148
134
|
"""
|
|
149
|
-
|
|
135
|
+
Get all cheques for a specific account.
|
|
150
136
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
137
|
+
:param count: The number of cheques to retrieve.
|
|
138
|
+
:param from_: The start index of the cheques to retrieve.
|
|
139
|
+
:param to: The end index of the cheques to retrieve.
|
|
140
|
+
:param offset: The offset for pagination.
|
|
141
|
+
:param timeout: The request timeout duration in seconds (default 10).
|
|
156
142
|
"""
|
|
157
143
|
method = "receipts.get_all"
|
|
144
|
+
params = {"count": count, "from": from_, "to": to, "offset": offset}
|
|
145
|
+
return self._post_request(method, params, timeout)
|
|
146
|
+
|
|
147
|
+
def set_fiscal_data(
|
|
148
|
+
self, receipt_id: str, qr_code_url: str, timeout: int = 10
|
|
149
|
+
) -> response.SetFiscalDataResponse:
|
|
150
|
+
"""
|
|
151
|
+
Get all cheques for a specific account.
|
|
152
|
+
|
|
153
|
+
:param receipt_id: The ID of the check used for payment.
|
|
154
|
+
:param qr_code_url: URL of the fiscal check from the ofd.uz.
|
|
155
|
+
:param timeout: The request timeout duration in seconds (default 10).
|
|
156
|
+
"""
|
|
157
|
+
method = "receipts.set_fiscal_data"
|
|
158
|
+
|
|
159
|
+
check_params = parse_qs(qr_code_url.split("?")[1])
|
|
160
|
+
terminal_id = check_params["t"][0]
|
|
161
|
+
fiscal_sign = check_params["s"][0]
|
|
162
|
+
fiscal_receipt_id = check_params["r"][0]
|
|
163
|
+
fiscal_date = check_params["c"][0]
|
|
164
|
+
|
|
158
165
|
params = {
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
"id": receipt_id, # required
|
|
167
|
+
"fiscal_data": {
|
|
168
|
+
"terminal_id": terminal_id,
|
|
169
|
+
"receipt_id": int(fiscal_receipt_id), # required
|
|
170
|
+
"date": fiscal_date,
|
|
171
|
+
"fiscal_sign": fiscal_sign,
|
|
172
|
+
"qr_code_url": qr_code_url, # required
|
|
173
|
+
}
|
|
163
174
|
}
|
|
164
175
|
return self._post_request(method, params, timeout)
|
|
165
176
|
|
|
@@ -185,6 +196,7 @@ class Receipts:
|
|
|
185
196
|
covering creation, payment, sending, cancellation, status checks,
|
|
186
197
|
retrieval of a single receipt, and retrieval of multiple receipts.
|
|
187
198
|
"""
|
|
199
|
+
|
|
188
200
|
# Helper to assert conditions with messaging
|
|
189
201
|
def assert_condition(condition, message, test_case):
|
|
190
202
|
self._assert_and_print(condition, message, test_case=test_case)
|
|
@@ -195,14 +207,14 @@ class Receipts:
|
|
|
195
207
|
account={"id": 12345},
|
|
196
208
|
amount=1000,
|
|
197
209
|
description="Test receipt",
|
|
198
|
-
detail={"key": "value"}
|
|
210
|
+
detail={"key": "value"},
|
|
199
211
|
)
|
|
200
212
|
|
|
201
213
|
# Test 1: Initialization check
|
|
202
214
|
assert_condition(
|
|
203
215
|
isinstance(self, Receipts),
|
|
204
216
|
"Initialized Receipts class successfully.",
|
|
205
|
-
test_case="Initialization Test"
|
|
217
|
+
test_case="Initialization Test",
|
|
206
218
|
)
|
|
207
219
|
|
|
208
220
|
# Test 2: Create and Pay Receipt
|
|
@@ -210,21 +222,19 @@ class Receipts:
|
|
|
210
222
|
assert_condition(
|
|
211
223
|
isinstance(create_response, response.CreateResponse),
|
|
212
224
|
"Created a new receipt successfully.",
|
|
213
|
-
test_case="Receipt Creation Test"
|
|
225
|
+
test_case="Receipt Creation Test",
|
|
214
226
|
)
|
|
215
227
|
|
|
216
228
|
# pylint: disable=W0212
|
|
217
229
|
assert_condition(
|
|
218
230
|
isinstance(create_response.result.receipt._id, str),
|
|
219
231
|
"Created a valid receipt ID.",
|
|
220
|
-
test_case="Receipt ID Test"
|
|
232
|
+
test_case="Receipt ID Test",
|
|
221
233
|
)
|
|
222
234
|
|
|
223
235
|
# Prepare card and verification
|
|
224
236
|
cards_create_response = self.__cards.create(
|
|
225
|
-
number="8600495473316478",
|
|
226
|
-
expire="0399",
|
|
227
|
-
save=True
|
|
237
|
+
number="8600495473316478", expire="0399", save=True
|
|
228
238
|
)
|
|
229
239
|
token = cards_create_response.result.card.token
|
|
230
240
|
self.__cards.get_verify_code(token=token)
|
|
@@ -236,7 +246,7 @@ class Receipts:
|
|
|
236
246
|
assert_condition(
|
|
237
247
|
pay_response.result.receipt.state == 4,
|
|
238
248
|
"Paid the receipt successfully.",
|
|
239
|
-
test_case="Payment Test"
|
|
249
|
+
test_case="Payment Test",
|
|
240
250
|
)
|
|
241
251
|
|
|
242
252
|
# Test 3: Create and Send Receipt
|
|
@@ -246,7 +256,7 @@ class Receipts:
|
|
|
246
256
|
assert_condition(
|
|
247
257
|
send_response.result.success is True,
|
|
248
258
|
"Sent the receipt successfully.",
|
|
249
|
-
test_case="Send Test"
|
|
259
|
+
test_case="Send Test",
|
|
250
260
|
)
|
|
251
261
|
|
|
252
262
|
# Test 4: Create and Cancel Receipt
|
|
@@ -256,7 +266,7 @@ class Receipts:
|
|
|
256
266
|
assert_condition(
|
|
257
267
|
cancel_response.result.receipt.state == 50,
|
|
258
268
|
"Cancelled the receipt successfully.",
|
|
259
|
-
test_case="Cancel Test"
|
|
269
|
+
test_case="Cancel Test",
|
|
260
270
|
)
|
|
261
271
|
|
|
262
272
|
# Test 5: Check Receipt Status
|
|
@@ -264,7 +274,7 @@ class Receipts:
|
|
|
264
274
|
assert_condition(
|
|
265
275
|
check_response.result.state == 50,
|
|
266
276
|
"Checked the receipt status successfully.",
|
|
267
|
-
test_case="Check Test"
|
|
277
|
+
test_case="Check Test",
|
|
268
278
|
)
|
|
269
279
|
|
|
270
280
|
# Test 6: Get Receipt Details
|
|
@@ -272,27 +282,21 @@ class Receipts:
|
|
|
272
282
|
assert_condition(
|
|
273
283
|
get_response.result.receipt._id == receipt_id,
|
|
274
284
|
"Retrieved the receipt details successfully.",
|
|
275
|
-
test_case="Get Test"
|
|
285
|
+
test_case="Get Test",
|
|
276
286
|
)
|
|
277
287
|
|
|
278
288
|
# Test 7: Retrieve All Receipts
|
|
279
289
|
get_all_response = self.get_all(
|
|
280
|
-
count=1,
|
|
281
|
-
from_=1730322122000,
|
|
282
|
-
to=1730398982000,
|
|
283
|
-
offset=0
|
|
290
|
+
count=1, from_=1730322122000, to=1730398982000, offset=0
|
|
284
291
|
)
|
|
285
292
|
assert_condition(
|
|
286
293
|
isinstance(get_all_response.result, list),
|
|
287
294
|
"Retrieved all receipts successfully.",
|
|
288
|
-
test_case="Get All Test"
|
|
295
|
+
test_case="Get All Test",
|
|
289
296
|
)
|
|
290
297
|
|
|
291
298
|
# pylint: disable=W0212
|
|
292
299
|
def _assert_and_print(
|
|
293
|
-
self,
|
|
294
|
-
condition: bool,
|
|
295
|
-
success_message: str,
|
|
296
|
-
test_case: Optional[str] = None
|
|
300
|
+
self, condition: bool, success_message: str, test_case: t.Optional[str] = None
|
|
297
301
|
):
|
|
298
302
|
self.__cards._assert_and_print(condition, success_message, test_case)
|
payme/exceptions/webhook.py
CHANGED
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Init Payme base exception.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import logging
|
|
6
|
+
import typing as t
|
|
7
|
+
|
|
8
|
+
from rest_framework import status
|
|
5
9
|
from rest_framework.exceptions import APIException
|
|
6
10
|
|
|
7
11
|
logger = logging.getLogger(__name__)
|
|
8
12
|
|
|
13
|
+
MessageT = t.Optional[t.Union[str, t.Dict[str, str]]]
|
|
14
|
+
|
|
9
15
|
|
|
10
16
|
class BasePaymeException(APIException):
|
|
11
17
|
"""
|
|
12
18
|
BasePaymeException inherits from APIException.
|
|
13
19
|
"""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
|
|
21
|
+
status_code: int = status.HTTP_200_OK
|
|
22
|
+
error_code: t.Optional[int] = None
|
|
23
|
+
message: MessageT = None
|
|
17
24
|
|
|
18
25
|
# pylint: disable=super-init-not-called
|
|
19
26
|
def __init__(self, message: str = None):
|
|
20
27
|
detail: dict = {
|
|
21
|
-
"error": {
|
|
22
|
-
"code": self.error_code,
|
|
23
|
-
"message": self.message,
|
|
24
|
-
"data": message
|
|
25
|
-
}
|
|
28
|
+
"error": {"code": self.error_code, "message": self.message, "data": message}
|
|
26
29
|
}
|
|
27
30
|
logger.error(f"Payme error detail: {detail}")
|
|
28
31
|
self.detail = detail
|
|
@@ -34,7 +37,8 @@ class PermissionDenied(BasePaymeException):
|
|
|
34
37
|
|
|
35
38
|
Raised when the client is not allowed to access the server.
|
|
36
39
|
"""
|
|
37
|
-
|
|
40
|
+
|
|
41
|
+
status_code = status.HTTP_200_OK
|
|
38
42
|
error_code = -32504
|
|
39
43
|
message = "Permission denied."
|
|
40
44
|
|
|
@@ -45,12 +49,13 @@ class InternalServiceError(BasePaymeException):
|
|
|
45
49
|
|
|
46
50
|
Raised when a transaction fails to perform.
|
|
47
51
|
"""
|
|
48
|
-
|
|
52
|
+
|
|
53
|
+
status_code = status.HTTP_200_OK
|
|
49
54
|
error_code = -32400
|
|
50
55
|
message = {
|
|
51
56
|
"uz": "Tizimda xatolik yuzaga keldi.",
|
|
52
57
|
"ru": "Внутренняя ошибка сервиса.",
|
|
53
|
-
"en": "Internal service error."
|
|
58
|
+
"en": "Internal service error.",
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
|
|
@@ -60,7 +65,8 @@ class MethodNotFound(BasePaymeException):
|
|
|
60
65
|
|
|
61
66
|
Raised when the requested method does not exist.
|
|
62
67
|
"""
|
|
63
|
-
|
|
68
|
+
|
|
69
|
+
status_code = status.HTTP_405_METHOD_NOT_ALLOWED
|
|
64
70
|
error_code = -32601
|
|
65
71
|
message = "Method not found."
|
|
66
72
|
|
|
@@ -71,12 +77,13 @@ class AccountDoesNotExist(BasePaymeException):
|
|
|
71
77
|
|
|
72
78
|
Raised when an account does not exist or has been deleted.
|
|
73
79
|
"""
|
|
74
|
-
|
|
80
|
+
|
|
81
|
+
status_code = status.HTTP_200_OK
|
|
75
82
|
error_code = -31050
|
|
76
83
|
message = {
|
|
77
84
|
"uz": "Hisob topilmadi.",
|
|
78
85
|
"ru": "Счет не найден.",
|
|
79
|
-
"en": "Account does not exist."
|
|
86
|
+
"en": "Account does not exist.",
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
|
|
@@ -86,12 +93,13 @@ class IncorrectAmount(BasePaymeException):
|
|
|
86
93
|
|
|
87
94
|
Raised when the provided amount is incorrect.
|
|
88
95
|
"""
|
|
89
|
-
|
|
96
|
+
|
|
97
|
+
status_code = status.HTTP_200_OK
|
|
90
98
|
error_code = -31001
|
|
91
99
|
message = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
"ru": "Неверная сумма.",
|
|
101
|
+
"uz": "Noto'g'ri summa.",
|
|
102
|
+
"en": "Incorrect amount.",
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
|
|
@@ -107,12 +115,13 @@ class TransactionAlreadyExists(BasePaymeException):
|
|
|
107
115
|
error_code (int): The specific error code for this exception.
|
|
108
116
|
message (dict): A dictionary containing localized error messages.
|
|
109
117
|
"""
|
|
110
|
-
|
|
118
|
+
|
|
119
|
+
status_code = status.HTTP_200_OK
|
|
111
120
|
error_code = -31099
|
|
112
121
|
message = {
|
|
113
122
|
"uz": "Tranzaksiya allaqachon mavjud.",
|
|
114
123
|
"ru": "Транзакция уже существует.",
|
|
115
|
-
"en": "Transaction already exists."
|
|
124
|
+
"en": "Transaction already exists.",
|
|
116
125
|
}
|
|
117
126
|
|
|
118
127
|
|
|
@@ -122,12 +131,13 @@ class InvalidFiscalParams(BasePaymeException):
|
|
|
122
131
|
|
|
123
132
|
Raised when the provided fiscal parameters are invalid.
|
|
124
133
|
"""
|
|
125
|
-
|
|
134
|
+
|
|
135
|
+
status_code = status.HTTP_200_OK
|
|
126
136
|
error_code = -32602
|
|
127
137
|
message = {
|
|
128
138
|
"uz": "Fiskal parameterlarida kamchiliklar bor",
|
|
129
139
|
"ru": "Неверные фискальные параметры.",
|
|
130
|
-
"en": "Invalid fiscal parameters."
|
|
140
|
+
"en": "Invalid fiscal parameters.",
|
|
131
141
|
}
|
|
132
142
|
|
|
133
143
|
|
|
@@ -137,12 +147,13 @@ class InvalidAccount(BasePaymeException):
|
|
|
137
147
|
|
|
138
148
|
Raised when the provided account is invalid.
|
|
139
149
|
"""
|
|
140
|
-
|
|
150
|
+
|
|
151
|
+
status_code = status.HTTP_200_OK
|
|
141
152
|
error_code = -32400
|
|
142
153
|
message = {
|
|
143
154
|
"uz": "Hisob nomida kamchilik bor",
|
|
144
155
|
"ru": "Неверный номер счета.",
|
|
145
|
-
"en": "Invalid account."
|
|
156
|
+
"en": "Invalid account.",
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
|
|
@@ -153,5 +164,5 @@ exception_whitelist = (
|
|
|
153
164
|
AccountDoesNotExist,
|
|
154
165
|
TransactionAlreadyExists,
|
|
155
166
|
InvalidFiscalParams,
|
|
156
|
-
InvalidAccount
|
|
167
|
+
InvalidAccount,
|
|
157
168
|
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.2.5 on 2025-08-25 19:12
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("payme", "0003_alter_paymetransactions_fiscal_data"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name="paymetransactions",
|
|
15
|
+
name="account_id",
|
|
16
|
+
field=models.CharField(max_length=256),
|
|
17
|
+
),
|
|
18
|
+
]
|
payme/models.py
CHANGED
|
@@ -26,7 +26,7 @@ class PaymeTransactions(models.Model):
|
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
transaction_id = models.CharField(max_length=50)
|
|
29
|
-
account_id = models.
|
|
29
|
+
account_id = models.CharField(max_length=256, null=False)
|
|
30
30
|
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
|
31
31
|
state = models.IntegerField(choices=STATE, default=CREATED)
|
|
32
32
|
fiscal_data = models.JSONField(default=dict)
|
payme/types/response/cards.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import typing as t
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
@dataclass
|
|
5
6
|
class Common:
|
|
6
7
|
"""
|
|
7
8
|
The common response structure.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
@classmethod
|
|
11
|
-
def from_dict(cls, data: Dict):
|
|
12
|
+
def from_dict(cls, data: t.Dict):
|
|
12
13
|
"""
|
|
13
14
|
Prepare fields for nested dataclasses
|
|
14
15
|
"""
|
|
@@ -30,13 +31,14 @@ class Card(Common):
|
|
|
30
31
|
"""
|
|
31
32
|
The card object represents a credit card.
|
|
32
33
|
"""
|
|
34
|
+
|
|
33
35
|
number: str
|
|
34
36
|
expire: str
|
|
35
37
|
token: str
|
|
36
38
|
recurrent: bool
|
|
37
39
|
verify: bool
|
|
38
40
|
type: str
|
|
39
|
-
number_hash: Optional[str] = None
|
|
41
|
+
number_hash: t.Optional[str] = None
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
@dataclass
|
|
@@ -44,6 +46,7 @@ class Result(Common):
|
|
|
44
46
|
"""
|
|
45
47
|
The result object contains the created card.
|
|
46
48
|
"""
|
|
49
|
+
|
|
47
50
|
card: Card
|
|
48
51
|
|
|
49
52
|
|
|
@@ -52,6 +55,7 @@ class CardsCreateResponse(Common):
|
|
|
52
55
|
"""
|
|
53
56
|
The cards.create response.
|
|
54
57
|
"""
|
|
58
|
+
|
|
55
59
|
jsonrpc: str
|
|
56
60
|
result: Result
|
|
57
61
|
|
|
@@ -61,6 +65,7 @@ class VerifyResult(Common):
|
|
|
61
65
|
"""
|
|
62
66
|
The result object for the verification response.
|
|
63
67
|
"""
|
|
68
|
+
|
|
64
69
|
sent: bool
|
|
65
70
|
phone: str
|
|
66
71
|
wait: int
|
|
@@ -71,6 +76,7 @@ class GetVerifyResponse(Common):
|
|
|
71
76
|
"""
|
|
72
77
|
The verification response structure.
|
|
73
78
|
"""
|
|
79
|
+
|
|
74
80
|
jsonrpc: str
|
|
75
81
|
result: VerifyResult
|
|
76
82
|
|
|
@@ -80,6 +86,7 @@ class VerifyResponse(Common):
|
|
|
80
86
|
"""
|
|
81
87
|
The verification response structure.
|
|
82
88
|
"""
|
|
89
|
+
|
|
83
90
|
jsonrpc: str
|
|
84
91
|
result: Result
|
|
85
92
|
|
|
@@ -89,6 +96,7 @@ class RemoveCardResult(Common):
|
|
|
89
96
|
"""
|
|
90
97
|
The result object for the removal response.
|
|
91
98
|
"""
|
|
99
|
+
|
|
92
100
|
success: bool
|
|
93
101
|
|
|
94
102
|
|
|
@@ -97,6 +105,7 @@ class RemoveResponse(Common):
|
|
|
97
105
|
"""
|
|
98
106
|
The remove response structure.
|
|
99
107
|
"""
|
|
108
|
+
|
|
100
109
|
jsonrpc: str
|
|
101
110
|
result: RemoveCardResult
|
|
102
111
|
|
|
@@ -106,5 +115,6 @@ class CheckResponse(Common):
|
|
|
106
115
|
"""
|
|
107
116
|
The check response structure.
|
|
108
117
|
"""
|
|
118
|
+
|
|
109
119
|
jsonrpc: str
|
|
110
120
|
result: Result
|
payme/types/response/receipts.py
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import typing as t
|
|
1
2
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Dict, Optional, Union
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
@dataclass
|
|
5
6
|
class Common:
|
|
6
7
|
"""
|
|
7
8
|
The common response structure.
|
|
8
9
|
"""
|
|
10
|
+
|
|
9
11
|
jsonrpc: str
|
|
10
12
|
id: int
|
|
11
13
|
|
|
12
14
|
@classmethod
|
|
13
|
-
def from_dict(cls, data: Dict):
|
|
15
|
+
def from_dict(cls, data: t.Dict):
|
|
14
16
|
"""
|
|
15
17
|
Prepare fields for nested dataclasses
|
|
16
18
|
"""
|
|
@@ -32,6 +34,7 @@ class Account(Common):
|
|
|
32
34
|
"""
|
|
33
35
|
The account object represents a user's banking account.
|
|
34
36
|
"""
|
|
37
|
+
|
|
35
38
|
_id: str
|
|
36
39
|
account_number: str
|
|
37
40
|
account_name: str
|
|
@@ -46,10 +49,11 @@ class PaymentMethod(Common):
|
|
|
46
49
|
"""
|
|
47
50
|
The payment method object represents a user's payment method.
|
|
48
51
|
"""
|
|
52
|
+
|
|
49
53
|
name: str
|
|
50
54
|
title: str
|
|
51
55
|
value: str
|
|
52
|
-
main: Optional[bool] = None
|
|
56
|
+
main: t.Optional[bool] = None
|
|
53
57
|
|
|
54
58
|
|
|
55
59
|
@dataclass
|
|
@@ -57,9 +61,10 @@ class Detail(Common):
|
|
|
57
61
|
"""
|
|
58
62
|
The detail object represents additional details for a receipt.
|
|
59
63
|
"""
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
|
|
65
|
+
discount: t.Optional[str] = None
|
|
66
|
+
shipping: t.Optional[str] = None
|
|
67
|
+
items: t.Optional[str] = None
|
|
63
68
|
|
|
64
69
|
|
|
65
70
|
# pylint: disable=C0103
|
|
@@ -68,6 +73,7 @@ class MerchantEpos(Common):
|
|
|
68
73
|
"""
|
|
69
74
|
The merchantEpos object represents a user's ePOS.
|
|
70
75
|
"""
|
|
76
|
+
|
|
71
77
|
eposId: str
|
|
72
78
|
eposName: str
|
|
73
79
|
eposType: str
|
|
@@ -79,9 +85,10 @@ class Meta(Common):
|
|
|
79
85
|
"""
|
|
80
86
|
The meta object represents additional metadata for a receipt.
|
|
81
87
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
|
|
89
|
+
source: t.Any = None
|
|
90
|
+
owner: t.Any = None
|
|
91
|
+
host: t.Any = None
|
|
85
92
|
|
|
86
93
|
|
|
87
94
|
@dataclass
|
|
@@ -89,17 +96,18 @@ class Merchant:
|
|
|
89
96
|
"""
|
|
90
97
|
The merchant object represents a user's merchant.
|
|
91
98
|
"""
|
|
99
|
+
|
|
92
100
|
_id: str
|
|
93
101
|
name: str
|
|
94
102
|
organization: str
|
|
95
|
-
address: Optional[str] = None
|
|
96
|
-
business_id: Optional[str] = None
|
|
97
|
-
epos: Optional[MerchantEpos] = None
|
|
98
|
-
restrictions: Optional[str] = None
|
|
99
|
-
date: Optional[int] = None
|
|
100
|
-
logo: Optional[str] = None
|
|
101
|
-
type: Optional[str] = None
|
|
102
|
-
terms: Optional[str] = None
|
|
103
|
+
address: t.Optional[str] = None
|
|
104
|
+
business_id: t.Optional[str] = None
|
|
105
|
+
epos: t.Optional[MerchantEpos] = None
|
|
106
|
+
restrictions: t.Optional[str] = None
|
|
107
|
+
date: t.Optional[int] = None
|
|
108
|
+
logo: t.Optional[str] = None
|
|
109
|
+
type: t.Optional[str] = None
|
|
110
|
+
terms: t.Optional[str] = None
|
|
103
111
|
|
|
104
112
|
|
|
105
113
|
@dataclass
|
|
@@ -107,6 +115,7 @@ class Payer(Common):
|
|
|
107
115
|
"""
|
|
108
116
|
The payer object represents a user's payer.
|
|
109
117
|
"""
|
|
118
|
+
|
|
110
119
|
phone: str
|
|
111
120
|
|
|
112
121
|
|
|
@@ -115,6 +124,7 @@ class Receipt(Common):
|
|
|
115
124
|
"""
|
|
116
125
|
The receipt object represents a payment receipt.
|
|
117
126
|
"""
|
|
127
|
+
|
|
118
128
|
_id: str
|
|
119
129
|
create_time: int
|
|
120
130
|
pay_time: int
|
|
@@ -123,19 +133,19 @@ class Receipt(Common):
|
|
|
123
133
|
type: int
|
|
124
134
|
external: bool
|
|
125
135
|
operation: int
|
|
126
|
-
error:
|
|
127
|
-
description: str = None
|
|
128
|
-
detail: Detail = None
|
|
129
|
-
currency: int = None
|
|
130
|
-
commission: int = None
|
|
131
|
-
card: str = None
|
|
132
|
-
creator: str = None
|
|
133
|
-
payer: Payer = None
|
|
134
|
-
amount: Union[float, int] = None
|
|
135
|
-
account:
|
|
136
|
-
merchant: Merchant = None
|
|
137
|
-
processing_id: str = None
|
|
138
|
-
meta: Meta = None
|
|
136
|
+
error: t.Any = None
|
|
137
|
+
description: t.Optional[str] = None
|
|
138
|
+
detail: t.Optional[Detail] = None
|
|
139
|
+
currency: t.Optional[int] = None
|
|
140
|
+
commission: t.Optional[int] = None
|
|
141
|
+
card: t.Optional[str] = None
|
|
142
|
+
creator: t.Optional[str] = None
|
|
143
|
+
payer: t.Optional[Payer] = None
|
|
144
|
+
amount: t.Optional[t.Union[float, int]] = None
|
|
145
|
+
account: t.Optional[t.List[Account]] = None
|
|
146
|
+
merchant: t.Optional[Merchant] = None
|
|
147
|
+
processing_id: t.Optional[str] = None
|
|
148
|
+
meta: t.Optional[Meta] = None
|
|
139
149
|
|
|
140
150
|
|
|
141
151
|
@dataclass
|
|
@@ -143,6 +153,7 @@ class CreateResult(Common):
|
|
|
143
153
|
"""
|
|
144
154
|
The result object for the create response.
|
|
145
155
|
"""
|
|
156
|
+
|
|
146
157
|
receipt: Receipt
|
|
147
158
|
|
|
148
159
|
|
|
@@ -151,6 +162,7 @@ class CreateResponse(Common):
|
|
|
151
162
|
"""
|
|
152
163
|
The create response structure.
|
|
153
164
|
"""
|
|
165
|
+
|
|
154
166
|
result: CreateResult
|
|
155
167
|
|
|
156
168
|
|
|
@@ -166,6 +178,7 @@ class SendResult(Common):
|
|
|
166
178
|
"""
|
|
167
179
|
The result object for the send response.
|
|
168
180
|
"""
|
|
181
|
+
|
|
169
182
|
success: bool
|
|
170
183
|
|
|
171
184
|
|
|
@@ -174,6 +187,7 @@ class SendResponse(Common):
|
|
|
174
187
|
"""
|
|
175
188
|
The send response structure.
|
|
176
189
|
"""
|
|
190
|
+
|
|
177
191
|
result: SendResult
|
|
178
192
|
|
|
179
193
|
|
|
@@ -189,6 +203,7 @@ class CheckResult(Common):
|
|
|
189
203
|
"""
|
|
190
204
|
The result object for the check response.
|
|
191
205
|
"""
|
|
206
|
+
|
|
192
207
|
state: int
|
|
193
208
|
|
|
194
209
|
|
|
@@ -197,6 +212,7 @@ class CheckResponse(Common):
|
|
|
197
212
|
"""
|
|
198
213
|
The check response structure.
|
|
199
214
|
"""
|
|
215
|
+
|
|
200
216
|
result: CheckResult
|
|
201
217
|
|
|
202
218
|
|
|
@@ -213,3 +229,11 @@ class GetAllResponse(Common):
|
|
|
213
229
|
The result object for the get all response.
|
|
214
230
|
"""
|
|
215
231
|
result: list[Receipt] = None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@dataclass
|
|
235
|
+
class SetFiscalDataResponse(Common):
|
|
236
|
+
"""
|
|
237
|
+
The result object for the set_fiscal_data response.
|
|
238
|
+
"""
|
|
239
|
+
result: SendResult
|
payme/types/response/webhook.py
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import typing as t
|
|
1
2
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import List, Optional, Dict
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class CommonResponse:
|
|
6
6
|
"""
|
|
7
7
|
The common response structure
|
|
8
8
|
"""
|
|
9
|
+
|
|
9
10
|
def as_resp(self):
|
|
10
|
-
response = {
|
|
11
|
+
response = {"result": {}}
|
|
11
12
|
for key, value in self.__dict__.items():
|
|
12
|
-
response[
|
|
13
|
+
response["result"][key] = value
|
|
13
14
|
return response
|
|
14
15
|
|
|
15
16
|
|
|
@@ -18,6 +19,7 @@ class Shipping(CommonResponse):
|
|
|
18
19
|
"""
|
|
19
20
|
Shipping information response structure
|
|
20
21
|
"""
|
|
22
|
+
|
|
21
23
|
title: str
|
|
22
24
|
price: int
|
|
23
25
|
|
|
@@ -27,6 +29,7 @@ class Item(CommonResponse):
|
|
|
27
29
|
"""
|
|
28
30
|
Item information response structure
|
|
29
31
|
"""
|
|
32
|
+
|
|
30
33
|
discount: int
|
|
31
34
|
title: str
|
|
32
35
|
price: int
|
|
@@ -45,7 +48,7 @@ class Item(CommonResponse):
|
|
|
45
48
|
"code": self.code,
|
|
46
49
|
"units": self.units,
|
|
47
50
|
"vat_percent": self.vat_percent,
|
|
48
|
-
"package_code": self.package_code
|
|
51
|
+
"package_code": self.package_code,
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
|
|
@@ -54,11 +57,12 @@ class CheckPerformTransaction(CommonResponse):
|
|
|
54
57
|
"""
|
|
55
58
|
Receipt information response structure for transaction checks.
|
|
56
59
|
"""
|
|
60
|
+
|
|
57
61
|
allow: bool
|
|
58
|
-
additional: Optional[Dict[str, str]] = None
|
|
59
|
-
receipt_type: Optional[int] = None
|
|
60
|
-
shipping: Optional[Shipping] = None
|
|
61
|
-
items: List[Item] = field(default_factory=list)
|
|
62
|
+
additional: t.Optional[t.Dict[str, str]] = None
|
|
63
|
+
receipt_type: t.Optional[int] = None
|
|
64
|
+
shipping: t.Optional[Shipping] = None
|
|
65
|
+
items: t.List[Item] = field(default_factory=list)
|
|
62
66
|
|
|
63
67
|
def add_item(self, item: Item):
|
|
64
68
|
self.items.append(item)
|
|
@@ -90,9 +94,10 @@ class CreateTransaction(CommonResponse):
|
|
|
90
94
|
"""
|
|
91
95
|
The create transaction request
|
|
92
96
|
"""
|
|
97
|
+
|
|
93
98
|
transaction: str
|
|
94
99
|
state: str
|
|
95
|
-
create_time:
|
|
100
|
+
create_time: int
|
|
96
101
|
|
|
97
102
|
|
|
98
103
|
@dataclass
|
|
@@ -100,9 +105,10 @@ class PerformTransaction(CommonResponse):
|
|
|
100
105
|
"""
|
|
101
106
|
The perform transaction response
|
|
102
107
|
"""
|
|
108
|
+
|
|
103
109
|
transaction: str
|
|
104
110
|
state: str
|
|
105
|
-
perform_time:
|
|
111
|
+
perform_time: int
|
|
106
112
|
|
|
107
113
|
|
|
108
114
|
@dataclass
|
|
@@ -110,6 +116,7 @@ class CancelTransaction(CommonResponse):
|
|
|
110
116
|
"""
|
|
111
117
|
The cancel transaction request
|
|
112
118
|
"""
|
|
119
|
+
|
|
113
120
|
transaction: str
|
|
114
121
|
state: str
|
|
115
122
|
cancel_time: str
|
|
@@ -120,12 +127,13 @@ class CheckTransaction(CommonResponse):
|
|
|
120
127
|
"""
|
|
121
128
|
The check transaction request
|
|
122
129
|
"""
|
|
130
|
+
|
|
123
131
|
transaction: str
|
|
124
132
|
state: str
|
|
125
133
|
reason: str
|
|
126
|
-
create_time:
|
|
127
|
-
perform_time: Optional[
|
|
128
|
-
cancel_time: Optional[
|
|
134
|
+
create_time: int
|
|
135
|
+
perform_time: t.Optional[int] = None
|
|
136
|
+
cancel_time: t.Optional[int] = None
|
|
129
137
|
|
|
130
138
|
|
|
131
139
|
@dataclass
|
|
@@ -133,7 +141,8 @@ class GetStatement(CommonResponse):
|
|
|
133
141
|
"""
|
|
134
142
|
The check perform transactions response
|
|
135
143
|
"""
|
|
136
|
-
|
|
144
|
+
|
|
145
|
+
transactions: t.List[t.Dict[str, str | int | t.Dict[str, str | int]]]
|
|
137
146
|
|
|
138
147
|
|
|
139
148
|
@dataclass
|
|
@@ -141,4 +150,5 @@ class SetFiscalData(CommonResponse):
|
|
|
141
150
|
"""
|
|
142
151
|
The set fiscal data request
|
|
143
152
|
"""
|
|
153
|
+
|
|
144
154
|
success: bool
|
payme/views.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
from decimal import Decimal
|
|
5
5
|
|
|
6
6
|
from django.conf import settings
|
|
7
|
+
from django.core.exceptions import ValidationError
|
|
7
8
|
from django.utils.module_loading import import_string
|
|
8
9
|
from rest_framework import views
|
|
9
10
|
from rest_framework.response import Response
|
|
@@ -33,6 +34,10 @@ def handle_exceptions(func):
|
|
|
33
34
|
logger.error(f"Account does not exist: {exc} {args} {kwargs}")
|
|
34
35
|
raise exceptions.AccountDoesNotExist(str(exc)) from exc
|
|
35
36
|
|
|
37
|
+
except ValidationError as exc:
|
|
38
|
+
logger.error(f"Invalid account identifier {exc}")
|
|
39
|
+
raise exceptions.AccountDoesNotExist("Invalid account identifier.")
|
|
40
|
+
|
|
36
41
|
except PaymeTransactions.DoesNotExist as exc:
|
|
37
42
|
logger.error(f"Transaction does not exist: {exc} {args} {kwargs}")
|
|
38
43
|
raise exceptions.AccountDoesNotExist(str(exc)) from exc
|
|
@@ -112,17 +117,11 @@ class PaymeWebHookAPIView(views.APIView):
|
|
|
112
117
|
"""
|
|
113
118
|
Fetch account based on settings and params.
|
|
114
119
|
"""
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
account_value = params['account'].get(account_field)
|
|
120
|
+
account_value = params["account"].get(settings.PAYME_ACCOUNT_FIELD)
|
|
118
121
|
if not account_value:
|
|
119
122
|
raise exceptions.InvalidAccount("Missing account field in parameters.")
|
|
120
123
|
|
|
121
|
-
|
|
122
|
-
if account_field == "order_id":
|
|
123
|
-
account_field = "id"
|
|
124
|
-
|
|
125
|
-
account = AccountModel.objects.get(**{account_field: account_value})
|
|
124
|
+
account = AccountModel.objects.get(pk=account_value)
|
|
126
125
|
|
|
127
126
|
return account
|
|
128
127
|
|
|
@@ -169,13 +168,17 @@ class PaymeWebHookAPIView(views.APIView):
|
|
|
169
168
|
defaults = {
|
|
170
169
|
"amount": amount,
|
|
171
170
|
"state": PaymeTransactions.INITIATING,
|
|
172
|
-
"account_id": account.
|
|
171
|
+
"account_id": account.pk,
|
|
173
172
|
}
|
|
174
173
|
|
|
175
174
|
# Handle already existing transaction with the same ID for one-time payments
|
|
176
175
|
if settings.PAYME_ONE_TIME_PAYMENT:
|
|
177
176
|
# Check for an existing transaction with a different transaction_id for the given account
|
|
178
|
-
if
|
|
177
|
+
if (
|
|
178
|
+
PaymeTransactions.objects.filter(account_id=account.pk)
|
|
179
|
+
.exclude(transaction_id=transaction_id)
|
|
180
|
+
.exists()
|
|
181
|
+
):
|
|
179
182
|
message = f"Transaction {transaction_id} already exists (Payme)."
|
|
180
183
|
logger.warning(message)
|
|
181
184
|
raise exceptions.TransactionAlreadyExists(message)
|
|
@@ -297,6 +300,7 @@ class PaymeWebHookAPIView(views.APIView):
|
|
|
297
300
|
"create_time": time_to_payme(transaction.created_at),
|
|
298
301
|
"perform_time": time_to_payme(transaction.performed_at),
|
|
299
302
|
"cancel_time": time_to_payme(transaction.cancelled_at),
|
|
303
|
+
"time": time_to_payme(transaction.created_at),
|
|
300
304
|
})
|
|
301
305
|
|
|
302
306
|
return result.as_resp()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: payme-pkg
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.28
|
|
4
4
|
Home-page: https://github.com/Muhammadali-Akbarov/payme-pkg
|
|
5
5
|
Author: Muhammadali Akbarov
|
|
6
6
|
Author-email: muhammadali17abc@gmail.com
|
|
@@ -8,9 +8,18 @@ License: MIT
|
|
|
8
8
|
Keywords: paymeuz paycomuz payme-merchant merchant-api subscribe-api payme-pkg payme-api
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE.txt
|
|
11
|
-
Requires-Dist: requests
|
|
12
|
-
Requires-Dist:
|
|
13
|
-
Requires-Dist:
|
|
11
|
+
Requires-Dist: requests==2.*
|
|
12
|
+
Requires-Dist: dataclasses==0.*; python_version < "3.7"
|
|
13
|
+
Requires-Dist: djangorestframework==3.*
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: description
|
|
17
|
+
Dynamic: description-content-type
|
|
18
|
+
Dynamic: home-page
|
|
19
|
+
Dynamic: keywords
|
|
20
|
+
Dynamic: license
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: requires-dist
|
|
14
23
|
|
|
15
24
|
<h1 align="center">Payme Software Development Kit</h1>
|
|
16
25
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
payme/__init__.py,sha256=dzLIyA9kQl0sO6z9nHkZDTjkfiI1BepdifKtJbjX2Cw,46
|
|
2
|
+
payme/admin.py,sha256=dEpd49Qo-LqhRH5FgZ8EiwVYOL4RxNrJa3uP_bkOoSE,561
|
|
3
|
+
payme/apps.py,sha256=HHCY4zUNKPcjz25z0MahZcks0lsAxTGPS0Ml3U4DhZc,142
|
|
4
|
+
payme/const.py,sha256=azndfKR53fe7mDfGW82Q-kwWdMu3x4S1upKc4gkYdlA,214
|
|
5
|
+
payme/models.py,sha256=dpFCQOPXCU1JjNJgqjUb7rUxflSnCkiTCwaTzWWCbD0,4189
|
|
6
|
+
payme/urls.py,sha256=_oUOwxW1Suc5TUmnj--lySYbotRg4yTDkDLJU20CGjE,145
|
|
7
|
+
payme/util.py,sha256=UFb4cEnaufS_hh9C_0z079CSgJGivYjIgOl2iAFrBMs,625
|
|
8
|
+
payme/views.py,sha256=Zd9bp1ZBwRsfQ3IPhwf6dLkXnBr9nuCfP83V0K6VBu8,13084
|
|
9
|
+
payme/classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
payme/classes/cards.py,sha256=hjg3Wg189INeStGArQUnoxAAutKFbB6BnwYtMGLA0x0,7621
|
|
11
|
+
payme/classes/client.py,sha256=HqJdFvgSBKxYsitAukYp6_UEa3J6ChVBUbUC1aGR2XM,904
|
|
12
|
+
payme/classes/http.py,sha256=OufMeHrj0jTomDJx_6go9GC1NtA6QpQCxIiM3ISy3Eo,3530
|
|
13
|
+
payme/classes/initializer.py,sha256=Pwb1oCUZzcW-ftFzaLMr8ySguC7fKsbeQ4vGmupYliw,2448
|
|
14
|
+
payme/classes/receipts.py,sha256=J_ubm1zpqqUY9vOCeSUzJkwtRXYxagaRzzvJZmuP74Q,11010
|
|
15
|
+
payme/exceptions/__init__.py,sha256=HoBFnDA3eW_xWZiFlonJK4vhBDTsuik91tvgzXTy8KA,94
|
|
16
|
+
payme/exceptions/general.py,sha256=-rkzvuLi6VoITMLrszrP7c-gM8X6lM8AWttd770KSJc,7679
|
|
17
|
+
payme/exceptions/webhook.py,sha256=ZW6HnjxZDQScaX0WLXltcEllCwl1m0JuCtEnR28shME,4090
|
|
18
|
+
payme/migrations/0001_initial.py,sha256=jdtGB6bN-Za6N9XU8IuWsa5FbonGIRH5ro9xHwT7JmU,2128
|
|
19
|
+
payme/migrations/0002_paymetransactions_fiscal_data.py,sha256=z-gxPP3IgN-XNPx6DEZUQ4E1XZceVnnpvUTcSkcv70c,395
|
|
20
|
+
payme/migrations/0003_alter_paymetransactions_fiscal_data.py,sha256=Ish4Seup9pdEM0g4q4RQKrvUOWB2DXPN0RmIScKI2IQ,410
|
|
21
|
+
payme/migrations/0004_alter_paymetransactions_account_id.py,sha256=Kzihw4-HHBG43fZ2WU-qLLU-kxN-plfS3mLeIEZGKxA,417
|
|
22
|
+
payme/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
payme/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
payme/types/request/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
payme/types/response/__init__.py,sha256=GAj5pjZ9oIO67T6YMiPd1fhTIvGrPfTv96tykfeChQc,81
|
|
26
|
+
payme/types/response/cards.py,sha256=ncGaE5NzI5AJLbrzR41G7jkUHXO71BnrIiaiV-lKsPo,2006
|
|
27
|
+
payme/types/response/receipts.py,sha256=zwbe74sKS9lQ7VSz5LnPkdlZZ_WCWorU-P2J0uxRuic,4401
|
|
28
|
+
payme/types/response/webhook.py,sha256=E8IVD683T7wra4OxUWq5T6y7HGpjwOVk8ak0tS0b-_o,3084
|
|
29
|
+
payme_pkg-3.0.28.dist-info/licenses/LICENSE.txt,sha256=75dBVYmbzWUhwtaB1MSZfj-M-PGaMmeT9UVPli2-ZJ0,1086
|
|
30
|
+
payme_pkg-3.0.28.dist-info/METADATA,sha256=vaTLw91LWEOD825jfZ7tcruIOjwJRSOCCYIEHNTgvl4,5554
|
|
31
|
+
payme_pkg-3.0.28.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
32
|
+
payme_pkg-3.0.28.dist-info/top_level.txt,sha256=8mN-hGAa38pWbhrKHFs9CZywPCdidhMuwPKwuFJa0qw,6
|
|
33
|
+
payme_pkg-3.0.28.dist-info/RECORD,,
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
payme/__init__.py,sha256=dzLIyA9kQl0sO6z9nHkZDTjkfiI1BepdifKtJbjX2Cw,46
|
|
2
|
-
payme/admin.py,sha256=k4_kAX6k8993aQo_7xokIc7InUVw4LGZT5ROn-C9EYU,561
|
|
3
|
-
payme/apps.py,sha256=HHCY4zUNKPcjz25z0MahZcks0lsAxTGPS0Ml3U4DhZc,142
|
|
4
|
-
payme/const.py,sha256=azndfKR53fe7mDfGW82Q-kwWdMu3x4S1upKc4gkYdlA,214
|
|
5
|
-
payme/models.py,sha256=nOVmknNjQkBos7w069ddAp_wTBj14UssdTgO8w8sTdI,4179
|
|
6
|
-
payme/urls.py,sha256=_oUOwxW1Suc5TUmnj--lySYbotRg4yTDkDLJU20CGjE,145
|
|
7
|
-
payme/util.py,sha256=UFb4cEnaufS_hh9C_0z079CSgJGivYjIgOl2iAFrBMs,625
|
|
8
|
-
payme/views.py,sha256=gSQgctinjjAWhEO-kCIF4Jn01yapzHRi2ovtkc6JgJw,12873
|
|
9
|
-
payme/classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
payme/classes/cards.py,sha256=dr3SQdKAhfQmECtwHYW2nmx8wXaNYQFkg5uQU9z8vs4,7624
|
|
11
|
-
payme/classes/client.py,sha256=Fjck3vSRh8-NQ8HnxwytCn_qZm6UfwMKCBYDHtUSJAs,864
|
|
12
|
-
payme/classes/http.py,sha256=OufMeHrj0jTomDJx_6go9GC1NtA6QpQCxIiM3ISy3Eo,3530
|
|
13
|
-
payme/classes/initializer.py,sha256=TWJnlJTXefROMleIvJeT64xjIVWQU-LIXai8TZ_M7nw,2488
|
|
14
|
-
payme/classes/receipts.py,sha256=KU4qyGHWZpWW88SjmmTD_N2Tz8pWOCvBbOPnw5tcS3Y,10094
|
|
15
|
-
payme/exceptions/__init__.py,sha256=HoBFnDA3eW_xWZiFlonJK4vhBDTsuik91tvgzXTy8KA,94
|
|
16
|
-
payme/exceptions/general.py,sha256=-rkzvuLi6VoITMLrszrP7c-gM8X6lM8AWttd770KSJc,7679
|
|
17
|
-
payme/exceptions/webhook.py,sha256=hiX3CEjlPsFkliJm7SNM3XImU1IBscPhiwsnJJqhku4,3843
|
|
18
|
-
payme/migrations/0001_initial.py,sha256=jdtGB6bN-Za6N9XU8IuWsa5FbonGIRH5ro9xHwT7JmU,2128
|
|
19
|
-
payme/migrations/0002_paymetransactions_fiscal_data.py,sha256=z-gxPP3IgN-XNPx6DEZUQ4E1XZceVnnpvUTcSkcv70c,395
|
|
20
|
-
payme/migrations/0003_alter_paymetransactions_fiscal_data.py,sha256=Ish4Seup9pdEM0g4q4RQKrvUOWB2DXPN0RmIScKI2IQ,410
|
|
21
|
-
payme/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
payme/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
payme/types/request/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
payme/types/response/__init__.py,sha256=GAj5pjZ9oIO67T6YMiPd1fhTIvGrPfTv96tykfeChQc,81
|
|
25
|
-
payme/types/response/cards.py,sha256=ilXFDUOPNabVsrQN1KWEzDiL6cDxdVvCbfEl6jCzGpU,1997
|
|
26
|
-
payme/types/response/receipts.py,sha256=TlZeJyymRVHIorg0kbUaogy6MZxN1oq2jHGVRUnlY5A,4070
|
|
27
|
-
payme/types/response/webhook.py,sha256=9tw_QsKNAUqgZLwL7Pg0SIVAry0BlxlWOu8BDmKewzc,3034
|
|
28
|
-
payme_pkg-3.0.24.dist-info/LICENSE.txt,sha256=75dBVYmbzWUhwtaB1MSZfj-M-PGaMmeT9UVPli2-ZJ0,1086
|
|
29
|
-
payme_pkg-3.0.24.dist-info/METADATA,sha256=5M5dOOlQtVeu9ZFGxxpAL2zuHWzvWm4TWC4XSXQuUoQ,5372
|
|
30
|
-
payme_pkg-3.0.24.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
31
|
-
payme_pkg-3.0.24.dist-info/top_level.txt,sha256=8mN-hGAa38pWbhrKHFs9CZywPCdidhMuwPKwuFJa0qw,6
|
|
32
|
-
payme_pkg-3.0.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|