<?php
declare(strict_types=1);
namespace App\Controller\V1\User;
use App\Entity\Local\GiftCard;
use App\Entity\Local\Response\PaymentStartResponse;
use App\Entity\Vista\Booking;
use App\Entity\Vista\CancelBookingResponse;
use App\Entity\Vista\LoyaltyMember;
use App\Entity\Vista\VistaApiV2Response;
use App\Exceptions\PaymentException;
use App\Helper\MPay24Helper;
use App\Helper\PaymentHelper;
use App\Helper\OrderPaymentHelper;
use App\Manager\SessionDetailsManager;
use App\Helper\UserHelper;
use App\Repository\BookingRepository;
use App\Repository\CinemaRepository;
use App\Repository\GiftCardsRepository;
use App\Repository\MailingRepositoryInterface as MailingRepository;
use App\Repository\RestrictionsRepository;
use App\Repository\SessionRepositoryInterface;
use App\Repository\UserBalanceTransactionRepository;
use FOS\RestBundle\Controller\Annotations as Rest;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security as NelmioSecurity;
use Swagger\Annotations as SWG;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use App\Security\Security as CoreSecurity;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Psr\Log\LoggerInterface;
/**
* @Rest\Route("/users/bookings")
* @SWG\Tag(name="Booking_v1")
*/
class BookingController
{
/** @var BookingRepository */
protected $bookingRepository;
/** @var UserHelper */
protected $userHelper;
/** @var MPay24Helper */
protected $mPay24Helper;
/** @var PaymentHelper */
protected $paymentHelper;
/** @var OrderPaymentHelper */
protected $orderPaymentHelper;
/** @var CinemaRepository */
protected $cinemaRepository;
/** @var UserBalanceTransactionRepository */
protected $balanceTransactionRepository;
/** @var RestrictionsRepository */
protected $restrictionsRepository;
/** @var SessionDetailsManager */
protected $sessionDetailsHelper;
/** @var SessionRepositoryInterface */
protected $sessionRepository;
/** @var MailingRepository */
protected $mailer;
/** @var GiftCardsRepository */
private $giftCardsRepository;
/** @var LoggerInterface */
protected $logger;
public function __construct(
BookingRepository $bookingRepository,
UserHelper $userHelper,
MPay24Helper $mPay24Helper,
PaymentHelper $paymentHelper,
OrderPaymentHelper $orderPaymentHelper,
CinemaRepository $cinemaRepository,
UserBalanceTransactionRepository $balanceTransactionRepository,
RestrictionsRepository $restrictionsRepository,
SessionRepositoryInterface $sessionRepository,
SessionDetailsManager $sessionDetailsHelper,
MailingRepository $mailer,
GiftCardsRepository $giftCardsRepository,
LoggerInterface $logger
) {
$this->bookingRepository = $bookingRepository;
$this->userHelper = $userHelper;
$this->mPay24Helper = $mPay24Helper;
$this->paymentHelper = $paymentHelper;
$this->orderPaymentHelper = $orderPaymentHelper;
$this->cinemaRepository = $cinemaRepository;
$this->balanceTransactionRepository = $balanceTransactionRepository;
$this->restrictionsRepository = $restrictionsRepository;
$this->sessionDetailsHelper = $sessionDetailsHelper;
$this->sessionRepository = $sessionRepository;
$this->mailer = $mailer;
$this->giftCardsRepository = $giftCardsRepository;
$this->logger = $logger;
}
/**
* @Rest\Route("", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @SWG\Schema(type="array", items=@SWG\Items(ref=@Model(type=\App\Entity\Vista\Booking::class))))
*
* @param CoreSecurity $security
* @return array
* @throws \Throwable
*/
public function indexAction(CoreSecurity $security)
{
/** @var LoyaltyMember $securityUser */
$securityUser = $security->getUser();
/** @var LoyaltyMember $user */
$user = $this->userHelper->requestUser($securityUser->getMemberId());
$result = $this->bookingRepository->getAllByUserButLegacy($user);
$this->logger->info('found '. count($result) . ' valid bookings');
return $result;
}
/**
* @Rest\Route("/cinema/{cinemaId}", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @SWG\Schema(type="array", items=@SWG\Items(ref=@Model(type=\App\Entity\Vista\Booking::class)))))
*
* @param CoreSecurity $security
* @param int $cinemaId
* @return array
* @throws \Throwable
*/
public function getByCinemaId(CoreSecurity $security, int $cinemaId)
{
/** @var LoyaltyMember $user */
$user = $security->getUser();
$this->userHelper->validate($user);
return $this->bookingRepository->getAllByUser($user, $cinemaId);
}
/**
* @Rest\Route("/tickets", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @SWG\Schema(type="array", items=@SWG\Items(ref=@Model(type=\App\Entity\Vista\Booking::class)))))
*
* @param CoreSecurity $security
* @return array
* @throws \Throwable
*/
public function getTicketsAction(CoreSecurity $security)
{
/** @var LoyaltyMember $user */
$user = $security->getUser();
$this->userHelper->validate($user);
return array_values($this->bookingRepository->getAllByUserButLegacy($user));
}
/**
* @Route("/pdf/{cinemaId}/{bookingId}", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success")
*
* @param CoreSecurity $security
* @param string $bookingId
* @param string $cinemaId
* @return Response
*/
public function bookingPdfAction(CoreSecurity $security, string $bookingId, string $cinemaId)
{
$booking = $this->bookingRepository->getById($bookingId, $cinemaId);
if (null === $booking) {
throw new NotFoundHttpException();
}
/** @var LoyaltyMember $user */
$user = $security->getUser();
$param = [];
$param['cinemaId'] = $booking->getCinemaId();
if ($booking->getTickets()) {
$param['sessionId'] = $booking->getTickets()[0]->getSessionId();
}
$session = $this->sessionRepository->findOneBy($param);
$pdf = $this->mailer->downloadTicketPdf($booking, $session, $user, null);
$response = new Response($pdf->getBody()->getContents());
$response->headers->set('Content-type', 'application/pdf');
return $response;
}
/**
* Perform payment
*
* @Rest\Route("/{bookingNumber}/payment", methods={"POST"})
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Local\Response\PaymentStartResponse::class))
*
* @param int $bookingNumber
* @param CoreSecurity $security
*
* @return PaymentStartResponse
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
* @throws \Throwable
*/
public function paymentAction(int $bookingNumber, CoreSecurity $security)
{
/** @var LoyaltyMember $user */
$user = $security->getUser();
$this->userHelper->validate($user);
$booking = $this->bookingRepository->findBooking($bookingNumber, $user);
if (null === $booking) {
throw new \InvalidArgumentException('Invalid booking id');
}
if ($booking->isPaid()) {
throw PaymentException::create(
'The booking is already paid',
PaymentException::CODE_PAYMENT_BOOKING_IS_PAID
);
}
$restrictions = $this->restrictionsRepository->findOrCreate();
//error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'), __METHOD__, __LINE__) . " paymentId(ordeId) {$booking->getPaymentId()}");
if(getenv('RAIFFEISEN_ADDRESS')) { /* Raiffeisen */
$paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' . getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
sprintf("/api/v1/orders/bkn-%s/payment/raiffeisen-redirect/%s/%s/%s", $booking->getPaymentId(), $this->paymentHelper->startBookingPayment($booking, $user), $booking->getTotalValueCents(), $booking->getCinemaId());
} else if(getenv('CPAY_ADDRESS')) { /* cPay */
$paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' . getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
sprintf("/api/v1/orders/%s/payment/cpay-booking/%s/%s/%s", $booking->getPaymentId(), $this->paymentHelper->startBookingPayment($booking, $user), $booking->getTotalValueCents(), $booking->getCinemaId());
} else if(getenv('KOM_BANK_ADDRESS')) {
$paymentPageUrl = (getenv('DEV_SIRMA') ? 'http://' . getenv('DEV_SIRMA') : getenv('SCHEME_AND_HTTP_HOST')) .
sprintf("/api/v1/orders/%s/payment/kom-bank-booking/%s/%s/%s", $booking->getPaymentId(), $this->paymentHelper->startBookingPayment($booking, $user), $booking->getTotalValueCents(), $booking->getCinemaId());
} else { /* mpay24 */
$paymentPageUrl = $this->mPay24Helper->startBookingPayment($booking, $user);
}
return (new PaymentStartResponse())
->setPaymentPageUrl($paymentPageUrl)
->setOrderId(null)
->setRestrictions($restrictions);
}
/**
* Perform payment with bonus card
*
* @Rest\Route("/{bookingNumber}/payment-with-bonus-card", methods={"POST"})
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\Booking::class))
*
* @param int $bookingNumber
* @param CoreSecurity $security
* @return mixed
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Throwable
*/
public function paymentBonusCardAction(int $bookingNumber, CoreSecurity $security)
{
/** @var LoyaltyMember $loyaltyMember */
$loyaltyMember = $security->getUser();
/** @var Booking $booking */
if (null === ($booking = $this->bookingRepository->findBooking($bookingNumber, $loyaltyMember))) {
throw new \InvalidArgumentException('Invalid booking id');
}
if ($booking->isPaid()) {
throw PaymentException::create(
'The booking is already paid',
PaymentException::CODE_PAYMENT_BOOKING_IS_PAID
);
}
$this->userHelper->validate($loyaltyMember);
$session = $this->sessionDetailsHelper->getById(sprintf(
'%s-%s',
$booking->getCinemaId(),
$booking->getTickets()[0]->getSessionId()
));
return $this->orderPaymentHelper->makePaymentForBookingWithBonusCard(
$loyaltyMember,
$booking,
$session
);
}
/**
* Perform payment with gift cards
*
* @Rest\Route("/{bookingNumber}/payment-with-gift-card", methods={"POST"})
* @ParamConverter("giftcards", converter="fos_rest.request_body", class="array")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\Booking::class))
*
* @param int $bookingNumber
* @param array $giftcards
* @param CoreSecurity $security
* @return mixed
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Throwable
*/
public function paymentGiftCardAction(int $bookingNumber, $giftcards, CoreSecurity $security)
{
/** @var LoyaltyMember $loyaltyMember */
$loyaltyMember = $security->getUser();
$this->logger->debug('paying booking with ' .count($giftcards) . ' giftcard(s)');
$usedgiftcards=[];
foreach($giftcards as $gcitem){
$gc=(new GiftCard)
->setNumber($gcitem['Number'])
->setValueInCents($this->giftCardsRepository->getGiftCardValue($gcitem['Number']));
$usedgiftcards[]=$gc;
}
usort($usedgiftcards, function($a, $b){
return $a->getValueInCents() - $b->getValueInCents();
});
$this->logger->debug('found '.count($usedgiftcards). ' giftcards and sorted them');
$this->logger->debug('searching booking '.$bookingNumber);
/** @var Booking $booking */
if (null === ($booking = $this->bookingRepository->findBooking($bookingNumber, $loyaltyMember))) {
throw new \InvalidArgumentException('Invalid booking id');
}
if ($booking->isPaid()) {
throw PaymentException::create(
'The booking is already paid',
PaymentException::CODE_PAYMENT_BOOKING_IS_PAID
);
}
$this->logger->debug('requested booking found and booking is still not paid');
$this->userHelper->validate($loyaltyMember);
$session = $this->sessionDetailsHelper->getById(sprintf(
'%s-%s',
$booking->getCinemaId(),
$booking->getTickets()[0]->getSessionId()
));
return $this->orderPaymentHelper->makePaymentForBookingWithGiftCard(
$loyaltyMember,
$usedgiftcards,
$booking,
$session
);
}
/**
* Finish payment
*
* @Rest\Route("/{orderId}/payment-finish-kombank/{hash}/{result}", methods={"POST"}, name="booking_finish_kombank")
*
* @SWG\Response(response="200", description="Success")
*
* @param $orderId
* @param $hash
* @param $result
* @return Response
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Throwable
*/
public function paymentFinishKombank($orderId, $hash, $result) {
$queryParams = $_POST;
$transaction = $this->paymentHelper->getTransaction($orderId);
$memberId = $transaction->getMemberId();
$member = (new LoyaltyMember())->setMemberId($memberId);
$user = $this->userHelper->validate($member);
$booking = $this->bookingRepository->findBooking((int) $transaction->getVistaBookingNumber(), $user);
if (null === $booking) {
throw new \InvalidArgumentException(sprintf(
'Invalid transaction, booking with number %s doesn\'t exist',
$transaction->getVistaBookingNumber()
));
}
if ($booking->isPaid() && 'success' === $result) {
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
if ('success' === $result) {
$queryParams['STATUS'] = 'BILLED';
} else {
$queryParams['STATUS'] = 'FAILED';
}
if (!$booking->isPaid() && 'success' === $result) {
$this->paymentHelper->finishPayment($booking, $hash, $queryParams);
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
/**
* Finish payment
*
* @Rest\Route("/{orderId}/payment-finish-cpay/{hash}/{result}", methods={"POST"}, name="booking_finish_cpay")
*
* @SWG\Response(response="200", description="Success")
*
* @param $orderId
* @param $hash
* @param $result
* @return Response
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Throwable
*/
public function paymentFinishCpay($orderId, $hash, $result) {
$queryParams = $_POST;
//error_log(sprintf("%s %s(%s) ", date('Y-m-d H:i:s'), __METHOD__, __LINE__) . var_export($queryParams, true));
$transaction = $this->paymentHelper->getTransaction($orderId);
$memberId = $transaction->getMemberId();
$member = (new LoyaltyMember())->setMemberId($memberId);
$user = $this->userHelper->validate($member);
$booking = $this->bookingRepository->findBooking((int) $transaction->getVistaBookingNumber(), $user);
if (null === $booking) {
throw new \InvalidArgumentException(sprintf(
'Invalid transaction, booking with number %s doesn\'t exist',
$transaction->getVistaBookingNumber()
));
}
if ($booking->isPaid() && 'success' === $result) {
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
if ('success' === $result) {
$queryParams['STATUS'] = 'BILLED';
} else {
$queryParams['STATUS'] = 'FAILED';
}
if (!$booking->isPaid() && 'success' === $result) {
$this->paymentHelper->finishPayment($booking, $hash, $queryParams);
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
return new RedirectResponse(sprintf(
'%s/purchase/payment/%s',
getenv('WEBSITE_SCHEME_AND_HTTP_HOST'),
$result
));
}
/**
* Finish payment
*
* @Rest\Route("/{orderId}/payment-finish/{hash}", methods={"GET"}, name="booking_finish")
*
* @SWG\Response(response="200", description="Success")
*
* @param $orderId
* @param $hash
* @param Request $request
* @return Response
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Throwable
*/
public function paymentFinishAction($orderId, $hash, Request $request)
{
$transaction = $this->mPay24Helper->getTransaction($orderId);
$memberId = $transaction->getMemberId();
$member = (new LoyaltyMember())->setMemberId($memberId);
$user = $this->userHelper->validate($member);
// find booking ignoring filters like pickup time
$booking = $this->bookingRepository->findBooking((int) $transaction->getVistaBookingNumber(), $user, true);
if (null === $booking) {
throw new \InvalidArgumentException(sprintf(
'Invalid transaction, booking with number %s doesn\'t exist',
$transaction->getVistaBookingNumber()
));
}
if ($booking->isPaid()) {
return new Response(MPay24Helper::PAYMENT_RESPONSE_OK);
}
$result = $this->mPay24Helper->finishPayment($booking, $hash, $request->query->all());
return new Response($result->getResponse());
}
/**
* @Rest\Route("/get-single/{cinemaId}/{bookingId}", methods={"GET"})
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\Booking::class))
*
* @param $bookingId
* @param $cinemaId
* @return mixed
*/
public function getByIdCinemaAction($bookingId, $cinemaId)
{
return $this->bookingRepository->getById($bookingId, $cinemaId);
}
/**
* @Rest\Route("/cancel/{cinemaId}/{bookingNumber}", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\CancelBookingResponse::class))
*
* @param $cinemaId
* @param $bookingNumber
* @return CancelBookingResponse
*/
public function cancelAction($cinemaId, $bookingNumber)
{
return $this->bookingRepository->cancel($cinemaId, $bookingNumber);
}
/**
* @Rest\Route("/refund/{cinemaId}/{bookingNumber}", methods={"GET"})
* @NelmioSecurity(name="Bearer")
* @Rest\View()
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\CancelBookingResponse::class))
*
* @param $cinemaId
* @param $bookingNumber
* @param CoreSecurity $security
* @return VistaApiV2Response
*/
public function refundAction($cinemaId, $bookingNumber, CoreSecurity $security)
{
return $this->bookingRepository->refund($security->getUser(), $cinemaId, $bookingNumber);
}
/**
* @Rest\Route("/refundanonym/{bookingNumber}", methods={"POST"})
* @Rest\View()
*
* @SWG\Parameter(
* name="body",
* in="body",
* @SWG\Schema(type="object",
* @SWG\Property(property="email", type="string")))
*
* @SWG\Response(
* response="200",
* description="Success",
* @Model(type=\App\Entity\Vista\CancelBookingResponse::class))
*
* @param Request $request
* @return VistaApiV2Response
*/
public function refundanonymAction(Request $request)
{
return $this->bookingRepository->refundanonym($request->get('email'), $request->get('bookingNumber'));
}
}