<?php
namespace App\Controller\Frontend;
use App\Controller\BaseController;
use App\Entity\Cotisation;
use App\Entity\CotisationNotification;
use App\Entity\CotisationStatut;
use App\Entity\Entreprise;
use App\Entity\FormTemplate;
use App\Entity\ParamCotisation;
use App\Entity\PaymentType;
use App\Entity\Order;
use App\Form\Frontend\CustomerCotisationType;
use App\Form\Frontend\PaymentSelectorType;
use App\Model\Paygate;
use App\Repository\CotisationNotificationRepository;
use App\Repository\CotisationRepository;
use App\Repository\ParameterRepository;
use App\Service\FormService;
use App\Service\MailerService;
use App\Service\SaleService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
class CotisationController extends BaseController
{
public function __construct(
private TokenStorageInterface $tokenStorage,
private EntityManagerInterface $em,
private MailerService $mailerService,
)
{
}
#[Route('/cotisations', name: 'customer_cotisation_list', methods: ['GET'])]
public function list(Request $request, PaginatorInterface $paginator, CotisationRepository $cotisationRepository): Response
{
$query = $cotisationRepository->findAllQuery($this->getUser());
$cotisations = $paginator->paginate(
$query,
$request->query->getInt('page', 1),
self::ITEM_PER_PAGE
);
return $this->render('frontend/cotisation/index.html.twig', [
'controller_name' => 'CotisationController',
'menu' => 'my-space',
'submenu' => 'my-cotisation',
'cotisations' => $cotisations
]);
}
#[Route('/cotisations/{id}/show', name: 'customer_cotisation_show', methods: ['GET'])]
public function show(Cotisation $cotisation, ParameterRepository $parameterRepository): Response
{
$paymentInfos = $parameterRepository->findBy([
'subtype' => 'banque'
], [
'paramOrder' => 'ASC'
]);
$rib = $parameterRepository->findOneBy([
'subtype' => 'banque',
'tag' => 'sale.bank.rib',
]);
return $this->render('frontend/cotisation/show.html.twig', [
'controller_name' => 'CotisationController',
'menu' => 'my-space',
'submenu' => 'my-cotisation',
'cotisation' => $cotisation,
'paymentInfos' => $paymentInfos,
'rib' => $rib,
]);
}
#[Route('/cotisations/cancel-notification/{id}', name: 'customer_cotisation_notification_cancel', methods: ['GET'])]
public function cancelCotisationNotification(
CotisationNotification $cotisationNotification,
CotisationNotificationRepository $repository,
Request $request
): RedirectResponse
{
$cotisationNotification->setStatus(CotisationNotification::STATUS_CANCELED);
$repository->save($cotisationNotification, true);
$referer = $request->headers->get('referer');
return $this->redirect($referer);
}
#[Route('/cotisations/cotisation-type/{cotisationId}', name: 'customer_cotisation_step_one', methods: ['GET'])]
public function selectCotisationType(?int $cotisationId = null): Response
{
if (!is_null($cotisationId)) {
$cotisation = $this->em->getRepository(Cotisation::class)->find($cotisationId);
$this->em->remove($cotisation);
$this->em->flush();
}
/** @var Entreprise $firm */
$firm = $this->getUser()->getContact()->getFirm();
$countCotisationYoungMember = $this->em->getRepository(Cotisation::class)->countCotisationByTagType($firm, 'young_member');
/** @var Cotisation $lastCotisation */
$lastCotisation = $this->em->getRepository(Cotisation::class)->findLastCotisation($firm);
$currentYear = (int)(new DateTime())->format('Y');
if ($firm->getFirmType()->getTag() === 'transporter') {
$cotisationType = $this->em->getRepository(ParamCotisation::class)->findOneBy([
'tag' => 'transporter'
]);
return $this->redirectToRoute('customer_cotisation_step_two', ['id' => $cotisationType->getId()]);
}
$cotisationTypes = $this->em->getRepository(ParamCotisation::class)->findBy([
'isEnabled' => true,
'hideInMember' => false
], [
'cotisationOrder' => 'ASC'
]);
foreach ($cotisationTypes as $key => $cotisationType) {
if (
$cotisationType->getTag() === 'transporter' ||
($cotisationType->getTag() === 'young_member' && $countCotisationYoungMember >= 3) ||
(!is_null($lastCotisation) && $cotisationType->getTag() === 'new_member' && ($currentYear - $lastCotisation->getYear() <= 3))
) {
unset($cotisationTypes[$key]);
}
}
return $this->render('frontend/cotisation/cotisation_selection.html.twig', [
'controller_name' => 'CotisationController',
'menu' => 'my-space',
'submenu' => 'my-cotisation',
'displayAlertCotisation' => false,
'cotisationTypes' => $cotisationTypes
]);
}
#[Route('/cotisations/{id}/cotisation-data/{cotisationId}', name: 'customer_cotisation_step_two', methods: ['GET', 'POST'])]
public function cotisationData(
ParamCotisation $paramCotisation,
Request $request,
?int $cotisationId = null
): Response
{
/** @var Entreprise $firm */
$firm = $this->getUser()->getContact()->getFirm();
$now = new DateTime();
if (is_null($cotisationId)) {
$cotisation = new Cotisation();
$cotisation
->setEntreprise($firm)
->setYear($this->getYear($firm))
;
$countCotisationYoungMember = $this->em->getRepository(Cotisation::class)->countCotisationByTagType($firm, 'young_member');
$firstCotisationYoungMemberDate = $this->em->getRepository(Cotisation::class)->findCotisationDateByTagType($firm, 'young_member');
} else {
$cotisation = $this->em->getRepository(Cotisation::class)->find($cotisationId);
$countCotisationYoungMember = $this->em->getRepository(Cotisation::class)->countCotisationByTagType($firm, 'young_member') - 1;
$firstCotisationYoungMemberDate = null;
}
$form = $this->createForm(CustomerCotisationType::class, $cotisation, [
'cotisation_tag' => $paramCotisation->getTag(),
'cotisation_count_young_member' => (int)$countCotisationYoungMember
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$cotisation
->setYear($this->getYear($firm))
->setEntreprise($firm)
->setCotisationStatut($this->em->getRepository(CotisationStatut::class)->find(4))
->setCotisationType($paramCotisation)
->setMontantCotisation($form->get('priceTtc')->getData())
->setRevenue($form->get('revenue')->getData())
->setRevenueDate($form->get('revenueDate')->getData())
->setOptionImportExport($form->get('optionImportExport')->getData())
->setOptionMapa($form->get('optionMapa')->getData())
->setPriceHt($form->get('priceHt')->getData())
->setPriceVat($form->get('priceVat')->getData())
->setPriceTtc($form->get('priceTtc')->getData())
->setInternalLicence($form->get('internalLicence')->getData())
->setCommunityLicence($form->get('communityLicence')->getData())
->setPriceDepartmentPart($form->get('priceDepartmentPart')->getData())
->setPriceNationalPart($form->get('priceNationalPart')->getData())
->setPriceNationalPartCalculated($form->get('priceNationalPartCalculated')->getData())
->setPriceOptionImportExport($form->get('priceOptionImportExport')->getData())
->setPriceOptionMapa($form->get('priceOptionMapa')->getData())
->setYoungMemberYearNumber($form->get('youngMemberYearNumber')->getData());
$notification = $this->em->getRepository(CotisationNotification::class)->findOneBy([
'firm' => $firm,
'status' => CotisationNotification::STATUS_ACTIVE
]);
if (!is_null($notification)) {
$notification->setStatus(CotisationNotification::STATUS_PERFORMED);
$this->em->persist($notification);
}
$this->em->persist($cotisation);
$this->em->flush();
$this->addFlash(
'success',
'Enregistrement effectué avec succès'
);
if ($cotisationId !== null) {
return $this->redirectToRoute('customer_cotisation_show', ['id' => $cotisation->getId()]);
} else {
return $this->redirectToRoute('customer_cotisation_step_three', ['id' => $cotisation->getId()]);
}
}
return $this->renderForm('frontend/cotisation/cotisation_info.html.twig', [
'controller_name' => 'CotisationController',
'menu' => 'my-space',
'submenu' => 'my-cotisation',
'paramCotisation' => $paramCotisation,
'countYoungMemberCotisation' => (int)$countCotisationYoungMember + 1,
'firstCotisationDate' => $firstCotisationYoungMemberDate,
'displayAlertCotisation' => false,
'cotisation' => $cotisation,
'form' => $form,
'firm' => $firm
]);
}
public function getYear(Entreprise $entreprise): int {
$now = new DateTime();
$year = (int)$now->format('Y');
$lastCotisationYear = 0;
foreach ($entreprise->getCotisations() as $previousCotisation){
if(
$previousCotisation->getAssocietedOrder()?->getStatus() === Order::STATUS_PAID
&& $previousCotisation->getYear() > $lastCotisationYear
){
$lastCotisationYear = $previousCotisation->getYear();
}
}
$lastSaturdayOfJanuary = new DateTime('third Saturday of January ' . $year);
if($now < $lastSaturdayOfJanuary && $lastCotisationYear < ($year - 1)) {
return $year - 1;
}
return $year;
}
#[Route('/cotisations/{id}/cotisation-payment', name: 'customer_cotisation_step_three', methods: ['GET', 'POST'])]
public function cotisationPayment(
Cotisation $cotisation,
Request $request,
SaleService $saleService,
FormService $formService,
string $bnpMerchantId,
string $bnpBlowfishPassword,
string $bnpHmacPassword,
): Response
{
/** @var Entreprise $firm */
$firm = $this->getUser()->getContact()->getFirm();
$paymentTypes = $this->em->getRepository(PaymentType::class)->findBy([
'isEnabled' => true
]);
$form = $this->createForm(PaymentSelectorType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('paymentType')->getData()->getId() === 1) {
$order = $saleService->buildOrderFromCotisation(
$this->getUser()->getContact()->getFirm(),
$cotisation,
$form->get('paymentType')->getData()
);
$order->setStatus(Order::STATUS_WAITING_PAYMENT);
$order->setUser($this->getUser());
$this->em->persist($cotisation);
$this->em->persist($order);
$this->em->flush();
$Currency = "EUR";
$amount = round($order->getTotalAmount(), 2);
$amount = intval($amount * 100);
$urlSuccess = $this->generateUrl('customer_cotisation_bank_success_response', ['id' => $order->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
$urlFailure = $this->generateUrl('customer_cotisation_bank_failure_response', ['id' => $order->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
$urlNotify = $this->generateUrl('customer_cotisation_bank_notify_response', ['id' => $order->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
$urlBack = $this->generateUrl('customer_cotisation_bank_back_response', ['id' => $order->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
//Creating MAC value
$myPayGate = new Paygate();
$MAC = $myPayGate->ctHMAC("", $order->getNumber(), $bnpMerchantId, $amount, $Currency, $bnpHmacPassword);
// format data which is to be transmitted - required
$pMerchantID = "MerchantID={$bnpMerchantId}";
$pMsgVer = "MsgVer=2.0";
$pTransID = "TransID={$order->getNumber()}";
// pRefNr a string of 12 characters based on order id
$refNr = str_pad($order->getId(), 12, "0", STR_PAD_LEFT);
$pRefNr = "RefNr={$refNr}";
$pAmount = "Amount={$amount}";
$pCurrency = "Currency=$Currency";
$pMAC = "MAC=$MAC";
$pURLSuccess = "URLSuccess={$urlSuccess}";
$pURLFailure = "URLFailure={$urlFailure}";
// $pResponse = "Response=encrypt";
$pURLNotify = "URLNotify={$urlNotify}";
$pUserData = "UserData=Commande {$order->getNumber()}";
$pCapture = "Capture=AUTO";
$pOrderDesc = "OrderDesc={$order->getNumber()}";
$pReqID = "ReqID={$order->getNumber()}";
$pURLBack = "URLBack={$urlBack}";
// $pResponse = "Response=$Response";
$query = [
$pMerchantID,
$pMsgVer,
$pTransID,
$pRefNr,
$pAmount,
$pCurrency,
$pMAC,
$pURLSuccess,
$pURLFailure,
// $pResponse,
$pURLNotify,
$pUserData,
$pCapture,
$pOrderDesc,
$pReqID,
$pURLBack,
];
$order->setBankRequest([
'MerchantID' => $bnpMerchantId,
'MsgVer' => "2.0",
'TransID' => $order->getNumber(),
'RefNr' => $refNr,
'Amount' => $amount,
'Currency' => $Currency,
'MAC' => $MAC,
'URLSuccess' => $urlSuccess,
'URLFailure' => $urlFailure,
// 'Response' => 'encrypt',
'URLNotify' => $urlNotify,
'UserData' => "Commande {$order->getNumber()}",
'Capture' => "Auto",
'OrderDesc' => "{$order->getNumber()}",
'ReqID' => "{$order->getNumber()}",
'URLBack' => $urlBack,
]);
// building the string MerchantID, Len and Data (encrypted)
$plaintext = join("&", $query);
$Len = strlen($plaintext); // Length of the plain text string
// encrypt plaintext
$Data = $myPayGate->ctEncrypt($plaintext, $Len, $bnpBlowfishPassword);
$this->em->persist($cotisation);
$this->em->persist($order);
$this->em->flush();
return $this->redirect(
'https://paymentpage.axepta.bnpparibas/payssl.aspx'
. '?MerchantID=' . $bnpMerchantId
. '&Len=' . $Len
. '&Data=' . $Data
);
} else {
$order = $saleService->buildOrderFromCotisation(
$this->getUser()->getContact()->getFirm(),
$cotisation,
$form->get('paymentType')->getData()
);
$cotisation->setAssocietedOrder($order);
$this->em->persist($cotisation);
$this->em->persist($order);
$this->em->flush();
$this->addFlash(
'success',
'Votre cotisation est bien enregistrée en attente de votre virement.'
);
$this->mailerService->sendCotisationNotificationForAdmin($cotisation);
}
/** @var FormTemplate $formTemplate */
$formTemplate = $this->em->getRepository(FormTemplate::class)->findCotisationFormTemplate();
if (is_null($formTemplate)) {
return $this->redirectToRoute('customer_cotisation_show', ['id' => $cotisation->getId()]);
} else {
$formUser = $formService->buildFormForUser($this->getUser(), $formTemplate);
return $this->redirectToRoute('customer_edit_form', [
'id' => $formUser->getId(),
'cotisationId' => $cotisation->getId()
]);
}
}
return $this->renderForm('frontend/cotisation/cotisation_payment.html.twig', [
'controller_name' => 'CotisationController',
'menu' => 'my-space',
'submenu' => 'my-cotisation',
'cotisation' => $cotisation,
'firm' => $firm,
'paymentTypes' => $paymentTypes,
'form' => $form
]);
}
#[Route('/cotisations/bank-response/{id}', name: 'customer_cotisation_bank_response')]
public function bankResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
): Response
{
return $this->handleBankResponse($order, $request, $bnpBlowfishPassword);
}
#[Route('/cotisation/bank-response/{id}/success', name: 'customer_cotisation_bank_success_response')]
public function bankSuccessResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
): Response
{
return $this->handleBankResponse(
$order,
$request,
$bnpBlowfishPassword,
'success'
);
}
#[Route('/cotisation/bank-response/{id}/failure', name: 'customer_cotisation_bank_failure_response')]
public function bankFailureResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
): Response
{
return $this->handleBankResponse(
$order,
$request,
$bnpBlowfishPassword,
'failure'
);
}
#[Route('/cotisation/bank-response/{id}/notify', name: 'customer_cotisation_bank_notify_response')]
public function bankNotifyResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
): Response
{
return $this->handleBankResponse(
$order,
$request,
$bnpBlowfishPassword,
'notify'
);
}
#[Route('/cotisation/bank-response/{id}/back', name: 'customer_cotisation_bank_back_response')]
public function bankBackResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
): Response
{
return $this->handleBankResponse(
$order,
$request,
$bnpBlowfishPassword,
'back'
);
}
private function handleBankResponse(
Order $order,
Request $request,
string $bnpBlowfishPassword,
?string $type = 'null',
): Response
{
$response = array_merge($request->query->all(), $request->request->all());
$bankResponse = $order->setBankResponse($response);
$bankResponse->setType($type);
$bankResponse->setStatus($response['Status'] ?? null);
$this->em->persist($bankResponse);
$this->em->flush();
if ($order->getStatus() === Order::STATUS_PAID) {
return $this->redirectToRoute('customer_cotisation_step_three', ['id' => $order->getCotisation()->getId()]);
}
if (isset($response['Data']) && isset($response['Len'])) {
$myPayGate = new Paygate();
$plaintext = $myPayGate->ctDecrypt($response['Data'], $response['Len'], $bnpBlowfishPassword);
parse_str($plaintext, $temp);
$response = array_merge($response, $temp);
}
if (null === $this->getUser()) {
$user = $order->getUser();
if(!$user){
$this->redirectToRoute('customer_login');
}
$token = new UsernamePasswordToken($order->getUser(), null, 'main', $order->getUser()->getRoles());
$this->tokenStorage->setToken($token);
}
if (null === $response && ($response['TransID'] ?? null) !== $order->getBankRequest()['TransID']) {
return $this->redirectToRoute('customer_cotisation_show', ['id' => $order->getCotisation()->getId()]);
}
if (in_array($response['Status'] ?? '', ['OK', 'AUTHORIZED'])) {
$this->em->persist($bankResponse);
if($order->getStatus() !== Order::STATUS_PAID){
$order->setStatus(Order::STATUS_PAID);
$this->em->persist($order);
}
$cotisation = $order->getCotisation();
if($cotisation->getCotisationStatut()->getNom() !== 'payé'){
$cotisationStatut = $this->em->getRepository(CotisationStatut::class)->findOneByNom('payé');
$cotisation->setCotisationStatut($cotisationStatut);
$cotisation->setDatePaiement(new DateTime());
$this->em->persist($cotisation);
$this->mailerService->sendCotisationNotificationForAdmin($cotisation);
}
$this->em->flush();
$this->addFlash(
'success',
'Votre cotisation est bien enregistrée et le paiement à bien été pris en compte.'
);
return $this->redirectToRoute('customer_cotisation_show', ['id' => $cotisation->getId()]);
}
$this->addFlash(
'error',
'Le paiement a échoué.'
);
$order->setStatus(Order::STATUS_CANCELED);
$this->em->persist($order);
$this->em->flush();
return $this->redirectToRoute('customer_cotisation_step_three', ['id' => $order->getCotisation()->getId()]);
}
}