Commit 7696ea61 by Damien Moulard

WIP: reccurent payment, first draft for tests on preprod

parent b9d2a992
......@@ -428,4 +428,9 @@ form[name="formEncaissement"] label {
.text-error {
color: #ff4136;
}
.tav-cotisation-payment-form {
display: none;
margin-top: 1rem;
}
\ No newline at end of file
......@@ -806,4 +806,26 @@ $(function() {
$('.prestataire-product-families-select').on('change', onPrestataireProductFamilyChange);
};
$("#add-prestataire-products-family").on("click", addFormToCollection);
$("#tav-cotisation-payment-type").on("change", function() {
$(".tav-cotisation-payment-form").hide();
if (this.value === "instant-payment") {
$("#tav-cotisation-instant-payment-container").show();
} else if (this.value === "recurrent-payment") {
$("#tav-cotisation-recurrent-payment-container").show();
}
});
$("input:text[name='formAchatMonnaieAdherentRecurrent[don][montant]']").on('input', function() {
let montant = 0;
montant = parseFloat($('input#formAchatMonnaieAdherentRecurrent_montant').val());
let montantDon = parseFloat($("input:text[name='formAchatMonnaieAdherentRecurrent[don][montant]']").val().replace(",", "."));
if (isNaN(montantDon)) {
montantDon = 0;
}
var valuetotal = montant + montantDon;
$("span.achat_monnaie_premier_montant_total").text(valuetotal + ' €')
});
});
......@@ -61,6 +61,17 @@ class CaptureAction implements ActionInterface, GatewayAwareInterface, GenericTo
);
$model['vads_url_check'] = $notifyToken->getTargetUrl();
}
// TODO : here ?
$payment = $request->getFirstModel();
if ('paiement_recurrent_cotisation_tav' == $payment->getDescription()) { // TODO right way to check type
$model['vads_page_action'] = 'REGISTER_PAY_SUBSCRIBE';
$model['vads_sub_amount'] = "1000"; // TODO get params
$model['vads_sub_currency'] = $model['vads_currency'];
$model['vads_sub_effect_date'] = (new \DateTime('now', new \DateTimeZone('UTC')))->format('YmdHis');
$model['vads_sub_desc'] = 'RRULE:FREQ=DAILY;INTERVAL=1;COUNT=2';
// $model['vads_sub_desc'] = 'RRULE:FREQ=MONTHLY;COUNT=12;BYMONTHDAY=10';
}
}
if (false == $model['vads_trans_id']) {
......
......@@ -353,6 +353,10 @@ class Api
'vads_url_return' => null, // Obligatoire si acquisition de la carte par commerçant
'vads_user_info' => null,
'vads_version' => 'V2',
'vads_sub_amount' => null,
'vads_sub_currency' => null,
'vads_sub_effect_date' => null,
'vads_sub_desc' => null,
])
->setRequired([
'vads_amount',
......@@ -365,7 +369,7 @@ class Api
->setAllowedValues('vads_action_mode', ['SILENT', 'INTERACTIVE'])
->setAllowedValues('vads_currency', $this->getCurrencyCodes())
->setAllowedValues('vads_language', $this->getLanguageCodes())
->setAllowedValues('vads_page_action', 'PAYMENT')
->setAllowedValues('vads_page_action', ['PAYMENT', 'REGISTER_PAY_SUBSCRIBE'])
->setAllowedValues('vads_payment_cards', $this->getCardsCodes())
->setAllowedValues('vads_payment_config', function ($value) {
if ($value === 'SINGLE') {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,10 +3,10 @@
"app": {
"js": [
"/build/runtime.6ad5c9da.js",
"/build/app.27091a64.js"
"/build/app.3644f7b2.js"
],
"css": [
"/build/app.5cdc32e6.css"
"/build/app.8a3f698b.css"
]
},
"admin": {
......
{
"build/app.css": "/build/app.5cdc32e6.css",
"build/app.js": "/build/app.27091a64.js",
"build/app.css": "/build/app.8a3f698b.css",
"build/app.js": "/build/app.3644f7b2.js",
"build/admin.css": "/build/admin.4de55830.css",
"build/admin.js": "/build/admin.86a2d986.js",
"build/runtime.js": "/build/runtime.6ad5c9da.js",
......
......@@ -190,7 +190,7 @@ class PaymentController extends AbstractController
$this->authenticator,
'main'
);
} else if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type) {
} else if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type || Payment::TYPE_PAIEMENT_RECURRENT_COTISATION_TAV) {
$this->addFlash(
'success',
$this->translator->trans('Cotisation payée !')
......
......@@ -11,6 +11,7 @@ use App\Entity\TransactionAdherentAdherent;
use App\Entity\TransactionAdherentPrestataire;
use App\Form\Type\AchatMonnaieAConfirmerAdherentFormType;
use App\Form\Type\AchatMonnaieAdherentFormType;
use App\Form\Type\AchatMonnaieAdherentRecurrentFormType;
use App\Form\Type\AdherentInfosFormType;
use App\Form\Type\TransactionAdherentAdherentFormType;
use App\Form\Type\TransactionAdherentPrestataireFormType;
......@@ -122,6 +123,37 @@ class UserAdherentController extends FluxController
}
/**
* Validations before proceeding to payment.
*
* Returns error message or null if no error.
*/
private function paiementCotisTavValidation($flux) {
// Look for existing cotisation
if ($this->tavCotisationsUtils->checkExistingCotisation($flux)) {
// return "Cotisation déjà payée ce mois-ci.";
}
$destinataire = $flux->getDestinataire();
// Look for cotisation data depending on active process
if (true == $this->getParameter('household_based_allowance')) {
$cotisationAmount = $destinataire->getCotisationAmount();
if (is_null($cotisationAmount) || is_null($destinataire->getHouseholdAdultCount())) {
return "Opération impossible : votre profil est incomplet, informations de cotisation manquantes. Veuillez contacter un administrateur.";
}
} else {
$profile = $destinataire->getProfilDeCotisation();
if (is_null($profile)) {
return "Opération impossible : vous n'avez pas de profil de cotisation associé. Veuillez contacter un administrateur.";
}
}
return null;
}
/**
* @Route("/adherent/paiement-cotis-tav/", name="paiementCotisTav")
* @IsGranted("ROLE_ADHERENT")
*/
......@@ -138,23 +170,11 @@ class UserAdherentController extends FluxController
if ($form->isSubmitted() && $form->isValid()) {
$flux = $form->getData();
// Look for existing cotisation
if ($this->tavCotisationsUtils->checkExistingCotisation($flux)) {
$validationError = $this->paiementCotisTavValidation($flux);
if (!is_null($validationError)) {
$this->addFlash(
'error',
$this->translator->trans('Cotisation déjà payée ce mois-ci.')
);
return $this->redirectToRoute('index');
}
$destinataire = $flux->getDestinataire();
$profile = $destinataire->getProfilDeCotisation();
if (is_null($profile)) {
$this->addFlash(
'error',
$this->translator->trans('Opération impossible : vous n\'avez pas de profil de cotisation associé. Veuillez contacter un administrateur.')
$this->translator->trans($validationError)
);
return $this->redirectToRoute('index');
......@@ -193,6 +213,50 @@ class UserAdherentController extends FluxController
}
/**
* @Route("/adherent/paiement-reccurent-cotis-tav/", name="paiementRecurrentCotisTav")
* @IsGranted("ROLE_ADHERENT")
*/
public function paiementRecurrentCotisTavAction(Request $request)
{
if (empty($this->getUser()) || empty($this->getUser()->getAdherent())) {
return $this->redirectToRoute('index');
}
$entity = new AchatMonnaieAdherent();
$form = $this->createForm(AchatMonnaieAdherentRecurrentFormType::class, $entity);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$flux = $form->getData();
$validationError = $this->paiementCotisTavValidation($flux);
if (!is_null($validationError)) {
$this->addFlash(
'error',
$this->translator->trans($validationError)
);
return $this->redirectToRoute('index');
}
if (null == $flux->getDon() || 0 == $flux->getDon()->getMontant()) {
$flux->setDon(null);
}
// Redirect to payment
return $this->forward('App\Controller\PaymentController::preparePaymentAction', [
'form' => $form,
'type' => Payment::TYPE_PAIEMENT_RECURRENT_COTISATION_TAV
]);
}
return $this->render('@kohinos/flux/transaction.html.twig', [
'form' => $form->createView(),
'title' => $this->translator->trans('Payer sa cotisation'),
]);
}
/**
* @Route("/adherent/demande/achat-monnaie/", name="achatMonnaieAConfirmerAdherent")
* @IsGranted("ROLE_ADHERENT")
*/
......
......@@ -18,6 +18,9 @@ class Payment extends BasePayment
const TYPE_COTISATION_PRESTA = 'cotisation_presta';
const TYPE_ADHESION = 'adhesion';
const TYPE_PAIEMENT_COTISATION_TAV = 'paiement_cotisation_tav';
const TYPE_PAIEMENT_RECURRENT_COTISATION_TAV = 'paiement_recurrent_cotisation_tav';
// todo : new field pour donnes d'abonnement
/**
* @var \Ramsey\Uuid\UuidInterface
......
......@@ -14,6 +14,7 @@ use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use App\Events\MLCEvents;
use App\Events\FluxEvent;
use App\Entity\Flux;
......@@ -42,6 +43,7 @@ class PaymentStatusExtension implements ExtensionInterface
private $userManager;
private $operationUtils;
private $tavCotisationsUtils;
private $container;
/**
* PaymentStatusExtension constructor.
......@@ -54,7 +56,8 @@ class PaymentStatusExtension implements ExtensionInterface
SerializerInterface $serializer,
UserManagerInterface $userManager,
OperationUtils $operationUtils,
TAVCotisationUtils $tavCotisationsUtils
TAVCotisationUtils $tavCotisationsUtils,
ContainerInterface $container
) {
$this->em = $em;
$this->eventDispatcher = $eventDispatcher;
......@@ -62,6 +65,7 @@ class PaymentStatusExtension implements ExtensionInterface
$this->userManager = $userManager;
$this->operationUtils = $operationUtils;
$this->tavCotisationsUtils = $tavCotisationsUtils;
$this->container = $container;
}
/**
......@@ -253,7 +257,8 @@ class PaymentStatusExtension implements ExtensionInterface
$payment->setClientId($user->getId());
$payment->setExtraData('');
$this->em->persist($payment);
} else if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type) {
} else if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type || Payment::TYPE_PAIEMENT_RECURRENT_COTISATION_TAV) {
// TODO deal with recurrent payment (don only on first payment...)
$flux = $this->serializer->deserialize(
$payment->getFluxData(),
AchatMonnaieAdherent::class,
......@@ -284,9 +289,13 @@ class PaymentStatusExtension implements ExtensionInterface
$this->em->persist($flux);
$this->operationUtils->executeOperations($flux);
if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type) {
// Apply cotisation rate, create new flux
$this->tavCotisationsUtils->applyTauxCotisation($flux);
if (Payment::TYPE_PAIEMENT_COTISATION_TAV == $type || Payment::TYPE_PAIEMENT_RECURRENT_COTISATION_TAV) {
// Create new flux for cotisation, depending on process
if ($this->container->getParameter('household_based_allowance')) {
$this->tavCotisationsUtils->applyHouseholdAllowance($flux);
} else {
$this->tavCotisationsUtils->applyTauxCotisation($flux);
}
}
// Invalidate (delete) notify token after payment is captured
......
......@@ -28,6 +28,7 @@ use App\Entity\User;
use App\Form\Type\AchatMonnaieAConfirmerAdherentFormType;
use App\Form\Type\AchatMonnaieAConfirmerPrestataireFormType;
use App\Form\Type\AchatMonnaieAdherentFormType;
use App\Form\Type\AchatMonnaieAdherentRecurrentFormType;
use App\Form\Type\AchatMonnaiePrestataireFormType;
use App\Form\Type\AdherentInfosFormType;
use App\Form\Type\ChangeAdherentComptoirFormType;
......@@ -474,6 +475,19 @@ class FormFactory
return $form->createView();
}
public function getPaiementRecurrentCotisationTAVForm(User $user)
{
if (empty($user) || !$user->isGranted('ROLE_ADHERENT')) {
throw new \Exception('[FORM 25] Opération impossible !');
}
$entity = new AchatMonnaieAdherent();
$entity->setOperateur($user);
$form = $this->ff->create(AchatMonnaieAdherentRecurrentFormType::class, $entity, ['action' => $this->router->generate('paiementRecurrentCotisTav')]);
return $form->createView();
}
public function getComptoirEncaisserDonAdherentForm(User $user)
{
if (empty($user) || empty($this->session->get('_comptoirgere'))) {
......
<?php
namespace App\Form\Type;
use App\Entity\AchatMonnaieAdherent;
use App\Entity\Adherent;
use App\Entity\DonAdherent;
use App\Entity\GlobalParameter;
use App\Entity\Prestataire;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AchatMonnaieAdherentRecurrentFormType extends AchatMonnaieAdherentFormType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$jourPrelevementChoices = [];
for ($i = 1; $i <= 28; $i++) {
$jourPrelevementChoices[strval($i)] = $i;
}
$builder
->add('nombreMois', IntegerType::class, [
'label' => 'Nombre d\'échéances désirées : ',
'required' => true,
'mapped' => false,
'help' => "Une échéance par mois.",
'attr' => ['autocomplete' => 'off']
])
->add('jourPrelevement', ChoiceType::class, [
'label' => 'Jour du prélèvement dans le mois : ',
'choices' => $jourPrelevementChoices,
'required' => true,
'mapped' => false,
'attr' => ['autocomplete' => 'off']
])
->remove('saveHelloAsso')
->remove('save')
->add('save', SubmitType::class, [
'label' => 'Payer en CB mon premier paiement et créer un paiement récurrent',
'translation_domain' => 'messages',
'attr' => [
'class' => 'btn-primary btn achatCBSubmit',
],
])
;
$builder
;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => AchatMonnaieAdherent::class,
]);
}
public function getParent()
{
return AchatMonnaieAdherentFormType::class;
}
public function getBlockPrefix()
{
return 'formAchatMonnaieAdherentRecurrent';
}
}
......@@ -55,6 +55,7 @@ class FormExtension extends AbstractExtension
new \Twig_SimpleFunction('getSetPaymentCodeForm', [$this, 'getSetPaymentCodeForm']),
new \Twig_SimpleFunction('getComptoirEncaisserCotisationForm', [$this, 'getComptoirEncaisserCotisationForm']),
new \Twig_SimpleFunction('getPayerCotisationTAVForm', [$this, 'getPayerCotisationTAVForm']),
new \Twig_SimpleFunction('getPaiementRecurrentCotisationTAVForm', [$this, 'getPaiementRecurrentCotisationTAVForm']),
new \Twig_SimpleFunction('getComptoirEncaisserDonAdherentForm', [$this, 'getComptoirEncaisserDonAdherentForm'])
];
}
......@@ -219,6 +220,11 @@ class FormExtension extends AbstractExtension
return $this->container->get('app.formfactory')->getPayerCotisationTAVForm($user);
}
public function getPaiementRecurrentCotisationTAVForm(User $user)
{
return $this->container->get('app.formfactory')->getPaiementRecurrentCotisationTAVForm($user);
}
public function getComptoirEncaisserDonAdherentForm(User $user)
{
return $this->container->get('app.formfactory')->getComptoirEncaisserDonAdherentForm($user);
......
......@@ -5,6 +5,7 @@
{% endblock blocktitle %}
{% block blockcontent %}
{% set form = getPayerCotisationTAVForm(app.user) %}
{% set formRecurrentPayment = getPaiementRecurrentCotisationTAVForm(app.user) %}
{% if form.montant.vars.value == false and not household_based_allowance %}
<p>{{ 'Vous n\'avez pas de profil de cotisation associé, vous ne pouvez donc pas payer de cotisation.'|trans }}</p>
......@@ -16,20 +17,42 @@
<p>
{{ 'Montant de la cotisation à payer'|trans }} : <span class="paiement_cotisation_montant">{{ form.montant.vars.value }}</span>
</p>
{{form_start(form)}}
{% if form.don is defined %}
{% include '@kohinos/tav/block/adherent_payer_cotisation_don.html.twig' %}
<hr/>
<p><b>{{ 'TOTAL A PAYER'|trans }} : <span class="achat_monnaie_montant_total">{{ form.montant.vars.value }}</span></b></p>
{% endif %}
{% if form.save is defined %}
{{ form_widget(form.save) }}
{% endif %}
{% if form.saveHelloAsso is defined %}
{{ form_widget(form.saveHelloAsso) }}
{% endif %}
{{form_end(form)}}
<select name="tav-cotisation-payment-type" id="tav-cotisation-payment-type" class="form-control" autocomplete="off">
<option value="">Choisir une option de paiement</option>
<option value="instant-payment">Paiement immédiat</option>
<option value="recurrent-payment">Paiement récurrent</option>
</select>
<div id="tav-cotisation-instant-payment-container" class="tav-cotisation-payment-form">
{{form_start(form)}}
{% if form.don is defined %}
{% include '@kohinos/tav/block/adherent_payer_cotisation_don.html.twig' with {'parentForm': form} %}
<hr/>
<p><b>{{ 'TOTAL A PAYER'|trans }} : <span class="achat_monnaie_montant_total">{{ form.montant.vars.value }}</span></b></p>
{% endif %}
{% if form.save is defined %}
{{ form_widget(form.save) }}
{% endif %}
{% if form.saveHelloAsso is defined %}
{{ form_widget(form.saveHelloAsso) }}
{% endif %}
{{form_end(form)}}
</div>
<div id="tav-cotisation-recurrent-payment-container" class="tav-cotisation-payment-form">
{{form_start(formRecurrentPayment)}}
{{ form_row(formRecurrentPayment.nombreMois) }}
{{ form_row(formRecurrentPayment.jourPrelevement) }}
{% if formRecurrentPayment.don is defined %}
{% include '@kohinos/tav/block/adherent_payer_cotisation_don.html.twig' with {'parentForm': formRecurrentPayment} %}
<hr/>
<p><b>{{ 'TOTAL PREMIER PAIEMENT'|trans }} : <span class="achat_monnaie_premier_montant_total">{{ formRecurrentPayment.montant.vars.value }}</span></b></p>
<p><b>{{ 'ÉHÉANCES SUIVANTES'|trans }} : <span class="achat_monnaie_montant_total">{{ formRecurrentPayment.montant.vars.value }}</span></b></p>
{% endif %}
{% if formRecurrentPayment.save is defined %}
{{ form_widget(formRecurrentPayment.save) }}
{% endif %}
{{form_end(formRecurrentPayment)}}
</div>
{% endif %}
{% endblock blockcontent %}
\ No newline at end of file
......@@ -4,5 +4,5 @@
En plus de ma cotisation je souhaite faire un don pour ce mois
{% endblock blocktitle %}
{% block blockcontent %}
{{ form_row(form.don, {row_attr:{style: 'max-width: 200px;margin: 0 auto;'}}) }}
{{ form_row(parentForm.don, {row_attr:{style: 'max-width: 200px;margin: 0 auto;'}}) }}
{% endblock blockcontent %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment