Commit 8b7d46cd by Yvon

Merge branch 'ssa-gironde' into 5691-paiement-reccurent-payzen

parents 47a7ad1f 41fca9e5
...@@ -66,3 +66,6 @@ templates/themes/custom/ ...@@ -66,3 +66,6 @@ templates/themes/custom/
#INTELLIJ #INTELLIJ
.idea/ .idea/
#dir containg exported reconversions xml
/reconversions/
...@@ -15,6 +15,7 @@ Extensions PHP : ...@@ -15,6 +15,7 @@ Extensions PHP :
iconv iconv
mariadb (ou mysql > 8.0) mariadb (ou mysql > 8.0)
gd gd
bcmath (en environnement tav/ssa)
Installer composer si besoin Installer composer si besoin
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
"ext-intl": "*", "ext-intl": "*",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"andrew-svirin/ebics-client-php": "^2.1",
"api-platform/core": "^2.6", "api-platform/core": "^2.6",
"beberlei/doctrineextensions": "^1.3", "beberlei/doctrineextensions": "^1.3",
"composer/package-versions-deprecated": "1.*", "composer/package-versions-deprecated": "1.*",
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "a59b75dfa4cd00a3ccefd4cda875dd52", "content-hash": "b4f4376c4660e8a7ab3c2a419263798f",
"packages": [ "packages": [
{ {
"name": "alcohol/iso4217", "name": "alcohol/iso4217",
...@@ -60,6 +60,82 @@ ...@@ -60,6 +60,82 @@
"time": "2019-10-30T10:03:42+00:00" "time": "2019-10-30T10:03:42+00:00"
}, },
{ {
"name": "andrew-svirin/ebics-client-php",
"version": "v2.1.2",
"source": {
"type": "git",
"url": "https://github.com/andrew-svirin/ebics-client-php.git",
"reference": "1692d4d5f2daab29c62bef6c54a0258d6fc927d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/andrew-svirin/ebics-client-php/zipball/1692d4d5f2daab29c62bef6c54a0258d6fc927d6",
"reference": "1692d4d5f2daab29c62bef6c54a0258d6fc927d6",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-json": "*",
"ext-openssl": "*",
"ext-zip": "*",
"ext-zlib": "*",
"php": "^7.4 || ^8"
},
"require-dev": {
"andrew-svirin/cfonb-php": "dev-master",
"andrew-svirin/mt942-php": "dev-master",
"mpdf/mpdf": "~8.0.17",
"phpseclib/phpseclib": "~2.0.35",
"phpstan/phpstan": "~1.9.17",
"phpunit/phpunit": "~9.6.3",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"squizlabs/php_codesniffer": "~3.7.1"
},
"suggest": {
"andrew-svirin/cfonb-php": "If you need to parse format CFONB from FDL requests.",
"andrew-svirin/mt942-php": "If you need to parse format MT942 from VMK, STA requests.",
"mpdf/mpdf": "If you need to generate PDF file letter for Bank.",
"psr/http-client": "If you want use the PsrHttpClient",
"psr/http-factory": "If you want use the PsrHttpClient"
},
"type": "library",
"autoload": {
"psr-4": {
"AndrewSvirin\\Ebics\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andrew Svirin"
}
],
"description": "PHP library to communicate with bank through EBICS protocol.",
"keywords": [
"cfonb.120",
"cfonb.240",
"client",
"ebics",
"mt940",
"mt942",
"openssl",
"php",
"rsa",
"x509"
],
"support": {
"issues": "https://github.com/andrew-svirin/ebics-client-php/issues",
"source": "https://github.com/andrew-svirin/ebics-client-php/tree/v2.1.2"
},
"time": "2023-08-16T18:19:58+00:00"
},
{
"name": "api-platform/core", "name": "api-platform/core",
"version": "v2.6.8", "version": "v2.6.8",
"source": { "source": {
...@@ -2449,46 +2525,6 @@ ...@@ -2449,46 +2525,6 @@
"time": "2021-10-11T09:18:27+00:00" "time": "2021-10-11T09:18:27+00:00"
}, },
{ {
"name": "ekyna/payum-payzen",
"version": "dev-master",
"dist": {
"type": "path",
"url": "./lib/ekyna/payum-payzen",
"reference": "781b74869b2acc65e7635c5bd5d40c66cf1c2177"
},
"require": {
"payum/core": "^1.5",
"php": "^7.0",
"php-http/guzzle6-adapter": "^2.0",
"psr/log": "~1.0",
"symfony/process": "4.4.*"
},
"type": "component",
"autoload": {
"psr-4": {
"Ekyna\\Component\\Payum\\Payzen\\": ""
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Etienne Dauvergne",
"homepage": "http://ekyna.com"
}
],
"description": "PayZen Payum gateway",
"homepage": "https://github.com/ekyna/PayumPayzen",
"keywords": [
"payum",
"payzen"
],
"transport-options": {
"relative": true
}
},
{
"name": "exsyst/swagger", "name": "exsyst/swagger",
"version": "v0.4.2", "version": "v0.4.2",
"source": { "source": {
...@@ -19565,9 +19601,7 @@ ...@@ -19565,9 +19601,7 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": [],
"ekyna/payum-payzen": 20
},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
......
...@@ -15,3 +15,4 @@ twig: ...@@ -15,3 +15,4 @@ twig:
presta_self_init_and_eval: '%env(PRESTA_SELF_INIT_AND_EVAL)%' presta_self_init_and_eval: '%env(PRESTA_SELF_INIT_AND_EVAL)%'
presta_extra_data: '%env(PRESTA_EXTRA_DATA)%' presta_extra_data: '%env(PRESTA_EXTRA_DATA)%'
household_based_allowance: '%env(HOUSEHOLD_BASED_ALLOWANCE)%' household_based_allowance: '%env(HOUSEHOLD_BASED_ALLOWANCE)%'
automatisation_reconversion: '%env(AUTOMATISATION_RECONVERSION)%'
\ No newline at end of file
...@@ -253,7 +253,7 @@ services: ...@@ -253,7 +253,7 @@ services:
admin.adherent.gerer: admin.adherent.gerer:
class: App\Admin\AdherentAdmin class: App\Admin\AdherentAdmin
# arguments: [~, App\Entity\OBJECT, 'PixSortableBehaviorBundle:SortableAdmin'] # arguments: [~, App\Entity\OBJECT, 'PixSortableBehaviorBundle:SortableAdmin']
arguments: [~, App\Entity\Adherent, 'App\Controller\CRUD\CRUDController'] arguments: [~, App\Entity\Adherent, 'App\Controller\AdherentAdminController']
tags: tags:
- name: sonata.admin - name: sonata.admin
manager_type: orm manager_type: orm
......
...@@ -583,6 +583,7 @@ class AdherentAdmin extends AbstractAdmin ...@@ -583,6 +583,7 @@ class AdherentAdmin extends AbstractAdmin
->addIdentifier('user.email', null, ['label' => 'Email']) ->addIdentifier('user.email', null, ['label' => 'Email'])
; ;
$actions = ['edit' => []];
if (!$this->getConfigurationPool()->getContainer()->getParameter('tav_env')) { if (!$this->getConfigurationPool()->getContainer()->getParameter('tav_env')) {
$listMapper $listMapper
->add( ->add(
...@@ -603,6 +604,21 @@ class AdherentAdmin extends AbstractAdmin ...@@ -603,6 +604,21 @@ class AdherentAdmin extends AbstractAdmin
'template' => '@kohinos/tav/list_user_tav_cotisation.html.twig', 'template' => '@kohinos/tav/list_user_tav_cotisation.html.twig',
] ]
); );
if($this->getConfigurationPool()->getContainer()->getParameter('household_based_allowance')
&& $this->security->isGranted('ROLE_SUPER_ADMIN') || $this->security->isGranted('ROLE_ADMIN_SIEGE')) {
$listMapper
->add(
'ceiling',
null,
[
'label' => 'Solde & plafond',
'template' => '@kohinos/tav/list_user_ssa_ceiling.html.twig',
]
);
$actions['withdrawDownToTheCeiling'] = [
'template' => '@kohinos/tav/adherent_action_withdraw_down_to_the_ceiling.html.twig'
];
}
} }
$listMapper $listMapper
...@@ -625,7 +641,7 @@ class AdherentAdmin extends AbstractAdmin ...@@ -625,7 +641,7 @@ class AdherentAdmin extends AbstractAdmin
'label' => 'Mis à jour le', 'label' => 'Mis à jour le',
]) ])
->add('_action', null, [ ->add('_action', null, [
'actions' => ['edit' => []], 'actions' => $actions,
]) ])
; ;
} }
...@@ -633,7 +649,9 @@ class AdherentAdmin extends AbstractAdmin ...@@ -633,7 +649,9 @@ class AdherentAdmin extends AbstractAdmin
protected function configureRoutes(RouteCollection $collection) protected function configureRoutes(RouteCollection $collection)
{ {
parent::configureRoutes($collection); parent::configureRoutes($collection);
$collection->remove('delete'); $collection
->remove('delete')
->add('withdrawDownToTheCeiling', $this->getRouterIdParameter() . '/withdrawDownToTheCeiling');
} }
public function getBatchActions() public function getBatchActions()
......
...@@ -206,6 +206,11 @@ class PrestataireAdmin extends AbstractAdmin ...@@ -206,6 +206,11 @@ class PrestataireAdmin extends AbstractAdmin
'label' => 'SIRET :', 'label' => 'SIRET :',
'required' => false, 'required' => false,
]) ])
//bic is new field in kohinos-ssa (I think it's OK to add it for non-tav env as well)
->add('bic', TextType::class, [
'label' => 'BIC :',
'required' => false,
])
->add('iban', PersonalDataType::class, [ ->add('iban', PersonalDataType::class, [
'label' => 'IBAN :', 'label' => 'IBAN :',
'required' => false, 'required' => false,
...@@ -366,7 +371,8 @@ class PrestataireAdmin extends AbstractAdmin ...@@ -366,7 +371,8 @@ class PrestataireAdmin extends AbstractAdmin
->add('enabled', null, [ ->add('enabled', null, [
'label' => 'Activé ?', 'label' => 'Activé ?',
'required' => false, 'required' => false,
'data' => false 'data' => $presta && $presta->getRaison() ? $presta->isEnabled() : false, //force false at create time only
'attr' => ['autocomplete' => 'off']
]) ])
->add('conventionnement', ChoiceType::class, [ ->add('conventionnement', ChoiceType::class, [
'choices' => [ 'choices' => [
......
...@@ -96,4 +96,8 @@ class ReconversionAdmin extends FluxAdmin ...@@ -96,4 +96,8 @@ class ReconversionAdmin extends FluxAdmin
'Reconverti ?' => 'reconverti', 'Reconverti ?' => 'reconverti',
]; ];
} }
public function isReconversionAdmin() {
return true;
}
} }
<?php
declare(strict_types=1);
namespace App\Command;
use App\Entity\GlobalParameter;
use App\Entity\Prestataire;
use App\Entity\Reconversion;
use App\Entity\Siege;
use App\Enum\MoyenEnum;
use App\Enum\ReconversionFrequencyEnum;
use App\Utils\CustomEntityManager;
use App\Utils\OperationUtils;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Twig\Environment;
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
class ReconversionMonaPrestatairesCommand extends Command
{
//Call with following crons :
//15 1 14,28 * * kohinos php /home/kohinos/kohinos/bin/console kohinos:ssa:reconversion-prestataires twice_a_month
//17 1 28 * * kohinos php /home/kohinos/kohinos/bin/console kohinos:ssa:reconversion-prestataires once_a_month
//19 1 28 1,3,5,7,9,11 * kohinos php /home/kohinos/kohinos/bin/console kohinos:ssa:reconversion-prestataires once_every_two_month
protected static $defaultName = 'kohinos:ssa:reconversion-prestataires';
protected $em;
protected $mailer;
protected $templating;
protected $io;
protected $param;
protected $operationUtils;
public function __construct(
CustomEntityManager $em,
\Swift_Mailer $mailer,
Environment $templating,
OperationUtils $operationUtils
) {
$this->em = $em;
$this->mailer = $mailer;
$this->templating = $templating;
$this->operationUtils = $operationUtils;
parent::__construct();
}
protected function configure()
{
$this
->setDescription('SSA : générer des flux de reconversion conformément à la fréquence configurée par les prestataires')
->addArgument('reconvmode', InputArgument::REQUIRED, 'Restriction aux seuls prestataires ayant opté pour la fréquence choisie.');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->io = new SymfonyStyle($input, $output);
$reconvmode = $input->getArgument('reconvmode');
if (!in_array($reconvmode, ReconversionFrequencyEnum::getAvailableTypes())) {
$this->io->error("L'argument " . $reconvmode . ' est invalide. Choix possibles : '
. implode(', ', ReconversionFrequencyEnum::getAvailableTypes()));
return 1;
}
$this->io->title('START. Reconversion pour les prestataires de compte positif ayant choisi la fréquence : ' . $reconvmode);
$prestas = $this->em->getRepository(Prestataire::class)->findBy(['reconversionFrequency' => $reconvmode]);
foreach ($prestas as $p) {
$balance = $p->getEmlcAccount()->getBalance();
if ($balance <= 0) {
continue;
}
/* @var Prestataire $p */
$flux = new Reconversion();
//do not fill operator as it is automated process $entity->setOperateur();
$flux->setExpediteur($p);
$flux->setMontant($balance); //montant maximal
$flux->setDestinataire($this->em->getRepository(Siege::class)->getTheOne());
$flux->setMoyen(MoyenEnum::MOYEN_AUTRE);
$flux->setTauxreconversion(
!empty($p->getTauxreconversion()) ?
$p->getTauxreconversion()
: floatval(
$this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::RECONVERSION_PRESTATAIRE)
)
);
$now = new \DateTime();
$flux->setReference(
'Reconversion automatique du ' . $now->format('d/m/Y')
. " pour le mode de reconversion " . $reconvmode
);
$this->operationUtils->executeOperations($flux);
}
$this->io->success('End');
$memoryUsage = memory_get_usage(true) / 1024 / 1024;
$this->io->text("Batch finished with memory: ${memoryUsage}M");
return 0;
}
}
<?php
namespace App\Controller;
use App\Utils\CustomEntityManager;
use App\Utils\TAVCotisationUtils;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Security;
class AdherentAdminController extends CRUDController
{
protected $em;
protected $security;
protected $tavCotisationUtils;
public function __construct(CustomEntityManager $em, Security $security, TAVCotisationUtils $tavCotisationUtils)
{
$this->em = $em;
$this->security = $security;
$this->tavCotisationUtils = $tavCotisationUtils;
}
/**
* Prélèvement d'un adhérent pour ramener son solde sous son plafond.
*
* @param Request $request
* @param Uuid $id Id du prestataire
* @IsGranted({"ROLE_SUPER_ADMIN", "ROLE_ADMIN_SIEGE"})
* @return Response
*/
public function withdrawDownToTheCeilingAction(Request $request, $id): Response
{
$adherent = $this->admin->getSubject();
if (!$adherent) {
throw new NotFoundHttpException(sprintf('Impossible de trouver l\'adhérent avec l\'id: %s', $id));
}
$amountDiff = $this->tavCotisationUtils->withdrawDownToTheCeiling($adherent);
$this->em->flush();
$this->addFlash(
'sonata_flash_success',
'Prélèvement de ' . -$amountDiff . ' MonA' . ' effectué.'
);
return new RedirectResponse(
$this->admin->generateUrl('list', ['filter' => $this->admin->getFilterParameters()])
);
}
}
...@@ -2,11 +2,14 @@ ...@@ -2,11 +2,14 @@
namespace App\Controller; namespace App\Controller;
use AndrewSvirin\Ebics\Builders\CustomerCreditTransfer\CustomerCreditTransferBuilder;
use App\Entity\Adherent; use App\Entity\Adherent;
use App\Entity\Don; use App\Entity\Don;
use App\Entity\Flux; use App\Entity\Flux;
use App\Entity\GlobalParameter;
use App\Entity\Groupe; use App\Entity\Groupe;
use App\Entity\Prestataire; use App\Entity\Prestataire;
use App\Entity\Reconversion;
use App\Entity\User; use App\Entity\User;
use App\Enum\CurrencyEnum; use App\Enum\CurrencyEnum;
use App\Flux\FluxInterface; use App\Flux\FluxInterface;
...@@ -16,6 +19,7 @@ use App\Utils\TAVCotisationUtils; ...@@ -16,6 +19,7 @@ use App\Utils\TAVCotisationUtils;
use FOS\UserBundle\Model\UserManagerInterface; use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Util\TokenGeneratorInterface; use FOS\UserBundle\Util\TokenGeneratorInterface;
use Gamez\Symfony\Component\Serializer\Normalizer\UuidNormalizer; use Gamez\Symfony\Component\Serializer\Normalizer\UuidNormalizer;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sonata\Exporter\Handler; use Sonata\Exporter\Handler;
use Sonata\Exporter\Source\DoctrineORMQuerySourceIterator; use Sonata\Exporter\Source\DoctrineORMQuerySourceIterator;
use Sonata\Exporter\Writer\CsvWriter; use Sonata\Exporter\Writer\CsvWriter;
...@@ -30,6 +34,7 @@ use Symfony\Component\HttpFoundation\Response; ...@@ -30,6 +34,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\JsonEncoder;
...@@ -75,6 +80,7 @@ class FluxController extends AbstractController ...@@ -75,6 +80,7 @@ class FluxController extends AbstractController
protected $tokenGenerator; protected $tokenGenerator;
protected $validator; protected $validator;
protected $userManager; protected $userManager;
protected $router;
public function __construct( public function __construct(
Security $security, Security $security,
...@@ -88,7 +94,8 @@ class FluxController extends AbstractController ...@@ -88,7 +94,8 @@ class FluxController extends AbstractController
TokenGeneratorInterface $tokenGenerator, TokenGeneratorInterface $tokenGenerator,
ValidatorInterface $validator, ValidatorInterface $validator,
CsrfTokenManagerInterface $tokenManager, CsrfTokenManagerInterface $tokenManager,
UserManagerInterface $userManager UserManagerInterface $userManager,
RouterInterface $router
) { ) {
$this->security = $security; $this->security = $security;
$this->em = $em; $this->em = $em;
...@@ -102,6 +109,7 @@ class FluxController extends AbstractController ...@@ -102,6 +109,7 @@ class FluxController extends AbstractController
$this->tokenManager = $tokenManager; $this->tokenManager = $tokenManager;
$this->tavCotisationsUtils = $tavCotisationsUtils; $this->tavCotisationsUtils = $tavCotisationsUtils;
$this->userManager = $userManager; $this->userManager = $userManager;
$this->router = $router;
} }
protected function manageFluxForm(Request $request, Form $form, $template = '@kohinos/flux/transaction.html.twig', $params = []) protected function manageFluxForm(Request $request, Form $form, $template = '@kohinos/flux/transaction.html.twig', $params = [])
...@@ -171,6 +179,101 @@ class FluxController extends AbstractController ...@@ -171,6 +179,101 @@ class FluxController extends AbstractController
} }
/** /**
* @param Request $request
* @Route("/credit-transfer-file", name="credit_transfer_file")
* @IsGranted({"ROLE_TRESORIER", "ROLE_SUPER_ADMIN"})
* @return Response
*/
public function creditTransferFileAction(Request $request)
{
//raison, bic and iban from debitor are fetched in global parameters
$globalParametersRepository = $this->em->getRepository(GlobalParameter::class);
$raison = $globalParametersRepository->val(GlobalParameter::VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE);
$bic = $globalParametersRepository->val(GlobalParameter::VIREMENT_RECONVERSION_BIC_GESTIONNAIRE);
$iban = $globalParametersRepository->val(GlobalParameter::VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE);
//make sure raison, bic and iban are not empty
if(!$raison || !$bic || !$iban) {
$this->addFlash(
'sonata_flash_error',
"Opération annulée car la raison, l'IBAN ou le BIC du gestionnaire pour les virements de reconversions est vide."
);
return $this->redirect($this->router->generate('index') . 'admin/app/reconversion/list');
}
//SEPA
$builder = new CustomerCreditTransferBuilder();
$customerCreditTransfer = $builder
->createInstance(
$bic,
$iban,
$raison
);
$reconversions = $this->em->getRepository(Reconversion::class)->findBy(["reconverti" => false]);
if(!$reconversions) {
$this->addFlash(
'sonata_flash_error',
"Aucune reconversion à traiter."
);
return $this->redirect($this->router->generate('index') . 'admin/app/reconversion/list');
}
foreach($reconversions as $r) {
/* @var Reconversion $r */
/* @var Prestataire $presta */
$presta = $r->getExpediteur();
if(!$presta || !$presta->isEnabled()) {
//fail ; do not flush : we don't want to toggle reconverti when file can't be generated
$this->addFlash(
'sonata_flash_error',
"Opération annulée car le prestataire " . $presta->getRaison() . " est désactivé ou introuvable."
);
return $this->redirect($this->router->generate('index') . 'admin/app/reconversion/list');
}
if(!$presta->getIban() || !$presta->getBic()) {
//fail ; do not flush : we don't want to toggle reconverti when file can't be generated
$this->addFlash(
'sonata_flash_error',
"Opération annulée car l'IBAN ou le BIC du prestataire " . $presta->getRaison() . " est vide."
);
return $this->redirect($this->router->generate('index') . 'admin/app/reconversion/list');
}
$customerCreditTransfer
->addTransaction(
$presta->getBic(),
$presta->getIban(),
$presta->getRaison(),
$r->getMontant(),
'EUR',
'Reconversion MonA vers EUR'
);
$r->setReconverti(true);
}
$filename = sprintf(
'credit_transfer_file_%s.%s',
date('Y_m_d_H_i_s', strtotime('now')),
'xml'
);
//projectDir is composer.json
$dir = $this->getParameter('kernel.project_dir') . "/reconversions";
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$path = $dir . "/" . $filename;
$customerCreditTransfer->popInstance()->save($path);
$this->em->flush();
return $this->file($path);
}
/**
* Export all operations for a user role. * Export all operations for a user role.
* *
* @param Request $request Request * @param Request $request Request
......
...@@ -446,4 +446,10 @@ class Adherent extends AccountableObject implements AccountableInterface ...@@ -446,4 +446,10 @@ class Adherent extends AccountableObject implements AccountableInterface
return $this; return $this;
} }
public function getCeiling()
{
//This formula has been configured for ssa gironde project
return 2 * $this->allocationAmount;
}
} }
...@@ -10,6 +10,8 @@ use Doctrine\ORM\Mapping as ORM; ...@@ -10,6 +10,8 @@ use Doctrine\ORM\Mapping as ORM;
* Dans les cas suivants : * Dans les cas suivants :
* - [Profil de Cotisation] La taux est inférieur à 1 * - [Profil de Cotisation] La taux est inférieur à 1
* - [Allocation selon foyer] Le montant reçu calculé est inférieur au montant payé * - [Allocation selon foyer] Le montant reçu calculé est inférieur au montant payé
* - [Allocation selon foyer] Un administrateur effectue une opération manuelle de prélèvement de l'adhérent
* pour ramener son solde au niveau de son plafond.
* *
* L'adhérent•e reçoit moins d'emlc que ce qu'elle•il paye en €, * 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. * un second flux est créé pour prélever le complément de la cotisation.
......
...@@ -51,6 +51,9 @@ class GlobalParameter ...@@ -51,6 +51,9 @@ class GlobalParameter
const HELLOASSO_URL_COTISATION_ADHERENT = 'HELLOASSO_URL_COTISATION_ADHERENT'; const HELLOASSO_URL_COTISATION_ADHERENT = 'HELLOASSO_URL_COTISATION_ADHERENT';
const HELLOASSO_URL_COTISATION_PRESTATAIRE = 'HELLOASSO_URL_COTISATION_PRESTATAIRE'; const HELLOASSO_URL_COTISATION_PRESTATAIRE = 'HELLOASSO_URL_COTISATION_PRESTATAIRE';
const CONTACT_FORM_PHONE_NUMBER = 'CONTACT_FORM_PHONE_NUMBER'; const CONTACT_FORM_PHONE_NUMBER = 'CONTACT_FORM_PHONE_NUMBER';
const VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE = 'VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE';
const VIREMENT_RECONVERSION_BIC_GESTIONNAIRE = 'VIREMENT_RECONVERSION_BIC_GESTIONNAIRE';
const VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE = 'VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE';
/** /**
* @var \Ramsey\Uuid\UuidInterface * @var \Ramsey\Uuid\UuidInterface
......
...@@ -146,6 +146,19 @@ class Prestataire extends AccountableObject implements AccountableInterface ...@@ -146,6 +146,19 @@ class Prestataire extends AccountableObject implements AccountableInterface
private $iban; private $iban;
/** /**
* Bank Identifier Code.
*
* @var string
*
* @ORM\Column(name="bic", type="string", nullable=true)
*
* @Assert\Bic(
* ibanPropertyPath="iban"
* )
*/
private $bic;
/**
* @var string * @var string
* *
* @ORM\Column(name="siret", type="string", length=50, nullable=true) * @ORM\Column(name="siret", type="string", length=50, nullable=true)
...@@ -541,6 +554,26 @@ class Prestataire extends AccountableObject implements AccountableInterface ...@@ -541,6 +554,26 @@ class Prestataire extends AccountableObject implements AccountableInterface
/** /**
* @return string * @return string
*/ */
public function getBic(): ?string
{
return $this->bic;
}
/**
* @param string $bic
*
* @return Prestataire
*/
public function setBic(?string $bic): self
{
$this->bic = $bic;
return $this;
}
/**
* @return string
*/
public function getSiret(): ?string public function getSiret(): ?string
{ {
return $this->siret; return $this->siret;
......
...@@ -331,6 +331,27 @@ class GlobalConfigurationFormType extends AbstractType ...@@ -331,6 +331,27 @@ class GlobalConfigurationFormType extends AbstractType
'required' => false, 'required' => false,
'_placeholder' => '', '_placeholder' => '',
]) ])
->add('raisongestionnairevirementreconversion', GlobalParameterType::class, [
'label' => 'Raison du gestionnaire pour les virements de reconversion automatisés',
'_description' => 'Raison du gestionnaire pour les virements de reconversion automatisés',
'name_param' => GlobalParameter::VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE,
'required' => false,
'_placeholder' => '',
])
->add('bicgestionnairevirementreconversion', GlobalParameterType::class, [
'label' => 'BIC du gestionnaire pour les virements de reconversion automatisés',
'_description' => 'BIC du gestionnaire pour les virements de reconversion automatisés',
'name_param' => GlobalParameter::VIREMENT_RECONVERSION_BIC_GESTIONNAIRE,
'required' => false,
'_placeholder' => '',
])
->add('ibangestionnairevirementreconversion', GlobalParameterType::class, [
'label' => 'IBAN du gestionnaire pour les virements de reconversion automatisés',
'_description' => 'IBAN du gestionnaire pour les virements de reconversion automatisés',
'name_param' => GlobalParameter::VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE,
'required' => false,
'_placeholder' => '',
])
; ;
} }
......
...@@ -66,6 +66,11 @@ class PrestataireInfosFormType extends AbstractType ...@@ -66,6 +66,11 @@ class PrestataireInfosFormType extends AbstractType
'label' => 'SIRET :', 'label' => 'SIRET :',
'required' => false, 'required' => false,
]) ])
//bic is new field in kohinos-ssa (I think it's OK to add it for non-tav env as well)
->add('bic', TextType::class, [
'label' => 'BIC :',
'required' => false,
])
->add('iban', TextType::class, [ ->add('iban', TextType::class, [
'label' => 'IBAN :', 'label' => 'IBAN :',
'required' => false, 'required' => false,
......
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240320144059 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire ADD bic VARCHAR(8) DEFAULT NULL, CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\'');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire DROP bic, CHANGE iban iban LONGTEXT CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci` COMMENT \'(DC2Type:personal_data)\'');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240320153828 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\', CHANGE bic bic VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci` COMMENT \'(DC2Type:personal_data)\', CHANGE bic bic VARCHAR(8) CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci`');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240321101500 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE', 'Raison du gestionnaire pour les virements de reconversion automatisés', null, '1')");
$this->addSql("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'VIREMENT_RECONVERSION_BIC_GESTIONNAIRE', 'Bic du gestionnaire pour les virements de reconversion automatisés', null, '1')");
$this->addSql("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE', 'Iban du gestionnaire pour les virements de reconversion automatisés', null, '1')");
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
}
}
...@@ -184,6 +184,37 @@ class TAVCotisationUtils ...@@ -184,6 +184,37 @@ class TAVCotisationUtils
$this->em->persist($fluxCotis); $this->em->persist($fluxCotis);
$this->operationUtils->executeOperations($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 * Get the last cotisation of an adhérent
* *
......
...@@ -33,6 +33,12 @@ ...@@ -33,6 +33,12 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% if tav_env and automatisation_reconversion and admin.isReconversionAdmin is defined and admin.isReconversionAdmin %}
<a href="{{ path('credit_transfer_file') }}" type="button" class="btn btn-default">
<i class="fa fa-share-square-o" aria-hidden="true"></i>
Générer SEPA
</a>
{% endif %}
</div> </div>
</div> </div>
{% if admin.total is defined and admin.total > 0 %} {% if admin.total is defined and admin.total > 0 %}
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
</div> </div>
{% endif %} {% endif %}
{{ form_row(form.siret) }} {{ form_row(form.siret) }}
{{ form_row(form.bic) }}
{{ form_row(form.iban) }} {{ form_row(form.iban) }}
{{ form_row(form.responsable) }} {{ form_row(form.responsable) }}
{{ form_row(form.metier) }} {{ form_row(form.metier) }}
......
{% set balance = object.user.adherent.emlcAccount.balance %}
{% set ceiling = object.user.adherent.ceiling %}
{% if balance and ceiling and balance > ceiling %}
{% set diff = balance - ceiling %}
{% set warnMsg =
'Vous vous apprêtez à prélever ' ~ diff|number_format ~ ' MonA sur le compte de '
~ object.user.adherent ~ ' afin de ramener le solde de son compte au niveau de son plafond autorisé. Poursuivre ?'
%}
<a class="btn btn-sm btn-default"
href="{{ admin.generateObjectUrl('withdrawDownToTheCeiling', object) }}"
onclick="return confirm('{{ warnMsg }}')">
Prélever
</a>
{% endif %}
{% extends admin.getTemplate('base_list_field') %}
{% block field %}
{%- spaceless %}
{% set balance = object.user.adherent.emlcAccount.balance %}
{% set ceiling = object.user.adherent.ceiling %}
{% if not ceiling %}
{% set class = 'label label-warning' %}
{% set text = 'profil incomplet' %}
{% elseif balance > ceiling %}
{% set class = 'label label-danger' %}
{% set text = balance ~ ' > ' ~ ceiling %}
{% else %}
{% set class = 'label label-success' %}
{% set text = balance ~ " &leq; " ~ ceiling %}
{% endif %}
<span class="{{ class }}">{{ text|raw }}</span>
{% endspaceless -%}
{% endblock %}
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