payme-pkg 3.0.25b0__tar.gz → 3.0.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of payme-pkg might be problematic. Click here for more details.

Files changed (38) hide show
  1. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/PKG-INFO +11 -2
  2. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/cards.py +1 -1
  3. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/client.py +9 -11
  4. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/initializer.py +10 -5
  5. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/receipts.py +101 -40
  6. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/exceptions/webhook.py +25 -36
  7. payme_pkg-3.0.26/payme/migrations/0004_alter_paymetransactions_account_id.py +18 -0
  8. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/models.py +1 -1
  9. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/response/cards.py +3 -13
  10. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/response/receipts.py +38 -47
  11. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/response/webhook.py +14 -24
  12. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/views.py +12 -10
  13. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme_pkg.egg-info/PKG-INFO +11 -2
  14. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme_pkg.egg-info/SOURCES.txt +1 -0
  15. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/setup.py +1 -1
  16. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/LICENSE.txt +0 -0
  17. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/README.md +0 -0
  18. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/__init__.py +0 -0
  19. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/admin.py +0 -0
  20. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/apps.py +0 -0
  21. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/__init__.py +0 -0
  22. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/classes/http.py +0 -0
  23. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/const.py +0 -0
  24. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/exceptions/__init__.py +0 -0
  25. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/exceptions/general.py +0 -0
  26. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/migrations/0001_initial.py +0 -0
  27. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/migrations/0002_paymetransactions_fiscal_data.py +0 -0
  28. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/migrations/0003_alter_paymetransactions_fiscal_data.py +0 -0
  29. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/migrations/__init__.py +0 -0
  30. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/__init__.py +0 -0
  31. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/request/__init__.py +0 -0
  32. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/types/response/__init__.py +0 -0
  33. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/urls.py +0 -0
  34. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme/util.py +0 -0
  35. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme_pkg.egg-info/dependency_links.txt +0 -0
  36. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme_pkg.egg-info/requires.txt +0 -0
  37. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/payme_pkg.egg-info/top_level.txt +0 -0
  38. {payme_pkg-3.0.25b0 → payme_pkg-3.0.26}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: payme-pkg
3
- Version: 3.0.25b0
3
+ Version: 3.0.26
4
4
  Home-page: https://github.com/Muhammadali-Akbarov/payme-pkg
5
5
  Author: Muhammadali Akbarov
6
6
  Author-email: muhammadali17abc@gmail.com
@@ -11,6 +11,15 @@ License-File: LICENSE.txt
11
11
  Requires-Dist: requests==2.*
12
12
  Requires-Dist: dataclasses==0.*; python_version < "3.7"
13
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
 
@@ -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) -> None:
22
+ def __init__(self, url: str, payme_id: str) -> "Cards":
23
23
  """
24
24
  Initialize the Cards client.
25
25
 
@@ -1,4 +1,5 @@
1
- import typing as t
1
+
2
+ from typing import Union
2
3
 
3
4
  from payme.const import Networks
4
5
  from payme.classes.cards import Cards
@@ -10,14 +11,14 @@ class Payme:
10
11
  """
11
12
  The payme class provides a simple interface
12
13
  """
13
-
14
14
  def __init__(
15
15
  self,
16
16
  payme_id: str,
17
- fallback_id: t.Optional[str] = None,
18
- payme_key: t.Optional[str] = None,
19
- is_test_mode: bool = False,
20
- ) -> None:
17
+ fallback_id: Union[str, None] = None,
18
+ payme_key: Union[str, None] = None,
19
+ is_test_mode: bool = False
20
+ ):
21
+
21
22
  # initialize payme network
22
23
  url = Networks.PROD_NET.value
23
24
 
@@ -25,8 +26,5 @@ class Payme:
25
26
  url = Networks.TEST_NET.value
26
27
 
27
28
  self.cards = Cards(url=url, payme_id=payme_id)
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)
29
+ self.initializer = Initializer(payme_id=payme_id, fallback_id=fallback_id, is_test_mode=is_test_mode)
30
+ self.receipts = Receipts(url=url, payme_id=payme_id, payme_key=payme_key) # noqa
@@ -13,14 +13,17 @@ class Initializer:
13
13
  The Payme ID associated with your account
14
14
  """
15
15
 
16
- def __init__(
17
- self, payme_id: str = None, fallback_id: str = None, is_test_mode: bool = False
18
- ) -> None:
16
+ def __init__(self, payme_id: str = None, fallback_id: str = None, is_test_mode: bool = False):
19
17
  self.payme_id = payme_id
20
18
  self.fallback_id = fallback_id
21
19
  self.is_test_mode = is_test_mode
22
20
 
