<?php
namespace App\Controller;
use App\Entity\Answer;
use App\Entity\Entrada;
use App\Entity\Event;
use App\Entity\Question;
use App\Entity\Ticket;
use App\Entity\User;
use App\Helper\Helpers;
use App\Helper\RedsysAPI;
use App\Helper\Tpv;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use DateTime;
use DateInterval;
class BuyTicketController extends Controller
{
private $kc = 'FxPwz4Pqmrrgkp72vFjWR8ztuvegrkxx';
/**
* @Route("/entradas/{eventId}", name="entradas")
*/
public function entradas($eventId, $error = "")
{
$repositoryEvent = $this->getDoctrine()->getRepository(Event::class);
$repositoryEntrada = $this->getDoctrine()->getRepository(Entrada::class);
$repTicket = $this->getDoctrine()->getRepository(Ticket::class);
//$securityContext = $this->container->get('security.authorization_checker');
//$shop = $securityContext->isGranted('ROLE_SHOP');
$event = $repositoryEvent->findOneById($eventId);
if (!$event) {
return $this->redirectToRoute('main');
}
if(isset($_GET['error'])){
$error = $_GET['error'];
}
$user = $this->get('security.token_storage')->getToken()->getUser();
$shop = Helpers::checkCrendentials('ROLE_SHOP', $event, $user, $this->get('security.authorization_checker'));
if ($event->getHidden() && !Helpers::checkCrendentials('ROLE_OWNER', $event, $user, $this->get('security.authorization_checker'))) {
return $this->redirectToRoute('main');
}
// $shop = $user->isRelated($event,'ROLE_SHOP',$this->container->get('security.authorization_checker'));
$entradas = $repositoryEntrada->findAllByEventNotHidden($event);
if (Helpers::checkCrendentials('ROLE_OWNER', $event, $user, $this->get('security.authorization_checker'))) {
$entradas = $repositoryEntrada->findAllByEvent($event);
}
$numTickets = $this->checkAvailable($entradas);
$paypal = $event->getPaypal();
$clientID = $event->getClientID();
return $this->render('buy_ticket/index.html.twig', [
'controller_name' => 'BuyTicketController',
'event' => $event,
'entradas' => $entradas,
'numTickets' => $numTickets,
'error' => $error,
'shop' => $shop,
'paypal' => $paypal,
'clientID' => $clientID,
]);
}
public function checkAvailable($entradas)
{
$numTickets = [];
foreach ($entradas as $key => $entrada) {
//encontrar el numero de entradas vendidas de este tipo en este momento
$entityManager = $this->getDoctrine()->getManager();
$repTicket = $this->getDoctrine()->getRepository(Ticket::class);
$numTickets[$entrada->getId()]['sold'] = $repTicket->getNumTickets($entrada);
$numTickets[$entrada->getId()]['reserved'] = $repTicket->getNumReserved($entrada);
}
return $numTickets;
}
/**
* This function ask questions from each ticket
* @Route("/prebuy_ticket/{entrada}", name="prebuy_ticket")
*/
public function prebuy_ticket($entrada)
{
$securityContext = $this->container->get('security.authorization_checker');
$user = $this->get('security.token_storage')->getToken()->getUser();
$repTicket = $this->getDoctrine()->getRepository(Ticket::class);
$repEntrada = $this->getDoctrine()->getRepository(Entrada::class);
$entrada = $repEntrada->find($entrada);
if (!$securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('login');
}
$entityManager = $this->getDoctrine()->getManager();
//RECOGEMOS LAS VARIABLES POST
if (isset($_POST['quantity']) && is_numeric($_POST['quantity'])) {
$quantity = $_POST['quantity'];
} else {
return $this->entradas($entrada->getEvent()->getName(), "Cantidad de entradas errónea");
}
//si el SHOP ha seleccionado cash shop se pone a 1
if (isset($_POST['cash'])) {
$_SESSION['shop'] = 1;
if (isset($_POST['altEmail']) && filter_var($_POST['altEmail'], FILTER_VALIDATE_EMAIL)) {
$_SESSION['altEmail'] = $_POST['altEmail'];
$_SESSION['altName'] = $_POST['altName'];
}
} else {
//sino shop es 0
$_SESSION['shop'] = 0;
}
if (!Helpers::checkCrendentials('ROLE_OWNER', $entrada->getEvent(), $user, $this->get('security.authorization_checker')) && $_SESSION['shop'] == 1) {
$_SESSION['shop'] = 0;
}
$numTickets = $repTicket->getNumTickets($entrada);
if (($entrada->getMaxTickets() - $numTickets) > $quantity && ($entrada->getMaxTickets() < $numTickets)) {
return $this->entradas($entrada->getEvent()->getName(), "No queda esa cantidad de entradas");
} else {
$bundle = $repTicket->getLastBundle();
$bundle = $bundle['bundle'] + 1;
for ($i = 0; $i < $quantity; $i++) {
$tickets[] = $this->createNotPaidTicket($entrada, $user, $bundle);
}
foreach ($tickets as $ticket) {
if ($_SESSION['shop'] == 1) {
$ticket->setEmailTo($_POST['altEmail']);
$ticket->setNameTo($_POST['altName']);
$entityManager->persist($ticket);
}
}
$entityManager->flush();
}
// sacamos las preguntas
$preguntas = $entrada->getQuestions();
if (count($preguntas) > 0) {
return $this->render('buy_ticket/questions.html.twig', [
'controller_name' => 'BuyTicketController',
'entrada' => $entrada,
'quantity' => $quantity,
'tickets' => $tickets,
'questions' => $preguntas,
]);
} else {
return $this->buy_ticket2($entrada, $quantity, $tickets, $bundle);
// return $this->buy_ticket($entrada, $quantity, $tickets, $bundle);
}
}
/**
* This function buys the tickets when the user is authenticated CECA function currently used
* @Route("/buy_ticket2/{entrada}/{quantity}", name="buy_ticket2")
*/
public function buy_ticket2($entrada, $quantity)
{
//Parseo de los argumentos para saber si viene desde prebuy o no
$args = func_get_args();
$entrada = $args[0];
$repEntrada = $this->getDoctrine()->getRepository(Entrada::class);
$entrada = $repEntrada->find($entrada);
$quantity = $args[1];
if (func_num_args() > 2) {
$tickets = $args[2];
$bundle = $args[3];
} elseif (empty($_POST)) {
return $this->redirectToRoute("main");
}
$securityContext = $this->container->get('security.authorization_checker');
if (!$securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('register');
}
$user = $this->get('security.token_storage')->getToken()->getUser();
$entityManager = $this->getDoctrine()->getManager();
//vamos a gestionar las respuestas
$questionRep = $this->getDoctrine()->getRepository(Question::class);
$ticketRep = $this->getDoctrine()->getRepository(Ticket::class);
if (isset($_POST["questions"])) {
$answers = $this->parseAnswers($_POST);
}
// parsear resupuestas
if (!empty($answers)) {
// asociar cada respuesta a su pregunta y guardar el value
foreach ($answers as $ticketId => $pregunta) {
foreach ($pregunta as $questionId => $value) {
$ticketObj = $ticketRep->findOneBy(array('identifier' => $ticketId));
$question = $questionRep->findOneById($questionId);
$this->createAnswer($question, $value, $ticketObj);
}
}
//recuperamos el bundle
$bundle = $ticketObj->getBundle();
}
if (!isset($tickets)) {
foreach ($answers as $ticketId => $pregunta) {
$tickets[] = $ticketRep->findOneByIdentifier($ticketId);
}
}
$amount = ($entrada->getPrice() * $quantity);
$amount = number_format($amount, 2, '.', ',');
//Si el importe es cero o paga en efectivo
if (intval($amount) == 0 || $_SESSION['shop']) {
foreach ($tickets as $key => $ticket) {
$this->payed_ticket($ticket);
}
$this->sendInvoice($bundle);
return $this->redirectToRoute("account");
}
$config = require __DIR__ . '/configCECA.local.php';
$TPV = new TPV($config);
# Indicamos los campos para el pedido
// $tempInfo = "";
$TPV->setFormHiddens(array(
'Num_operacion' => $bundle,
'Descripcion' => $entrada->getName(),
'Importe' => $amount,
'URL_OK' => 'https://entradasytickets.com/account?info=Pedido%20' . $bundle . '%20pagado%20correctamente.&error=',
'URL_NOK' => 'https://entradasytickets.com/account?error=Error%20en%20Pedido%20' . $bundle . '&info=',
));
# Imprimimos el pedido el formulario y redirigimos a la TPV
echo '<form action="' . $TPV->getPath() . '" method="post">' . $TPV->getFormHiddens() . '</form>';
die('<script>document.forms[0].submit();</script>');
return;
}
/**
* Function to parse the answers
*/
public function parseAnswers($answersBulk)
{
// var_dump($answersBulk);
if (!empty($answersBulk)) {
foreach ($answersBulk as $answerName => $value) {
if ($answerName != 'submit' && $answerName != "questions") {
$nombre = explode("-", $answerName);
$answers[$nombre[0]][$nombre[1]] = $value;
}
}
} else {
$answers = null;
}
return $answers;
}
/**
* Function to create an answer
*/
public function createAnswer($question, $value, $ticket)
{
$entityManager = $this->getDoctrine()->getManager();
//$repAnswer = $this->getDoctrine()->getRepository(Answer::class);
$answer = new Answer();
$answer->setQuestion($question);
$answer->setValue($value);
$answer->setTicket($ticket);
$entityManager->persist($answer);
$entityManager->flush();
return $answer;
}
/**
* Function to create not paid tickets
*/
public function createNotPaidTicket($entrada, $user, $bundle)
{
$entityManager = $this->getDoctrine()->getManager();
$ticket = new Ticket($bundle);
$ticket->setBuyer($user);
$ticket->setEntradaType($entrada);
$entityManager->persist($ticket);
$entityManager->flush();
return $ticket;
}
/**
* @Route("/check_ticket/{id}", name="check_ticket")
*/
public function checkTicket($id)
{
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$ticket = $repository->findOneByIdentifier($id);
if ($ticket) {
return $this->json(array('ticket' => true));
} else {
return $this->json(array('ticket' => false));
}
}
/**
* @Route("/verify_ticket/", name="verify_ticket")
*/
public function verifyTicket()
{
$user = $_GET["user"];
$pass = $_GET["pass"];
$id = $_GET["ticketID"];
$result = "";
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$ticket = $repository->findOneByIdentifier($id);
$entityManager = $this->getDoctrine()->getManager();
$now = new \DateTime();
$startToday = new \DateTime();
$startToday->setTime(0, 0);
if (!$ticket || !$ticket->getBuyDate()) {
$result = 'not_exists';
} else {
$entrada = $ticket->getEntradaType();
$entradaName = $entrada->getName();
$correctType = false;
$passwords = explode(";", $entrada->getValidatorPassword());
$key = array_search($pass, $passwords);
if($passwords[$key] === $pass){
$event = $entrada->getEvent();
if($event->getValidatorUser() === $user)
$correctType = true;
}
$minutesBefore = 30;
$beforeStartDate = new \DateTime($entrada->getStartDate()->format('Y-m-d h:i:s'));
$beforeStartDate->sub(new DateInterval('PT' . $minutesBefore . 'M'));
if (!$correctType) {
$result = "type_incorrect";
} elseif ($ticket->getRefunded()) {
$result = "refunded";
} else {
$last_used = $ticket->getUsed();
if ($last_used) {
$result = "used";
if($now->getTimeStamp() - $last_used->getTimeStamp() < 60){
$result = "recently_validated";
if ($last_used < $startToday && $entrada->getDaily()) {
if ($beforeStartDate < $now && $entrada->getEndDate() > $now) {
$result = 'ok';
} else {
$result = 'outatime';
}
}
}
} else {
if ($beforeStartDate < $now && $entrada->getEndDate() > $now) {
$result = 'ok';
} else {
$result = 'outatime';
}
}
}
}
switch ($result) {
case 'used':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n ALREADY VALIDATED, \n\n Entrada = $entradaName", 'ret' => 'ko'));
break;
case 'not_exists':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n DOES NOT EXIST", 'ret' => 'ko'));
break;
case 'type_incorrect':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n is wrong type, \n\n Entrada = $entradaName", 'ret' => 'ko'));
break;
case 'outatime':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n is out of time event, \n\n Entrada = $entradaName", 'ret' => 'ko'));
break;
case 'refunded':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n is refunded, \n\n Entrada = $entradaName", 'ret' => 'ko'));
break;
case 'recently_validated':
return $this->json(array('ticket' => "Ticket with ID = $id \n\n WAS RECENTLY VALIDATED, \n\n Entrada = $entradaName", 'ret' => 'ko'));
break;
case 'ok':
$ticket->setUsed($now);
$entityManager->persist($ticket);
$entityManager->flush();
return $this->json(array('ticket' => "Ticket with ID = $id \n\n IS OK, \n\n Entrada = $entradaName", 'ret' => 'ok'));
break;
default:
return $this->json(array('ticket' => "Ticket with ID = $id \n\n NOT EXIST", 'ret' => 'ko'));
break;
}
}
/**
* @Route("/return_redsys/", name="return_redsys")
*/
public function returnRedsys()
{
$miObj = new RedsysAPI();
$return = 'Not response';
if (!empty($_POST)) {
//URL DE RESP. ONLINE
$version = $_POST["Ds_SignatureVersion"];
$datos = $_POST["Ds_MerchantParameters"];
$signatureRecibida = $_POST["Ds_Signature"];
$decodec = $miObj->decodeMerchantParameters($datos);
$firma = $miObj->createMerchantSignatureNotif($this->kc, $datos);
$jsonDecoded = json_decode($decodec);
$error = $return = "";
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$tickets = $repository->findByBundle($jsonDecoded->Ds_Order);
if ($firma === $signatureRecibida && intval($jsonDecoded->Ds_Response) < 100) {
foreach ($tickets as $ticket) {
$this->payed_ticket($ticket);
}
$this->sendInvoice($jsonDecoded->Ds_Order);
$return = "Pedido " . $jsonDecoded->Ds_Order . " pagado correctamente.";
} else {
$error = "Pedido " . $jsonDecoded->Ds_Order . " no completado. Error en pago.";
}
} else {
if (!empty($_GET)) {
$version = $_GET["Ds_SignatureVersion"];
$datos = $_GET["Ds_MerchantParameters"];
$signatureRecibida = $_GET["Ds_Signature"];
$decodec = $miObj->decodeMerchantParameters($datos);
$jsonDecoded = json_decode($decodec);
$firma = $miObj->createMerchantSignatureNotif($this->kc, $datos);
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$tickets = $repository->findByBundle($jsonDecoded->Ds_Order);
if ($firma === $signatureRecibida && intval($jsonDecoded->Ds_Response) < 100) {
foreach ($tickets as $ticket) {
$this->payed_ticket($ticket);
}
$this->sendInvoice($jsonDecoded->Ds_Order);
$return = "Pedido " . $jsonDecoded->Ds_Order . " pagado correctamente.";
} else {
$error = "Pedido " . $jsonDecoded->Ds_Order . " no completado. Error en pago.";
}
}
}
return $this->render('account/account.html.twig', [
'controller_name' => 'AccountController',
'tickets' => $tickets,
'info' => $return,
'error' => $error,
]);
}
/**
* @Route("/check_ceca/", name="check_ceca")
*/
public function checkCECA()
{
$config = require __DIR__ . '/configCECA.local.php';
$TPV = new TPV($config);
try {
$TPV->checkTransaction($_POST);
} catch (\Exception $e) {
file_put_contents(__DIR__ . '/../../var/log/errores-tpv.log', $e->getMessage(), FILE_APPEND);
die();
}
$bundle = $_POST['Num_operacion'];
$reference = $_POST['Referencia'];
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$tickets = $repository->findByBundle($bundle);
foreach ($tickets as $ticket) {
$this->payed_ticket($ticket, $reference);
}
$this->sendInvoice($bundle);
die($TPV->successCode());
}
/**
* @Route("/getPDF/{ticket_id}", name="getPDF")
*/
public function getPDF($ticket_id = '')
{
$securityContext = $this->container->get('security.authorization_checker');
if (!$securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('login');
}
$usr = $this->get('security.token_storage')->getToken()->getUser();
$entityManager = $this->getDoctrine()->getManager();
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$tickets = $repository->findByUserPayedTickets($usr);
$foundTicket = '';
foreach ($tickets as $ticket) {
if ($ticket->getId() == $ticket_id) {
$foundTicket = $ticket;
}
}
if ($foundTicket == '') {
return $this->redirectToRoute('main');
} else {
$pdf = $this->createInvoicePDF([$foundTicket]);
$pdf->Output($foundTicket->getIdentifier() . ".pdf", 'D');
// $pdf->Output($foundTicket->getIdentifier().".pdf", 'I');
}
return;
}
/**
* @Route("/getPDFAdmin/{id}", name="getPDFAdmin")
*/
public function getPDFAdmin($id = '')
{
$securityContext = $this->container->get('security.authorization_checker');
if (!$securityContext->isGranted('ROLE_ADMIN')) {
return $this->redirectToRoute('login');
}
$entityManager = $this->getDoctrine()->getManager();
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$ticket = $repository->findOneById($id);
if (!$ticket) {
$ticket = $repository->findByBundle($id);
} else {
$ticket = [$ticket];
}
if (!$ticket) {
throw new NotFoundHttpException('Sorry not existing!');
} else {
$pdf = $this->createInvoicePDF($ticket);
$pdf->Output($ticket[0]->getIdentifier() . ".pdf", 'D');
// $pdf->Output($foundTicket->getIdentifier().".pdf", 'I');
}
return;
}
private function payed_ticket($ticket = '', $reference = '')
{
$entityManager = $this->getDoctrine()->getManager();
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$ticket = $repository->findOneById($ticket);
if ($ticket) {
$now = new \DateTime();
$email = $ticket->getBuyer()->getEmail();
$ticket->setBuyDate($now);
if ($reference) {
$ticket->setReference($reference);
}
$entityManager->persist($ticket);
$entityManager->flush();
return true;
} else {
return false;
}
}
private function sendInvoice($bundle = '')
{
$entityManager = $this->getDoctrine()->getManager();
$repository = $this->getDoctrine()->getRepository(Ticket::class);
$tickets = $repository->findByBundle($bundle);
if (isset($_SESSION['altEmail'])) {
$email = $_SESSION['altEmail'];
$name = $_SESSION['altName'];
} else {
$email = $tickets[0]->getBuyer()->getEmail();
}
$name = $tickets[0]->getBuyer()->getName();
$surname = $tickets[0]->getBuyer()->getSurname();
$buydate = $tickets[0]->getBuyDate()->format('d/m/Y');
$total = 0;
$pdf = $this->createInvoicePDF($tickets);
$pdfdoc = $pdf->Output($bundle . ".pdf", "S");
$separator = md5(time());
$eol = PHP_EOL;
$filename = "./pdf/" . $bundle . ".pdf";
$to = $email;
$from = 'admin@entradasytickets.com';
$subject = 'Recibo de EntradasyTickets';
$attachment = chunk_split(base64_encode($pdfdoc));
// main header
$headers = "From: " . $from . $eol;
$headers .= "MIME-Version: 1.0" . $eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"" . $separator . "\"";
$message = file_get_contents('./partials/invoice1.html');
$message .= "<br/>" . $name . " " . $surname;
$message .= "<br/>" . "<p style='color: #777777'>" . $email . "<p>";
$message .= "<br/>";
$message .= file_get_contents('./partials/invoice2.html');
$message .= "<br/>" . $buydate;
$message .= "<br/>";
$message .= "<br/>";
$message .= '<span class="header-sm">Orden</span><br/>' . $bundle;
$message .= file_get_contents('./partials/invoice3.html');
foreach ($tickets as $ticket) {
$nombreEvento = $ticket->getEntradaType()->getEvent()->getName();
$nombreEntrada = $ticket->getEntradaType()->getName();
$identifier = $ticket->getIdentifier();
$total += $ticket->getEntradaType()->getPrice();
$message .= '<tr>
<td class="item-col item">
<table cellspacing="0" cellpadding="0" width="100%">
<tr>
<td class="mobile-hide-img">
<a href=""><img width="200" height="200" src="https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=' . $identifier . '&choe=UTF-8" alt="item1"></a>
</td>
<td class="product">
<span style="color: #4d4d4d; font-weight:bold;">' . $nombreEntrada . '</span>
<br /> <p style="color: #777777">' . $nombreEvento . '<p>
<br /> ' . $identifier . '
</td>
</tr>
</table>
</td>
<td class="item-col quantity">
1
</td>
<td class="item-col">
' . $ticket->getEntradaType()->getPrice() . '€
</td>
</tr>';
}
$message .= file_get_contents('./partials/invoice4.html');
$message .= '<tr>
<td class="item-col item">
</td>
<td class="item-col quantity" style="text-align:right; padding-right: 10px; border-top: 1px solid #cccccc;">
<br />
<span class="total-space" style="font-weight: bold; color: #4d4d4d">Total</span>
</td>
<td class="item-col price" style="text-align: left; border-top: 1px solid #cccccc;">
<br />
<span class="total-space" style="font-weight:bold; color: #4d4d4d">' . $total . '€</span>
<br />
</td>
</tr>';
$message .= file_get_contents('./partials/invoice5.html');
$body = "";
// message
$body .= "--" . $separator . $eol;
$body .= "Content-Type: text/html; charset=\"iso-8859-1\"" . $eol;
$body .= "Content-Transfer-Encoding: 8bit" . $eol . $eol;
$body .= $message . $eol;
// message
$body .= "--" . $separator . $eol;
$body .= "Content-Type: text/plain; charset=\"iso-8859-1\"" . $eol;
$body .= "Content-Transfer-Encoding: 8bit" . $eol . $eol;
$body .= "*Este mensaje se envia con HTML si no lo ves bien por favor configure su navegador" . $eol;
// attachment
$body .= "--" . $separator . $eol;
$body .= "Content-Type: application/octet-stream; name=\"" . $filename . "\"" . $eol;
$body .= "Content-Transfer-Encoding: base64" . $eol;
$body .= "Content-Disposition: attachment" . $eol . $eol;
$body .= $attachment . $eol;
$body .= "--" . $separator . "--";
mail($to, $subject, $body, $headers);
// unlink($filename);
}
/**
* Create the pdf to enter the event
*/
private function createInvoicePDF($tickets = "")
{
$user = $tickets[0]->getBuyer();
$bundle = $tickets[0]->getBundle();
$pdf = $this->container->get("qipsius.tcpdf.public")->create();
foreach ($tickets as $ticket) {
$entrada = $ticket->getEntradaType();
$event = $entrada->getEvent();
$pdf->SetPrintHeader(false);
$pdf->SetPrintFooter(false);
$pdf->AddPage();
$html = $this->renderView('buy_ticket/pdf_invoice.html.twig', [
'ticket' => $ticket,
'entrada' => $entrada,
'event' => $event,
]);
$ticketURL = '<img src="https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=' . $ticket->getIdentifier() . '&choe=UTF-8" width="300" height="300">';
$html = str_replace('%qr%', $ticketURL, $html);
$pdf->writeHTML($html, true, false, true, false, '');
}
// $pdf->Output("./pdf/" . $bundle . ".pdf", "F");
// $doc = $pdf->Output($bundle . ".pdf",'I');
// $doc = $pdf->Output($bundle . ".pdf", "S");
return $pdf;
}
}