1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-05-19 12:11:21 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Emmy D'Anello
01ba0a1df9
Replace assertEquals by assertEqual (deprecated and removed in Python 3.12)
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-02-24 23:10:06 +01:00
Emmy D'Anello
207af441a0
Add payment interface tests
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-02-24 23:05:21 +01:00
Emmy D'Anello
2a2786ba6d
Add payment information after payment
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-02-24 22:58:06 +01:00
8 changed files with 703 additions and 184 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,11 @@
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.test import TestCase
from django.urls import reverse
from registration.models import CoachRegistration, StudentRegistration
from registration.models import CoachRegistration, Payment, StudentRegistration
from .models import Participation, Team, Tournament
@ -515,6 +516,365 @@ class TestStudentParticipation(TestCase):
self.assertEqual(resp.status_code, 403)
class TestPayment(TestCase):
"""
Tests that are relative to a payment
"""
def setUp(self):
self.superuser = User.objects.create_superuser(
username="admin",
email="admin@example.com",
password="admin",
)
self.tournament = Tournament.objects.create(
name="France",
place="Here",
price=21,
)
self.team = Team.objects.create(
name="Super team",
trigram="AAA",
access_code="azerty",
)
self.user = User.objects.create(
first_name="Toto",
last_name="Toto",
email="toto@example.com",
password="toto",
)
StudentRegistration.objects.create(
user=self.user,
team=self.team,
student_class=12,
address="1 Rue de Rivoli",
zip_code=75001,
city="Paris",
school="Earth",
give_contact_to_animath=True,
email_confirmed=True,
)
self.second_user = User.objects.create(
first_name="Lalala",
last_name="Lalala",
email="lalala@example.com",
password="lalala",
)
StudentRegistration.objects.create(
user=self.second_user,
team=self.team,
student_class=11,
address="1 Rue de Rivoli",
zip_code=75001,
city="Paris",
school="Moon",
give_contact_to_animath=True,
email_confirmed=True,
)
self.coach = User.objects.create(
first_name="Coach",
last_name="Coach",
email="coach@example.com",
password="coach",
)
CoachRegistration.objects.create(
user=self.coach,
team=self.team,
address="1 Rue de Rivoli",
zip_code=75001,
city="Paris",
)
self.team.participation.tournament = self.tournament
self.team.participation.valid = True
self.team.participation.save()
self.client.force_login(self.user)
def test_check_payments_exists(self):
"""
Check that users in a validated team have an invalid payment, but not for the final,
and that coaches are not concerned.
"""
self.assertTrue(Payment.objects.filter(final=False, valid=False, type='',
registrations=self.user.registration).exists())
self.assertTrue(Payment.objects.filter(final=False, valid=False, type='',
registrations=self.second_user.registration).exists())
self.assertFalse(Payment.objects.filter(final=False, valid=False, type='',
registrations=self.coach.registration).exists())
self.assertFalse(Payment.objects.filter(final=True, valid=False, type='',
registrations=self.user.registration).exists())
self.assertFalse(Payment.objects.filter(final=True, valid=False, type='',
registrations=self.second_user.registration).exists())
self.assertFalse(Payment.objects.filter(final=True, valid=False, type='',
registrations=self.coach.registration).exists())
def test_load_payment_page(self):
"""
Ensure that the payment page loads correctly.
"""
response = self.client.get(reverse('participation:team_detail', args=(self.team.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('registration:user_detail', args=(self.user.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('participation:tournament_payments', args=(self.tournament.pk,)))
self.assertEqual(response.status_code, 403)
payment = Payment.objects.get(registrations=self.user.registration, final=False)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
def test_bank_transfer_payment(self):
"""
Try to send a bank transfer.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "bank_transfer",
'additional_information': "This is a bank transfer"})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["This field is required.", "You must upload your receipt."])
payment.refresh_from_db()
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
# README is not a valid PDF file
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "bank_transfer",
'additional_information': "This is a bank transfer",
'receipt': open("README.md", "rb")})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["The uploaded file must be a PDF, PNG of JPEG file."])
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
# Don't send too large files
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "bank_transfer",
'additional_information': "This is a bank transfer",
'receipt': SimpleUploadedFile(
"file.pdf",
content=int(0).to_bytes(2000001, "big"),
content_type="application/pdf"),
})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["The uploaded file size must be under 2 Mo."])
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "bank_transfer",
'additional_information': "This is a bank transfer",
'receipt': open("tfjm/static/Fiche_sanitaire.pdf", "rb")})
self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200)
payment.refresh_from_db()
self.assertIsNone(payment.valid)
self.assertEqual(payment.type, "bank_transfer")
self.assertEqual(payment.additional_information, "This is a bank transfer")
self.assertIsNotNone(payment.receipt)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
def test_scholarship(self):
"""
Try to don't pay because of a scholarship.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "scholarship",
'additional_information': "I don't have to pay because I have a scholarship"})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["This field is required.", "You must upload your receipt."])
payment.refresh_from_db()
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
self.assertEqual(payment.amount, self.tournament.price)
# README is not a valid PDF file
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "scholarship",
'additional_information': "I don't have to pay because I have a scholarship",
'receipt': open("README.md", "rb")})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["The uploaded file must be a PDF, PNG of JPEG file."])
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
self.assertEqual(payment.amount, self.tournament.price)
# Don't send too large files
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "scholarship",
'additional_information': "I don't have to pay because I have a scholarship",
'receipt': SimpleUploadedFile(
"file.pdf",
content=int(0).to_bytes(2000001, "big"),
content_type="application/pdf"),
})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'receipt',
["The uploaded file size must be under 2 Mo."])
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
self.assertEqual(payment.amount, self.tournament.price)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "scholarship",
'additional_information': "I don't have to pay because I have a scholarship",
'receipt': open("tfjm/static/Fiche_sanitaire.pdf", "rb")})
self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200)
payment.refresh_from_db()
self.assertIsNone(payment.valid)
self.assertEqual(payment.type, "scholarship")
self.assertEqual(payment.additional_information, "I don't have to pay because I have a scholarship")
self.assertIsNotNone(payment.receipt)
self.assertEqual(payment.amount, 0)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
def test_other(self):
"""
Try to send a different type of payment.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "other"})
self.assertEqual(response.status_code, 200)
self.assertFormError(response.context['form'], 'additional_information',
["This field is required."])
payment.refresh_from_db()
self.assertFalse(payment.valid)
self.assertEqual(payment.type, "")
self.assertEqual(payment.amount, self.tournament.price)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'type': "other",
'additional_information': "Why should I pay"})
self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200)
payment.refresh_from_db()
self.assertIsNone(payment.valid)
self.assertEqual(payment.type, "other")
self.assertEqual(payment.additional_information, "Why should I pay")
self.assertIsNotNone(payment.receipt)
self.assertEqual(payment.amount, self.tournament.price)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
def test_group(self):
payment = Payment.objects.get(registrations=self.user.registration, final=False)
self.assertFalse(payment.grouped)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,)))
self.assertRedirects(response, reverse('registration:update_payment', args=(payment.pk,)), 302, 200)
payment.refresh_from_db()
self.assertTrue(payment.grouped)
self.assertEqual(Payment.objects.count(), 1)
self.assertIn(self.user.registration, payment.registrations.all())
self.assertIn(self.second_user.registration, payment.registrations.all())
self.assertEqual(payment.amount, 2 * self.tournament.price)
def test_ungroup(self):
"""
Test to ungroup payments
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,)))
payment.refresh_from_db()
self.assertTrue(payment.grouped)
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,)))
self.assertRedirects(response, reverse('registration:update_payment', args=(payment.pk,)), 302, 200)
payment.refresh_from_db()
self.assertFalse(payment.grouped)
self.assertEqual(Payment.objects.count(), 2)
self.assertIn(self.user.registration, payment.registrations.all())
self.assertNotIn(self.second_user.registration, payment.registrations.all())
self.assertEqual(payment.amount, self.tournament.price)
def test_group_forbidden(self):
"""
Payment grouping is forbidden if at least one payment is already valid.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
payment.valid = True
payment.save()
payment2 = Payment.objects.get(registrations=self.second_user.registration, final=False)
response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,)))
self.assertEqual(response.status_code, 403)
response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment2.pk,)))
self.assertEqual(response.status_code, 403)
def test_validate_payment(self):
"""
Try to validate a payment.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
payment.type = "other"
payment.valid = None
payment.save()
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'valid': True})
self.assertEqual(response.status_code, 403)
self.assertFalse(payment.valid)
self.client.force_login(self.superuser)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'valid': True})
self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200)
payment.refresh_from_db()
self.assertTrue(payment.valid)
def test_invalidate_payment(self):
"""
Try to invalidate a payment.
"""
payment = Payment.objects.get(registrations=self.user.registration, final=False)
payment.type = "other"
payment.valid = None
payment.save()
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
self.assertEqual(response.status_code, 200)
self.client.force_login(self.superuser)
response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)),
data={'valid': False})
self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200)
payment.refresh_from_db()
self.assertFalse(payment.valid)
class TestAdmin(TestCase):
def setUp(self) -> None:
self.user = User.objects.create_superuser(

View File

@ -12,8 +12,8 @@ class RegistrationConfig(AppConfig):
name = 'registration'
def ready(self):
from registration.signals import create_admin_registration, \
set_username, send_email_link
pre_save.connect(set_username, "auth.User")
pre_save.connect(send_email_link, "auth.User")
post_save.connect(create_admin_registration, "auth.User")
from registration import signals
pre_save.connect(signals.set_username, 'auth.User')
pre_save.connect(signals.send_email_link, 'auth.User')
pre_save.connect(signals.update_payment_amount, 'registration.Payment')
post_save.connect(signals.create_admin_registration, 'auth.User')

View File

@ -226,6 +226,9 @@ class PaymentAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["valid"].widget.choices[0] = ('unknown', _("Pending"))
payment_type = kwargs.get('data', {}).get('type', "")
self.fields['receipt'].required = payment_type in ["scholarship", "bank_transfer"]
self.fields['additional_information'].required = payment_type in ["other"]
def clean_receipt(self):
if "receipt" in self.files:

View File

@ -387,7 +387,7 @@ class StudentRegistration(ParticipantRegistration):
'priority': 3,
'content': content,
})
elif self.payment.valid is None:
elif payment.valid is None:
text = _("Your payment is under approval.")
content = text
informations.append({

View File

@ -41,3 +41,13 @@ def create_admin_registration(instance, **_):
"""
if instance.is_superuser:
VolunteerRegistration.objects.get_or_create(user=instance, admin=True)
def update_payment_amount(instance, **_):
"""
When a payment got created, ensure that the amount is set.
"""
if instance.type == 'free' or instance.type == 'scholarship':
instance.amount = 0
elif instance.pk:
instance.amount = instance.registrations.count() * instance.tournament.price

View File

@ -201,13 +201,82 @@
</div>
</div>
{% else %}
<form method="post" enctype="multipart/form-data">
<div id="form-content">
{% csrf_token %}
{{ form|crispy }}
</div>
<button class="btn btn-primary" type="submit">{% trans "Update" %}</button>
</form>
{% if user.registration.is_volunteer %}
<form method="post" enctype="multipart/form-data">
<div id="form-content">
{% csrf_token %}
{{ form|crispy }}
</div>
<button class="btn btn-primary" type="submit">{% trans "Update" %}</button>
</form>
{% else %}
{% if payment.type == 'helloasso' %}
{% if payment.valid is True %}
<div class="alert alert-success">
{% with order=payment.get_checkout_intent.order %}
{% trans "Your payment by credit card via Hello Asso is successfully validated." %}
{% trans "The paid amount is" %} {% widthratio order.amount.total 100 1 %} €.
{% if grouped %}
{% trans "It includes the registrations of all members of the team." %}
{% endif %}
{% trans "The payer was " %} {{ order.payer.firstName }} {{ order.payer.lastName }}.
{% trans "The payment was done on" %} {{ order.date }}.
{% endwith %}
</div>
{% elif payment.valid is None %}
<div class="alert alert-warning">
{% trans "The payment by credit card via Hello Asso is pending validation." %}
{% trans "It should takes only few minutes. If it takes longer, please contact us." %}
</div>
{% endif %}
{% else %}
{% if payment.valid is True %}
<div class="alert alert-success">
{% trans "Your payment is successfully validated by the organizers." %}
<ul>
<li>{% trans "Type:" %} {{ payment.get_type_display }}</li>
<li>
{% trans "Amount:" %} {{ payment.amount }} €
{% if payment.grouped %}
({% trans "It includes the registrations of all members of the team." %})
{% endif %}
</li>
{% if payment.receipt %}
<li>
{% trans "Receipt:" %}
<a href="{{ payment.receipt.url }}"><i class="fas fa-download"></i> {% trans "Download" %}</a>
</li>
{% endif %}
{% if payment.additional_information %}
<li>{% trans "Additional information:" %} {{ payment.additional_information }}</li>
{% endif %}
</ul>
</div>
{% elif payment.valid is None %}
<div class="alert alert-warning">
{% trans "Your payment is pending validation from the organizers." %}
<ul>
<li>{% trans "Type:" %} {{ payment.get_type_display }}</li>
<li>
{% trans "Amount:" %} {{ payment.amount }} €
{% if payment.grouped %}
({% trans "It includes the registrations of all members of the team." %})
{% endif %}
</li>
{% if payment.receipt %}
<li>
{% trans "Receipt:" %}
<a href="{{ payment.receipt.url }}"><i class="fas fa-download"></i> {% trans "Download" %}</a>
</li>
{% endif %}
{% if payment.additional_information %}
<li>{% trans "Additional information:" %} {{ payment.additional_information }}</li>
{% endif %}
</ul>
</div>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endblock content %}

View File

@ -451,8 +451,7 @@ class PaymentUpdateView(LoginRequiredMixin, UpdateView):
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_authenticated or \
not self.request.user.registration.is_admin \
and (self.request.user.registration not in self.get_object().registrations.all()
or self.get_object().valid is not False):
and self.request.user.registration not in self.get_object().registrations.all():
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
@ -477,8 +476,12 @@ class PaymentUpdateView(LoginRequiredMixin, UpdateView):
return context
def form_valid(self, form):
form.instance.valid = None
old_instance = Payment.objects.get(pk=self.object.pk)
if self.request.user.registration.participates:
if old_instance.valid is not False:
raise PermissionDenied(_("This payment is already valid or pending validation."))
else:
form.instance.valid = None
if old_instance.receipt:
old_instance.receipt.delete()
old_instance.save()