PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.11
Booking for Appointments and Events Calendar – Amelia v1.2.11
2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Infrastructure / Repository / Notification / NotificationLogRepository.php
ameliabooking / src / Infrastructure / Repository / Notification Last commit date
NotificationLogRepository.php 2 years ago NotificationRepository.php 2 years ago NotificationSMSHistoryRepository.php 2 years ago NotificationsToEntitiesRepository.php 4 years ago
NotificationLogRepository.php
1059 lines
1 <?php
2
3 namespace AmeliaBooking\Infrastructure\Repository\Notification;
4
5 use AmeliaBooking\Domain\Collection\Collection;
6 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
7 use AmeliaBooking\Domain\Entity\Entities;
8 use AmeliaBooking\Domain\Entity\Notification\Notification;
9 use AmeliaBooking\Domain\Entity\User\AbstractUser;
10 use AmeliaBooking\Domain\Factory\Booking\Appointment\AppointmentFactory;
11 use AmeliaBooking\Domain\Factory\Booking\Event\EventFactory;
12 use AmeliaBooking\Domain\Factory\Notification\NotificationLogFactory;
13 use AmeliaBooking\Domain\Factory\User\UserFactory;
14 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
15 use AmeliaBooking\Domain\ValueObjects\String\Status;
16 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
17 use AmeliaBooking\Infrastructure\Connection;
18 use AmeliaBooking\Infrastructure\Repository\AbstractRepository;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsToEventsPeriodsTable;
20 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsToExtrasTable;
21 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsPeriodsTable;
22 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsProvidersTable;
23 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsTable;
24 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Coupon\CouponsTable;
25 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Payment\PaymentsTable;
26
27 /**
28 * Class NotificationLogRepository
29 *
30 * @package AmeliaBooking\Infrastructure\Repository\Notification
31 */
32 class NotificationLogRepository extends AbstractRepository
33 {
34 const FACTORY = NotificationLogFactory::class;
35
36 /** @var string */
37 protected $notificationsTable;
38
39 /** @var string */
40 protected $appointmentsTable;
41
42 /** @var string */
43 protected $bookingsTable;
44
45 /** @var string */
46 protected $usersTable;
47
48 /**
49 * NotificationLogRepository constructor.
50 *
51 * @param Connection $connection
52 * @param string $table
53 * @param string $notificationsTable
54 * @param string $appointmentsTable
55 * @param string $bookingsTable
56 * @param string $usersTable
57 */
58 public function __construct(
59 Connection $connection,
60 $table,
61 $notificationsTable,
62 $appointmentsTable,
63 $bookingsTable,
64 $usersTable
65 ) {
66 parent::__construct($connection, $table);
67 $this->notificationsTable = $notificationsTable;
68 $this->appointmentsTable = $appointmentsTable;
69 $this->bookingsTable = $bookingsTable;
70 $this->usersTable = $usersTable;
71 }
72
73 /**
74 * @param Notification $notification
75 * @param int|null $userId
76 * @param int|null $appointmentId
77 * @param int|null $eventId
78 * @param int|null $packageCustomerId
79 * @param string|null $data
80 *
81 * @return int
82 *
83 * @throws QueryExecutionException
84 * @throws \Exception
85 */
86 public function add($notification, $userId, $appointmentId = null, $eventId = null, $packageCustomerId = null, $data = null)
87 {
88 $notificationData = $notification->toArray();
89
90 $params = [
91 ':notificationId' => $notificationData['id'],
92 ':userId' => $userId,
93 ':appointmentId' => $appointmentId,
94 ':packageCustomerId' => $packageCustomerId,
95 ':eventId' => $eventId,
96 ':sentDateTime' => DateTimeService::getNowDateTimeInUtc(),
97 ':data' => $data,
98 ];
99
100 try {
101 $statement = $this->connection->prepare(
102 "INSERT INTO {$this->table}
103 (`notificationId`, `userId`, `appointmentId`, `eventId`, `packageCustomerId`, `sentDateTime`, `sent`, `data`)
104 VALUES (:notificationId, :userId, :appointmentId, :eventId, :packageCustomerId, :sentDateTime, 0, :data)"
105 );
106
107 $res = $statement->execute($params);
108
109 if (!$res) {
110 throw new QueryExecutionException('Unable to add data in ' . __CLASS__);
111 }
112
113 return $this->connection->lastInsertId();
114 } catch (\Exception $e) {
115 throw new QueryExecutionException('Unable to add data in ' . __CLASS__, $e->getCode(), $e);
116 }
117 }
118
119 /**
120 * @param int $entityId
121 * @param string $entityType
122 * @param int $userId
123 * @param array $notificationsIds
124 *
125 * @return void
126 * @throws QueryExecutionException
127 */
128 public function invalidateSentEmails($entityId, $entityType, $userId, $notificationsIds)
129 {
130 if (empty($notificationsIds)) {
131 return;
132 }
133
134 $params = [
135 ":$entityType" . 'Id' => $entityId,
136 ];
137
138 $userQuery = '';
139
140 if ($userId) {
141 $params[':userId'] = $userId;
142
143 $userQuery = ' AND userId = :userId';
144 }
145
146 $queryNotificationsIds = [];
147
148 foreach ($notificationsIds as $index => $value) {
149 $param = ':notificationId' . $index;
150
151 $queryNotificationsIds[] = $param;
152
153 $params[$param] = $value;
154 }
155
156 try {
157 $statement = $this->connection->prepare(
158 "UPDATE {$this->table} SET
159 `sent` = -1
160 WHERE
161 {$entityType}Id = :{$entityType}Id
162 AND notificationId IN (" . implode(', ', $queryNotificationsIds) . ')'
163 . $userQuery
164 );
165
166 $res = $statement->execute($params);
167
168 if (!$res) {
169 throw new QueryExecutionException('Unable to save data in ' . __CLASS__);
170 }
171 } catch (\Exception $e) {
172 throw new QueryExecutionException('Unable to save data in ' . __CLASS__, $e->getCode(), $e);
173 }
174 }
175
176 /**
177 * Return a collection of tomorrow appointments where customer notification is not sent and should be.
178 *
179 * @param int $notificationId
180 * @param bool $nextDay
181 * @param array $statuses
182 *
183 * @return Collection
184 *
185 * @throws InvalidArgumentException
186 * @throws QueryExecutionException
187 * @throws \Exception
188 */
189 public function getCustomersNextDayAppointments($notificationId, $nextDay = true, $statuses = [])
190 {
191 $couponsTable = CouponsTable::getTableName();
192
193 $customerBookingsExtrasTable = CustomerBookingsToExtrasTable::getTableName();
194
195 $paymentsTable = PaymentsTable::getTableName();
196
197 $startDate = DateTimeService::getCustomDateTimeObjectInUtc(
198 DateTimeService::getNowDateTimeObject()->setTime(0, 0, 0)->format('Y-m-d H:i:s')
199 );
200
201 $endDate = DateTimeService::getCustomDateTimeObjectInUtc(
202 DateTimeService::getNowDateTimeObject()->setTime(23, 59, 59)->format('Y-m-d H:i:s')
203 );
204
205 if ($nextDay) {
206 $startDate = $startDate->modify('+1 day');
207 $endDate = $endDate->modify('+1 day');
208 }
209
210 $startCurrentDate = "STR_TO_DATE('" . $startDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
211
212 $endCurrentDate = "STR_TO_DATE('" . $endDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
213
214 $whereStatuses = [];
215
216 foreach ($statuses as $key => $status) {
217 $whereStatuses[] = "cb.status = '$status'";
218 }
219
220 $whereStatuses = $whereStatuses ? 'AND (' . implode(' OR ', $whereStatuses) . ')' : '';
221
222 try {
223 $statement = $this->connection->query(
224 "SELECT
225 a.id AS appointment_id,
226 a.bookingStart AS appointment_bookingStart,
227 a.bookingEnd AS appointment_bookingEnd,
228 a.notifyParticipants AS appointment_notifyParticipants,
229 a.serviceId AS appointment_serviceId,
230 a.providerId AS appointment_providerId,
231 a.locationId AS appointment_locationId,
232 a.internalNotes AS appointment_internalNotes,
233 a.status AS appointment_status,
234 a.zoomMeeting AS appointment_zoom_meeting,
235 a.lessonSpace AS appointment_lesson_space,
236 a.googleMeetUrl AS appointment_google_meet_url,
237
238 cb.id AS booking_id,
239 cb.customerId AS booking_customerId,
240 cb.status AS booking_status,
241 cb.price AS booking_price,
242 cb.customFields AS booking_customFields,
243 cb.info AS booking_info,
244 cb.utcOffset AS booking_utcOffset,
245 cb.aggregatedPrice AS booking_aggregatedPrice,
246 cb.persons AS booking_persons,
247 cb.duration AS booking_duration,
248 cb.created AS booking_created,
249
250 p.id AS payment_id,
251 p.amount AS payment_amount,
252 p.dateTime AS payment_dateTime,
253 p.status AS payment_status,
254 p.gateway AS payment_gateway,
255 p.gatewayTitle AS payment_gatewayTitle,
256 p.data AS payment_data,
257
258 cbe.id AS bookingExtra_id,
259 cbe.extraId AS bookingExtra_extraId,
260 cbe.customerBookingId AS bookingExtra_customerBookingId,
261 cbe.quantity AS bookingExtra_quantity,
262 cbe.price AS bookingExtra_price,
263 cbe.aggregatedPrice AS bookingExtra_aggregatedPrice,
264
265 c.id AS coupon_id,
266 c.code AS coupon_code,
267 c.discount AS coupon_discount,
268 c.deduction AS coupon_deduction,
269 c.limit AS coupon_limit,
270 c.customerLimit AS coupon_customerLimit,
271 c.status AS coupon_status
272 FROM {$this->appointmentsTable} a
273 INNER JOIN {$this->bookingsTable} cb ON cb.appointmentId = a.id
274 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
275 LEFT JOIN {$customerBookingsExtrasTable} cbe ON cbe.customerBookingId = cb.id
276 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
277 WHERE a.bookingStart BETWEEN $startCurrentDate AND $endCurrentDate
278 {$whereStatuses}
279 AND a.notifyParticipants = 1 AND
280 a.id NOT IN (
281 SELECT nl.appointmentId
282 FROM {$this->table} nl
283 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
284 WHERE n.id = {$notificationId} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.appointmentId IS NOT NULL
285 )"
286 );
287
288 $rows = $statement->fetchAll();
289 } catch (\Exception $e) {
290 throw new QueryExecutionException('Unable to find appointments in ' . __CLASS__, $e->getCode(), $e);
291 }
292
293 return AppointmentFactory::createCollection($rows);
294 }
295
296 /**
297 * Return a collection of tomorrow events where customer notification is not sent and should be.
298 *
299 * @param $notificationId
300 *
301 * @return Collection
302 *
303 * @throws InvalidArgumentException
304 * @throws QueryExecutionException
305 * @throws \Exception
306 */
307 public function getCustomersNextDayEvents($notificationId, $nextDay = true)
308 {
309 $couponsTable = CouponsTable::getTableName();
310 $paymentsTable = PaymentsTable::getTableName();
311 $eventsTable = EventsTable::getTableName();
312
313 $eventsPeriodsTable = EventsPeriodsTable::getTableName();
314
315 $customerBookingsEventsPeriods = CustomerBookingsToEventsPeriodsTable::getTableName();
316
317 $eventsProvidersTable = EventsProvidersTable::getTableName();
318
319 $startDate = DateTimeService::getCustomDateTimeObjectInUtc(
320 DateTimeService::getNowDateTimeObject()->setTime(0, 0, 0)->format('Y-m-d H:i:s')
321 );
322 $endDate = DateTimeService::getCustomDateTimeObjectInUtc(
323 DateTimeService::getNowDateTimeObject()->setTime(23, 59, 59)->format('Y-m-d H:i:s')
324 );
325
326 if ($nextDay) {
327 $startDate = $startDate->modify('+1 day');
328 $endDate = $endDate->modify('+1 day');
329 }
330
331 $startCurrentDate = "STR_TO_DATE('" . $startDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
332 $endCurrentDate = "STR_TO_DATE('" . $endDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
333
334 try {
335 $statement = $this->connection->query(
336 "SELECT
337 e.id AS event_id,
338 e.name AS event_name,
339 e.status AS event_status,
340 e.bookingOpens AS event_bookingOpens,
341 e.bookingCloses AS event_bookingCloses,
342 e.recurringCycle AS event_recurringCycle,
343 e.recurringOrder AS event_recurringOrder,
344 e.recurringUntil AS event_recurringUntil,
345 e.maxCapacity AS event_maxCapacity,
346 e.price AS event_price,
347 e.description AS event_description,
348 e.color AS event_color,
349 e.show AS event_show,
350 e.locationId AS event_locationId,
351 e.customLocation AS event_customLocation,
352 e.parentId AS event_parentId,
353 e.created AS event_created,
354 e.notifyParticipants AS event_notifyParticipants,
355 e.zoomUserId AS event_zoomUserId,
356 e.deposit AS event_deposit,
357 e.depositPayment AS event_depositPayment,
358 e.depositPerPerson AS event_depositPerPerson,
359 e.organizerId AS event_organizerId,
360
361 ep.id AS event_periodId,
362 ep.periodStart AS event_periodStart,
363 ep.periodEnd AS event_periodEnd,
364 ep.zoomMeeting AS event_periodZoomMeeting,
365 ep.lessonSpace AS event_periodLessonSpace,
366 ep.googleMeetUrl AS event_googleMeetUrl,
367
368 cb.id AS booking_id,
369 cb.customerId AS booking_customerId,
370 cb.status AS booking_status,
371 cb.price AS booking_price,
372 cb.customFields AS booking_customFields,
373 cb.info AS booking_info,
374 cb.utcOffset AS booking_utcOffset,
375 cb.aggregatedPrice AS booking_aggregatedPrice,
376 cb.persons AS booking_persons,
377 cb.created AS booking_created,
378
379 p.id AS payment_id,
380 p.amount AS payment_amount,
381 p.dateTime AS payment_dateTime,
382 p.status AS payment_status,
383 p.gateway AS payment_gateway,
384 p.gatewayTitle AS payment_gatewayTitle,
385 p.data AS payment_data,
386
387 pu.id AS provider_id,
388 pu.firstName AS provider_firstName,
389 pu.lastName AS provider_lastName,
390 pu.email AS provider_email,
391 pu.note AS provider_note,
392 pu.description AS provider_description,
393 pu.phone AS provider_phone,
394 pu.gender AS provider_gender,
395 pu.pictureFullPath AS provider_pictureFullPath,
396 pu.pictureThumbPath AS provider_pictureThumbPath,
397 pu.translations AS provider_translations,
398
399 c.id AS coupon_id,
400 c.code AS coupon_code,
401 c.discount AS coupon_discount,
402 c.deduction AS coupon_deduction,
403 c.limit AS coupon_limit,
404 c.customerLimit AS coupon_customerLimit,
405 c.status AS coupon_status
406 FROM {$eventsTable} e
407 INNER JOIN {$eventsPeriodsTable} ep ON ep.eventId = e.id
408 INNER JOIN {$customerBookingsEventsPeriods} cbe ON cbe.eventPeriodId = ep.id
409 INNER JOIN {$this->bookingsTable} cb ON cb.id = cbe.customerBookingId
410 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
411 LEFT JOIN {$eventsProvidersTable} epr ON epr.eventId = e.id
412 LEFT JOIN {$this->usersTable} pu ON pu.id = epr.userId
413 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
414 WHERE ep.periodStart BETWEEN {$startCurrentDate} AND {$endCurrentDate}
415 AND cb.status = 'approved'
416 AND e.status = 'approved'
417 AND e.notifyParticipants = 1 AND
418 e.id NOT IN (
419 SELECT nl.eventId
420 FROM {$this->table} nl
421 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
422 WHERE n.id = {$notificationId} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.eventId IS NOT NULL
423 )"
424 );
425
426 $rows = $statement->fetchAll();
427 } catch (\Exception $e) {
428 throw new QueryExecutionException('Unable to find appointments in ' . __CLASS__, $e->getCode(), $e);
429 }
430
431 return EventFactory::createCollection($rows);
432 }
433
434 /**
435 * Return a collection of tomorrow appointments where provider notification is not sent and should be.
436 *
437 * @param int $notificationId
438 * @param bool $nextDay
439 * @param array $statuses
440 *
441 * @return Collection
442 * @throws InvalidArgumentException
443 * @throws QueryExecutionException
444 * @throws \Exception
445 */
446 public function getProvidersNextDayAppointments($notificationId, $nextDay, $statuses)
447 {
448 $couponsTable = CouponsTable::getTableName();
449
450 $customerBookingsExtrasTable = CustomerBookingsToExtrasTable::getTableName();
451
452 $paymentsTable = PaymentsTable::getTableName();
453
454 $startDate = DateTimeService::getCustomDateTimeObjectInUtc(
455 DateTimeService::getNowDateTimeObject()->setTime(0, 0, 0)->format('Y-m-d H:i:s')
456 );
457
458 $endDate = DateTimeService::getCustomDateTimeObjectInUtc(
459 DateTimeService::getNowDateTimeObject()->setTime(23, 59, 59)->format('Y-m-d H:i:s')
460 );
461
462 if ($nextDay) {
463 $startDate = $startDate->modify('+1 day');
464 $endDate = $endDate->modify('+1 day');
465 }
466
467 $startCurrentDate = "STR_TO_DATE('" . $startDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
468
469 $endCurrentDate = "STR_TO_DATE('" . $endDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
470
471 $whereStatuses = [];
472
473 foreach ($statuses as $key => $status) {
474 $whereStatuses[] = "cb.status = '$status'";
475 }
476
477 $whereStatuses = $whereStatuses ? 'AND (' . implode(' OR ', $whereStatuses) . ')' : '';
478
479 try {
480 $statement = $this->connection->query(
481 "SELECT
482 a.id AS appointment_id,
483 a.bookingStart AS appointment_bookingStart,
484 a.bookingEnd AS appointment_bookingEnd,
485 a.notifyParticipants AS appointment_notifyParticipants,
486 a.serviceId AS appointment_serviceId,
487 a.providerId AS appointment_providerId,
488 a.locationId AS appointment_locationId,
489 a.internalNotes AS appointment_internalNotes,
490 a.status AS appointment_status,
491 a.zoomMeeting AS appointment_zoom_meeting,
492 a.lessonSpace AS appointment_lesson_space,
493 a.googleMeetUrl AS appointment_google_meet_url,
494
495 cb.id AS booking_id,
496 cb.customerId AS booking_customerId,
497 cb.status AS booking_status,
498 cb.price AS booking_price,
499 cb.customFields AS booking_customFields,
500 cb.persons AS booking_persons,
501 cb.aggregatedPrice AS booking_aggregatedPrice,
502 cb.duration AS booking_duration,
503 cb.created AS booking_created,
504
505 p.id AS payment_id,
506 p.amount AS payment_amount,
507 p.dateTime AS payment_dateTime,
508 p.status AS payment_status,
509 p.gateway AS payment_gateway,
510 p.gatewayTitle AS payment_gatewayTitle,
511 p.data AS payment_data,
512
513 cbe.id AS bookingExtra_id,
514 cbe.extraId AS bookingExtra_extraId,
515 cbe.customerBookingId AS bookingExtra_customerBookingId,
516 cbe.quantity AS bookingExtra_quantity,
517 cbe.price AS bookingExtra_price,
518 cbe.aggregatedPrice AS bookingExtra_aggregatedPrice,
519
520 c.id AS coupon_id,
521 c.code AS coupon_code,
522 c.discount AS coupon_discount,
523 c.deduction AS coupon_deduction,
524 c.limit AS coupon_limit,
525 c.customerLimit AS coupon_customerLimit,
526 c.status AS coupon_status
527 FROM {$this->appointmentsTable} a
528 INNER JOIN {$this->bookingsTable} cb ON cb.appointmentId = a.id
529 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
530 LEFT JOIN {$customerBookingsExtrasTable} cbe ON cbe.customerBookingId = cb.id
531 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
532 WHERE a.bookingStart BETWEEN $startCurrentDate AND $endCurrentDate
533 {$whereStatuses}
534 AND a.id NOT IN (
535 SELECT nl.appointmentId
536 FROM {$this->table} nl
537 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
538 WHERE n.id = {$notificationId} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.appointmentId IS NOT NULL
539 )"
540 );
541
542 $rows = $statement->fetchAll();
543 } catch (\Exception $e) {
544 throw new QueryExecutionException('Unable to find appointments in ' . __CLASS__, $e->getCode(), $e);
545 }
546
547 return AppointmentFactory::createCollection($rows);
548 }
549
550 /**
551 * Return a collection of tomorrow events where provider notification is not sent and should be.
552 *
553 * @param $notificationId
554 *
555 * @return Collection
556 * @throws InvalidArgumentException
557 * @throws QueryExecutionException
558 * @throws \Exception
559 */
560 public function getProvidersNextDayEvents($notificationId, $nextDay)
561 {
562 $couponsTable = CouponsTable::getTableName();
563 $eventsTable = EventsTable::getTableName();
564 $eventsPeriodsTable = EventsPeriodsTable::getTableName();
565 $customerBookingsEventsPeriods = CustomerBookingsToEventsPeriodsTable::getTableName();
566 $eventsProvidersTable = EventsProvidersTable::getTableName();
567 $paymentsTable = PaymentsTable::getTableName();
568
569 $startDate = DateTimeService::getCustomDateTimeObjectInUtc(
570 DateTimeService::getNowDateTimeObject()->setTime(0, 0, 0)->format('Y-m-d H:i:s')
571 );
572 $endDate = DateTimeService::getCustomDateTimeObjectInUtc(
573 DateTimeService::getNowDateTimeObject()->setTime(23, 59, 59)->format('Y-m-d H:i:s')
574 );
575
576 if ($nextDay) {
577 $startDate = $startDate->modify('+1 day');
578 $endDate = $endDate->modify('+1 day');
579 }
580
581 $startCurrentDate = "STR_TO_DATE('" . $startDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
582 $endCurrentDate = "STR_TO_DATE('" . $endDate->format('Y-m-d H:i:s') . "', '%Y-%m-%d %H:%i:%s')";
583
584
585 try {
586 $statement = $this->connection->query(
587 "SELECT
588 e.id AS event_id,
589 e.name AS event_name,
590 e.status AS event_status,
591 e.bookingOpens AS event_bookingOpens,
592 e.bookingCloses AS event_bookingCloses,
593 e.recurringCycle AS event_recurringCycle,
594 e.recurringOrder AS event_recurringOrder,
595 e.recurringUntil AS event_recurringUntil,
596 e.maxCapacity AS event_maxCapacity,
597 e.price AS event_price,
598 e.description AS event_description,
599 e.color AS event_color,
600 e.show AS event_show,
601 e.locationId AS event_locationId,
602 e.customLocation AS event_customLocation,
603 e.parentId AS event_parentId,
604 e.created AS event_created,
605 e.notifyParticipants AS event_notifyParticipants,
606 e.zoomUserId AS event_zoomUserId,
607 e.deposit AS event_deposit,
608 e.depositPayment AS event_depositPayment,
609 e.depositPerPerson AS event_depositPerPerson,
610 e.organizerId AS event_organizerId,
611
612 ep.id AS event_periodId,
613 ep.periodStart AS event_periodStart,
614 ep.periodEnd AS event_periodEnd,
615 ep.zoomMeeting AS event_periodZoomMeeting,
616 ep.lessonSpace AS event_periodLessonSpace,
617 ep.googleMeetUrl AS event_googleMeetUrl,
618
619 pu.id AS provider_id,
620 pu.firstName AS provider_firstName,
621 pu.lastName AS provider_lastName,
622 pu.email AS provider_email,
623 pu.note AS provider_note,
624 pu.description AS provider_description,
625 pu.phone AS provider_phone,
626 pu.gender AS provider_gender,
627 pu.pictureFullPath AS provider_pictureFullPath,
628 pu.pictureThumbPath AS provider_pictureThumbPath,
629 pu.timeZone AS provider_timeZone,
630
631 cb.id AS booking_id,
632 cb.customerId AS booking_customerId,
633 cb.status AS booking_status,
634 cb.price AS booking_price,
635 cb.customFields AS booking_customFields,
636 cb.persons AS booking_persons,
637 cb.created AS booking_created,
638
639 p.id AS payment_id,
640 p.amount AS payment_amount,
641 p.dateTime AS payment_dateTime,
642 p.status AS payment_status,
643 p.gateway AS payment_gateway,
644 p.gatewayTitle AS payment_gatewayTitle,
645 p.data AS payment_data,
646
647 c.id AS coupon_id,
648 c.code AS coupon_code,
649 c.discount AS coupon_discount,
650 c.deduction AS coupon_deduction,
651 c.limit AS coupon_limit,
652 c.customerLimit AS coupon_customerLimit,
653 c.status AS coupon_status
654 FROM {$eventsTable} e
655 INNER JOIN {$eventsPeriodsTable} ep ON ep.eventId = e.id
656 INNER JOIN {$customerBookingsEventsPeriods} cbe ON cbe.eventPeriodId = ep.id
657 INNER JOIN {$this->bookingsTable} cb ON cb.id = cbe.customerBookingId
658 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
659 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
660 LEFT JOIN {$eventsProvidersTable} epr ON epr.eventId = e.id
661 LEFT JOIN {$this->usersTable} pu ON pu.id = epr.userId
662 WHERE ep.periodStart BETWEEN {$startCurrentDate} AND {$endCurrentDate}
663 AND cb.status = 'approved'
664 AND e.status = 'approved'
665 AND e.id NOT IN (
666 SELECT nl.eventId
667 FROM {$this->table} nl
668 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
669 WHERE n.id = {$notificationId} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.eventId IS NOT NULL
670 )"
671 );
672
673 $rows = $statement->fetchAll();
674 } catch (\Exception $e) {
675 throw new QueryExecutionException('Unable to find events in ' . __CLASS__, $e->getCode(), $e);
676 }
677
678 return EventFactory::createCollection($rows);
679 }
680
681 /**
682 * Return a collection of today's past appointments where follow up notification is not sent and should be.
683 *
684 * @param Notification $notification
685 * @param array $statuses
686 *
687 * @return Collection
688 * @throws InvalidArgumentException
689 * @throws QueryExecutionException
690 */
691 public function getScheduledAppointments($notification, $statuses = [])
692 {
693 $couponsTable = CouponsTable::getTableName();
694 $customerBookingsExtrasTable = CustomerBookingsToExtrasTable::getTableName();
695 $paymentsTable = PaymentsTable::getTableName();
696
697 try {
698 $currentDateTime = "STR_TO_DATE('" . DateTimeService::getNowDateTimeInUtc() . "', '%Y-%m-%d %H:%i:%s')";
699
700 $where = '';
701 if ($notification->getTimeAfter()) {
702 $timeAfter = apply_filters('amelia_modify_scheduled_notification_time_after', $notification->getTimeAfter()->getValue(), $notification->toArray());
703 $lastTime = apply_filters('amelia_modify_scheduled_notification_last_time', $timeAfter + 259200, $notification->toArray());
704
705 $where = "{$currentDateTime} BETWEEN DATE_ADD(a.bookingEnd, INTERVAL {$timeAfter} SECOND) AND DATE_ADD(a.bookingEnd, INTERVAL {$lastTime} SECOND)";
706 } else if ($notification->getTimeBefore()) {
707 $timeBefore = apply_filters('amelia_modify_scheduled_notification_time_before', $notification->getTimeBefore()->getValue(), $notification->toArray());
708 $where = "({$currentDateTime} BETWEEN DATE_SUB(a.bookingStart, INTERVAL {$timeBefore} SECOND) AND a.bookingStart) AND (a.bookingStart >= DATE_ADD(cb.created, INTERVAL {$timeBefore} SECOND))";
709 }
710
711 $whereStatuses = [];
712
713 foreach ($statuses as $key => $status) {
714 $whereStatuses[] = "cb.status = '$status'";
715 }
716
717 $whereStatuses = $whereStatuses ? ($where ? ' AND ' : '') . '(' . implode(' OR ', $whereStatuses) . ')' : '';
718
719
720 $statement = $this->connection->query(
721 "SELECT
722 a.id AS appointment_id,
723 a.bookingStart AS appointment_bookingStart,
724 a.bookingEnd AS appointment_bookingEnd,
725 a.notifyParticipants AS appointment_notifyParticipants,
726 a.serviceId AS appointment_serviceId,
727 a.providerId AS appointment_providerId,
728 a.locationId AS appointment_locationId,
729 a.internalNotes AS appointment_internalNotes,
730 a.status AS appointment_status,
731 a.googleMeetUrl AS appointment_google_meet_url,
732 a.lessonSpace AS appointment_lesson_space,
733 a.zoomMeeting AS appointment_zoom_meeting,
734
735 cb.id AS booking_id,
736 cb.customerId AS booking_customerId,
737 cb.status AS booking_status,
738 cb.price AS booking_price,
739 cb.customFields AS booking_customFields,
740 cb.info AS booking_info,
741 cb.utcOffset AS booking_utcOffset,
742 cb.aggregatedPrice AS booking_aggregatedPrice,
743 cb.persons AS booking_persons,
744 cb.duration AS booking_duration,
745 cb.created AS booking_created,
746
747 p.id AS payment_id,
748 p.amount AS payment_amount,
749 p.dateTime AS payment_dateTime,
750 p.status AS payment_status,
751 p.gateway AS payment_gateway,
752 p.gatewayTitle AS payment_gatewayTitle,
753 p.data AS payment_data,
754
755 cbe.id AS bookingExtra_id,
756 cbe.extraId AS bookingExtra_extraId,
757 cbe.customerBookingId AS bookingExtra_customerBookingId,
758 cbe.quantity AS bookingExtra_quantity,
759 cbe.price AS bookingExtra_price,
760 cbe.aggregatedPrice AS bookingExtra_aggregatedPrice,
761
762 c.id AS coupon_id,
763 c.code AS coupon_code,
764 c.discount AS coupon_discount,
765 c.deduction AS coupon_deduction,
766 c.limit AS coupon_limit,
767 c.customerLimit AS coupon_customerLimit,
768 c.status AS coupon_status
769 FROM {$this->appointmentsTable} a
770 INNER JOIN {$this->bookingsTable} cb ON cb.appointmentId = a.id
771 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
772 LEFT JOIN {$customerBookingsExtrasTable} cbe ON cbe.customerBookingId = cb.id
773 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
774 WHERE {$where}
775 AND a.notifyParticipants = 1
776 {$whereStatuses}
777 AND a.id NOT IN (
778 SELECT nl.appointmentId
779 FROM {$this->table} nl
780 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
781 WHERE n.id = {$notification->getId()->getValue()} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.appointmentId IS NOT NULL
782 )"
783 );
784
785 $rows = $statement->fetchAll();
786 } catch (\Exception $e) {
787 throw new QueryExecutionException('Unable to find appointments in ' . __CLASS__, $e->getCode(), $e);
788 }
789
790 return AppointmentFactory::createCollection($rows);
791 }
792
793 /**
794 * Return a collection of today's past appointments where follow-up notification is not sent and should be.
795 *
796 * @param Notification $notification
797 *
798 * @return Collection
799 * @throws InvalidArgumentException
800 * @throws QueryExecutionException
801 */
802 public function getScheduledEvents($notification)
803 {
804 $eventsTable = EventsTable::getTableName();
805
806 $eventsPeriodsTable = EventsPeriodsTable::getTableName();
807
808 $customerBookingsEventsPeriods = CustomerBookingsToEventsPeriodsTable::getTableName();
809
810 $paymentsTable = PaymentsTable::getTableName();
811
812 $currentDateTime = "STR_TO_DATE('" . DateTimeService::getNowDateTimeInUtc() . "', '%Y-%m-%d %H:%i:%s')";
813
814 $where = "WHERE e.notifyParticipants = 1
815 AND cb.status = 'approved'
816 AND e.status = 'approved'
817 AND e.id NOT IN (
818 SELECT nl.eventId
819 FROM {$this->table} nl
820 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
821 WHERE n.id = {$notification->getId()->getValue()} AND (nl.sent IS NULL OR nl.sent = 1) AND nl.eventId IS NOT NULL
822 )";
823
824 if ($notification->getTimeAfter()) {
825 $timeAfter = $notification->getTimeAfter()->getValue();
826
827 $lastTime = $timeAfter + 432000;
828
829 $where .= " AND {$currentDateTime} BETWEEN DATE_ADD(ep.periodEnd, INTERVAL {$timeAfter} SECOND) AND DATE_ADD(ep.periodEnd, INTERVAL {$lastTime} SECOND)";
830 } else if ($notification->getTimeBefore()) {
831 $timeBefore = $notification->getTimeBefore()->getValue();
832
833 $where .= " AND ({$currentDateTime} BETWEEN DATE_SUB(ep.periodStart, INTERVAL {$timeBefore} SECOND) AND ep.periodStart) AND (ep.periodStart >= DATE_ADD(p.created, INTERVAL {$timeBefore} SECOND))";
834 }
835
836 try {
837 $statement = $this->connection->query(
838 "SELECT
839 e.id AS event_id,
840 e.name AS event_name,
841 e.status AS event_status,
842 e.bookingOpens AS event_bookingOpens,
843 e.bookingCloses AS event_bookingCloses,
844 e.recurringCycle AS event_recurringCycle,
845 e.recurringOrder AS event_recurringOrder,
846 e.recurringUntil AS event_recurringUntil,
847 e.recurringInterval AS event_recurringInterval,
848 e.bringingAnyone AS event_bringingAnyone,
849 e.bookMultipleTimes AS event_bookMultipleTimes,
850 e.maxCapacity AS event_maxCapacity,
851 e.price AS event_price,
852 e.description AS event_description,
853 e.color AS event_color,
854 e.show AS event_show,
855 e.locationId AS event_locationId,
856 e.customLocation AS event_customLocation,
857 e.parentId AS event_parentId,
858 e.created AS event_created,
859 e.notifyParticipants AS event_notifyParticipants,
860 e.zoomUserId AS event_zoomUserId,
861 e.deposit AS event_deposit,
862 e.depositPayment AS event_depositPayment,
863 e.depositPerPerson AS event_depositPerPerson,
864 e.organizerId AS event_organizerId,
865
866 ep.id AS event_periodId,
867 ep.periodStart AS event_periodStart,
868 ep.periodEnd AS event_periodEnd,
869 ep.lessonSpace AS event_periodLessonSpace,
870 ep.zoomMeeting AS event_periodZoomMeeting,
871 ep.googleMeetUrl AS event_googleMeetUrl,
872
873 cb.id AS booking_id,
874 cb.customerId AS booking_customerId,
875 cb.status AS booking_status,
876 cb.price AS booking_price,
877 cb.customFields AS booking_customFields,
878 cb.info AS booking_info,
879 cb.utcOffset AS booking_utcOffset,
880 cb.aggregatedPrice AS booking_aggregatedPrice,
881 cb.persons AS booking_persons,
882 cb.duration AS booking_duration,
883 cb.created AS booking_created
884 FROM {$eventsTable} e
885 INNER JOIN {$eventsPeriodsTable} ep ON ep.eventId = e.id
886 INNER JOIN {$customerBookingsEventsPeriods} cbe ON cbe.eventPeriodId = ep.id
887 INNER JOIN {$this->bookingsTable} cb ON cb.id = cbe.customerBookingId
888 LEFT JOIN {$paymentsTable} p ON p.customerBookingId = cb.id
889 {$where}"
890 );
891
892 $rows = $statement->fetchAll();
893 } catch (\Exception $e) {
894 throw new QueryExecutionException('Unable to find events in ' . __CLASS__, $e->getCode(), $e);
895 }
896
897 return EventFactory::createCollection($rows);
898 }
899
900 /**
901 * Returns a collection of customers that have birthday on today's date and where notification is not sent
902 *
903 * @param $notificationType
904 *
905 * @return Collection
906 * @throws InvalidArgumentException
907 * @throws QueryExecutionException
908 * @throws \Exception
909 */
910 public function getBirthdayCustomers($notificationType)
911 {
912 $currentDate = "STR_TO_DATE('" . DateTimeService::getNowDateTimeInUtc() . "', '%Y-%m-%d')";
913
914 $params = [
915 ':type' => AbstractUser::USER_ROLE_CUSTOMER,
916 ':statusVisible' => Status::VISIBLE,
917 ];
918
919 try {
920 $statement = $this->connection->prepare(
921 "SELECT * FROM {$this->usersTable} as u
922 WHERE
923 u.type = :type AND
924 u.status = :statusVisible AND
925 MONTH(u.birthday) = MONTH({$currentDate}) AND
926 DAY(u.birthday) = DAY({$currentDate}) AND
927 u.id NOT IN (
928 SELECT nl.userID
929 FROM {$this->table} nl
930 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
931 WHERE n.name = 'customer_birthday_greeting' AND n.type = '{$notificationType}' AND
932 YEAR(nl.sentDateTime) = YEAR({$currentDate}) AND (nl.sent IS NULL OR nl.sent = 1)
933 )"
934 );
935
936 $statement->execute($params);
937
938 $rows = $statement->fetchAll();
939 } catch (\Exception $e) {
940 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
941 }
942
943 $items = [];
944 foreach ($rows as $row) {
945 $items[] = call_user_func([UserFactory::class, 'create'], $row);
946 }
947
948 return new Collection($items);
949 }
950
951 /**
952 * Returns a collection of undelivered notifications
953 *
954 * @param string $type
955 *
956 * @return Collection
957 * @throws InvalidArgumentException
958 * @throws QueryExecutionException
959 */
960 public function getUndeliveredNotifications($type)
961 {
962 $params = [
963 ':type' => $type,
964 ];
965
966 $currentDateTime = "STR_TO_DATE('" . DateTimeService::getNowDateTimeInUtc() . "', '%Y-%m-%d %H:%i:%s')";
967
968 $pastDateTime =
969 "STR_TO_DATE('" .
970 DateTimeService::getNowDateTimeObjectInUtc()->modify('-1 day')->format('Y-m-d H:i:s') .
971 "', '%Y-%m-%d %H:%i:%s')";
972
973 try {
974 $statement = $this->connection->prepare(
975 "SELECT nl.* FROM {$this->table} nl
976 INNER JOIN {$this->notificationsTable} n ON nl.notificationId = n.id
977 WHERE
978 nl.sent = 0 AND
979 {$currentDateTime} > DATE_ADD(nl.sentDateTime, INTERVAL 300 SECOND) AND
980 {$pastDateTime} < nl.sentDateTime AND
981 nl.data IS NOT NULL AND
982 n.type = :type"
983 );
984
985 $statement->execute($params);
986
987 $rows = $statement->fetchAll();
988 } catch (\Exception $e) {
989 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
990 }
991
992 $items = [];
993
994 foreach ($rows as $row) {
995 $items[] = call_user_func([static::FACTORY, 'create'], $row);
996 }
997
998 return new Collection($items);
999 }
1000
1001 /**
1002 * @param int $userId
1003 * @param string $type
1004 * @param string $entityType
1005 * @param int $entityId
1006 *
1007 * @return Collection
1008 * @throws InvalidArgumentException
1009 * @throws QueryExecutionException
1010 */
1011 public function getSentNotificationsByUserAndEntity($userId, $type, $entityType, $entityId)
1012 {
1013 $entityColumn = '';
1014
1015 switch ($entityType) {
1016 case (Entities::APPOINTMENT):
1017 $entityColumn = 'nl.appointmentId';
1018
1019 break;
1020 case (Entities::EVENT):
1021 $entityColumn = 'nl.eventId';
1022
1023 break;
1024 case (Entities::PACKAGE):
1025 $entityColumn = 'nl.packageCustomerId';
1026
1027 break;
1028 }
1029
1030 $params = [
1031 ':entityId' => $entityId,
1032 ':userId' => $userId,
1033 ':type' => $type,
1034 ];
1035
1036 try {
1037 $statement = $this->connection->prepare(
1038 "SELECT * FROM {$this->table} nl
1039 WHERE nl.userId = :userId AND {$entityColumn} = :entityId AND nl.notificationId IN (SELECT id FROM {$this->notificationsTable} WHERE type = :type)
1040 ORDER BY nl.sentDateTime DESC"
1041 );
1042
1043 $statement->execute($params);
1044
1045 $rows = $statement->fetchAll();
1046 } catch (\Exception $e) {
1047 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
1048 }
1049
1050 $items = [];
1051
1052 foreach ($rows as $row) {
1053 $items[] = call_user_func([static::FACTORY, 'create'], $row);
1054 }
1055
1056 return new Collection($items);
1057 }
1058 }
1059