Laurent 4 weeks ago
commit 16bc3e4428
  1. 14
      tournaments/admin_utils.py
  2. 8
      tournaments/models/tournament.py
  3. 97
      tournaments/services/payment_service.py
  4. 28852
      tournaments/static/rankings/CLASSEMENT-PADEL-DAMES-10-2025.csv
  5. 181275
      tournaments/static/rankings/CLASSEMENT-PADEL-MESSIEURS-10-2025.csv
  6. 2
      tournaments/templates/tournaments/tournament_info.html

@ -391,7 +391,19 @@ def download_french_padel_rankings(request):
try:
# API endpoint and parameters
url = "https://tenup.fft.fr/back/public/v1/classements/recherche"
headers = {"Content-Type": "application/json"}
headers = {
'Accept': 'application/json',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'fr-FR,fr;q=0.9',
'Content-Type': 'application/json',
'Cookie': 'QueueITAccepted-SDFrts345E-V3_tenupprod=EventId%3Dtenupprod%26RedirectType%3Dsafetynet%26IssueTime%3D1760201365%26Hash%3D9df48ec92a3fda96d0f1f66b4b17602f43a294c4c847e57248401fd8ae3e21c0; _pcid=%7B%22browserId%22%3A%22mckhos3iasswydjm%22%2C%22_t%22%3A%22mwas74z5%7Cmgmb4hv5%22%7D; tc_cj_v2=%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQPJLJKMPMQMLZZZ%5D; tc_cj_v2_cmp=; tc_cj_v2_med=; i18n_redirected=fr; SHARED_SESSION_JAVA=085692ea-c23f-4812-ae86-6cc0f3467a69; userStore=%7B%22isLogged%22%3Atrue%2C%22user%22%3A%7B%22id%22%3A10000984864%2C%22idPersonne%22%3A109001023%2C%22nom%22%3A%22SARKISSIAN%22%2C%22prenom%22%3A%22Razmig%22%2C%22civilite%22%3A%22M%22%2C%22classement%22%3A%22NC%22%2C%22pratiquePrincipale%22%3A%22PADEL%22%2C%22pratiqueSecondaire%22%3A%5B%5D%2C%22licencie%22%3Atrue%2C%22licencieMillesimePrecedent%22%3Atrue%2C%22licencieMillesimeSuivant%22%3Afalse%2C%22codeTypeLicence%22%3A%22PAD%22%2C%22groupes%22%3A%5B%22Licenci%C3%A9%20Padel%22%2C%22Adherent%22%2C%22Juge%20arbitre%22%2C%22Loisir%22%2C%22Licenci%C3%A9%22%5D%2C%22clubs%22%3A%5B%7B%22code%22%3A%2262130180%22%2C%22nom%22%3A%22TENNIS%20SPORTING%20CLUB%20DE%20CASSIS%22%7D%5D%2C%22codeClubActif%22%3A%2262130180%22%2C%22nbPaiementsEnAttente%22%3A0%2C%22completionConnexionRequise%22%3Afalse%2C%22completionDonneesRequise%22%3Afalse%2C%22completionCGARequise%22%3Afalse%2C%22completionHonorabilite%22%3Afalse%2C%22millesimeSuivant%22%3Afalse%2C%22dirigeant%22%3Afalse%7D%7D; datadome=eOhBW_xLJNlEXp_0ffYtq~AAuDrpoQZ38mo9fuxTeCItoQl_g0Tr1YfswxzFATknzJ2Er4j_dOLzqfN0iO~2gsEES5GMdrNiat6SFAy7_sRFRs0nFykcBf_wrSCt360D; xtan=-; xtant=1; SSESS7ba44afc36c80c3faa2b8fa87e7742c5=t7J6ikkE34JlGEgFUittt_nQWNiNtHySzLCpRXYnn64; TCID=; pa_vid=%22mckhos3iasswydjm%22; TC_PRIVACY=1%40033%7C64%7C3288%40%405%401748938434779%2C1748938434779%2C1782634434779%40; TC_PRIVACY_CENTER=; pa_privacy=%22optin%22; TCPID=125629554310878226394; xtvrn=$548419$',
'Origin': 'https://tenup.fft.fr',
'Referer': 'https://tenup.fft.fr/classement-padel',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0.1 Safari/605.1.15'
}
all_players = []
total_tranches = end_tranche - start_tranche + 1

@ -1525,7 +1525,13 @@ class Tournament(BaseModel):
if is_woman is not None and self.federal_category == FederalCategory.WOMEN and is_woman is False:
reasons.append("Ce tournoi est réservé aux femmes")
if birth_year is None:
if birth_year is None or birth_year == 'N/A':
return reasons if reasons else None
try:
tournament_start_year = self.season_year()
user_age = tournament_start_year - int(birth_year)
except (ValueError, TypeError):
return reasons if reasons else None
tournament_start_year = self.season_year()

