src/Service/Pyton.php line 1182

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Entity\Game;
  4. use App\Model\AccomodationRecipe;
  5. use App\Model\AirportRecipe;
  6. use App\Model\Basket as BasketModel;
  7. use App\Model\Pyton\Accommodation\AccommodationWrapper;
  8. use App\Model\Pyton\Accommodation\Results;
  9. use App\Model\Pyton\AccommodationReceipt;
  10. use App\Model\Pyton\Basket as PytonBasket;
  11. use App\Model\Pyton\Flight\Results as FlightResults;
  12. use App\Model\Pyton\FlightReceipt;
  13. use DateInterval;
  14. use DateTime;
  15. use Exception;
  16. use GuzzleHttp\Client;
  17. use GuzzleHttp\Exception\BadResponseException;
  18. use GuzzleHttp\Exception\ClientException;
  19. use GuzzleHttp\Exception\GuzzleException;
  20. use GuzzleHttp\Exception\RequestException;
  21. use InvalidArgumentException;
  22. use JMS\Serializer\Serializer;
  23. use Money\Currency;
  24. use Money\Money;
  25. use Psr\Http\Message\ResponseInterface;
  26. use Psr\Log\LoggerInterface;
  27. use Psr\Log\LogLevel;
  28. use Ramsey\Uuid\Uuid;
  29. use Symfony\Component\Console\Output\OutputInterface;
  30. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  31. use Symfony\Component\Intl\Countries;
  32. class Pyton
  33. {
  34.     public const FLIGHTS_RECEIPT '/api/flights/receipt/create';
  35.     public const FLIGHTS_SEARCH_FLIGHTS_ENDPOINT '/api/flights/search';
  36.     public const BASICDATA_AIRPORTS_ENDPOINT '/api/basicdata/airports';
  37.     public const FLIGHTS_SEARCH_DESTINATIONS_ENDPOINT '/api/flights/search/destinations';
  38.     public const FLIGHTS_SEARCH_DESTINATION_ENDPOINT '/api/flights/search/destination';
  39.     public const ACCOMMODATIONS_SEARCH_DESTINATIONS_ENDPOINT '/api/accommodations/search/destinations';
  40.     public const ACCOMMODATIONS_SEARCH_ENDPOINT '/api/accommodations/search';
  41.     public const BASKET_CREATE_ENDPOINT '/api/basket/create';
  42.     public const BASKET_BOOK_ENDPOINT '/api/basket/book/%s';
  43.     public const BASKET_CREATE_BASKET_RECEIPT_ENDPOINT '/api/basket/receipt/%s';
  44.     public const BASKET_PASSENGERS_ENDPOINT '/api/basket/passengers/%s';
  45.     public const ACCOMMODATIONS_RECEIPT_ENDPOINT '/api/accommodations/receipt/create';
  46.     public const ACCOMMODATIONS_DETAIL_ENDPOINT '/api/accommodations/details';
  47.     public const FLIGHTS_DETAIL_ENDPOINT '/api/flights/details';
  48.     public const ACTIONCODE_AVAILABLE_ENDPOINT '/api/actioncodes/available/%s';
  49.     public const ACTIONCODE_CHECK_ENDPOINT '/api/actioncodes/check/%s/%s';
  50.     public const MATCH_ARRIVAL_MIN_INTERVAL '-6 hour';
  51.     /**
  52.      * The response trigger from Pyton if a basket has already been booked.
  53.      */
  54.     public const RESPONSE_MESSAGE_ALREADY_BOOKED 'This basket is already booked!';
  55.     protected $ignoreFinalCountries = [
  56.         'duitsland',
  57.     ];
  58.     /**
  59.      * @var Client
  60.      */
  61.     protected $client;
  62.     /**
  63.      * @var Serializer
  64.      */
  65.     protected $serializer;
  66.     /**
  67.      * @var LoggerInterface
  68.      */
  69.     private $logger;
  70.     /**
  71.      * @var \App\Service\PytonScanjobLogger
  72.      */
  73.     private $scanjobLogger;
  74.     /**
  75.      * @var SessionInterface
  76.      */
  77.     private $session;
  78.     /**
  79.      * @var array
  80.      */
  81.     private $flightPlaces = [];
  82.     /**
  83.      * Pyton constructor.
  84.      */
  85.     public function __construct(
  86.         Client $client,
  87.         Serializer $serializer,
  88.         LoggerInterface $logger,
  89.         PytonScanjobLogger $scanjobLogger,
  90.         SessionInterface $session,
  91.     ) {
  92.         $this->client $client;
  93.         $this->serializer $serializer;
  94.         $this->logger $logger;
  95.         $this->scanjobLogger $scanjobLogger;
  96.         $this->session $session;
  97.     }
  98.     /**
  99.      * @throws Exception
  100.      */
  101.     public function book(BasketModel $basket): bool
  102.     {
  103.         if (!$basket->getPytonBasket() instanceof PytonBasket) {
  104.             return false;
  105.         }
  106.         $basketId $basket->getPytonBasket()->getBasketId();
  107.         //remove all known elementIDs?
  108.         $this->createBasketReceipt($basket$basket->getPytonBasket()->getAccommodationReceipt());
  109.         if (\is_string($basket->getPytonBasket()->getFlightReceipt())) {
  110.             $this->createBasketReceipt($basket$basket->getPytonBasket()->getFlightReceipt());
  111.         }
  112.         try {
  113.             $this->logger->log(LogLevel::INFO'PYTON: '.sprintf(self::BASKET_BOOK_ENDPOINT$basketId));
  114.             $response $this->client->post(sprintf(self::BASKET_BOOK_ENDPOINT$basketId), [
  115.                 'headers' => [
  116.                     'Session' => $this->session->getId(),
  117.                 ],
  118.             ]);
  119. //            $this->log('post', self::BASKET_BOOK_ENDPOINT, $basketId, $response);
  120.         } catch (BadResponseException $exception) {
  121. //            $this->log('post', self::BASKET_BOOK_ENDPOINT, $basketId, $exception);
  122.             if ($this->isAlreadyBooked($exception->getResponse())) {
  123.                 $this->logger->log(
  124.                     LogLevel::CRITICAL,
  125.                     sprintf(
  126.                         'Error trigger when sending request to endpoint `%s`. Basket is already booked. Got response `%s`',
  127.                         sprintf(self::BASKET_BOOK_ENDPOINT$basketId),
  128.                         $exception->getResponse()->getBody()->getContents()
  129.                     )
  130.                 );
  131.                 return true;
  132.             }
  133.             $this->logger->log(
  134.                 LogLevel::CRITICAL,
  135.                 sprintf(
  136.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  137.                     sprintf(self::BASKET_BOOK_ENDPOINT$basketId),
  138.                     $exception->getResponse()->getBody()->getContents()
  139.                 )
  140.             );
  141.             return false;
  142.         }
  143.         return true;
  144.     }
  145.     private function isAlreadyBooked(ResponseInterface $response): bool
  146.     {
  147.         $result json_decode($response->getBody()->getContents(), true);
  148.         if (
  149.             \is_array($result)
  150.             && !\array_key_exists('MessageDetail'$result)
  151.             && self::RESPONSE_MESSAGE_ALREADY_BOOKED === $result['MessageDetail']
  152.         ) {
  153.             return true;
  154.         }
  155.         return false;
  156.     }
  157.     private function createBasketReceipt(BasketModel $basketstring $receipt): bool
  158.     {
  159.         if (!$basket->getPytonBasket() instanceof PytonBasket) {
  160.             throw new \UnexpectedValueException('$pytonBasket of Basket is not defined');
  161.         }
  162.         $basketId $basket->getPytonBasket()->getBasketId();
  163.         if(count($basket->getPytonBasket()->getElementIds()) > 0){
  164.            $receipt json_decode($receiptTRUE);
  165.            foreach ($basket->getPytonBasket()->getElementIds() AS $elementId){
  166.                $receipt['ElementId'] = $elementId;
  167.            }
  168.            $receipt json_encode($receipt);
  169.         }
  170.         try {
  171.             $this->logger->log(LogLevel::CRITICAL'PYTON: '.sprintf(self::BASKET_CREATE_BASKET_RECEIPT_ENDPOINT$basketId));
  172.             $response $this->client->put(sprintf(self::BASKET_CREATE_BASKET_RECEIPT_ENDPOINT$basketId), [
  173.                 'headers' => [
  174.                     'Session' => $this->session->getId(),
  175.                     'CorrelationId' => Uuid::uuid4()->toString(),
  176.                 ],
  177.                 'body' => $receipt,
  178.             ]);
  179.         } catch (BadResponseException $exception) {
  180.             $this->logger->log(
  181.                 LogLevel::CRITICAL,
  182.                 sprintf(
  183.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  184.                     sprintf(self::BASKET_CREATE_BASKET_RECEIPT_ENDPOINT$basketId),
  185.                     $exception->getResponse()->getBody()->getContents()
  186.                 )
  187.             );
  188.             return false;
  189.         }
  190.         $result json_decode($response->getBody()->getContents(), true);
  191.         if (!\is_array($result) || !$this->isValidBasketReceiptResponse($result)) {
  192.             return false;
  193.         }
  194.         $basket->getPytonBasket()->addElementId($result['BasketActionResult']['ElementId']);
  195. //        dump($result);
  196.         return true;
  197.     }
  198.     private function isValidBasketReceiptResponse(array $result): bool
  199.     {
  200.         return !empty($result['BasketActionResult']['ElementId']) &&
  201.             !empty($result['BasketActionResult']['StatusId']) &&
  202.             'OK' === $result['BasketActionResult']['StatusId'];
  203.     }
  204.     public function createBasket(): string
  205.     {
  206.         try {
  207.             $this->logger->log(LogLevel::INFO'PYTON: 'self::BASKET_CREATE_ENDPOINT.' session:'.$this->session->getId());
  208.             $response $this->client->post(self::BASKET_CREATE_ENDPOINT, [
  209.                 'headers' => [
  210.                     'Session' => $this->session->getId(),
  211.                 ],
  212.             ]);
  213.             return $response->getBody()->getContents();
  214.         } catch (RequestException $exception) {
  215.             $this->logger->log(
  216.                 LogLevel::CRITICAL,
  217.                 sprintf(
  218.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  219.                     self::BASKET_CREATE_ENDPOINT,
  220.                     $exception->getResponse()?->getBody()->getContents()
  221.                 )
  222.             );
  223.             throw $exception;
  224.         }
  225.     }
  226.     private function getGenderNameFromText(string $text): string
  227.     {
  228.         $gender 'Male';
  229.         if ('male' !== $text) {
  230.             $gender 'Female';
  231.         }
  232.         return $gender;
  233.     }
  234.     public function updatePassengers(BasketModel $basket): string
  235.     {
  236.         if (!$basket->getPytonBasket() instanceof PytonBasket) {
  237.             throw new \UnexpectedValueException();
  238.         }
  239.         $basketId $basket->getPytonBasket()->getBasketId();
  240.         $travelersData $basket->getTravelersData();
  241.         if (!\is_array($travelersData) || !\array_key_exists('mainBooker'$travelersData)) {
  242.             throw new \InvalidArgumentException('Travelersdata of basket does not have mainBooker index');
  243.         }
  244.         $countryCode '0031';
  245.         switch ($travelersData['mainBooker']['country']){
  246.             case 'NL'$countryCode '0031';
  247.             case 'BE'$countryCode '0032';
  248.         }
  249.         $body = [
  250.             'Contact' => [
  251.                 'Gender' => $this->getGenderNameFromText($travelersData['mainBooker']['gender']),
  252.                 'Initials' => $travelersData['mainBooker']['firstNames'],
  253.                 'FirstName' => $travelersData['mainBooker']['firstNames'],
  254.                 'Infix' => '',
  255.                 'LastName' => $travelersData['mainBooker']['lastName'],
  256.                 'Street' => $travelersData['mainBooker']['address'],
  257.                 'HouseNumber' => $travelersData['mainBooker']['houseNumber'],
  258.                 'PostalCode' => $travelersData['mainBooker']['zipcode'],
  259.                 'City' => $travelersData['mainBooker']['city'],
  260.                 'CountryISOCode' => $travelersData['mainBooker']['country'],
  261.                 'Home' => [
  262.                     'CountryCode' => $countryCode,
  263.                     'AreaNumber' => mb_substr($travelersData['mainBooker']['mobile'], 02),
  264.                     'ClientNumber' => mb_substr($travelersData['mainBooker']['mobile'], 2),
  265.                 ],
  266.                 'Mobile' => [
  267.                     'CountryCode' => $countryCode,
  268.                     'AreaNumber' => mb_substr($travelersData['mainBooker']['mobile'], 02),
  269.                     'ClientNumber' => mb_substr($travelersData['mainBooker']['mobile'], 2),
  270.                 ],
  271.                 'Email' => $travelersData['mainBooker']['email'],
  272.                 'ExtraItems' => [],
  273.             ],
  274.             'EmergencyContact' => [
  275.                 'FullName' => sprintf(
  276.                     '%s %s',
  277.                     $travelersData['mainBooker']['firstNames'],
  278.                     $travelersData['mainBooker']['lastName']
  279.                 ),
  280.                 'Home' => [
  281.                     'CountryCode' => mb_substr($travelersData['mainBooker']['mobile'], 01),
  282.                     'AreaNumber' => mb_substr($travelersData['mainBooker']['mobile'], 11),
  283.                     'ClientNumber' => mb_substr($travelersData['mainBooker']['mobile'], 2),
  284.                 ],
  285.                 'Mobile' => [
  286.                     'CountryCode' => mb_substr($travelersData['mainBooker']['mobile'], 01),
  287.                     'AreaNumber' => mb_substr($travelersData['mainBooker']['mobile'], 11),
  288.                     'ClientNumber' => mb_substr($travelersData['mainBooker']['mobile'], 2),
  289.                 ],
  290.                 'ExtraItems' => [],
  291.             ],
  292.             'Travellers' => [],
  293.         ];
  294.         $count 1;
  295.         foreach ($travelersData['persons'] ?? [] as $person) {
  296.             /** @var DateTime $dob */
  297.             $dob $person['dob'];
  298.             $body['Travellers'][] = [
  299.                 'Id' => $count++,
  300.                 'Gender' => $this->getGenderNameFromText($person['gender']),
  301.                 'Initials' => $person['firstNames'],
  302.                 'FirstName' => $person['firstNames'],
  303.                 'Infix' => '',
  304.                 'LastName' => $person['lastName'],
  305.                 'DateOfBirth' => $dob->format('Y-m-d'),
  306.                 'Nationality' => [
  307.                     'Id' => '0031',
  308.                     'Code' => $person['country'],
  309.                     'Name' => Countries::getName($person['country']),
  310.                 ],
  311.                 'ExtraItems' => [],
  312.             ];
  313.         }
  314.         try {
  315.             $this->logger->log(LogLevel::INFO'PYTON: 'sprintf(self::BASKET_PASSENGERS_ENDPOINT$basketId));
  316.             $response $this->client->put(sprintf(self::BASKET_PASSENGERS_ENDPOINT$basketId), [
  317.                 'headers' => [
  318.                     'Session' => $this->session->getId(),
  319.                 ],
  320.                 'body' => json_encode($body),
  321.             ]);
  322. //            $this->log('put', self::BASKET_PASSENGERS_ENDPOINT, $basketId, $response);
  323.         } catch (BadResponseException $exception) {
  324. //            $this->log('put', self::BASKET_PASSENGERS_ENDPOINT, $basketId, $exception);
  325.             $this->logger->log(
  326.                 LogLevel::CRITICAL,
  327.                 sprintf(
  328.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  329.                     sprintf(self::BASKET_PASSENGERS_ENDPOINT$basketId),
  330.                     $exception->getResponse()->getBody()->getContents()
  331.                 )
  332.             );
  333.         }
  334.         return $response->getBody()->getContents();
  335.     }
  336.     /**
  337.      * @param $search
  338.      *
  339.      * @throws Exception
  340.      *
  341.      * @return string
  342.      */
  343.     public function getPlaces($search)
  344.     {
  345.         $body = [
  346.             'Destination' => $search,
  347.         ];
  348.         try {
  349.             $this->logger->log(LogLevel::INFO'PYTON: 'self::ACCOMMODATIONS_SEARCH_DESTINATIONS_ENDPOINT.' session: '.$this->session->getId());
  350.             $response $this->client->post(self::ACCOMMODATIONS_SEARCH_DESTINATIONS_ENDPOINT, [
  351.                 'headers' => [
  352.                     'Session' => $this->session->getId(),
  353.                     'CorrelationId' => Uuid::uuid4()->toString(),
  354.                 ],
  355.                 'body' => json_encode($body),
  356.             ]);
  357.             return $response->getBody()->getContents();
  358.         } catch (BadResponseException $exception) {
  359.             $this->logger->log(
  360.                 LogLevel::CRITICAL,
  361.                 sprintf(
  362.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  363.                     self::ACCOMMODATIONS_SEARCH_DESTINATIONS_ENDPOINT,
  364.                     $exception->getResponse()->getBody()->getContents()
  365.                 )
  366.             );
  367.             throw $exception;
  368.         }
  369.     }
  370.     public function getLowestPriceForMatch(
  371.         Game $match,
  372.         AccomodationRecipe $recipe,
  373.         OutputInterface $output null,
  374.     ) {
  375.         $pageNumber 1;
  376.         $availableAccommodations $this->getAccommodations($match$recipe$pageNumber);
  377.         $maxNumberOfPages 0;
  378.         if ($availableAccommodations->getPaging()) {
  379.             $maxNumberOfPages $availableAccommodations->getPaging()
  380.                 ->getTotalNumberOfPages();
  381.         }
  382.         $availableAccommodations array_filter(
  383.             $availableAccommodations->getAccommodations() ?? [],
  384.             function (AccommodationWrapper $accommodationWrapper) {
  385.                 return $accommodationWrapper->getAccommodation()->getNumberOfStars() > 3;
  386.             }
  387.         );
  388.         if (\count($availableAccommodations) > 0) {
  389.             return reset($availableAccommodations);
  390.         }
  391.         if ($output) {
  392.             $output->writeln('No 3 star accommodations on this page');
  393.         }
  394.         while (=== \count($availableAccommodations) && $pageNumber $maxNumberOfPages) {
  395.             ++$pageNumber;
  396.             if ($output) {
  397.                 $output->writeln('Searching through page '.$pageNumber);
  398.             }
  399.             $availableAccommodations $this->getAccommodations($match$recipe$pageNumber);
  400.             $availableAccommodations array_filter(
  401.                 $availableAccommodations->getAccommodations() ?? [],
  402.                 function (AccommodationWrapper $accommodationWrapper) {
  403.                     return $accommodationWrapper->getAccommodation()->getNumberOfStars() >= 3;
  404.                 }
  405.             );
  406.         }
  407.         return reset($availableAccommodations);
  408.     }
  409.     /**
  410.      * @throws Exception
  411.      */
  412.     public function getFlights(
  413.         Game $match,
  414.         AirportRecipe $recipe,
  415.         array $departures,
  416.         int $arrivalAirportId 0,
  417.     ): FlightResults {
  418.         $arrivals = [$arrivalAirportId];
  419.         if (=== $arrivalAirportId) {
  420.             $result json_decode((string) $this->getFlightPlaces($match->getStadium()->getPlace()), true);
  421.             if (!\is_array($result) || === \count($result['Locations'])) {
  422.                 throw new Exception('No place found');
  423.             }
  424.             $arrivalAirports $result['Locations'] ?? [];
  425.             if (empty($arrivalAirports)) {
  426.                 return new FlightResults();
  427.             }
  428.             $arrivals array_map(function ($location) {
  429.                 return $location['AirportLocation']['Id'];
  430.             }, $arrivalAirports);
  431.         }
  432.         $flightOptions = [];
  433.         foreach ($departures as $departure) {
  434.             foreach ($arrivals as $arrival) {
  435.                 $flightOptions[] = [$departure$arrival];
  436.             }
  437.         }
  438.         $flightResults null;
  439.         foreach ($flightOptions as $flightOption) {
  440.             $flights $this->getFlightsForDepartsAndArrivals(
  441.                 $flightOption[0],
  442.                 $flightOption[1],
  443.                 $recipe->getDepartDate(),
  444.                 $recipe->getReturnDate()
  445.             );
  446.             if (empty($flights)) {
  447.                 continue;
  448.             }
  449.             if (!$flightResults) {
  450.                 $flightResults $this->transformFlights($match$flights);
  451.                 continue;
  452.             }
  453.             $flightResults $flightResults->merge($this->transformFlights($match$flights));
  454.         }
  455.         return null !== $flightResults $flightResults : new FlightResults();
  456.     }
  457.     /**
  458.      * @param int $pageNumber
  459.      * @param int $pageSize
  460.      */
  461.     public function getAccommodations(
  462.         Game $match,
  463.         AccomodationRecipe $recipe,
  464.         $pageNumber 1,
  465.         $pageSize 10,
  466.         ?BasketModel $basket null,
  467.     ): Results {
  468.         if ($pageSize 10) {
  469.             throw new InvalidArgumentException('PageSize has a limit of 10');
  470.         }
  471.         $travellersInRooms = [];
  472.         if ($basket) {
  473.             $rooms $basket->getRooms();
  474.             $persons range(1, (int) $basket->getChildren() + (int) $basket->getAdults());
  475.             foreach ($persons as $index => $person) {
  476.                 $travellersInRooms[$index $rooms]['PaxIds'][] = $person;
  477.             }
  478.         }
  479.         $body = [
  480.             'Travellers' => [],
  481.             'Filters' => [
  482.                 'Destination' => [
  483.                     'Type' => 'Place',
  484.                     'Id' => (string) $match->getStadium()->getPlaceId(),
  485.                 ],
  486.                 'ArriveDate' => $recipe->getStartDate()->format('Y-m-d'),
  487.                 'DepartDate' => $recipe->getEndDate()->format('Y-m-d'),
  488.             ],
  489.             'Paging' => [
  490.                 'PageNumber' => $pageNumber,
  491.                 'PageSize' => $pageSize,
  492.             ],
  493.             'TravellersInRooms' => $travellersInRooms,
  494.         ];
  495.         /* @var DateTime $dateOfBirth */
  496.         foreach (range(1$basket->getAdults()) as $person) {
  497.             $body['Travellers'][] = ['DateOfBirth' => '1986-08-03'];
  498.         }
  499.         $childrenDob = new DateTime();
  500.         $childrenDob->modify('- 16 year');
  501.         if ($basket->getChildren()) {
  502.             foreach (range(1$basket->getChildren()) as $person) {
  503.                 $body['Travellers'][] = ['DateOfBirth' => $childrenDob->format('Y-m-d')];
  504.             }
  505.         }
  506.         try {
  507.             $request json_encode($body);
  508.             $this->logger->log(LogLevel::INFO'PYTON: '.self::ACCOMMODATIONS_SEARCH_ENDPOINT.' session:'.$this->session->getId() );
  509.             $response $this->client->post(self::ACCOMMODATIONS_SEARCH_ENDPOINT, [
  510.                 'headers' => [
  511.                     'Session' => $this->session->getId(),
  512.                 ],
  513.                 'body' => $request,
  514.             ]);
  515.         } catch (BadResponseException $exception) {
  516.             $this->log('post'self::ACCOMMODATIONS_SEARCH_ENDPOINTnull$exception$request);
  517.             $this->logger->log(
  518.                 LogLevel::CRITICAL,
  519.                 sprintf(
  520.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  521.                     self::ACCOMMODATIONS_SEARCH_ENDPOINT,
  522.                     $exception->getResponse()->getBody()->getContents()
  523.                 )
  524.             );
  525.         }
  526.         $results $this->serializer->deserialize($response->getBody()->getContents(), Results::class, 'json');
  527.         return $results;
  528.     }
  529.     /**
  530.      * @param bool $bubbleExceptions
  531.      */
  532.     public function getVirtualAccommodationsByMatch(
  533.         Game $match,
  534.         int $travellers 1,
  535.         int $durationInDays 1,
  536.         int $pageNumber 1,
  537.         $bubbleExceptions false,
  538.     ): Results {
  539.         $matchDate = clone $match->getDate();
  540.         $arriveDate $matchDate->format('Y-m-d');
  541.         $departDate $matchDate->add(new DateInterval('P'.$durationInDays.'D'))->format('Y-m-d');
  542.         $body = [
  543.             'Travellers' => [],
  544.             'Filters' => [
  545.                 'Destination' => [
  546.                     'Type' => 'Place',
  547.                     'Id' => (string) $match->getStadium()->getPlaceId(),
  548.                 ],
  549.                 'ArriveDate' => $arriveDate,
  550.                 'DepartDate' => $departDate,
  551.             ],
  552.             'Paging' => [
  553.                 'PageNumber' => $pageNumber,
  554.                 'PageSize' => 1000,
  555.             ],
  556.             'TravellersInRooms' => [
  557.                 ['PaxIds' => range(1$travellers)],
  558.             ],
  559.         ];
  560.         foreach (range(1$travellers) as $traveler) {
  561.             $body['Travellers'][] = ['DateOfBirth' => '1970-01-01'];
  562.         }
  563.         $request json_encode($body);
  564.         $this->scanjobLogger->insert(
  565.             self::ACCOMMODATIONS_SEARCH_ENDPOINT,
  566.             $this->session->getId(),
  567.             new \DateTime(),
  568.             $request,
  569.             ''
  570.         );
  571.         try {
  572.             $this->logger->log(LogLevel::INFO'PYTON: 'self::ACCOMMODATIONS_SEARCH_ENDPOINT.' session:'.$this->session->getId());
  573.             $response $this->client->post(self::ACCOMMODATIONS_SEARCH_ENDPOINT, [
  574.                 'headers' => [
  575.                     'Session' => $this->session->getId(),
  576.                 ],
  577.                 'body' => $request,
  578.             ]);
  579.         } catch (BadResponseException $exception) {
  580.             $this->scanjobLogger->insert(
  581.                 $exception->getRequest()->getUri()->getPath(),
  582.                 $this->session->getId(),
  583.                 new \DateTime(),
  584.                 $request,
  585.                 $exception->getResponse()->getBody()->getContents()
  586.             );
  587.             if (true === $bubbleExceptions) {
  588.                 throw $exception;
  589.             }
  590.             $this->log('post'self::ACCOMMODATIONS_SEARCH_ENDPOINTnull$exception$request);
  591.             $this->logger->log(
  592.                 LogLevel::CRITICAL,
  593.                 sprintf(
  594.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  595.                     self::ACCOMMODATIONS_SEARCH_ENDPOINT,
  596.                     $exception->getResponse()->getBody()->getContents()
  597.                 )
  598.             );
  599.         }
  600.         $results $this->serializer->deserialize($response->getBody()->getContents(), Results::class, 'json');
  601.         return $results;
  602.     }
  603.     public function getVirtualAccommodationDetailbyMatch(
  604.         Game $match,
  605.         int $travellers,
  606.         int $durationInDays,
  607.         AccommodationWrapper $accommodation,
  608.     ): string {
  609.         $matchDate = clone $match->getDate();
  610.         $arriveDate $matchDate->format('Y-m-d');
  611.         $departDate $matchDate->add(new DateInterval('P'.$durationInDays.'D'))->format('Y-m-d');
  612.         $body = [
  613.             'Travellers' => [],
  614.             'TravellersInRooms' => [
  615.                 ['PaxIds' => range(1$travellers)],
  616.             ],
  617.         ];
  618.         foreach (range(1$travellers) as $traveler) {
  619.             $body['Travellers'][] = ['DateOfBirth' => '1970-01-01'];
  620.         }
  621.         $body['SelectedAccommodations'][] = $accommodation;
  622.         $request $this->serializer->serialize($body'json');
  623.         $this->scanjobLogger->insert(
  624.             self::ACCOMMODATIONS_DETAIL_ENDPOINT,
  625.             $this->session->getId(),
  626.             new \DateTime(),
  627.             $request,
  628.             ''
  629.         );
  630.         try {
  631.             $this->logger->log(LogLevel::INFO'PYTON: 'self::ACCOMMODATIONS_DETAIL_ENDPOINT.' session: '.$this->session->getId());
  632.             $response $this->client->post(self::ACCOMMODATIONS_DETAIL_ENDPOINT, [
  633.                 'headers' => [
  634.                     'Session' => $this->session->getId(),
  635.                 ],
  636.                 'body' => $request,
  637.             ]);
  638.         } catch (BadResponseException $exception) {
  639.             $this->scanjobLogger->insert(
  640.                 $exception->getRequest()->getUri()->getPath(),
  641.                 $this->session->getId(),
  642.                 new \DateTime(),
  643.                 $request,
  644.                 $exception->getResponse()->getBody()->getContents()
  645.             );
  646.             // NOTE: Do Not Throw Exception when this fails. Just return string nok
  647.             // throw $exception;
  648.             $this->log('post'self::ACCOMMODATIONS_DETAIL_ENDPOINTnull$exception$request);
  649.             $this->logger->log(
  650.                 LogLevel::CRITICAL,
  651.                 sprintf(
  652.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  653.                     self::ACCOMMODATIONS_DETAIL_ENDPOINT,
  654.                     $exception->getResponse()->getBody()->getContents()
  655.                 )
  656.             );
  657.             return 'nok';
  658.         }
  659.         $results $response->getBody()->getContents();
  660.         return $results;
  661.     }
  662.     public function createAccommodationReceipt(BasketModel $basketAccommodationReceipt $receiptGame $match$selectedRooms null$roomlayout null): bool
  663.     {
  664.         if ($selectedAccommodationDetails $this->getAccommodationDetails($basket$receipt$roomlayout)) {
  665.             $accommodation json_decode($selectedAccommodationDetailstrue);
  666.             $firstAccommodation current($accommodation['Accommodations']);
  667.             $body = [
  668.                 'Travellers' => [],
  669.                 'SelectedAccommodations' => [$firstAccommodation],
  670.                 'Assignments' => [],
  671.             ];
  672.             foreach ($receipt->getTravellers() as $dateOfBirth) {
  673.                 $body['Travellers'][] = ['DateOfBirth' => $dateOfBirth->format('Y-m-d')];
  674.             }
  675. //            dump($roomlayout);
  676.             $travellersInRooms = [];
  677.             if ($basket) {
  678.                 $rooms $basket->getRooms();
  679.                 $persons range(1$basket->getChildren() + $basket->getAdults());
  680.                 if (!$roomlayout) {
  681.                     foreach ($persons as $index => $person) {
  682.                         $travellersInRooms[$index $rooms]['PaxIds'][] = $person;
  683.                     }
  684.                 } else {
  685.                     $j 0;
  686.                     foreach ($roomlayout as $room => $numberpersons) {
  687.                         $travellersInRooms[$room]['PaxIds'] = [];
  688.                         for ($i 0$i $numberpersons; ++$i) {
  689.                             $travellersInRooms[$room]['PaxIds'][] = $persons[$j];
  690.                             ++$j;
  691.                         }
  692.                     }
  693.                 }
  694.             }
  695. //            dump($travellersInRooms);
  696.             if (!$selectedRooms) {
  697. //                dump('er zijn geen selected kamers');
  698.                 $travellersInRooms = [];
  699.                 if ($basket) {
  700.                     $rooms $basket->getRooms();
  701.                     $persons range(1$basket->getChildren() + $basket->getAdults());
  702.                     if (!$roomlayout) {
  703.                         foreach ($persons as $index => $person) {
  704.                             $travellersInRooms[$index $rooms]['PaxIds'][] = $person;
  705.                         }
  706.                     } else {
  707.                         $j 0;
  708.                         foreach ($roomlayout as $room => $numberpersons) {
  709.                             $travellersInRooms[$room]['PaxIds'] = [];
  710.                             for ($i 0$i $numberpersons; ++$i) {
  711.                                 $travellersInRooms[$room]['PaxIds'][] = $persons[$j];
  712.                                 ++$j;
  713.                             }
  714.                         }
  715.                     }
  716.                 }
  717.                 foreach ($travellersInRooms as $travellersInRoom) {
  718.                     $paxIds $travellersInRoom['PaxIds'];
  719.                     foreach ($body['SelectedAccommodations'][0]['Units'] as &$unit) {
  720.                         if (\count($paxIds) < $unit['Occupancy']['Minimal']) {
  721.                             continue;
  722.                         }
  723.                         if (\count($paxIds) > $unit['Occupancy']['Maximal']) {
  724.                             continue;
  725.                         }
  726.                         if ($unit['Allotment']['Chosen'] === $unit['Allotment']['Available']) {
  727.                             continue;
  728.                         }
  729.                         $unit['Allotment']['Chosen'] = $unit['Allotment']['Chosen'] + 1;
  730.                         $firstBoardOfUnit current($unit['Boards']);
  731.                         $body['Assignments'][] = [
  732.                             'Board' => $firstBoardOfUnit['Code'],
  733.                             'UnitId' => $unit['Id'],
  734.                             'PaxIds' => $paxIds,
  735.                         ];
  736.                         break;
  737.                     }
  738.                 }
  739.             } else {
  740. //                dump('er zijn wel geselecteerde kamers door gebruiker');
  741.                 $count 0;
  742. //                $travellersInRooms = array_reverse($travellersInRooms);
  743. //                dump($travellersInRooms);
  744.                 $body['Assignments'] = null;
  745.                 foreach ($selectedRooms as $room) {
  746. //                    dump("op zoek naar iemand in kamer: ".$room);
  747.                     $paxIds $travellersInRooms[$count]['PaxIds'];
  748. //                    dd($paxIds);
  749. //                    $accommodation = json_decode($basket->getPytonBasket()->getAccomodation(), true);
  750. //                    foreach($accommodation['Units'] AS $unit){
  751.                     foreach ($body['SelectedAccommodations'][0]['Units'] as &$unit) {
  752.                         $board current($unit['Boards']);
  753.                         $roomIdentifier $unit['Description'].$unit['Type'].$board['Name'];
  754.                         if ($roomIdentifier !== $room) {
  755.                             continue;
  756.                         }
  757.                         // dump('roomIdentifier '.$roomIdentifier.' is gelijk aan '.$room);
  758.                         $body['Assignments'][] = [
  759.                             'Board' => $board['Code'],
  760.                             'UnitId' => $unit['Id'],
  761.                             'PaxIds' => $paxIds,
  762.                         ];
  763. //                        dump("Aantql gekozen is nu ".$unit['Allotment']['Chosen']);
  764.                         $unit['Allotment']['Chosen'] = $unit['Allotment']['Chosen'] + 1;
  765.                         break;
  766.                     }
  767.                     ++$count;
  768.                 }
  769.             }
  770.             // dd("hier altijd stoppen");
  771. //            dd($body);
  772.             try {
  773.                 $request $this->serializer->serialize($body'json');
  774. //                dump($this->session->getId());
  775.                 // dd($request);
  776.                 $this->logger->log(LogLevel::INFO'PYTON: 'self::ACCOMMODATIONS_RECEIPT_ENDPOINT.' session: '.$this->session->getId());
  777.                 $response $this->client->post(self::ACCOMMODATIONS_RECEIPT_ENDPOINT, [
  778.                     'headers' => [
  779.                         'Session' => $this->session->getId(),
  780.                     ],
  781.                     'body' => $request,
  782.                 ]);
  783. //                dump(self::ACCOMMODATIONS_RECEIPT_ENDPOINT);
  784. //                dd($this->session->getId());
  785.                 $responseContent $response->getBody()->getContents();
  786.                 $result json_decode($responseContenttrue);
  787.                 $roomsTotalValue $result['Receipt']['Prices']['Total']['Value'];
  788.                 $this->syncBasketAccommodationListPrice(
  789.                     $basket,
  790.                     $roomsTotalValue,
  791.                     \count($receipt->getTravellers()),
  792.                     $match
  793.                 );
  794.                 $this->log('post'self::ACCOMMODATIONS_RECEIPT_ENDPOINTnull$responseContent$request);
  795.                 $this->logger->log(
  796.                     LogLevel::DEBUG,
  797.                     sprintf(
  798.                         'DEBUG: info when sending request to endpoint `%s`. Got response `%s`',
  799.                         self::ACCOMMODATIONS_RECEIPT_ENDPOINT,
  800.                         $responseContent
  801.                     )
  802.                 );
  803.                 $basket->getPytonBasket()->setAccommodationReceipt($responseContent);
  804.                 $basket->getPytonBasket()->setAccomodation(json_encode($firstAccommodation));
  805. //                dd("Er ging iets goed");
  806.                 return true;
  807.             } catch (BadResponseException $exception) {
  808.                 $this->log('post'self::ACCOMMODATIONS_RECEIPT_ENDPOINTnull$exception$request);
  809.                 $this->logger->log(
  810.                     LogLevel::CRITICAL,
  811.                     sprintf(
  812.                         'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  813.                         self::ACCOMMODATIONS_RECEIPT_ENDPOINT,
  814.                         $exception->getResponse()->getBody()->getContents()
  815.                     )
  816.                 );
  817. //                dump($exception);
  818. //                dd("Er ging iets fout");
  819.                 return false;
  820.             }
  821.         }
  822.         return false;
  823.     }
  824.     /**
  825.      * @return string
  826.      */
  827.     public function getAccommodationDetails(BasketModel $basketAccommodationReceipt $receipt$roomlayout null)
  828.     {
  829.         $travellersInRooms = [];
  830.         if ($basket) {
  831.             $rooms $basket->getRooms();
  832.         if($rooms === null) { $rooms 1;}
  833.             $persons range(1$basket->getChildren() + $basket->getAdults());
  834.             if (!$roomlayout) {
  835.                 foreach ($persons as $index => $person) {
  836.                     $travellersInRooms[$index $rooms]['PaxIds'][] = $person;
  837.                 }
  838.             } else {
  839.                 $j 0;
  840.                 foreach ($roomlayout as $room => $numberpersons) {
  841.                     $travellersInRooms[$room]['PaxIds'] = [];
  842.                     for ($i 0$i $numberpersons; ++$i) {
  843.                         $travellersInRooms[$room]['PaxIds'][] = $persons[$j];
  844.                         ++$j;
  845.                     }
  846.                 }
  847.             }
  848.         }
  849.         $body = [
  850.             'Travellers' => [],
  851.             'SelectedAccommodations' => [],
  852.             'TravellersInRooms' => $travellersInRooms,
  853.         ];
  854. dump($receipt->getTravellers());
  855.         foreach ($receipt->getTravellers() as $dateOfBirth) {
  856.             $body['Travellers'][] = ['DateOfBirth' => $dateOfBirth->format('Y-m-d')];
  857.         }
  858.         foreach ($receipt->getAccommodations() as $accommodation) {
  859.             $body['SelectedAccommodations'][] = $accommodation;
  860.         }
  861.         dd($body);
  862.         try {
  863.             $this->logger->log(LogLevel::INFO'PYTON: '.self::ACCOMMODATIONS_DETAIL_ENDPOINT.' session: '.$this->session->getId());
  864.             $response $this->client->post(self::ACCOMMODATIONS_DETAIL_ENDPOINT, [
  865.                 'headers' => [
  866.                     'Session' => $this->session->getId(),
  867.                 ],
  868.                 'body' => $this->serializer->serialize($body'json'),
  869.             ]);
  870. //            echo json_encode([
  871. //                'headers' => [
  872. //                    'Session' => $this->session->getId(),
  873. //                ],
  874. //                'body' => $this->serializer->serialize($body, 'json'),
  875. //            ]);
  876.             $this->log('post'self::ACCOMMODATIONS_DETAIL_ENDPOINTnull$response);
  877. //            dd($response->getBody()->getContents());
  878.             return $response->getBody()->getContents();
  879.         } catch (ClientException $exception) {
  880.             $exceptionContent $exception->getResponse()->getBody()->getContents();
  881.             $this->logger->log(
  882.                 LogLevel::CRITICAL,
  883.                 sprintf(
  884.                     'ClientException on sending request to endpoint `%s`. Got response `%s`',
  885.                     self::ACCOMMODATIONS_DETAIL_ENDPOINT,
  886.                     $exceptionContent
  887.                 )
  888.             );
  889.             $this->scanjobLogger->insert(
  890.                 $exception->getRequest()->getUri()->getPath(),
  891.                 $this->session->getId(),
  892.                 new \DateTime(),
  893.                 $this->serializer->serialize($body'json'),
  894.                 $exceptionContent
  895.             );
  896.             return false;
  897.         } catch (BadResponseException $exception) {
  898.             $this->logger->log(
  899.                 LogLevel::CRITICAL,
  900.                 sprintf(
  901.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  902.                     self::ACCOMMODATIONS_DETAIL_ENDPOINT,
  903.                     $exception->getResponse()->getBody()->getContents()
  904.                 )
  905.             );
  906.             return false;
  907.         }
  908.     }
  909.     public function getAirports(): string
  910.     {
  911.         try {
  912.             $this->logger->log(LogLevel::INFO'PYTON: 'self::BASICDATA_AIRPORTS_ENDPOINT.' session: '.$this->session->getId());
  913.             $response $this->client->get(self::BASICDATA_AIRPORTS_ENDPOINT, [
  914.                 'headers' => [
  915.                     'Session' => $this->session->getId(),
  916.                 ],
  917.             ]);
  918. //            $this->log('get', self::BASICDATA_AIRPORTS_ENDPOINT, null, $response);
  919.         } catch (BadResponseException $exception) {
  920. //            $this->log('get', self::BASICDATA_AIRPORTS_ENDPOINT, null, $exception);
  921.             $this->logger->log(
  922.                 LogLevel::CRITICAL,
  923.                 sprintf(
  924.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  925.                     self::BASICDATA_AIRPORTS_ENDPOINT,
  926.                     $exception->getResponse()->getBody()->getContents()
  927.                 )
  928.             );
  929.         }
  930.         return $response->getBody()->getContents();
  931.     }
  932.     /**
  933.      * @param $search
  934.      *
  935.      * @throws Exception
  936.      *
  937.      * @return string
  938.      */
  939.     public function getFlightPlaces($search): ?string
  940.     {
  941.         if (isset($this->flightPlaces[$search])) {
  942.             return $this->flightPlaces[$search];
  943.         }
  944.         $body = [
  945.             'Destination' => $search,
  946.             'DestinationType' => 'Depart',
  947.         ];
  948.         try {
  949.             $this->logger->log(LogLevel::INFO'PYTON: 'self::FLIGHTS_SEARCH_DESTINATIONS_ENDPOINT.' session: '.$this->session->getId());
  950.             $response $this->client->post(self::FLIGHTS_SEARCH_DESTINATIONS_ENDPOINT, [
  951.                 'headers' => [
  952.                     'Session' => $this->session->getId(),
  953.                     'CorrelationId' => Uuid::uuid4()->toString(),
  954.                 ],
  955.                 'body' => json_encode($body),
  956.             ]);
  957.             $this->flightPlaces[$search] = $response->getBody()->getContents();
  958.         } catch (BadResponseException $exception) {
  959.             $this->logger->log(
  960.                 LogLevel::CRITICAL,
  961.                 sprintf(
  962.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  963.                     self::FLIGHTS_SEARCH_DESTINATIONS_ENDPOINT,
  964.                     $exception->getResponse()->getBody()->getContents()
  965.                 )
  966.             );
  967.         }
  968.         return $this->flightPlaces[$search];
  969.     }
  970.     public function createFlightReceipt(BasketModel $basketFlightReceipt $receipt): bool
  971.     {
  972.         $body = [
  973.             'Travellers' => [],
  974.             'Assignment' => [
  975.                 'TransportId' => $receipt->getTrips()->first()->getId(),
  976.                 'ClassId' => '1',
  977.                 'PaxIds' => range(1\count($receipt->getTravellers())),
  978.             ],
  979.             'SelectedFlight' => $this->getFlightDetails($receipt),
  980.         ];
  981.         foreach ($receipt->getTravellers()->toArray() as $dateOfBirth) {
  982.             /* @var DateTime $dateOfBirth */
  983.             $body['Travellers'][] = ['DateOfBirth' => $dateOfBirth->format('Y-m-d')];
  984.         }
  985.         try {
  986.             $this->logger->log(LogLevel::INFO'PYTON: '.self::FLIGHTS_RECEIPT.' session: '.$this->session->getId());
  987.             $response $this->client->post(self::FLIGHTS_RECEIPT, [
  988.                 'headers' => [
  989.                     'Session' => $this->session->getId(),
  990.                 ],
  991.                 'body' => $this->serializer->serialize($body'json'),
  992.             ]);
  993. //            $this->log('post', self::FLIGHTS_RECEIPT, null, $response);
  994.         } catch (BadResponseException $exception) {
  995. //            $this->log('post', self::FLIGHTS_RECEIPT, null, $exception);
  996.             $this->logger->log(
  997.                 LogLevel::CRITICAL,
  998.                 sprintf(
  999.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  1000.                     self::FLIGHTS_RECEIPT,
  1001.                     $exception->getResponse()->getBody()->getContents()
  1002.                 )
  1003.             );
  1004.             return false;
  1005.         }
  1006.         $basket->getPytonBasket()->setFlightReceipt($response->getBody()->getContents());
  1007.         return true;
  1008.     }
  1009.     public function getBasket($basketId)
  1010.     {
  1011.         $this->logger->log(LogLevel::INFO'PYTON: ''/api/basket/'.$basketId.' session: '.$this->session->getId());
  1012.         $response $this->client->get('/api/basket/'.$basketId, [
  1013.             'headers' => [
  1014.                 'Session' => $this->session->getId(),
  1015.             ],
  1016.         ]);
  1017. //        $this->log('get', '/api/basket/' . $basketId, null, $response);
  1018.         return $response->getBody()->getContents();
  1019.     }
  1020.     public function getArriveAirports(Game $match): array
  1021.     {
  1022.         $airports = [];
  1023.         try {
  1024.             $locations json_decode(
  1025.                 $this->getFlightPlaces(
  1026.                     $match->getStadium()
  1027.                         ->getPlace()
  1028.                 ),
  1029.                 true
  1030.             );
  1031.             if (!isset($locations['Locations']) || !$locations['Locations']) {
  1032.                 return $airports;
  1033.             }
  1034.             foreach ($locations['Locations'] as $location) {
  1035.                 $airports[$location['AirportLocation']['Id']] = $location['AirportLocation']['Name'].' ('.
  1036.                     $location['CountryLocation']['Name'].')';
  1037.             }
  1038.             return $airports;
  1039.         } catch (Exception $exception) {
  1040.             return $airports;
  1041.         }
  1042.     }
  1043.     /**
  1044.      * @return string
  1045.      */
  1046.     public function getFlightDetails(FlightReceipt $receipt): array
  1047.     {
  1048.         $body = [
  1049.             'Travellers' => [],
  1050.             'SelectedFlight' => [
  1051.                 'Legs' => [],
  1052.                 'Trips' => [],
  1053.             ],
  1054.             'FirstDeparture' => $receipt->getFirstDeparture(),
  1055.             'FinalDestination' => $receipt->getFinalDestination(),
  1056.             'HasTrips' => true,
  1057.         ];
  1058.         foreach ($receipt->getTravellers()->toArray() as $dateOfBirth) {
  1059.             /* @var DateTime $dateOfBirth */
  1060.             $body['Travellers'][] = ['DateOfBirth' => $dateOfBirth->format('Y-m-d')];
  1061.         }
  1062.         foreach ($receipt->getLegs() as $leg) {
  1063.             $body['SelectedFlight']['Legs'][] = $leg;
  1064.         }
  1065.         foreach ($receipt->getTrips()->toArray() as $trip) {
  1066.             $body['SelectedFlight']['Trips'][] = $trip;
  1067.         }
  1068.         try {
  1069.             $this->logger->log(LogLevel::INFO'PYTON: '.self::FLIGHTS_DETAIL_ENDPOINT.' session: '.$this->session->getId());
  1070.             $response $this->client->post(self::FLIGHTS_DETAIL_ENDPOINT, [
  1071.                 'headers' => [
  1072.                     'Session' => $this->session->getId(),
  1073.                 ],
  1074.                 'body' => $this->serializer->serialize($body'json'),
  1075.             ]);
  1076. //            $this->log('post', self::FLIGHTS_DETAIL_ENDPOINT, null, $response);
  1077.             return json_decode($response->getBody()->getContents(), true)['Flights'];
  1078.         } catch (BadResponseException $exception) {
  1079. //            $this->log('post', self::FLIGHTS_DETAIL_ENDPOINT, null, $exception);
  1080.             $this->logger->log(
  1081.                 LogLevel::CRITICAL,
  1082.                 sprintf(
  1083.                     'Error trigger when sending request to endpoint `%s`. Got response `%s`',
  1084.                     self::FLIGHTS_DETAIL_ENDPOINT,
  1085.                     $exception->getResponse()->getBody()->getContents()
  1086.                 )
  1087.             );
  1088.             return [];
  1089.         }
  1090.     }
  1091.     public function log($type$endpoint$basket ''$response null$request null)
  1092.     {
  1093. //        echo '<pre>';
  1094. //
  1095. //        echo "Endpoint:\t{$endpoint} <br/>";
  1096. //        echo "SessionId:\t" . $this->session->getId(). "<br/>";
  1097. //        echo "DateTime:\t" . (new DateTime())->format('d-m-Y h:i:s');
  1098. //        echo '<hr>';
  1099. //        echo "Request: <br/><br/>";
  1100. //        echo $request;
  1101. //        echo '<hr>';
  1102. //        echo "Response: <br/><br/>";
  1103. //        echo $response->getBody()->getContents();
  1104. //        exit;
  1105.         $handle fopen('test.log''a');
  1106.         fwrite(
  1107.             $handle,
  1108.             sprintf(
  1109.                 '%s : %s %s',
  1110.                 (new DateTime())->format('d-m-Y H:i:s'),
  1111.                 $type,
  1112.                 $endpoint
  1113.             )."\r\n"
  1114.         );
  1115.         fclose($handle);
  1116.     }
  1117.     /**
  1118.      * @param $accommodations
  1119.      * @param $match
  1120.      *
  1121.      * @return mixed
  1122.      */
  1123.     public function processPriceDifference($results$match)
  1124.     {
  1125.         foreach ($results->getAccommodations() as &$accommodation) {
  1126.             if (!$match->getCheapestAccommodation()) {
  1127.                 continue;
  1128.             }
  1129.             $priceDetails $accommodation->getPriceDetails();
  1130.             $price $priceDetails->getPrice();
  1131.             $cheapestAccommodationPrice $match->getCheapestAccommodation()->getAmount();
  1132.             if(!in_array(
  1133.                 $match->getStadium()->getCountry()->getSlug(),
  1134.                 $this->ignoreFinalCountries,
  1135.                 true
  1136.             )){
  1137.                 if (!$match->isFinal() && !in_array($match->getStadium()->getCountry()->getSlug(),['duitsland''frankrijk''denemarken'])) {
  1138.                     $cheapestAccommodationPrice $match->getCheapestAccommodation()->getAmount() * 2;
  1139.                     $price->setValue(
  1140.                         $price->getValue() * 2
  1141.                     );
  1142.                 }
  1143.             }
  1144.             $difference $price->getValue() - $cheapestAccommodationPrice;
  1145.             $difference ceil($difference 100) * 100;
  1146.             $price->setDifference($difference);
  1147.             $priceDetails->setPrice($price);
  1148.         }
  1149.         return $results;
  1150.     }
  1151.     /**
  1152.      * @param int $priceValue
  1153.      */
  1154.     private function syncBasketAccommodationListPrice(BasketModel $basketint $totalPriceValue$travelersGame $match)
  1155.     {
  1156.         $selectedAccommodationWrapper null;
  1157.         $matchCheapestAccommodation $match->getCheapestAccommodation();
  1158.         if(!$match->isFinal() && !in_array($match->getStadium()->getCountry()->getSlug(),['duitsland''frankrijk''denemarken'])){
  1159.             $priceForExtraDay ceil($match->getCheapestAccommodation()->multiply(0.7,Money::ROUND_UP)->getAmount()/100)*100;
  1160.             $matchCheapestAccommodation $matchCheapestAccommodation->addMoney::EUR($priceForExtraDay));
  1161.         }
  1162.         foreach ($basket->getAccomodationList() as &$accommodationWrapper) {
  1163.             if ($basket->getAccommodation() === $accommodationWrapper->getAccommodation()->getId()) {
  1164.                 $totalPricePerPerson = ($totalPriceValue $travelers);
  1165.                 $roundedPriceValue ceil($totalPricePerPerson 100) * 100;
  1166.                 $accommodationWrapper->getPriceDetails()->getPrice()
  1167.                     ->setValue($roundedPriceValue)
  1168.                     ->setDifference($roundedPriceValue $matchCheapestAccommodation->getAmount());
  1169.             }
  1170.         }
  1171.     }
  1172.     private function supportsDiscounts(string $basketId): bool
  1173.     {
  1174.         try {
  1175.             $this->logger->log(LogLevel::INFO'PYTON: 'sprintf(self::ACTIONCODE_AVAILABLE_ENDPOINT$basketId));
  1176.             $response $this->client->get(sprintf(self::ACTIONCODE_AVAILABLE_ENDPOINT$basketId), [
  1177.                 'headers' => [
  1178.                     'Session' => $this->session->getId(),
  1179.                     'CorrelationId' => Uuid::uuid4()->toString(),
  1180.                 ],
  1181.             ]);
  1182.             $content $response->getBody()->getContents();
  1183.             if ('false' !== $content) {
  1184.                 return true;
  1185.             }
  1186.         } catch (Exception $exception) {
  1187.         }
  1188.         return false;
  1189.     }
  1190.     private function fetchDiscountReceipt(string $basketIdstring $actionCode): ?string
  1191.     {
  1192.         try {
  1193.             $this->logger->log(LogLevel::CRITICAL'PYTON: 'sprintf(self::ACTIONCODE_CHECK_ENDPOINT$basketId$actionCode));
  1194.             $this->logger->log(LogLevel::CRITICAL'PYTON: SESSION ID'$this->session->getId());
  1195.             $response $this->client->get(
  1196.                 sprintf(self::ACTIONCODE_CHECK_ENDPOINT$basketId$actionCode),
  1197.                 [
  1198.                     'headers' => [
  1199.                         'Session' => $this->session->getId(),
  1200.                         'CorrelationId' => Uuid::uuid4()->toString(),
  1201.                     ],
  1202.                 ]
  1203.             );
  1204.             $content $response->getBody()->getContents();
  1205.             $this->logger->log(LogLevel::CRITICAL'PYTON: SESSION ID'$this->session->getId());
  1206.             $this->logger->log(LogLevel::CRITICAL'PYTON: RESPONSE'$content);
  1207.             if ('false' !== $content) {
  1208.                 return $content;
  1209.             }
  1210.         } catch (Exception $exception) {
  1211.             $exception->getMessage();
  1212.         }
  1213.         return null;
  1214.     }
  1215.     /**
  1216.      * @throws Exception
  1217.      */
  1218.     public function applyDiscount(BasketModel $basketstring $actionCodeGame $match): bool
  1219.     {
  1220.         $basketId $basket->getPytonBasket()->getBasketId();
  1221.         $this->createBasketReceipt($basket$basket->getPytonBasket()->getAccommodationReceipt());
  1222.         $discountReceipt $this->fetchDiscountReceipt($basketId$actionCode);
  1223. //        dd($discountReceipt);
  1224.         if (
  1225.             $this->supportsDiscounts($basketId) &&
  1226.             $discountReceipt &&
  1227.             $totalDiscount $this->extractTotalDiscountPrice($discountReceipt)
  1228.         ) {
  1229.             $basket->setDiscountReceipt($discountReceipt);
  1230.             $basket->setDiscountTotal($totalDiscount);
  1231.             return true;
  1232.         }
  1233.         return false;
  1234.     }
  1235.     private function extractTotalDiscountPrice(string $discountReceipt): ?Money
  1236.     {
  1237.         $discountReceipt json_decode($discountReceipttrue);
  1238.         if (
  1239.             $discountReceipt['Receipt'] &&
  1240.             $discountReceipt['Receipt']['Prices'] &&
  1241.             $total $discountReceipt['Receipt']['Prices']['Total']
  1242.         ) {
  1243.             return new Money(
  1244.                 $total['Value'],
  1245.                 new Currency($total['Currency'])
  1246.             );
  1247.         }
  1248.         return null;
  1249.     }
  1250.     private function getFlightsForDepartsAndArrivals(
  1251.         $departureId,
  1252.         $arrivalId,
  1253.         $departureDate,
  1254.         $returnDate,
  1255.         $pageNumber 1,
  1256.     ) {
  1257.         $body = [
  1258.             'Travellers' => [
  1259.                 ['DateOfBirth' => '1983-06-24'],
  1260.             ],
  1261.             'Filters' => [
  1262.                 'DepartLocation' => [
  1263.                     'Type' => 'Airport',
  1264.                     'Id' => $departureId,
  1265.                 ],
  1266.                 'ArriveLocation' => [
  1267.                     'Type' => 'Airport',
  1268.                     'Id' => $arrivalId,
  1269.                 ],
  1270.                 'DepartDate' => $departureDate->format('Y-m-d'),
  1271.                 'ReturnDate' => $returnDate->format('Y-m-d'),
  1272.                 'OnlyDirectFlights' => false,
  1273.                 'IncludeCheapestLuggageInPrice' => false,
  1274.                 'FlightType' => 'OnlyRoundTrips',
  1275.                 'FlightClasses' => 'All',
  1276.                 'NumberOfStopovers' => 0,
  1277.             ],
  1278.             'Paging' => [
  1279.                 'PageNumber' => $pageNumber,
  1280.                 'PageSize' => 10,
  1281.             ],
  1282.         ];
  1283.         try {
  1284.             $this->logger->log(LogLevel::INFO'PYTON: '.self::FLIGHTS_SEARCH_FLIGHTS_ENDPOINT.' session: '.$this->session->getId());
  1285.             $rawResponse $this->client->post(self::FLIGHTS_SEARCH_FLIGHTS_ENDPOINT, [
  1286.                 'headers' => [
  1287.                     'Session' => $this->session->getId(),
  1288.                     'CorrelationId' => Uuid::uuid4()->toString(),
  1289.                 ],
  1290.                 'body' => json_encode($body),
  1291.             ])->getBody()->getContents();
  1292.             $result json_decode($rawResponsetrue);
  1293.             if (empty($result['Paging'])) {
  1294.                 return $result;
  1295.             }
  1296.             if ($result['Paging']['HasMoreResults'] && === $pageNumber) {
  1297.                 foreach (range(2$result['Paging']['TotalNumberOfPages']) as $page) {
  1298.                     $pagedResult $this->getFlightsForDepartsAndArrivals(
  1299.                         $departureId,
  1300.                         $arrivalId,
  1301.                         $departureDate,
  1302.                         $returnDate,
  1303.                         $page
  1304.                     );
  1305.                     $result['Flights']['Trips'] = array_merge_recursive(
  1306.                         $result['Flights']['Trips'],
  1307.                         $pagedResult['Flights']['Trips']
  1308.                     );
  1309.                     $result['Flights']['Legs'] = array_merge_recursive(
  1310.                         $result['Flights']['Legs'],
  1311.                         $pagedResult['Flights']['Legs']
  1312.                     );
  1313.                 }
  1314.             }
  1315.         } catch (RequestException $exception) {
  1316.             return [];
  1317.         }
  1318.         return $result;
  1319.     }
  1320.     private function transformFlights(Game $match, array $response): FlightResults
  1321.     {
  1322.         $minimumArriveDatetime = clone $match->getDate();
  1323.         $minimumArriveDatetime $minimumArriveDatetime->modify(self::MATCH_ARRIVAL_MIN_INTERVAL);
  1324.         $whiteListedTrips = [];
  1325.         $flightResultsPrototype = [];
  1326.         $flightResultsPrototype['Paging'] = !empty($response['Paging']) ? $response['Paging'] : [];
  1327.         $flightResultsPrototype['Flights'] = [
  1328.             'Legs' => [],
  1329.             'Trips' => [],
  1330.             'FirstDeparture' => [],
  1331.             'FinalDestination' => [],
  1332.             'HasTrips' => $response['Flights']['HasTrips'],
  1333.         ];
  1334.         $flightResultsPrototype['Filters'] = $response['Filters'];
  1335.         foreach ($response['Flights']['Legs'] as $i => $leg) {
  1336.             if ('TO' === mb_substr($leg['Id'], 02)) {
  1337.                 $arriveDatetime = new \DateTime(
  1338.                     $leg['Arrive']['Date'].' '.
  1339.                     $leg['Arrive']['Time']
  1340.                 );
  1341.                 if ($arriveDatetime <= $minimumArriveDatetime) {
  1342.                     $flightResultsPrototype['Flights']['Legs'][] = $leg;
  1343.                     $whiteListedTrips[] = mb_substr($leg['Id'], 3);
  1344.                     $flightResultsPrototype['Flights']['Legs'][] = $response['Flights']['Legs'][$i 1];
  1345.                 }
  1346.             }
  1347.         }
  1348.         foreach ($response['Flights']['Trips'] as $i => $trip) {
  1349.             if (\in_array($trip['Id'], $whiteListedTripstrue)) {
  1350.                 $flightResultsPrototype['Flights']['Trips'][] = $trip;
  1351.             }
  1352.         }
  1353.         $flightResultsPrototype json_encode($flightResultsPrototype);
  1354.         return $this->serializer->deserialize($flightResultsPrototypeFlightResults::class, 'json');
  1355.     }
  1356. }