src/AdminBundle/Repository/BookingRepository.php line 875

Open in your IDE?
  1. <?php
  2. namespace AdminBundle\Repository;
  3. use AdminBundle\Entity\Booking;
  4. use AdminBundle\Entity\BroadcastedDriver;
  5. use AdminBundle\Entity\Driver;
  6. use AdminBundle\Entity\Settings;
  7. use AdminBundle\Entity\User;
  8. use DateInterval;
  9. use DateTime;
  10. use Doctrine\ORM\QueryBuilder;
  11. /**
  12. * BookingRepository
  13. *
  14. * This class was generated by the Doctrine ORM. Add your own custom
  15. * repository methods below.
  16. */
  17. class BookingRepository extends \Doctrine\ORM\EntityRepository
  18. {
  19. const LIST_INCOMING = 'incoming';
  20. const LIST_LIVE = 'live';
  21. const LIST_COMPLETED = 'completed';
  22. const LIST_CANCELLED = 'cancelled';
  23. const LIST_UNASSIGNED = 'unassigned';
  24. const LIST_STATUSES = [
  25. self::LIST_INCOMING,
  26. self::LIST_LIVE,
  27. self::LIST_COMPLETED,
  28. self::LIST_CANCELLED,
  29. self::LIST_UNASSIGNED,
  30. ];
  31. public function getDriverCurrentBooking($driverId)
  32. {
  33. $em = $this->getEntityManager();
  34. $conn = $em->getConnection();
  35. $status = [
  36. Booking::STATUS_ON_THE_WAY,
  37. Booking::STATUS_ARRIVED_AND_WAITING,
  38. Booking::STATUS_PASSENGER_ON_BOARD,
  39. Booking::STATUS_ABOUT_TO_DROP,
  40. ];
  41. $sql = 'SELECT id, booking_status FROM booking WHERE driver_id = ' . $driverId . ' AND booking_status IN(' . implode($status, ',') . ')';
  42. $stmt = $conn->prepare($sql);
  43. $stmt->execute();
  44. $result = $stmt->fetchAll();
  45. return !empty($result[0]) ? $result[0] : null;
  46. }
  47. public function getUpdatedBookingsCount($driverId)
  48. {
  49. $em = $this->getEntityManager();
  50. $conn = $em->getConnection();
  51. $sql = 'SELECT count(id) as notifications FROM notification_booking_update WHERE driver_id=' . $driverId . ' AND seen=false';
  52. $stmt = $conn->prepare($sql);
  53. $stmt->execute();
  54. $result = $stmt->fetchAll();
  55. return intval($result[0]['notifications']);
  56. }
  57. public function getNewBookingsCount($driverId)
  58. {
  59. $queryBuilder = $this->createQueryBuilder('b')
  60. ->select('count(b.id)');
  61. $queryBuilder
  62. ->leftJoin('b.broadcastedDrivers', 'broadcasted')
  63. ->where($queryBuilder->expr()->orX(
  64. $queryBuilder->expr()->andX(
  65. $queryBuilder->expr()->eq('b.status', Booking::STATUS_BROADCAST),
  66. $queryBuilder->expr()->eq('broadcasted.driver', $driverId),
  67. $queryBuilder->expr()->eq('broadcasted.status', BroadcastedDriver::STATUS_WAITING)
  68. ),
  69. $queryBuilder->expr()->andX(
  70. $queryBuilder->expr()->eq('b.status', Booking::STATUS_DISPATCHED),
  71. $queryBuilder->expr()->eq('b.driver', $driverId)
  72. )
  73. ));
  74. return intval($queryBuilder->getQuery()->getSingleScalarResult());
  75. }
  76. public function getUnassignedBookingsAvailableCount(Driver $driver)
  77. {
  78. $bookings = $this->getUnassignedBookingList($driver);
  79. return count($bookings);
  80. }
  81. /**
  82. * @param $type
  83. * @param Driver $driver
  84. * @return array
  85. */
  86. public function getBookingList($type, Driver $driver)
  87. {
  88. $queryBuilder = $this->createQueryBuilder('b');
  89. switch ($type) {
  90. case self::LIST_INCOMING:
  91. $queryBuilder
  92. ->leftJoin('b.broadcastedDrivers', 'broadcasted')
  93. ->where($queryBuilder->expr()->orX(
  94. $queryBuilder->expr()->andX(
  95. $queryBuilder->expr()->eq('b.status', Booking::STATUS_BROADCAST),
  96. $queryBuilder->expr()->eq('broadcasted.driver', $driver->getId()),
  97. $queryBuilder->expr()->eq('broadcasted.status', BroadcastedDriver::STATUS_WAITING)
  98. ),
  99. $queryBuilder->expr()->andX(
  100. $queryBuilder->expr()->eq('b.status', Booking::STATUS_DISPATCHED),
  101. $queryBuilder->expr()->eq('b.driver', $driver->getId())
  102. )
  103. ))
  104. ;
  105. break;
  106. case self::LIST_LIVE:
  107. $queryBuilder->where('b.status in (:status)')
  108. ->andWhere('b.driver = :driver')
  109. ->setParameter('status', [
  110. Booking::STATUS_DRIVER_ACCEPT,
  111. Booking::STATUS_ON_THE_WAY,
  112. Booking::STATUS_ARRIVED_AND_WAITING,
  113. Booking::STATUS_PASSENGER_ON_BOARD,
  114. Booking::STATUS_ABOUT_TO_DROP
  115. ])
  116. ->setParameter('driver', $driver);
  117. break;
  118. case self::LIST_COMPLETED:
  119. $queryBuilder->where('b.status = :status')
  120. ->andWhere('b.driver = :driver')
  121. ->setParameter('status', Booking::STATUS_COMPLETED)
  122. ->setParameter('driver', $driver->getId());
  123. break;
  124. case self::LIST_CANCELLED:
  125. $queryBuilder->where('b.status in (:status)')
  126. ->andWhere('b.driver = :driver')
  127. ->setParameter('status', [
  128. Booking::STATUS_CANCELLED_OTHER_REASON,
  129. Booking::STATUS_CLIENT_CANCELLATION,
  130. Booking::STATUS_CLIENT_NOT_SHOW_UP,
  131. Booking::STATUS_CAR_BROKE_DOWN,
  132. Booking::STATUS_OFFICE_CANCELLATION
  133. ])
  134. ->setParameter('driver', $driver);
  135. break;
  136. }
  137. $queryBuilder->andWhere('DATE(b.pickUpDate) >= DATE(:lastWeekMonday)')
  138. ->setParameter('lastWeekMonday', new \DateTime('last week last mon'));
  139. return $queryBuilder->getQuery()->getResult();
  140. }
  141. /**
  142. * @param $type
  143. * @param User $user
  144. * @return array
  145. */
  146. public function getClientBookingList($type, User $user)
  147. {
  148. $queryBuilder = $this->createQueryBuilder('b');
  149. switch ($type) {
  150. case self::LIST_LIVE:
  151. $queryBuilder
  152. ->where('b.status in (:status)')
  153. ->andWhere('b.clientUser = :client')
  154. ->setParameter('status', [
  155. Booking::STATUS_NEW_BOOKING,
  156. Booking::STATUS_DISPATCHED,
  157. Booking::STATUS_DRIVER_ACCEPT,
  158. Booking::STATUS_ON_THE_WAY,
  159. Booking::STATUS_ARRIVED_AND_WAITING,
  160. Booking::STATUS_PASSENGER_ON_BOARD,
  161. Booking::STATUS_ABOUT_TO_DROP,
  162. ])
  163. ->setParameter('client', $user);
  164. break;
  165. case self::LIST_COMPLETED:
  166. $queryBuilder
  167. ->where('b.status = :status')
  168. ->andWhere('b.clientUser = :client')
  169. ->setParameter('status', Booking::STATUS_COMPLETED)
  170. ->setParameter('client', $user)
  171. ->orderBy('b.pickUpDateTime', 'DESC')
  172. ;
  173. break;
  174. case self::LIST_CANCELLED:
  175. $queryBuilder
  176. ->where('b.status in (:status)')
  177. ->andWhere('b.client = :client')
  178. ->setParameter('status', [
  179. Booking::STATUS_CANCELLED_OTHER_REASON,
  180. Booking::STATUS_CLIENT_CANCELLATION,
  181. Booking::STATUS_CLIENT_NOT_SHOW_UP,
  182. Booking::STATUS_CAR_BROKE_DOWN,
  183. Booking::STATUS_OFFICE_CANCELLATION
  184. ])
  185. ->setParameter('client', $user);
  186. break;
  187. case 'all':
  188. $queryBuilder
  189. ->where('b.status in (:status)')
  190. ->andWhere('b.clientUser = :client')
  191. ->setParameter('status', [
  192. Booking::STATUS_NEW_BOOKING,
  193. Booking::STATUS_DISPATCHED,
  194. Booking::STATUS_CANCELLED_OTHER_REASON,
  195. Booking::STATUS_CLIENT_CANCELLATION,
  196. Booking::STATUS_CLIENT_NOT_SHOW_UP,
  197. Booking::STATUS_CAR_BROKE_DOWN,
  198. Booking::STATUS_OFFICE_CANCELLATION,
  199. Booking::STATUS_COMPLETED,
  200. Booking::STATUS_DRIVER_ACCEPT,
  201. Booking::STATUS_ON_THE_WAY,
  202. Booking::STATUS_ARRIVED_AND_WAITING,
  203. Booking::STATUS_PASSENGER_ON_BOARD,
  204. Booking::STATUS_ABOUT_TO_DROP,
  205. ])
  206. ->setParameter('client', $user)
  207. ->orderBy('b.pickUpDateTime', 'DESC')
  208. ;
  209. break;
  210. }
  211. return $queryBuilder->getQuery()->getResult();
  212. }
  213. public function findByPickUpDate($date, $driverName = null)
  214. {
  215. $queryBuilder = $this->createQueryBuilder('b')
  216. ->innerJoin('b.driver', 'd')
  217. ->leftJoin('b.returnBooking', 'r')
  218. ->innerJoin('d.user', 'u')
  219. ->where('b.pickUpDate = :date')
  220. ->setParameter('date', $date->format('Y-m-d'));
  221. if ($driverName) {
  222. $queryBuilder->andWhere($queryBuilder->expr()->orX(
  223. $queryBuilder->expr()->like('u.firstname', $queryBuilder->expr()->literal('%' . $driverName . '%')),
  224. $queryBuilder->expr()->like('u.lastname', $queryBuilder->expr()->literal('%' . $driverName . '%')),
  225. $queryBuilder->expr()->like($queryBuilder->expr()->concat(
  226. 'u.firstname', $queryBuilder->expr()->concat(
  227. $queryBuilder->expr()->literal(' '), 'u.lastname'
  228. )
  229. ),
  230. $queryBuilder->expr()->literal($driverName . '%')
  231. )
  232. ));
  233. }
  234. return $queryBuilder->getQuery()->getResult();
  235. }
  236. public function createUnallocatedBookingsQb()
  237. {
  238. return $this
  239. ->createQueryBuilder('b')
  240. ->where('b.driver IS NULL')
  241. ->andWhere('b.status = :status')
  242. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  243. ;
  244. }
  245. public function findUnallocatedBookings($date, $isArray = true)
  246. {
  247. $queryBuilder = $this->createUnallocatedBookingsQb();
  248. if ($isArray) {
  249. $queryBuilder->select('b.id, b.key, b.pickUpPostCode, b.destinationPostCode, b.pickUpTime, b.matchJob');
  250. }
  251. return $queryBuilder
  252. ->andWhere('b.pickUpDate = :date')
  253. ->setParameter('date', $date->format('Y-m-d'))
  254. ->orderBy('b.pickUpTime')
  255. ->getQuery()
  256. ->getResult()
  257. ;
  258. }
  259. public function findUnallocatedBookingsCreatedBetweenDates(DateTime $startDate, DateTime $endDate)
  260. {
  261. $qb = $this
  262. ->createQueryBuilder('b')
  263. ->where('b.driver IS NULL')
  264. ->andWhere('b.status = :status')
  265. ;
  266. // TODO: These will be removed after we cover future bookings with this feature
  267. $startDatePickUp = clone $startDate;
  268. $startDatePickUp->add(new \DateInterval('P3D'));
  269. $endDatePickUp = clone $endDate;
  270. $endDatePickUp->add(new \DateInterval('P3D'));
  271. return $qb
  272. ->andWhere($qb->expr()->orX(
  273. $qb->expr()->between('b.bookingDate', ':startDate', ':endDate'),
  274. $qb->expr()->between('b.pickUpDateTime', ':startDatePickUp', ':endDatePickUp')
  275. ))
  276. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  277. ->setParameter('startDate', $startDate)
  278. ->setParameter('endDate', $endDate)
  279. ->setParameter('startDatePickUp', $startDatePickUp)
  280. ->setParameter('endDatePickUp', $endDatePickUp)
  281. ->getQuery()
  282. ->getResult()
  283. ;
  284. }
  285. public function findDispatchedAcceptBetweenDates(DateTime $startDate, DateTime $endDate)
  286. {
  287. $qb = $this
  288. ->createQueryBuilder('b')
  289. ->where('b.driver IS NOT NULL')
  290. ->andWhere('b.status = :status')
  291. ;
  292. return $qb
  293. ->andWhere(
  294. $qb->expr()->between('b.pickUpDateTime', ':startDate', ':endDate')
  295. )
  296. ->setParameter('status', Booking::STATUS_DRIVER_ACCEPT)
  297. ->setParameter('startDate', $startDate)
  298. ->setParameter('endDate', $endDate)
  299. ->getQuery()
  300. ->getResult()
  301. ;
  302. }
  303. public function findUnallocatedBookingsForCarTypeBeforeTime($date, $time, $carType, $isArray = true)
  304. {
  305. $queryBuilder = $this->createQueryBuilder('b');
  306. if ($isArray) {
  307. $queryBuilder->select('b.id, b.key, b.pickUpPostCode, b.destinationPostCode, b.pickUpTime, b.matchJob');
  308. }
  309. $queryBuilder
  310. ->where('b.pickUpDate = :date')
  311. ->andWhere('b.pickUpTime < :time')
  312. ->andWhere('b.status = :status');
  313. $queryBuilder
  314. ->join('b.carType', 'ct')
  315. ->andWhere('ct.id = :carType OR :carType MEMBER OF ct.replacements')
  316. ->setParameter('carType', $carType);
  317. $queryBuilder
  318. ->orderBy('b.pickUpTime')
  319. ->setParameter('time', $time)
  320. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  321. ->setParameter('date', $date->format('Y-m-d'));
  322. return $queryBuilder->getQuery()->getResult();
  323. }
  324. public function findMatchedJobs($date)
  325. {
  326. $queryBuilder = $this->createQueryBuilder('b')
  327. //->select('b.id, b.key, b.pickUpPostCode, b.destinationPostCode, b.pickUpTime, b.matchJob')
  328. ->where('b.matchJob IS NOT NULL')
  329. ->andWhere('b.driver IS NULL')
  330. ->andWhere('b.status = :status')
  331. ->andWhere('b.pickUpDate = :date')
  332. ->orderBy('b.pickUpTime')
  333. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  334. ->setParameter('date', $date->format('Y-m-d'));
  335. return $queryBuilder->getQuery()->getResult();
  336. }
  337. public function deletePreallocationBookings($date)
  338. {
  339. $queryBuilder = $this->createQueryBuilder('b')
  340. ->update()
  341. ->set('b.driver', 'null')
  342. ->where('b.driver IS NOT NULL')
  343. ->andWhere('b.pickUpDate = :date')
  344. ->andWhere('b.status = :status')
  345. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  346. ->setParameter('date', $date->format('Y-m-d'));
  347. $queryBuilder->getQuery()->execute();
  348. }
  349. public function deletePreallocationWithoutMatchedBookings($date)
  350. {
  351. $queryBuilder = $this->createQueryBuilder('b')
  352. ->update()
  353. ->set('b.driver', 'null')
  354. ->where('b.driver IS NOT NULL')
  355. ->andWhere('b.matchJob IS NOT NULL')
  356. ->andWhere('b.pickUpDate = :date')
  357. ->andWhere('b.status = :status')
  358. ->setParameter('status', Booking::STATUS_NEW_BOOKING)
  359. ->setParameter('date', $date->format('Y-m-d'));
  360. $queryBuilder->getQuery()->execute();
  361. }
  362. /**
  363. * @param Driver $driver
  364. * @param null $day
  365. * @return array
  366. */
  367. public function getUnassignedBookingList(Driver $driver, $day = null)
  368. {
  369. $undispatched_time_start = $this->getEntityManager()->getRepository(Settings::class)->findOneBy(['key' => 'undispatched_time_start'])->getValue();
  370. $undispatched_time_limit = $this->getEntityManager()->getRepository(Settings::class)->findOneBy(['key' => 'undispatched_time_limit'])->getValue();
  371. $undispatched_interval_between_bookings_pickup = $this->getEntityManager()->getRepository(Settings::class)->findOneBy(['key' => 'undispatched_interval_between_bookings_pickup']);
  372. $undispatched_interval_between_bookings_dropoff = $this->getEntityManager()->getRepository(Settings::class)->findOneBy(['key' => 'undispatched_interval_between_bookings_dropoff']);
  373. $st = new \DateTime('now');
  374. $et = new \DateTime('now');
  375. $yt = new \DateTime('now');
  376. //daca exista parametrul day, prima zi incepe de la +8 ore (deoarece de la +4 pana la +8 ore se aplica primul interval, ziua curenta)
  377. if (!empty($day)) {
  378. $yt = (new \DateTime('now'))->add(new \DateInterval('P' . $day . 'D'));
  379. $st = ($st->add(new \DateInterval('P' . $day . 'D')));
  380. $et = ($et->add(new \DateInterval('P' . $day . 'D')));
  381. $et->setTime(23, 59);
  382. $yt = ($yt->sub(new \DateInterval('P1D')));
  383. if ($day == 1) {
  384. $startTime = ($st->add(new \DateInterval('PT' . $undispatched_time_limit . 'H')))->format('Y-m-d H:i:s');
  385. } else {
  386. $st->setTime(00, 00);
  387. $startTime = $st->format('Y-m-d H:i:s');
  388. }
  389. $endTime = $et->format('Y-m-d H:i:s');
  390. } else {
  391. $startTime = ($st->add(new \DateInterval('PT' . $undispatched_time_start . 'H')))->format('Y-m-d H:i:s');
  392. $endTime = ($et->add(new \DateInterval('PT' . $undispatched_time_limit . 'H')))->format('Y-m-d H:i:s');
  393. }
  394. $result = [];
  395. /** @var QueryBuilder $queryBuilder */
  396. $queryBuilder = $this->createQueryBuilder('b');
  397. $queryBuilder
  398. ->where('b.driver is NULL');
  399. $queryBuilder
  400. ->andWhere('b.status = :statusNew or b.status = :statusBroadcast')
  401. ->setParameter('statusNew', Booking::STATUS_NEW_BOOKING)->setParameter('statusBroadcast', Booking::STATUS_BROADCAST);
  402. $queryBuilder
  403. ->join('b.carType', 'ct')
  404. ->andWhere('ct.id = :carType OR :carType MEMBER OF ct.replacements')
  405. ->setParameter('carType', $driver->getCar()->getType()->getId());
  406. $queryBuilder
  407. ->andWhere('b.pickUpDateTime >= :startTime and b.pickUpDateTime <= :endTime')->setParameter('startTime', $startTime)->setParameter('endTime', $endTime);
  408. $queryBuilder
  409. ->orderBy('b.pickUpDateTime', 'ASC');
  410. $result = array_merge($result, $queryBuilder->getQuery()->getResult());
  411. $bookings = array_unique($result, SORT_REGULAR);
  412. /** @var QueryBuilder $driverQueryBuilder */
  413. $driverQueryBuilder = $this->createQueryBuilder('b');
  414. $driverQueryBuilder
  415. ->where('b.driver = :driver')
  416. ->setParameter('driver', $driver);
  417. $driverQueryBuilder
  418. ->andWhere('b.pickUpDate = :yesterday or b.pickUpDate = :startDate or b.pickUpDate = :endDate')
  419. ->setParameter('startDate', (new \DateTime($startTime))->format('Y-m-d'))
  420. ->setParameter('endDate', (new \DateTime($endTime))->format('Y-m-d'))
  421. ->setParameter('yesterday', $yt->format('Y-m-d'));
  422. $driverBookings = array_unique($driverQueryBuilder->getQuery()->getResult(), SORT_REGULAR);
  423. if (!empty($driverBookings) and !empty($bookings)) {
  424. /** @var Booking $dBook */
  425. foreach ($driverBookings as $dBook) {
  426. $estimated = explode(':', $dBook->getEstimatedTime());
  427. $bookingPickup = (new \DateTime($dBook->getPickUpDateTime()->format('Y-m-d H:i')))->format('Y-m-d H:i');
  428. $ed = new \DateTime($dBook->getPickUpDateTime()->format('Y-m-d H:i'));
  429. $bookingEnd = ($ed->add(new \DateInterval('PT' . $estimated[0] . 'H' . $estimated[1] . 'M')));
  430. /** @var Booking $fBook */
  431. foreach ($bookings as $key => $fBook) {
  432. if ($bookingPickup >= $startTime and $bookingPickup <= $endTime and date_diff($bookingEnd, $fBook->getPickUpDateTime()) <= $undispatched_interval_between_bookings_pickup) {
  433. unset($bookings[$key]);
  434. }
  435. }
  436. }
  437. }
  438. if ($day == null) {
  439. if (!empty($bookings)) {
  440. $settingsRepo = $this->getEntityManager()->getRepository(Settings::class);
  441. /** @var Booking $fBook */
  442. foreach ($bookings as $key => $fBook) {
  443. $driver_rating_max_limit = floatval($settingsRepo->findOneByKey('driver_rating_max_limit')->getValue());
  444. $driver_current_rating = floatval($driver->getOverallRating());
  445. if ($driver_current_rating < $driver_rating_max_limit) {
  446. $vehicle_undispatched_max_price = (!empty($fBook->getCarType()) && !empty($fBook->getCarType()->getMaxPriceUndispatchedBooking())) ? floatval($fBook->getCarType()->getMaxPriceUndispatchedBooking()) : 0;
  447. if ($vehicle_undispatched_max_price > 0) {
  448. if (!empty($fBook->getDriverPrice())) {
  449. if ($fBook->getDriverPrice() > $vehicle_undispatched_max_price) {
  450. unset($bookings[$key]);
  451. }
  452. } elseif (!empty($fBook->getOverridePrice())) {
  453. if ($fBook->getOverridePrice() > $vehicle_undispatched_max_price) {
  454. unset($bookings[$key]);
  455. }
  456. } elseif (!empty($fBook->getQuotePrice())) {
  457. if ($fBook->getQuotePrice() > $vehicle_undispatched_max_price) {
  458. unset($bookings[$key]);
  459. }
  460. }
  461. }
  462. }
  463. }
  464. }
  465. }
  466. return $bookings;
  467. }
  468. /**
  469. * @param Driver $driver
  470. * @param null $day
  471. * @param bool $timeLimit
  472. * @return array
  473. */
  474. public function getUnassignedBookingListV2(Driver $driver, $day = null,$undispatchedTimeLimit = true)
  475. {
  476. $settingsRepo = $this->getEntityManager()->getRepository(Settings::class);
  477. $undispatched_time_start = $settingsRepo->findOneByKey('undispatched_time_start')->getValue();
  478. $undispatched_time_limit = $settingsRepo->findOneByKey('undispatched_time_limit')->getValue();
  479. $unassigned_bookings_start_period = $settingsRepo->findOneByKey('unassigned_bookings_start_period')->getValue();
  480. $undispatched_interval_between_bookings_pickup = $settingsRepo->findOneByKey('undispatched_interval_between_bookings_pickup')->getValue();
  481. $undispatched_interval_between_bookings_dropoff = $settingsRepo->findOneByKey('undispatched_interval_between_bookings_dropoff')->getValue();
  482. $driver_bonus_feature_active = $settingsRepo->findOneBy([
  483. 'key' => 'driver_bonus_feature_active',
  484. 'type' => Settings::TYPE_GLOBAL,
  485. ])->getValue();
  486. $driver_bonus_week_active = $settingsRepo->findOneBy([
  487. 'key' => 'driver_bonus_week_active',
  488. 'type' => Settings::TYPE_GLOBAL,
  489. ])->getValue();
  490. if (!empty($driver_bonus_week_active)) {
  491. $driver_bonus_week_active = explode(',', str_replace(' ', '', $driver_bonus_week_active));
  492. }
  493. // DRIVER RATING LIMITS
  494. $driver_rating_max_limit = floatval($settingsRepo->findOneByKey('driver_rating_max_limit')->getValue());
  495. $driver_rating_min_limit = floatval($settingsRepo->findOneByKey('driver_rating_min_limit')->getValue());
  496. $driver_rating_lowest_limit = floatval($settingsRepo->findOneByKey('driver_rating_lowest_limit')->getValue());
  497. $driver_current_rating = floatval($driver->getOverallRating());
  498. $currentWeek = date('W', strtotime('monday this week'));
  499. $st = new \DateTime('now');
  500. $et = new \DateTime('now');
  501. $preSt = new \DateTime('now');
  502. //daca exista parametrul day, prima zi incepe de la +8 ore (deoarece de la +4 pana la +8 ore se aplica primul interval, ziua curenta)
  503. if (!empty($day) && $driver_current_rating > $driver_rating_lowest_limit) {
  504. if ($day <= 7) {
  505. $day8=$day+1; // added 1 day to 7 days interval to cover the margins of 7 days interval for calculations of bookings
  506. $preSt = ($preSt->add(new \DateInterval('PT' . $unassigned_bookings_start_period . 'H')));
  507. $st = ($st->add(new \DateInterval('PT' . $unassigned_bookings_start_period . 'H')));
  508. $et = ($et->add(new \DateInterval('P' . $day8 . 'D')));
  509. $et->setTime(23, 59);
  510. } elseif ($day > 7 && $driver_current_rating > $driver_rating_min_limit) {
  511. // TODO: @cristi de rezolvat problema cu day=day+15 in cazul in care day>7 apar bookings si dupa perioada maxima definita pt period 2
  512. // if ($driver_current_rating >= $driver_rating_max_limit) {
  513. // $day = $day + 15;
  514. // }
  515. $preSt = ($preSt->add(new \DateInterval('P8D')));
  516. $st = ($st->add(new \DateInterval('P8D')));
  517. $et = ($et->add(new \DateInterval('P' . $day . 'D')));
  518. $et->setTime(23, 59);
  519. } else {
  520. $st = $st->add(new \DateInterval('PT' . $undispatched_time_start . 'H'));
  521. $et = $et->add(new \DateInterval('PT' . $undispatched_time_limit . 'H'));
  522. }
  523. $preStartTime = ($preSt->sub(new \DateInterval('P1D')))->format('Y-m-d H:i:s');
  524. $startTime = $st->format('Y-m-d H:i:s');
  525. $endTime = $et->format('Y-m-d H:i:s');
  526. } else {
  527. $preStartTime = ($preSt->sub(new \DateInterval('P1D')))->format('Y-m-d H:i:s');
  528. if ($undispatchedTimeLimit) {
  529. $startTime = ($st->add(new \DateInterval('PT' . $undispatched_time_start . 'H')))->format('Y-m-d H:i:s');
  530. $endTime = ($et->add(new \DateInterval('PT' . $undispatched_time_limit . 'H')))->format('Y-m-d H:i:s');
  531. } else {
  532. $startTime = $st->format('Y-m-d H:i:s');
  533. $endTime = ($et->add(new \DateInterval('P1D')))->format('Y-m-d H:i:s');
  534. }
  535. }
  536. /** @var QueryBuilder $driverQueryBuilder */
  537. $driverQueryBuilder = $this->createQueryBuilder('b');
  538. $driverQueryBuilder
  539. ->where('b.driver = :driver')
  540. ->setParameter('driver', $driver);
  541. $driverQueryBuilder
  542. ->andWhere('b.pickUpDate >= :preStartTime and b.pickUpDate < :endDate')
  543. ->setParameter('endDate', (new \DateTime($endTime))->format('Y-m-d'))
  544. ->setParameter('preStartTime', (new \DateTime($preStartTime))->format('Y-m-d'));
  545. $driverBookings = array_unique($driverQueryBuilder->getQuery()->getResult(), SORT_REGULAR);
  546. $excludedBookingTimes = [];
  547. $excludeStartDates = [];
  548. if (!empty($driverBookings)) {
  549. // /** @var Booking $dBook */
  550. // foreach ($driverBookings as $dBook) {
  551. // $estimated = explode(':', $dBook->getEstimatedTime());
  552. // $bookingPickup = (new \DateTime($dBook->getPickUpDateTime()->format('Y-m-d H:i')))->format('Y-m-d H:i');
  553. // $ed = new \DateTime($dBook->getPickUpDateTime()->format('Y-m-d H:i'));
  554. // $bookingEnd = ($ed->add(new \DateInterval('PT' . $estimated[0] . 'H' . $estimated[1] . 'M')));
  555. // $bookingEnd = ($ed->add(new \DateInterval('PT' . $undispatched_interval_between_bookings_dropoff . 'H')));
  556. // $excludeStartDates[] = $bookingPickup;
  557. // $excludedBookingTimes[] = [
  558. // 'startDate' => $bookingPickup,
  559. // 'endDate' => $bookingEnd->format('Y-m-d H:i'),
  560. // ];
  561. // }
  562. /** @var Booking $dBook */
  563. foreach ($driverBookings as $dBook) {
  564. $estimated = explode(':', $dBook->getEstimatedTime());
  565. $starDate = clone $dBook->getPickUpDateTime();
  566. $endDate = clone $dBook->getPickUpDateTime();
  567. $endDate = $endDate->add(
  568. new \DateInterval('PT'. $estimated[0]. 'H'. $estimated[1]. 'M')
  569. );
  570. $excludeStartDates[] = $starDate->format('Y-m-d H:i');
  571. $excludedBookingTimes[] = [
  572. 'startDate' => $starDate,
  573. 'endDate' => $endDate,
  574. ];
  575. }
  576. }
  577. $result = [];
  578. /** @var QueryBuilder $queryBuilder */
  579. $queryBuilder = $this->createQueryBuilder('b');
  580. $queryBuilder
  581. ->where('b.driver is NULL');
  582. $queryBuilder
  583. ->andWhere('b.status = :statusNew')
  584. ->setParameter('statusNew', Booking::STATUS_NEW_BOOKING);
  585. $queryBuilder
  586. ->join('b.carType', 'ct')
  587. ->andWhere('ct.id = :carType OR :carType MEMBER OF ct.replacements')
  588. ->setParameter('carType', $driver->getCar()->getType()->getId());
  589. $queryBuilder
  590. ->andWhere('b.pickUpDateTime >= :startTime and b.pickUpDateTime <= :endTime')->setParameter('startTime', $startTime)->setParameter('endTime', $endTime);
  591. if (!empty($excludeStartDates)) {
  592. $queryBuilder
  593. ->andWhere('b.pickUpDateTime not IN (:excluded)')->setParameter('excluded', $excludeStartDates);
  594. }
  595. $queryBuilder
  596. ->orderBy('b.pickUpDateTime', 'ASC');
  597. $result = array_merge($result, $queryBuilder->getQuery()->getResult());
  598. $bookings = array_unique($result, SORT_REGULAR);
  599. if (!empty($bookings)) {
  600. /** @var Booking $fBook */
  601. foreach ($bookings as $key => $fBook) {
  602. if ($fBook->getUnassignedHideAt() && $this->checkUnassignedDate(intval($day), $fBook)) {
  603. unset($bookings[$key]);
  604. continue;
  605. }
  606. if ($driver_bonus_feature_active == 1 && in_array($currentWeek, $driver_bonus_week_active) && empty($fBook->getDriverPrice())) {
  607. if (!empty($fBook->getBookingDataSerialized())) {
  608. $unserializedData = $fBook->getBookingDataSerializedDecoded();
  609. // $priceWithoutPeriod = $unserializedData->priceWithoutPeriod;
  610. $priceWithoutPeriod = $this->getEntityManager()->getRepository(Settings::class)->applyDriverRoundedBySettings(($unserializedData->price - abs($unserializedData->periodPriceStart)));
  611. $bookingPriceWithoutPeriod = $priceWithoutPeriod;
  612. $totalBPrice = $unserializedData->price;
  613. $bPrice = $unserializedData->result->routePrice;
  614. $rbPrice = $unserializedData->result->returnRoutePrice;
  615. if ($rbPrice !== 0) {
  616. $bookingPriceWithoutPeriod = $this->getEntityManager()->getRepository(Settings::class)->applyDriverRoundedBySettings((($bPrice * $priceWithoutPeriod) / $totalBPrice));
  617. }
  618. $fBook->setDriverPrice($bookingPriceWithoutPeriod);
  619. }
  620. }
  621. // $estimated = explode(':', $fBook->getEstimatedTime());
  622. // $bookingPickup = $fBook->getPickUpDateTime()->format('Y-m-d H:i');
  623. // $ed = new \DateTime($fBook->getPickUpDateTime()->format('Y-m-d H:i'));
  624. // $edu = new \DateTime($fBook->getPickUpDateTime()->format('Y-m-d H:i'));
  625. // $stu = new \DateTime($fBook->getPickUpDateTime()->format('Y-m-d H:i'));
  626. // $bookingEndEstimated = ($ed->add(new \DateInterval('PT' . $estimated[0] . 'H' . $estimated[1] . 'M')))->format('Y-m-d H:i');
  627. // $eduEst = ($edu->add(new \DateInterval('PT' . $estimated[0] . 'H' . $estimated[1] . 'M')));
  628. // $bookingStartUndispatchedPickup = ($stu->add(new \DateInterval('PT' . $undispatched_interval_between_bookings_pickup . 'H')))->format('Y-m-d H:i');
  629. // $bookingEndUndispatchedDropoff = ($eduEst->add(new \DateInterval('PT' . $undispatched_interval_between_bookings_dropoff . 'H')))->format('Y-m-d H:i');
  630. // foreach ($excludedBookingTimes as $exDate) {
  631. // if (($bookingPickup >= $exDate['startDate'] and $bookingPickup <= $exDate['endDate']) or
  632. // ($bookingEndEstimated >= $exDate['startDate'] and $bookingEndEstimated <= $exDate['endDate']) or
  633. // ($bookingStartUndispatchedPickup >= $exDate['startDate'] and $bookingStartUndispatchedPickup <= $exDate['endDate']) or
  634. // ($bookingEndUndispatchedDropoff >= $exDate['startDate'] and $bookingEndUndispatchedDropoff <= $exDate['endDate'])
  635. // ) {
  636. // unset($bookings[$key]);
  637. // }
  638. // }
  639. $bookingPickup = $fBook->getPickUpDateTime();
  640. $before = $undispatched_interval_between_bookings_pickup;
  641. $after = $undispatched_interval_between_bookings_dropoff;
  642. $startBefore = clone $bookingPickup;
  643. $startAfter = clone $bookingPickup;
  644. $endDate = clone $bookingPickup;
  645. $startBefore = $startBefore->add(new \DateInterval('PT'. $before. 'H'));
  646. $startAfter = $startAfter->sub(new \DateInterval('PT'. $after. 'H'));
  647. $estimated = explode(':', $fBook->getEstimatedTime());
  648. $estimatedInterval = new \DateInterval('PT'. $estimated[0]. 'H'. $estimated[1]. 'M');
  649. $endDate->add($estimatedInterval);
  650. $endBefore = clone $endDate;
  651. $endAfter = clone $endDate;
  652. $endBefore = $endBefore->add(new \DateInterval('PT'. $before. 'H'));
  653. $endAfter = $endAfter->sub(new \DateInterval('PT'. $after. 'H'));
  654. // Logic:
  655. // If booking times (pickup or dropoff) are between:
  656. // [
  657. // $b hours (margin) before the assigned booking's pickup
  658. // and
  659. // $a hours (margin) after the assigned booking's dropoff
  660. // ]
  661. // Comp: $aS - $b <= $date <= $aE + $a
  662. // Simplified: $aS <= $date + $b && $date - $a <= $aE
  663. foreach ($excludedBookingTimes as $assigned) {
  664. $aS = $assigned['startDate'];
  665. $aE = $assigned['endDate'];
  666. if (
  667. // pickup is in between the assigned booking's dates with margins
  668. ($aS <= $startBefore && $startAfter <= $aE) ||
  669. // dropoff is in between the assigned booking's dates with margins
  670. ($aS <= $endBefore && $endAfter <= $aE)
  671. ) {
  672. unset($bookings[$key]);
  673. }
  674. }
  675. // No point doing extra checks if booking was already removed.
  676. if (isset($bookings[$key]) && $day == null) {
  677. $driver_rating_max_limit = floatval($settingsRepo->findOneByKey('driver_rating_max_limit')->getValue());
  678. $driver_current_rating = floatval($driver->getOverallRating());
  679. if ($driver_current_rating < $driver_rating_max_limit) {
  680. $vehicle_undispatched_max_price = (!empty($driver->getCar()->getType()) && !empty($driver->getCar()->getType()->getMaxPriceUndispatchedBooking())) ? floatval($driver->getCar()->getType()->getMaxPriceUndispatchedBooking()) : 0;
  681. if ($vehicle_undispatched_max_price > 0) {
  682. if (!empty($fBook->getDriverPrice())) {
  683. if ($fBook->getDriverPrice() > $vehicle_undispatched_max_price) {
  684. unset($bookings[$key]);
  685. }
  686. } else {
  687. if (!empty($fBook->getOverridePrice())) {
  688. if ($fBook->getOverridePrice() > $vehicle_undispatched_max_price) {
  689. unset($bookings[$key]);
  690. }
  691. } else {
  692. if ($fBook->getQuotePrice() > $vehicle_undispatched_max_price) {
  693. unset($bookings[$key]);
  694. }
  695. }
  696. }
  697. }
  698. }
  699. }
  700. }
  701. }
  702. return $bookings;
  703. }
  704. /**
  705. * @param int $day
  706. * @param Booking $booking
  707. *
  708. * @return bool
  709. */
  710. private function checkUnassignedDate($day, Booking $booking)
  711. {
  712. $settingsRepo = $this->getEntityManager()->getRepository(Settings::class);
  713. $bookingHide7daysOver = $settingsRepo->findOneByKey('live_linked_hide_booking_7d_over3');
  714. $bookingHide7daysUnder = $settingsRepo->findOneByKey('live_linked_hide_booking_7d_under3');
  715. $bookingHide30days = $settingsRepo->findOneByKey('live_linked_hide_booking_30d');
  716. $now = new DateTime();
  717. $unset = false;
  718. $hideDiff = date_diff($now, $booking->getUnassignedHideAt());
  719. $hoursDiff = $hideDiff->h + ($hideDiff->days * 24);
  720. if ($day === 7) {
  721. $dateDiff = date_diff($booking->getPickUpDateTime(), $now);
  722. if (($dateDiff->days < 3 && $hoursDiff < $bookingHide7daysUnder)
  723. || ($dateDiff->days > 3 && $hoursDiff < $bookingHide7daysOver)
  724. ) {
  725. $unset = true;
  726. }
  727. }
  728. if ($day === 30 && $hoursDiff < $bookingHide30days) {
  729. $unset = true;
  730. }
  731. return $unset;
  732. }
  733. public function countBetweenDatesByStatusAndDriver(Driver $driver, DateTime $startDate, DateTime $endDate, $status = null)
  734. {
  735. $qb = $this
  736. ->createQueryBuilder('b')
  737. ->select('count(b.id)')
  738. ;
  739. if ($status) {
  740. $qb
  741. ->andWhere('b.status = :status')
  742. ->setParameter('status', $status)
  743. ;
  744. }
  745. $qb
  746. ->andWhere('b.driver = :driver')
  747. ->andWhere($qb->expr()->between('b.pickUpDateTime', ':startDatePickUp', ':endDatePickUp'))
  748. ->setParameter('driver', $driver)
  749. ->setParameter('startDatePickUp', $startDate)
  750. ->setParameter('endDatePickUp', $endDate)
  751. ;
  752. return intval($qb->getQuery()->getSingleScalarResult());
  753. }
  754. /**
  755. * @param string $search
  756. *
  757. * @return array
  758. */
  759. public function searchByKey(string $search = null)
  760. {
  761. $qb = $this
  762. ->createQueryBuilder('b')
  763. ->select('
  764. b.key AS bookingKey, c.id AS clientId, c.firstname AS clientFirstName,
  765. c.lastname AS clientLastName, c.phone AS clientPhone, c.email AS clientEmail
  766. ')
  767. ->leftJoin('b.clientUser', 'c')
  768. ->addSelect('
  769. du.id AS driverId, du.firstname AS driverFirstName,
  770. du.lastname AS driverLastName, du.phone AS driverPhone, du.email AS driverEmail
  771. ')
  772. ->leftJoin('b.driver', 'd')
  773. ->leftJoin('d.user', 'du')
  774. ;
  775. if ($search) {
  776. $qb
  777. ->andWhere('b.key LIKE :key')
  778. ->setParameter('key', "%{$search}%")
  779. ;
  780. }
  781. return $qb
  782. ->setMaxResults(15)
  783. ->getQuery()
  784. ->getArrayResult()
  785. ;
  786. }
  787. /**
  788. * @param Driver $driver
  789. * @param int $numberOfWeeks
  790. *
  791. * @return array
  792. */
  793. public function countCompletedBookingsPastWeeksByDriverId(int $driverId, int $numberOfWeeks)
  794. {
  795. $endDatePickUp = new DateTime('last sunday');
  796. $endDatePickUp->setTime(23, 59, 59);
  797. $startDatePickUp = clone $endDatePickUp;
  798. $startDatePickUp = $startDatePickUp->sub(new DateInterval("P{$numberOfWeeks}W"));
  799. $startDatePickUp = $startDatePickUp->add(new DateInterval('P1D'));
  800. $startDatePickUp->setTime(0, 0, 0);
  801. $qb = $this->createQueryBuilder('b')->select('count(b.id)');
  802. $qb
  803. ->innerJoin('b.driver', 'd')
  804. ->andWhere('d.id = :driverId')
  805. ->andWhere('b.status = :status')
  806. ->andWhere($qb->expr()->between('b.pickUpDateTime', ':startDatePickUp', ':endDatePickUp'))
  807. ->setParameter('driverId', $driverId)
  808. ->setParameter('status', Booking::STATUS_COMPLETED)
  809. ->setParameter('startDatePickUp', $startDatePickUp)
  810. ->setParameter('endDatePickUp', $endDatePickUp)
  811. ;
  812. return intval($qb->getQuery()->getSingleScalarResult());
  813. }
  814. }