Payment providers as classes (Strategy + factory); 10342 = monthly; health logs a failed Bazaar check
- payment/providers.py: ZarinpalProvider / BazaarProvider with one interface (check_plan, sku_for, payment_url, purchase_extras, discount_blocker, reconcile_user); provider_for / provider_for_method pick one; unknown fails. create_order, purchase view, discount redeem and reconcile_user_orders use it instead of scattered ifs. - subscription.0015: Bazaar SKU 10342 on the one-month plan (owner: "probably the monthly one"). - config/health: the Bazaar check no longer swallows its exception without a log. 982 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ from rest_framework.exceptions import APIException
|
||||
from statuslog.signals import status_changed
|
||||
|
||||
from .models import Order, Transaction
|
||||
from .providers import PROVIDERS, provider_for
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -102,7 +103,7 @@ def create_order(*, user_id: int, amount: int, currency: str = 'IRT',
|
||||
existing, user_id=user_id, amount=amount, currency=currency,
|
||||
subscription_id=subscription_id, plan_id=plan_id, provider=provider,
|
||||
)
|
||||
payment_url = None if existing.provider == 'bazaar' else call_payment_gateway(existing)
|
||||
payment_url = provider_for(existing.provider).payment_url(existing)
|
||||
return existing, payment_url
|
||||
|
||||
from subscription.models import Plan
|
||||
@@ -136,9 +137,8 @@ def create_order(*, user_id: int, amount: int, currency: str = 'IRT',
|
||||
subscription_id=subscription_id, plan_id=plan_id, provider=provider,
|
||||
)
|
||||
|
||||
# برای provider='bazaar' هیچ paymentUrlی وجود ندارد: کلاینت اندروید مستقیماً
|
||||
# با SDK بازار خرید را انجام میدهد و purchaseToken را به verify میفرستد.
|
||||
payment_url = None if order.provider == 'bazaar' else call_payment_gateway(order)
|
||||
# بازار paymentUrl ندارد (اپ با Poolakey میخرد)؛ زرینپال آدرسِ PaymentRedirectView را دارد (providers.py).
|
||||
payment_url = provider_for(order.provider).payment_url(order)
|
||||
return order, payment_url
|
||||
|
||||
|
||||
@@ -282,13 +282,9 @@ def reconcile_pending_order(order: Order) -> bool:
|
||||
|
||||
|
||||
def reconcile_user_orders(user_id: int) -> None:
|
||||
"""سفارشهای pendingِ اخیرِ یک کاربر و تمدیدِ اشتراکِ بازار؛ از صفحهی وضعیتِ اشتراک صدا زده میشود."""
|
||||
since = timezone.now() - timezone.timedelta(days=2)
|
||||
for order in Order.objects.filter(
|
||||
user_id=user_id, status='pending', provider='gateway', created_at__gte=since,
|
||||
).exclude(gateway_authority='')[:3]:
|
||||
reconcile_pending_order(order)
|
||||
sync_bazaar_renewals(user_id)
|
||||
"""هر روشِ پرداخت آنچه از این کاربر جا مانده را از درگاهِ خودش میپرسد (providers.py)؛ از صفحهی وضعیتِ اشتراک."""
|
||||
for provider in PROVIDERS:
|
||||
provider.reconcile_user(user_id)
|
||||
|
||||
|
||||
# تا این فاصله پیش از پایانِ دوره، از بازار پرسیده میشود که تمدید شده یا نه. بازار روزِ آخر تمدید میکند.
|
||||
|
||||
Reference in New Issue
Block a user