Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 58

Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler

src/Service/BookingService.php line 73

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Entity\Booking;
  4. use App\Entity\BookingConfig;
  5. use App\Entity\BookingConfigDate;
  6. use App\Entity\BookingConfigHour;
  7. use App\Entity\DeliveryNote;
  8. use DateInterval;
  9. use DatePeriod;
  10. use DateTime;
  11. use DateTimeInterface;
  12. use Doctrine\Common\Collections\ArrayCollection;
  13. use Doctrine\ORM\EntityManagerInterface;
  14. use Exception;
  15. use GuzzleHttp\Exception\GuzzleException;
  16. class BookingService
  17. {
  18.     private EntityManagerInterface $em;
  19.     private BookingConfig $config;
  20.     private KheopsService $kheopsService;
  21.     private BrandService $brandService;
  22.     private int $slotLength;
  23.     private array $days;
  24.     /**
  25.      * @param EntityManagerInterface $em
  26.      * @param KheopsService $kheopsService
  27.      * @param BrandService $brandService
  28.      */
  29.     public function __construct(EntityManagerInterface $emKheopsService $kheopsServiceBrandService $brandService)
  30.     {
  31.         $this->em $em;
  32.         $this->kheopsService $kheopsService;
  33.         $this->brandService $brandService;
  34.         $this->config $this->getConfig();
  35.         $this->slotLength $this->config->getSlotLength();
  36.         $this->days array_map(fn(BookingConfigHour $hour) => $hour->getDay(), $this->em->getRepository(BookingConfigHour::class)->findBy(['bookingConfig' => $this->config], ['day' => 'ASC']));
  37.     }
  38.     public function getConfig()
  39.     {
  40.         return $this->em->getRepository(BookingConfig::class)->findOneByType('delivery_note');
  41.     }
  42.     public function getDay(DateTimeInterface $date): ?BookingConfigHour
  43.     {
  44.         return $this->em->getRepository(BookingConfigHour::class)->findOneBy(['bookingConfig' => $this->config'day' => $date->format('N')]);
  45.     }
  46.     public function check(Booking $booking): bool
  47.     {
  48.         return $this->getSlots($booking->getDate(), $booking->getDeliveryNote())
  49.             ->filter(fn(array $slot) => $slot['enable'])
  50.             ->map(fn(array $slot) => $slot['datetime']->format('H:i'))
  51.             ->contains($booking->getTime()->format('H:i'));
  52.     }
  53.     /**
  54.      * @param DateTimeInterface $date
  55.      * @param DeliveryNote|null $deliveryNote
  56.      * @return ArrayCollection
  57.      */
  58.     public function getSlots(DateTimeInterface $dateDeliveryNote $deliveryNote null): ArrayCollection
  59.     {
  60.         $this->cleanBookings();
  61.         $day $this->getDay($date);
  62.         if (!$day) {
  63.             return new ArrayCollection();
  64.         }
  65.         $slots = array();
  66.         $now = new DateTime();
  67.         $startMorningHour = (clone $date)->setTime($day->getMorningStart()->format('H'), $day->getMorningStart()->format('i'));
  68.         $endMorningHour = (clone $date)->setTime($day->getMorningEnd()->format('H'), $day->getMorningEnd()->format('i'));
  69.         $startAfternoonHour = (clone $date)->setTime($day->getAfternoonStart()->format('H'), $day->getAfternoonStart()->format('i'));
  70.         $endAfternoonHour = (clone $date)->setTime($day->getAfternoonEnd()->format('H'), $day->getAfternoonEnd()->format('i'));
  71.         $startHour max($now->modify('+3 hours'), $startMorningHour);
  72.         $period = new DatePeriod($startMorningHourDateInterval::createFromDateString($this->slotLength ' minutes'), $endAfternoonHour);
  73.         foreach ($period as $dt) {
  74.             if ($dt > (clone $endMorningHour)->modify('-' $this->slotLength ' minutes') && $dt $startAfternoonHour) {
  75.                 continue;
  76.             }
  77.             $dtEnable $dt >= $startHour && $this->isAvailable($dt);
  78.             if ($deliveryNote && !$this->isBooked($dt$deliveryNote) && $deliveryNote->getBooking() && $deliveryNote->getBooking()->bookingDateTime($dt)) {
  79.                 $dtEnable true;
  80.             }
  81.             $slots[] = array(
  82.                 'datetime' => $dt,
  83.                 'enable' => $dtEnable
  84.             );
  85.         }
  86.         return new ArrayCollection($slots);
  87.     }
  88.     public function cleanBookings()
  89.     {
  90.         $this->em->getRepository(Booking::class)->createQueryBuilder('b')
  91.             ->delete()
  92.             ->where('b.confirmed = 0')
  93.             ->andWhere('b.updatedAt < :datetime')
  94.             ->setParameter('datetime', (new DateTime())->modify('-30 minutes'))
  95.             ->getQuery()->getResult();
  96.     }
  97.     public function isAvailable(DateTimeInterface $dt): bool
  98.     {
  99.         return !$this->isBooked($dt) && !$this->getExcludedSlotsOfDay($dt)->contains($dt->format(DateTimeInterface::ATOM));
  100.     }
  101.     public function isBooked(DateTimeInterface $dt, ?DeliveryNote $deliveryNote null): bool
  102.     {
  103.         $qb $this->em->getRepository(Booking::class)->createQueryBuilder('b')
  104.             ->where('b.date = :date')
  105.             ->andWhere('b.time = :time')
  106.             ->andWhere('b.bookingConfig = :bookingConfig')
  107.             ->setParameter('date'$dt->format('Y-m-d'))
  108.             ->setParameter('time'$dt->format('H:i:s'))
  109.             ->setParameter('bookingConfig'$this->config);
  110.         if ($deliveryNote) {
  111.             $qb->andWhere('b.deliveryNote != :deliveryNote')
  112.                 ->setParameter('deliveryNote'$deliveryNote->getId());
  113.         }
  114.         return !empty($qb->getQuery()->getResult());
  115.     }
  116.     public function getExcludedSlotsOfDay(DateTimeInterface $date null): ArrayCollection
  117.     {
  118.         $excludedSlots = new ArrayCollection();
  119.         foreach ($this->config->getExcludeDates() as $excludedDate) {
  120.             if ($excludedDate->getDateEnd() && $excludedDate->getDateStart()->format('Y-m-d') == $excludedDate->getDateEnd()->format('Y-m-d')) {
  121.                 $period = new DatePeriod($excludedDate->getDateStart(), DateInterval::createFromDateString($this->slotLength ' minutes'), $excludedDate->getDateEnd());
  122.                 foreach ($period as $dt) {
  123.                     $excludedSlots->add($dt->format(DateTimeInterface::ATOM));
  124.                 }
  125.             }
  126.         }
  127.         if ($date) {
  128.             foreach ($this->config->getExcludeSlots() as $excludedSlot) {
  129.                 if ($excludedSlot->getDay() == $date->format('N')) {
  130.                     $timeStart = (clone $date)->setTime($excludedSlot->getTimeStart()->format('H'), $excludedSlot->getTimeStart()->format('i'));
  131.                     $timeEnd = (clone $date)->setTime($excludedSlot->getTimeEnd()->format('H'), $excludedSlot->getTimeEnd()->format('i'));
  132.                     $period = new DatePeriod($timeStartDateInterval::createFromDateString($this->slotLength ' minutes'), $timeEnd);
  133.                     foreach ($period as $dt) {
  134.                         $excludedSlots->add($dt->format(DateTimeInterface::ATOM));
  135.                     }
  136.                 }
  137.             }
  138.             $period = new DatePeriod($this->getClosestsSlot(new DateTime()), DateInterval::createFromDateString($this->slotLength ' minutes'), (new DateTime())->modify('+3 hours'));
  139.             foreach ($period as $dt) {
  140.                 $excludedSlots->add($dt->format(DateTimeInterface::ATOM));
  141.             }
  142.         }
  143.         return $excludedSlots;
  144.     }
  145.     public function getClosestsSlot(DateTimeInterface $dt): DateTimeInterface
  146.     {
  147.         $minutes $dt->format('i');
  148.         $dt->setTime($dt->format('H'), $minutes);
  149.         $minutes $minutes round($minutes 10) * 10;
  150.         return $dt->modify('-' $minutes ' minutes');
  151.     }
  152.     /**
  153.      * @throws Exception
  154.      */
  155.     public function getExcludedDates(?DeliveryNote $deliveryNote null): ArrayCollection
  156.     {
  157.         $excludedDates = new ArrayCollection();
  158.         foreach ($this->config->getExcludeDates() as $excludedDate) {
  159.             if (!$excludedDate->getDateEnd()) {
  160.                 $excludedDates->add($excludedDate->getDateStart()->format(DateTimeInterface::ATOM));
  161.                 continue;
  162.             }
  163.             if ($excludedDate->getDateStart()->format('Y-m-d') == $excludedDate->getDateEnd()->format('Y-m-d')) {
  164.                 continue;
  165.             }
  166.             $period = new DatePeriod($excludedDate->getDateStart(), DateInterval::createFromDateString("1 day"), $excludedDate->getDateEnd()->modify('+1 day'));
  167.             foreach ($period as $dt) {
  168.                 $excludedDates->add($dt->format(DateTimeInterface::ATOM));
  169.             }
  170.         }
  171.         if (($firstSlot = new DateTime($this->firstAvailableSlot($deliveryNote)))->setTime(00)->format('Y-m-d') != ($now = new DateTime())->setTime(00)->format('Y-m-d')) {
  172.             $period = new DatePeriod($nowDateInterval::createFromDateString("1 day"), $firstSlot);
  173.             foreach ($period as $dt) {
  174.                 $excludedDates->add($dt->format(DateTimeInterface::ATOM));
  175.             }
  176.         }
  177.         return $excludedDates;
  178.     }
  179.     /**
  180.      * @throws Exception
  181.      */
  182.     public function firstAvailableSlot(?DeliveryNote $deliveryNote null): ?string
  183.     {
  184.         $date = (new DateTime())->modify('+3 hours');
  185.         if ($deliveryNote && $deliveryNote->getBooking() && !$deliveryNote->getBooking()->isExpired()) {
  186.             if ($deliveryNote->getBooking()->isConfirmed()) {
  187.                 $date $deliveryNote->getBooking()->getSlot();
  188.             }
  189.             if ($history $deliveryNote->getBooking()->getHistory()) {
  190.                 $date = new DateTime(end($history));
  191.             }
  192.         }
  193.         $periodStart /*$date->format('Y-m-d') == (new DateTime())->format('Y-m-d') ? $date->modify('+3 hours') :*/
  194.             $date;
  195.         $period = new DatePeriod($periodStartDateInterval::createFromDateString("1 day"), (new DateTime())->modify('+1 year'));
  196.         $excludedDates $this->config->getExcludeDates();
  197.         $excludedDates $excludedDates->filter(fn(BookingConfigDate $configDate) => !$configDate->getDateEnd())
  198.             ->map(fn(BookingConfigDate $configDate) => $configDate->getDateStart()->format(DateTimeInterface::ATOM));
  199.         foreach ($period as $dt) {
  200.             $dt->setTime(00);
  201.             if ($excludedDates->contains($dt->format(DateTimeInterface::ATOM))) {
  202.                 continue;
  203.             }
  204.             $slots $this->getSlots($dt)->filter(fn(array $slot) => $slot['enable'] === true);
  205.             if (!$slots->isEmpty()) {
  206.                 return $slots->first()['datetime']->format(DateTimeInterface::ATOM);
  207.             }
  208.         }
  209.         return null;
  210.     }
  211.     public function getExcludedDays(): array
  212.     {
  213.         return array_diff(array_keys(BookingConfigHour::DAYS_OF_WEEK), $this->days);
  214.     }
  215.     /**
  216.      * @param DeliveryNote $deliveryNote
  217.      * @return bool
  218.      * @throws GuzzleException
  219.      */
  220.     public function canBook(DeliveryNote $deliveryNote): bool
  221.     {
  222.         if (!$this->brandService->getBrand()->getEnableLocationCheck()) {
  223.             return true;
  224.         }
  225.         if ($deliveryNote->getBooking() && $deliveryNote->getBooking()->isConfirmed()) {
  226.             return $deliveryNote->getBooking()->getDate()->format('Y-m-d') >= (new DateTime())->format('Y-m-d');
  227.         }
  228.         $deliveryNoteItems $this->kheopsService->getItems($deliveryNote->getCode());
  229.         $enable false;
  230.         foreach ($deliveryNoteItems as $item) {
  231.             $matches preg_match('/^A.*$/'$item->lieu);
  232.             if (!empty($matches)) {
  233.                 $enable true;
  234.                 break;
  235.             }
  236.         }
  237.         return $enable;
  238.     }
  239.     /**
  240.      * @param DeliveryNote $deliveryNote
  241.      * @return bool
  242.      * @throws GuzzleException
  243.      */
  244.     public function hasNoDeliveryBatch(DeliveryNote $deliveryNote): bool
  245.     {
  246.         if (!$this->brandService->getBrand()->getEnableLocationCheck()) {
  247.             return false;
  248.         }
  249.         $deliveryNoteItems $this->kheopsService->getItems($deliveryNote->getCode());
  250.         $hasNoDeliveryBatch false;
  251.         foreach ($deliveryNoteItems as $item) {
  252.             $matches preg_match('/^A.*$/'$item->lieu);
  253.             if (empty($matches)) {
  254.                 $hasNoDeliveryBatch true;
  255.             }
  256.         }
  257.         return $hasNoDeliveryBatch;
  258.     }
  259. }