23
- def generate_pay_link(self, id: int, amount: int, return_url: str) -> str:
21
+ def generate_pay_link(
22
+ self,
23
+ id: int,
24
+ amount: int,
25
+ return_url: str
26
+ ) -> str:
24
27
  """
25
28
  Generate a payment link for a specific order.
26
29
 
@@ -49,7 +52,9 @@ class Initializer:
49
52
  https://developer.help.paycom.uz/initsializatsiya-platezhey/
50
53
  """
51
54
  amount = amount * 100 # Convert amount to the smallest currency unit
52
- params = f"m={self.payme_id};ac.{settings.PAYME_ACCOUNT_FIELD}={id};a={amount};c={return_url}"
55
+ params = (
56
+ f'm={self.payme_id};ac.{settings.PAYME_ACCOUNT_FIELD}={id};a={amount};c={return_url}'
57
+ )
53
58
  params = base64.b64encode(params.encode("utf-8")).decode("utf-8")
54
59
 
55
60
  if self.is_test_mode is True:
@@ -1,4 +1,5 @@
1
- import typing as t
1
+ from typing import Union, Optional
2
+ from urllib.parse import parse_qs
2
3
 
3
4
  from payme.classes.cards import Cards
4
5
  from payme.classes.http import HttpClient
@@ -13,6 +14,7 @@ ALLOWED_METHODS = {
13
14
  "receipts.check": response.CheckResponse,
14
15
  "receipts.get": response.GetResponse,
15
16
  "receipts.get_all": response.GetAllResponse,
17
+ "receipts.set_fiscal_data": response.SetFiscalDataResponse,
16
18
  }
17
19
 
18
20
 
@@ -20,8 +22,7 @@ class Receipts:
20
22
  """
21
23
  The Receipts class provides methods to interact with the Payme Receipts.
22
24
  """
23
-
24
- def __init__(self, payme_id: str, payme_key: str, url: str) -> None:
25
+ def __init__(self, payme_id: str, payme_key: str, url: str) -> "Receipts":
25
26
  """
26
27
  Initialize the Receipts client.
27
28
 
@@ -33,25 +34,25 @@ class Receipts:
33
34
 
34
35
  headers = {
35
36
  "X-Auth": f"{payme_id}:{payme_key}",
36
- "Content-Type": "application/json",
37
+ "Content-Type": "application/json"
37
38
  }
38
39
  self.http = HttpClient(url, headers)
39
40
 
40
41
  def create(
41
42
  self,
42
43
  account: dict,
43
- amount: t.Union[float, int],
44
- description: t.Optional[str] = None,
45
- detail: t.Optional[t.Dict] = None,
46
- timeout: int = 10,
44
+ amount: Union[float, int],
45
+ description: Optional[str] = None,
46
+ detail: Optional[dict] = None,
47
+ timeout: int = 10
47
48
  ) -> response.CreateResponse:
48
49
  """
49
50
  Create a new receipt.
50
51
 
51
52
  :param account: The account details for the receipt.
52
53
  :param amount: The amount of the receipt.
53
- :param description: t.Optional description for the receipt.
54
- :param detail: t.Optional additional details for the receipt.
54
+ :param description: Optional description for the receipt.
55
+ :param detail: Optional additional details for the receipt.
55
56
  :param timeout: The request timeout duration in seconds (default 10).
56
57
  """
57
58
  method = "receipts.create"
@@ -59,7 +60,7 @@ class Receipts:
59
60
  "amount": amount,
60
61
  "account": account,
61
62
  "description": description,
62
- "detail": detail,
63
+ "detail": detail
63
64
  }
64
65
  return self._post_request(method, params, timeout)
65
66
 
@@ -75,7 +76,10 @@ class Receipts:
75
76
  The request timeout duration in seconds (default is 10).
76
77
  """
77
78
  method = "receipts.pay"
78
- params = {"id": receipts_id, "token": token}
79
+ params = {
80
+ "id": receipts_id,
81
+ "token": token
82
+ }
79
83
  return self._post_request(method, params, timeout)
80
84
 
