payme-pkg 2.6.7__py3-none-any.whl → 3.0.18__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.

Files changed (64) hide show
  1. payme/__init__.py +1 -0
  2. payme/admin.py +12 -6
  3. payme/apps.py +0 -4
  4. payme/classes/cards.py +203 -0
  5. payme/classes/client.py +30 -0
  6. payme/classes/http.py +111 -0
  7. payme/classes/initializer.py +82 -0
  8. payme/classes/receipts.py +298 -0
  9. payme/const.py +12 -0
  10. payme/exceptions/__init__.py +5 -0
  11. payme/exceptions/general.py +275 -0
  12. payme/exceptions/webhook.py +125 -0
  13. payme/models.py +113 -46
  14. payme/types/response/__init__.py +4 -0
  15. payme/types/response/cards.py +110 -0
  16. payme/types/response/receipts.py +215 -0
  17. payme/types/response/webhook.py +136 -0
  18. payme/urls.py +2 -2
  19. payme/util.py +26 -0
  20. payme/views.py +287 -113
  21. payme_pkg-3.0.18.dist-info/METADATA +193 -0
  22. payme_pkg-3.0.18.dist-info/RECORD +29 -0
  23. payme_pkg-3.0.18.dist-info/top_level.txt +1 -0
  24. core/asgi.py +0 -16
  25. core/settings.py +0 -133
  26. core/urls.py +0 -25
  27. core/wsgi.py +0 -16
  28. my_app/admin.py +0 -3
  29. my_app/apps.py +0 -6
  30. my_app/models.py +0 -3
  31. my_app/tests.py +0 -3
  32. my_app/views.py +0 -16
  33. payme/cards/__init__.py +0 -1
  34. payme/cards/subscribe_cards.py +0 -166
  35. payme/decorators/__init__.py +0 -0
  36. payme/decorators/decorators.py +0 -34
  37. payme/errors/__init__.py +0 -0
  38. payme/errors/exceptions.py +0 -89
  39. payme/methods/__init__.py +0 -0
  40. payme/methods/cancel_transaction.py +0 -54
  41. payme/methods/check_perform_transaction.py +0 -26
  42. payme/methods/check_transaction.py +0 -43
  43. payme/methods/create_transaction.py +0 -68
  44. payme/methods/generate_link.py +0 -83
  45. payme/methods/get_statement.py +0 -65
  46. payme/methods/perform_transaction.py +0 -47
  47. payme/migrations/0001_initial.py +0 -48
  48. payme/receipts/__init__.py +0 -1
  49. payme/receipts/subscribe_receipts.py +0 -217
  50. payme/serializers.py +0 -86
  51. payme/utils/__init__.py +0 -0
  52. payme/utils/get_params.py +0 -24
  53. payme/utils/logging.py +0 -9
  54. payme/utils/make_aware_datetime.py +0 -21
  55. payme/utils/support.py +0 -8
  56. payme/utils/to_json.py +0 -13
  57. payme_pkg-2.6.7.dist-info/METADATA +0 -13
  58. payme_pkg-2.6.7.dist-info/RECORD +0 -48
  59. payme_pkg-2.6.7.dist-info/top_level.txt +0 -3
  60. {core → payme/classes}/__init__.py +0 -0
  61. {my_app → payme/types}/__init__.py +0 -0
  62. {my_app/migrations → payme/types/request}/__init__.py +0 -0
  63. {payme_pkg-2.6.7.dist-info → payme_pkg-3.0.18.dist-info}/LICENSE.txt +0 -0
  64. {payme_pkg-2.6.7.dist-info → payme_pkg-3.0.18.dist-info}/WHEEL +0 -0
payme/__init__.py CHANGED
@@ -0,0 +1 @@
1
+ from payme.classes.client import Payme # noqa
payme/admin.py CHANGED
@@ -1,11 +1,17 @@
1
1
  from django.contrib import admin
2
2
 
3
- from payme.models import CUSTOM_ORDER
4
- from payme.models import Order as DefaultOrderModel
5
3
 
