src/MDS/VenuesBundle/Controller/ReservationsController.php line 2981

Open in your IDE?
  1. <?php
  2. namespace App\MDS\VenuesBundle\Controller;
  3. use App\Constants\BusinessTypeSettingsCompanyConstants;
  4. use App\Constants\LanguageConstants;
  5. use App\DTO\SyncronizationsAVDTO;
  6. use App\DTO\SyncronizationsCateringDTO;
  7. use App\Entity\DocContract;
  8. use App\MDS\VenuesBundle\Entity\ReservationTracing;
  9. use App\Entity\CotizacionWebObservations;
  10. use App\Entity\DocContractModel;
  11. use App\Entity\Client;
  12. use App\Entity\ClientContact;
  13. use App\Entity\InvoiceProformaExtraField;
  14. use App\Entity\Space;
  15. use App\Entity\Supplier;
  16. use App\Entity\User;
  17. use App\Entity\HtFile;
  18. use App\Entity\ReservationLoungeWebDescription;
  19. use App\Entity\SageArticle;
  20. use App\Entity\SageVatRates;
  21. use App\Entity\SettingsCompany;
  22. use App\Entity\WidgetNotes;
  23. use App\Form\InvoiceProformaExtraFieldType;
  24. use App\Form\WidgetNotesType;
  25. use App\MDS\AvexpressBundle\Entity\AveFiles;
  26. use App\MDS\VenuesBundle\Entity\ReservationVisit;
  27. use App\MDS\VenuesBundle\Entity\Reservation;
  28. use App\MDS\VenuesBundle\Entity\ReservationDeposit;
  29. use App\MDS\VenuesBundle\Entity\ReservationLounge;
  30. use App\MDS\VenuesBundle\Entity\ReservationLoungeDescription;
  31. use App\MDS\VenuesBundle\Entity\ReservationLoungeDetails;
  32. use App\MDS\VenuesBundle\Entity\ReservationLoungePicture;
  33. use App\MDS\VenuesBundle\Entity\ReservationLoungeProfile;
  34. use App\MDS\VenuesBundle\Entity\ReservationLoungeSimple;
  35. use App\MDS\VenuesBundle\Entity\ReservationLoungeVideo;
  36. use App\MDS\VenuesBundle\Entity\ReservationMailAlertClient;
  37. use App\MDS\VenuesBundle\Entity\ReservationPeriod;
  38. use App\MDS\VenuesBundle\Entity\ReservationService;
  39. use App\MDS\VenuesBundle\Entity\ReservationAlertStarted;
  40. use App\MDS\VenuesBundle\Entity\ReservationAlertSecondDeposit;
  41. use App\MDS\VenuesBundle\Entity\ReservationInvoice;
  42. use App\MDS\VenuesBundle\Entity\ReservationInvoiceItems;
  43. use App\MDS\VenuesBundle\Entity\ReservationInvoiceRec;
  44. use App\MDS\VenuesBundle\Entity\ReservationPaymentsClient;
  45. use App\MDS\VenuesBundle\Entity\ReservationProforma;
  46. use App\MDS\VenuesBundle\Form\ReservationLoungeDetailsType;
  47. use App\MDS\VenuesBundle\Form\ReservationLoungeProfileType;
  48. use App\MDS\VenuesBundle\Form\ReservationLoungeType;
  49. use App\MDS\VenuesBundle\Form\ReservationPeriodType;
  50. use App\MDS\VenuesBundle\Form\ReservationType;
  51. use App\MDS\VenuesBundle\Form\VisitEditType;
  52. use App\Service\CalendarService;
  53. use App\Service\ReservationService as ReservationServiceAlias;
  54. use App\Service\SincGpHtAvService;
  55. use Symfony\Component\Routing\Annotation\Route;
  56. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  57. use Symfony\Component\HttpFoundation\Request;
  58. use Symfony\Component\HttpFoundation\Session\Session;
  59. use Symfony\Component\HttpFoundation\JsonResponse;
  60. use Symfony\Component\HttpFoundation\Response;
  61. use App\Service\DocContractService;
  62. use App\Service\SyncronizationsAVService;
  63. use App\Service\SyncronizationsCateringService;
  64. use Google_Client;
  65. use Google_Service_Calendar;
  66. use Psr\Log\LoggerInterface;
  67. use DateTime;
  68. use DatePeriod;
  69. use DateInterval;
  70. use Symfony\Contracts\Translation\TranslatorInterface;
  71. use Doctrine\ORM\EntityManagerInterface;
  72. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  73. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  74. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  75. use Symfony\Component\Security\Core\Security;
  76. use Symfony\Component\Serializer\SerializerInterface;
  77. use App\Service\AgendaService;
  78. use App\MDS\VenuesBundle\Repository\ReservationAgendaItemRepository;
  79. use App\MDS\VenuesBundle\Entity\ReservationAgendaItem;
  80. use App\Service\AppConfigManager;
  81. use App\Settings\AppConfig\ReservationWorkflowMode;
  82. use App\Service\VenueService;
  83. class ReservationsController extends AbstractController
  84. {
  85.     private $translator;
  86.     protected $googleCalendar;
  87.     private $docContractService;
  88.     private $em;
  89.     private $session;
  90.     private $syncronizationsCateringService;
  91.     private $syncronizationsAVService;
  92.     private $agendaService;
  93.     private ReservationServiceAlias $reservationService;
  94.     public function __construct(
  95.         TranslatorInterface $translator,
  96.         DocContractService $docContractService,
  97.         EntityManagerInterface $em,
  98.         SessionInterface $session,
  99.         SyncronizationsCateringService $syncronizationsCateringService,
  100.         SyncronizationsAVService $syncronizationsAVService,
  101.         AgendaService $agendaService,
  102.         VenueService $venueService,
  103.         ReservationAgendaItemRepository $repository,
  104.         ReservationServiceAlias $reservationService,
  105.         SincGpHtAvService $sincGpHtAvService
  106.     ) {
  107.         $redirect_uri 'https://' $_SERVER['HTTP_HOST'] . '/calendar/token';
  108.         $googleCalendar = new Google_Client();
  109.         $googleCalendar->setApplicationName('Google Calendar API PHP Quickstart');
  110.         $googleCalendar->setClientId('2790497987-57qc3vu4pr7vb0s8phpub2me58pe34lb.apps.googleusercontent.com');
  111.         $googleCalendar->setClientSecret('nj2C7unaTO68DRhyORsyipSj');
  112.         $googleCalendar->setRedirectUri($redirect_uri);
  113.         $googleCalendar->addScope(Google_Service_Calendar::CALENDAR);
  114.         $guzzleClient = new \GuzzleHttp\Client(['curl' => [CURLOPT_SSL_VERIFYPEER => false]]);
  115.         $googleCalendar->setHttpClient($guzzleClient);
  116.         $this->googleCalendar $googleCalendar;
  117.         $this->translator $translator;
  118.         $this->docContractService $docContractService;
  119.         $this->em $em;
  120.         $this->session $session;
  121.         $this->syncronizationsCateringService $syncronizationsCateringService;
  122.         $this->syncronizationsAVService $syncronizationsAVService;
  123.         $this->agendaService $agendaService;
  124.         $this->repository $repository;
  125.         $this->reservationService $reservationService;
  126.         $this->venueService $venueService;
  127.         $this->sincGpHtAvService $sincGpHtAvService;
  128.     }
  129.     /**
  130.      * @Route("/connectGoogle", name="homepage_Connect_Google")
  131.      */
  132.     public function indexConnectGoogleAction(Request $request)
  133.     {
  134.         $session = new Session();
  135.         $token $session->get('tokenGoogleCalendar');
  136.         if (!is_null($token)) {
  137.             $this->googleCalendar->setAccessToken($token);
  138.         }
  139.         // If there is no previous token or it's expired.
  140.         $data = array();
  141.         if ($this->googleCalendar->isAccessTokenExpired()) {
  142.             // Refresh the token if possible, else fetch a new one.
  143.             if ($this->googleCalendar->getRefreshToken()) {
  144.                 $this->googleCalendar->fetchAccessTokenWithRefreshToken($this->googleCalendar->getRefreshToken());
  145.             } else {
  146.                 // Request authorization from the user.
  147.                 $authUrl $this->googleCalendar->createAuthUrl();
  148.                 return $this->redirect($authUrl);
  149.             }
  150.         }
  151.         return $this->redirectToRoute('homepage');
  152.     }
  153.     /**
  154.      * @Route("/add",  name="reservations_venues_add")
  155.      */
  156.     public function addReservationAction(Request $request)
  157.     {
  158.         return $this->redirectToRoute('reservations_venues_add_simple');
  159.     }
  160.     /**
  161.      * @Route("/create", name="reservations_venues_create")
  162.      */
  163.     public function createAction(EntityManagerInterface $emRequest $request)
  164.     {
  165.         $reserva = new Reservation();
  166.         // // $reserva->setComAvGp(10);                       // Valor por defecto de ComAvGg
  167.         $form $this->createReservationCreateForm($reserva);
  168.         $form->handleRequest($request);
  169.         /* Obtengo usuario logueado */
  170.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  171.         $user_id $user_logueado->getId();
  172.         $hoy = new \DateTime("now"NULL);
  173.         if ($form->isValid()) {
  174.             $reserva->setUpdatedBy($user_id);
  175.             $reserva->setUpdatedAt($hoy);
  176.             //            if (is_null($reserva->getCateringName())){
  177.             //                $reserva->setSupplier(null);
  178.             //                $reserva->setCateringName(null);
  179.             //            } else {
  180.             //                $reserva->setSupplier($reserva->getCateringName()->getId());
  181.             //                $reserva->setCateringName($reserva->getCateringName()->getName());
  182.             //            }
  183.             $clientId $arrayRequest['client'] ?? null;
  184.             $reserva->setClient(
  185.                 $clientId $em->getRepository(\App\Entity\Client::class)->find($clientId) : null
  186.             );
  187.             $reserva->setCreatedAt($hoy);
  188.             $reserva->setCreatedBy($user_id);
  189.             $reserva->setDateStart(new \DateTime('2078-01-01'));
  190.             $reserva->setDateEnd(new \DateTime('2000-01-01'));
  191.             if (is_null($reserva->getStatus())) {
  192.                 $reserva->setStatus('Cotizado');
  193.             }
  194.             if (is_null($reserva->getPriority()) or empty($reserva->getPriority()) or ($reserva->getPriority() == 'Auto')) {
  195.                 $reserva->setPriority(1);
  196.             }
  197.             // Buscamos la menor fecha de sala para el inicio y la mayor para determinar el fin del evento
  198.             $salas $request->request->get('salas');
  199.             // crea una reserva sin sala. que fechas le pongo al evento
  200.             if (!is_null($salas)) {
  201.                 foreach ($salas as $sala) {
  202.                     if (sizeof($sala['mountingHourStart']) != 5) {
  203.                         // Necesitamos la hora en formato HH:mm
  204.                         switch (strlen($sala['mountingHourStart'])) {
  205.                             case 0:
  206.                                 $sala['mountingHourStart'] = '00:00';
  207.                                 break; // Vacio
  208.                             case 1// H  -> 0H:00
  209.                                 if (is_numeric($sala['mountingHourStart'])) {
  210.                                     $sala['mountingHourStart'] = '0' $sala['mountingHourStart'] . ':00';
  211.                                 } else {
  212.                                     $sala['mountingHourStart'] = '00:00';
  213.                                 }
  214.                                 break;
  215.                             case 2:
  216.                                 $sala['mountingHourStart'] = $sala['mountingHourStart'] . ':00';
  217.                                 break;   // HH  -> HH:00
  218.                             case 3:
  219.                                 $sala['mountingHourStart'] = '0' $sala['mountingHourStart'];
  220.                                 break;     // Hmm  -> 0H:mm
  221.                             case 4:
  222.                                 $sala['mountingHourStart'] = substr($sala['mountingHourStart'], 02) . ':' substr($sala['mountingHourStart'], 22);
  223.                                 break;      // HHmm  -> HH:mm
  224.                             default:
  225.                                 $sala['mountingHourStart'] = '00:00';
  226.                                 break;      // XXXXyyy
  227.                         }
  228.                     }
  229.                     if (sizeof($sala['removalHourEnd']) != 5) {
  230.                         // Necesitamos la hora en formato HH:mm
  231.                         switch (strlen($sala['removalHourEnd'])) {
  232.                             case 0:
  233.                                 $sala['removalHourEnd'] = '00:00';
  234.                                 break;      // Vacio
  235.                             case 1:
  236.                                 if (is_numeric($sala['removalHourEnd'])) {
  237.                                     $sala['removalHourEnd'] = '0' $sala['removalHourEnd'] . ':00';
  238.                                 } else {
  239.                                     $sala['removalHourEnd'] = '00:00';
  240.                                 }
  241.                                 break;      // H  -> 0H:00
  242.                             case 2:
  243.                                 $sala['removalHourEnd'] = $sala['removalHourEnd'] . ':00';
  244.                                 break;      // HH  -> HH:00
  245.                             case 3:
  246.                                 $sala['removalHourEnd'] = '0' $sala['removalHourEnd'];
  247.                                 break;      // Hmm  -> 0H:mm
  248.                             case 4:
  249.                                 $sala['removalHourEnd'] = substr($sala['removalHourEnd'], 02) . ':' substr($sala['removalHourEnd'], 22);
  250.                                 break;      // HHmm  -> HH:mm
  251.                             default:
  252.                                 $sala['removalHourEnd'] = '00:00';
  253.                                 break;      // XXXXyyy
  254.                         }
  255.                     }
  256.                     // Verificamos el montaje
  257.                     if ($reserva->getDateStart() > (new \DateTime($sala['mountingDate']))) {
  258.                         $reserva->setDateStart((new \DateTime($sala['mountingDate'] . " " $sala['mountingHourStart'])));
  259.                     }
  260.                     if ($reserva->getDateStart() > (new \DateTime($sala['dateStart']))) {
  261.                         $reserva->setDateStart((new \DateTime($sala['dateStart'] . " " $sala['hourStart'])));
  262.                     }
  263.                     if ($reserva->getDateEnd() < (new \DateTime($sala['dateEnd']))) {
  264.                         $reserva->setDateEnd((new \DateTime($sala['dateEnd'] . " " $sala['hourEnd'])));
  265.                     }
  266.                     //Verificamos el desmontaje
  267.                     if ($reserva->getDateEnd() < (new \DateTime($sala['removalDate']))) {
  268.                         $reserva->setDateEnd((new \DateTime($sala['removalDate'] . " " $sala['removalHourEnd'])));
  269.                     }
  270.                 }
  271.             } else {
  272.                 // No hay salas, se asigna a la reserva la fecha del dia actual
  273.                 $reserva->setDateStart((new \DateTime()));
  274.                 $reserva->setDateEnd((new \DateTime()));
  275.             }
  276.             // INICIO: se determina el numero de opcion o prioridad que tiene el evento
  277.             $salasTemp $request->request->get('salas');
  278.             // Pendiente reunion con Rafa (se determina el numero de opcion o prioridad que tiene el evento)
  279.             // FIN: se determina el numero de opcion o prioridad que tiene el evento
  280.             try {
  281.                 $em->persist($reserva);
  282.                 $em->flush();
  283.                 $event 'The Reservation has been created.';
  284.                 //                $successMessage = $this->translator->trans($event);
  285.                 $successMessage 'La reserva ha sido creada.';
  286.                 $this->addFlash('mensajereservation'$successMessage);
  287.             } catch (\Exception $e) {
  288.                 $event 'An error occurred: ' $e->getMessage();
  289.                 $errorMessage $this->translator->trans($event);
  290.                 $this->addFlash('mensajereservationerror'$errorMessage);
  291.             }
  292.         } else {
  293.             $errorMessagebase $this->translator->trans('Error, some fields are empty');
  294.             $this->addFlash('mensajetracingerror'$errorMessagebase);
  295.             $periods $em->getRepository(ReservationPeriod::class)->findAll();
  296.             return $this->render(
  297.                 'MDS/VenuesBundle/reservations/add-reservations.html.twig',
  298.                 array(
  299.                     'form' => $form->createView(),
  300.                     'periods' => $periods,
  301.                 )
  302.             );
  303.         }
  304.         /* Fin Gestión de eventos en Log */
  305.         $salas $request->request->get('salas');
  306.         // Inicio: Verificamos que hayan metido bien las salas, toda sala para poder facturar debe tener IdLounge, Fecha de inicio y fecha de fin
  307.         for ($i 0$i sizeof($salas); $i++) {
  308.             if (empty($salas[$i]['idLounge']) or empty($salas[$i]['dateStart']) or empty($salas[$i]['dateEnd'])) {
  309.                 unset($salas[$i]);
  310.             }
  311.         }
  312.         // Fin: Verificamos que hayan metido bien las salas, toda sala para poder facturar debe tener IdLounge, Fecha de inicio y fecha de fin
  313.         if (!is_null($reserva->getId())) {
  314.             if (!is_null($salas)) {
  315.                 foreach ($salas as $sala) {
  316.                     // Se guarda una sala si hay una sala seleccionada
  317.                     // IdLounge es el ID en la tabla reservation profile
  318.                     if (!empty(($sala['idLounge']))) {
  319.                         // consulto la tabla de precios para obtener el id de salon desde el id de precios
  320.                         $queryProfile $em->getRepository(ReservationLoungeProfile::class)->findOneById($sala['idLounge']);
  321.                         $reservaLounge = new ReservationLounge();
  322.                         $reservaLounge->setIdLounge($queryProfile->getLoungeId());
  323.                         $reservaLounge->setLoungeName(($em->getRepository(ReservationLoungeDetails::class)->findOneById($queryProfile->getLoungeId()))->getName());
  324.                         $reservaLounge->setCreatedAt($hoy);
  325.                         $reservaLounge->setCreatedBy($user_id);
  326.                         $reservaLounge->setUpdatedAt($hoy);
  327.                         $reservaLounge->setUpdatedBy($user_id);
  328.                         $reservaLounge->setIdReservation($reserva->getId());
  329.                         $reservaLounge->setDateStart(new \DateTime($sala['dateStart'] . " " $sala['hourStart']));
  330.                         $reservaLounge->setDateEnd(new \DateTime($sala['dateEnd'] . " " $sala['hourEnd']));
  331.                         $reservaLounge->setHourStart(substr($sala['hourStart'], 02));
  332.                         $reservaLounge->setMinStart(substr($sala['hourStart'], 32));
  333.                         $reservaLounge->setHourEnd(substr($sala['hourEnd'], 02));
  334.                         $reservaLounge->setMinEnd(substr($sala['hourEnd'], 32));
  335.                         $reservaLounge->setServicePrice($sala['servicePrice']);
  336.                         // el service name es la descripcion
  337.                         $reservaLounge->setServiceName($sala['serviceName']);
  338.                         $reservaLounge->setIdPeriod($sala['idLoungePrice']);
  339.                         if (empty($sala['servicePax'])) {
  340.                             $reservaLounge->setPax(null);
  341.                         } else {
  342.                             $reservaLounge->setPax($sala['servicePax']);
  343.                         }
  344.                         $reservaLounge->setMounting($sala['serviceMounting']);
  345.                         if (empty($sala['mountingPrice'])) {
  346.                             $reservaLounge->setMountingPrice(0);
  347.                         } else {
  348.                             $reservaLounge->setMountingPrice($sala['mountingPrice']);
  349.                         }
  350.                         $reservaLounge->setMountingLapse($sala['mountingLapse']);
  351.                         switch (strlen($sala['mountingHourStart'])) {
  352.                             case 0// Vacio
  353.                                 $reservaLounge->setMountingHourStart('00');
  354.                                 $reservaLounge->setMountingMinStart('00');
  355.                                 break;
  356.                             case 1// H  -> 0H:00
  357.                                 if (is_numeric($sala['mountingHourStart'])) {
  358.                                     $reservaLounge->setMountingHourStart('0' $sala['mountingHourStart']);
  359.                                 } else {
  360.                                     $reservaLounge->setMountingHourStart('00');
  361.                                 }
  362.                                 $reservaLounge->setMountingMinStart('00');
  363.                                 break;
  364.                             case 2// HH  -> HH:00
  365.                                 $reservaLounge->setMountingHourStart($sala['mountingHourStart']);
  366.                                 $reservaLounge->setMountingMinStart('00');
  367.                                 break;
  368.                             case 3// Hmm  -> 0H:mm
  369.                                 $reservaLounge->setMountingHourStart('0' substr($sala['mountingHourStart'], 01));
  370.                                 $reservaLounge->setMountingMinStart(substr($sala['mountingHourStart'], 12));
  371.                                 break;
  372.                             case 4// HHmm  -> HH:mm
  373.                                 $reservaLounge->setMountingHourStart(substr($sala['mountingHourStart'], 02));
  374.                                 $reservaLounge->setMountingMinStart(substr($sala['mountingHourStart'], 22));
  375.                                 break;
  376.                             case 5// HH:mm  -> HH:mm
  377.                                 $reservaLounge->setMountingHourStart(substr($sala['mountingHourStart'], 02));
  378.                                 $reservaLounge->setMountingMinStart(substr($sala['mountingHourStart'], 32));
  379.                                 break;
  380.                             default: // XXXXyyy
  381.                                 $reservaLounge->setMountingHourStart('00');
  382.                                 $reservaLounge->setMountingMinStart('00');
  383.                                 break;
  384.                         }
  385.                         switch (strlen($sala['mountingHourEnd'])) {
  386.                             case 0// Vacio
  387.                                 $reservaLounge->setMountingHourEnd('00');
  388.                                 $reservaLounge->setMountingMinEnd('00');
  389.                                 break;
  390.                             case 1// H  -> 0H:00
  391.                                 if (is_numeric($sala['mountingHourEnd'])) {
  392.                                     $reservaLounge->setMountingHourEnd('0' $sala['mountingHourEnd']);
  393.                                 } else {
  394.                                     $reservaLounge->setMountingHourEnd('00');
  395.                                 }
  396.                                 $reservaLounge->setMountingMinEnd('00');
  397.                                 break;
  398.                             case 2// HH  -> HH:00
  399.                                 $reservaLounge->setMountingHourEnd($sala['mountingHourEnd']);
  400.                                 $reservaLounge->setMountingMinEnd('00');
  401.                                 break;
  402.                             case 3// Hmm  -> 0H:mm
  403.                                 $reservaLounge->setMountingHourEnd('0' substr($sala['mountingHourEnd'], 01));
  404.                                 $reservaLounge->setMountingMinEnd(substr($sala['mountingHourEnd'], 12));
  405.                                 break;
  406.                             case 4// HHmm  -> HH:mm
  407.                                 $reservaLounge->setMountingHourEnd(substr($sala['mountingHourEnd'], 02));
  408.                                 $reservaLounge->setMountingMinEnd(substr($sala['mountingHourEnd'], 22));
  409.                                 break;
  410.                             case 5// HH:mm  -> HH:mm
  411.                                 $reservaLounge->setMountingHourEnd(substr($sala['mountingHourEnd'], 02));
  412.                                 $reservaLounge->setMountingMinEnd(substr($sala['mountingHourEnd'], 32));
  413.                                 break;
  414.                             default: // XXXXyyy
  415.                                 $reservaLounge->setMountingHourEnd('00');
  416.                                 $reservaLounge->setMountingMinEnd('00');
  417.                                 break;
  418.                         }
  419.                         $reservaLounge->setMountingDate(new \DateTime($sala['mountingDate'] . ' ' $reservaLounge->getMountingHourStart() . ':' $reservaLounge->getMountingMinStart()));
  420.                         $reservaLounge->setRemovalLapse($sala['removalLapse']);
  421.                         $reservaLounge->setRemovalDate(new \DateTime($sala['removalDate']));
  422.                         switch (strlen($sala['removalHourStart'])) {
  423.                             case 0// Vacio
  424.                                 $reservaLounge->setRemovalHourStart('00');
  425.                                 $reservaLounge->setRemovalMinStart('00');
  426.                                 break;
  427.                             case 1// H  -> 0H:00
  428.                                 if (is_numeric($sala['removalHourStart'])) {
  429.                                     $reservaLounge->setRemovalHourStart('0' $sala['removalHourStart']);
  430.                                 } else {
  431.                                     $reservaLounge->setRemovalHourStart('00');
  432.                                 }
  433.                                 $reservaLounge->setRemovalMinStart('00');
  434.                                 break;
  435.                             case 2// HH  -> HH:00
  436.                                 $reservaLounge->setRemovalHourStart($sala['removalHourStart']);
  437.                                 $reservaLounge->setRemovalMinStart('00');
  438.                                 break;
  439.                             case 3// Hmm  -> 0H:mm
  440.                                 $reservaLounge->setRemovalHourStart('0' substr($sala['removalHourStart'], 01));
  441.                                 $reservaLounge->setRemovalMinStart(substr($sala['removalHourStart'], 12));
  442.                                 break;
  443.                             case 4// HHmm  -> HH:mm
  444.                                 $reservaLounge->setRemovalHourStart(substr($sala['removalHourStart'], 02));
  445.                                 $reservaLounge->setRemovalMinStart(substr($sala['removalHourStart'], 22));
  446.                                 break;
  447.                             case 5// HH:mm  -> HH:mm
  448.                                 $reservaLounge->setRemovalHourStart(substr($sala['removalHourStart'], 02));
  449.                                 $reservaLounge->setRemovalMinStart(substr($sala['removalHourStart'], 32));
  450.                                 break;
  451.                             default: // XXXXyyy
  452.                                 $reservaLounge->setRemovalHourStart('00');
  453.                                 $reservaLounge->setRemovalMinStart('00');
  454.                                 break;
  455.                         }
  456.                         switch (strlen($sala['removalHourEnd'])) {
  457.                             case 0// Vacio
  458.                                 $reservaLounge->setRemovalHourEnd('00');
  459.                                 $reservaLounge->setRemovalMinEnd('00');
  460.                                 break;
  461.                             case 1// H  -> 0H:00
  462.                                 if (is_numeric($sala['removalHourEnd'])) {
  463.                                     $reservaLounge->setRemovalHourEnd('0' $sala['removalHourEnd']);
  464.                                 } else {
  465.                                     $reservaLounge->setRemovalHourEnd('00');
  466.                                 }
  467.                                 $reservaLounge->setRemovalMinEnd('00');
  468.                                 break;
  469.                             case 2// HH  -> HH:00
  470.                                 $reservaLounge->setRemovalHourEnd($sala['removalHourEnd']);
  471.                                 $reservaLounge->setRemovalMinEnd('00');
  472.                                 break;
  473.                             case 3// Hmm  -> 0H:mm
  474.                                 $reservaLounge->setRemovalHourEnd('0' substr($sala['removalHourEnd'], 01));
  475.                                 $reservaLounge->setRemovalMinEnd(substr($sala['removalHourEnd'], 12));
  476.                                 break;
  477.                             case 4// HHmm  -> HH:mm
  478.                                 $reservaLounge->setRemovalHourEnd(substr($sala['removalHourEnd'], 02));
  479.                                 $reservaLounge->setRemovalMinEnd(substr($sala['removalHourEnd'], 22));
  480.                                 break;
  481.                             case 5// HH:mm  -> HH:mm
  482.                                 $reservaLounge->setRemovalHourEnd(substr($sala['removalHourEnd'], 02));
  483.                                 $reservaLounge->setRemovalMinEnd(substr($sala['removalHourEnd'], 32));
  484.                                 break;
  485.                             default: // XXXXyyy
  486.                                 $reservaLounge->setRemovalHourEnd('00');
  487.                                 $reservaLounge->setRemovalMinEnd('00');
  488.                                 break;
  489.                         }
  490.                         if (empty($sala['removalPrice'])) {
  491.                             $reservaLounge->setRemovalPrice(0);
  492.                         } else {
  493.                             $reservaLounge->setRemovalPrice($sala['removalPrice']);
  494.                         }
  495.                         // INICIO: Verificamos si choca con otra reserva
  496.                         // Si sucede se usara el booleano OtherPriceSave para indicarlo
  497.                         $resFun $this->VerificarCoflictosEnSalas($reservaLounge);
  498.                         $tempBool $resFun['bool'];
  499.                         if ($tempBool) {
  500.                             $reservaLounge->setOtherPriceSave(true);
  501.                             $reserva->setPriority($resFun['priority']);
  502.                             // Se debe modificar la prioridad de la nueva reserva, que ya se habia guardado previamente
  503.                             try {
  504.                                 $em->persist($reserva);
  505.                                 $em->flush();
  506.                             } catch (\Exception $e) {
  507.                                 $event 'Error al actualizar la prioridad del evento ' $e->getMessage();
  508.                                 /* Para el usuario */
  509.                                 $errorMessage $this->translator->trans($event);
  510.                                 $this->addFlash('mensajereservationerror'$errorMessage);
  511.                             }
  512.                         } else {
  513.                             $reservaLounge->setOtherPriceSave(false);
  514.                         }
  515.                         // FIN: Verificamos si choca con otra reserva
  516.                         // INICIO: Si es necesario se actualizan fechas de inicio y fin usando dia de montaje y desmontaje
  517.                         if (($reservaLounge->getMountingDate() < $reserva->getDateStart()) or ($reserva->getDateEnd() < $reservaLounge->getRemovalDate())) {
  518.                             if ($reservaLounge->getMountingDate() < $reserva->getDateStart()) {
  519.                                 $reserva->setDateStart($reservaLounge->getMountingDate());
  520.                             }
  521.                             if ($reserva->getDateEnd() < $reservaLounge->getRemovalDate()) {
  522.                                 $reserva->setDateEnd($reservaLounge->getRemovalDate());
  523.                             }
  524.                             try {
  525.                                 $em->persist($reserva);
  526.                                 $em->flush();
  527.                             } catch (\Exception $e) {
  528.                                 $event 'Error al actualizar fechas de inicio y fin, por montaje y desmontaje de sala: ' $e->getMessage();
  529.                                 $errorMessage $this->translator->trans($event);
  530.                                 $this->addFlash('mensajereservationerror'$errorMessage);
  531.                             }
  532.                         }
  533.                         // FIN: Si es necesario se actualizan fechas de inicio y fin usando dia de montaje y desmontaje
  534.                         try {
  535.                             $em->persist($reservaLounge);
  536.                             $em->flush();
  537.                         } catch (\Exception $e) {
  538.                             $event 'Al agregar la sala ha ocurrido un error: ' $e->getMessage();
  539.                             /* Para el usuario */
  540.                             $errorMessage $this->translator->trans($event);
  541.                             $this->addFlash('mensajereservationerror'$errorMessage);
  542.                         }
  543.                     }
  544.                 }
  545.                 // INICIO: Verificamos la prioridad
  546.                 $numeroPriority 1;
  547.                 //INICIO: Buscamos las salas que coincidan en tiempo de reserva
  548.                 foreach ($salas as $sala) {
  549.                     $newdateStar $sala['dateStart'] . ' ' $sala['hourStart'];
  550.                     $newdateEnd $sala['dateEnd'] . ' ' $sala['hourEnd'];
  551.                     $reservaProfile $em->getRepository(ReservationLoungeProfile::class)->findOneById($sala['idLounge']);
  552.                     $parameters = array(
  553.                         'dateStar' => $newdateStar,
  554.                         'dateEnd' => $newdateEnd,
  555.                         'idLounge' => $reservaProfile->getLoungeId(),
  556.                         'idRes' => $reserva->getId(),
  557.                     );
  558.                     $dql 'SELECT i
  559.                             FROM VenuesBundle:ReservationLounge i
  560.                             WHERE  (i.dateStart >= :dateStar
  561.                               and i.dateStart <= :dateEnd
  562.                               and i.idLounge = :idLounge
  563.                               and i.idReservation != :idRes)
  564.                               or 
  565.                               (i.dateStart <= :dateStar
  566.                               and i.dateStart >= :dateEnd
  567.                               and i.idLounge = :idLounge
  568.                               and i.idReservation != :idRes)
  569.                               ';
  570.                     $query $em->createQuery($dql)->setParameters($parameters);
  571.                     $reservationLounge $query->getResult();
  572.                 }
  573.                 //FIN: Buscamos las salas que coincidan en tiempo de reserva
  574.                 // INICIO: Buscamos el numero de opcion a asignar
  575.                 $modificarPrior false;
  576.                 if (!empty($reservaLounge)) {
  577.                     foreach ($reservationLounge as $resLoung) {
  578.                         $reservaClash $em->getRepository(Reservation::class)->findOneById($resLoung->getIdReservation());
  579.                         $tempPrior $reservaClash->getPriority();
  580.                         if ($numeroPriority <= $tempPrior) {
  581.                             // Ya tenemos una reserva con opcion de mayor relevancia (un numero de opción inferior)
  582.                             $numeroPriority $tempPrior 1;
  583.                             $modificarPrior true;
  584.                         }
  585.                     }
  586.                     if ($modificarPrior) {
  587.                         // Se debe modificar la prioridad
  588.                         $reserva->setPriority($numeroPriority);
  589.                         try {
  590.                             $em->persist($reserva);
  591.                             $em->flush();
  592.                             $event 'The Reservation has been created.';
  593.                             //                            $successMessage = $this->translator->trans($event);
  594.                             $successMessage 'La reserva ha sido creada.';
  595.                             $this->addFlash('mensajereservation'$successMessage);
  596.                         } catch (\Exception $e) {
  597.                             $event 'An error occurred: ' $e->getMessage();
  598.                             $errorMessage $this->translator->trans($event);
  599.                             $this->addFlash('mensajereservationerror'$errorMessage);
  600.                         }
  601.                     }
  602.                 } else {
  603.                     // El numero de opción asignada fue el correcto
  604.                 }
  605.                 // FIN: Buscamos el numero de opcion a asignar
  606.                 // FIN: Verificamos la prioridad
  607.             }
  608.         } else {
  609.             $reservationsLounges null;    // Si fallo la reserva no habrá salas
  610.         }
  611.         return $this->redirectToRoute('reservations_venues_index');
  612.     }
  613.     public function VerificarCoflictosEnSalas(EntityManagerInterface $em$nuevaSala)
  614.     {
  615.         $allSalas $em->getRepository(ReservationLounge::class)->findAll();
  616.         $tempBool false;  //Aun no se ha detectado un conflicto
  617.         $prioridad 1;
  618.         foreach ($allSalas as $sala) {
  619.             if ($sala->getIdReservation() == $nuevaSala->getIdReservation()) {
  620.                 // No hay conflicto son de la misma reserva
  621.                 $tempBool = ($tempBool or false);
  622.             } else {
  623.                 if (!($sala->getIdLounge() == $nuevaSala->getIdLounge())) {
  624.                     // No hay conflicto no son la misma sala
  625.                     $tempBool = ($tempBool or false);
  626.                 } else {
  627.                     // Caso 1: F. inicio de $nuevaSala entre las feachas de $sala
  628.                     if (($nuevaSala->getDateStart() > $sala->getDateStart()) and ($nuevaSala->getDateStart() < $sala->getDateEnd())) {
  629.                         $tempBool true;
  630.                         // Buscamos la prioridad que tiene el evento de la sala que colisiona para determinar la nueva prioridad del evento que se está creando
  631.                         $resTemp $em->getRepository(Reservation::class)->findOneById($sala->getIdReservation());
  632.                         if (($prioridad $resTemp->getPriority()) or ($prioridad == $resTemp->getPriority())) {
  633.                             $prioridad $resTemp->getPriority() + 1;
  634.                         }
  635.                     }
  636.                     // Caso 2: F. fin de $nuevaSala entre las feachas de $sala
  637.                     if (($nuevaSala->getDateEnd() > $sala->getDateStart()) and ($nuevaSala->getDateEnd() < $sala->getDateEnd())) {
  638.                         $tempBool true;
  639.                         // Buscamos la prioridad que tiene el evento de la sala que colisiona para determinar la nueva prioridad del evento que se está creando
  640.                         $resTemp $em->getRepository(Reservation::class)->findOneById($sala->getIdReservation());
  641.                         if (($prioridad <= $resTemp->getPriority()) or ($prioridad == $resTemp->getPriority())) {
  642.                             $prioridad $resTemp->getPriority() + 1;
  643.                         }
  644.                     }
  645.                     // Caso 3: F. inicio de $sala entre las feachas de $nuevaSala
  646.                     if (($sala->getDateStart() > $nuevaSala->getDateStart()) and ($sala->getDateStart() < $nuevaSala->getDateEnd())) {
  647.                         $tempBool true;
  648.                         // Buscamos la prioridad que tiene el evento de la sala que colisiona para determinar la nueva prioridad del evento que se está creando
  649.                         $resTemp $em->getRepository(Reservation::class)->findOneById($sala->getIdReservation());
  650.                         if (($prioridad <= $resTemp->getPriority()) or ($prioridad == $resTemp->getPriority())) {
  651.                             $prioridad $resTemp->getPriority() + 1;
  652.                         }
  653.                     }
  654.                     // Caso 4: F. fin de $sala entre las feachas de $nuevaSala
  655.                     if (($sala->getDateEnd() > $nuevaSala->getDateStart()) and ($sala->getDateEnd() < $nuevaSala->getDateEnd())) {
  656.                         $tempBool true;
  657.                         // Buscamos la prioridad que tiene el evento de la sala que colisiona para determinar la nueva prioridad del evento que se está creando
  658.                         $resTemp $em->getRepository(Reservation::class)->findOneById($sala->getIdReservation());
  659.                         if (($prioridad <= $resTemp->getPriority()) or ($prioridad == $resTemp->getPriority())) {
  660.                             $prioridad $resTemp->getPriority() + 1;
  661.                         }
  662.                     }
  663.                     // Caso 5: fechas iguales
  664.                     if (
  665.                         ($nuevaSala->getDateStart() == $sala->getDateStart()) or
  666.                         ($nuevaSala->getDateStart() == $sala->getDateEnd()) or
  667.                         ($nuevaSala->getDateEnd() == $sala->getDateStart()) or
  668.                         ($nuevaSala->getDateEnd() == $sala->getDateEnd())
  669.                     ) {
  670.                         $tempBool true;
  671.                     }
  672.                 }
  673.             }
  674.         }
  675.         $res = array('bool' => $tempBool'priority' => $prioridad);
  676.         return ($res);
  677.     }
  678.     public function CalculoPrioridad(EntityManagerInterface $em$reserva)
  679.     {
  680.         $listAllReservas $em->getRepository(Reservation::class)->findAll();
  681.         // logico para controlar el conflicto entre salas
  682.         $logSalasError false;
  683.         // valor original de la prioridad
  684.         $oldPriority $reserva->getPriority();
  685.         foreach ($listAllReservas as $resv) {
  686.             $reservaSala explode(","$reserva->getSalas());          // Arreglo de salas para agregar
  687.             $resSala explode(","$resv->getSalas());                  // Arreglo de salas que ya estan en
  688.             foreach ($reservaSala as $item) {
  689.                 if (in_array($item$resSala)) {
  690.                     $logSalasError = ($logSalasError or true);          // Este logico indica si hay conflicto entre las salas
  691.                 }
  692.             }
  693.             if (
  694.                 (($reserva->getDateStart() == $resv->getDateStart()) or ($reserva->getDateStart() < $resv->getDateStart())) and
  695.                 ($resv->getDateStart() < $reserva->getDateEnd()) and ($resv->getStatus() == 'Confirmed')
  696.             ) {
  697.                 if ($resv->getPriority() == $reserva->getPriority()) {
  698.                     $reserva->setPriority($reserva->getPriority() - 1);
  699.                 } else {
  700.                     if ($resv->getPriority() < $reserva->getPriority()) {
  701.                         $reserva->setPriority($resv->getPriority() - 1);
  702.                     } else {
  703.                         // ($resv->getPriority() > $reserva->getPriority())
  704.                         // No se debe cambiar la prioridad ya que esta por debajo de la reserva ya creada
  705.                     }
  706.                 }
  707.             }
  708.             if (
  709.                 (($resv->getDateStart() == $reserva->getDateStart()) or ($resv->getDateStart() < $reserva->getDateStart())) and
  710.                 ($reserva->getDateEnd() < $resv->getDateEnd()) and ($resv->getStatus() == 'Confirmed')
  711.             ) {
  712.                 if ($resv->getPriority() == $reserva->getPriority()) {
  713.                     $reserva->setPriority($reserva->getPriority() - 1);
  714.                 } else {
  715.                     if ($resv->getPriority() < $reserva->getPriority()) {
  716.                         $reserva->setPriority($resv->getPriority() - 1);
  717.                     } else {
  718.                         // ($resv->getPriority() > $reserva->getPriority())
  719.                         // No se debe cambiar la prioridad ya que esta por debajo de la reserva ya creada
  720.                     }
  721.                 }
  722.             }
  723.             if (
  724.                 (($reserva->getDateStart() == $resv->getDateStart()) or ($reserva->getDateStart() < $resv->getDateStart())) and
  725.                 (($resv->getDateEnd() == $reserva->getDateEnd()) or ($resv->getDateEnd() < $reserva->getDateEnd())) and
  726.                 ($resv->getStatus() == 'Confirmed')
  727.             ) {
  728.                 if ($resv->getPriority() == $reserva->getPriority()) {
  729.                     $reserva->setPriority($reserva->getPriority() - 1);
  730.                 } else {
  731.                     if ($resv->getPriority() < $reserva->getPriority()) {
  732.                         $reserva->setPriority($resv->getPriority() - 1);
  733.                     } else {
  734.                         // ($resv->getPriority() > $reserva->getPriority())
  735.                         // No se debe cambiar la prioridad ya que esta por debajo de la reserva ya creada
  736.                     }
  737.                 }
  738.             }
  739.             if (
  740.                 (($resv->getDateStart() == $reserva->getDateStart()) or ($resv->getDateStart() < $reserva->getDateStart())) and
  741.                 (($resv->getDateEnd() == $reserva->getDateEnd()) or ($resv->getDateEnd() < $reserva->getDateEnd())) and
  742.                 ($resv->getStatus() == 'Confirmed')
  743.             ) {
  744.                 if ($resv->getPriority() == $reserva->getPriority()) {
  745.                     $reserva->setPriority($reserva->getPriority() - 1);
  746.                 } else {
  747.                     if ($resv->getPriority() < $reserva->getPriority()) {
  748.                         $reserva->setPriority($resv->getPriority() - 1);
  749.                     } else {
  750.                         // ($resv->getPriority() > $reserva->getPriority())
  751.                         // No se debe cambiar la prioridad ya que esta por debajo de la reserva ya creada
  752.                     }
  753.                 }
  754.             }
  755.         }
  756.         $priority $reserva->getPriority();
  757.         $reserva->setPriority($oldPriority);    // Se restablece el valor de origen de la prioridad
  758.         $data = array('prioridad' => $priority);
  759.         return $data;
  760.     }
  761.     public function NombreSalasPrecios(EntityManagerInterface $em)
  762.     {
  763.         $reservaLoungeDetails $em->getRepository(ReservationLoungeDetails::class)->findAll();
  764.         $data = array();
  765.         foreach ($reservaLoungeDetails as $res) {
  766.             if (!empty($data['salas'])) {
  767.                 $data['salas'] = $data['salas'] . ',' $res->getName();
  768.             } else {
  769.                 $data['salas'] = $res->getName();
  770.             }
  771.         }
  772.         $dataArray = array('-1');
  773.         foreach ($reservaLoungeDetails as $res) {
  774.             array_push($dataArray, array($res->getId(), $res->getName()));
  775.         }
  776.         unset($dataArray[0]);
  777.         $data['arraySalas'] = $dataArray;
  778.         $parameters = array();
  779.         $dql 'SELECT p
  780.                 FROM VenuesBundle:ReservationGpPrice p                         
  781.                 ORDER BY p.idService ASC ';
  782.         $query $em->createQuery($dql)->setParameters($parameters);
  783.         $reservaGpPrice $query->getResult();
  784.         foreach ($reservaGpPrice as $res) {
  785.             if (!empty($data['precios'])) {
  786.                 $data['precios'] = $data['precios'] . ',' $res->getNameAndPrice();
  787.             } else {
  788.                 $data['precios'] = $res->getNameAndPrice();
  789.             }
  790.         }
  791.         $dataArray = array('-1');
  792.         foreach ($reservaGpPrice as $res) {
  793.             array_push($dataArray, array($res->getIdService(), $res->getNameAndPrice()));
  794.         }
  795.         unset($dataArray[0]);
  796.         $data['arrayPrecios'] = $dataArray;
  797.         return $data;
  798.     }
  799.    /**
  800.      * Calcula los totales financieros del expediente.
  801.      * 
  802.      * @param int $id ID de la reserva
  803.      * @param array|null $overrideLounges Salas pre-cargadas (opcional)
  804.      * @param array|null $overrideServices Servicios pre-cargados (opcional)
  805.      * @param int|null $targetRank Si se proporciona, solo suma los items asociados a esta opción específica
  806.      * @return array Array con los desgloses financieros precisos
  807.      */
  808.     private function CalculosTotalesEditSimple(
  809.         int $id
  810.         ?array $overrideLounges null
  811.         ?array $overrideServices null,
  812.         ?int $targetRank null
  813.     ): array {
  814.         $em $this->getDoctrine()->getManager();
  815.         $reserva $em->getRepository(Reservation::class)->find($id);
  816.         
  817.         // Verificamos si la reserva está exenta/sujeta a alguna regla fiscal específica
  818.         $reservaSucoe $reserva && $reserva->isSucoe();
  819.         // 1. Cargar Salas y Servicios (Evitando duplicar queries si se pasan por parámetro)
  820.         $reservaLounges $overrideLounges ?? $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  821.         $reservaServices $overrideServices ?? $em->getRepository(ReservationService::class)->findByReservationId($id);
  822.         $loungeAcc = ['neto' => 0.0'iva' => 0.0'total' => 0.0];
  823.         $serviceAcc = ['neto' => 0.0'iva' => 0.0'total' => 0.0];
  824.         
  825.         $loungeLines = [];
  826.         $serviceLines = [];
  827.         // ==========================================
  828.         // 1. CÁLCULO DE SALAS / ESPACIOS
  829.         // ==========================================
  830.         foreach ($reservaLounges as $item) {
  831.             // Filtrar por opción si se está evaluando un Rank concreto
  832.             if ($targetRank !== null && method_exists($item'getRankQuote') && $item->getRankQuote() !== null && (int)$item->getRankQuote() !== $targetRank) {
  833.                 continue;
  834.             }
  835.             $price = (float)$item->getServicePrice();
  836.             $ivaRate $item->getSageIva() ? (float)$item->getSageIva()->getIva() : 21.0;
  837.             
  838.             $neto round($price2PHP_ROUND_HALF_UP);
  839.             $montoIva $reservaSucoe 0.0 round($neto * ($ivaRate 100), 2PHP_ROUND_HALF_UP);
  840.             $subtotalLine $neto $montoIva;
  841.             if ($price 0) {
  842.                 $loungeAcc['neto'] += $neto;
  843.                 $loungeAcc['iva'] += $montoIva;
  844.                 $loungeAcc['total'] += $subtotalLine;
  845.             }
  846.             $loungeLines[] = [
  847.                 'item' => $item,
  848.                 'neto' => $neto,
  849.                 'iva'  => $montoIva,
  850.                 'subtotal' => $subtotalLine
  851.             ];
  852.         }
  853.         // --- 2. CÁLCULO DE SERVICIOS (Opción B: Over Global) ---
  854. // CÁLCULO DE SERVICIOS (Precio del input tratado como BASE NETA)
  855. foreach ($reservaServices as $item) {
  856.     if (method_exists($item'getToinvoice') && !$item->getToinvoice()) {
  857.         continue;
  858.     }
  859.     if ($targetRank !== null && method_exists($item'getRank') && $item->getRank() !== null && (int)$item->getRank() !== $targetRank) {
  860.         continue;
  861.     }
  862.     $priceRaw = (float)$item->getPrice();
  863.     // 1. Comisión sobre el precio unitario
  864.     $commission = (float)$item->getCommission();
  865.     $unitPrice = ($item->getOpCommission() == '1')
  866.         ? ($priceRaw + ($priceRaw $commission 100))
  867.         : ($priceRaw - ($priceRaw $commission 100));
  868.     // 2. Multiplicadores (Unidades, Pax, Días)
  869.     $pax max(1, (int)$item->getPax());
  870.     $units max(1, (int)$item->getUnits());
  871.     $dateIn $item->getDateInAt();
  872.     $dateOut $item->getDateOutAt();
  873.     $catId $item->getServiceCatId();
  874.     $days 1;
  875.     if ($dateIn && $dateOut) {
  876.         $days = ($catId == 5) ? $dateIn->diff($dateOut)->days : ($dateIn->diff($dateOut)->days 1);
  877.         $days max(1$days);
  878.     }
  879.     $multiplicador = match ($catId) {
  880.         => max(1$dateIn?->diff($dateOut)->days ?? 1) * $units,
  881.         => $days $units,
  882.         default => $days $units $pax
  883.     };
  884.     // 3. BASE NETA: Multiplicadores + Over Global
  885.     $over = (float)$item->getOver();
  886.     $opOverSign = ($item->getOpOver() == '1') ? : -1;
  887.     $neto = ($unitPrice $multiplicador) + ($over $opOverSign);
  888.     // 4. IVA: Sumar el IVA correspondiente sobre la Base Neta
  889.     $ivaRate $item->getSageIva() ? (float)$item->getSageIva()->getIva() : 21.0;
  890.     $montoIva $reservaSucoe 0.0 : ($neto * ($ivaRate 100));
  891.     $subtotalLine $neto $montoIva;
  892.     // Redondeos
  893.     $neto round($neto2PHP_ROUND_HALF_UP);
  894.     $montoIva round($montoIva2PHP_ROUND_HALF_UP);
  895.     $subtotalLine round($subtotalLine2PHP_ROUND_HALF_UP);
  896.     if ($priceRaw 0) {
  897.         $serviceAcc['neto'] += $neto;
  898.         $serviceAcc['iva'] += $montoIva;
  899.         $serviceAcc['total'] += $subtotalLine;
  900.     }
  901.     $serviceLines[] = [
  902.         'item' => $item,
  903.         'neto' => $neto,
  904.         'iva'  => $montoIva,
  905.         'subtotal' => $subtotalLine,
  906.         'units' => $units,
  907.         'days' => $days,
  908.         'pax' => $pax
  909.     ];
  910. }
  911.         // ==========================================
  912.         // 3. CONSOLIDACIÓN Y RETORNO
  913.         // ==========================================
  914.         $sumatoriaNeto $loungeAcc['neto'] + $serviceAcc['neto'];
  915.         $sumatoriaIva $loungeAcc['iva'] + $serviceAcc['iva'];
  916.         $sumatoriaConIva $loungeAcc['total'] + $serviceAcc['total'];
  917.         return [
  918.             // BLOQUE 1: SOLO SALAS
  919.             'totales_global_neto'    => round($loungeAcc['neto'], 2),
  920.             'totales_global_iva'     => round($loungeAcc['iva'], 2),
  921.             'totales_global_con_iva' => round($loungeAcc['total'], 2),
  922.             // BLOQUE 2: SOLO SERVICIOS
  923.             'totales_global_servicios_neto'    => round($serviceAcc['neto'], 2),
  924.             'totales_global_servicios_iva'     => round($serviceAcc['iva'], 2),
  925.             'totales_global_servicios_con_iva' => round($serviceAcc['total'], 2),
  926.             // BLOQUE 3: TOTAL REAL EXPEDIENTE (Salas + Servicios)
  927.             'sumatoria_totales_global_neto'    => round($sumatoriaNeto2),
  928.             'sumatoria_totales_global_iva'     => round($sumatoriaIva2),
  929.             'sumatoria_totales_global_con_iva' => round($sumatoriaConIva2),
  930.             // REFERENCIAS
  931.             'loungeLines'  => $loungeLines,
  932.             'serviceLines' => $serviceLines
  933.         ];
  934.     }
  935.     /**
  936.      * @Route("/calendar/space/{id}", name="calendar_by_space")
  937.      */
  938.     public function calendarBySpaceAction(int $idRequest $requestEntityManagerInterface $em): Response
  939.     {
  940.         $space $em->getRepository(Space::class)->find($id);
  941.         if (!$space) {
  942.             throw $this->createNotFoundException('Espacio no encontrado');
  943.         }
  944.         $session = new Session();
  945.         $token $session->get('tokenGoogleCalendar');
  946.         $connectGoogle $token "1" "0";
  947.         if ($token) {
  948.             $this->googleCalendar->setAccessToken($token);
  949.         }
  950.         $user $this->get('security.token_storage')->getToken()->getUser();
  951.         return $this->render(
  952.             'MDS/VenuesBundle/calendar/calendar-space.html.twig',
  953.             [
  954.                 'user' => $user->getId(),
  955.                 'connectGoogle' => $connectGoogle,
  956.                 'space' => $space,
  957.             ]
  958.         );
  959.     }
  960.     /**
  961.      * Devuelve las RESERVAS (no visitas) para FullCalendar por espacio.
  962.      *
  963.      * FullCalendar le pasa ?start=...&end=... en ISO 8601.
  964.      *
  965.      * @Route("/calendar/space/{id}/reservations", name="calendar_reservations_by_space", methods={"GET"})
  966.      */
  967.     public function calendarReservationsBySpace(int $idRequest $requestCalendarService $calendar): JsonResponse
  968.     {
  969.         $start $request->query->get('start');
  970.         $end $request->query->get('end');
  971.         $from $start ? new \DateTimeImmutable($start) : new \DateTimeImmutable('first day of this month 00:00');
  972.         $to $end ? new \DateTimeImmutable($end) : new \DateTimeImmutable('last day of next month 23:59');
  973.         $events $calendar->getReservationsForCalendar(spaceId$idloungeIdnullfrom$fromto$to);
  974.         return new JsonResponse($events);
  975.     }
  976.     /**
  977.      * @Route("/calendar/events/space/{id}", name="calendar_events_by_space", methods={"GET"})
  978.      */
  979.     public function calendarEventsBySpace(int $idRequest $requestCalendarService $calendar): JsonResponse
  980.     {
  981.         $start $request->query->get('start');
  982.         $end $request->query->get('end');
  983.         $from $start ? new \DateTimeImmutable($start) : new \DateTimeImmutable('first day of this month 00:00');
  984.         $to $end ? new \DateTimeImmutable($end) : new \DateTimeImmutable('last day of next month 23:59');
  985.         $events $calendar->getVisitsForCalendar(spaceId$idloungeIdnullfrom$fromto$to);
  986.         return new JsonResponse($events);
  987.     }
  988.     /**
  989.      * @Route("/calendar/lounge/{id}", name="calendar_by_lounge", methods={"GET"})
  990.      */
  991.     public function calendarByLoungeAction(int $idRequest $requestEntityManagerInterface $em): Response
  992.     { {
  993.             $lounge $em->getRepository(\App\MDS\VenuesBundle\Entity\ReservationLoungeDetails::class)->find($id);
  994.             if (!$lounge) {
  995.                 $this->addFlash('danger''No se ha podido encontrar el calendario para esa sala.');
  996.                 // Volver a la pantalla anterior si es del mismo host (evita open redirect)
  997.                 $referer $request->headers->get('referer');
  998.                 if ($referer && parse_url($refererPHP_URL_HOST) === $request->getHost()) {
  999.                     return $this->redirect($referer);
  1000.                 }
  1001.                 // Fallback razonable (ajusta la ruta que prefieras)
  1002.                 return $this->redirectToRoute('app_space_index');
  1003.             }
  1004.             return $this->render('MDS/VenuesBundle/calendar/calendar-lounge.html.twig', [
  1005.                 'lounge' => $lounge,
  1006.                 'currentSpaceId' => $lounge->getSpace() ? $lounge->getSpace()->getId() : null,
  1007.             ]);
  1008.         }
  1009.     }
  1010.     /**
  1011.      * RESERVAS por sala (lounge)
  1012.      * FullCalendar envía ?start=...&end=...
  1013.      * Ojo con el prefijo /venues si tu controlador lo tiene a nivel de clase.
  1014.      *
  1015.      * @Route("/calendar/lounge/{id}/reservations", name="calendar_reservations_by_lounge", methods={"GET"})
  1016.      */
  1017.     public function calendarReservationsByLounge(int $idRequest $requestCalendarService $calendar): JsonResponse
  1018.     {
  1019.         $start $request->query->get('start');
  1020.         $end $request->query->get('end');
  1021.         $from $start ? new \DateTimeImmutable($start) : new \DateTimeImmutable('first day of this month 00:00');
  1022.         $to $end ? new \DateTimeImmutable($end) : new \DateTimeImmutable('last day of next month 23:59');
  1023.         $events $calendar->getReservationsForCalendar(spaceIdnullloungeId$idfrom$fromto$to);
  1024.         return new JsonResponse($events);
  1025.     }
  1026.     /**
  1027.      * @Route("/calendar/lounge/{id}/visits", name="calendar_visits_by_lounge", methods={"GET"})
  1028.      */
  1029.     public function calendarEventsByLounge(int $idRequest $requestCalendarService $calendar): JsonResponse
  1030.     {
  1031.         $start $request->query->get('start');
  1032.         $end $request->query->get('end');
  1033.         $from $start ? new \DateTimeImmutable($start) : new \DateTimeImmutable('first day of this month 00:00');
  1034.         $to $end ? new \DateTimeImmutable($end) : new \DateTimeImmutable('last day of next month 23:59');
  1035.         $events $calendar->getVisitsForCalendar(spaceIdnullloungeId$idfrom$fromto$to);
  1036.         return new JsonResponse($events);
  1037.     }
  1038.     /**
  1039.      * @Route("/calendar/events/all", name="calendar_events_all")
  1040.      */
  1041.     public function allEvents(): Response
  1042.     {
  1043.         return $this->render('MDS/VenuesBundle/calendar/calendar-all.html.twig');
  1044.     }
  1045.     /**
  1046.      * @Route("/calendar/events/visits", name="calendar_events_visits")
  1047.      */
  1048.     public function visitsEventsAction(): Response
  1049.     {
  1050.         return $this->render('MDS/VenuesBundle/calendar/calendar-visits.html.twig');
  1051.     }
  1052.     /**
  1053.      * @Route("/", name="reservations_venues")
  1054.      */
  1055.     public function calendarReservationAction(Request $request)
  1056.     {
  1057.         // Enviar correos a los agentes de las reservas que se deban Cotizar
  1058.         $this->notificacionReservasPorCotizar();
  1059.         // Enviar correos a los agentes de las reservas que tienen depósitos pendientes por recibir
  1060.         $this->notificacionReservasPendientesDelSegundoDepósito();
  1061.         $session = new Session();
  1062.         $token $session->get('tokenGoogleCalendar');
  1063.         if (!is_null($token)) {
  1064.             $this->googleCalendar->setAccessToken($token);
  1065.             $connectGoogle "1";
  1066.         } else {
  1067.             $connectGoogle "0";
  1068.         }
  1069.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1070.         $user_id $user_logueado->getId();
  1071.         $wnotes = new WidgetNotes();
  1072.         $wnotes->setDateAt(new \DateTime("now"));
  1073.         $form $this->createWidgetNotesCreateForm($wnotes);
  1074.         return $this->render(
  1075.             'MDS/VenuesBundle/reservations/calendar-reservations.html.twig',
  1076.             array(
  1077.                 'form' => $form->createView(),
  1078.                 'user' => $user_id,
  1079.                 'connectGoogle' => $connectGoogle,
  1080.             )
  1081.         );
  1082.     }
  1083.     private function createWidgetNotesCreateForm(WidgetNotes $entity)
  1084.     {
  1085.         $form $this->createForm(WidgetNotesType::class, $entity, array(
  1086.             'action' => $this->generateUrl('widget_notes_calendar_create'),
  1087.             'method' => 'POST'
  1088.         ));
  1089.         return $form;
  1090.     }
  1091.     /**
  1092.      * @Route("/widget/notes/calendar/create/", name="widget_notes_calendar_create")
  1093.      */
  1094.     public function addNotesAction(EntityManagerInterface $emRequest $requestLoggerInterface $logger)
  1095.     {
  1096.         $notes $em->getRepository(WidgetNotes::class)->findAll();
  1097.         $wnotes = new WidgetNotes();
  1098.         $form $this->createWidgetNotesCreateForm($wnotes);
  1099.         $form->handleRequest($request);
  1100.         $forAgent $form->get('forAgent')->getData();
  1101.         if (!is_null($forAgent)) {
  1102.             $wnotes->setForAgent($forAgent->getId());
  1103.         }
  1104.         if ($form->isValid()) {
  1105.             /* Obtengo usuario logueado */
  1106.             $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1107.             $user_id $user_logueado->getId();
  1108.             $wnotes->setCreatedId($user_id);
  1109.             $wnotes->setUpdatedId($user_id);
  1110.             /* Gestión de eventos en Log */
  1111.             $user_lastname $user_logueado->getLastname();
  1112.             $user_name $user_logueado->getName();
  1113.             $user_email $user_logueado->getEmail();
  1114.             $user_rol $user_logueado->getRoles();
  1115.             $event_url $request->getPathInfo();
  1116.             $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  1117.             try {
  1118.                 $em->persist($wnotes);
  1119.                 $em->flush();
  1120.                 $event 'The Note has been created succesfully.';
  1121.                 $successMessage $this->translator->trans($event);
  1122.                 $this->addFlash('mensaje'$successMessage);
  1123.                 $logger->info($event_complete ' | ' $event);
  1124.             } catch (\Exception $e) {
  1125.                 $event 'An error occurred: ' $e->getMessage();
  1126.                 /* Para el log */
  1127.                 $logger->error($event_complete ' | ' $event);
  1128.                 /* Para el usuario */
  1129.                 $errorMessage $this->translator->trans($event);
  1130.                 $this->addFlash('mensajeerror'$errorMessage);
  1131.             }
  1132.             /* Fin Gestión de eventos en Log */
  1133.         } else {
  1134.             $errorMessage $this->translator->trans('Error, some fields are empty');
  1135.             $this->addFlash('mensajeerror'$errorMessage);
  1136.         }
  1137.         return $this->redirectToRoute('homepage');
  1138.     }
  1139.     /**
  1140.      * @Route("/list/", defaults={"idgroup" = 0}, name="reservations_venues_index")
  1141.      */
  1142.     public function indexAction($idgroupEntityManagerInterface $emRequest $request)
  1143.     {
  1144.         return $this->render('MDS/VenuesBundle/reservations/list-reservations.html.twig', [
  1145.             'groups' => null,
  1146.             'type' => 'list',
  1147.             'titleView' => '',
  1148.             'reservations' => [], // DataTables will load data
  1149.             'dataUrl' => $this->generateUrl('reservations_venues_data', ['idgroup' => $idgroup]),
  1150.         ]);
  1151.     }
  1152.     /**
  1153.      * @Route("/list/space/{idspace}", name="reservations_venues_space_index")
  1154.      */
  1155.     public function indexSpaceAction(int $idspaceEntityManagerInterface $em)
  1156.     {
  1157.         $space $em->getRepository(Space::class)->find($idspace);
  1158.         if (!$space) {
  1159.             throw $this->createNotFoundException('Espacio no encontrado');
  1160.         }
  1161.         return $this->render('MDS/VenuesBundle/reservations/list-reservations.html.twig', [
  1162.             'groups' => null,
  1163.             'type' => 'space',
  1164.             'titleView' => ' de ' $space->getName(),
  1165.             'reservations' => [], // DataTables will load data
  1166.             'dataUrl' => $this->generateUrl('reservations_venues_space_data', ['idspace' => $idspace]),
  1167.         ]);
  1168.     }
  1169.     /**
  1170.      * @Route("/list/data/{idgroup}", defaults={"idgroup" = 0}, name="reservations_venues_data", methods={"POST", "GET"})
  1171.      */
  1172.     public function dataAction($idgroupRequest $requestEntityManagerInterface $em): JsonResponse
  1173.     {
  1174.         /** @var \App\MDS\VenuesBundle\Repository\ReservationRepository $repo */
  1175.         $repo $em->getRepository(Reservation::class);
  1176.         // Fetch ALL data
  1177.         $result $repo->findDataTablesData();
  1178.         return new JsonResponse(['data' => $this->formatDataTablesData($result)]);
  1179.     }
  1180.     /**
  1181.      * @Route("/list/space/data/{idspace}", name="reservations_venues_space_data", methods={"POST", "GET"})
  1182.      */
  1183.     public function dataSpaceAction(int $idspaceRequest $requestEntityManagerInterface $em): JsonResponse
  1184.     {
  1185.         /** @var \App\MDS\VenuesBundle\Repository\ReservationRepository $repo */
  1186.         $repo $em->getRepository(Reservation::class);
  1187.         // Fetch data filtered by Space
  1188.         $result $repo->findDataTablesData($idspace);
  1189.         return new JsonResponse(['data' => $this->formatDataTablesData($result)]);
  1190.     }
  1191.     /**
  1192.      * Auxiliar para formatear datos de DataTables (DRY)
  1193.      */
  1194.     private function formatDataTablesData(array $result): array
  1195.     {
  1196.         $data = [];
  1197.         foreach ($result as $row) {
  1198.             // Helper for Date formatting
  1199.             $fmtDate = function ($d) {
  1200.                 return $d instanceof \DateTimeInterface $d->format('d/m/Y') : '';
  1201.             };
  1202.             $fmtYMD = function ($d) {
  1203.                 return $d instanceof \DateTimeInterface $d->format('Y/m/d') : '';
  1204.             };
  1205.             $getTimestamp = function ($d) {
  1206.                 return $d instanceof \DateTimeInterface $d->getTimestamp() : 0;
  1207.             };
  1208.             // Date Start Logic
  1209.             $dateStartDisplay $fmtDate($row['dateStart']);
  1210.             $dateStartTimestamp $getTimestamp($row['dateStart']);
  1211.             if ($row['dateStart'] instanceof \DateTimeInterface && $fmtYMD($row['dateStart']) === '2078/01/01') {
  1212.                 $dateStartDisplay 'SIN ASIGNAR';
  1213.                 $dateStartTimestamp 0;
  1214.             }
  1215.             // Date End Logic
  1216.             $dateEndDisplay $fmtDate($row['dateEnd']);
  1217.             $dateEndTimestamp $getTimestamp($row['dateEnd']);
  1218.             if ($row['dateEnd'] instanceof \DateTimeInterface && $fmtYMD($row['dateEnd']) === '2000/01/01') {
  1219.                 $dateEndDisplay 'SIN ASIGNAR';
  1220.                 $dateEndTimestamp 0;
  1221.             }
  1222.             $statusLabel = match ($row['status']) {
  1223.                 'Bloqueo' => 'BLOQUEO',
  1224.                 'Confirmed' => 'CONFIRMADO',
  1225.                 'Invoiced' => 'FACTURADO',
  1226.                 'Cotizado' => 'COTIZADO',
  1227.                 'Deleted' => 'CANCELADO',
  1228.                 default => 'INICIADO',
  1229.             };
  1230.             $actions '<div class="btn-group">
  1231.                             <a href="/venues/edit/' $row['id'] . '" class="btn btn-sm bg-btn-vivid_sky_blue">
  1232.                                 <i class="glyphicon glyphicon-pencil"></i>
  1233.                             </a>
  1234.                             <a href="/venues/delete/' $row['id'] . '" class="btn btn-sm bg-btn-trash">
  1235.                                 <i class="glyphicon glyphicon-trash"></i>
  1236.                             </a>
  1237.                         </div>';
  1238.             $data[] = [
  1239.                 'createdAt' => [
  1240.                     'display' => $fmtDate($row['createdAt']),
  1241.                     'timestamp' => $getTimestamp($row['createdAt'])
  1242.                 ],
  1243.                 'id' => $row['id'],
  1244.                 'dateStart' => [
  1245.                     'display' => $dateStartDisplay,
  1246.                     'timestamp' => $dateStartTimestamp
  1247.                 ],
  1248.                 'dateEnd' => [
  1249.                     'display' => $dateEndDisplay,
  1250.                     'timestamp' => $dateEndTimestamp
  1251.                 ],
  1252.                 'title' => $row['title'],
  1253.                 'client' => $row['clientName'],
  1254.                 'createdBy' => $row['creatorName'],
  1255.                 'status' => $statusLabel,
  1256.                 'actions' => $actions
  1257.             ];
  1258.         }
  1259.         return $data;
  1260.     }
  1261.     /**
  1262.      * @Route("/listcanceled/{idgroup}", defaults={"idgroup" = 0}, name="reservations_canceled")
  1263.      */
  1264.     public function indexCanceledAction(EntityManagerInterface $em$idgroupRequest $request)
  1265.     {
  1266.         return $this->render(
  1267.             'MDS/VenuesBundle/reservations/list-reservations.html.twig',
  1268.             array(
  1269.                 'groups' => null,
  1270.                 'type' => 'canceled',
  1271.                 'titleView' => ' Canceladas',
  1272.                 'reservations' => [],
  1273.                 'dataUrl' => $this->generateUrl('reservations_canceled_data', ['idgroup' => $idgroup])
  1274.             )
  1275.         );
  1276.     }
  1277.     /**
  1278.      * @Route("/list/canceled/data/{idgroup}", defaults={"idgroup" = 0}, name="reservations_canceled_data", methods={"POST", "GET"})
  1279.      */
  1280.     public function canceledDataAction($idgroupRequest $requestEntityManagerInterface $em): JsonResponse
  1281.     {
  1282.         /** @var \App\MDS\VenuesBundle\Repository\ReservationRepository $repo */
  1283.         $repo $em->getRepository(Reservation::class);
  1284.         // Fetch ALL data (Client-side handling)
  1285.         $result $repo->findDataTablesCanceledData();
  1286.         $data = [];
  1287.         foreach ($result as $row) {
  1288.             // Helper for Date formatting
  1289.             $fmtDate = function ($d) {
  1290.                 return $d instanceof \DateTimeInterface $d->format('d/m/Y') : '';
  1291.             };
  1292.             $fmtYMD = function ($d) {
  1293.                 return $d instanceof \DateTimeInterface $d->format('Y/m/d') : '';
  1294.             };
  1295.             $getTimestamp = function ($d) {
  1296.                 return $d instanceof \DateTimeInterface $d->getTimestamp() : 0;
  1297.             };
  1298.             // Date Start Logic
  1299.             $dateStartDisplay $fmtDate($row['dateStart']);
  1300.             $dateStartTimestamp $getTimestamp($row['dateStart']);
  1301.             if ($row['dateStart'] instanceof \DateTimeInterface && $fmtYMD($row['dateStart']) === '2078/01/01') {
  1302.                 $dateStartDisplay 'SIN ASIGNAR';
  1303.                 $dateStartTimestamp 0;
  1304.             }
  1305.             // Date End Logic
  1306.             $dateEndDisplay $fmtDate($row['dateEnd']);
  1307.             $dateEndTimestamp $getTimestamp($row['dateEnd']);
  1308.             if ($row['dateEnd'] instanceof \DateTimeInterface && $fmtYMD($row['dateEnd']) === '2000/01/01') {
  1309.                 $dateEndDisplay 'SIN ASIGNAR';
  1310.                 $dateEndTimestamp 0;
  1311.             }
  1312.             // Status is always Deleted
  1313.             $statusLabel 'CANCELADO';
  1314.             $actions '<div class="btn-group">
  1315.                             <a href="/venues/edit/' $row['id'] . '" class="btn btn-sm bg-btn-vivid_sky_blue">
  1316.                                 <i class="glyphicon glyphicon-pencil"></i>
  1317.                             </a>
  1318.                             <a href="/venues/delete/' $row['id'] . '" class="btn btn-sm bg-btn-trash">
  1319.                                 <i class="glyphicon glyphicon-trash"></i>
  1320.                             </a>
  1321.                         </div>';
  1322.             $data[] = [
  1323.                 'createdAt' => [
  1324.                     'display' => $fmtDate($row['createdAt']),
  1325.                     'timestamp' => $getTimestamp($row['createdAt'])
  1326.                 ],
  1327.                 'id' => $row['id'],
  1328.                 'dateStart' => [
  1329.                     'display' => $dateStartDisplay,
  1330.                     'timestamp' => $dateStartTimestamp
  1331.                 ],
  1332.                 'dateEnd' => [
  1333.                     'display' => $dateEndDisplay,
  1334.                     'timestamp' => $dateEndTimestamp
  1335.                 ],
  1336.                 'title' => $row['title'],
  1337.                 'client' => $row['clientName'],
  1338.                 'createdBy' => $row['creatorName'],
  1339.                 'status' => $statusLabel,
  1340.                 'actions' => $actions
  1341.             ];
  1342.         }
  1343.         return new JsonResponse(['data' => $data]);
  1344.     }
  1345.     /**
  1346.      * @Route("/listquoted/{idgroup}", defaults={"idgroup" = 0}, name="reservations_quoted")
  1347.      */
  1348.     public function indexQuotedAction(EntityManagerInterface $em$idgroupRequest $request)
  1349.     {
  1350.         $parameters = array('status' => 'Cotizado');
  1351.         $dql 'SELECT i
  1352.                 FROM VenuesBundle:Reservation i
  1353.                 WHERE i.status = :status
  1354.                 ORDER BY i.createdAt ASC';
  1355.         $query $em->createQuery($dql)->setParameters($parameters);
  1356.         $ref = array();
  1357.         $reservas $query->getResult();
  1358.         foreach ($reservas as $res) {
  1359.             $client $em->getRepository(Client::class)->findOneById($res->getClient());
  1360.             if (!empty($client)) {
  1361.                 $res->setClient($client->getName());
  1362.             } else {
  1363.                 $res->setClient(null);
  1364.             }
  1365.             $res->setCreatedBy(
  1366.                 ($em->getRepository(User::class)->findOneById($res->getCreatedBy()))->getName() . ' ' .
  1367.                 ($em->getRepository(User::class)->findOneById($res->getCreatedBy()))->getLastName()
  1368.             );
  1369.             $ref[$res->getId()] = '#' . ($res->getCreatedAt())->format('ymdHi');
  1370.         }
  1371.         $reservasZero = array();
  1372.         foreach ($reservas as $res) {
  1373.             $data $this->CalculosTotalesEditSimple($res->getId());
  1374.             $reservasZero[] = array(
  1375.                 'dateStart' => $res->getDateStart(),
  1376.                 'dateEnd' => $res->getDateEnd(),
  1377.                 'id' => $res->getId(),
  1378.                 'title' => $res->getTitle(),
  1379.                 'client' => $res->getClient(),
  1380.                 'sales' => $data['sumatoria_totales_global_con_iva'],
  1381.                 'ref' => $ref[$res->getId()],
  1382.                 'createdAt' => $res->getCreatedAt(),
  1383.             );
  1384.         }
  1385.         $reservas $reservasZero;
  1386.         return $this->render(
  1387.             'MDS/VenuesBundle/reservations/list-reservations-quotation.html.twig',
  1388.             array(
  1389.                 'groups' => null,
  1390.                 'titleView' => ' Cotizadas',
  1391.                 'reservations' => $reservas
  1392.             )
  1393.         );
  1394.     }
  1395.     /**
  1396.      * @Route("/edit/{id}", name="reservations_venues_edit")
  1397.      */
  1398.     public function editAction($id)
  1399.     {
  1400.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $id'token' => null));
  1401.     }
  1402.     private function createEditReservationsForm(Reservation $entity$id)
  1403.     {
  1404.         $form $this->createForm(ReservationType::class, $entity, array('action' => $this->generateUrl('reservations_update', array('id' => $id)), 'method' => 'PUT'));
  1405.         return $form;
  1406.     }
  1407.   /**
  1408.      * @Route("/update/{id}", name="reservations_update")
  1409.      */
  1410.     public function update(
  1411.         int $id
  1412.         Request $request
  1413.         EntityManagerInterface $em
  1414.         Security $security
  1415.         TranslatorInterface $translator
  1416.         DocContractService $docContractService
  1417.     ): Response {
  1418.         $reserva $em->getRepository(Reservation::class)->find($id);
  1419.         if (!$reserva) {
  1420.             throw $this->createNotFoundException('Reserva no encontrada');
  1421.         }
  1422.         // 1. Guardar estados previos necesarios para lógica de negocio
  1423.         $oldPriority $reserva->getPriority();
  1424.         $oldStatus $reserva->getStatus();
  1425.         $user $security->getUser();
  1426.         $userId $user instanceof User $user->getId() : null;
  1427.         // 2. Crear formulario pasando las opciones necesarias
  1428.         $invoiceRepository $em->getRepository(ReservationInvoice::class);
  1429.         $invoiceRecRepository $em->getRepository(ReservationInvoiceRec::class);
  1430.         $hasInvoices = !empty($invoiceRepository->findByReservationId($id)) || !empty($invoiceRecRepository->findByReservationId($id));
  1431.         $form $this->createForm(ReservationType::class, $reserva, [
  1432.             'confirmable' => $this->laReservaEsConfirmable($id),
  1433.             'cotizable' => $this->laReservaEsCotizable($id),
  1434.             'invoiced' => $hasInvoices,
  1435.         ]);
  1436.         // Clonamos las fechas originales para aislar el estado antes del handleRequest
  1437.         $dateStart = clone $reserva->getDateStart();
  1438.         $dateEnd = clone $reserva->getDateEnd();
  1439.         $form->handleRequest($request);
  1440.         if ($form->isSubmitted() && $form->isValid()) {
  1441.             /** @var Reservation $reserva */
  1442.             $reserva $form->getData();
  1443.             $now = new \DateTime();
  1444.             // Restauramos las fechas para que mantengan la consistencia si el formulario las alteró
  1445.             $reserva->setDateStart($dateStart);
  1446.             $reserva->setDateEnd($dateEnd);
  1447.             // 3. Auditoría básica
  1448.             $reserva->setUpdatedBy($userId);
  1449.             $reserva->setUpdatedAt($now);
  1450.             // 4. Lógica de Prioridad
  1451.             if ($this->isGranted('ROLE_USER') && !$this->isGranted('ROLE_ADMIN')) {
  1452.                 $reserva->setPriority($oldPriority);
  1453.             }
  1454.             if (!$reserva->getPriority()) {
  1455.                 $reserva->setPriority(1);
  1456.             }
  1457.             // 5. Manejo de Contacto No Registrado
  1458.             $this->handleUnregisteredContact($form$reserva$user$em);
  1459.             // 6. Manejo de Status "Bloqueo"
  1460.             $newStatusFromForm $reserva->getStatus();
  1461.             $this->handleBlockStatus($form$reserva$user$em);
  1462.             // 7. Verificación final de Status
  1463.             $verifiedStatus $this->verificarStatusInicialyFinal($id$userId$oldStatus$newStatusFromForm);
  1464.             $reserva->setStatus($verifiedStatus);
  1465.             // 8. Lógica de Cancelación
  1466.             if ($verifiedStatus === 'Deleted' && $verifiedStatus !== 'Bloqueo') {
  1467.                 $this->handleCancellationAlert($id$reserva$em);
  1468.             }
  1469.             // 9. Recalcular fechas
  1470.             $this->reservationService->updateReservationDates($reserva);
  1471.             // 10. Valores por defecto
  1472.             if (!$reserva->getStatus()) {
  1473.                 $reserva->setStatus('Cotizado');
  1474.             }
  1475.             try {
  1476.                 $em->persist($reserva);
  1477.                 $em->flush();
  1478.                 $data $this->sincGpHtAvService->sincGlobalGpHtAv($id);
  1479.                 $this->addFlash('mensajereservation''La reserva ha sido actualizada.');
  1480.                 // --- ACTUALIZACIÓN DE LA AGENDA ---
  1481.                 $agendaLineTitle $em->getRepository(ReservationAgendaItem::class)->findBy([
  1482.                     'reservationId' => $reserva->getId(), 
  1483.                     'sourceType' => 'Reservation'
  1484.                 ]);
  1485.                 if (empty($agendaLineTitle)) {
  1486.                     $newItem = new ReservationAgendaItem();
  1487.                     $newItem->setReservationId($id);
  1488.                     $newItem->setRankListing(1);
  1489.                     $newItem->setTitleOne('EVENTO: ' $reserva->getTitle());
  1490.                     $newItem->setTitleTwo(null);
  1491.                     $newItem->setTitleThree(null);
  1492.                     $newItem->setDescription('.');
  1493.                     $newItem->setSourceId($id);
  1494.                     $newItem->setSourceType('Reservation');
  1495.                     $newItem->setCreatedId($userId);
  1496.                     $newItem->setUpdatedId($userId);
  1497.                     $newItem->setCreatedAt(new \DateTime());
  1498.                     $newItem->setUpdatedAt(new \DateTime());
  1499.                     $this->repository->add($newItemtrue);
  1500.                 } else {
  1501.                     $agendaLineTitle[0]->setTitleOne('EVENTO: ' $reserva->getTitle());
  1502.                     $agendaLineTitle[0]->setUpdatedId($userId);
  1503.                     $agendaLineTitle[0]->setUpdatedAt(new \DateTime());
  1504.                     $this->repository->add($agendaLineTitle[0], true);
  1505.                 }
  1506.                 // --- PROCESAMIENTO MAPPED => FALSE ---
  1507.                 $nameUnreg $form->get('nameContactUnregistered')->getData();
  1508.                 $phoneUnreg $form->get('phoneContactUnregistered')->getData();
  1509.                 $emailUnreg $form->get('contactUnregistered')->getData();
  1510.                 $contactString '';
  1511.                 $contactString .= !empty($nameUnreg) ? $nameUnreg 'No se pudo determinar el nombre';
  1512.                 $contactString .= !empty($phoneUnreg) ? ' / ' $phoneUnreg ' / No se pudo determinar el teléfono';
  1513.                 $contactString .= !empty($emailUnreg) ? ' / ' $emailUnreg ' / No se pudo determinar el email';
  1514.                 $this->agendaService->updateClientContactLine($reserva->getId(), $contactString$userId);
  1515.                 // 11. Redirecciones especiales post-guardado
  1516.                 if ($verifiedStatus === 'Confirmed') {
  1517.                     $this->_actualizarSalasYServicios($reserva);
  1518.                     $docContractService->autoAssignContracts($reserva$user);
  1519.                     
  1520.                     if ($verifiedStatus !== $oldStatus) {
  1521.                         return $this->redirectToRoute('reservations_venues_send_confirmation_request_mail', ['id' => $id]);
  1522.                     }
  1523.                 }
  1524.                 $this->_actualizarSalasYServicios($reserva);
  1525.                 return $this->redirectToRoute('reservations_venues_edit_simple', ['id' => $id'token' => null]);
  1526.             } catch (\Exception $e) {
  1527.                 $this->addFlash('mensajereservationerror'$translator->trans('An error occurred: ' $e->getMessage()));
  1528.                 return $this->redirectToRoute('reservations_venues_edit_simple', ['id' => $id'token' => null]);
  1529.             }
  1530.         }
  1531.         // =================================================================================
  1532.         // MANEJO DE ERRORES DE VALIDACIÓN (Si isValid() es false debido a las fechas o inputs)
  1533.         // =================================================================================
  1534.         foreach ($form->getErrors(true) as $error) {
  1535.             $this->addFlash('mensajereservationerror'$error->getMessage());
  1536.         }
  1537.         // Si hay un fallo crítico, redirigimos mostrando los mensajes flash acumulados en la sesión
  1538.         return $this->redirectToRoute('reservations_venues_edit_simple', ['id' => $id'token' => null]);
  1539.     }
  1540.     /**
  1541.      * @Route("/delete/{id}", name="reservations_delete")
  1542.      */
  1543.     public function deleteAction($idEntityManagerInterface $emRequest $request)
  1544.     {
  1545.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  1546.         $hoy = new \DateTime("now"NULL);
  1547.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1548.         $user_id $user_logueado->getId();
  1549.         $reserva->setUpdatedBy($user_id);
  1550.         $reserva->setUpdatedAt($hoy);
  1551.         $reserva->setStatus('Deleted');
  1552.         try {
  1553.             $em->persist($reserva);
  1554.             $em->flush();
  1555.             $data $this->sincGpHtAvService->sincGlobalGpHtAv($id);
  1556.             $successMessage 'La reserva ha sido actualizada.';
  1557.             $this->addFlash('mensajereservation'$successMessage);
  1558.         } catch (\Exception $e) {
  1559.             $event 'An error occurred: ' $e->getMessage();
  1560.             $errorMessage $this->translator->trans($event);
  1561.             $this->addFlash('mensajereservationerror'$errorMessage);
  1562.         }
  1563. //        return $this->redirectToRoute('reservations_venues_index');
  1564.         return $this->redirectToRoute('reservations_venues_edit_simple', ['id' => $id'token' => null]);
  1565.     }
  1566.     /**
  1567.      * @Route("/listgpprices", name="reservations_venues_prices")
  1568.      */
  1569.     public function indexPricesAction(EntityManagerInterface $emRequest $request)
  1570.     {
  1571.         $prices $em->getRepository(ReservationLoungeProfile::class)->findBy(
  1572.             array(),
  1573.             array('id' => 'ASC')
  1574.         );
  1575.         $data = [];
  1576.         foreach ($prices as $price) {
  1577.             $periodSql $em->getRepository(ReservationPeriod::class)->findOneById($price->getPeriodId());
  1578.             $price->setPeriodId($periodSql->getName());
  1579.             $reservationsLoungeTemp $em->getRepository(ReservationLoungeDetails::class)->findOneById($price->getLoungeId());
  1580.             if (!is_null($reservationsLoungeTemp)) {
  1581.                 $price->setLoungeId($reservationsLoungeTemp->getName());
  1582.             }
  1583.             $data[] = $price;
  1584.         }
  1585.         $reserv = new ReservationLoungeProfile();
  1586.         $form $this->createReservationLoungeProfileCreateForm($reserv);
  1587.         return $this->render(
  1588.             'MDS/VenuesBundle/reservations/list-reservations-gp-prices.html.twig',
  1589.             array(
  1590.                 'groups' => null,
  1591.                 'prices' => $data,
  1592.                 'form' => $form->createView()
  1593.             )
  1594.         );
  1595.     }
  1596.     /**
  1597.      * @Route("/deletegpprice/{id}", name="reservations_price_delete")
  1598.      */
  1599.     public function deletePriceAction($idEntityManagerInterface $emRequest $request)
  1600.     {
  1601.         $price $em->getRepository(ReservationLoungeProfile::class)->findOneById($id);
  1602.         try {
  1603.             $em->remove($price);
  1604.             $em->flush();
  1605.             $event 'The Item has been Deleted.';
  1606.             $successMessage $this->translator->trans($event);
  1607.             $this->addFlash('mensajereservation'$successMessage);
  1608.         } catch (\Exception $e) {
  1609.             $event 'An error occurred: ' $e->getMessage();
  1610.             /* Para el usuario */
  1611.             $errorMessage $this->translator->trans($event);
  1612.             $this->addFlash('mensajereservationerror'$errorMessage);
  1613.         }
  1614.         return $this->redirectToRoute('reservations_venues_prices');
  1615.     }
  1616.     /**
  1617.      * @Route("/addgpprice/",  name="reservations_venues_addgpprice")
  1618.      */
  1619.     public function addReservationGpPriceAction(EntityManagerInterface $emRequest $request)
  1620.     {
  1621.         $reserv = new ReservationLoungeProfile();
  1622.         $form $this->createReservationLoungeProfileCreateForm($reserv);
  1623.         $gpPrices $em->getRepository(ReservationLoungeProfile::class)->findAll();
  1624.         return $this->render('MDS/VenuesBundle/reservations/add-reservations-gp-price.html.twig', array('form' => $form->createView(), 'gpPrices' => $gpPrices));
  1625.     }
  1626.     private function createReservationLoungeProfileCreateForm(ReservationLoungeProfile $entity)
  1627.     {
  1628.         $form $this->createForm(ReservationLoungeProfileType::class, $entity, array(
  1629.             'action' => $this->generateUrl('reservations_venues_price_create'),
  1630.             'method' => 'POST'
  1631.         ));
  1632.         return $form;
  1633.     }
  1634.     /**
  1635.      * @Route("/creategpprice", name="reservations_venues_price_create")
  1636.      */
  1637.     public function createGpPriceAction(EntityManagerInterface $emRequest $request)
  1638.     {
  1639.         $reservaGpPrice = new ReservationLoungeProfile();
  1640.         $form $this->createReservationLoungeProfileCreateForm($reservaGpPrice);
  1641.         $form->handleRequest($request);
  1642.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1643.         $user_id $user_logueado->getId();
  1644.         $hoy = new \DateTime("now"NULL);
  1645.         $reservaGpPrice->setCreatedAt($hoy);
  1646.         $reservaGpPrice->setCreatedId($user_id);
  1647.         $reservaGpPrice->setUpdatedAt($hoy);
  1648.         $reservaGpPrice->setUpdatedId($user_id);
  1649.         $periodSql $em->getRepository(ReservationPeriod::class)->findOneById($form->get('periodId')->getData());
  1650.         if (!empty($periodSql)) {
  1651.             $descTemp $periodSql->getName();
  1652.         } else {
  1653.             $descTemp null;
  1654.         }
  1655.         $reservaGpPrice->setPeriodId($reservaGpPrice->getPeriodId()->getId());
  1656.         $reservaGpPrice->setLoungeId($reservaGpPrice->getLoungeId()->getId());
  1657.         if ((!is_null($reservaGpPrice->getLoungeId())) and (!is_null($descTemp))) {
  1658.             $descriptionSql $em->getRepository(ReservationLoungeDetails::class)->findOneById($form->get('loungeId')->getData());
  1659.             $description $descriptionSql->getName() . ' - ' $descTemp;
  1660.             $reservaGpPrice->setDescription($description);
  1661.         } else {
  1662.             $reservaGpPrice->setDescription(null);
  1663.         }
  1664.         if ($form->isValid()) {
  1665.             try {
  1666.                 $em->persist($reservaGpPrice);
  1667.                 $em->flush();
  1668.                 $event 'The Item Price has been created.';
  1669.                 $successMessage $this->translator->trans($event);
  1670.                 $this->addFlash('mensajereservation'$successMessage);
  1671.             } catch (\Exception $e) {
  1672.                 $event 'An error occurred: ' $e->getMessage();
  1673.                 $errorMessage $this->translator->trans($event);
  1674.                 $this->addFlash('mensajereservationerror'$errorMessage);
  1675.             }
  1676.         } else {
  1677.             $errorMessage $this->translator->trans('Error, some fields are empty');
  1678.             $this->addFlash('mensajereservationerror'$errorMessage);
  1679.         }
  1680.         return $this->redirectToRoute('reservations_venues_prices');
  1681.     }
  1682.     /**
  1683.      * @Route("/getReservationLoungeProfile", name="get_reservation_lounge_profile")
  1684.      */
  1685.     public function getReservationLoungeProfileAction(EntityManagerInterface $emRequest $request)
  1686.     {
  1687.         $codProfile $_POST['idprofile'];
  1688.         $salasPorPerfil $em->getRepository(ReservationLoungeProfile::class)->findBy(array('periodId' => $codProfile));
  1689.         $datos = [];
  1690.         if (!empty($salasPorPerfil)) {
  1691.             foreach ($salasPorPerfil as $sala) {
  1692.                 $datos[] = array(
  1693.                     "id" => $sala->getId(),
  1694.                     "idlounge" => $sala->getLoungeId(),
  1695.                     "nameDescription" => $sala->getDescription(),
  1696.                     "price" => $sala->getPrice(),
  1697.                 );
  1698.             }
  1699.         }
  1700.         $return = array('salasPerfil' => $datos'id' => $codProfile, );
  1701.         $response = new JsonResponse($return);
  1702.         return $response;
  1703.     }
  1704.     /**
  1705.      * @Route("/getReservationPeriod", name="get_reservation_Period")
  1706.      */
  1707.     public function getReservationPeriodAction(EntityManagerInterface $emRequest $request)
  1708.     {
  1709.         $id $_POST['id'];
  1710.         $period $em->getRepository(ReservationPeriod::class)->findOneById($id);
  1711.         $datos = array();
  1712.         if (!empty($period)) {
  1713.             $datos = array(
  1714.                 "id" => $period->getId(),
  1715.                 "hourStart" => is_null($period->getHourStart()) ? "" $period->getHourStart()->format('H:i'),
  1716.                 "hourEnd" => is_null($period->getHourEnd()) ? "" $period->getHourEnd()->format('H:i'),
  1717.             );
  1718.         }
  1719.         $return $datos;
  1720.         $response = new JsonResponse($return);
  1721.         return $response;
  1722.     }
  1723.     /**
  1724.      * @Route("/getReservationLoungePrice", name="get_reservation_lounge_price")
  1725.      */
  1726.     public function getReservationLoungePriceAction(EntityManagerInterface $emRequest $request)
  1727.     {
  1728.         $id $_POST['id'];
  1729.         $precio $em->getRepository(ReservationLoungeProfile::class)->findOneById($id);
  1730.         $datos = array();
  1731.         if (!empty($precio)) {
  1732.             $datos = array("id" => $precio->getId(), "price" => $precio->getPrice());
  1733.         }
  1734.         $return $datos;
  1735.         $response = new JsonResponse($return);
  1736.         return $response;
  1737.     }
  1738.     /**
  1739.      * @Route("/addloungedetails/",  name="reservations_venues_addloungedetails")
  1740.      */
  1741.     public function addReservationLoungeDetailsAction(Request $request)
  1742.     {
  1743.         $reservationsLounge = new ReservationLoungeDetails();
  1744.         $form $this->createReservationLoungeDetailsCreateForm($reservationsLounge);
  1745.         return $this->render('MDS/VenuesBundle/reservations/add-reservations-lounge-details.html.twig', array('form' => $form->createView()));
  1746.     }
  1747.     private function createReservationLoungeDetailsCreateForm(ReservationLoungeDetails $entity)
  1748.     {
  1749.         $form $this->createForm(ReservationLoungeDetailsType::class, $entity, array(
  1750.             'action' => $this->generateUrl('reservations_venues_lounge_details_create'),
  1751.             'method' => 'POST'
  1752.         ));
  1753.         return $form;
  1754.     }
  1755.     /**
  1756.      * @Route("/createloungedetails", name="reservations_venues_lounge_details_create")
  1757.      */
  1758.     public function createLoungeDetailsAction(EntityManagerInterface $emRequest $request)
  1759.     {
  1760.         $reservationsLounge = new ReservationLoungeDetails();
  1761.         $form $this->createReservationLoungeDetailsCreateForm($reservationsLounge);
  1762.         $form->handleRequest($request);
  1763.         /* Obtengo usuario logueado */
  1764.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1765.         $user_id $user_logueado->getId();
  1766.         $hoy = new \DateTime("now"NULL);
  1767.         $reservationsLounge->setCreatedAt($hoy);
  1768.         $reservationsLounge->setCreatedId($user_id);
  1769.         $reservationsLounge->setUpdatedAt($hoy);
  1770.         $reservationsLounge->setUpdatedId($user_id);
  1771.         if ($form->isValid()) {
  1772.             try {
  1773.                 $em->persist($reservationsLounge);
  1774.                 $em->flush();
  1775.                 $event 'The Lounge has been created.';
  1776.                 $successMessage $this->translator->trans($event);
  1777.                 $this->addFlash('mensajereservation'$successMessage);
  1778.                 $this->reordenarSalas($reservationsLounge->getRankLounge(), $reservationsLounge->getId());
  1779.             } catch (\Exception $e) {
  1780.                 $event 'An error occurred: ' $e->getMessage();
  1781.                 /* Para el usuario */
  1782.                 $errorMessage $this->translator->trans($event);
  1783.                 $this->addFlash('mensajereservationerror'$errorMessage);
  1784.             }
  1785.         } else {
  1786.             $errorMessage $this->translator->trans('Error, some fields are empty');
  1787.             $this->addFlash('mensajereservationerror'$errorMessage);
  1788.         }
  1789.         return $this->redirectToRoute('reservations_venues_list_lounges');
  1790.     }
  1791.     /**
  1792.      * @Route("/listloungedetails", name="reservations_venues_list_lounges")
  1793.      */
  1794.     public function indexLoungesAction(EntityManagerInterface $emRequest $request)
  1795.     {
  1796.         $salas $em->getRepository(ReservationLoungeDetails::class)->findAll();
  1797.         $reservationsLounge = new ReservationLoungeDetails();
  1798.         $form $this->createReservationLoungeDetailsCreateForm($reservationsLounge);
  1799.         return $this->render(
  1800.             'MDS/VenuesBundle/reservations/list-reservations-lounges-details.html.twig',
  1801.             array(
  1802.                 'groups' => null,
  1803.                 'salas' => $salas,
  1804.                 'form' => $form->createView()
  1805.             )
  1806.         );
  1807.     }
  1808.     /**
  1809.      * @Route("/editloungedetails/{id}", name="reservations_lounge_details")
  1810.      */
  1811.     public function editLoungeDetailsAction($idEntityManagerInterface $emRequest $request)
  1812.     {
  1813.         $reservationsLounge $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  1814.         $reservationsLoungePictures $em->getRepository(ReservationLoungePicture::class)->findBy(array('loungeId' => $id'title' => null, ));
  1815.         $reservationsLoungeVideos $em->getRepository(ReservationLoungeVideo::class)->findByLoungeId($id);
  1816.         $reservationsLoungeDescriptions $em->getRepository(ReservationLoungeDescription::class)->findByLoungeId($id);
  1817.         $reservationsLoungeWebDescriptions $em->getRepository(ReservationLoungeWebDescription::class)->findByLounge($reservationsLounge);
  1818.         $descriptionsByLanguage = [];
  1819.         foreach ($reservationsLoungeWebDescriptions as $description) {
  1820.             $descriptionsByLanguage[$description->getLanguage()] = $description;
  1821.         }
  1822.         /* Obtengo usuario logueado */
  1823.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1824.         $user_id $user_logueado->getId();
  1825.         /* Gestión de eventos en Log */
  1826.         $user_lastname $user_logueado->getLastname();
  1827.         $user_name $user_logueado->getName();
  1828.         $user_email $user_logueado->getEmail();
  1829.         $user_rol $user_logueado->getRoles();
  1830.         $event_url $request->getPathInfo();
  1831.         $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  1832.         $hoy = new \DateTime("now"NULL);
  1833.         $form $this->createEditReservationLoungeDetailsForm($reservationsLounge$id);
  1834.         // Para evitar le duplicidad de idiomas en las descripciones
  1835.         $reservationsLoungeDescriptionsPreexistentes $em->getRepository(ReservationLoungeDescription::class)->findByLoungeId($id);
  1836.         $idiomasPreexistentes = array();
  1837.         foreach ($reservationsLoungeDescriptionsPreexistentes as $item) {
  1838.             $idiomasPreexistentes[] = $item->getLanguage();
  1839.         }
  1840.         $datos_videos = array();
  1841.         foreach ($reservationsLoungeVideos as $video) {
  1842.             $urvideo_final '<iframe class="embed-responsive-item" src="' $video->getVideo() . '"></iframe>';
  1843.             $datos_videos[] = array(
  1844.                 'id' => $video->getId(),
  1845.                 'urlvideo' => $urvideo_final
  1846.             );
  1847.         }
  1848.         $blueprints $em->getRepository(ReservationLoungePicture::class)->findBy(array('loungeId' => $id'title' => 'Blueprint', ));
  1849.         $pictTeatro $em->getRepository(ReservationLoungePicture::class)->findBy(array('loungeId' => $id'title' => 'Teatro', ));
  1850.         if (sizeof($pictTeatro) == 0) {
  1851.             $pictTeatro null;
  1852.         }
  1853.         $pictCoctel $em->getRepository(ReservationLoungePicture::class)->findBy(array('loungeId' => $id'title' => 'Coctel', ));
  1854.         if (sizeof($pictCoctel) == 0) {
  1855.             $pictCoctel null;
  1856.         }
  1857.         $pictEscuela $em->getRepository(ReservationLoungePicture::class)->findBy(array('loungeId' => $id'title' => 'Escuela', ));
  1858.         if (sizeof($pictEscuela) == 0) {
  1859.             $pictEscuela null;
  1860.         }
  1861.         $picsMontaje = array(
  1862.             'pictTeatro' => $pictTeatro,
  1863.             'pictCoctel' => $pictCoctel,
  1864.             'pictEscuela' => $pictEscuela
  1865.         );
  1866.         if (empty($picsMontaje['pictTeatro']) and empty($picsMontaje['pictCoctel']) and empty($picsMontaje['pictEscuela'])) {
  1867.             $picsMontaje null;
  1868.         }
  1869.         $reservationsLoungedimmensions $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  1870.         return $this->render(
  1871.             'MDS/VenuesBundle/reservations/edit-reservations-lounge-details.html.twig',
  1872.             array(
  1873.                 'id' => $id,
  1874.                 'hoy' => $hoy,
  1875.                 'lounge' => $reservationsLounge,
  1876.                 'descriptions' => $reservationsLoungeDescriptions,
  1877.                 'loungeWebDesctiptions' => $descriptionsByLanguage,
  1878.                 'languagesWeb' => LanguageConstants::getAvailableLanguages(),
  1879.                 'pictures' => $reservationsLoungePictures,
  1880.                 'blueprints' => $blueprints,
  1881.                 'picsMontaje' => $picsMontaje,
  1882.                 'loungedimmensions' => $reservationsLoungedimmensions,
  1883.                 'videos' => $datos_videos,
  1884.                 'idiomasPreexistentes' => $idiomasPreexistentes,
  1885.                 'form' => $form->createView()
  1886.             )
  1887.         );
  1888.     }
  1889.     private function createEditReservationLoungeDetailsForm(ReservationLoungeDetails $entity$id)
  1890.     {
  1891.         $form $this->createForm(
  1892.             ReservationLoungeDetailsType::class,
  1893.             $entity,
  1894.             array(
  1895.                 'action' => $this->generateUrl(
  1896.                     'reservations_lounge_details_update',
  1897.                     array(
  1898.                         'id' => $id,
  1899.                         'price' => $entity
  1900.                     )
  1901.                 ),
  1902.                 'method' => 'PUT'
  1903.             )
  1904.         );
  1905.         return $form;
  1906.     }
  1907.     /**
  1908.      * @Route("/updateloungedetails/{id}", name="reservations_lounge_details_update")
  1909.      */
  1910.     public function updateLoungeDetailsAction($idRequest $request)
  1911.     {
  1912.         $em $this->getDoctrine()->getManager();
  1913.         $reservationsLounge $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  1914.         $reservationsLounge->setName($request->request->get('mds_venuesbundle_reservationloungedetails')['name']);
  1915.         $preNumber $reservationsLounge->getRankLounge();
  1916.         $postNumber $request->request->get('mds_venuesbundle_reservationloungedetails')['rankLounge'];
  1917.         $hoy = new \DateTime("now"NULL);
  1918.         $form $this->createEditReservationLoungeDetailsForm($reservationsLounge$id);
  1919.         $form->handleRequest($request);
  1920.         if ($form->isValid()) {
  1921.             /* Obtengo usuario logueado */
  1922.             $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  1923.             $user_id $user_logueado->getId();
  1924.             /* Gestión de eventos en Log */
  1925.             $user_lastname $user_logueado->getLastname();
  1926.             $user_name $user_logueado->getName();
  1927.             $user_email $user_logueado->getEmail();
  1928.             $user_rol $user_logueado->getRoles();
  1929.             $event_url $request->getPathInfo();
  1930.             $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  1931.             $reservationsLounge->setUpdatedId($user_id);
  1932.             $reservationsLounge->setUpdatedAt($hoy);
  1933.             try {
  1934.                 // Reordenar salas si se ha cambiado el rank number de la sala
  1935.                 if (!($preNumber == $postNumber)) {
  1936.                     $this->reordenarSalas($postNumber$reservationsLounge->getId());
  1937.                 }
  1938.                 $em->persist($reservationsLounge);
  1939.                 $em->flush();
  1940.                 $event 'The lounge has been Updated. Now';
  1941.                 $successMessage $this->translator->trans($event);
  1942.                 $this->addFlash('mensajereservation'$successMessage);
  1943.             } catch (\Exception $e) {
  1944.                 $event 'An error occurred: ' $e->getMessage();
  1945.                 /* Para el usuario */
  1946.                 $errorMessage $this->translator->trans($event);
  1947.                 $this->addFlash('mensajereservationerror'$errorMessage);
  1948.             }
  1949.             /* Fin Gestión de eventos en Log */
  1950.             return $this->redirectToRoute('reservations_venues_list_lounges');
  1951.         } else {
  1952.             $errorMessage $this->translator->trans('Error, some fields are empty');
  1953.             $this->addFlash('mensajereservationerror'$errorMessage);
  1954.         }
  1955.         return $this->render(
  1956.             'MDS/VenuesBundle/reservations/edit-reservations-lounge-details.html.twig',
  1957.             array(
  1958.                 'id' => $reservationsLounge->getId(),
  1959.                 'lounge' => $reservationsLounge,
  1960.                 'form' => $form->createView()
  1961.             )
  1962.         );
  1963.     }
  1964.     /**
  1965.      * @Route("/deleteloungedetails/{id}", name="reservations_lounge_details_delete")
  1966.      */
  1967.     public function deleteLoungeDetailsAction($idEntityManagerInterface $emRequest $request)
  1968.     {
  1969.         $reservationsLounge $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  1970.         try {
  1971.             $em->remove($reservationsLounge);
  1972.             $em->flush();
  1973.             // INICIO: Eliminamos los precios asociados a la sala
  1974.             $profiles $em->getRepository(ReservationLoungeProfile::class)->findByLoungeId($id);
  1975.             foreach ($profiles as $item) {
  1976.                 $em->remove($item);
  1977.                 $em->flush();
  1978.             }
  1979.             // FIN: Eliminamos los precios asociados a la sala
  1980.             $event 'The Reservation has been Deleted. Now';
  1981.             $successMessage $this->translator->trans($event);
  1982.             $this->addFlash('mensajereservation'$successMessage);
  1983.         } catch (\Exception $e) {
  1984.             $event 'An error occurred: ' $e->getMessage();
  1985.             /* Para el usuario */
  1986.             $errorMessage $this->translator->trans($event);
  1987.             $this->addFlash('mensajereservationerror'$errorMessage);
  1988.         }
  1989.         /* Fin Gestión de eventos en Log */
  1990.         return $this->redirectToRoute('reservations_venues_list_lounges');
  1991.     }
  1992.     /**
  1993.      * @Route("/deleteloungeelement/{idlounge}/{idtype}/{idelement}", name="reservations_lounge_element_delete")
  1994.      */
  1995.     public function deleteLoungeElementAction($idlounge$idtype$idelementEntityManagerInterface $emRequest $request)
  1996.     {
  1997.         switch ($idtype) {
  1998.             case 1:
  1999.                 $item $em->getRepository(ReservationLoungeDescription::class)->findOneById($idelement);
  2000.                 break;      //Descripcion
  2001.             case 2:
  2002.                 $item $em->getRepository(ReservationLoungePicture::class)->findOneById($idelement);
  2003.                 break;      //Imagenes
  2004.             case 3:
  2005.                 $item $em->getRepository(ReservationLoungeVideo::class)->findOneById($idelement);
  2006.                 break;      //Videos
  2007.             default:
  2008.                 $item null;
  2009.                 break;
  2010.         }
  2011.         try {
  2012.             $em->remove($item);
  2013.             $em->flush();
  2014.             $event 'The Item has been Deleted. Now';
  2015.             $successMessage $this->translator->trans($event);
  2016.             $this->addFlash('mensajereservation'$successMessage);
  2017.         } catch (\Exception $e) {
  2018.             $event 'An error occurred: ' $e->getMessage();
  2019.             /* Para el usuario */
  2020.             $errorMessage $this->translator->trans($event);
  2021.             $this->addFlash('mensajereservationerror'$errorMessage);
  2022.         }
  2023.         /* Fin Gestión de eventos en Log */
  2024.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $idlounge));
  2025.     }
  2026.     /**
  2027.      *@Route("/exclamation", name="get_exclamation")
  2028.      */
  2029.     public function exclamationAction(EntityManagerInterface $emRequest $request)
  2030.     {
  2031.         $dateStar $request->request->get('dateStar');
  2032.         $dateEnd $request->request->get('dateEnd');
  2033.         $hourStar $request->request->get('hourStar');
  2034.         $hourEnd $request->request->get('hourEnd');
  2035.         $profileId $request->request->get('profileId');
  2036.         $mountingDate $request->request->get('mountingDate');
  2037.         $mountingHourStart $request->request->get('mountingHourStart');
  2038.         $removalDate $request->request->get('removalDate');
  2039.         $removalHourEnd $request->request->get('removalHourEnd');
  2040.         // INICIO: Si hay montaje o desmontaje  en el evento nuevo las fechas a utilizar son estas y no las del evento
  2041.         if (!empty($mountingDate)) {
  2042.             $dateStar $mountingDate;
  2043.             if (!empty($mountingHourStart)) {
  2044.                 $hourStar $mountingHourStart;
  2045.             }
  2046.         }
  2047.         if (!empty($removalDate)) {
  2048.             $dateEnd $removalDate;
  2049.             if (!empty($removalHourEnd)) {
  2050.                 $hourEnd $removalHourEnd;
  2051.             }
  2052.         }
  2053.         // FIN: Si hay montaje o desmontaje  en el evento nuevo las fechas a utilizar son estas y no las del evento
  2054.         $reservationsLoungeId $em->getRepository(ReservationLoungeProfile::class)->findOneById($profileId);
  2055.         $newdateStar $dateStar ' ' $hourStar ':00';
  2056.         $newdateEnd $dateEnd ' ' $hourEnd ':00';
  2057.         $parameters = array(
  2058.             'dateStar' => $newdateStar,
  2059.             'dateEnd' => $newdateEnd,
  2060.             'idLounge' => $reservationsLoungeId->getLoungeId(),
  2061.         );
  2062.         $dql 'SELECT i
  2063.                     FROM VenuesBundle:ReservationLounge i
  2064.                     WHERE  i.dateStart >= :dateStar
  2065.                       and i.dateStart <= :dateEnd
  2066.                       and i.idLounge = :idLounge';
  2067.         $query $em->createQuery($dql)->setParameters($parameters);
  2068.         $reservationLounge1 $query->getResult();
  2069.         $dql 'SELECT i
  2070.                     FROM VenuesBundle:ReservationLounge i
  2071.                     WHERE  i.dateEnd >= :dateStar
  2072.                       and i.dateEnd <= :dateEnd
  2073.                       and i.idLounge = :idLounge';
  2074.         $query $em->createQuery($dql)->setParameters($parameters);
  2075.         $reservationLounge2 $query->getResult();
  2076.         $parameters = array(
  2077.             'dateStar' => $newdateStar,
  2078.             'idLounge' => $reservationsLoungeId->getLoungeId()
  2079.         );
  2080.         $dql 'SELECT i
  2081.                     FROM VenuesBundle:ReservationLounge i
  2082.                     WHERE  :dateStar >= i.dateStart
  2083.                       and :dateStar <= i.dateEnd
  2084.                       and i.idLounge = :idLounge';
  2085.         $query $em->createQuery($dql)->setParameters($parameters);
  2086.         $reservationLounge3 $query->getResult();
  2087.         $parameters = array(
  2088.             'dateEnd' => $newdateEnd,
  2089.             'idLounge' => $reservationsLoungeId->getLoungeId(),
  2090.         );
  2091.         $dql 'SELECT i
  2092.                     FROM VenuesBundle:ReservationLounge i
  2093.                     WHERE  :dateEnd >= i.dateStart
  2094.                       and :dateEnd <= i.dateEnd
  2095.                       and i.idLounge = :idLounge';
  2096.         $query $em->createQuery($dql)->setParameters($parameters);
  2097.         $reservationLounge4 $query->getResult();
  2098.         // INICIO: Si hay montaje o desmontaje  en los eventos de la BD, las fechas a utilizar son estas y no las del evento
  2099.         $parameters = array(
  2100.             'dateStar' => $newdateStar,
  2101.             'dateEnd' => $newdateEnd,
  2102.             'idLounge' => $reservationsLoungeId->getLoungeId(),
  2103.         );
  2104.         $dql 'SELECT i
  2105.                     FROM VenuesBundle:ReservationLounge i
  2106.                     WHERE  i.mountingDate >= :dateStar
  2107.                       and i.mountingDate <= :dateEnd
  2108.                       and i.idLounge = :idLounge';
  2109.         $query $em->createQuery($dql)->setParameters($parameters);
  2110.         $reservationLounge5 $query->getResult();
  2111.         // FIN: Si hay montaje o desmontaje  en los eventos de la BD, las fechas a utilizar son estas y no las del evento
  2112.         $reservationLounge array_merge($reservationLounge1$reservationLounge2$reservationLounge3$reservationLounge4);
  2113.         $data = array();
  2114.         foreach ($reservationLounge as $res) {
  2115.             $reservation $em->getRepository(Reservation::class)->findOneById($res->getIdReservation());
  2116.             $user $em->getRepository(User::class)->findOneById($reservation->getCreatedBy());
  2117.             $data[] = array(
  2118.                 'name' => 'Id Venues',
  2119.                 'idproposal' => $reservation->getId(),
  2120.                 'title' => $reservation->getTitle(),
  2121.                 'Agent' => $user->getName() . ' ' $user->getLastname(),
  2122.             );
  2123.         }
  2124.         $return = array('reservation' => $data, );
  2125.         $response = new JsonResponse($return);
  2126.         return $response;
  2127.     }
  2128.     /**
  2129.      * @Route("/addperiod/",  name="reservations_venues_addperiod")
  2130.      */
  2131.     public function addReservationPeriodAction(Request $request)
  2132.     {
  2133.         $period = new ReservationPeriod();
  2134.         $form $this->createReservationperiodCreateForm($period);
  2135.         return $this->render('MDS/VenuesBundle/reservations/list-reservations-period.html.twig', array('form' => $form->createView()));
  2136.     }
  2137.     private function createReservationperiodCreateForm(Reservationperiod $entity)
  2138.     {
  2139.         $form $this->createForm(ReservationPeriodType::class, $entity, array(
  2140.             'action' => $this->generateUrl('reservations_venues_period_create'),
  2141.             'method' => 'POST'
  2142.         ));
  2143.         return $form;
  2144.     }
  2145.     /**
  2146.      * @Route("/createperiod", name="reservations_venues_period_create")
  2147.      */
  2148.     public function createPeriodAction(EntityManagerInterface $emRequest $request)
  2149.     {
  2150.         $period = new ReservationPeriod();
  2151.         $form $this->createReservationPeriodCreateForm($period);
  2152.         $form->handleRequest($request);
  2153.         /* Obtengo usuario logueado */
  2154.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  2155.         $user_id $user_logueado->getId();
  2156.         $hoy = new \DateTime("now"NULL);
  2157.         $period->setCreatedAt($hoy);
  2158.         $period->setCreatedId($user_id);
  2159.         $period->setUpdatedAt($hoy);
  2160.         $period->setUpdatedId($user_id);
  2161.         if ($form->isValid()) {
  2162.             try {
  2163.                 $em->persist($period);
  2164.                 $em->flush();
  2165.                 $event 'The Period has been created.';
  2166.                 $successMessage $this->translator->trans($event);
  2167.                 $this->addFlash('mensajereservation'$successMessage);
  2168.             } catch (\Exception $e) {
  2169.                 $event 'An error occurred: ' $e->getMessage();
  2170.                 /* Para el usuario */
  2171.                 $errorMessage $this->translator->trans($event);
  2172.                 $this->addFlash('mensajereservationerror'$errorMessage);
  2173.             }
  2174.         } else {
  2175.             $errorMessage $this->translator->trans('Error, some fields are empty');
  2176.             $this->addFlash('mensajereservationerror'$errorMessage);
  2177.         }
  2178.         return $this->redirectToRoute('reservations_venues_list_period');
  2179.     }
  2180.     /**
  2181.      * @Route("/listperiod", name="reservations_venues_list_period")
  2182.      */
  2183.     public function indexPeriodAction(EntityManagerInterface $emRequest $request)
  2184.     {
  2185.         $periods $em->getRepository(ReservationPeriod::class)->findAll();
  2186.         $period = new ReservationPeriod();
  2187.         $form $this->createReservationPeriodCreateForm($period);
  2188.         return $this->render(
  2189.             'MDS/VenuesBundle/reservations/list-reservations-period.html.twig',
  2190.             array(
  2191.                 'groups' => null,
  2192.                 'form' => $form->createView(),
  2193.                 'periods' => $periods
  2194.             )
  2195.         );
  2196.     }
  2197.     /**
  2198.      * @Route("/deleteperiod/{id}", name="reservations_period_delete")
  2199.      */
  2200.     public function deletePeriodAction(EntityManagerInterface $em$idRequest $request)
  2201.     {
  2202.         $period $em->getRepository(ReservationPeriod::class)->findOneById($id);
  2203.         try {
  2204.             $em->remove($period);
  2205.             $em->flush();
  2206.             $event 'The Reservation has been Deleted. Now';
  2207.             $successMessage $this->translator->trans($event);
  2208.             $this->addFlash('mensajereservation'$successMessage);
  2209.         } catch (\Exception $e) {
  2210.             $event 'An error occurred: ' $e->getMessage();
  2211.             /* Para el usuario */
  2212.             $errorMessage $this->translator->trans($event);
  2213.             $this->addFlash('mensajereservationerror'$errorMessage);
  2214.         }
  2215.         /* Fin Gestión de eventos en Log */
  2216.         return $this->redirectToRoute('reservations_venues_list_period');
  2217.     }
  2218.     /**
  2219.      * @Route("/editperiod/{id}", name="reservations_edit_period")
  2220.      */
  2221.     public function editPeriodAction($idEntityManagerInterface $emRequest $request)
  2222.     {
  2223.         $period $em->getRepository(ReservationPeriod::class)->findOneById($id);
  2224.         /* Obtengo usuario logueado */
  2225.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  2226.         /* Gestión de eventos en Log */
  2227.         $user_lastname $user_logueado->getLastname();
  2228.         $user_name $user_logueado->getName();
  2229.         $user_email $user_logueado->getEmail();
  2230.         $user_rol $user_logueado->getRoles();
  2231.         $event_url $request->getPathInfo();
  2232.         $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  2233.         $hoy = new \DateTime("now"NULL);
  2234.         $form $this->createEditPeriodForm($period$id);
  2235.         return $this->render(
  2236.             'MDS/VenuesBundle/reservations/edit-reservations-period.html.twig',
  2237.             array(
  2238.                 'id' => $id,
  2239.                 'hoy' => $hoy,
  2240.                 'period' => $period,
  2241.                 'form' => $form->createView()
  2242.             )
  2243.         );
  2244.     }
  2245.     private function createEditPeriodForm(ReservationPeriod $entity$id)
  2246.     {
  2247.         $form $this->createForm(
  2248.             ReservationPeriodType::class,
  2249.             $entity,
  2250.             array(
  2251.                 'action' => $this->generateUrl(
  2252.                     'reservations_period_update',
  2253.                     array(
  2254.                         'id' => $id,
  2255.                         'period' => $entity
  2256.                     )
  2257.                 ),
  2258.                 'method' => 'PUT'
  2259.             )
  2260.         );
  2261.         return $form;
  2262.     }
  2263.     /**
  2264.      * @Route("/updateperiod/{id}", name="reservations_period_update")
  2265.      */
  2266.     public function updatePeriodAction($idEntityManagerInterface $emRequest $request)
  2267.     {
  2268.         $period $em->getRepository(ReservationPeriod::class)->findOneById($id);
  2269.         $newName $request->request->get('mds_venuesbundle_reservationperiod')['name'];
  2270.         $period->setName($newName);
  2271.         $hoy = new \DateTime("now"NULL);
  2272.         $form $this->createEditPeriodForm($period$id);
  2273.         $form->handleRequest($request);
  2274.         if ($form->isValid()) {
  2275.             /* Obtengo usuario logueado */
  2276.             $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  2277.             $user_id $user_logueado->getId();
  2278.             /* Gestión de eventos en Log */
  2279.             $user_lastname $user_logueado->getLastname();
  2280.             $user_name $user_logueado->getName();
  2281.             $user_email $user_logueado->getEmail();
  2282.             $user_rol $user_logueado->getRoles();
  2283.             $event_url $request->getPathInfo();
  2284.             $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  2285.             $period->setUpdatedId($user_id);
  2286.             $period->setUpdatedAt($hoy);
  2287.             try {
  2288.                 $em->persist($period);
  2289.                 $em->flush();
  2290.                 $event 'The period has been Updated. Now';
  2291.                 $successMessage $this->translator->trans($event);
  2292.                 $this->addFlash('mensajereservation'$successMessage);
  2293.             } catch (\Exception $e) {
  2294.                 $event 'An error occurred: ' $e->getMessage();
  2295.                 /* Para el usuario */
  2296.                 $errorMessage $this->translator->trans($event);
  2297.                 $this->addFlash('mensajereservationerror'$errorMessage);
  2298.             }
  2299.             /* Fin Gestión de eventos en Log */
  2300.             return $this->redirectToRoute('reservations_venues_list_period');
  2301.         } else {
  2302.             $errorMessage $this->translator->trans('Error, some fields are empty');
  2303.             $this->addFlash('mensajereservationerror'$errorMessage);
  2304.         }
  2305.         return $this->render(
  2306.             'MDS/VenuesBundle/reservations/edit-reservations-period.html.twig',
  2307.             array(
  2308.                 'id' => $id,
  2309.                 'hoy' => $hoy,
  2310.                 'period' => $period,
  2311.                 'form' => $form->createView()
  2312.             )
  2313.         );
  2314.     }
  2315.     /**
  2316.      * @Route("/getperiodos/",  name="reservations_venues_get_periods")
  2317.      */
  2318.     public function addReservationPeriodsAction(EntityManagerInterface $emRequest $request)
  2319.     {
  2320.         $periods $em->getRepository(ReservationPeriod::class)->findAll();
  2321.         $data = array();
  2322.         foreach ($periods as $items) {
  2323.             $data[] = array('id' => $items->getId(), 'name' => $items->getName(), );
  2324.         }
  2325.         $return = array('periods' => $data, );
  2326.         $response = new JsonResponse($return);
  2327.         return $response;
  2328.     }
  2329.     /**
  2330.      * @Route("/addsimple/",  name="reservations_venues_add_simple")
  2331.      */
  2332.     public function addReservationSimpleAction(EntityManagerInterface $emRequest $request)
  2333.     {
  2334.         $reserv = new Reservation();
  2335.         $form $this->createReservationCreateForm($reserv, ['cotizable' => true]);
  2336.         return $this->render(
  2337.             'MDS/VenuesBundle/reservations/add-reservations-simple.html.twig',
  2338.             array(
  2339.                 'form' => $form->createView(),
  2340.                 'clientsContact' => '',
  2341.             )
  2342.         );
  2343.     }
  2344.     private function createReservationCreateForm(Reservation $entity, array $options = [])
  2345.     {
  2346.         $id $entity->getId();
  2347.         $hasInvoices false;
  2348.         if ($id) {
  2349.             $invoiceRepository $this->em->getRepository(ReservationInvoice::class);
  2350.             $invoiceRecRepository $this->em->getRepository(ReservationInvoiceRec::class);
  2351.             $hasInvoices = !empty($invoiceRepository->findByReservationId($id)) || !empty($invoiceRecRepository->findByReservationId($id));
  2352.         }
  2353.         $form $this->createForm(ReservationType::class, $entity, array(
  2354.             'action' => $this->generateUrl('reservations_venues_create_simple'),
  2355.             'method' => 'POST',
  2356.             'confirmable' => $options['confirmable'] ?? false,
  2357.             'cotizable' => $options['cotizable'] ?? false,
  2358.             'invoiced' => $hasInvoices,
  2359.         ));
  2360.         return $form;
  2361.     }
  2362.     /**
  2363.      * @Route("/createsimple", name="reservations_venues_create_simple")
  2364.      */
  2365.     public function createSimpleAction(EntityManagerInterface $emRequest $request)
  2366.     {
  2367.         $clientContact $request->request->get('clientContact');
  2368.         $contactUnregistered trim((string) $request->request->get('contactUnregistered'));
  2369.         $nameContactUnregistered trim((string) $request->request->get('nameContactUnregistered'));
  2370.         $phoneContactUnregistered trim((string) $request->request->get('phoneContactUnregistered'));
  2371.         $reserva = new Reservation();
  2372.         $form $this->createReservationCreateForm($reserva);
  2373.         $form->handleRequest($request);
  2374.         /* Obtengo usuario logueado */
  2375.         $user_logueado $this->getUser();
  2376.         $user_id $user_logueado->getId();
  2377.         $hoy = new \DateTime("now"NULL);
  2378.         if ($form->isValid()) {
  2379.             $clientId $request->request->get('mds_venuesbundle_reservation')['client'] ?? null;
  2380.             if ($clientId) {
  2381.                 $client $em->getRepository(Client::class)->find($clientId);
  2382.             }
  2383.             $reserva->setClient(
  2384.                 $clientId $client null
  2385.             );
  2386.             $reserva->setCreatedAt($hoy);
  2387.             $reserva->setCreatedBy($user_id);
  2388.             if (empty($reserva->getDaysBlock()) or !(is_numeric($reserva->getDaysBlock()))) {
  2389.                 $reserva->setDaysBlock(7);
  2390.             }
  2391.             if (is_null($reserva->getPriority()) or empty($reserva->getPriority()) or ($reserva->getPriority() == 'Auto')) {
  2392.                 $reserva->setPriority(1);
  2393.             } else {
  2394.                 // Se ha establecido una prioridad y todas las prioridades que coincidan con este evento deben ser alteradas
  2395.                 // PENDIENTE A HABLAR CON RAFA
  2396.             }
  2397.             // No hay salas, se asigna a la reserva la fecha del dia actual. Por indicaciones de Rafa se debe agregar fechas al formulario
  2398.             // Si solo agrega una fecha, pone ambas fechas igual, si no pone fecha se ponen las fechas de control
  2399.             $dateStart $reserva->getDateStart(); $dateEnd   $reserva->getDateEnd();
  2400.             if ($dateStart === null && $dateEnd === null) {
  2401.                 $reserva->setDateStart(new \DateTime('2078-01-01'));
  2402.                 $reserva->setDateEnd(new \DateTime('2000-01-01'));
  2403.             } elseif ($dateStart === null) {
  2404.                 $reserva->setDateStart((clone $dateEnd)->setTime(00000));
  2405.                 $reserva->setDateEnd((clone $dateEnd)->setTime(23590));
  2406.             } elseif ($dateEnd === null) {
  2407.                 // El dateStart con hora 00:00 es lo deseado
  2408.                 $reserva->setDateEnd((clone $dateStart)->setTime(23590));
  2409.             }
  2410.             // Si viene información de un contacto no registrado, creamos el contrato y lo vinculamos al cliente y luego al expediente
  2411.             if ($clientId && $contactUnregistered !== '' && $nameContactUnregistered !== '' && $phoneContactUnregistered !== '') {
  2412.                 $existClientContact $em->getRepository(ClientContact::class)->findOneBy(['email' => $contactUnregistered]);
  2413.                 if ($existClientContact) {
  2414.                     // Si ya existe un contacto con ese email, lo vinculamos al expediente
  2415.                     $reserva->setClientContact($existClientContact->getId());
  2416.                 } else {
  2417.                     $newClientContact = new ClientContact();
  2418.                     $newClientContact->setClientId($client->getId());
  2419.                     $newClientContact->setTypeclient('Business Travel');
  2420.                     $newClientContact->setAssignedAgent($user_id);
  2421.                     $newClientContact->setName($nameContactUnregistered);
  2422.                     $newClientContact->setLastName('');
  2423.                     $newClientContact->setPosition('');
  2424.                     $newClientContact->setSituation('CLIENT');
  2425.                     $newClientContact->setStatus('');
  2426.                     $newClientContact->setEmail($contactUnregistered);
  2427.                     $newClientContact->setPhone($phoneContactUnregistered);
  2428.                     $newClientContact->setCreatedId($user_id);
  2429.                     $newClientContact->setUpdatedId($user_id);
  2430.                     $em->persist($newClientContact);
  2431.                     $em->flush();
  2432.                     $reserva->setClientContact($newClientContact->getId());
  2433.                 }
  2434.             }
  2435.             if (!empty($clientContact) && $clientContact != '0') {
  2436.                 $reserva->setClientContact($clientContact);
  2437.             }
  2438.             if (empty($reserva->getStatus())) {
  2439.                 $reserva->setStatus('Iniciado');
  2440.             } else {
  2441.                 //No se debe crear un evento con estado confirmado. Salva y Rafa seran quienes confirmen los eventos
  2442.                 if (($reserva->getStatus() == 'Confirmed')) {
  2443.                     //                    $reserva->setStatus('Cotizado');              //Ya no es necesario que Rafa o Salva confirmen
  2444.                 }
  2445.             }
  2446.             // Genera un token único utilizando la función uniqid() de PHP
  2447.             $token uniqid();
  2448.             $reserva->setToken($token);
  2449.             $reserva->setCreatedBy($user_id);
  2450.             $reserva->setUpdatedBy($user_id);
  2451.             try {
  2452.                 $em->persist($reserva);
  2453.                 $em->flush();
  2454.                 $event 'The Reservation has been created.';
  2455.                 $successMessage $this->translator->trans($event);
  2456.                 $this->addFlash('mensajereservation'$successMessage);
  2457.             } catch (\Exception $e) {
  2458.                 dd($e);
  2459.                 $event 'An error occurred: ' $e->getMessage();
  2460.                 $errorMessage $this->translator->trans($event);
  2461.                 $this->addFlash('mensajereservationerror'$errorMessage);
  2462.             }
  2463.             //Envio de correo al cliente y al agente si es un bloqueo
  2464.             if (is_null($reserva->getStatus())) {
  2465.                 $reserva->setStatus('Cotizado');
  2466.                 $em->persist($reserva);
  2467.                 $em->flush();
  2468.             } else {
  2469.                 if (($reserva->getStatus() == 'Bloqueo')) {
  2470.                     if (empty($reserva->getDays())) {
  2471.                         $now = new \DateTime("now");
  2472.                         $dateLimit date("Y-m-d H:i"strtotime($now->format('Y-m-d H:i') . "+" $reserva->getDaysBlock() . " days"));
  2473.                         $dateLimit = new \DateTime($dateLimit);
  2474.                         $reserva->setDays($dateLimit);
  2475.                     }
  2476.                     if ((!empty($reserva->getClient())) or (!empty($reserva->getClientContact())) or (!empty($reserva->getContactUnregistered()))) {
  2477.                         //Solo se envia correo de notificacion del correo si hay cliente o contacto o contacto no registrado
  2478.                         $client $reserva->getClient();
  2479.                         $mailAddressTo null;
  2480.                         // if (!empty($client) and (!empty($client->getEmail()))){ $mailAddressTo = $client->getEmail(); }         // Si hay cliente con correo se le envia a este
  2481.                         // if (!empty($reserva->getClientContact())){
  2482.                         //     $contacto = $em->getRepository(ClientContact::class)->findOneById($reserva->getClientContact());
  2483.                         //     if (!empty($contacto) and (!empty($contacto->getEmail()))){ $mailAddressTo = $contacto->getEmail(); }   // Si hay un contacto seleccionado tiene prioridad sobre el contacto de cliente
  2484.                         // }
  2485.                         // if (!empty($reserva->getContactUnregistered())){ $mailAddressTo = $reserva->getContactUnregistered(); }     // Si hay correo de contacto no registrado este tiene prioridad sobre todos
  2486.                         if (!empty($mailAddressTo)) {
  2487.                             $agente $em->getRepository(User::class)->findOneById($user_id);
  2488.                             $mailAddressFrom $agente->getEmail();
  2489.                             $mailSubject 'Notificación de Bloqueo - Reserva de espacio en Venues';
  2490.                             $mailBody 'Estimado cliente,' .
  2491.                                 '<br><br> Nos ponemos en contacto con usted para confirmarle que su reserva ha quedado registrada en Venues para la realización de su próximo evento.' .
  2492.                                 '<br>Le recordamos que esta reserva tiene una validez de ' $reserva->getDaysBlock() . ' días. Si pasado este tiempo no hemos recibido confirmación de vuestra parte, procederemos a la cancelación de la misma.' .
  2493.                                 '<br><br>Reserva: ' $reserva->getId() . ' - ' $reserva->getTitle();
  2494.                             $mailBody $mailBody '<br><br><br>Muchas gracias por su colaboración.<br><br><br>';
  2495.                             //Se envia el correo al cliente y al agente
  2496.                             $this->sendMail($mailAddressFrom$mailAddressTo$mailSubject$mailBody);
  2497.                             //Se genera el control de la alerta
  2498.                             $this->makeAlert($reserva->getId(), $client?->getId(), $mailAddressTo$agente->getId(), $agente->getEmail());
  2499.                         }
  2500.                     }
  2501.                 }
  2502.             }
  2503.         } else {
  2504.             $errorMessagebase $this->translator->trans('Error, some fields are empty');
  2505.             $this->addFlash('mensajetracingerror'$errorMessagebase);
  2506.             $periods $em->getRepository(ReservationPeriod::class)->findAll();
  2507.             return $this->render(
  2508.                 'MDS/VenuesBundle/reservations/add-reservations.html.twig',
  2509.                 array(
  2510.                     'form' => $form->createView(),
  2511.                     'periods' => $periods,
  2512.                 )
  2513.             );
  2514.         }
  2515.         $id $reserva->getId();
  2516.         // Actualizamos la agenda
  2517.         $newItem = new ReservationAgendaItem();
  2518.         $newItem->setReservationId($id);
  2519.         $newItem->setRankListing(1);
  2520.         $newItem->setTitleOne('EVENTO: ' $reserva->getTitle());
  2521.         $newItem->setTitleTwo(null);
  2522.         $newItem->setTitleThree(null);
  2523.         $newItem->setDescription('.');
  2524.         $newItem->setDateStart(null);
  2525.         $newItem->setDateEnd(null);
  2526.         $newItem->setPicture(null);
  2527.         $newItem->setSourceId($id);
  2528.         $newItem->setSourceType('Reservation');
  2529.         $user $this->getUser();
  2530.         $newItem->setCreatedId($user->getId());
  2531.         $newItem->setUpdatedId($user->getId());
  2532.         $newItem->setCreatedAt(new \DateTime());
  2533.         $newItem->setUpdatedAt(new \DateTime());
  2534.         $this->repository->add($newItemtrue);
  2535.         //Actualizamos el contacto de la Agenda
  2536.         $contactString null;
  2537.         if (!empty($reserva->getNameContactUnregistered())) {
  2538.             $contactString .= $reserva->getNameContactUnregistered();
  2539.         } else {
  2540.             $contactString .= 'No se pudo determinar el nombre';
  2541.         }
  2542.         if (!empty($reserva->getPhoneContactUnregistered())) {
  2543.             $contactString .= ' / ' $reserva->getPhoneContactUnregistered();
  2544.         } else {
  2545.             $contactString .= ' / No se pudo determinar el teléfono';
  2546.         }
  2547.         if (!empty($reserva->getContactUnregistered())) {
  2548.             $contactString .= ' / ' $reserva->getContactUnregistered();
  2549.         } else {
  2550.             $contactString .= ' / No se pudo determinar el email';
  2551.         }
  2552.         $agenda $this->agendaService->updateClientContactLine($reserva->getId(), $contactString$user->getId());
  2553.         // Sincronización con Av Express
  2554.         $cotizable $this->laReservaEsCotizable($reserva->getId());
  2555.         if ($cotizable) {
  2556.             // Rafa indico que siempre se sincronice al abrir un expediente de GP
  2557.             //    if (in_array($reserva->getStatus(), ['Confirmed', 'Invoiced', 'Iniciado', 'Cotizado', 'Bloqueo'])) {
  2558.             //        $AveFile = $em->getRepository(AveFiles::class)->findByReservation($reserva);
  2559.             //        if (empty($AveFile)) {
  2560.             //            // Si no se ha creado aun el expediente de Av Express debemos crearlo
  2561.             //            return $this->redirectToRoute('sinc_gp_ave', array('id' => $id,));
  2562.             //        }
  2563.             //    }
  2564.         }
  2565.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $id'token' => null));
  2566.     }
  2567.    /**
  2568.      * @Route("/editsimple/{id}", name="reservations_venues_edit_simple")
  2569.      */
  2570.     public function editReservationSimpleItemsAction(
  2571.         int $id
  2572.         EntityManagerInterface $em
  2573.         TokenStorageInterface $tokenStorage,
  2574.         Request $request
  2575.     ): Response {
  2576.         // 1. Carga inicial de datos críticos (Fail Fast)
  2577.         $reserva $em->getRepository(Reservation::class)->find($id);
  2578.         if (!$reserva) {
  2579.             throw new NotFoundHttpException('Reserva no encontrada.');
  2580.         }
  2581.         $client $reserva->getClient();
  2582.         $clientId $client?->getId() ?? 0;
  2583.         // Settings Company
  2584.         $settingsCompany $em->getRepository(SettingsCompany::class)->findOneBy([
  2585.             'businessType' => BusinessTypeSettingsCompanyConstants::VENUE
  2586.         ]);
  2587.         // 2. Preparación de Formularios (Objetos vacíos para crear)
  2588.         $reservationsLounge = new ReservationLounge();
  2589.         $reservationsLounge->setIdReservation($id);
  2590.         $monDesmon = new ReservationLounge();
  2591.         $monDesmon->setIdReservation($id);
  2592.         $options['confirmable'] = $this->laReservaEsConfirmable($id);
  2593.         $options['cotizable'] = $this->laReservaEsCotizable($id);
  2594.         $form1 $this->createReservationCreateForm($reserva$options);
  2595.         // =================================================================================
  2596.         // PROCESAMIENTO DEL FORMULARIO PRINCIPAL (PETICIÓN POST)
  2597.         // =================================================================================
  2598.         $form1->handleRequest($request);
  2599.         if ($form1->isSubmitted()) {
  2600.             if (!$form1->isValid()) {
  2601.                 // Esto te mostrará exactamente qué campo está fallando en la validación
  2602.                 dd($form1->getErrors(truefalse)); 
  2603.             }
  2604.         }
  2605.         // =================================================================================
  2606.         // CORRECCIÓN: Rellenar los campos "mapped => false" si ya existe un contacto guardado
  2607.         // (Solo se ejecuta si no es un POST de envío válido, manteniendo los datos previos)
  2608.         // =================================================================================
  2609.         if (!$form1->isSubmitted()) {
  2610.             $savedContactId $reserva->getClientContact();
  2611.             if ($savedContactId) {
  2612.                 $savedContact $em->getRepository(ClientContact::class)->find($savedContactId);
  2613.                 if ($savedContact) {
  2614.                     $form1->get('contactUnregistered')->setData($savedContact->getEmail());
  2615.                     $fullName $savedContact->getName();
  2616.                     if (!empty($savedContact->getLastName())) {
  2617.                         $fullName .= ' ' $savedContact->getLastName();
  2618.                     }
  2619.                     $form1->get('nameContactUnregistered')->setData($fullName);
  2620.                     $form1->get('phoneContactUnregistered')->setData($savedContact->getPhone());
  2621.                     $form1->get('clientContact')->setData($savedContactId);
  2622.                 }
  2623.             }
  2624.         }
  2625.         $form2 $this->createReservationLoungeCreateForm($reservationsLounge);
  2626.         $form3 $this->createReservationLoungeMonDesCreateForm($monDesmon);
  2627.         // 3. Procesamiento de Espacios (Lounges)
  2628.         $reservationsLoungesSimple $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  2629.         $loungesData $this->processLounges($reservationsLoungesSimple);
  2630.         // 4. Cálculos Totales
  2631.         $data $this->CalculosTotalesEditSimple($id);
  2632.         // 5. Proveedores y Catering
  2633.         $caterings $this->getCateringSuppliers($em);
  2634.         // 6. Usuarios y Creador
  2635.         $userCreatedBy $em->getRepository(User::class)->find($reserva->getCreatedBy());
  2636.         $createdBy $userCreatedBy ? ($userCreatedBy->getName() . ' ' $userCreatedBy->getLastName()) : '';
  2637.         // 7. Facturación y Finanzas
  2638.         $invoicesData $this->calculateInvoicesData($id$reserva$client$em);
  2639.         // 8. Pagos
  2640.         $paymentsAll $em->getRepository(ReservationPaymentsClient::class)->findByReservationId($id);
  2641.         $paymentNotIvoiced $this->filterUninvoicedPayments($id$paymentsAll$em);
  2642.         // 9. Contactos y Usuarios Activos
  2643.         $userLogueado $tokenStorage->getToken()?->getUser();
  2644.         $userId $userLogueado instanceof User $userLogueado->getId() : null;
  2645.         $clientsContact $em->getRepository(ClientContact::class)->findBy(
  2646.             ['clientId' => $clientId],
  2647.             ['name' => 'ASC']
  2648.         );
  2649.         $allUsersActive $this->getAllActiveUsersAndFreelancers($em);
  2650.         // 10. Alertas de Correo
  2651.         $nextMailAlert $this->getNextMailAlertDate($id$em);
  2652.         // 11. Datos Adicionales (Servicios, Clientes Venues, Depósitos)
  2653.         $reservationsLounges $em->getRepository(ReservationLounge::class)->findByIdReservation($id);
  2654.         
  2655.         /** @var ReservationService[] $services */
  2656.         $services $em->getRepository(ReservationService::class)->findByReservationId($id);
  2657.         // --- SEGMENTACIÓN DE SERVICIOS POR OPCIÓN (RANK) ---
  2658.         $servicesByRank = [];
  2659.         foreach ($services as $service) {
  2660.             $rankKey $service->getRank() !== null ? (int)$service->getRank() : 0;
  2661.             $servicesByRank[$rankKey][] = $service;
  2662.         }
  2663.         $datax $this->benefitForReservation($id);
  2664.         $clients $em->getRepository(Client::class)
  2665.             ->createQueryBuilder('c')
  2666.             ->innerJoin('c.settingsCompany''sc')
  2667.             ->where('sc.id = :settingsCompanyId')
  2668.             ->setParameter('settingsCompanyId'$settingsCompany?->getId())
  2669.             ->orderBy('c.name''ASC')
  2670.             ->getQuery()
  2671.             ->getResult();
  2672.         $depositsData $this->getDepositsAndProformas($id$em);
  2673.         $allReservationProformas $em->getRepository(ReservationProforma::class)->findBy(
  2674.             ['reservationId' => $id],
  2675.             ['id' => 'DESC']
  2676.         );
  2677.         $reservationsLoungesPre $em->createQueryBuilder()
  2678.             ->select('p')
  2679.             ->from('VenuesBundle:ReservationLoungeDetails''p')
  2680.             ->orderBy('p.rankLounge''ASC')
  2681.             ->getQuery()
  2682.             ->getResult();
  2683.         $reservationsLoungesNames $em->getRepository(ReservationLoungeDetails::class)->findAll();
  2684.         $listSupplier $em->getRepository(Supplier::class)->findAll();
  2685.         $urlCotizacion "https://cotizacion.greenpatio.es/index.php?token=" $reserva->getToken();
  2686.         $urlCotizacionNew "https://develup.solutions/cotizacion/?token=" $reserva->getToken();
  2687.         $msgMailToClient $reserva->getMailToClient();
  2688.         $languagesWeb LanguageConstants::getAvailableLanguages();
  2689.         $agenda $this->agendaService->getAgendaForView($id);
  2690.         $htFile $reserva->getHtFile();
  2691.         $aveFile $reserva->getAveFile();
  2692.         $tracings $em->getRepository(ReservationTracing::class)->findBy(
  2693.             ['reservationId' => $id],
  2694.             ['createdAt' => 'DESC']
  2695.         );
  2696.         // Obtener comentarios de la cotización web asociados a la reserva
  2697.         $webObservations $em->getRepository(CotizacionWebObservations::class)->findBy(
  2698.             ['reservation' => $reserva],
  2699.             ['createdAt' => 'DESC']
  2700.         );
  2701.         return $this->render('MDS/VenuesBundle/reservations/edit-reservations-simple.html.twig', [
  2702.             'form' => $form1->createView(),
  2703.             'form2' => $form2->createView(),
  2704.             'form3' => $form3->createView(),
  2705.             'id' => $id,
  2706.             'clients' => $clients,
  2707.             'clientId' => $clientId,
  2708.             'caterings' => $caterings,
  2709.             'loungesPre' => $reservationsLoungesPre,
  2710.             'loungesNames' => $reservationsLoungesNames,
  2711.             'arrayLoungesInFile' => $loungesData['arrayLoungesInFile'],
  2712.             'facturas' => $invoicesData['allInvoiced'],
  2713.             'numeroItems' => count($loungesData['arrayLoungesByDay']),
  2714.             'arrayLoungesByDay' => $loungesData['arrayLoungesByDay'],
  2715.             'totales_global_con_iva' => $data['totales_global_con_iva'] ?? 0,
  2716.             'totales_global_iva' => $data['totales_global_iva'] ?? 0,
  2717.             'totales_global_neto' => $data['totales_global_neto'] ?? 0,
  2718.             'totales_global_servicios_con_iva' => $data['totales_global_servicios_con_iva'] ?? 0,
  2719.             'totales_global_servicios_neto' => $data['totales_global_servicios_neto'] ?? 0,
  2720.             'totales_global_servicios_iva' => $data['totales_global_servicios_iva'] ?? 0,
  2721.             'sumatoria_totales_global_con_iva' => $data['sumatoria_totales_global_con_iva'] ?? 0,
  2722.             'sumatoria_totales_global_neto' => $data['sumatoria_totales_global_neto'] ?? 0,
  2723.             'sumatoria_totales_global_iva' => $data['sumatoria_totales_global_iva'] ?? 0,
  2724.             'reserva' => $reserva,
  2725.             'createdBy' => $createdBy,
  2726.             'arraySalas' => null,
  2727.             'lounges' => $reservationsLounges,
  2728.             'salasReserva' => $reservationsLounges,
  2729.             'periods' => null,
  2730.             'services' => $services,
  2731.             'servicesByRank' => $servicesByRank// <--- INYECTADO PARA LA SEGMENTACIÓN EN TWIG
  2732.             'loungesNumbers' => count($reservationsLounges),
  2733.             'listSupplier' => $listSupplier,
  2734.             'resultados' => $invoicesData['resultados'],
  2735.             'paymentsAll' => $paymentsAll,
  2736.             'paymentNotIvoiced' => $paymentNotIvoiced,
  2737.             'allUsersActive' => $allUsersActive,
  2738.             'userLog' => $userId,
  2739.             'clientsContact' => $clientsContact,
  2740.             'nextMailAlert' => $nextMailAlert,
  2741.             'benefit' => $datax['benefit'],
  2742.             'percBenefit' => $datax['percBenefit'],
  2743.             'payedLounges' => $datax['payedLounges'],
  2744.             'payedServices' => $datax['payedServices'],
  2745.             'unPayedServices' => $datax['unPayedServices'],
  2746.             'depositsAll' => $depositsData['depositsAll'],
  2747.             'sumsByProforma' => $depositsData['sumsByProforma'],
  2748.             'proformas' => $depositsData['proformas'],
  2749.             'allReservationProformas' => $allReservationProformas,
  2750.             'urlCotizacion' => $urlCotizacion,
  2751.             'urlCotizacionNew' => $urlCotizacionNew,
  2752.             'msgMailToClient' => $msgMailToClient,
  2753.             'reservationContracts' => $reserva->getDocContracts(),
  2754.             'viewContract' => !$reserva->getDocContracts()->isEmpty(),
  2755.             'languagesWeb' => $languagesWeb,
  2756.             'sageVatRates' => $em->getRepository(SageVatRates::class)->findAll(),
  2757.             'arregloLineasAgenda' => $agenda,
  2758.             'htFile' => $htFile,
  2759.             'aveFile' => $aveFile,
  2760.             'tracings' => $tracings,
  2761.             'webObservations' => $webObservations,
  2762.         ]);
  2763.     }
  2764.     /**
  2765.      * @Route("/showsimple/{id}",  name="reservations_venues_show_simple")
  2766.      */
  2767.     public function showReservationSimpleItemsAction(int $idEntityManagerInterface $em): Response
  2768.     {
  2769.         $reserva $em->getRepository(Reservation::class)->find($id);
  2770.         if (!$reserva) {
  2771.             throw new NotFoundHttpException('Reserva no encontrada.');
  2772.         }
  2773.         $user $this->getUser();
  2774.         $isLegendTeam = ($user && strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW');
  2775.         $allowedLoungeIds null;
  2776.         // Procesamiento de Salas (Lounges)
  2777.         $reservationsLoungesSimple $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  2778.         $services $em->getRepository(ReservationService::class)->findByReservationId($id);
  2779.         if ($isLegendTeam) {
  2780.             // Buscar espacio LEGEND
  2781.             $lSpace $em->getRepository(Space::class)->createQueryBuilder('s')
  2782.                 ->where('s.name LIKE :n')->setParameter('n''%LEGEND%')
  2783.                 ->setMaxResults(1)->getQuery()->getOneOrNullResult();
  2784.             if ($lSpace) {
  2785.                 $filteredLounges = [];
  2786.                 $allowedLoungeIds = [];
  2787.                 foreach ($reservationsLoungesSimple as $rls) {
  2788.                     $loungeDetails $em->getRepository(ReservationLoungeDetails::class)->find($rls->getIdLounge());
  2789.                     if ($loungeDetails && $loungeDetails->getSpace() && $loungeDetails->getSpace()->getId() === $lSpace->getId()) {
  2790.                         $filteredLounges[] = $rls;
  2791.                         $allowedLoungeIds[] = $rls->getId();
  2792.                     }
  2793.                 }
  2794.                 $reservationsLoungesSimple $filteredLounges;
  2795.             }
  2796.         }
  2797.         $loungesData $this->processLounges($reservationsLoungesSimple);
  2798.         // Cálculos Totales (si es Legend, recalculamos solo para sus salas)
  2799.         $data $this->CalculosTotalesEditSimple($id$reservationsLoungesSimple$services);
  2800.         // Usuarios y Creador
  2801.         $userCreatedBy $em->getRepository(User::class)->find($reserva->getCreatedBy());
  2802.         $createdBy $userCreatedBy ? ($userCreatedBy->getName() . ' ' $userCreatedBy->getLastName()) : '';
  2803.         // Facturación y Finanzas
  2804.         $client $reserva->getClient();
  2805.         $invoicesData $this->calculateInvoicesData($id$reserva$client$em);
  2806.         // Pagos
  2807.         $paymentsAll $em->getRepository(ReservationPaymentsClient::class)->findByReservationId($id);
  2808.         // Datos Adicionales
  2809.         $reservationsLounges $em->getRepository(ReservationLounge::class)->findByIdReservation($id);
  2810.         
  2811.         // Agenda filtrada
  2812.         $agenda $this->agendaService->getAgendaForView($id$allowedLoungeIds);
  2813.         return $this->render('MDS/VenuesBundle/reservations/show-reservations-simple.html.twig', [
  2814.             'id' => $id,
  2815.             'reserva' => $reserva,
  2816.             'arrayLoungesInFile' => $loungesData['arrayLoungesInFile'],
  2817.             'arrayLoungesByDay' => $loungesData['arrayLoungesByDay'],
  2818.             'facturas' => $invoicesData['allInvoiced'],
  2819.             'totales_global_con_iva' => $data['totales_global_con_iva'] ?? 0,
  2820.             'totales_global_iva' => $data['totales_global_iva'] ?? 0,
  2821.             'totales_global_neto' => $data['totales_global_neto'] ?? 0,
  2822.             'sumatoria_totales_global_con_iva' => $data['sumatoria_totales_global_con_iva'] ?? 0,
  2823.             'sumatoria_totales_global_neto' => $data['sumatoria_totales_global_neto'] ?? 0,
  2824.             'sumatoria_totales_global_iva' => $data['sumatoria_totales_global_iva'] ?? 0,
  2825.             'createdBy' => $createdBy,
  2826.             'lounges' => $reservationsLounges,
  2827.             'serviceLines' => $data['serviceLines'],
  2828.             'paymentsAll' => $paymentsAll,
  2829.             'arregloLineasAgenda' => $agenda,
  2830.             'aveFile' => $reserva->getAveFile(),
  2831.         ]);
  2832.     }
  2833.     /**
  2834.      * @Route("/tracing/add/{id}", name="reservations_venues_tracing_ajax_add", methods={"POST"})
  2835.      * @param int $id
  2836.      * @param Request $request
  2837.      * @param EntityManagerInterface $em
  2838.      * @return \Symfony\Component\HttpFoundation\JsonResponse
  2839.      */
  2840.     public function addTracingAjaxAction(int $idRequest $requestEntityManagerInterface $em)
  2841.     {
  2842.         $reserva $em->getRepository(Reservation::class)->find($id);
  2843.         if (!$reserva) {
  2844.             return new \Symfony\Component\HttpFoundation\JsonResponse(['status' => 'error''msg' => 'Reserva no encontrada'], 404);
  2845.         }
  2846.         $dateStr $request->request->get('tracingDate');
  2847.         $text $request->request->get('tracingText');
  2848.         if (empty($dateStr) || empty($text)) {
  2849.             return new \Symfony\Component\HttpFoundation\JsonResponse(['status' => 'error''msg' => 'Faltan parámetros'], 400);
  2850.         }
  2851.         try {
  2852.             $date = new \DateTime($dateStr);
  2853.             $user $this->getUser();
  2854.             $tracing = new ReservationTracing();
  2855.             $tracing->setReservationId($reserva->getId());
  2856.             $tracing->setDateAt($date);
  2857.             $tracing->setText($text);
  2858.             $tracing->setAgentId($user->getId());
  2859.             $tracing->setViewed('NO');
  2860.             $tracing->setCreatedId($user->getId());
  2861.             $tracing->setUpdatedId($user->getId());
  2862.             $tracing->setCreatedAt(new \DateTime());
  2863.             $tracing->setUpdatedAt(new \DateTime());
  2864.             
  2865.             $em->persist($tracing);
  2866.             $em->flush();
  2867.             return new \Symfony\Component\HttpFoundation\JsonResponse(['status' => 'ok']);
  2868.         } catch (\Exception $e) {
  2869.             return new \Symfony\Component\HttpFoundation\JsonResponse(['status' => 'error''msg' => $e->getMessage()], 500);
  2870.         }
  2871.     }
  2872.     private function createReservationLoungeCreateForm(ReservationLounge $entity)
  2873.     {
  2874.         $form $this->createForm(ReservationLoungeType::class, $entity, array(
  2875.             'action' => $this->generateUrl(
  2876.                 'reservations_venues_create_simple_lounge',
  2877.                 array(
  2878.                     'id' => $entity->getIdReservation(),
  2879.                 )
  2880.             ),
  2881.             'method' => 'POST'
  2882.         ));
  2883.         return $form;
  2884.     }
  2885.     private function createReservationLoungeMonDesCreateForm(ReservationLounge $entity)
  2886.     {
  2887.         $form $this->createForm(ReservationLoungeType::class, $entity, array(
  2888.             'action' => $this->generateUrl(
  2889.                 'reservations_venues_create_simple_lounge_mondes',
  2890.                 array(
  2891.                     'id' => $entity->getIdReservation(),
  2892.                 )
  2893.             ),
  2894.             'method' => 'POST'
  2895.         ));
  2896.         return $form;
  2897.     }
  2898.     /**
  2899.      * @Route("/contract/{id}", name="reservations_contract")
  2900.      */
  2901.     public function goContractAction($idEntityManagerInterface $em): Response
  2902.     {
  2903.         try {
  2904.             $dataContract $this->docContractService->renderContractTemplate((int)$id);
  2905.         } catch (\RuntimeException $e) {
  2906.             $this->addFlash('mensajereservationerror'$e->getMessage());
  2907.             $docContract $em->getRepository(DocContract::class)->find($id);
  2908.             $reservaId $docContract $docContract->getReservation()?->getId() : null;
  2909.             if ($reservaId) {
  2910.                 return $this->redirectToRoute('reservations_venues_edit_simple', ['id' => $reservaId]);
  2911.             }
  2912.             return $this->redirectToRoute('homepage');
  2913.         }
  2914.         return $this->render(
  2915.             'MDS/VenuesBundle/reservations/print-contract-gp.html.twig',
  2916.             array(
  2917.                 'dataContract' => $dataContract,
  2918.             )
  2919.         );
  2920.     }
  2921.     /**
  2922.      * @Route("/contract/{id}/save", name="reservations_contract_save", methods={"POST"})
  2923.      */
  2924.     public function saveContractAction(int $idRequest $requestEntityManagerInterface $em): JsonResponse
  2925.     {
  2926.         // 1. Obtener el contrato por su propio ID (ya no por ID de reserva)
  2927.         $docContract $em->getRepository(DocContract::class)->find($id);
  2928.         if (!$docContract) {
  2929.             return new JsonResponse(['status' => 'error''message' => 'Contrato no encontrado'], 404);
  2930.         }
  2931.         // 2. Obtener el contenido enviado por AJAX
  2932.         $content $request->request->get('content');
  2933.         if (empty($content)) {
  2934.             return new JsonResponse(['status' => 'error''message' => 'El contenido no puede estar vacío'], 400);
  2935.         }
  2936.         // 3. Actualizar y Guardar
  2937.         $docContract->setContractualDocument($content);
  2938.         $em->flush();
  2939.         return new JsonResponse(['status' => 'success''message' => 'Contrato guardado correctamente']);
  2940.     }
  2941.     /**
  2942.      * Muestra el contenido actual del contrato en una vista simple.
  2943.      * Se usa para abrir la "copia de seguridad" en una nueva pestaña.
  2944.      *
  2945.      * @Route("/contract/{id}/show-current", name="reservations_contract_show_current", methods={"GET"})
  2946.      */
  2947.     public function showCurrentContractAction(int $idEntityManagerInterface $em): Response
  2948.     {
  2949.         $docContract $em->getRepository(DocContract::class)->find($id);
  2950.         if (!$docContract) {
  2951.             throw $this->createNotFoundException('El contrato no existe.');
  2952.         }
  2953.         return $this->render('MDS/VenuesBundle/reservations/show_raw_contract.html.twig', [
  2954.             'contract_content' => $docContract->getContractualDocument()
  2955.         ]);
  2956.     }
  2957.     /**
  2958.      * Resincroniza el contrato desde su modelo original.
  2959.      *
  2960.      * @Route("/contract/{id}/resync", name="reservations_contract_resync", methods={"POST"})
  2961.      */
  2962.     public function resyncContractAction(int $idDocContractService $docContractServiceEntityManagerInterface $em): JsonResponse
  2963.     {
  2964.         try {
  2965.             $docContract $em->getRepository(DocContract::class)->find($id);
  2966.             if (!$docContract) {
  2967.                 return new JsonResponse(['status' => 'error''message' => 'Contrato no encontrado'], 404);
  2968.             }
  2969.             $newContent $docContractService->renderContractModelTemplate($docContract);
  2970.             // Actualizamos la entidad y guardamos en la BBDD.
  2971.             // $docContract->setContractualDocument($newContent);
  2972.             // $em->flush();
  2973.             // 4. Devolvemos el nuevo contenido al frontend.
  2974.             return new JsonResponse([
  2975.                 'status' => 'success',
  2976.                 'newContent' => $newContent
  2977.             ]);
  2978.         } catch (\Exception $e) {
  2979.             // Captura cualquier error que pueda ocurrir durante el renderizado y devuelve código HTTP 200 con status error
  2980.             return new JsonResponse(['status' => 'error''message' => $e->getMessage()], 200);
  2981.         }
  2982.     }
  2983.     /**
  2984.      * @Route("/updateloungegrid", name="reservations_venues_updateloungegrid", methods={"POST"})
  2985.      */
  2986.     public function updateLoungeGridAction(
  2987.         EntityManagerInterface $em,
  2988.         Request $request,
  2989.         TokenStorageInterface $tokenStorage
  2990.     ): Response {
  2991.         // 1. Obtención y validación de datos iniciales
  2992.         $reservationsLoungeGrid $request->request->all('lounge');
  2993.         $reservationGlobalLounge $request->request->all('reservation_global_lounge');
  2994.         $id $request->request->get('reservationId');
  2995.         $reserva $em->getRepository(Reservation::class)->find($id);
  2996.         if (!$reserva) {
  2997.             throw new NotFoundHttpException('Reserva no encontrada.');
  2998.         }
  2999.         $userLogueado $tokenStorage->getToken()?->getUser();
  3000.         $userId $userLogueado instanceof User $userLogueado->getId() : null;
  3001.         // 2. Pre-carga de datos para evitar consultas en bucle (Optimization N+1)
  3002.         // Mapeamos LoungeDetails por nombre para acceso rápido
  3003.         $loungeDetailsMap = [];
  3004.         $allLoungeDetails $em->getRepository(ReservationLoungeDetails::class)->findAll();
  3005.         foreach ($allLoungeDetails as $detail) {
  3006.             $loungeDetailsMap[$detail->getName()] = $detail;
  3007.         }
  3008.         // Cargamos la tasa de IVA por defecto
  3009.         $defaultSageVatRate $em->getRepository(SageVatRates::class)->findOneBy(['sageCode' => '03']);
  3010.         // Cache y arreglo diferido de agendas
  3011.         $sageArticlesCache = [];
  3012.         $agendasToProcess = [];
  3013.         // Carga masiva (Batch Pre-load) de Entidades ReservationLoungeSimple
  3014.         $loungeSimplesCache = [];
  3015.         if (is_array($reservationsLoungeGrid)) {
  3016.             $loungeIdsToFetch array_filter(array_keys($reservationsLoungeGrid), function($id) {
  3017.                 return is_numeric($id) && $id 0;
  3018.             });
  3019.             if (!empty($loungeIdsToFetch)) {
  3020.                 $loungesInDb $em->getRepository(ReservationLoungeSimple::class)->findBy(['id' => $loungeIdsToFetch]);
  3021.                 foreach ($loungesInDb as $lounge) {
  3022.                     $loungeSimplesCache[$lounge->getId()] = $lounge;
  3023.                 }
  3024.             }
  3025.         }
  3026.         // 3. Inicialización de fechas extremas para recalcular el rango de la reserva
  3027.         // Usamos variables locales para no modificar la entidad Reserva hasta el final
  3028.         $minDateStart = new DateTime('2999-01-01');
  3029.         $maxDateEnd = new DateTime('2000-01-01');
  3030.         $hasItems false// Flag para saber si procesamos algo
  3031.         $updatedCount 0;
  3032.         // 4. Procesamiento del Grid
  3033.         if (is_array($reservationsLoungeGrid)) {
  3034.             foreach ($reservationsLoungeGrid as $idReservationLounge => $reservationsLoungeData) {
  3035.                 if (!is_array($reservationsLoungeData)) {
  3036.                     continue;
  3037.                 }
  3038.                 // Basado en la estructura recibida, cada ID tiene un único día y una única sala
  3039.                 $dia key($reservationsLoungeData);
  3040.                 $items $reservationsLoungeData[$dia] ?? null;
  3041.                 if (!is_array($items)) {
  3042.                     continue;
  3043.                 }
  3044.                 $name key($items);
  3045.                 $item $items[$name] ?? null;
  3046.                 if (!is_array($item)) {
  3047.                     continue;
  3048.                 }
  3049.                 // Buscar o Crear entidad (usando Identity Map en memoria)
  3050.                 if (array_key_exists($idReservationLounge$loungeSimplesCache)) {
  3051.                             $reservationLounge $loungeSimplesCache[$idReservationLounge];
  3052.                         } else {
  3053.                             $reservationLounge = new ReservationLoungeSimple();
  3054.                             // Asignamos ID solo si es nuevo y persistimos implícitamente al final
  3055.                             // Lo añadimos al cache para evitar crear múltiples objetos vacíos si el mismo "fake id" itera en otro dia
  3056.                             $loungeSimplesCache[$idReservationLounge] = $reservationLounge;
  3057.                         }
  3058.                         // Parseo de horas (Refactorizado a método privado)
  3059.                         $startData $this->reservationService->formatTimeInput($item['dateHourMinStart'] ?? '');
  3060.                         $endData $this->reservationService->formatTimeInput($item['dateHourMinEnd'] ?? '');
  3061.                         $dateStartStr = ($item['newDate'] ?? '') . ' ' $startData['formatted'];
  3062.                         $dateEndStr = ($item['newDate'] ?? '') . ' ' $endData['formatted'];
  3063.                         // Validaciones de lógica de negocio (Sage)
  3064.                         /** @var ReservationLoungeDetails|null $loungeDetail */
  3065.                         $loungeDetail $loungeDetailsMap[$name] ?? null;
  3066.                         // Determinar IVA y Artículo Sage
  3067.                         $targetVat $defaultSageVatRate;
  3068.                         if (array_key_exists('iva'$item) && !empty($item['iva']) && is_numeric($item['iva'])) {
  3069.                             // Si viene un ID de IVA, tendríamos que buscar la entidad. 
  3070.                             // Asumo que $item['iva'] es el ID o la entidad si Symfony lo mapea, 
  3071.                             // pero para seguridad buscamos la referencia si es un ID.
  3072.                             $targetVat $em->getReference(SageVatRates::class, $item['iva']);
  3073.                         }
  3074.                         // Buscamos el artículo. Esto sigue siendo una query por iteración si varía mucho,
  3075.                         // pero es necesario ya que depende de la combinación VAT + Nombre.
  3076.                         $sageArticle null;
  3077.                         // Si el modulo de Sage no está activo no se hace
  3078.                         if ($this->session->get('_config')['msage']) {
  3079.                             if ($loungeDetail) {
  3080.                                 $cacheKey $targetVat->getId() . '_' $loungeDetail->getName();
  3081.                                 if (!array_key_exists($cacheKey$sageArticlesCache)) {
  3082.                                     $sageArticlesCache[$cacheKey] = $em->getRepository(SageArticle::class)->findOneBy([
  3083.                                         'vatType' => $targetVat,
  3084.                                         'name' => $loungeDetail->getName()
  3085.                                     ]);
  3086.                                 }
  3087.                                 $sageArticle $sageArticlesCache[$cacheKey];
  3088.                             }
  3089.                             if (!$sageArticle && $loungeDetail) {
  3090.                                 // Intento fallback con default VAT si falló el específico
  3091.                                 $cacheKeyFallback $defaultSageVatRate->getId() . '_' $loungeDetail->getName();
  3092.                                 if (!array_key_exists($cacheKeyFallback$sageArticlesCache)) {
  3093.                                     $sageArticlesCache[$cacheKeyFallback] = $em->getRepository(SageArticle::class)->findOneBy([
  3094.                                         'vatType' => $defaultSageVatRate,
  3095.                                         'name' => $loungeDetail->getName()
  3096.                                     ]);
  3097.                                 }
  3098.                                 $sageArticle $sageArticlesCache[$cacheKeyFallback];
  3099.                             }
  3100.                             if (!$sageArticle) {
  3101.                                 $this->addFlash('mensajereservationerror''No se ha encontrado el artículo de Sage para la sala: ' $name);
  3102.                                 continue;
  3103.                             }
  3104.                         }
  3105.                         // Asignación de datos
  3106.                         $reservationLounge->setIdReservation((int) $id);
  3107.                         // Datos heredados de ReservationGlobalLounge
  3108.                         if ($loungeDetail && isset($reservationGlobalLounge[$loungeDetail->getId()])) {
  3109.                             $globalData $reservationGlobalLounge[$loungeDetail->getId()];
  3110.                             $reservationLounge->setIdLounge($loungeDetail->getId());
  3111.                             $reservationLounge->setImportantDescription($globalData['importantDescription'] ?? null);
  3112.                             $reservationLounge->setImportantDescGeneralText($globalData['importantDescGeneralText'] ?? null);
  3113.                             $reservationLounge->setImportantDescSchedules($globalData['importantDescSchedules'] ?? null);
  3114.                             $reservationLounge->setImportantDescParking($globalData['importantDescParking'] ?? null);
  3115.                             // =================================================================================
  3116.                             // PROCESAMIENTO DE BOOLEANOS AUDIOVISUALES
  3117.                             // =================================================================================
  3118.                             // Evaluamos de manera estricta a booleano ("1" o true equivale a true, lo demás a false)
  3119.                             $showAvPrice = isset($globalData['showAudiovisualPrice']) && ($globalData['showAudiovisualPrice'] === '1' || $globalData['showAudiovisualPrice'] === true);
  3120.                             $showAvPackage = isset($globalData['showAudiovisualPackage']) && ($globalData['showAudiovisualPackage'] === '1' || $globalData['showAudiovisualPackage'] === true);
  3121.                             $reservationLounge->setShowAudiovisualPrice($showAvPrice);
  3122.                             $reservationLounge->setShowAudiovisualPackage($showAvPackage);
  3123.                             // =================================================================================
  3124.                         } else {
  3125.                             $reservationLounge->setIdLounge(0);
  3126.                             // Por seguridad, si no viene la configuración global, definimos valores por defecto
  3127.                             $reservationLounge->setShowAudiovisualPrice(false);
  3128.                             $reservationLounge->setShowAudiovisualPackage(false);
  3129.                         }
  3130.                         // Seteo de valores simples
  3131.                         $price $item['price'] ?? 0;
  3132.                         $pax = !empty($item['pax']) ? $item['pax'] : 0;
  3133.                         // if(!array_key_exists('type', $item)){
  3134.                         //     dd($item);
  3135.                         // }
  3136.                         // dump($item['type']);
  3137.                         if (!array_key_exists('type'$item)){
  3138.                             $type = empty($item['pax']) ? ($item['type'] ?? null) : null// Lógica original invertida para type
  3139.                         } else{
  3140.                             $type $item['type'];
  3141.                         }
  3142.                 
  3143.                         try {
  3144.                             $dtStart = new DateTime($dateStartStr);
  3145.                             $dtEnd = new DateTime($dateEndStr);
  3146.                             $reservationLounge->setDateStart($dtStart);
  3147.                             $reservationLounge->setDateEnd($dtEnd);
  3148.                             // Actualizar rango global
  3149.                             if ($dtStart $minDateStart) {
  3150.                                 $minDateStart = clone $dtStart;
  3151.                                 $hasItems true;
  3152.                             }
  3153.                             if ($dtEnd $maxDateEnd) {
  3154.                                 $maxDateEnd = clone $dtEnd;
  3155.                                 $hasItems true;
  3156.                             }
  3157.                         } catch (\Exception $e) {
  3158.                             // Ignorar fechas inválidas
  3159.                         }
  3160.                         $reservationLounge->setType($type);
  3161.                         $reservationLounge->setPax($pax);
  3162.                         $reservationLounge->setServicePrice($price);
  3163.                         $reservationLounge->setSageIva($targetVat);
  3164.                         $reservationLounge->setOpIva(1);
  3165.                         $reservationLounge->setLoungeName($name);
  3166.                         // Horas desglosadas
  3167.                         $reservationLounge->setHourStart($startData['hour']);
  3168.                         $reservationLounge->setMinStart($startData['min']);
  3169.                         $reservationLounge->setHourEnd($endData['hour']);
  3170.                         $reservationLounge->setMinEnd($endData['min']);
  3171.                         $reservationLounge->setLanguage($reservationGlobalLounge['language'] ?? 'es'); // Default 'es' por seguridad
  3172.                         $reservationLounge->setUpdatedBy($userId);
  3173.                         $reservationLounge->setCreatedBy($userId); // Nota: Originalmente sobreescribe createdBy al editar
  3174.                         $reservationLounge->setSageArticle($sageArticle);
  3175.                         $em->persist($reservationLounge);
  3176.                         $updatedCount++;
  3177.                         // Guardamos en memoria para procesar en bloque después del flush global
  3178.                         $agendasToProcess[] = $reservationLounge;
  3179.             }
  3180.         }
  3181.         // 5. Persistencia y Actualización Diferida (Salas y Agendas)
  3182.         try {
  3183.             if ($updatedCount 0) {
  3184.                 // Solo actualizamos las fechas de la reserva si procesamos items válidos
  3185.                 // y si las fechas calculadas expanden el rango actual (según lógica original).
  3186.                 if ($hasItems) {
  3187.                     $this->reservationService->updateReservationDates($reserva);
  3188.                 }
  3189.                 // Flush GLOBAL para guardar salas y evitar llamadas continuas a BD 
  3190.                 $em->flush();
  3191.                 
  3192.                 // --- Post Procesamiento Diferido de Agenda ---
  3193.                 foreach ($agendasToProcess as $rLounge) {
  3194.                     $this->agendaService->createAgendaFromSource(
  3195.                         $rLounge->getIdReservation(),
  3196.                         'SALAS A UTILIZAR',
  3197.                         null,
  3198.                         null,
  3199.                         $rLounge->getDateStart(),
  3200.                         $rLounge->getDateEnd(),
  3201.                         $rLounge->getLoungename(),
  3202.                         $rLounge->getId(),
  3203.                         'ReservationLoungeSimple',
  3204.                         $rLounge->getUpdatedBy(),
  3205.                         false // $doFlush = false para englobarlo en el último flush
  3206.                     );
  3207.                 }
  3208.                 // Se llama al servicio para actualizar en la agenda de las fechas
  3209.                 $this->agendaService->updateDatesLine($id$userId);
  3210.                 // Actualizamos el Pax de la Agenda
  3211.                 $paxAge $this->agendaService->calculatePaxForReservation($id);
  3212.                 $this->agendaService->updatePaxLine($id$paxAge$userId);
  3213.                 // Ultimo Flush global para aplicar la agenda calculada sin latencias
  3214.                 $em->flush();
  3215.                 $this->addFlash('mensajereservation''The Item has been updated.');
  3216.             }
  3217.         } catch (\Exception $e) {
  3218.             $this->addFlash('mensajereservationerror''An error occurred: ' $e->getMessage());
  3219.         }
  3220.         // Creamos la Snapshot de las salas y servicios del sistema (LOG)
  3221.         $version $this->venueService->createSnapshot($reserva);
  3222.         return $this->redirectToRoute('reservations_venues_edit_simple', [
  3223.             'id' => $id,
  3224.             'token' => null,
  3225.             '_fragment' => 'btn_quotes'
  3226.         ]);
  3227.     }
  3228.     /**
  3229.      * @Route("/deleteitemservice/{idService}/{idReservation}", name="reservations_venues_deleteitemservice")
  3230.      */
  3231.     public function deleteItemServiceAction($idService$idReservationEntityManagerInterface $emRequest $request)
  3232.     {
  3233.         $service $em->getRepository(ReservationService::class)->findOneById($idService);
  3234.         $em->remove($service);
  3235.         $em->flush();
  3236.         $event 'The Item has been deleted.';
  3237.         $successMessage $this->translator->trans($event);
  3238.         $this->addFlash('mensajereservation'$successMessage);
  3239.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $idReservation'token' => null));
  3240.     }
  3241.     /**
  3242.      * @Route("/updateservicegrid/{id}", name="reservations_venues_updateservicegrid", requirements={"id"="\d+"}, methods={"POST"})
  3243.      */
  3244.     public function updateServiceGridAction(
  3245.         int $id,
  3246.         EntityManagerInterface $em,
  3247.         Request $request,
  3248.         TokenStorageInterface $tokenStorage,
  3249.         TranslatorInterface $translator,
  3250.         SyncronizationsCateringService $syncCateringService,
  3251.         SyncronizationsAVService $syncAVService,
  3252.         AppConfigManager $configManager
  3253.     ): Response {
  3254.         $servicesInput $request->request->all('services');
  3255.         if (!is_array($servicesInput)) {
  3256.             $servicesInput = [];
  3257.         }
  3258.         $reserva $em->getRepository(Reservation::class)->find($id);
  3259.         if (!$reserva) {
  3260.             throw new NotFoundHttpException('Reservation not found');
  3261.         }
  3262.         $userLogueado $tokenStorage->getToken()?->getUser();
  3263.         $userId $userLogueado instanceof User $userLogueado->getId() : null;
  3264.         $agendaSecurity null;
  3265.         // 1. Pre-carga de configuraciones y datos globales
  3266.         $sessionConfig $request->getSession()->get('_config', []);
  3267.         $mcatering = !empty($sessionConfig['mcatering']);
  3268.         $mav = !empty($sessionConfig['mav']);
  3269.         $msage = !empty($sessionConfig['msage']);
  3270.         $cachedSuppliers = [];
  3271.         // Datos para Sincronización
  3272.         $htFile $em->getRepository(HtFile::class)->findByReservation($reserva);
  3273.         $aveFile $em->getRepository(AveFiles::class)->findByReservation($reserva);
  3274.         // Determinamos el VAT Rate base (Lógica original SUCOE como valor por defecto)
  3275.         $sageIvaCode = ($reserva->IsSucoe()) ? '00' '03';
  3276.         $defaultSageVatRate $em->getRepository(SageVatRates::class)->findOneBy(['sageCode' => $sageIvaCode]);
  3277.         $updatedCount 0;
  3278.         foreach ($servicesInput as $idService => $serviceData) {
  3279.             $serviceEntity $em->getRepository(ReservationService::class)->find($idService);
  3280.             if (!$serviceEntity) {
  3281.                 $serviceEntity = new ReservationService();
  3282.                 $serviceEntity->setReservationId($id);
  3283.             }
  3284.             // --- 1. Datos Básicos ---
  3285.             $supplierId = isset($serviceData['supplier']) ? (int) $serviceData['supplier'] : null;
  3286.             $serviceEntity->setSupplierId($supplierId);
  3287.             // --- 2. Agente / Nombre ---
  3288.             $this->resolveAgentAndName($serviceEntity$serviceData$em);
  3289.             if (isset($serviceData['name']) && trim((string)$serviceData['name']) !== '') {
  3290.                 $serviceEntity->setName(trim((string)$serviceData['name']));
  3291.             } elseif (empty($serviceEntity->getName()) && !empty($serviceEntity->getServiceCatName())) {
  3292.                 // Fallback: Si el grid no envía un nombre, pero tenemos categoría, rellenamos con ella para que la API nunca devuelva null
  3293.                 $serviceEntity->setName($serviceEntity->getServiceCatName());
  3294.             }
  3295.             // --- 3. Precios y Numéricos ---
  3296.             $serviceEntity->setPrice($this->parseCurrency($serviceData['price'] ?? null, (float) $serviceEntity->getPrice()));
  3297.             $serviceEntity->setCommission($this->parseCurrency($serviceData['commission'] ?? null, (float) $serviceEntity->getCommission(), true));
  3298.             
  3299.             $overVal trim((string)($serviceData['over'] ?? ''));
  3300.             if ($overVal === '') {
  3301.                 $serviceEntity->setOver('0');
  3302.             } else {
  3303.                 $serviceEntity->setOver((string) $this->parseCurrency($overVal0.0));
  3304.             }
  3305.             $serviceEntity->setCurrency($serviceData['currency'] ?? null);
  3306.             $serviceEntity->setUnits($serviceData['units'] ?? null);
  3307.             $serviceEntity->setPax($serviceData['pax'] ?? null);
  3308.             $serviceEntity->setOpCommission($serviceData['opCommission'] ?? null);
  3309.             $serviceEntity->setOpOver($serviceData['opOver'] ?? null);
  3310. //            $serviceEntity->setOpIva($serviceData['opIva'] ?? null);
  3311.             $serviceEntity->setOpIva($serviceData['opIva'] ?? 1);
  3312.             // --- 4. Flags ---
  3313.             $serviceEntity->setToinvoice(array_key_exists('toinvoice'$serviceData));
  3314.             $serviceEntity->setViewInfo(array_key_exists('viewinfo'$serviceData));
  3315.             // --- 5. Fechas ---
  3316.             try {
  3317.                 $startStr = ($serviceData['dateInAt'] ?? '') . ' ' . ($serviceData['start'] ?? '00:00');
  3318.                 $endStr = ($serviceData['dateOutAt'] ?? '') . ' ' . ($serviceData['end'] ?? '00:00');
  3319.                 $serviceEntity->setDateInAt(new DateTime($startStr));
  3320.                 $serviceEntity->setDateOutAt(new DateTime($endStr));
  3321.             } catch (\Exception $e) {
  3322.                 // Error de fecha silenciado según lógica original
  3323.             }
  3324.             $serviceEntity->setUpdatedId($userId);
  3325.             $serviceEntity->setUpdatedAt(new DateTime('now'));
  3326.             // --- 6. LÓGICA DE IVA Y ARTÍCULO SAGE (MODIFICADO) ---
  3327.             $catName $serviceEntity->getServiceCatName();
  3328.             // 6.1 Priorizar el IVA enviado desde el formulario
  3329.             if (isset($serviceData['iva']) && !empty($serviceData['iva'])) {
  3330.                 $selectedVat $em->getRepository(SageVatRates::class)->find($serviceData['iva']);
  3331.                 if ($selectedVat) {
  3332.                     $serviceEntity->setSageIva($selectedVat);
  3333.                 }
  3334.             } else {
  3335.                 // Si no se envía IVA (o el select estaba vacío), aplicamos el SUCOE/Default
  3336.                 $serviceEntity->setSageIva($defaultSageVatRate);
  3337.             }
  3338.             // 6.2 Buscar el artículo Sage basándonos en el IVA asignado arriba
  3339.             $sageArticle $em->getRepository(SageArticle::class)->findOneBy([
  3340.                 'vatType' => $serviceEntity->getSageIva(),
  3341.                 'name'    => $catName
  3342.             ]);
  3343.             if (!$sageArticle && $msage) {
  3344.                 $this->addFlash(
  3345.                     'mensajereservationerror',
  3346.                     'No se ha encontrado el artículo de Sage para el servicio: ' $catName ' con el IVA ' $serviceEntity->getSageIva()?->getIva() . '%. No se ha podido actualizar.'
  3347.                 );
  3348.                 return $this->redirectToRoute('reservations_venues_edit_simple', [
  3349.                     'id' => $id,
  3350.                     '_fragment' => 'btn_srv'
  3351.                 ]);
  3352.             }
  3353.             $serviceEntity->setSageArticle($sageArticle);
  3354.             $em->persist($serviceEntity);
  3355.             if (($serviceEntity->getServiceCatId() == 17)) {
  3356.                 $agendaSecurity[] = array(
  3357.                     'units' => $serviceEntity->getUnits(),
  3358.                     'pax' => $serviceEntity->getPax(),
  3359.                     'dateStart' => $serviceEntity->getDateInAt(),
  3360.                     'dateEnd' => $serviceEntity->getDateOutAt(),
  3361.                 );
  3362.             }
  3363.             $updatedCount++;
  3364.             // --- 7. Sincronizaciones ---
  3365.             if ($supplierId) {
  3366.                 if (!isset($cachedSuppliers[$supplierId])) {
  3367.                     $cachedSuppliers[$supplierId] = $em->getRepository(Supplier::class)->find($supplierId);
  3368.                 }
  3369.                 $supplier $cachedSuppliers[$supplierId];
  3370.                 if ($supplier) {
  3371.                     $this->handleSynchronization(
  3372.                         $reserva,
  3373.                         $serviceEntity,
  3374.                         $supplier,
  3375.                         $mcatering,
  3376.                         $mav,
  3377.                         $htFile,
  3378.                         $aveFile,
  3379.                         $userLogueado,
  3380.                         $syncCateringService,
  3381.                         $syncAVService,
  3382.                         $em,
  3383.                         $configManager
  3384.                     );
  3385.                 }
  3386.             }
  3387.         }
  3388.         // Actualizamos la línea de Seguridad
  3389.         if ($agendaSecurity) {
  3390.             $this->agendaService->updateSecurityLine($id$agendaSecurity$userId);
  3391.         }
  3392.         try {
  3393.             if ($updatedCount 0) {
  3394.                 $em->flush();
  3395.                 $this->addFlash('mensajereservation'$translator->trans('The Item has been updated.'));
  3396.             }
  3397.         } catch (\Exception $e) {
  3398.             $this->addFlash('mensajereservationerror'$translator->trans('An error occurred: ' $e->getMessage()));
  3399.         }
  3400.         $this->venueService->createSnapshot($reserva);
  3401.         return $this->redirectToRoute('reservations_venues_edit_simple', [
  3402.             'id' => $id,
  3403.             'token' => null,
  3404.             '_fragment' => 'btn_srv'
  3405.         ]);
  3406.     }
  3407.     /**
  3408.      * @Route("/addloungegeneral", name="reservations_venues_add_lounge_general")
  3409.      */
  3410.     public function addLoungeGeneralAction(EntityManagerInterface $emRequest $request)
  3411.     {
  3412.         $reservationsLounge $request->request->get('lounge_price');
  3413.         $yaExisteLounge $em->getRepository(ReservationLoungeDetails::class)->findOneByName($reservationsLounge['name']);
  3414.         if (!empty($yaExisteLounge)) {
  3415.             //Si ya existe la sala con ese nombre se envia a la pantalla de edicion de la sala en cuestion
  3416.             $id $yaExisteLounge->getId();
  3417.             return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3418.         }
  3419.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3420.         $user_id $user_logueado->getId();
  3421.         $now = new DateTime('now');
  3422.         $reservationsLoungeNew = new ReservationLoungeDetails();
  3423.         $reservationsLoungeNew->setName($reservationsLounge['name']);
  3424.         $reservationsLoungeNew->setMeters($reservationsLounge['meters']);
  3425.         $reservationsLoungeNew->setLength($reservationsLounge['length']);
  3426.         $reservationsLoungeNew->setWidth($reservationsLounge['width']);
  3427.         $reservationsLoungeNew->setHeight($reservationsLounge['height']);
  3428.         $reservationsLoungeNew->setCapSchool($reservationsLounge['capschool']);
  3429.         $reservationsLoungeNew->setCapTheater($reservationsLounge['captheater']);
  3430.         $reservationsLoungeNew->setCapCocktail($reservationsLounge['capcocktail']);
  3431.         $reservationsLoungeNew->setCapBanquet($reservationsLounge['capbanquet']);
  3432.         $reservationsLoungeNew->setCapImperial($reservationsLounge['capimperial']);
  3433.         $reservationsLoungeNew->setCreatedId($user_id);
  3434.         $reservationsLoungeNew->setCreatedAt($now);
  3435.         $reservationsLoungeNew->setUpdatedId($user_id);
  3436.         $reservationsLoungeNew->setUpdatedAt($now);
  3437.         try {
  3438.             $em->persist($reservationsLoungeNew);
  3439.             $em->flush();
  3440.             $event 'The Item has been created.';
  3441.             $successMessage $this->translator->trans($event);
  3442.             $this->addFlash('mensajereservation'$successMessage);
  3443.         } catch (\Exception $e) {
  3444.             $event 'An error occurred: ' $e->getMessage();
  3445.             $errorMessage $this->translator->trans($event);
  3446.             $this->addFlash('mensajereservationerror'$errorMessage);
  3447.         }
  3448.         if (!empty($reservationsLoungeNew->getId())) {
  3449.             // Esto pertenece a otra entidad
  3450.             $reservationsLoungeNewDescription = new ReservationLoungeDescription();
  3451.             $reservationsLoungeNewDescription->setLoungeId($reservationsLoungeNew->getId());
  3452.             $reservationsLoungeNewDescription->setLanguage($reservationsLounge['language']);
  3453.             $reservationsLoungeNewDescription->setDescription($reservationsLounge['description']);
  3454.             $reservationsLoungeNewDescription->setCreatedId($user_id);
  3455.             $reservationsLoungeNewDescription->setCreatedAt($now);
  3456.             $reservationsLoungeNewDescription->setUpdatedId($user_id);
  3457.             $reservationsLoungeNewDescription->setUpdatedAt($now);
  3458.             try {
  3459.                 $em->persist($reservationsLoungeNewDescription);
  3460.                 $em->flush();
  3461.                 $event 'The Item has been created.';
  3462.                 $successMessage $this->translator->trans($event);
  3463.                 $this->addFlash('mensajereservation'$successMessage);
  3464.             } catch (\Exception $e) {
  3465.                 $event 'An error occurred: ' $e->getMessage();
  3466.                 $errorMessage $this->translator->trans($event);
  3467.                 $this->addFlash('mensajereservationerror'$errorMessage);
  3468.             }
  3469.             return $this->redirectToRoute('reservations_lounge_details', array('id' => $reservationsLoungeNew->getId()));
  3470.         }
  3471.         return $this->redirectToRoute('reservations_venues_edit_general');
  3472.     }
  3473.     /**
  3474.      * @Route("/addloungedescription/{id}", name="reservations_venues_add_lounge_description")
  3475.      */
  3476.     public function addLoungeDescriptionAction($idRequest $request)
  3477.     {
  3478.         $em $this->getDoctrine()->getManager();
  3479.         /* Obtengo usuario logueado */
  3480.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3481.         $user_id $user_logueado->getId();
  3482.         $now = new DateTime('now');
  3483.         $reservationsLoungeDescriptoin $request->request->get('lounge_description');
  3484.         //        $reservationsLoungeDetail = $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  3485.         //        $reservationsLoungeDetail->setImportantDescription($reservationsLoungeDescriptoin['importantDescription']);
  3486.         //
  3487.         //        $em->persist($reservationsLoungeDetail);
  3488.         //        $em->flush();
  3489.         if (empty($reservationsLoungeDescriptoin['language']) or empty($reservationsLoungeDescriptoin['description'])) {
  3490.             return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3491.         }
  3492.         $newLoungeDescription = new reservationLoungeDescription();
  3493.         $newLoungeDescription->setLoungeId($id);
  3494.         $newLoungeDescription->setLanguage($reservationsLoungeDescriptoin['language']);
  3495.         $newLoungeDescription->setDescription($reservationsLoungeDescriptoin['description']);
  3496.         $newLoungeDescription->setCreatedId($user_id);
  3497.         $newLoungeDescription->setUpdatedId($user_id);
  3498.         $newLoungeDescription->setCreatedAt($now);
  3499.         $newLoungeDescription->setUpdatedAt($now);
  3500.         try {
  3501.             $em->persist($newLoungeDescription);
  3502.             $em->flush();
  3503.             $event 'The Item has been created.';
  3504.             //            $successMessage = $this->translator->trans($event);
  3505.             $successMessage 'El elemento ha sido creado.';
  3506.             $this->addFlash('mensajereservation'$successMessage);
  3507.         } catch (\Exception $e) {
  3508.             $event 'An error occurred: ' $e->getMessage();
  3509.             $errorMessage $this->translator->trans($event);
  3510.             $this->addFlash('mensajereservationerror'$errorMessage);
  3511.         }
  3512.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3513.     }
  3514.     /**
  3515.      * @Route("/addwebinfo/{id}", name="reservations_venues_add_web_info")
  3516.      * Actualiza la información de la sala a presentar en la web, que esta almacenada por defecto
  3517.      * Actualiza la información del contrato
  3518.      */
  3519.     public function addLoungeWebInfoAction($idEntityManagerInterface $emRequest $request)
  3520.     {
  3521.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3522.         $user_id $user_logueado->getId();
  3523.         $now = new \DateTimeImmutable('now');
  3524.         $reservationsLounge $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  3525.         if (empty($reservationsLounge)) {
  3526.             $this->addFlash('mensajereservationerror''Error, no se ha encontrado la sala con ID: ' $id);
  3527.             return $this->redirectToRoute('reservations_venues_edit_general');
  3528.         }
  3529.         $reservationsLoungeWebDescription $request->request->get('lounge_web_description') ?? [];
  3530.         foreach ($reservationsLoungeWebDescription as $key => $descriptions) {
  3531.             $reservationsLoungeDetail $em->getRepository(ReservationLoungeWebDescription::class)->findOneBy(array('lounge' => $reservationsLounge'language' => $key));
  3532.             if (empty($reservationsLoungeDetail)) {
  3533.                 $reservationsLoungeDetail = new ReservationLoungeWebDescription();
  3534.                 $reservationsLoungeDetail->setLounge($reservationsLounge);
  3535.                 $reservationsLoungeDetail->setLanguage($key);
  3536.                 $reservationsLoungeDetail->setCreatedId($user_logueado);
  3537.             }
  3538.             $reservationsLoungeDetail->setImportantDescription($descriptions['importantDescription']);
  3539.             $reservationsLoungeDetail->setImportantDescGeneralText($descriptions['importantDescGeneralText']);
  3540.             $reservationsLoungeDetail->setImportantDescSchedules($descriptions['importantDescSchedules']);
  3541.             $reservationsLoungeDetail->setImportantDescParking($descriptions['importantDescParking']);
  3542.             $reservationsLoungeDetail->setUpdatedId($user_logueado);
  3543.             $em->persist($reservationsLoungeDetail);
  3544.         }
  3545.         $em->flush();
  3546.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3547.     }
  3548.     /**
  3549.      * @Route("/updatedescritiongrid/{id}", name="reservations_venues_updatedescriptiongrid")
  3550.      */
  3551.     public function updateDescriptionGridAction($idRequest $request)
  3552.     {
  3553.         $descriptions $request->request->get('description');
  3554.         $em $this->getDoctrine()->getManager();
  3555.         /* Obtengo usuario logueado */
  3556.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3557.         $user_id $user_logueado->getId();
  3558.         foreach ($descriptions as $idDesc => $description) {
  3559.             $descriptionOriginal $em->getRepository(ReservationLoungeDescription::class)->findOneById($idDesc);
  3560.             $descriptionOriginal->setLanguage($description['language']);
  3561.             $descriptionOriginal->setDescription($description['text']);
  3562.             $descriptionOriginal->setUpdatedId($user_id);
  3563.             $descriptionOriginal->setUpdatedAt(new DateTime('now'));
  3564.             try {
  3565.                 $em->persist($descriptionOriginal);
  3566.                 $em->flush();
  3567.                 $event 'The Item has been updated.';
  3568.                 //                $successMessage = $this->translator->trans($event);
  3569.                 $successMessage 'El elemento ha sido actualizado.';
  3570.                 $this->addFlash('mensajereservation'$successMessage);
  3571.             } catch (\Exception $e) {
  3572.                 $event 'An error occurred: ' $e->getMessage();
  3573.                 $errorMessage $this->translator->trans($event);
  3574.                 $this->addFlash('mensajereservationerror'$errorMessage);
  3575.             }
  3576.         }
  3577.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3578.     }
  3579.     /**
  3580.      * @Route("/addloungepicture/{id}", name="reservations_venues_add_lounge_picture")
  3581.      */
  3582.     public function addLoungePictureAction($idEntityManagerInterface $emRequest $request//, LoggerInterface $logger)
  3583.     {
  3584.         /* Obtengo usuario logueado */
  3585.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3586.         $user_id $user_logueado->getId();
  3587.         $now = new DateTime('now');
  3588.         $picturefiles $request->files->all();
  3589.         $reservationsLoungeId $id;
  3590.         $imagenes $picturefiles['loungepicturegallery'];
  3591.         $data $reservationsLoungeId;
  3592.         if (!empty($imagenes['image1']) || !empty($imagenes['image2']) || !empty($imagenes['image3']) || !empty($imagenes['image4']) || !empty($imagenes['image5'])) {
  3593.             $num 0;
  3594.             foreach ($imagenes as $img) {
  3595.                 $num $num;
  3596.                 if (!is_null($img)) {
  3597.                     $data $this->CargarImgGalleryAction($reservationsLoungeId$img$num$request);
  3598.                 } //, $logger);
  3599.             }
  3600.         } else {
  3601.             $errorMessage $this->translator->trans('Error, some fields are empty');
  3602.             $this->addFlash('mensajegalleryerror'$errorMessage);
  3603.         }
  3604.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3605.     }
  3606.     protected function CargarImgGalleryAction($reservationsLoungeId$image$numRequest $request//, LoggerInterface $logger)
  3607.     {
  3608.         $gallery = new ReservationLoungePicture();
  3609.         $gallery->setLoungeId($reservationsLoungeId);
  3610.         $gallery->setCreatedAt(new DateTime('now'));
  3611.         $gallery->setUpdatedAt(new DateTime('now'));
  3612.         $gallery->setTitle(null);
  3613.         if ($num == -1) {
  3614.             $gallery->setTitle('Blueprint');
  3615.         }
  3616.         if ($num == 'TEATRO') {
  3617.             $gallery->setTitle('Teatro');
  3618.         }
  3619.         if ($num == 'COCTEL') {
  3620.             $gallery->setTitle('Coctel');
  3621.         }
  3622.         if ($num == 'ESCUELA') {
  3623.             $gallery->setTitle('Escuela');
  3624.         }
  3625.         $id $reservationsLoungeId;
  3626.         /* Carga de imagenes */
  3627.         $calidad "90";
  3628.         $calidadpng "9";
  3629.         $imageName md5(rand() * time());
  3630.         $camino "assets/images/venues/lounges/";
  3631.         $extension $image->guessExtension();
  3632.         $entrada 'si';
  3633.         $image_id $imageName '.' $extension;
  3634.         $image_temp $id '-' $imageName '.' $extension;
  3635.         $image->move($camino$image_temp);
  3636.         // Nombres image
  3637.         $s "small-";
  3638.         $m "medium-";
  3639.         $l "large-";
  3640.         ########################
  3641.         # Copiar imagen 300 x Altura
  3642.         ########################
  3643.         $datos getimagesize($camino $image_temp);
  3644.         $anchura "300";
  3645.         $altura "190";
  3646.         $thumb imagecreatetruecolor($anchura$altura);
  3647.         switch ($extension) {
  3648.             case 'jpeg':
  3649.                 $img imagecreatefromjpeg($camino $image_temp);
  3650.                 imagecopyresampled($thumb$img0000$anchura$altura$datos[0], $datos[1]);
  3651.                 imagejpeg($thumb$camino $s $image_id$calidad);
  3652.                 break;
  3653.             case 'png':
  3654.                 $img imagecreatefrompng($camino $image_temp);
  3655.                 imagecopyresampled($thumb$img0000$anchura$altura$datos[0], $datos[1]);
  3656.                 imagepng($thumb$camino $s $image_id$calidadpng);
  3657.                 break;
  3658.             case 'gif':
  3659.                 $img imagecreatefromgif($camino $image_temp);
  3660.                 imagecopyresampled($thumb$img0000$anchura$altura$datos[0], $datos[1]);
  3661.                 imagegif($thumb$camino $s $image_id);
  3662.                 break;
  3663.         }
  3664.         ########################
  3665.         # Copiar imagen 600 x Altura
  3666.         ########################
  3667.         $datos2 getimagesize($camino $image_temp);
  3668.         $anchura2 "600";
  3669.         $ratio2 = ($datos2[0] / $anchura2);
  3670.         $altura2 round($datos2[1] / $ratio2);
  3671.         $thumb2 imagecreatetruecolor($anchura2$altura2);
  3672.         switch ($extension) {
  3673.             case 'jpeg':
  3674.                 $img2 imagecreatefromjpeg($camino $image_temp);
  3675.                 imagecopyresampled($thumb2$img20000$anchura2$altura2$datos2[0], $datos2[1]);
  3676.                 imagejpeg($thumb2$camino $m $image_id$calidad);
  3677.                 break;
  3678.             case 'png':
  3679.                 $img2 imagecreatefrompng($camino $image_temp);
  3680.                 imagecopyresampled($thumb2$img20000$anchura2$altura2$datos2[0], $datos2[1]);
  3681.                 imagepng($thumb2$camino $m $image_id$calidadpng);
  3682.                 break;
  3683.             case 'gif':
  3684.                 $img2 imagecreatefromgif($camino $image_temp);
  3685.                 imagecopyresampled($thumb2$img20000$anchura2$altura2$datos2[0], $datos2[1]);
  3686.                 imagegif($thumb2$camino $m $image_id);
  3687.                 break;
  3688.         }
  3689.         ########################
  3690.         # Copiar imagen 1600 x Altura
  3691.         ########################
  3692.         $datos3 getimagesize($camino $image_temp);
  3693.         $anchura3 "1600";
  3694.         $ratio3 = ($datos3[0] / $anchura3);
  3695.         $altura3 round($datos3[1] / $ratio3);
  3696.         $thumb3 imagecreatetruecolor($anchura3$altura3);
  3697.         switch ($extension) {
  3698.             case 'jpeg':
  3699.                 $img3 imagecreatefromjpeg($camino $image_temp);
  3700.                 imagecopyresampled($thumb3$img30000$anchura3$altura3$datos3[0], $datos3[1]);
  3701.                 imagejpeg($thumb3$camino $l $image_id$calidad);
  3702.                 break;
  3703.             case 'png':
  3704.                 $img3 imagecreatefrompng($camino $image_temp);
  3705.                 imagecopyresampled($thumb3$img30000$anchura3$altura3$datos3[0], $datos3[1]);
  3706.                 imagepng($thumb3$camino $l $image_id$calidadpng);
  3707.                 break;
  3708.             case 'gif':
  3709.                 $img3 imagecreatefromgif($camino $image_temp);
  3710.                 imagecopyresampled($thumb3$img30000$anchura3$altura3$datos3[0], $datos3[1]);
  3711.                 imagegif($thumb3$camino $l $image_id);
  3712.                 break;
  3713.         }
  3714.         ########################
  3715.         # borrar imagen original
  3716.         ########################
  3717.         $imagen_borrar $camino $image_temp;
  3718.         unlink($imagen_borrar);
  3719.         $gallery->setImageSmall($s $image_id);
  3720.         $gallery->setImageMedium($m $image_id);
  3721.         $gallery->setImageLarge($l $image_id);
  3722.         /* Fin Carga de imagenes */
  3723.         /* Obtengo usuario logueado */
  3724.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3725.         $user_id $user_logueado->getId();
  3726.         $gallery->setCreatedId($user_id);
  3727.         $gallery->setUpdatedId($user_id);
  3728.         $em $this->getDoctrine()->getManager();
  3729.         /* Gestión de eventos en Log */
  3730.         $user_lastname $user_logueado->getLastname();
  3731.         $user_name $user_logueado->getName();
  3732.         $user_email $user_logueado->getEmail();
  3733.         $user_rol $user_logueado->getRoles();
  3734.         $event_url $request->getPathInfo();
  3735.         $event_complete $user_name ' ' $user_lastname ' - ' $user_email ' - ' $user_rol[0] . ' | ' $event_url;
  3736.         try {
  3737.             $em->persist($gallery);
  3738.             $em->flush();
  3739.             $event 'Images from this supplier have been uploaded.';
  3740.             $successMessage $this->translator->trans($event);
  3741.             $this->addFlash('mensajegallery'$successMessage);
  3742.         } catch (\Exception $e) {
  3743.             $event 'An error occurred: ' $e->getMessage() . ' | transport';
  3744.             /* Para el usuario */
  3745.             $errorMessage $this->translator->trans($event);
  3746.             $this->addFlash('mensajegalleryerror'$errorMessage);
  3747.         }
  3748.         /* Fin Gestión de eventos en Log */
  3749.         return $id;
  3750.     }
  3751.     /**
  3752.      * @Route("/addloungevideo/{id}", name="reservations_venues_add_lounge_video")
  3753.      */
  3754.     public function addLoungeVideoAction($idEntityManagerInterface $emRequest $request//, LoggerInterface $logger)
  3755.     {
  3756.         /* Obtengo usuario logueado */
  3757.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3758.         $user_id $user_logueado->getId();
  3759.         $now = new DateTime('now');
  3760.         $urlvideo $request->request->get('loungevideo');
  3761.         $urlvideo $urlvideo['urlvideo'];
  3762.         $reservationsLoungeId $id;
  3763.         if (!empty($urlvideo)) {
  3764.             switch (true) {
  3765.                 case strpos($urlvideo'youtube'):
  3766.                     $patron '%^ (?:https?://)? (?:www\.)? (?: youtu\.be/ | youtube\.com (?: /embed/ | /v/ | /watch\?v= ) ) ([\w-]{10,12}) ($|&).* $%x';
  3767.                     preg_match($patron$urlvideo$parte);
  3768.                     $urvideo_final 'https://www.youtube.com/embed/' $parte[1];
  3769.                     break;
  3770.                 case strpos($urlvideo'youtu'):
  3771.                     $patron '%^ (?:https?://)? (?:www\.)? (?: youtu\.be/ | youtube\.com (?: /embed/ | /v/ | /watch\?v= ) ) ([\w-]{10,12}) ($|&).* $%x';
  3772.                     preg_match($patron$urlvideo$parte);
  3773.                     $urvideo_final 'https://www.youtube.com/embed/' $parte[1];
  3774.                     break;
  3775.                 case strpos($urlvideo'vimeo'):
  3776.                     $patron '%^https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)(?:[?]?.*)$%im';
  3777.                     preg_match($patron$urlvideo$parte);
  3778.                     $urvideo_final 'https://player.vimeo.com/video/' $parte[3];
  3779.                     break;
  3780.             }
  3781.             if (!empty($urlvideo) && !empty($urvideo_final)) {
  3782.                 $video = new ReservationLoungeVideo();
  3783.                 $video->setCreatedId($user_id);
  3784.                 $video->setUpdatedId($user_id);
  3785.                 $video->setVideo($urvideo_final);
  3786.                 $video->setLoungeId($reservationsLoungeId);
  3787.                 $video->setCreatedAt($now);
  3788.                 $video->setUpdatedAt($now);
  3789.                 $em->persist($video);
  3790.                 $em->flush();
  3791.             }
  3792.         }
  3793.         if (empty($urlvideo)) {
  3794.             $errorMessage $this->translator->trans('Error, some fields are empty');
  3795.             $this->addFlash('mensajegalleryerror'$errorMessage);
  3796.         }
  3797.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3798.     }
  3799.     /**
  3800.      * @Route("/deleteloungevideo/{id}", name="reservations_venues_delete_lounge_video")
  3801.      */
  3802.     public function deleteLoungeVideoAction($idEntityManagerInterface $emRequest $request//, LoggerInterface $logger)
  3803.     {
  3804.         $video $em->getRepository(ReservationLoungeVideo::class)->findOneById($id);
  3805.         $idLounge $video->getLoungeId();
  3806.         try {
  3807.             $em->remove($video);
  3808.             $em->flush();
  3809.             //            $event = 'The Item has been deleted.';
  3810.             $successMessage 'El elemento ha sido eliminado.';
  3811.             //            $successMessage = $this->translator->trans($event);
  3812.             $this->addFlash('mensajereservation'$successMessage);
  3813.         } catch (\Exception $e) {
  3814.             $event 'An error occurred: ' $e->getMessage();
  3815.             $errorMessage $this->translator->trans($event);
  3816.             $this->addFlash('mensajereservationerror'$errorMessage);
  3817.         }
  3818.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $idLounge));
  3819.     }
  3820.     /**
  3821.      * @Route("/addloungeblueprints/{id}", name="reservations_venues_add_lounge_blueprints")
  3822.      */
  3823.     public function addLoungeBlueprintsAction($idEntityManagerInterface $emRequest $request//, LoggerInterface $logger)
  3824.     {
  3825.         /* Obtengo usuario logueado */
  3826.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3827.         $user_id $user_logueado->getId();
  3828.         $now = new DateTime('now');
  3829.         $picturefiles $request->files->all();
  3830.         $reservationsLoungeId $id;
  3831.         $imagen $picturefiles['loungepicturegalleryblueprints'];
  3832.         $data $reservationsLoungeId;
  3833.         if (!empty($imagen)) {
  3834.             $num = -1;
  3835.             $data $this->CargarImgGalleryAction($reservationsLoungeId$imagen$num$request); //, $logger);
  3836.         } else {
  3837.             $errorMessage $this->translator->trans('Error, some fields are empty');
  3838.             $this->addFlash('mensajegalleryerror'$errorMessage);
  3839.         }
  3840.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3841.     }
  3842.     /**
  3843.      * @Route("/addpicturemounting/{id}", name="reservations_venues_add_lounge_picture_mounting")
  3844.      */
  3845.     public function addLoungePictureMountingAction($idEntityManagerInterface $emRequest $request//, LoggerInterface $logger)
  3846.     {
  3847.         /* Obtengo usuario logueado */
  3848.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3849.         $user_id $user_logueado->getId();
  3850.         $now = new DateTime('now');
  3851.         $picturefiles $request->files->all();
  3852.         $reservationsLoungeId $id;
  3853.         $imagen $picturefiles['picturemounting'];
  3854.         $data $reservationsLoungeId;
  3855.         if (!empty($imagen)) {
  3856.             $num $request->request->get('picturemounting');
  3857.             $num $num['type'];
  3858.             $data $this->CargarImgGalleryAction($reservationsLoungeId$imagen$num$request); //, $logger);
  3859.         } else {
  3860.             $errorMessage $this->translator->trans('Error, some fields are empty');
  3861.             $this->addFlash('mensajegalleryerror'$errorMessage);
  3862.         }
  3863.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3864.     }
  3865.     /**
  3866.      * @Route("/updatedimmensions/{id}", name="update_dimmensions")
  3867.      */
  3868.     public function updateDimmensionsAction($idEntityManagerInterface $emRequest $request)
  3869.     {
  3870.         $reservationsLounge $em->getRepository(ReservationLoungeDetails::class)->findOneById($id);
  3871.         $newData $request->request->get('loungedimmensions');
  3872.         $reservationsLounge->setMeters($newData['meters']);
  3873.         $reservationsLounge->setLength($newData['length']);
  3874.         $reservationsLounge->setWidth($newData['width']);
  3875.         $reservationsLounge->setHeight($newData['height']);
  3876.         $reservationsLounge->setCapSchool($newData['capSchool']);
  3877.         $reservationsLounge->setCapTheater($newData['capTheater']);
  3878.         $reservationsLounge->setCapCocktail($newData['capCocktail']);
  3879.         $reservationsLounge->setCapBanquet($newData['capBanquet']);
  3880.         $reservationsLounge->setCapImperial($newData['capImperial']);
  3881.         /* Obtengo usuario logueado */
  3882.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  3883.         $user_id $user_logueado->getId();
  3884.         $now = new DateTime('now');
  3885.         $reservationsLounge->setUpdatedId($user_id);
  3886.         $reservationsLounge->setUpdatedAt($now);
  3887.         try {
  3888.             $em->persist($reservationsLounge);
  3889.             $em->flush();
  3890.             $event 'The Note has been created succesfully.';
  3891.             $successMessage $this->translator->trans($event);
  3892.             $this->addFlash('mensaje'$successMessage);
  3893.         } catch (\Exception $e) {
  3894.             $event 'An error occurred: ' $e->getMessage();
  3895.             /* Para el usuario */
  3896.             $errorMessage $this->translator->trans($event);
  3897.             $this->addFlash('mensajeerror'$errorMessage);
  3898.         }
  3899.         return $this->redirectToRoute('reservations_lounge_details', array('id' => $id));
  3900.     }
  3901.     /**
  3902.      * @Route("/get_lounges_by_space", name="venues_get_lounges_by_space", methods={"GET"})
  3903.      */
  3904.     public function getLoungesBySpaceAction(Request $requestEntityManagerInterface $em): JsonResponse
  3905.     {
  3906.         $spaceId $request->query->get('space_id');
  3907.         $lounges = [];
  3908.         if ($spaceId) {
  3909.             $repo $em->getRepository(ReservationLoungeDetails::class);
  3910.             $results $repo->findBy(['space' => $spaceId], ['name' => 'ASC']);
  3911.             foreach ($results as $lounge) {
  3912.                 $lounges[] = [
  3913.                     'id' => $lounge->getId(),
  3914.                     'name' => $lounge->getName()
  3915.                 ];
  3916.             }
  3917.         }
  3918.         return new JsonResponse($lounges);
  3919.     }
  3920.     /**
  3921.      * @Route("/addvisit", name="reservations_venues_addvisit", methods={"GET", "POST"})
  3922.      */
  3923.     public function addVisitAction(EntityManagerInterface $emRequest $request)
  3924.     {
  3925.         $visit = new ReservationVisit();
  3926.         $visit->setDateStart(new \DateTime());
  3927.         // REFACTORIZACIÓN: El array 'agent_choices' ya no es necesario.
  3928.         $form $this->createForm(VisitEditType::class, $visit);
  3929.         $form->handleRequest($request);
  3930.         if ($form->isSubmitted() && $form->isValid()) {
  3931.             // Al estar la lógica dentro de la Entidad, esto ya guarda ambos IDs automáticamente
  3932.             return $this->processVisitForm($form$visit$em$requesttrue);
  3933.         }
  3934.         // Listado de visitas (para la tabla inferior)
  3935.         $visitas $em->getRepository(ReservationVisit::class)
  3936.             ->createQueryBuilder('v')
  3937.             ->leftJoin('v.agent''a')
  3938.             ->addSelect('a')
  3939.             ->orderBy('v.dateStart''DESC')
  3940.             ->setMaxResults(50)
  3941.             ->getQuery()
  3942.             ->getResult();
  3943.         return $this->render('MDS/VenuesBundle/reservations/add-visit.html.twig', [
  3944.             'visitas' => $visitas,
  3945.             'form' => $form->createView(),
  3946.         ]);
  3947.     }
  3948.     /**
  3949.      * @Route("/editvisit/{id}", name="venues_edit_visit", methods={"GET", "POST"})
  3950.      */
  3951.     public function editVisitAction(Request $requestEntityManagerInterface $emint $id): Response
  3952.     {
  3953.         $visit $em->getRepository(\App\MDS\VenuesBundle\Entity\ReservationVisit::class)->find($id);
  3954.         if (!$visit) {
  3955.             throw $this->createNotFoundException('Visita no encontrada');
  3956.         }
  3957.         // REFACTORIZACIÓN: Ya no necesitamos pasar el array de 'agent_choices'
  3958.         $form $this->createForm(\App\MDS\VenuesBundle\Form\VisitEditType::class, $visit);
  3959.         // Preload manual fields (fechas)
  3960.         if ($visit->getDateStart() instanceof \DateTimeInterface) {
  3961.             $form->get('visit_date')->setData($visit->getDateStart());
  3962.             $form->get('visit_time')->setData($visit->getDateStart()->format('H:i'));
  3963.         }
  3964.         // REFACTORIZACIÓN: Todo el bloque de "Agent mapping" SE ELIMINA.
  3965.         // Symfony ahora hace el mapeo automáticamente porque quitamos el 'mapped' => false del formulario.
  3966.         // Space / Lounge mapping
  3967.         $loungeId $visit->getIdLounge();
  3968.         $loadedLounge null;
  3969.         if ($loungeId) {
  3970.             $loadedLounge $em->getRepository(ReservationLoungeDetails::class)->find($loungeId);
  3971.             if ($loadedLounge) {
  3972.                 $form->get('lounge')->setData($loadedLounge);
  3973.                 // Force space from lounge
  3974.                 if ($loadedLounge->getSpace()) {
  3975.                     $form->get('space')->setData($loadedLounge->getSpace());
  3976.                 }
  3977.             }
  3978.         }
  3979.         if (!$loadedLounge && $visit->getSpace()) {
  3980.             $form->get('space')->setData($visit->getSpace());
  3981.         }
  3982.         // Reservation mapping
  3983.         if ($visit->getIdReservation()) {
  3984.             $res $em->getRepository(Reservation::class)->find($visit->getIdReservation());
  3985.             if ($res) {
  3986.                 $form->get('reservation')->setData($res);
  3987.             }
  3988.         }
  3989.         $form->handleRequest($request);
  3990.         if ($form->isSubmitted() && $form->isValid()) {
  3991.             return $this->processVisitForm($form$visit$em$requestfalse);
  3992.         }
  3993.         return $this->render('MDS/VenuesBundle/reservations/edit-visit.html.twig', [
  3994.             'form' => $form->createView(),
  3995.             'visit' => $visit,
  3996.         ]);
  3997.     }
  3998.     /**
  3999.      * @Route("/createvisit", name="reservations_venues_createvisit", methods={"GET", "POST"})
  4000.      */
  4001.     public function createVisitAction(EntityManagerInterface $emRequest $request)
  4002.     {
  4003.         // Redirect logic to addVisitAction to use the same form handling
  4004.         return $this->addVisitAction($em$request);
  4005.     }
  4006.     private function getAgentChoices(EntityManagerInterface $em): array
  4007.     {
  4008.         $users $em->getRepository(\App\Entity\User::class)
  4009.             ->createQueryBuilder('u')
  4010.             ->select('partial u.{id, name, lastname}')
  4011.             // AÑADIMOS EL FILTRO POR EQUIPOS AQUÍ
  4012.             ->where('u.team IN (:teams)')
  4013.             ->setParameter('teams', [416])
  4014.             ->orderBy('u.id''ASC')
  4015.             ->getQuery()
  4016.             ->getResult();
  4017.         $agentChoices = [];
  4018.         foreach ($users as $u) {
  4019.             // PHP 8.1: Uso del operador nullsafe (?->) para simplificar la lógica
  4020.             $label $u->getFullName() ?: ($u->getName() ?: 'Usuario #' $u->getId());
  4021.             $agentChoices[$label] = $u->getId();
  4022.         }
  4023.         return $agentChoices;
  4024.     }
  4025.     private function processVisitForm($form$visitEntityManagerInterface $emRequest $requestbool $isNew)
  4026.     {
  4027.         /* Obtengo usuario logueado */
  4028.         $user_logueado $this->getUser();
  4029.         // 1. Agent
  4030.         $selAgentId $form->get('agent')->getData();
  4031.         if ($selAgentId) {
  4032.             $agent $em->getRepository(\App\Entity\User::class)->find($selAgentId);
  4033.             $visit->setAgent($agent);
  4034.         }
  4035.         // 2. Date/Time -> dateStart / dateEnd
  4036.         $selDate $form->get('visit_date')->getData(); // DateTime object
  4037.         $selTime $form->get('visit_time')->getData(); // String "H:i"
  4038.         if ($selDate && $selTime) {
  4039.             [$h$m] = explode(':'$selTime);
  4040.             $start = (clone $selDate)->setTime((int) $h, (int) $m0);
  4041.             $visit->setDateStart($start);
  4042.             $visit->setDateEnd($start);
  4043.             // Legacy hour/min fields
  4044.             $visit->setHourStart($h);
  4045.             $visit->setMinStart($m);
  4046.             $visit->setHourEnd(sprintf('%02d', (int) $h 1));
  4047.             $visit->setMinEnd($m);
  4048.         }
  4049.         // 3. Space (mapped=true, handled automatically)
  4050.         // Ensure space is set on entity.
  4051.         // 4. Lounge (mapped=false)
  4052.         $lounge $form->get('lounge')->getData(); // ReservationLoungeDetails entity
  4053.         if ($lounge) {
  4054.             $visit->setIdLounge($lounge->getId());
  4055.         } else {
  4056.             $visit->setIdLounge(null); // or 0
  4057.         }
  4058.         // 5. Reservation
  4059.         $res $form->get('reservation')->getData();
  4060.         if ($res) {
  4061.             $visit->setIdReservation($res->getId());
  4062.             // Append title if creating? Legacy logic did: $title . ' - ' . $res->getTitle()
  4063.             // But title is mapped field now.
  4064.             // Maybe we should append only if it's not already there? 
  4065.             // Leaving title as user typed it in form.
  4066.         } else {
  4067.             $visit->setIdReservation(null);
  4068.         }
  4069.         if ($isNew) {
  4070.             $visit->setType('Visit');
  4071.             $visit->setCreatedAt(new \DateTime());
  4072.             $visit->setCreatedId($user_logueado->getId());
  4073.             $visit->setUpdatedAt(new \DateTime());
  4074.             $visit->setUpdatedId($user_logueado->getId());
  4075.             $em->persist($visit);
  4076.             $msg 'Visita creada correctamente';
  4077.             $route 'reservations_venues_addvisit';
  4078.         } else {
  4079.             $visit->setUpdatedAt(new \DateTime());
  4080.             // $visit->setUpdatedId($user_logueado->getId()); // if method exists
  4081.             $msg 'Visita actualizada correctamente';
  4082.             $route 'reservations_venues_addvisit';
  4083.         }
  4084.         $em->flush();
  4085.         $this->addFlash('mensajeclient'$msg);
  4086.         return $this->redirectToRoute($route);
  4087.     }
  4088.     /**
  4089.      * @Route("/deletevisit/{id}", name="get_reservations_deletevisit")
  4090.      */
  4091.     public function deleteVisitAction($idEntityManagerInterface $emRequest $request)
  4092.     {
  4093.         $visit $em->getRepository(ReservationVisit::class)->findOneById($id);
  4094.         if (!empty($visit)) {
  4095.             $em->remove($visit);
  4096.             $em->flush();
  4097.         }
  4098.         return $this->redirectToRoute('reservations_venues_addvisit');
  4099.     }
  4100.     /**
  4101.      * @Route("/sendconfirmationrequestmail/{id}", name="reservations_venues_send_confirmation_request_mail")
  4102.      * Enviar correo a Salvador y Rafael Guerrero para que la reserva (id) pase al estado confirmado
  4103.      */
  4104.     public function sendConfirmationRequestMailAction($idEntityManagerInterface $emRequest $request)
  4105.     {
  4106.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  4107.         $user_id $user_logueado->getId();
  4108.         $mailArrayTo = [];
  4109.         $mailAlert = [];
  4110.         //        $mailArrayTo['salvador@avexpress.tv'] = 'salvador@avexpress.tv';
  4111.         $mailArrayTo['rafael.guerrero@inout-travel.com'] = 'rafael.guerrero@inout-travel.com';
  4112.         //
  4113.         //        $dataGP = $this->disponibilidadVenues($id);
  4114.         //        $dataAV = $this->disponibilidadAvExpress($id);
  4115.         $dataLounges = array();
  4116.         //        foreach ($dataGP as $item){
  4117.         //            $reservationsLounges = $em->getRepository(ReservationLoungeSimple::class)->findBy(array('idReservation'=>$item->getId(),'type'=>null));
  4118.         //            foreach ($reservationsLounges as $elem){ $dataLounges[$item->getId()][] = $elem; }
  4119.         //        }
  4120.         $dataLounges = [];
  4121.         $dataLounges[$id] = $em->getRepository(ReservationLoungeSimple::class)
  4122.             ->findBy(['idReservation' => $id'type' => null]);
  4123.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  4124.         $agente $em->getRepository(User::class)->findOneById($user_id);
  4125.         $mailAddressFrom $agente->getEmail();
  4126.         $mailSubject 'Confirmación de reserva: ' $reserva->getTitle();
  4127.         $mensajePopup '';
  4128.         $mailBody 'Estimado administrador,' .
  4129.             '<br><br>' $agente->getName() . ' ' $agente->getLastName() . ' ha solicitado la confirmación de la reserva:' .
  4130.             '<br><br>' $reserva->getTitle() . ' con ID: ' $reserva->getId() .
  4131.             '<br>Este evento incia el día ' $reserva->getDateStart()->format('d/m/Y') . ' a las ' $reserva->getDateStart()->format('H:i') . ' y finaliza el día ' $reserva->getDateEnd()->format('d/m/Y') . ' a las ' $reserva->getDateEnd()->format('H:i') . '<br><br><br>';
  4132.         if (!empty($dataGP) or !empty($dataAV)) {
  4133.             if (!empty($dataGP)) {
  4134.                 $mensajePopup .= 'No se puede CONFIRMAR, conflicto con:' '<br><br>';
  4135.                 // Conflictos con otros eventos en Venues
  4136.                 $mailSubject '⚠️ ALERTA️ ‼️ DOBLE CONFIRMADO MISMA SALA' $mailSubject;
  4137.                 $mailBody $mailBody 'Este evento coincide con la(s) reserva(s): <br>';
  4138.                 foreach ($dataGP as $res) {
  4139.                     $mailBody $mailBody 'Reserva: ' $res->getTitle() . ', con ID: ' $res->getId() . ', fecha de inicio: ' $res->getDateStart()->format('d/m/Y') . ' a las ' $res->getDateStart()->format('H:i') . ', fecha de finalización: ' $res->getDateEnd()->format('d/m/Y') . ' a las ' $res->getDateEnd()->format('H:i');
  4140.                     if (!empty($dataLounges[$res->getId()])) {
  4141.                         $mailBody $mailBody ', Salas: ';
  4142.                         foreach ($dataLounges[$res->getId()] as $reservationsLoungeItem) {
  4143.                             $mailBody $mailBody $reservationsLoungeItem->getLoungeName() . ', ';
  4144.                         }
  4145.                         $mailBody $mailBody '<br>';
  4146.                     }
  4147.                     $mensajePopup .= 'Reserva: ' $res->getTitle() . ', con ID: ' $res->getId() . '<br>';
  4148.                 }
  4149.                 $mailBody $mailBody '<br><br>';
  4150.             }
  4151.             if (!empty($dataAV)) {
  4152.                 // Conflictos con otros eventos de AvExpress
  4153.                 $mailBody $mailBody 'Este evento coincide en AV con el expediente(s): <br>';
  4154.                 foreach ($dataAV as $file) {
  4155.                     $mailBody $mailBody 'Expediente: ' $file->getTitle() . ', con ID: ' $file->getId() . ', fecha de inicio: ' $file->getDateStart()->format('d/m/Y H:i') . ', fecha de finalización: ' $file->getDateEnd()->format('d/m/Y H:i') . '<br>';
  4156.                 }
  4157.             }
  4158.             $mailAlert = array('mailBody' => $mailBody'mailSubject' => $mailSubject);
  4159.         }
  4160.         $mailBody $mailBody '<br><br><a href="https://mantevenues.mante.solutions/venues/">CALENDARIO GREEN PATIO</a>';
  4161.         $mailBody $mailBody '<br><br> <a href="https://mantevenues.mante.solutions/venues/adminconfirmres/y/' $id '">"SI"</a> deseo confirmar la reserva.';
  4162.         $mailBody $mailBody '<br><br> <a href="https://mantevenues.mante.solutions/venues/adminconfirmres/n/' $id '">"NO"</a> deseo confirmar la reserva.';
  4163.         $mailBody $mailBody '<br><br><br> <a href="https://inout.mante.solutions">"PARA QUE LOS ENLACES FUNCIONEN, ANTES DEBES INCIAR SESION"</a><br><br>';
  4164.         // Se envia el correo pidiendo la confirmacion
  4165.         $this->sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailBody);
  4166.         //Alerta a Gabriela, Agente modificador del expediente y Mariale
  4167.         if (!empty($dataGP)) {
  4168.             $mailArrayTo = [];
  4169.             $agentAlert $em->getRepository(User::class)->findOneById($reserva->getUpdatedBy());
  4170.             if (!empty($agentAlert) and ($agentAlert->getStatus() == 1)) {
  4171.                 $mailArrayTo[$agentAlert->getEmail()] = $agentAlert->getEmail();
  4172.             }
  4173.             $agentAlert $em->getRepository(User::class)->findOneById(82);         // Gabriela Bracho
  4174.             if (!empty($agentAlert) and ($agentAlert->getStatus() == 1)) {
  4175.                 $mailArrayTo[$agentAlert->getEmail()] = $agentAlert->getEmail();
  4176.             }
  4177.             $agentAlert $em->getRepository(User::class)->findOneById(129);         // Maria Alejandra Martinez
  4178.             if (!empty($agentAlert) and ($agentAlert->getStatus() == 1)) {
  4179.                 $mailArrayTo[$agentAlert->getEmail()] = $agentAlert->getEmail();
  4180.             }
  4181.             $this->sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailAlert['mailBody']);
  4182.         }
  4183.         if (!empty($mensajePopup)) {
  4184.             $this->addFlash('mensajereservationerror'$mensajePopup);
  4185.         }
  4186.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $id'token' => null));
  4187.     }
  4188.     /**
  4189.      * @Route("/adminconfirmres/{op}/{id}", name="reservations_venues_admin_confirm_res")
  4190.      * Confirmacion del administrador, positiva o negativa (op) de la reserva (id)
  4191.      */
  4192.     public function adminConfirmationReservationAction($op$idEntityManagerInterface $emRequest $request)
  4193.     {
  4194.         /* Obtengo usuario logueado */
  4195.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  4196.         $user_id $user_logueado->getId();
  4197.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  4198.         $mailArrayTo = array();
  4199.         $mailArrayTo['salvador@avexpress.tv'] = 'salvador@avexpress.tv';
  4200.         $mailArrayTo['rafael.guerrero@inout-travel.com'] = 'rafael.guerrero@inout-travel.com';
  4201.         $mailArrayTo['comercial@venues.es'] = 'comercial@venues.es';
  4202.         $mailArrayTo['comercial2@venues.es'] = 'comercial2@venues.es';
  4203.         //        $mailArrayTo['gustavo.ayala@develup.solutions'] = 'gustavo.ayala@develup.solutions';
  4204.         $agente $em->getRepository(User::class)->findOneById($user_id);
  4205.         $mailAddressFrom $agente->getEmail();
  4206.         $mailSubject 'Confirmación de reserva: ' $reserva->getTitle();
  4207.         switch ($op) {
  4208.             case 'y':
  4209.                 // Se va a Confirmar la reserva
  4210.                 $reserva->setStatus('Confirmed');
  4211.                 $reserva->setUpdatedBy($user_id);
  4212.                 $reserva->setUpdatedAt(new DateTime('now'));
  4213.                 $em->persist($reserva);
  4214.                 $em->flush();
  4215.                 $mailBody 'Estimado agente,' .
  4216.                     '<br><br>' $agente->getName() . ' ' $agente->getLastName() . ' ha confirmado la reserva:' .
  4217.                     '<br><br>' $reserva->getTitle() . ' con ID: ' $reserva->getId() .
  4218.                     '<br>Este evento incia el día ' $reserva->getDateStart()->format('d/m/Y H:i') . ' y finaliza el día ' $reserva->getDateEnd()->format('d/m/Y H:i') . '<br><br><br>';
  4219.                 //                $mailBody = $mailBody .'<br><br> <a href="http://127.0.0.1:8000/venues/editsimple/'.$id.'">Ir a la reserva</a>';
  4220.                 $mailBody $mailBody '<br><br> <a href="https://mantevenues.mante.solutions/venues/editsimple/' $id '">Ir a la reserva</a>';
  4221.                 break;
  4222.             case 'n':
  4223.                 // No se va a Confirmar la reserva - Pasa a un editar (para ajustar fechas etc)
  4224.                 $reserva->setStatus('Cotizado');
  4225.                 $reserva->setUpdatedBy($user_id);
  4226.                 $reserva->setUpdatedAt(new DateTime('now'));
  4227.                 $em->persist($reserva);
  4228.                 $em->flush();
  4229.                 $mailBody 'Estimado agente,' .
  4230.                     '<br><br>' $agente->getName() . ' ' $agente->getLastName() . ' ha rechazado la confirmación de la reserva:' .
  4231.                     '<br><br>' $reserva->getTitle() . ' con ID: ' $reserva->getId() .
  4232.                     '<br>Este evento inciaba el día ' $reserva->getDateStart()->format('d/m/Y H:i') . ' y finalizaba el día ' $reserva->getDateEnd()->format('d/m/Y H:i') . '<br><br><br>' .
  4233.                     '<br>POR FAVOR, PONGANSE EN CONTACTO PARA DETEMINAR UN NUEVO HORARIO<br><br><br>';
  4234.                 //                $mailBody = $mailBody .'<br><br> <a href="http://127.0.0.1:8000/venues/editsimple/'.$id.'">Ir a la reserva</a>';
  4235.                 $mailBody $mailBody '<br><br> <a href="http://inout.mante.solutions/venues/editsimple/' $id '">Ir a la reserva</a>';
  4236.                 break;
  4237.             default:
  4238.                 break;
  4239.         }
  4240.         // Enviar correo al agente (envia a las 2 agentes? enviar al creador de la reserva?)
  4241.         $this->sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailBody);
  4242.         echo 'Ha finalizado correctamente su sesión. Puede cerrar la aplicación';
  4243.         exit();
  4244.     }
  4245.     /**
  4246.      * @Route("/viewcontract/{id}", name="reservations_venues_view_contract")
  4247.      * Vista del contrato de la reserva (id)
  4248.      */
  4249.     public function viewContractReservationAction($idEntityManagerInterface $emRequest $request)
  4250.     {
  4251.         // El cliente es obligatorio y no puede ser null
  4252.         // El contacto es obligatorio y no puede ser null, será el representante del cliente en el contrato
  4253.         // En el expediente solo deben estar las salas definitivas para el contrato
  4254.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  4255.         $contractOrigin $reserva->getContract();
  4256.         $dateStart $reserva->getDateStart();
  4257.         $dateEnd $reserva->getDateEnd();
  4258.         //Buscamos el representante
  4259.         $representante $reserva->getClientContact();
  4260.         $representante $em->getRepository(ClientContact::class)->findOneById($representante);
  4261.         $representanteCorreo $representante->getEmail();
  4262.         $representante $representante->getName() . ' ' $representante->getLastName();
  4263.         //Buscamos el cliente
  4264.         $client $reserva->getClient();
  4265.         $client $em->getRepository(Client::class)->findOneById($client);
  4266.         // La fecha de inicio y fin del evento incluyen montaje y desmontaje
  4267.         // Determinamos el primer y ultimo dia del evento y lo modificamos en la reserva sin tocar la base de datos
  4268.         $allOnlySalasReservadas $em->getRepository(ReservationLoungeSimple::class)->findBy(array('idReservation' => $id'type' => null));
  4269.         if (!empty($allOnlySalasReservadas)) {
  4270.             $reserva->setDateStart($allOnlySalasReservadas[0]->getDateStart());
  4271.             $reserva->setDateEnd($allOnlySalasReservadas[0]->getDateEnd());
  4272.             foreach ($allOnlySalasReservadas as $item) {
  4273.                 if ($item->getDateStart() < $reserva->getDateStart()) {
  4274.                     $reserva->setDateStart($item->getDateStart());
  4275.                 }
  4276.                 if ($item->getDateEnd() > $reserva->getDateEnd()) {
  4277.                     $reserva->setDateEnd($item->getDateEnd());
  4278.                 }
  4279.             }
  4280.         }
  4281.         //Generamos la fecha actual
  4282.         $fechaActual = new DateTime('now');
  4283.         $mesActual $fechaActual->format('m');
  4284.         switch ($mesActual) {
  4285.             case '01':
  4286.                 $mesActual 'enero';
  4287.                 break;
  4288.             case '02':
  4289.                 $mesActual 'febrero';
  4290.                 break;
  4291.             case '03':
  4292.                 $mesActual 'marzo';
  4293.                 break;
  4294.             case '04':
  4295.                 $mesActual 'abril';
  4296.                 break;
  4297.             case '05':
  4298.                 $mesActual 'mayo';
  4299.                 break;
  4300.             case '06':
  4301.                 $mesActual 'jumio';
  4302.                 break;
  4303.             case '07':
  4304.                 $mesActual 'julio';
  4305.                 break;
  4306.             case '08':
  4307.                 $mesActual 'agosto';
  4308.                 break;
  4309.             case '09':
  4310.                 $mesActual 'septiembre';
  4311.                 break;
  4312.             case '10':
  4313.                 $mesActual 'octubre';
  4314.                 break;
  4315.             case '11':
  4316.                 $mesActual 'noviembre';
  4317.                 break;
  4318.             case '12':
  4319.                 $mesActual 'diciembre';
  4320.                 break;
  4321.             default:
  4322.                 $mesActual '';
  4323.                 break;
  4324.         }
  4325.         $contract00 '';
  4326.         $contract01 '';
  4327.         $contract02 '';
  4328.         $contract03 '';
  4329.         $contract04 '';
  4330.         $contract05 '';
  4331.         //Generamos la fecha de inicio
  4332.         $fechaInicio $reserva->getDateStart()->format('m');
  4333.         switch ($fechaInicio) {
  4334.             case '01':
  4335.                 $mesInicio 'enero';
  4336.                 break;
  4337.             case '02':
  4338.                 $mesInicio 'febrero';
  4339.                 break;
  4340.             case '03':
  4341.                 $mesInicio 'marzo';
  4342.                 break;
  4343.             case '04':
  4344.                 $mesInicio 'abril';
  4345.                 break;
  4346.             case '05':
  4347.                 $mesInicio 'mayo';
  4348.                 break;
  4349.             case '06':
  4350.                 $mesInicio 'jumio';
  4351.                 break;
  4352.             case '07':
  4353.                 $mesInicio 'julio';
  4354.                 break;
  4355.             case '08':
  4356.                 $mesInicio 'agosto';
  4357.                 break;
  4358.             case '09':
  4359.                 $mesInicio 'septiembre';
  4360.                 break;
  4361.             case '10':
  4362.                 $mesInicio 'octubre';
  4363.                 break;
  4364.             case '11':
  4365.                 $mesInicio 'noviembre';
  4366.                 break;
  4367.             case '12':
  4368.                 $mesInicio 'diciembre';
  4369.                 break;
  4370.             default:
  4371.                 $mesInicio '';
  4372.                 break;
  4373.         }
  4374.         $fechaInicio $reserva->getDateStart()->format('d') . ' de ' $mesInicio ' del ' $reserva->getDateStart()->format('Y') . ' ';
  4375.         $contract06 '';
  4376.         $horaInicio $reserva->getDateStart()->format('H:i') . ' ';
  4377.         $contract07 '';
  4378.         //Generamos la fecha de fin
  4379.         $fechaFin $reserva->getDateEnd()->format('m');
  4380.         switch ($fechaFin) {
  4381.             case '01':
  4382.                 $mesFin 'enero';
  4383.                 break;
  4384.             case '02':
  4385.                 $mesFin 'febrero';
  4386.                 break;
  4387.             case '03':
  4388.                 $mesFin 'marzo';
  4389.                 break;
  4390.             case '04':
  4391.                 $mesFin 'abril';
  4392.                 break;
  4393.             case '05':
  4394.                 $mesFin 'mayo';
  4395.                 break;
  4396.             case '06':
  4397.                 $mesFin 'jumio';
  4398.                 break;
  4399.             case '07':
  4400.                 $mesFin 'julio';
  4401.                 break;
  4402.             case '08':
  4403.                 $mesFin 'agosto';
  4404.                 break;
  4405.             case '09':
  4406.                 $mesFin 'septiembre';
  4407.                 break;
  4408.             case '10':
  4409.                 $mesFin 'octubre';
  4410.                 break;
  4411.             case '11':
  4412.                 $mesFin 'noviembre';
  4413.                 break;
  4414.             case '12':
  4415.                 $mesFin 'diciembre';
  4416.                 break;
  4417.             default:
  4418.                 $mesFin '';
  4419.                 break;
  4420.         }
  4421.         if ($reserva->getDateStart()->format('ymd') != $reserva->getDateEnd()->format('ymd')) {
  4422.             $fechaFin ' el día ' $reserva->getDateEnd()->format('d') . ' de ' $mesFin ' del ' $reserva->getDateEnd()->format('Y') . ' a las ' $reserva->getDateEnd()->format('H:i') . ' ';
  4423.             $contractAlfa '';
  4424.             $contract08 $fechaFin $contractAlfa;
  4425.         } else {
  4426.             // El evento empieza y termina el mismo dia
  4427.             $horaFin ' las ' $reserva->getDateEnd()->format('H:i') . ' ';
  4428.             $contractAlfa '';
  4429.             $contract08 $horaFin $contractAlfa;
  4430.         }
  4431.         // Buscamos las salas
  4432.         $allSalasReservadas $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  4433.         $arrayTextoSalas = array();
  4434.         foreach ($allSalasReservadas as $item) {
  4435.             $arrayTextoSalas[$item->getIdLounge()] = $item->getIdLounge();
  4436.         }
  4437.         $textoSalas '';
  4438.         $logAllGreen false;       // Si se asigna el edificio completo no hay que verificar mas salas
  4439.         foreach ($arrayTextoSalas as $item) {
  4440.             $sala $em->getRepository(ReservationLoungeDetails::class)->findOneById($item);
  4441.             switch ($sala->getId()) {
  4442.                 case '1':
  4443.                     $textoSalas '<b>TODO EL EDIFICIO EN EXCLUSIVA</b>';
  4444.                     $logAllGreen true;
  4445.                     break;
  4446.                 case '16':
  4447.                     if (empty($textoSalas)) {
  4448.                         $textoSalas '<b>Sala Plenaria La Imprenta, Sala Invernadero</b>';
  4449.                     } else {
  4450.                         $textoSalas $textoSalas '<b>Sala Plenaria La Imprenta, Sala Invernadero</b>';
  4451.                     }
  4452.                     break;
  4453.                 case '17':
  4454.                     if (empty($textoSalas)) {
  4455.                         $textoSalas '<b>Sala Plenaria La Imprenta, Sala Invernadero, Sala Escenario</b>';
  4456.                     } else {
  4457.                         $textoSalas $textoSalas '<b>Sala Plenaria La Imprenta, Sala Invernadero, Sala Escenario</b>';
  4458.                     }
  4459.                     break;
  4460.                 default:
  4461.                     if (!$logAllGreen) {
  4462.                         if (empty($textoSalas)) {
  4463.                             $textoSalas '<b>' $sala->getName() . '</b>';
  4464.                         } else {
  4465.                             $textoSalas $textoSalas '<b>, ' $sala->getName() . '</b>';
  4466.                         }
  4467.                     }
  4468.                     break;
  4469.             }
  4470.         }
  4471.         $contract09 '';
  4472.         $cierre $reserva->getDateEnd()->format('H:i') . ' horas del día ' $reserva->getDateEnd()->format('d') . ' de ' $mesFin ' del ' $reserva->getDateEnd()->format('Y');
  4473.         $contract10 '';
  4474.         $pax $reserva->getPax();
  4475.         $contract11 '';
  4476.         $contract12 '</span></span><b><span lang="ES-TRAD" style="font-size:12.0pt"><o:p></o:p></span></b></font></p><p class="MsoListParagraph"><!--[if !supportLists]--><font face="Arial"><span lang="ES-TRAD" style="font-size:12.0pt">-<span style="font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 7pt; line-height: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><!--[endif]--><span class="Hyperlink1"><span lang="ES-TRAD" style="font-size:12.0pt">Salas a utilizar: </span></span><span class="Ninguno"><b><u><span lang="ES-TRAD">';
  4477.         $contract13 '</span></u></b></span><b><span lang="ES-TRAD" style="font-size:12.0pt"><o:p></o:p></span></b></font></p>';
  4478.         // Se asume que los montajes seran como maximo de dos dias
  4479.         $montaje = array();
  4480.         $mesInicioMontaje '';
  4481.         $mesFinMontaje '';
  4482.         foreach ($allSalasReservadas as $item) {
  4483.             if ($item->getType() == 'Montaje') {
  4484.                 if (empty($montaje)) {
  4485.                     $montaje[0] = $item->getDateStart();
  4486.                     switch ($item->getDateStart()->format('m')) {
  4487.                         case '01':
  4488.                             $mesInicioMontaje 'enero';
  4489.                             break;
  4490.                         case '02':
  4491.                             $mesInicioMontaje 'febrero';
  4492.                             break;
  4493.                         case '03':
  4494.                             $mesInicioMontaje 'marzo';
  4495.                             break;
  4496.                         case '04':
  4497.                             $mesInicioMontaje 'abril';
  4498.                             break;
  4499.                         case '05':
  4500.                             $mesInicioMontaje 'mayo';
  4501.                             break;
  4502.                         case '06':
  4503.                             $mesInicioMontaje 'jumio';
  4504.                             break;
  4505.                         case '07':
  4506.                             $mesInicioMontaje 'julio';
  4507.                             break;
  4508.                         case '08':
  4509.                             $mesInicioMontaje 'agosto';
  4510.                             break;
  4511.                         case '09':
  4512.                             $mesInicioMontaje 'septiembre';
  4513.                             break;
  4514.                         case '10':
  4515.                             $mesInicioMontaje 'octubre';
  4516.                             break;
  4517.                         case '11':
  4518.                             $mesInicioMontaje 'noviembre';
  4519.                             break;
  4520.                         case '12':
  4521.                             $mesInicioMontaje 'diciembre';
  4522.                             break;
  4523.                         default:
  4524.                             $mesInicioMontaje '';
  4525.                             break;
  4526.                     }
  4527.                 } else {
  4528.                     $montaje[1] = $item->getDateEnd();
  4529.                     switch ($item->getDateEnd()->format('m')) {
  4530.                         case '01':
  4531.                             $mesFinMontaje 'enero';
  4532.                             break;
  4533.                         case '02':
  4534.                             $mesFinMontaje 'febrero';
  4535.                             break;
  4536.                         case '03':
  4537.                             $mesFinMontaje 'marzo';
  4538.                             break;
  4539.                         case '04':
  4540.                             $mesFinMontaje 'abril';
  4541.                             break;
  4542.                         case '05':
  4543.                             $mesFinMontaje 'mayo';
  4544.                             break;
  4545.                         case '06':
  4546.                             $mesFinMontaje 'jumio';
  4547.                             break;
  4548.                         case '07':
  4549.                             $mesFinMontaje 'julio';
  4550.                             break;
  4551.                         case '08':
  4552.                             $mesFinMontaje 'agosto';
  4553.                             break;
  4554.                         case '09':
  4555.                             $mesFinMontaje 'septiembre';
  4556.                             break;
  4557.                         case '10':
  4558.                             $mesFinMontaje 'octubre';
  4559.                             break;
  4560.                         case '11':
  4561.                             $mesFinMontaje 'noviembre';
  4562.                             break;
  4563.                         case '12':
  4564.                             $mesFinMontaje 'diciembre';
  4565.                             break;
  4566.                         default:
  4567.                             $mesFinMontaje '';
  4568.                             break;
  4569.                     }
  4570.                 }
  4571.             }
  4572.         }
  4573.         switch (sizeof($montaje)) {
  4574.             case 1:
  4575.                 $textoMontaje $montaje[0]->format('d') . ' de ' $mesInicioMontaje ' del ' $montaje[0]->format('Y');
  4576.                 break;
  4577.             case 2:
  4578.                 if ($mesInicioMontaje == $mesFinMontaje) {
  4579.                     // Dos dias de montaje en el mismo mes
  4580.                     $textoMontaje $montaje[0]->format('d') . ' y ' $montaje[1]->format('d') . ' de ' $mesInicioMontaje ' del ' $montaje[0]->format('Y');
  4581.                 } else {
  4582.                     // Dos dias de montaje con diferentes meses, ejemplo 31/03 y 01/04
  4583.                     $textoMontaje $montaje[0]->format('d') . ' de ' $mesInicioMontaje ' y ' $montaje[1]->format('d') . ' de ' $mesFinMontaje ' del ' $montaje[0]->format('Y');
  4584.                 }
  4585.                 break;
  4586.             default:
  4587.                 $textoMontaje null;
  4588.                 break;
  4589.         }
  4590.         if (!empty($textoMontaje)) {
  4591.             $textoMontaje '<p class="MsoListParagraph"><!--[if !supportLists]--><font face="Arial"><span lang="ES-TRAD" style="font-size:12.0pt">-<span style="font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 7pt; line-height: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><!--[endif]--><span class="Hyperlink1"><span lang="ES-TRAD" style="font-size:12.0pt">MONTAJE: ' $textoMontaje '</span></span><b><span lang="ES-TRAD" style="font-size:12.0pt"><o:p></o:p></span></b></font></p>';
  4592.         }
  4593.         // Se asume que los desmontajes seran como maximo de dos dias
  4594.         $desmontaje = array();
  4595.         $mesInicioDesmontaje '';
  4596.         $mesFinDesmontaje '';
  4597.         foreach ($allSalasReservadas as $item) {
  4598.             if ($item->getType() == 'Desmontaje') {
  4599.                 if (empty($desmontaje)) {
  4600.                     $desmontaje[0] = $item->getDateStart();
  4601.                     switch ($item->getDateStart()->format('m')) {
  4602.                         case '01':
  4603.                             $mesInicioDesmontaje 'enero';
  4604.                             break;
  4605.                         case '02':
  4606.                             $mesInicioDesmontaje 'febrero';
  4607.                             break;
  4608.                         case '03':
  4609.                             $mesInicioDesmontaje 'marzo';
  4610.                             break;
  4611.                         case '04':
  4612.                             $mesInicioDesmontaje 'abril';
  4613.                             break;
  4614.                         case '05':
  4615.                             $mesInicioDesmontaje 'mayo';
  4616.                             break;
  4617.                         case '06':
  4618.                             $mesInicioDesmontaje 'jumio';
  4619.                             break;
  4620.                         case '07':
  4621.                             $mesInicioDesmontaje 'julio';
  4622.                             break;
  4623.                         case '08':
  4624.                             $mesInicioDesmontaje 'agosto';
  4625.                             break;
  4626.                         case '09':
  4627.                             $mesInicioDesmontaje 'septiembre';
  4628.                             break;
  4629.                         case '10':
  4630.                             $mesInicioDesmontaje 'octubre';
  4631.                             break;
  4632.                         case '11':
  4633.                             $mesInicioDesmontaje 'noviembre';
  4634.                             break;
  4635.                         case '12':
  4636.                             $mesInicioDesmontaje 'diciembre';
  4637.                             break;
  4638.                         default:
  4639.                             $mesInicioDesmontaje '';
  4640.                             break;
  4641.                     }
  4642.                 } else {
  4643.                     $desmontaje[1] = $item->getDateEnd();
  4644.                     switch ($item->getDateEnd()->format('m')) {
  4645.                         case '01':
  4646.                             $mesFinDesmontaje 'enero';
  4647.                             break;
  4648.                         case '02':
  4649.                             $mesFinDesmontaje 'febrero';
  4650.                             break;
  4651.                         case '03':
  4652.                             $mesFinDesmontaje 'marzo';
  4653.                             break;
  4654.                         case '04':
  4655.                             $mesFinDesmontaje 'abril';
  4656.                             break;
  4657.                         case '05':
  4658.                             $mesFinDesmontaje 'mayo';
  4659.                             break;
  4660.                         case '06':
  4661.                             $mesFinDesmontaje 'jumio';
  4662.                             break;
  4663.                         case '07':
  4664.                             $mesFinDesmontaje 'julio';
  4665.                             break;
  4666.                         case '08':
  4667.                             $mesFinDesmontaje 'agosto';
  4668.                             break;
  4669.                         case '09':
  4670.                             $mesFinDesmontaje 'septiembre';
  4671.                             break;
  4672.                         case '10':
  4673.                             $mesFinDesmontaje 'octubre';
  4674.                             break;
  4675.                         case '11':
  4676.                             $mesFinDesmontaje 'noviembre';
  4677.                             break;
  4678.                         case '12':
  4679.                             $mesFinDesmontaje 'diciembre';
  4680.                             break;
  4681.                         default:
  4682.                             $mesFinDesmontaje '';
  4683.                             break;
  4684.                     }
  4685.                 }
  4686.             }
  4687.         }
  4688.         switch (sizeof($desmontaje)) {
  4689.             case 1:
  4690.                 $textoDesmontaje $desmontaje[0]->format('d') . ' de ' $mesInicioDesmontaje ' del ' $desmontaje[0]->format('Y');
  4691.                 break;
  4692.             case 2:
  4693.                 if ($mesInicioDesmontaje == $mesFinDesmontaje) {
  4694.                     // Dos dias de montaje en el mismo mes
  4695.                     $textoDesmontaje $desmontaje[0]->format('d') . ' y ' $desmontaje[1]->format('d') . ' de ' $mesInicioDesmontaje ' del ' $desmontaje[0]->format('Y');
  4696.                 } else {
  4697.                     // Dos dias de montaje con diferentes meses, ejemplo 31/03 y 01/04
  4698.                     $textoDesmontaje $desmontaje[0]->format('d') . ' de ' $mesInicioDesmontaje ' y ' $desmontaje[1]->format('d') . ' de ' $mesFinDesmontaje ' del ' $desmontaje[0]->format('Y');
  4699.                 }
  4700.                 break;
  4701.             default:
  4702.                 $textoDesmontaje 'Mismo día al finalizar el evento desde las 17 horas hasta las 00:00 horas';
  4703.                 break;
  4704.         }
  4705.         if (!empty($textoDesmontaje)) {
  4706.             $textoDesmontaje '';
  4707.         }
  4708.         $contract14 '';
  4709.         if (empty($mesInicioMontaje)) {
  4710.             switch ($dateStart->format('m')) {
  4711.                 case '01':
  4712.                     $mesInicioMontajeZ 'enero';
  4713.                     break;
  4714.                 case '02':
  4715.                     $mesInicioMontajeZ 'febrero';
  4716.                     break;
  4717.                 case '03':
  4718.                     $mesInicioMontajeZ 'marzo';
  4719.                     break;
  4720.                 case '04':
  4721.                     $mesInicioMontajeZ 'abril';
  4722.                     break;
  4723.                 case '05':
  4724.                     $mesInicioMontajeZ 'mayo';
  4725.                     break;
  4726.                 case '06':
  4727.                     $mesInicioMontajeZ 'jumio';
  4728.                     break;
  4729.                 case '07':
  4730.                     $mesInicioMontajeZ 'julio';
  4731.                     break;
  4732.                 case '08':
  4733.                     $mesInicioMontajeZ 'agosto';
  4734.                     break;
  4735.                 case '09':
  4736.                     $mesInicioMontajeZ 'septiembre';
  4737.                     break;
  4738.                 case '10':
  4739.                     $mesInicioMontajeZ 'octubre';
  4740.                     break;
  4741.                 case '11':
  4742.                     $mesInicioMontajeZ 'noviembre';
  4743.                     break;
  4744.                 case '12':
  4745.                     $mesInicioMontajeZ 'diciembre';
  4746.                     break;
  4747.                 default:
  4748.                     $mesInicioMontajeZ '';
  4749.                     break;
  4750.             }
  4751.             $tiempoCedido $dateStart->format('H:i') . ' horas del día ' $dateStart->format('d') . ' de ' $mesInicioMontajeZ ' del ' $dateStart->format('Y') . ' hasta las ';
  4752.         } else {
  4753.             $tiempoCedido $dateStart->format('H:i') . ' horas del día ' $dateStart->format('d') . ' de ' $mesInicioMontaje ' del ' $dateStart->format('Y') . ' hasta las ';
  4754.         }
  4755.         if (empty($mesInicioDesmontaje)) {
  4756.             switch ($dateStart->format('m')) {
  4757.                 case '01':
  4758.                     $mesInicioDesmontajeZ 'enero';
  4759.                     break;
  4760.                 case '02':
  4761.                     $mesInicioDesmontajeZ 'febrero';
  4762.                     break;
  4763.                 case '03':
  4764.                     $mesInicioDesmontajeZ 'marzo';
  4765.                     break;
  4766.                 case '04':
  4767.                     $mesInicioDesmontajeZ 'abril';
  4768.                     break;
  4769.                 case '05':
  4770.                     $mesInicioDesmontajeZ 'mayo';
  4771.                     break;
  4772.                 case '06':
  4773.                     $mesInicioDesmontajeZ 'jumio';
  4774.                     break;
  4775.                 case '07':
  4776.                     $mesInicioDesmontajeZ 'julio';
  4777.                     break;
  4778.                 case '08':
  4779.                     $mesInicioDesmontajeZ 'agosto';
  4780.                     break;
  4781.                 case '09':
  4782.                     $mesInicioDesmontajeZ 'septiembre';
  4783.                     break;
  4784.                 case '10':
  4785.                     $mesInicioDesmontajeZ 'octubre';
  4786.                     break;
  4787.                 case '11':
  4788.                     $mesInicioDesmontajeZ 'noviembre';
  4789.                     break;
  4790.                 case '12':
  4791.                     $mesInicioDesmontajeZ 'diciembre';
  4792.                     break;
  4793.                 default:
  4794.                     $mesInicioDesmontajeZ '';
  4795.                     break;
  4796.             }
  4797.             $tiempoCedido $tiempoCedido $dateEnd->format('H:i') . ' horas del día ' $dateEnd->format('d') . ' de ' $mesInicioDesmontajeZ ' del ' $dateEnd->format('Y');
  4798.         } else {
  4799.             $tiempoCedido $tiempoCedido $dateEnd->format('H:i') . ' horas del día ' $dateEnd->format('d') . ' de ' $mesInicioDesmontaje ' del ' $dateEnd->format('Y');
  4800.         }
  4801.         $contract15 '';
  4802.         // 5. Normas de Seguridad
  4803.         $contract16 '';
  4804.         // 6. Coste, plazo y forma de pago
  4805.         $data $this->CalculosTotalesEditSimple($reserva->getId());
  4806.         $contract17 '';
  4807.         // 8. Reserva
  4808.         $contract18 '';
  4809.         // 9. Confidencialidad y publicidad
  4810.         // 11. Derechos de imagen y propiedad intelectual
  4811.         // 12. Prevencion de la corrupcion
  4812.         // 13. Proteccion de datos personales
  4813.         // 14. Responsabilidad
  4814.         $contract19 '';
  4815.         // 15. Comunicaciones
  4816.         $contract20 '';
  4817.         // 16. Cesión
  4818.         // 17. Nulidad Parcial
  4819.         // 18. Fuerza Mayor
  4820.         // 19. Acuerdo Completo
  4821.         $contract21 '';
  4822.         // Normas de uso
  4823.         $contract22 '';
  4824.         // Logotipo de Venues centrado
  4825.         $contract23 '
  4826.         <div class="col-md-4 col-xs-6" ></div><div class="col-md-4 col-xs-6" ><p class="MsoNormal" align="right" style="margin-bottom: background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><b><span lang="EN-US" style="font-size: 9pt;"><font face="Arial"><o:p><br></o:p></font></span></b></p><p class="MsoNormal" align="right" style="margin-bottom: 7.5pt; text-align: right; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><b><span lang="EN-US" style="font-size: 9pt;"><font face="Arial"><o:p><br></o:p></font></span></b></p><p class="MsoNormal" align="right" style="margin-bottom: 7.5pt; text-align: right; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVYAAAEJCAYAAADPdw+hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFxEAABcRAcom8z8AACVdSURBVHhe7d0JmFxVmTfwBBAQUWTfZJFdliTdde+t6iw2MpCJyA4BEhgFSQJ8GCCEJN3p7jp3qeqq3tNhF2ZAGRyfOAoyOmFkWAQZB0FxPkb8RPlAVhFFw2IEMtT839tvNV3Vt7qW7oRO5/97nvN03XPPPXc7973nLlU9iYiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIho3Gs2dVPcwL40CJx56fS03TWbiIhqYXzrXD/lvN+eTeQyHQ0517fvRfZWA2OJiKhqxrNezHY25BBcc0E6npMAizxfRxMRUTW8wElmOhveloCKz2GSwIpe6zpjErtoMSIiqsSiRbGPGN/+z86eGYNBVZL0XDMdiXfdwLlZixIRUSUQVBcEaWf90N5qPnV2N+SM7/yHMUduq8WJiKgc9Ex7evqmDwuqklLt8RyC7uvGWOdqcSIiKsd49rXdvdGBVZIEXde3rtHiREQ0kjbPakxn4i9JzzQqqErSoNutkxAR0UjcwLm4d1XhQ6vi1NUzXV67+uqaNXO31smIiKgUN4hfKIEzKqDmU9ibTTmvGeMcp5MREW2ZjInN7O2dfl5ra+xEzRrG+PELygVWSZ3d03PJZOwinWwYz7PO7L921nktLfUHaxYR0cSCoOqkM/HXVq2emQtSzgZj6i/XUQWMZ19SSWDtQmB1XScysLq+vaKjqyG3+tpZuXQ28TjmfYSOIiKaGBDY9vcC+yn5eqrrO7l0JpHLdiTeRwBcqkUGIbA2SVCMCqZDkwRfuW2gk4X6Fx+yHcZlM5iP3C6QefX2z8wlXesKLUJENDGk0/Epmc5Ezk998KRfgmtHZ2KD68eXZrOxnbToJATgVRKA8+VKpYHA+kGPtc2zG4xvPyj1Dn2jIAywnv371tb4oVqUiGjz5/v2UfJ11KGBNR/0kN53A/txE8SO9X3r/CAdf1fKDi0XlTIdCQRM604PARX1L/BT9nr5LYHib2vJPCXf952pujhERJu/UoE1H/gkwEpPU1JUmVJJgmh+uqivv0qS+sIy6DXr4hARbf6MsY4O0tGBNZ8GAm/0uJFSuek04L5lTAMfYBHRxCE91nKBdWMluV+b9GNdxjRur4tDRLT5W7z4kO3cwO7r6Cr/GtVYJ3nI1ebZp+uiEBFNHJ4XOyHTkXinlsv9WlP4epdnP93aWn+MLgYR0cQhv/qPIPf97r4Z4fulUYFwLJPcW0Ug/6v8tqsuAhHRxOP7Vl22I/Gr9mz591RHm+QWQNKzH21qt3fV2RMRTUxJ37pBgt7GvCUg762m2uPPyUMznS0R0cQlPUg/sB+SH1GJCoqjTXILQN6LTSZji3WWREQTX1PTzJ0RXP9zYwTXrh75n1jWXUuWJD6qsyMi2jLID7P4aeexTvnO/xg8zJI6unpm5PyU/aMuM2UPnQ0R0cRhzJE7GmOdEgTWfpo1jDHxA9PZxJj0XOW+bSYbf9CYun20+mFMKubIv37RQSKizUf426tZ5yeeb7+eao8/6Qb2t/xM9LukK1bE9m/PxB+t5BetSqVMR0OuPeM8vHJl/d5a7VCTXd9qbu9I3Ifl+W22I/GyG1iX5XKTJut4IqLxz/fjp/StnplLZ+LhS/ryS1Qd3YlXg7TjN2WO2VmLDWr1rfP9lPOWPHSKCpwjpfAXrVLO00vMkbtodYNSKdtyffuudCbxP9IrlrIShLOdiXdMwH/rQkSbEQTWE7NFP1YtQS38+b6U/ZDnWZ/XooNcz/6/CHgF01SSJGgnk9aPtZqQ3A5AL3khAvl7Ub98Ff6X15RzqhYnIhr/ogKrJHl3dSC4SqCzW93AuSzpOhdL8nznZenhFk9TLkkv1/WsF41vLWr16xdIneilPigBN5AecMT7st29M3JtKf5+ABFtRlKpxMldA//7PzJJgJVLc+k5SgDuwOdSv6daSZIAKvXIfymQoCnBO6qcJLkV4KftHxsz9UBdXCKi8S+dju+J4HlvJf+7aixTJd/mkmAu/1dLF5WIaPNhWusXdHRO/8toeqJjnSTQI/g+w6+6EtFmy/Xsr3V0b9pea6kk92KznQ3vG8+6WhePiGjzY4LYTNe335Z/Rx0V7DZV0p8QzCGo+rpoRESbL9+PnxGknfXy2lNU0NvYSf4ljLxLi6D6DSwOvxRARBNDW5t1pp9y3pMn8pvynqtc/subAug19zU1Df9iAhHRZq3VxE50A/tJeTVqpNehilP4nmpgP+UGzlPVfDNLXufKdiY2+O22Z0zjNroYREQTi3mgcRs35QTpbOLP8qMp5QKl/GJVT9+MnOfbX/d85/rOMg/CpLxc9ssDs2xHw498316qsyYimtjkv6b6KeerXmC/JYEzf/+1+D1U6dlmOxK/DwLnONe3MmGQHTJeyueT3Gbo7Z+R8wP7x7j0TxsT20FnR0S05UDAnN2ejV+IHukvpAcrAVZ6sZLks/x2gPHszkVm7x2MqZ8dpOP/T3qtQ8uEX11Ny9da7duzXfEL5XdetXoioi2XMdZBnX3TG9q8+s8ZP/aP0pPFpf9zyD9Dfg3LSzlz2zznCy1B/cEIqL2pdPwtL7BecP1Yi9duy3TxpUunfEyrIyKioYw5YHvTae+FnudumjUJl/Ztru8Y+Tx37qStOzE+nZ62eziSiIiqh95pEr1YVweJiGi0hvZYiYhoDDCwEhGNMQZWIqIxxsBKRDTGJLAaz27VQSIiGi0E1hYT2L06SEREo+UFznIE1/uMadxRs4iIaDR8P77UDeyfy//S0iwiIhoNz3NWGt/6QxDUHaBZREQ0Gl7KOdX1nWX8XVUiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiKiLUX/4kO2S7r2pV5gr/JT8dWe76w2ntVrAuc4LVKzxYvnbOe61jnGm9Zkgvqri5Pr1y8zXmy58a1T5s6dtK1OVrPcpEmTUdcZMr+k1B0xz8iE8l6q7ivGNG6vVVXEBNOOx3xMZJ0lEtYZ5adN1yoqYozzCePVtbaYqcdqVsWa00fvKevX5tUnfX/aoZq9SRgz7XiD+UZtBy+ILXf9uiXGxGZq8TGXTsf3NEHsKtl2xkzZQ7OrZsxhu2E9rsTyrohal3JJ9nkQ1H1WqxuRl66flXTrAzeov3TRothHNHvUWoL6g3Fc+65v9fspZ7Uc78bYlyzuP2Q7LUJjwfj2Sa7v3OMHzhOp9nhu1eqZuf5rZoV/e/tn5LDh16XSzsMIjHemcXDqZFXJZmM7YUc+1J6N5yRlOxORyfXtvyKgP5Fuj/9QdnytB0EuN2my61lrZV7pEeZXnLp6GmR93zEmsYtWVRHPt67vWTU9l+mIrjcqXXPdzJwJ7HatoiJB0HBA0O5gPvGXg2DqbM2uSJsfj8n26O6dnvNS9umavUmE26evxPbpSoT52O5/9ALnMazfg2iPAU6wW+vkoxYE8WMzHQ3hvBBUbunvn1NTEDGmboqfdsJ2Urwesg4p7JsA40u1A9nnfmD3aXUj8gIru/ramTnPt19b2jXlY5pdk5tuin0E653MdjY8gO38bFfPdD3OZ4Z/5bj3Us7PcKzc53l1f2MaG7fRSalaK1fW740gdn1HV+K93n7swMBej8D2ItJzHyRH/v4O4zb09M2QBvOy7zu3NaMHoNVURAPrD6XBoc4/o7G8MDw5zyO9jPm9Lju6d9UMNELnmeUrpzpaTcXCwOrH/jU8YFPO29HzG54wX1mGJ1dkj99Jq6qIbMdubB9Z/qh6o1JX7/TnsS2WaBUVkcCKaTZIcHQD67/Ry9tfR5U1EFgTCKwzcm3epg6sDgKrnKSdV4ZvC+z3IPyMdua8joM/19OHAJSy7zdm6jTZl1pNTboQlJKudb/UK8EVHYl3m4x1kI6uiu9bh7uB/fRAOylaD6wb2u6GII0gVaId6D5v1upGNBBYZ+Vcz/n9aAJr0nXmoaPynAT2zm60G9/5A5b1tx8c42GS4/4vcsylMwkcL85jy0zdPloFVUouk7GjfyuNHY3kVTdwvuP7dZ+RM1tU8rz6OBrUd2XDy9kOwfXLWlVFBgKr/UCfBPBU/PKoeQxNuDQ5O51NPNDZ3YAebuKVFlNf1e2IgcBqfU/mhx7CdVHzKJUWIWk1FXM9+yY5cFta6g+OqrNUmjt3blW9MgmsxnPelROGHCTGq7zHa1KJejlhhdP5zmmavUngBHnDQLuxj4raDkMTAsESBKfHV62eJT3Ap006doRWUxPpZSJYIKBYT+Bk9EtZDvTeVuvoak2OWmZJra0SdK2fyzbGFc8hUWUkVbrPcbJpl94kgtwrtQZWCaqyPFIPetK/9jy7FSfjHaKWq6nJPgzb5TaU3yBXrOi9/mzFiqkHalVUjtxjSfrWOtnY6YzzU68tNkNHleUF9SlMa9aYuVXdBx0aWBGgL9XssnAwZORAQHD9hUnV12t2WYWB1enX7I0mH1hxEG/Us7wEVvQ2NiD9Dpekrw7M0/o/OnpE4yGwBmh7mjUiY47cET21tQMnYvubxjTUfF8UHYhvrL5uFoKps8oEU47r6E68irb4x6VL9xzV5XUxuXpA2/6ZbONUKrGvZtdstIHV9+PnpjPxDalMPIe2srbJTDlMR40ombT+DuvwG+lE4bh7THrpOopGkvTs28PL+s6GR6WHpdkbVWFgdS7T7LLCyzjPWhdeEvl2WrPLKuqxXqPZG80HgbXyS/NaSGANb2/g0jrp2tfJ+rXjwEkm7YVapKTx0WOt/CA1Qf1xcssj7GEaJ6HZVZHeGQLrumxXw4ue58ySPATsR7TX6oeFxghOcAdJr1i2sewnza7ZaAKrXH1iWf4g0yfd2CMrVsSqurXV3Fb3N15g/WUVeq64ur1NtqOOoig4AC+V+0yZbPyPCKpVPfwYjVoD602LcGnoW3eFPZfAdjW7rIkcWDu65AGb0y33yHHJ/Fh48AX2ujbPatRikTa7wGoSuwTtzh0D94QHgmK1kq7Vj+nfN779A82a5Kft+bKvsA0fM2bsHtKMp8CKY60vvM2Xjv9/WS7Nrorx6xfISRy91rc8Lx7XbIqCnfV9uX9iXPtHmrVJ1BpYhdwPlssSTO9pVlkTPrD69o0ybIy9l59y/ksOwKA9fsdIT9I3t8Aq0NtaIfvQBPYczapYc3ra7n4q/ius83tyn1Wzsc0at0FbehZt6h30Wq/W7FEbL4G1tTV+KLb3k+1ZaY/18zW7asYcua3chuldFW7/3rE8CU0o2qAewllog/FjX9TsTWKUgfX80QXWTXePdeXKqaO+tzaSfGB1fecGzcJ+nXYkTh7runrQQ0nFu5AV+RR9cwys2IfL+hBcagmsxnNSEpiwb36qWYNc175UenTp9vj3Uqn6vTV7VMZLYPU868qB48V5p7s7tptm18R49iXhMes7747FOk1ILYF1vJdyXpfXLcbyHcFK1BpY5YsFxo09KNOhodV0KwC9u2slz5hJW42UGhsnyRm5pld7PuixDjxFjao/n2Tby/KFE1YpKrDKU2Z5R7ELAVOCpus6GR1VYHMLrC0tR+2HfXdvVy+WN6juywPyBQg/7Tzc0TU91+rHhq2rMdP3Sfr2+lWrZ2Bb2DX36oYaN4E1sK6WkxGOt2eqfR+7GNrSvGxH4n/Q3t5nYC0h6TvBwAv/zkub+mZ0rYE1uwLTedab8vBKeiCaXVY+sIYPegL7WTewv4X1/peREgLj9/MPOKolr3R1InC4gfXvWM+7ourPJ+klIWDcUu27wCIqsIqmzDE7y3zlsi2VjiNYRASTze4ea92cHgRVOWGlTKyqd5kRLC+QoNnmWetxSbuXZg+Sb9ahZ5cMe3ae/W0cD6Pq2YnxEljl9oYG1r41a6p7na8Y1ulo49q/kXdzGVhLwEHdLfdX8bemwCrTIEDdjZ32MILjRZpdkaGB1fjxRZo9IpkfGtc/SeOXd1oxXPH9y3xgDRs5krzHWC5JUMJ6zdMqqiK9YulZyfyi6h6awl6lb7/YlKn+oUKpwCqaMjN3Rv3hu8borT3R1HTErjoqNB4CaxDUVXRwGmMfhnb6lOwTX75abRp31FFltbTUHYAT5E/lSy+4lL1c7hXqqAKeZzdksvH35EsT8lmzazaObgXkA+tSzapZKjV1X5ykfiKvbDGwltCashe0oyFhg79ay6WofE8dO/svN361Meen4h2aXZF8YJWD3gTykrLzqZbA2m9oMiZ+oO/HD5WUTNYvDdLOyz1hkLBfbDVTTtKqKpIPrDI/L2X/g7xfWi51dEzfZ0lP4qNaRVXkYZL0rNCo7ai6hyaZj+lq2KOW3sRIgVVc1mTviu32M7kywd9/Xrr0gwNyPARWXNIfW7zfg3DfWweFl+/Y9wiGLtrZ6+H90cB+aaWpr+pVqzYvdoLcFkEv6zUE5amaPYzcZvLRqxv4dpN15+LFo/uu/HgJrBJQ9dbZt3tqbM95Jqj7bJCyf4fjnbcCSpHLHRyQsuPf9lvtozS7YggIH8fOejXc2YFT1TuA+cAqPTYcLH/CWVC+Rvd8PmH4eVySve4HcQka72NHIgBIALEfQrAa8TWiKPnAKg0Ml+kVfTd7NPL3WJuba/sthUqVC6yi1cTO8nHpNtBzjX9DToiSL19p/bACa9ijH7hV8gr2v3ydcnDfI+8F7Ks3g5STk3WTfdY+8K7umpaW6n6k5tZbG7dHW/qBfGsLVx8Xa3ZJbW318a7uhhewnd6VE7tm12Tc9FgDu0neP8XfN0f78MoN4gvlIZ8cj0HgfFqzqRga2z2ys4xnrdGsio1FYJV7NRKA5KCX3mg+yXBX7wwJuuF4Sa5r3Sq/uKVVVKUosE64161GCqzCde0ueUugs3d6Lula4cMsk45P+bADq7zwP3S/D+z7mTn5nQW0jz/L6z24NO+WX3TSSatiMlMPRNvcMHC7xbkbaRmGl5dKxnOuxHyfzGKbyjJqNTUZL4EVJ5azM52JN7HuOFk4n9LsmmB9rpBjE9voF83N03bXbCqGwHWdvHCNRvRstWfosQiscnBh2ttxJrxwaArkr2t/qS1lnez51ho5S3qp2D+uwHRaRVW29MAqbx/I5bfsa/x9S95tNO2JQz68wOpcH/ZYfac5at/jkvwCuU0gy62T1ARXN7elMwP3uWV+0lbLJQmq4Ynct18odT+2EuMlsEpZ49r/Gh5Dnn2LZletBT3U9kz8F9KG9PXMUf0YzoQmv0uJwPaMfBsFl91VXSKPRWCVaY0fv0CzIxkz9Vg/Zb/f2dOQazLVv78otvTAKuSHNVJp5x9kG6D8D9F7me3jcvvDvMfaNYrfQi1HXs/Cvn4D6/gGeukXygOpShOm+SV6z++gjcp7wDUZL4FVJH17hbylIm/FJN1pV2h2xdCOd0ga6zth2wmc3zcb50gdRaXg7HNWOitPpxs2BGm7tZpfWEJAfWU0gVV31IivW8lDHePZV+GycT0a6Uu+X3+MjqoYA+uANm+ajZPUqwO9RftP2G/hfcwPK7BW+wWBarie9bWwfXnOI5pVMeNZKblNEaSdn6TTtV3yjqfAKg9h0SbvDN8CStlPV/OV4GXLDv940rVXyNsS2Gfv4PPCan+FbYskZyMcWGukoctZLUjFeyt5QBS023NwZv/zNdfNyrkpp0ezK1JNYM2Te17hQwjf/jV6sZ/U7IrkA6s0TASWmnshlfogsA48KNpYqg2sos2zrpRlk9+ImKiBVd4mQED7OdbznVbfOl+zKybHBPbhn+SHn9HeWjS7KuMpsApj5m7rBnbYucAx97abspqxniM+zPL9xDGpjPNtaS8duLIJqvglOgK5rEevsBMH2hv94S9HOe+iQbWl2p1mHHRflAcdJrCmm5TzRQTTZnzuRtl35dWUTDbxkufFT9CqKlJLYG316z6DZXxDDsg2E2vS7IrkA6tMi8Z1v5t2LsLfheWSSdmXhOtf5b02rNMNAwHPXoE6FkTVXZywbpe4QWxeucY+VC2BVRjPuVoCqzw8nIiBFdvd09em1s1dU/23CqVHhp6ZJ8uY9KwHKn3fdqjxFliFnOixbe6WE4bcc8XJ49/kGEf7W+y11X8OJ6E6z4udarx4kxdYSZR9Vn5iUQIryjCo1kr+nxV6rI/LfTfZibIDpGEgiD6D9Ip8lvyw54feTjYbvwo7q+qfcJPAanz7RwPfoIpfrtll+WnnNASEd7t6Gl73UvEzNbssDaz3yD0mue0hSV7hKZfkFS806PXysr1WVRH0rm/s658xUE+l88JBjHm9ZlJ1llZTljxwDP97gOfcrFkVc10rI78iLweY/LCNZm8SaEs3y9NlnERG9aPVUdraLDtIOb+WoIgTyFdq/bZR0G3tJw++av2aq/wEJzog/y1tbrSvbglcaXXI1SEC6x9qDaxCgmumM/FF41lPhccyjvGBtyasPyKQymuPf5UvU8iXCqRtYV/dvqn/w8SEtHz5MZ9q72qwcZBfhQb1XJB23sLn97CB30lnEm9hwz+CoPZ5Yyr/oeli/f04c+KypHfVzHVuEC/726FDtZn6yzu6G9ajN/JEpT0eCazydgF6aJif/QZ6eFiP8gknkjfRkJ83fY1V3XrA2b4bgXIdtpm85hJZd3HCtn0T2/mX6OFO02rKCoJZ+6E3sQ77pOp3c+X/h/mB/Wh3z4x12M9VfeFitDDfPhzM6+SSXbPGjATBjq7puOKy/iQPZzW7auF9Sd8yXb3TsX2ce+TLHDqqIhJMsV8eRhtaJ/tJs2smy4Jgtw69zKfNTaP/Crr8jkW2u2E6ttfXcYy/4aWcv8pxjs/rccX1StK3lkkcGPqlEhojGfTU5KVio6m7u3G3ar5OWIoEOum1dt/UuNuSJdV/GyRcHmPv1V/Ff5KUM/XQdakkSfn2dntXWV6tpiLGHLljuK2K6hsphctmErtU83NsxpitRrNP5BaQ7IPRvFZUC1leWe7Rfnc9Cure/qZwnWJjUr8sp/ziVbX/GVVuJzQ1HTNw/GA/aXbNpJcq69XUZMtXk8fsVSfZ94XHeGy3JrR5HU1ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERES0kZxyyin7nHrqqcfq4DCLFy/e7qyzzpp7xhlnHKBZIZkO+SfoYEVOOumkHVDPRXPnzt1fPp922mlfRh2H6+gCKLPXmWeeOVsHZXh/lD2nsbFxG80adPrpp09FsnVwGNSzEMmSzyiXQLoM9e0YjlSod3vk1+Pj5IGcD2DaOqQpOjgIeUdhmr11cBhZZmynuA4OI8tw9tlnn6iDVZk3b95u2B5zdDCS1I8yp+tgAYzbCfv9QB0MYX/sKkkHS0KdTn57DoX8E6Rd6GABaT9Y18/pYKUmY3kuGbLvTsE8zovFYh8Jx6rzzjvvE0O3I6Y5DGUv1MFIqHM62uBuOhgJ2yiG+TWjrj3weWuZN6Ybdqxg3T6LcYfoIG3pcGB9Eg1iARrGDWgwn9fsAlIG495GSmlWCMOzke7VwbLQ+PfGfM5BfctPPvnkT59//vkfwwFwKfKWfuELXzhIiw3Cch2H+u/XQVmOAzHcjnSJZg1CWYP8VTpYAPO4CvPowsGR0OGZqGspAsDHwwJKDjKUyxpjttKsQTiozsc8foN5FARXDK/ANMfrYAHMYz/Mqx/zvRx/P6PZBVDnp5Eew8dhwbwczDuOaR/WwUhYbjk5fU0HB2F5DpbtjlSw3ZEfk2CigyWhzo5zzjnnJalfs0LIvxdp8GQ4FJZV3K2DFcE+qsN2XJnfd/h7Fur/8qJFiwoCK+o9HOlRHZT1+AzKpZC3TLMKyD7D+Hb8NaWCKwL1DEx/C5J/4okn7iWBVeaNZRjWmUD+N2WcDtKWDg3wMDSua9F4TkD6u6igIg0P4+5Hg5IgcgWywiCAz59DY/qOfK4EpneRFujgIATZo1DP1+fMmbOdZoWQNwvzvUsHQ7J8WObZmHdBQEC55SjfroODkL8MZVt1cESod1eUTUZtA9QzB/X3YfmvHBpMkCdBs1EHC2C7HYGgcBqmuQzpYs0ugPkdgLr/HR9rCawWpv0XHYykweDzSAUnRcz3s1jubh0chOU9BuOO0MGSUF+AwHMb/nZiHvtrtuR/B9NH9kqxrNLbvEMHK4JlvBbbbg8dLAn1HoJUcJJHe/oEliejgwWQ34byFyM1Y3mHndQlkMp+q2RbCJT7e9Q1VwdpS6YH3UJpWPo5g78zdfQgBL490WjuwTi5rPRlGrkcx0F4LD5XFFgx7bY4SJxSBwnqmX3CCSd8TAdDyJPAeqcODkI9MQlaOhhCucjAiry+qMtPvZ1QEMxQb8nAiuU+C/Wcib/Hocxgfag/MrDqbYU75GQhJyaU+zLKHayjB6GumgMrtuk0TPsQ6p4i6dxzz52CXuRhOnoQlsPG+DtkmXR4Dwyvxv77ZFhgCCxjA+qRXmFYJ+o/UgKUjh6EcZ0Yt0DWCetwI9ZxB80f08CKKxm5xXMNppPAeYy0QR1VQMcXBFaU3QnL0qKDg5AfQ/5SuX2Add0Hy3yzjhqEMjOxbsN6+qWgvq9i2zflt5vsC0xf9pYKTUByMKDRtumgHFTSEzyzOMDJgYhG+wAa29aSpLHioNwPDSguB5IWG5H0AEZqaKh3x+IDWBo36v+eBCfM/6NIn8aw3Cu9GqMLAhHGleqxNiN/2D0x5MWL11OWD+sWGVhlu6Cu8J4dpl2Nz+G9TeRfgemGBVbt+S3SQVmOqxCYp+rgIJSpObBiOrn8/R3SWizTWhzY8ndYkIDJmM85GHeZDMg8kfrDMUVQ17nz589/ROrD8q7F8Bp8HnaPGHkdSEvkM9YVm+C0hZo/poFVyIkJdcqtnrX4ezzm5eRPEnlY94NR931ye+lLX/rS9ih3BIYvxjQ9WiQkJ1RMPxvj5muWbI9mzGOw1y1kPijzbzpYFuazGtvtv2QZJeHzWsznJB1NWxI0nqvQCJbg70X4Kz3XC9CYfom/BZdGGljvzzdmlD0KZb6C/OOQvyYsVAFMMx/THK2DgzRYL8/3evLQMCWwrpWAi/nsgjInY/g+HV0A40v1WG9FgPhbHRyE8qcU99gwv3KBNbyNIeVQ742yfMi7EH+HBVaUlwDTItOg7EL8XSonseJ1RJnR9FjlwcqItwLyZBkxr0V6kmqN6oUKOSEgSEXeDx4K69SBeq6Sz/KwCuvWiSQ941ukXYSFiqB8TYF1KNlnSN9FT3ZfzQph/SSwPoC0u5TBcpyEJLcBik/A+yL/VmyLC/BX2ry0fRd//16LhLBOh6POq6LaQhTUcQvS2TpIWzI0Mrm/1KINbBEO1EX4ewXS8RLstFg+sP5waC8BjXc+pnsU+cMu1UuReWCaq1H3tpoVQp4cBCnpTWhWCOXlSevgww4JSmjsC4cuWx7ymlA2q4OD5CBH3dfLOmhWCHWfKAegDoZQtwRMt9StANk+OiiXqPsiT+7ReahrhmaHUO+xyJPt+BXUF25b+YvyNxQvB8oeiDoewMeqAyvqlHus9+hgWZj3ZZjmbKRL5DJYswtgeaZF9ayLYb5d2B5y5RDCvjkC69k7b968X6H+yLcgkH8qpvumDlYE+0RubRRsG6zH7TgxfEoHQ5j3oah78EFnKSh3EMoZ2Sf5/YK/sq8ujdg3JyJv2DOBKKjnVqTzdZC2VGgEl6PRRL6qg3HflEsqHcwH1h8UX36hXBvSP+tgWRKwUD6O+m7FQRmTwIYGfZ00cOlJabFBKCM9wqH1T8ZwI+pwdXgQ8q5GCnSwAPJnIX1P5iPDmP+VSN8o7rVJYEWZlhKB9XTUUfDUF1lzUP5R/C0IRCh3syynDg5C0NkN8+gdegLBOsorZBIcqw6sCID1mPa7OlgWllNeM7tbg1UkLHt4f1AHS0K5dsz7Sh0Moad7IJbpceQ3aFYBTHMSxn1dByuC7XsElvdr+Csnr62w/Bmky4vbot4KWKuDkaRNo8y1OlgA9f8txhU85JR9gzYqD1zvwbIfJe0Df7+F4fO0yCDk34Q0TwdpS4XG8ani142EBBU00v2GBhc0sK1xsO2Jj8MOfjTG3fVjxeTAlnlLgJHPxZfHeXLwYDkLehF6/6zgfVqBZZR3Moc9jMnDch4ul6zyGeX2k9e98LEggMo6l6pDlhHzKHhwIsNy8BW/+iPbqriskhODzHdwO8o20G1bNcxj2+LtU47sdyzDR3VwGKlTkg6WNH/+/J2jer2zZ8/epVT9sg3l5KKDlZosl+VYpp3kM/b9QcXbW1SyHVGHvIdasP3zpH5sm2HvIyN/R+RPlfvx8u4sPh8tD3N19CAJukM7I0RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERFuKSZP+F0vlO4rFICMJAAAAAElFTkSuQmCC" alt="" style="float: left;"></p><p class="MsoNormal" style="margin-bottom: 7.5pt; text-indent: 3pt; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"></p></div></div></div></div><div class="col-md-4 col-xs-6" ></div>
  4827.         ';
  4828.         //Generamos el contrato
  4829.         $contract $contract00 '<b>' ' ' $client->getName() . '</b>' ' ' $contract01 'CIF ' $client->getIdDocument() . ' ' .
  4830.             $contract02 '<b>' ' ' $client->getAddress() . '</b>' ',' $contract03 ' ' $representante '.' .
  4831.             $contract04 $reserva->getTitle() . $contract05 $fechaInicio $contract06 $horaInicio $contract07 .
  4832.             $contract08 $textoSalas $contract09 $cierre $contract10 $pax $contract11 $fechaInicio .
  4833.             $contract12 $textoSalas $contract13 $textoMontaje $textoDesmontaje $contract14 $tiempoCedido .
  4834.             $contract15 $contract16 $contract17 $contract18 $contract19 $contract20 $contract21 $contract22 $contract23;
  4835.         // Si no habia contracto originalmente en la reserva se actualiza
  4836.         if (empty($contractOrigin)) {
  4837.             $reserva->setContract($contract);
  4838.             $em->persist($reserva);
  4839.             $em->flush();
  4840.         } else {
  4841.             $contract $contractOrigin;
  4842.         }
  4843.         return $this->render('MDS/VenuesBundle/reservations/view-contract-reservation.html.twig', array('id' => $id'contract' => $contract, ));
  4844.     }
  4845.     /**
  4846.      * @Route("/createdeposit/{id}", name="reservations_venues_createdeposit")
  4847.      */
  4848.     public function createDepositAction($idEntityManagerInterface $emRequest $request)
  4849.     {
  4850.         $newRequest $request->request->get('reservation_deposit');
  4851.         /* Obtengo usuario logueado */
  4852.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  4853.         $user_id $user_logueado->getId();
  4854.         $newDeposit = new ReservationDeposit();
  4855.         $newDeposit->setReservationId($id);
  4856.         if (empty($newRequest['date'])) {
  4857.             $newDeposit->setDate(new DateTime('now'));
  4858.         } else {
  4859.             $newDeposit->setDate(new DateTime($newRequest['date']));
  4860.         }
  4861.         if (empty($newRequest['description'])) {
  4862.             $newDeposit->setDescription(null);
  4863.         } else {
  4864.             $newDeposit->setDescription($newRequest['description']);
  4865.         }
  4866.         if (empty($newRequest['amount'])) {
  4867.             $newDeposit->setAmount(null);
  4868.         } else {
  4869.             $newDeposit->setAmount($newRequest['amount']);
  4870.         }
  4871.         if (array_key_exists('isDone'$newRequest)) {
  4872.             $newDeposit->setIsDone(true);
  4873.         } else {
  4874.             $newDeposit->setIsDone(false);
  4875.         }
  4876.         $newDeposit->setCreatedId($user_id);
  4877.         $newDeposit->setUpdatedId($user_id);
  4878.         $em->persist($newDeposit);
  4879.         $em->flush();
  4880.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $id'token' => null'_fragment' => 'btn_dpt'));
  4881.     }
  4882.     /**
  4883.      * @Route("/depositupdate/{id}", name="reservations_venues_deposit_update")
  4884.      */
  4885.     public function depositUpdateAction($idEntityManagerInterface $emRequest $request)
  4886.     {
  4887.         $newRequest $request->request->get('reservation_deposit_isdone_pending');
  4888.         $depósito $em->getRepository(ReservationDeposit::class)->findOneById($id);
  4889.         if (array_key_exists('isDone'$newRequest)) {
  4890.             $depósito->setIsDone(true);
  4891.         } else {
  4892.             $depósito->setIsDone(false);
  4893.         }
  4894.         /* Obtengo usuario logueado */
  4895.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  4896.         $user_id $user_logueado->getId();
  4897.         $depósito->setUpdatedAt(new DateTime('now'));
  4898.         $depósito->setUpdatedId($user_id);
  4899.         $em->persist($depósito);
  4900.         $em->flush();
  4901.         return $this->redirectToRoute('reservations_venues_edit_simple', array('id' => $depósito->getReservationId(), 'token' => null'_fragment' => 'btn_dpt'));
  4902.     }
  4903.     /**
  4904.      * @Route("/loadedreservations", name="reservations_venues_loaded_reservations")
  4905.      */
  4906.     public function loadedReservationsAction(EntityManagerInterface $emRequest $request)
  4907.     {
  4908.         $hoy = new DateTime('now');
  4909.         $diaInicio = new DateTime($hoy->format('Y-m') . '-01');
  4910.         // Se buscan las reservas creadas desde el inicio de mes
  4911.         $parameters = array('diaInicio' => $diaInicio, );
  4912.         $dql 'SELECT i
  4913.                 FROM VenuesBundle:Reservation i
  4914.                 WHERE  i.createdAt > :diaInicio';
  4915.         $query $em->createQuery($dql)->setParameters($parameters);
  4916.         $reservas $query->getResult();
  4917.         return $this->render('MDS/VenuesBundle/reservations/list-loaded-reservations.html.twig', array('reservations' => $reservas'itemsOfSearch' => '', ));
  4918.     }
  4919.     /**
  4920.      * @Route("/searchreservations", name="reservations_venues_search_reservations")
  4921.      */
  4922.     public function searchReservationsAction(EntityManagerInterface $emRequest $request)
  4923.     {
  4924.         $searchloaded $request->request->get('searchloaded');
  4925.         $dateStart = new \DateTime($searchloaded['date_start']);
  4926.         $dateEnd = new \DateTime($searchloaded['date_end']);
  4927.         $itemsOfSearch ' Entre las fechas: ' $dateStart->format('d/m/Y') . ' y ' $dateEnd->format('d/m/Y');
  4928.         // Se buscan las reservas creadas en las fechas solicitadas
  4929.         $parameters = array('diaInicio' => $dateStart'diaFin' => $dateEnd, );
  4930.         $dql 'SELECT i
  4931.                 FROM VenuesBundle:Reservation i
  4932.                 WHERE  i.createdAt BETWEEN :diaInicio AND :diaFin';
  4933.         $query $em->createQuery($dql)->setParameters($parameters);
  4934.         $reservas $query->getResult();
  4935.         return $this->render('MDS/VenuesBundle/reservations/list-loaded-reservations.html.twig', array('reservations' => $reservas'itemsOfSearch' => $itemsOfSearch, ));
  4936.     }
  4937.     /**
  4938.      * Cambia las descripciones de las reservas al idioma seleccionado
  4939.      * @Route("/changeLanguage/{id}/{idLanguage}", name="reservations_venues_change_language", methods={"GET"})
  4940.      */
  4941.     public function changeLanguageAction(int $idint $idLanguageEntityManagerInterface $emSerializerInterface $serializerInterface): JsonResponse
  4942.     {
  4943.         $descriptions $em->getRepository(ReservationLoungeSimple::class)->findBy(array('idReservation' => $id));
  4944.         $idiomas = array();
  4945.         foreach ($descriptions as $description) {
  4946.             $reservationsLoungeDetails $em->getRepository(ReservationLoungeDetails::class)->findOneById($description->getIdLounge());
  4947.             $idiomas[$description->getIdLounge()] = $em->getRepository(ReservationLoungeWebDescription::class)->findOneBy(array('lounge' => $reservationsLoungeDetails'language' => $idLanguage));
  4948.         }
  4949.         $idiomas $serializerInterface->serialize($idiomas'json', [
  4950.             'groups' => ['reservation_lounge_web_description:read']
  4951.         ]);
  4952.         $idiomas json_decode($idiomastrue);
  4953.         return $this->json([
  4954.             'status' => JsonResponse::HTTP_OK,
  4955.             'idiomas' => $idiomas,
  4956.         ], JsonResponse::HTTP_OK);
  4957.     }
  4958.     private function sendMail($mailAddressFrom$mailAddressTo$mailSubject$mailBody)
  4959.     {
  4960.         $em $this->getDoctrine()->getManager();
  4961.         $agent $em->getRepository(User::class)->findOneByEmail($mailAddressFrom);
  4962.         $client $em->getRepository(Client::class)->findOneByEmail($mailAddressTo);
  4963.         if (empty($client)) {
  4964.             $client $em->getRepository(ClientContact::class)->findOneByEmail($mailAddressTo);
  4965.         }     // Si el cliente era null puede ser un client contact
  4966.         if (!empty($client)) {
  4967.             $replyTo = array(
  4968.                 $client->getEmail() => $client->getName(),
  4969.                 $agent->getEmail() => $agent->getName() . ' ' $agent->getLastName(),
  4970.             );
  4971.         } else {
  4972.             // El AddressTo es un contacto no registrado
  4973.             $replyTo = array(
  4974.                 $mailAddressTo => $mailAddressTo,
  4975.                 $agent->getEmail() => $agent->getName() . ' ' $agent->getLastName(),
  4976.             );
  4977.         }
  4978.         $agentMail $mailAddressFrom;
  4979.         $mailAgent $agentMail;
  4980.         //Se prepara el correo con los agentes a notificar
  4981.         $firmGmail $agent->getFirmGmail();
  4982.         $data = array(
  4983.             'body' => $mailBody,
  4984.             'firm' => $firmGmail,
  4985.         );
  4986.         // EJECUTAR ENVIO DE ALERTA PARA EL AGENTE
  4987.         $transporter = new \Swift_SmtpTransport();
  4988.         $transporter->setHost('smtp.gmail.com')
  4989.             ->setEncryption('ssl'//ssl / tls
  4990.             ->setPort(465// 465 / 587
  4991.             ->setUsername('desarrollo@develup.solutions')
  4992.             ->setPassword('utvh hzoi wfdo ztjs');
  4993.         //            ->setPassword('MeDITeRRANeAN_Develup30102023#');
  4994.         $mailer = new \Swift_Mailer($transporter);
  4995.         $message = new \Swift_Message();
  4996.         $message->setSubject($mailSubject)
  4997.             ->setSender($agentMail)
  4998.             ->setFrom(array("desarrollo@develup.solutions" => "Venues"))
  4999.             ->setReplyTo($agentMail)
  5000.             ->setTo($replyTo)
  5001.             ->setBody(
  5002.                 $this->renderView(
  5003.                     'mail/structure-mail.html.twig',
  5004.                     array('data' => $data)
  5005.                 ),
  5006.                 'text/html'
  5007.             );
  5008.         //        $mailer->send($message);          Rafa dijo que no queria envío de correos con el cliente ya que se haría mediante la cotización Web (04/02/2025)
  5009.         return true;
  5010.     }
  5011.     private function makeAlert($reservaId$clientId$clientMail$agentId$agentMail)
  5012.     {
  5013.         $em $this->getDoctrine()->getManager();
  5014.         $alertaPrevia $em->getRepository(ReservationMailAlertClient::class)->findOneByReservationId($reservaId);
  5015.         $reserva $em->getRepository(Reservation::class)->findOneById($reservaId);
  5016.         $dias $reserva->getDaysBlock();
  5017.         if (empty($dias) or !(is_numeric($dias))) {
  5018.             $dias 7;
  5019.         }
  5020.         $diasMenosDos $dias 2;
  5021.         /* Obtengo usuario logueado */
  5022.         $user_logueado $this->get('security.token_storage')->getToken()->getUser();
  5023.         $user_id $user_logueado->getId();
  5024.         $hoy = new \DateTime("now"NULL);
  5025.         $hoyMasCinco $hoy;
  5026.         $hoyMasCinco->add(new DateInterval('P' $diasMenosDos 'D'));                   // 5 dias despues, 48 horas antes de la cancelacion (o los especificados)
  5027.         $hoyMasCinco->add(new DateInterval("PT2H"));                                  // Ajustamos la diferencia con el reloj del servidor
  5028.         $hoy = new \DateTime("now"NULL);
  5029.         $hoyMasSiete $hoy;
  5030.         $hoyMasSiete->add(new DateInterval('P' $dias 'D'));                           // Siete dias despues (o los especificados)
  5031.         $hoyMasSiete->add(new DateInterval("PT2H"));
  5032.         //Si no hay una alerta previa se hace la alerta
  5033.         if (empty($alertaPrevia)) {
  5034.             $alerta = new ReservationMailAlertClient();
  5035.             $alerta->setReservationId($reservaId);
  5036.             $alerta->setClientId($clientId);
  5037.             $alerta->setClientMail($clientMail);
  5038.             $alerta->setAgentId($agentId);
  5039.             $alerta->setAgentMail($agentMail);
  5040.             $alerta->setAlertDateTime($hoyMasCinco);                // A los 5 dias se alerta (o los especificados)
  5041.             $alerta->setAlertSended(false);
  5042.             $alerta->setCancelDateTime($hoyMasSiete);               // A los 7 dias se cancela (o los especificados)
  5043.             $alerta->setCancelSended(false);
  5044.             $alerta->setOldReservationId(null);                     // Aqui se guardara el Id de reserva cuando se vaya a eliminar el registro (solo se pondra reservationId a 0)
  5045.             $alerta->setCreatedAt($hoy);
  5046.             $alerta->setCreatedId($user_id);
  5047.             $em->persist($alerta);
  5048.             $em->flush();
  5049.         }
  5050.         return true;
  5051.     }
  5052. //    private function benefitForReservation($id)
  5053. //    {
  5054. //
  5055. //        $em = $this->getDoctrine()->getManager();
  5056. //        $reserva = $em->getRepository(Reservation::class)->findOneById($id);
  5057. //        $reservationsLounges = $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  5058. //        $services = $em->getRepository(ReservationService::class)->findByReservationId($id);
  5059. //        $payedLounges = array();
  5060. //        $payedServices = array();
  5061. //        $unPayedServices = array();
  5062. //
  5063. //        // Salas
  5064. //        foreach ($reservationsLounges as $item) {
  5065. //            // Si la sala esta en ReservationInvoiceItems se encuentra facturado, en caso contraio, no lo esta o ha sido rectificado
  5066. //            $reservationsLoungeInvoicedItem = $em->getRepository(ReservationInvoiceItems::class)->findOneByLngControlId($item->getId());
  5067. //            if (!empty($reservationsLoungeInvoicedItem)) {
  5068. //                $payedLounges[] = $item;
  5069. //            }                       // Esta facturado el Item
  5070. //        }
  5071. //
  5072. //        // Servicios
  5073. //        foreach ($services as $item) {
  5074. //            // Si el servicio esta en ReservationInvoiceItems se encuentra facturado, en caso contraio, no lo esta o ha sido rectificado
  5075. //            $serviceInvoicedItem = $em->getRepository(ReservationInvoiceItems::class)->findOneBySrvControlId($item->getId());
  5076. //
  5077. //            if (!empty($serviceInvoicedItem)) {
  5078. //                // Esta facturado el Item
  5079. //                $payedServices[] = $item;
  5080. //            } else {
  5081. //                // No esta facturado el Item o fue rectificado
  5082. //                $unPayedServices[] = $item;
  5083. //            }
  5084. //        }
  5085. //
  5086. //        $benefit = 0;
  5087. //        $payed = 0;
  5088. //
  5089. //        // Se suman los pagos
  5090. //        foreach ($payedLounges as $item) {
  5091. //            $benefit = $benefit + (float) $item->getServicePrice();
  5092. //            $payed = $payed + (float) $item->getServicePrice();
  5093. //        }
  5094. //
  5095. //        foreach ($payedServices as $item) {
  5096. //            $benefit = $benefit + (float) $item->getPrice();
  5097. //            $payed = $payed + (float) $item->getPrice();
  5098. //        }
  5099. //
  5100. //        // Se restan los impagos
  5101. //        foreach ($unPayedServices as $item) {
  5102. //            // Se verifica el check de toinvoice por si el servicio se facturara a futuro (Requisito de Rafa)
  5103. //            if ($item->getToinvoice()) {
  5104. //                $benefit += (float) $item->getPrice();
  5105. //                $payed += (float) $item->getPrice();
  5106. //            } else {
  5107. //                // No esta pagado y no esta marcado "Para facturar"
  5108. //                $benefit = $benefit - (float) $item->getPrice();
  5109. //            }
  5110. //        }
  5111. //
  5112. //        // Porcentaje de beneficio
  5113. //        $percBenefit = ($benefit * 100);
  5114. //        if (!($payed == 0)) {
  5115. //            $percBenefit = $percBenefit / $payed;
  5116. //        } else {
  5117. //            $percBenefit = 0;
  5118. //        }
  5119. //        ;
  5120. //
  5121. //        return array(
  5122. //            'benefit' => $benefit,
  5123. //            'percBenefit' => $percBenefit,
  5124. //            'payedLounges' => $payedLounges,
  5125. //            'payedServices' => $payedServices,
  5126. //            'unPayedServices' => $unPayedServices,
  5127. //        );
  5128. //    }
  5129. /**
  5130.      * Calcula el beneficio estimado y real de la reserva, considerando el desglose
  5131.      * correcto de multiplicadores (unidades, días, pax) y tratamiento de IVA.
  5132.      */
  5133.     private function benefitForReservation(int $id): array
  5134.     {
  5135.         $em $this->getDoctrine()->getManager();
  5136.         $reserva $em->getRepository(Reservation::class)->find($id);
  5137.         if (!$reserva) {
  5138.             return [
  5139.                 'benefit' => 0,
  5140.                 'percBenefit' => 0,
  5141.                 'payedLounges' => [],
  5142.                 'payedServices' => [],
  5143.                 'unPayedServices' => [],
  5144.             ];
  5145.         }
  5146.         $reservationsLounges $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  5147.         $services $em->getRepository(ReservationService::class)->findByReservationId($id);
  5148.         $payedLounges = [];
  5149.         $payedServices = [];
  5150.         $unPayedServices = [];
  5151.         $reservaSucoe method_exists($reserva'isSucoe') ? $reserva->isSucoe() : (method_exists($reserva'getSucoe') ? $reserva->getSucoe() : false);
  5152.         // 1. Clasificación de Salas (Facturadas vs Pendientes)
  5153.         foreach ($reservationsLounges as $item) {
  5154.             $invoicedItem $em->getRepository(ReservationInvoiceItems::class)->findOneByLngControlId($item->getId());
  5155.             if (!empty($invoicedItem)) {
  5156.                 $payedLounges[] = $item;
  5157.             }
  5158.         }
  5159.         // 2. Clasificación de Servicios (Facturados vs Pendientes)
  5160.         foreach ($services as $item) {
  5161.             $invoicedItem $em->getRepository(ReservationInvoiceItems::class)->findOneBySrvControlId($item->getId());
  5162.             if (!empty($invoicedItem)) {
  5163.                 $payedServices[] = $item;
  5164.             } else {
  5165.                 $unPayedServices[] = $item;
  5166.             }
  5167.         }
  5168.         // --- CLOSURE CORREGIDA PARA CALCULAR LA BASE NETO REAL DEL SERVICIO ---
  5169.         $calculateServicePrice = function ($item) use ($reservaSucoe) {
  5170.     $priceRaw = (float) $item->getPrice();
  5171.     $commission = (float) $item->getCommission();
  5172.     $unitPrice = ($item->getOpCommission() == '1')
  5173.         ? ($priceRaw + ($priceRaw $commission 100))
  5174.         : ($priceRaw - ($priceRaw $commission 100));
  5175.     $pax max(1, (int) $item->getPax());
  5176.     $units max(1, (int) $item->getUnits());
  5177.     $dateIn $item->getDateInAt();
  5178.     $dateOut $item->getDateOutAt();
  5179.     $catId $item->getServiceCatId();
  5180.     $days 1;
  5181.     if ($dateIn && $dateOut) {
  5182.         $daysDiff $dateIn->diff($dateOut)->days;
  5183.         $days = ($catId == 5) ? $daysDiff : ($daysDiff 1);
  5184.         $days max(1$days);
  5185.     }
  5186.     $multiplicador = match ($catId) {
  5187.         => max(1$dateIn?->diff($dateOut)->days ?? 1) * $units,
  5188.         => $days $units,
  5189.         default => $days $units $pax
  5190.     };
  5191.     // OPCIÓN B: Over sumado al final del cálculo
  5192.     $over = (float) $item->getOver();
  5193.     $opOverSign = ($item->getOpOver() == '1') ? : -1;
  5194.     $subnetoTotal = ($unitPrice $multiplicador) + ($over $opOverSign);
  5195.     $ivaRate $item->getSageIva() ? (float) $item->getSageIva()->getIva() : 21.0;
  5196.     if ($item->getOpIva() == '1') {
  5197.         $neto $subnetoTotal;
  5198.     } else {
  5199.         $neto = ($subnetoTotal 100) / (100 $ivaRate);
  5200.     }
  5201.     return round($neto2PHP_ROUND_HALF_UP);
  5202. };;
  5203.         $benefit 0.0;
  5204.         $totalIngresos 0.0;
  5205.         $totalCostes 0.0;
  5206.         // Sumar Salas
  5207.         foreach ($payedLounges as $item) {
  5208.             $price = (float) $item->getServicePrice();
  5209.             $benefit += $price;
  5210.             $totalIngresos += $price;
  5211.         }
  5212.         // Sumar Servicios Facturados
  5213.         foreach ($payedServices as $item) {
  5214.             $realPrice $calculateServicePrice($item);
  5215.             $benefit += $realPrice;
  5216.             $totalIngresos += $realPrice;
  5217.         }
  5218.         // Procesar Servicios Pendientes
  5219.         foreach ($unPayedServices as $item) {
  5220.             $realPrice $calculateServicePrice($item);
  5221.             if ($item->getToinvoice()) {
  5222.                 // Venta a futuro al cliente
  5223.                 $benefit += $realPrice;
  5224.                 $totalIngresos += $realPrice;
  5225.             } else {
  5226.                 // Gasto / Coste de proveedor no facturable al cliente
  5227.                 $benefit -= $realPrice;
  5228.                 $totalCostes += $realPrice;
  5229.             }
  5230.         }
  5231.         // Porcentaje de beneficio sobre la venta total
  5232.         $percBenefit 0.0;
  5233.         if ($totalIngresos 0) {
  5234.             $percBenefit = ($benefit $totalIngresos) * 100;
  5235.         }
  5236.         return [
  5237.             'benefit' => round($benefit2),
  5238.             'percBenefit' => round($percBenefit2),
  5239.             'payedLounges' => $payedLounges,
  5240.             'payedServices' => $payedServices,
  5241.             'unPayedServices' => $unPayedServices,
  5242.         ];
  5243.     }
  5244.     private function verificarStatusInicialyFinal($id$user_id$estadoInicial$estadoFinal)
  5245.     {
  5246.         $em $this->getDoctrine()->getManager();
  5247.         // Nueva validación: No permitir pasar a 'Invoiced' manualmente si no hay facturas
  5248.         if ($estadoFinal === 'Invoiced' && $estadoInicial !== 'Invoiced') {
  5249.             $invoiceRepository $em->getRepository(ReservationInvoice::class);
  5250.             $invoiceRecRepository $em->getRepository(ReservationInvoiceRec::class);
  5251.             $hasInvoices = !empty($invoiceRepository->findByReservationId($id)) || !empty($invoiceRecRepository->findByReservationId($id));
  5252.             if (!$hasInvoices) {
  5253.                 $this->addFlash('mensajereservationerror''No se puede cambiar el estado a FACTURADO si la reserva no tiene facturas.');
  5254.                 return $estadoInicial;
  5255.             }
  5256.         }
  5257.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  5258.         $user_logueado $em->getRepository(User::class)->findOneById($user_id);
  5259.         $newStatus 'Pendiente';
  5260.         //Este Switch ya no es necesario
  5261.         switch ($estadoInicial) {
  5262.             case 'Bloqueo':
  5263.                 // De bloqueo solo se sale si el usuario es Salvador o un Admin O si se va a Cancelar "Deleted" o "Cotizado"
  5264.                 //                if (($user_logueado->getRole() == 'ROLE_ADMIN') or ($user_id == 14) or $estadoFinal == 'Deleted' or $estadoFinal == 'Cotizado'){
  5265.                 if ($estadoFinal == 'Deleted' or $estadoFinal == 'Cotizado') {
  5266.                     $newStatus $estadoFinal;
  5267.                 } else {
  5268.                     // No se cambia el estado
  5269.                     $newStatus $estadoInicial;
  5270.                 }
  5271.                 break;
  5272.             case 'Pendiente':
  5273.                 // De Pendiente solo se sale si el usuario es Salvador o un Admin O si se va a Cancelar "Deleted"
  5274.                 $newStatus $estadoFinal;
  5275.                 //                if (($user_logueado->getRole() == 'ROLE_ADMIN') or ($user_id == 14) or $estadoFinal == 'Deleted'){
  5276.                 if ($estadoFinal == 'Deleted') {
  5277.                     $newStatus $estadoFinal;
  5278.                 } else {
  5279.                     // No se cambia el estado
  5280.                     $newStatus $estadoInicial;
  5281.                 }
  5282.                 break;
  5283.             case 'Deleted':
  5284.                 // De Cancelado solo se sale si el usuario es Salvador o un Admin O "Bloqueo" o "Pendiente"
  5285.                 //                if (($user_logueado->getRole() == 'ROLE_ADMIN') or ($user_id == 14) or $estadoFinal == 'Bloqueo' or $estadoFinal == 'Pendiente'or $estadoFinal == 'Cotizado'){
  5286.                 if ($estadoFinal == 'Bloqueo' or $estadoFinal == 'Pendiente' or $estadoFinal == 'Cotizado') {
  5287.                     $newStatus $estadoFinal;
  5288.                 } else {
  5289.                     // No se cambia el estado
  5290.                     $newStatus $estadoInicial;
  5291.                 }
  5292.                 break;
  5293.             case 'Cotizado':
  5294.                 $newStatus $estadoFinal;
  5295.                 // De Cotizado solo se sale si el usuario es Salvador o un Admin O a  O "Bloqueo" o "Pendiente" o "Cancelado"
  5296.                 //                if (($user_logueado->getRole() == 'ROLE_ADMIN') or ($user_id == 14) or $estadoFinal == 'Bloqueo' or $estadoFinal == 'Pendiente' or $estadoFinal == 'Deleted'){
  5297.                 if ($estadoFinal == 'Bloqueo' or $estadoFinal == 'Pendiente' or $estadoFinal == 'Deleted' or $estadoFinal == 'Confirmed') {
  5298.                     $newStatus $estadoFinal;
  5299.                 }
  5300.                 break;
  5301.             case 'Invoiced':
  5302.                 // De Facturado no se debe salir a menos que se rectifique
  5303.                 // Si todas las facturas del expediente se encuentran rectificadas pasamos al estado "Confirmado" sino seguimos en "Facturado"
  5304.                 $reservaInvoices $em->getRepository(ReservationInvoice::class)->findByReservationId($id);
  5305.                 $estanTodasRectificadas true;
  5306.                 foreach ($reservaInvoices as $item) {
  5307.                     $reservaInvoiceRect $em->getRepository(ReservationInvoiceRec::class)->findOneByInvoiceToRec($item->getId());
  5308.                     if (empty($reservaInvoiceRect)) {
  5309.                         $estanTodasRectificadas false;
  5310.                     } else {
  5311.                         $estanTodasRectificadas = ($estanTodasRectificadas and true);
  5312.                     }
  5313.                 }
  5314.                 if ($estanTodasRectificadas) {
  5315.                     $newStatus 'Confirmed';
  5316.                 } else {
  5317.                     $newStatus $estadoInicial;
  5318.                 }
  5319.                 break;
  5320.             case 'Confirmed':
  5321.                 // Se puede ir a cualquier estado
  5322.                 $newStatus $estadoFinal;
  5323.                 break;
  5324.             default:
  5325.                 // No hacer nada con el campo Status
  5326.                 $newStatus $estadoInicial;
  5327.                 break;
  5328.         }
  5329.         $newStatus $estadoFinal;
  5330.         return $newStatus;
  5331.     }
  5332.     private function disponibilidadVenues($id)
  5333.     {
  5334.         // $id Id de la reserva
  5335.         $em $this->getDoctrine()->getManager();
  5336.         $reserva $em->getRepository(Reservation::class)->findOneById($id);
  5337.         //        $reservationsLounges = $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($id);
  5338.         //Buscamos salas que tengamos entre el inicio y fin del evento a confirmar
  5339.         //Sumamos un dia ya que por solicitud de Salva deseamos saber que eventos hay un dia antes y un dia despues
  5340.         $fechaInicio = new \DateTime($reserva->getDateStart()->format('Y-m-d H:i:s'));
  5341.         //        $fechaInicio->sub(new \DateInterval("P1D"));
  5342.         $fechaFin = new \Datetime($reserva->getDateEnd()->format('Y-m-d H:i:s'));
  5343.         //        $fechaFin->add(new \DateInterval("P1D"));
  5344.         // Los eventos que debemos verificar son los Confirmados y Facturados
  5345.         //        $parameters = array(
  5346.         //            'reservaId' => $id,
  5347.         //            'dateStart' => $fechaInicio,
  5348.         //            'dateEnd' => $fechaFin,
  5349.         //            'facturado' => 'Invoiced',
  5350.         //            'confirmado' => 'Confirmed',
  5351.         //        );
  5352.         //        $dql = 'SELECT r
  5353.         //                FROM  VenuesBundle:Reservation r
  5354.         //                INNER JOIN VenuesBundle:ReservationLoungeSimple l WITH r.id = l.idReservation
  5355.         //                  WHERE (r.status = :facturado OR r.status = :confirmado)
  5356.         //                    AND (not(r.id = :reservaId))
  5357.         //                    AND ((l.dateStart >= :dateStart and l.dateStart <= :dateEnd))';
  5358.         //
  5359.         //        $query = $em->createQuery($dql)->setParameters($parameters);
  5360.         //        $reservationInDates = $query->getResult();
  5361.         $parameters = array(
  5362.             'dateStart' => $fechaInicio,
  5363.             'dateEnd' => $fechaFin,
  5364.             'facturado' => 'Invoiced',
  5365.             'confirmado' => 'Confirmed',
  5366.         );
  5367.         $dql 'SELECT r
  5368.         FROM VenuesBundle:Reservation r
  5369.         INNER JOIN VenuesBundle:ReservationLoungeSimple l WITH r.id = l.idReservation
  5370.         WHERE (r.status = :facturado OR r.status = :confirmado) 
  5371.         AND (
  5372.             l.dateStart <= :dateEnd 
  5373.             AND l.dateEnd >= :dateStart
  5374.         )';
  5375.         $query $em->createQuery($dql)->setParameters($parameters);
  5376.         $reservationsInConflict $query->getResult();
  5377.         $arrayUso = [];
  5378.         $arrayAlert = [];
  5379.         $arrayAlertMontDesmont = [];                // Nuevo array para almacenar conflictos de montaje y desmontaje
  5380.         if (sizeof($reservationsInConflict) > 1) {
  5381.             foreach ($reservationsInConflict as $resConflict) {
  5382.                 $reservationsLoungesConflict $em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($resConflict->getId());
  5383.                 foreach ($reservationsLoungesConflict as $item) {
  5384.                     $type $item->getType();                               // Puede ser NULL, "Montaje" o "Desmontaje"
  5385.                     $dateKey $item->getDateStart()->format('Ymd');
  5386.                     $reservationsLoungeId $item->getIdLounge();
  5387.                     $reservationId $item->getIdReservation();
  5388.                     if (in_array($reservationsLoungeId, [249])) {
  5389.                         // Plenaria, Invernadero y Escenario se consideran la misma sala
  5390.                         $arrayUso[2][$dateKey][$reservationId] = empty($type) ? 'Sala' $type;
  5391.                         $arrayUso[4][$dateKey][$reservationId] = empty($type) ? 'Sala' $type;
  5392.                         ;
  5393.                         $arrayUso[9][$dateKey][$reservationId] = empty($type) ? 'Sala' $type;
  5394.                         ;
  5395.                     } else {
  5396.                         $lngDetails $em->getRepository(ReservationLoungeDetails::class)->findOneById($reservationsLoungeId);
  5397.                         if (empty($lngDetails->getCombo())) {
  5398.                             $arrayUso[$reservationsLoungeId][$dateKey][$reservationId] = empty($type) ? 'Sala' $type;
  5399.                         } else {
  5400.                             $arrayComboLounges explode(","$lngDetails->getCombo());
  5401.                             foreach ($arrayComboLounges as $indLounge) {
  5402.                                 $arrayUso[$indLounge][$dateKey][$reservationId] = empty($type) ? 'Sala' $type;
  5403.                             }
  5404.                         }
  5405.                     }
  5406.                 }
  5407.             }
  5408.             foreach ($arrayUso as $idLounge => $dates) {
  5409.                 foreach ($dates as $dateKey => $reservations) {
  5410.                     // Si el ID de la reserva está presente, obtener su dato
  5411.                     $datoId = isset($reservations[$id]) ? $reservations[$id] : 0;
  5412.                     foreach ($reservations as $reservationId => $dato) {
  5413.                         if ($reservationId != $id) {
  5414.                             if ($datoId === "Sala" && $dato === "Sala") {
  5415.                                 $arrayAlert[$reservationId][] = array('dateKey' => $dateKey'idLounge' => $idLounge'reservationId' => $reservationId);
  5416.                             } elseif (($datoId === "Montaje" || $datoId === "Desmontaje") && ($dato === "Montaje" || $dato === "Desmontaje")) {
  5417.                                 $arrayAlertMontDesmont[$reservationId][] = array('dateKey' => $dateKey'idLounge' => $idLounge'reservationId' => $reservationId);
  5418.                             } elseif ($datoId === "Sala" && ($dato === "Montaje" || $dato === "Desmontaje")) {
  5419.                                 $arrayAlert[$reservationId][] = array('dateKey' => $dateKey'idLounge' => $idLounge'reservationId' => $reservationId);
  5420.                             } elseif (($datoId === "Montaje" || $datoId === "Desmontaje") && $dato === "Sala") {
  5421.                                 $arrayAlert[$reservationId][] = array('dateKey' => $dateKey'idLounge' => $idLounge'reservationId' => $reservationId);
  5422.                             }
  5423.                         }
  5424.                     }
  5425.                 }
  5426.             }
  5427.         }
  5428.         $reservationInDates = [];
  5429.         if (!empty($arrayAlert)) {
  5430.             foreach ($arrayAlert as $key => $item) {
  5431.                 $resvConf $em->getRepository(Reservation::class)->findOneById($key);
  5432.                 $reservationInDates[] = $resvConf;
  5433.             }
  5434.             // La reserva no puede pasar a confirmada
  5435.             $reserva->setStatus('Cotizado');
  5436.             $em->persist($reserva);
  5437.             $em->flush();
  5438.         } else {
  5439.             $mensajeWarning '<br>';
  5440.             if (!empty($arrayAlertMontDesmont)) {
  5441.                 foreach ($arrayAlertMontDesmont as $key => $item) {
  5442.                     $mensajeWarning .= 'Reserva ID: ' $key '<br>';
  5443.                 }
  5444.                 $this->addFlash('mensajereservationerror''ADVERTENCIA, se han guardado los cambios, pero hay coincidencias en los Montajes y/o Desmontajes' $mensajeWarning);
  5445.                 $reservationInDates = [];
  5446.             }
  5447.         }
  5448.         return $reservationInDates;
  5449.     }
  5450.     //    private function disponibilidadAvExpress($id){
  5451.     //        // $id Id de la reserva de Venues que vamos a confirmar
  5452.     //        $em = $this->getDoctrine()->getManager();
  5453.     //        $reserva = $em->getRepository(Reservation::class)->findOneById($id);
  5454.     //
  5455.     //        //Sumamos un dia ya que por solicitud de Salva deseamos saber que eventos hay un dia antes y un dia despues
  5456.     //        $fechaInicio = new \Datetime($reserva->getDateStart()->format('Y-m-d'));
  5457.     //        $fechaInicio->sub(new \DateInterval("P1D"));
  5458.     //        $fechaFin = new \Datetime($reserva->getDateEnd()->format('Y-m-d 23:59'));
  5459.     //        $fechaFin->add(new \DateInterval("P1D"));
  5460.     //
  5461.     //        $parameters = array( 'dateStart' => $fechaInicio, 'dateEnd' => $fechaFin, );
  5462.     //
  5463.     //        $dql = 'SELECT i
  5464.     //                FROM AvexpressBundle:AveFiles i
  5465.     //                WHERE (i.dateStart <= i.dateEnd)
  5466.     //                  AND (
  5467.     //                      (i.dateStart <= :dateStart AND i.dateEnd >= :dateEnd)
  5468.     //                      OR (i.dateEnd = :dateStart)
  5469.     //                      OR (i.dateEnd > :dateStart AND i.dateEnd <= :dateEnd)
  5470.     //                      OR (i.dateStart = :dateStart)
  5471.     //                      OR (i.dateStart > :dateStart AND i.dateStart <= :dateEnd)
  5472.     //                      OR (i.dateStart = :dateEnd)
  5473.     //                  )
  5474.     //                ORDER BY i.dateStart ASC';
  5475.     //
  5476.     //        $query = $em->createQuery($dql)->setParameters($parameters);
  5477.     //        $avFilesInDates = $query->getResult();
  5478.     //
  5479.     //        return $avFilesInDates;
  5480.     //    }
  5481.     private function sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailBody)
  5482.     {
  5483.         $em $this->getDoctrine()->getManager();
  5484.         $agent $em->getRepository(User::class)->findOneByEmail($mailAddressFrom);
  5485.         $replyTo = array();
  5486.         // Verificamos que los correos sean validos
  5487.         foreach ($mailArrayTo as $item) {
  5488.             if (filter_var($itemFILTER_VALIDATE_EMAIL)) {
  5489.                 $replyTo[$item] = $item;
  5490.             }
  5491.         }
  5492.         $agentMail $mailAddressFrom;
  5493.         $mailAgent $agentMail;
  5494.         //Se prepara el correo con los agentes a notificar
  5495.         $firmGmail $agent->getFirmGmail();
  5496.         $data = array('body' => $mailBody'firm' => $firmGmail, );
  5497.         // EJECUTAR ENVIO DE ALERTA PARA EL AGENTE
  5498.         $transporter = new \Swift_SmtpTransport();
  5499.         $transporter->setHost('smtp.gmail.com')
  5500.             ->setEncryption('ssl'//ssl / tls
  5501.             ->setPort(465// 465 / 587
  5502.             ->setUsername('desarrollo@develup.solutions')
  5503.             ->setPassword('utvh hzoi wfdo ztjs');
  5504.         //            ->setPassword('MeDITeRRANeAN_Develup30102023#');
  5505.         $mailer = new \Swift_Mailer($transporter);
  5506.         $message = new \Swift_Message();
  5507.         $message->setSubject($mailSubject)
  5508.             ->setSender($agentMail)
  5509.             ->setFrom(array("desarrollo@develup.solutions" => "System Mante 3.0"))
  5510.             ->setReplyTo($agentMail)
  5511.             ->setTo($replyTo)
  5512.             ->setBody(
  5513.                 $this->renderView(
  5514.                     'mail/structure-mail.html.twig',
  5515.                     array('data' => $data)
  5516.                 ),
  5517.                 'text/html'
  5518.             );
  5519.         $mailer->send($message);
  5520.         return true;
  5521.     }
  5522.     private function notificacionReservasPorCotizar()
  5523.     {
  5524.         // Se buscan las reservas en estado "Iniciado" y se notifica a todos los
  5525.         // agentes de Venues, Solo se notifica 1 vez por dia
  5526.         // Solo se mantendran las alertas de los ultimos 6 meses
  5527.         $em $this->getDoctrine()->getManager();
  5528.         $alertas $em->getRepository(ReservationAlertStarted::class)->findAll();
  5529.         if (!empty($alertas)) {
  5530.             $ultimaAlerta end($alertas);
  5531.         } else {
  5532.             $ultimaAlerta null;
  5533.         }
  5534.         $alertas $em->getRepository(ReservationAlertStarted::class)->findAll();
  5535.         $agentesVenues $em->getRepository(User::class)->findByUserrol(48);
  5536.         $hoy = new DateTime('now');
  5537.         $fechaLimite = new DateTime('now');
  5538.         $fechaLimite->modify('-180 day');
  5539.         if (!empty($ultimaAlerta)) {
  5540.             $mismaFecha $ultimaAlerta->getAlertDate()->format('Ymd') == $hoy->format('Ymd');
  5541.         } else {
  5542.             $mismaFecha false;
  5543.         }
  5544.         if ($mismaFecha) {
  5545.             // No se debe notificar, la ultima alerta es del dia de hoy
  5546.         } else {
  5547.             // Hay que notificar
  5548.             if (empty($agentesVenues)) {
  5549.                 return true;
  5550.             }
  5551.             $mailAddressFrom $agentesVenues[0]->getEmail();
  5552.             $mailArrayTo = array();
  5553.             foreach ($agentesVenues as $agente) {
  5554.                 $mailArrayTo[$agente->getEmail()] = $agente->getEmail();
  5555.             }
  5556.             $mailSubject 'EXPENDIENTES POR COTIZAR';
  5557.             $reservasIniciado $em->getRepository(Reservation::class)->findByStatus('Iniciado');
  5558.             $mailBody null;
  5559.             foreach ($reservasIniciado as $reserva) {
  5560.                 $agenteReserva $em->getRepository(User::class)->findOneById($reserva->getCreatedBy());
  5561.                 $agenteReserva $agenteReserva->getName() . ' ' $agenteReserva->getLastName();
  5562.                 $mailBody $mailBody '<br>Evento: ' $reserva->getId() . '<br>Nombre del Evento: ' $reserva->getTitle() . '<br>Agente: ' $agenteReserva '<br>Enlace al Evento: <a href="https://mantevenues.mante.solutions/venues/editsimple/' $reserva->getId() . '">"IR AL EXPEDIENTE"</a><br><br>';
  5563.             }
  5564.             if (!empty($mailBody)) {
  5565.                 $this->sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailBody);
  5566.                 // Creamos la alerta del dia
  5567.                 $alertToday = new ReservationAlertStarted();
  5568.                 $alertToday->setAlertDate($hoy);
  5569.                 $alertToday->setMessage($mailBody);
  5570.                 $em->persist($alertToday);
  5571.                 $em->flush();
  5572.             }
  5573.         }
  5574.         // Eliminamos las alertas con mas de 6 meses de antiguedad
  5575.         foreach ($alertas as $alerta) {
  5576.             if ($alerta->getAlertDate() < $fechaLimite) {
  5577.                 $em->remove($alerta);
  5578.                 $em->flush();
  5579.             }
  5580.         }
  5581.         return true;
  5582.     }
  5583.     private function reordenarSalas($number$idLounge)
  5584.     {
  5585.         // number es el numero de la sala editada
  5586.         $em $this->getDoctrine()->getManager();
  5587.         $number--;
  5588.         $parameters = array('idLounge' => $idLounge'rankLounge' => $number, );
  5589.         $dql 'SELECT i
  5590.                 FROM VenuesBundle:ReservationLoungeDetails i
  5591.                 WHERE  i.rankLounge > :rankLounge AND i.id <> :idLounge';
  5592.         $query $em->createQuery($dql)->setParameters($parameters);
  5593.         $salasParaReordenar $query->getResult();
  5594.         foreach ($salasParaReordenar as $sala) {
  5595.             $sala->setRankLounge(($sala->getRankLounge() + 1));
  5596.             $em->persist($sala);
  5597.             $em->flush();
  5598.         }
  5599.         return empty($resInv);
  5600.     }
  5601.     private function laReservaEsConfirmable($id)
  5602.     {
  5603.         $confirmable false;
  5604.         // Una reserva se puede confirmar solo cuando tiene un depósito realizado
  5605.         $em $this->getDoctrine()->getManager();
  5606.         $depósitos $em->getRepository(ReservationDeposit::class)->findBy(array('reservationId' => $id'isDone' => true));
  5607.         $depósitos true;      // Rafa indica que este requisito no se usara por el momento 24/02/2025
  5608.         // Si la reserva no tiene ninguna sala asignada, no se puede pasar a confirmado
  5609.         $salas $em->getRepository(ReservationLoungeSimple::class)->findBy(array('idReservation' => $id));
  5610.         if (!empty($depósitos) and !empty($salas)) {
  5611.             $confirmable true;
  5612.         }
  5613.         return $confirmable;
  5614.     }
  5615.     private function laReservaEsCotizable($id)
  5616.     {
  5617.         // Una reserva se puede cotizar solo cuando tiene al menos una sala agregada
  5618.         $em $this->getDoctrine()->getManager();
  5619.         $salas $em->getRepository(ReservationLoungeSimple::class)->findBy(array('idReservation' => $id));
  5620.         return true;            // Se pidio que siempre se sincronizara con Av
  5621.     }
  5622.     private function notificacionReservasPendientesDelSegundoDepósito()
  5623.     {
  5624.         // Se buscan las reservas con depósitos y se notifica a todos los
  5625.         // agentes de Venues si no tienen el segundo depósito y faltan 30 días
  5626.         // o menos para el evento, Solo se notifica 1 vez por dia
  5627.         $em $this->getDoctrine()->getManager();
  5628.         $depósitosHechos $em->getRepository(ReservationDeposit::class)->findByIsDone(true);
  5629.         $arrayDepósitos = array();
  5630.         $arrayReservasPemdientesSegunDepósitos = array();
  5631.         $today = new \Datetime('now');
  5632.         $todayPlusMonth = new \Datetime('+ 30 days');
  5633.         // Se agrupan los depósitos por reservas
  5634.         foreach ($depósitosHechos as $item) {
  5635.             $arrayDepósitos[$item->getReservationId()][] = $item;
  5636.         }
  5637.         foreach ($arrayDepósitos as $item) {
  5638.             if (sizeof($item) < 2) {
  5639.                 // Solo nos interesan reservas con un depósito
  5640.                 $reserva $em->getRepository(Reservation::class)->findOneById($item[0]->getReservationId());
  5641.                 if ($reserva->getStatus() == 'Confirmed') {
  5642.                     // Solo nos interesan reservas confirmadas
  5643.                     if (($reserva->getDateStart() < $todayPlusMonth) and ($reserva->getDateStart() > $today)) {
  5644.                         // Solo nos interesan reservas que inician en 30 dias
  5645.                         $arrayReservasPemdientesSegunDepósitos[] = $reserva;
  5646.                     }
  5647.                 }
  5648.             }
  5649.         }
  5650.         $alertas $em->getRepository(ReservationAlertSecondDeposit::class)->findAll();
  5651.         if (!empty($alertas)) {
  5652.             $ultimaAlerta end($alertas);
  5653.         } else {
  5654.             $ultimaAlerta null;
  5655.         }
  5656.         $agentesVenues $em->getRepository(User::class)->findByUserrol(48);
  5657.         $hoy = new DateTime('now');
  5658.         $fechaLimite = new DateTime('now');
  5659.         $fechaLimite->modify('-180 day');
  5660.         if (!empty($ultimaAlerta)) {
  5661.             $mismaFecha $ultimaAlerta->getAlertDate()->format('Ymd') == $hoy->format('Ymd');
  5662.         } else {
  5663.             $mismaFecha false;
  5664.         }
  5665.         if ($mismaFecha) {
  5666.             // No se debe notificar, la ultima alerta es del dia de hoy
  5667.         } else {
  5668.             // Hay que notificar
  5669.             if (empty($agentesVenues)) {
  5670.                 return true;
  5671.             }
  5672.             $mailAddressFrom $agentesVenues[0]->getEmail();
  5673.             $mailArrayTo = array();
  5674.             foreach ($agentesVenues as $agente) {
  5675.                 $mailArrayTo[$agente->getEmail()] = $agente->getEmail();
  5676.             }
  5677.             $mailSubject 'EXPENDIENTES CON DEPÓSITOS PENDIENTES';
  5678.             $reservasIniciado $arrayReservasPemdientesSegunDepósitos;
  5679.             $mailBody null;
  5680.             foreach ($reservasIniciado as $reserva) {
  5681.                 $agenteReserva $em->getRepository(User::class)->findOneById($reserva->getCreatedBy());
  5682.                 $agenteReserva $agenteReserva->getName() . ' ' $agenteReserva->getLastName();
  5683.                 $mailBody $mailBody '<br>Evento: ' $reserva->getId() . '<br>Nombre del Evento: ' $reserva->getTitle() . '<br>Agente: ' $agenteReserva '<br>Enlace al Evento: <a href="https://mantevenues.mante.solutions/venues/editsimple/' $reserva->getId() . '">"IR AL EXPEDIENTE"</a><br><br>';
  5684.             }
  5685.             if (!empty($mailBody)) {
  5686.                 $this->sendMailLot($mailAddressFrom$mailArrayTo$mailSubject$mailBody);
  5687.                 // Creamos la alerta del dia
  5688.                 $alertToday = new ReservationAlertSecondDeposit();
  5689.                 $alertToday->setAlertDate($hoy);
  5690.                 $alertToday->setMessage($mailBody);
  5691.                 $em->persist($alertToday);
  5692.                 $em->flush();
  5693.             }
  5694.         }
  5695.         // Eliminamos las alertas con mas de 6 meses de antiguedad
  5696.         foreach ($alertas as $alerta) {
  5697.             if ($alerta->getAlertDate() < $fechaLimite) {
  5698.                 $em->remove($alerta);
  5699.                 $em->flush();
  5700.             }
  5701.         }
  5702.         return true;
  5703.     }
  5704.     /**
  5705.      * Actualiza las salas y servicios de la reserva.
  5706.      */
  5707.     private function _actualizarSalasYServicios(Reservation $reserva)
  5708.     {
  5709.         $msage $this->session->get('_config')['msage'];
  5710.         // Si no es sucoe, cogemos el IVA del 21% y si lo es, entonces el del 0%
  5711.         if (!$reserva->isSucoe()) {
  5712.             $sageVatRate $this->em->getRepository(SageVatRates::class)->findOneBy(array('sageCode' => '03'));
  5713.         } else {
  5714.             $sageVatRate $this->em->getRepository(SageVatRates::class)->findOneBy(array('sageCode' => '00'));
  5715.         }
  5716.         // Coger todas las salas de la reserva
  5717.         $reservationsLounges $this->em->getRepository(ReservationLoungeSimple::class)->findByIdReservation($reserva->getId());
  5718.         foreach ($reservationsLounges as $reservationsLounge) {
  5719.             // Si el módulo de Sage está activo, asignar el artículo correspondientec
  5720.             if ($msage) {
  5721.                 $sageArticle $this->em->getRepository(SageArticle::class)->findOneBy(array('vatType' => $sageVatRate'name' => $reservationsLounge->getLoungeName()));
  5722.                 if (!$sageArticle) {
  5723.                     throw new \Exception('No se ha encontrado el artículo Sage para la sala: ' $reservationsLounge->getLoungeName());
  5724.                 }
  5725.                 $reservationsLounge->setSageArticle($sageArticle);
  5726.             }
  5727.             $reservationsLounge->setSageIva($sageVatRate);
  5728.             $this->em->persist($reservationsLounge);
  5729.         }
  5730.         // Coger todos los servicios de la reserva
  5731.         $services $this->em->getRepository(ReservationService::class)->findByReservationId($reserva->getId());
  5732.         foreach ($services as $service) {
  5733.             // Si el módulo de Sage está activo, asignar el artículo correspondiente
  5734.             if ($msage) {
  5735.                 $sageArticle $this->em->getRepository(SageArticle::class)->findOneBy(array('vatType' => $sageVatRate'name' => $service->getServiceCatName()));
  5736.                 if (!$sageArticle) {
  5737.                     throw new \Exception('No se ha encontrado el artículo Sage para el servicio: ' $service->getServiceCatName());
  5738.                 }
  5739.                 $service->setSageArticle($sageArticle);
  5740.             } else {
  5741.                 // Mantener el SageVatRate si existe, si no, ya tenemos el 21% en $sageVatRate
  5742.                 if ($service->getSageIva()){
  5743.                     $sageVatRate $this->em->getRepository(SageVatRates::class)->findOneById($service->getSageIva()->getId());
  5744.                 }
  5745.             }
  5746.             $service->setSageIva($sageVatRate);
  5747.             $this->em->persist($service);
  5748.         }
  5749.         // Persistimos los cambios
  5750.         $this->em->flush();
  5751.     }
  5752.     /**
  5753.          * Procesa los lounges simples para agruparlos por día y generar el array para el archivo.
  5754.          */
  5755.         private function processLounges(array $reservationsLoungesSimple): array
  5756.         {
  5757.             $arrayLoungesByDay = [];
  5758.             $arrayLoungesInFile = [];
  5759.             foreach ($reservationsLoungesSimple as $item) {
  5760.                 $dateStart $item->getDateStart()->format('Ymd');
  5761.                 $rank $item->getRankQuote();
  5762.                 $arrayLoungesByDay[$rank][$dateStart][] = $item;
  5763.                 ksort($arrayLoungesByDay[$rank]);
  5764.                 $fullContract '';
  5765.                 $loungeName $item->getLoungeName() ?? '';
  5766.                 
  5767.                 $isLegendsOrCobarrubias = (
  5768.                     stripos($loungeName'LEGENDS') !== false || 
  5769.                     stripos($loungeName'COBARRUBIAS') !== false
  5770.                 );
  5771.                 // Respetamos los booleanos por defecto según el espacio
  5772.                // Respetamos los booleanos de base de datos. Solo aplicamos el valor por defecto
  5773.                 // si la entidad es nueva en memoria, o si los campos en base de datos son estrictamente NULL.
  5774.                 if ($item->getId() === null || $item->isShowAudiovisualPrice() === null || $item->isShowAudiovisualPackage() === null) {
  5775.                      $showAudiovisualPrice $isLegendsOrCobarrubias;
  5776.                      $showAudiovisualPackage $isLegendsOrCobarrubias;
  5777.                 } else {
  5778.                      $showAudiovisualPrice $item->isShowAudiovisualPrice();
  5779.                      $showAudiovisualPackage $item->isShowAudiovisualPackage();
  5780.                 }
  5781.                 // =================================================================================
  5782.                 // CORRECCIÓN CLAVE: Volvemos a indexar por [$item->getIdLounge()] para evitar duplicados
  5783.                 // =================================================================================
  5784.                 $arrayLoungesInFile[$rank][$item->getIdLounge()] = [
  5785.                     'rankQuote' => $rank,
  5786.                     'idLounge' => $item->getIdLounge(),
  5787.                     'loungeName' => $loungeName,
  5788.                     'loungeImportantDescription' => $item->getImportantDescription(),
  5789.                     'loungeImportantDescGeneralText' => $item->getImportantDescGeneralText(),
  5790.                     'loungeImportantDescSchedules' => $item->getImportantDescSchedules(),
  5791.                     'loungeImportantDescParking' => $item->getImportantDescParking(),
  5792.                     'loungeDocFullContract' => $fullContract,
  5793.                     'language' => $item->getLanguage(),
  5794.                     'showAudiovisualPrice' => $showAudiovisualPrice,
  5795.                     'showAudiovisualPackage' => $showAudiovisualPackage,
  5796.                 ];
  5797.                 // =================================================================================
  5798.             }
  5799.             
  5800.             return [
  5801.                 'arrayLoungesByDay' => $arrayLoungesByDay,
  5802.                 'arrayLoungesInFile' => $arrayLoungesInFile
  5803.             ];
  5804.         }
  5805.     /**
  5806.      * Obtiene proveedores de Catering con la lógica de ordenamiento específica.
  5807.      */
  5808.     private function getCateringSuppliers(EntityManagerInterface $em): array
  5809.     {
  5810.         $caterings $em->createQueryBuilder()
  5811.             ->select('p')
  5812.             ->from(Supplier::class, 'p')
  5813.             ->where('p.tags LIKE :tags')
  5814.             ->andWhere('p.company <> :company')
  5815.             ->orderBy('p.company''ASC')
  5816.             ->setParameters([
  5817.                 'tags' => '%CATERING%'// Aseguramos el wildcard si es necesario o se mantiene estricto según lógica original
  5818.                 'company' => 'HIGO & TRIGO, S.L.'
  5819.             ])
  5820.             ->getQuery()
  5821.             ->getResult();
  5822.         // Agregamos Higo & Trigo al principio (Hardcoded ID según código original)
  5823.         $catHigoTrigo $em->getRepository(Supplier::class)->find(4765);
  5824.         if ($catHigoTrigo) {
  5825.             array_unshift($caterings$catHigoTrigo);
  5826.         }
  5827.         return $caterings;
  5828.     }
  5829.     /**
  5830.      * Lógica optimizada para facturas. Evita consultas dentro del bucle.
  5831.      */
  5832.     private function calculateInvoicesData(int $reservationIdReservation $reserva, ?Client $clientEntityManagerInterface $em): array
  5833.     {
  5834.         $invoices $em->getRepository(ReservationInvoice::class)->findByReservationId($reservationId);
  5835.         $invoicesRec $em->getRepository(ReservationInvoiceRec::class)->findByReservationId($reservationId);
  5836.         // Merge de facturas normales y rectificativas
  5837.         $allInvoicesEntities array_merge($invoices$invoicesRec);
  5838.         // --- INICIO PRE-CARGA PARA RESOLVER N+1 ---
  5839.         $depositInvoiceIds = [];
  5840.         $invoiceToRecIds = [];
  5841.         foreach ($allInvoicesEntities as $item) {
  5842.             if ($item->getType() === 'Invoice Deposit') {
  5843.                 $depositInvoiceIds[] = $item->getId();
  5844.             } elseif (in_array($item->getType(), ['Invoice Rec''Invoice Deposit Rec'], true) && $item->getId()) {
  5845.                 $invoiceToRecIds[] = $item->getInvoiceToRec();
  5846.             }
  5847.         }
  5848.         $depositInvoiceIds array_filter(array_unique($depositInvoiceIds));
  5849.         $invoiceToRecIds array_filter(array_unique($invoiceToRecIds));
  5850.         $paymentItemsByInvoiceId = [];
  5851.         $invoiceElementItemsByPaymentId = [];
  5852.         $invoicesById = [];
  5853.         if (!empty($depositInvoiceIds)) {
  5854.             $qbPayments $em->createQueryBuilder();
  5855.             $paymentItems $qbPayments->select('p')
  5856.                 ->from(ReservationPaymentsClient::class, 'p')
  5857.                 ->where($qbPayments->expr()->in('p.invoiceId'':invoiceIds'))
  5858.                 ->setParameter('invoiceIds'$depositInvoiceIds)
  5859.                 ->getQuery()
  5860.                 ->getResult();
  5861.             $paymentIds = [];
  5862.             foreach ($paymentItems as $paymentItem) {
  5863.                 // Emulamos el comportamiento de findOneBy asignando solo la primera coincidencia
  5864.                 if (!isset($paymentItemsByInvoiceId[$paymentItem->getInvoiceId()])) {
  5865.                     $paymentItemsByInvoiceId[$paymentItem->getInvoiceId()] = $paymentItem;
  5866.                     $paymentIds[] = $paymentItem->getId();
  5867.                 }
  5868.             }
  5869.             $paymentIds array_filter(array_unique($paymentIds));
  5870.             if (!empty($paymentIds)) {
  5871.                 $qbItems $em->createQueryBuilder();
  5872.                 $invoiceElementItems $qbItems->select('i')
  5873.                     ->from(ReservationInvoiceItems::class, 'i')
  5874.                     ->where($qbItems->expr()->in('i.payControlId'':paymentIds'))
  5875.                     ->setParameter('paymentIds'$paymentIds)
  5876.                     ->getQuery()
  5877.                     ->getResult();
  5878.                 $invoiceIdsToFetch = [];
  5879.                 foreach ($invoiceElementItems as $invoiceElementItem) {
  5880.                     if (!isset($invoiceElementItemsByPaymentId[$invoiceElementItem->getPayControlId()])) {
  5881.                         $invoiceElementItemsByPaymentId[$invoiceElementItem->getPayControlId()] = $invoiceElementItem;
  5882.                         $invoiceIdsToFetch[] = $invoiceElementItem->getInvoiceId();
  5883.                     }
  5884.                 }
  5885.                 $invoiceIdsToFetch array_filter(array_unique($invoiceIdsToFetch));
  5886.                 if (!empty($invoiceIdsToFetch)) {
  5887.                     $qbInvoices $em->createQueryBuilder();
  5888.                     $fetchedInvoices $qbInvoices->select('inv')
  5889.                         ->from(ReservationInvoice::class, 'inv')
  5890.                         ->where($qbInvoices->expr()->in('inv.id'':invoiceIds'))
  5891.                         ->setParameter('invoiceIds'$invoiceIdsToFetch)
  5892.                         ->getQuery()
  5893.                         ->getResult();
  5894.                     foreach ($fetchedInvoices as $inv) {
  5895.                         $invoicesById[$inv->getId()] = $inv;
  5896.                     }
  5897.                 }
  5898.             }
  5899.         }
  5900.         if (!empty($invoiceToRecIds)) {
  5901.             $qbInvoicesRec $em->createQueryBuilder();
  5902.             $fetchedInvoicesToRec $qbInvoicesRec->select('inv')
  5903.                 ->from(ReservationInvoice::class, 'inv')
  5904.                 ->where($qbInvoicesRec->expr()->in('inv.id'':invoiceToRecIds'))
  5905.                 ->setParameter('invoiceToRecIds'$invoiceToRecIds)
  5906.                 ->getQuery()
  5907.                 ->getResult();
  5908.             foreach ($fetchedInvoicesToRec as $inv) {
  5909.                 $invoicesById[$inv->getId()] = $inv;
  5910.             }
  5911.         }
  5912.         // --- FIN PRE-CARGA ---
  5913.         $sumNet 0.0;
  5914.         $sumVat 0.0;
  5915.         $sumTotal 0.0;
  5916.         $allInvoicedData = [];
  5917.         foreach ($allInvoicesEntities as $item) {
  5918.             // Lógica de Balance para Invoice Deposit utilizando datos cacheados
  5919.             if ($item->getType() === 'Invoice Deposit') {
  5920.                 $paymentItem $paymentItemsByInvoiceId[$item->getId()] ?? null;
  5921.                 if ($paymentItem) {
  5922.                     $invoiceElementItem $invoiceElementItemsByPaymentId[$paymentItem->getId()] ?? null;
  5923.                     if ($invoiceElementItem) {
  5924.                         $invoiceOfItem $invoicesById[$invoiceElementItem->getInvoiceId()] ?? null;
  5925.                         if ($invoiceOfItem?->getType() === 'Invoice') {
  5926.                             $item->setBalance(0);
  5927.                         }
  5928.                     }
  5929.                 }
  5930.             }
  5931.             // Factura rectificativa relacionada utilizando datos cacheados
  5932.             $invoiceToRec null;
  5933.             if (in_array($item->getType(), ['Invoice Rec''Invoice Deposit Rec'], true) && $item->getId()) {
  5934.                 $invoiceToRec $invoicesById[$item->getInvoiceToRec()] ?? null;
  5935.             }
  5936.             $clientInvoice = [
  5937.                 'name' => $item->getClientName(),
  5938.                 'address' => $item->getClientAddress(),
  5939.                 'clientDocument' => $item->getClientDocument(),
  5940.             ];
  5941.             $allInvoicedData[] = [
  5942.                 'dateAt' => $item->getDateAt(),
  5943.                 'type' => $item->getType(),
  5944.                 'id' => $item->getId(),
  5945.                 'invoiceToRec' => $invoiceToRec,
  5946.                 'clientType' => $item->getClientType(),
  5947.                 'reservationId' => $item->getReservationId(),
  5948.                 'number' => $item->getNumber(),
  5949.                 'totalNet' => $item->getTotalNet(),
  5950.                 'total' => $item->getTotal(),
  5951.                 'vat' => $item->getVat(),
  5952.                 'balance' => $item->getBalance(),
  5953.                 'client' => $clientInvoice,  // Reutilizamos el cliente ya cargado
  5954.                 'reservation' => $reserva// Reutilizamos la reserva ya cargada
  5955.             ];
  5956.             // Cálculos acumulativos
  5957.             $isDeposit in_array($item->getType(), ['Invoice Deposit''Invoice Deposit Rec'], true);
  5958.             if (!$isDeposit) {
  5959.                 // Las facturas rectificativas suelen tener valores negativos en DB, por lo que sumar es correcto.
  5960.                 $sumNet += $item->getTotalNet();
  5961.                 $sumVat += $item->getVat();
  5962.                 $sumTotal += $item->getTotal();
  5963.             }
  5964.             // Si es depósito, se suma 0 (no computa), por lo que no hacemos nada.
  5965.         }
  5966.         return [
  5967.             'allInvoiced' => $allInvoicedData,
  5968.             'resultados' => [
  5969.                 'totalNeto' => $sumNet,
  5970.                 'vat' => $sumVat,
  5971.                 'total' => $sumTotal,
  5972.             ]
  5973.         ];
  5974.     }
  5975.     /**
  5976.      * Filtra pagos no facturados.
  5977.      */
  5978.     private function filterUninvoicedPayments(int $reservationId, array $paymentsEntityManagerInterface $em): array
  5979.     {
  5980.         $notInvoiced = [];
  5981.         foreach ($payments as $payment) {
  5982.             // Esto sigue siendo una consulta en bucle, pero es difícil de optimizar sin cambiar la lógica de InvoiceItems.
  5983.             // Se mantiene por seguridad "sin inventar", pero idealmente InvoiceItems debería cargarse en bloque.
  5984.             $isInvoiced $em->getRepository(ReservationInvoiceItems::class)->findBy([
  5985.                 'reservationId' => $reservationId,
  5986.                 'payControlId' => $payment->getId()
  5987.             ]);
  5988.             if (empty($isInvoiced)) {
  5989.                 $notInvoiced[] = $payment;
  5990.             }
  5991.         }
  5992.         return $notInvoiced;
  5993.     }
  5994.     /**
  5995.      * Obtiene usuarios activos y añade freelancers.
  5996.      */
  5997.     private function getAllActiveUsersAndFreelancers(EntityManagerInterface $em): array
  5998.     {
  5999.         $users $em->createQueryBuilder()
  6000.             ->select('u')
  6001.             ->from(User::class, 'u')
  6002.             ->where('u.status = :status')
  6003.             ->andWhere('u.team = :team')
  6004.             ->orderBy('u.name''ASC')
  6005.             ->setParameter('status'1)
  6006.             ->setParameter('team'16)
  6007.             ->getQuery()
  6008.             ->getResult();
  6009.         $freeLances = []; // $em->getRepository(ExternalUser::class)->findAll();
  6010.         // Lcl Freelance logic removed
  6011.         return $users;
  6012.     }
  6013.     /**
  6014.      * Calcula la fecha de la próxima alerta de correo.
  6015.      */
  6016.     private function getNextMailAlertDate(int $reservationIdEntityManagerInterface $em): ?\DateTimeInterface
  6017.     {
  6018.         $alert $em->getRepository(ReservationMailAlertClient::class)->findOneByReservationId($reservationId);
  6019.         if (!$alert) {
  6020.             return null;
  6021.         }
  6022.         if (!$alert->getAlertSended()) {
  6023.             return $alert->getAlertDateTime();
  6024.         }
  6025.         if (!$alert->getCancelSended()) {
  6026.             return $alert->getCancelDateTime();
  6027.         }
  6028.         return null;
  6029.     }
  6030.     /**
  6031.      * Obtiene depósitos y calcula sumas por proforma.
  6032.      */
  6033.     private function getDepositsAndProformas(int $reservationIdEntityManagerInterface $em): array
  6034.     {
  6035.         $depositsAll $em->getRepository(ReservationDeposit::class)->findByReservationId($reservationId);
  6036.         $proformaIds = [];
  6037.         $proformas = [];
  6038.         foreach ($depositsAll as $d) {
  6039.             $p $d->getProformaDeposit();
  6040.             if ($p && !$p->getInvoice()) {
  6041.                 $pid $p->getId();
  6042.                 $proformaIds[$pid] = true;
  6043.                 $proformas[$pid] = $p;
  6044.             }
  6045.         }
  6046.         $ids array_keys($proformaIds);
  6047.         $sums = [];
  6048.         if (!empty($ids)) {
  6049.             // Asumiendo que sumsByProformaIds maneja un array vacío correctamente, si no, el if protege.
  6050.             $sums $em->getRepository(ReservationDeposit::class)->sumsByProformaIds($ids);
  6051.         }
  6052.         return [
  6053.             'depositsAll' => $depositsAll,
  6054.             'sumsByProforma' => $sums,
  6055.             'proformas' => $proformas
  6056.         ];
  6057.     }
  6058.     /**
  6059.      * Helper para parsear los formatos de hora manuales del input.
  6060.      * Devuelve array con 'hour', 'min' y 'formatted' (HH:mm).
  6061.      */
  6062.     /**
  6063.      * Resuelve el nombre del servicio y el ID del asistente.
  6064.      */
  6065.     private function resolveAgentAndName(ReservationService $service, array $dataEntityManagerInterface $em): void
  6066.     {
  6067.         // ID 15 parece ser "Personal" o similar en tu lógica de negocio
  6068.         if ($service->getServiceCatId() == 15 && array_key_exists('agent'$data)) {
  6069.             $agentId = (int) $data['agent'];
  6070.             if ($agentId 0) {
  6071.                 $user $em->getRepository(User::class)->find($agentId);
  6072.                 if ($user) {
  6073.                     $service->setName(trim($user->getName() . ' ' $user->getLastName()));
  6074.                     $service->setAssistantId($agentId);
  6075.                     return;
  6076.                 }
  6077.             }
  6078.             // Fallback si viene 'agent' pero es 0 o no se encuentra usuario
  6079.             $service->setName($data['name'] ?? null);
  6080.             $service->setAssistantId(null);
  6081.         } else {
  6082.             // No es categoría 15 o no viene agente
  6083.             $service->setName($data['name'] ?? null);
  6084.         }
  6085.     }
  6086.     /**
  6087.      * Parsea valores monetarios manejando comas y puntos.
  6088.      */
  6089.     private function parseCurrency(?string $inputfloat $fallbackbool $onlyComma false): float
  6090.     {
  6091.         if ($input === null) {
  6092.             return 0.0;
  6093.         }
  6094.         if ($onlyComma) {
  6095.             // Caso especial para comisiones: solo reemplaza coma por punto
  6096.             $val str_replace(',''.'$input);
  6097.         } else {
  6098.             // Caso general: elimina puntos (miles), cambia coma a punto (decimal)
  6099.             $val str_replace(['.'','], ['''.'], $input);
  6100.         }
  6101.         return is_numeric($val) ? (float) $val $fallback;
  6102.     }
  6103.     /**
  6104.      * Maneja la lógica compleja de sincronización para Catering y AV.
  6105.      */
  6106.     private function handleSynchronization(
  6107.         Reservation $reserva,
  6108.         ReservationService $service,
  6109.         Supplier $supplier,
  6110.         bool $mcatering,
  6111.         bool $mav,
  6112.         array $htFiles// Array de HtFile encontrados
  6113.         array $aveFiles// Array de AveFiles encontrados
  6114.         $user,
  6115.         SyncronizationsCateringService $cateringService,
  6116.         SyncronizationsAVService $avService,
  6117.         EntityManagerInterface $em,
  6118.         AppConfigManager $configManager
  6119.     ): void {
  6120.         $companyName $supplier->getCompany();
  6121.         if (!$companyName) {
  6122.             return;
  6123.         }
  6124.         $mode $configManager->getSettings()->workflow->reservationMode;
  6125.         // --- CATERING ---
  6126.         if ($mcatering) {
  6127.             // Verificamos si este proveedor es de tipo Catering buscando en SettingsCompany
  6128.             // Optimización: Usamos una consulta simple, idealmente esto se cachearía a nivel de clase si son pocos settings.
  6129.             $isCatering $em->getRepository(SettingsCompany::class)->findOneBy([
  6130.                 'businessType' => BusinessTypeSettingsCompanyConstants::CATERING,
  6131.                 'company' => $companyName
  6132.             ]);
  6133.             if ($isCatering) {
  6134.                 $dto = new SyncronizationsCateringDTO();
  6135.                 $dto->setDateStart($service->getDateInAt());
  6136.                 $dto->setDateEnd($service->getDateOutAt());
  6137.                 $dto->setReservation($reserva);
  6138.                 if (empty($htFiles)) {
  6139.                     // Crear expediente HT solo si NO estamos en modo Automático (que ya los crea al iniciar)
  6140.                     // O si estamos en modo Clásico (implícito)
  6141.                     if ($mode !== ReservationWorkflowMode::ON_RESERVATION_CREATION) {
  6142.                         $dto->setClient($reserva->getClient());
  6143.                         $dto->setClientContName($reserva->getClientContact());
  6144.                         $dto->setUser($user);
  6145.                         $dto->setTitle($reserva->getTitle());
  6146.                         $dto->setPax($reserva->getPax());
  6147.                         $dto->setDescription($reserva->getDescription());
  6148.                         $dto->setContactUnregistered($reserva->getContactUnregistered());
  6149.                         $dto->setNameContactUnregistered($reserva->getNameContactUnregistered());
  6150.                         $dto->setPhoneContactUnregistered($reserva->getPhoneContactUnregistered());
  6151.                         $cateringService->syncVenues($dto);
  6152.                     }
  6153.                 } else {
  6154.                     // Actualizar fechas
  6155.                     $cateringService->updateCateringDate($dto);
  6156.                 }
  6157.             }
  6158.         }
  6159.         // --- AUDIOVISUAL ---
  6160.         if ($mav) {
  6161.             $isAV $em->getRepository(SettingsCompany::class)->findOneBy([
  6162.                 'businessType' => BusinessTypeSettingsCompanyConstants::AUDIOVISUAL,
  6163.                 'company' => $companyName
  6164.             ]);
  6165.             if ($isAV) {
  6166.                 $dto = new SyncronizationsAVDTO();
  6167.                 $dto->setDateStart($service->getDateInAt());
  6168.                 $dto->setDateEnd($service->getDateOutAt());
  6169.                 $dto->setReservation($reserva);
  6170.                 if (empty($aveFiles)) {
  6171.                     // Crear expediente AV - Misma lógica
  6172.                     if ($mode !== ReservationWorkflowMode::ON_RESERVATION_CREATION) {
  6173.                         $dto->setClient($reserva->getClient());
  6174.                         $dto->setUser($user);
  6175.                         $dto->setTitle($reserva->getTitle());
  6176.                         $dto->setPax($reserva->getPax());
  6177.                         $dto->setDescription($reserva->getDescription());
  6178.                         $avService->syncVenues($dto);
  6179.                     }
  6180.                 } else {
  6181.                     // Actualizar fechas
  6182.                     $avService->updateAVDate($dto);
  6183.                 }
  6184.             }
  6185.         }
  6186.     }
  6187.     private function handleUnregisteredContact($formReservation $reservaUser $userEntityManagerInterface $em): void
  6188.     {
  6189.         // 1. Ahora leemos los datos directamente de la entidad Reserva
  6190.         // (Como quitamos mapped=>false, el form ya los ha puesto aquí)
  6191.         $email $reserva->getContactUnregistered();
  6192.         $name $reserva->getNameContactUnregistered();
  6193.         $phone $reserva->getPhoneContactUnregistered();
  6194.         // Obtener el objeto Cliente del formulario
  6195.         $client $form->get('client')->getData();
  6196.         $contactHandled false;
  6197.         // 2. Si hay datos escritos a mano, tienen PRIORIDAD
  6198.         if ($client && !empty($email) && !empty($name)) {
  6199.             // Verificamos si ya existe ese email en la tabla de contactos
  6200.             $existClientContact $em->getRepository(ClientContact::class)->findOneBy(['email' => $email]);
  6201.             if ($existClientContact) {
  6202.                 // CASO A: Ya existía -> Solo vinculamos su ID
  6203.                 $reserva->setClientContact($existClientContact->getId());
  6204.             } else {
  6205.                 // CASO B: No existía -> Lo creamos en la tabla de contactos para el futuro
  6206.                 $newContact = new ClientContact();
  6207.                 $newContact->setClientId($client->getId());
  6208.                 $newContact->setTypeclient('Business Travel');
  6209.                 $newContact->setAssignedAgent($user->getId());
  6210.                 $newContact->setName($name);
  6211.                 $newContact->setLastName('');
  6212.                 $newContact->setPosition(''); // Evitamos error SQL "position cannot be null"
  6213.                 $newContact->setSituation('CLIENT');
  6214.                 $newContact->setEmail($email);
  6215.                 $newContact->setPhone($phone ?? '');
  6216.                 // Auditoría
  6217.                 $newContact->setCreatedId($user->getId());
  6218.                 $newContact->setUpdatedId($user->getId());
  6219.                 if (method_exists($newContact'setCreated')) {
  6220.                     $newContact->setCreated(new \DateTime());
  6221.                 }
  6222.                 $em->persist($newContact);
  6223.                 $em->flush(); // Guardamos para obtener el ID
  6224.                 // Vinculamos el nuevo ID a la reserva
  6225.                 $reserva->setClientContact($newContact->getId());
  6226.             }
  6227.             $contactHandled true;
  6228.         }
  6229.         // 3. Si NO escribió nada a mano, miramos el desplegable (campo oculto clientContact)
  6230.         if (!$contactHandled) {
  6231.             $manualContactId $form->get('clientContact')->getData();
  6232.             // Si viene un ID válido del selector
  6233.             if (!empty($manualContactId) && $manualContactId !== '0') {
  6234.                 $reserva->setClientContact((int) $manualContactId);
  6235.             }
  6236.         }
  6237.     }
  6238.     /**
  6239.      * Lógica específica cuando el estado es "Bloqueo"
  6240.      */
  6241.     private function handleBlockStatus($formReservation $reservaUser $userEntityManagerInterface $em): void
  6242.     {
  6243.         $status $reserva->getStatus();
  6244.         if ($status === 'Bloqueo') {
  6245.             // 1. Calcular fecha límite si no existe
  6246.             if (!$reserva->getDays()) {
  6247.                 $daysBlock $reserva->getDaysBlock() ?? 7// Valor por defecto
  6248.                 $dateLimit = (new \DateTime())->modify("+$daysBlock days");
  6249.                 $reserva->setDays($dateLimit);
  6250.             }
  6251.             // 2. Envío de Correos (Simplificado manteniendo tu lógica)
  6252.             // NOTA: Aquí deberías refactorizar para usar un Servicio de Mailing, 
  6253.             // pero mantengo la llamada a $this->sendMail() y lógica local por restricción del prompt.
  6254.             if ($reserva->getClient() || $reserva->getClientContact() || $form->get('contactUnregistered')->getData()) {
  6255.                 // ... Tu lógica de envío de correo de bloqueo ...
  6256.                 // $this->sendMail(...) 
  6257.             }
  6258.             // 3. Modificar fecha de notificación (Next Mail Alert)
  6259.             $newDateAlert $form->get('dateNextMailAlert')->getData(); // Campo mapped => false o true en tu type nuevo
  6260.             if ($newDateAlert && $newDateAlert > new \DateTime('now')) {
  6261.                 $alertRepo $em->getRepository(ReservationMailAlertClient::class);
  6262.                 $nextAlert $alertRepo->findOneByReservationId($reserva->getId());
  6263.                 if ($nextAlert) {
  6264.                     $newAlertDt = clone $newDateAlert;
  6265.                     $newAlertDt->setTime(150);
  6266.                     if ($nextAlert->getAlertSended() == 0) {
  6267.                         $newCancelDt = (clone $newAlertDt)->modify('+2 days');
  6268.                         $nextAlert->setAlertDateTime($newAlertDt);
  6269.                         $nextAlert->setCancelDateTime($newCancelDt);
  6270.                     } else {
  6271.                         // Solo modificar cancelación
  6272.                         $nextAlert->setCancelDateTime($newAlertDt);
  6273.                     }
  6274.                     $em->persist($nextAlert);
  6275.                 }
  6276.             }
  6277.         } else {
  6278.             // Si NO es bloqueo, limpiar la fecha límite
  6279.             if ($reserva->getDays()) {
  6280.                 $reserva->setDays(null);
  6281.             }
  6282.         }
  6283.     }
  6284.     /**
  6285.      * Maneja el envío de correo de cancelación si existía una alerta previa
  6286.      */
  6287.     private function handleCancellationAlert(int $idReservation $reservaEntityManagerInterface $em): void
  6288.     {
  6289.         $alert $em->getRepository(ReservationMailAlertClient::class)->findOneByReservationId($id);
  6290.         if ($alert) {
  6291.             $agent $em->getRepository(User::class)->find($alert->getAgentId());
  6292.             // Configurar datos del correo
  6293.             $mailTo $alert->getClientMail();
  6294.             $mailFrom $alert->getAgentMail();
  6295.             $subject 'Notificación de Bloqueo - Reserva de espacio en Venues';
  6296.             $body 'Estimado cliente,<br><br>Nos ponemos en contacto con usted para informarle de que su reserva ha sido cancelada.<br><br>Reserva: ' $reserva->getId() . ' - ' $reserva->getTitle();
  6297.             // Llamada a tu método existente
  6298.             // $this->sendMail($mailFrom, $mailTo, $subject, $body);
  6299.             // Actualizar la entidad de alerta
  6300.             $alert->setOldReservationId($alert->getReservationId());
  6301.             $alert->setReservationId(0);
  6302.             $alert->setCancelSended(1);
  6303.             $em->persist($alert);
  6304.         }
  6305.     }
  6306.     /**
  6307.      * Recalcula fecha inicio y fin basado en las salas (Lounges)
  6308.      */
  6309.     /**
  6310.      * Gestiona la creación o actualización del DocContract basado en el modelo seleccionado.
  6311.      */
  6312.     private function handleContractLogic(
  6313.         ?DocContractModel $selectedModel,
  6314.         ?DocContract $currentDocContract,
  6315.         Reservation $reserva,
  6316.         User $user,
  6317.         EntityManagerInterface $em
  6318.     ): void {
  6319.         // Si no se seleccionó nada, no hacemos nada (o podrías decidir borrar el contrato si existía)
  6320.         if (!$selectedModel) {
  6321.             return;
  6322.         }
  6323.         // Verificamos si ha cambiado el modelo o si no existía contrato previo
  6324.         $modelHasChanged = !$currentDocContract || ($currentDocContract->getModel()?->getId() !== $selectedModel->getId());
  6325.         if ($modelHasChanged) {
  6326.             // Opción A: Actualizar el contrato existente (para mantener el ID y no llenar la BD de basura)
  6327.             // Opción B: Crear uno nuevo siempre (si necesitas histórico estricto). 
  6328.             // Usaremos Opción A (Actualizar o Crear si no existe) por eficiencia.
  6329.             if (!$currentDocContract) {
  6330.                 $currentDocContract = new DocContract();
  6331.                 $currentDocContract->setReservation($reserva);
  6332.                 $currentDocContract->setCreatedAt(new \DateTime());
  6333.                 $currentDocContract->setCreatedId($user->getId());
  6334.             }
  6335.             // Actualizamos los datos con la nueva plantilla
  6336.             $currentDocContract->setModel($selectedModel);
  6337.             // Copiamos el texto de la plantilla al contrato real
  6338.             // Ajusta 'getContractualDocument()' al método real de tu entidad DocContractModel
  6339.             if (method_exists($selectedModel'getContractualDocument')) {
  6340.                 $currentDocContract->setContractualDocument($selectedModel->getContractualDocument());
  6341.             }
  6342.             // Datos de auditoría / actualización
  6343.             $currentDocContract->setUpdatedAt(new \DateTime());
  6344.             $currentDocContract->setUpdatedId($user->getId());
  6345.             $currentDocContract->setDateAt(new \DateTime()); // Fecha del contrato = ahora
  6346.             $em->persist($currentDocContract);
  6347.         }
  6348.     }
  6349. }