81
85
  def send(
@@ -89,10 +93,15 @@ class Receipts:
89
93
  :param timeout: The request timeout duration in seconds (default 10).
90
94
  """
91
95
  method = "receipts.send"
92
- params = {"id": receipts_id, "phone": phone}
96
+ params = {
97
+ "id": receipts_id,
98
+ "phone": phone
99
+ }
93
100
  return self._post_request(method, params, timeout)
94
101
 
95
- def cancel(self, receipts_id: str, timeout: int = 10) -> response.CancelResponse:
102
+ def cancel(
103
+ self, receipts_id: str, timeout: int = 10
104
+ ) -> response.CancelResponse:
96
105
  """
97
106
  Cancel the receipt.
98
107
 
@@ -100,10 +109,14 @@ class Receipts:
100
109
  :param timeout: The request timeout duration in seconds (default 10).
101
110
  """
102
111
  method = "receipts.cancel"
103
- params = {"id": receipts_id}
112
+ params = {
113
+ "id": receipts_id
114
+ }
104
115
  return self._post_request(method, params, timeout)
105
116
 
106
- def check(self, receipts_id: str, timeout: int = 10) -> response.CheckResponse:
117
+ def check(
118
+ self, receipts_id: str, timeout: int = 10
119
+ ) -> response.CheckResponse:
107
120
  """
108
121
  Check the status of a cheque.
109
122
 
@@ -111,10 +124,14 @@ class Receipts:
111
124
  :param timeout: The request timeout duration in seconds (default 10).
112
125
  """
113
126
  method = "receipts.check"
114
- params = {"id": receipts_id}
127
+ params = {
128
+ "id": receipts_id
129
+ }
115
130
  return self._post_request(method, params, timeout)
116
131
 
117
- def get(self, receipts_id: str, timeout: int = 10) -> response.GetResponse:
132
+ def get(
133
+ self, receipts_id: str, timeout: int = 10
134
+ ) -> response.GetResponse:
118
135
  """
119
136
  Get the details of a specific cheque.
120
137
 
@@ -122,23 +139,60 @@ class Receipts:
122
139
  :param timeout: The request timeout duration in seconds (default 10).
123
140
  """
124
141
  method = "receipts.get"
125
- params = {"id": receipts_id}
142
+ params = {
143
+ "id": receipts_id
144
+ }
126
145
  return self._post_request(method, params, timeout)
127
146
 
128
147
  def get_all(
129
148
  self, count: int, from_: int, to: int, offset: int, timeout: int = 10
130
149
  ) -> response.GetAllResponse:
131
150
  """
132
- Get all cheques for a specific account.
151
+ Get all cheques for a specific account.
133
152
 
134
- :param count: The number of cheques to retrieve.
135
- :param from_: The start index of the cheques to retrieve.
136
- :param to: The end index of the cheques to retrieve.
137
- :param offset: The offset for pagination.
138
- :param timeout: The request timeout duration in seconds (default 10).
153
+ :param count: The number of cheques to retrieve.
154
+ :param from_: The start index of the cheques to retrieve.
155
+ :param to: The end index of the cheques to retrieve.
156
+ :param offset: The offset for pagination.
157
+ :param timeout: The request timeout duration in seconds (default 10).
139
158
  """
140
159
  method = "receipts.get_all"
141
- params = {"count": count, "from": from_, "to": to, "offset": offset}
160
+ params = {
161
+ "count": count,
162
+ "from": from_,
163
+ "to": to,
164
+ "offset": offset
165
+ }
166
+ return self._post_request(method, params, timeout)
167
+
168
+ def set_fiscal_data(
169
+ self, receipt_id: str, qr_code_url: str, timeout: int = 10
170
+ ) -> response.SetFiscalDataResponse:
171
+ """
172
+ Get all cheques for a specific account.
173
+
174
+ :param receipt_id: The ID of the check used for payment.
175
+ :param qr_code_url: URL of the fiscal check from the ofd.uz.
176
+ :param timeout: The request timeout duration in seconds (default 10).
177
+ """
178
+ method = "receipts.set_fiscal_data"
179
+
180
+ check_params = parse_qs(qr_code_url.split("?")[1])
181
+ terminal_id = check_params["t"][0]
182
+ fiscal_sign = check_params["s"][0]
183
+ fiscal_receipt_id = check_params["r"][0]
184
+ fiscal_date = check_params["c"][0]
185
+
186
+ params = {
187
+ "id": receipt_id, # required
188
+ "fiscal_data": {
189
+ "terminal_id": terminal_id,
190
+ "receipt_id": int(fiscal_receipt_id), # required
191
+ "date": fiscal_date,
192
+ "fiscal_sign": fiscal_sign,
193
+ "qr_code_url": qr_code_url, # required
194
+ }
195
+ }
142
196
  return self._post_request(method, params, timeout)
143
197
 
144
198
  def _post_request(
@@ -163,7 +217,6 @@ class Receipts:
163
217
  covering creation, payment, sending, cancellation, status checks,
164
218
  retrieval of a single receipt, and retrieval of multiple receipts.
165
219
  """
166
-
167
220
  # Helper to assert conditions with messaging
168
221
  def assert_condition(condition, message, test_case):
169
222
  self._assert_and_print(condition, message, test_case=test_case)
@@ -174,14 +227,14 @@ class Receipts:
174
227
  account={"id": 12345},
175
228
  amount=1000,
176
229
  description="Test receipt",
177
- detail={"key": "value"},
230
+ detail={"key": "value"}
178
231
  )
179
232
 
180
233
  # Test 1: Initialization check
181
234
  assert_condition(
182
235
  isinstance(self, Receipts),
183
236
  "Initialized Receipts class successfully.",
184
- test_case="Initialization Test",
237
+ test_case="Initialization Test"
185
238
  )
186
239
 
187
240
  # Test 2: Create and Pay Receipt
