<?php
namespace App\Controller;
use DateTime;
use App\Entity\Booking;
use App\Service\Mailjet;
use App\Service\SwiklyService;
use App\Form\BookingType;
use App\Service\StaticData;
use App\Service\CheckRecaptcha;
use App\Entity\ProcessLogs;
use App\Form\CheckAvailabilityType;
use App\Repository\BookingRepository;
use Symfony\Component\Form\FormError;
use App\Repository\PageHeaderRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Repository\BookingConstraintRepository;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use App\Repository\BookingConstraintSaisonRepository;
use App\Repository\BookingContractRepository;
use App\Repository\BookingMailRepository;
use DateTimeImmutable;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Spipu\Html2Pdf\Html2Pdf;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Gestion des réservation et des disponibilités
*/
class BookingController extends AbstractController
{
private $manager;
private $statics;
private $pageRepo;
private $constraint;
private $translator;
public function __construct(EntityManagerInterface $manager, TranslatorInterface $translator, StaticData $statics, PageHeaderRepository $pageRepo, BookingConstraintRepository $bookingConstraintRepo)
{
$this->manager = $manager;
$this->statics = $statics->getStaticData();
$this->pageRepo = $pageRepo;
$this->constraint = $bookingConstraintRepo->findOneBy([]);
$this->translator = $translator;
}
/**
* Permet de prendre en charge une réservation
*
* @Route("/{_locale}/booking", name="booking_index")
*
* @param Request $request
* @param CheckRecaptcha $recaptcha
* @param PageHeaderRepository $pageRepo
* @param BookingConstraintRepository $bookingConstraintRepo
* @return Response
*/
public function index(Request $request, CheckRecaptcha $recaptcha, BookingConstraintRepository $bookingConstraintRepo, BookingContractRepository $bookingContractRepo, Session $session, BookingRepository $bookingRepo, BookingMailRepository $bookingMailRepo, SwiklyService $swiklyService): Response
{
# Variables de travail
$page = $this->pageRepo->findOneBy(['page' => 'booking']);
$locale = $request->getLocale();
$constraint = $this->constraint;
$contract = $bookingContractRepo->findOneBy([]);
$endDate = $this->getEndDate();
if (is_string($endDate)) {
$endDate = DateTime::createFromFormat('d/m/Y', $endDate);
}
# Variables du formulaire
$bookingEntity = new Booking();
# Inserssion de données en provenance d'une autre page
if (array_key_exists('startDate', $_GET)) {
$startDate = DateTime::createFromFormat('d/m/Y', $_GET['startDate']);
$endDate = DateTime::createFromFormat('d/m/Y', $_GET['endDate']);
$bookingEntity
->setStartDate($startDate)
->setEndDate($endDate)
->setNumber($_GET['number']);
}
$bookingForm = $this->createForm(BookingType::class, $bookingEntity);
$bookingForm->handleRequest($request);
# Soumission du formulaire
if ($bookingForm->isSubmitted() && $bookingForm->isValid()) {
define('SITE_KEY', '6LecwkQsAAAAAJ2fiCGD_CZeXV-v5UlIpBG57OmE');
define('SECRETE_KEY', '6LecwkQsAAAAAEPV_YSvd_jWoaaKZG4ja_l4PS6c');
# Google Recaptcha
if ($recaptcha->check($_POST['booking-recaptcha_response'], SECRETE_KEY)) {
# Récupération des données
$data = $bookingForm->getData();
# Formatage des données
# Formatage des dates selectionnées par le client
$formatedStartDate = str_replace('/', '-', date_format($data->getStartDate(), 'd/m/Y'));
$formatedEndDate = str_replace('/', '-', date_format($data->getEndDate(), 'd/m/Y'));
// $formatedStartDate = str_replace('/', '-', $data->getStartDate());
$startDate = new DateTime($formatedStartDate);
$startDate1 = new DateTime($formatedStartDate);
$startDate2 = new DateTime($formatedStartDate);
// $formatedEndDate = str_replace('/', '-', $data->getEndDate());
$endDate = new DateTime($formatedEndDate);
$now = new DateTime();
$uid = "R" . date('U');
# On test si on se trouve dans le cas d'une reservation iminente : si aujourd'hui est supérieur la start date moins le delai donnée pour regler le reliquat
if (date('U', strtotime($now->format('Y-m-d'))) >= date('U', strtotime('-' . ($constraint->getBalancePaymentDeadline() + 10) . ' day', date('U', strtotime($startDate->format('Y-m-d')))))) {
# On défini qu'il s'agit d'une reservation iminente et on change l'etat des acompte pour ne pas envoi d'alerte d'acompte dans ce cas de figure
$isSoonBooking = true;
$isAdvancePayed = true;
$advanceAlerte1 = true;
$advanceAlerte2 = true;
# On défini la deadlines de paiement : now + délai de paiement pour réservation iminente (ex : now + 3)
$paymentDelay = $constraint->getSoonBookingPaymentDelay();
$paymentDeadline = $now->modify('+' . $paymentDelay . ' day');
$advancePaymentDeadline = $paymentDeadline;
$balancePaymentDeadline = $paymentDeadline;
$cautionPaymentDeadline = $paymentDeadline;
# On récupère le mail
$recapMail = $bookingMailRepo->findOneBy(['title' => 'Récapitulatif : Réservation imminente']);
} else {
$isSoonBooking = false;
$isAdvancePayed = false;
$advanceAlerte1 = false;
$advanceAlerte2 = false;
# On défini les deadlines
$advancePaymentDeadline = $now->modify('+' . $constraint->getAdvancePaymentDeadline() . ' day');
$balancePaymentDeadline = $startDate1->modify('-' . $constraint->getBalancePaymentDeadline() . ' day');
$cautionPaymentDeadline = $now->modify('+' . $constraint->getCautionPaymentDelay() . ' day');
# On récupère le mail
$recapMail = $bookingMailRepo->findOneBy(['title' => 'Récapitulatif : Réservation classique']);
}
$bookingEntity
->setUniqId($uid)
->setStartDate(new DateTime($formatedStartDate))
->setEndDate(new DateTime($formatedEndDate))
->setDeposit($constraint->getDeposit())
->setAdvancePaymentDeadline($advancePaymentDeadline)
->setPaymentMethod($data->getPaymentMethod())
->setBalancePaymentDeadline($balancePaymentDeadline)
->setCautionPaymentDeadline($cautionPaymentDeadline)
->setBookingConstraint($constraint)
->setIsForSoon($isSoonBooking)
->setIsAdvancePayed($isAdvancePayed)
->setIsAdvancePaymentAlert1($advanceAlerte1)
->setIsAdvancePaymentAlert2($advanceAlerte2)
->setTracking(true)
->setlocale($locale)
->setContract('contrat-' . $uid . '.pdf');
# On ajoute une réduction si il s'agit d'un long séjour
if ($constraint->getLongStayDiscount() > 0 && $bookingEntity->getDuration() >= 7) {
$bookingEntity->setDiscount($constraint->getLongStayDiscount());
}
### Vérification de la validité de informations soumises avec le formulaire
# On test si la date de départ est supérieure à la date d'arrivé
if (strtotime($formatedStartDate) > strtotime($formatedEndDate)) {
# On créer l'erreur
$bookingForm->get('startDate')->addError(new FormError($this->translator->trans("Vous ne pouvez pas partir avant d'être arrivé")));
$bookingForm->get('endDate')->addError(new FormError($this->translator->trans("Vous ne pouvez pas partir avant d'être arrivé")));
# Flash
$this->addFlash(
'warning',
$this->translator->trans("Vous ne pouvez pas partir avant d'être arrivé")
);
# Check si les dates choisies sont disponibles
} elseif (!$bookingEntity->isBookableDates()) {
# On créer l'erreur
$bookingForm->get('startDate')->addError(new FormError($this->translator->trans('Les dates choisies ne sont pas disponibles')));
$bookingForm->get('endDate')->addError(new FormError($this->translator->trans('Les dates choisies ne sont pas disponibles')));
# Flash
$this->addFlash(
'warning',
$this->translator->trans("Les dates que vous avez choisi ne sont pas disponibles.")
);
} elseif (strtotime($formatedStartDate) >= strtotime($endDate->format('Y-m-d'))) {
# On créer l'erreur
$bookingForm->get('startDate')->addError(new FormError($this->translator->trans('Les dates choisies ne sont pas disponibles')));
$bookingForm->get('endDate')->addError(new FormError($this->translator->trans('Les dates choisies ne sont pas disponibles')));
# Flash
$this->addFlash(
'warning',
$this->translator->trans("Les dates que vous avez choisi ne sont pas disponibles.")
);
} else {
# Préparation des données à envoyer au différent template
$statics = $this->statics['data'];
# Enregistrement de la réservation en BDD
$this->manager->persist($bookingEntity);
# SWIKLY GENERATION (Moved here to ensure entity is fully hydrated)
# Generate link for ALL bookings so they can pay deposit immediately if they wish.
if (!$bookingEntity->getSwiklyUrl()) {
error_log("Attempting to create Swikly deposit for booking UID: " . $bookingEntity->getUniqId());
$successUrl = $this->generateUrl('swikly_accept', ['uid' => $bookingEntity->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$errorUrl = $this->generateUrl('swikly_decline', ['uid' => $bookingEntity->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$res = $swiklyService->createDeposit($bookingEntity, $successUrl, $errorUrl);
error_log("Swikly Response: " . print_r($res, true));
if ($res && isset($res['accept_url'])) {
$bookingEntity->setSwiklyUrl($res['accept_url']);
$bookingEntity->setSwiklyRequestId($res['swik_id'] ?? null);
// No flush needed here as flush comes right after
} elseif (isset($res['error'])) {
$this->addFlash('danger', 'Erreur création caution Swikly : ' . $res['error']);
} else {
$this->addFlash('danger', 'Erreur création caution Swikly : Réponse invalide.');
}
}
$this->manager->flush();
# Gestion du contrat de location
$templateContract_bailleur = $this->replaceVar($contract->translate($locale)->getContent(), $bookingEntity, $constraint, "bailleur");
$templateContract_locataire = $this->replaceVar($contract->translate($locale)->getContent(), $bookingEntity, $constraint, "locataire");
$contractMaker_bailleur = $this->makePdf($uid, $templateContract_bailleur, $request, 'bailleur');
$contractMaker_locataire = $this->makePdf($uid, $templateContract_locataire, $request, 'locataire');
$contract_bailleur = base64_encode(file_get_contents('/home/maxappu/www/gite-colombine.fr/v3/public/file/contrats/contrat-' . $uid . '-bailleur.pdf'));
$contract_locataire = base64_encode(file_get_contents('/home/maxappu/www/gite-colombine.fr/v3/public/file/contrats/contrat-' . $uid . '-locataire.pdf'));
## Envoi d'email MailJet
# Client
$mailjet = new Mailjet();
$mail_content = $this->replaceVar($recapMail->translate($locale)->getContent(), $bookingEntity, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $data->getEmail(), $data->getFirstName() . " " . $data->getLastName(), $recapMail->translate($locale)->getSubject(), $mail_content, $contract_locataire, $bookingEntity, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content = $this->renderView('components/mail/_booking.html.twig', compact('data', 'statics', 'bookingEntity', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $data->getFirstName() . " " . $data->getLastName(), "Réservation", $mail_content, $contract_bailleur, $bookingEntity, 7650701);
# Flash
$this->addFlash(
'success',
$this->translator->trans("Réservation enregistrée")
);
# Redirection vers une page de validation reprennant les details de la réservation
return $this->redirectToRoute('booking_validation', [
'uid' => $bookingEntity->getUniqId()
]);
}
} else {
# Flash
$this->addFlash(
'warning',
$this->translator->trans("Erreur liée au Recaptcha...")
);
# Redirection sur la page de validation de réservation
return $this->render('booking/index.html.twig', [
'statics' => $this->statics['data'],
'page' => $page,
'constraint' => $constraint,
'endDate' => $endDate,
'bookingForm' => $bookingForm->createView()
]);
}
}
# Redirection sur la page de validation de réservation
return $this->render('booking/index.html.twig', [
'statics' => $this->statics['data'],
'page' => $page,
'constraint' => $constraint,
'endDate' => $endDate,
'bookingForm' => $bookingForm->createView()
]);
}
/**
* Permet de check la disponibilité
*
* @Route("/{_locale}/check-availability", name="booking_check_avail")
*
* @param BookingConstraintRepository $bookingConstraintRepo
* @return void
*/
public function checkAvailability(BookingConstraintRepository $bookingConstraintRepo, Request $request)
{
# Variables de travail
$constraint = $bookingConstraintRepo->findOneBy([]);
# Variables du formulaire
$bookingEntity = new Booking();
$bookingForm = $this->createForm(CheckAvailabilityType::class, $bookingEntity);
$bookingForm->handleRequest($request);
# Soumission du formulaire
if ($bookingForm->isSubmitted()) {
# Récupération des données
$data = $bookingForm->getData();
# Formatage des dates selectionnées par le client
$formatedStartDate = str_replace('/', '-', date_format($data->getStartDate(), 'd/m/Y'));
$formatedEndDate = str_replace('/', '-', date_format($data->getEndDate(), 'd/m/Y'));
# Insertion des donnée formatées dans l'entity
$bookingEntity
->setStartDate(new DateTime($formatedStartDate))
->setEndDate(new DateTime($formatedEndDate))
->setDeposit($constraint->getDeposit() / 100)
->setBookingConstraint($constraint);
# On test si la date de départ est supérieure à la date d'arrivé
if ($data->getStartDate() > $data->getEndDate()) {
# Ajax Flash
$flashbag = [
'label' => "warning",
'title' => "Oups...",
'message' => $this->translator->trans("Vous ne pouvez pas partir avant d'être arrivé") . ' <i class="fas fa-smile-wink"></i> <br> <strong>' . $data->getStartDate()->format("d/m/Y") . '</strong> < <strong>' . $data->getEndDate()->format("d/m/Y") . '</strong>',
'btnText' => $this->translator->trans("Je recommence"),
'btnPath' => "#"
];
return $this->render('components/flash/ajax_check_avail.html.twig', [
'flashbag' => $flashbag,
]);
}
# On test si le client essaye de reservé pour une date anterieur ou trop proche d'aujourd'hui
$minDate = (new \DateTime())->modify('+1 day')->setTime(0, 0, 0);
if ($data->getStartDate() < $minDate || $data->getEndDate() < $minDate) {
# Ajax Flash
$flashbag = [
'label' => "warning",
'title' => $this->translator->trans("Bien essayé..."),
'message' => $data->getStartDate()->format('d/m/Y') . " " . $data->getEndDate()->format('d/m/Y'),
'btnText' => $this->translator->trans("Je recommence"),
'btnPath' => "#"
];
return $this->render('components/flash/ajax_check_avail.html.twig', [
'flashbag' => $flashbag,
]);
}
# Check si les dates choisies sont disponibles
if (!$bookingEntity->isBookableDates()) {
# Ajax Flash
$flashbag = [
'label' => "warning",
'title' => $this->translator->trans("Désolé..."),
'message' => $this->translator->trans("La période du") . " <strong>" . $data->getStartDate()->format('d/m/Y') . "</strong> " . $this->translator->trans("au") . " <strong>" . $data->getEndDate()->format('d/m/Y') . "</strong> " . $this->translator->trans("pour") . " <strong>" . $data->getNumber() . "</strong> " . $this->translator->trans("personnes n'est pas disponible à la réservation") . ".",
'btnText' => $this->translator->trans("Je recommence"),
'btnPath' => "#"
];
return $this->render('components/flash/ajax_check_avail.html.twig', [
'flashbag' => $flashbag,
]);
}
# Check si le nombre de personnes ne dépasse pas la limite
if ($data->getNumber() > $constraint->getMaxNumber()) {
# Ajax flash
$flashbag = [
'label' => "warning",
'title' => "Oups...",
'message' => $this->translator->trans("Vous avez dépassé le nombre maximum de personnes") . " <br> " . $this->translator->trans("Le nombre maximum est de") . " " . $constraint->getMaxNumber() . " " . $this->translator->trans("personnes") . "",
'btnText' => $this->translator->trans("Je recommence"),
'btnPath' => "#"
];
return $this->render('components/flash/ajax_check_avail.html.twig', [
'flashbag' => $flashbag,
]);
}
# Sinon, validation du checking
# Ajax flash
$flashbag = [
'label' => "success",
'title' => $this->translator->trans("C'est bon"),
'message' => $this->translator->trans("La période du") . " <strong>" . $data->getStartDate()->format('d/m/Y') . "</strong> " . $this->translator->trans("au") . " <strong>" . $data->getEndDate()->format('d/m/Y') . "</strong> " . $this->translator->trans("pour") . " <strong>" . $data->getNumber() . "</strong> " . $this->translator->trans("personnes est disponible à la réservation") . ".",
'btnText' => $this->translator->trans("Je réserve"),
'btnPath' => $this->generateUrl('booking_index', [
'startDate' => $data->getStartDate()->format('d/m/Y'),
'endDate' => $data->getEndDate()->format('d/m/Y'),
'number' => $data->getNumber()
])
];
return $this->render('components/flash/ajax_check_avail.html.twig', [
'flashbag' => $flashbag,
]);
} else {
return $this->json(false);
}
}
/**
* Affiche la page de validation d'une réservation
*
* @Route("/{_locale}/booking/{uid}", name="booking_validation")
*
* @param Booking $booking
*/
public function validation($uid, Request $request, BookingRepository $bookingRepo, BookingConstraintRepository $bookingConstraintRepo, BookingMailRepository $bookingMailRepo)
{
$page = $this->pageRepo->findOneBy(['page' => 'validation']);
$booking = $bookingRepo->findOneBy(["uniqId" => $uid]);
$constraint = $bookingConstraintRepo->findOneBy([]);
$locale = $request->getLocale();
if ($booking->getIsForSoon() == true) {
# On récupère le contenu de la page de validation
$validationContent = $bookingMailRepo->findOneBy(['title' => 'Validation : Réservation imminente']);
} else {
# On récupère le contenu de la page de validation
$validationContent = $bookingMailRepo->findOneBy(['title' => 'Validation : Réservation classique']);
}
return $this->render('booking/validation.html.twig', [
'statics' => $this->statics['data'],
'page' => $page,
'booking' => $booking,
'constraint' => $constraint,
'content' => $this->replaceVar($validationContent->translate($locale)->getContent(), $booking, $constraint)
]);
}
/**
* Permet de connaitre la saison de la réservation
*
* @Route("/booking/get-saison", name="booking_get_saison")
*
* @return JsonResponce
*/
public function checkSaison(BookingConstraintSaisonRepository $bookingConstraintSaisonRepo)
{
if (array_key_exists('start', $_GET)) {
$formatedStartDate = date('Y-m-d', strtotime($_GET['start']));
$formatedEndDate = date('Y-m-d', strtotime($_GET['end']));
$start = date('U', strtotime($formatedStartDate));
$end = date('U', strtotime($formatedEndDate));
$bookingDays = [
'start' => $start,
'end' => $end
];
$saisonConstraints = $bookingConstraintSaisonRepo->findAll();
$saisons = $this->getSaison($bookingDays);
$temp = [];
$temp['count'] = 0;
$temp['price'] = 0;
foreach ($saisonConstraints as $saisonConstraint) {
foreach ($saisons as $key => $saison) {
# On récupère les saisons dans les quel on se trouve
if ($saisonConstraint->translate('fr')->getTitle() == $saison['saison']) {
# On incrémente le prix et le nombre de jour à chaque boucle
$temp['count'] += 1;
$temp['price'] += $saisonConstraint->getPrice();
}
}
}
$mediumPrice = ceil($temp['price'] / $temp['count']);
return $this->json([
'price' => $mediumPrice
]);
}
}
public function getSaison($bookingDays)
{
$saisons = $this->constraint->getSaisons();
$periods_days = [];
foreach ($saisons as $key => $saison) {
foreach ($saison->getPeriods() as $key => $period) {
$resultat = range(
$period->getStartDate()->getTimestamp(),
$period->getEndDate()->getTimestamp(),
24 * 60 * 60
);
$days = array_map(function ($dayTimestamp) {
return new \DateTime(date('Y-m-d', $dayTimestamp));
}, $resultat);
$periods_days[$saison->translate('fr')->getTitle()][$key] = $days;
}
}
$resultat = range(
$bookingDays['start'],
$bookingDays['end'],
24 * 60 * 60
);
$bookingDays = array_map(function ($dayTimestamp) {
return new \DateTime(date('Y-m-d', $dayTimestamp));
}, $resultat);
$formatDays = function ($day) {
return $day->format('Y-m-d');
};
//Tableau des strings de mes journées à reserver
$daysToReserve = array_map($formatDays, $bookingDays);
//Tableau des jours diférentes saisons
foreach ($periods_days as $saison_key => $array) {
foreach ($array as $key => $item) {
$saisonsDays[$saison_key][$key] = array_map($formatDays, $item);
}
}
//Pour chaques journées à reserver je regarde si elle se trouve dans les journées d'une saison
$temp = [];
foreach ($daysToReserve as $day) {
foreach ($saisonsDays as $saison_key => $saison) {
foreach ($saison as $key => $item) {
if (array_search($day, $item) !== false) {
$temp[] = [
'day' => $day,
'saison' => $saison_key,
];
}
}
}
}
return $temp;
}
/**
* CRONJOB
* Permet de vérifier l'état des paiements pour chaque réservation
*
* @Route("/booking/check-payment", name="booking_check_payment")
*/
public function checkPayments(BookingRepository $bookingRepo, BookingMailRepository $bookingMailRepo, SwiklyService $swiklyService)
{
$now = date('Y-m-d');
$bookings = $bookingRepo->findFutures($now);
$statics = $this->statics['data'];
$logs = [];
$logs['advance']['title'] = 'CRON du paiement de l\'acompte';
$logs['balance']['title'] = 'CRON du paiement du reliquat';
$logs['caution']['title'] = 'CRON du paiement du dépôt';
foreach ($bookings as $key => $booking) {
$advancePaymentDeadline = $booking->getAdvancePaymentDeadline();
$balancePaymentDeadline = $booking->getBalancePaymentDeadline();
$cautionPaymentDeadline = $booking->getCautionPaymentDeadline();
$isForSoon = $booking->getIsForSoon();
$bookingCreatedAt = $booking->getCreatedAt();
$constraint = $booking->getBookingConstraint();
### On check si le tracking est activé sur la réservation
if ($booking->getTracking() == true && date('U', strtotime($now)) < date('U', strtotime($booking->getStartDate()->format('Y-m-d')))) {
### Alerte 1 acompte
# On check si il s'agit d'une reservation imminente et si les alerte n'ont pas déja été envoyées
if ($booking->getIsAdvancePaymentAlert1() != true && $booking->getIsAdvancePayed() != true && $isForSoon != true) {
# Pour chaque reservation on vérifie si la advancePaymentDeadline/3 est dépassée pour envoyer une 1ere alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($advancePaymentDeadline->format('Y-m-d'))) - ((ceil($constraint->getAdvancePaymentDeadline() / 3) * 86400)))) {
# Logs de process
$logs['advance'][1][$key]['process'] = 'Vérification N°1 du paiement de l\'accompte';
$logs['advance'][1][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte acompte N°1']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_advance_alert_1_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
$logs['advance'][1][$key]['content'] = $mail_content_c;
$booking->setIsAdvancePaymentAlert1(true);
$this->manager->persist($booking);
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['advance']['title'])
->setProcess($logs['advance'][1][$key]['process'])
->setReference($logs['advance'][1][$key]['reference'])
->setContent($logs['advance'][1][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
### Alerte 2 acompte
if ($booking->getIsAdvancePaymentAlert2() != true && $booking->getIsAdvancePaymentAlert1() == true && $booking->getIsAdvancePayed() != true && $isForSoon != true) {
# Pour chaque reservation on vérifie si la advancePaymentDeadline est dépasser pour envoyer une 1ere alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($advancePaymentDeadline->format('Y-m-d'))) + 86400)) {
# Logs de process
$logs['advance'][2][$key]['process'] = 'Vérification N°2 du paiement de l\'accompte';
$logs['advance'][2][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte acompte N°2']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_advance_alert_2_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
$logs['advance'][2][$key]['content'] = $mail_content_c;
$booking->setIsAdvancePaymentAlert2(true);
$this->manager->persist($booking);
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['advance']['title'])
->setProcess($logs['advance'][2][$key]['process'])
->setReference($logs['advance'][2][$key]['reference'])
->setContent($logs['advance'][2][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
### Alerte 1 caution
if ($booking->getIsCautionPaymentAlert1() != true && $booking->getIsCautionPayed() != true && $isForSoon == false) {
# Pour chaque reservation on vérifie si la cautionPaymentDeadline est dépassée pour envoyer une 1ere alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($cautionPaymentDeadline->format('Y-m-d'))) - ((ceil($constraint->getCautionPaymentDelay() / 3) * 86400)))) {
# Logs de process
$logs['caution'][1][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte caution N°1']);
# SWIKLY GENERATION
if (!$booking->getSwiklyUrl()) {
$successUrl = $this->generateUrl('swikly_accept', ['uid' => $booking->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$errorUrl = $this->generateUrl('swikly_decline', ['uid' => $booking->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$res = $swiklyService->createDeposit($booking, $successUrl, $errorUrl);
if ($res && isset($res['accept_url'])) {
$booking->setSwiklyUrl($res['accept_url']);
$booking->setSwiklyRequestId($res['swik_id'] ?? null);
$this->manager->persist($booking);
$this->manager->flush(); // Flush explicitly to save the link
}
}
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_caution_alert_1_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['caution'][1][$key]['process'] = 'Vérification N°1 du paiement de la caution';
$logs['caution'][1][$key]['content'] = $mail_content_c;
# Changement d'état
$booking->setIsCautionPaymentAlert1(true);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['caution']['title'])
->setProcess($logs['caution'][1][$key]['process'])
->setReference($logs['caution'][1][$key]['reference'])
->setContent($logs['caution'][1][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
### Alerte 2 caution
if ($booking->getIsCautionPaymentAlert2() != true && $booking->getIsCautionPayed() != true && $isForSoon == false) {
# Pour chaque reservation on vérifie si la cautionPaymentDeadline est dépassée pour envoyer une 2eme alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($cautionPaymentDeadline->format('Y-m-d'))))) {
# Logs de process
$logs['caution'][2][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte caution N°2']);
# SWIKLY GENERATION (Reuse or create if missing)
if (!$booking->getSwiklyUrl()) {
$successUrl = $this->generateUrl('swikly_accept', ['uid' => $booking->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$errorUrl = $this->generateUrl('swikly_decline', ['uid' => $booking->getUniqId()], UrlGeneratorInterface::ABSOLUTE_URL);
$res = $swiklyService->createDeposit($booking, $successUrl, $errorUrl);
if ($res && isset($res['accept_url'])) {
$booking->setSwiklyUrl($res['accept_url']);
$booking->setSwiklyRequestId($res['swik_id'] ?? null);
$this->manager->persist($booking);
$this->manager->flush();
}
}
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_caution_alert_2_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['caution'][2][$key]['process'] = 'Vérification N°2 du paiement de la caution';
$logs['caution'][2][$key]['content'] = $mail_content_c;
# Changement d'état
$booking->setIsCautionPaymentAlert1(true);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['caution']['title'])
->setProcess($logs['caution'][2][$key]['process'])
->setReference($logs['caution'][2][$key]['reference'])
->setContent($logs['caution'][2][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
### Alerte 1 reliquat
if ($booking->getIsBalancePaymentAlert1() != true && $booking->getIsBalancePayed() != true) {
# Si il s'agit d'une reservation iminente
if ($isForSoon == true) {
# On vérifie si nous sommes à la deadline de paiement du montant total
if ((date('U', strtotime($now))) > (date('U', strtotime($balancePaymentDeadline->format('Y-m-d'))))) {
# Logs de process
$logs['balance'][1][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte solde N°1 : Réservation imminente']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_balance_alert_1_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['balance'][1][$key]['process'] = 'Vérification N°1 du paiement total';
$logs['balance'][1][$key]['content'] = $mail_content_c;
# Changement d'état
$booking->setIsBalancePaymentAlert1(true);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['balance']['title'])
->setProcess($logs['balance'][1][$key]['process'])
->setReference($logs['balance'][1][$key]['reference'])
->setContent($logs['balance'][1][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
} else {
# Pour chaque reservation on vérifie si la balancePaymentDeadline est dépasser pour envoyer une 1ere alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($balancePaymentDeadline->format('Y-m-d'))))) {
# Logs de process
$logs['balance'][1][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte solde N°1 : Réservation classique']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_balance_alert_1_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['balance'][1][$key]['process'] = 'Vérification N°1 du paiement du recliquat';
$logs['balance'][1][$key]['content'] = $mail_content_c;
# Changement d'état
$booking->setIsBalancePaymentAlert1(true);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['balance']['title'])
->setProcess($logs['balance'][1][$key]['process'])
->setReference($logs['balance'][1][$key]['reference'])
->setContent($logs['balance'][1][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
}
### Alerte 2 reliquat
if ($booking->getIsBalancePaymentAlert2() != true && $booking->getIsBalancePaymentAlert1() == true && $booking->getIsBalancePayed() != true) {
# Réservation iminente
if ($isForSoon == true) {
# On vérifie si nous sommes 72h après la deadline de paiement du montant total
if ((date('U', strtotime($now))) > (date('U', strtotime($balancePaymentDeadline->format('Y-m-d')) + (3 * 84600)))) {
# Logs de process
$logs['balance'][2][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte solde N°2 : Réservation imminente']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_balance_alert_2_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['balance'][2][$key]['process'] = 'Vérification N°1 du paiement total';
$logs['balance'][2][$key]['content'] = $mail_content_c;
# Changement d'état
$booking
->setIsBalancePaymentAlert2(true)
->setTracking(false);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['balance']['title'])
->setProcess($logs['balance'][2][$key]['process'])
->setReference($logs['balance'][2][$key]['reference'])
->setContent($logs['balance'][2][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
# Réservation normale
} else {
# Pour chaque reservation on vérifie si la balancePaymentDeadline + 72h est dépasser pour envoyer une 2eme alerte au client
if ((date('U', strtotime($now))) > (date('U', strtotime($balancePaymentDeadline->format('Y-m-d'))) + (3 * 84600))) {
# Logs de process
$logs['balance'][2][$key]['reference'] = $booking->getUniqId();
# Récupéreration du contenu du mail
$templateMail_locataire = $bookingMailRepo->findOneBy(['title' => 'Alerte solde N°2 : Réservation classique']);
## Envoi d'email d'alerte MailJet
# Client
$mailjet = new Mailjet();
$mail_content_c = $this->replaceVar($templateMail_locataire->translate($booking->getLocale())->getContent(), $booking, $constraint);
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", $booking->getEmail(), $booking->getFirstName() . " " . $booking->getLastName(), $this->translator->trans("Votre réservation") . " N°" . $booking->getUniqId(), $mail_content_c, false, false, 7650701);
# Propriétaire
$mailjet = new Mailjet();
$mail_content_p = $this->renderView('components/mail/_booking_balance_alert_2_p.html.twig', compact('booking', 'statics', 'constraint'));
$mailjet->send("caurettemarc@gmail.com", "gite-colombine.fr", "maximeavril.dev@gmail.com", $booking->getFirstName() . " " . $booking->getLastName(), "Alerte réservation N°" . $booking->getUniqId(), $mail_content_p, false, false, 7650701);
# Logs de process
$logs['balance'][2][$key]['process'] = 'Vérification N°1 du paiement du recliquat';
$logs['balance'][2][$key]['content'] = $mail_content_c;
# Changement d'état
$booking
->setIsBalancePaymentAlert2(true)
->setTracking(false);
$this->manager->persist($booking);
# Enregistrement des logs de process
$ProcessLogs = new ProcessLogs();
$ProcessLogs
->setTitle($logs['balance']['title'])
->setProcess($logs['balance'][2][$key]['process'])
->setReference($logs['balance'][2][$key]['reference'])
->setContent($logs['balance'][2][$key]['content'])
->setCreatedAt(new DateTimeImmutable());
$this->manager->persist($ProcessLogs);
}
}
}
}
}
$this->manager->flush();
// return new Response('success', 200);
return new JsonResponse($logs);
}
/**
* Permet de récupérer la date la plus éloignée parmis les periodes des saisons en BDD
* Afin de bloquer les reservations en ligne après cette date
*
* @Route("/booking/get-end-date", name="booking_end_date")
*/
public function getEndDate()
{
$saisons = $this->constraint->getSaisons();
$endDates = [];
foreach ($saisons as $key => $saison) {
foreach ($saison->getPeriods() as $key => $period) {
$endDates[] = date('U', strtotime($period->getEndDate()->format('Y-m-d')));
}
}
sort($endDates, SORT_NUMERIC);
$endDate = date('d/m/Y', array_slice($endDates, -1, 1)[0]);
return $endDate;
}
/**
* Permet d'afficher la page des conditions générales
*
* @Route("/booking/conditions-generales", name="booking_conditions")
*/
public function showConditions()
{
$page = $this->pageRepo->findOneBy(['page' => 'CGV']);
# Redirection sur la page de validation de réservation
return $this->render('booking/conditions.html.twig', [
'statics' => $this->statics['data'],
'page' => $page,
'constraints' => $this->constraint,
]);
}
/**
* Permet de générer un PDF a partir d'un template HTML
*
* @Route("/booking/make-pdf/{uid}", name="booking_make_pdf")
*/
public function makePdf($uid, $template, $request, $for = null)
{
$locale = $request->attributes->get('_locale');
$html2pdf = new Html2Pdf('p', 'A4', $locale, true, 'UTF-8', [15, 15, 15, 15], true);
$html2pdf->writeHTML($template);
if ($for == 'bailleur') {
$html2pdf->output('/home/maxappu/www/' . str_replace('https://', '', $request->getSchemeAndHttpHost()) . '/v3/public/file/contrats/contrat-' . $uid . '-bailleur.pdf', 'F');
} elseif ($for == 'locataire') {
$html2pdf->output('/home/maxappu/www/' . str_replace('https://', '', $request->getSchemeAndHttpHost()) . '/v3/public/file/contrats/contrat-' . $uid . '-locataire.pdf', 'F');
}
return $this->json(true);
}
/**
* Permet de remplacer les variables des templates de mail
*
* @Route("/{_locale}/booking/replacevar", name="booking_make_pdf")
*/
public function replaceVar($template, $booking, $constraint, $for = null)
{
$copyFor = "";
if ($for == 'locataire') {
$copyFor = "Copie pour le locataire";
} elseif ($for == 'bailleur') {
$copyFor = "Copie pour le bailleur";
}
$search = [
'__uid__',
'__copyFor__',
'__a.phone__',
'__gender__',
'__firstname__',
'__lastname__',
'__advancePayment__',
'__c.advancePaymentDeadline__',
'__balance__',
'__c.balancePaymentDeadline__',
'__advancePaymentDeadline__',
'__balancePaymentDeadline__',
'__deposit__',
'__c.cautionPaymentDelay__',
'__cautionPaymentDeadline__',
'__finalAmount__',
'__rib__',
'__paypal__',
'__startdate__',
'__enddate__',
'__housework__',
'__staytax__',
'__email__',
'__phone__',
'__comment__',
'__dayprice__',
'__paymentMethod__',
'__number__',
'__duration__',
'__swikly_url__',
];
$replace = [
$booking->getUniqId(),
$copyFor,
$this->statics['data']['about']->getPhone(),
$booking->getGender(),
$booking->getFirstName(),
$booking->getLastName(),
number_format(($booking->getAdvancePayment() / 100), 2, ',', ' '),
$constraint->getAdvancePaymentDeadline(),
number_format((($booking->getFinalAmount() - $booking->getAdvancePayment()) / 100), 2, ',', ' '),
$constraint->getBalancePaymentDeadline(),
$booking->getAdvancePaymentDeadline()->format('d/m/Y'),
$booking->getBalancePaymentDeadline()->format('d/m/Y'),
number_format(($booking->getDeposit() / 100), 2, ',', ' '),
$constraint->getCautionPaymentDelay(),
$booking->getCautionPaymentDeadline()->format('d/m/Y'),
number_format(($booking->getFinalAmount() / 100), 2, ',', ' '),
'www.gite-colombine.fr/images/profile/' . $constraint->getPaymentMethods()[0]->getImg(),
$constraint->getPaymentMethods()[1]->getUrl(),
$booking->getStartDate()->format('d/m/Y'),
$booking->getEndDate()->format('d/m/Y'),
number_format(($booking->getHousework() / 100), 2, ',', ' '),
number_format(($booking->getStayTax() / 100), 2, ',', ' '),
$booking->getEmail(),
$booking->getPhone(),
html_entity_decode($booking->getComment()),
number_format(($booking->getDayPrice() / 100), 2, ',', ' '),
$booking->getPaymentMethod(),
$booking->getNumber(),
$booking->getDuration(),
$booking->getSwiklyUrl() ?? '',
];
$template = str_replace($search, $replace, $template);
return $template;
}
}