feat(events): harden registration checkout lifecycle
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user