mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-02-25 03:06:32 +00:00
Compare commits
2 Commits
6a928ee35b
...
de504398d2
Author | SHA1 | Date | |
---|---|---|---|
|
de504398d2 | ||
|
cae1c6fdb8 |
@ -7,11 +7,34 @@ from django.utils.translation import gettext_lazy as _
|
||||
from .models import Draw, Pool, Round, TeamDraw
|
||||
|
||||
|
||||
class RoundInline(admin.TabularInline):
|
||||
model = Round
|
||||
extra = 0
|
||||
autocomplete_fields = ('draw', 'current_pool',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class PoolInline(admin.TabularInline):
|
||||
model = Pool
|
||||
extra = 0
|
||||
autocomplete_fields = ('round', 'current_team', 'associated_pool',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class TeamDrawInline(admin.TabularInline):
|
||||
model = TeamDraw
|
||||
extra = 0
|
||||
autocomplete_fields = ('participation', 'round', 'pool',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
@admin.register(Draw)
|
||||
class DrawAdmin(admin.ModelAdmin):
|
||||
list_display = ('tournament', 'teams', 'current_round', 'get_state',)
|
||||
list_filter = ('tournament', 'current_round',)
|
||||
list_filter = ('tournament', 'current_round__number',)
|
||||
search_fields = ('tournament__name', 'tournament__participation__team__trigram',)
|
||||
autocomplete_fields = ('tournament',)
|
||||
inlines = (RoundInline,)
|
||||
|
||||
@admin.display(description=_("teams"))
|
||||
def teams(self, record: Draw):
|
||||
@ -20,10 +43,16 @@ class DrawAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Round)
|
||||
class RoundAdmin(admin.ModelAdmin):
|
||||
list_display = ('draw', 'number', 'teams',)
|
||||
list_display = ('draw', 'tournament', 'number', 'teams',)
|
||||
list_filter = ('draw__tournament', 'number',)
|
||||
search_fields = ('draw__tournament__name', 'pool__teamdraw__participation__team__trigram')
|
||||
ordering = ('draw__tournament__name', 'number')
|
||||
autocomplete_fields = ('draw', 'current_pool',)
|
||||
inlines = (PoolInline,)
|
||||
|
||||
@admin.display(description=_("tournament"), ordering='draw__tournament__name')
|
||||
def tournament(self, record):
|
||||
return record.draw.tournament
|
||||
|
||||
@admin.display(description=_("teams"))
|
||||
def teams(self, record: Round):
|
||||
@ -36,6 +65,8 @@ class PoolAdmin(admin.ModelAdmin):
|
||||
list_filter = ('round__draw__tournament', 'round__number', 'letter')
|
||||
ordering = ('round__draw__tournament__name', 'round', 'letter')
|
||||
search_fields = ('round__draw__tournament__name', 'teamdraw__participation__team__trigram',)
|
||||
autocomplete_fields = ('round', 'current_team', 'associated_pool',)
|
||||
inlines = (TeamDrawInline,)
|
||||
|
||||
@admin.display(ordering='round__draw__tournament__name', description=_("tournament"))
|
||||
def tournament(self, record):
|
||||
@ -52,6 +83,7 @@ class TeamDrawAdmin(admin.ModelAdmin):
|
||||
'passage_index', 'choose_index', 'passage_dice', 'choice_dice',)
|
||||
list_filter = ('round__draw__tournament', 'round__number', 'pool__letter',)
|
||||
search_fields = ('round__draw__tournament__name', 'participation__team__trigram',)
|
||||
autocomplete_fields = ('participation', 'round', 'pool',)
|
||||
|
||||
@admin.display(ordering='round__draw__tournament__name', description=_("tournament"))
|
||||
def tournament(self, record):
|
||||
|
@ -89,6 +89,7 @@ class Draw(models.Model):
|
||||
return 'WAITING_DRAW_PROBLEM'
|
||||
else:
|
||||
return 'WAITING_CHOOSE_PROBLEM'
|
||||
get_state.short_description = _('State')
|
||||
|
||||
@property
|
||||
def information(self):
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,11 +7,74 @@ from django.utils.translation import gettext_lazy as _
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
|
||||
|
||||
|
||||
class ParticipationInline(admin.StackedInline):
|
||||
model = Participation
|
||||
extra = 0
|
||||
autocomplete_fields = ('team', 'tournament',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class ParticipationTabularInline(admin.TabularInline):
|
||||
model = Participation
|
||||
extra = 0
|
||||
fields = ('team', 'valid', 'final',)
|
||||
readonly_fields = ('team',)
|
||||
ordering = ('final', 'valid', 'team__trigram',)
|
||||
autocomplete_fields = ('tournament',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class SolutionInline(admin.TabularInline):
|
||||
model = Solution
|
||||
extra = 0
|
||||
ordering = ('problem',)
|
||||
autocomplete_fields = ('participation',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class SynthesisInline(admin.TabularInline):
|
||||
model = Synthesis
|
||||
extra = 0
|
||||
ordering = ('passage__solution_number', 'type',)
|
||||
autocomplete_fields = ('passage',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class PoolInline(admin.TabularInline):
|
||||
model = Pool
|
||||
extra = 0
|
||||
autocomplete_fields = ('tournament', 'participations', 'juries',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class PassageInline(admin.TabularInline):
|
||||
model = Passage
|
||||
extra = 0
|
||||
ordering = ('position',)
|
||||
autocomplete_fields = ('defender', 'opponent', 'reporter', 'observer',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class NoteInline(admin.TabularInline):
|
||||
model = Note
|
||||
extra = 0
|
||||
autocomplete_fields = ('jury',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class TweakInline(admin.TabularInline):
|
||||
model = Tweak
|
||||
extra = 0
|
||||
autocomplete_fields = ('participation', 'pool',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
@admin.register(Team)
|
||||
class TeamAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'trigram', 'tournament', 'valid', 'final',)
|
||||
search_fields = ('name', 'trigram',)
|
||||
list_filter = ('participation__valid', 'participation__tournament', 'participation__final',)
|
||||
inlines = (ParticipationInline,)
|
||||
|
||||
@admin.display(description=_("tournament"))
|
||||
def tournament(self, record):
|
||||
@ -32,6 +95,7 @@ class ParticipationAdmin(admin.ModelAdmin):
|
||||
search_fields = ('team__name', 'team__trigram',)
|
||||
list_filter = ('valid',)
|
||||
autocomplete_fields = ('team', 'tournament',)
|
||||
inlines = (SolutionInline, SynthesisInline,)
|
||||
|
||||
|
||||
@admin.register(Pool)
|
||||
@ -40,6 +104,7 @@ class PoolAdmin(admin.ModelAdmin):
|
||||
list_filter = ('tournament', 'round', 'letter',)
|
||||
search_fields = ('participations__team__name', 'participations__team__trigram',)
|
||||
autocomplete_fields = ('tournament', 'participations', 'juries',)
|
||||
inlines = (PassageInline, TweakInline,)
|
||||
|
||||
@admin.display(description=_("teams"))
|
||||
def teams(self, record: Pool):
|
||||
@ -49,28 +114,30 @@ class PoolAdmin(admin.ModelAdmin):
|
||||
@admin.register(Passage)
|
||||
class PassageAdmin(admin.ModelAdmin):
|
||||
list_display = ('__str__', 'defender_trigram', 'solution_number', 'opponent_trigram', 'reporter_trigram',
|
||||
'pool_abbr', 'tournament')
|
||||
'pool_abbr', 'position', 'tournament')
|
||||
list_filter = ('pool__tournament', 'pool__round', 'pool__letter', 'solution_number',)
|
||||
search_fields = ('pool__participations__team__name', 'pool__participations__team__trigram',)
|
||||
ordering = ('pool__tournament', 'pool__round', 'pool__letter', 'position',)
|
||||
autocomplete_fields = ('pool', 'defender', 'opponent', 'reporter', 'observer',)
|
||||
inlines = (NoteInline,)
|
||||
|
||||
@admin.display(description=_("defender"))
|
||||
@admin.display(description=_("defender"), ordering='defender__team__trigram')
|
||||
def defender_trigram(self, record: Passage):
|
||||
return record.defender.team.trigram
|
||||
|
||||
@admin.display(description=_("opponent"))
|
||||
@admin.display(description=_("opponent"), ordering='opponent__team__trigram')
|
||||
def opponent_trigram(self, record: Passage):
|
||||
return record.opponent.team.trigram
|
||||
|
||||
@admin.display(description=_("reporter"))
|
||||
@admin.display(description=_("reporter"), ordering='reporter__team__trigram')
|
||||
def reporter_trigram(self, record: Passage):
|
||||
return record.reporter.team.trigram
|
||||
|
||||
@admin.display(description=_("pool"))
|
||||
@admin.display(description=_("pool"), ordering='pool__letter')
|
||||
def pool_abbr(self, record):
|
||||
return f"{record.pool.get_letter_display()}{record.pool.round}"
|
||||
|
||||
@admin.display(description=_("tournament"))
|
||||
@admin.display(description=_("tournament"), ordering='pool__tournament__name')
|
||||
def tournament(self, record: Passage):
|
||||
return record.pool.tournament
|
||||
|
||||
@ -124,9 +191,11 @@ class SynthesisAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Tournament)
|
||||
class TournamentAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
list_display = ('name', 'date_start', 'date_end',)
|
||||
search_fields = ('name',)
|
||||
ordering = ('date_start', 'name',)
|
||||
autocomplete_fields = ('organizers',)
|
||||
inlines = (ParticipationTabularInline, PoolInline,)
|
||||
|
||||
|
||||
@admin.register(Tweak)
|
||||
|
@ -1,87 +0,0 @@
|
||||
# Copyright (C) 2020 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import os
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.management import BaseCommand
|
||||
from django.db.models import Q
|
||||
import requests
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options): # noqa: C901
|
||||
# Get access token
|
||||
response = requests.post('https://api.helloasso.com/oauth2/token', headers={
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
}, data={
|
||||
'client_id': os.getenv('HELLOASSO_CLIENT_ID', ''),
|
||||
'client_secret': os.getenv('HELLOASSO_CLIENT_SECRET', ''),
|
||||
'grant_type': 'client_credentials',
|
||||
}).json()
|
||||
|
||||
token = response['access_token']
|
||||
|
||||
organization = "animath"
|
||||
form_slug = "tfjm-2023-tournois-regionaux"
|
||||
from_date = "2000-01-01"
|
||||
url = f"https://api.helloasso.com/v5/organizations/{organization}/forms/Event/{form_slug}/payments" \
|
||||
f"?from={from_date}&pageIndex=1&pageSize=100&retrieveOfflineDonations=false"
|
||||
headers = {
|
||||
"Accept": "application/json",
|
||||
"Authorization": f"Bearer {token}",
|
||||
}
|
||||
http_response = requests.get(url, headers=headers)
|
||||
response = http_response.json()
|
||||
|
||||
if http_response.status_code != 200:
|
||||
message = response["message"]
|
||||
self.stderr.write(f"Error while querying Hello Asso: {message}")
|
||||
return
|
||||
|
||||
for payment in response["data"]:
|
||||
if payment["state"] != "Authorized":
|
||||
continue
|
||||
|
||||
payer = payment["payer"]
|
||||
email = payer["email"]
|
||||
last_name = payer["lastName"]
|
||||
first_name = payer["firstName"]
|
||||
base_filter = Q(
|
||||
registration__participantregistration__isnull=False,
|
||||
registration__participantregistration__team__isnull=False,
|
||||
registration__participantregistration__team__participation__valid=True,
|
||||
)
|
||||
qs = User.objects.filter(
|
||||
base_filter,
|
||||
email=email,
|
||||
)
|
||||
if not qs.exists():
|
||||
qs = User.objects.filter(
|
||||
base_filter,
|
||||
last_name__icontains=last_name,
|
||||
)
|
||||
if qs.count() >= 2:
|
||||
qs = qs.filter(first_name__icontains=first_name)
|
||||
if not qs.exists():
|
||||
self.stderr.write(f"Warning: a payment was found by {first_name} {last_name} ({email}), "
|
||||
"but this user is unknown.")
|
||||
continue
|
||||
if qs.count() > 1:
|
||||
self.stderr.write(f"Warning: a payment was found by {first_name} {last_name} ({email}), "
|
||||
f"but there are {qs.count()} matching users.")
|
||||
continue
|
||||
user = qs.get()
|
||||
if not user.registration.participates:
|
||||
self.stderr.write(f"Warning: a payment was found by the email address {email}, "
|
||||
"but this user is not a participant.")
|
||||
continue
|
||||
payment_obj = user.registration.payment
|
||||
payment_obj.valid = True
|
||||
payment_obj.type = "helloasso"
|
||||
payment_obj.additional_information = f"Identifiant de transation : {payment['id']}\n" \
|
||||
f"Date : {payment['date']}\n" \
|
||||
f"Reçu : {payment['paymentReceiptUrl']}\n" \
|
||||
f"Montant : {payment['amount'] / 100:.2f} €"
|
||||
payment_obj.save()
|
||||
self.stdout.write(f"{payment_obj} is validated")
|
@ -3,13 +3,45 @@
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import ModelAdmin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from polymorphic.admin import PolymorphicChildModelAdmin, PolymorphicChildModelFilter, PolymorphicParentModelAdmin
|
||||
from polymorphic.admin import PolymorphicChildModelAdmin, PolymorphicChildModelFilter, PolymorphicParentModelAdmin, \
|
||||
PolymorphicInlineSupportMixin, StackedPolymorphicInline
|
||||
|
||||
from .models import CoachRegistration, ParticipantRegistration, Payment, Registration, \
|
||||
StudentRegistration, VolunteerRegistration
|
||||
|
||||
|
||||
class RegistrationInline(StackedPolymorphicInline):
|
||||
class StudentRegistrationInline(StackedPolymorphicInline.Child):
|
||||
model = StudentRegistration
|
||||
autocomplete_fields = ('team',)
|
||||
show_change_link = True
|
||||
|
||||
class CoachRegistrationInline(StackedPolymorphicInline.Child):
|
||||
model = CoachRegistration
|
||||
autocomplete_fields = ('team',)
|
||||
show_change_link = True
|
||||
|
||||
class VolunteerRegistrationInline(StackedPolymorphicInline.Child):
|
||||
model = VolunteerRegistration
|
||||
show_change_link = True
|
||||
|
||||
model = Registration
|
||||
child_inlines = (
|
||||
StudentRegistrationInline,
|
||||
CoachRegistrationInline,
|
||||
VolunteerRegistrationInline,
|
||||
)
|
||||
|
||||
|
||||
class PaymentInline(admin.TabularInline):
|
||||
model = Payment
|
||||
extra = 0
|
||||
autocomplete_fields = ('registrations',)
|
||||
|
||||
|
||||
@admin.register(Registration)
|
||||
class RegistrationAdmin(PolymorphicParentModelAdmin):
|
||||
child_models = (StudentRegistration, CoachRegistration, VolunteerRegistration,)
|
||||
@ -97,12 +129,34 @@ class VolunteerRegistrationAdmin(PolymorphicChildModelAdmin):
|
||||
|
||||
@admin.register(Payment)
|
||||
class PaymentAdmin(ModelAdmin):
|
||||
list_display = ('id', 'concerned_people', 'grouped', 'type', 'valid', )
|
||||
search_fields = ('registrations__user__last_name', 'registrations__user__first_name', 'registrations__user__email',)
|
||||
list_display = ('concerned_people', 'tournament', 'team', 'grouped', 'type', 'amount', 'valid', )
|
||||
search_fields = ('registrations__user__last_name', 'registrations__user__first_name', 'registrations__user__email',
|
||||
'registrations__team__name', 'registrations__team__participation__team__trigram',)
|
||||
list_filter = ('registrations__team__participation__valid', 'type',
|
||||
'grouped', 'valid', 'registrations__polymorphic_ctype',)
|
||||
'grouped', 'valid', 'registrations__team__participation__tournament', 'final',)
|
||||
autocomplete_fields = ('registrations',)
|
||||
actions = ('mark_as_valid', 'mark_as_pending', 'mark_as_invalid',)
|
||||
|
||||
@admin.display(description=_('concerned people'))
|
||||
def concerned_people(self, record: Payment):
|
||||
return ", ".join(f"{reg.user.first_name} {reg.user.last_name}" for reg in record.registrations.all())
|
||||
|
||||
@admin.action(description=_('Mark as valid'))
|
||||
def mark_as_valid(self, request, queryset):
|
||||
queryset.update(valid=True)
|
||||
|
||||
@admin.action(description=_('Mark as pending'))
|
||||
def mark_as_pending(self, request, queryset):
|
||||
queryset.update(valid=None)
|
||||
|
||||
@admin.action(description=_('Mark as invalid'))
|
||||
def mark_as_invalid(self, request, queryset):
|
||||
queryset.update(valid=False)
|
||||
|
||||
|
||||
admin.site.unregister(User)
|
||||
|
||||
|
||||
@admin.register(User)
|
||||
class UserCustomAdmin(PolymorphicInlineSupportMixin, UserAdmin):
|
||||
inlines = [RegistrationInline]
|
||||
|
25
registration/management/commands/check_hello_asso.py
Normal file
25
registration/management/commands/check_hello_asso.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2024 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import json
|
||||
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from registration.models import Payment
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
This command checks if the initiated Hello Asso payments are validated or not.
|
||||
"""
|
||||
help = "Vérifie si les paiements Hello Asso initiés sont validés ou non. Si oui, valide les inscriptions."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for payment in Payment.objects.exclude(valid=True).filter(checkout_intent_id__isnull=False).all():
|
||||
checkout_intent = payment.get_checkout_intent()
|
||||
if checkout_intent is not None and 'order' in checkout_intent:
|
||||
payment.type = 'helloasso'
|
||||
payment.valid = True
|
||||
payment.additional_information = json.dumps(checkout_intent['order'])
|
||||
payment.save()
|
||||
payment.send_helloasso_payment_confirmation_mail()
|
17
registration/management/commands/remind_payments.py
Normal file
17
registration/management/commands/remind_payments.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2024 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from registration.models import Payment
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
This command sends a mail to each participant who has not yet paid.
|
||||
"""
|
||||
help = "Envoie un mail de rappel à toustes les participant⋅es qui n'ont pas encore payé ou déclaré de paiement."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for payment in Payment.objects.filter(valid=False).filter(registrations__team__participation__valid=True).all():
|
||||
payment.send_remind_mail()
|
@ -4,11 +4,12 @@
|
||||
from datetime import date, datetime
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.mail import send_mail
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.template import loader
|
||||
from django.urls import reverse_lazy, reverse
|
||||
from django.utils import timezone
|
||||
from django.utils import timezone, translation
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.http import urlsafe_base64_encode
|
||||
@ -588,6 +589,8 @@ class Payment(models.Model):
|
||||
@property
|
||||
def team(self):
|
||||
return self.registrations.first().team
|
||||
team.fget.short_description = _("team")
|
||||
team.fget.admin_order_field = 'registrations__team__trigram'
|
||||
|
||||
@property
|
||||
def tournament(self):
|
||||
@ -595,6 +598,8 @@ class Payment(models.Model):
|
||||
from participation.models import Tournament
|
||||
return Tournament.final_tournament()
|
||||
return self.registrations.first().team.participation.tournament
|
||||
tournament.fget.short_description = _("tournament")
|
||||
tournament.fget.admin_order_field = 'registrations__team__participation__tournament'
|
||||
|
||||
def get_checkout_intent(self, none_if_link_disabled=False):
|
||||
if self.checkout_intent_id is None:
|
||||
@ -634,6 +639,37 @@ class Payment(models.Model):
|
||||
|
||||
return checkout_intent
|
||||
|
||||
def send_remind_mail(self):
|
||||
translation.activate('fr')
|
||||
subject = "[TFJM²] " + str(_("Reminder for your payment"))
|
||||
site = Site.objects.first()
|
||||
for registration in self.registrations.all():
|
||||
message = loader.render_to_string('registration/mails/payment_reminder.txt',
|
||||
dict(registration=registration, payment=self, domain=site.domain))
|
||||
html = loader.render_to_string('registration/mails/payment_reminder.html',
|
||||
dict(registration=registration, payment=self, domain=site.domain))
|
||||
registration.user.email_user(subject, message, html_message=html)
|
||||
|
||||
def send_helloasso_payment_confirmation_mail(self):
|
||||
translation.activate('fr')
|
||||
subject = "[TFJM²] " + str(_("Payment confirmation"))
|
||||
site = Site.objects.first()
|
||||
for registration in self.registrations.all():
|
||||
message = loader.render_to_string('registration/mails/payment_confirmation.txt',
|
||||
dict(registration=registration, payment=self, domain=site.domain))
|
||||
html = loader.render_to_string('registration/mails/payment_confirmation.html',
|
||||
dict(registration=registration, payment=self, domain=site.domain))
|
||||
registration.user.email_user(subject, message, html_message=html)
|
||||
|
||||
payer = self.get_checkout_intent()['order']['payer']
|
||||
payer_name = f"{payer['firstName']} {payer['lastName']}"
|
||||
if not self.registrations.filter(user__email=payer['email']).exists():
|
||||
message = loader.render_to_string('registration/mails/payment_confirmation.txt',
|
||||
dict(registration=payer_name, payment=self, domain=site.domain))
|
||||
html = loader.render_to_string('registration/mails/payment_confirmation.html',
|
||||
dict(registration=payer_name, payment=self, domain=site.domain))
|
||||
send_mail(subject, message, None, [payer['email']], html_message=html)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse_lazy("registration:update_payment", args=(self.pk,))
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
<body>
|
||||
<p>
|
||||
{% trans "Hi" %} {{ user.registration }},
|
||||
{% trans "Hi" %} {{ registration }},
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -28,7 +28,7 @@
|
||||
<ul>
|
||||
<li>{% trans "Deadline to send the solutions:" %} {{ payment.tournament.solution_limit|date }}</li>
|
||||
<li>{% trans "Problems draw:" %} {{ payment.tournament.solutions_draw|date }}</li>
|
||||
<li>{% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.start|date }} {% trans "to" %} {{ payment.tournament.end|date }}</li>
|
||||
<li>{% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.date_start|date }} {% trans "to" %} {{ payment.tournament.date_end|date }}</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% trans "Hi" %} {{ user.registration }},
|
||||
{% trans "Hi" %} {{ registration|safe }},
|
||||
|
||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament.name %}
|
||||
We successfully received the payment of {{ amount }} € for the TFJM² registration in the team {{ team }} for the tournament {{ tournament }}!
|
||||
@ -12,7 +11,7 @@ We successfully received the payment of {{ amount }} € for the TFJM² registra
|
||||
{% trans "As a reminder, here are the following important dates:" %}
|
||||
* {% trans "Deadline to send the solutions:" %} {{ payment.tournament.solution_limit|date }}
|
||||
* {% trans "Problems draw:" %} {{ payment.tournament.solutions_draw|date }}
|
||||
* {% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.start|date }} {% trans "to" %} {{ payment.tournament.end|date }}
|
||||
* {% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.date_start|date }} {% trans "to" %} {{ payment.tournament.date_end|date }}
|
||||
|
||||
{% trans "Please note that these dates may be subject to change. If your local organizers gave you different dates, trust them." %}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
<body>
|
||||
<p>
|
||||
{% trans "Hi" %} {{ user.registration }},
|
||||
{% trans "Hi" %} {{ registration }},
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -19,19 +19,19 @@
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{% if payment.grouped %}
|
||||
{% if payment.grouped %}
|
||||
<p>
|
||||
{% trans "This price includes the registrations of all members of your team." %}
|
||||
{% endif %}
|
||||
</p>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
{% trans "You can pay by credit card or by bank transfer. You can read full instructions on the payment page:" %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://{{ domain }}{% url "registration.update_payment" pk=payment.pk %}">
|
||||
https://{{ domain }}{% url "registration.update_payment" pk=payment.pk %}
|
||||
<a href="https://{{ domain }}{% url "registration:update_payment" pk=payment.pk %}">
|
||||
https://{{ domain }}{% url "registration:update_payment" pk=payment.pk %}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
@ -1,19 +1,16 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% trans "Hi" %} {{ user.registration }},
|
||||
{% trans "Hi" %} {{ registration|safe }},
|
||||
|
||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament %}
|
||||
You are registered for the TFJM² of {{ tournament }}. Your team {{ team }} has been successfully validated.
|
||||
To end your inscription, you must pay the amount of {{ amount }} €.
|
||||
{% endblocktrans %}
|
||||
|
||||
{% if payment.grouped %}
|
||||
{% trans "This price includes the registrations of all members of your team." %}
|
||||
{% endif %}
|
||||
|
||||
{% trans "You can pay by credit card or by bank transfer. You can read full instructions on the payment page:" %}
|
||||
|
||||
https://{{ domain }}{% url "registration.update_payment" pk=payment.pk %}
|
||||
https://{{ domain }}{% url "registration:update_payment" pk=payment.pk %}
|
||||
|
||||
{% trans "If you have a scholarship, then the registration is free for you. You must then upload it on the payment page using the above link." %}
|
||||
|
||||
|
@ -623,6 +623,7 @@ class PaymentHelloAssoReturnView(DetailView):
|
||||
payment.save()
|
||||
messages.success(request, _("The payment has been successfully validated! "
|
||||
"Your registration is now complete."))
|
||||
payment.send_helloasso_payment_confirmation_mail()
|
||||
else:
|
||||
payment.type = "helloasso"
|
||||
payment.valid = None
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
# Check payments from Hello Asso
|
||||
*/6 * * * * cd /code && python manage.py check_hello_asso &> /dev/null
|
||||
# Send reminders for payments
|
||||
30 6 * * 1 cd /code && python manage.py remind_payments &> /dev/null
|
||||
|
||||
# Clean temporary files
|
||||
30 * * * * rm -rf /tmp/*
|
||||
|
@ -46,7 +46,7 @@ def get_hello_asso_access_token():
|
||||
return _access_token
|
||||
|
||||
if response.status_code == 400:
|
||||
raise ValueError(str(response.json()['errors']))
|
||||
raise ValueError(str(response.json()))
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
|
Loading…
x
Reference in New Issue
Block a user