From 3b5e7b6a69fc13e112001e2f879c1a5e0af8e346 Mon Sep 17 00:00:00 2001 From: Dimitri Gritsajuk Date: Sat, 27 Apr 2024 11:07:11 +0200 Subject: [PATCH] [BDE] create donation form page (#10150) --- .env | 4 + .../components/FirstFormStep.js | 7 +- .../pages/donation_funnel/components/Page.js | 2 +- assets/style/components/_bde-theme.scss | 3 +- config/services.yaml | 3 + .../Donation/DonationRequest.php | 89 +++++++++ .../BesoinDEurope/DonationController.php | 70 +++++++ .../Donation/V2/DonationController.php | 2 +- .../Systempay/RequestParamsBuilder.php | 59 ++++++ .../BesoinDEurope/DonationRequestType.php | 36 ++++ src/Twig/AnonymousRuntime.php | 17 +- .../besoindeurope/donation/form.html.twig | 179 ++++++++++++++++++ .../besoindeurope/donation/payment.html.twig | 45 +++++ .../besoindeurope/inscription/form.html.twig | 2 +- templates/renaissance/donation/form.html.twig | 3 +- translations/messages+intl-icu.fr.yml | 1 + 16 files changed, 500 insertions(+), 22 deletions(-) create mode 100644 src/BesoinDEurope/Donation/DonationRequest.php create mode 100644 src/Controller/BesoinDEurope/DonationController.php create mode 100644 src/Donation/Systempay/RequestParamsBuilder.php create mode 100644 src/Form/BesoinDEurope/DonationRequestType.php create mode 100644 templates/besoindeurope/donation/form.html.twig create mode 100644 templates/besoindeurope/donation/payment.html.twig diff --git a/.env b/.env index 0ded373fe40..25dd32686cf 100644 --- a/.env +++ b/.env @@ -154,3 +154,7 @@ CAPTAIN_VERIFY_API_KEY= NATIONAL_EVENT_WEBHOOK_HOST=http://webhook.renaissance.code NATIONAL_EVENT_TICKET_HOST=http://webhook.renaissance.code NATIONAL_EVENT_TICKET_API_KEY=123 + +SYSTEMPAY_KEY=123 +SYSTEMPAY_SITE_ID=123 +SYSTEMPAY_MODE=TEST diff --git a/assets/pages/donation_funnel/components/FirstFormStep.js b/assets/pages/donation_funnel/components/FirstFormStep.js index 8e074bc49c7..173334ba760 100644 --- a/assets/pages/donation_funnel/components/FirstFormStep.js +++ b/assets/pages/donation_funnel/components/FirstFormStep.js @@ -19,8 +19,7 @@ function closest(num, arr) { * First Step component for funnel * @returns {AlpineComponent} */ -const FirstForm = () => { - const uniqAmounts = [30, 60, 120, 250, 500, 1000]; +const FirstForm = ({ amounts: uniqAmounts = [30, 60, 120, 250, 500, 1000] } = {}) => { const monthlyAmounts = [5, 10, 20, 30, 60, 100]; return ({ ...CommonFormStep(), @@ -32,7 +31,7 @@ const FirstForm = () => { defaultCustomAmount: '', getTaxTextReduction() { - return `${(this.amount * 0.34).toFixed(2)} € ${'-1' === this.duration ? '/ mois' : ''}`; + return `${(this.amount * 0.34).toFixed(2).toLocaleString()} € ${'-1' === this.duration ? '/ mois' : ''}`; }, handleAmountClick(amount) { @@ -78,7 +77,7 @@ const FirstForm = () => { this.defaultCustomAmount = this.getCustomAmount(); }, - getAmounts(duration) { + getAmounts() { return '0' === this.duration ? uniqAmounts : monthlyAmounts; }, getCustomAmount() { diff --git a/assets/pages/donation_funnel/components/Page.js b/assets/pages/donation_funnel/components/Page.js index 3ae1675d142..16a504b2453 100644 --- a/assets/pages/donation_funnel/components/Page.js +++ b/assets/pages/donation_funnel/components/Page.js @@ -20,7 +20,7 @@ const Page = (props) => ({ }, disableDispatchToStepper: false, amount: props.amount, - duration: props.duration, + duration: props.duration ?? '0', localDestination: props.localDestination, handleStepperChange(step) { diff --git a/assets/style/components/_bde-theme.scss b/assets/style/components/_bde-theme.scss index 1ac3d72102b..50e5afd0d9f 100644 --- a/assets/style/components/_bde-theme.scss +++ b/assets/style/components/_bde-theme.scss @@ -17,7 +17,7 @@ $tertiary: #959CA0; } } - a { + a:not(.re-button) { color: $secondary !important; text-decoration: none; transition: all 0.2s ease-in-out; @@ -48,7 +48,6 @@ $tertiary: #959CA0; .re-linked-toggle .re-linked-toggle-content { input { &[type=radio] { - &:checked + label { @apply bg-white border-black text-black z-10; border-width: 2px; diff --git a/config/services.yaml b/config/services.yaml index c26c7c2c51b..8c6773f2999 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -78,6 +78,9 @@ services: $openAIApiKey: '%env(OPENAI_API_KEY)%' $friendlyCaptchaEuropeSiteKey: '%env(FRIENDLY_CAPTCHA_EUROPE_SITE_KEY)%' $captainVerifyApiKey: '%env(CAPTAIN_VERIFY_API_KEY)%' + $systemPayMode: '%env(SYSTEMPAY_MODE)%' + $systemPaySiteId: '%env(SYSTEMPAY_SITE_ID)%' + $systemPayKey: '%env(SYSTEMPAY_KEY)%' _instanceof: App\Adherent\Unregistration\Handlers\UnregistrationAdherentHandlerInterface: diff --git a/src/BesoinDEurope/Donation/DonationRequest.php b/src/BesoinDEurope/Donation/DonationRequest.php new file mode 100644 index 00000000000..ee041bc8c36 --- /dev/null +++ b/src/BesoinDEurope/Donation/DonationRequest.php @@ -0,0 +1,89 @@ +email = $user->getEmailAddress(); + $this->firstName = $user->getFirstName(); + $this->lastName = $user->getLastName(); + $this->civility = $user->getGender(); + $this->nationality = $user->getNationality(); + $this->address = Address::createFromAddress($user->getPostAddress()); + } + + public function hasAmount(): bool + { + return $this->amount >= 10; + } +} diff --git a/src/Controller/BesoinDEurope/DonationController.php b/src/Controller/BesoinDEurope/DonationController.php new file mode 100644 index 00000000000..82c791f69ce --- /dev/null +++ b/src/Controller/BesoinDEurope/DonationController.php @@ -0,0 +1,70 @@ +anonymousFollowerSession->start($request)) { + return $response; + } + + $donationRequest = $this->getDonationRequest($request); + + $form = $this + ->createForm(DonationRequestType::class, $donationRequest) + ->handleRequest($request) + ; + + if ($form->isSubmitted() && $form->isValid()) { + return $this->render('besoindeurope/donation/payment.html.twig', [ + 'params' => $this->requestParamsBuilder->build($donationRequest), + ]); + } + + return $this->renderForm('besoindeurope/donation/form.html.twig', [ + 'form' => $form, + 'email_validation_token' => $this->csrfTokenManager->getToken('email_validation_token'), + 'step' => $donationRequest->hasAmount() ? 1 : 0, + ]); + } + + private function getDonationRequest(Request $request): DonationRequest + { + $donationRequest = new DonationRequest(); + + if ($user = $this->getUser()) { + $donationRequest->updateFromAdherent($user); + } + + $donationRequest->email = $request->query->get('email'); + $donationRequest->amount = $request->query->getInt('amount'); + + if ($request->query->has(UtmParams::UTM_SOURCE)) { + $donationRequest->utmSource = UtmParams::filterUtmParameter($request->query->get(UtmParams::UTM_SOURCE)); + $donationRequest->utmCampaign = UtmParams::filterUtmParameter($request->query->get(UtmParams::UTM_CAMPAIGN)); + } + + return $donationRequest; + } +} diff --git a/src/Controller/Renaissance/Donation/V2/DonationController.php b/src/Controller/Renaissance/Donation/V2/DonationController.php index 1b72e9f396a..26751a82782 100644 --- a/src/Controller/Renaissance/Donation/V2/DonationController.php +++ b/src/Controller/Renaissance/Donation/V2/DonationController.php @@ -76,7 +76,7 @@ private function getDonationRequest(Request $request, ?Adherent $currentUser): D $isSubscription ? DonationRequest::MIN_AMOUNT : DonationRequest::MIN_AMOUNT_SUBSCRIPTION ); - $localDestination = $request->query->getBoolean('localDestination', false); + $localDestination = $request->query->getBoolean('localDestination'); $donationRequest = $currentUser ? DonationRequest::createFromAdherent($currentUser, $clientIp, $amount) diff --git a/src/Donation/Systempay/RequestParamsBuilder.php b/src/Donation/Systempay/RequestParamsBuilder.php new file mode 100644 index 00000000000..fefc7748f95 --- /dev/null +++ b/src/Donation/Systempay/RequestParamsBuilder.php @@ -0,0 +1,59 @@ + $this->systemPaySiteId, + 'vads_ctx_mode' => $this->systemPayMode, + 'vads_trans_id' => sprintf("%'.06d", (strtotime('tomorrow') - time()) * 10 + ((microtime(true) * 10) % 10)), + 'vads_trans_date' => date('YmdHis'), + 'vads_amount' => $donationRequest->amount * 100, + 'vads_currency' => '978', + 'vads_action_mode' => 'INTERACTIVE', + 'vads_page_action' => 'PAYMENT', + 'vads_version' => 'V2', + 'vads_payment_config' => 'SINGLE', + 'vads_capture_delay' => '0', + 'vads_validation_mode' => '0', + 'vads_cust_title' => match ($donationRequest->civility) { + Genders::MALE => 'Monsieur', + Genders::FEMALE => 'Madame', + default => '', + }, + 'vads_cust_first_name' => $donationRequest->firstName, + 'vads_cust_last_name' => $donationRequest->lastName, + 'vads_cust_email' => $donationRequest->email, + 'vads_cust_address' => $donationRequest->address->getAddress(), + 'vads_cust_address2' => $donationRequest->address->getAdditionalAddress(), + 'vads_cust_zip' => $donationRequest->address->getPostalCode(), + 'vads_cust_city' => $donationRequest->address->getCityName(), + 'vads_cust_country' => $donationRequest->address->getCountry(), + 'vads_ext_info_nationalite' => $donationRequest->nationality, + 'vads_ext_info_utm_source' => $donationRequest->utmSource, + 'vads_ext_info_utm_campagne' => $donationRequest->utmCampaign, + ]; + ksort($params); + $data = implode('+', $params); + $data .= '+'.$this->systemPayKey; + + $signData = base64_encode(hash_hmac('sha256', $data, $this->systemPayKey, true)); + + $params['signature'] = $signData; + + return $params; + } +} diff --git a/src/Form/BesoinDEurope/DonationRequestType.php b/src/Form/BesoinDEurope/DonationRequestType.php new file mode 100644 index 00000000000..6f1e531150d --- /dev/null +++ b/src/Form/BesoinDEurope/DonationRequestType.php @@ -0,0 +1,36 @@ +add('amount', HiddenType::class) + ->add('email', EmailType::class) + ->add('civility', CivilityType::class) + ->add('firstName', TextType::class) + ->add('lastName', TextType::class) + ->add('nationality', CountryType::class, ['preferred_choices' => [AddressInterface::FRANCE]]) + ->add('address', AutocompleteAddressType::class, ['with_additional_address' => true]) + ->add('autorisations', RequiredCheckboxType::class) + ; + } + + public function getBlockPrefix(): string + { + return 'donation_request'; + } +} diff --git a/src/Twig/AnonymousRuntime.php b/src/Twig/AnonymousRuntime.php index fd8f2d4ceef..aad79dbf2ce 100644 --- a/src/Twig/AnonymousRuntime.php +++ b/src/Twig/AnonymousRuntime.php @@ -9,20 +9,15 @@ class AnonymousRuntime implements RuntimeExtensionInterface { - private const USER_LOGIN_ROUTE = 'app_renaissance_login'; - - private $urlGenerator; - private $requestStack; - - public function __construct(UrlGeneratorInterface $urlGenerator, RequestStack $requestStack) - { - $this->urlGenerator = $urlGenerator; - $this->requestStack = $requestStack; + public function __construct( + private readonly UrlGeneratorInterface $urlGenerator, + private readonly RequestStack $requestStack, + ) { } public function generateLoginPathForAnonymousFollower(string $callbackRoute = '', array $params = []): string { - return $this->doGeneratePathForAnonymousFollower(self::USER_LOGIN_ROUTE, $callbackRoute, $params); + return $this->doGeneratePathForAnonymousFollower('/connexion', $callbackRoute, $params); } private function doGeneratePathForAnonymousFollower( @@ -38,7 +33,7 @@ private function doGeneratePathForAnonymousFollower( $params = $this->requestStack->getMainRequest()->attributes->get('_route_params'); } - $params[AnonymousFollowerSession::AUTHENTICATION_INTENTION] = $this->urlGenerator->generate($intention); + $params[AnonymousFollowerSession::AUTHENTICATION_INTENTION] = $intention; return $this->urlGenerator->generate($callbackRoute, $params); } diff --git a/templates/besoindeurope/donation/form.html.twig b/templates/besoindeurope/donation/form.html.twig new file mode 100644 index 00000000000..eb34f382156 --- /dev/null +++ b/templates/besoindeurope/donation/form.html.twig @@ -0,0 +1,179 @@ +{% extends 'besoindeurope/base_besoindeurope.html.twig' %} + +{% block page_title 'Financer la campagne' %} + +{% block open_graph_image "https://doc.besoindeurope.fr/images/sharer/don.jpg" %} +{% block open_graph_description "Derrière chaque action locale, chaque événement, chaque tract et affiche de campagne produit, il y a vos dons." %} +{% block canonical_url url('app_bde_donation') %} + +{% form_theme form 'renaissance/forms/tailwind_form_theme.html.twig' %} + +{% block sub_content %} +
+
+
+
+
+
+ {% include 'renaissance/donation/form_visual.svg.twig' %} +
+
+
+ +
+
+ {{ form_start(form) }} +
+ {% if form.vars.errors|length > 0 %} + +
    1 %} + class="list-disc list-inside flex flex-col gap-2.5" + {% endif %} + > + {% for error in form.vars.errors %} +
  • {{ error.message|raw }}
  • + {% endfor %} +
