Commit 3a401fc8 by Yvon Kerdoncuff

Merge branch '5866-encaissement-calculate-amount-based-on-conventionnement' into 'ssa-gironde'

calculate encaissement max amount based on conventionnement

See merge request cooperatic/kohinos-tav!72
parents 9f8b9625 8e9d69ac
...@@ -405,3 +405,27 @@ form[name="formEncaissement"] label { ...@@ -405,3 +405,27 @@ form[name="formEncaissement"] label {
text-align: right; text-align: right;
font-style: italic; font-style: italic;
} }
.presta-conventionnement-applied-text {
margin-top: -0.75rem !important;
margin-bottom: 1rem;
font-size: 100%;
}
.montant-panier-error {
margin-top: -0.75rem !important;
margin-bottom: 1rem;
font-size: 100%;
color: #ff4136;
}
.input-error {
border-color: #ff4136 !important;
}
.input-error:focus {
box-shadow: 0 0 0 0.2rem #ff403667 !important;
}
.text-error {
color: #ff4136;
}
\ No newline at end of file
...@@ -494,6 +494,88 @@ $(function() { ...@@ -494,6 +494,88 @@ $(function() {
// Set payment summary on validation page // Set payment summary on validation page
let recap = `${$("#formEncaissement_adherent option:selected").text()}, montant : ${$("#formEncaissement_montant").val()} ${KOH_MLC_NAME_SMALL}`; let recap = `${$("#formEncaissement_adherent option:selected").text()}, montant : ${$("#formEncaissement_montant").val()} ${KOH_MLC_NAME_SMALL}`;
$(".payment-recap").text(recap); $(".payment-recap").text(recap);
// If conventionnement mode is active
if ($(this).find("#formEncaissement_montantPanier").length > 0) {
$("#formEncaissement_montant").prop("disabled",true);
let maxAmount = 0;
function disableMontant() {
$("#formEncaissement_montant").val("");
$("#formEncaissement_montant").prop("disabled", true);
$(".presta-conventionnement-applied-text").hide();
}
/**
* If basket amount is set and valid, enable emlc amount field & hide errors if needed.
* Else display errors.
*/
function checkMontantPanier() {
let input = $("#formEncaissement_montantPanier");
let val = input.val();
if (val === '') {
// reset
$(".montant-panier-error").hide();
input.removeClass('input-error');
disableMontant();
} else {
let basketAmount = parseFloat(val);
if (isNaN(basketAmount)) {
// display error and reset the rest
$(".montant-panier-error").show();
input.addClass('input-error');
disableMontant();
return;
}
$(".montant-panier-error").hide();
input.removeClass('input-error');
// no error: enable amount field, set max emlc amount and display helper text
$("#formEncaissement_montant").prop("disabled", false);
$(".presta-conventionnement-applied-text").show();
maxAmount = parseFloat(formEncaissementConventionnement) * basketAmount;
$(".encaissment-emlc-max-amount").text(maxAmount);
}
checkMaxAmount();
}
checkMontantPanier();
$("#formEncaissement_montantPanier").on("input", checkMontantPanier);
/**
* Check that emlc amount is valid depending on basket amount
*/
function checkMaxAmount() {
function reset() {
$("#formEncaissement_montant").removeClass('input-error');
$(".encaissment-emlc-max-amount-container").removeClass("text-error");
}
let val = $("#formEncaissement_montant").val();
if (val === '') {
reset();
} else {
let amount = parseFloat(val);
if (!isNaN(amount) && amount > maxAmount) {
$(this).addClass('input-error');
$(".encaissment-emlc-max-amount-container").addClass("text-error");
} else if (!isNaN(amount) && amount <= maxAmount) {
reset();
}
}
}
checkMaxAmount();
$("#formEncaissement_montant").on("input", checkMaxAmount);
}
} }
/** /**
......
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 @@ ...@@ -3,10 +3,10 @@
"app": { "app": {
"js": [ "js": [
"/build/runtime.6ad5c9da.js", "/build/runtime.6ad5c9da.js",
"/build/app.a926d504.js" "/build/app.6ea8ce63.js"
], ],
"css": [ "css": [
"/build/app.6350a995.css" "/build/app.04bd0e32.css"
] ]
}, },
"admin": { "admin": {
......
{ {
"build/app.css": "/build/app.6350a995.css", "build/app.css": "/build/app.04bd0e32.css",
"build/app.js": "/build/app.a926d504.js", "build/app.js": "/build/app.6ea8ce63.js",
"build/admin.css": "/build/admin.4de55830.css", "build/admin.css": "/build/admin.4de55830.css",
"build/admin.js": "/build/admin.86a2d986.js", "build/admin.js": "/build/admin.86a2d986.js",
"build/runtime.js": "/build/runtime.6ad5c9da.js", "build/runtime.js": "/build/runtime.6ad5c9da.js",
......
...@@ -315,14 +315,33 @@ class UserController extends AbstractController ...@@ -315,14 +315,33 @@ class UserController extends AbstractController
} }
/** /**
* Payment terminal page.
*
* @Route("/encaissement", name="encaissement") * @Route("/encaissement", name="encaissement")
* @IsGranted({"ROLE_CAISSIER", "ROLE_PRESTATAIRE"}) * @IsGranted({"ROLE_CAISSIER", "ROLE_PRESTATAIRE"})
*/ */
public function encaissementAction(Request $request) public function encaissementAction(Request $request)
{ {
// If conventionnement process is activated, prevent access to payment terminal if prestataire conventionnement is not set
$conventionnementMode = $this->getParameter('presta_self_init_and_eval');
if ($conventionnementMode == true) {
$presta = $this->session->get('_prestagere');
$presta = $this->em->getRepository(Prestataire::class)->findOneById($presta->getId());
$conventionnement = $presta->getConventionnement();
if ($conventionnement == null || $conventionnement == 0) {
$this->addFlash(
'error',
$this->translator->trans("Impossible d'accéder au terminal de paiement tant que votre conventionnement n'a pas été établi par un·e gestionnaire.")
);
return $this->redirectToRoute('index');
}
}
$form = $this->createForm(EncaissementFormType::class, null, []); $form = $this->createForm(EncaissementFormType::class, null, []);
$form->handleRequest($request); $form->handleRequest($request);
$validation = false; $validation = false; // validation = user enters its code
$insufficientBalance = null; // if not null, will indicate for the template an insufficient founds situation $insufficientBalance = null; // if not null, will indicate for the template an insufficient founds situation
if ($form->isSubmitted()) { if ($form->isSubmitted()) {
...@@ -331,34 +350,55 @@ class UserController extends AbstractController ...@@ -331,34 +350,55 @@ class UserController extends AbstractController
if ($form->isValid()) { if ($form->isValid()) {
$adherent = $data["adherent"]; $adherent = $data["adherent"];
$adherent_code = $adherent->getPaymentCode(); $adherent_code = $adherent->getPaymentCode();
$input_code = $data["payment_code"];
// if adherent account isn't enabled // Perform first step checks
if (!$adherent->getUser()->isEnabled()) { if (empty($input_code)) {
$this->addFlash( // if adherent account isn't enabled
'error', if (!$adherent->getUser()->isEnabled()) {
$this->translator->trans('Le compte de l\'habitant·e est désactivé.') $this->addFlash(
); 'error',
$this->translator->trans('Le compte de l\'habitant·e est désactivé.')
);
goto end; goto end;
} }
// if adherent doesn't have a validation code // if adherent doesn't have a validation code
if (is_null($adherent_code)) { if (is_null($adherent_code)) {
$this->addFlash( $this->addFlash(
'error', 'error',
$this->translator->trans('L\'habitant·e n\'a pas encore défini un code de validation de paiement sur son espace personnel, il·elle ne peut pas payer en Monnaie Solidaire pour l\'instant.') $this->translator->trans('L\'habitant·e n\'a pas encore défini un code de validation de paiement sur son espace personnel, il·elle ne peut pas payer en Monnaie Solidaire pour l\'instant.')
); );
goto end; goto end;
} }
$input_code = $data["payment_code"]; // If entered amount is above maximum amount, depending on prestataire conventionnement
$validation = true; // When the form is submitted & valid, and the user account checks passed, we enter the validation process if ($conventionnementMode == true) {
$transaction_amount = floatval($data["montant"]);
$montantPanier = floatval($form['montantPanier']->getData());
$maxAmount = $montantPanier * floatval($conventionnement);
if ($transaction_amount > $maxAmount) {
$this->addFlash(
'error',
$this->translator->trans('Montant maximal en MonA dépassé. Veuillez modifier le montant en MonA.')
);
goto end;
}
}
// When the form is submitted & valid, and the user account checks passed, we enter the validation process
$validation = true;
if (empty($input_code)) {
// First step validated (set user & amount) -> go to validation // First step validated (set user & amount) -> go to validation
goto end; goto end;
} } else {
// We're in the validation process
$validation = true;
}
// Check validation code // Check validation code
// NOTE as we use password salt, the user must change his payment code if his password changes // NOTE as we use password salt, the user must change his payment code if his password changes
...@@ -401,13 +441,15 @@ class UserController extends AbstractController ...@@ -401,13 +441,15 @@ class UserController extends AbstractController
goto end; goto end;
} }
// Save transaction // No error at this point: save transaction
$flux = new TransactionAdherentPrestataire(); $flux = new TransactionAdherentPrestataire();
$flux->setExpediteur($adherent); $flux->setExpediteur($adherent);
$presta = $this->session->get('_prestagere'); if (!isset($presta)) {
$presta = $this->em->getRepository(Prestataire::class)->findOneById($presta->getId()); $presta = $this->session->get('_prestagere');
$presta = $this->em->getRepository(Prestataire::class)->findOneById($presta->getId());
}
$flux->setDestinataire($presta); $flux->setDestinataire($presta);
$flux->setOperateur($this->security->getUser()); $flux->setOperateur($this->security->getUser());
...@@ -421,7 +463,15 @@ class UserController extends AbstractController ...@@ -421,7 +463,15 @@ class UserController extends AbstractController
$this->operationUtils->executeOperations($flux); $this->operationUtils->executeOperations($flux);
$this->em->flush(); $this->em->flush();
return $this->redirectToRoute('encaissementSuccess'); $redirectParams = [];
if ($form->has('montantPanier')) {
$transaction_amount = floatval($data["montant"]);
$montantPanier = floatval($form['montantPanier']->getData());
$redirectParams['remainingAmount'] = $montantPanier - $transaction_amount;
}
return $this->redirectToRoute('encaissementSuccess', $redirectParams);
} else { } else {
$this->addFlash( $this->addFlash(
'error', 'error',
...@@ -431,11 +481,17 @@ class UserController extends AbstractController ...@@ -431,11 +481,17 @@ class UserController extends AbstractController
} }
end: end:
return $this->render('@kohinos/tav/encaissement_page.html.twig', [ $templateData = [
'form' => $form->createView(), 'form' => $form->createView(),
'validation' => $validation, 'validation' => $validation,
'insufficientBalance' => $insufficientBalance 'insufficientBalance' => $insufficientBalance
]); ];
if ($conventionnementMode == true) {
$templateData['conventionnement'] = $conventionnement;
}
return $this->render('@kohinos/tav/encaissement_page.html.twig', $templateData);
} }
/** /**
...@@ -444,6 +500,13 @@ class UserController extends AbstractController ...@@ -444,6 +500,13 @@ class UserController extends AbstractController
*/ */
public function encaissementSuccessAction(Request $request) public function encaissementSuccessAction(Request $request)
{ {
return $this->render('@kohinos/tav/payment_done_page.html.twig', []); $templateData = [];
$remainingAmount = $request->query->get('remainingAmount');
if ($remainingAmount != '') {
$templateData['remainingAmount'] = $remainingAmount;
}
return $this->render('@kohinos/tav/payment_done_page.html.twig', $templateData);
} }
} }
...@@ -10,23 +10,29 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType; ...@@ -10,23 +10,29 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\DependencyInjection\ContainerInterface;
use App\Entity\Adherent; use App\Entity\Adherent;
use App\Entity\GlobalParameter;
class EncaissementFormType extends AbstractType class EncaissementFormType extends AbstractType
{ {
protected $em; protected $em;
protected $security; protected $security;
protected $container;
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
Security $security Security $security,
ContainerInterface $container
) { ) {
$this->em = $em; $this->em = $em;
$this->security = $security; $this->security = $security;
$this->container = $container;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$mlcName = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_NAME_SMALL);
$builder $builder
->add('adherent', EntityType::class, [ ->add('adherent', EntityType::class, [
'class' => Adherent::class, 'class' => Adherent::class,
...@@ -40,7 +46,7 @@ class EncaissementFormType extends AbstractType ...@@ -40,7 +46,7 @@ class EncaissementFormType extends AbstractType
'choice_label' => 'name' 'choice_label' => 'name'
]) ])
->add('montant', NumberType::class, [ ->add('montant', NumberType::class, [
'label' => 'Montant : ', 'label' => "Montant à payer en {$mlcName} : ",
'required' => true, 'required' => true,
'attr' => ['autocomplete' => 'off'] 'attr' => ['autocomplete' => 'off']
]) ])
...@@ -51,6 +57,20 @@ class EncaissementFormType extends AbstractType ...@@ -51,6 +57,20 @@ class EncaissementFormType extends AbstractType
]) ])
->add('save', SubmitType::class, ['label' => 'Valider']) ->add('save', SubmitType::class, ['label' => 'Valider'])
; ;
if ($this->container->getParameter('presta_self_init_and_eval')) {
$builder
->add('montantPanier', NumberType::class, [
'label' => 'Montant total du panier : ',
'required' => true,
'attr' => ['autocomplete' => 'off'],
'mapped' => false,
'help' => ''
])
;
}
} }
public function getBlockPrefix() public function getBlockPrefix()
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<b>{{ app.session.get('_prestagere') }}</b> <b>{{ app.session.get('_prestagere') }}</b>
</div> </div>
<h2 class='text-center w-100 mt-4 mb-4'>{{ "Paiement en MonA"|trans }}</h2> <h2 class='text-center w-100 mt-4 mb-4'>{{ "Paiement"|trans }}</h2>
{% else %} {% else %}
<div class="mt-3 payment-page-header"> <div class="mt-3 payment-page-header">
<a href='{{ path('encaissement') }}'> <a href='{{ path('encaissement') }}'>
...@@ -71,10 +71,27 @@ ...@@ -71,10 +71,27 @@
<div style="display:none;"> <div style="display:none;">
{{ form_row(form.adherent) }} {{ form_row(form.adherent) }}
{{ form_row(form.montant) }} {{ form_row(form.montant) }}
{% if form.montantPanier is defined %}
{{ form_row(form.montantPanier) }}
{% endif %}
</div> </div>
{% else %} {% else %}
{{ form_row(form.adherent) }} {{ form_row(form.adherent) }}
{% if form.montantPanier is defined %}
{{ form_row(form.montantPanier) }}
<div class="presta-conventionnement-applied-text form-text text-muted" style="display:none;">
Conventionnement du point de vente : {{ conventionnement * 100 }}% ;
<span class="encaissment-emlc-max-amount-container">
le montant maximum payable en MonA est de : <span class="encaissment-emlc-max-amount"></span> MonA
</span>
</div>
<div class="montant-panier-error form-text" style="display:none;">La valeur est invalide.</div>
{% endif %}
{{ form_row(form.montant) }} {{ form_row(form.montant) }}
<br/> <br/>
{% endif %} {% endif %}
<br/> <br/>
...@@ -86,6 +103,13 @@ ...@@ -86,6 +103,13 @@
var formEncaissementValidation = '{{ validation }}'; var formEncaissementValidation = '{{ validation }}';
var KOH_MLC_NAME_SMALL = "{{ KOH_MLC_NAME_SMALL|default('') }}"; var KOH_MLC_NAME_SMALL = "{{ KOH_MLC_NAME_SMALL|default('') }}";
</script> </script>
{% if conventionnement is defined %}
<script type="text/javascript">
var formEncaissementConventionnement = '{{ conventionnement }}';
</script>
{% endif %}
{% endblock %} {% endblock %}
{% block footer %}{% endblock footer %} {% block footer %}{% endblock footer %}
\ No newline at end of file
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
{% block content %} {% block content %}
<div class='container' style='max-width: 800px;'> <div class='container' style='max-width: 800px;'>
<div class="payment-done-container"> <div class="payment-done-container">
<h1 class="text-center w-100 mt-4 payment-done-title">Paiement réussi !</h1> <h1 class="text-center w-100 mt-4 payment-done-title">
{{ 'Paiement réussi !'|trans }}
</h1>
<br/> <br/>
...@@ -20,6 +22,12 @@ ...@@ -20,6 +22,12 @@
<br/> <br/>
{% if remainingAmount is defined %}
<h5>{{ 'Reste à payer en euros :'|trans }} {{ remainingAmount }}</h5>
<br/>
{% endif %}
<a class='btn btn-xs btn-primary mt-4' href='{{ path('encaissement') }}'> <a class='btn btn-xs btn-primary mt-4' href='{{ path('encaissement') }}'>
{{ 'Nouvel encaissement'|trans }} {{ 'Nouvel encaissement'|trans }}
</a> </a>
......
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