|
|
|
|
@ -1,6 +1,9 @@ |
|
|
|
|
from django.shortcuts import get_object_or_404 |
|
|
|
|
from django.conf import settings |
|
|
|
|
from django.urls import reverse |
|
|
|
|
from django.http import HttpResponse |
|
|
|
|
from django.views.decorators.csrf import csrf_exempt |
|
|
|
|
from django.views.decorators.http import require_POST |
|
|
|
|
import stripe |
|
|
|
|
|
|
|
|
|
from ..models import TeamRegistration, PlayerRegistration, Tournament |
|
|
|
|
@ -44,6 +47,50 @@ class PaymentService: |
|
|
|
|
reverse('register_tournament', kwargs={'tournament_id': tournament_id}) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
base_metadata = { |
|
|
|
|
'tournament_id': str(tournament_id), |
|
|
|
|
'user_id': str(self.request.user.id) if self.request.user.is_authenticated else None, |
|
|
|
|
'payment_source': 'tournament', # Identify payment source |
|
|
|
|
'source_page': 'tournament_info' if team_registration_id else 'register_tournament', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if tournament.is_corporate_tournament: |
|
|
|
|
# Corporate tournament metadata |
|
|
|
|
metadata = { |
|
|
|
|
**base_metadata, |
|
|
|
|
'is_corporate_tournament': 'true', |
|
|
|
|
'stripe_account_type': 'direct' |
|
|
|
|
} |
|
|
|
|
else: |
|
|
|
|
# Regular tournament metadata |
|
|
|
|
metadata = { |
|
|
|
|
**base_metadata, |
|
|
|
|
'is_corporate_tournament': 'false', |
|
|
|
|
'stripe_account_type': 'connect', |
|
|
|
|
'stripe_account_id': tournament.stripe_account_id |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if cart_data: |
|
|
|
|
metadata.update({ |
|
|
|
|
'registration_cart_id': str(cart_data['cart_id']), |
|
|
|
|
'registration_type': 'cart', |
|
|
|
|
'player_count': str(cart_data.get('player_count', 0)), |
|
|
|
|
'waiting_list_position': str(cart_data.get('waiting_list_position', -1)) |
|
|
|
|
}) |
|
|
|
|
elif team_registration_id: |
|
|
|
|
metadata.update({ |
|
|
|
|
'team_registration_id': str(team_registration_id), |
|
|
|
|
'registration_type': 'direct' |
|
|
|
|
}) |
|
|
|
|
self.request.session['team_registration_id'] = str(team_registration_id) |
|
|
|
|
|
|
|
|
|
metadata.update({ |
|
|
|
|
'tournament_name': tournament.broadcast_display_name(), |
|
|
|
|
'tournament_date': tournament.formatted_start_date(), |
|
|
|
|
'tournament_club': tournament.event.club.name, |
|
|
|
|
'tournament_fee': str(team_fee) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
# Common checkout session parameters |
|
|
|
|
if tournament.is_corporate_tournament: |
|
|
|
|
# Direct charge without transfers when umpire is platform owner |
|
|
|
|
@ -65,12 +112,7 @@ class PaymentService: |
|
|
|
|
reverse('tournament-payment-success', kwargs={'tournament_id': tournament_id}) |
|
|
|
|
), |
|
|
|
|
'cancel_url': cancel_url, |
|
|
|
|
'metadata': { |
|
|
|
|
'tournament_id': str(tournament_id), |
|
|
|
|
'user_id': str(self.request.user.id) if self.request.user.is_authenticated else None, |
|
|
|
|
'source_page': 'tournament_info' if team_registration_id else 'register_tournament', |
|
|
|
|
'is_corporate_tournament': 'true' |
|
|
|
|
} |
|
|
|
|
'metadata': metadata |
|
|
|
|
} |
|
|
|
|
else: |
|
|
|
|
# Get the umpire's Stripe account ID |
|
|
|
|
@ -106,19 +148,15 @@ class PaymentService: |
|
|
|
|
'destination': stripe_account_id, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
'metadata': { |
|
|
|
|
'tournament_id': str(tournament_id), # Convert UUID to string |
|
|
|
|
'user_id': str(self.request.user.id) if self.request.user.is_authenticated else None, # Convert UUID to string |
|
|
|
|
'source_page': 'tournament_info' if team_registration_id else 'register_tournament', |
|
|
|
|
} |
|
|
|
|
'metadata': metadata |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
# Add cart or team data to metadata based on payment context |
|
|
|
|
if cart_data: |
|
|
|
|
checkout_session_params['metadata']['registration_cart_id'] = str(cart_data['cart_id']) # Convert to string |
|
|
|
|
elif team_registration_id: |
|
|
|
|
checkout_session_params['metadata']['team_registration_id'] = str(team_registration_id) # Convert to string |
|
|
|
|
self.request.session['team_registration_id'] = str(team_registration_id) # Convert to string |
|
|
|
|
# # Add cart or team data to metadata based on payment context |
|
|
|
|
# if cart_data: |
|
|
|
|
# checkout_session_params['metadata']['registration_cart_id'] = str(cart_data['cart_id']) # Convert to string |
|
|
|
|
# elif team_registration_id: |
|
|
|
|
# checkout_session_params['metadata']['team_registration_id'] = str(team_registration_id) # Convert to string |
|
|
|
|
# self.request.session['team_registration_id'] = str(team_registration_id) # Convert to string |
|
|
|
|
|
|
|
|
|
# Add customer_email if available |
|
|
|
|
if customer_email: |
|
|
|
|
@ -287,3 +325,61 @@ class PaymentService: |
|
|
|
|
return False, f"Erreur de remboursement Stripe: {str(e)}", None |
|
|
|
|
except Exception as e: |
|
|
|
|
return False, f"Erreur lors du remboursement: {str(e)}", None |
|
|
|
|
|
|
|
|
|
@staticmethod |
|
|
|
|
@csrf_exempt |
|
|
|
|
@require_POST |
|
|
|
|
def stripe_webhook(request): |
|
|
|
|
payload = request.body |
|
|
|
|
sig_header = request.META.get('HTTP_STRIPE_SIGNATURE') |
|
|
|
|
print("Received webhook call") |
|
|
|
|
print(f"Signature: {sig_header}") |
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
event = stripe.Webhook.construct_event( |
|
|
|
|
payload, sig_header, settings.TOURNAMENT_STRIPE_WEBHOOK_SECRET |
|
|
|
|
) |
|
|
|
|
print(f"Tournament webhook event type: {event['type']}") |
|
|
|
|
|
|
|
|
|
if event['type'] == 'checkout.session.completed': |
|
|
|
|
session = event['data']['object'] |
|
|
|
|
metadata = session.get('metadata', {}) |
|
|
|
|
tournament_id = metadata.get('tournament_id') |
|
|
|
|
|
|
|
|
|
if not tournament_id: |
|
|
|
|
print("No tournament_id in metadata") |
|
|
|
|
return HttpResponse(status=400) |
|
|
|
|
|
|
|
|
|
payment_service = PaymentService(request) |
|
|
|
|
success = payment_service.process_successful_payment(tournament_id, session) |
|
|
|
|
|
|
|
|
|
if success: |
|
|
|
|
print(f"Successfully processed webhook payment for tournament {tournament_id}") |
|
|
|
|
return HttpResponse(status=200) |
|
|
|
|
else: |
|
|
|
|
print(f"Failed to process webhook payment for tournament {tournament_id}") |
|
|
|
|
return HttpResponse(status=400) |
|
|
|
|
|
|
|
|
|
elif event['type'] == 'payment_intent.payment_failed': |
|
|
|
|
intent = event['data']['object'] |
|
|
|
|
metadata = intent.get('metadata', {}) |
|
|
|
|
|
|
|
|
|
tournament_id = metadata.get('tournament_id') |
|
|
|
|
source_page = metadata.get('source_page') |
|
|
|
|
|
|
|
|
|
if tournament_id and source_page == 'register_tournament': |
|
|
|
|
try: |
|
|
|
|
tournament = Tournament.objects.get(id=tournament_id) |
|
|
|
|
# Decrease reserved spots, minimum 0 |
|
|
|
|
tournament.reserved_spots = max(0, tournament.reserved_spots - 1) |
|
|
|
|
tournament.save() |
|
|
|
|
print(f"Decreased reserved spots for tournament {tournament_id} after payment failure") |
|
|
|
|
except Tournament.DoesNotExist: |
|
|
|
|
print(f"Tournament {tournament_id} not found") |
|
|
|
|
except Exception as e: |
|
|
|
|
print(f"Error updating tournament reserved spots: {str(e)}") |
|
|
|
|
|
|
|
|
|
return HttpResponse(status=200) |
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
print(f"Tournament webhook error: {str(e)}") |
|
|
|
|
|