src/Aviatur/ParkBundle/Controller/ParkCheckoutController.php line 1269

Open in your IDE?
  1. <?php
  2. namespace Aviatur\ParkBundle\Controller;
  3. use Doctrine\Persistence\ManagerRegistry;
  4. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  5. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  6. use Symfony\Component\HttpFoundation\JsonResponse;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  10. use Symfony\Component\Routing\RouterInterface;
  11. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  12. use Aviatur\GeneralBundle\Controller\OrderController;
  13. use Aviatur\AgencyBundle\Entity\Agency;
  14. use Aviatur\GeneralBundle\Entity\FormUserInfo;
  15. use Aviatur\CustomerBundle\Services\ValidateSanctionsRenewal;
  16. use Aviatur\GeneralBundle\Services\AviaturChangeCoin;
  17. use Aviatur\GeneralBundle\Services\AviaturEncoder;
  18. use Aviatur\GeneralBundle\Services\AviaturQrcodeService;
  19. use Aviatur\GeneralBundle\Services\AviaturErrorHandler;
  20. use Aviatur\GeneralBundle\Services\AviaturLogSave;
  21. use Aviatur\GeneralBundle\Services\AviaturMailer;
  22. use Aviatur\GeneralBundle\Services\AviaturRestService;
  23. use Aviatur\GeneralBundle\Services\AviaturWebService;
  24. use Aviatur\GeneralBundle\Services\ExceptionLog;
  25. use Aviatur\ParkBundle\Services\ListParkService;
  26. use Aviatur\ParkBundle\Services\LegacyTicketParkService;
  27. use Aviatur\ParkBundle\Services\ParkTemplateVoucherkService;
  28. use Aviatur\ParkBundle\Services\CancelBookingParkService;
  29. use Aviatur\ParkBundle\Services\SendVoucherEmailParkService;
  30. use Aviatur\ParkBundle\Models\ParkSearchModel;
  31. use Aviatur\ParkBundle\Models\ParkDetailModel;
  32. use Aviatur\ParkBundle\Models\ParkBookingModel;
  33. use Aviatur\PaymentBundle\Controller\P2PController;
  34. use Aviatur\PaymentBundle\Services\CustomerMethodPaymentService;
  35. use Aviatur\PaymentBundle\Services\TokenizerService;
  36. use Aviatur\TwigBundle\Services\TwigFolder;
  37. use Knp\Snappy\Pdf;
  38. class ParkCheckoutController extends AbstractController
  39. {
  40.     /**
  41.      * @var ManagerRegistry
  42.      */
  43.     protected ManagerRegistry $managerRegistry;
  44.     /**
  45.      * @var AviaturRestService
  46.      */
  47.     private $aviaturRestService;
  48.     /**
  49.      * @var SessionInterface
  50.      */
  51.     protected $session;
  52.     /**
  53.      * @var Agency|object|null
  54.      */
  55.     protected $agency;
  56.     protected static $exceptionLog;
  57.     private $em;
  58.     private $listParkService;
  59.     private $legacyTicketParkService;
  60.     private $parkTemplateVoucherkService;
  61.     private $cancelBookingParkService;
  62.     private $sendVoucherEmailParkService;
  63.     public function __construct(ManagerRegistry $managerRegistrySessionInterface $sessionAviaturRestService $aviaturRestServiceExceptionLog $exceptionLogListParkService $listParkServiceParkTemplateVoucherkService $parkTemplateVoucherkServiceLegacyTicketParkService $legacyTicketParkServiceCancelBookingParkService $cancelBookingParkServiceSendVoucherEmailParkService $sendVoucherEmailParkService)
  64.     {
  65.         self::$exceptionLog $exceptionLog;
  66.         $this->em $managerRegistry->getManager();
  67.         $this->aviaturRestService $aviaturRestService;
  68.         $this->session $session;
  69.         $this->agency $this->em->getRepository(Agency::class)->find($session->get('agencyId'));
  70.         $this->listParkService $listParkService;
  71.         $this->legacyTicketParkService $legacyTicketParkService;
  72.         $this->parkTemplateVoucherkService $parkTemplateVoucherkService;
  73.         $this->cancelBookingParkService $cancelBookingParkService;
  74.         $this->sendVoucherEmailParkService $sendVoucherEmailParkService;
  75.     }
  76.     public function searchAction()
  77.     {
  78.         return $this->redirect(
  79.             $this->generateUrl(
  80.                 'aviatur_search_parks',
  81.                 []
  82.             )
  83.         );
  84.     }
  85.     public function checkoutAction(Request $requestAviaturLogSave $logSaveParameterBagInterface $parameterBagTwigFolder $twigFolderSessionInterface $sessionAviaturErrorHandler $aviaturErrorHandlerAviaturChangeCoin $aviaturChangeCoinAviaturWebService $webServiceAviaturEncoder $aviaturEncoder
  86.     ) {
  87.         if (empty($request->query->all()) && empty($request->request->all())) {
  88.             $titleError "Página no accesible";
  89.             $textError "No puedes acceder al detalle sin disponibilidad";
  90.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl('aviatur_search_parks', []), $titleError$textError));
  91.         }
  92.         // Obtener request enviado
  93.         $ticketsSelectedInfo $request->request->all() ?? $request->query->all();
  94.         // Obtener TransactionId
  95.         $transactionId = (string) !empty($ticketsSelectedInfo['transactionId']) ? $ticketsSelectedInfo['transactionId'] : $ticketsSelectedInfo['transactionRetryId'];
  96.         // Validar si es reintento de pago
  97.         $isretry = !empty($ticketsSelectedInfo['transactionRetryId']);
  98.         if($isretry){
  99.             // Si ya no quedan intentos de compra, redirigir al home de parques
  100.             $retryCount $session->get($transactionId '[park][retry]');
  101.             if($retryCount <= 0){
  102.                 $titleError "Acceso no autorizado";
  103.                 $textError "Ha sido redirigido al home para que pueda seguir explorando opciones.";
  104.                 return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl("aviatur_search_parks", []), $titleError$textError));
  105.             }
  106.             // Información de tickets seleccionados
  107.             $sessionKey $transactionId "[park][ticketsInfo]";
  108.             $ticketsSelectedInfo $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  109.             $filteredTickets $ticketsSelectedInfo['filteredTickets'];
  110.             $ticketsSelectedInfo['searchParams'] = json_encode($ticketsSelectedInfo["searchParams"]);
  111.             $ticketsSelectedInfo['transactionId'] = $transactionId;
  112.             // Información de formularios de usuario
  113.             $formUserInfo $this->em->getRepository(\Aviatur\GeneralBundle\Entity\FormUserInfo::class)->find($session->get($transactionId '[park][userInfo]'));
  114.             $decodedResponseInfoUser json_decode($aviaturEncoder->AviaturDecode($formUserInfo->getInfo(), $formUserInfo->getPublicKey()), true);
  115.             $passengersInfoBD $decodedResponseInfoUser["PI"];
  116.             $billingDataInfoBD $decodedResponseInfoUser["BD"];
  117.         }
  118.         // Obtener la respuesta de disponibilidad desde la sesión
  119.         $sessionKey $transactionId '[park][ticketsAvailability]';
  120.         $parkAvailabilityInfo $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  121.         $searchParams $this->parseSearchParams($ticketsSelectedInfo['searchParams']);
  122.         if (empty($parkAvailabilityInfo) || !isset($parkAvailabilityInfo['productCatalogs'])) {
  123.             $url $this->generateUrl('aviatur_park_avaliability'$searchParams['model']->getData());
  124.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($url'Página no accesible''No puedes acceder al detalle sin disponibilidad. Puede seguir explorando opciones.'));
  125.         }
  126.         // Validación de la existencia del parque y sede
  127.         $availabilityParameters $this->validParkAndSede($searchParams['park'], $searchParams['sede'], $aviaturErrorHandler);
  128.         // Filtrar info dispo para ticket(s) seleccionado(s)
  129.         if(!$isretry){
  130.             $ticketsSelected json_decode($ticketsSelectedInfo['ticketsSelected'], true);
  131.             $filteredTickets array_values(array_filter($parkAvailabilityInfo['productCatalogs'], fn($ticket) => in_array($ticket['productId'], $ticketsSelected)));
  132.         }
  133.         // Arreglo RS del detalle
  134.         $arrayDetailParks $this->getTicketDetails($filteredTickets$searchParams$availabilityParameters$logSave$transactionId$aviaturErrorHandler);
  135.         // Precios totalizados de los tickets
  136.         $priceTotaltickets $this->calculatePriceTotal($filteredTickets$arrayDetailParks$searchParams$aviaturChangeCoin);
  137.         // Eliminar "Adult" o "Child" del nombre del ticket para agruparlos
  138.         $baseName preg_replace('/(Adult|Child|Ad |Ch )/'''$filteredTickets[0]['productName']);
  139.         $baseName trim($baseName);
  140.         // Datos requeridos para los formularios del checkOut
  141.         $typeDocument $this->em->getRepository(\Aviatur\CustomerBundle\Entity\DocumentType::class)->findAll();
  142.         $typeGender $this->em->getRepository(\Aviatur\CustomerBundle\Entity\Gender::class)->findAll();
  143.         $repositoryDocumentType $this->em->getRepository(\Aviatur\CustomerBundle\Entity\DocumentType::class);
  144.         $queryDocumentType $repositoryDocumentType
  145.             ->createQueryBuilder('p')
  146.             ->where('p.paymentcode != :paymentcode')
  147.             ->setParameter('paymentcode''')
  148.             ->getQuery();
  149.         $documentPaymentType $queryDocumentType->getResult();
  150.         $passangerTypes[1] = [
  151.             'ADT' => (int) $searchParams['adults'],
  152.             'CHD' => (int) $searchParams['children'],
  153.             'INF' => 0,
  154.         ];
  155.         /* Aplicando para vuelo, pero teniendo cuidado con los otros productos */
  156.         /* Necesitamos crear un arreglo que tenga todos los rangos de IIN asociados a su franquicia y a sus límites de número de tarjeta */
  157.         $iinRecordsArray $webService->getIINRanges($this->em);
  158.         // Opciones de pago
  159.         $paymentMethodAgency $this->em->getRepository(\Aviatur\GeneralBundle\Entity\PaymentMethodAgency::class)->findBy(['agency' => $this->agency'isactive' => 1]);
  160.         $paymentOptions = [];
  161.         foreach ($paymentMethodAgency as $payMethod) {
  162.             $paymentCode $payMethod->getPaymentMethod()->getCode();
  163.             if (!in_array($paymentCode$paymentOptions) && 'p2p' == $paymentCode || 'cybersource' == $paymentCode) {
  164.                 $paymentOptions[] = $paymentCode;
  165.             }
  166.         }
  167.         // Guardar información de dispo y detalle de tickets, encodeada en session
  168.         $ticketsInfo = [
  169.             "availabilityParameters" => $availabilityParameters,
  170.             "filteredTickets" => $filteredTickets,
  171.             "searchParams" => $searchParams
  172.         ];
  173.         $session->set($transactionId '[park][ticketsInfo]'base64_encode(json_encode($ticketsInfo)));
  174.         // Extraer número de parques si existe "X-Park"
  175.         $parkNumber "";
  176.         if (preg_match('/(\d+)-Park/'$baseName$matches)) {
  177.             $parkNumber $matches[1];
  178.         }
  179.         
  180.         // Agregando politicas de los ticket's
  181.         $legacyTicketPark $this->legacyTicketParkService->getLegacyTicketPark($availabilityParameters["parkSedesId"], (int) $filteredTickets[0]['salesProgramId'], $baseName$filteredTickets[0]['numberOfDays'], $parkNumber);
  182.         
  183.         // Validar si es Park to Park
  184.         $aditionalData = !empty($filteredTickets[0]["aditionalData"]) ? $filteredTickets[0]["aditionalData"] : $filteredTickets[0]["detailTicket"]["usosTicket"];
  185.         $isParkToPark $this->sendVoucherEmailParkService->isParkToPark($aditionalData);
  186.         // Obtener lista de parques permitidos y conector de text park
  187.         $themeParkAccessNamesList $filteredTickets[0]["themeParkAccessNames"];
  188.         $conectorText $isParkToPark "<strong>AND</strong>" "<strong>OR</strong>";
  189.         $nameParksVisitList "";  
  190.         if(!empty($themeParkAccessNamesList)){
  191.             $themeParkAccessNames $this->sendVoucherEmailParkService->getParksVisitList($themeParkAccessNamesList);
  192.             $countParks count($themeParkAccessNames);
  193.             foreach ($themeParkAccessNames as $i => $park) {
  194.                 $nameParksVisitList .= $park;
  195.                 if ($i $countParks 1) {
  196.                     $nameParksVisitList .= $conectorText ";
  197.                 }
  198.             }
  199.         }
  200.         // Agregar políticas legacy y reemplazar valores
  201.         $legacyTicketPark str_replace("{{productName}}"$baseName$legacyTicketPark);
  202.         $legacyTicketPark str_replace("{{nameParksVisitList}}"$nameParksVisitList$legacyTicketPark);
  203.     
  204.         // Renderizar la vista
  205.         $agencyFolder $twigFolder->twigFlux();
  206.         return $this->render($twigFolder->twigExists(sprintf('@AviaturTwig/%s/Park/parkCheckout_index.html.twig'$agencyFolder)), [
  207.             'twig_readonly' => $isretry,
  208.             'isPark' => true,
  209.             "ticketsSelectedInfo" => $ticketsSelectedInfo,
  210.             "productName" => $baseName,
  211.             "eventDateTime" => $filteredTickets[0]['eventDateTime'],
  212.             "days" => $filteredTickets[0]['numberOfDays'],
  213.             "legacyTicketPark" => $legacyTicketPark,
  214.             "price" => $priceTotaltickets,
  215.             'payment_doc_type' => $documentPaymentType,
  216.             'doc_type' => $typeDocument,
  217.             'gender' => $typeGender,
  218.             'render' => $this->generateUrl('aviatur_park_avaliability'$searchParams['model']->getData()),
  219.             'services' => $passangerTypes,
  220.             'paymentOptions' => $paymentOptions,
  221.             'ccfranchises' => $iinRecordsArray["ccfranchises"],
  222.             'ccranges' => $iinRecordsArray["ccranges"],
  223.             'passengers' => $passengersInfoBD ?? [],
  224.             'billingData' => $billingDataInfoBD ?? []
  225.         ]);
  226.     }
  227.     // Función que aplica el modelo de búsqueda
  228.     private function parseSearchParams(string $json): array
  229.     {
  230.         $params json_decode($jsontrue);
  231.         $model = new ParkSearchModel();
  232.         $model->setNamePark($params['park']);
  233.         $model->setNameSedePark($params['sede']);
  234.         $model->setDatePark($params['datepark']);
  235.         $model->setPassengerPark($params['adults'] . "-" $params['children']);
  236.         return array_merge($params, ['model' => $model]);
  237.     }
  238.     // Función que valida la existencia del parque y sede
  239.     private function validParkAndSede($namePark$nameSedeAviaturErrorHandler $aviaturErrorHandler)
  240.     {
  241.         $availabilityParameters $this->em->getRepository(\Aviatur\ParkBundle\Entity\ParkSedes::class)->findAvailabilityParameters($this->agency$namePark$nameSede);
  242.         // Si no se encuentra el parque o la sede, redirigir al Home de parques con el mensaje de error
  243.         if (empty($availabilityParameters)) {
  244.             $titleError "La ubicación seleccionada no está disponible.";
  245.             $textError "Ha sido redirigido al home para que pueda seguir explorando opciones.";
  246.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl('aviatur_search_parks', []), $titleError$textError));
  247.         }
  248.         return $availabilityParameters;
  249.     }
  250.     // Función que obtiene la disponibilidad de acuerdo al transactionId
  251.     private function getAvailabilityFromSession($sessionKeyAviaturErrorHandler $aviaturErrorHandler)
  252.     {
  253.         $encoded $this->session->get($sessionKey);
  254.         if (!$encoded) {
  255.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl('aviatur_search_parks', []), 'Página no accesible''No puedes acceder al detalle sin disponibilidad. Ha sido redirigido al home para que pueda seguir explorando opciones.'));
  256.         }
  257.         return json_decode(base64_decode($encoded), true);
  258.     }
  259.     // Función que realiza y mapea el servicio del detalle
  260.     private function getTicketDetails(array $filteredTickets, array $searchParams, array $availabilityParametersAviaturLogSave $logSavestring $transactionIdAviaturErrorHandler $errorHandler)
  261.     {
  262.         $detailResults = [];
  263.         $formattedDetailRS = [];
  264.         $startDate = new \DateTime($searchParams['datepark']);
  265.         $endDate = clone $startDate;
  266.         $endDate->modify('+1 day');
  267.         foreach ($filteredTickets as $ticket) {
  268.             $passengerInfo $this->getTicketPassengerInfo($ticket$searchParams);
  269.             // Definir cantidad de tickets
  270.             $quantity $passengerInfo['quantity'];
  271.             // Determinar el tipo de pasajero (Adulto, Niño, No importa la edad)
  272.             $typePassenger $passengerInfo['typePassenger'];
  273.             // RQ detalle
  274.             $detailParkRQ = new ParkDetailModel(
  275.                 $availabilityParameters['requestKind'],
  276.                 $ticket['productId'],
  277.                 $searchParams['datepark'],
  278.                 $endDate->format('Y-m-d'),
  279.                 $ticket['salesProgramId'],
  280.                 $ticket['capacity'],
  281.                 $ticket['numberOfDays'],
  282.                 $availabilityParameters['environmentCode'],
  283.                 $quantity,
  284.                 $ticket['price']['amountAfterTax']
  285.             );
  286.             $logSave->logSave(json_encode($detailParkRQ->toArray()), 'ParkDetail'$availabilityParameters['providerIdentifier'] . '_' $ticket['productId'] . '_RQ'$transactionId);
  287.             $response $this->aviaturRestService->callRestWebService($availabilityParameters['wsUrl'], 'detalle'$detailParkRQ->toArray());
  288.             $logSave->logSave(json_encode($response), 'ParkDetail'$ticket['productId'] . '_RS'$transactionId);
  289.             $url $this->generateUrl('aviatur_park_avaliability'$searchParams['model']->getData());
  290.             $redirectTitle "Lo sentimos, no se encontró disponibilidad en este momento.";
  291.             $redirectText "Ha sido redirigido a la búsqueda para que pueda seguir explorando opciones.";
  292.             if (empty($response) || !$response['succeeded'] || empty($response['productDetalle'])) {
  293.                 return $this->redirect($errorHandler->errorRedirectNoEmail($url$redirectTitle$redirectText));
  294.             }
  295.             $filteredDetails $this->filterEventDetails($response['productDetalle'], $searchParams['datepark'], $quantity);
  296.             if (empty($filteredDetails)) {
  297.                 return $this->redirect($errorHandler->errorRedirectNoEmail($url$redirectTitle$redirectText));
  298.             }
  299.             $selectedDetail count($filteredTickets) <= $filteredDetails $this->getCombinationsDetailParks($formattedDetailRS$filteredDetails);
  300.             $detailResults[$ticket['productId']] = [
  301.                 'productId' => $ticket['productId'],
  302.                 'quantity' => $quantity,
  303.                 'typePassenger' => $typePassenger,
  304.                 'productDetalle' => reset($selectedDetail)
  305.             ];
  306.         }
  307.         return $detailResults;
  308.     }
  309.     // Función que obtiene la cantidad y tipo de pasajeros
  310.     private function getTicketPassengerInfo(array $ticket, array $searchParams): array
  311.     {
  312.         $ageType $ticket['ageValue'] ?? ($ticket['ageQualifies'][0]['ageType'] ?? '');
  313.         $quantity 0;
  314.         $typePassenger '';
  315.         switch ($ageType) {
  316.             case 'Adult':
  317.             case '10 Años en adelante':
  318.                 $quantity = (int) !empty($searchParams) ? $searchParams['adults'] : 0;
  319.                 $typePassenger 'ADT';
  320.                 break;
  321.             case 'Child':
  322.             case 'Entre 3 y 9 años':
  323.                 $quantity = (int) !empty($searchParams) ? $searchParams['children'] : 0;
  324.                 $typePassenger 'CHD';
  325.                 break;
  326.             case 'No importa la edad':
  327.                 $quantity = (int) !empty($searchParams) ? ($searchParams['adults'] + (int)$searchParams['children']) : 0;
  328.                 $typePassenger 'ALL';
  329.                 break;
  330.             default:
  331.                 $quantity 0;
  332.                 $typePassenger '';
  333.         }
  334.         return [
  335.             'quantity' => $quantity,
  336.             'typePassenger' => $typePassenger
  337.         ];
  338.     }
  339.     // Función que filtra solo los tickets con eventDateTime de la fecha seleccionada y con capacidad disponible a la búsqueda
  340.     private function filterEventDetails(array $productsstring $targetDateint $minCapacity): array
  341.     {
  342.         return array_filter(
  343.             $products,
  344.             fn($product) =>
  345.             substr($product['eventDateTime'], 010) === $targetDate &&
  346.                 $product['capacityAvailable'] >= $minCapacity
  347.         );
  348.     }
  349.     // Función para filtrar las combinaciones de eventos
  350.     private function getCombinationsDetailParks($arrayDetailParks$responseDetailParks)
  351.     {
  352.         $arrayDetailTickets = [];
  353.         if (!empty($arrayDetailParks)) {
  354.             // Obtener los valores comunes de eventId
  355.             $datesDetail1 array_column($arrayDetailParks'eventId');
  356.             $datesDetail2 array_column($responseDetailParks'eventId');
  357.             $commonDates array_intersect($datesDetail1$datesDetail2);
  358.             if (!empty($commonDates)) {
  359.                 // Filtrar todos los elementos de responseDetailParks cuyo eventId esté en los comunes
  360.                 $filteredDetail2 array_filter($responseDetailParks, function ($item) use ($commonDates) {
  361.                     return in_array($item['eventId'], $commonDates);
  362.                 });
  363.                 // Ordenar por totalPriceWithTax de menor a mayor
  364.                 usort($filteredDetail2, function ($a$b) {
  365.                     return $a['totalPriceWithTax'] <=> $b['totalPriceWithTax'];
  366.                 });
  367.                 // Tomar el más barato, es decir, el primer elemento de filteredDetail2
  368.                 $arrayDetailTickets reset($filteredDetail2);
  369.             }
  370.         } else {
  371.             // Si no hay detalle base, se retorna el response del detalle
  372.             $arrayDetailTickets $responseDetailParks;
  373.         }
  374.         return $arrayDetailTickets;
  375.     }
  376.     // Función integra la información de la respuesta del detalle en los tickets disponibles y realiza el cálculo de precios de acuerdo a los pasajeros
  377.     private function calculatePriceTotal(array &$filteredTickets, array $arrayDetailParks, array $searchParamsAviaturChangeCoin $changeCoin): array
  378.     {
  379.         // Obtener el porcentaje de markup del parque
  380.         $markupPark $this->em->getRepository(\Aviatur\ParkBundle\Entity\ParkMarkup::class)->getMarkupPark($searchParams['park'], $searchParams['sede']);
  381.         $markup = empty($markupPark) ? $markupPark;
  382.         // Obtener TRM del día
  383.         $trm $changeCoin->getExchangeRate('USD''COP''TRM')['OfficialExchangeRate'];
  384.         $currency $trm == 'USD' 'COP';
  385.         // Inicialización de precios
  386.         $priceTotals = ['priceAdultTicket' => 0'priceChildTicket' => 0'currency' => $currency];
  387.         array_walk($filteredTickets, function (&$ticket) use ($arrayDetailParks$markup$trm, &$priceTotals$searchParams) {
  388.             $detail $arrayDetailParks[$ticket['productId']] ?? null;
  389.             if (!$detail) return;
  390.             $ticket['quantity'] = $detail['quantity'];
  391.             $ticket['eventId'] = $detail['productDetalle']['eventId'];
  392.             $ticket['eventDateTime'] = $detail['productDetalle']['eventDateTime'];
  393.             $ticket['capacityAvailable'] = $detail['productDetalle']['capacityAvailable'];
  394.             $ticket['totalPriceWithTax'] = $detail['productDetalle']['totalPriceWithTax'];
  395.             $ticket['usageDateRange'] = $detail['productDetalle']['usageDateRange'];
  396.             $price $this->calculateTicketPrice($ticket['totalPriceWithTax'], $ticket['price']['decimalPlaces'], $markup$trm);
  397.             switch ($detail['typePassenger']) {
  398.                 case 'ADT':
  399.                     $priceTotals['priceAdultTicket'] += $price $ticket['quantity'];
  400.                     break;
  401.                 case 'CHD':
  402.                     $priceTotals['priceChildTicket'] += $price $ticket['quantity'];
  403.                     break;
  404.                 case 'ALL':
  405.                     $priceTotals['priceAdultTicket'] += $price * (int) $searchParams['adults'];
  406.                     $priceTotals['priceChildTicket'] += $price * (int) $searchParams['children'];
  407.                     break;
  408.             }
  409.         });
  410.         return $priceTotals;
  411.     }
  412.     // Calcular el precio del ticket con markup en COP
  413.     private function calculateTicketPrice($priceTicket$decimalPlacesTicket$markupPark$trm)
  414.     {
  415.         $priceTicket $priceTicket * (/ (100 $markupPark)) * 100;
  416.         $priceTicket round($priceTicket, (int) $decimalPlacesTicket); //Redondeando en USD
  417.         $priceTicket $priceTicket $trm;
  418.         return round($priceTicket, (int) $decimalPlacesTicket); //Redondeando en COP
  419.     }
  420.     // Proceso reserva, pago y facturación
  421.     public function processFullCheckoutAction(Request $request, \Swift_Mailer $mailerTokenizerService $tokenizerServiceCustomerMethodPaymentService $customerMethodPaymentTokenStorageInterface $tokenStorageAviaturErrorHandler $aviaturErrorHandlerAviaturEncoder $aviaturEncoderSessionInterface $sessionParameterBagInterface $parameterBagOrderController $orderControllerAviaturLogSave $aviaturLogSaveManagerRegistry $registryAviaturChangeCoin $aviaturChangeCoin)
  422.     {
  423.         if (empty($request->query->all()) && empty($request->request->all())) {
  424.             $titleError "Acceso no autorizado";
  425.             $textError "Ha sido redirigido al home para que pueda seguir explorando opciones.";
  426.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl("aviatur_search_parks", []), $titleError$textError));
  427.         }
  428.         $hostPark $request->getHost();
  429.         $request $request->request ?? $request->query;
  430.         $em $this->em;
  431.         $session $this->session;
  432.         $agency $this->agency;
  433.         $checkoutInfo $request->all();
  434.         // Obtener el transactionId
  435.         $transactionId = (string) $checkoutInfo["transactionIdCheckout"];
  436.         // Guardar intentos de compra
  437.         $aviaturPaymentRetryTimes $parameterBag->get('aviatur_payment_retry_times');
  438.         $retryCount $session->get($transactionId '[park][retry]');
  439.         if($retryCount == null){
  440.             $session->set($transactionId '[park][retry]'$aviaturPaymentRetryTimes);
  441.         }
  442.         
  443.         // Validar si ya hay userInfo en la sesión para reintentos
  444.         if($session->get($transactionId "[park][userInfo]") != null){
  445.             // Información de formularios de usuario
  446.             $formUserInfo $this->em->getRepository(\Aviatur\GeneralBundle\Entity\FormUserInfo::class)->find($session->get($transactionId '[park][userInfo]'));
  447.             $decodedResponseInfoUser json_decode($aviaturEncoder->AviaturDecode($formUserInfo->getInfo(), $formUserInfo->getPublicKey()), true);
  448.             $decodedResponseInfoUser["PD"] = $checkoutInfo["PD"];
  449.             $checkoutInfo $decodedResponseInfoUser;
  450.         }else{
  451.             $formUserInfo = new FormUserInfo();
  452.         }
  453.         // Token de la tarjeta, en caso que exista
  454.         $publicKey $aviaturEncoder->aviaturRandomKey();
  455.         if (isset($checkoutInfo["PD"]["card_num"])) {
  456.             $postDataInfo $checkoutInfo;
  457.             if (isset($postDataInfo["PD"]["cusPOptSelected"])) {
  458.                 $customerLogin $tokenStorage->getToken()->getUser();
  459.                 $infoMethodPaymentByClient $customerMethodPayment->getMethodsByCustomer($customerLogintrue);
  460.                 $cardToken $infoMethodPaymentByClient["info"][$postDataInfo["PD"]["cusPOptSelected"]]["token"];
  461.                 $postDataInfo["PD"]["card_num"] = $cardToken;
  462.             } else {
  463.                 $postDataInfo["PD"]["card_num"] = $tokenizerService->getToken($checkoutInfo["PD"]["card_num"]);
  464.             }
  465.             $checkoutInfo["PD"]["card_values"] = ["card_num_token" => $postDataInfo["PD"]["card_num"], "card_num" => $checkoutInfo["PD"]["card_num"]];
  466.         }
  467.         // Encodear y guardar la info de los formularios en la tabla form_user_info
  468.         $encodedInfo $aviaturEncoder->AviaturEncode(json_encode($postDataInfo ?? $checkoutInfo), $publicKey);
  469.         $formUserInfo->setInfo($encodedInfo);
  470.         $formUserInfo->setPublicKey($publicKey);
  471.         $em->persist($formUserInfo);
  472.         $em->flush();
  473.         // Guardar en session el id de la tabla
  474.         $session->set($transactionId "[park][userInfo]"$formUserInfo->getId());
  475.         // Obtener la información de los tickets desde la sesión
  476.         $sessionKey $transactionId "[park][ticketsInfo]";
  477.         $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  478.         $filteredTickets $infoTickets["filteredTickets"];
  479.         $searchParams $infoTickets["searchParams"];
  480.         // Si no hay información de los tickets rediriguir a disponibilidad
  481.         if (empty($infoTickets) || !isset($filteredTickets)) {
  482.             $searchParams $this->parseSearchParams(json_encode($searchParams));
  483.             $url $this->generateUrl("aviatur_park_avaliability"$searchParams["model"]->getData());
  484.             return $this->json(["error" => true"message" => $aviaturErrorHandler->errorRedirect($url"Acceso no autorizado""No encontramos información del detalle de tu búsqueda, por favor vuelve a intentarlo.")]);
  485.         }
  486.         // Información facturador
  487.         $billingData $checkoutInfo["BD"];
  488.         $customer $em->getRepository(\Aviatur\CustomerBundle\Entity\Customer::class)->find($billingData["id"]);
  489.         $ordersProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->getOrderProductsPending($customer);
  490.         if (null == $ordersProduct) {
  491.             $session->set($transactionId '[park][detailDataPark]'json_encode($postDataInfo));
  492.             // Información pasajeros
  493.             $passangersData $postDataInfo["PI"];
  494.             $passangerInfo = [];
  495.             for ($i 1$i <= $passangersData["person_count_1"]; ++$i) {
  496.                 if ($i == 1) {
  497.                     if (false !== strpos($passangersData["first_name_1_" $i], '***')) {
  498.                         $passangerInfo[$i]["first_name"] = $customer->getFirstname();
  499.                         $passangerInfo[$i]["last_name"] = $customer->getLastname();
  500.                         $passangerInfo[$i]["email"] = $customer->getEmail();
  501.                         $passangerInfo[$i]["phone"] = $customer->getPhone();
  502.                         $passangerInfo[$i]["passanger_type"] = $passangersData["passanger_type_1_" $i];
  503.                         continue;
  504.                     } else {
  505.                         $passangerInfo[$i]["email"] = $passangersData["email_1_" $i];
  506.                         $passangerInfo[$i]["phone"] = $passangersData["phone_1_" $i] ?? $postDataInfo["CD"]["phone"];
  507.                     }
  508.                 }
  509.                 $passangerInfo[$i]["first_name"] = mb_convert_case($passangersData["first_name_1_" $i], MB_CASE_TITLE"UTF-8");
  510.                 $passangerInfo[$i]["last_name"] = mb_convert_case($passangersData["last_name_1_" $i], MB_CASE_TITLE"UTF-8");
  511.                 $passangerInfo[$i]["passanger_type"] = $passangersData["passanger_type_1_" $i];
  512.             }
  513.             // Reserva
  514.             $namePark $searchParams["park"];
  515.             $productType mb_strtolower($namePark);
  516.             if(true != $session->has($transactionId '[' $productType '][order]')){
  517.                 $bookingInfo $this->bookingReservation($session$mailer$transactionId$infoTickets$passangerInfo$aviaturLogSave);
  518.                 $arrayBookingInfo json_decode($bookingInfo);
  519.             }else{
  520.                 // Obtener order y orderProduct
  521.                 $orderInfo json_decode($session->get($transactionId '[' $productType '][order]'), true);
  522.                 $productId str_replace('PN'''$orderInfo["products"]);
  523.                 $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  524.                 // obtener emailData y asignar valor de error
  525.                 $arrayBookingInfo json_decode($orderProduct->getEmail());
  526.                 $arrayBookingInfo->error = !$arrayBookingInfo->bookingData->success;
  527.             }
  528.             if (!$arrayBookingInfo->error) {
  529.                 $session->set($transactionId '[park][prepayment_check]'true);
  530.                 $bookingData $arrayBookingInfo->bookingData;
  531.                 $reservationId = (string) $bookingData->reservationIds->productResId;
  532.                 // Guardar provedor en session para OrderController
  533.                 $providerIdentifier $infoTickets["availabilityParameters"]["providerIdentifier"];
  534.                 $session->set($transactionId '[' $productType '][provider]'$providerIdentifier);
  535.                 $status 'waiting';
  536.                 $order = [];
  537.                 if(true != $session->has($transactionId '[' $productType '][order]')){
  538.                     if (!isset($agency)) {
  539.                         $titleError "No se encontró la agencia con el dominio: " $hostPark;
  540.                         $textError "Ha sido redirigido al home para que pueda seguir explorando opciones.";
  541.                         return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($this->generateUrl("aviatur_search_parks", []), $titleError$textError));
  542.                     }
  543.                     // Crear Order y order product, con add_productData
  544.                     $productType $em->getRepository(\Aviatur\MpaBundle\Entity\ProductType::class)->findByCode(strtoupper($namePark));
  545.                     $order $orderController->createAction($agency$customer$productType$reservationId$status);
  546.                     $orderId str_replace('ON'''$order['order']);
  547.                     $orderEntity $em->getRepository(\Aviatur\GeneralBundle\Entity\Order::class)->find($orderId);
  548.                     $formUserInfo $em->getRepository(\Aviatur\GeneralBundle\Entity\FormUserInfo::class)->find($session->get($transactionId '[park][userInfo]'));
  549.                     $formUserInfo->setOrder($orderEntity);
  550.                     $em->persist($formUserInfo);
  551.                     $em->flush();
  552.                 }
  553.                 
  554.                 // Obtener orderProduct
  555.                 $orderInfo = !empty($order) ? $order json_decode($session->get($transactionId '[' $productType '][order]'), true);
  556.                 $productId str_replace('PN'''$orderInfo["products"]);
  557.                 $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  558.                 
  559.                 // Actualizar setEmissiondata
  560.                 $orderProduct->setEmissiondata($reservationId);
  561.                 $em->persist($orderProduct);
  562.                 $em->flush();
  563.                 // Eliminar "Adult" o "Child" del nombre del ticket para agruparlos
  564.                 $baseName preg_replace('/(Adult|Child|Ad |Ch )/'''$filteredTickets[0]["productName"]);
  565.                 $baseName trim($baseName);
  566.                 // Validación de la existencia del parque y sede
  567.                 $availabilityParameters $this->validParkAndSede($namePark$searchParams['sede'], $aviaturErrorHandler);
  568.                 // Arreglo RS del detalle
  569.                 $searchParams $this->parseSearchParams(json_encode($searchParams));
  570.                 $arrayDetailParks $this->getTicketDetails($filteredTickets$searchParams$availabilityParameters$aviaturLogSave$transactionId$aviaturErrorHandler);
  571.                 // Precios totalizados de los tickets
  572.                 $priceTotaltickets $this->calculatePriceTotal($filteredTickets$arrayDetailParks$searchParams$aviaturChangeCoin);
  573.                 // COLLECT INFORMATION TO PERSIST OrderProduct->Email
  574.                 $this->generate_email($session$registry$parameterBag$orderProduct$infoTickets,  $arrayBookingInfo$aviaturErrorHandler$baseName$priceTotaltickets);
  575.                 // Enviar correo de reserva exitosa con orden creada
  576.                 $emailContent 'Park reservation ' $orderProduct->getEmissiondata() . ', the product id is: ' $orderProduct->getId() . ', the customer id is: ' $customer->getId() . '</b> Email customer new DB: <b>' $customer->getEmail() . '</b>, the info is: ' $orderProduct->getEmail();
  577.                 $message = (new \Swift_Message())
  578.                     ->setContentType('text/html')
  579.                     ->setFrom('noreply@aviatur.com.co')
  580.                     ->setSubject('Park Reservation')
  581.                     ->setTo(['soptepagelectronic@aviatur.com''soportepagoelectronico@aviatur.com.co'])
  582.                     ->setBcc(['notificacionessitioweb@aviatur.com'])
  583.                     ->setBody($emailContent);
  584.                 // Envio de correo
  585.                 $mailer->send($message);
  586.                 // Ir a pago
  587.                 $orderInfo['url'] = $this->generateUrl('aviatur_park_payment_secure');
  588.                 return $this->json($orderInfo);
  589.             } else {
  590.                 // Datos de búsqueda
  591.                 $searchParams $this->parseSearchParams(json_encode($infoTickets['searchParams']));
  592.                 // Mensaje codificado con estilos en HTML, debe ir centrado
  593.                 $nameSedePark = (string) $searchParams["sede"];
  594.                 $adults = (int) $searchParams["adults"];
  595.                 $children = (int) $searchParams["children"];
  596.                 $fechaFormateada date("d/m/Y"strtotime($searchParams['datepark']));
  597.                 $textoAdultos $adults == "1 adulto" "$adults adultos";
  598.                 $textoNinos $children == "" : ($children == " y 1 niño" " y $children niños");
  599.                 $mensaje "Hola! Estoy intentando hacer una reserva para " .
  600.                         "$nameSedePark el $fechaFormateada, ($textoAdultos$textoNinos), " .
  601.                         "pero algo falló al momento de procesar la reserva. Este es el ID de la transacción: " $transactionId 
  602.                         "\n ¿me podrías ayudar?";
  603.                 $mensajeCodificado rawurlencode($mensaje);
  604.                 $linkWA "https://api.whatsapp.com/send?phone=5713821616&text=$mensajeCodificado";
  605.                 $urlRedirect $this->generateUrl('aviatur_park_avaliability'$searchParams['model']->getData());
  606.                 
  607.                 $return json_encode(['error' => 'noReservation''product' => 'ticket''message' => $transactionId'link_wa' => $linkWA'url_redirect' => $urlRedirect]);
  608.                 return new Response($return);
  609.             }
  610.         } else {
  611.             $booking = [];
  612.             $cus = [];
  613.             foreach ($ordersProduct as $orderProduct) {
  614.                 $productResponse $aviaturEncoder->AviaturDecode($orderProduct->getPayResponse(), $orderProduct->getPublicKey());
  615.                 $paymentResponse json_decode($productResponse);
  616.                 array_push($booking"ON" $orderProduct->getOrder()->getId() . "-PN" $orderProduct->getId());
  617.                 if (isset($paymentResponse->x_approval_code)) {
  618.                     array_push($cus$paymentResponse->x_approval_code);
  619.                 } elseif (isset($paymentResponse->createTransactionResult->trazabilityCode)) {
  620.                     array_push($cus$paymentResponse->createTransactionResult->trazabilityCode);
  621.                 }
  622.             }
  623.             $return = [
  624.                 "error" => "pending_payments",
  625.                 "message" => "pending_payments",
  626.                 "booking" => $booking,
  627.                 "domain" => $domain ?? null,
  628.                 "agencyId" => $this->agency ?? null,
  629.                 "operatorId" => $operatorId ?? null,
  630.                 "cus" => $cus,
  631.             ];
  632.             return new JsonResponse($return);
  633.         }
  634.     }
  635.     // Consumo de reserva
  636.     private function bookingReservation(SessionInterface $session, \Swift_Mailer $mailer$transactionId$infoTickets, array $passangerInfoAviaturLogSave $logSave)
  637.     {
  638.         // Combinando respuesta de dispo con detalle
  639.         $productCatalog $this->combineDispoWithDetails($infoTickets["filteredTickets"], $passangerInfo);
  640.         $contactPerson = [
  641.             'firstName' => $passangerInfo[1]['first_name'],
  642.             'lastName' => $passangerInfo[1]['last_name'],
  643.             'phone' => $passangerInfo[1]['phone'],
  644.             'email' => $passangerInfo[1]['email'],
  645.         ];
  646.         $bookingParkRQ = new ParkBookingModel(
  647.             $infoTickets['availabilityParameters']['requestKind'],
  648.             $contactPerson,
  649.             $productCatalog,
  650.             $infoTickets['availabilityParameters']['environmentCode']
  651.         );
  652.         $logSave->logSave(json_encode($bookingParkRQ->toArray()), "ParkBooking"$infoTickets["availabilityParameters"]["providerIdentifier"] . "_RQ"$transactionId);
  653.         $response $this->aviaturRestService->callRestWebService($infoTickets['availabilityParameters']['wsUrl'], "book"$bookingParkRQ->toArray());
  654.         $logSave->logSave(json_encode($response), "ParkBooking""RS"$transactionId);
  655.         $bookingSucceeded true;
  656.         $reservation $response["reservation"];
  657.         $bookingData = [];
  658.         if ($response["succeeded"] && !empty($reservation)) {
  659.             $bookingData $reservation[0];
  660.             $bookingData["contactPerson"] = $contactPerson;
  661.             $bookingSucceeded false;
  662.             // Actualizar info del ticket combinando dispo con detalle
  663.             $infoTickets["filteredTickets"] = $productCatalog;
  664.             $session->set($transactionId '[park][ticketsInfo]'base64_encode(json_encode($infoTickets)));
  665.         };
  666.         // Enviar correo de reserva exitosa
  667.         if(!$bookingSucceeded){
  668.             // Información agencia
  669.             $agency $this->agency;
  670.             $agencyData = [
  671.                 "agency_name" => $agency->getName(),
  672.                 "agency_nit" => $agency->getNit(),
  673.                 "agency_phone" => $agency->getPhone(),
  674.                 "agency_email" => $agency->getMailContact(),
  675.             ];
  676.             $setTo = ['union@udr.com'];
  677.             $emailSubject 'Park Reservation' ;
  678.             $emailContent '
  679.                 <b>Reserva exitosa</b><br/>
  680.                 Info:<br/>
  681.                 The agency is: '.json_encode($agencyData).'<br/></b>
  682.                 The reservation ids is: '.json_encode($bookingData["reservationIds"]).'<br/></b>
  683.                 The contact customer is: '.json_encode($contactPerson).'<br/></b>
  684.                 The info is: '.json_encode($productCatalog);
  685.             
  686.             $message = (new \Swift_Message())
  687.                 ->setContentType('text/html')
  688.                 ->setFrom('noreply@aviatur.com.co')
  689.                 ->setSubject($emailSubject)
  690.                 ->setTo($setTo)
  691.                 ->setBody($emailContent);
  692.             // Envio de correo
  693.             $mailer->send($message);
  694.         }
  695.         $result = [
  696.             "bookingData" => $bookingData,
  697.             "error" => $bookingSucceeded,
  698.             "message" => [
  699.                 "title" => $bookingSucceeded "No se pudo completar la reserva." "Operación exitosa",
  700.                 "text" => $bookingSucceeded "Hubo un problema al procesar tu solicitud. Por favor, intenta nuevamente." ""
  701.             ]
  702.         ];
  703.         return json_encode($resultJSON_UNESCAPED_SLASHES);
  704.     }
  705.     // Combinando dispo con detalle
  706.     private function combineDispoWithDetails($productCatalog$passangerInfo)
  707.     {
  708.         foreach ($productCatalog as $keyTicket => $valueTicket) {
  709.             $passengerDetail $this->getTicketPassengerInfo($valueTicket, []);
  710.             $typePassenger $passengerDetail["typePassenger"];
  711.             if ($typePassenger === "ALL") {
  712.                 // Si el tipo de pasajero es "ALL", incluir todos los pasajeros
  713.                 $guestNames $passangerInfo;
  714.             } else {
  715.                 // Filtrar array de acuerdo al tipo de pasajero específico
  716.                 $guestNames array_filter($passangerInfo, fn($p) => $p["passanger_type"] === $typePassenger);
  717.             }
  718.             // Mapear guestNames y reindexar desde 0
  719.             $productCatalog[$keyTicket]["byTicketGuestNames"] = array_values(array_map(
  720.                 fn($p) => ["first" => $p["first_name"], "last" => $p["last_name"]],
  721.                 $guestNames
  722.             ));
  723.             if (empty($valueTicket["usageDateRange"])) {
  724.                 $productCatalog[$keyTicket]["usageDateRange"] = [
  725.                     "startDate" => "string",
  726.                     "endDate" => "string"
  727.                 ];
  728.             }
  729.             if (empty($valueTicket["detailTicket"])) {
  730.                 $productCatalog[$keyTicket]["detailTicket"] = [
  731.                     "usosTicket" => $valueTicket["aditionalData"]
  732.                 ];
  733.                 // Al agregarlo en usosTicket se elimina el campo aditionalData
  734.                 unset($productCatalog[$keyTicket]["aditionalData"]);
  735.             }
  736.             $productCatalog[$keyTicket]["quantity"] = (string) $productCatalog[$keyTicket]["quantity"];
  737.             $productCatalog[$keyTicket]["totalPriceWithTax"] = (string) $productCatalog[$keyTicket]["totalPriceWithTax"];
  738.         }
  739.         return $productCatalog;
  740.     }
  741.     // Funcion para guardar en email BD
  742.     public function generate_email(SessionInterface $sessionManagerRegistry $registryParameterBagInterface $parameterBag$orderProduct$infoTickets$prepaymentInfoaviaturErrorHandler $aviaturErrorHandler$baseName$priceTotaltickets)
  743.     {
  744.         $transactionIdSessionName $parameterBag->get("transaction_id_session_name");
  745.         $transactionId $session->get($transactionIdSessionName);
  746.         // Información agencia
  747.         $em $registry->getManager();
  748.         $agency $em->getRepository(\Aviatur\AgencyBundle\Entity\Agency::class)->find($session->get("agencyId"));
  749.         $agencyData = [
  750.             "agency_name" => $agency->getName(),
  751.             "agency_nit" => $agency->getNit(),
  752.             "agency_phone" => $agency->getPhone(),
  753.             "agency_email" => $agency->getMailContact(),
  754.         ];
  755.         //  Cantidad de intentos
  756.         $retryCount = (int) $session->get($transactionId "[park][retry]");
  757.         // Información tickets
  758.         $filteredTickets $infoTickets["filteredTickets"];
  759.         $searchParams $infoTickets["searchParams"];
  760.         // Información formularios
  761.         $postDataJson json_decode($session->get($transactionId "[park][detailDataPark]"));
  762.         // Información pasajeros
  763.         $passangersData json_decode(json_encode($postDataJson->PI), true);
  764.         $passangerInfo = [];
  765.         for ($i 1$i <= $passangersData["person_count_1"]; ++$i) {
  766.             $passangerInfo[$i]["first_name"] = mb_convert_case($passangersData["first_name_1_" $i], MB_CASE_TITLE"UTF-8");
  767.             $passangerInfo[$i]["last_name"] = mb_convert_case($passangersData["last_name_1_" $i], MB_CASE_TITLE"UTF-8");
  768.             $passangerInfo[$i]["passanger_type"] = $passangersData["passanger_type_1_" $i];
  769.         }
  770.         // Politicas de cancelacion?
  771.         $cancelPolicies = (string) "";
  772.         // Información journey
  773.         $startDate = new \DateTime($searchParams["datepark"]);
  774.         $endDate = clone $startDate;
  775.         $endDate->modify("+1 day");
  776.         $journeySummary = [
  777.             "parkName" => $searchParams["park"],
  778.             "sedeParkName" => $searchParams["sede"],
  779.             "ticketName" => $baseName,
  780.             "ticketDays" => $filteredTickets[0]["numberOfDays"],
  781.             "startDate" => $searchParams["datepark"],
  782.             "endDate" => $endDate->format("Y-m-d"),
  783.             "ticketPricing" => [
  784.                 "adults" => [
  785.                     "quantity" => $searchParams["adults"],
  786.                     "price" => $priceTotaltickets["priceAdultTicket"],
  787.                     "currency" => $priceTotaltickets["currency"]
  788.                 ],
  789.                 "children" => [
  790.                     "quantity" => $searchParams["children"],
  791.                     "price" => $priceTotaltickets["priceChildTicket"],
  792.                     "currency" => $priceTotaltickets["currency"]
  793.                 ]
  794.             ],
  795.             "cancelPolicies" => $cancelPolicies
  796.         ];
  797.         // Información del facturador
  798.         $factInfo $postDataJson->BD;
  799.         $facturationResume = [
  800.             "customer_names" => $factInfo->first_name " " $factInfo->last_name,
  801.             "customer_doc_num" => $factInfo->doc_num,
  802.             "customer_phone" => $factInfo->phone,
  803.             "customer_email" => $factInfo->email
  804.         ];
  805.         // Información de medio de pago
  806.         $paymentData $postDataJson->PD;
  807.         $description 'Parques - ' $searchParams["sede"] . ': ' $baseName;
  808.         $paymentResume = [
  809.             'total_amount' => $priceTotaltickets["priceAdultTicket"] + $priceTotaltickets["priceChildTicket"],
  810.             'currency' => $priceTotaltickets["currency"],
  811.             'ip_address' => $this->get_client_ip(),
  812.             'bank_name' => '',
  813.             'franquice' => $paymentData->franquise,
  814.             'cuotas' => $paymentData->differed,
  815.             'card_num' => "************" substr($paymentData->card_numstrlen($paymentData->card_num) - 4),
  816.             'reference' => '',
  817.             'auth' => '',
  818.             'transaction_date' => $orderProduct->getCreationDate()->format('Y-m-d H:i:s'),
  819.             'description' => $description,
  820.             'reason_code' => '',
  821.             'reason_description' => 'Reserva rechazada.',
  822.             'client_names' => $paymentData->first_name ' ' $paymentData->last_name
  823.         ];
  824.         // Información de reserva si ya existe
  825.         $bookingData = [];
  826.         if (!empty($prepaymentInfo->bookingData)) {
  827.             $bookingData = [
  828.                 "success" => $prepaymentInfo->bookingData->success,
  829.                 "reservationIds" => $prepaymentInfo->bookingData->reservationIds,
  830.                 "contactPerson" => $prepaymentInfo->bookingData->contactPerson,
  831.                 "createdTicketResponses" => $prepaymentInfo->bookingData->createdTicketResponses
  832.             ];
  833.             $filteredTickets $this->combineDispoWithDetails($filteredTickets$passangerInfo);
  834.         }
  835.         // agent
  836.         $responseOrder null;
  837.         if ($session->has($transactionId '[user]')) {
  838.             $responseOrder = \simplexml_load_string($session->get($transactionId '[user]'));
  839.         }
  840.         $emailData = [
  841.             'agencyData' => $agencyData,
  842.             'retry_count' => $retryCount,
  843.             'facturationResume' => $facturationResume,
  844.             'journeySummary' => $journeySummary,
  845.             'paymentResume' => $paymentResume,
  846.             'bookingData' => $bookingData,
  847.             'transactionID' => $transactionId,
  848.             'tickets' => $filteredTickets,
  849.             'passangers' => $passangerInfo,
  850.             'agent' => $responseOrder
  851.         ];
  852.         $orderProduct->setEmail(json_encode($emailData));
  853.         $em->persist($orderProduct);
  854.         $em->flush();
  855.     }
  856.     // Obtener ip del cliente
  857.     final private function get_client_ip()
  858.     {
  859.         $ipaddress '';
  860.         if (getenv('HTTP_CLIENT_IP')) {
  861.             $ipaddress getenv('HTTP_CLIENT_IP');
  862.         } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
  863.             $ipaddress getenv('HTTP_X_FORWARDED_FOR');
  864.         } elseif (getenv('HTTP_X_FORWARDED')) {
  865.             $ipaddress getenv('HTTP_X_FORWARDED');
  866.         } elseif (getenv('HTTP_FORWARDED_FOR')) {
  867.             $ipaddress getenv('HTTP_FORWARDED_FOR');
  868.         } elseif (getenv('HTTP_FORWARDED')) {
  869.             $ipaddress getenv('HTTP_FORWARDED');
  870.         } elseif (getenv('REMOTE_ADDR')) {
  871.             $ipaddress getenv('REMOTE_ADDR');
  872.         } else {
  873.             $ipaddress 'UNKNOWN';
  874.         }
  875.         return (strpos($ipaddress',') !== false) ? trim(explode(','$ipaddress)[0]) : (substr_count($ipaddress':') > $ipaddress explode(':'$ipaddress)[0]);
  876.     }
  877.     // Funcion de pago
  878.     public function paymentAction(\Swift_Mailer $mailerP2PController $p2pPaymentControllerAviaturErrorHandler $aviaturErrorHandlerSessionInterface $sessionParameterBagInterface $parameterBagTokenizerService $tokenizerServiceCustomerMethodPaymentService $customerMethodPaymentAviaturLogSave $aviaturLogSaveAviaturChangeCoin $aviaturChangeCoin)
  879.     {
  880.         $em $this->em;
  881.         $session $this->session;
  882.         // Iniciación de variables
  883.         $orderProduct = [];
  884.         $paymentResponse null;
  885.         $array = [];
  886.         // Obtener el transactionId
  887.         $transactionIdSessionName $parameterBag->get('transaction_id_session_name');
  888.         $transactionId $session->get($transactionIdSessionName);       
  889.         // Obtener la información de los tickets desde la sesión
  890.         $sessionKey $transactionId "[park][ticketsInfo]";
  891.         $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  892.         $filteredTickets $infoTickets["filteredTickets"];
  893.         $searchParams $infoTickets["searchParams"];
  894.         $namePark = (string) $searchParams["park"];
  895.         $productType mb_strtolower($namePark);
  896.         $nameParkSede = (string) $searchParams["sede"];
  897.         // Obtener información de los formularios del checkOut
  898.         $postData json_decode($session->get($transactionId '[park][detailDataPark]'));
  899.         $paymentData $postData->PD;
  900.         // Eliminar "Adult" o "Child" del nombre del ticket para generalizarlo
  901.         $baseName preg_replace('/(Adult|Child|Ad |Ch )/'''$filteredTickets[0]["productName"]);
  902.         $baseName trim($baseName);
  903.         // Validación de la existencia del parque y sede
  904.         $availabilityParameters $this->validParkAndSede($searchParams['park'], $searchParams['sede'], $aviaturErrorHandler);
  905.         // Arreglo RS del detalle
  906.         $searchParams $this->parseSearchParams(json_encode($searchParams));
  907.         $arrayDetailParks $this->getTicketDetails($filteredTickets$searchParams$availabilityParameters$aviaturLogSave$transactionId$aviaturErrorHandler);
  908.         // Precios totalizados de los tickets
  909.         $priceTotaltickets $this->calculatePriceTotal($filteredTickets$arrayDetailParks$searchParams$aviaturChangeCoin);
  910.         $totalAmountCOP $priceTotaltickets["priceAdultTicket"] + $priceTotaltickets["priceChildTicket"];
  911.         // IdOrder y IdOrderProduct
  912.         $orderInfo json_decode($session->get($transactionId '[' $productType '][order]'));
  913.         $productId str_replace('PN'''$orderInfo->products);
  914.         $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  915.         // Actualizar reintentos de pago
  916.         $retryCount = (int) $session->get($transactionId '[park][retry]');
  917.         $session->set($transactionId '[park][retry]'$retryCount 1);
  918.         $arrayEmail json_decode($orderProduct->getEmail(), true);
  919.         if (isset($arrayEmail["retry_count"])) {
  920.             $arrayEmail["retry_count"] = $retryCount 1;
  921.             $orderProduct->setEmail(json_encode($arrayEmail));
  922.             $em->persist($orderProduct);
  923.             $em->flush();
  924.         }
  925.         // Pago p2p
  926.         if ('p2p' == $paymentData->type) {
  927.             $customer $em->getRepository(\Aviatur\CustomerBundle\Entity\Customer::class)->find($postData->BD->id);
  928.             if (false !== strpos($paymentData->address'***')) {
  929.                 $paymentData->address $customer->getAddress();
  930.                 $paymentData->phone $customer->getPhone();
  931.                 $paymentData->email $customer->getEmail();
  932.             }
  933.             $description 'Parques - ' $nameParkSede ': ' $baseName;
  934.             $array = [
  935.                 'x_currency_code' => (string)"COP",
  936.                 'x_amount' => $totalAmountCOP,
  937.                 'x_tax' => number_format(02'.'''),
  938.                 'x_amount_base' => number_format($totalAmountCOP2'.'''),
  939.                 'x_invoice_num' => $orderInfo->order '-' $orderInfo->products,
  940.                 'x_first_name' => $paymentData->first_name,
  941.                 'x_last_name' => $paymentData->last_name,
  942.                 'x_description' => $description,
  943.                 'x_city' => $customer->getCity()->getIatacode(),
  944.                 'x_country_id' => $customer->getCountry()->getIatacode(),
  945.                 'x_cust_id' => $paymentData->doc_type ' ' $paymentData->doc_num,
  946.                 'x_address' => $paymentData->address,
  947.                 'x_phone' => $paymentData->phone,
  948.                 'x_email' => $paymentData->email,
  949.                 'x_card_num' => $paymentData->card_num,
  950.                 'x_exp_date' => $paymentData->exp_month $paymentData->exp_year,
  951.                 'x_card_code' => $paymentData->card_code,
  952.                 'x_differed' => $paymentData->differed,
  953.                 'x_client_id' => $postData->BD->id,
  954.                 'product_type' => $productType,
  955.                 'productId' => str_replace('PN'''$orderInfo->products),
  956.                 'orderId' => str_replace('ON'''$orderInfo->order),
  957.                 'franchise' => $paymentData->franquise,
  958.                 'worldpay_validate' => false,
  959.             ];
  960.             if (isset($paymentData->card_values)) {
  961.                 $array['card_values'] = (array) $paymentData->card_values;
  962.             }
  963.             // Consumo de pago
  964.             $paymentResponse $p2pPaymentController->placetopayAction($parameterBag$tokenizerService$customerMethodPayment$mailer$aviaturLogSave$array$combination false$segment nullfalse);
  965.             if (empty($paymentResponse)) {
  966.                 // No hay respuesta por parte del servicio de pago, estado pendiente
  967.                 $orderProduct->setStatus('pending');
  968.                 $em->persist($orderProduct);
  969.                 $em->flush();
  970.                 $urlResume $this->generateUrl('aviatur_park_payment_pending_secure');
  971.                 return $this->redirect($urlResume);
  972.             }
  973.             return $this->redirect($this->generateUrl('aviatur_park_payment_p2p_secure', [], true));
  974.         } else {
  975.             // Cambiar estado de pago
  976.             $orderProduct->setStatus('reject');
  977.             $em->persist($orderProduct);
  978.             $em->flush();
  979.             // Cancelar Reserva
  980.             $this->cancelBookingParkService->cancelReservation($orderInfo->order '-' $orderInfo->productstrue);
  981.             
  982.             // Redireccionar a dispo
  983.             $url $this->generateUrl('aviatur_park_avaliability'$searchParams['model']->getData());
  984.             $titleError "El tipo de pago es inválido.";
  985.             $textError "Ha sido redirigido a la búsqueda para que pueda seguir explorando opciones.";
  986.             return $this->redirect($aviaturErrorHandler->errorRedirectNoEmail($url$titleError$textError));
  987.         }
  988.     }
  989.     // Control de estados de pago
  990.     public function p2pCallbackAction(OrderController $orderControllerValidateSanctionsRenewal $validateSanctionsTokenStorageInterface $tokenStorageCustomerMethodPaymentService $customerMethodPaymentAviaturMailer $aviaturMailerAviaturEncoder $aviaturEncoderAviaturErrorHandler $aviaturErrorHandlerParameterBagInterface $parameterBag)
  991.     {
  992.         $transactionIdSessionName $parameterBag->get('transaction_id_session_name');
  993.         $em $this->em;
  994.         $session $this->session;
  995.         // Obtener la información de los tickets desde la sesión
  996.         $transactionId $session->get($transactionIdSessionName);
  997.         $sessionKey $transactionId "[park][ticketsInfo]";
  998.         $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  999.         $searchParams $infoTickets["searchParams"];
  1000.         $namePark = (string) $searchParams["park"];
  1001.         $productType mb_strtolower($namePark);
  1002.         $orderProductCode $session->get($transactionId '[' $productType '][order]');
  1003.         $productId str_replace('PN'''json_decode($orderProductCode)->products);
  1004.         $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  1005.         // Traer información de pago
  1006.         $decodedRequest json_decode($aviaturEncoder->AviaturDecode($orderProduct->getPayrequest(), $orderProduct->getPublicKey()));
  1007.         $decodedResponse json_decode($aviaturEncoder->AviaturDecode($orderProduct->getPayresponse(), $orderProduct->getPublicKey()));
  1008.         if (null != $decodedResponse) {
  1009.             $twig '';
  1010.             $jsonSendEmail $em->getRepository(\Aviatur\GeneralBundle\Entity\Parameter::class)->findOneByName('send_email');
  1011.             if (!empty($jsonSendEmail->getDescription()) && isset(json_decode($jsonSendEmail->getDescription())->email)) {
  1012.                 $email json_decode($jsonSendEmail->getDescription())->email->CallBack;
  1013.             }
  1014.             $reference str_replace('{"order":"'''$orderProductCode);
  1015.             $reference str_replace('","products":"''-'$reference);
  1016.             $reference str_replace('"}'''$reference);
  1017.             $references $reference;
  1018.             $bookings $orderProduct->getBooking();
  1019.             // Cantidad de intentos de pago:
  1020.             $aviaturPaymentRetryTimes $parameterBag->get('aviatur_payment_retry_times');
  1021.             $retryCount = (int) $session->get($transactionId "[park][retry]");
  1022.             switch ($decodedResponse->x_response_code) {
  1023.                 case 0// error p2p
  1024.                 case 4// error p2p
  1025.                     $twig 'aviatur_park_payment_error_secure';
  1026.                     if (isset($email)) {
  1027.                         $from $session->get('emailNoReply');
  1028.                         $error $twig;
  1029.                         $subject $orderProduct->getDescription() . ':Error en el proceso de pago de Aviatur';
  1030.                         $body '</br>El proceso de pago a retornado un error </br>Referencia: ' $references '</br>Reserva:' $bookings;
  1031.                         $aviaturMailer->sendEmailGeneral($from$email$subject$body);
  1032.                     }
  1033.                 case 1// aprobado p2p
  1034.                     $postData json_decode($session->get($transactionId '[park][detailDataPark]'));
  1035.                     if (isset($postData->PD->savePaymProc)) {
  1036.                         $customerLogin $tokenStorage->getToken()->getUser();
  1037.                         $customerMethodPayment->setMethodsByCustomer($customerLoginjson_decode(json_encode($postData), true) && 'NOTVERIFIED' == $postData->PD->cusPOptSelectedStatus);
  1038.                     }
  1039.                     if (isset($postData->PD->cusPOptSelected) && isset($postData->PD->cusPOptSelectedStatus)) {
  1040.                         $postData->PD->cusPOptSelectedStatus 'ACTIVE';
  1041.                         $customerLogin $tokenStorage->getToken()->getUser();
  1042.                         $customerMethodPayment->setMethodsByCustomer($customerLoginjson_decode(json_encode($postData), true));
  1043.                     }
  1044.                     // Obtener la información de los tickets desde la sesión
  1045.                     $sessionKey $transactionId "[park][ticketsInfo]";
  1046.                     $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  1047.                     $searchParams $infoTickets["searchParams"];
  1048.                     $namePark = (string) $searchParams["park"];
  1049.                     $productType mb_strtolower($namePark);
  1050.                     $decodedRequest->product_type $productType;
  1051.                     $decodedResponse->product_type $productType;
  1052.                     $encodedRequest $aviaturEncoder->AviaturEncode(json_encode($decodedRequest), $orderProduct->getPublicKey());
  1053.                     $encodedResponse $aviaturEncoder->AviaturEncode(json_encode($decodedResponse), $orderProduct->getPublicKey());
  1054.                     $orderProduct->setPayrequest($encodedRequest);
  1055.                     $orderProduct->setPayresponse($encodedResponse);
  1056.                     $twig 'aviatur_park_payment_success_secure';
  1057.                     $orderController->updatePaymentAction($orderProductfalsenull);
  1058.                     break;
  1059.                 case 2// rechazada p2p
  1060.                     $twig '' != $twig $twig 'aviatur_park_payment_rejected_secure';
  1061.                     $emissionData 'No Reservation';
  1062.                     if (isset($email)) {
  1063.                         $from $session->get('emailNoReply');
  1064.                         $error $twig;
  1065.                         $subject $orderProduct->getDescription() . ':Transacción rechazada';
  1066.                         $body '</br>El pago fue rechazado </br>Referencia: ' $references '</br>Reserva:' $bookings;
  1067.                         $aviaturMailer->sendEmailGeneral($from$email$subject$body);
  1068.                     }
  1069.                     break;
  1070.                 case 3// pendiente p2p
  1071.                     $twig '' != $twig $twig 'aviatur_park_payment_pending_secure';
  1072.                     $emissionData 'No Reservation';
  1073.                     $orderProduct->setEmissiondata(json_encode($emissionData));
  1074.                     $orderProduct->setUpdatingdate(new \DateTime());
  1075.                     $em->persist($orderProduct);
  1076.                     $em->flush();
  1077.                     $retryCount 1;
  1078.                     break;
  1079.                 case isset($decodedResponse->x_response_code_cyber) && (== $decodedResponse->x_response_code_cyber): //rechazado cybersource
  1080.                     //rechazado cybersource
  1081.                     $parameters $em->getRepository(\Aviatur\GeneralBundle\Entity\Parameter::class)->findOneByName('aviatur_switch_rechazada_cyber');
  1082.                     if ($parameters && == $parameters->getValue() && == $decodedResponse->x_response_code) {
  1083.                         $postData json_decode($session->get($transactionId '[park][detailDataPark]'));
  1084.                         if (isset($postData->PD->savePaymProc)) {
  1085.                             $customerLogin $tokenStorage->getToken()->getUser();
  1086.                             $customerMethodPayment->setMethodsByCustomer($customerLoginjson_decode(json_encode($postData), true));
  1087.                         }
  1088.                         if (isset($postData->PD->cusPOptSelected) && isset($postData->PD->cusPOptSelectedStatus) && 'NOTVERIFIED' == $postData->PD->cusPOptSelectedStatus) {
  1089.                             $postData->PD->cusPOptSelectedStatus 'ACTIVE';
  1090.                             $customerLogin $tokenStorage->getToken()->getUser();
  1091.                             $customerMethodPayment->setMethodsByCustomer($customerLoginjson_decode(json_encode($postData), true));
  1092.                         }
  1093.                     }
  1094.                     $twig 'aviatur_park_payment_rejected_secure';
  1095.             }
  1096.             // Update Payment
  1097.             $orderController->updatePaymentAction($orderProductfalsenull);
  1098.             $orderUpdatePayment str_replace(
  1099.                 ['{web_book_id}''{booking_id}'],
  1100.                 ['PN' $orderProduct->getId(), $orderProduct->getBooking()],
  1101.                 $orderProduct->getUpdatePaymentData()
  1102.             );
  1103.             $orderProduct->setUpdatePaymentData($orderUpdatePayment);
  1104.             $em->persist($orderProduct);
  1105.             $em->flush($orderProduct);
  1106.             /* Pero solo si hay condicionados (no bloqueados) y que paguen con Tarjeta */
  1107.             if ($session->has('Marked_users')) {
  1108.                 $validateSanctions->sendMarkedEmail($orderProductCode$session$this->agency$orderProduct$transactionId$productType);
  1109.             }
  1110.             $urlResume $this->generateUrl($twig);
  1111.             return $this->redirect($urlResume);
  1112.         } else {
  1113.             // No hay respuesta por parte del servicio de pago, estado pendiente
  1114.             $orderProduct->setStatus('pending');
  1115.             $em->persist($orderProduct);
  1116.             $em->flush();
  1117.             $urlResume $this->generateUrl('aviatur_park_payment_pending_secure');
  1118.             return $this->redirect($urlResume);
  1119.         }
  1120.     }
  1121.     public function paymentOutputAction(Request $request, \Swift_Mailer $maileraviaturErrorHandler $aviaturErrorHandlerAviaturEncoder $aviaturEncoderTwigFolder $twigFolderParameterBagInterface $parameterBagAviaturQrcodeService $QrcodePdf $pdf)
  1122.     {
  1123.         $em $this->em;
  1124.         $transactionIdSessionName $parameterBag->get('transaction_id_session_name');
  1125.         $session $this->session;
  1126.         $transactionId $session->get($transactionIdSessionName);
  1127.         // Información tickets
  1128.         $sessionKey $transactionId "[park][ticketsInfo]";
  1129.         $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  1130.         // Información formularios
  1131.         $postDataJson json_decode($session->get($transactionId "[park][detailDataPark]"));
  1132.         $customer $em->getRepository(\Aviatur\CustomerBundle\Entity\Customer::class)->find($postDataJson->BD->id);
  1133.         // Obtener IdOrder
  1134.         $searchParams $infoTickets["searchParams"];
  1135.         $namePark = (string) $searchParams["park"];
  1136.         $productType mb_strtolower($namePark);
  1137.         $orderProductCode $session->get($transactionId '[' $productType '][order]');
  1138.         // Obtener order_product
  1139.         $productId str_replace('PN'''json_decode($orderProductCode)->products);
  1140.         $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  1141.         $emailData json_decode($orderProduct->getEmail(), true);
  1142.         // RQ Y RS de Pago
  1143.         $opRequest json_decode($aviaturEncoder->AviaturDecode($orderProduct->getPayrequest(), $orderProduct->getPublicKey()));
  1144.         $opResponse json_decode($aviaturEncoder->AviaturDecode($orderProduct->getPayResponse(), $orderProduct->getPublicKey()));
  1145.         if ((null != $opRequest) && (null != $opResponse) && isset($opResponse->x_description)) {
  1146.             $emailData["paymentResume"] = [
  1147.                 'transaction_state' => $opResponse->x_response_code,
  1148.                 'ta_transaction_state' => $opResponse->x_ta_response_code,
  1149.                 'transaction_state_cyber' => $opResponse->x_response_code_cyber ?? '1',
  1150.                 'id' => $orderProduct->getBooking(),
  1151.                 'id_context' => $opRequest->x_invoice_num,
  1152.                 'total_amount' => $opResponse->x_amount,
  1153.                 'currency' => $opResponse->x_bank_currency,
  1154.                 'amount' => != $opRequest->x_amount_base $opRequest->x_amount_base $opResponse->x_amount,
  1155.                 'iva' => $opRequest->x_tax,
  1156.                 'ip_address' => $opRequest->x_customer_ip,
  1157.                 'bank_name' => $opResponse->x_bank_name,
  1158.                 'franquice' => $opResponse->x_franchise,
  1159.                 'cuotas' => $opRequest->x_differed,
  1160.                 'card_num' => '************' substr($opRequest->x_card_numstrlen($opRequest->x_card_num) - 4),
  1161.                 'reference' => $opResponse->x_transaction_id,
  1162.                 'auth' => $opResponse->x_approval_code,
  1163.                 'transaction_date' => $opResponse->x_transaction_date,
  1164.                 'description' => $opResponse->x_description,
  1165.                 'reason_code' => $opResponse->x_response_reason_code,
  1166.                 'reason_description' => $opResponse->x_response_reason_text,
  1167.                 'client_names' => $opResponse->x_first_name ' ' $opResponse->x_last_name,
  1168.                 'client_email' => $opResponse->x_email
  1169.             ];
  1170.         } else {
  1171.             $customer null;
  1172.             $emailData["paymentResume"]['id'] = $orderProduct->getBooking();
  1173.             $emailData["paymentResume"]['transaction_state_cyber'] = '1';
  1174.             $emailData["paymentResume"]['transaction_state'] = '2';
  1175.         }
  1176.         // Si existe reserva y pago
  1177.         if (!empty($emailData["bookingData"]) && == $emailData["paymentResume"]['transaction_state']) {
  1178.             // Información de reserva (contactPerson y idReserva)
  1179.             $bookingResume['firstName'] = $emailData["bookingData"]["contactPerson"]["firstName"];
  1180.             $bookingResume['lastName'] = $emailData["bookingData"]["contactPerson"]["lastName"];
  1181.             $bookingResume['ReservationID'] = (string) $emailData["bookingData"]["reservationIds"]["productResId"];
  1182.             $bookingResume['ParkReservationID'] = "";
  1183.             // Información del facturador
  1184.             $emailData["facturationResume"] = [
  1185.                 'customer_names' => $customer->getFirstname() . ' ' $customer->getLastname(),
  1186.                 'customer_doc_num' => $customer->getDocumentnumber(),
  1187.                 'customer_phone' => $customer->getPhone(),
  1188.                 'customer_email' => $customer->getEmail(),
  1189.             ];
  1190.             // Pasajero 1 igual al facturador
  1191.             if (false !== strpos($emailData["passangers"][1]["first_name"], '***')) {
  1192.                 // Actualizando información pasajeros
  1193.                 $emailData["passangers"][1] = [
  1194.                     "first_name" => $customer->getFirstname(),
  1195.                     "last_name" => $customer->getLastname(),
  1196.                     "passanger_type" => $emailData["passangers"][1]["passanger_type"]
  1197.                 ];
  1198.                 // Actualizando información de reserva
  1199.                 $bookingResume['firstName'] = $customer->getFirstname();
  1200.                 $bookingResume['lastName'] = $customer->getLastname();
  1201.             }
  1202.         }
  1203.         $emailData += [
  1204.             'currency' => isset($emailData["paymentResume"]['currency']) ? $emailData["paymentResume"]['currency'] : '',
  1205.             'bookingResume' => $bookingResume ?? [],
  1206.         ];
  1207.         //validacion de parametros vacios usando en twig
  1208.         $emailData["paymentResume"]["reason_description"] = isset($emailData["paymentResume"]["reason_description"]) ? $emailData["paymentResume"]["reason_description"] : "";
  1209.         $emailData["paymentResume"]["auth"] = isset($emailData["paymentResume"]["auth"]) ? $emailData["paymentResume"]["auth"] : "";
  1210.         $emailData["paymentResume"]["reason_code"] = isset($emailData["paymentResume"]["reason_code"]) ? $emailData["paymentResume"]["reason_code"] : "";
  1211.         $emailData["paymentResume"]["reference"] = isset($emailData["paymentResume"]["reference"]) ? $emailData["paymentResume"]["reference"] : "";
  1212.         $emailData["paymentResume"]["total_amount"] = isset($emailData["paymentResume"]["total_amount"]) ? $emailData["paymentResume"]["total_amount"] : "";
  1213.         $emailData["paymentResume"]["currency"] = isset($emailData["paymentResume"]["currency"]) ? $emailData["paymentResume"]["currency"] : "";
  1214.         $orderProduct->setEmail(json_encode($emailData));
  1215.         $em->persist($orderProduct);
  1216.         $em->flush();
  1217.         //Envio de correo
  1218.         $orderInfo json_decode($orderProductCode);
  1219.         if($orderProduct->getStatus() == 'approved'){
  1220.             $ordersIdsString $orderInfo->order '-' $orderInfo->products;
  1221.             $sendEmailParkService $this->sendVoucherEmailParkService->sendEmailParkService($ordersIdsString);
  1222.             if($sendEmailParkService["error"]){
  1223.                 //Enviar correo en fallo de envio de voucher
  1224.                 $emailContent '
  1225.                     <b>No se pudo realizar el envio del voucher.</b><br/>
  1226.                     Info:<br/>
  1227.                     The booking id is: ' $orderProduct->getBooking() . '<br/>
  1228.                     The product id is: ' $orderProduct->getId() . '<br/>
  1229.                     The reference id is: ' $ordersIdsString '<br/>
  1230.                     The customer id is: ' $customer->getId() . '<br/></b>
  1231.                     Email customer DB: <b>' $customer->getEmail() . '</b>,<br/>
  1232.                     The message is: ' $sendEmailParkService["message"]["title"] . " - " $sendEmailParkService["message"]["text"]
  1233.                 ;
  1234.                 $message = (new \Swift_Message())
  1235.                     ->setContentType('text/html')
  1236.                     ->setFrom('noreply@aviatur.com.co')
  1237.                     ->setSubject('Park reservation approved with payment - Voucher NOT attached')
  1238.                     ->setTo(['soptepagelectronic@aviatur.com''soportepagoelectronico@aviatur.com.co'])
  1239.                     ->setBcc(['notificacionessitioweb@aviatur.com'])
  1240.                     ->setBody($emailContent)
  1241.                 ;
  1242.                 $mailer->send($message);
  1243.             }
  1244.         } else {
  1245.             //Enviar correo de reserva exitosa, pago no exitoso
  1246.             $emailContent '
  1247.                 <b>Se realizó la reserva del parque, pero no tiene pago aprobado.</b><br/>
  1248.                 Info:<br/>
  1249.                 The booking id is: ' $orderProduct->getBooking() . '<br/>
  1250.                 The product id is: ' $orderProduct->getId() . '<br/>
  1251.                 The customer id is: ' $customer->getId() . '<br/></b>
  1252.                 Email customer DB: <b>' $customer->getEmail() . '</b>,<br/>
  1253.                 The info is: ' $orderProduct->getEmail()
  1254.             ;
  1255.             $message = (new \Swift_Message())
  1256.                 ->setContentType('text/html')
  1257.                 ->setFrom('noreply@aviatur.com.co')
  1258.                 ->setSubject('Park reservation aprroved with payment ' $orderProduct->getStatus())
  1259.                 ->setTo(['soptepagelectronic@aviatur.com''soportepagoelectronico@aviatur.com.co'])
  1260.                 ->setBcc(['notificacionessitioweb@aviatur.com'])
  1261.                 ->setBody($emailContent)
  1262.             ;
  1263.             $mailer->send($message);
  1264.         }
  1265.     
  1266.         // En caso de que exista pago y sea aprobado, limpiar session con el transaction
  1267.         if (isset($emailData["paymentResume"]['transaction_state']) && == $emailData["paymentResume"]['transaction_state']) {
  1268.             $session->remove($transactionId '[park][retry]');
  1269.             $session->remove($transactionId '[park][prepayment_check]');
  1270.             $session->remove($transactionId '[park][ticketsAvailability]');
  1271.             $session->remove($transactionId '[park][userInfo]');
  1272.             $session->remove($transactionId '[park][detailDataPark]');
  1273.             $session->remove($transactionId '[' $productType '][provider]');
  1274.             // $session->remove($transactionId . '[' . $productType . '][order]');
  1275.         
  1276.             // Eliminar los archivos de códigos QR's generados
  1277.             if (isset($sendEmailParkService["qrcodespath"]) && is_array($sendEmailParkService["qrcodespath"])) {
  1278.                 foreach ($sendEmailParkService["qrcodespath"] as $path) {
  1279.                     if (file_exists($path)) {
  1280.                         unlink($path);
  1281.                     }
  1282.                 }
  1283.             }
  1284.         }
  1285.         $urlResume $this->generateUrl('thank_you_page_park_secure');
  1286.         return $this->redirect($urlResume);
  1287.     }
  1288.     // vista de gracias por tu compra
  1289.     public function thankYouPageAction(TwigFolder $twigFolderParameterBagInterface $parameterBagAviaturErrorHandler $aviaturErrorHandler
  1290.     {
  1291.         $em $this->em;
  1292.         $session $this->session;
  1293.         $transactionIdSessionName $parameterBag->get('transaction_id_session_name');
  1294.         $transactionId $session->get($transactionIdSessionName);
  1295.         // Información tickets
  1296.         $sessionKey $transactionId "[park][ticketsInfo]";
  1297.         $infoTickets $this->getAvailabilityFromSession($sessionKey$aviaturErrorHandler);
  1298.         // Obtener IdOrder
  1299.         $searchParams $infoTickets["searchParams"];
  1300.         $namePark = (string) $searchParams["park"];
  1301.         $productType mb_strtolower($namePark);
  1302.         $orderProductCode $session->get($transactionId '[' $productType '][order]');
  1303.         // Obtener order_product
  1304.         $productId str_replace('PN'''json_decode($orderProductCode)->products);
  1305.         $orderProduct $em->getRepository(\Aviatur\GeneralBundle\Entity\OrderProduct::class)->find($productId);
  1306.         $emailData json_decode($orderProduct->getEmail(), true);
  1307.         $agencyFolder $twigFolder->twigFlux();
  1308.         
  1309.         $viewParams $this->sendVoucherEmailParkService->formatTransactionData($productId);
  1310.         $viewParams json_decode($viewParamstrue);
  1311.         $orderProduct->setResume(json_encode($viewParams));
  1312.         $em->persist($orderProduct);
  1313.         $em->flush();
  1314.         
  1315.         $view "@AviaturTwig/{$agencyFolder}/Park/Default/paymentStatus.html.twig";
  1316.         return $this->render($view$viewParams);
  1317.     }
  1318. }