<?php
declare(strict_types=1);
namespace App\Controller\V1;
use App\Entity\Vista\ConcessionItem;
use App\Entity\Local\Response\SetTicketsOnServerResponse;
use App\Entity\Local\SetConcessionsRequest;
use App\Entity\Vista\DTO\TicketDTO;
use App\Entity\Vista\LoyaltyMember;
use App\Entity\Vista\Order;
use App\Entity\Vista\OrderConcessionItem;
use App\Form\OrderTicketType;
use App\Helper\MPay24Helper;
use App\Manager\SeatPlanManager;
use App\Helper\UserHelper;
use App\Repository\CinemaRepository;
use App\Repository\OrderRepositoryInterface;
use App\Repository\SessionRepositoryInterface;
use FOS\RestBundle\Controller\Annotations\View;
use InvalidArgumentException;
use Nelmio\ApiDocBundle\Annotation\Model;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Swagger\Annotations as SWG;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use App\Security\Security as CoreSecurity;
use App\Helper\PaymentHelper;
use Symfony\Component\Yaml\Yaml;
use Psr\Log\LoggerInterface;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectRepository;
/**
* @Route("/orders")
* @SWG\Tag(name="Order_v1")
*/
class OrderController
{
/** @var ObjectRepository */
protected $concessionDbRepository;
/** @var OrderRepositoryInterface */
protected $orderRepository;
/** @var UserHelper */
protected $userHelper;
/** @var MPay24Helper */
protected $mPay24Helper;
/** @var PaymentHelper */
protected $paymentHelper;
/** @var SeatPlanManager */
protected $seatPlanManager;
/** @var CinemaRepository */
protected $cinemaRepository;
/** @var SessionRepositoryInterface */
private $sessionRepository;
/** @var FormFactoryInterface */
private $formFactory;
/** @var LoggerInterface */
private $logger;
/** @var string */
protected $rootDir;
public function __construct(
OrderRepositoryInterface $orderRepository,
UserHelper $userHelper,
MPay24Helper $mPay24Helper,
PaymentHelper $paymentHelper,
SeatPlanManager $seatPlanManager,
CinemaRepository $cinemaRepository,
SessionRepositoryInterface $sessionRepository,
FormFactoryInterface $formFactory,
LoggerInterface $logger,
string $rootDir,
ManagerRegistry $managerRegistry
) {
$this->orderRepository = $orderRepository;
$this->userHelper = $userHelper;
$this->mPay24Helper = $mPay24Helper;
$this->paymentHelper = $paymentHelper;
$this->seatPlanManager = $seatPlanManager;
$this->cinemaRepository = $cinemaRepository;
$this->sessionRepository = $sessionRepository;
$this->formFactory = $formFactory;
$this->logger = $logger;
$this->rootDir = $rootDir;
$this->concessionDbRepository = $managerRegistry->getRepository(ConcessionItem::class);
}
/**
* @Route("", methods={"POST"})
* @ParamConverter("order", converter="fos_rest.request_body")
* @View(statusCode=201)
*
* @SWG\Response(
* response="201",
* description="Order successfully created",
* @Model(type=\App\Entity\Vista\Order::class))
* @SWG\Response(
* response="400",
* description="Invalid request data")
* @SWG\Parameter(
* name="body",
* in="body",
* @SWG\Schema(type="object",
* @SWG\Property(property="cinemaId", type="string")))
*
* @param Order $order
* @param CoreSecurity $security
* @return Order
*/
public function createAction(Order $order, CoreSecurity $security)
{
/** @var LoyaltyMember $user */
if ($user = $security->getUser()) {
$country = getenv('APP_COUNTRY');
if (!$user->getValidatedFiscaliazionLaw() && $country === 'rou') {
$response = $this->userHelper->validateFiscaliazionLaw($user);
if ($response['status']) {
throw new InvalidArgumentException($response['message']);
}
}
try {
$existingOrder = $this->orderRepository->findBySessionId($user->getUserSessionId());
$this->orderRepository->cancel($existingOrder);
} catch (\Exception $ex) {
}
}
if (($cinema = $this->cinemaRepository->find($order->getCinemaId())) === null) {
throw new InvalidArgumentException('Invalid cinema id');
}
$order->setCinemaName($cinema->getName());
$order = $this->orderRepository->create($order);
if ($user instanceof LoyaltyMember) {
$user->setValidatedFiscaliazionLaw(true);
$order->setUser($user);
$this->userHelper->validate($user, $order->getUserSessionId());
}
return $order;
}
/**
* @Route("/{orderId}/sessions/{sessionId}/tickets", methods={"POST"})
* @View(statusCode=201)
*
* @SWG\Response(
* response="201",
* description="Seats successfully selected",
* @Model(type=App\Entity\Local\Response\SetTicketsOnServerResponse::class))
* @SWG\Response(
* response="400",
* description="Invalid request data")
* @SWG\Parameter(
* name="body",
* in="body",
* @SWG\Schema(type="object",
* @SWG\Property(property="isBonusCard", type="boolean"),
* @SWG\Property(property="numberOfSeats", type="integer"),
* @SWG\Property(property="numberOfChildSeats", type="integer"),
* @SWG\Property(property="numberOfReducedSeats", type="integer"),
* @SWG\Property(property="numberOfFilmBrunchSeats", type="integer"),
* @SWG\Property(property="numberOfFilmBrunchChildSeats", type="integer"),
* @SWG\Property(property="numberOfCBCCar", type="integer"),
* @SWG\Property(property="numberOfCar", type="integer"),
* @SWG\Property(property="numberOfAdditionalCar", type="integer"),
* @SWG\Property(property="seats", type="array", @SWG\Items(type="object",
* @SWG\Property(property="areaNumber", type="integer"),
* @SWG\Property(property="rowIndex", type="integer"),
* @SWG\Property(property="columnIndex", type="integer")))))
*
* @codeCoverageIgnore
*
* @param $orderId
* @param $sessionId
* @param Request $request
* @return Order|\Symfony\Component\Form\FormInterface
*/
public function ticketsAction($orderId, $sessionId, Request $request)
{
$this->logger->info('profiling seat selection :: entering ticketsAction for order ' . $orderId);
$start = microtime(true);
$response = $this->ticketsOnServerAction($orderId, $sessionId, $request);
$this->logger->info(sprintf("profiling seat selection :: ticketsOnServerAction execution time: %f", microtime(true) - $start));
$this->logger->info('profiling seat selection :: exiting ticketsAction for order ' . $orderId);
return $response;
}
/**
* @Route("/{orderId}/sessions/{sessionId}/tickets-on-server", methods={"POST"})
* @View(statusCode=201)
*
* @SWG\Parameter(
* name="body",
* in="body",
* @SWG\Schema(type="object",
* @SWG\Property(property="isBonusCard", type="boolean"),
* @SWG\Property(property="numberOfSeats", type="integer"),
* @SWG\Property(property="numberOfChildSeats", type="integer"),
* @SWG\Property(property="numberOfReducedSeats", type="integer"),
* @SWG\Property(property="numberOfPackageReducedSeats", type="integer"),
* @SWG\Property(property="numberOfPackageRegularSeats", type="integer"),
* @SWG\Property(property="numberOfPackageClubSeats", type="integer"),
* @SWG\Property(property="numberOfPackageChildSeats", type="integer"),
* @SWG\Property(property="numberOfPackageWheelchairSeats", type="integer"),
* @SWG\Property(property="numberOfFilmBrunchSeats", type="integer"),
* @SWG\Property(property="numberOfFilmBrunchChildSeats", type="integer"),
* @SWG\Property(property="numberOfCBCCar", type="integer"),
* @SWG\Property(property="numberOfCar", type="integer"),
* @SWG\Property(property="numberOfAdditionalCar", type="integer"),
* @SWG\Property(property="seats", type="array", @SWG\Items(type="object",
* @SWG\Property(property="areaNumber", type="integer"),
* @SWG\Property(property="rowIndex", type="integer"),
* @SWG\Property(property="columnIndex", type="integer")))))
* @SWG\Response(
* response="201",
* description="Seats successfully selected",
* @Model(type=App\Entity\Local\Response\SetTicketsOnServerResponse::class))
* @SWG\Response(
* response="400",
* description="Invalid request data")
*
* @param $orderId
* @param $sessionId
* @param Request $request
*
* @return SetTicketsOnServerResponse|\Symfony\Component\Form\FormInterface
*/
public function ticketsOnServerAction($orderId, $sessionId, Request $request)
{
$start = microtime(true);
/** @var Order $order */
$order = $this->getAction($orderId);
$cinemaId = $order->getCinemaId();
$session = $this->sessionRepository->findOneBy([
'sessionId' => $sessionId,
'cinemaId' => $cinemaId
]);
if (!$session){
// read drive in cinema mapping config
$di_mapping = Yaml::parseFile($this->rootDir.'/config/drive_in_mapping.yml');
// search session with drive-in cinema id if not found with real cinema id
foreach ($di_mapping as $map) {
if ($cinemaId === $map['host_cinema_id']) {
$cinemaId = $map['drive_in_cinema_id'];
break;
}
}
$session = $this->sessionRepository->findOneBy([
'sessionId' => $sessionId,
'cinemaId' => $cinemaId
]);
}
if (!$session){
throw "session not available";
}
// set cinemname from session to have the correct name, even with drive-in cinemas
$order->setCinemaName($session->getCinemaName());
$ticketDTO = new TicketDTO($sessionId, $order->getCinemaId());
$form = $this->formFactory->create(OrderTicketType::class, $ticketDTO);
/** @var array $data */
$data = $request->request->all();
// prepare vista index to reserve seat(s);
$rowsSaved = false;
//error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'), __METHOD__, __LINE__) . var_export($rowsSaved, true));
//error_log(sprintf("%s %s(%s) before form submit", date('Y-m-d H:i:s'), __METHOD__, __LINE__));
for($i = 0; $i < count($data['seats']); $i++) {
if ($data['seats'][$i]['rowIndex'] == 0 && $data['seats'][$i]['areaNumber'] == 2) {
error_log(sprintf("%s %s(%s) i data[$i] ", date('Y-m-d H:i:s'), __METHOD__, __LINE__) . json_encode($data));
}
if(isset($data['seats'][$i]['columnIndexVista'])) {
$data['seats'][$i]['columnIndex'] = $data['seats'][$i]['columnIndexVista'];
unset($data['seats'][$i]['columnIndexVista']);
unset($data['seats'][$i]['columnIndexRender']);
} else {
if($rowsSaved === false) {
$start = microtime(true);
$rowsSaved = $this->seatPlanManager->getSavedRows($sessionId, $cinemaId, $session->getScreenNumber());
$this->logger->info(sprintf("profiling seat selection :: getSavedRows execution time: %f", microtime(true) - $start));
}
if($rowsSaved) {
$found = false;
foreach($rowsSaved as $rowSaved) {
foreach($rowSaved->getSeats() as $seatSaved) {
if($data['seats'][$i]['columnIndex'] == $seatSaved->getPosition()->getColumnIndexRender() &&
$data['seats'][$i]['areaNumber'] == $seatSaved->getPosition()->getAreaNumber() &&
$data['seats'][$i]['rowIndex'] == $seatSaved->getPosition()->getRowIndex()) {
$data['seats'][$i]['columnIndex'] = $seatSaved->getPosition()->getColumnIndexVista();
$found = true;
// if ($data['seats'][$i]['rowIndex'] == 8 && $data['seats'][$i]['areaNumber'] == 1 && $seatSaved->getPosition()->getColumnIndexVista() == 16) {
// error_log(sprintf("%s %s(%s) i data[$i] ", date('Y-m-d H:i:s'), __METHOD__, __LINE__) . json_encode($data));
// }
break;
}
}
if($found) {
break;
}
}
}
}
}
$form->submit($data);
if (!$form->isSubmitted() || !$form->isValid()) {
return $form;
}
$setTicketsResponse = $this->seatPlanManager->setTickets($order, $session, $ticketDTO);
$this->logger->info(sprintf("profiling seat selection :: seatPlanManager->setTickets execution time: %f", microtime(true) - $start));
return $setTicketsResponse;
}
/**
* @Route("/{orderId}/concessions-on-server", methods={"POST"})
* @View(statusCode=201)
*
* @SWG\Parameter(
* name="body",
* in="body",
* @SWG\Schema(type="object",
* @SWG\Property(property="orderConcessionItems", type="array", @SWG\Items(type="object",
* @SWG\Property(property="numberOfConcessionItem", type="integer"),
* @SWG\Property(property="cinemaId", type="string"),
* @SWG\Property(property="itemId", type="string")))))
* @SWG\Response(
* response="201",
* description="Concessions successfully added",
* @Model(type=App\Entity\Local\Response\SetTicketsOnServerResponse::class))
* @SWG\Response(
* response="400",
* description="Invalid request data")
*
* @param $orderId
* @param Request $request
*
* @return SetTicketsOnServerResponse|\Symfony\Component\Form\FormInterface
*/
public function concessionsOnServerAction($orderId, Request $request)
{
/** @var Order $order */
$order = $this->getAction($orderId);
$requestedConcessionItems=$request->get('orderConcessionItems');
/** @var OrderConcessionItem[] $orderConcessionItems */
$orderConcessionItems = [];
foreach ($requestedConcessionItems as $concessionItem){
$orderConcessionItems[] = (new OrderConcessionItem())
->setItemId($concessionItem['itemId'])
->setQuantity($concessionItem['numberOfConcessionItem']);
}
$order->setOrderConcessionItem($orderConcessionItems);
$order = $this->orderRepository->setConcessions($order, (new SetConcessionsRequest())->setConcessionItems($orderConcessionItems));
$this->orderRepository->save($order);
return (new SetTicketsOnServerResponse())->setOrder($order);
}
/**
* Remove all concessions from order
*
* @Route("/{orderId}/remove-concessions", methods={"DELETE"})
* @View()
*
* @SWG\Response(
* response="200",
* description="Concessions have been successfully removed from order",
* @Model(type=\App\Entity\Vista\Order::class))
*
* @param $orderId
* @return bool
*/
public function removeConcessions($orderId)
{
if($order = $this->getAction($orderId)){
$this->orderRepository->removeConcessions($order);
$this->orderRepository->save($order);
return true;
}
return false;
}
/**
* Cancel order
*
* @Route("/{orderId}", methods={"DELETE"})
* @View()
*
* @SWG\Response(
* response="200",
* description="Order has been successfully canceled",
* @Model(type=\App\Entity\Vista\Order::class))
*
* @param $orderId
* @return bool
*/
public function cancelAction($orderId)
{
$order = $this->orderRepository->findOneBy(['userSessionId' => $orderId]);
if (getenv('KOM_BANK_ADDRESS') || getenv('RAIFFEISEN_ADDRESS') || getenv('CPAY_ADDRESS')) {
if ($this->paymentHelper->canBeCanceled($order)) {
$this->orderRepository->cancel($order);
return true;
}
} else {
if ($this->mPay24Helper->canBeCanceled($order)) {
$this->orderRepository->cancel($order);
return true;
}
}
return false;
}
/**
* @Route("/{orderId}", methods={"GET"})
* @View()
*
* @SWG\Response(
* response=200,
* description="Order",
* @Model(type=\App\Entity\Vista\Order::class))
*
* @param $orderId
* @return Order
*/
public function getAction($orderId)
{
return $this->orderRepository->findBySessionId($orderId);
}
}