paytechuz 0.1.3__tar.gz → 0.1.4__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 paytechuz might be problematic. Click here for more details.

Files changed (48) hide show
  1. paytechuz-0.1.4/PKG-INFO +146 -0
  2. paytechuz-0.1.4/README.md +131 -0
  3. paytechuz-0.1.4/pyproject.toml +18 -0
  4. {paytechuz-0.1.3 → paytechuz-0.1.4}/setup.py +3 -15
  5. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/__init__.py +1 -2
  6. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/base.py +12 -3
  7. paytechuz-0.1.4/src/gateways/payme/client.py +262 -0
  8. paytechuz-0.1.4/src/paytechuz.egg-info/PKG-INFO +146 -0
  9. {paytechuz-0.1.3 → paytechuz-0.1.4/src}/paytechuz.egg-info/SOURCES.txt +6 -6
  10. paytechuz-0.1.4/src/paytechuz.egg-info/top_level.txt +3 -0
  11. paytechuz-0.1.3/PKG-INFO +0 -198
  12. paytechuz-0.1.3/README.md +0 -147
  13. paytechuz-0.1.3/paytechuz.egg-info/PKG-INFO +0 -198
  14. paytechuz-0.1.3/paytechuz.egg-info/requires.txt +0 -19
  15. paytechuz-0.1.3/paytechuz.egg-info/top_level.txt +0 -1
  16. paytechuz-0.1.3/src/gateways/payme/client.py +0 -238
  17. {paytechuz-0.1.3 → paytechuz-0.1.4}/MANIFEST.in +0 -0
  18. {paytechuz-0.1.3 → paytechuz-0.1.4}/setup.cfg +0 -0
  19. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/__init__.py +0 -0
  20. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/constants.py +0 -0
  21. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/exceptions.py +0 -0
  22. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/http.py +0 -0
  23. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/payme/errors.py +0 -0
  24. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/core/utils.py +0 -0
  25. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/__init__.py +0 -0
  26. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/click/__init__.py +0 -0
  27. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/click/client.py +0 -0
  28. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/click/merchant.py +0 -0
  29. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/click/webhook.py +0 -0
  30. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/payme/__init__.py +0 -0
  31. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/payme/cards.py +0 -0
  32. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/payme/receipts.py +0 -0
  33. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/gateways/payme/webhook.py +0 -0
  34. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/__init__.py +0 -0
  35. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/__init__.py +0 -0
  36. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/admin.py +0 -0
  37. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/apps.py +0 -0
  38. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/migrations/0001_initial.py +0 -0
  39. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/migrations/__init__.py +0 -0
  40. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/models.py +0 -0
  41. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/signals.py +0 -0
  42. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/views.py +0 -0
  43. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/django/webhooks.py +0 -0
  44. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/fastapi/__init__.py +0 -0
  45. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/fastapi/models.py +0 -0
  46. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/fastapi/routes.py +0 -0
  47. {paytechuz-0.1.3 → paytechuz-0.1.4}/src/integrations/fastapi/schemas.py +0 -0
  48. {paytechuz-0.1.3 → paytechuz-0.1.4/src}/paytechuz.egg-info/dependency_links.txt +0 -0
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: paytechuz
3
+ Version: 0.1.4
4
+ Summary: Unified Python package for Uzbekistan payment gateways
5
+ Home-page: https://github.com/Muhammadali-Akbarov/paytechuz
6
+ Author: Muhammadali Akbarov
7
+ Author-email: muhammadali17abc@gmail.com
8
+ License: MIT
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: home-page
14
+ Dynamic: requires-python
15
+
16
+ # PayTechUZ
17
+
18
+ [![PyPI version](https://badge.fury.io/py/paytechuz.svg)](https://badge.fury.io/py/paytechuz)
19
+ [![Python Versions](https://img.shields.io/pypi/pyversions/paytechuz.svg)](https://pypi.org/project/paytechuz/)
20
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
21
+ ## Installation
22
+
23
+ ### Basic Installation
24
+
25
+ ```bash
26
+ pip install paytechuz
27
+ ```
28
+
29
+ ### Framework-Specific Installation
30
+
31
+ ```bash
32
+ # For Django
33
+ pip install paytechuz[django]
34
+
35
+ # For FastAPI
36
+ pip install paytechuz[fastapi]
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ### Generate Payment Links
42
+
43
+ ```python
44
+ from paytechuz.gateways.payme import PaymeGateway
45
+ from paytechuz.gateways.click import ClickGateway
46
+
47
+ # Initialize gateways
48
+ payme = PaymeGateway()
49
+ click = ClickGateway()
50
+
51
+ # Generate payment links
52
+ payme_link = payme.generate_payment_link(
53
+ id="order_123",
54
+ amount=150000, # amount in UZS
55
+ return_url="https://example.com/return"
56
+ )
57
+
58
+ click_link = click.generate_payment_link(
59
+ id="order_123",
60
+ amount=150000, # amount in UZS
61
+ return_url="https://example.com/return"
62
+ )
63
+ ```
64
+
65
+ ### Django Integration
66
+
67
+ 1. Add to `INSTALLED_APPS`:
68
+
69
+ ```python
70
+ # settings.py
71
+ INSTALLED_APPS = [
72
+ # ...
73
+ 'paytechuz.integrations.django',
74
+ ]
75
+
76
+ PAYME_ID = 'your_payme_merchant_id'
77
+ PAYME_KEY = 'your_payme_merchant_key'
78
+ PAYME_ACCOUNT_MODEL = 'your_app.models.YourModel' # For example: 'orders.models.Order'
79
+ PAYME_ACCOUNT_FIELD = 'id'
80
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
81
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
82
+
83
+ CLICK_SERVICE_ID = 'your_click_service_id'
84
+ CLICK_MERCHANT_ID = 'your_click_merchant_id'
85
+ CLICK_SECRET_KEY = 'your_click_secret_key'
86
+ CLICK_ACCOUNT_MODEL = 'your_app.models.YourModel'
87
+ CLICK_COMMISSION_PERCENT = 0.0
88
+ ```
89
+
90
+ 2. Create webhook handlers:
91
+
92
+ ```python
93
+ # views.py
94
+ from paytechuz.integrations.django.views import PaymeWebhookView
95
+ from .models import Order
96
+
97
+ class PaymeWebhookView(PaymeWebhookView):
98
+ def successfully_payment(self, params, transaction):
99
+ order = Order.objects.get(id=transaction.account_id)
100
+ order.status = 'paid'
101
+ order.save()
102
+
103
+ def cancelled_payment(self, params, transaction):
104
+ order = Order.objects.get(id=transaction.account_id)
105
+ order.status = 'cancelled'
106
+ order.save()
107
+ ```
108
+
109
+ ### FastAPI Integration
110
+
111
+ 1. Create webhook handler:
112
+
113
+ ```python
114
+ from fastapi import FastAPI, Request
115
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler
116
+
117
+ app = FastAPI()
118
+
119
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
120
+ def successfully_payment(self, params, transaction):
121
+ # Handle successful payment
122
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
123
+ order.status = "paid"
124
+ self.db.commit()
125
+
126
+ def cancelled_payment(self, params, transaction):
127
+ # Handle cancelled payment
128
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
129
+ order.status = "cancelled"
130
+ self.db.commit()
131
+
132
+ @app.post("/payments/payme/webhook")
133
+ async def payme_webhook(request: Request):
134
+ handler = CustomPaymeWebhookHandler(
135
+ payme_id="your_merchant_id",
136
+ payme_key="your_merchant_key"
137
+ )
138
+ return await handler.handle_webhook(request)
139
+ ```
140
+
141
+ ## Documentation
142
+
143
+ Detailed documentation is available in multiple languages:
144
+
145
+ - 📖 [English Documentation](docs/en/index.md)
146
+ - 📖 [O'zbek tilidagi hujjatlar](docs/uz/index.md)
@@ -0,0 +1,131 @@
1
+ # PayTechUZ
2
+
3
+ [![PyPI version](https://badge.fury.io/py/paytechuz.svg)](https://badge.fury.io/py/paytechuz)
4
+ [![Python Versions](https://img.shields.io/pypi/pyversions/paytechuz.svg)](https://pypi.org/project/paytechuz/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ ## Installation
7
+
8
+ ### Basic Installation
9
+
10
+ ```bash
11
+ pip install paytechuz
12
+ ```
13
+
14
+ ### Framework-Specific Installation
15
+
16
+ ```bash
17
+ # For Django
18
+ pip install paytechuz[django]
19
+
20
+ # For FastAPI
21
+ pip install paytechuz[fastapi]
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Generate Payment Links
27
+
28
+ ```python
29
+ from paytechuz.gateways.payme import PaymeGateway
30
+ from paytechuz.gateways.click import ClickGateway
31
+
32
+ # Initialize gateways
33
+ payme = PaymeGateway()
34
+ click = ClickGateway()
35
+
36
+ # Generate payment links
37
+ payme_link = payme.generate_payment_link(
38
+ id="order_123",
39
+ amount=150000, # amount in UZS
40
+ return_url="https://example.com/return"
41
+ )
42
+
43
+ click_link = click.generate_payment_link(
44
+ id="order_123",
45
+ amount=150000, # amount in UZS
46
+ return_url="https://example.com/return"
47
+ )
48
+ ```
49
+
50
+ ### Django Integration
51
+
52
+ 1. Add to `INSTALLED_APPS`:
53
+
54
+ ```python
55
+ # settings.py
56
+ INSTALLED_APPS = [
57
+ # ...
58
+ 'paytechuz.integrations.django',
59
+ ]
60
+
61
+ PAYME_ID = 'your_payme_merchant_id'
62
+ PAYME_KEY = 'your_payme_merchant_key'
63
+ PAYME_ACCOUNT_MODEL = 'your_app.models.YourModel' # For example: 'orders.models.Order'
64
+ PAYME_ACCOUNT_FIELD = 'id'
65
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
66
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
67
+
68
+ CLICK_SERVICE_ID = 'your_click_service_id'
69
+ CLICK_MERCHANT_ID = 'your_click_merchant_id'
70
+ CLICK_SECRET_KEY = 'your_click_secret_key'
71
+ CLICK_ACCOUNT_MODEL = 'your_app.models.YourModel'
72
+ CLICK_COMMISSION_PERCENT = 0.0
73
+ ```
74
+
75
+ 2. Create webhook handlers:
76
+
77
+ ```python
78
+ # views.py
79
+ from paytechuz.integrations.django.views import PaymeWebhookView
80
+ from .models import Order
81
+
82
+ class PaymeWebhookView(PaymeWebhookView):
83
+ def successfully_payment(self, params, transaction):
84
+ order = Order.objects.get(id=transaction.account_id)
85
+ order.status = 'paid'
86
+ order.save()
87
+
88
+ def cancelled_payment(self, params, transaction):
89
+ order = Order.objects.get(id=transaction.account_id)
90
+ order.status = 'cancelled'
91
+ order.save()
92
+ ```
93
+
94
+ ### FastAPI Integration
95
+
96
+ 1. Create webhook handler:
97
+
98
+ ```python
99
+ from fastapi import FastAPI, Request
100
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler
101
+
102
+ app = FastAPI()
103
+
104
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
105
+ def successfully_payment(self, params, transaction):
106
+ # Handle successful payment
107
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
108
+ order.status = "paid"
109
+ self.db.commit()
110
+
111
+ def cancelled_payment(self, params, transaction):
112
+ # Handle cancelled payment
113
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
114
+ order.status = "cancelled"
115
+ self.db.commit()
116
+
117
+ @app.post("/payments/payme/webhook")
118
+ async def payme_webhook(request: Request):
119
+ handler = CustomPaymeWebhookHandler(
120
+ payme_id="your_merchant_id",
121
+ payme_key="your_merchant_key"
122
+ )
123
+ return await handler.handle_webhook(request)
124
+ ```
125
+
126
+ ## Documentation
127
+
128
+ Detailed documentation is available in multiple languages:
129
+
130
+ - 📖 [English Documentation](docs/en/index.md)
131
+ - 📖 [O'zbek tilidagi hujjatlar](docs/uz/index.md)
@@ -0,0 +1,18 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "paytechuz"
7
+ version = "0.1.4"
8
+ description = "Unified Python package for Uzbekistan payment gateways"
9
+ readme = "README.md"
10
+ requires-python = ">=3.7"
11
+ license = {text = "MIT"}
12
+
13
+ [tool.setuptools]
14
+ package-dir = {"" = "src"}
15
+
16
+ [tool.setuptools.packages.find]
17
+ where = ["src"]
18
+ include = ["paytechuz*", "core*", "gateways*", "integrations*"]
@@ -1,14 +1,14 @@
1
1
  """Setup script for PayTechUZ package."""
2
2
 
3
3
  import pathlib
4
- from setuptools import setup
4
+ from setuptools import setup, find_namespace_packages
5
5
 
6
6
  here = pathlib.Path(__file__).parent.resolve()
7
7
  long_description = (here / "README.md").read_text(encoding="utf-8")
8
8
 
9
9
  setup(
10
10
  name='paytechuz',
11
- version='0.1.3',
11
+ version='0.1.4',
12
12
  license='MIT',
13
13
  author="Muhammadali Akbarov",
14
14
  author_email='muhammadali17abc@gmail.com',
@@ -17,19 +17,7 @@ setup(
17
17
  long_description_content_type="text/markdown",
18
18
  url='https://github.com/Muhammadali-Akbarov/paytechuz',
19
19
 
20
- packages=[
21
- 'paytechuz',
22
- 'paytechuz.core',
23
- 'paytechuz.core.payme',
24
- 'paytechuz.gateways',
25
- 'paytechuz.gateways.payme',
26
- 'paytechuz.gateways.click',
27
- 'paytechuz.integrations',
28
- 'paytechuz.integrations.django',
29
- 'paytechuz.integrations.django.migrations',
30
- 'paytechuz.integrations.fastapi',
31
- 'paytechuz.integrations.flask',
32
- ],
20
+ packages=find_namespace_packages(include=['paytechuz*']),
33
21
  package_dir={
34
22
  'paytechuz': 'src',
35
23
  },
@@ -5,8 +5,7 @@ payment systems in Uzbekistan. It supports Django, Flask, and FastAPI.
5
5
  """
6
6
  from typing import Any
7
7
 
8
- __version__ = '0.1.1'
9
-
8
+ __version__ = '0.1.4'
10
9
 
11
10
 
12
11
  # Define dummy classes to avoid import errors
@@ -4,6 +4,7 @@ Base classes for payment gateways.
4
4
  from abc import ABC, abstractmethod
5
5
  from typing import Dict, Any, Optional, Union
6
6
 
7
+
7
8
  class BasePaymentGateway(ABC):
8
9
  """
9
10
  Base class for all payment gateways.
@@ -23,7 +24,12 @@ class BasePaymentGateway(ABC):
23
24
  self.is_test_mode = is_test_mode
24
25
 
25
26
  @abstractmethod
26
- def create_payment(self, amount: Union[int, float, str], account_id: Union[int, str], **kwargs) -> Dict[str, Any]:
27
+ def create_payment(
28
+ self,
29
+ amount: Union[int, float, str],
30
+ account_id: Union[int, str],
31
+ **kwargs
32
+ ) -> Dict[str, Any]:
27
33
  """
28
34
  Create a payment.
29
35
 
@@ -51,7 +57,11 @@ class BasePaymentGateway(ABC):
51
57
  raise NotImplementedError
52
58
 
53
59
  @abstractmethod
54
- def cancel_payment(self, transaction_id: str, reason: Optional[str] = None) -> Dict[str, Any]:
60
+ def cancel_payment(
61
+ self,
62
+ transaction_id: str,
63
+ reason: Optional[str] = None
64
+ ) -> Dict[str, Any]:
55
65
  """
56
66
  Cancel payment.
57
67
 
@@ -65,7 +75,6 @@ class BasePaymentGateway(ABC):
65
75
  raise NotImplementedError
66
76
 
67
77
 
68
-
69
78
  class BaseWebhookHandler(ABC):
70
79
  """
71
80
  Base class for payment gateway webhook handlers.
@@ -0,0 +1,262 @@
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
+ amount: Payment amount in som
153
+ account_id: Account or order ID
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
+ amount: Payment amount in som
180
+ account_id: Account or order ID
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
+ }