6
- from payme.models import MerchantTransactionsModel
4
+ from payme.models import PaymeTransactions
7
5
 
8
- if not CUSTOM_ORDER:
9
- admin.site.register(DefaultOrderModel)
10
6
 
11
- admin.site.register(MerchantTransactionsModel)
7
+ class PaymeTransactionsUI(admin.ModelAdmin):
8
+ """
9
+ Custom admin interface for PaymeTransactions model.
10
+ """
11
+ list_display = ('id', 'state', 'cancel_reason', 'created_at')
12
+ list_filter = ('state', 'cancel_reason', 'created_at')
13
+ search_fields = ('transaction_id', 'account__id')
14
+ ordering = ('-created_at',)
15
+
16
+
17
+ admin.site.register(PaymeTransactions, PaymeTransactionsUI)
payme/apps.py CHANGED
@@ -2,9 +2,5 @@ from django.apps import AppConfig
2
2
 
3
3
 
4
4
  class PaymeConfig(AppConfig):
5
- """
6
- PaymeConfig AppConfig \
7
- That is used to configure the payme application with django settings.
8
- """
9
5
  default_auto_field = 'django.db.models.BigAutoField'
10
6
  name = 'payme'
payme/classes/cards.py ADDED
@@ -0,0 +1,203 @@
1
+ from typing import Optional
2
+
3
+ from payme.classes.http import HttpClient
4
+ from payme.types.response import cards as response
5
+
6
+
7
+ ALLOWED_METHODS = {
8
+ "cards.create": response.CardsCreateResponse,
9
+ "cards.get_verify_code": response.GetVerifyResponse,
10
+ "cards.verify": response.VerifyResponse,
11
+ "cards.remove": response.RemoveResponse,
12
+ "cards.check": response.CheckResponse
13
+ }
14
+
15
+
16
+ class Cards:
17
+ """
18
+ The Cards class provides a simple interface to interact with Paycom card
19
+ services. It allows you to create new cards and retrieve verification
20
+ codes for existing cards.
21
+ """
22
+ def __init__(self, url: str, payme_id: str) -> "Cards":
23
+ """
24
+ Initialize the Cards client.
25
+
26
+ :param payme_id: The Paycom ID used for authentication.
27
+ :param url: The base URL for the Paycom card service API.
28
+ """
29
+ headers = {
30
+ "X-Auth": payme_id,
31
+ "Content-Type": "application/json"
32
+ }
33
+ self.http = HttpClient(url, headers)
34
+
35
+ def create(self, number: str, expire: str, save: bool = False,
36
+ timeout: int = 10) -> response.CardsCreateResponse:
37
+ """
38
+ Create a new card.
39
+
40
+ :param number: The card number.
41
+ :param expire: The expiration date of the card in MMYY format.
42
+ :param save: A boolean indicating whether to save the card for future
43
+ use (default is False).
44
+ :param timeout: The request timeout duration in seconds (default is
45
+ 10 seconds).
46
+ :return: A CardsCreateResponse object containing the response data.
47
+ """
48
+ method = "cards.create"
49
+ params = {"card": {"number": number, "expire": expire}, "save": save}
50
+ return self._post_request(method, params, timeout)
51
+
52
+ def get_verify_code(self, token: str, timeout: int = 10) -> \
53
+ response.GetVerifyResponse:
54
+ """
55
+ Retrieve a verification code for a specified token.
56
+
57
+ :param token: The token associated with the card.
58
+ :param timeout: The request timeout duration in seconds (default is
59
+ 10 seconds).
60
+ :return: A GetVerifyResponse object containing the response data.
61
+ """
62
+ method = "cards.get_verify_code"
63
+ params = {"token": token}
64
+ return self._post_request(method, params, timeout)
65
+
66
+ def verify(self, token: str, code: str, timeout: int = 10) -> \
67
+ response.VerifyResponse:
68
+ """
69
+ Verify a verification code for a specified token.
70
+
71
+ :param token: The token associated with the card.
72
+ :param code: The verification code to be verified.
73
+ :param timeout: The request timeout duration in seconds (default is
74
+ 10 seconds).
75
+ :return: A VerifyResponse object containing the response data.
76
+ """
77
+ method = "cards.verify"
78
+ params = {"token": token, "code": code}
79
+ return self._post_request(method, params, timeout)
80
+
81
+ def remove(self, token: str, timeout: int = 10) -> response.RemoveResponse:
82
+ """
83
+ Remove a card from the Paycom system.
84
+
85
+ :param token: The token associated with the card.
86
+ :param timeout: The request timeout duration in seconds (default is
87
+ 10 seconds).
88
+ :return: A RemoveResponse object containing the response data.
89
+ """
90
+ method = "cards.remove"
91
+ params = {"token": token}
92
+ return self._post_request(method, params, timeout)
93
+
94
+ def check(self, token: str, timeout: int = 10) -> response.CheckResponse:
95
+ """
96
+ Check the status of a card.
97
+
98
+ :param token: The token associated with the card.
99
+ :param timeout: The request timeout duration in seconds (default is
100
+ 10 seconds).
101
+ :return: A CheckResponse object containing the response data.
102
+ """
103
+ method = "cards.check"
104
+ params = {"token": token}
105
+ return self._post_request(method, params, timeout)
106
+
107
+ def _post_request(self, method: str, params: dict,
108
+ timeout: int = 10) -> response.Common:
109
+ """
110
+ Helper method to post requests to the HTTP client.
111
+
112
+ :param method: The API method to be called.
113
+ :param params: The parameters to be sent with the request.
114
+ :param timeout: The request timeout duration in seconds (default is
115
+ 10 seconds).
116
+ :return: A response object corresponding to the method called.
117
+ """
118
+ json = {"method": method, "params": params}
119
+ dict_result = self.http.post(json, timeout)
120
+ response_class = ALLOWED_METHODS[method]
121
+ return response_class.from_dict(dict_result)
122
+
123
+ def test(self):
124
+ """
125
+ Run a comprehensive test suite for card functionalities including
126
+ creation, verification, status check, and removal.
127
+ """
128
+ # Expected values for verification
129
+ number = "8600495473316478"
130
+ expire = "0399"
131
+
132
+ expected_number = "860049******6478"
133
+ expected_expire = "03/99"
134
+ verify_code = "666666"
135
+
136
+ # Step 1: Create Card
137
+ create_response = self.create(number=number, expire=expire)
138
+ token = create_response.result.card.token
139
+
140
+ # Validate card creation response
141
+ self._assert_and_print(
142
+ create_response.result.card.number == expected_number,
143
+ "Card number matched.",
144
+ test_case="Card Creation - Number Validation"
145
+ )
146
+ self._assert_and_print(
147
+ create_response.result.card.expire == expected_expire,
148
+ "Expiration date matched.",
149
+ test_case="Card Creation - Expiration Date Validation"
150
+ )
151
+
152
+ # Step 2: Get Verification Code
153
+ get_verify_response = self.get_verify_code(token=token)
154
+ self._assert_and_print(
155
+ get_verify_response.result.sent is True,
156
+ "Verification code requested successfully.",
157
+ test_case="Verification Code Request"
158
+ )
159
+
160
+ # Step 3: Verify Code
161
+ verify_response = self.verify(token=token, code=verify_code)
162
+ self._assert_and_print(
163
+ verify_response.result.card.verify is True,
164
+ "Verification code validated successfully.",
165
+ test_case="Code Verification"
166
+ )
167
+
168
+ # Step 4: Check Card Status
169
+ check_response = self.check(token=token)
170
+ self._assert_and_print(
171
+ check_response.result.card.verify is True,
172
+ "Card status verified successfully.",
173
+ test_case="Card Status Check"
174
+ )
175
+
176
+ # Step 5: Remove Card
177
+ remove_response = self.remove(token=token)
178
+ self._assert_and_print(
179
+ remove_response.result.success is True,
180
+ "Card removed successfully.",
181
+ test_case="Card Removal"
182
+ )
183
+
184
+ def _assert_and_print(self, condition: bool, success_message: str,
185
+ test_case: Optional[str] = None):
186
+ """
187
+ Assertion helper that prints success or failure messages based on
188
+ test outcomes.
189
+
190
+ :param condition: The test condition to check.
191
+ :param success_message: Message to print upon successful test.
192
+ :param test_case: A description of the test case (optional).
193
+ """
194
+ try:
195
+ assert condition, "Assertion failed!"
196
+ print(f"Success: {success_message}")
197
+ except AssertionError as exc:
198
+ error_message = (
199
+ f"Test Case Failed: {test_case or 'Unknown Test Case'}\n"
200
+ f"Error Details: {str(exc)}"
201
+ )
202
+ print(error_message)
203
+ raise AssertionError(error_message) from exc
@@ -0,0 +1,30 @@
1
+
2
+ from typing import Union
3
+
4
+ from payme.const import Networks
5
+ from payme.classes.cards import Cards
6
+ from payme.classes.receipts import Receipts
7
+ from payme.classes.initializer import Initializer
8
+
9
+
10
+ class Payme:
11
+ """
12
+ The payme class provides a simple interface
13
+ """
14
+ def __init__(
15
+ self,
16
+ payme_id: str,
17
+ fallback_id: Union[str, None] = None,
18
+ payme_key: Union[str, None] = None,
19
+ is_test_mode: bool = False
20
+ ):
21
+
22
+ # initialize payme network
23
+ url = Networks.PROD_NET.value
24
+
25
+ if is_test_mode is True:
26
+ url = Networks.TEST_NET.value
27
+
28
+ self.cards = Cards(url=url, payme_id=payme_id)
29
+ self.initializer = Initializer(payme_id=payme_id, fallback_id=fallback_id)
30
+ self.receipts = Receipts(url=url, payme_id=payme_id, payme_key=payme_key) # noqa
payme/classes/http.py ADDED
@@ -0,0 +1,111 @@
1
+ import requests
2
+
3
+ from payme.exceptions import general as exc
4
+
5
+
6
+ networking_errors = (
7
+ requests.exceptions.Timeout,
8
+ requests.exceptions.HTTPError,
9
+ requests.exceptions.ConnectionError,
10
+ requests.exceptions.TooManyRedirects,
11
+ requests.exceptions.URLRequired,
12
+ requests.exceptions.MissingSchema,
13
+ requests.exceptions.InvalidURL,
14
+ requests.exceptions.InvalidHeader,
15
+ requests.exceptions.JSONDecodeError,
16
+ requests.exceptions.ConnectTimeout,
17
+ requests.exceptions.ReadTimeout,
18
+ requests.exceptions.SSLError,
19
+ requests.exceptions.ProxyError,
20
+ requests.exceptions.ChunkedEncodingError,
21
+ requests.exceptions.StreamConsumedError,
22
+ requests.exceptions.RequestException
23
+ )
24
+
25
+
26
+ class HttpClient:
27
+ """
28
+ A simple HTTP client to handle requests to a specified URL.
29
+ It provides methods for sending GET, POST, PUT, and DELETE requests
30
+ with error handling.
31
+ """
32
+
33
+ def __init__(self, url: str, headers: dict = None):
34
+ """
35
+ Initialize the HttpClient.
36
+
37
+ Parameters
38
+ ----------
39
+ url : str
40
+ The base URL for the API (e.g., 'https://checkout.paycom.uz/api').
41
+ headers : dict, optional
42
+ Optional default headers to include in all requests.
43
+ These headers will be sent with every request unless overridden.
44
+ """
45
+ self.url = url
46
+ self.headers = headers
47
+
48
+ def post(self, json: dict, timeout: int = 10):
49
+ """
50
+ Send a POST request to the specified URL with the provided JSON data.
51
+
52
+ Parameters
53
+ ----------
54
+ json : dict
55
+ The JSON data payload for the POST request. This will be sent
56
+ as the request body.
57
+ timeout : int, optional
58
+ The request timeout duration in seconds (default is 10 seconds).
59
+
60
+ Returns
61
+ -------
62
+ dict
63
+ A dictionary containing the response data if the request was
64
+ successful, or an error message if an error occurred.
65
+ """
66
+ try:
67
+ response = requests.post(
68
+ url=self.url,
69
+ headers=self.headers,
70
+ json=json,
71
+ timeout=timeout
72
+ )
73
+ response.raise_for_status()
74
+ response_data = response.json()
75
+
76
+ # Check if the response contains a specific error format
77
+ if "error" in response_data:
78
+ return self.handle_payme_error(response_data["error"])
79
+
80
+ return response_data
81
+
82
+ except networking_errors as exc_data:
83
+ raise exc.PaymeNetworkError(data=exc_data)
84
+
85
+ def handle_payme_error(self, error: dict):
86
+ """
87
+ Handle Paycom-specific errors from the JSON-RPC error response.
88
+
89
+ Parameters
90
+ ----------
91
+ error : dict
92
+ The error dictionary from Paycom's response, typically containing
93
+ error details such as code, message, and data.
94
+
95
+ Returns
96
+ -------
97
+ None
98
+ Raises an exception based on the error code received from
99
+ Paycom's response.
100
+ """
101
+ error_code = error.get("code", "Unknown code")
102
+ error_message = error.get("message", "Unknown error")
103
+ error_data = error.get("data", "")
104
+
105
+ exception_class = exc.errors_map.get(error_code, exc.BaseError)
106
+ exception_class.message = error_message
107
+
108
+ if exception_class == exc.BaseError:
109
+ raise exc.BaseError(code=error_code, message=error_message)
110
+
111
+ raise exception_class(data=error_data)
@@ -0,0 +1,82 @@
1
+ import base64
2
+
3
+ from django.conf import settings
4
+
5
+
6
+ class Initializer:
7
+ """
8
+ Initialize the Payme class with necessary details.
9
+
10
+ Attributes
11
+ ----------
12
+ payme_id: str
13
+ The Payme ID associated with your account
14
+ """
15
+
16
+ def __init__(self, payme_id: str = None, fallback_id: str = None):
17
+ self.payme_id = payme_id
18
+ self.fallback_id = fallback_id
19
+
20
+
21
+ def generate_pay_link(
22
+ self,
23
+ id: int,
24
+ amount: int,
25
+ return_url: str
26
+ ) -> str:
27
+ """
28
+ Generate a payment link for a specific order.
29
+
30
+ This method encodes the payment parameters into a base64 string and
31
+ constructs a URL for the Payme checkout.
32
+
33
+ Parameters
34
+ ----------
35
+ id : int
36
+ Unique identifier for the account.
37
+ amount : int
38
+ The amount associated with the order in currency units.
39
+ return_url : str
40
+ The URL to which the user will be redirected after the payment is
41
+ processed.
42
+
43
+ Returns
44
+ -------
45
+ str
46
+ A payment link formatted as a URL, ready to be used in the payment
47
+ process.
48
+
49
+ References
50
+ ----------
51
+ For full method documentation, visit:
52
+ https://developer.help.paycom.uz/initsializatsiya-platezhey/
53
+ """
54
+ 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
+ )
58
+ params = base64.b64encode(params.encode("utf-8")).decode("utf-8")
59
+ return f"https://checkout.paycom.uz/{params}"
60
+
61
+ def generate_fallback_link(self, form_fields: dict = None):
62
+ """
63
+ Generate a fallback URL for the Payme checkout.
64
+
65
+ Parameters
66
+ ----------
67
+ fields : dict, optional
68
+ Additional query parameters to be appended to the fallback URL.
69
+
70
+ Returns
71
+ -------
72
+ str
73
+ A fallback URL formatted as a URL, ready to be used in the payment
74
+ process.
75
+ """
76
+ result = f"https://payme.uz/fallback/merchant/?id={self.fallback_id}"
77
+
78
+ if form_fields is not None:
79
+ for key, value in form_fields.items():
80
+ result += f"&{key}={value}"
81
+
82
+ return result