paytechuz 0.1.0__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 (42) hide show
  1. paytechuz-0.1.0/MANIFEST.in +16 -0
  2. paytechuz-0.1.0/PKG-INFO +198 -0
  3. paytechuz-0.1.0/README.md +147 -0
  4. paytechuz-0.1.0/core/__init__.py +0 -0
  5. paytechuz-0.1.0/core/base.py +88 -0
  6. paytechuz-0.1.0/core/constants.py +68 -0
  7. paytechuz-0.1.0/core/exceptions.py +190 -0
  8. paytechuz-0.1.0/core/http.py +268 -0
  9. paytechuz-0.1.0/core/utils.py +192 -0
  10. paytechuz-0.1.0/gateways/__init__.py +0 -0
  11. paytechuz-0.1.0/gateways/click/__init__.py +0 -0
  12. paytechuz-0.1.0/gateways/click/client.py +202 -0
  13. paytechuz-0.1.0/gateways/click/merchant.py +264 -0
  14. paytechuz-0.1.0/gateways/click/webhook.py +227 -0
  15. paytechuz-0.1.0/gateways/payme/__init__.py +0 -0
  16. paytechuz-0.1.0/gateways/payme/cards.py +222 -0
  17. paytechuz-0.1.0/gateways/payme/client.py +238 -0
  18. paytechuz-0.1.0/gateways/payme/receipts.py +336 -0
  19. paytechuz-0.1.0/gateways/payme/webhook.py +379 -0
  20. paytechuz-0.1.0/integrations/__init__.py +0 -0
  21. paytechuz-0.1.0/integrations/django/__init__.py +4 -0
  22. paytechuz-0.1.0/integrations/django/admin.py +78 -0
  23. paytechuz-0.1.0/integrations/django/apps.py +21 -0
  24. paytechuz-0.1.0/integrations/django/migrations/0001_initial.py +51 -0
  25. paytechuz-0.1.0/integrations/django/migrations/__init__.py +3 -0
  26. paytechuz-0.1.0/integrations/django/models.py +174 -0
  27. paytechuz-0.1.0/integrations/django/signals.py +46 -0
  28. paytechuz-0.1.0/integrations/django/views.py +100 -0
  29. paytechuz-0.1.0/integrations/django/webhooks.py +880 -0
  30. paytechuz-0.1.0/integrations/fastapi/__init__.py +21 -0
  31. paytechuz-0.1.0/integrations/fastapi/models.py +151 -0
  32. paytechuz-0.1.0/integrations/fastapi/routes.py +1028 -0
  33. paytechuz-0.1.0/integrations/fastapi/schemas.py +99 -0
  34. paytechuz-0.1.0/paytechuz.egg-info/PKG-INFO +198 -0
  35. paytechuz-0.1.0/paytechuz.egg-info/SOURCES.txt +40 -0
  36. paytechuz-0.1.0/paytechuz.egg-info/dependency_links.txt +1 -0
  37. paytechuz-0.1.0/paytechuz.egg-info/requires.txt +19 -0
  38. paytechuz-0.1.0/paytechuz.egg-info/top_level.txt +4 -0
  39. paytechuz-0.1.0/setup.cfg +4 -0
  40. paytechuz-0.1.0/setup.py +64 -0
  41. paytechuz-0.1.0/tests/__init__.py +1 -0
  42. paytechuz-0.1.0/tests/test_gateway.py +70 -0
