paytechuz 0.2.10__tar.gz → 0.2.13__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.
- {paytechuz-0.2.10 → paytechuz-0.2.13}/PKG-INFO +30 -13
- {paytechuz-0.2.10 → paytechuz-0.2.13}/README.md +29 -12
- paytechuz-0.2.13/examples/paytechuz_fastapi/app/database.py +10 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/app/models.py +17 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/app/typing.py +55 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/app/webhook_handlers.py +28 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/main.py +103 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/payments.db +0 -0
- paytechuz-0.2.13/examples/paytechuz_fastapi/run.sh +2 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/pyproject.toml +1 -1
- {paytechuz-0.2.10 → paytechuz-0.2.13}/setup.py +1 -1
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/fastapi/routes.py +1 -1
- paytechuz-0.2.13/src/paytechuz/gateways/__init__.py +0 -0
- paytechuz-0.2.13/src/paytechuz/integrations/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/webhooks.py +41 -28
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/fastapi/routes.py +1 -1
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz.egg-info/PKG-INFO +30 -13
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz.egg-info/SOURCES.txt +9 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/MANIFEST.in +0 -0
- {paytechuz-0.2.10/src/core → paytechuz-0.2.13/examples/paytechuz_fastapi}/__init__.py +0 -0
- {paytechuz-0.2.10/src/gateways → paytechuz-0.2.13/examples/paytechuz_fastapi/app}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/setup.cfg +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/__init__.py +0 -0
- {paytechuz-0.2.10/src/gateways/click → paytechuz-0.2.13/src/core}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/base.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/constants.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/exceptions.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/http.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/payme/errors.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/core/utils.py +0 -0
- {paytechuz-0.2.10/src/gateways/payme → paytechuz-0.2.13/src/gateways}/__init__.py +0 -0
- {paytechuz-0.2.10/src/integrations → paytechuz-0.2.13/src/gateways/click}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/click/client.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/click/merchant.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/click/webhook.py +0 -0
- {paytechuz-0.2.10/src/paytechuz/core → paytechuz-0.2.13/src/gateways/payme}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/payme/cards.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/payme/client.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/payme/receipts.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/gateways/payme/webhook.py +0 -0
- {paytechuz-0.2.10/src/paytechuz/gateways → paytechuz-0.2.13/src/integrations}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/admin.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/apps.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/migrations/0001_initial.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/migrations/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/models.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/signals.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/views.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/django/webhooks.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/fastapi/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/fastapi/models.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/integrations/fastapi/schemas.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/__init__.py +0 -0
- {paytechuz-0.2.10/src/paytechuz/integrations → paytechuz-0.2.13/src/paytechuz/core}/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/base.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/constants.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/exceptions.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/http.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/payme/errors.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/core/utils.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/click/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/click/client.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/click/merchant.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/click/webhook.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/payme/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/payme/cards.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/payme/client.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/payme/receipts.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/gateways/payme/webhook.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/admin.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/apps.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/migrations/0001_initial.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/migrations/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/models.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/signals.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/views.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/fastapi/__init__.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/fastapi/models.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/fastapi/schemas.py +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz.egg-info/dependency_links.txt +0 -0
- {paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paytechuz
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
4
4
|
Summary: Unified Python package for Uzbekistan payment gateways
|
|
5
5
|
Home-page: https://github.com/Muhammadali-Akbarov/paytechuz
|
|
6
6
|
Author: Muhammadali Akbarov
|
|
@@ -17,10 +17,13 @@ Dynamic: requires-python
|
|
|
17
17
|
|
|
18
18
|
[](https://badge.fury.io/py/paytechuz)
|
|
19
19
|
[](https://pypi.org/project/paytechuz/)
|
|
20
|
+
[](https://pay-tech.uz)
|
|
20
21
|
[](https://opensource.org/licenses/MIT)
|
|
21
22
|
|
|
22
23
|
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
|
|
|
25
|
+
📖 **[Complete Documentation](https://pay-tech.uz)** | 🚀 **[Quick Start Guide](https://pay-tech.uz/quickstart)**
|
|
26
|
+
|
|
24
27
|
## Features
|
|
25
28
|
|
|
26
29
|
- 🔄 **API**: Consistent interface for multiple payment providers
|
|
@@ -49,6 +52,8 @@ pip install paytechuz[fastapi]
|
|
|
49
52
|
|
|
50
53
|
## Quick Start
|
|
51
54
|
|
|
55
|
+
> 💡 **Need help?** Check out our [complete documentation](https://pay-tech.uz) for detailed guides and examples.
|
|
56
|
+
|
|
52
57
|
### Generate Payment Links
|
|
53
58
|
|
|
54
59
|
```python
|
|
@@ -121,18 +126,26 @@ INSTALLED_APPS = [
|
|
|
121
126
|
'paytechuz.integrations.django',
|
|
122
127
|
]
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
PAYTECHUZ = {
|
|
130
|
+
'PAYME': {
|
|
131
|
+
'PAYME_ID': 'your_payme_id',
|
|
132
|
+
'PAYME_KEY': 'your_payme_key',
|
|
133
|
+
'ACCOUNT_MODEL': 'your_app.models.Order', # For example: 'orders.models.Order'
|
|
134
|
+
'ACCOUNT_FIELD': 'id',
|
|
135
|
+
'AMOUNT_FIELD': 'amount',
|
|
136
|
+
'ONE_TIME_PAYMENT': True,
|
|
137
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
138
|
+
},
|
|
139
|
+
'CLICK': {
|
|
140
|
+
'SERVICE_ID': 'your_service_id',
|
|
141
|
+
'MERCHANT_ID': 'your_merchant_id',
|
|
142
|
+
'MERCHANT_USER_ID': 'your_merchant_user_id',
|
|
143
|
+
'SECRET_KEY': 'your_secret_key',
|
|
144
|
+
'ACCOUNT_MODEL': 'your_app.models.Order',
|
|
145
|
+
'COMMISSION_PERCENT': 0.0,
|
|
146
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
147
|
+
}
|
|
148
|
+
}
|
|
136
149
|
```
|
|
137
150
|
|
|
138
151
|
3. Create webhook handlers:
|
|
@@ -313,6 +326,10 @@ Detailed documentation is available in multiple languages:
|
|
|
313
326
|
|
|
314
327
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
315
328
|
|
|
329
|
+
📖 **Documentation:** [pay-tech.uz](https://pay-tech.uz)
|
|
330
|
+
🐛 **Issues:** [GitHub Issues](https://github.com/PayTechUz/paytechuz-py/issues)
|
|
331
|
+
💬 **Support:** [Telegram](https://t.me/paytechuz)
|
|
332
|
+
|
|
316
333
|
## License
|
|
317
334
|
|
|
318
335
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/py/paytechuz)
|
|
4
4
|
[](https://pypi.org/project/paytechuz/)
|
|
5
|
+
[](https://pay-tech.uz)
|
|
5
6
|
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
8
|
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
|
|
|
10
|
+
📖 **[Complete Documentation](https://pay-tech.uz)** | 🚀 **[Quick Start Guide](https://pay-tech.uz/quickstart)**
|
|
11
|
+
|
|
9
12
|
## Features
|
|
10
13
|
|
|
11
14
|
- 🔄 **API**: Consistent interface for multiple payment providers
|
|
@@ -34,6 +37,8 @@ pip install paytechuz[fastapi]
|
|
|
34
37
|
|
|
35
38
|
## Quick Start
|
|
36
39
|
|
|
40
|
+
> 💡 **Need help?** Check out our [complete documentation](https://pay-tech.uz) for detailed guides and examples.
|
|
41
|
+
|
|
37
42
|
### Generate Payment Links
|
|
38
43
|
|
|
39
44
|
```python
|
|
@@ -106,18 +111,26 @@ INSTALLED_APPS = [
|
|
|
106
111
|
'paytechuz.integrations.django',
|
|
107
112
|
]
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
PAYTECHUZ = {
|
|
115
|
+
'PAYME': {
|
|
116
|
+
'PAYME_ID': 'your_payme_id',
|
|
117
|
+
'PAYME_KEY': 'your_payme_key',
|
|
118
|
+
'ACCOUNT_MODEL': 'your_app.models.Order', # For example: 'orders.models.Order'
|
|
119
|
+
'ACCOUNT_FIELD': 'id',
|
|
120
|
+
'AMOUNT_FIELD': 'amount',
|
|
121
|
+
'ONE_TIME_PAYMENT': True,
|
|
122
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
123
|
+
},
|
|
124
|
+
'CLICK': {
|
|
125
|
+
'SERVICE_ID': 'your_service_id',
|
|
126
|
+
'MERCHANT_ID': 'your_merchant_id',
|
|
127
|
+
'MERCHANT_USER_ID': 'your_merchant_user_id',
|
|
128
|
+
'SECRET_KEY': 'your_secret_key',
|
|
129
|
+
'ACCOUNT_MODEL': 'your_app.models.Order',
|
|
130
|
+
'COMMISSION_PERCENT': 0.0,
|
|
131
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
132
|
+
}
|
|
133
|
+
}
|
|
121
134
|
```
|
|
122
135
|
|
|
123
136
|
3. Create webhook handlers:
|
|
@@ -298,6 +311,10 @@ Detailed documentation is available in multiple languages:
|
|
|
298
311
|
|
|
299
312
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
300
313
|
|
|
314
|
+
📖 **Documentation:** [pay-tech.uz](https://pay-tech.uz)
|
|
315
|
+
🐛 **Issues:** [GitHub Issues](https://github.com/PayTechUz/paytechuz-py/issues)
|
|
316
|
+
💬 **Support:** [Telegram](https://t.me/paytechuz)
|
|
317
|
+
|
|
301
318
|
## License
|
|
302
319
|
|
|
303
320
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from sqlalchemy import create_engine
|
|
2
|
+
from sqlalchemy.orm import sessionmaker, declarative_base
|
|
3
|
+
|
|
4
|
+
SQLALCHEMY_DATABASE_URL = "sqlite:///payments.db"
|
|
5
|
+
|
|
6
|
+
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
|
|
7
|
+
|
|
8
|
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
9
|
+
|
|
10
|
+
Base = declarative_base()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from sqlalchemy import Column, Integer, String, Float, DateTime
|
|
3
|
+
from app.database import Base
|
|
4
|
+
from paytechuz.integrations.fastapi.models import run_migrations
|
|
5
|
+
|
|
6
|
+
class Order(Base):
|
|
7
|
+
__tablename__ = "orders"
|
|
8
|
+
|
|
9
|
+
id = Column(Integer, primary_key=True, index=True)
|
|
10
|
+
product_name = Column(String, index=True)
|
|
11
|
+
amount = Column(Float)
|
|
12
|
+
status = Column(String, default="pending")
|
|
13
|
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
|
14
|
+
|
|
15
|
+
def init_db(engine):
|
|
16
|
+
run_migrations(engine) # Creates Payme/Click payment tables
|
|
17
|
+
Base.metadata.create_all(bind=engine)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
class OrderCreate(BaseModel):
|
|
6
|
+
"""Order yaratish uchun request model"""
|
|
7
|
+
product_name: str
|
|
8
|
+
amount: float
|
|
9
|
+
description: Optional[str] = None
|
|
10
|
+
payment_method: str # "payme" yoki "click"
|
|
11
|
+
return_url: Optional[str] = "https://example.com/return"
|
|
12
|
+
|
|
13
|
+
class OrderResponse(BaseModel):
|
|
14
|
+
"""Order ma'lumotlarini qaytarish uchun response model"""
|
|
15
|
+
id: int
|
|
16
|
+
product_name: str
|
|
17
|
+
amount: float
|
|
18
|
+
status: str
|
|
19
|
+
created_at: datetime
|
|
20
|
+
payment_method: str
|
|
21
|
+
payment_link: str
|
|
22
|
+
|
|
23
|
+
class Config:
|
|
24
|
+
from_attributes = True
|
|
25
|
+
|
|
26
|
+
class PaymentLinkRequest(BaseModel):
|
|
27
|
+
"""To'lov linkini generatsiya qilish uchun request model"""
|
|
28
|
+
order_id: int
|
|
29
|
+
payment_method: str # "payme" yoki "click"
|
|
30
|
+
return_url: Optional[str] = "https://example.com/return"
|
|
31
|
+
|
|
32
|
+
class PaymentLinkResponse(BaseModel):
|
|
33
|
+
"""To'lov linkini qaytarish uchun response model"""
|
|
34
|
+
order_id: int
|
|
35
|
+
payment_method: str
|
|
36
|
+
payment_link: str
|
|
37
|
+
|
|
38
|
+
class OrderUpdate(BaseModel):
|
|
39
|
+
"""Order yangilash uchun request model"""
|
|
40
|
+
product_name: Optional[str] = None
|
|
41
|
+
amount: Optional[float] = None
|
|
42
|
+
status: Optional[str] = None
|
|
43
|
+
description: Optional[str] = None
|
|
44
|
+
|
|
45
|
+
class OrderListResponse(BaseModel):
|
|
46
|
+
"""Orderlar ro'yxatini qaytarish uchun response model"""
|
|
47
|
+
orders: list[OrderResponse]
|
|
48
|
+
total: int
|
|
49
|
+
skip: int
|
|
50
|
+
limit: int
|
|
51
|
+
|
|
52
|
+
class ErrorResponse(BaseModel):
|
|
53
|
+
"""Xatolik xabarini qaytarish uchun response model"""
|
|
54
|
+
detail: str
|
|
55
|
+
error_code: Optional[str] = None
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from app.models import Order
|
|
2
|
+
from paytechuz.integrations.fastapi import PaymeWebhookHandler, ClickWebhookHandler
|
|
3
|
+
|
|
4
|
+
class CustomPaymeWebhookHandler(PaymeWebhookHandler):
|
|
5
|
+
def successfully_payment(self, params, transaction):
|
|
6
|
+
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
|
|
7
|
+
if order:
|
|
8
|
+
order.status = "paid"
|
|
9
|
+
self.db.commit()
|
|
10
|
+
|
|
11
|
+
def cancelled_payment(self, params, transaction):
|
|
12
|
+
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
|
|
13
|
+
if order:
|
|
14
|
+
order.status = "cancelled"
|
|
15
|
+
self.db.commit()
|
|
16
|
+
|
|
17
|
+
class CustomClickWebhookHandler(ClickWebhookHandler):
|
|
18
|
+
def successfully_payment(self, params, transaction):
|
|
19
|
+
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
|
|
20
|
+
if order:
|
|
21
|
+
order.status = "paid"
|
|
22
|
+
self.db.commit()
|
|
23
|
+
|
|
24
|
+
def cancelled_payment(self, params, transaction):
|
|
25
|
+
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
|
|
26
|
+
if order:
|
|
27
|
+
order.status = "cancelled"
|
|
28
|
+
self.db.commit()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from fastapi import FastAPI, Request, Depends, HTTPException
|
|
2
|
+
from sqlalchemy.orm import Session
|
|
3
|
+
|
|
4
|
+
from app.database import SessionLocal, engine
|
|
5
|
+
from app.models import init_db, Order
|
|
6
|
+
from app.webhook_handlers import CustomPaymeWebhookHandler, CustomClickWebhookHandler
|
|
7
|
+
from app.typing import (
|
|
8
|
+
OrderCreate,
|
|
9
|
+
OrderResponse
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from paytechuz.gateways.payme import PaymeGateway
|
|
13
|
+
from paytechuz.gateways.click import ClickGateway
|
|
14
|
+
|
|
15
|
+
app = FastAPI()
|
|
16
|
+
|
|
17
|
+
init_db(engine)
|
|
18
|
+
|
|
19
|
+
payme = PaymeGateway(
|
|
20
|
+
payme_id="your_payme_id",
|
|
21
|
+
payme_key="your_payme_key",
|
|
22
|
+
is_test_mode=True # Set to False in production environment
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
click = ClickGateway(
|
|
26
|
+
service_id="your_service_id",
|
|
27
|
+
merchant_id="your_merchant_id",
|
|
28
|
+
merchant_user_id="your_merchant_user_id",
|
|
29
|
+
secret_key="your_secret_key",
|
|
30
|
+
is_test_mode=True # Set to False in production environment
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_db():
|
|
35
|
+
db = SessionLocal()
|
|
36
|
+
try:
|
|
37
|
+
yield db
|
|
38
|
+
finally:
|
|
39
|
+
db.close()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@app.post("/orders/", response_model=OrderResponse)
|
|
43
|
+
async def create_order(order_data: OrderCreate, db: Session = Depends(get_db)):
|
|
44
|
+
"""Create a new order with payment link"""
|
|
45
|
+
if order_data.payment_method.lower() not in ["payme", "click"]:
|
|
46
|
+
raise HTTPException(status_code=400, detail="Invalid payment method. Use 'payme' or 'click'")
|
|
47
|
+
|
|
48
|
+
db_order = Order(
|
|
49
|
+
product_name=order_data.product_name,
|
|
50
|
+
amount=order_data.amount,
|
|
51
|
+
status="pending"
|
|
52
|
+
)
|
|
53
|
+
db.add(db_order)
|
|
54
|
+
db.commit()
|
|
55
|
+
db.refresh(db_order)
|
|
56
|
+
|
|
57
|
+
if order_data.payment_method.lower() == "payme":
|
|
58
|
+
payment_link = payme.create_payment(
|
|
59
|
+
id=str(db_order.id),
|
|
60
|
+
amount=int(db_order.amount * 100), # Convert to smallest currency unit
|
|
61
|
+
return_url=order_data.return_url
|
|
62
|
+
)
|
|
63
|
+
else: # click
|
|
64
|
+
payment_link = click.create_payment(
|
|
65
|
+
id=str(db_order.id),
|
|
66
|
+
amount=int(db_order.amount * 100), # Convert to smallest currency unit
|
|
67
|
+
description=db_order.product_name,
|
|
68
|
+
return_url=order_data.return_url
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return OrderResponse(
|
|
72
|
+
id=db_order.id,
|
|
73
|
+
product_name=db_order.product_name,
|
|
74
|
+
amount=db_order.amount,
|
|
75
|
+
status=db_order.status,
|
|
76
|
+
created_at=db_order.created_at,
|
|
77
|
+
payment_method=order_data.payment_method.lower(),
|
|
78
|
+
payment_link=payment_link
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@app.post("/payments/payme/webhook")
|
|
83
|
+
async def payme_webhook(request: Request, db: Session = Depends(get_db)):
|
|
84
|
+
handler = CustomPaymeWebhookHandler(
|
|
85
|
+
db=db,
|
|
86
|
+
payme_id="your_payme_id",
|
|
87
|
+
payme_key="your_payme_key",
|
|
88
|
+
account_model=Order,
|
|
89
|
+
account_field='id',
|
|
90
|
+
amount_field='amount'
|
|
91
|
+
)
|
|
92
|
+
return await handler.handle_webhook(request)
|
|
93
|
+
|
|
94
|
+
@app.post("/payments/click/webhook")
|
|
95
|
+
async def click_webhook(request: Request, db: Session = Depends(get_db)):
|
|
96
|
+
handler = CustomClickWebhookHandler(
|
|
97
|
+
db=db,
|
|
98
|
+
service_id="your_service_id",
|
|
99
|
+
merchant_id="your_merchant_id",
|
|
100
|
+
secret_key="your_secret_key",
|
|
101
|
+
account_model=Order
|
|
102
|
+
)
|
|
103
|
+
return await handler.handle_webhook(request)
|
|
Binary file
|
|
@@ -357,7 +357,7 @@ class PaymeWebhookHandler:
|
|
|
357
357
|
# Check for existing transactions in non-final states
|
|
358
358
|
existing_transactions = self.db.query(PaymentTransaction).filter(
|
|
359
359
|
PaymentTransaction.gateway == PaymentTransaction.PAYME,
|
|
360
|
-
PaymentTransaction.account_id == account.id
|
|
360
|
+
PaymentTransaction.account_id == str(account.id)
|
|
361
361
|
).filter(
|
|
362
362
|
PaymentTransaction.transaction_id != transaction_id
|
|
363
363
|
).all()
|
|
File without changes
|
|
File without changes
|
|
@@ -38,30 +38,37 @@ class PaymeWebhook(View):
|
|
|
38
38
|
def __init__(self, **kwargs):
|
|
39
39
|
super().__init__(**kwargs)
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
paytechuz_settings = getattr(settings, 'PAYTECHUZ', {})
|
|
42
|
+
payme_settings = paytechuz_settings.get('PAYME', {})
|
|
43
|
+
|
|
44
|
+
self.payme_id = payme_settings.get('PAYME_ID') or getattr(settings, 'PAYME_ID', '')
|
|
45
|
+
self.payme_key = payme_settings.get('PAYME_KEY') or getattr(settings, 'PAYME_KEY', '')
|
|
46
|
+
|
|
47
|
+
account_model_path = (
|
|
48
|
+
payme_settings.get('ACCOUNT_MODEL') or
|
|
49
|
+
getattr(settings, 'PAYME_ACCOUNT_MODEL', 'django.contrib.auth.models.User')
|
|
45
50
|
)
|
|
46
51
|
try:
|
|
47
52
|
self.account_model = import_string(account_model_path)
|
|
48
53
|
except ImportError:
|
|
49
|
-
# If the model is not found, log an error and raise an exception
|
|
50
54
|
logger.error(
|
|
51
|
-
"Could not import %s. Check
|
|
55
|
+
"Could not import %s. Check PAYTECHUZ.PAYME.ACCOUNT_MODEL setting.",
|
|
52
56
|
account_model_path
|
|
53
57
|
)
|
|
54
|
-
raise ImportError(
|
|
55
|
-
f"Import error: {account_model_path}"
|
|
56
|
-
) from None
|
|
58
|
+
raise ImportError(f"Import error: {account_model_path}") from None
|
|
57
59
|
|
|
58
|
-
self.account_field =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
self.account_field = (
|
|
61
|
+
payme_settings.get('ACCOUNT_FIELD') or
|
|
62
|
+
getattr(settings, 'PAYME_ACCOUNT_FIELD', 'id')
|
|
63
|
+
)
|
|
64
|
+
self.amount_field = (
|
|
65
|
+
payme_settings.get('AMOUNT_FIELD') or
|
|
66
|
+
getattr(settings, 'PAYME_AMOUNT_FIELD', 'amount')
|
|
67
|
+
)
|
|
68
|
+
self.one_time_payment = (
|
|
69
|
+
payme_settings.get('ONE_TIME_PAYMENT') or
|
|
70
|
+
getattr(settings, 'PAYME_ONE_TIME_PAYMENT', True)
|
|
62
71
|
)
|
|
63
|
-
self.payme_id = getattr(settings, 'PAYME_ID', '')
|
|
64
|
-
self.payme_key = getattr(settings, 'PAYME_KEY', '')
|
|
65
72
|
|
|
66
73
|
def post(self, request, **_):
|
|
67
74
|
"""
|
|
@@ -580,27 +587,33 @@ class ClickWebhook(View):
|
|
|
580
587
|
def __init__(self, **kwargs):
|
|
581
588
|
super().__init__(**kwargs)
|
|
582
589
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
590
|
+
paytechuz_settings = getattr(settings, 'PAYTECHUZ', {})
|
|
591
|
+
click_settings = paytechuz_settings.get('CLICK', {})
|
|
592
|
+
|
|
593
|
+
account_model_path = (
|
|
594
|
+
click_settings.get('ACCOUNT_MODEL') or
|
|
595
|
+
getattr(settings, 'CLICK_ACCOUNT_MODEL')
|
|
587
596
|
)
|
|
588
597
|
try:
|
|
589
598
|
self.account_model = import_string(account_model_path)
|
|
590
599
|
except ImportError:
|
|
591
|
-
# If the model is not found, log an error and raise an exception
|
|
592
600
|
logger.error(
|
|
593
|
-
"Could not import %s. Check
|
|
601
|
+
"Could not import %s. Check PAYTECHUZ.CLICK.ACCOUNT_MODEL setting.",
|
|
594
602
|
account_model_path
|
|
595
603
|
)
|
|
596
|
-
raise ImportError(
|
|
597
|
-
f"Import error: {account_model_path}"
|
|
598
|
-
) from None
|
|
604
|
+
raise ImportError(f"Import error: {account_model_path}") from None
|
|
599
605
|
|
|
600
|
-
self.service_id =
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
606
|
+
self.service_id = (
|
|
607
|
+
click_settings.get('SERVICE_ID') or
|
|
608
|
+
getattr(settings, 'CLICK_SERVICE_ID', '')
|
|
609
|
+
)
|
|
610
|
+
self.secret_key = (
|
|
611
|
+
click_settings.get('SECRET_KEY') or
|
|
612
|
+
getattr(settings, 'CLICK_SECRET_KEY', '')
|
|
613
|
+
)
|
|
614
|
+
self.commission_percent = (
|
|
615
|
+
click_settings.get('COMMISSION_PERCENT') or
|
|
616
|
+
getattr(settings, 'CLICK_COMMISSION_PERCENT', 0.0)
|
|
604
617
|
)
|
|
605
618
|
|
|
606
619
|
def post(self, request, **_):
|
|
@@ -356,7 +356,7 @@ class PaymeWebhookHandler:
|
|
|
356
356
|
# Check for existing transactions in non-final states
|
|
357
357
|
existing_transactions = self.db.query(PaymentTransaction).filter(
|
|
358
358
|
PaymentTransaction.gateway == PaymentTransaction.PAYME,
|
|
359
|
-
PaymentTransaction.account_id == account.id
|
|
359
|
+
PaymentTransaction.account_id == str(account.id)
|
|
360
360
|
).filter(
|
|
361
361
|
PaymentTransaction.transaction_id != transaction_id
|
|
362
362
|
).all()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paytechuz
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
4
4
|
Summary: Unified Python package for Uzbekistan payment gateways
|
|
5
5
|
Home-page: https://github.com/Muhammadali-Akbarov/paytechuz
|
|
6
6
|
Author: Muhammadali Akbarov
|
|
@@ -17,10 +17,13 @@ Dynamic: requires-python
|
|
|
17
17
|
|
|
18
18
|
[](https://badge.fury.io/py/paytechuz)
|
|
19
19
|
[](https://pypi.org/project/paytechuz/)
|
|
20
|
+
[](https://pay-tech.uz)
|
|
20
21
|
[](https://opensource.org/licenses/MIT)
|
|
21
22
|
|
|
22
23
|
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
|
|
|
25
|
+
📖 **[Complete Documentation](https://pay-tech.uz)** | 🚀 **[Quick Start Guide](https://pay-tech.uz/quickstart)**
|
|
26
|
+
|
|
24
27
|
## Features
|
|
25
28
|
|
|
26
29
|
- 🔄 **API**: Consistent interface for multiple payment providers
|
|
@@ -49,6 +52,8 @@ pip install paytechuz[fastapi]
|
|
|
49
52
|
|
|
50
53
|
## Quick Start
|
|
51
54
|
|
|
55
|
+
> 💡 **Need help?** Check out our [complete documentation](https://pay-tech.uz) for detailed guides and examples.
|
|
56
|
+
|
|
52
57
|
### Generate Payment Links
|
|
53
58
|
|
|
54
59
|
```python
|
|
@@ -121,18 +126,26 @@ INSTALLED_APPS = [
|
|
|
121
126
|
'paytechuz.integrations.django',
|
|
122
127
|
]
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
PAYTECHUZ = {
|
|
130
|
+
'PAYME': {
|
|
131
|
+
'PAYME_ID': 'your_payme_id',
|
|
132
|
+
'PAYME_KEY': 'your_payme_key',
|
|
133
|
+
'ACCOUNT_MODEL': 'your_app.models.Order', # For example: 'orders.models.Order'
|
|
134
|
+
'ACCOUNT_FIELD': 'id',
|
|
135
|
+
'AMOUNT_FIELD': 'amount',
|
|
136
|
+
'ONE_TIME_PAYMENT': True,
|
|
137
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
138
|
+
},
|
|
139
|
+
'CLICK': {
|
|
140
|
+
'SERVICE_ID': 'your_service_id',
|
|
141
|
+
'MERCHANT_ID': 'your_merchant_id',
|
|
142
|
+
'MERCHANT_USER_ID': 'your_merchant_user_id',
|
|
143
|
+
'SECRET_KEY': 'your_secret_key',
|
|
144
|
+
'ACCOUNT_MODEL': 'your_app.models.Order',
|
|
145
|
+
'COMMISSION_PERCENT': 0.0,
|
|
146
|
+
'IS_TEST_MODE': True, # Set to False in production
|
|
147
|
+
}
|
|
148
|
+
}
|
|
136
149
|
```
|
|
137
150
|
|
|
138
151
|
3. Create webhook handlers:
|
|
@@ -313,6 +326,10 @@ Detailed documentation is available in multiple languages:
|
|
|
313
326
|
|
|
314
327
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
315
328
|
|
|
329
|
+
📖 **Documentation:** [pay-tech.uz](https://pay-tech.uz)
|
|
330
|
+
🐛 **Issues:** [GitHub Issues](https://github.com/PayTechUz/paytechuz-py/issues)
|
|
331
|
+
💬 **Support:** [Telegram](https://t.me/paytechuz)
|
|
332
|
+
|
|
316
333
|
## License
|
|
317
334
|
|
|
318
335
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -2,6 +2,15 @@ MANIFEST.in
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
setup.py
|
|
5
|
+
examples/paytechuz_fastapi/__init__.py
|
|
6
|
+
examples/paytechuz_fastapi/main.py
|
|
7
|
+
examples/paytechuz_fastapi/payments.db
|
|
8
|
+
examples/paytechuz_fastapi/run.sh
|
|
9
|
+
examples/paytechuz_fastapi/app/__init__.py
|
|
10
|
+
examples/paytechuz_fastapi/app/database.py
|
|
11
|
+
examples/paytechuz_fastapi/app/models.py
|
|
12
|
+
examples/paytechuz_fastapi/app/typing.py
|
|
13
|
+
examples/paytechuz_fastapi/app/webhook_handlers.py
|
|
5
14
|
src/__init__.py
|
|
6
15
|
src/core/__init__.py
|
|
7
16
|
src/core/base.py
|
|
File without changes
|
|
File without changes
|
{paytechuz-0.2.10/src/gateways → paytechuz-0.2.13/examples/paytechuz_fastapi/app}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paytechuz-0.2.10/src/paytechuz/integrations → paytechuz-0.2.13/src/paytechuz/core}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/migrations/0001_initial.py
RENAMED
|
File without changes
|
{paytechuz-0.2.10 → paytechuz-0.2.13}/src/paytechuz/integrations/django/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|