payme-pkg 2.6.7__tar.gz → 3.0.3__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.
- {payme_pkg-2.6.7/lib/payme_pkg.egg-info → payme_pkg-3.0.3}/PKG-INFO +1 -1
- payme_pkg-3.0.3/README.md +125 -0
- payme_pkg-3.0.3/payme/__init__.py +1 -0
- payme_pkg-3.0.3/payme/admin.py +17 -0
- {payme_pkg-2.6.7/lib/my_app → payme_pkg-3.0.3/payme}/apps.py +2 -2
- payme_pkg-3.0.3/payme/classes/cards.py +212 -0
- payme_pkg-3.0.3/payme/classes/client.py +31 -0
- payme_pkg-3.0.3/payme/classes/http.py +106 -0
- payme_pkg-3.0.3/payme/classes/initializer.py +77 -0
- payme_pkg-3.0.3/payme/classes/receipts.py +307 -0
- payme_pkg-3.0.3/payme/const.py +35 -0
- payme_pkg-3.0.3/payme/exceptions/__init__.py +5 -0
- payme_pkg-3.0.3/payme/exceptions/general.py +250 -0
- payme_pkg-3.0.3/payme/exceptions/webhook.py +125 -0
- payme_pkg-3.0.3/payme/models.py +136 -0
- payme_pkg-3.0.3/payme/types/response/__init__.py +4 -0
- payme_pkg-3.0.3/payme/types/response/cards.py +110 -0
- payme_pkg-3.0.3/payme/types/response/receipts.py +216 -0
- payme_pkg-3.0.3/payme/types/response/webhook.py +136 -0
- payme_pkg-3.0.3/payme/urls.py +8 -0
- payme_pkg-3.0.3/payme/util.py +53 -0
- payme_pkg-3.0.3/payme/views.py +332 -0
- {payme_pkg-2.6.7 → payme_pkg-3.0.3/payme_pkg.egg-info}/PKG-INFO +1 -1
- payme_pkg-3.0.3/payme_pkg.egg-info/SOURCES.txt +33 -0
- payme_pkg-3.0.3/payme_pkg.egg-info/top_level.txt +1 -0
- {payme_pkg-2.6.7 → payme_pkg-3.0.3}/setup.py +2 -3
- payme_pkg-2.6.7/README.md +0 -22
- payme_pkg-2.6.7/lib/core/asgi.py +0 -16
- payme_pkg-2.6.7/lib/core/settings.py +0 -133
- payme_pkg-2.6.7/lib/core/urls.py +0 -25
- payme_pkg-2.6.7/lib/core/wsgi.py +0 -16
- payme_pkg-2.6.7/lib/my_app/admin.py +0 -3
- payme_pkg-2.6.7/lib/my_app/models.py +0 -3
- payme_pkg-2.6.7/lib/my_app/tests.py +0 -3
- payme_pkg-2.6.7/lib/my_app/views.py +0 -16
- payme_pkg-2.6.7/lib/payme/admin.py +0 -11
- payme_pkg-2.6.7/lib/payme/apps.py +0 -10
- payme_pkg-2.6.7/lib/payme/cards/__init__.py +0 -1
- payme_pkg-2.6.7/lib/payme/cards/subscribe_cards.py +0 -166
- payme_pkg-2.6.7/lib/payme/decorators/__init__.py +0 -0
- payme_pkg-2.6.7/lib/payme/decorators/decorators.py +0 -34
- payme_pkg-2.6.7/lib/payme/errors/__init__.py +0 -0
- payme_pkg-2.6.7/lib/payme/errors/exceptions.py +0 -89
- payme_pkg-2.6.7/lib/payme/methods/__init__.py +0 -0
- payme_pkg-2.6.7/lib/payme/methods/cancel_transaction.py +0 -54
- payme_pkg-2.6.7/lib/payme/methods/check_perform_transaction.py +0 -26
- payme_pkg-2.6.7/lib/payme/methods/check_transaction.py +0 -43
- payme_pkg-2.6.7/lib/payme/methods/create_transaction.py +0 -68
- payme_pkg-2.6.7/lib/payme/methods/generate_link.py +0 -83
- payme_pkg-2.6.7/lib/payme/methods/get_statement.py +0 -65
- payme_pkg-2.6.7/lib/payme/methods/perform_transaction.py +0 -47
- payme_pkg-2.6.7/lib/payme/migrations/0001_initial.py +0 -48
- payme_pkg-2.6.7/lib/payme/migrations/__init__.py +0 -0
- payme_pkg-2.6.7/lib/payme/models.py +0 -68
- payme_pkg-2.6.7/lib/payme/receipts/__init__.py +0 -1
- payme_pkg-2.6.7/lib/payme/receipts/subscribe_receipts.py +0 -217
- payme_pkg-2.6.7/lib/payme/serializers.py +0 -86
- payme_pkg-2.6.7/lib/payme/urls.py +0 -8
- payme_pkg-2.6.7/lib/payme/utils/__init__.py +0 -0
- payme_pkg-2.6.7/lib/payme/utils/get_params.py +0 -24
- payme_pkg-2.6.7/lib/payme/utils/logging.py +0 -9
- payme_pkg-2.6.7/lib/payme/utils/make_aware_datetime.py +0 -21
- payme_pkg-2.6.7/lib/payme/utils/support.py +0 -8
- payme_pkg-2.6.7/lib/payme/utils/to_json.py +0 -13
- payme_pkg-2.6.7/lib/payme/views.py +0 -163
- payme_pkg-2.6.7/lib/payme_pkg.egg-info/SOURCES.txt +0 -54
- payme_pkg-2.6.7/lib/payme_pkg.egg-info/top_level.txt +0 -3
- payme_pkg-2.6.7/tests/test_cards.py +0 -25
- payme_pkg-2.6.7/tests/test_receipts.py +0 -67
- {payme_pkg-2.6.7 → payme_pkg-3.0.3}/LICENSE.txt +0 -0
- {payme_pkg-2.6.7/lib/core → payme_pkg-3.0.3/payme/classes}/__init__.py +0 -0
- {payme_pkg-2.6.7/lib/my_app → payme_pkg-3.0.3/payme/migrations}/__init__.py +0 -0
- {payme_pkg-2.6.7/lib/my_app/migrations → payme_pkg-3.0.3/payme/types}/__init__.py +0 -0
- {payme_pkg-2.6.7/lib/payme → payme_pkg-3.0.3/payme/types/request}/__init__.py +0 -0
- {payme_pkg-2.6.7/lib → payme_pkg-3.0.3}/payme_pkg.egg-info/dependency_links.txt +0 -0
- {payme_pkg-2.6.7/lib → payme_pkg-3.0.3}/payme_pkg.egg-info/requires.txt +0 -0
- {payme_pkg-2.6.7 → payme_pkg-3.0.3}/setup.cfg +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<h1 align="center">Payme PKG</h1>
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
<p align="center">
|
|
5
|
+
<a href="https://docs.pay-tech.uz"><img src="https://img.shields.io/static/v1?message=Documented%20on%20GitBook&logo=gitbook&logoColor=ffffff&label=%20&labelColor=5c5c5c&color=3F89A1"></a>
|
|
6
|
+
<a href="https://github.com/PayTechUz/payme-pkg"><img src="https://img.shields.io/badge/Open_Source-❤️-FDA599?"/></a>
|
|
7
|
+
<a href="t.me/+DK7n7lKx8GY5ZDZi"><img src="https://img.shields.io/badge/Community-Join%20Us-blueviolet"/></a>
|
|
8
|
+
<a href="https://github.com/PayTechUz/payme-pkg/issues"><img src="https://img.shields.io/github/issues/gitbookIO/gitbook"/></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">Welcome to payme-pkg, the open source payme sdk for python.</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">You can use for test and production mode. Join our community and ask everything you need.
|
|
14
|
+
</p>
|
|
15
|
+
<a href="https://docs.pay-tech.uz">
|
|
16
|
+
<p align="center">Visit to full documentation for Merchant and Subcribe Api</p>
|
|
17
|
+
</a>
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img style="width: 60%;" src="https://i.postimg.cc/WbD32bHC/payme-pkg-demo-m4a.gif">
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```shell
|
|
25
|
+
pip install payme-pkg
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Installation to Django
|
|
29
|
+
|
|
30
|
+
Add `'payme'` in to your settings.py
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
INSTALLED_APPS = [
|
|
34
|
+
...
|
|
35
|
+
'payme',
|
|
36
|
+
...
|
|
37
|
+
]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Add `'payme'` credentials inside to settings.py
|
|
41
|
+
|
|
42
|
+
One time payment configuration settings.py
|
|
43
|
+
```python
|
|
44
|
+
PAYME_ID = "your-payme-id"
|
|
45
|
+
PAYME_KEY = "your-payme-key"
|
|
46
|
+
PAYME_ACCOUNT_FIELD = "id"
|
|
47
|
+
PAYME_AMOUNT_FIELD = "total_amount"
|
|
48
|
+
PAYME_ACCOUNT_MODEL = "orders.models.Orders"
|
|
49
|
+
PAYME_ONE_TIME_PAYMENT = True
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Multi payment configuration settings.py
|
|
53
|
+
```python
|
|
54
|
+
PAYME_ID = "your-payme-id"
|
|
55
|
+
PAYME_KEY = "your-payme-key"
|
|
56
|
+
PAYME_ACCOUNT_FIELD = "id"
|
|
57
|
+
PAYME_ACCOUNT_MODEL = "clients.models.Client"
|
|
58
|
+
PAYME_ONE_TIME_PAYMENT = False
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Create a new View that about handling call backs
|
|
62
|
+
```python
|
|
63
|
+
from payme.views import PaymeWebHookAPIView
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PaymeCallBackAPIView(PaymeWebHookAPIView):
|
|
67
|
+
def handle_created_payment(self, params, result, *args, **kwargs):
|
|
68
|
+
"""
|
|
69
|
+
Handle the successful payment. You can override this method
|
|
70
|
+
"""
|
|
71
|
+
print(f"Transaction created for this params: {params} and cr_result: {result}")
|
|
72
|
+
|
|
73
|
+
def handle_successfully_payment(self, params, result, *args, **kwargs):
|
|
74
|
+
"""
|
|
75
|
+
Handle the successful payment. You can override this method
|
|
76
|
+
"""
|
|
77
|
+
print(f"Transaction successfully performed for this params: {params} and performed_result: {result}")
|
|
78
|
+
|
|
79
|
+
def handle_cancelled_payment(self, params, result, *args, **kwargs):
|
|
80
|
+
"""
|
|
81
|
+
Handle the cancelled payment. You can override this method
|
|
82
|
+
"""
|
|
83
|
+
print(f"Transaction cancelled for this params: {params} and cancelled_result: {result}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Add a `payme` path to core of urlpatterns:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from django.urls import path
|
|
90
|
+
from django.urls import include
|
|
91
|
+
|
|
92
|
+
from your_app.views import PaymeCallBackAPIView
|
|
93
|
+
|
|
94
|
+
urlpatterns = [
|
|
95
|
+
...
|
|
96
|
+
path("payment/update/", PaymeCallBackAPIView.as_view()),
|
|
97
|
+
...
|
|
98
|
+
]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Run migrations
|
|
102
|
+
```shell
|
|
103
|
+
python3 manage.py makemigrations && python manage.py migrate
|
|
104
|
+
```
|
|
105
|
+
🎉 Congratulations you have been integrated merchant api methods with django, keep reading docs. After successfull migrations check your admin panel and see results what happened.
|
|
106
|
+
|
|
107
|
+
## Generate Pay Link
|
|
108
|
+
|
|
109
|
+
Example to generate link:
|
|
110
|
+
|
|
111
|
+
- Input
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from payme import Payme
|
|
115
|
+
|
|
116
|
+
payme = Payme(payme_id="your-payme-id")
|
|
117
|
+
pay_link = payme.initializer.generate_pay_link(id=123456, amount=5000, return_url="https://example.com")
|
|
118
|
+
print(pay_link)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Output
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
https://checkout.paycom.uz/bT15b3VyLXBheW1lLWlkO2FjLmlkPTEyMzQ1NjthPTUwMDAwMDtjPWh0dHBzOi8vZXhhbXBsZS5jb20=
|
|
125
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from payme.classes.client import Payme # noqa
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from payme.models import PaymeTransactions
|
|
5
|
+
|
|
6
|
+
|
|
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)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from payme.util import input_type_checker
|
|
4
|
+
from payme.classes.http import HttpClient
|
|
5
|
+
from payme.types.response import cards as response
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ALLOWED_METHODS = {
|
|
9
|
+
"cards.create": response.CardsCreateResponse,
|
|
10
|
+
"cards.get_verify_code": response.GetVerifyResponse,
|
|
11
|
+
"cards.verify": response.VerifyResponse,
|
|
12
|
+
"cards.remove": response.RemoveResponse,
|
|
13
|
+
"cards.check": response.CheckResponse
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Cards:
|
|
18
|
+
"""
|
|
19
|
+
The Cards class provides a simple interface to interact with Paycom card
|
|
20
|
+
services. It allows you to create new cards and retrieve verification
|
|
21
|
+
codes for existing cards.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@input_type_checker
|
|
25
|
+
def __init__(self, url: str, payme_id: str) -> "Cards":
|
|
26
|
+
"""
|
|
27
|
+
Initialize the Cards client.
|
|
28
|
+
|
|
29
|
+
:param payme_id: The Paycom ID used for authentication.
|
|
30
|
+
:param url: The base URL for the Paycom card service API.
|
|
31
|
+
"""
|
|
32
|
+
headers = {
|
|
33
|
+
"X-Auth": payme_id,
|
|
34
|
+
"Content-Type": "application/json"
|
|
35
|
+
}
|
|
36
|
+
self.http = HttpClient(url, headers)
|
|
37
|
+
|
|
38
|
+
@input_type_checker
|
|
39
|
+
def create(self, number: str, expire: str, save: bool = False,
|
|
40
|
+
timeout: int = 10) -> response.CardsCreateResponse:
|
|
41
|
+
"""
|
|
42
|
+
Create a new card.
|
|
43
|
+
|
|
44
|
+
:param number: The card number.
|
|
45
|
+
:param expire: The expiration date of the card in MMYY format.
|
|
46
|
+
:param save: A boolean indicating whether to save the card for future
|
|
47
|
+
use (default is False).
|
|
48
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
49
|
+
10 seconds).
|
|
50
|
+
:return: A CardsCreateResponse object containing the response data.
|
|
51
|
+
"""
|
|
52
|
+
method = "cards.create"
|
|
53
|
+
params = {"card": {"number": number, "expire": expire}, "save": save}
|
|
54
|
+
return self._post_request(method, params, timeout)
|
|
55
|
+
|
|
56
|
+
@input_type_checker
|
|
57
|
+
def get_verify_code(self, token: str, timeout: int = 10) -> \
|
|
58
|
+
response.GetVerifyResponse:
|
|
59
|
+
"""
|
|
60
|
+
Retrieve a verification code for a specified token.
|
|
61
|
+
|
|
62
|
+
:param token: The token associated with the card.
|
|
63
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
64
|
+
10 seconds).
|
|
65
|
+
:return: A GetVerifyResponse object containing the response data.
|
|
66
|
+
"""
|
|
67
|
+
method = "cards.get_verify_code"
|
|
68
|
+
params = {"token": token}
|
|
69
|
+
return self._post_request(method, params, timeout)
|
|
70
|
+
|
|
71
|
+
@input_type_checker
|
|
72
|
+
def verify(self, token: str, code: str, timeout: int = 10) -> \
|
|
73
|
+
response.VerifyResponse:
|
|
74
|
+
"""
|
|
75
|
+
Verify a verification code for a specified token.
|
|
76
|
+
|
|
77
|
+
:param token: The token associated with the card.
|
|
78
|
+
:param code: The verification code to be verified.
|
|
79
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
80
|
+
10 seconds).
|
|
81
|
+
:return: A VerifyResponse object containing the response data.
|
|
82
|
+
"""
|
|
83
|
+
method = "cards.verify"
|
|
84
|
+
params = {"token": token, "code": code}
|
|
85
|
+
return self._post_request(method, params, timeout)
|
|
86
|
+
|
|
87
|
+
@input_type_checker
|
|
88
|
+
def remove(self, token: str, timeout: int = 10) -> response.RemoveResponse:
|
|
89
|
+
"""
|
|
90
|
+
Remove a card from the Paycom system.
|
|
91
|
+
|
|
92
|
+
:param token: The token associated with the card.
|
|
93
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
94
|
+
10 seconds).
|
|
95
|
+
:return: A RemoveResponse object containing the response data.
|
|
96
|
+
"""
|
|
97
|
+
method = "cards.remove"
|
|
98
|
+
params = {"token": token}
|
|
99
|
+
return self._post_request(method, params, timeout)
|
|
100
|
+
|
|
101
|
+
@input_type_checker
|
|
102
|
+
def check(self, token: str, timeout: int = 10) -> response.CheckResponse:
|
|
103
|
+
"""
|
|
104
|
+
Check the status of a card.
|
|
105
|
+
|
|
106
|
+
:param token: The token associated with the card.
|
|
107
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
108
|
+
10 seconds).
|
|
109
|
+
:return: A CheckResponse object containing the response data.
|
|
110
|
+
"""
|
|
111
|
+
method = "cards.check"
|
|
112
|
+
params = {"token": token}
|
|
113
|
+
return self._post_request(method, params, timeout)
|
|
114
|
+
|
|
115
|
+
@input_type_checker
|
|
116
|
+
def _post_request(self, method: str, params: dict,
|
|
117
|
+
timeout: int = 10) -> response.Common:
|
|
118
|
+
"""
|
|
119
|
+
Helper method to post requests to the HTTP client.
|
|
120
|
+
|
|
121
|
+
:param method: The API method to be called.
|
|
122
|
+
:param params: The parameters to be sent with the request.
|
|
123
|
+
:param timeout: The request timeout duration in seconds (default is
|
|
124
|
+
10 seconds).
|
|
125
|
+
:return: A response object corresponding to the method called.
|
|
126
|
+
"""
|
|
127
|
+
json = {"method": method, "params": params}
|
|
128
|
+
dict_result = self.http.post(json, timeout)
|
|
129
|
+
response_class = ALLOWED_METHODS[method]
|
|
130
|
+
return response_class.from_dict(dict_result)
|
|
131
|
+
|
|
132
|
+
def test(self):
|
|
133
|
+
"""
|
|
134
|
+
Run a comprehensive test suite for card functionalities including
|
|
135
|
+
creation, verification, status check, and removal.
|
|
136
|
+
"""
|
|
137
|
+
# Expected values for verification
|
|
138
|
+
number = "8600495473316478"
|
|
139
|
+
expire = "0399"
|
|
140
|
+
|
|
141
|
+
expected_number = "860049******6478"
|
|
142
|
+
expected_expire = "03/99"
|
|
143
|
+
verify_code = "666666"
|
|
144
|
+
|
|
145
|
+
# Step 1: Create Card
|
|
146
|
+
create_response = self.create(number=number, expire=expire)
|
|
147
|
+
token = create_response.result.card.token
|
|
148
|
+
|
|
149
|
+
# Validate card creation response
|
|
150
|
+
self._assert_and_print(
|
|
151
|
+
create_response.result.card.number == expected_number,
|
|
152
|
+
"Card number matched.",
|
|
153
|
+
test_case="Card Creation - Number Validation"
|
|
154
|
+
)
|
|
155
|
+
self._assert_and_print(
|
|
156
|
+
create_response.result.card.expire == expected_expire,
|
|
157
|
+
"Expiration date matched.",
|
|
158
|
+
test_case="Card Creation - Expiration Date Validation"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Step 2: Get Verification Code
|
|
162
|
+
get_verify_response = self.get_verify_code(token=token)
|
|
163
|
+
self._assert_and_print(
|
|
164
|
+
get_verify_response.result.sent is True,
|
|
165
|
+
"Verification code requested successfully.",
|
|
166
|
+
test_case="Verification Code Request"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Step 3: Verify Code
|
|
170
|
+
verify_response = self.verify(token=token, code=verify_code)
|
|
171
|
+
self._assert_and_print(
|
|
172
|
+
verify_response.result.card.verify is True,
|
|
173
|
+
"Verification code validated successfully.",
|
|
174
|
+
test_case="Code Verification"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Step 4: Check Card Status
|
|
178
|
+
check_response = self.check(token=token)
|
|
179
|
+
self._assert_and_print(
|
|
180
|
+
check_response.result.card.verify is True,
|
|
181
|
+
"Card status verified successfully.",
|
|
182
|
+
test_case="Card Status Check"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Step 5: Remove Card
|
|
186
|
+
remove_response = self.remove(token=token)
|
|
187
|
+
self._assert_and_print(
|
|
188
|
+
remove_response.result.success is True,
|
|
189
|
+
"Card removed successfully.",
|
|
190
|
+
test_case="Card Removal"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def _assert_and_print(self, condition: bool, success_message: str,
|
|
194
|
+
test_case: Optional[str] = None):
|
|
195
|
+
"""
|
|
196
|
+
Assertion helper that prints success or failure messages based on
|
|
197
|
+
test outcomes.
|
|
198
|
+
|
|
199
|
+
:param condition: The test condition to check.
|
|
200
|
+
:param success_message: Message to print upon successful test.
|
|
201
|
+
:param test_case: A description of the test case (optional).
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
assert condition, "Assertion failed!"
|
|
205
|
+
print(f"Success: {success_message}")
|
|
206
|
+
except AssertionError as exc:
|
|
207
|
+
error_message = (
|
|
208
|
+
f"Test Case Failed: {test_case or 'Unknown Test Case'}\n"
|
|
209
|
+
f"Error Details: {str(exc)}"
|
|
210
|
+
)
|
|
211
|
+
print(error_message)
|
|
212
|
+
raise AssertionError(error_message) from exc
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
from payme.const import Networks
|
|
5
|
+
from payme.classes.cards import Cards
|
|
6
|
+
from payme.util import input_type_checker
|
|
7
|
+
from payme.classes.receipts import Receipts
|
|
8
|
+
from payme.classes.initializer import Initializer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Payme:
|
|
12
|
+
"""
|
|
13
|
+
The payme class provides a simple interface
|
|
14
|
+
"""
|
|
15
|
+
@input_type_checker
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
payme_id: str,
|
|
19
|
+
payme_key: Union[str, None] = None,
|
|
20
|
+
is_test_mode: bool = False
|
|
21
|
+
):
|
|
22
|
+
|
|
23
|
+
# initialize payme network
|
|
24
|
+
url = Networks.PROD_NET
|
|
25
|
+
|
|
26
|
+
if is_test_mode is True:
|
|
27
|
+
url = Networks.TEST_NET
|
|
28
|
+
|
|
29
|
+
self.cards = Cards(url=url, payme_id=payme_id)
|
|
30
|
+
self.initializer = Initializer(payme_id=payme_id)
|
|
31
|
+
self.receipts = Receipts(url=url, payme_id=payme_id, payme_key=payme_key) # noqa
|
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
raise exception_class(message=error_message, data=error_data)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
|
|
3
|
+
from payme.util import input_type_checker
|
|
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
|
+
@input_type_checker
|
|
17
|
+
def __init__(self, payme_id: str = None):
|
|
18
|
+
self.payme_id = payme_id
|
|
19
|
+
|
|
20
|
+
# pylint: disable=W0622
|
|
21
|
+
@input_type_checker
|
|
22
|
+
def generate_pay_link(
|
|
23
|
+
self,
|
|
24
|
+
id: int,
|
|
25
|
+
amount: int,
|
|
26
|
+
return_url: str
|
|
27
|
+
) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Generate a payment link for a specific order.
|
|
30
|
+
|
|
31
|
+
This method encodes the payment parameters into a base64 string and
|
|
32
|
+
constructs a URL for the Payme checkout.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
id : int
|
|
37
|
+
Unique identifier for the account.
|
|
38
|
+
amount : int
|
|
39
|
+
The amount associated with the order in currency units.
|
|
40
|
+
return_url : str
|
|
41
|
+
The URL to which the user will be redirected after the payment is
|
|
42
|
+
processed.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
str
|
|
47
|
+
A payment link formatted as a URL, ready to be used in the payment
|
|
48
|
+
process.
|
|
49
|
+
|
|
50
|
+
References
|
|
51
|
+
----------
|
|
52
|
+
For full method documentation, visit:
|
|
53
|
+
https://developer.help.paycom.uz/initsializatsiya-platezhey/
|
|
54
|
+
"""
|
|
55
|
+
amount = amount * 100 # Convert amount to the smallest currency unit
|
|
56
|
+
params = (
|
|
57
|
+
f'm={self.payme_id};ac.id={id};a={amount};c={return_url}'
|
|
58
|
+
)
|
|
59
|
+
params = base64.b64encode(params.encode("utf-8")).decode("utf-8")
|
|
60
|
+
return f"https://checkout.paycom.uz/{params}"
|
|
61
|
+
|
|
62
|
+
def test(self):
|
|
63
|
+
"""
|
|
64
|
+
Test method for the Initializer class.
|
|
65
|
+
|
|
66
|
+
This method generates a payment link for a sample order and checks
|
|
67
|
+
if the result is a valid string. If successful, it prints a
|
|
68
|
+
confirmation message.
|
|
69
|
+
"""
|
|
70
|
+
result = self.generate_pay_link(
|
|
71
|
+
id=12345,
|
|
72
|
+
amount=7000,
|
|
73
|
+
return_url="https://example.com"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
assert isinstance(result, str), "Failed to generate payment link"
|
|
77
|
+
print("Success: Payment link generated successfully.")
|