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.

gateways/payme/client.py DELETED
@@ -1,262 +0,0 @@
1
- """
2
- Payme payment gateway client.
3
- """
4
- import logging
5
- from typing import Dict, Any, Optional, Union
6
- import base64
7
-
8
- from paytechuz.core.base import BasePaymentGateway
9
- from paytechuz.core.http import HttpClient
10
- from paytechuz.core.constants import PaymeNetworks
11
- from paytechuz.core.utils import format_amount, handle_exceptions
12
- from paytechuz.gateways.payme.cards import PaymeCards
13
- from paytechuz.gateways.payme.receipts import PaymeReceipts
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class PaymeGateway(BasePaymentGateway):
19
- """
20
- Payme payment gateway implementation.
21
-
22
- This class provides methods for interacting with the Payme payment gateway,
23
- including creating payments, checking payment status, and canceling payments.
24
- """
25
-
26
- def __init__(
27
- self,
28
- payme_id: str,
29
- payme_key: Optional[str] = None,
30
- fallback_id: Optional[str] = None,
31
- is_test_mode: bool = False
32
- ):
33
- """
34
- Initialize the Payme gateway.
35
-
36
- Args:
37
- payme_id: Payme merchant ID
38
- payme_key: Payme merchant key for authentication
39
- fallback_id: Fallback merchant ID
40
- is_test_mode: Whether to use the test environment
41
- """
42
- super().__init__(is_test_mode)
43
- self.payme_id = payme_id
44
- self.payme_key = payme_key
45
- self.fallback_id = fallback_id
46
-
47
- # Set the API URL based on the environment
48
- url = PaymeNetworks.TEST_NET if is_test_mode else PaymeNetworks.PROD_NET
49
-
50
- # Initialize HTTP client
51
- self.http_client = HttpClient(base_url=url)
52
-
53
- # Initialize components
54
- self.cards = PaymeCards(http_client=self.http_client, payme_id=payme_id)
55
- self.receipts = PaymeReceipts(
56
- http_client=self.http_client,
57
- payme_id=payme_id,
58
- payme_key=payme_key
59
- )
60
-
61
- def generate_pay_link(
62
- self,
63
- id: Union[int, str],
64
- amount: Union[int, float, str],
65
- return_url: str,
66
- account_field_name: str = "order_id"
67
- ) -> str:
68
- """
69
- Generate a payment link for a specific order.
70
-
71
- Parameters
72
- ----------
73
- id : Union[int, str]
74
- Unique identifier for the account/order.
75
- amount : Union[int, float, str]
76
- Payment amount in som.
77
- return_url : str
78
- URL to redirect after payment completion.
79
- account_field_name : str, optional
80
- Field name for account identifier (default: "order_id").
81
-
82
- Returns
83
- -------
84
- str
85
- Payme checkout URL with encoded parameters.
86
-
87
- References
88
- ----------
89
- https://developer.help.paycom.uz/initsializatsiya-platezhey/
90
- """
91
- # Convert amount to tiyin (1 som = 100 tiyin)
92
- amount_tiyin = int(float(amount) * 100)
93
-
94
- # Build parameters
95
- params = (
96
- f'm={self.payme_id};'
97
- f'ac.{account_field_name}={id};'
98
- f'a={amount_tiyin};'
99
- f'c={return_url}'
100
- )
101
- encoded_params = base64.b64encode(params.encode("utf-8")).decode("utf-8")
102
-
103
- # Return URL based on environment
104
- base_url = "https://test.paycom.uz" if self.is_test_mode else "https://checkout.paycom.uz"
105
- return f"{base_url}/{encoded_params}"
106
-
107
- async def generate_pay_link_async(
108
- self,
109
- id: Union[int, str],
110
- amount: Union[int, float, str],
111
- return_url: str,
112
- account_field_name: str = "order_id"
113
- ) -> str:
114
- """
115
- Async version of generate_pay_link.
116
-
117
- Parameters
118
- ----------
119
- id : Union[int, str]
120
- Unique identifier for the account/order.
121
- amount : Union[int, float, str]
122
- Payment amount in som.
123
- return_url : str
124
- URL to redirect after payment completion.
125
- account_field_name : str, optional
126
- Field name for account identifier (default: "order_id").
127
-
128
- Returns
129
- -------
130
- str
131
- Payme checkout URL with encoded parameters.
132
- """
133
- return self.generate_pay_link(
134
- id=id,
135
- amount=amount,
136
- return_url=return_url,
137
- account_field_name=account_field_name
138
- )
139
-
140
- @handle_exceptions
141
- def create_payment(
142
- self,
143
- id: Union[int, str],
144
- amount: Union[int, float, str],
145
- return_url: str = "",
146
- account_field_name: str = "order_id"
147
- ) -> str:
148
- """
149
- Create a payment using Payme.
150
-
151
- Args:
152
- id: Account or order ID
153
- amount: Payment amount in som
154
- return_url: Return URL after payment (default: "")
155
- account_field_name: Field name for account ID (default: "order_id")
156
-
157
- Returns:
158
- str: Payme payment URL
159
- """
160
- return self.generate_pay_link(
161
- id=id,
162
- amount=amount,
163
- return_url=return_url,
164
- account_field_name=account_field_name
165
- )
166
-
167
- @handle_exceptions
168
- async def create_payment_async(
169
- self,
170
- id: Union[int, str],
171
- amount: Union[int, float, str],
172
- return_url: str = "",
173
- account_field_name: str = "order_id"
174
- ) -> str:
175
- """
176
- Async version of create_payment.
177
-
178
- Args:
179
- id: Account or order ID
180
- amount: Payment amount in som
181
- return_url: Return URL after payment (default: "")
182
- account_field_name: Field name for account ID (default: "order_id")
183
-
184
- Returns:
185
- str: Payme payment URL
186
- """
187
- return await self.generate_pay_link_async(
188
- id=id,
189
- amount=amount,
190
- return_url=return_url,
191
- account_field_name=account_field_name
192
- )
193
-
194
- @handle_exceptions
195
- def check_payment(self, transaction_id: str) -> Dict[str, Any]:
196
- """
197
- Check payment status using Payme receipts.
198
-
199
- Args:
200
- transaction_id: The receipt ID to check
201
-
202
- Returns:
203
- Dict containing payment status and details
204
- """
205
- receipt_data = self.receipts.check(receipt_id=transaction_id)
206
-
207
- # Extract receipt status
208
- receipt = receipt_data.get('receipt', {})
209
- status = receipt.get('state')
210
-
211
- # Map Payme status to our status
212
- status_mapping = {
213
- 0: 'created',
214
- 1: 'waiting',
215
- 2: 'paid',
216
- 3: 'cancelled',
217
- 4: 'refunded'
218
- }
219
-
220
- mapped_status = status_mapping.get(status, 'unknown')
221
-
222
- return {
223
- 'transaction_id': transaction_id,
224
- 'status': mapped_status,
225
- 'amount': receipt.get('amount') / 100, # Convert from tiyin to som
226
- 'paid_at': receipt.get('pay_time'),
227
- 'created_at': receipt.get('create_time'),
228
- 'cancelled_at': receipt.get('cancel_time'),
229
- 'raw_response': receipt_data
230
- }
231
-
232
- @handle_exceptions
233
- def cancel_payment(
234
- self,
235
- transaction_id: str,
236
- reason: Optional[str] = None
237
- ) -> Dict[str, Any]:
238
- """
239
- Cancel payment using Payme receipts.
240
-
241
- Args:
242
- transaction_id: The receipt ID to cancel
243
- reason: Optional reason for cancellation
244
-
245
- Returns:
246
- Dict containing cancellation status and details
247
- """
248
- receipt_data = self.receipts.cancel(
249
- receipt_id=transaction_id,
250
- reason=reason or "Cancelled by merchant"
251
- )
252
-
253
- # Extract receipt status
254
- receipt = receipt_data.get('receipt', {})
255
- status = receipt.get('state')
256
-
257
- return {
258
- 'transaction_id': transaction_id,
259
- 'status': 'cancelled' if status == 3 else 'unknown',
260
- 'cancelled_at': receipt.get('cancel_time'),
261
- 'raw_response': receipt_data
262
- }
@@ -1,336 +0,0 @@
1
- """
2
- Payme receipts operations.
3
- """
4
- # base64 is used indirectly through generate_basic_auth
5
- import logging
6
- from typing import Dict, Any, Optional
7
-
8
- from paytechuz.core.http import HttpClient
9
- from paytechuz.core.constants import PaymeEndpoints
10
- from paytechuz.core.utils import handle_exceptions, generate_basic_auth
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- class PaymeReceipts:
15
- """
16
- Payme receipts operations.
17
-
18
- This class provides methods for working with receipts in the Payme payment system,
19
- including creating receipts, paying receipts, and checking receipt status.
20
- """
21
-
22
- def __init__(
23
- self,
24
- http_client: HttpClient,
25
- payme_id: str,
26
- payme_key: Optional[str] = None
27
- ):
28
- """
29
- Initialize the Payme receipts component.
30
-
31
- Args:
32
- http_client: HTTP client for making requests
33
- payme_id: Payme merchant ID
34
- payme_key: Payme merchant key for authentication
35
- """
36
- self.http_client = http_client
37
- self.payme_id = payme_id
38
- self.payme_key = payme_key
39
-
40
- def _get_auth_headers(self, language: str = 'uz') -> Dict[str, str]:
41
- """
42
- Get authentication headers for Payme API.
43
-
44
- Args:
45
- language: Language code (uz, ru, en)
46
-
47
- Returns:
48
- Dict containing authentication headers
49
- """
50
- headers = {"Accept-Language": language}
51
-
52
- if self.payme_key:
53
- auth = generate_basic_auth(self.payme_id, self.payme_key)
54
- headers["Authorization"] = auth
55
-
56
- return headers
57
-
58
- @handle_exceptions
59
- def create(
60
- self,
61
- amount: int,
62
- account: Dict[str, Any],
63
- **kwargs
64
- ) -> Dict[str, Any]:
65
- """
66
- Create a new receipt.
67
-
68
- Args:
69
- amount: Payment amount in tiyin (1 som = 100 tiyin)
70
- account: Account information (e.g., {"account_id": "12345"})
71
- **kwargs: Additional parameters
72
- - description: Payment description
73
- - detail: Payment details
74
- - callback_url: URL to redirect after payment
75
- - return_url: URL to return after payment
76
- - phone: Customer phone number
77
- - email: Customer email
78
- - language: Language code (uz, ru, en)
79
- - expire_minutes: Payment expiration time in minutes
80
-
81
- Returns:
82
- Dict containing receipt creation response
83
- """
84
- # Extract additional parameters
85
- description = kwargs.get('description', 'Payment')
86
- detail = kwargs.get('detail', {})
87
- callback_url = kwargs.get('callback_url')
88
- return_url = kwargs.get('return_url')
89
- phone = kwargs.get('phone')
90
- email = kwargs.get('email')
91
- language = kwargs.get('language', 'uz')
92
- expire_minutes = kwargs.get('expire_minutes', 60) # Default 1 hour
93
-
94
- # Prepare request data
95
- data = {
96
- "method": PaymeEndpoints.RECEIPTS_CREATE,
97
- "params": {
98
- "amount": amount,
99
- "account": account,
100
- "description": description,
101
- "detail": detail,
102
- "merchant_id": self.payme_id
103
- }
104
- }
105
-
106
- # Add optional parameters
107
- if callback_url:
108
- data["params"]["callback_url"] = callback_url
109
-
110
- if return_url:
111
- data["params"]["return_url"] = return_url
112
-
113
- if phone:
114
- data["params"]["phone"] = phone
115
-
116
- if email:
117
- data["params"]["email"] = email
118
-
119
- if expire_minutes:
120
- data["params"]["expire_minutes"] = expire_minutes
121
-
122
- # Get authentication headers
123
- headers = self._get_auth_headers(language)
124
-
125
- # Make request
126
- response = self.http_client.post(
127
- endpoint="",
128
- json_data=data,
129
- headers=headers
130
- )
131
-
132
- return response
133
-
134
- @handle_exceptions
135
- def pay(
136
- self,
137
- receipt_id: str,
138
- token: str,
139
- **kwargs
140
- ) -> Dict[str, Any]:
141
- """
142
- Pay a receipt with a card token.
143
-
144
- Args:
145
- receipt_id: Receipt ID
146
- token: Card token
147
- **kwargs: Additional parameters
148
- - language: Language code (uz, ru, en)
149
-
150
- Returns:
151
- Dict containing receipt payment response
152
- """
153
- # Extract additional parameters
154
- language = kwargs.get('language', 'uz')
155
-
156
- # Prepare request data
157
- data = {
158
- "method": PaymeEndpoints.RECEIPTS_PAY,
159
- "params": {
160
- "id": receipt_id,
161
- "token": token
162
- }
163
- }
164
-
165
- # Get authentication headers
166
- headers = self._get_auth_headers(language)
167
-
168
- # Make request
169
- response = self.http_client.post(
170
- endpoint="",
171
- json_data=data,
172
- headers=headers
173
- )
174
-
175
- return response
176
-
177
- @handle_exceptions
178
- def send(
179
- self,
180
- receipt_id: str,
181
- phone: str,
182
- **kwargs
183
- ) -> Dict[str, Any]:
184
- """
185
- Send a receipt to a phone number.
186
-
187
- Args:
188
- receipt_id: Receipt ID
189
- phone: Phone number
190
- **kwargs: Additional parameters
191
- - language: Language code (uz, ru, en)
192
-
193
- Returns:
194
- Dict containing receipt sending response
195
- """
196
- # Extract additional parameters
197
- language = kwargs.get('language', 'uz')
198
-
199
- # Prepare request data
200
- data = {
201
- "method": PaymeEndpoints.RECEIPTS_SEND,
202
- "params": {
203
- "id": receipt_id,
204
- "phone": phone
205
- }
206
- }
207
-
208
- # Get authentication headers
209
- headers = self._get_auth_headers(language)
210
-
211
- # Make request
212
- response = self.http_client.post(
213
- endpoint="",
214
- json_data=data,
215
- headers=headers
216
- )
217
-
218
- return response
219
-
220
- @handle_exceptions
221
- def check(self, receipt_id: str, **kwargs) -> Dict[str, Any]:
222
- """
223
- Check receipt status.
224
-
225
- Args:
226
- receipt_id: Receipt ID
227
- **kwargs: Additional parameters
228
- - language: Language code (uz, ru, en)
229
-
230
- Returns:
231
- Dict containing receipt status response
232
- """
233
- # Extract additional parameters
234
- language = kwargs.get('language', 'uz')
235
-
236
- # Prepare request data
237
- data = {
238
- "method": PaymeEndpoints.RECEIPTS_CHECK,
239
- "params": {
240
- "id": receipt_id
241
- }
242
- }
243
-
244
- # Get authentication headers
245
- headers = self._get_auth_headers(language)
246
-
247
- # Make request
248
- response = self.http_client.post(
249
- endpoint="",
250
- json_data=data,
251
- headers=headers
252
- )
253
-
254
- return response
255
-
256
- @handle_exceptions
257
- def cancel(
258
- self,
259
- receipt_id: str,
260
- reason: Optional[str] = None,
261
- **kwargs
262
- ) -> Dict[str, Any]:
263
- """
264
- Cancel a receipt.
265
-
266
- Args:
267
- receipt_id: Receipt ID
268
- reason: Cancellation reason
269
- **kwargs: Additional parameters
270
- - language: Language code (uz, ru, en)
271
-
272
- Returns:
273
- Dict containing receipt cancellation response
274
- """
275
- # Extract additional parameters
276
- language = kwargs.get('language', 'uz')
277
-
278
- # Prepare request data
279
- data = {
280
- "method": PaymeEndpoints.RECEIPTS_CANCEL,
281
- "params": {
282
- "id": receipt_id
283
- }
284
- }
285
-
286
- # Add reason if provided
287
- if reason:
288
- data["params"]["reason"] = reason
289
-
290
- # Get authentication headers
291
- headers = self._get_auth_headers(language)
292
-
293
- # Make request
294
- response = self.http_client.post(
295
- endpoint="",
296
- json_data=data,
297
- headers=headers
298
- )
299
-
300
- return response
301
-
302
- @handle_exceptions
303
- def get(self, receipt_id: str, **kwargs) -> Dict[str, Any]:
304
- """
305
- Get receipt details.
306
-
307
- Args:
308
- receipt_id: Receipt ID
309
- **kwargs: Additional parameters
310
- - language: Language code (uz, ru, en)
311
-
312
- Returns:
313
- Dict containing receipt details response
314
- """
315
- # Extract additional parameters
316
- language = kwargs.get('language', 'uz')
317
-
318
- # Prepare request data
319
- data = {
320
- "method": PaymeEndpoints.RECEIPTS_GET,
321
- "params": {
322
- "id": receipt_id
323
- }
324
- }
325
-
326
- # Get authentication headers
327
- headers = self._get_auth_headers(language)
328
-
329
- # Make request
330
- response = self.http_client.post(
331
- endpoint="",
332
- json_data=data,
333
- headers=headers
334
- )
335
-
336
- return response