paytechuz 0.2.7__tar.gz → 0.2.8__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 (77) hide show
  1. paytechuz-0.2.8/PKG-INFO +312 -0
  2. paytechuz-0.2.8/README.md +297 -0
  3. {paytechuz-0.2.7 → paytechuz-0.2.8}/pyproject.toml +1 -1
  4. {paytechuz-0.2.7 → paytechuz-0.2.8}/setup.py +1 -1
  5. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/click/client.py +13 -20
  6. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/fastapi/models.py +55 -23
  7. {paytechuz-0.2.7/src/paytechuz → paytechuz-0.2.8/src}/integrations/fastapi/schemas.py +31 -14
  8. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/fastapi/models.py +16 -11
  9. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/fastapi/routes.py +163 -61
  10. {paytechuz-0.2.7/src → paytechuz-0.2.8/src/paytechuz}/integrations/fastapi/schemas.py +26 -7
  11. paytechuz-0.2.8/src/paytechuz.egg-info/PKG-INFO +312 -0
  12. paytechuz-0.2.7/PKG-INFO +0 -170
  13. paytechuz-0.2.7/README.md +0 -155
  14. paytechuz-0.2.7/src/paytechuz.egg-info/PKG-INFO +0 -170
  15. {paytechuz-0.2.7 → paytechuz-0.2.8}/MANIFEST.in +0 -0
  16. {paytechuz-0.2.7 → paytechuz-0.2.8}/setup.cfg +0 -0
  17. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/__init__.py +0 -0
  18. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/__init__.py +0 -0
  19. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/base.py +0 -0
  20. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/constants.py +0 -0
  21. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/exceptions.py +0 -0
  22. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/http.py +0 -0
  23. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/payme/errors.py +0 -0
  24. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/core/utils.py +0 -0
  25. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/__init__.py +0 -0
  26. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/click/__init__.py +0 -0
  27. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/click/merchant.py +0 -0
  28. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/click/webhook.py +0 -0
  29. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/payme/__init__.py +0 -0
  30. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/payme/cards.py +0 -0
  31. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/payme/client.py +0 -0
  32. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/payme/receipts.py +0 -0
  33. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/gateways/payme/webhook.py +0 -0
  34. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/__init__.py +0 -0
  35. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/__init__.py +0 -0
  36. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/admin.py +0 -0
  37. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/apps.py +0 -0
  38. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/migrations/0001_initial.py +0 -0
  39. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/migrations/__init__.py +0 -0
  40. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/models.py +0 -0
  41. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/signals.py +0 -0
  42. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/views.py +0 -0
  43. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/django/webhooks.py +0 -0
  44. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/fastapi/__init__.py +0 -0
  45. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/integrations/fastapi/routes.py +0 -0
  46. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/__init__.py +0 -0
  47. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/__init__.py +0 -0
  48. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/base.py +0 -0
  49. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/constants.py +0 -0
  50. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/exceptions.py +0 -0
  51. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/http.py +0 -0
  52. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/payme/errors.py +0 -0
  53. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/core/utils.py +0 -0
  54. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/__init__.py +0 -0
  55. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/click/__init__.py +0 -0
  56. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/click/client.py +0 -0
  57. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/click/merchant.py +0 -0
  58. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/click/webhook.py +0 -0
  59. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/payme/__init__.py +0 -0
  60. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/payme/cards.py +0 -0
  61. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/payme/client.py +0 -0
  62. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/payme/receipts.py +0 -0
  63. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/gateways/payme/webhook.py +0 -0
  64. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/__init__.py +0 -0
  65. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/__init__.py +0 -0
  66. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/admin.py +0 -0
  67. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/apps.py +0 -0
  68. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/migrations/0001_initial.py +0 -0
  69. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/migrations/__init__.py +0 -0
  70. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/models.py +0 -0
  71. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/signals.py +0 -0
  72. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/views.py +0 -0
  73. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/django/webhooks.py +0 -0
  74. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz/integrations/fastapi/__init__.py +0 -0
  75. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz.egg-info/SOURCES.txt +0 -0
  76. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz.egg-info/dependency_links.txt +0 -0
  77. {paytechuz-0.2.7 → paytechuz-0.2.8}/src/paytechuz.egg-info/top_level.txt +0 -0