@@ -189,19 +242,21 @@ class Receipts:
189
242
  assert_condition(
190
243
  isinstance(create_response, response.CreateResponse),
191
244
  "Created a new receipt successfully.",
192
- test_case="Receipt Creation Test",
245
+ test_case="Receipt Creation Test"
193
246
  )
194
247
 
195
248
  # pylint: disable=W0212
196
249
  assert_condition(
197
250
  isinstance(create_response.result.receipt._id, str),
198
251
  "Created a valid receipt ID.",
199
- test_case="Receipt ID Test",
252
+ test_case="Receipt ID Test"
200
253
  )
201
254
 
202
255
  # Prepare card and verification
203
256
  cards_create_response = self.__cards.create(
204
- number="8600495473316478", expire="0399", save=True
257
+ number="8600495473316478",
258
+ expire="0399",
259
+ save=True
205
260
  )
206
261
  token = cards_create_response.result.card.token
207
262
  self.__cards.get_verify_code(token=token)
@@ -213,7 +268,7 @@ class Receipts:
213
268
  assert_condition(
214
269
  pay_response.result.receipt.state == 4,
215
270
  "Paid the receipt successfully.",
216
- test_case="Payment Test",
271
+ test_case="Payment Test"
217
272
  )
218
273
 
219
274
  # Test 3: Create and Send Receipt
@@ -223,7 +278,7 @@ class Receipts:
223
278
  assert_condition(
224
279
  send_response.result.success is True,
225
280
  "Sent the receipt successfully.",
226
- test_case="Send Test",
281
+ test_case="Send Test"
227
282
  )
228
283
 
229
284
  # Test 4: Create and Cancel Receipt
@@ -233,7 +288,7 @@ class Receipts:
233
288
  assert_condition(
234
289
  cancel_response.result.receipt.state == 50,
235
290
  "Cancelled the receipt successfully.",
236
- test_case="Cancel Test",
291
+ test_case="Cancel Test"
237
292
  )
238
293
 
239
294
  # Test 5: Check Receipt Status
@@ -241,7 +296,7 @@ class Receipts:
241
296
  assert_condition(
242
297
  check_response.result.state == 50,
243
298
  "Checked the receipt status successfully.",
244
- test_case="Check Test",
299
+ test_case="Check Test"
245
300
  )
246
301
 
247
302
  # Test 6: Get Receipt Details
@@ -249,21 +304,27 @@ class Receipts:
249
304
  assert_condition(
250
305
  get_response.result.receipt._id == receipt_id,
251
306
  "Retrieved the receipt details successfully.",
252
- test_case="Get Test",
307
+ test_case="Get Test"
253
308
  )
254
309
 
255
310
  # Test 7: Retrieve All Receipts
256
311
  get_all_response = self.get_all(
257
- count=1, from_=1730322122000, to=1730398982000, offset=0
312
+ count=1,
313
+ from_=1730322122000,
314
+ to=1730398982000,
315
+ offset=0
258
316
  )
259
317
  assert_condition(
260
318
  isinstance(get_all_response.result, list),
261
319
  "Retrieved all receipts successfully.",
262
- test_case="Get All Test",
320
+ test_case="Get All Test"
263
321
  )
264
322
 
265
323
  # pylint: disable=W0212
266
324
  def _assert_and_print(
267
- self, condition: bool, success_message: str, test_case: t.Optional[str] = None
325
+ self,
326
+ condition: bool,
327
+ success_message: str,
328
+ test_case: Optional[str] = None
268
329
  ):
269
330
  self.__cards._assert_and_print(condition, success_message, test_case)
@@ -1,31 +1,28 @@
1
1
  """
2
2
  Init Payme base exception.
3
3
  """
4
-
5
4
  import logging
6
- import typing as t
7
-
8
- from rest_framework import status
9
5
  from rest_framework.exceptions import APIException
10
6
 
11
7
  logger = logging.getLogger(__name__)
12
8
 
13
- MessageT = t.Optional[t.Union[str, t.Dict[str, str]]]
14
-
15
9
 
16
10
  class BasePaymeException(APIException):
17
11
  """
18
12
  BasePaymeException inherits from APIException.
19
13
  """
20
-
21
- status_code: int = status.HTTP_200_OK
22
- error_code: t.Optional[int] = None
23
- message: MessageT = None
14
+ status_code = 200
15
+ error_code = None
16
+ message = None
24
17
 
25
18
  # pylint: disable=super-init-not-called
26
19
  def __init__(self, message: str = None):
27
20
  detail: dict = {
28
- "error": {"code": self.error_code, "message": self.message, "data": message}
21
+ "error": {
22
+ "code": self.error_code,
23
+ "message": self.message,
24
+ "data": message
25
+ }
29
26
  }
30
27
  logger.error(f"Payme error detail: {detail}")
31
28
  self.detail = detail
@@ -37,8 +34,7 @@ class PermissionDenied(BasePaymeException):
37
34
 