@ -593,31 +593,75 @@ class PaymentService:
payload = request.body
sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
# Check if this is a Connect account webhook
stripe_account = request.META.get('HTTP_STRIPE_ACCOUNT')
# Check if this is a Connect account webhook (header method - for direct API calls)
stripe_account_header = request.META.get('HTTP_STRIPE_ACCOUNT')
print("=== WEBHOOK DEBUG ===")
print(f"Signature: {sig_header}")
print(f"Connect Account: {stripe_account}")
print(f"Connect Account Header: {stripe_account_header}")
if stripe_account:
# This is a connected account (regular umpire tournament)
webhook_secret = settings.TOURNAMENT_STRIPE_WEBHOOK_SECRET
print(f"Using umpire webhook secret for connected account: {stripe_account}")
# First, try to construct the event with any available webhook secret to inspect the payload
webhook_secrets = []
if hasattr(settings, 'XLR_STRIPE_WEBHOOK_SECRET') and settings.XLR_STRIPE_WEBHOOK_SECRET:
webhook_secrets.append(('XLR', settings.XLR_STRIPE_WEBHOOK_SECRET))
if hasattr(settings, 'TOURNAMENT_STRIPE_WEBHOOK_SECRET') and settings.TOURNAMENT_STRIPE_WEBHOOK_SECRET:
webhook_secrets.append(('TOURNAMENT', settings.TOURNAMENT_STRIPE_WEBHOOK_SECRET))
if hasattr(settings, 'SHOP_STRIPE_WEBHOOK_SECRET') and settings.SHOP_STRIPE_WEBHOOK_SECRET:
webhook_secrets.append(('SHOP', settings.SHOP_STRIPE_WEBHOOK_SECRET))
print(f"Available webhook secrets: {[name for name, _ in webhook_secrets]}")
event = None
used_secret = None
# Try to verify with each secret to get the event payload
for secret_name, secret_value in webhook_secrets:
try:
print(f"Trying {secret_name} webhook secret...")
event = stripe.Webhook.construct_event(payload, sig_header, secret_value)
used_secret = secret_name
print(f"SUCCESS: Webhook verified with {secret_name} secret")
break
except stripe.error.SignatureVerificationError as e:
print(f"Failed with {secret_name} secret: {str(e)}")
continue
if not event:
print("ERROR: No webhook secret worked")
return HttpResponse("Webhook signature verification failed", status=400)
# Now check if this is a Connect webhook by looking at the payload
connect_account_id = event.get('account') # This is how Connect webhooks are identified
print(f"Connect Account ID from payload: {connect_account_id}")
# Log webhook details
print(f"Event ID: {event.get('id')}")
print(f"Event Type: {event.get('type')}")
print(f"Live Mode: {event.get('livemode')}")
# Determine if this should have used a different webhook secret based on the account
if connect_account_id:
print(f"This is a Connect webhook from account: {connect_account_id}")
# Check if the account matches the expected tournament account
if connect_account_id == "acct_1S0jbSAs9xuFLROy":
print("This matches the expected tournament Connect account")
if used_secret != 'TOURNAMENT':
print(f"WARNING: Used {used_secret} secret but should probably use TOURNAMENT secret")
else:
print(f"Unknown Connect account: {connect_account_id}")
else:
# This is platform account (corporate tournament)
webhook_secret = settings.XLR_STRIPE_WEBHOOK_SECRET
print("Using XLR company webhook secret")
print("This is a platform/direct webhook (no Connect account)")
if used_secret != 'XLR':
print(f"WARNING: Used {used_secret} secret but should probably use XLR secret")
try:
event = stripe.Webhook.construct_event(payload, sig_header, webhook_secret)
print(f"Tournament webhook event type: {event['type']}")
# Debug metadata
# Process the webhook event
stripe_object = event['data']['object']
metadata = stripe_object.get('metadata', {})
print(f"is_corporate_tournament: {metadata.get('is_corporate_tournament', 'unknown')}")
print(f"payment_source: {metadata.get('payment_source', 'unknown')}")
print(f"stripe_account_type: {metadata.get('stripe_account_type', 'unknown')}")
print(f"stripe_account_id: {metadata.get('stripe_account_id', 'unknown')}")
if event['type'] == 'checkout.session.completed':
success = PaymentService.process_direct_payment(stripe_object)
@ -628,33 +672,20 @@ class PaymentService:
print(f"Failed to process completed checkout session")
return HttpResponse(status=400)
elif event['type'] == 'payment_intent.payment_failed':
success = PaymentService.process_failed_payment_intent(stripe_object)
if success:
print(f"Successfully processed failed payment intent")
return HttpResponse(status=200)
else:
print(f"Failed to process failed payment intent")
return HttpResponse(status=400)
elif event['type'] == 'checkout.session.expired':
success = PaymentService.process_expired_checkout_session(stripe_object)
if success:
print(f"Successfully processed expired checkout session")
return HttpResponse(status=200)
else:
print(f"Failed to process expired checkout session")
return HttpResponse(status=400)
# Handle other event types if needed
elif event['type'] == 'payment_intent.succeeded':
print(f"Payment intent succeeded - you might want to handle this")
return HttpResponse(status=200)
else:
print(f"Unhandled event type: {event['type']}")
return HttpResponse(status=200)
except Exception as e:
print(f"Webhook error: {str(e)}")
print(f"Error processing webhook: {str(e)}")
import traceback
traceback.print_exc()
return HttpResponse(status=400)
return HttpResponse("Webhook processing failed", status=500)
@staticmethod
def create_payment_link(team_registration_id):

File diff suppressed because it is too large Load Diff

@ -164,7 +164,7 @@
{% else %}
<div class="topmargin20">
<p class="minor info">
La désincription en ligne n'est plus possible. Veuillez contacter directement le juge-arbitre si besoin.
La désinscription en ligne n'est plus possible. Veuillez contacter directement le juge-arbitre si besoin.
</p>
</div>
{% endif %}

Loading…
Cancel
Save