@@ -0,0 +1,312 @@
1
+ Metadata-Version: 2.4
2
+ Name: paytechuz
3
+ Version: 0.2.8
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
+
22
+ PayTechUZ is a unified payment library for integrating with popular payment systems in Uzbekistan. It provides a simple and consistent interface for working with Payme and Click payment gateways.
23
+
24
+ ## Features
25
+
26
+ - 🔄 **API**: Consistent interface for multiple payment providers
27
+ - 🛡️ **Secure**: Built-in security features for payment processing
28
+ - 🔌 **Framework Integration**: Native support for Django and FastAPI
29
+ - 🌐 **Webhook Handling**: Easy-to-use webhook handlers for payment notifications
30
+ - 📊 **Transaction Management**: Automatic transaction tracking and management
31
+ - 🧩 **Extensible**: Easy to add new payment providers
32
+ ## Installation
33
+
34
+ ### Basic Installation
35
+
36
+ ```bash
37
+ pip install paytechuz
38
+ ```
39
+
40
+ ### Framework-Specific Installation
41
+
42
+ ```bash
43
+ # For Django
44
+ pip install paytechuz[django]
45
+
46
+ # For FastAPI
47
+ pip install paytechuz[fastapi]
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ### Generate Payment Links
53
+
54
+ ```python
55
+ from paytechuz.gateways.payme import PaymeGateway
56
+ from paytechuz.gateways.click import ClickGateway
57
+
58
+ # Initialize Payme gateway
59
+ payme = PaymeGateway(
60
+ payme_id="your_payme_id",
61
+ payme_key="your_payme_key",
62
+ is_test_mode=True # Set to False in production environment
63
+ )
64
+
65
+ # Initialize Click gateway
66
+ click = ClickGateway(
67
+ service_id="your_service_id",
68
+ merchant_id="your_merchant_id",
69
+ merchant_user_id="your_merchant_user_id",
70
+ secret_key="your_secret_key",
71
+ is_test_mode=True # Set to False in production environment
72
+ )
73
+
74
+ # Generate payment links
75
+ payme_link = payme.create_payment(
76
+ id="order_123",
77
+ amount=150000, # amount in UZS
78
+ return_url="https://example.com/return"
79
+ )
80
+
81
+ click_link = click.create_payment(
82
+ id="order_123",
83
+ amount=150000, # amount in UZS
84
+ description="Test payment",
85
+ return_url="https://example.com/return"
86
+ )
87
+ ```
88
+
89
+ ### Django Integration
90
+
91
+ 1. Create Order model:
92
+
93
+ ```python
94
+ # models.py
95
+ from django.db import models
96
+ from django.utils import timezone
97
+
98
+ class Order(models.Model):
99
+ STATUS_CHOICES = (
100
+ ('pending', 'Pending'),
101
+ ('paid', 'Paid'),
102
+ ('cancelled', 'Cancelled'),
103
+ ('delivered', 'Delivered'),
104
+ )
105
+
106
+ product_name = models.CharField(max_length=255)
107
+ amount = models.DecimalField(max_digits=12, decimal_places=2)
108
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
109
+ created_at = models.DateTimeField(default=timezone.now)
110
+
111
+ def __str__(self):
112
+ return f"{self.id} - {self.product_name} ({self.amount})"
113
+ ```
114
+
115
+ 2. Add to `INSTALLED_APPS` and configure settings:
116
+
117
+ ```python
118
+ # settings.py
119
+ INSTALLED_APPS = [
120
+ # ...
121
+ 'paytechuz.integrations.django',
122
+ ]
123
+
124
+ PAYME_ID = 'your_payme_merchant_id'
125
+ PAYME_KEY = 'your_payme_merchant_key'
126
+ PAYME_ACCOUNT_MODEL = 'your_app.models.Order' # For example: 'orders.models.Order'
127
+ PAYME_ACCOUNT_FIELD = 'id'
128
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
129
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
130
+
131
+ CLICK_SERVICE_ID = 'your_click_service_id'
132
+ CLICK_MERCHANT_ID = 'your_click_merchant_id'
133
+ CLICK_SECRET_KEY = 'your_click_secret_key'
134
+ CLICK_ACCOUNT_MODEL = 'your_app.models.Order'
135
+ CLICK_COMMISSION_PERCENT = 0.0
136
+ ```
137
+
138
+ 3. Create webhook handlers:
139
+
140
+ ```python
141
+ # views.py
142
+ from paytechuz.integrations.django.views import BasePaymeWebhookView, BaseClickWebhookView
143
+ from .models import Order
144
+
145
+ class PaymeWebhookView(BasePaymeWebhookView):
146
+ def successfully_payment(self, params, transaction):
147
+ order = Order.objects.get(id=transaction.account_id)
148
+ order.status = 'paid'
149
+ order.save()
150
+
151
+ def cancelled_payment(self, params, transaction):
152
+ order = Order.objects.get(id=transaction.account_id)
153
+ order.status = 'cancelled'
154
+ order.save()
155
+
156
+ class ClickWebhookView(BaseClickWebhookView):
157
+ def successfully_payment(self, params, transaction):
158
+ order = Order.objects.get(id=transaction.account_id)
159
+ order.status = 'paid'
160
+ order.save()
161
+
162
+ def cancelled_payment(self, params, transaction):
163
+ order = Order.objects.get(id=transaction.account_id)
164
+ order.status = 'cancelled'
165
+ order.save()
166
+ ```
167
+
168
+ 4. Add webhook URLs to `urls.py`:
169
+
170
+ ```python
171
+ # urls.py
172
+ from django.urls import path
173
+ from django.views.decorators.csrf import csrf_exempt
174
+ from .views import PaymeWebhookView, ClickWebhookView
175
+
176
+ urlpatterns = [
177
+ # ...
178
+ path('payments/webhook/payme/', csrf_exempt(PaymeWebhookView.as_view()), name='payme_webhook'),
179
+ path('payments/webhook/click/', csrf_exempt(ClickWebhookView.as_view()), name='click_webhook'),
180
+ ]
181
+ ```
182
+
183
+ ### FastAPI Integration
184
+
185
+ 1. Set up database models:
186
+
187
+ ```python
188
+ from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime
189
+ from sqlalchemy.ext.declarative import declarative_base
190
+ from sqlalchemy.orm import sessionmaker
191
+ from paytechuz.integrations.fastapi import Base as PaymentsBase
192
+ from paytechuz.integrations.fastapi.models import run_migrations
193
+ from datetime import datetime, timezone
194
+
195
+ # Create database engine
196
+ SQLALCHEMY_DATABASE_URL = "sqlite:///./payments.db"
197
+ engine = create_engine(SQLALCHEMY_DATABASE_URL)
198
+
199
+ # Create base declarative class
200
+ Base = declarative_base()
201
+
202
+ # Create Order model
203
+ class Order(Base):
204
+ __tablename__ = "orders"
205
+
206
+ id = Column(Integer, primary_key=True, index=True)
207
+ product_name = Column(String, index=True)
208
+ amount = Column(Float)
209
+ status = Column(String, default="pending")
210
+ created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
211
+
212
+ # Create payment tables using run_migrations
213
+ run_migrations(engine)
214
+
215
+ # Create Order table
216
+ Base.metadata.create_all(bind=engine)
217
+
218
+ # Create session
219
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
220
+ ```
221
+
222
+ 2. Create webhook handlers:
223
+
224
+ ```python
225
+ from fastapi import FastAPI, Request, Depends
226
+ from sqlalchemy.orm import Session
227
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler, ClickWebhookHandler
228
+
229
+ app = FastAPI()
230
+
231
+ # Dependency to get the database session
232
+ def get_db():
233
+ db = SessionLocal()
234
+ try:
235
+ yield db
236
+ finally:
237
+ db.close()
238
+
239
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
240
+ def successfully_payment(self, params, transaction):
241
+ # Handle successful payment
242
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
243
+ order.status = "paid"
244
+ self.db.commit()
245
+
246
+ def cancelled_payment(self, params, transaction):
247
+ # Handle cancelled payment
248
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
249
+ order.status = "cancelled"
250
+ self.db.commit()
251
+
252
+ class CustomClickWebhookHandler(ClickWebhookHandler):
253
+ def successfully_payment(self, params, transaction):
254
+ # Handle successful payment
255
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
256
+ order.status = "paid"
257
+ self.db.commit()
258
+
259
+ def cancelled_payment(self, params, transaction):
260
+ # Handle cancelled payment
261
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
262
+ order.status = "cancelled"
263
+ self.db.commit()
264
+
265
+ @app.post("/payments/payme/webhook")
266
+ async def payme_webhook(request: Request, db: Session = Depends(get_db)):
267
+ handler = CustomPaymeWebhookHandler(
268
+ db=db,
269
+ payme_id="your_merchant_id",
270
+ payme_key="your_merchant_key",
271
+ account_model=Order,
272
+ account_field='id',
273
+ amount_field='amount'
274
+ )
275
+ return await handler.handle_webhook(request)
276
+
277
+ @app.post("/payments/click/webhook")
278
+ async def click_webhook(request: Request, db: Session = Depends(get_db)):
279
+ handler = CustomClickWebhookHandler(
280
+ db=db,
281
+ service_id="your_service_id",
282
+ merchant_id="your_merchant_id",
283
+ secret_key="your_secret_key",
284
+ account_model=Order
285
+ )
286
+ return await handler.handle_webhook(request)
287
+ ```
288
+
289
+ ## Documentation
290
+
291
+ Detailed documentation is available in multiple languages:
292
+
293
+ - 📖 [English Documentation](src/docs/en/index.md)
294
+ - 📖 [O'zbek tilidagi hujjatlar](src/docs/index.md)
295
+
296
+ ### Framework-Specific Documentation
297
+
298
+ - [Django Integration Guide](src/docs/en/django_integration.md) | [Django integratsiyasi bo'yicha qo'llanma](src/docs/django_integration.md)
299
+ - [FastAPI Integration Guide](src/docs/en/fastapi_integration.md) | [FastAPI integratsiyasi bo'yicha qo'llanma](src/docs/fastapi_integration.md)
300
+
301
+ ## Supported Payment Systems
302
+
303
+ - **Payme** - [Official Website](https://payme.uz)
304
+ - **Click** - [Official Website](https://click.uz)
305
+
306
+ ## Contributing
307
+
308
+ Contributions are welcome! Please feel free to submit a Pull Request.
309
+
310
+ ## License
311
+
312
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -0,0 +1,297 @@
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
+
7
+ PayTechUZ is a unified payment library for integrating with popular payment systems in Uzbekistan. It provides a simple and consistent interface for working with Payme and Click payment gateways.
8
+
9
+ ## Features
10
+
11
+ - 🔄 **API**: Consistent interface for multiple payment providers
12
+ - 🛡️ **Secure**: Built-in security features for payment processing
13
+ - 🔌 **Framework Integration**: Native support for Django and FastAPI
14
+ - 🌐 **Webhook Handling**: Easy-to-use webhook handlers for payment notifications
15
+ - 📊 **Transaction Management**: Automatic transaction tracking and management
16
+ - 🧩 **Extensible**: Easy to add new payment providers
17
+ ## Installation
18
+
19
+ ### Basic Installation
20
+
21
+ ```bash
22
+ pip install paytechuz
23
+ ```
24
+
25
+ ### Framework-Specific Installation
26
+
27
+ ```bash
28
+ # For Django
29
+ pip install paytechuz[django]
30
+
31
+ # For FastAPI
32
+ pip install paytechuz[fastapi]
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ### Generate Payment Links
38
+
39
+ ```python
40
+ from paytechuz.gateways.payme import PaymeGateway
41
+ from paytechuz.gateways.click import ClickGateway
42
+
43
+ # Initialize Payme gateway
44
+ payme = PaymeGateway(
45
+ payme_id="your_payme_id",
46
+ payme_key="your_payme_key",
47
+ is_test_mode=True # Set to False in production environment
48
+ )
49
+
50
+ # Initialize Click gateway
51
+ click = ClickGateway(
52
+ service_id="your_service_id",
53
+ merchant_id="your_merchant_id",
54
+ merchant_user_id="your_merchant_user_id",
55
+ secret_key="your_secret_key",
56
+ is_test_mode=True # Set to False in production environment
57
+ )
58
+
59
+ # Generate payment links
60
+ payme_link = payme.create_payment(
61
+ id="order_123",
62
+ amount=150000, # amount in UZS
63
+ return_url="https://example.com/return"
64
+ )
65
+
66
+ click_link = click.create_payment(
67
+ id="order_123",
68
+ amount=150000, # amount in UZS
69
+ description="Test payment",
70
+ return_url="https://example.com/return"
71
+ )
72
+ ```
73
+
74
+ ### Django Integration
75
+
76
+ 1. Create Order model:
77
+
78
+ ```python
79
+ # models.py
80
+ from django.db import models
81
+ from django.utils import timezone
82
+
83
+ class Order(models.Model):
84
+ STATUS_CHOICES = (
85
+ ('pending', 'Pending'),
86
+ ('paid', 'Paid'),
87
+ ('cancelled', 'Cancelled'),
88
+ ('delivered', 'Delivered'),
89
+ )
90
+
91
+ product_name = models.CharField(max_length=255)
92
+ amount = models.DecimalField(max_digits=12, decimal_places=2)
93
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
94
+ created_at = models.DateTimeField(default=timezone.now)
95
+
96
+ def __str__(self):
97
+ return f"{self.id} - {self.product_name} ({self.amount})"
98
+ ```
99
+
100
+ 2. Add to `INSTALLED_APPS` and configure settings:
101
+
102
+ ```python
103
+ # settings.py
104
+ INSTALLED_APPS = [
105
+ # ...
106
+ 'paytechuz.integrations.django',
107
+ ]
108
+
109
+ PAYME_ID = 'your_payme_merchant_id'
110
+ PAYME_KEY = 'your_payme_merchant_key'
111
+ PAYME_ACCOUNT_MODEL = 'your_app.models.Order' # For example: 'orders.models.Order'
112
+ PAYME_ACCOUNT_FIELD = 'id'
113
+ PAYME_AMOUNT_FIELD = 'amount' # Field for storing payment amount
114
+ PAYME_ONE_TIME_PAYMENT = True # Allow only one payment per account
115
+
116
+ CLICK_SERVICE_ID = 'your_click_service_id'
117
+ CLICK_MERCHANT_ID = 'your_click_merchant_id'
118
+ CLICK_SECRET_KEY = 'your_click_secret_key'
119
+ CLICK_ACCOUNT_MODEL = 'your_app.models.Order'
120
+ CLICK_COMMISSION_PERCENT = 0.0
121
+ ```
122
+
123
+ 3. Create webhook handlers:
124
+
125
+ ```python
126
+ # views.py
127
+ from paytechuz.integrations.django.views import BasePaymeWebhookView, BaseClickWebhookView
128
+ from .models import Order
129
+
130
+ class PaymeWebhookView(BasePaymeWebhookView):
131
+ def successfully_payment(self, params, transaction):
132
+ order = Order.objects.get(id=transaction.account_id)
133
+ order.status = 'paid'
134
+ order.save()
135
+
136
+ def cancelled_payment(self, params, transaction):
137
+ order = Order.objects.get(id=transaction.account_id)
138
+ order.status = 'cancelled'
139
+ order.save()
140
+
141
+ class ClickWebhookView(BaseClickWebhookView):
142
+ def successfully_payment(self, params, transaction):
143
+ order = Order.objects.get(id=transaction.account_id)
144
+ order.status = 'paid'
145
+ order.save()
146
+
147
+ def cancelled_payment(self, params, transaction):
148
+ order = Order.objects.get(id=transaction.account_id)
149
+ order.status = 'cancelled'
150
+ order.save()
151
+ ```
152
+
153
+ 4. Add webhook URLs to `urls.py`:
154
+
155
+ ```python
156
+ # urls.py
157
+ from django.urls import path
158
+ from django.views.decorators.csrf import csrf_exempt
159
+ from .views import PaymeWebhookView, ClickWebhookView
160
+
161
+ urlpatterns = [
162
+ # ...
163
+ path('payments/webhook/payme/', csrf_exempt(PaymeWebhookView.as_view()), name='payme_webhook'),
164
+ path('payments/webhook/click/', csrf_exempt(ClickWebhookView.as_view()), name='click_webhook'),
165
+ ]
166
+ ```
167
+
168
+ ### FastAPI Integration
169
+
170
+ 1. Set up database models:
171
+
172
+ ```python
173
+ from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime
174
+ from sqlalchemy.ext.declarative import declarative_base
175
+ from sqlalchemy.orm import sessionmaker
176
+ from paytechuz.integrations.fastapi import Base as PaymentsBase
177
+ from paytechuz.integrations.fastapi.models import run_migrations
178
+ from datetime import datetime, timezone
179
+
180
+ # Create database engine
181
+ SQLALCHEMY_DATABASE_URL = "sqlite:///./payments.db"
182
+ engine = create_engine(SQLALCHEMY_DATABASE_URL)
183
+
184
+ # Create base declarative class
185
+ Base = declarative_base()
186
+
187
+ # Create Order model
188
+ class Order(Base):
189
+ __tablename__ = "orders"
190
+
191
+ id = Column(Integer, primary_key=True, index=True)
192
+ product_name = Column(String, index=True)
193
+ amount = Column(Float)
194
+ status = Column(String, default="pending")
195
+ created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
196
+
197
+ # Create payment tables using run_migrations
198
+ run_migrations(engine)
199
+
200
+ # Create Order table
201
+ Base.metadata.create_all(bind=engine)
202
+
203
+ # Create session
204
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
205
+ ```
206
+
207
+ 2. Create webhook handlers:
208
+
209
+ ```python
210
+ from fastapi import FastAPI, Request, Depends
211
+ from sqlalchemy.orm import Session
212
+ from paytechuz.integrations.fastapi import PaymeWebhookHandler, ClickWebhookHandler
213
+
214
+ app = FastAPI()
215
+
216
+ # Dependency to get the database session
217
+ def get_db():
218
+ db = SessionLocal()
219
+ try:
220
+ yield db
221
+ finally:
222
+ db.close()
223
+
224
+ class CustomPaymeWebhookHandler(PaymeWebhookHandler):
225
+ def successfully_payment(self, params, transaction):
226
+ # Handle successful payment
227
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
228
+ order.status = "paid"
229
+ self.db.commit()
230
+
231
+ def cancelled_payment(self, params, transaction):
232
+ # Handle cancelled payment
233
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
234
+ order.status = "cancelled"
235
+ self.db.commit()
236
+
237
+ class CustomClickWebhookHandler(ClickWebhookHandler):
238
+ def successfully_payment(self, params, transaction):
239
+ # Handle successful payment
240
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
241
+ order.status = "paid"
242
+ self.db.commit()
243
+
244
+ def cancelled_payment(self, params, transaction):
245
+ # Handle cancelled payment
246
+ order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
247
+ order.status = "cancelled"
248
+ self.db.commit()
249
+
250
+ @app.post("/payments/payme/webhook")
251
+ async def payme_webhook(request: Request, db: Session = Depends(get_db)):
252
+ handler = CustomPaymeWebhookHandler(
253
+ db=db,
254
+ payme_id="your_merchant_id",
255
+ payme_key="your_merchant_key",
256
+ account_model=Order,
257
+ account_field='id',
258
+ amount_field='amount'
259
+ )
260
+ return await handler.handle_webhook(request)
261
+
262
+ @app.post("/payments/click/webhook")
263
+ async def click_webhook(request: Request, db: Session = Depends(get_db)):
264
+ handler = CustomClickWebhookHandler(
265
+ db=db,
266
+ service_id="your_service_id",
267
+ merchant_id="your_merchant_id",
268
+ secret_key="your_secret_key",
269
+ account_model=Order
270
+ )
271
+ return await handler.handle_webhook(request)
272
+ ```
273
+
274
+ ## Documentation
275
+
276
+ Detailed documentation is available in multiple languages:
277
+
278
+ - 📖 [English Documentation](src/docs/en/index.md)
279
+ - 📖 [O'zbek tilidagi hujjatlar](src/docs/index.md)
280
+
281
+ ### Framework-Specific Documentation
282
+
283
+ - [Django Integration Guide](src/docs/en/django_integration.md) | [Django integratsiyasi bo'yicha qo'llanma](src/docs/django_integration.md)
284
+ - [FastAPI Integration Guide](src/docs/en/fastapi_integration.md) | [FastAPI integratsiyasi bo'yicha qo'llanma](src/docs/fastapi_integration.md)
285
+
286
+ ## Supported Payment Systems
287
+
288
+ - **Payme** - [Official Website](https://payme.uz)
289
+ - **Click** - [Official Website](https://click.uz)
290
+
291
+ ## Contributing
292
+
293
+ Contributions are welcome! Please feel free to submit a Pull Request.
294
+
295
+ ## License
296
+
297
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "paytechuz"
7
- version = "0.2.7"
7
+ version = "0.2.8"
8
8
  description = "Unified Python package for Uzbekistan payment gateways"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.7"
@@ -8,7 +8,7 @@ long_description = (here / "README.md").read_text(encoding="utf-8")
8
8
 
9
9
  setup(
10
10
  name='paytechuz',
11
- version='0.2.7',
11
+ version='0.2.8',
12
12
  license='MIT',
13
13
  author="Muhammadali Akbarov",
14
14
  author_email='muhammadali17abc@gmail.com',
@@ -7,7 +7,7 @@ from typing import Dict, Any, Optional, Union
7
7
  from paytechuz.core.base import BasePaymentGateway
8
8
  from paytechuz.core.http import HttpClient
9
9
  from paytechuz.core.constants import ClickNetworks
10
- from paytechuz.core.utils import format_amount, handle_exceptions
10
+ from paytechuz.core.utils import handle_exceptions
11
11
  from paytechuz.gateways.click.merchant import ClickMerchantApi
12
12
 
13
13
  logger = logging.getLogger(__name__)
@@ -65,7 +65,7 @@ class ClickGateway(BasePaymentGateway):
65
65
  id: Union[int, str],
66
66
  amount: Union[int, float, str],
67
67
  **kwargs
68
- ) -> Dict[str, Any]:
68
+ ) -> str:
69
69
  """
70
70
  Create a payment using Click.
71
71
 
@@ -81,13 +81,12 @@ class ClickGateway(BasePaymentGateway):
81
81
  - email: Customer email
82
82
 
83
83
  Returns:
84
- Dict containing payment details including transaction ID and payment URL
84
+ Payment URL string for redirecting the user to Click payment page
85
85
  """
86
- # Format amount to tiyin (1 som = 100 tiyin)
87
- amount_tiyin = format_amount(amount)
86
+ # Format amount for URL (no need to convert to tiyin for URL)
88
87
 
89
88
  # Extract additional parameters
90
- description = kwargs.get('description', f'Payment for account {account_id}')
89
+ description = kwargs.get('description', f'Payment for account {id}')
91
90
  return_url = kwargs.get('return_url')
92
91
  callback_url = kwargs.get('callback_url')
93
92
  # These parameters are not used in the URL but are available in the API
@@ -111,18 +110,8 @@ class ClickGateway(BasePaymentGateway):
111
110
  if description:
112
111
  payment_url += f"&merchant_user_id={description}"
113
112
 
114
- # Generate a unique transaction ID
115
- transaction_id = f"click_{id}_{int(amount_tiyin)}"
116
-
117
- return {
118
- 'transaction_id': transaction_id,
119
- 'payment_url': payment_url,
120
- 'amount': amount,
121
- 'account_id': id,
122
- 'status': 'created',
123
- 'service_id': self.service_id,
124
- 'merchant_id': self.merchant_id
125
- }
113
+ # Return the payment URL directly
114
+ return payment_url
126
115
 
127
116
  @handle_exceptions
128
117
  def check_payment(self, transaction_id: str) -> Dict[str, Any]:
@@ -139,7 +128,9 @@ class ClickGateway(BasePaymentGateway):
139
128
  # Format: click_account_id_amount
140
129
  parts = transaction_id.split('_')
141
130
  if len(parts) < 3 or parts[0] != 'click':
142
- raise ValueError(f"Invalid transaction ID format: {transaction_id}")
131
+ raise ValueError(
132
+ f"Invalid transaction ID format: {transaction_id}"
133
+ )
143
134
 
144
135
  account_id = parts[1]
145
136
 
@@ -188,7 +179,9 @@ class ClickGateway(BasePaymentGateway):
188
179
  # Format: click_account_id_amount
189
180
  parts = transaction_id.split('_')
190
181
  if len(parts) < 3 or parts[0] != 'click':
191
- raise ValueError(f"Invalid transaction ID format: {transaction_id}")
182
+ raise ValueError(
183
+ f"Invalid transaction ID format: {transaction_id}"
184
+ )
192
185
 
193
186
  account_id = parts[1]
194
187