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.
Files changed (42) hide show
  1. finopal_py_sdk-0.1.0/LICENSE +21 -0
  2. finopal_py_sdk-0.1.0/PKG-INFO +428 -0
  3. finopal_py_sdk-0.1.0/README.md +391 -0
  4. finopal_py_sdk-0.1.0/pyproject.toml +59 -0
  5. finopal_py_sdk-0.1.0/setup.cfg +4 -0
  6. finopal_py_sdk-0.1.0/src/finopal/__init__.py +106 -0
  7. finopal_py_sdk-0.1.0/src/finopal/errors/__init__.py +17 -0
  8. finopal_py_sdk-0.1.0/src/finopal/errors/exceptions.py +124 -0
  9. finopal_py_sdk-0.1.0/src/finopal/finopal.py +140 -0
  10. finopal_py_sdk-0.1.0/src/finopal/http/__init__.py +6 -0
  11. finopal_py_sdk-0.1.0/src/finopal/http/client.py +69 -0
  12. finopal_py_sdk-0.1.0/src/finopal/http/transport.py +176 -0
  13. finopal_py_sdk-0.1.0/src/finopal/models.py +224 -0
  14. finopal_py_sdk-0.1.0/src/finopal/py.typed +0 -0
  15. finopal_py_sdk-0.1.0/src/finopal/resources/__init__.py +9 -0
  16. finopal_py_sdk-0.1.0/src/finopal/resources/fees.py +70 -0
  17. finopal_py_sdk-0.1.0/src/finopal/resources/inquiries.py +77 -0
  18. finopal_py_sdk-0.1.0/src/finopal/resources/payments.py +168 -0
  19. finopal_py_sdk-0.1.0/src/finopal/resources/reversals.py +68 -0
  20. finopal_py_sdk-0.1.0/src/finopal/resources/verifications.py +120 -0
  21. finopal_py_sdk-0.1.0/src/finopal/utils/__init__.py +41 -0
  22. finopal_py_sdk-0.1.0/src/finopal/utils/amount.py +72 -0
  23. finopal_py_sdk-0.1.0/src/finopal/utils/callback.py +102 -0
  24. finopal_py_sdk-0.1.0/src/finopal/utils/config.py +87 -0
  25. finopal_py_sdk-0.1.0/src/finopal/utils/enums.py +66 -0
  26. finopal_py_sdk-0.1.0/src/finopal/utils/error_codes.py +101 -0
  27. finopal_py_sdk-0.1.0/src/finopal/utils/response.py +75 -0
  28. finopal_py_sdk-0.1.0/src/finopal/utils/validator.py +172 -0
  29. finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/PKG-INFO +428 -0
  30. finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/SOURCES.txt +40 -0
  31. finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/dependency_links.txt +1 -0
  32. finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/requires.txt +14 -0
  33. finopal_py_sdk-0.1.0/src/finopal_py_sdk.egg-info/top_level.txt +1 -0
  34. finopal_py_sdk-0.1.0/tests/test_config.py +104 -0
  35. finopal_py_sdk-0.1.0/tests/test_fees.py +52 -0
  36. finopal_py_sdk-0.1.0/tests/test_inquiries.py +65 -0
  37. finopal_py_sdk-0.1.0/tests/test_payments.py +182 -0
  38. finopal_py_sdk-0.1.0/tests/test_reversals.py +63 -0
  39. finopal_py_sdk-0.1.0/tests/test_transport.py +127 -0
  40. finopal_py_sdk-0.1.0/tests/test_utils.py +130 -0
  41. finopal_py_sdk-0.1.0/tests/test_validator.py +138 -0
  42. 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).