+
+ {% endif %} + + +

Financez
la campagne

+ +

Derrière chaque action locale, chaque événement, chaque tract et affiche de campagne produit, il y a vos dons.

+ + + + + + + + + {{ form_errors(form.amount) }} + + {{ form_row(form.amount, {attr: { 'x-bind:value': 'amount'}}) }} + +
+ Après réduction d’impôt : +
+ +
+
+ + Suivant + +

Vous préférez effectuer votre contribution
par chèque ? Retrouvez ici nos
coordonnées bancaires.

+ + Télécharger le bulletin de don +
+ +
+ {% if not app.user %} + +

+ Vous avez déjà un compte Besoin d'Europe ? + Connectez vous pour pré-remplir toutes vos informations. +

+ + Me connecter + +
+ {% endif %} + + + {{ form_row(form.civility, { + label: 'Mes informations', + attr: {color:'green', onCheck:"setFieldValid('gender')", validate: "['required']" } + }) }} + +
+ {{ form_row(form.lastName, { + label: false, + attr: { placeholder: 'Nom', onCheck:"setFieldValid('lastName')", validate: "['required', 'min:1', 'max:50']" } + }) }} + {{ form_row(form.firstName, { + label: false, + attr: { placeholder: 'Prénom', onCheck:"setFieldValid('firstName')", validate: "['required', 'min:2', 'max:50']" } + }) }} +
+ + {{ form_row(form.email, { + attr: { + placeholder: 'Adresse email', + validate:"['required', 'email']", + autocomplete: 'email', + type: 'email', + onCheck:"setFieldValid('emailAddress')", + }, label: false}) }} + + {{ form_row(form.nationality, { + label: 'Nationalité', + attr: { onCheck:"setFieldValid('nationality')", validate: "['required']" } + }) }} + + {{ form_row(form.address, {label: 'Adresse postale'}) }} + + Suivant +
+
+ + Autorisations + {{ form_row(form.autorisations, { + label: 'besoindeurope.donation.autorisations', label_html: true, + attr: { onCheck:"setFieldValid('autorisations')", validate: "['required']" } + }) }} + +
+ {% include 'renaissance/partials/friendly-captcha.html.twig' with {friendly_captcha_site_key: friendly_captcha_europe_site_key} %} +
+ Passer au paiement +
+ + + Légalités + +

