58 lines
2.5 KiB
Python
58 lines
2.5 KiB
Python
# apps/billing/providers/dynamic_discount.py
|
|
"""
|
|
تولید توکن «تخفیف پویا» کافهبازار
|
|
(developers.cafebazaar.ir/fa/guidelines/in-app-billing/dynamic-discount).
|
|
|
|
فقط یک تابع خام است، بدون endpoint/کمپین — چون فعلا کمپین تخفیف مشخصی در
|
|
کار نیست؛ هر وقت لازم شد (مثلا یک ویو که برای یک GemPack با قیمت پایینتر
|
|
توکن میسازد)، همین تابع را صدا بزن. کلید امضا (BazaarSettings.
|
|
dynamic_discount_secret) عمدا فقط همینجا (سمت سرور) استفاده میشود و
|
|
هیچوقت نباید به کلاینت/اپ فلاتر فرستاده شود — طبق مستندات، ذخیرهی این کلید
|
|
در اپ یعنی افشای آن، و کافهبازار مسئولیتی در قبال سوءاستفاده نمیپذیرد.
|
|
|
|
خروجی این تابع مستقیم در فیلد dynamicPriceToken کلاس PurchaseRequest
|
|
(سمت اپ، هنگام FlutterPoolakey.purchase) استفاده میشود.
|
|
"""
|
|
|
|
import time
|
|
import uuid
|
|
|
|
import jwt
|
|
|
|
from apps.billing.models import BazaarSettings
|
|
|
|
|
|
class DynamicDiscountNotConfigured(Exception):
|
|
"""کلید امضای تخفیف پویا در BazaarSettings تنظیم نشده."""
|
|
|
|
|
|
def generate_dynamic_discount_token(
|
|
*,
|
|
sku: str,
|
|
price_rial: int,
|
|
ttl_seconds: int = 300,
|
|
account_id: str | None = None,
|
|
) -> str:
|
|
"""یک توکن یکبارمصرف طبق مشخصات مستندات کافهبازار میسازد.
|
|
|
|
price_rial باید <= قیمت ثبتشدهی همین sku در پنل پیشخان باشد، وگرنه
|
|
کافهبازار خودش موقع خرید خطای «قیمت بیش از حد مجاز» (کد ۱۰) برمیگرداند."""
|
|
settings_obj = BazaarSettings.get_solo()
|
|
if not settings_obj.dynamic_discount_secret or not settings_obj.package_name:
|
|
raise DynamicDiscountNotConfigured(
|
|
"dynamic_discount_secret یا package_name در تنظیمات کافهبازار خالی است."
|
|
)
|
|
|
|
now = int(time.time())
|
|
payload = {
|
|
"price": price_rial,
|
|
"package_name": settings_obj.package_name,
|
|
"sku": sku,
|
|
"exp": now + ttl_seconds,
|
|
"nonce": uuid.uuid4().hex,
|
|
}
|
|
if account_id:
|
|
payload["account_id"] = account_id
|
|
|
|
return jwt.encode(payload, settings_obj.dynamic_discount_secret, algorithm="HS256")
|