<?php
namespace App\Controller;
use App\Service\SessionManagerLMDVInterface;
use App\Service\WebServiceLMDV;
use App\Service\WebServiceLMDVInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\HttpFoundation\Request;
use App\Form\Type\GIRDirectMail\Etape0Type;
use App\Form\Type\GIRDirectMail\Etape1Type;
use App\Form\Type\GIRDirectMail\Etape2Type;
use App\Form\Type\GIRDirectMail\Etape3Type;
use App\Form\Type\GIRDirectMail\ParticipantType;
use App\Entity\GIRDirectMail\Etape0;
use App\Entity\GIRDirectMail\Etape1;
use App\Entity\GIRDirectMail\Etape2;
use App\Entity\GIRDirectMail\Etape3;
use App\Entity\GIRDirectMail\Participant;
use App\Form\Type\GIRDirectMail\ChambreType;
use App\Entity\GIRDirectMail\Chambre;
use App\Exception\LMDVException;
use App\Exception\NonTranslatedException;
use App\Service\SessionManagerLMDV;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
use App\Service\Payment\PaymentInterface;
/**
* There are at least 4 form steps. In every step we must verify that the $_SESSION information exists
* otherwise we should return to the FrontController. $_SESSION information must be missing if the user
* tries to hit a step without having gone through the previous ones or if the PHP garbage collection decides to
* kill the session. These controls are implemented inside SessionManagerLMDVInterface class.
*
* @author jra
*
*/
class GIRDirectMailController extends AbstractController implements SessionValidController
{
use LMDVControllerTrait;
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @var \Symfony\Contracts\Translation\TranslatorInterface
*/
protected $translator;
public function __construct(LoggerInterface $logger, TranslatorInterface $translator)
{
$this->logger = $logger;
$this->translator = $translator;
}
/**
* @Route("/GIRDirectMail/step0", name="girdirectmail_step0")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function step0(Request $request, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm)
{
$sm->setEntityNamespace('App\Entity\GIRDirectMail');
$voyage = $sm->getDataFromSession();
if(! $sm->isValidCustomSessionId($voyage->getSessionId())) {
//$this->addFlash('error', ['id' => 'error.session.expired']);
return $this->redirectToRoute('front', $request->query->all());
}
// if PDFVoyage is empty, do not show the link
try {
$result = $ws->getPdfVoyage($voyage);
}
catch(\Exception $e) {
$request->getSession()->set('hasPDFVoyage', FALSE);
}
if(empty($result['content'])) {
$request->getSession()->set('hasPDFVoyage', FALSE);
}
else {
$request->getSession()->set('hasPDFVoyage', TRUE);
}
// if PDFVoyage is empty, do not show the link
// NbrAdultes et NbrEnfants are filled up by default, but we can modify them
if($voyage->getEtape0()) {
$etape0 = $voyage->getEtape0();
}
else {
$etape0 = new Etape0();
$etape0->setNbrAdultes($voyage->getAdults());
$etape0->setNbrEnfants($voyage->getChildren());
}
$etape0->setVilleDepart($voyage->getDepartureCity());
$etape0->setCodeSociete($voyage->getBusinessCode());
$etape0->setCodeAgent($voyage->getAgentCode());
$ws->getSalesForceTitleVoyage($voyage);
$form = $this->createForm(Etape0Type::class, $etape0);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$etape0 = $form->getData();
// Saves object into session after serializing it.
$sm->setDataToSession('etape0', $etape0);
return $this->redirectToRoute('girdirectmail_step1', $request->query->all());
}
return $this->render('lmdv/girdirectmail/step0.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @Route("/GIRDirectMail/step1", name="girdirectmail_step1")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function step1(Request $request, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm)
{
$sm->setEntityNamespace('App\Entity\GIRDirectMail');
$voyage = $sm->getDataFromSession();
if(! $voyage->getEtape0()) {
$this->addFlash('error', ['id' => 'error.session.expired']);
return $this->redirectToRoute('front', $request->query->all());
}
try {
$volAller = $ws->getVolAller($voyage);
$volRetour = $ws->getVolRetour($voyage);
$miscellaneous = $ws->getMiscellaneous($voyage);
$assurances = $ws->getAssurances($voyage);
$prestations = $ws->getPrestations($voyage);
$ws->getBoxRecap($voyage);
}
catch(\Exception $e) {
$request->getSession()->invalidate();
return $this->redirectToErrorPage($e);
}
$etape1 = $voyage->getEtape1() ? $voyage->getEtape1() : new Etape1();
$maxChambres = $voyage->getEtape0()->getNbrAdultes() + $voyage->getEtape0()->getNbrEnfants();
$nbrChambres = $etape1->getNbrChambres() ? $etape1->getNbrChambres() : 1;
if($nbrChambres > $maxChambres) {
$nbrChambres = $maxChambres;
}
$etape1->setNbrChambres($nbrChambres);
$etape1->setMaxChambres($maxChambres);
$form = $this->createForm(Etape1Type::class, $etape1);
$chambres = $etape1->getChambres();
for($i = 1; $i <= $maxChambres; $i++) {
if(isset($chambres[$i-1])) {
$chambre = $chambres[$i-1];
$chambre->refreshChambresInformation($ws, $voyage);
}
else {
$chambre = new Chambre($ws, $voyage);
}
// This is to disable validation for chambres hidden by AJAX
// Anotations dont work for unmapped fields.
// it is tricky, it is a dirty way but it works
$aux = @$request->request->get('etape1')['nbrChambres'];
if(isset($aux) && is_numeric($aux)) {
$nbrChambres = $aux;
if($i > $nbrChambres) {
$chambre->setValidated(TRUE);
}
else {
$chambre->setValidated(FALSE);
}
}
$form->add('chambre_' . $i, ChambreType::class, [
'mapped' => FALSE,
'data' => $chambre,
]);
}
$saved_data = $etape1->getAssurances() ? $etape1->getAssurances() : [];
foreach($miscellaneous as $group => $miscellaneous_choices) {
$default = '';
foreach($miscellaneous_choices as $choice) {
foreach($choice as $value) {
if(in_array($value, $saved_data)) {
$default = $value;
}
}
}
$form->add('miscellaneous_' . $group, ChoiceType::class, [
'choices' => $miscellaneous_choices,
'choice_translation_domain' => FALSE,
'multiple' => FALSE,
'expanded' => TRUE,
'mapped' => FALSE,
'data' => $default
]);
}
$groups = [];
foreach($assurances as $group => $assurance_choices) {
$default = [];
foreach($assurance_choices as $choice) {
foreach($choice as $value) {
if(in_array($value, $saved_data)) {
$default[] = $value;
}
}
}
$form->add('assurances_' . $group, ChoiceType::class, [
'label' => $ws->getAssuranceGroupLabel($group, $assurance_choices),
'label_html' => TRUE,
'translation_domain' => FALSE,
'choices' => $assurance_choices,
'choice_label' => [$ws, 'getAssuranceDescription'],
'choice_translation_domain' => FALSE,
'multiple' => TRUE,
'expanded' => TRUE,
'mapped' => FALSE,
'data' => $default
]);
$groups[] = $group;
}
$form->add('hasAssurances', HiddenType::class, [
'data' => json_encode($groups),
'mapped' => FALSE
]);
$form->add('prestations', ChoiceType::class, [
'choices' => $prestations,
'multiple' => TRUE,
'expanded' => TRUE
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if($form->get('prev')->isClicked() || $form->get('next')->isClicked()) {
/** @var \App\Entity\GIRResaWeb\Etape1 $etape1 */
$etape1 = $form->getData();
$nbrChambres = $etape1->getNbrChambres();
$etape1->setChambres([]);
for($i = 1; $i <= $nbrChambres; $i++) {
$chambre = $form->get('chambre_' . $i)->getData();
if($chambre->getCategory()) {
list($category, $code, $segmentCode) = explode('#', $chambre->getCategory());
$chambre->setDescription($category);
$chambre->setCode($code);
$chambre->setSegmentCode($segmentCode);
$etape1->addChambres($chambre);
}
}
$etape1->setVolAller($volAller);
$etape1->setVolRetour($volRetour);
// Retrieval of non-mapped miscellaneous/assurances data, which we must merge and save with etape1->setAssurances()
$aux = [];
foreach(array_keys($miscellaneous) as $group) {
$aux[] = $form->get('miscellaneous_' . $group)->getData();
}
foreach(array_keys($assurances) as $group) {
$aux = array_merge($aux, $form->get('assurances_' . $group)->getData());
}
$etape1->setAssurances($aux);
// Saves object into session after serializing it.
$sm->setDataToSession('etape1', $etape1);
if($form->get('prev')->isClicked()) {
return $this->redirectToRoute('girdirectmail_step0', $request->query->all());
}
if($form->get('next')->isClicked()) {
return $this->redirectToRoute('girdirectmail_step2', $request->query->all());
}
}
// AJAX callback come here... We need to get the AJAX updated value 'nbrChambres'
// Note that we can not add elements to a submitted form !
if($request->isXmlHttpRequest()) {
$ajaxData = $form->getData();
$nbrChambres = $ajaxData->getNbrChambres();
}
}
return $this->render('lmdv/girdirectmail/step1.html.twig', [
'form' => $form->createView(),
'volAller' => $volAller,
'volRetour' => $volRetour,
'nbrChambres' => $nbrChambres,
'maxChambres' => $maxChambres,
'miscellaneous' => $miscellaneous,
'assurances' => $assurances
]);
}
/**
* @Route("/GIRDirectMail/step2", name="girdirectmail_step2")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function step2(Request $request, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm)
{
$sm->setEntityNamespace('App\Entity\GIRDirectMail');
$voyage = $sm->getDataFromSession();
if(! $voyage->getEtape1()) {
$this->addFlash('error', ['id' => 'error.session.expired']);
return $this->redirectToRoute('front', $request->query->all());
}
$cont = 0;
$total_adults = 0;
$total_children = 0;
$chambres = $voyage->getEtape1()->getChambres();
foreach($chambres as $chambre) {
$cont = $cont + $chambre->getNbrAdultes();
$cont = $cont + $chambre->getNbrEnfants();
$total_adults = $total_adults + $chambre->getNbrAdultes();
$total_children = $total_children + $chambre->getNbrEnfants();
}
// Validates that the sum of adults/children of all rooms is equal than the total number of adults/children specified in etape0
if(($voyage->getEtape0()->getNbrAdultes() != $total_adults) || ($voyage->getEtape0()->getNbrEnfants() != $total_children)) {
$this->addFlash('error', ['id' => "error.form.travellers_mismatch", 'parameters' => ['%nbrAdults%' => $voyage->getEtape0()->getNbrAdultes(), '%nbrChildren%' => $voyage->getEtape0()->getNbrEnfants()]]);
return $this->redirectToRoute('girdirectmail_step1', $request->query->all());
}
if($voyage->getEtape2()) {
$etape2 = $voyage->getEtape2();
}
else {
$etape2 = new Etape2();
try {
$responsable = $ws->getSalesForceResponsable($voyage->getIdOppSF());
$participants = $ws->getSalesForceParticipants($voyage->getIdOppSF());
}
catch(\Exception $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('girdirectagence_step1', $request->query->all());
}
// Prefills up responsable information
$etape2->setCivilite($responsable['civilite']);
$etape2->setPrenom($responsable['prenom']);
$etape2->setNom($responsable['nom']);
$etape2->setTelephone($responsable['telephone']);
$etape2->setTelephone2($responsable['telephone2']);
$etape2->setAdresse($responsable['adresse']);
$etape2->setCodePostal($responsable['codePostal']);
$etape2->setVille($responsable['ville']);
$etape2->setPays($responsable['pays']);
$etape2->setEmail($responsable['email']);
$etape2->setSfId($responsable['sfId']);
$etape2->setCommentaires($responsable['comments']);
// Prefills up participants information
foreach($participants as $pax) {
$p = new Participant();
$p->setCivilite($pax['civilite']);
$p->setPrenom($pax['prenom']);
$p->setNom($pax['nom']);
$p->setNomJeuneFille($pax['nomJeuneFille']);
$p->setDateNaissance($pax['dateNaissance']);
$p->setNationalite($pax['nationalite']);
$p->setSfId($pax['sfId']);
$etape2->addParticipants($p);
}
}
$form = $this->createForm(Etape2Type::class, $etape2);
$participants = $etape2->getParticipants();
for($i = 1; $i <= $cont; $i++) {
$form->add('participant_' . $i, ParticipantType::class, [
'mapped' => FALSE,
'data' => isset($participants[$i-1]) ? $participants[$i-1] : new Participant()
]);
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$etape2 = $form->getData();
$etape2->setParticipants([]);
for($i = 1; $i <= $cont; $i++) {
$participant = $form->get('participant_' . $i)->getData();
$etape2->addParticipants($participant);
}
// Saves object into session after serializing it.
$sm->setDataToSession('etape2', $etape2);
if($form->get('prev')->isClicked()) {
return $this->redirectToRoute('girdirectmail_step1', $request->query->all());
}
return $this->redirectToRoute('girdirectmail_step3', $request->query->all());
}
// On récupère le prix du voyage pour afficher le bandeau recap
try {
$ws->getBoxRecap($voyage);
} catch (\Exception $e) {
$request->getSession()->invalidate();
return $this->redirectToErrorPage($e);
}
return $this->render('lmdv/girdirectmail/step2.html.twig', [
'nbrParticipants' => $cont,
'form' => $form->createView(),
]);
}
/**
* @Route("/GIRDirectMail/step3", name="girdirectmail_step3")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function step3(Request $request, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm, PaymentInterface $paymentGateway)
{
$sm->setEntityNamespace('App\Entity\GIRDirectMail');
$voyage = $sm->getDataFromSession();
if(! $voyage->getEtape2()) {
$this->addFlash('error', ['id' => 'error.session.expired']);
return $this->redirectToRoute('front', $request->query->all());
}
// Validates that the number of adults and children are equal to the initially specified number on etape0
// using the birthday date of travellers
$total_adults = 0;
$total_children = 0;
foreach($voyage->getEtape2()->getParticipants() as $participant) {
if($participant->isChild()) {
$total_children += 1;
}
else {
$total_adults += 1;
}
}
if(($voyage->getEtape0()->getNbrAdultes() != $total_adults) || ($voyage->getEtape0()->getNbrEnfants() != $total_children)) {
$this->addFlash('error', ['id' => "error.form.travellers_mismatch", 'parameters' => ['%nbrAdults%' => $voyage->getEtape0()->getNbrAdultes(), '%nbrChildren%' => $voyage->getEtape0()->getNbrEnfants()]]);
return $this->redirectToRoute('girdirectmail_step2', $request->query->all());
}
try {
$price = $ws->getTotalAmount($voyage);
$price_hors_assurances = $ws->getTotalAmountHorsAssurances($voyage);
$accompte = $ws->getPayment($voyage);
$solde = $price->substract($accompte);
$price_details = $ws->getPriceDetails($voyage);
$vols_warning = $ws->getVolsWarning($voyage);
}
catch(\Exception $e) {
if($e instanceof NonTranslatedException) {
$msg = $e->getMessage();
$params = $e->getTranslationParameters();
$errMsg = $this->translator->trans($msg, $params, 'messages');
$this->addFlash('error', $errMsg);
}
else {
$this->addFlash('error', $e->getMessage());
}
return $this->redirectToRoute('girdirectmail_step2', $request->query->all());
}
$etape3 = $voyage->getEtape3() ? $voyage->getEtape3() : new Etape3();
$form = $this->createForm(Etape3Type::class, $etape3);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$etape3 = $form->getData();
$etape3->setPriceDetails($price_details);
$etape3->setTotalPrice($price);
$etape3->setSolde($solde);
$etape3->setAccompte($accompte);
// Saves object into session after serializing it.
$sm->setDataToSession('etape3', $etape3);
$voyage = $sm->getDataFromSession();
if($form->get('prev')->isClicked()) {
return $this->redirectToRoute('girdirectmail_step2', $request->query->all());
}
if($form->get('print')->isClicked()) {
return $this->redirectToRoute('print_girdirectmail', $request->query->all());
}
if ($etape3->getTypePayment() == Etape3::PAYMENT_TYPE_ONLINE) {
try {
$result = $ws->createBooking($voyage);
$etape3->setNewIdOpp($result['opportunityId']);
$etape3->setBookingNumber($result['bookingNumber']);
$sm->setDataToSession('etape3', $etape3);
// Ticket JIRA-451 : HiPay : Gérer les erreurs HiPay
try {
$external_url = $paymentGateway->getPaymentUrl($voyage);
}
catch(\Exception $e) {
return $this->render('payment/error.html.twig', ['ga' => NULL, 'bookingID' => substr($voyage->getEtape3()->getBookingNumber(), 3)]);
}
// Ticket JIRA-451 : HiPay : Gérer les erreurs HiPay
}
catch(\Exception $e) {
$request->getSession()->set('finished', TRUE);
return $this->redirectToErrorPage($e);
}
return $this->redirect($external_url);
}
else {
try {
$result = $ws->createBooking($voyage);
$etape3->setBookingNumber($result['bookingNumber']);
$etape3->setNewIdOpp($result['opportunityId']);
$sm->setDataToSession('etape3', $etape3);
}
catch(\Exception $e) {
$request->getSession()->set('finished', TRUE);
return $this->redirectToErrorPage($e);
}
return $this->redirectToRoute('girdirectmail_step4', $request->query->all());
}
}
// La date du réglement c'est la date du départ - 45 jours.
$date_reglement = strtotime($voyage->getDepartureDate()) - (45 * 86400);
$date_reglement = date('d/m/Y', $date_reglement);
return $this->render('lmdv/girdirectmail/step3.html.twig', [
'form' => $form->createView(),
'accompte' => $accompte,
'prix' => $price,
'prix_hors_assurances' => $price_hors_assurances,
'solde' => $solde,
'price_details' => $price_details,
'vols_warning' => $vols_warning,
'dateReglement' => $date_reglement
]);
}
/**
* @Route("/GIRDirectMail/step4", name="girdirectmail_step4")
*
* @param Request $request
* @param WebServiceLMDVInterface $ws
* @param SessionManagerLMDVInterface $sm
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function step4(Request $request, WebServiceLMDVInterface $ws, SessionManagerLMDVInterface $sm)
{
$sm->setEntityNamespace('App\Entity\GIRDirectMail');
$voyage = $sm->getDataFromSession();
if(! $voyage->getEtape3()) {
$this->addFlash('error', ['id' => 'error.session.expired']);
return $this->redirectToRoute('front', $request->query->all());
}
$output = $this->render('lmdv/girdirectmail/step4.html.twig', [
'bookingID' => substr($voyage->getEtape3()->getBookingNumber(), 3),
]);
// Clean up session information if everthing goes well
// $request->getSession()->invalidate(); - we can no longer do this otherwise the download of the PDFVoyage will not work at last step
$request->getSession()->set('finished', TRUE);
return $output;
}
}