Les dons sont exclusivement versés à l’Association de Financement Electorale Besoin d’Europe pour les élections européennes 2024 (AFEBE 2024), déclarée à la Préfecture de Police de Paris le 6 mars 2024, mandataire financier de la liste Besoin d’Europe conduite par Valérie Hayer pour les élections des représentants au Parlement européen prévues les 8 et 9 juin 2024. La liste ne peut recueillir de dons que par l’intermédiaire de son mandataire financier. Conformément à l’article L.52-8 du code électoral, une personne physique peut verser un don à un candidat si elle est de nationalité française ou si elle réside en France. Les dons consentis par une personne physique dûment identifiée pour le financement de la campagne d'un ou plusieurs candidats lors des mêmes élections ne peuvent excéder 4 600 euros. Les personnes morales, à l'exception des partis ou groupements politiques, ne peuvent participer au financement de la campagne électorale d'un candidat, ni en lui consentant des dons sous quelque forme que ce soit, ni en lui fournissant des biens, services ou autres avantages directs ou indirects à des prix inférieurs à ceux qui sont habituellement pratiqués. Les personnes morales, à l'exception des partis et groupements politiques ainsi que des établissements de crédit ou sociétés de financement ayant leur siège social dans un Etat membre de l'Union européenne ou partie à l'accord sur l'Espace économique européen, ne peuvent ni consentir des prêts à un candidat, ni lui apporter leur garantie pour l'obtention de prêts. Tout don de plus de 150 euros consentis à un candidat en vue de sa campagne doit être versé par chèque, virement, prélèvement automatique ou carte bancaire. Sera puni de trois ans d'emprisonnement et de 45 000 € d'amende quiconque aura, en vue d'une campagne électorale, accordé un don ou un prêt en violation des articles L. 52-7-1 et L. 52-8. Les données recueillies sur ce formulaire de don seront traitées par Renaissance pour le compte de l’AFEBE 2024, afin de gérer le financement de la campagne de la liste Besoin d’Europe conduite par Valérie Hayer pour l’élection des représentants au parlement européen prévue les 8 et 9 juin 2024, et de vous en tenir informé. Elles permettront également, si vous le souhaitez, de vous envoyer les communications politiques relatives à l’élection européenne. Les champs marqués d’un astérisque sont obligatoires. L’absence de renseignement dans ces champs ne permettra pas à Renaissance et à l’AFEBE 2024 de traiter votre demande. Ces données seront conservées jusqu’à la fin des procédures de contrôle du compte de campagne de la liste ou jusqu’à la fin du délai de prescription lié à tout éventuel contentieux sur le financement de la campagne de la liste. En envoyant ce formulaire, vous autorisez Renaissance à traiter vos données pour ces finalités pour le compte de l’AFEBE 2024. Conformément à la réglementation en vigueur, vous disposez d’un droit d’opposition et d’un droit à la limitation du traitement de données vous concernant, ainsi que d’un droit d’accès, de rectification, de portabilité et d’effacement de vos données. Vous disposez également de la faculté de donner des directives sur le sort de vos données après votre décès. Vous pouvez exercer vos droits en nous adressant votre demande accompagnée d’une copie de votre pièce d’identité à l’adresse postale ou électronique suivante : 25 rue d’Edimbourg, 75008 Paris, ou contact@besoindeurope.fr. Nous prendrons votre demande en compte dans les meilleurs délais. Vous êtes enfin en droit d’introduire une réclamation auprès de la Commission nationale de l’Informatique et des Libertés (CNIL). Pour toute information sur le traitement de vos données, vous pouvez consulter notre politique de protection des données.

