<?php
namespace App\Controller;
use App\Service\SessionManagerLMDV;
use App\Service\SessionManagerLMDVInterface;
use App\Service\WebServiceLMDV;
use App\Service\WebServiceLMDVInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Psr\Log\LoggerInterface;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use App\ValueObject\Flight;
use App\ValueObject\Money;
use App\Exception\LMDVException;
use App\Exception\NonTranslatedExceptionInterface;
use App\Exception\NonTranslatedException;
use App\Service\SalesForceConnectorInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use App\Exception\WebServiceException;
/**
* This class has only one route "/" (front) which is the entry-point for all the LMDV forms.
* It inspects the query string parameters in order to take a decision over which LMDV form
* we must head on (GIRDirectAgence, GIRDirectMail, GIRDistrib, GIRResaWeb, GRPFactIndivAgence,
* GRPFactIndivMail, GRPFactIndivWeb).
*
* @author jra
*
*/
class FrontController extends AbstractController
{
use LMDVControllerTrait;
public const PARAM_AGENCE_EMAIL_GIR = 'gir';
public const PARAM_AGENCE_EMAIL_GRP = 'grp';
public const STATUS_REVISON = 'Révision';
public const STATUS_ACCORD_CLIENT = 'Accord client';
public const STATUS_CARNET_VOYAGE = 'Carnet de Voyage';
public const STATUS_SANS_SUITE = 'Sans suite';
public const STATUS_ANNULEE = 'Annulée';
public const STATUS_ARCHIVEE = 'Archivée';
public const BLOCKED_OPP_STATUS = [
self::STATUS_REVISON,
self::STATUS_ACCORD_CLIENT,
self::STATUS_CARNET_VOYAGE,
self::STATUS_SANS_SUITE,
self::STATUS_ANNULEE,
self::STATUS_ARCHIVEE
];
/**
* @var \App\Service\WebServiceLMDV
*/
protected $ws;
/**
* @var \App\Service\SessionManagerLMDV
*/
protected $sm;
/**
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @var \Symfony\Contracts\Translation\TranslatorInterface
*/
protected $translator;
/**
* Dependency injection.
*
* @param \App\Service\WebServiceLMDVInterface $ws
* @param \App\Service\SessionManagerLMDVInterface $sm
*/
public function __construct(RequestStack $request_stack, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm, LoggerInterface $logger, TranslatorInterface $translator) {
$this->request = $request_stack->getCurrentRequest();
$this->ws = $ws;
$this->sm = $sm;
$this->logger = $logger;
$this->translator = $translator;
}
/**
* Utility url to clear all caches. Only for DEV/TEST environments
*
* @Route("/clear-cache", name="clearCache")
*
*/
public function clearCache(SalesForceConnectorInterface $sf, KernelInterface $kernel) {
if(in_array($_ENV['APP_ENV'], ['dev', 'test'])) {
// Clean up old session information every time we arrive to this dispatcher.
// We migrate the session to obtain a new sess_id() which invalidates WS caches.
$this->request->getSession()->clear();
$this->request->getSession()->migrate(TRUE);
// Clear all WS caches
$sf->invalidateAllCaches();
// Clear Twig cache like "symfony console cache:clear" does. Note that the cache
// directory will not be completely empty because after this command is executed,
// we need to create a Twig template for the final render.
// @see : https://symfony.com/doc/current/console/command_in_controller.html
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput([
'command' => 'cache:clear',
'--no-warmup' => TRUE
]);
$output = new BufferedOutput();
$application->run($input, $output);
$content = $output->fetch();
$this->logger->error("clear-cache controller output", ['message' => $content]);
$content = array_filter(explode("\n", $content));
$content = array_pop($content);
// Renders error page
return $this->render('lmdv/error_page.html.twig', [
'label' => 'error.clear_cache',
'errorMsg' => $content
], new Response('', 400));
}
else {
return $this->redirectToRoute('front');
}
}
/**
* Controller that decides to which tunnel head in. The first thing that this controller does
* is to empty the $_SESSION, in order to clean up all previous stored information.
*
* @Route("/", name="front")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function front() {
// Generates namespace for all the session values using a timestamp
$timestamp = (string)microtime(true);
$this->request->getSession()->setNamespace($timestamp);
// Grab $_GET parameters and save them into the session
$this->sm->setExternalParametersIntoSession($timestamp);
$session = $this->request->getSession();
// Invalidates (old) session data if the timestamp value exists in the url
if($this->request->query->get('_ts')) {
$session->invalidateNamespace($this->request->query->get('_ts'));
}
$id_opp = $session->get('idOppSF');
if(! $id_opp) {
/////////////////////////////////////////////
// There is *not* an idOppSF, then :
/////////////////////////////////////////////
$businessCode = $session->get('businessCode');
$productCode = $session->get('productCode');
$departureDate = $session->get('departureDate');
$endDate = $session->get('endDate');
$departureCity = $session->get('departureCity');
if($businessCode) {
if($productCode && $departureDate && $endDate && $departureCity) {
// CAS 3 (DISTRIB slide 1.4/ le vendeur Marco Vasco fait une réservation)
return $this->redirectToRoute('girdistrib_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
}
else {
if($productCode && $departureDate && $endDate && $departureCity) {
// CAS 1 (RESAWEB slide 1.3/ le client réserve tout seul en ligne)
return $this->redirectToRoute('girresaweb_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
}
}
else {
////////////////////////////////////
// If there is an idOppSF, then :
////////////////////////////////////
try {
$isOppFille = $this->ws->isOpportunityFille($id_opp);
if($isOppFille) {
// This is a FILLE opportunity - type GRP
if($this->request->query->get('agence_email') == self::PARAM_AGENCE_EMAIL_GRP) {
// FACTINDIV Mail
$this->ws->getSalesForceDataIntoSession($id_opp, $this->ws::TYPE_OPP_FILLE, TRUE);
$status = $session->get('stageName');
if(! $this->isValidStatusOppMail($status)) {
throw new \Exception($this->translator->trans("error.opportunity.invalid_status", ['status' => $status]), LMDVException::ERROR_BAD_OPP_STATUS);
}
return $this->redirectToRoute('grpfactindivmail_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
elseif($this->ws->isAgent()
|| (in_array($_ENV['APP_ENV'], ['dev', 'test']) && $this->request->query->get('test_agence'))) {
// FACTINDIV Agence
$this->ws->getSalesForceDataIntoSession($id_opp, $this->ws::TYPE_OPP_FILLE, TRUE);
$status = $session->get('stageName');
if($status != self::STATUS_ACCORD_CLIENT) {
throw new \Exception($this->translator->trans("error.opportunity.invalid_status", ['status' => $status]));
}
return $this->redirectToRoute('grpfactindivagence_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
else {
$this->logger->error("IP check error GRP: clientIP : '" + $this->request->getClientIp() + "', agenceIp : '" + $_ENV['IP_ADDRESS_AGENCE'] + "'");
}
}
else {
// This is a GRP PARENT opportunity (or a GIR opportunity - that have no PARENTs).
if($this->request->query->get('agence_email') == self::PARAM_AGENCE_EMAIL_GIR) {
// DIRECT Mail
$this->ws->getSalesForceDataIntoSession($id_opp, $this->ws::TYPE_OPP_PARENT, FALSE);
$session->set('businessCode', ''); // Eric - Gautier 12/02/2021 : don't send businessCode in this case.
$status = $session->get('stageName');
if(! $this->isValidStatusOppMail($status)) {
throw new \Exception($this->translator->trans("error.opportunity.invalid_status", ['status' => $status]), LMDVException::ERROR_BAD_OPP_STATUS);
}
return $this->redirectToRoute('girdirectmail_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
else {
$productCode = $session->get('productCode');
$departureDate = $session->get('departureDate');
if($productCode && $departureDate) {
// FACTINDIV Web : we need to retrive the businessCode from the opp PARENT
$this->ws->getSalesForceDataIntoSession($id_opp, $this->ws::TYPE_OPP_PARENT, TRUE);
$status = $session->get('stageName');
if($status != self::STATUS_ACCORD_CLIENT) {
throw new \Exception($this->translator->trans("error.opportunity.invalid_status", ['status' => $status]));
}
// NOTE: In this case we must create the opp FILLE at the end of the tunnel with createBooking
// so we must empty the FILLE and set the PARENT opp.
$session->set('idOppSFParent', $session->get('idOppSF'));
$session->set('idOppSF', NULL);
return $this->redirectToRoute('grpfactindivweb_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
elseif($this->ws->isAgent()
|| (in_array($_ENV['APP_ENV'], ['dev', 'test']) && $this->request->query->get('test_agence'))) {
// DIRECT Agence
$this->ws->getSalesForceDataIntoSession($id_opp, $this->ws::TYPE_OPP_PARENT, FALSE);
$session->set('businessCode', ''); // Eric - Gautier 12/02/2021 : don't send businessCode in this case.
return $this->redirectToRoute('girdirectagence_step0', \array_merge($this->request->query->all(), ['_fragment' => 'breadcrumb', '_ts' => $timestamp]));
}
else {
$this->logger->error("IP check error GIR: clientIP : '" + $this->request->getClientIp() + "', agenceIp : '" + $_ENV['IP_ADDRESS_AGENCE'] + "'");
}
}
}
}
catch(\Exception $e) {
return $this->redirectToErrorPage($e);
}
}
// If we get to here, something went wrong or there a missing case that we have not yet coded.
$e = new \Exception($this->translator->trans("error.missing_get_parameters"));
return $this->redirectToErrorPage($e);
}
/**
* Verifies that for GIR and GRP email cases, the opp status is valid, to avoid
* entering through the tunnel multiple times (@see TICKET JIRA LMDV-445)
*
* @param string $status
* @return bool
* TRUE if the status is valid, FALSE otherwise.
*/
protected function isValidStatusOppMail($status) {
$check = array_search($status, self::BLOCKED_OPP_STATUS);
$this->logger->notice("isValidStatusOppMail check", ['status' => $status, 'not allowed values' => self::BLOCKED_OPP_STATUS]);
if($check === FALSE) {
return TRUE;
}
else {
return FALSE;
}
}
}