38
35
  Raised when the client is not allowed to access the server.
39
36
  """
40
-
41
- status_code = status.HTTP_200_OK
37
+ status_code = 200
42
38
  error_code = -32504
43
39
  message = "Permission denied."
44
40
 
@@ -49,13 +45,12 @@ class InternalServiceError(BasePaymeException):
49
45
 
50
46
  Raised when a transaction fails to perform.
51
47
  """
52
-
53
- status_code = status.HTTP_200_OK
48
+ status_code = 200
54
49
  error_code = -32400
55
50
  message = {
56
51
  "uz": "Tizimda xatolik yuzaga keldi.",
57
52
  "ru": "Внутренняя ошибка сервиса.",
58
- "en": "Internal service error.",
53
+ "en": "Internal service error."
59
54
  }
60
55
 
61
56
 
@@ -65,8 +60,7 @@ class MethodNotFound(BasePaymeException):
65
60
 
66
61
  Raised when the requested method does not exist.
67
62
  """
68
-
69
- status_code = status.HTTP_405_METHOD_NOT_ALLOWED
63
+ status_code = 405
70
64
  error_code = -32601
71
65
  message = "Method not found."
72
66
 
@@ -77,13 +71,12 @@ class AccountDoesNotExist(BasePaymeException):
77
71
 
78
72
  Raised when an account does not exist or has been deleted.
79
73
  """
80
-
81
- status_code = status.HTTP_200_OK
74
+ status_code = 200
82
75
  error_code = -31050
83
76
  message = {
84
77
  "uz": "Hisob topilmadi.",
85
78
  "ru": "Счет не найден.",
86
- "en": "Account does not exist.",
79
+ "en": "Account does not exist."
87
80
  }
88
81
 
89
82
 
@@ -93,13 +86,12 @@ class IncorrectAmount(BasePaymeException):
93
86
 
94
87
  Raised when the provided amount is incorrect.
95
88
  """
96
-
97
- status_code = status.HTTP_200_OK
89
+ status_code = 200
98
90
  error_code = -31001
99
91
  message = {
100
- "ru": "Неверная сумма.",
101
- "uz": "Noto'g'ri summa.",
102
- "en": "Incorrect amount.",
92
+ 'ru': 'Неверная сумма.',
93
+ 'uz': "Noto'g'ri summa.",
94
+ 'en': 'Incorrect amount.'
103
95
  }
104
96
 
105
97
 
@@ -115,13 +107,12 @@ class TransactionAlreadyExists(BasePaymeException):
115
107
  error_code (int): The specific error code for this exception.
116
108
  message (dict): A dictionary containing localized error messages.
117
109
  """
118
-
119
- status_code = status.HTTP_200_OK
110
+ status_code = 200
120
111
  error_code = -31099
121
112
  message = {
122
113
  "uz": "Tranzaksiya allaqachon mavjud.",
123
114
  "ru": "Транзакция уже существует.",
124
- "en": "Transaction already exists.",
115
+ "en": "Transaction already exists."
125
116
  }
126
117
 
127
118
 
@@ -131,13 +122,12 @@ class InvalidFiscalParams(BasePaymeException):
131
122
 
132
123
  Raised when the provided fiscal parameters are invalid.
133
124
  """
134
-
135
- status_code = status.HTTP_200_OK
125
+ status_code = 200
136
126
  error_code = -32602
137
127
  message = {
138
128
  "uz": "Fiskal parameterlarida kamchiliklar bor",
139
129
  "ru": "Неверные фискальные параметры.",
140
- "en": "Invalid fiscal parameters.",
130
+ "en": "Invalid fiscal parameters."
141
131
  }
142
132
 
143
133
 
@@ -147,13 +137,12 @@ class InvalidAccount(BasePaymeException):
147
137
 
148
138
  Raised when the provided account is invalid.
149
139
  """
150
-
151
- status_code = status.HTTP_200_OK
140
+ status_code = 200
152
141
  error_code = -32400
153
142
  message = {
154
143
  "uz": "Hisob nomida kamchilik bor",
155
144
  "ru": "Неверный номер счета.",
156
- "en": "Invalid account.",
145
+ "en": "Invalid account."
157
146
  }
158
147
 
159
148
 
@@ -164,5 +153,5 @@ exception_whitelist = (
164
153
  AccountDoesNotExist,
165
154
  TransactionAlreadyExists,
166
155
  InvalidFiscalParams,
167
- InvalidAccount,
156
+ InvalidAccount
168
157
  )
@@ -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
+ ]
@@ -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.BigIntegerField(null=False)
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)
@@ -1,15 +1,14 @@
1
- import typing as t
1
+ from typing import Dict, Optional
2
2
  from dataclasses import dataclass
3
3
 
4
4
 
5
- @dataclass
6
5
  class Common:
7
6
  """
8
7
  The common response structure.
9
8
  """
10
9
 
11
10
  @classmethod
12
- def from_dict(cls, data: t.Dict):
11
+ def from_dict(cls, data: Dict):
13
12
  """
14
13
  Prepare fields for nested dataclasses
15
14
  """
@@ -31,14 +30,13 @@ class Card(Common):
31
30
  """
32
31
  The card object represents a credit card.
33
32
  """
34
-
35
33
  number: str
36
34
  expire: str
37
35
  token: str
38
36
  recurrent: bool
39
37
  verify: bool
40
38
  type: str
41
- number_hash: t.Optional[str] = None
39
+ number_hash: Optional[str] = None
42
40
 
43
41
 
44
42
  @dataclass
@@ -46,7 +44,6 @@ class Result(Common):
46
44
  """
47
45
  The result object contains the created card.
48
46
  """
49
-
50
47
  card: Card
51
48
 
52
49
 
@@ -55,7 +52,6 @@ class CardsCreateResponse(Common):
55
52
  """
56
53
  The cards.create response.
57
54
  """
58
-
59
55
  jsonrpc: str
60
56
  result: Result
61
57
 
@@ -65,7 +61,6 @@ class VerifyResult(Common):
65
61
  """
66
62
  The result object for the verification response.
67
63
  """
68
-
69
64
  sent: bool
70
65
  phone: str
71
66
  wait: int
@@ -76,7 +71,6 @@ class GetVerifyResponse(Common):
76
71
  """
77
72
  The verification response structure.
78
73
  """
79
-
80
74
  jsonrpc: str
81
75
  result: VerifyResult
82
76
 
@@ -86,7 +80,6 @@ class VerifyResponse(Common):
86
80
  """
87
81
  The verification response structure.
88
82
  """
89
-
90
83
  jsonrpc: str
91
84
  result: Result
92
85
 
@@ -96,7 +89,6 @@ class RemoveCardResult(Common):
96
89
  """
97
90
  The result object for the removal response.
98
91
  """
99
-
100
92
  success: bool
101
93
 
102
94
 
@@ -105,7 +97,6 @@ class RemoveResponse(Common):
105
97
  """
106
98
  The remove response structure.
107
99
  """
108
-
109
100
  jsonrpc: str
110
101
  result: RemoveCardResult
111
102
 
@@ -115,6 +106,5 @@ class CheckResponse(Common):
115
106
  """
116
107
  The check response structure.
117
108
  """
118
-
119
109
  jsonrpc: str
120
110
  result: Result
@@ -1,18 +1,16 @@
1
- import typing as t
2
1
  from dataclasses import dataclass
2
+ from typing import Dict, Optional, Union
3
3
 
4
4
 
5
- @dataclass
6
5
  class Common:
7
6
  """
8
7
  The common response structure.
9
8
  """
10
-
11
9
  jsonrpc: str
12
10
  id: int
13
11
 
14
12
  @classmethod
15
- def from_dict(cls, data: t.Dict):
13
+ def from_dict(cls, data: Dict):
16
14
  """
17
15
  Prepare fields for nested dataclasses
18
16
  """
@@ -34,7 +32,6 @@ class Account(Common):
34
32
  """
35
33
  The account object represents a user's banking account.
36
34
  """
37
-
38
35
  _id: str
39
36
  account_number: str
40
37
  account_name: str
@@ -49,11 +46,10 @@ class PaymentMethod(Common):
49
46
  """
50
47
  The payment method object represents a user's payment method.
51
48
  """
52
-
53
49
  name: str
54
50
  title: str
55
51
  value: str
56
- main: t.Optional[bool] = None
52
+ main: Optional[bool] = None
57
53
 
58
54
 
59
55
  @dataclass
@@ -61,10 +57,9 @@ class Detail(Common):
61
57
  """
62
58
  The detail object represents additional details for a receipt.
63
59
  """
64
-
65
- discount: t.Optional[str] = None
66
- shipping: t.Optional[str] = None
67
- items: t.Optional[str] = None
60
+ discount: Optional[str] = None
61
+ shipping: Optional[str] = None
62
+ items: Optional[str] = None
68
63
 
69
64
 
70
65
  # pylint: disable=C0103
@@ -73,7 +68,6 @@ class MerchantEpos(Common):
73
68
  """
74
69
  The merchantEpos object represents a user's ePOS.
75
70
  """
76
-
77
71
  eposId: str
78
72
  eposName: str
79
73
  eposType: str
@@ -85,10 +79,9 @@ class Meta(Common):
85
79
  """
86
80
  The meta object represents additional metadata for a receipt.
87
81
  """
88
-
89
- source: t.Any = None
90
- owner: t.Any = None
91
- host: t.Any = None
82
+ source: any = None
83
+ owner: any = None
84
+ host: any = None
92
85
 
93
86
 
94
87
  @dataclass
