fix issue with payment and registration

sync_v2
Raz 6 months ago
parent 7b7c5fdb71
commit 4f4b293d52
  1. 33
      tournaments/migrations/0124_playerregistration_club_code_and_more.py
  2. 18
      tournaments/migrations/0125_tournament_unregister_delta_in_hours.py
  3. 2
      tournaments/models/club.py
  4. 14
      tournaments/models/player_registration.py
  5. 13
      tournaments/models/team_registration.py
  6. 46
      tournaments/models/tournament.py
  7. 4
      tournaments/services/email_service.py
  8. 39
      tournaments/services/tournament_registration.py
  9. 7
      tournaments/templates/register_tournament.html
  10. 10
      tournaments/templates/tournaments/tournament_info.html
  11. 2
      tournaments/utils/player_search.py
  12. 2
      tournaments/views.py

@ -0,0 +1,33 @@
# Generated by Django 5.1 on 2025-05-19 09:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0123_teamregistration_unique_random_index'),
]
operations = [
migrations.AddField(
model_name='playerregistration',
name='club_code',
field=models.CharField(blank=True, max_length=20, null=True),
),
migrations.AddField(
model_name='playerregistration',
name='club_member',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='tournament',
name='club_member_fee_deduction',
field=models.FloatField(blank=True, null=True),
),
migrations.AlterField(
model_name='club',
name='code',
field=models.CharField(blank=True, max_length=20, null=True),
),
]

@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2025-05-19 13:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0124_playerregistration_club_code_and_more'),
]
operations = [
migrations.AddField(
model_name='tournament',
name='unregister_delta_in_hours',
field=models.IntegerField(default=24),
),
]

@ -9,7 +9,7 @@ class Club(BaseModel):
name = models.CharField(max_length=50)
acronym = models.CharField(max_length=50)
phone = models.CharField(max_length=15, null=True, blank=True)
code = models.CharField(max_length=10, null=True, blank=True)
code = models.CharField(max_length=20, null=True, blank=True)
federal_club_data = models.JSONField(null=True, blank=True)
address = models.CharField(max_length=200, null=True, blank=True)

@ -25,6 +25,8 @@ class PlayerRegistration(SideStoreModel):
club_name = models.CharField(max_length=200, null=True, blank=True)
ligue_name = models.CharField(max_length=200, null=True, blank=True)
assimilation = models.CharField(max_length=50, null=True, blank=True)
club_code = models.CharField(max_length=20, null=True, blank=True)
club_member = models.BooleanField(default=False)
#beachpadel
phone_number = models.CharField(max_length=50, null=True, blank=True)
@ -175,3 +177,15 @@ class PlayerRegistration(SideStoreModel):
def has_paid(self):
return self.payment_type is not None
def get_remaining_fee(self):
if self.has_paid():
return 0
if self.club_member and self.team_registration.tournament.club_member_fee_deduction is not None and self.team_registration.tournament.entry_fee is not None:
return self.team_registration.tournament.entry_fee - self.team_registration.tournament.club_member_fee_deduction
elif self.team_registration.tournament.entry_fee is not None:
return self.team_registration.tournament.entry_fee
elif self.team_registration.tournament.club_member_fee_deduction is not None:
return self.team_registration.tournament.club_member_fee_deduction
else:
return 0

