Improve Payment Service: Add Transaction Safety and Error Handling

main
Razmig Sarkissian 3 weeks ago
parent 8de8a9ac49
commit 11d6913807
  1. 32
      tournaments/services/payment_service.py

@ -4,8 +4,10 @@ from django.urls import reverse
from django.http import HttpResponse from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.db import transaction
import stripe import stripe
from datetime import datetime, timedelta from datetime import datetime, timedelta
import traceback
from ..models import TeamRegistration, PlayerRegistration, Tournament from ..models import TeamRegistration, PlayerRegistration, Tournament
from ..models.player_registration import PlayerPaymentType from ..models.player_registration import PlayerPaymentType
@ -544,12 +546,16 @@ class PaymentService:
team_registration_id = metadata.get('team_registration_id') team_registration_id = metadata.get('team_registration_id')
registration_type = metadata.get('registration_type') registration_type = metadata.get('registration_type')
# Wrap all database operations in an atomic transaction
# This ensures either all changes are saved or none are
try:
with transaction.atomic():
if tournament_id and registration_type == 'cart': if tournament_id and registration_type == 'cart':
try: try:
tournament = Tournament.objects.get(id=tournament_id) tournament = Tournament.objects.get(id=tournament_id)
tournament.reserved_spots = max(0, tournament.reserved_spots - 1) tournament.reserved_spots = max(0, tournament.reserved_spots - 1)
tournament.save() tournament.save()
print(f"Decreased reserved spots for tournament {tournament_id} after payment failure") print(f"Decreased reserved spots for tournament {tournament_id}")
except Tournament.DoesNotExist: except Tournament.DoesNotExist:
print(f"Tournament not found with ID: {tournament_id}") print(f"Tournament not found with ID: {tournament_id}")
except Exception as e: except Exception as e:
@ -559,9 +565,9 @@ class PaymentService:
print("No team registration ID found in session") print("No team registration ID found in session")
return False return False
try:
print(f"Looking for team registration with ID: {team_registration_id}") print(f"Looking for team registration with ID: {team_registration_id}")
team_registration = TeamRegistration.objects.get(id=team_registration_id) team_registration = TeamRegistration.objects.get(id=team_registration_id)
if tournament_id and registration_type == 'cart' and team_registration.tournament is None: if tournament_id and registration_type == 'cart' and team_registration.tournament is None:
try: try:
tournament = Tournament.objects.get(id=tournament_id) tournament = Tournament.objects.get(id=tournament_id)
@ -574,18 +580,34 @@ class PaymentService:
print(f"Error saving tournament for team registration: {str(e)}") print(f"Error saving tournament for team registration: {str(e)}")
if team_registration.is_paid(): if team_registration.is_paid():
print(f"Team registration {team_registration.id} is already paid")
return True return True
# Update player registration with payment info
team_registration.confirm_registration(checkout_session.payment_intent) team_registration.confirm_registration(checkout_session.payment_intent)
print(f"✅ Registration confirmed and committed to database")
TournamentEmailService.send_payment_confirmation(team_registration, checkout_session.payment_intent)
return True
except TeamRegistration.DoesNotExist: except TeamRegistration.DoesNotExist:
print(f"Team registration not found with ID: {team_registration_id}") print(f"Team registration not found with ID: {team_registration_id}")
return False
except Exception as e: except Exception as e:
print(f"Error in _process_direct_payment: {str(e)}") print(f"❌ Error in process_direct_payment database operations: {str(e)}")
traceback.print_exc()
return False return False
# After successful database commit, send confirmation email
# Email failures won't affect the payment confirmation
try:
print(f"Sending payment confirmation email...")
TournamentEmailService.send_payment_confirmation(team_registration, checkout_session.payment_intent)
print(f"✅ Email sent successfully")
except Exception as email_error:
print(f" Warning: Email sending failed but payment was confirmed: {str(email_error)}")
traceback.print_exc()
# Don't return False - payment is still confirmed
return True
@staticmethod @staticmethod
@csrf_exempt @csrf_exempt
@require_POST @require_POST

Loading…
Cancel
Save