@@ -96,18 +89,17 @@ class Merchant:
96
89
  """
97
90
  The merchant object represents a user's merchant.
98
91
  """
99
-
100
92
  _id: str
101
93
  name: str
102
94
  organization: str
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
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
111
103
 
112
104
 
113
105
  @dataclass
@@ -115,7 +107,6 @@ class Payer(Common):
115
107
  """
116
108
  The payer object represents a user's payer.
117
109
  """
118
-
119
110
  phone: str
120
111
 
121
112
 
@@ -124,7 +115,6 @@ class Receipt(Common):
124
115
  """
125
116
  The receipt object represents a payment receipt.
126
117
  """
127
-
128
118
  _id: str
129
119
  create_time: int
130
120
  pay_time: int
@@ -133,19 +123,19 @@ class Receipt(Common):
133
123
  type: int
134
124
  external: bool
135
125
  operation: int
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
126
+ error: any = None
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: list[Account] = None
136
+ merchant: Merchant = None
137
+ processing_id: str = None
138
+ meta: Meta = None
149
139
 
150
140
 
151
141
  @dataclass
@@ -153,7 +143,6 @@ class CreateResult(Common):
153
143
  """
154
144
  The result object for the create response.
155
145
  """
156
-
157
146
  receipt: Receipt
158
147
 
159
148
 
@@ -162,7 +151,6 @@ class CreateResponse(Common):
162
151
  """
163
152
  The create response structure.
164
153
  """
165
-
166
154
  result: CreateResult
167
155
 
168
156
 
@@ -178,7 +166,6 @@ class SendResult(Common):
178
166
  """
179
167
  The result object for the send response.
180
168
  """
181
-
182
169
  success: bool
183
170
 
184
171
 
@@ -187,7 +174,6 @@ class SendResponse(Common):
187
174
  """
188
175
  The send response structure.
189
176
  """
190
-
191
177
  result: SendResult
192
178
 
193
179
 
@@ -203,7 +189,6 @@ class CheckResult(Common):
203
189
  """
204
190
  The result object for the check response.
205
191
  """
206
-
207
192
  state: int
208
193
 
209
194
 
@@ -212,7 +197,6 @@ class CheckResponse(Common):
212
197
  """
213
198
  The check response structure.
214
199
  """
215
-
216
200
  result: CheckResult
217
201
 
218
202
 
@@ -228,5 +212,12 @@ class GetAllResponse(Common):
228
212
  """
229
213
  The result object for the get all response.
230
214
  """
215
+ result: list[Receipt] = None
216
+
231
217
 
232
- result: t.Optional[t.List[Receipt]] = None
218
+ @dataclass
219
+ class SetFiscalDataResponse(Common):
220
+ """
221
+ The result object for the set_fiscal_data response.
222
+ """
223
+ result: SendResult
@@ -1,16 +1,15 @@
1
- import typing as t
2
1
  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
-
10
9
  def as_resp(self):
11
- response = {"result": {}}
10
+ response = {'result': {}}
12
11
  for key, value in self.__dict__.items():
13
- response["result"][key] = value
12
+ response['result'][key] = value
14
13
  return response
15
14
 
16
15
 
@@ -19,7 +18,6 @@ class Shipping(CommonResponse):
19
18
  """
20
19
  Shipping information response structure
21
20
  """
22
-
23
21
  title: str
24
22
  price: int
25
23
 
@@ -29,7 +27,6 @@ class Item(CommonResponse):
29
27
  """
30
28
  Item information response structure
31
29
  """
32
-
33
30
  discount: int
34
31
  title: str
35
32
  price: int
@@ -48,7 +45,7 @@ class Item(CommonResponse):
48
45
  "code": self.code,
49
46
  "units": self.units,
50
47
  "vat_percent": self.vat_percent,
51
- "package_code": self.package_code,
48
+ "package_code": self.package_code
52
49
  }
53
50
 
54
51
 
@@ -57,12 +54,11 @@ class CheckPerformTransaction(CommonResponse):
57
54
  """
58
55
  Receipt information response structure for transaction checks.
59
56
  """
60
-
61
57
  allow: bool
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)
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)
66
62
 
67
63
  def add_item(self, item: Item):
68
64
  self.items.append(item)
@@ -94,10 +90,9 @@ class CreateTransaction(CommonResponse):
94
90
  """
95
91
  The create transaction request
96
92
  """
97
-
98
93
  transaction: str
99
94
  state: str
100
- create_time: int
95
+ create_time: str
101
96
 
102
97
 
103
98
  @dataclass
@@ -105,10 +100,9 @@ class PerformTransaction(CommonResponse):
105
100
  """
106
101
  The perform transaction response
107
102
  """
108
-
109
103
  transaction: str
110
104
  state: str
111
- perform_time: int
105
+ perform_time: str
112
106
 
113
107
 
114
108
  @dataclass