+
+ +
+
+ + {{ form_end(form) }} +
+
+
+ +
+
+{% endblock %} + +{% block final_javascripts %} + + +{% endblock %} diff --git a/templates/besoindeurope/donation/payment.html.twig b/templates/besoindeurope/donation/payment.html.twig new file mode 100644 index 00000000000..c85a33d400c --- /dev/null +++ b/templates/besoindeurope/donation/payment.html.twig @@ -0,0 +1,45 @@ +{% extends 'besoindeurope/base_besoindeurope.html.twig' %} + +{% block page_title 'Paiement' %} + +{% block sub_content %} +
+ + + +
+ {% for key, value in params %} + + {% endfor %} + + Continuer vers ma banque +
+
+
+{% endblock %} + +{% block final_javascripts %} + +{% endblock %} diff --git a/templates/besoindeurope/inscription/form.html.twig b/templates/besoindeurope/inscription/form.html.twig index a006073a456..aa9e3019c11 100644 --- a/templates/besoindeurope/inscription/form.html.twig +++ b/templates/besoindeurope/inscription/form.html.twig @@ -68,7 +68,7 @@ }) }}
- {% include 'renaissance/partials/friendly-captcha.html.twig' %} + {% include 'renaissance/partials/friendly-captcha.html.twig' with {friendly_captcha_site_key: friendly_captcha_europe_site_key} %}
-
- Autorisations + Légalités