@@ -0,0 +1,16 @@
1
+ include LICENSE
2
+ include README.md
3
+ include PYPI_UPLOAD.md
4
+ recursive-include examples *
5
+ recursive-exclude examples *.pyc
6
+ recursive-exclude examples __pycache__
7
+ recursive-exclude examples/shop_env *
8
+ recursive-exclude examples/shop/media *
9
+ recursive-exclude examples/shop/static/img *
10
+ recursive-exclude examples/shop/db.sqlite3
11
+ recursive-exclude tests *.pyc
12
+ recursive-exclude tests __pycache__
13
+ recursive-exclude * *.py[co]
14
+ recursive-exclude * __pycache__
15
+ recursive-exclude * *.so
16
+ recursive-exclude * .DS_Store
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: paytechuz
3
+ Version: 0.1.0
4
+ Summary: Unified Python package for Uzbekistan payment gateways (Payme, Click)
5
+ Home-page: https://github.com/Muhammadali-Akbarov/paytechuz
6
+ Author: Muhammadali Akbarov
7
+ Author-email: muhammadali17abc@gmail.com
8
+ License: MIT
9
+ Keywords: paytechuz,payme,click,uzbekistan,payment,gateway,payment-gateway,payment-processing,django,flask,fastapi
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.6
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: License :: OSI Approved :: MIT License
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.6
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: requests<3.0,>=2.0
26
+ Requires-Dist: dataclasses<1.0,>=0.6; python_version < "3.7"
27
+ Provides-Extra: django
28
+ Requires-Dist: django<5.0,>=3.0; extra == "django"
29
+ Requires-Dist: djangorestframework<4.0,>=3.0; extra == "django"
30
+ Provides-Extra: fastapi
31
+ Requires-Dist: fastapi<1.0.0,>=0.68.0; extra == "fastapi"
32
+ Requires-Dist: sqlalchemy<3.0,>=1.4; extra == "fastapi"
33
+ Requires-Dist: httpx<1.0,>=0.20; extra == "fastapi"
34
+ Requires-Dist: python-multipart==0.0.20; extra == "fastapi"
35
+ Requires-Dist: pydantic<2.0,>=1.8; extra == "fastapi"
36
+ Provides-Extra: flask
37
+ Requires-Dist: flask<3.0,>=2.0; extra == "flask"
38
+ Requires-Dist: flask-sqlalchemy<3.0,>=2.5; extra == "flask"
39
+ Dynamic: author
40
+ Dynamic: author-email
41
+ Dynamic: classifier
42
+ Dynamic: description
43
+ Dynamic: description-content-type
44
+ Dynamic: home-page
45
+ Dynamic: keywords
46
+ Dynamic: license
47
+ Dynamic: provides-extra
48
+ Dynamic: requires-dist
49
+ Dynamic: requires-python
50
+ Dynamic: summary
51
+
52
+ # paytechuz
53
+
54
+ paytechuz is a unified payment library for integration with popular payment systems in Uzbekistan (Payme and Click).
55
+
56
+ [![PyPI version](https://badge.fury.io/py/paytechuz.svg)](https://badge.fury.io/py/paytechuz)
57
+ [![Python Versions](https://img.shields.io/pypi/pyversions/paytechuz.svg)](https://pypi.org/project/paytechuz/)
58
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
59
+
60
+ ## Installation
61
+
62
+ To install paytechuz with all dependencies:
63
+
64
+ ```bash
65
+ pip install paytechuz
66
+ ```
67
+
68
+ For specific framework support:
69
+
70
+ ```bash
71
+ # For Django
72
+ pip install paytechuz[django]
73
+
74
+ # For FastAPI
75
+ pip install paytechuz[fastapi]
76
+ ```
77
+
78
+ ## Quick Start
79
+
80
+ ### Django Integration
81
+
82
+ 1. Add the app to your `INSTALLED_APPS`:
83
+
84
+ ```python
85
+ # settings.py
86
+ INSTALLED_APPS = [
87
+ # ...
88
+ 'paytechuz.integrations.django',
89
+ ]
90
+
91
+ # Payme settings
92
+ PAYME_ID = 'your_payme_merchant_id'
93
+ PAYME_KEY = 'your_payme_merchant_key'
94
+ PAYME_ACCOUNT_MODEL = 'your_app.YourModel' # For example: 'orders.Order'
95
+ PAYME_ACCOUNT_FIELD = 'id' # Field for account identifier
96
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
97
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
98
+ ```
99
+
100
+ 2. Set up the webhook URLs:
101
+
102
+ ```python
103
+ # urls.py
104
+ from django.urls import path
105
+ from django.views.decorators.csrf import csrf_exempt
106
+
107
+ from your_app.views import PaymeWebhookView, ClickWebhookView
108
+
109
+
110
+ urlpatterns = [
111
+ # ...
112
+ path('payments/payme/', csrf_exempt(PaymeWebhookView.as_view()), name='payme_webhook'),
113
+ path('payments/click/', csrf_exempt(ClickWebhookView.as_view()), name='click_webhook'),
114
+ ]
115
+ ```
116
+
117
+ 3. Create custom webhook handlers:
118
+
119
+ ```python
120
+ # views.py
121
+ from paytechuz.integrations.django.views import PaymeWebhookView as BasePaymeWebhookView
122
+ from .models import Order
123
+
124
+ class PaymeWebhookView(BasePaymeWebhookView):
125
+ def successfully_payment(self, params, transaction):
126
+ """Called when payment is successful"""
127
+ order_id = transaction.account_id
128
+ order = Order.objects.get(id=order_id)
129
+ order.status = 'paid'
130
+ order.save()
131
+
132
+ def cancelled_payment(self, params, transaction):
133
+ """Called when payment is cancelled"""
134
+ order_id = transaction.account_id
135
+ order = Order.objects.get(id=order_id)
136
+ order.status = 'cancelled'
137
+ order.save()
138
+ ```
139
+
140
+ ### FastAPI Integration
141
+
142
+ 1. Create a custom webhook handler:
143
+
144
+ ```python
145
+ from fastapi import APIRouter, Depends, Request
146
+ from sqlalchemy.orm import Session
147
+
148
+ from app.database.db import get_db
149
+ from app.models.models import Order
150
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler
151
+
152
+ # Payme configuration
153
+ PAYME_ID = 'your_payme_id'
154
+ PAYME_KEY = 'your_payme_key'
155
+
156
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
157
+ def successfully_payment(self, params, transaction) -> None:
158
+ """Called when payment is successful"""
159
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
160
+ if order:
161
+ order.status = "paid"
162
+ self.db.commit()
163
+
164
+ def cancelled_payment(self, params, transaction) -> None:
165
+ """Called when payment is cancelled"""
166
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
167
+ if order:
168
+ order.status = "cancelled"
169
+ self.db.commit()
170
+ ```
171
+
172
+ 2. Create a webhook endpoint:
173
+
174
+ ```python
175
+ router = APIRouter()
176
+
177
+ @router.post("/payments/payme/webhook")
178
+ async def payme_webhook(request: Request, db: Session = Depends(get_db)):
179
+ """Handle Payme webhook requests"""
180
+ handler = CustomPaymeWebhookHandler(
181
+ db=db,
182
+ payme_id=PAYME_ID,
183
+ payme_key=PAYME_KEY,
184
+ account_model=Order,
185
+ account_field="id",
186
+ amount_field="amount",
187
+ one_time_payment=False
188
+ )
189
+ result = await handler.handle_webhook(request)
190
+ return result
191
+ ```
192
+
193
+ ## Documentation
194
+
195
+ For detailed documentation, see:
196
+
197
+ - [English Documentation](paytechuz/docs/en/index.md)
198
+ - [O'zbek tilidagi hujjatlar](paytechuz/docs/index.md)
@@ -0,0 +1,147 @@
1
+ # paytechuz
2
+
3
+ paytechuz is a unified payment library for integration with popular payment systems in Uzbekistan (Payme and Click).
4
+
5
+ [![PyPI version](https://badge.fury.io/py/paytechuz.svg)](https://badge.fury.io/py/paytechuz)
6
+ [![Python Versions](https://img.shields.io/pypi/pyversions/paytechuz.svg)](https://pypi.org/project/paytechuz/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Installation
10
+
11
+ To install paytechuz with all dependencies:
12
+
13
+ ```bash
14
+ pip install paytechuz
15
+ ```
16
+
17
+ For specific framework support:
18
+
19
+ ```bash
20
+ # For Django
21
+ pip install paytechuz[django]
22
+
23
+ # For FastAPI
24
+ pip install paytechuz[fastapi]
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Django Integration
30
+
31
+ 1. Add the app to your `INSTALLED_APPS`:
32
+
33
+ ```python
34
+ # settings.py
35
+ INSTALLED_APPS = [
36
+ # ...
37
+ 'paytechuz.integrations.django',
38
+ ]
39
+
40
+ # Payme settings
41
+ PAYME_ID = 'your_payme_merchant_id'
42
+ PAYME_KEY = 'your_payme_merchant_key'
43
+ PAYME_ACCOUNT_MODEL = 'your_app.YourModel' # For example: 'orders.Order'
44
+ PAYME_ACCOUNT_FIELD = 'id' # Field for account identifier
45
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
46
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
47
+ ```
48
+
49
+ 2. Set up the webhook URLs:
50
+
51
+ ```python
52
+ # urls.py
53
+ from django.urls import path
54
+ from django.views.decorators.csrf import csrf_exempt
55
+
56
+ from your_app.views import PaymeWebhookView, ClickWebhookView
57
+
58
+
59
+ urlpatterns = [
60
+ # ...
61
+ path('payments/payme/', csrf_exempt(PaymeWebhookView.as_view()), name='payme_webhook'),
62
+ path('payments/click/', csrf_exempt(ClickWebhookView.as_view()), name='click_webhook'),
63
+ ]
64
+ ```
65
+
66
+ 3. Create custom webhook handlers:
67
+
68
+ ```python
69
+ # views.py
70
+ from paytechuz.integrations.django.views import PaymeWebhookView as BasePaymeWebhookView
71
+ from .models import Order
72
+
73
+ class PaymeWebhookView(BasePaymeWebhookView):
74
+ def successfully_payment(self, params, transaction):
75
+ """Called when payment is successful"""
76
+ order_id = transaction.account_id
77
+ order = Order.objects.get(id=order_id)
78
+ order.status = 'paid'
79
+ order.save()
80
+
81
+ def cancelled_payment(self, params, transaction):
82
+ """Called when payment is cancelled"""
83
+ order_id = transaction.account_id
84
+ order = Order.objects.get(id=order_id)
85
+ order.status = 'cancelled'
86
+ order.save()
87
+ ```
88
+
89
+ ### FastAPI Integration
90
+
91
+ 1. Create a custom webhook handler:
92
+
93
+ ```python
94
+ from fastapi import APIRouter, Depends, Request
95
+ from sqlalchemy.orm import Session
96
+
97
+ from app.database.db import get_db
98
+ from app.models.models import Order
99
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler
100
+
101
+ # Payme configuration
102
+ PAYME_ID = 'your_payme_id'
103
+ PAYME_KEY = 'your_payme_key'
104
+
105
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
106
+ def successfully_payment(self, params, transaction) -> None:
107
+ """Called when payment is successful"""
108
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
109
+ if order:
110
+ order.status = "paid"
111
+ self.db.commit()
112
+
113
+ def cancelled_payment(self, params, transaction) -> None:
114
+ """Called when payment is cancelled"""
115
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
116
+ if order:
117
+ order.status = "cancelled"
118
+ self.db.commit()
119
+ ```
120
+
121
+ 2. Create a webhook endpoint:
122
+
123
+ ```python
124
+ router = APIRouter()
125
+
126
+ @router.post("/payments/payme/webhook")
127
+ async def payme_webhook(request: Request, db: Session = Depends(get_db)):
128
+ """Handle Payme webhook requests"""
129
+ handler = CustomPaymeWebhookHandler(
130
+ db=db,
131
+ payme_id=PAYME_ID,
132
+ payme_key=PAYME_KEY,
133
+ account_model=Order,
134
+ account_field="id",
135
+ amount_field="amount",
136
+ one_time_payment=False
137
+ )
138
+ result = await handler.handle_webhook(request)
139
+ return result
140
+ ```
141
+
142
+ ## Documentation
143
+
144
+ For detailed documentation, see:
145
+
146
+ - [English Documentation](paytechuz/docs/en/index.md)
147
+ - [O'zbek tilidagi hujjatlar](paytechuz/docs/index.md)
File without changes
@@ -0,0 +1,88 @@
1
+ """
2
+ Base classes for payment gateways.
3
+ """
4
+ from abc import ABC, abstractmethod
5
+ from typing import Dict, Any, Optional, Union
6
+
7
+ class BasePaymentGateway(ABC):
8
+ """
9
+ Base class for all payment gateways.
10
+
11
+ This abstract class defines the common interface that all payment gateways
12
+ must implement. It provides a consistent API for creating, checking, and
13
+ canceling payments regardless of the underlying payment provider.
14
+ """
15
+
16
+ def __init__(self, is_test_mode: bool = False):
17
+ """
18
+ Initialize the payment gateway.
19
+
20
+ Args:
21
+ is_test_mode (bool): Whether to use the test environment
22
+ """
23
+ self.is_test_mode = is_test_mode
24
+
25
+ @abstractmethod
26
+ def create_payment(self, amount: Union[int, float, str], account_id: Union[int, str], **kwargs) -> Dict[str, Any]:
27
+ """
28
+ Create a payment.
29
+
30
+ Args:
31
+ amount: The payment amount
32
+ account_id: The account ID or order ID
33
+ **kwargs: Additional parameters specific to the payment gateway
34
+
35
+ Returns:
36
+ Dict containing payment details including transaction ID
37
+ """
38
+ raise NotImplementedError
39
+
40
+ @abstractmethod
41
+ def check_payment(self, transaction_id: str) -> Dict[str, Any]:
42
+ """
43
+ Check payment status.
44
+
45
+ Args:
46
+ transaction_id: The transaction ID to check
47
+
48
+ Returns:
49
+ Dict containing payment status and details
50
+ """
51
+ raise NotImplementedError
52
+
53
+ @abstractmethod
54
+ def cancel_payment(self, transaction_id: str, reason: Optional[str] = None) -> Dict[str, Any]:
55
+ """
56
+ Cancel payment.
57
+
58
+ Args:
59
+ transaction_id: The transaction ID to cancel
60
+ reason: Optional reason for cancellation
61
+
62
+ Returns:
63
+ Dict containing cancellation status and details
64
+ """
65
+ raise NotImplementedError
66
+
67
+
68
+
69
+ class BaseWebhookHandler(ABC):
70
+ """
71
+ Base class for payment gateway webhook handlers.
72
+
73
+ This abstract class defines the common interface for handling webhook
74
+ callbacks from payment gateways.
75
+ """
76
+
77
+ @abstractmethod
78
+ def handle_webhook(self, data: Dict[str, Any]) -> Dict[str, Any]:
79
+ """
80
+ Handle webhook data from payment gateway.
81
+
82
+ Args:
83
+ data: The webhook data received from the payment gateway
84
+
85
+ Returns:
86
+ Dict containing the response to be sent back to the payment gateway
87
+ """
88
+ raise NotImplementedError
@@ -0,0 +1,68 @@
1
+ """
2
+ Constants for payment gateways.
3
+ """
4
+ from enum import Enum
5
+
6
+ class TransactionState(Enum):
7
+ """Transaction states."""
8
+ CREATED = 0
9
+ INITIATING = 1
10
+ SUCCESSFULLY = 2
11
+ CANCELED = -2
12
+ CANCELED_DURING_INIT = -1
13
+
14
+
15
+ class PaymentGateway(Enum):
16
+ """Payment gateway types."""
17
+ PAYME = "payme"
18
+ CLICK = "click"
19
+
20
+ class PaymeEndpoints:
21
+ """Payme API endpoints."""
22
+ RECEIPTS_CREATE = "receipts/create"
23
+ RECEIPTS_PAY = "receipts/pay"
24
+ RECEIPTS_SEND = "receipts/send"
25
+ RECEIPTS_CHECK = "receipts/check"
26
+ RECEIPTS_CANCEL = "receipts/cancel"
27
+ RECEIPTS_GET = "receipts/get"
28
+ CARDS_CREATE = "cards/create"
29
+ CARDS_VERIFY = "cards/verify"
30
+ CARDS_CHECK = "cards/check"
31
+ CARDS_REMOVE = "cards/remove"
32
+ CARDS_GET_VERIFY_CODE = "cards/get_verify_code"
33
+
34
+
35
+ class PaymeNetworks:
36
+ """Payme API networks."""
37
+ TEST_NET = "https://checkout.test.paycom.uz/api"
38
+ PROD_NET = "https://checkout.paycom.uz/api"
39
+
40
+ class ClickEndpoints:
41
+ """Click API endpoints."""
42
+ PREPARE = "prepare"
43
+ COMPLETE = "complete"
44
+ MERCHANT_API = "merchant/api"
45
+
46
+
47
+ class ClickNetworks:
48
+ """Click API networks."""
49
+ TEST_NET = "https://api.click.uz/v2/merchant"
50
+ PROD_NET = "https://api.click.uz/v2/merchant"
51
+
52
+ class ClickActions:
53
+ """Click API actions."""
54
+ PREPARE = 0
55
+ COMPLETE = 1
56
+
57
+
58
+ class PaymeCancelReason:
59
+ """Payme cancel reason codes."""
60
+ REASON_USER_NOT_FOUND = 1
61
+ REASON_DEBIT_OPERATION_FAILED = 2
62
+ REASON_EXECUTION_ERROR = 3
63
+ REASON_TIMEOUT = 4
64
+ REASON_FUND_RETURNED = 5
65
+ REASON_UNKNOWN = 6
66
+ REASON_CANCELLED_BY_USER = 7
67
+ REASON_SUSPICIOUS_OPERATION = 8
68
+ REASON_MERCHANT_DECISION = 9