@@ -116,7 +110,6 @@ class CancelTransaction(CommonResponse):
116
110
  """
117
111
  The cancel transaction request
118
112
  """
119
-
120
113
  transaction: str
121
114
  state: str
122
115
  cancel_time: str
@@ -127,13 +120,12 @@ class CheckTransaction(CommonResponse):
127
120
  """
128
121
  The check transaction request
129
122
  """
130
-
131
123
  transaction: str
132
124
  state: str
133
125
  reason: str
134
- create_time: int
135
- perform_time: t.Optional[int] = None
136
- cancel_time: t.Optional[int] = None
126
+ create_time: str
127
+ perform_time: Optional[str] = None
128
+ cancel_time: Optional[str] = None
137
129
 
138
130
 
139
131
  @dataclass
@@ -141,8 +133,7 @@ class GetStatement(CommonResponse):
141
133
  """
142
134
  The check perform transactions response
143
135
  """
144
-
145
- transactions: t.List[t.Dict[str, str | int | t.Dict[str, str | int]]]
136
+ transactions: List[str]
146
137
 
147
138
 
148
139
  @dataclass
@@ -150,5 +141,4 @@ class SetFiscalData(CommonResponse):
150
141
  """
151
142
  The set fiscal data request
152
143
  """
153
-
154
144
  success: bool
@@ -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,9 @@ 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:
38
+ raise exceptions.AccountDoesNotExist("Invalid account identifier.")
39
+
36
40
  except PaymeTransactions.DoesNotExist as exc:
37
41
  logger.error(f"Transaction does not exist: {exc} {args} {kwargs}")
38
42
  raise exceptions.AccountDoesNotExist(str(exc)) from exc
@@ -112,17 +116,11 @@ class PaymeWebHookAPIView(views.APIView):
112
116
  """
113
117
  Fetch account based on settings and params.
114
118
  """
115
- account_field = settings.PAYME_ACCOUNT_FIELD
116
-
117
- account_value = params['account'].get(account_field)
119
+ account_value = params["account"].get(settings.PAYME_ACCOUNT_FIELD)
118
120
  if not account_value:
119
121
  raise exceptions.InvalidAccount("Missing account field in parameters.")
120
122
 
121
- # hard change
122
- if account_field == "order_id":
123
- account_field = "id"
124
-
125
- account = AccountModel.objects.get(**{account_field: account_value})
123
+ account = AccountModel.objects.get(pk=account_value)
126
124
 
127
125
  return account
128
126
 
@@ -169,13 +167,17 @@ class PaymeWebHookAPIView(views.APIView):
169
167
  defaults = {
170
168
  "amount": amount,
171
169
  "state": PaymeTransactions.INITIATING,
172
- "account_id": account.id,
170
+ "account_id": account.pk,
173
171
  }
174
172
 
175
173
  # Handle already existing transaction with the same ID for one-time payments
176
174
  if settings.PAYME_ONE_TIME_PAYMENT:
177
175
  # Check for an existing transaction with a different transaction_id for the given account
178
- if PaymeTransactions.objects.filter(account_id=account.id).exclude(transaction_id=transaction_id).exists():
176
+ if (
177
+ PaymeTransactions.objects.filter(account_id=account.pk)
178
+ .exclude(transaction_id=transaction_id)
179
+ .exists()
180
+ ):
179
181
  message = f"Transaction {transaction_id} already exists (Payme)."
180
182
  logger.warning(message)
181
183
  raise exceptions.TransactionAlreadyExists(message)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: payme-pkg
3
- Version: 3.0.25b0
3
+ Version: 3.0.26
4
4
  Home-page: https://github.com/Muhammadali-Akbarov/payme-pkg
5
5
  Author: Muhammadali Akbarov
6
6
  Author-email: muhammadali17abc@gmail.com
@@ -11,6 +11,15 @@ License-File: LICENSE.txt
11
11
  Requires-Dist: requests==2.*
12
12
  Requires-Dist: dataclasses==0.*; python_version < "3.7"
13
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
 
@@ -22,6 +22,7 @@ payme/exceptions/webhook.py
22
22
  payme/migrations/0001_initial.py
23
23
  payme/migrations/0002_paymetransactions_fiscal_data.py
24
24
  payme/migrations/0003_alter_paymetransactions_fiscal_data.py
25
+ payme/migrations/0004_alter_paymetransactions_account_id.py
25
26
  payme/migrations/__init__.py
26
27
  payme/types/__init__.py
27
28
  payme/types/request/__init__.py
@@ -8,7 +8,7 @@ long_description = (here / "README.md").read_text(encoding="utf-8")
8
8
 
9
9
  setup(
10
10
  name='payme-pkg',
11
- version='3.0.25b',
11
+ version='3.0.26',
12
12
  license='MIT',
13
13
  author="Muhammadali Akbarov",
14
14
  author_email='muhammadali17abc@gmail.com',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes