<?php namespace App\Utils; use App\Entity\Adherent; use App\Entity\Siege; use App\Entity\Flux; use App\Entity\CotisationTavReversement; use App\Entity\CotisationTavPrelevement; use App\Enum\MoyenEnum; use App\Utils\CustomEntityManager; use Symfony\Component\Security\Core\Security; class TAVCotisationUtils { private $em; private $security; private $operationUtils; public function __construct ( CustomEntityManager $em, Security $security, OperationUtils $operationUtils ) { $this->em = $em; $this->security = $security; $this->operationUtils = $operationUtils; } /** * Check if cotisation already exist this month the the recipient of the given Flux. */ public function checkExistingCotisation(Flux $flux) { $first_day_this_month = date('Y-m-01'); $last_day_this_month = date('Y-m-t'); $existing = $this->em->getRepository(Flux::class)->getTavCotisationsBetweenDates( $flux->getDestinataire(), $first_day_this_month, $last_day_this_month ); return count($existing) > 0; } /** * First method to calculate allowance: * according to a contribution rate defined in user's profile (ProfilDeCotisation). * * Apply the cotisation profile rate to the amount paid * and register the complement as a new flux (only if rate != 1) * * Warning: EntityManager not flushed here. */ public function applyTauxCotisation(Flux $flux) { $profile = $flux->getDestinataire()->getProfilDeCotisation(); $cotisationTaux = $profile->getTauxCotisation(); // don't need to create an other Flux if the rate is 1 if ($cotisationTaux != 1) { // calculate the mlc amount the user will receive $cotisationAmount = $profile->getMontant(); $mlcAmount = round($cotisationAmount * $cotisationTaux); // get the difference between what the user paid and what he•she's supposed to receive $amountDiff = $mlcAmount - $cotisationAmount; if ($flux->getExpediteur() instanceof Siege) { $siege = $flux->getExpediteur(); } else { $siege = $flux->getExpediteur()->getGroupe()->getSiege(); } 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($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 CotisationTavPrelevement(); $fluxCotis->setExpediteur($flux->getDestinataire()); $fluxCotis->setDestinataire($siege); $fluxCotis->setMontant(-$amountDiff); $fluxCotis->setReference("Prélèvement cotisation après paiement de " . $cotisationAmount . "€ et application du taux " . $cotisationTaux); } $fluxCotis->setOperateur($flux->getOperateur()); $fluxCotis->setRole($flux->getRole()); $fluxCotis->setMoyen(MoyenEnum::MOYEN_EMLC); $this->em->persist($fluxCotis); $this->operationUtils->executeOperations($fluxCotis); } } /** * Second method to calculate allowance: * allowance based on user's household. * * Rules are as follow: * - 150 emlc for the first person in user's household * - 75 emlc for each other adult * - 75 emlc amount for each dependant child, with a percentage applied if the child is in shared custody: * 25%, 50% or 75% depending on the shared custody arrangement * * 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) { // TODO base amounts to param in .env, or in global params ? // base allowance, for one adult $mlcAllowanceAmount = 150; $adultsCount = $adherent->getHouseholdAdultCount(); if ($adultsCount == null) { return; } // increment for each other adult in the household $mlcAllowanceAmount += 75 * ($adultsCount - 1); // increment allowance for each dependant child, depending on the shared custody arrangement $dependentChildren = $adherent->getDependentChildren(); foreach ($dependentChildren as $child) { $childAllowanceAmount = 75; $sharedCustodyPercentage = $child->getSharedCustodyPercentage(); if ($sharedCustodyPercentage != null) { $childAllowanceAmount = $childAllowanceAmount * $sharedCustodyPercentage; } $mlcAllowanceAmount += $childAllowanceAmount; } $adherent->setAllocationAmount($mlcAllowanceAmount); } /** * Method called to create Flux based on allowance amount (for household based allowance). */ 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(); if ($flux->getExpediteur() instanceof Siege) { $siege = $flux->getExpediteur(); } else { $siege = $flux->getExpediteur()->getGroupe()->getSiege(); } // 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); $this->em->persist($fluxCotis); $this->operationUtils->executeOperations($fluxCotis); } /** * Method called to create Flux based on allowance amount (for household based allowance). */ public function withdrawDownToTheCeiling(Adherent $adherent) { $balance = $adherent->getEmlcAccount()->getBalance(); $ceiling = $adherent->getCeiling(); $siege = $this->em->getRepository(Siege::class)->getTheOne(); // get the amount we want to withdraw $amountDiff = $ceiling - $balance; if ($amountDiff >= 0) { throw new \Exception("Impossible de prélèver : le solde de l'adhérent est inférieur ou égal au plafond."); } $flux = new CotisationTavPrelevement(); $flux->setExpediteur($adherent); $flux->setDestinataire($siege); $flux->setMontant(-$amountDiff); $flux->setReference("Prélèvement pour ramener le solde de " . $balance . "MonA sous le plafond de " . $ceiling . " MonA."); $flux->setOperateur($this->security->getUser()); $flux->setRole($this->security->getUser()->getGroups()[0]->__toString()); $flux->setMoyen(MoyenEnum::MOYEN_EMLC); $this->em->persist($flux); $this->operationUtils->executeOperations($flux); return $amountDiff; } /** * Get the last cotisation of an adhérent * * @param Adherent $adherent * * @return bool|date */ public function getLastTavCotisationForAdherent(?Adherent $adherent) { $cotisations = []; if (null !== $adherent) { $cotisations = $this->em->getRepository(Flux::class)->getLastTavCotisation($adherent); } if (count($cotisations) > 0) { return $cotisations[0]["created_at"]; } return false; } }