Files
guilan-ace-backend/apps/payments/tests/integration/test_payment_recovery_sweep.py

83 lines
2.7 KiB
Python

from datetime import timedelta
import pytest
from django.utils import timezone
from apps.payments.models import Payment
from apps.payments.tasks import sweep_stale_payment_verifications
pytestmark = [pytest.mark.integration, pytest.mark.django_db]
def test_sweep_schedules_only_old_unresolved_payments_and_deduplicates_dispatch(
user_factory, event_factory, mocker, settings
):
settings.PAYMENT_VERIFICATION_GRACE_SECONDS = 1800
user = user_factory()
event = event_factory(price=25000)
old_payment = Payment.objects.create(
user=user,
event=event,
base_amount=25000,
amount=25000,
authority="AUTH-RECOVERY-OLD",
status=Payment.OrderStatusChoices.PENDING,
)
recent_payment = Payment.objects.create(
user=user,
event=event,
base_amount=25000,
amount=25000,
authority="AUTH-RECOVERY-NEW",
status=Payment.OrderStatusChoices.PENDING,
)
Payment.objects.filter(pk=old_payment.pk).update(
created_at=timezone.now() - timedelta(seconds=1801)
)
enqueue = mocker.patch("apps.payments.tasks.reconcile_payment.apply_async")
scheduled = sweep_stale_payment_verifications.run()
old_payment.refresh_from_db()
recent_payment.refresh_from_db()
assert scheduled == 1
enqueue.assert_called_once_with(args=(old_payment.pk,))
assert old_payment.verification_dispatch_expires_at is not None
assert old_payment.verification_dispatch_expires_at > timezone.now()
assert recent_payment.verification_next_attempt_at is None
assert sweep_stale_payment_verifications.run() == 0
enqueue.assert_called_once()
def test_sweep_does_not_restart_exhausted_or_terminal_attempts(
user_factory, event_factory, mocker, settings
):
settings.PAYMENT_VERIFICATION_GRACE_SECONDS = 60
settings.PAYMENT_VERIFICATION_MAX_ATTEMPTS = 3
user = user_factory()
event = event_factory(price=25000)
payments = [
Payment.objects.create(
user=user,
event=event,
base_amount=25000,
amount=25000,
authority=f"AUTH-RECOVERY-{status}-{index}",
status=status,
verification_attempts=3,
)
for index, status in enumerate(
[Payment.OrderStatusChoices.PENDING, Payment.OrderStatusChoices.FAILED]
)
]
Payment.objects.filter(pk__in=[payment.pk for payment in payments]).update(
created_at=timezone.now() - timedelta(minutes=5)
)
enqueue = mocker.patch("apps.payments.tasks.reconcile_payment.apply_async")
scheduled = sweep_stale_payment_verifications.run()
assert scheduled == 0
enqueue.assert_not_called()