Commit d621a4fd by Damien Moulard

allowance based on household

parent 4ce2d41f
......@@ -111,7 +111,7 @@ legend.required:after {
margin-bottom: 20px;
}
.formEncaisserCotisationAdherent-no-profile {
.formEncaisserCotisationAdherent-no-cotisation-amount {
font-style: italic;
color: #ff4136;
}
......
......@@ -542,20 +542,20 @@ $(function() {
if (cotisationmontant === undefined) {
$("#formEncaisserCotisationAdherent-montant-container").hide();
$("#formEncaisserCotisationAdherent-no-profile").hide();
$("#formEncaisserCotisationAdherent-no-cotisation-amount").hide();
return;
}
if (cotisationmontant !== null) {
$("#formEncaisserCotisationAdherent-montant-display").text(`${cotisationmontant} €`);
$("#formEncaisserCotisationAdherent-montant-container").show();
$("#formEncaisserCotisationAdherent-no-profile").hide();
$("#formEncaisserCotisationAdherent-no-cotisation-amount").hide();
$("#formEncaisserCotisationAdherent_save").prop("disabled",false);
} else {
// no cotisation profile
$("#formEncaisserCotisationAdherent-montant-container").hide();
$("#formEncaisserCotisationAdherent-no-profile").show();
$("#formEncaisserCotisationAdherent-no-cotisation-amount").show();
$("#formEncaisserCotisationAdherent_save").prop("disabled",true);
}
......
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.a926d504.js"
"/build/app.435420b4.js"
],
"css": [
"/build/app.6350a995.css"
"/build/app.7133af83.css"
]
},
"admin": {
......
{
"build/app.css": "/build/app.6350a995.css",
"build/app.js": "/build/app.a926d504.js",
"build/app.css": "/build/app.7133af83.css",
"build/app.js": "/build/app.435420b4.js",
"build/admin.css": "/build/admin.4de55830.css",
"build/admin.js": "/build/admin.86a2d986.js",
"build/runtime.js": "/build/runtime.6ad5c9da.js",
......
......@@ -429,26 +429,14 @@ class AdherentAdmin extends AbstractAdmin
$adherent->addAccount($account);
$em->persist($account);
}
$em->persist($adherent->getUser());
$em->persist($adherent);
$em->flush();
}
public function postUpdate($adherent)
{
$this->postUpdateAdherent($adherent);
}
public function postPersist($adherent)
{
$this->postUpdateAdherent($adherent);
}
private function postUpdateAdherent($adherent)
{
if ($this->getConfigurationPool()->getContainer()->getParameter('household_based_allowance')) {
$this->tavCotisationUtils->calculateAllowanceAccordingToHousehold($adherent);
}
$em->persist($adherent->getUser());
$em->persist($adherent);
$em->flush();
}
/**
......
......@@ -136,8 +136,6 @@ class UserAdherentController extends FluxController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// TODO: set CB payment when the functionality is validated
$flux = $form->getData();
// Look for existing cotisation
......@@ -166,12 +164,13 @@ class UserAdherentController extends FluxController
$flux->setDon(null);
}
// TODO redirect to paiement
// Redirect to payment
return $this->forward('App\Controller\PaymentController::preparePaymentAction', [
'form' => $form,
'type' => Payment::TYPE_PAIEMENT_COTISATION_TAV // TODO
'type' => Payment::TYPE_PAIEMENT_COTISATION_TAV
]);
/* For test purposes, comment redirections and uncomment following part to skip payment */
// $this->em->persist($flux);
// $this->operationUtils->executeOperations($flux);
......
......@@ -215,25 +215,54 @@ class UserComptoirController extends FluxController
}
$destinataire = $flux->getDestinataire();
$profile = $destinataire->getProfilDeCotisation();
if (is_null($profile)) {
$this->addFlash(
'error',
$this->translator->trans('Opération impossible : l\'habitant.e n\'a pas de profil de cotisation associé.')
);
if ($this->getParameter('household_based_allowance') == true) {
/* Process: allowance based on household */
$cotisationAmount = $destinataire->getCotisationAmount();
return $this->redirectToRoute('index');
}
// Verifications
if (is_null($cotisationAmount) || is_null($destinataire->getHouseholdAdultCount())) {
$this->addFlash(
'error',
$this->translator->trans("Opération impossible : le profil de l'habitant.e est incomplet, veuillez le compléter dans l'interface d'administration.")
);
$cotisationAmount = $profile->getMontant(); // Amount in € paid by the user
$flux->setMontant($cotisationAmount);
$this->em->persist($flux);
$this->operationUtils->executeOperations($flux);
return $this->redirectToRoute('index');
}
if (is_null($destinataire->getAllocationAmount())) {
$this->tavCotisationUtils->calculateAllowanceAccordingToHousehold($destinataire);
$this->em->persist($destinataire);
}
$flux->setMontant($cotisationAmount);
$this->em->persist($flux);
$this->operationUtils->executeOperations($flux);
// Apply cotisation rate, create new flux
$this->tavCotisationsUtils->applyHouseholdAllowance($flux);
} else {
/* Process: allowance based on cotisation profile with cotisation rate */
$profile = $destinataire->getProfilDeCotisation();
if (is_null($profile)) {
$this->addFlash(
'error',
$this->translator->trans('Opération impossible : l\'habitant.e n\'a pas de profil de cotisation associé.')
);
return $this->redirectToRoute('index');
}
// Apply cotisation rate, create new flux
$this->tavCotisationsUtils->applyTauxCotisation($flux);
$cotisationAmount = $profile->getMontant(); // Amount in € paid by the user
$flux->setMontant($cotisationAmount);
$this->em->persist($flux);
$this->operationUtils->executeOperations($flux);
// Apply cotisation rate, create new flux
$this->tavCotisationsUtils->applyTauxCotisation($flux);
}
$this->em->flush();
......
......@@ -7,16 +7,19 @@ use App\Utils\OperationFactory;
use Doctrine\ORM\Mapping as ORM;
/**
* Application du taux de cotisation lors du paiement d'une cotisation (au sens TAV).
* Application du calcul de l'allocation (emlc reçues) lors du paiement d'une cotisation (au sens TAV).
*
* Au paiement d'une cotisation:
* - Un premier Flux est enregistré, correspondant à l'achat/vente d'emlc.
* - Puis on applique le taux défini dans le ProfilDeCotisation de l'adhérent,
* on crée un nouveau flux pour compléter la cositsation.
* - On crée un nouveau flux pour compléter la cotisation, en fonction du système de calcul choisi.
*
* Systèmes de calculs possibles :
* - On applique le taux défini dans le ProfilDeCotisation de l'adhérent
* - On calcule le montant à recevoir en fonction du foyer de l'adhérent
*
* @ORM\Entity
*/
class TauxCotisationApplication extends Flux
class CotisationTavApplication extends Flux
{
const TYPE_REVERSEMENT_COTISATION_ADHERENT = 'reversement_cotisation_adherent';
const TYPE_PRELEVEMENT_COTISATION_ADHERENT = 'prelevement_cotisation_adherent';
......@@ -26,7 +29,7 @@ class TauxCotisationApplication extends Flux
*/
public function getParenttype(): string
{
return parent::TYPE_APPLICATION_TAUX_COTISATION;
return parent::TYPE_APPLICATION_COTISATION_TAV;
}
public function getAllOperations($em)
......
......@@ -7,12 +7,16 @@ use App\Utils\OperationFactory;
use Doctrine\ORM\Mapping as ORM;
/**
* En cas de taux < 1, l'adhérent•e reçoit moins d'emlc que ce qu'elle•il paye en € :
* Dans les cas suivants :
* - [Profil de Cotisation] La taux est inférieur à 1
* - [Allocation selon foyer] Le montant reçu calculé est inférieur au montant payé
*
* L'adhérent•e reçoit moins d'emlc que ce qu'elle•il paye en €,
* un second flux est créé pour prélever le complément de la cotisation.
*
* @ORM\Entity
*/
class TauxCotisationPrelevement extends TauxCotisationApplication
class CotisationTavPrelevement extends CotisationTavApplication
{
/**
* @ORM\OneToOne(targetEntity="Adherent")
......
......@@ -7,12 +7,16 @@ use App\Utils\OperationFactory;
use Doctrine\ORM\Mapping as ORM;
/**
* En cas de taux > 1, l'adhérent•e reçoit plus d'emlc que ce qu'elle•il paye en € :
* * Dans les cas suivants :
* - [Profil de Cotisation] La taux est supérieur à 1
* - [Allocation selon foyer] Le montant reçu calculé est supérieur au montant payé
*
* L'adhérent•e reçoit plus d'emlc que ce qu'elle•il paye en €,
* un second flux est créé pour reverser le complément de la cotisation.
*
* @ORM\Entity
*/
class TauxCotisationReversement extends TauxCotisationApplication
class CotisationTavReversement extends CotisationTavApplication
{
/**
* @ORM\OneToOne(targetEntity="Siege")
......
......@@ -54,9 +54,9 @@ use Symfony\Component\Validator\Constraints as Assert;
* "ticket_fix" = "TicketFix",
* "ticket_fix_print" = "TicketFixPrint",
* "ticket_fix_destroy" = "TicketFixDestroy",
* "application_taux_cotisation" = "TauxCotisationApplication",
* "reversement_cotisation_adherent" = "TauxCotisationReversement",
* "prelevement_cotisation_adherent" = "TauxCotisationPrelevement",
* "application_cotisation_tav" = "CotisationTavApplication",
* "reversement_cotisation_adherent" = "CotisationTavReversement",
* "prelevement_cotisation_adherent" = "CotisationTavPrelevement",
* })
*/
abstract class Flux implements FluxInterface
......@@ -74,7 +74,7 @@ abstract class Flux implements FluxInterface
const TYPE_VENTE = 'vente';
const TYPE_VENTE_EMLC = 'vente_emlc';
const TYPE_TICKET_FIX = 'ticket_fix';
const TYPE_APPLICATION_TAUX_COTISATION = 'application_taux_cotisation';
const TYPE_APPLICATION_COTISATION_TAV = 'application_cotisation_tav';
/**
* @var \Ramsey\Uuid\UuidInterface
......
......@@ -20,13 +20,17 @@ class EncaisserCotisationAdherentFormType extends VenteEmlcAdherentFormType
// Get the cotisation amount for each adherent. Used for display purposes on the front end.
$adherents = $this->em->getRepository(Adherent::class)->findOrderByName();
$adherentsProfiles = [];
$adherentsCotisationAmounts = [];
foreach ($adherents as $adh) {
$montant = null;
if (!is_null($adh->getProfilDeCotisation()) ) {
if ($this->container->getParameter('household_based_allowance') && !is_null($adh->getCotisationAmount())) {
$montant = $adh->getCotisationAmount();
} else if (!$this->container->getParameter('household_based_allowance') && !is_null($adh->getProfilDeCotisation())) {
$montant = $adh->getProfilDeCotisation()->getMontant();
}
$adherentsProfiles[strval($adh->getId())] = $montant;
$adherentsCotisationAmounts[strval($adh->getId())] = $montant;
}
$builder
......@@ -37,7 +41,7 @@ class EncaisserCotisationAdherentFormType extends VenteEmlcAdherentFormType
'data' => 0
])
->add('cotisationMontants', HiddenType::class, [
'data' => json_encode($adherentsProfiles),
'data' => json_encode($adherentsCotisationAmounts),
'mapped' => false
])
;
......
......@@ -5,8 +5,8 @@ namespace App\Utils;
use App\Entity\Adherent;
use App\Entity\Siege;
use App\Entity\Flux;
use App\Entity\TauxCotisationReversement;
use App\Entity\TauxCotisationPrelevement;
use App\Entity\CotisationTavReversement;
use App\Entity\CotisationTavPrelevement;
use App\Enum\MoyenEnum;
use App\Utils\CustomEntityManager;
use Symfony\Component\Security\Core\Security;
......@@ -75,14 +75,14 @@ class TAVCotisationUtils
if ($amountDiff > 0) {
// User should receive more than he•she paid: send a new flux to the user to complete its cotisation
$fluxCotis = new TauxCotisationReversement();
$fluxCotis = new CotisationTavReversement();
$fluxCotis->setExpediteur($siege);
$fluxCotis->setDestinataire($flux->getDestinataire());
$fluxCotis->setMontant($amountDiff);
$fluxCotis->setReference("Reversement cotisation après paiement de " . $cotisationAmount . "€ et application du taux " . $cotisationTaux);
} else {
// User should receive less than he•she paid: fetch the difference from his account
$fluxCotis = new TauxCotisationPrelevement();
$fluxCotis = new CotisationTavPrelevement();
$fluxCotis->setExpediteur($flux->getDestinataire());
$fluxCotis->setDestinataire($siege);
$fluxCotis->setMontant(-$amountDiff);
......@@ -109,11 +109,11 @@ class TAVCotisationUtils
*
* Once the full amount is calculated, cap user's balance.
* User account balance is capped at twice the amount previously calculated.
*
* @param Adherent $adherent (by ref)
*/
public function calculateAllowanceAccordingToHousehold($adherent) {
$cotisationAmount = $adherent->getCotisationAmount();
// TODO base amounts to param in .env)
public function calculateAllowanceAccordingToHousehold(&$adherent) {
// TODO base amounts to param in .env, or in global params ?
// base allowance, for one adult
$mlcAllowanceAmount = 150;
......@@ -140,41 +140,45 @@ class TAVCotisationUtils
}
$adherent->setAllocationAmount($mlcAllowanceAmount);
$this->em->persist($adherent);
$this->em->flush();
}
/**
* Method called to create Flux
* Method called to create Flux based on allowance amount (for household based allowance)
*
* TODO
*/
public function applyHouseholdAllowance(Flux $flux) {
// get allowance
$adherent = $flux->getDestinataire();
$cotisationAmount = $flux->getMontant();
// get the mlc amount the user is supposed to receive
$mlcAllowanceAmount = $adherent->getAllocationAmount();
// Apply cap
$currentBalance = $adherent->getEmlcAccount()->getBalance();
$capped = false;
if ($currentBalance + $mlcAllowanceAmount >= 2 * $mlcAllowanceAmount) {
// Allow difference to reach max balance
$mlcAllowanceAmount = 2 * $mlcAllowanceAmount - $currentBalance;
$capped = true;
}
// Create Flux
if ($flux->getExpediteur() instanceof Siege) {
$siege = $flux->getExpediteur();
} else {
$siege = $flux->getExpediteur()->getGroupe()->getSiege();
}
// TODO new flux entity ? use same entities ?
$fluxCotis = new TauxCotisationReversement();
$fluxCotis->setExpediteur($siege);
$fluxCotis->setDestinataire($flux->getDestinataire());
$fluxCotis->setMontant($amountDiff);
$fluxCotis->setReference("Reversement allocation après paiement de " . $cotisationAmount . "€ et calcul en fonction du foyer.");
// get the difference between what the user paid and what he•she's supposed to receive
$amountDiff = $mlcAllowanceAmount - $cotisationAmount;
if ($amountDiff > 0) {
// User should receive more than he•she paid: send a new flux to the user to complete its cotisation
$fluxCotis = new CotisationTavReversement();
$fluxCotis->setExpediteur($siege);
$fluxCotis->setDestinataire($adherent);
$fluxCotis->setMontant($amountDiff);
$fluxCotis->setReference("Reversement du complément de cotisation après paiement de " . $cotisationAmount . "€ pour une allocation de " . $mlcAllowanceAmount . " MonA.");
} else {
// User should receive less than he•she paid: fetch the difference from his account
$fluxCotis = new CotisationTavPrelevement();
$fluxCotis->setExpediteur($adherent);
$fluxCotis->setDestinataire($siege);
$fluxCotis->setMontant(-$amountDiff);
$fluxCotis->setReference("Prélèvement du complément de cotisation après paiement de " . $cotisationAmount . "€ pour une allocation de " . $mlcAllowanceAmount . " MonA.");
}
$fluxCotis->setOperateur($flux->getOperateur());
$fluxCotis->setRole($flux->getRole());
$fluxCotis->setMoyen(MoyenEnum::MOYEN_EMLC);
......
......@@ -9,9 +9,13 @@
<h5> <b>Montant de la cotisation : <span id="formEncaisserCotisationAdherent-montant-display"></span></b></h5>
<br/>
</div>
<div id="formEncaisserCotisationAdherent-no-profile" style="display:none">
<p class="formEncaisserCotisationAdherent-no-profile">
L'habitant•e n'a pas de profil de cotisation affecté, impossible de l'encaisser.
<div id="formEncaisserCotisationAdherent-no-cotisation-amount" style="display:none">
<p class="formEncaisserCotisationAdherent-no-cotisation-amount">
{% if household_based_allowance %}
L'habitant•e n'a pas de montant de cotisation renseigné, impossible de l'encaisser.
{% else %}
L'habitant•e n'a pas de profil de cotisation affecté, impossible de l'encaisser.
{% endif %}
</p>
</div>
{% set form = getComptoirEncaisserCotisationForm(app.user) %}
......
......@@ -89,6 +89,7 @@ des_vente_adherent_email_subject: 'Vente de billets à un adhérent'
des_vente_prestataire_email_subject: 'Vente de billets à un prestataire'
des_vente_emlc_adherent_email_subject: 'Vente de monnaie numérique à un adhérent'
des_vente_emlc_prestataire_email_subject: 'Vente de monnaie numérique à un prestataire'
des_application_cotisation_tav: 'Complément de cotisation'
confirmation-cotisation-title: 'Cotisation bien reçue !'
confirmation-cotisation-content: 'Cotisation bien reçue, merci !'
confirmation-cotisation-footer-cta: 'acheter de la monnaie locale numérique'
......
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