مثال استفاده از كتابخانه payexa
استفاده از كتابخانه payexa از طريق نصب pip
دانلود ثبت شده
62
آخرین بروزرسانی
2026-09-25
حجم بسته
7.5 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
در این صفحه بسته های آماده برای اتصال به سرویس پرداخت، افزونه های کمکی و مثال های اجرایی را مثل یک ریپازیتوری مرور می کنید: فایل ها را می بینید، README را می خوانید و کل بسته را با یک دانلود می گیرید.
CONTROLLED RELEASE
انتشار کنترل شده از پنل رسمی
هر بسته از مسیر مدیریتی رسمی پی اکسا منتشر می شود و قبل از دانلود، اطلاعات کلیدی آن به صورت شفاف نمایش داده می شود.
PRE-DOWNLOAD VISIBILITY
شفافیت محتوا پیش از دریافت
پیش نمایش README، مرور ساختار فایل و نمایش متادیتای بسته کمک می کند قبل از دانلود، ارزیابی دقیق تری از محتوا داشته باشید.
TRUST PROFILE
نمای رسمی تر برای انتخاب ابزار
صفحه بر پایه شفافیت انتشار، نمایش منبع README، تاریخ بروزرسانی و آمار دانلود چیده شده تا حس ارزیابی حرفه ای تری منتقل کند.
مرجع حقوقی و هویتی کنار دسترس
ساختار صفحه طوری چیده شده که اطلاعات انتشار، محتوای فایل ها و جزئیات هر بسته بدون شلوغی اضافه در دسترس باشند.
استفاده از كتابخانه payexa از طريق نصب pip
دانلود ثبت شده
62
آخرین بروزرسانی
2026-09-25
حجم بسته
7.5 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
پوشه جاری را انتخاب کنید یا برای فایل های متنی پیش نمایش بگیرید.
| نام | نوع | اندازه |
|---|---|---|
| templates | پوشه | - |
| .env.example | دانلودی | 0.2 KB |
| app.py | قابل پیش نمایش | 10.2 KB |
| README.md | قابل پیش نمایش | 1.7 KB |
| requirements.txt | قابل پیش نمایش | 0.0 KB |
app.py
from __future__ import annotations
import os
import sqlite3
from datetime import datetime, timezone
from decimal import Decimal, InvalidOperation
from dotenv import load_dotenv
from flask import Flask, flash, redirect, render_template, request, url_for
from payexa import PayexaAPIError, PayexaClient, PayexaTransportError, PayexaValidationError
def _read_env(name: str, default: str) -> str:
value = str(os.getenv(name, "") or "").strip()
return value or default
def _read_optional_int(name: str) -> int | None:
value = str(os.getenv(name, "") or "").strip()
if not value:
return None
return int(value)
def _resolve_database_path(database_path: str) -> str:
normalized = str(database_path or "").strip()
if not normalized:
return os.path.join(app.instance_path, "wallet.sqlite3")
if os.path.isabs(normalized):
return normalized
return os.path.abspath(os.path.join(app.instance_path, normalized))
load_dotenv()
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("FLASK_SECRET_KEY", "dev-secret-key")
app.config["PAYEXA_BASE_URL"] = _read_env("PAYEXA_BASE_URL", "https://pay.pexn.ir")
app.config["PAYEXA_API_KEY"] = _read_env("PAYEXA_API_KEY", "YOUR_API_KEY")
app.config["PAYEXA_MERCHANT_ID"] = _read_optional_int("PAYEXA_MERCHANT_ID")
app.config["APP_BASE_URL"] = _read_env("APP_BASE_URL", "http://127.0.0.1:5000")
app.config["WALLET_CURRENCY_LABEL"] = _read_env("WALLET_CURRENCY_LABEL", "تومان")
app.config["DATABASE_PATH"] = _resolve_database_path(
_read_env("DATABASE_PATH", os.path.join(app.instance_path, "wallet.sqlite3"))
)
os.makedirs(app.instance_path, exist_ok=True)
@app.get("/")
def index() -> str:
return render_template(
"index.html",
balance=get_wallet_balance(app.config["DATABASE_PATH"]),
currency_label=app.config["WALLET_CURRENCY_LABEL"],
payexa_base_url=app.config["PAYEXA_BASE_URL"],
)
@app.post("/charge")
def charge_wallet():
amount_raw = str(request.form.get("amount") or "").strip()
try:
amount = int(Decimal(amount_raw))
if amount <= 0:
raise ValueError
except (InvalidOperation, ValueError):
flash("مبلغ باید یک عدد صحیح و بزرگتر از صفر باشد.", "error")
return redirect(url_for("index"))
try:
with build_client() as client:
payment = client.request_payment(
amount=amount,
callback_url=build_callback_url(app.config["APP_BASE_URL"]),
merchant_id=app.config["PAYEXA_MERCHANT_ID"],
meta={"source": "test-pypi-flask-demo", "amount": amount},
)
except (PayexaValidationError, PayexaTransportError, PayexaAPIError) as exc:
flash(f"ایجاد درخواست پرداخت ناموفق بود: {exc}", "error")
return redirect(url_for("index"))
save_payment(
database_path=app.config["DATABASE_PATH"],
authority=payment.authority,
order_id=payment.order_id,
amount=amount,
amount_unique_token=payment.amount_unique_token,
start_pay_url=payment.start_pay_url,
)
return redirect(payment.start_pay_url)
@app.get("/callback")
def callback() -> str:
try:
with build_client() as client:
callback_data = client.parse_callback(request.args)
except PayexaValidationError as exc:
return render_template("result.html", ok=False, title="Callback نامعتبر", message=str(exc))
if not callback_data.has_authority:
return render_template(
"result.html",
ok=False,
title="Authority پیدا نشد",
message="پارامتر authority در callback ارسال نشده است.",
)
payment = get_payment_by_authority(app.config["DATABASE_PATH"], callback_data.authority)
if payment is None:
return render_template(
"result.html",
ok=False,
title="تراکنش پیدا نشد",
message="برای این authority هیچ رکوردی در دیتابیس این پروژه وجود ندارد.",
)
if not callback_data.is_ok:
update_payment_status(app.config["DATABASE_PATH"], callback_data.authority, callback_data.normalized_status or "FAILED")
return render_template(
"result.html",
ok=False,
title="پرداخت ناموفق",
message=f"وضعیت callback موفق نبود: {callback_data.normalized_status or 'UNKNOWN'}",
payment=payment,
)
try:
with build_client() as client:
verification = client.verify_payment(
order_id=payment["order_id"],
token=payment["amount_unique_token"],
)
except (PayexaValidationError, PayexaTransportError, PayexaAPIError) as exc:
return render_template(
"result.html",
ok=False,
title="خطا در verify",
message=f"verify انجام نشد: {exc}",
payment=payment,
)
if verification.is_success:
if payment["status"] != "verified":
update_payment_status(app.config["DATABASE_PATH"], callback_data.authority, "verified")
add_wallet_balance(app.config["DATABASE_PATH"], payment["amount"])
payment = get_payment_by_authority(app.config["DATABASE_PATH"], callback_data.authority)
return render_template(
"result.html",
ok=True,
title="شارژ کیف پول موفق",
message="پرداخت verify شد و موجودی کیف پول افزایش یافت.",
payment=payment,
verification_status=verification.normalized_status,
balance=get_wallet_balance(app.config["DATABASE_PATH"]),
currency_label=app.config["WALLET_CURRENCY_LABEL"],
)
update_payment_status(app.config["DATABASE_PATH"], callback_data.authority, verification.normalized_status or "FAILED")
return render_template(
"result.html",
ok=False,
title="verify ناموفق",
message=f"نتیجه verify موفق نبود: {verification.normalized_status or 'UNKNOWN'}",
payment=payment,
)
def build_client() -> PayexaClient:
return PayexaClient(
base_url=app.config["PAYEXA_BASE_URL"],
api_key=app.config["PAYEXA_API_KEY"],
default_merchant_id=app.config["PAYEXA_MERCHANT_ID"],
)
def build_callback_url(app_base_url: str) -> str:
return f"{app_base_url.rstrip('/')}/callback"
def init_db(database_path: str) -> None:
with connect_db(database_path) as connection:
connection.execute(
"""
CREATE TABLE IF NOT EXISTS wallet (
id INTEGER PRIMARY KEY CHECK (id = 1),
balance INTEGER NOT NULL DEFAULT 0
)
"""
)
connection.execute(
"""
CREATE TABLE IF NOT EXISTS payments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
authority TEXT NOT NULL UNIQUE,
order_id TEXT NOT NULL,
amount INTEGER NOT NULL,
amount_unique_token TEXT NOT NULL,
start_pay_url TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
"""
)
connection.execute("INSERT OR IGNORE INTO wallet (id, balance) VALUES (1, 0)")
def save_payment(
database_path: str,
*,
authority: str,
order_id: str,
amount: int,
amount_unique_token: str,
start_pay_url: str,
) -> None:
now = utc_now()
with connect_db(database_path) as connection:
connection.execute(
"""
INSERT INTO payments (
authority,
order_id,
amount,
amount_unique_token,
start_pay_url,
status,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)
ON CONFLICT(authority) DO UPDATE SET
order_id = excluded.order_id,
amount = excluded.amount,
amount_unique_token = excluded.amount_unique_token,
start_pay_url = excluded.start_pay_url,
status = 'pending',
updated_at = excluded.updated_at
""",
(authority, order_id, amount, amount_unique_token, start_pay_url, now, now),
)
def get_payment_by_authority(database_path: str, authority: str) -> dict[str, object] | None:
with connect_db(database_path) as connection:
row = connection.execute(
"""
SELECT authority, order_id, amount, amount_unique_token, start_pay_url, status, created_at, updated_at
FROM payments WHERE authority = ?
""",
(authority,),
).fetchone()
return dict(row) if row is not None else None
def get_wallet_balance(database_path: str) -> int:
with connect_db(database_path) as connection:
row = connection.execute("SELECT balance FROM wallet WHERE id = 1").fetchone()
return int(row[0] if row is not None else 0)
def add_wallet_balance(database_path: str, amount: int) -> None:
with connect_db(database_path) as connection:
connection.execute("UPDATE wallet SET balance = balance + ? WHERE id = 1", (amount,))
def update_payment_status(database_path: str, authority: str, status: str) -> None:
normalized_status = str(status or "failed").strip().casefold() or "failed"
with connect_db(database_path) as connection:
connection.execute(
"UPDATE payments SET status = ?, updated_at = ? WHERE authority = ?",
(normalized_status, utc_now(), authority),
)
def connect_db(database_path: str) -> sqlite3.Connection:
parent_dir = os.path.dirname(os.path.abspath(database_path))
if parent_dir:
os.makedirs(parent_dir, exist_ok=True)
connection = sqlite3.connect(database_path)
connection.row_factory = sqlite3.Row
return connection
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat()
init_db(app.config["DATABASE_PATH"])
if __name__ == "__main__":
app.run(debug=True)منبع: README.md
این پروژه یک دمو ساده Flask برای شارژ کیف پول با استفاده از پکیج payexa از PyPI است.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
cp .env.example .env
مقادیر مهم در .env:
PAYEXA_BASE_URL=https://pay.pexn.irPAYEXA_API_KEY=YOUR_API_KEYPAYEXA_MERCHANT_ID=APP_BASE_URL=http://127.0.0.1:5000اگر DATABASE_PATH خالی باشد، پروژه از instance/wallet.sqlite3 استفاده می کند.
source .venv/bin/activate
python app.py
بعد از اجرا اپ روی آدرس زیر در دسترس است:
http://127.0.0.1:5000
PayexaClient درخواست پرداخت می سازد.parse_callback و سپس verify_payment را اجرا می کند..venv/bin/python -c "from payexa import PayexaClient; print(PayexaClient)"
.venv/bin/python -c "from app import app; client = app.test_client(); print(client.get('/').status_code)"
برای callback واقعی، مقدار APP_BASE_URL باید از بیرون قابل دسترسی باشد. اگر روی localhost اجرا می کنید، فقط بخش local flow را راحت تست می کنید.
من دستیار پی اکسا هستم، شما را در تمام مسیر راهنمایی میکنم و اگر به من نیازی ندارید با ۲ بار کلیک خاموش میشوم.