"""Bounded retries for payment verification after an inconclusive callback.""" import logging from celery import shared_task from django.shortcuts import get_object_or_404 from apps.payments.models import Payment from apps.payments.services import PaymentVerificationUncertain, request_payment_verification logger = logging.getLogger(__name__) @shared_task(bind=True, max_retries=5, name="apps.payments.reconcile_payment") def reconcile_payment(self, payment_id: int): payment = get_object_or_404( Payment.objects.select_related("event", "user"), pk=payment_id, ) if payment.status in (Payment.OrderStatusChoices.PAID, Payment.OrderStatusChoices.FAILED): return payment.get_status_display().lower() if not payment.authority: logger.error( "Payment %s remains pending without a gateway authority; manual review is required", payment.id, ) return "pending_manual_review" # Imported at task runtime to avoid a view/task import cycle. from apps.payments.api.views import ( _mark_payment_paid, _mark_payment_pending, _mark_payment_unsuccessful, _notify_payment_status, ) try: code, data = request_payment_verification(payment) except PaymentVerificationUncertain as exc: _mark_payment_pending(payment.id) if self.request.retries >= self.max_retries: logger.error( "Payment %s verification remains uncertain after bounded retries; manual review is required", payment.id, exc_info=exc, ) return "pending_manual_review" countdown = min(60 * (2 ** self.request.retries), 15 * 60) raise self.retry(exc=exc, countdown=countdown) if code in (100, 101): payment, newly_verified = _mark_payment_paid(payment.id, data) if newly_verified: _notify_payment_status( payment, title=f"پرداخت رویداد «{payment.event.title}» تأیید شد", message="پرداخت شما با موفقیت ثبت شد و ثبت‌نام رویداد تکمیل شده است.", level="success", ) return "paid" payment, result, transitioned = _mark_payment_unsuccessful( payment.id, Payment.OrderStatusChoices.FAILED, ) if transitioned: _notify_payment_status( payment, title=f"پرداخت رویداد «{payment.event.title}» ناموفق بود", message="تراکنش شما توسط درگاه تأیید نشد. در صورت نیاز دوباره پرداخت را انجام دهید.", level="error", ) return result