mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-05-20 04:51:25 +00:00
Compare commits
No commits in common. "83300ad4b75483ceb8e50d0ffcf1ac2cc46cc769" and "01ba0a1df9d4f14a4ba3648025e2c07ca94cb9cd" have entirely different histories.
83300ad4b7
...
01ba0a1df9
@ -6,7 +6,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.test import LiveServerTestCase, override_settings, TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from registration.models import CoachRegistration, Payment, StudentRegistration
|
from registration.models import CoachRegistration, Payment, StudentRegistration
|
||||||
|
|
||||||
@ -875,208 +875,6 @@ class TestPayment(TestCase):
|
|||||||
self.assertFalse(payment.valid)
|
self.assertFalse(payment.valid)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(HELLOASSO_TEST_ENDPOINT=True, ROOT_URLCONF="tfjm.helloasso.test_urls")
|
|
||||||
class TestHelloAssoPayment(LiveServerTestCase):
|
|
||||||
"""
|
|
||||||
Tests that are relative to a HelloAsso
|
|
||||||
"""
|
|
||||||
|
|
||||||
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.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)
|
|
||||||
|
|
||||||
Site.objects.update(domain=self.live_server_url.replace("http://", ""))
|
|
||||||
|
|
||||||
def test_create_checkout_intent(self):
|
|
||||||
with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url):
|
|
||||||
payment = Payment.objects.get(registrations=self.user.registration, final=False)
|
|
||||||
checkout_intent = payment.create_checkout_intent()
|
|
||||||
|
|
||||||
self.assertIsNotNone(checkout_intent)
|
|
||||||
self.assertEqual(checkout_intent['metadata'], {
|
|
||||||
'payment_id': payment.pk,
|
|
||||||
'users': [
|
|
||||||
{
|
|
||||||
'user_id': self.user.pk,
|
|
||||||
'first_name': self.user.first_name,
|
|
||||||
'last_name': self.user.last_name,
|
|
||||||
'email': self.user.email,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'final': False,
|
|
||||||
'tournament_id': self.tournament.pk,
|
|
||||||
})
|
|
||||||
self.assertNotIn('order', checkout_intent)
|
|
||||||
|
|
||||||
checkout_intent_fetched = payment.get_checkout_intent()
|
|
||||||
self.assertEqual(checkout_intent, checkout_intent_fetched)
|
|
||||||
|
|
||||||
# Don't create a new checkout intent if one already exists
|
|
||||||
checkout_intent_new = payment.create_checkout_intent()
|
|
||||||
self.assertEqual(checkout_intent, checkout_intent_new)
|
|
||||||
|
|
||||||
payment.refresh_from_db()
|
|
||||||
self.assertEqual(payment.checkout_intent_id, checkout_intent['id'])
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
def test_helloasso_payment_success(self):
|
|
||||||
"""
|
|
||||||
Simulates the redirection to Hello Asso and the return for a successful payment.
|
|
||||||
"""
|
|
||||||
with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url):
|
|
||||||
payment = Payment.objects.get(registrations=self.user.registration, final=False)
|
|
||||||
self.assertIsNone(payment.checkout_intent_id)
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
response = self.client.get(reverse('registration:payment_hello_asso', args=(payment.pk,)),
|
|
||||||
follow=True)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response.redirect_chain[-1],
|
|
||||||
(reverse('participation:team_detail', args=(self.team.pk,)), 302))
|
|
||||||
self.assertIn("type=return", response.redirect_chain[1][0])
|
|
||||||
self.assertIn("code=succeeded", response.redirect_chain[1][0])
|
|
||||||
|
|
||||||
payment.refresh_from_db()
|
|
||||||
self.assertIsNotNone(payment.checkout_intent_id)
|
|
||||||
self.assertTrue(payment.valid)
|
|
||||||
|
|
||||||
checkout_intent = payment.get_checkout_intent()
|
|
||||||
self.assertIn('order', checkout_intent)
|
|
||||||
|
|
||||||
def test_helloasso_payment_refused(self):
|
|
||||||
"""
|
|
||||||
Simulates the redirection to Hello Asso and the return for a refused payment.
|
|
||||||
"""
|
|
||||||
with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url):
|
|
||||||
payment = Payment.objects.get(registrations=self.user.registration, final=False)
|
|
||||||
checkout_intent = payment.create_checkout_intent()
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
response = self.client.get(checkout_intent['redirectUrl'] + "?refused", follow=True)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response.redirect_chain[-1],
|
|
||||||
(reverse('registration:update_payment', args=(payment.pk,)), 302))
|
|
||||||
self.assertIn("type=return", response.redirect_chain[0][0])
|
|
||||||
self.assertIn("code=refused", response.redirect_chain[0][0])
|
|
||||||
|
|
||||||
payment.refresh_from_db()
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
checkout_intent = payment.get_checkout_intent()
|
|
||||||
self.assertNotIn('order', checkout_intent)
|
|
||||||
|
|
||||||
def test_helloasso_payment_error(self):
|
|
||||||
"""
|
|
||||||
Simulates the redirection to Hello Asso and the return for an errored payment.
|
|
||||||
"""
|
|
||||||
with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url):
|
|
||||||
payment = Payment.objects.get(registrations=self.user.registration, final=False)
|
|
||||||
checkout_intent = payment.create_checkout_intent()
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
response = self.client.get(reverse('registration:update_payment', args=(payment.pk,)))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
response = self.client.get(checkout_intent['redirectUrl'] + "?error", follow=True)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response.redirect_chain[-1],
|
|
||||||
(reverse('registration:update_payment', args=(payment.pk,)), 302))
|
|
||||||
self.assertIn("type=error", response.redirect_chain[0][0])
|
|
||||||
self.assertIn("error=", response.redirect_chain[0][0])
|
|
||||||
|
|
||||||
payment.refresh_from_db()
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
checkout_intent = payment.get_checkout_intent()
|
|
||||||
self.assertNotIn('order', checkout_intent)
|
|
||||||
|
|
||||||
def test_anonymous_payment(self):
|
|
||||||
"""
|
|
||||||
Test to make a successful payment from an anonymous user, authenticated by token.
|
|
||||||
"""
|
|
||||||
self.client.logout()
|
|
||||||
|
|
||||||
with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url):
|
|
||||||
payment = Payment.objects.get(registrations=self.user.registration, final=False)
|
|
||||||
self.assertIsNone(payment.checkout_intent_id)
|
|
||||||
self.assertFalse(payment.valid)
|
|
||||||
|
|
||||||
response = self.client.get(reverse('registration:payment_hello_asso', args=(payment.pk,)),
|
|
||||||
follow=True)
|
|
||||||
self.assertRedirects(response,
|
|
||||||
f"{reverse('login')}?next="
|
|
||||||
f"{reverse('registration:payment_hello_asso', args=(payment.pk,))}")
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse('registration:payment_hello_asso', args=(payment.pk,)) + "?token=" + payment.token,
|
|
||||||
follow=True)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response.redirect_chain[-1], (reverse('index'), 302))
|
|
||||||
self.assertIn("type=return", response.redirect_chain[1][0])
|
|
||||||
self.assertIn("code=succeeded", response.redirect_chain[1][0])
|
|
||||||
|
|
||||||
payment.refresh_from_db()
|
|
||||||
self.assertIsNotNone(payment.checkout_intent_id)
|
|
||||||
self.assertTrue(payment.valid)
|
|
||||||
|
|
||||||
checkout_intent = payment.get_checkout_intent()
|
|
||||||
self.assertIn('order', checkout_intent)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAdmin(TestCase):
|
class TestAdmin(TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = User.objects.create_superuser(
|
self.user = User.objects.create_superuser(
|
||||||
|
@ -6,15 +6,14 @@ from datetime import datetime, timedelta
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
_access_token = None
|
_access_token = None
|
||||||
_refresh_token = None
|
_refresh_token = None
|
||||||
_expires_at = None
|
_expires_at = None
|
||||||
|
|
||||||
|
|
||||||
def _get_hello_asso_api_base_url():
|
def _get_hello_asso_api_base_url():
|
||||||
if settings.HELLOASSO_TEST_ENDPOINT:
|
if not settings.DEBUG:
|
||||||
return f"{settings.HELLOASSO_TEST_ENDPOINT_URL}/helloasso-test/api"
|
|
||||||
elif not settings.DEBUG:
|
|
||||||
return "https://api.helloasso.com"
|
return "https://api.helloasso.com"
|
||||||
else:
|
else:
|
||||||
return "https://api.helloasso-sandbox.com"
|
return "https://api.helloasso-sandbox.com"
|
@ -1,23 +0,0 @@
|
|||||||
# Copyright (C) 2024 by Animath
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
from django.urls import path
|
|
||||||
import tfjm.urls
|
|
||||||
|
|
||||||
from . import test_views
|
|
||||||
|
|
||||||
urlpatterns = tfjm.urls.urlpatterns
|
|
||||||
|
|
||||||
urlpatterns += [
|
|
||||||
path('helloasso-test/api/oauth2/token', test_views.TestHelloAssoOAuth2View.as_view(),
|
|
||||||
name='helloasso-test-oauth2-token'),
|
|
||||||
path('helloasso-test/api/v5/organizations/animath/checkout-intents/',
|
|
||||||
test_views.TestHelloAssoCheckoutIntentCreateView.as_view(),
|
|
||||||
name='helloasso-test-checkout-intent-create'),
|
|
||||||
path('helloasso-test/api/v5/organizations/animath/checkout-intents/<int:checkout_intent_id>/',
|
|
||||||
test_views.TestHelloAssoCheckoutIntentDetailView.as_view(),
|
|
||||||
name='helloasso-test-checkout-intent-detail'),
|
|
||||||
path('helloasso-test/redirect-payment/<int:checkout_intent_id>/',
|
|
||||||
test_views.TestHelloAssoRedirectPaymentView.as_view(),
|
|
||||||
name='helloasso-test-redirect-payment'),
|
|
||||||
]
|
|
@ -1,149 +0,0 @@
|
|||||||
# Copyright (C) 2024 by Animath
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.http import Http404, HttpResponse, JsonResponse
|
|
||||||
from django.shortcuts import redirect
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
|
||||||
from django.views.generic.base import View
|
|
||||||
|
|
||||||
_CHECKOUT_INTENTS = {}
|
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(csrf_exempt, name='dispatch')
|
|
||||||
class TestHelloAssoOAuth2View(View):
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
data = {
|
|
||||||
'access_token': 'test_access_token',
|
|
||||||
'refresh_token': 'test_refresh_token',
|
|
||||||
'expires_in': 3600,
|
|
||||||
}
|
|
||||||
return JsonResponse(data)
|
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(csrf_exempt, name='dispatch')
|
|
||||||
class TestHelloAssoCheckoutIntentCreateView(View):
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
checkout_intent_id = len(_CHECKOUT_INTENTS) + 1
|
|
||||||
body = json.loads(request.body.decode())
|
|
||||||
|
|
||||||
body['backUrl'] = body['backUrl'].replace("https", "http")
|
|
||||||
body['returnUrl'] = body['returnUrl'].replace("https", "http")
|
|
||||||
body['errorUrl'] = body['errorUrl'].replace("https", "http")
|
|
||||||
|
|
||||||
output_data = {
|
|
||||||
'id': checkout_intent_id,
|
|
||||||
'redirectUrl': f"{settings.HELLOASSO_TEST_ENDPOINT_URL}"
|
|
||||||
f"{reverse('helloasso-test-redirect-payment', args=(checkout_intent_id,))}",
|
|
||||||
'metadata': body['metadata'],
|
|
||||||
}
|
|
||||||
|
|
||||||
checkout_intent = {'input': body, 'output': output_data}
|
|
||||||
_CHECKOUT_INTENTS[checkout_intent_id] = checkout_intent
|
|
||||||
|
|
||||||
return JsonResponse(output_data)
|
|
||||||
|
|
||||||
|
|
||||||
class TestHelloAssoCheckoutIntentDetailView(View):
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
checkout_intent_id = kwargs['checkout_intent_id']
|
|
||||||
if checkout_intent_id not in _CHECKOUT_INTENTS:
|
|
||||||
raise Http404
|
|
||||||
return JsonResponse(_CHECKOUT_INTENTS[checkout_intent_id]['output'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestHelloAssoRedirectPaymentView(View):
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
checkout_intent_id = kwargs['checkout_intent_id']
|
|
||||||
if checkout_intent_id not in _CHECKOUT_INTENTS:
|
|
||||||
raise Http404
|
|
||||||
|
|
||||||
checkout_intent = _CHECKOUT_INTENTS[checkout_intent_id]
|
|
||||||
ci_input = checkout_intent['input']
|
|
||||||
ci_output = checkout_intent['output']
|
|
||||||
|
|
||||||
if 'error' in request.GET:
|
|
||||||
return redirect(ci_input['errorUrl'] + f"&checkoutIntentId={checkout_intent_id}&error=An error occurred.")
|
|
||||||
elif 'refused' in request.GET:
|
|
||||||
return redirect(ci_input['returnUrl'] + f"&checkoutIntentId={checkout_intent_id}&code=refused")
|
|
||||||
|
|
||||||
dt = timezone.now().isoformat()
|
|
||||||
|
|
||||||
ci_output['order'] = {
|
|
||||||
'payer': {
|
|
||||||
'email': 'payer@example.com',
|
|
||||||
'country': 'FRA',
|
|
||||||
'dateOfBirth': '2000-01-01T00:00:00+01:00',
|
|
||||||
'firstName': "Payer",
|
|
||||||
'lastName': "Payer",
|
|
||||||
},
|
|
||||||
'items': [
|
|
||||||
{
|
|
||||||
'payments': [
|
|
||||||
{
|
|
||||||
'id': checkout_intent_id,
|
|
||||||
'shareAmount': ci_input['totalAmount'],
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'name': ci_input['itemName'],
|
|
||||||
'priceCategory': 'Fixed',
|
|
||||||
'qrCode': '',
|
|
||||||
'id': checkout_intent_id,
|
|
||||||
'amount': ci_input['totalAmount'],
|
|
||||||
'type': 'Payment',
|
|
||||||
'state': 'Processed'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'payments': [
|
|
||||||
{
|
|
||||||
'items': [
|
|
||||||
{
|
|
||||||
'id': checkout_intent_id,
|
|
||||||
'shareAmount': ci_input['totalAmount'],
|
|
||||||
'shareItemAmount': ci_input['totalAmount'],
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'cashOutState': 'MoneyIn',
|
|
||||||
'paymentReceiptUrl': "https://example.com/",
|
|
||||||
'id': checkout_intent_id,
|
|
||||||
'amount': ci_input['totalAmount'],
|
|
||||||
'date': dt,
|
|
||||||
'paymentMeans': 'Card',
|
|
||||||
'installmentNumber': 1,
|
|
||||||
'state': 'Authorized',
|
|
||||||
'meta': {
|
|
||||||
'createdAt': dt,
|
|
||||||
'updatedAt': dt,
|
|
||||||
},
|
|
||||||
'refundOperations': []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'amount': {
|
|
||||||
'total': ci_input['totalAmount'],
|
|
||||||
'vat': 0,
|
|
||||||
'discount': 0
|
|
||||||
},
|
|
||||||
'id': 13339,
|
|
||||||
'date': dt,
|
|
||||||
'formSlug': 'default',
|
|
||||||
'formType': 'Checkout',
|
|
||||||
'organizationName': 'Animath',
|
|
||||||
'organizationSlug': 'animath',
|
|
||||||
'checkoutIntentId': checkout_intent_id,
|
|
||||||
'meta': {
|
|
||||||
'createdAt': dt,
|
|
||||||
'updatedAt': dt,
|
|
||||||
},
|
|
||||||
'isAnonymous': False,
|
|
||||||
'isAmountHidden': False
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect(ci_input['returnUrl'] + f"&checkoutIntentId={checkout_intent_id}&code=succeeded")
|
|
||||||
|
|
||||||
def head(self, request, *args, **kwargs):
|
|
||||||
return HttpResponse()
|
|
@ -244,7 +244,6 @@ PHONENUMBER_DEFAULT_REGION = 'FR'
|
|||||||
# Hello Asso API creds
|
# Hello Asso API creds
|
||||||
HELLOASSO_CLIENT_ID = os.getenv('HELLOASSO_CLIENT_ID', 'CHANGE_ME_IN_ENV_SETTINGS')
|
HELLOASSO_CLIENT_ID = os.getenv('HELLOASSO_CLIENT_ID', 'CHANGE_ME_IN_ENV_SETTINGS')
|
||||||
HELLOASSO_CLIENT_SECRET = os.getenv('HELLOASSO_CLIENT_SECRET', 'CHANGE_ME_IN_ENV_SETTINGS')
|
HELLOASSO_CLIENT_SECRET = os.getenv('HELLOASSO_CLIENT_SECRET', 'CHANGE_ME_IN_ENV_SETTINGS')
|
||||||
HELLOASSO_TEST_ENDPOINT = False # Enable custom test endpoint, for unit tests
|
|
||||||
|
|
||||||
# Custom parameters
|
# Custom parameters
|
||||||
PROBLEMS = [
|
PROBLEMS = [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user