Bazaar: subscriptions (10343/10344), dynamic price (discount codes on Bazaar), auto-renewal sync
- Purchase with paymentMethod=bazaar now works for subscription plans with a bazaar_sku (not only packs);
response carries bazaarProductType. Migration subscription.0014 puts 10343/10344 on the 90/180-day plans.
- Verify asks Bazaar for the right product type (from the order) and stores validUntil (payment.0012).
- POST /api/payment/bazaar/orders/{id}/start: SKU, type, and an HS256 dynamic-price JWT when a discount
code lowered the price (BAZAAR_DYNAMIC_PRICE_KEY); discount on Bazaar orders allowed only with that key
and only before start.
- Auto-renewal: sync_bazaar_renewals re-asks Bazaar when the paid period is near its end (status page and
the paywall via has_subscription_access); each new period becomes a paid order.
- Default BAZAAR_PACKAGE_NAME = com.tadrisino.math.app; health shows bazaarDynamicPrice.
979 tests green. No real Bazaar purchase or renewal tested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -559,6 +559,8 @@ REST_FRAMEWORK = {
|
||||
# را سقفِ هر کد (OTP_MAX_FAILED_ATTEMPTS=۵، در دیتابیس) و هر شماره میبندد، نه این.
|
||||
'otp_login': os.environ.get('OTP_LOGIN_IP_RATE', '300/hour'),
|
||||
'bazaar_verify': '10/hour',
|
||||
# شروعِ خریدِ بازار (امضای قیمت)؛ بیفراخوانیِ بیرونی، ولی هر بار یک توکنِ تازه.
|
||||
'bazaar_start': '30/hour',
|
||||
'bazaar_oauth': '20/hour',
|
||||
'ai_ask': '20/hour',
|
||||
'rag_ingest': '30/hour',
|
||||
@@ -697,6 +699,7 @@ SPECTACULAR_SETTINGS = {
|
||||
'ENUM_NAME_OVERRIDES': {
|
||||
'LessonKindEnum': [('quiz', 'quiz'), ('video', 'video')],
|
||||
'PlanKindEnum': [('pack', 'pack'), ('subscription', 'subscription')],
|
||||
'BazaarProductTypeEnum': [('inapp', 'inapp'), ('subscription', 'subscription')],
|
||||
},
|
||||
'SWAGGER_UI_SETTINGS': {
|
||||
'deepLinking': True,
|
||||
@@ -884,7 +887,9 @@ INTERNAL_SERVICE_KEY = os.environ.get('INTERNAL_SERVICE_KEY', '')
|
||||
# گرفته میشه، بعد بکاند با همون REFRESH_TOKEN، ACCESS_TOKEN تازه میگیره.
|
||||
# قبل از اتصال واقعی، مسیرِ endpointها رو از پنل devapi تایید کنید — بازار
|
||||
# این روش رو قبلاً تغییر داده.
|
||||
BAZAAR_PACKAGE_NAME = os.environ.get('BAZAAR_PACKAGE_NAME', 'ir.tadrisino.app')
|
||||
# applicationIdِ APK و پکیجِ پیشخان (com.tadrisino.math.app روی سرور؛ ۲۰۲۶-۱۰-۱۲ بازار محصولهای ۱۰۳۴۲–۱۰۳۴۴ را
|
||||
# زیرِ همین نام شناخت). پیشفرض همان است تا لپتاپ و سرور یکی باشند.
|
||||
BAZAAR_PACKAGE_NAME = os.environ.get('BAZAAR_PACKAGE_NAME', 'com.tadrisino.math.app')
|
||||
BAZAAR_CLIENT_ID = os.environ.get('BAZAAR_CLIENT_ID', '')
|
||||
BAZAAR_CLIENT_SECRET = os.environ.get('BAZAAR_CLIENT_SECRET', '')
|
||||
BAZAAR_REFRESH_TOKEN = os.environ.get('BAZAAR_REFRESH_TOKEN', '')
|
||||
@@ -900,6 +905,11 @@ BAZAAR_REDIRECT_URI = (
|
||||
os.environ.get('BAZAAR_REDIRECT_URI', '').strip()
|
||||
or f'{PUBLIC_BASE_URL}/api/payment/bazaar/verify'
|
||||
)
|
||||
# کلیدِ «تخفیف پویا» از پیشخانِ بازار (پرداخت درونبرنامهای ← تخفیف پویا). با آن سرور برای هر خرید
|
||||
# یک JWTِ یکبارمصرف امضا میکند که قیمتِ همان سفارش (پس از کدِ تخفیف) را به بازار میگوید؛ پس قیمتِ
|
||||
# ادمین ملاک است، نه قیمتِ پیشخان (که باید از آن کمتر نباشد). بیآن بازار قیمتِ پیشخان را میگیرد و
|
||||
# کدِ تخفیف روی سفارشِ بازار ۴۰۰ است. فقط سمتِ سرور؛ هرگز در اپ.
|
||||
BAZAAR_DYNAMIC_PRICE_KEY = os.environ.get('BAZAAR_DYNAMIC_PRICE_KEY', '').strip()
|
||||
# چند ساعت لینکِ «اجازه»ی بازار باز میماند؛ بعد از اتصالِ موفق خودش بسته میشود.
|
||||
BAZAAR_AUTHORIZE_WINDOW_HOURS = int(os.environ.get('BAZAAR_AUTHORIZE_WINDOW_HOURS', '72'))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user