| @@ -3,8 +3,9 @@ | ||
| 3 | 3 | namespace FluentBooking\App\Hooks\Handlers; |
| 4 | 4 | |
| 5 | 5 | use FluentBooking\App\Models\Booking; |
| 6 | 6 | use FluentBooking\App\Services\EmailNotificationService; |
| 7 | +use FluentBooking\App\Services\NotificationGate; | |
| 7 | 8 | use FluentBooking\Framework\Support\Arr; |
| 8 | 9 | |
| 9 | 10 | class NotificationHandler |
| 10 | 11 | { |
| @@ -10,13 +11,13 @@ | ||
| 10 | 11 | { |
| 11 | 12 | public function register() |
| 12 | 13 | { |
| 13 | 14 | add_action('fluent_booking/after_booking_scheduled', [$this, 'pushBookingScheduledToQueue'], 10, 2); |
| 14 | - add_action('fluent_booking/after_booking_scheduled_async', [$this, 'bookingScheduledEmails'], 10, 2); | |
| 15 | + add_action('fluent_booking/after_booking_scheduled_async', [$this, 'bookingScheduledEmails'], 10, 1); | |
| 15 | 16 | add_action('fluent_booking/after_booking_pending', [$this, 'pushBookingPendingToQueue'], 10, 2); |
| 16 | 17 | add_action('fluent_booking/after_booking_pending_async', [$this, 'bookingRequestEmails'], 10, 2); |
| 17 | 18 | add_action('fluent_booking/booking_schedule_reminder', [$this, 'bookingReminderEmails'], 10, 2); |
| 18 | - add_action('fluent_booking/after_booking_rescheduled', [$this, 'emailOnBookingRescheduled'], 10, 2); | |
| 19 | + add_action('fluent_booking/after_booking_rescheduled', [$this, 'emailOnBookingRescheduled'], 10, 3); | |
| 19 | 20 | add_action('fluent_booking/booking_schedule_cancelled', [$this, 'emailOnBookingCancelled'], 10, 2); |
| 20 | 21 | add_action('fluent_booking/booking_schedule_rejected', [$this, 'emailOnBookingRejected'], 10, 2); |
| 21 | 22 | add_action('fluent_booking/after_patch_booking_email', [$this, 'emailToUpdatedEmail'], 10, 2); |
| 22 | 23 | } |
| @@ -33,10 +34,15 @@ | ||
| 33 | 34 | |
| 34 | 35 | return $timestamp; |
| 35 | 36 | } |
| 36 | 37 | |
| 37 | - private function pushRemindersToQueue($booking, $slot, $reminderTimes, $emailTo) | |
| 38 | + private function pushRemindersToQueue($booking, $reminderTimes, $emailTo) | |
| 38 | 39 | { |
| 40 | + // A booking can be scheduled again (e.g. no_show back to scheduled); replace, don't stack. | |
| 41 | + \as_unschedule_all_actions('fluent_booking/booking_schedule_reminder', [$booking->id, $emailTo], 'fluent-booking'); | |
| 42 | + | |
| 43 | + $this->clearGroupRemindersForHost($booking, $emailTo); | |
| 44 | + | |
| 39 | 45 | foreach ($reminderTimes as $time) { |
| 40 | 46 | $reminderTimestamp = $this->getReminderTime($time); |
| 41 | 47 | |
| 42 | 48 | $happeningTimestamp = strtotime($booking->start_time); |
| @@ -51,40 +57,69 @@ | ||
| 51 | 57 | } |
| 52 | 58 | } |
| 53 | 59 | } |
| 54 | 60 | |
| 61 | + private function clearGroupRemindersForHost($booking, $emailTo) | |
| 62 | + { | |
| 63 | + if (!$booking->isMultiGuestBooking() || $emailTo != 'host') { | |
| 64 | + return; | |
| 65 | + } | |
| 66 | + | |
| 67 | + $otherBookingIds = Booking::where('group_id', $booking->group_id)->where('id', '!=', $booking->id)->pluck('id')->toArray(); | |
| 68 | + | |
| 69 | + foreach ($otherBookingIds as $otherBookingId) { | |
| 70 | + \as_unschedule_all_actions('fluent_booking/booking_schedule_reminder', [$otherBookingId, 'host'], 'fluent-booking'); | |
| 71 | + } | |
| 72 | + } | |
| 73 | + | |
| 55 | 74 | public function pushBookingScheduledToQueue($booking, $bookingEvent) |
| 56 | 75 | { |
| 57 | 76 | $notifications = $bookingEvent->getNotifications(); |
| 58 | 77 | |
| 59 | - if (Arr::isTrue($notifications, 'booking_conf_attendee.enabled') || (Arr::isTrue($notifications, 'booking_conf_host.enabled'))) { | |
| 60 | - as_enqueue_async_action('fluent_booking/after_booking_scheduled_async', [ | |
| 61 | - $booking->id, | |
| 62 | - $bookingEvent->id | |
| 63 | - ], 'fluent-booking'); | |
| 64 | - } | |
| 65 | - | |
| 66 | 78 | if (Arr::isTrue($notifications, 'reminder_to_attendee.enabled')) { |
| 67 | 79 | $reminderTimes = Arr::get($notifications, 'reminder_to_attendee.email.times', []); |
| 68 | - $this->pushRemindersToQueue($booking, $bookingEvent, $reminderTimes, 'guest'); | |
| 80 | + $this->pushRemindersToQueue($booking, $reminderTimes, 'guest'); | |
| 69 | 81 | } |
| 70 | 82 | |
| 71 | 83 | if (Arr::isTrue($notifications, 'reminder_to_host.enabled')) { |
| 72 | 84 | $reminderTimes = Arr::get($notifications, 'reminder_to_host.email.times', []); |
| 73 | - $this->pushRemindersToQueue($booking, $bookingEvent, $reminderTimes, 'host'); | |
| 85 | + $this->pushRemindersToQueue($booking, $reminderTimes, 'host'); | |
| 74 | 86 | } |
| 87 | + | |
| 88 | + if (!is_null($booking->parent_id) && $booking->isRecurringBooking()) { | |
| 89 | + return; | |
| 90 | + } | |
| 91 | + | |
| 92 | + if (NotificationGate::isSuppressed('booking_scheduled', $booking)) { | |
| 93 | + return; | |
| 94 | + } | |
| 95 | + | |
| 96 | + if (Arr::isTrue($notifications, 'booking_conf_attendee.enabled') || (Arr::isTrue($notifications, 'booking_conf_host.enabled'))) { | |
| 97 | + as_enqueue_async_action('fluent_booking/after_booking_scheduled_async', [ | |
| 98 | + $booking->id, | |
| 99 | + $bookingEvent->id | |
| 100 | + ], 'fluent-booking'); | |
| 101 | + } | |
| 75 | 102 | } |
| 76 | 103 | |
| 77 | 104 | public function pushBookingPendingToQueue($booking, $bookingEvent) |
| 78 | 105 | { |
| 79 | - if (!$bookingEvent->isConfirmationEnabled()) { | |
| 106 | + if (NotificationGate::isSuppressed('booking_pending', $booking)) { | |
| 80 | 107 | return; |
| 81 | 108 | } |
| 82 | 109 | |
| 110 | + if (!$bookingEvent->isConfirmationEnabled() || $bookingEvent->isMultiGuestEvent()) { | |
| 111 | + return; | |
| 112 | + } | |
| 113 | + | |
| 83 | 114 | if ($booking->payment_method && $booking->payment_status != 'paid') { |
| 84 | 115 | return; |
| 85 | 116 | } |
| 86 | 117 | |
| 118 | + if (!is_null($booking->parent_id) && $booking->isRecurringBooking()) { | |
| 119 | + return; | |
| 120 | + } | |
| 121 | + | |
| 87 | 122 | $notifications = $bookingEvent->getNotifications(); |
| 88 | 123 | |
| 89 | 124 | if (Arr::isTrue($notifications, 'booking_request_host.enabled') || (Arr::isTrue($notifications, 'booking_request_attendee.enabled'))) { |
| 90 | 125 | as_enqueue_async_action('fluent_booking/after_booking_pending_async', [ |
| @@ -95,8 +130,12 @@ | ||
| 95 | 130 | } |
| 96 | 131 | |
| 97 | 132 | public function emailToUpdatedEmail($booking, $calendarEvent) |
| 98 | 133 | { |
| 134 | + if (NotificationGate::isSuppressed('booking_email_changed', $booking)) { | |
| 135 | + return; | |
| 136 | + } | |
| 137 | + | |
| 99 | 138 | $notifications = $calendarEvent->getNotifications(); |
| 100 | 139 | |
| 101 | 140 | if (Arr::isTrue($notifications, 'booking_conf_attendee.enabled') || (Arr::isTrue($notifications, 'booking_conf_host.enabled'))) { |
| 102 | 141 | as_enqueue_async_action('fluent_booking/after_booking_scheduled_async', [ |
| @@ -105,9 +144,9 @@ | ||
| 105 | 144 | ], 'fluent-booking'); |
| 106 | 145 | } |
| 107 | 146 | } |
| 108 | 147 | |
| 109 | - public function bookingScheduledEmails($bookingId, $slotId) | |
| 148 | + public function bookingScheduledEmails($bookingId) | |
| 110 | 149 | { |
| 111 | 150 | $booking = Booking::with(['calendar', 'calendar_event'])->find($bookingId); |
| 112 | 151 | |
| 113 | 152 | if (!$booking || !$booking->calendar_event) { |
| @@ -153,9 +192,11 @@ | ||
| 153 | 192 | |
| 154 | 193 | if ('guest' == $emailTo && Arr::isTrue($notifications, 'reminder_to_attendee.enabled')) { |
| 155 | 194 | $email = Arr::get($notifications, 'reminder_to_attendee.email', []); |
| 156 | 195 | EmailNotificationService::reminderEmail($booking, $email, $emailTo); |
| 157 | - } elseif ('host' == $emailTo && Arr::isTrue($notifications, 'reminder_to_host.enabled')) { | |
| 196 | + } | |
| 197 | + | |
| 198 | + if ('host' == $emailTo && Arr::isTrue($notifications, 'reminder_to_host.enabled')) { | |
| 158 | 199 | $email = Arr::get($notifications, 'reminder_to_host.email', []); |
| 159 | 200 | $additionalRecipients = Arr::get($email, 'additional_recipients', false); |
| 160 | 201 | if ($additionalRecipients) { |
| 161 | 202 | $email['recipients'] = $this->getAdditionalRecipients($additionalRecipients); |
| @@ -192,19 +233,20 @@ | ||
| 192 | 233 | } |
| 193 | 234 | |
| 194 | 235 | public function getAdditionalRecipients($additionalRecipients) |
| 195 | 236 | { |
| 196 | - if ($additionalRecipients) { | |
| 197 | - $recipients = explode(',', $additionalRecipients); | |
| 198 | - $recipients = array_map('trim', $recipients); | |
| 199 | - return array_unique($recipients); | |
| 237 | + if (!$additionalRecipients) { | |
| 238 | + return []; | |
| 200 | 239 | } |
| 201 | - return []; | |
| 240 | + | |
| 241 | + $recipients = explode(',', $additionalRecipients); | |
| 242 | + $recipients = array_map('trim', $recipients); | |
| 243 | + return array_unique($recipients); | |
| 202 | 244 | } |
| 203 | 245 | |
| 204 | 246 | public function emailOnBookingCancelled(Booking $booking, $calendarEvent) |
| 205 | 247 | { |
| 206 | - if (!$calendarEvent) { | |
| 248 | + if (!$calendarEvent || NotificationGate::isSuppressed('booking_cancelled', $booking)) { | |
| 207 | 249 | return; |
| 208 | 250 | } |
| 209 | 251 | |
| 210 | 252 | $notifications = $calendarEvent->getNotifications(); |
| @@ -232,11 +274,10 @@ | ||
| 232 | 274 | EmailNotificationService::bookingCancelOrRejectEmail($booking, $email, 'host'); |
| 233 | 275 | } |
| 234 | 276 | } |
| 235 | 277 | |
| 236 | - public function emailOnBookingRescheduled(Booking $booking) | |
| 278 | + public function emailOnBookingRescheduled(Booking $booking, $oldBooking, $calendarEvent) | |
| 237 | 279 | { |
| 238 | - $calendarEvent = $booking->calendar_event; | |
| 239 | 280 | if (!$calendarEvent) { |
| 240 | 281 | return; |
| 241 | 282 | } |
| 242 | 283 | |
| @@ -244,8 +285,26 @@ | ||
| 244 | 285 | if (!$notifications) { |
| 245 | 286 | return; |
| 246 | 287 | } |
| 247 | 288 | |
| 289 | + // Remove all reminders | |
| 290 | + \as_unschedule_all_actions('fluent_booking/booking_schedule_reminder', [$oldBooking->id, 'host'], 'fluent-booking'); | |
| 291 | + \as_unschedule_all_actions('fluent_booking/booking_schedule_reminder', [$oldBooking->id, 'guest'], 'fluent-booking'); | |
| 292 | + | |
| 293 | + if (Arr::isTrue($notifications, 'reminder_to_attendee.enabled')) { | |
| 294 | + $reminderTimes = Arr::get($notifications, 'reminder_to_attendee.email.times', []); | |
| 295 | + $this->pushRemindersToQueue($booking, $reminderTimes, 'guest'); | |
| 296 | + } | |
| 297 | + | |
| 298 | + if (Arr::isTrue($notifications, 'reminder_to_host.enabled')) { | |
| 299 | + $reminderTimes = Arr::get($notifications, 'reminder_to_host.email.times', []); | |
| 300 | + $this->pushRemindersToQueue($booking, $reminderTimes, 'host'); | |
| 301 | + } | |
| 302 | + | |
| 303 | + if (NotificationGate::isSuppressed('booking_rescheduled', $booking)) { | |
| 304 | + return; | |
| 305 | + } | |
| 306 | + | |
| 248 | 307 | $rescheduledBy = $booking->getMeta('rescheduled_by_type', 'host'); |
| 249 | 308 | |
| 250 | 309 | if ($rescheduledBy == 'host') { |
| 251 | 310 | if (Arr::isTrue($notifications, 'rescheduled_by_host.enabled')) { |
| @@ -267,9 +326,9 @@ | ||
| 267 | 326 | } |
| 268 | 327 | |
| 269 | 328 | public function emailOnBookingRejected(Booking $booking, $calendarEvent) |
| 270 | 329 | { |
| 271 | - if (!$calendarEvent) { | |
| 330 | + if (!$calendarEvent || NotificationGate::isSuppressed('booking_rejected', $booking)) { | |
| 272 | 331 | return; |
| 273 | 332 | } |
| 274 | 333 | |
| 275 | 334 | $notifications = $calendarEvent->getNotifications(); |