paytechuz 0.2.21__py3-none-any.whl → 0.2.22__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 paytechuz might be problematic. Click here for more details.
- {paytechuz-0.2.21.dist-info → paytechuz-0.2.22.dist-info}/METADATA +6 -33
- {paytechuz-0.2.21.dist-info → paytechuz-0.2.22.dist-info}/RECORD +4 -35
- {paytechuz-0.2.21.dist-info → paytechuz-0.2.22.dist-info}/WHEEL +1 -1
- paytechuz-0.2.22.dist-info/top_level.txt +1 -0
- core/__init__.py +0 -0
- core/base.py +0 -97
- core/constants.py +0 -68
- core/exceptions.py +0 -190
- core/http.py +0 -268
- core/payme/errors.py +0 -25
- core/utils.py +0 -192
- gateways/__init__.py +0 -0
- gateways/click/__init__.py +0 -0
- gateways/click/client.py +0 -199
- gateways/click/merchant.py +0 -265
- gateways/click/webhook.py +0 -227
- gateways/payme/__init__.py +0 -0
- gateways/payme/cards.py +0 -222
- gateways/payme/client.py +0 -262
- gateways/payme/receipts.py +0 -336
- gateways/payme/webhook.py +0 -379
- integrations/__init__.py +0 -0
- integrations/django/__init__.py +0 -4
- integrations/django/admin.py +0 -78
- integrations/django/apps.py +0 -21
- integrations/django/migrations/0001_initial.py +0 -51
- integrations/django/migrations/__init__.py +0 -3
- integrations/django/models.py +0 -174
- integrations/django/signals.py +0 -46
- integrations/django/views.py +0 -102
- integrations/django/webhooks.py +0 -884
- integrations/fastapi/__init__.py +0 -21
- integrations/fastapi/models.py +0 -183
- integrations/fastapi/routes.py +0 -1038
- integrations/fastapi/schemas.py +0 -116
- paytechuz-0.2.21.dist-info/top_level.txt +0 -4
gateways/click/merchant.py
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Click merchant API operations.
|
|
3
|
-
"""
|
|
4
|
-
import hashlib
|
|
5
|
-
import logging
|
|
6
|
-
from typing import Dict, Any, Optional, Union
|
|
7
|
-
|
|
8
|
-
from paytechuz.core.http import HttpClient
|
|
9
|
-
from paytechuz.core.constants import ClickEndpoints
|
|
10
|
-
from paytechuz.core.utils import handle_exceptions, generate_timestamp
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ClickMerchantApi:
|
|
16
|
-
"""
|
|
17
|
-
Click merchant API operations.
|
|
18
|
-
|
|
19
|
-
This class provides methods for interacting with the Click merchant API,
|
|
20
|
-
including checking payment status and canceling payments.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
http_client: HttpClient,
|
|
26
|
-
service_id: str,
|
|
27
|
-
merchant_user_id: Optional[str] = None,
|
|
28
|
-
secret_key: Optional[str] = None
|
|
29
|
-
):
|
|
30
|
-
"""
|
|
31
|
-
Initialize the Click merchant API.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
http_client: HTTP client for making requests
|
|
35
|
-
service_id: Click service ID
|
|
36
|
-
merchant_user_id: Click merchant user ID
|
|
37
|
-
secret_key: Secret key for authentication
|
|
38
|
-
"""
|
|
39
|
-
self.http_client = http_client
|
|
40
|
-
self.service_id = service_id
|
|
41
|
-
self.merchant_user_id = merchant_user_id
|
|
42
|
-
self.secret_key = secret_key
|
|
43
|
-
|
|
44
|
-
def _generate_signature(self, data: Dict[str, Any]) -> str:
|
|
45
|
-
"""
|
|
46
|
-
Generate signature for Click API requests.
|
|
47
|
-
|
|
48
|
-
Args:
|
|
49
|
-
data: Request data
|
|
50
|
-
|
|
51
|
-
Returns:
|
|
52
|
-
Signature string
|
|
53
|
-
"""
|
|
54
|
-
if not self.secret_key:
|
|
55
|
-
return ""
|
|
56
|
-
|
|
57
|
-
# Sort keys alphabetically
|
|
58
|
-
sorted_data = {k: data[k] for k in sorted(data.keys())}
|
|
59
|
-
|
|
60
|
-
# Create string to sign
|
|
61
|
-
sign_string = ""
|
|
62
|
-
for key, value in sorted_data.items():
|
|
63
|
-
if key != "sign":
|
|
64
|
-
sign_string += str(value)
|
|
65
|
-
|
|
66
|
-
# Add secret key
|
|
67
|
-
sign_string += self.secret_key
|
|
68
|
-
|
|
69
|
-
# Generate signature
|
|
70
|
-
return hashlib.md5(sign_string.encode('utf-8')).hexdigest()
|
|
71
|
-
|
|
72
|
-
@handle_exceptions
|
|
73
|
-
def check_payment(self, id: Union[int, str]) -> Dict[str, Any]:
|
|
74
|
-
"""
|
|
75
|
-
Check payment status.
|
|
76
|
-
|
|
77
|
-
Args:
|
|
78
|
-
account_id: Account ID or order ID
|
|
79
|
-
|
|
80
|
-
Returns:
|
|
81
|
-
Dict containing payment status and details
|
|
82
|
-
"""
|
|
83
|
-
# Prepare request data
|
|
84
|
-
data = {
|
|
85
|
-
"service_id": self.service_id,
|
|
86
|
-
"merchant_transaction_id": str(id),
|
|
87
|
-
"request_id": str(generate_timestamp())
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# Add signature if secret key is provided
|
|
91
|
-
if self.secret_key:
|
|
92
|
-
data["sign"] = self._generate_signature(data)
|
|
93
|
-
|
|
94
|
-
# Make request
|
|
95
|
-
response = self.http_client.post(
|
|
96
|
-
endpoint=f"{ClickEndpoints.MERCHANT_API}/payment/status",
|
|
97
|
-
json_data=data
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
return response
|
|
101
|
-
|
|
102
|
-
@handle_exceptions
|
|
103
|
-
def cancel_payment(
|
|
104
|
-
self,
|
|
105
|
-
id: Union[int, str],
|
|
106
|
-
reason: Optional[str] = None
|
|
107
|
-
) -> Dict[str, Any]:
|
|
108
|
-
"""
|
|
109
|
-
Cancel payment.
|
|
110
|
-
|
|
111
|
-
Args:
|
|
112
|
-
id: Account ID or order ID
|
|
113
|
-
reason: Optional reason for cancellation
|
|
114
|
-
|
|
115
|
-
Returns:
|
|
116
|
-
Dict containing cancellation status and details
|
|
117
|
-
"""
|
|
118
|
-
# Prepare request data
|
|
119
|
-
data = {
|
|
120
|
-
"service_id": self.service_id,
|
|
121
|
-
"merchant_transaction_id": str(id),
|
|
122
|
-
"request_id": str(generate_timestamp())
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
# Add reason if provided
|
|
126
|
-
if reason:
|
|
127
|
-
data["reason"] = reason
|
|
128
|
-
|
|
129
|
-
# Add signature if secret key is provided
|
|
130
|
-
if self.secret_key:
|
|
131
|
-
data["sign"] = self._generate_signature(data)
|
|
132
|
-
|
|
133
|
-
# Make request
|
|
134
|
-
response = self.http_client.post(
|
|
135
|
-
endpoint=f"{ClickEndpoints.MERCHANT_API}/payment/cancel",
|
|
136
|
-
json_data=data
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
return response
|
|
140
|
-
|
|
141
|
-
@handle_exceptions
|
|
142
|
-
def create_invoice(
|
|
143
|
-
self,
|
|
144
|
-
id: Union[int, str],
|
|
145
|
-
amount: Union[int, float],
|
|
146
|
-
**kwargs
|
|
147
|
-
) -> Dict[str, Any]:
|
|
148
|
-
"""
|
|
149
|
-
Create an invoice.
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
amount: Payment amount
|
|
153
|
-
id: Account ID or order ID
|
|
154
|
-
**kwargs: Additional parameters
|
|
155
|
-
- description: Payment description
|
|
156
|
-
- phone: Customer phone number
|
|
157
|
-
- email: Customer email
|
|
158
|
-
- expire_time: Invoice expiration time in minutes
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
Dict containing invoice details
|
|
162
|
-
"""
|
|
163
|
-
# Extract additional parameters
|
|
164
|
-
description = kwargs.get('description', f'Payment for account {id}')
|
|
165
|
-
phone = kwargs.get('phone')
|
|
166
|
-
email = kwargs.get('email')
|
|
167
|
-
expire_time = kwargs.get('expire_time', 60) # Default 1 hour
|
|
168
|
-
|
|
169
|
-
# Prepare request data
|
|
170
|
-
data = {
|
|
171
|
-
"service_id": self.service_id,
|
|
172
|
-
"amount": float(amount),
|
|
173
|
-
"merchant_transaction_id": str(id),
|
|
174
|
-
"description": description,
|
|
175
|
-
"request_id": str(generate_timestamp()),
|
|
176
|
-
"expire_time": expire_time
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
# Add optional parameters
|
|
180
|
-
if phone:
|
|
181
|
-
data["phone"] = phone
|
|
182
|
-
|
|
183
|
-
if email:
|
|
184
|
-
data["email"] = email
|
|
185
|
-
|
|
186
|
-
# Add signature if secret key is provided
|
|
187
|
-
if self.secret_key:
|
|
188
|
-
data["sign"] = self._generate_signature(data)
|
|
189
|
-
|
|
190
|
-
# Make request
|
|
191
|
-
response = self.http_client.post(
|
|
192
|
-
endpoint=f"{ClickEndpoints.MERCHANT_API}/invoice/create",
|
|
193
|
-
json_data=data
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
return response
|
|
197
|
-
|
|
198
|
-
@handle_exceptions
|
|
199
|
-
def check_invoice(self, invoice_id: str) -> Dict[str, Any]:
|
|
200
|
-
"""
|
|
201
|
-
Check invoice status.
|
|
202
|
-
|
|
203
|
-
Args:
|
|
204
|
-
invoice_id: Invoice ID
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
Dict containing invoice status and details
|
|
208
|
-
"""
|
|
209
|
-
# Prepare request data
|
|
210
|
-
data = {
|
|
211
|
-
"service_id": self.service_id,
|
|
212
|
-
"invoice_id": invoice_id,
|
|
213
|
-
"request_id": str(generate_timestamp())
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
# Add signature if secret key is provided
|
|
217
|
-
if self.secret_key:
|
|
218
|
-
data["sign"] = self._generate_signature(data)
|
|
219
|
-
|
|
220
|
-
# Make request
|
|
221
|
-
response = self.http_client.post(
|
|
222
|
-
endpoint=f"{ClickEndpoints.MERCHANT_API}/invoice/status",
|
|
223
|
-
json_data=data
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
return response
|
|
227
|
-
|
|
228
|
-
@handle_exceptions
|
|
229
|
-
def cancel_invoice(
|
|
230
|
-
self,
|
|
231
|
-
invoice_id: str,
|
|
232
|
-
reason: Optional[str] = None
|
|
233
|
-
) -> Dict[str, Any]:
|
|
234
|
-
"""
|
|
235
|
-
Cancel invoice.
|
|
236
|
-
|
|
237
|
-
Args:
|
|
238
|
-
invoice_id: Invoice ID
|
|
239
|
-
reason: Optional reason for cancellation
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Dict containing cancellation status and details
|
|
243
|
-
"""
|
|
244
|
-
# Prepare request data
|
|
245
|
-
data = {
|
|
246
|
-
"service_id": self.service_id,
|
|
247
|
-
"invoice_id": invoice_id,
|
|
248
|
-
"request_id": str(generate_timestamp())
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
# Add reason if provided
|
|
252
|
-
if reason:
|
|
253
|
-
data["reason"] = reason
|
|
254
|
-
|
|
255
|
-
# Add signature if secret key is provided
|
|
256
|
-
if self.secret_key:
|
|
257
|
-
data["sign"] = self._generate_signature(data)
|
|
258
|
-
|
|
259
|
-
# Make request
|
|
260
|
-
response = self.http_client.post(
|
|
261
|
-
endpoint=f"{ClickEndpoints.MERCHANT_API}/invoice/cancel",
|
|
262
|
-
json_data=data
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
return response
|
gateways/click/webhook.py
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Click webhook handler.
|
|
3
|
-
"""
|
|
4
|
-
import hashlib
|
|
5
|
-
import logging
|
|
6
|
-
from typing import Dict, Any, Callable
|
|
7
|
-
|
|
8
|
-
from paytechuz.core.base import BaseWebhookHandler
|
|
9
|
-
from paytechuz.core.constants import ClickActions
|
|
10
|
-
from paytechuz.core.exceptions import (
|
|
11
|
-
PermissionDenied,
|
|
12
|
-
InvalidAmount,
|
|
13
|
-
TransactionNotFound,
|
|
14
|
-
UnsupportedMethod,
|
|
15
|
-
AccountNotFound
|
|
16
|
-
)
|
|
17
|
-
from paytechuz.core.utils import handle_exceptions
|
|
18
|
-
|
|
19
|
-
logger = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
|
-
class ClickWebhookHandler(BaseWebhookHandler):
|
|
22
|
-
"""
|
|
23
|
-
Click webhook handler.
|
|
24
|
-
|
|
25
|
-
This class handles webhook requests from the Click payment system,
|
|
26
|
-
including transaction preparation and completion.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
service_id: str,
|
|
32
|
-
secret_key: str,
|
|
33
|
-
find_transaction_func: Callable[[str], Dict[str, Any]],
|
|
34
|
-
find_account_func: Callable[[str], Dict[str, Any]],
|
|
35
|
-
create_transaction_func: Callable[[Dict[str, Any]], Dict[str, Any]],
|
|
36
|
-
complete_transaction_func: Callable[[str, bool], Dict[str, Any]],
|
|
37
|
-
commission_percent: float = 0.0
|
|
38
|
-
):
|
|
39
|
-
"""
|
|
40
|
-
Initialize the Click webhook handler.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
service_id: Click service ID
|
|
44
|
-
secret_key: Secret key for authentication
|
|
45
|
-
find_transaction_func: Function to find a transaction by ID
|
|
46
|
-
find_account_func: Function to find an account by ID
|
|
47
|
-
create_transaction_func: Function to create a transaction
|
|
48
|
-
complete_transaction_func: Function to complete a transaction
|
|
49
|
-
commission_percent: Commission percentage
|
|
50
|
-
"""
|
|
51
|
-
self.service_id = service_id
|
|
52
|
-
self.secret_key = secret_key
|
|
53
|
-
self.find_transaction = find_transaction_func
|
|
54
|
-
self.find_account = find_account_func
|
|
55
|
-
self.create_transaction = create_transaction_func
|
|
56
|
-
self.complete_transaction = complete_transaction_func
|
|
57
|
-
self.commission_percent = commission_percent
|
|
58
|
-
|
|
59
|
-
def _check_auth(self, params: Dict[str, Any]) -> None:
|
|
60
|
-
"""
|
|
61
|
-
Check authentication using signature.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
params: Request parameters
|
|
65
|
-
|
|
66
|
-
Raises:
|
|
67
|
-
PermissionDenied: If authentication fails
|
|
68
|
-
"""
|
|
69
|
-
if str(params.get('service_id')) != self.service_id:
|
|
70
|
-
raise PermissionDenied("Invalid service ID")
|
|
71
|
-
|
|
72
|
-
# Check signature if secret key is provided
|
|
73
|
-
if self.secret_key:
|
|
74
|
-
sign_string = params.get('sign_string')
|
|
75
|
-
sign_time = params.get('sign_time')
|
|
76
|
-
|
|
77
|
-
if not sign_string or not sign_time:
|
|
78
|
-
raise PermissionDenied("Missing signature parameters")
|
|
79
|
-
|
|
80
|
-
# Create string to sign
|
|
81
|
-
to_sign = f"{params.get('click_trans_id')}{params.get('service_id')}"
|
|
82
|
-
to_sign += f"{self.secret_key}{params.get('merchant_trans_id')}"
|
|
83
|
-
to_sign += f"{params.get('amount')}{params.get('action')}"
|
|
84
|
-
to_sign += f"{sign_time}"
|
|
85
|
-
|
|
86
|
-
# Generate signature
|
|
87
|
-
signature = hashlib.md5(to_sign.encode('utf-8')).hexdigest()
|
|
88
|
-
|
|
89
|
-
if signature != sign_string:
|
|
90
|
-
raise PermissionDenied("Invalid signature")
|
|
91
|
-
|
|
92
|
-
def _validate_amount(
|
|
93
|
-
self,
|
|
94
|
-
received_amount: float,
|
|
95
|
-
expected_amount: float
|
|
96
|
-
) -> None:
|
|
97
|
-
"""
|
|
98
|
-
Validate payment amount.
|
|
99
|
-
|
|
100
|
-
Args:
|
|
101
|
-
received_amount: Amount received from Click
|
|
102
|
-
expected_amount: Expected amount
|
|
103
|
-
|
|
104
|
-
Raises:
|
|
105
|
-
InvalidAmount: If amounts don't match
|
|
106
|
-
"""
|
|
107
|
-
# Add commission if needed
|
|
108
|
-
if self.commission_percent > 0:
|
|
109
|
-
expected_amount = expected_amount * (1 + self.commission_percent / 100)
|
|
110
|
-
expected_amount = round(expected_amount, 2)
|
|
111
|
-
|
|
112
|
-
# Allow small difference due to floating point precision
|
|
113
|
-
if abs(received_amount - expected_amount) > 0.01:
|
|
114
|
-
raise InvalidAmount(f"Incorrect amount. Expected: {expected_amount}, received: {received_amount}")
|
|
115
|
-
|
|
116
|
-
@handle_exceptions
|
|
117
|
-
def handle_webhook(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
118
|
-
"""
|
|
119
|
-
Handle webhook data from Click.
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
data: The webhook data received from Click
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
Dict containing the response to be sent back to Click
|
|
126
|
-
|
|
127
|
-
Raises:
|
|
128
|
-
PermissionDenied: If authentication fails
|
|
129
|
-
UnsupportedMethod: If the requested action is not supported
|
|
130
|
-
"""
|
|
131
|
-
# Check authentication
|
|
132
|
-
self._check_auth(data)
|
|
133
|
-
|
|
134
|
-
# Extract parameters
|
|
135
|
-
click_trans_id = data.get('click_trans_id')
|
|
136
|
-
merchant_trans_id = data.get('merchant_trans_id')
|
|
137
|
-
amount = float(data.get('amount', 0))
|
|
138
|
-
action = int(data.get('action', -1))
|
|
139
|
-
error = int(data.get('error', 0))
|
|
140
|
-
|
|
141
|
-
# Find account
|
|
142
|
-
try:
|
|
143
|
-
account = self.find_account(merchant_trans_id)
|
|
144
|
-
except AccountNotFound:
|
|
145
|
-
logger.error(f"Account not found: {merchant_trans_id}")
|
|
146
|
-
return {
|
|
147
|
-
'click_trans_id': click_trans_id,
|
|
148
|
-
'merchant_trans_id': merchant_trans_id,
|
|
149
|
-
'error': -5,
|
|
150
|
-
'error_note': "User not found"
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
# Validate amount
|
|
154
|
-
try:
|
|
155
|
-
self._validate_amount(amount, float(account.get('amount', 0)))
|
|
156
|
-
except InvalidAmount as e:
|
|
157
|
-
logger.error(f"Invalid amount: {e}")
|
|
158
|
-
return {
|
|
159
|
-
'click_trans_id': click_trans_id,
|
|
160
|
-
'merchant_trans_id': merchant_trans_id,
|
|
161
|
-
'error': -2,
|
|
162
|
-
'error_note': str(e)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
# Check if transaction already exists
|
|
166
|
-
try:
|
|
167
|
-
transaction = self.find_transaction(click_trans_id)
|
|
168
|
-
|
|
169
|
-
# If transaction is already completed, return success
|
|
170
|
-
if transaction.get('state') == 2: # SUCCESSFULLY
|
|
171
|
-
return {
|
|
172
|
-
'click_trans_id': click_trans_id,
|
|
173
|
-
'merchant_trans_id': merchant_trans_id,
|
|
174
|
-
'merchant_prepare_id': transaction.get('id'),
|
|
175
|
-
'error': 0,
|
|
176
|
-
'error_note': "Success"
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
# If transaction is cancelled, return error
|
|
180
|
-
if transaction.get('state') == -2: # CANCELLED
|
|
181
|
-
return {
|
|
182
|
-
'click_trans_id': click_trans_id,
|
|
183
|
-
'merchant_trans_id': merchant_trans_id,
|
|
184
|
-
'merchant_prepare_id': transaction.get('id'),
|
|
185
|
-
'error': -9,
|
|
186
|
-
'error_note': "Transaction cancelled"
|
|
187
|
-
}
|
|
188
|
-
except TransactionNotFound:
|
|
189
|
-
# Transaction doesn't exist, continue with the flow
|
|
190
|
-
pass
|
|
191
|
-
|
|
192
|
-
# Handle different actions
|
|
193
|
-
if action == ClickActions.PREPARE:
|
|
194
|
-
# Create transaction
|
|
195
|
-
transaction = self.create_transaction({
|
|
196
|
-
'click_trans_id': click_trans_id,
|
|
197
|
-
'merchant_trans_id': merchant_trans_id,
|
|
198
|
-
'amount': amount,
|
|
199
|
-
'account': account
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
'click_trans_id': click_trans_id,
|
|
204
|
-
'merchant_trans_id': merchant_trans_id,
|
|
205
|
-
'merchant_prepare_id': transaction.get('id'),
|
|
206
|
-
'error': 0,
|
|
207
|
-
'error_note': "Success"
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
elif action == ClickActions.COMPLETE:
|
|
211
|
-
# Check if error is negative (payment failed)
|
|
212
|
-
is_successful = error >= 0
|
|
213
|
-
|
|
214
|
-
# Complete transaction
|
|
215
|
-
transaction = self.complete_transaction(click_trans_id, is_successful)
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
'click_trans_id': click_trans_id,
|
|
219
|
-
'merchant_trans_id': merchant_trans_id,
|
|
220
|
-
'merchant_prepare_id': transaction.get('id'),
|
|
221
|
-
'error': 0,
|
|
222
|
-
'error_note': "Success"
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
else:
|
|
226
|
-
logger.error(f"Unsupported action: {action}")
|
|
227
|
-
raise UnsupportedMethod(f"Unsupported action: {action}")
|
gateways/payme/__init__.py
DELETED
|
File without changes
|
gateways/payme/cards.py
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Payme cards operations.
|
|
3
|
-
"""
|
|
4
|
-
import logging
|
|
5
|
-
from typing import Dict, Any
|
|
6
|
-
|
|
7
|
-
from paytechuz.core.http import HttpClient
|
|
8
|
-
from paytechuz.core.constants import PaymeEndpoints
|
|
9
|
-
from paytechuz.core.utils import handle_exceptions
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
class PaymeCards:
|
|
14
|
-
"""
|
|
15
|
-
Payme cards operations.
|
|
16
|
-
|
|
17
|
-
This class provides methods for working with cards in the Payme payment system,
|
|
18
|
-
including creating cards, verifying cards, and removing cards.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
def __init__(self, http_client: HttpClient, payme_id: str):
|
|
22
|
-
"""
|
|
23
|
-
Initialize the Payme cards component.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
http_client: HTTP client for making requests
|
|
27
|
-
payme_id: Payme merchant ID
|
|
28
|
-
"""
|
|
29
|
-
self.http_client = http_client
|
|
30
|
-
self.payme_id = payme_id
|
|
31
|
-
|
|
32
|
-
@handle_exceptions
|
|
33
|
-
def create(
|
|
34
|
-
self,
|
|
35
|
-
card_number: str,
|
|
36
|
-
expire_date: str,
|
|
37
|
-
save: bool = True,
|
|
38
|
-
**kwargs
|
|
39
|
-
) -> Dict[str, Any]:
|
|
40
|
-
"""
|
|
41
|
-
Create a new card.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
card_number: Card number
|
|
45
|
-
expire_date: Card expiration date in format "MM/YY"
|
|
46
|
-
save: Whether to save the card for future use
|
|
47
|
-
**kwargs: Additional parameters
|
|
48
|
-
- phone: Customer phone number
|
|
49
|
-
- language: Language code (uz, ru, en)
|
|
50
|
-
|
|
51
|
-
Returns:
|
|
52
|
-
Dict containing card creation response
|
|
53
|
-
"""
|
|
54
|
-
# Extract additional parameters
|
|
55
|
-
phone = kwargs.get('phone')
|
|
56
|
-
language = kwargs.get('language', 'uz')
|
|
57
|
-
|
|
58
|
-
# Prepare request data
|
|
59
|
-
data = {
|
|
60
|
-
"method": PaymeEndpoints.CARDS_CREATE,
|
|
61
|
-
"params": {
|
|
62
|
-
"card": {
|
|
63
|
-
"number": card_number,
|
|
64
|
-
"expire": expire_date
|
|
65
|
-
},
|
|
66
|
-
"save": save,
|
|
67
|
-
"merchant_id": self.payme_id
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
# Add optional parameters
|
|
72
|
-
if phone:
|
|
73
|
-
data["params"]["phone"] = phone
|
|
74
|
-
|
|
75
|
-
# Add language header
|
|
76
|
-
headers = {"Accept-Language": language}
|
|
77
|
-
|
|
78
|
-
# Make request
|
|
79
|
-
response = self.http_client.post(
|
|
80
|
-
endpoint="",
|
|
81
|
-
json_data=data,
|
|
82
|
-
headers=headers
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
return response
|
|
86
|
-
|
|
87
|
-
@handle_exceptions
|
|
88
|
-
def verify(
|
|
89
|
-
self,
|
|
90
|
-
token: str,
|
|
91
|
-
code: str,
|
|
92
|
-
**kwargs
|
|
93
|
-
) -> Dict[str, Any]:
|
|
94
|
-
"""
|
|
95
|
-
Verify a card with the verification code.
|
|
96
|
-
|
|
97
|
-
Args:
|
|
98
|
-
token: Card token received from create method
|
|
99
|
-
code: Verification code sent to the card owner
|
|
100
|
-
**kwargs: Additional parameters
|
|
101
|
-
- language: Language code (uz, ru, en)
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
Dict containing card verification response
|
|
105
|
-
"""
|
|
106
|
-
# Extract additional parameters
|
|
107
|
-
language = kwargs.get('language', 'uz')
|
|
108
|
-
|
|
109
|
-
# Prepare request data
|
|
110
|
-
data = {
|
|
111
|
-
"method": PaymeEndpoints.CARDS_VERIFY,
|
|
112
|
-
"params": {
|
|
113
|
-
"token": token,
|
|
114
|
-
"code": code
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Add language header
|
|
119
|
-
headers = {"Accept-Language": language}
|
|
120
|
-
|
|
121
|
-
# Make request
|
|
122
|
-
response = self.http_client.post(
|
|
123
|
-
endpoint="",
|
|
124
|
-
json_data=data,
|
|
125
|
-
headers=headers
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
return response
|
|
129
|
-
|
|
130
|
-
@handle_exceptions
|
|
131
|
-
def check(self, token: str) -> Dict[str, Any]:
|
|
132
|
-
"""
|
|
133
|
-
Check if a card exists and is active.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
token: Card token
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
Dict containing card check response
|
|
140
|
-
"""
|
|
141
|
-
# Prepare request data
|
|
142
|
-
data = {
|
|
143
|
-
"method": PaymeEndpoints.CARDS_CHECK,
|
|
144
|
-
"params": {
|
|
145
|
-
"token": token
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
# Make request
|
|
150
|
-
response = self.http_client.post(
|
|
151
|
-
endpoint="",
|
|
152
|
-
json_data=data
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
return response
|
|
156
|
-
|
|
157
|
-
@handle_exceptions
|
|
158
|
-
def remove(self, token: str) -> Dict[str, Any]:
|
|
159
|
-
"""
|
|
160
|
-
Remove a card.
|
|
161
|
-
|
|
162
|
-
Args:
|
|
163
|
-
token: Card token
|
|
164
|
-
|
|
165
|
-
Returns:
|
|
166
|
-
Dict containing card removal response
|
|
167
|
-
"""
|
|
168
|
-
# Prepare request data
|
|
169
|
-
data = {
|
|
170
|
-
"method": PaymeEndpoints.CARDS_REMOVE,
|
|
171
|
-
"params": {
|
|
172
|
-
"token": token
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
# Make request
|
|
177
|
-
response = self.http_client.post(
|
|
178
|
-
endpoint="",
|
|
179
|
-
json_data=data
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
return response
|
|
183
|
-
|
|
184
|
-
@handle_exceptions
|
|
185
|
-
def get_verify_code(
|
|
186
|
-
self,
|
|
187
|
-
token: str,
|
|
188
|
-
**kwargs
|
|
189
|
-
) -> Dict[str, Any]:
|
|
190
|
-
"""
|
|
191
|
-
Get a new verification code for a card.
|
|
192
|
-
|
|
193
|
-
Args:
|
|
194
|
-
token: Card token
|
|
195
|
-
**kwargs: Additional parameters
|
|
196
|
-
- language: Language code (uz, ru, en)
|
|
197
|
-
|
|
198
|
-
Returns:
|
|
199
|
-
Dict containing verification code response
|
|
200
|
-
"""
|
|
201
|
-
# Extract additional parameters
|
|
202
|
-
language = kwargs.get('language', 'uz')
|
|
203
|
-
|
|
204
|
-
# Prepare request data
|
|
205
|
-
data = {
|
|
206
|
-
"method": PaymeEndpoints.CARDS_GET_VERIFY_CODE,
|
|
207
|
-
"params": {
|
|
208
|
-
"token": token
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
# Add language header
|
|
213
|
-
headers = {"Accept-Language": language}
|
|
214
|
-
|
|
215
|
-
# Make request
|
|
216
|
-
response = self.http_client.post(
|
|
217
|
-
endpoint="",
|
|
218
|
-
json_data=data,
|
|
219
|
-
headers=headers
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
return response
|