<?php
/**
* Created by Elements.at New Media Solutions GmbH
*
*/
namespace App\Controller\BookingApi;
use App\Model\BookingApi\CartItemTicket;
use App\Model\BookingApi\Exception\DataMappingException;
use App\Model\BookingApi\Exception\DataMissingException;
use App\Model\BookingApi\LocalizedText;
use App\Model\BookingApi\TicketAcquisitionType;
use App\Model\BookingApi\TicketAvailability;
use App\Model\BookingApi\TicketAvailabilityIncludingUpgrades;
use App\Model\BookingApi\TicketCatalogUpgradeRelation;
use App\Model\BookingApi\TicketInsurancePrice;
use App\Model\BookingApi\TicketUpgradePrice;
use App\Model\Shop\Ticket\TicketProduct;
use App\Model\Type\TenantType;
use App\Service\BookingApi\ApiService;
use App\Service\Shop\JsonDataService;
use App\Service\Shop\ShopService;
use App\Service\TicketShopFrameworkBundle\TicketFilter;
use Carbon\Carbon;
use Elements\Bundle\SkidataTicketingSwebBundle\Service\OrderService;
use Elements\Bundle\TicketShopFrameworkBundle\Model\Constant\AcquisitionType;
use Elements\Bundle\TicketShopFrameworkBundle\Model\DataObject\TicketCatalog;
use Elements\Bundle\TicketShopFrameworkBundle\Model\Shop\Ticketing\TicketCatalogAvailability;
use League\Csv\Exception;
use OpenApi\Annotations as OA;
use Pimcore\Model\DataObject\KeycardNumber;
use Pimcore\Model\DataObject\ShopTicketCatalog;
use Pimcore\Model\DataObject\TicketshopTicketAdditional;
use Pimcore\Translation\Translator;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class ApiTicketControllerApi
*
* @Route("/bookingAPI/ticket")
*
* @OA\Tag(name="Ticket")
*/
class ApiTicketControllerApi extends ApiAbstractController
{
/**
* Get availability for ShopTicketCatalog and specific date
*
* @Route("/availability", name="ticket_availability")
*
* @param Request $request
*
* @return JsonResponse
*
* @OA\Post(
* path="/bookingAPI/ticket/availability",
* description="Get availability for ShopTicketCatalog and specific date",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(
* required={"startDate","catalogId"},
*
* @OA\Property( property="startDate", type="string", description="YYYY-MM-DD"),
* @OA\Property( property="endDate", type="string", description="YYYY-MM-DD"),
* @OA\Property( property="catalogId", type="int"),
* @OA\Property( property="countryCode", type="string", description="required if acquisitionTypesPerConsumerCategory should be included in response (stop sale for delivery is set per country)"),
*
* @OA\Examples(example="sandboxTicketExample", value="{
""catalogId"": ""3000188"",
""startDate"": ""2024-04-11"",
""endDate"": ""2024-04-11"",
""countryCode"": ""CH""
}", summary="SANDBOX ticket availability"),
@OA\Examples(example="liveTicketExample", value="{
""catalogId"": ""1501805"",
""startDate"": ""2024-03-30"",
""endDate"": ""2024-03-30"",
""countryCode"": ""CH""
}", summary="LIVE ticket availability")
* )
* ),
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="availabilities", type="array",
*
* @OA\Items(ref="#/components/schemas/TicketAvailability")
* )
* )
* )
* ),
*
* @OA\Response(
* response=500,
* description="Error",
* ),
* )
*
*
*/
public function getTicketAvailability(Request $request, ApiService $apiService, ShopService $shopHelper, JsonDataService $jsonDataService): JsonResponse
{
try {
$body = $request->getContent();
$requestData = json_decode($body, true);
$cart = $this->getCart();
$this->clearCartData($cart);
// only for testing purposes
if (!$requestData && $request->get('debug')) {
$requestData = [
'startDate' => '2024-04-20',
'endDate' => '2024-04-25',
'catalogId' => 1501817,
'countryCode' => 'CH',
];
}
//check for required params
if (!is_array($requestData) || !array_key_exists('startDate', $requestData) || empty($requestData['startDate'])) {
$this->bookingapiLogger->warning('required startDate for ticket/availability endpoint is missing');
return $this->sendErrors(['startDate missing'], 400);
}
if (!is_array($requestData) || !array_key_exists('catalogId', $requestData) || empty($requestData['catalogId'])) {
$this->bookingapiLogger->warning('required catalogId for ticket/availability endpoint is missing');
return $this->sendErrors(['catalogId missing'], 400);
}
$from = Carbon::createFromFormat('Y-m-d', $requestData['startDate']);
$from = $from->startOfDay();
if (isset($requestData['endDate']) && $requestData['endDate']) {
$to = Carbon::createFromFormat('Y-m-d', $requestData['endDate']);
} else {
$to = $from->copy();
}
$to = $to->endOfDay();
$countryCode = isset($requestData['countryCode']) ? $requestData['countryCode'] : null;
$catalog = TicketCatalog::getById($requestData['catalogId']);
if (!$catalog) {
throw new \Exception('ticketCatalog with id ' . $requestData['catalogId'] . 'not found');
} elseif (!in_array(TenantType::MARKETPLACE, $catalog->getTenant())) {
$this->bookingapiLogger->warning('call to ticket/availability with catalogId' . $requestData['catalogId'] . ' but catalog does not have marketplace tenant');
return $this->sendErrors(['ticketCatalog with id ' . $requestData['catalogId'] . ' not available for tenant ' . TenantType::MARKETPLACE], 400);
}
$filter = new TicketFilter($from, $to);
$filter->setExactDuration(true);
$filter->setUseTicketValidity(true);
$allowedConsumers = [];
foreach ($catalog->getTicketConsumerCategories() as $allowedConsumer) {
$allowedConsumers[] = $allowedConsumer->getId();
}
if ($allowedConsumers) {
$filter->setConsumers($allowedConsumers);
}
/**
* @var TicketCatalogAvailability $ticketCatalogAvailability
*/
$ticketCatalogAvailability = $filter->getTicketCatalogAvailability($catalog, true);
//insurances
$insuranceData = $shopHelper->getInsurancesForProduct($ticketCatalogAvailability);
$insurances = $this->getInsuranceData($catalog, $ticketCatalogAvailability, $insuranceData);
$availabilityData = [];
foreach ($ticketCatalogAvailability->getTicketAvailability() as $productAvailability) {
$ticketProduct = $productAvailability->getTicketProduct();
//upgrades
/** @phpstan-ignore-next-line */
$upgrades = $this->getUpgradeData($catalog, $ticketProduct, $from, $to);
$consumerCategories = [];
$consumerCategoryData = [];
$acquisitionTypesByConsumerCategory = [];
foreach ($productAvailability->getConsumerAvailabilities() as $consumerAvailability) {
$priceInfo = $consumerAvailability->getPriceInfo();
if ($priceInfo) {
$consumerCategories[$consumerAvailability->getTicketConsumer()->getId()] = $priceInfo->getPrice()->getGrossAmount()->asNumeric();
$consumerCategoryData[] = $consumerAvailability->getTicketConsumer();
if ($countryCode) {
$possibleAquisitionTypes = $apiService->calculatePossibleAcquisitionTypes($countryCode, $productAvailability->getValidFrom(), $consumerAvailability->getTicketConsumer(), $productAvailability->getTicketProduct());
$acquisitionTypesByConsumerCategory[$consumerAvailability->getTicketConsumer()->getId()] = array_values($possibleAquisitionTypes);
}
}
}
$localizedName = new LocalizedText();
$localizedInfoBubbleText = new LocalizedText();
$localizedCatalogInfoText = new LocalizedText();
foreach ($this->languages as $language) {
$localizedName->$language = $ticketProduct->getName($language);
$localizedCatalogInfoText->$language = $catalog->getInfoBubbleDescription($language) ?: '';
$localizedInfoBubbleText->$language = $ticketProduct->getDescription($language) ?: '';
}
$apiTicketAvailability = new TicketAvailability();
$apiTicketAvailability->setTicketId($productAvailability->getTicketProduct()->getId());
$apiTicketAvailability->setName($localizedName);
$apiTicketAvailability->setInfoText($localizedInfoBubbleText);
$apiTicketAvailability->setInfoTextCatalog($localizedCatalogInfoText);
$apiTicketAvailability->setConsumerCategories($this->getConsumerCategories($consumerCategoryData));
$apiTicketAvailability->setPriceByConsumerCategory($consumerCategories);
$apiTicketAvailability->setAcquisitionTypesByConsumerCategory($acquisitionTypesByConsumerCategory);
$apiTicketAvailability->setDefaultAcquisitionType($ticketProduct->getDefaultAcquisitionType());
$apiTicketAvailability->setPersonalization($productAvailability->getTicketProduct()->getRequirements() ?: []);
$apiInsurances = isset($insurances[$productAvailability->getTicketProduct()->getId()]) ? $insurances[$productAvailability->getTicketProduct()->getId()] : [];
$apiTicketAvailability->setInsurances(array_values($apiInsurances));
$apiTicketAvailability->setUpgrades($upgrades);
//delivery prices
$deliveryPrices = [];
if ($countryCode) {
$deliveryPrices[$countryCode] = $apiService->getDeliveryPriceForCountry($countryCode);
} else {
$deliveryPrices = $apiService->getDeliveryPricePerCountry();
}
$apiTicketAvailability->setDeliveryPricePerCountry($deliveryPrices);
$availabilityData[] = $apiTicketAvailability->jsonSerialize();
}
if ($request->get('debug')) {
p_r($availabilityData);
die();
}
return new JsonResponse(
[
'success' => true,
'availabilities' => $availabilityData,
]
);
} catch (\Throwable $throwable) {
$this->bookingapiLogger->error($throwable->getMessage() . 'Stack Trace: ' . $throwable->getTraceAsString());
return $this->sendErrors([$throwable->getMessage()], 500);
}
}
/**
* Get all ticket acquisitionTypes with description
*
* @Route("/acquisitionTypes")
*
* @param Request $request
*
* @return JsonResponse
*
* @OA\Post(
* path="/bookingAPI/ticket/acquisitionTypes",
* description="Get all ticket acquisitionTypes with description",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=false
* ),
*
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="acquisitionTypes", type="array",
*
* @OA\Items(type="object", ref="#/components/schemas/TicketAcquisitionType")
* ),
* )
* )
* ),
*
* @OA\Response(
* response=500,
* description="Error",
* ),
*
* )
*/
public function getAcquisitionTypes(Request $request, ShopService $shopHelper, Translator $translator): JsonResponse
{
$acquisitionTypes = [AcquisitionType::SWISSSPASS, AcquisitionType::BARCODE, AcquisitionType::RELOAD, AcquisitionType::REQUEST, AcquisitionType::TICKETPICKUP];
$returnData = [];
foreach ($acquisitionTypes as $acquisitionType) {
$descriptions = new LocalizedText();
foreach ($this->languages as $language) {
$tk = "shop.acquisition-type." . $acquisitionType . ".info-text";
$translated = $translator->trans($tk, [], null, $language);
$descriptions->$language = $translated != $tk ? $translated : '';
}
$apiAcquisitionType = new TicketAcquisitionType();
$apiAcquisitionType->setAcquisitionType($acquisitionType);
$apiAcquisitionType->setTexts($descriptions);
$returnData[] = $apiAcquisitionType;
}
return new JsonResponse(
[
'success' => true,
'acquisitionTypes' => $returnData,
]
);
}
/**
* Get all possible insurances for a specific ShopTicketCatalog
*
* @Route("/insurances")
*
* @param Request $request
*
* @return JsonResponse
*
* @OA\Post(
* path="/bookingAPI/ticket/insurances",
* description="Get all possible insurances for a specific ShopTicketCatalog",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(
* required={"catalogId","ticketId"},
*
* @OA\Property( property="catalogId", type="int", example=1501805),
* @OA\Property( property="ticketId", type="int", example=518928)
* )
* ),
*
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="insurances", type="array",
*
* @OA\Items(type="object", ref="#/components/schemas/TicketInsurancePrice")
* ),
* )
* )
* ),
*
* @OA\Response(
* response=500,
* description="Error",
* ),
*
* )
*/
public function getInsurances(Request $request, ShopService $shopHelper): JsonResponse
{
try {
$body = $request->getContent();
$requestData = json_decode($body, true);
// only for testing purposes
if (!$requestData && $request->get('debug')) {
$requestData['catalogId'] = 1501805;
$requestData['ticketId'] = 518928;
}
//check for required params
$required = ['ticketId', 'catalogId'];
foreach ($required as $key) {
if (!$requestData || !array_key_exists($key, $requestData) || !$requestData[$key]) {
$this->bookingapiLogger->warning('required data for ticket/insurances endpoint ist missing. missing ' . $key);
return $this->sendErrors([$key . ' missing'], 400);
}
}
$catalog = TicketCatalog::getById($requestData['catalogId']);
if (!$catalog) {
throw new \Exception('ticketCatalog with id ' . $request['catalogId'] . 'not found');
}
$filter = new TicketFilter(Carbon::now());
$filter->setExactDuration(false);
$filter->setUseTicketValidity(true);
$allowedConsumers = [];
foreach ($catalog->getTicketConsumerCategories() as $allowedConsumer) {
$allowedConsumers[] = $allowedConsumer->getId();
}
if ($allowedConsumers) {
$filter->setConsumers($allowedConsumers);
}
$ticketCatalogAvailability = $filter->getTicketCatalogAvailability($catalog, true);
//insurances
$insuranceData = $shopHelper->getInsurancesForProduct($ticketCatalogAvailability);
$insurances = $this->getInsuranceData($catalog, $ticketCatalogAvailability, $insuranceData);
$returnData = [];
if (isset($insurances[$requestData['ticketId']])) {
foreach ($insurances[$requestData['ticketId']] as $ticketInsurancePrice) {
$returnData[] = $ticketInsurancePrice->jsonSerialize();
}
}
if ($request->get('debug')) {
p_r($returnData);
die();
}
return new JsonResponse(
[
'success' => true,
'insurances' => $returnData,
]
);
} catch (\Throwable $throwable) {
$this->bookingapiLogger->error($throwable->getMessage() . 'Stack Trace: ' . $throwable->getTraceAsString());
return $this->sendErrors([$throwable->getMessage()], 500);
}
}
/**
* Keycard validation
*
* @Route("/validateKeycard")
*
* @param Request $request
*
* @return JsonResponse
*
* @OA\Post(
* path="/bookingAPI/ticket/validateKeycard",
* description="validates key card number; if a short number is given, mapping to a skidata key card number is attempted",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(
* required={"keycardNumber"},
*
* @OA\Property( property="keycardNumber", type="string", example="01-11111111111111111111-1 or U111111"),
* )
* ),
*
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="keycardNumber", type="string"),
* @OA\Property(property="keycardShortNumber", type="string"),
* @OA\Property(property="valid", type="boolean"),
* )
* )
*
* ),
*
* @OA\Response(
* response=500,
* description="Error"
* ),
* @OA\Response(
* response=400,
* description="Invalid request - data is missing."
* )
* )
*/
public function validateKeycard(Request $request, ApiService $apiService, OrderService $orderService, ValidatorInterface $validator): JsonResponse
{
try {
$body = $request->getContent();
$requestData = json_decode($body, true);
// only for testing purposes
if (!$requestData && $request->get('debug')) {
$requestData = [
'keycardNumber' => '01-16147133534995632168-4',
];
}
// check for required params
if (!$requestData || !array_key_exists('keycardNumber', $requestData) || !$requestData['keycardNumber']) {
$this->bookingapiLogger->warning('required keycardNumber for ticket/validateKeycard endpoint is missing');
return $this->sendErrors(['keycardNumber missing'], 400);
}
$keycardNr = $requestData['keycardNumber'];
$keycardNumberObj = KeycardNumber::getByShortNumber($keycardNr, 1);
if (strpos($keycardNr, '-') === false) {
//this is a shortNumber - try to map
if ($keycardNumberObj && $keycardNumberObj->getNumber()) {
$keycardNr = $keycardNumberObj->getNumber();
}
}
$valid = $apiService->validateKeycard($orderService, $validator, $keycardNr);
return new JsonResponse(
[
'success' => true,
'keycardNumber' => $keycardNr,
'keycardShortNumber' => $keycardNumberObj ? strval($keycardNumberObj->getShortNumber()) : '',
'valid' => $valid,
]
);
} catch (\Throwable $throwable) {
$this->bookingapiLogger->error($throwable->getMessage() . 'Stack Trace: ' . $throwable->getTraceAsString());
return $this->sendErrors([$throwable->getMessage()], 500);
}
}
/**
* Swisspass validation
*
* @Route("/validateSwisspass")
*
* @param Request $request
*
* @return JsonResponse
*
* @OA\Post(
* path="/bookingAPI/ticket/validateSwisspass",
* description="validates Swisspass number",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(
* required={"swisspassNumber","zip"},
*
* @OA\Property( property="swisspassNumber", type="string", example="S42682117607"),
* @OA\Property( property="zip", type="string", example="3048")
* )
* ),
*
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="valid", type="boolean"),
* )
* )
*
* ),
*
* @OA\Response(
* response=500,
* description="Error"
* ),
* @OA\Response(
* response=400,
* description="Invalid request - data is missing."
* )
* )
*/
public function validateSwisspass(Request $request, ApiService $apiService, OrderService $orderService, ValidatorInterface $validator): JsonResponse
{
try {
$body = $request->getContent();
$requestData = json_decode($body, true);
// only for testing purposes
if (!$requestData && $request->get('debug')) {
$requestData = [
'swisspassNumber' => 'S42682117607',
'zip' => '3048',
];
}
// check for required params
if (!is_array($requestData) || !array_key_exists('swisspassNumber', $requestData) || empty($requestData['swisspassNumber'])) {
$this->bookingapiLogger->warning('required swisspassNumber for ticket/validateSwisspass endpoint is missing');
return $this->sendErrors(['swisspassNumber missing'], 400);
}
if (!is_array($requestData) || !array_key_exists('zip', $requestData) || empty($requestData['zip'])) {
$this->bookingapiLogger->warning('required zip for ticket/validateSwisspass endpoint is missing');
return $this->sendErrors(['zip missing'], 400);
}
$swisspassNumber = $requestData['swisspassNumber'];
$zip = $requestData['zip'];
try {
$valid = $apiService->validateSwisspass($swisspassNumber, $zip);
$success = true;
} catch (\Throwable $throwable) {
$valid = false;
$success = false;
}
return new JsonResponse(
[
'success' => $success,
'valid' => $valid,
]
);
} catch (\Throwable $throwable) {
$this->bookingapiLogger->error($throwable->getMessage() . 'Stack Trace: ' . $throwable->getTraceAsString());
return $this->sendErrors([$throwable->getMessage()], 500);
}
}
/**
* Validate ticket booking data before submitting the order (optional step)
*
* @Route("/validateData")
*
* @OA\Post(
* path="/bookingAPI/ticket/validateData",
* description="Validate ticket item booking data before submitting the order (optional step)",
* tags={"Ticket"},
*
* @OA\RequestBody(
* required=true,
*
* @OA\JsonContent(
* required={"ticket"},
*
* @OA\Property(property="tickets", type="array", @OA\Items(type="object", ref="#/components/schemas/CartItemTicket")),
*
* @OA\Examples(example="ticketExample", value="{""tickets"": [{
""price"": 10,
""ticketId"": 518928,
""catalogId"": 1501805,
""consumerCategoryId"": 502338,
""date"": ""2024-11-30"",
""deliveryType"": ""reload"",
""deliveryCountry"": """",
""firstName"": ""John"",
""lastName"": ""Doe"",
""birthday"": ""2001-01-01"",
""keycardNumber"": ""01-16147133534995632168-4"",
""keycardShortnumber"": """",
""swisspassNumber"": """",
""swisspassZip"": """",
""insuranceId"": 518668
}]}", summary="a valid example for ticket validation")
* )
* ),
* @OA\Response(
* response=200,
* description="Successful operation",
*
* @OA\MediaType(
* mediaType="application/json",
*
* @OA\Schema(
* type = "object",
*
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="valid", type="boolean"),
* @OA\Property(property="errors", type="array",
*
* @OA\Items(type="string", example="keycardNumber missing")
* ),
* )
* )
*
* ),
*
* @OA\Response(
* response=500,
* description="Error"
* ),
* @OA\Response(
* response=400,
* description="Invalid request - data is missing."
* )
* )
*
* @param Request $request
*
* @return JsonResponse
*/
public function validateTicketData(Request $request, ApiService $apiService, OrderService $orderService, ShopService $shopHelper, ValidatorInterface $validator): JsonResponse
{
try {
$body = $request->getContent();
$requestData = json_decode($body, true);
// only for testing purposes
if (!$requestData && $request->get('debug')) {
$requestData = ['tickets' => [[
'ticketId' => 518928,
'catalogId' => 1501805,
'consumerCategoryId' => 502338,
'date' => '2024-11-04',
// "profilePicture" => "string", // TODO TBD
'deliveryType' => 'reload',
'firstName' => 'Michaela',
'lastName' => 'Steyrer',
'birthday' => '2001-08-16',
//'keycardNumber' => '01-16147133534995632168-4',
"keycardShortnumber" => "U123123",
//'insuranceId' => 518668,
'deliveryCountry' => 'CH',
]]];
}
if (!isset($requestData['tickets'])) {
$this->bookingapiLogger->warning('required array tickets for ticket/validateData endpoint is missing');
return $this->sendErrors(['ticket data missing'], 400);
}
$errors = [];
try {
foreach($requestData['tickets'] as $index => $ticketData) {
$cartItemTicket = new CartItemTicket();
$cartItemTicket->unmarshall($ticketData);
$keycardCheck = $this->keyCardNumberShortToLongCheck($cartItemTicket);
if (!$keycardCheck) {
return $this->sendErrors(['could not map keycard short number ' . $cartItemTicket->getKeycardShortnumber()], 500);
}
$errors = array_merge($errors, $apiService->validateTicketData($shopHelper, $orderService, $validator, $cartItemTicket, 'ticket '.($index+1).": "));
}
} catch (DataMappingException $e) {
$errors[] = $e->getMessage();
} catch (DataMissingException $e) {
$this->bookingapiLogger->warning('required data for ticket/validateData endpoint is missing:' . $e->getMessage());
return $this->sendErrors([$e->getMessage()], 400);
}
return new JsonResponse(
[
'success' => true,
'valid' => empty($errors),
'errors' => $errors,
]
);
} catch (\Throwable $throwable) {
$this->bookingapiLogger->error($throwable->getMessage() . 'Stack Trace: ' . $throwable->getTraceAsString());
return $this->sendErrors([$throwable->getMessage()], 500);
}
}
/**
* @param TicketCatalog $catalog
* @param TicketCatalogAvailability $ticketCatalogAvailability
* @param array<mixed> $insuranceData
*
* @return array<int,mixed>
*
* @throws \Exception
*/
protected function getInsuranceData(TicketCatalog $catalog, TicketCatalogAvailability $ticketCatalogAvailability, array $insuranceData): array
{
$insurances = [];
if (isset($insuranceData['insurances'])) {
foreach ($insuranceData['insurances'] as $ticketId => $insuranceProducts) {
foreach ($insuranceProducts as $insuranceProduct) {
/**
* @var TicketProduct $insuranceProduct
*/
$insuranceMetaListing = new TicketshopTicketAdditional\Listing();
$insuranceMetaListing->setCondition("o_id in (select src_id from object_relations_TSF_Additional where dest_id = " . $insuranceProduct->getId() . ")");
$metaListings = $insuranceMetaListing->load();
$descriptionLocalized = new LocalizedText();
$nameLocalized = new LocalizedText();
$groupNameLocalized = new LocalizedText();
$groupId = 0;
foreach ($this->languages as $language) {
if (count($metaListings) > 0) {
$descriptionLocalized->$language = $metaListings[0]->getDescription($language) ?: '';
$groupNameLocalized->$language = $metaListings[0]->getName($language) ?: '';
$groupId = $metaListings[0]->getId();
} else {
$descriptionLocalized->$language = '';
$groupNameLocalized->$language = '';
}
$nameLocalized->$language = $insuranceProduct->getName($language) ?: '';
}
foreach ($ticketCatalogAvailability->getTicketAvailability() as $ticketAvailability) {
if ($ticketAvailability->getTicketProduct()->getId() == $ticketId) {
$insurancePricesPerConsumer = [];
$ticketArticleId = null;
foreach ($ticketAvailability->getSortedConsumerAvailabilities() as $consumerAvailability) {
$insurancePriceInfo = $insuranceProduct->getOSPriceInfo(1, [],
$ticketAvailability->getValidFrom(),
$consumerAvailability->getTicketConsumer(), catalog: $catalog);
$insurancePrice = $insurancePriceInfo->getTotalPrice()->getGrossAmount()->asNumeric();
$insurancePricesPerConsumer[$consumerAvailability->getTicketConsumer()->getId()] = $insurancePrice;
if (!$ticketArticleId || $ticketArticleId === $consumerAvailability->getId()) {
$ticketArticleId = $consumerAvailability->getId();
} else {
continue 2;
//throw new \Exception('Insurance TicketArticle '.$ticketArticleId.' ID is not the same across all consumer availabilities for ticket ' . $ticketAvailability->getTicketProduct()->getId());
}
}
$apiInsurancePrice = new TicketInsurancePrice();
$apiInsurancePrice->insuranceId = $insuranceProduct->getId();
$apiInsurancePrice->ticketArticleId = $ticketArticleId;
$apiInsurancePrice->priceByConsumerCategory = $insurancePricesPerConsumer;
$apiInsurancePrice->name = $nameLocalized;
$apiInsurancePrice->description = $descriptionLocalized;
$apiInsurancePrice->groupName = $groupNameLocalized;
$apiInsurancePrice->groupId = $groupId;
$insurances[$ticketAvailability->getTicketProduct()->getId()][$insuranceProduct->getId()] = $apiInsurancePrice;
}
}
}
}
}
return $insurances;
}
/**
* @param ShopTicketCatalog $catalog
* @param TicketProduct $ticketProduct
* @param Carbon $from
* @param Carbon $to
*
* @return TicketUpgradePrice[]
*
* @throws \Exception
*/
protected function getUpgradeData(ShopTicketCatalog $catalog, TicketProduct $ticketProduct, Carbon $from, Carbon $to): array
{
$metaProduct = $ticketProduct->getMetaProduct();
$relatedProductIds = [];
if($metaProduct){
foreach($metaProduct->getRelatedTo() as $relatedProduct){
$relatedProductIds[]=$relatedProduct->getId();
}
}
$upgradeCatalogKeys = [];
foreach($catalog->getUpgrades() as $objectMetadata){
$upgradeCatalogKeys[$objectMetadata->getObject()->getId()] = $objectMetadata->getData()['name'];
}
$upgrades = [];
foreach ($catalog->getUpgrades() as $upgrade) {
/** @var TicketCatalog $upgradeObject */
$upgradeObject = $upgrade->getObject();
$upgradeFilter = new TicketFilter($from, $to);
$upgradeFilter->setExactDuration(true);
$upgradeFilter->setIgnorePrice(true);
$upgradeFilter->setUseTicketValidity(true);
$upgradeCatalogAvailability = $upgradeFilter->getTicketCatalogAvailability($upgradeObject, false);
if ($upgradeCatalogAvailability->hasAvailability() && !$upgradeObject->getIsNotBookable()) {
//special logic for flex passes where there is no shuttle
$useUpgrade = false;
if ($metaProduct) {
if (array_intersect($metaProduct->getRelatedTo(), $upgradeObject->getTicketProducts())) {
$useUpgrade = true;
}
} else {
$useUpgrade = true;
}
if ($useUpgrade) {
$nameLocalized = new LocalizedText();
$descriptionLocalized = new LocalizedText();
$infoBubbleTextLocalized = new LocalizedText();
foreach ($this->languages as $language) {
$nameLocalized->$language = $upgradeObject->getName($language) ?: '';
$descriptionLocalized->$language = $upgradeObject->getMarketplaceDescription() ?: '';
$infoBubbleTextLocalized->$language = $upgradeObject->getInfoBubbleDescription($language) ?: '';
}
$upgradePricesPerConsumerCategory = [];
$ticketProductId = null;
foreach ($upgradeCatalogAvailability->getTicketAvailability() as $ticketAvailability) {
foreach ($ticketAvailability->getConsumerAvailabilities() as $consumerAvailability) {
$ticketProduct = $consumerAvailability->getTicketProductAvailability()->getTicketProduct();
if ($metaProduct) {
if ($ticketProduct != null && !in_array($ticketProduct->getId(), $relatedProductIds)) {
//this is not a directly related product, ignore
continue;
}
}
foreach ($this->languages as $language) {
if ($ticketProduct->getDescription($language)) {
$infoBubbleTextLocalized->$language = $ticketProduct->getDescription($language);
}
}
if (!$ticketProductId || $ticketProductId === $ticketProduct->getId()) {
$ticketProductId = $ticketProduct->getId();
} else {
continue 2;
//throw new \Exception('Upgrade TicketArticle ID '.$ticketProductId.' is not the same across all consumer availabilities for ticket ' . $ticketAvailability->getTicketProduct()->getId());
}
/** @phpstan-ignore-next-line */
$priceInfo = $ticketProduct->getOSPriceInfo(1, [], $ticketAvailability->getValidFrom(), $consumerAvailability->getTicketConsumer(), $catalog);
$price = $priceInfo->getTotalPrice()->getGrossAmount()->asNumeric();
$upgradePricesPerConsumerCategory[$consumerAvailability->getTicketConsumer()->getId()] = $price;
}
}
$apiUpgradePrice = new TicketUpgradePrice();
$apiUpgradePrice->upgradeId = $upgradeObject->getId();
if(isset($upgradeCatalogKeys[$upgradeObject->getId()])){
$apiUpgradePrice->setUpgradeKey($upgradeCatalogKeys[$upgradeObject->getId()]);
}
$apiUpgradePrice->ticketArticleId = $ticketProductId;
$apiUpgradePrice->priceByConsumerCategory = $upgradePricesPerConsumerCategory;
$apiUpgradePrice->name = $nameLocalized;
$apiUpgradePrice->description = $descriptionLocalized;
$apiUpgradePrice->infoText = $infoBubbleTextLocalized;
$upgrades[] = $apiUpgradePrice;
}
}
}
return $upgrades;
}
}