finopal-py-sdk 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.
- finopal_py_sdk-0.1.0/LICENSE +21 -0
- finopal_py_sdk-0.1.0/PKG-INFO +428 -0
- finopal_py_sdk-0.1.0/README.md +391 -0
- finopal_py_sdk-0.1.0/pyproject.toml +59 -0
- finopal_py_sdk-0.1.0/setup.cfg +4 -0
- finopal_py_sdk-0.1.0/src/finopal/__init__.py +106 -0
- finopal_py_sdk-0.1.0/src/finopal/errors/__init__.py +17 -0
- finopal_py_sdk-0.1.0/src/finopal/errors/exceptions.py +124 -0
- finopal_py_sdk-0.1.0/src/finopal/finopal.py +140 -0
- finopal_py_sdk-0.1.0/src/finopal/http/__init__.py +6 -0
- finopal_py_sdk-0.1.0/src/finopal/http/client.py +69 -0
- finopal_py_sdk-0.1.0/src/finopal/http/transport.py +176 -0
- finopal_py_sdk-0.1.0/src/finopal/models.py +224 -0
- finopal_py_sdk-0.1.0/src/finopal/py.typed +0 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/__init__.py +9 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/fees.py +70 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/inquiries.py +77 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/payments.py +168 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/reversals.py +68 -0
- finopal_py_sdk-0.1.0/src/finopal/resources/verifications.py +120 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/__init__.py +41 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/amount.py +72 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/callback.py +102 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/config.py +87 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/enums.py +66 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/error_codes.py +101 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/response.py +75 -0
- finopal_py_sdk-0.1.0/src/finopal/utils/validator.py +172 -0
- finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/PKG-INFO +428 -0
- finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/SOURCES.txt +40 -0
- finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/dependency_links.txt +1 -0
- finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/requires.txt +14 -0
- finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/top_level.txt +1 -0
- finopal_py_sdk-0.1.0/tests/test_config.py +104 -0
- finopal_py_sdk-0.1.0/tests/test_fees.py +52 -0
- finopal_py_sdk-0.1.0/tests/test_inquiries.py +65 -0
- finopal_py_sdk-0.1.0/tests/test_payments.py +182 -0
- finopal_py_sdk-0.1.0/tests/test_reversals.py +63 -0
- finopal_py_sdk-0.1.0/tests/test_transport.py +127 -0
- finopal_py_sdk-0.1.0/tests/test_utils.py +130 -0
- finopal_py_sdk-0.1.0/tests/test_validator.py +138 -0
- finopal_py_sdk-0.1.0/tests/test_verifications.py +86 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FinoPal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: finopal-py-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the FinoPal online payment gateway (درگاه پرداخت اینترنتی فینوپال)
|
|
5
|
+
Author-email: FinoPal <support@finopal.ir>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Documentation, https://finopal.ir/docs
|
|
8
|
+
Project-URL: Repository, https://github.com/FinoPal-Lab/finopal-python-sdk
|
|
9
|
+
Keywords: finopal,payment,payment-gateway,psp,shaparak,iran,درگاه پرداخت,پرداخت یاری
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Natural Language :: Persian
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.28.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
29
|
+
Requires-Dist: requests-mock>=1.11; extra == "dev"
|
|
30
|
+
Provides-Extra: flask
|
|
31
|
+
Requires-Dist: flask>=2.3; extra == "flask"
|
|
32
|
+
Provides-Extra: django
|
|
33
|
+
Requires-Dist: django>=4.2; extra == "django"
|
|
34
|
+
Provides-Extra: fastapi
|
|
35
|
+
Requires-Dist: fastapi>=0.110; extra == "fastapi"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# FinoPal Python SDK
|
|
39
|
+
|
|
40
|
+
کیت توسعهی پایتون برای **درگاه پرداخت اینترنتی فینوپال** — نوشتهشده بر اساس
|
|
41
|
+
[مستندات رسمی فینوپال](https://finopal.ir/docs).
|
|
42
|
+
|
|
43
|
+
معماری این SDK از [Zarinpal Python SDK](https://github.com/ZarinPal/Zarinpal-Python-Sdk)
|
|
44
|
+
الگو گرفته است (یک کلاینت، منابع تنبلساز، متدهای `create` / `verify` / `inquire` /
|
|
45
|
+
`reverse` / `calculate`) اما API آن دقیقاً همان چیزی است که فینوپال ارائه میدهد و
|
|
46
|
+
با SDK موجود PHP در افزونهی ووکامرس همین پروژه (`finopay-plugins/finopal-woocommerce`)
|
|
47
|
+
همخوان است.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install finopal-py-sdk
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
تا زمان انتشار روی PyPI، بسته را از همین پوشه نصب کنید:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install .
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## فهرست
|
|
62
|
+
|
|
63
|
+
- [نصب](#نصب)
|
|
64
|
+
- [شروع سریع](#شروع-سریع)
|
|
65
|
+
- [جریان کامل پرداخت](#جریان-کامل-پرداخت)
|
|
66
|
+
- [منابع API](#منابع-api)
|
|
67
|
+
- [حالت Sandbox](#حالت-sandbox)
|
|
68
|
+
- [تبدیل مبلغ (تومان ↔ ریال)](#تبدیل-مبلغ-تومان--ریال)
|
|
69
|
+
- [مدیریت خطا](#مدیریت-خطا)
|
|
70
|
+
- [کدهای خطا](#کدهای-خطا)
|
|
71
|
+
- [تستها](#تستها)
|
|
72
|
+
- [ساختار پروژه](#ساختار-پروژه)
|
|
73
|
+
- [English summary](#english-summary)
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## نصب
|
|
78
|
+
|
|
79
|
+
نیازمندی: **Python 3.9+** و `pip`. وابستگی زمان اجرا بستهی `requests` است.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install finopal-py-sdk
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
یا:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip3 install finopal-py-sdk
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
تا زمان انتشار روی PyPI:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install .
|
|
95
|
+
# حالت توسعه، همراه با تستها
|
|
96
|
+
pip install -e ".[dev]"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
برای اجرای مثال Flask:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pip install ".[flask]"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## شروع سریع
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from finopal import FinoPal, Config
|
|
111
|
+
|
|
112
|
+
finopal = FinoPal(Config(
|
|
113
|
+
merchant_id="fino-xxxx-xxxx-xxxx-xxxx", # از پنل کاربری فینوپال
|
|
114
|
+
sandbox=True, # برای محیط آزمایشی
|
|
115
|
+
))
|
|
116
|
+
|
|
117
|
+
payment = finopal.payments.create({
|
|
118
|
+
"amount": 1_100, # مبلغ به ریال
|
|
119
|
+
"callback_url": "https://shop.example.com/payment/callback",
|
|
120
|
+
"order_id": "ORD-1001",
|
|
121
|
+
"description": "خرید شماره ۱۰۰۱",
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
print(payment.authority) # FP_636E4A5CBBCE0F222B46829BD74AB4A9
|
|
125
|
+
print(payment.payment_url) # کاربر را به این آدرس هدایت کنید
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
هر پاسخ، همزمان با دسترسی دیکشنری و هم با دسترسی ویژگی قابل استفاده است و
|
|
129
|
+
پیلود خام گیتوی همیشه در `raw` نگه داشته میشود:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
payment.authority # → "FP_636E..."
|
|
133
|
+
payment["authority"] # → "FP_636E..."
|
|
134
|
+
payment.raw # → {"success": True, "code": 100, "data": {...}}
|
|
135
|
+
payment.is_successful # → True
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## جریان کامل پرداخت
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
┌──────────┐ 1. request ┌────────────┐
|
|
144
|
+
│ سایت شما │ ───────────────▶│ فینوپال │
|
|
145
|
+
└──────────┘ authority + └────────────┘
|
|
146
|
+
│ payment_url │
|
|
147
|
+
│ 2. هدایت کاربر (302) │
|
|
148
|
+
└─────────────────────────────▶│ صفحه پرداخت
|
|
149
|
+
│
|
|
150
|
+
┌──────────┐ 3. callback ┌──────┴─────┐
|
|
151
|
+
│ سایت شما │ ◀───────────────│ فینوپال │
|
|
152
|
+
└──────────┘ ?Authority=.. └────────────┘
|
|
153
|
+
│ &Status=OK
|
|
154
|
+
│ 4. verify (فقط اگر Status=OK باشد)
|
|
155
|
+
└─────────────────────────────▶ ref_id
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### ۱) ساخت درخواست پرداخت
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
payment = finopal.payments.create({
|
|
162
|
+
"amount": 120_000, # ریال — الزامی
|
|
163
|
+
"callback_url": "...", # الزامی، باید با دامنهی ثبتشده یکی باشد
|
|
164
|
+
"order_id": "ORD-1001", # الزامی
|
|
165
|
+
"description": "...", # الزامی، حداکثر ۲۵۵ کاراکتر
|
|
166
|
+
"mobile": "09121234567", # اختیاری
|
|
167
|
+
"email": "a@b.com", # اختیاری
|
|
168
|
+
"metadata": {"user_id": "960", "product_id": "123"},
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
redirect(payment.payment_url) # کاربر را هدایت کنید
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
میانبر با آرگومانهای کلیدواژهای:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
payment = finopal.payments.request(
|
|
178
|
+
amount=120_000,
|
|
179
|
+
callback_url="https://shop.example.com/callback",
|
|
180
|
+
order_id="ORD-1001",
|
|
181
|
+
)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### ۲) بازگشت کاربر و تأیید (verify)
|
|
185
|
+
|
|
186
|
+
فینوپال کاربر را با کوئریاسترینگ برمیگرداند. قالب پارامترها در محیط واقعی و
|
|
187
|
+
آزمایشی متفاوت است و `parse_callback` هر دو را یکسان میکند:
|
|
188
|
+
|
|
189
|
+
| محیط | کوئریاسترینگ | نشانهی موفقیت |
|
|
190
|
+
|---|---|---|
|
|
191
|
+
| واقعی | `?Authority=...&Status=OK` | `Status=OK` |
|
|
192
|
+
| آزمایشی | `?authority=...&status=0&sandbox=1` | `status=0` |
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from finopal import parse_callback
|
|
196
|
+
|
|
197
|
+
cb = parse_callback(request.args)
|
|
198
|
+
|
|
199
|
+
if not cb.is_success:
|
|
200
|
+
return render_template("payment_failed.html")
|
|
201
|
+
|
|
202
|
+
result = finopal.verifications.verify({
|
|
203
|
+
"authority": cb.authority,
|
|
204
|
+
"amount": order.amount_rial, # دقیقاً همان مبلغ مرحلهی اول
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
print(result.ref_id) # شماره تراکنش برای نمایش به کاربر
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
> **مهم:** متد `verify` را فقط زمانی صدا بزنید که `Status=OK` (یا در سندباکس
|
|
211
|
+
> `status=0`) باشد. کد `100` یعنی «تازه تأیید شد» و کد `101` یعنی «قبلاً تأیید
|
|
212
|
+
> شده بود» — **هر دو یعنی پرداخت موفق است**.
|
|
213
|
+
|
|
214
|
+
### ۳) استعلام (اختیاری ولی توصیهشده)
|
|
215
|
+
|
|
216
|
+
اگر `verify` با خطای شبکه برگشت، **هرگز** دوباره درخواست پرداخت نسازید؛ وضعیت
|
|
217
|
+
واقعی را استعلام کنید:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
status = finopal.inquiries.inquire({"authority": cb.authority})
|
|
221
|
+
print(status.status) # pending | successful | failed | cancelled | refunded | callback
|
|
222
|
+
print(status.is_paid) # True فقط وقتی status == "successful"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### ۴) ریورس (لغو تراکنش تأییدشده)
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
finopal.reversals.reverse({"authority": "FP_636E4A5C..."})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
- فقط روی تراکنش **verifyشده** و در بازهی کوتاه (۱۵ دقیقه بر اساس مستندات) کار میکند.
|
|
232
|
+
- بعد از موفقیت، وضعیت تراکنش `refunded` میشود و تکرار درخواست خطای `-1551` میدهد.
|
|
233
|
+
- انقضای مهلت → خطای `-1552`.
|
|
234
|
+
|
|
235
|
+
### ۵) محاسبه کارمزد (قبل از پرداخت)
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
fee = finopal.fees.calculate({"amount": 1_000_000})
|
|
239
|
+
print(fee.fee, fee.fee_type) # 20000 Merchant
|
|
240
|
+
print(fee.is_paid_by_customer) # False → کارمزد روی پذیرنده است
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## منابع API
|
|
246
|
+
|
|
247
|
+
| منبع | متدها | اندپوینت |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| `finopal.payments` | `create()` / `request()` / `redirect_url()` | `POST /api/v1/payment/request` |
|
|
250
|
+
| `finopal.verifications` | `verify()` / `verify_authority()` / `is_verified()` | `POST /api/v1/payment/verify` |
|
|
251
|
+
| `finopal.inquiries` | `inquire()` / `status_of()` | `POST /api/v1/payment/inquiry` |
|
|
252
|
+
| `finopal.reversals` | `reverse()` / `reverse_authority()` | `POST /api/v1/payment/reverse` |
|
|
253
|
+
| `finopal.fees` | `calculate()` / `calculate_amount()` | `POST /api/v1/payment/feeCalculation` |
|
|
254
|
+
|
|
255
|
+
اندپوینت جدیدی که هنوز پوشش داده نشده است:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
finopal.request("POST", "/api/v1/payment/anything", {"foo": "bar"})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## حالت Sandbox
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
Config(merchant_id="...", sandbox=True) # → https://sandbox.finopal.ir
|
|
267
|
+
Config(merchant_id="...") # → https://payment.finopal.ir
|
|
268
|
+
Config(merchant_id="...", base_url="http://localhost:8000") # میزبان دلخواه
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
ساختار API در سندباکس یکسان است؛ فقط مقصد نهایی بانک شبیهسازی میشود. در صفحهی
|
|
272
|
+
آزمایشی میتوانید نتیجه را انتخاب کنید:
|
|
273
|
+
|
|
274
|
+
| دکمه | نتیجه در Callback |
|
|
275
|
+
|---|---|
|
|
276
|
+
| پرداخت موفق | `Status=0` / `status=OK` |
|
|
277
|
+
| پرداخت ناموفق | `Status=-1` / `status=NOK` |
|
|
278
|
+
| انصراف | `status=-138` |
|
|
279
|
+
|
|
280
|
+
مدت اعتبار نشست سندباکس ۱۰ دقیقه است.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## تبدیل مبلغ (تومان ↔ ریال)
|
|
285
|
+
|
|
286
|
+
فینوپال همهی مبلغها را **ریال و بهصورت عدد صحیح** میپذیرد. برای جلوگیری از
|
|
287
|
+
اشتباه ضریب ده، از این توابع استفاده کنید:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from finopal import to_rial, to_toman
|
|
291
|
+
|
|
292
|
+
to_rial(12_000, "TOMAN") # → 120000
|
|
293
|
+
to_rial(5, "IRHT") # → 50000 (هزار تومان)
|
|
294
|
+
to_rial(1_100) # → 1100 (پیشفرض ریال)
|
|
295
|
+
to_toman(120_000) # → 12000.0
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
مبالغ مجاز: حداقل `1,000` ریال و حداکثر `1,000,000,000` ریال (۱۰۰ میلیون تومان).
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## مدیریت خطا
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
from finopal import FinoPalError, FinoPalException, ValidationError, TransportError
|
|
306
|
+
|
|
307
|
+
try:
|
|
308
|
+
result = finopal.verifications.verify({"authority": authority, "amount": amount})
|
|
309
|
+
except ValidationError as exc:
|
|
310
|
+
# ورودی نامعتبر — هیچ درخواستی به گیتوی ارسال نشده است
|
|
311
|
+
...
|
|
312
|
+
except FinoPalException as exc:
|
|
313
|
+
# گیتوی پاسخ success=false یا کد غیر ۱۰۰ داده است
|
|
314
|
+
print(exc.code, exc.message, exc.describe(), exc.scope)
|
|
315
|
+
except TransportError as exc:
|
|
316
|
+
# خطای شبکه / پاسخ غیر JSON / خطای 5xx — نتیجه نامعلوم است
|
|
317
|
+
# → قبل از هر تصمیمی استعلام بگیرید
|
|
318
|
+
print(exc.status_code, exc.message)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
| کلاس | معنا |
|
|
322
|
+
|---|---|
|
|
323
|
+
| `ValidationError` | اعتبارسنجی سمت کلاینت؛ درخواستی ارسال نشده است |
|
|
324
|
+
| `FinoPalException` | گیتوی درخواست را رد کرده؛ دارای `code` و `message` |
|
|
325
|
+
| `TransportError` | عدم دسترسی به گیتوی یا پاسخ نامعتبر؛ دارای `status_code` |
|
|
326
|
+
|
|
327
|
+
`describe()` توضیح انگلیسی کد خطا را از فهرست رسمی برمیگرداند و `scope` مشخص
|
|
328
|
+
میکند کد مربوط به کدام بخش API است (`PaymentRequest`، `PaymentVerify`، ...).
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## کدهای خطا
|
|
333
|
+
|
|
334
|
+
فهرست کامل در `src/finopal/utils/error_codes.py` قرار دارد. مهمترینها:
|
|
335
|
+
|
|
336
|
+
| کد | توضیح |
|
|
337
|
+
|---|---|
|
|
338
|
+
| `100` | عملیات موفق |
|
|
339
|
+
| `101` | تراکنش قبلاً تأیید شده است (پرداخت موفق است) |
|
|
340
|
+
| `-9` | خطای اعتبارسنجی (مرچنتکد، callback، توضیحات، مبلغ) |
|
|
341
|
+
| `-10` | مرچنتکد یا آیپی پذیرنده صحیح نیست |
|
|
342
|
+
| `-11` | مرچنتکد فعال نیست / تراکنش یافت نشد |
|
|
343
|
+
| `-13` | محدودیت تراکنش ترمینال |
|
|
344
|
+
| `-14` | دامنهی callback با دامنهی ثبتشده مغایرت دارد |
|
|
345
|
+
| `-15` | درگاه در حالت تعلیق |
|
|
346
|
+
| `-16` / `-17` | سطح تأیید پذیرنده نامعتبر / محدودیت سطح آبی |
|
|
347
|
+
| `-18` | عدم تطابق آدرس referrer با دامنهی ثبتشده |
|
|
348
|
+
| `-19` | ایجاد تراکنش برای این ترمینال مجاز نیست |
|
|
349
|
+
| `-30` … `-41` | خطاهای ساخت درخواست پرداخت (تسهیم، کارمزد، سقف مبلغ) |
|
|
350
|
+
| `-50` | مبلغ وریفای با مبلغ پرداختشده یکسان نیست |
|
|
351
|
+
| `-51` | پرداخت ناموفق / نشست فعال نیست |
|
|
352
|
+
| `-53` | پرداخت متعلق به این مرچنتکد نیست |
|
|
353
|
+
| `-54` | authority نامعتبر |
|
|
354
|
+
| `-55` | تراکنش مورد نظر یافت نشد |
|
|
355
|
+
| `-60` … `-63` | خطاهای ریورس |
|
|
356
|
+
| `-1551` | تراکنش قبلاً برگشت داده شده است |
|
|
357
|
+
| `-1552` | تراکنش verify نشده یا مهلت ریورس تمام شده است |
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## تستها
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
pip install -e ".[dev]"
|
|
365
|
+
pytest
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
مجموعهی تست آفلاین و قطعی است: کلاس `FakeGateway` (در `tests/conftest.py`) نقش
|
|
369
|
+
گیتوی را بازی میکند و لایهی HTTP واقعی هم با `requests_mock` تست میشود.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## ساختار پروژه
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
finopal-python-sdk/
|
|
377
|
+
├── src/finopal/
|
|
378
|
+
│ ├── __init__.py # API عمومی
|
|
379
|
+
│ ├── finopal.py # کلاس FinoPal (ورودی اصلی)
|
|
380
|
+
│ ├── models.py # پاسخهای نرمالشده (ApiResponse و ...)
|
|
381
|
+
│ ├── errors/exceptions.py # سلسلهمراتب خطاها
|
|
382
|
+
│ ├── http/
|
|
383
|
+
│ │ ├── transport.py # Transport، RequestsTransport، CallableTransport
|
|
384
|
+
│ │ └── client.py # HttpClient
|
|
385
|
+
│ ├── resources/ # payments, verifications, inquiries, reversals, fees
|
|
386
|
+
│ └── utils/ # config, validator, amount, callback, error_codes, enums
|
|
387
|
+
├── examples/ # ۶ مثال قابل اجرا (شامل جریان کامل Flask)
|
|
388
|
+
└── tests/ # pytest + FakeGateway
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## English summary
|
|
394
|
+
|
|
395
|
+
A Python SDK for the [FinoPal](https://finopal.ir/docs) online payment gateway,
|
|
396
|
+
modelled on the ZarinPal Python SDK and consistent with the FinoPal WooCommerce
|
|
397
|
+
plugin already in this repository.
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
from finopal import FinoPal, Config, parse_callback, to_rial
|
|
401
|
+
|
|
402
|
+
finopal = FinoPal(Config(merchant_id="fino-xxxx-xxxx-xxxx-xxxx", sandbox=True))
|
|
403
|
+
|
|
404
|
+
payment = finopal.payments.create({
|
|
405
|
+
"amount": to_rial(12_000, "TOMAN"),
|
|
406
|
+
"callback_url": "https://shop.example.com/callback",
|
|
407
|
+
"order_id": "ORD-1001",
|
|
408
|
+
})
|
|
409
|
+
# -> redirect the buyer to payment.payment_url
|
|
410
|
+
|
|
411
|
+
cb = parse_callback(request.args)
|
|
412
|
+
if cb.is_success:
|
|
413
|
+
result = finopal.verifications.verify({
|
|
414
|
+
"authority": cb.authority,
|
|
415
|
+
"amount": 120_000,
|
|
416
|
+
})
|
|
417
|
+
print(result.ref_id)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Coverage:** `request`, `verify`, `inquiry`, `reverse`, `feeCalculation`.
|
|
421
|
+
**Extras:** Rial/Toman conversion, live+sandbox callback normalisation, the full
|
|
422
|
+
published error catalogue, pluggable transports, and a fully offline test suite.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## مجوز
|
|
427
|
+
|
|
428
|
+
MIT — see [LICENSE](LICENSE).
|