Une question relative aux dons ? Écrivez-nous à dons@parti-renaissance.fr.

66 % de votre don vient en réduction de votre Impôt sur le Revenu des Personnes Physiques (IRPP), dans la limite de 20 % du revenu imposable.

diff --git a/translations/messages+intl-icu.fr.yml b/translations/messages+intl-icu.fr.yml index 5a214ff8b96..d1fbfe16397 100644 --- a/translations/messages+intl-icu.fr.yml +++ b/translations/messages+intl-icu.fr.yml @@ -1506,6 +1506,7 @@ donation.autorisations.label: Je certifie sur l’honneur être une personne phy national_event.inscription.accept_cgu: J’ai lu et j’accepte la politique de protection des données et les mentions d’informations relatives au traitement de mes données ci-dessous besoindeurope.inscription.accept_cgu: J’accepte les CGU du site et déclare avoir lu la Politique de protection des données personnelles et les mentions d’information relatives au traitement de mes données ci-dessous. +besoindeurope.donation.autorisations: Je certifie sur l’honneur être une personne physique d’au moins 16 ans et que le règlement de mon don ne provient pas du compte d’une personne morale (entreprise, association, collectivité...) mais bien de mon compte bancaire personnel.

Je certifie être de nationalité Française ou résident fiscal Français.

J’accepte les CGU du site Renaissance et déclare avoir lu la Politique de protection des données personnelles et les mentions d’information relatives au traitement de mes données ci-dessous. # # Administrators