@ -402,14 +402,11 @@ class TeamRegistration(SideStoreModel):
return status == 'PAID'
def get_remaining_fee(self):
"""Get the remaining fee for this team"""
status = self.get_payment_status()
if status == 'PAID':
return 0
elif status == 'UNPAID':
return self.tournament.team_fee()
elif status == 'MIXED':
return self.tournament.player_fee()
# Get all player registrations for this team
player_registrations = self.players_sorted_by_rank
# Check payment status for each player
payment_statuses = [player.get_remaining_fee() for player in player_registrations]
return sum(payment_statuses)
def is_confirmation_expired(self):
"""

@ -92,6 +92,8 @@ class Tournament(BaseModel):
animation_type = models.IntegerField(default=AnimationType.TOURNAMENT, choices=AnimationType.choices)
publish_prog = models.BooleanField(default=False)
show_teams_in_prog = models.BooleanField(default=False)
club_member_fee_deduction = models.FloatField(null=True, blank=True)
unregister_delta_in_hours = models.IntegerField(default=24)
def delete_dependencies(self):
for team_registration in self.team_registrations.all():
@ -1093,6 +1095,18 @@ class Tournament(BaseModel):
return False
return True
def options_fee(self):
options = []
# Entry fee
if self.entry_fee is not None and self.entry_fee > 0:
options.append(f"Frais d'inscription: {self.entry_fee} € par équipe")
# Club member fee reduction
if self.club_member_fee_deduction and self.club_member_fee_deduction > 0:
options.append(f"Réduction de {self.club_member_fee_deduction} € pour les membres du club")
return options
def options_online_registration(self):
options = []
timezone = self.timezone()
@ -1132,11 +1146,11 @@ class Tournament(BaseModel):
if self.enable_online_payment_refund and self.refund_date_limit:
date = formats.date_format(self.refund_date_limit.astimezone(timezone), format='j F Y H:i')
options.append(f"Remboursement possible jusqu'au {date}")
options.append(f"Remboursement en ligne possible jusqu'au {date}")
elif self.enable_online_payment_refund:
options.append("Remboursement possible")
options.append("Remboursement en ligne possible")
else:
options.append("Remboursement impossible")
options.append("Remboursement en ligne impossible")
# Joueurs par équipe
min_players = self.minimum_player_per_team
@ -1236,7 +1250,7 @@ class Tournament(BaseModel):
if self.supposedly_in_progress():
return False
if self.will_start_soon(12):
if self.will_start_soon(self.unregister_delta_in_hours):
return False
if self.closed_registration_date is not None:
@ -1844,19 +1858,6 @@ class Tournament(BaseModel):
else:
return False
def player_fee(self):
if self.entry_fee is not None and self.entry_fee > 0 and self.enable_online_payment:
return self.entry_fee
else:
return 0
def team_fee(self):
entry_fee = self.entry_fee
if entry_fee is not None and entry_fee > 0 and self.enable_online_payment:
return self.entry_fee * self.minimum_player_per_team
else:
return 0
def is_free(self):
if self.entry_fee is not None and self.entry_fee == 0:
return True
@ -2060,6 +2061,17 @@ class Tournament(BaseModel):
def has_sponsors(self):
return self.event.images.exists()
def is_cart_player_from_club(self, player_data):
player_club_code = player_data.get('club_code', None)
if player_club_code is None and len(player_club_code) > 0:
return False
club_code = self.event.club.code
if club_code is None and len(club_code) > 0:
return False
player_club_code = player_club_code.replace(" ", "")
club_code = club_code.replace(" ", "")
return player_club_code.lower() == club_code.lower()
class MatchGroup:
def __init__(self, name, matches, formatted_schedule, round_id=None, round_index=None):
self.name = name

@ -699,7 +699,7 @@ class TournamentEmailService:
payment_amount = payment['amount'] / 100
if payment_amount is None:
payment_amount = tournament.team_fee()
payment_amount = team_registration.get_remaining_fee()
federal_level_category = FederalLevelCategory(tournament.federal_level_category)
tournament_word = federal_level_category.localized_word()
@ -774,7 +774,7 @@ class TournamentEmailService:
if refund_amount is None:
refund_amount = tournament.team_fee()
refund_amount = team_registration.get_remaining_fee()
federal_level_category = FederalLevelCategory(tournament.federal_level_category)
tournament_word = federal_level_category.localized_word()

@ -8,6 +8,7 @@ from ..models.enums import FederalCategory, RegistrationStatus
from ..models.player_enums import PlayerSexType, PlayerDataSource
from django.contrib.auth import get_user_model
from django.conf import settings
from django.utils.dateparse import parse_datetime
class RegistrationCartManager:
"""
@ -110,7 +111,6 @@ class RegistrationCartManager:
if expiry_str:
try:
# Parse the ISO format string to datetime
from django.utils.dateparse import parse_datetime
expiry_datetime = parse_datetime(expiry_str)
except (ValueError, TypeError):
# If parsing fails, set a new expiry
@ -123,6 +123,7 @@ class RegistrationCartManager:
'players': self.session.get('registration_cart_players', []),
'expiry': expiry_datetime, # Now a datetime object, not a string
'is_cart_expired': self.is_cart_expired(),
'team_fee_from_cart_players': self.team_fee_from_cart_players(),
'mobile_number': self.session.get('registration_mobile_number', user_phone)
}
@ -132,6 +133,27 @@ class RegistrationCartManager:
return cart_data
def team_fee_from_cart_players(self):
# Get tournament
tournament_id = self.session.get('registration_tournament_id')
try:
tournament = Tournament.objects.get(id=tournament_id)
except Tournament.DoesNotExist:
return 0
players = self.session.get('registration_cart_players', []),
entry_fee = tournament.entry_fee
if entry_fee is not None and entry_fee > 0 and tournament.enable_online_payment:
fee = entry_fee * tournament.minimum_player_per_team
players = self.session.get('registration_cart_players', [])
club_members = sum(1 for player in players if player.get('club_member', False))
if tournament.club_member_fee_deduction is not None:
return fee - club_members * tournament.club_member_fee_deduction
return fee
else:
return 0
def add_player(self, player_data):
"""Add a player to the registration cart"""
if self.is_cart_expired():
@ -198,8 +220,10 @@ class RegistrationCartManager:
'tournament_count': fed_data.get('tournament_count'),
'ligue_name': fed_data.get('ligue_name'),
'club_name': fed_data.get('club_name'),
'club_code': fed_data.get('club_code'),
'birth_year': fed_data.get('birth_year'),
'found_in_french_federation': True,
'club_member': tournament.is_cart_player_from_club(fed_data)
})
elif not first_name or not last_name:
# License not required or not found, but name is needed
@ -379,6 +403,15 @@ class RegistrationCartManager:
except User.DoesNotExist:
pass
is_woman = player_data.get('is_woman')
if is_woman is not None:
if is_woman:
sex = 0
else:
sex = 1
else:
sex = None
# Create player registration with all the original fields
PlayerRegistration.objects.create(
team_registration=team_registration,
@ -393,8 +426,10 @@ class RegistrationCartManager:
tournament_played=player_data.get('tournament_count'),
ligue_name=player_data.get('ligue_name'),
club_name=player_data.get('club_name'),
club_code=player_data.get('club_code'),
club_member=tournament.is_cart_player_from_club(player_data),
birthdate=player_data.get('birth_year'),
sex=player_data.get('sex'),
sex= sex,
rank=player_data.get('rank'),
computed_rank=player_data.get('computed_rank'),
licence_id=player_data.get('licence_id'),

@ -102,7 +102,10 @@
{{ player.first_name }} {{ player.last_name }}{% if player.licence_id %} ({{ player.licence_id }}){% endif %}
</div>
<div>
{{ player.club_name }}
{{ player.club_name }}{% if player.club_member %} | Membre du club{% endif %}{% if player.club_member and tournament.club_member_fee_deduction %} | Tarif réduit{% endif %}
</div>
<div>
{{ player.email }}
</div>
<div>
Classement à ce jour : {% if player.rank %}{{ player.rank }}{% if player.computed_rank and player.rank != player.computed_rank %} ({{ player.computed_rank }}){% endif %}{% else %}Non classé ({{ player.computed_rank }}){% endif %}
@ -194,7 +197,7 @@
Confirmer votre inscription en payant immédiatement :
</div>
<button type="submit" name="proceed_to_payment" class="rounded-button">
Procéder au paiement ({{ tournament.team_fee }}€)
Procéder au paiement de {{ cart_data.team_fee_from_cart_players }}€
</button>
{% endif %}
{% if tournament.should_request_payment is False or tournament.online_payment_is_mandatory is False or cart_data.waiting_list_position >= 0 %}

@ -197,6 +197,16 @@
</p>
{% endif %}
{% if tournament.options_fee %}
<p>
<div class="semibold">Frais d'inscription</div>
<ul>
{% for option in tournament.options_fee %}
<li>{{ option }}</li>
{% endfor %}
</ul>
</p>
{% endif %}
{% with status=tournament.get_online_registration_status %}
{% if tournament.enable_online_registration %}
<p>

@ -70,6 +70,7 @@ def get_player_name_from_csv(category, licence_id, base_folder=None):
if cleaned_licence_id:
for row in rows:
if len(row) >= 15: # Ensure row has enough columns
player_club_code = row[10].replace(" ", "")
current_licence_id = row[5]
if current_licence_id == str(cleaned_licence_id):
data = {
@ -81,6 +82,7 @@ def get_player_name_from_csv(category, licence_id, base_folder=None):
"tournament_count": row[8],
"ligue_name": row[9],
"club_name": row[11],
"club_code": player_club_code,
"birth_year": row[14],
"is_woman": is_woman,
}

@ -1459,7 +1459,7 @@ def handle_payment_request(request, tournament, cart_manager, context, tournamen
payment_service = PaymentService(request)
checkout_session = payment_service.create_checkout_session(
tournament_id=tournament_id,
team_fee=tournament.team_fee(), # Use the appropriate fee field
team_fee=cart_data.team_fee_from_cart_players(), # Use the appropriate fee field
cart_data=cart_data
)

Loading…
Cancel
Save