PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / trunk
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution vtrunk
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
← All changes | app/Http/Controllers/SchedulesController.php +409 -104 1.5.22trunk View file →
@@ -1,126 +1,198 @@
1 1 <?php
2 2
3 3 namespace FluentBooking\App\Http\Controllers;
4 4
5 -use FluentBooking\App\App;
6 5 use FluentBooking\App\Models\Booking;
7 6 use FluentBooking\App\Models\Calendar;
7 +use FluentBooking\App\Models\CalendarSlot;
8 8 use FluentBooking\App\Models\BookingActivity;
9 -use FluentBooking\App\Models\Meta;
9 +use FluentBooking\Framework\Database\Orm\ModelNotFoundException;
10 10 use FluentBooking\App\Services\EmailNotificationService;
11 11 use FluentBooking\App\Services\Helper;
12 +use FluentBooking\Framework\Support\Arr;
12 13 use FluentBooking\App\Services\CurrenciesHelper;
13 -use FluentBooking\Framework\Support\Arr;
14 14 use FluentBooking\Framework\Http\Request\Request;
15 15 use FluentBooking\App\Services\PermissionManager;
16 16 use FluentBooking\App\Services\CalendarService;
17 +use FluentBooking\App\Services\ExportHelper;
18 +use FluentBooking\App\Services\Integrations\FluentCRM\CrmContactService;
19 +use FluentBooking\App\Services\Integrations\FluentCart\CustomerProfileService;
20 +use FluentCrm\App\Services\PermissionManager as CrmPermissionManager;
17 21
18 22 class SchedulesController extends Controller
19 23 {
20 24 public function index(Request $request)
21 25 {
22 - $filters = $request->get('filters', []);
26 + $author = $this->resolveAuthor($request);
23 27
24 - $period = Arr::get($filters, 'period', 'upcoming');
28 + $query = $this->buildSchedulesQuery($request, $author);
25 29
26 - $eventId = Arr::get($filters, 'event');
30 + $query->groupBy('group_id');
27 31
28 - $eventType = Arr::get($filters, 'event_type');
32 + $schedules = $query->paginate();
29 33
30 - $query = Booking::with(['calendar_event']);
34 + foreach ($schedules as $schedule) {
35 + $this->formatBooking($schedule);
36 + }
31 37
32 - $author = Arr::get($filters, 'author');
38 + $data = [
39 + 'schedules' => $schedules,
40 + 'timezone' => 'UTC'
41 + ];
33 42
34 - if ($author !== 'all') {
35 - $author = (int)$author;
43 + $data['calendar_event_lists'] = CalendarService::getCalendarOptionsByTitle();
44 +
45 + if ($author == 'me') {
46 + $slotOptions = CalendarService::getSlotOptions(null, get_current_user_id());
47 + $data['slot_options'] = $slotOptions;
36 48 }
37 49
38 - if (!PermissionManager::userCanSeeAllBookings()) {
39 - if (!$author || $author == 'all') {
40 - $authorCalendar = Calendar::where('user_id', get_current_user_id())
41 - ->where('type', 'simple')
42 - ->first();
43 - if($authorCalendar) {
44 - $author = $authorCalendar->id;
45 - }
46 - }
50 + if ($request->get('page') == 1) {
51 + $this->addCountsForFirstPage($author, $data);
47 52 }
48 53
49 - if ($author && $author !== 'all') {
50 - $query->where('calendar_id', $author);
54 + return $data;
55 + }
51 56
52 - if ($eventId && $eventId !== 'all') {
53 - $query->where('event_id', $eventId);
54 - }
57 + public function export(Request $request)
58 + {
59 + $limit = (int) apply_filters('fluent_booking/data_export_limit', 2000);
55 60
56 - if ($eventType && $eventType !== 'all') {
57 - $query->where('event_type', $eventType);
58 - }
61 + $author = $this->resolveAuthor($request);
62 +
63 + $query = $this->buildSchedulesQuery($request, $author);
64 +
65 + $relations = [
66 + 'calendar_event',
67 + 'user',
68 + 'booking_activities' => function ($q) {
69 + $q->where('type', 'cancel_reason');
70 + },
71 + 'booking_meta',
72 + ];
73 +
74 + if (defined('FLUENT_BOOKING_PRO_DIR_FILE')) {
75 + $relations[] = 'payment_order.transaction';
59 76 }
60 77
61 - do_action_ref_array('fluent_booking/schedules_query', [&$query]);
78 + $query->with($relations);
62 79
63 - $query->applyComputedStatus($period);
80 + $total = (clone $query)->withoutEagerLoads()->count();
81 + $limited = $total > $limit;
64 82
65 - if ($period == 'upcoming') {
66 - $query = $query->orderBy('start_time', 'ASC');
67 - } else if ($period == 'latest_bookings') {
68 - $query = $query->orderBy('created_at', 'DESC');
69 - } else if ($period == 'no_show') {
70 - $query = $query->orderBy('start_time', 'DESC');
71 - } else if ($period == 'latest_bookings') {
72 - $query = $query->orderBy('id', 'DESC');
83 + $bookings = $query->take($limit)->get();
84 +
85 + $rows = $bookings->map(function ($booking) {
86 + $row = ExportHelper::mapBooking($booking);
87 + return apply_filters('fluent_booking/booking_export_row', $row, $booking);
88 + })->all();
89 +
90 + $rows = apply_filters('fluent_booking/booking_export_columns', $rows, $bookings);
91 +
92 + return [
93 + 'bookings' => $rows,
94 + 'limited' => $limited,
95 + 'total' => $total,
96 + ];
97 + }
98 +
99 + protected function resolveAuthor(Request $request)
100 + {
101 + $author = Arr::get($request->get('filters', []), 'author');
102 +
103 + if (is_numeric($author)) {
104 + $author = (int) $author;
73 105 } else {
74 - $query = $query->orderBy('start_time', 'DESC');
106 + $author = sanitize_text_field($author);
75 107 }
76 108
77 - $query->groupBy('group_id');
109 + $hasPermission = PermissionManager::userCanSeeAllBookings();
78 110
79 - $search = Arr::get($filters, 'search');
111 + if ($hasPermission) {
112 + return $author;
113 + }
80 114
81 - if (!empty($search)) {
82 - $author = 'all';
83 - $query = $query->orderBy('start_time', 'DESC');
84 - $query = $query->searchBy($search);
115 + if (!$author || $author == 'all') {
116 + $authorCalendar = Calendar::where('user_id', get_current_user_id())
117 + ->where('type', 'simple')
118 + ->first();
119 +
120 + $author = $authorCalendar ? $authorCalendar->id : '';
85 121 }
86 122
87 - $schedules = $query->paginate();
123 + return $author;
124 + }
88 125
89 - foreach ($schedules as $schedule) {
90 - $this->formatBooking($schedule);
126 + protected function buildSchedulesQuery(Request $request, $author = null)
127 + {
128 + $filters = $request->get('filters', []);
129 + $search = $request->getSafe('search');
130 + $eventVal = Arr::get($filters, 'event');
131 + $eventId = is_numeric($eventVal) ? (int) $eventVal : 0;
132 + $eventType = sanitize_text_field(Arr::get($filters, 'event_type'));
133 + $period = sanitize_text_field(Arr::get($filters, 'period', 'upcoming'));
134 + $range = array_map('sanitize_text_field', Arr::get($filters, 'range', []));
135 + $email = sanitize_email(Arr::get($filters, 'email', ''));
136 +
137 + $allowedPeriods = ['upcoming', 'completed', 'cancelled', 'pending', 'no_show', 'latest_bookings', 'all'];
138 + if (!in_array($period, $allowedPeriods, true)) {
139 + $period = 'upcoming';
91 140 }
92 141
93 - $data = [
94 - 'schedules' => $schedules,
95 - 'timezone' => 'UTC'
96 - ];
142 + $query = Booking::with(['calendar_event']);
97 143
98 - $data['calendar_event_lists'] = CalendarService::getCalendarOptionsByTitle();
144 + $hasPermission = PermissionManager::userCanSeeAllBookings();
99 145
100 - if ($author && $author != 'all') {
101 - $slotOptions = CalendarService::getSlotOptions($author);
102 - $data['slot_options'] = $slotOptions;
146 + if (!$hasPermission || $author == 'me') {
147 + $query->where('host_user_id', get_current_user_id());
103 148 }
104 149
105 - if ($request->get('page') == 1) {
106 - $pendingQuery = Booking::query()
107 - ->whereIn('status', ['pending', 'reserved'])
108 - ->distinct('group_id');
109 - if ($author && $author !== 'all') {
110 - $pendingCount = $pendingQuery->where('calendar_id', $author)->count('group_id');
111 - } else {
112 - $pendingCount = $pendingQuery->count('group_id');
150 + if ($author && $author !== 'all') {
151 + if ($author != 'me') {
152 + $query->where('calendar_id', $author);
113 153 }
154 + if ($eventId > 0) {
155 + $query->where('event_id', $eventId);
156 + }
157 + if ($eventType && $eventType !== 'all') {
158 + $query->where('event_type', $eventType);
159 + }
160 + }
114 161
115 - $data['no_show_count'] = Booking::where('status', 'no_show')->count();
116 - $data['pending_count'] = $pendingCount;
117 - $data['cancelled_count'] = Booking::where('status', 'cancelled')->count();
162 + if (!empty($email) && is_email($email)) {
163 + $query->where('email', $email);
118 164 }
119 165
120 - return $data;
166 + do_action_ref_array('fluent_booking/schedules_query', [&$query]);
167 +
168 + $query->applyDateRangeFilter($range);
169 + $query->applyComputedStatus($period);
170 + $query->applyBookingOrderByStatus($period);
171 +
172 + if (!empty($search)) {
173 + $query->searchBy($search);
174 + }
175 +
176 + return $query;
121 177 }
122 178
179 + private function addCountsForFirstPage($author, &$data)
180 + {
181 + $bookingQuery = Booking::query()
182 + ->when(!PermissionManager::userCanSeeAllBookings() || $author == 'me', function($query) {
183 + return $query->where('host_user_id', get_current_user_id());
184 + })
185 + ->when($author && is_numeric($author), function($query) use ($author) {
186 + return $query->where('calendar_id', $author);
187 + })
188 + ->distinct('group_id');
189 +
190 + $data['pending_count'] = (clone $bookingQuery)->whereIn('status', ['pending', 'reserved'])->count('group_id');
191 + $data['no_show_count'] = (clone $bookingQuery)->where('status', 'no_show')->count('group_id');
192 + $data['cancelled_count'] = (clone $bookingQuery)->where('status', 'cancelled')->count('group_id');
193 + }
194 +
123 195 public function patchBooking(Request $request, $bookingId)
124 196 {
125 197 $booking = Booking::findOrFail($bookingId);
126 198 $oldBooking = clone $booking;
@@ -188,23 +260,37 @@
188 260
189 261 if ($value == 'cancelled') {
190 262 $cancelReason = sanitize_text_field($data['cancel_reason']);
191 263 $booking->cancelMeeting($cancelReason, 'host', get_current_user_id());
192 - return [
193 - 'message' => __('The booking has been cancelled', 'fluent-booking')
194 - ];
195 264 }
196 265
197 266 if ($value == 'rejected') {
198 267 $rejectReason = sanitize_text_field($data['reject_reason']);
199 268 $booking->rejectMeeting($rejectReason, get_current_user_id());
269 + }
270 +
271 + if (in_array($value, ['cancelled', 'rejected'])) {
272 + if ($booking->payment_method && Arr::get($data, 'refund_payment') == 'yes') {
273 + do_action('fluent_booking/refund_payment_' . $booking->payment_method, $booking, $booking->calendar_event);
274 + }
200 275 return [
201 - 'message' => __('The booking has been rejected', 'fluent-booking')
276 + /* translators: %s: Booking status */
277 + 'message' => sprintf(__('The booking has been %s', 'fluent-booking'), $value)
202 278 ];
203 279 }
204 280
205 - if ($booking->payment_method && Arr::get($data, 'refund_payment') == 'yes' && in_array($value, ['cancelled', 'rejected'])) {
206 - do_action('fluent_booking/refund_payment_' . $booking->payment_method, $booking, $booking->calendar_event);
281 + $updateAll = Arr::isTrue($data, 'update_all') && $booking->isMultiGuestBooking();
282 +
283 + if ($updateAll && in_array($value, ['no_show', 'completed'])) {
284 + Booking::where('event_id', $booking->event_id)
285 + ->where('group_id', $booking->group_id)
286 + ->update([
287 + 'status' => $value
288 + ]);
289 + return [
290 + /* translators: %s: Booking status */
291 + 'message' => sprintf(__('The booking has been %s', 'fluent-booking'), $value)
292 + ];
207 293 }
208 294 }
209 295
210 296 if ($column == 'payment_status') {
@@ -218,8 +304,12 @@
218 304
219 305 if ($value == 'pending') {
220 306 do_action('fluent_booking/log_booking_activity', $this->getPaymentPendingLog($booking->id));
221 307 }
308 +
309 + if ($booking->payment_order) {
310 + do_action('fluent_booking/payment/status_changed', $booking->payment_order, $booking, $value);
311 + }
222 312 }
223 313
224 314 $updateData[$column] = $value;
225 315 $booking->fill($updateData);
@@ -249,11 +339,9 @@
249 339 {
250 340 $booking = Booking::with('calendar_event');
251 341
252 342 if (!PermissionManager::userCanSeeAllBookings()) {
253 - $booking->whereHas('calendar', function ($q) {
254 - $q->where('user_id', get_current_user_id());
255 - });
343 + $booking->whereHostAccess(get_current_user_id());
256 344 }
257 345
258 346 $booking = $booking->findOrFail($bookingId);
259 347 $booking = $this->formatBooking($booking);
@@ -291,9 +379,9 @@
291 379 }
292 380
293 381 public function sendConfirmationEmail(Request $request, $bookingId)
294 382 {
295 - $booking = Booking::with(['calendar', 'calendar_event'])->find($bookingId);
383 + $booking = Booking::with(['calendar', 'calendar_event'])->findOrFail($bookingId);
296 384
297 385 $emailTo = $request->get('email_to', 'guest');
298 386
299 387 $notifications = $booking->calendar_event->getNotifications();
@@ -318,11 +406,9 @@
318 406 {
319 407 $booking = Booking::with('slot');
320 408
321 409 if (!PermissionManager::userCanSeeAllBookings()) {
322 - $booking->whereHas('calendar', function ($q) {
323 - $q->where('user_id', get_current_user_id());
324 - });
410 + $booking->whereHostAccess(get_current_user_id());
325 411 }
326 412
327 413 $booking = $booking->where('group_id', $groupId)->first();
328 414
@@ -330,9 +416,9 @@
330 416 return $this->sendError(['message' => __('Invalid group id or the event is not a group event', 'fluent-booking')]);
331 417 }
332 418
333 419 $attendees = Booking::where('group_id', $booking->group_id);
334 - $search = sanitize_text_field($request->get('search'));
420 + $search = $request->getSafe('search');
335 421
336 422 if (!empty($search)) {
337 423 $attendees = $attendees->searchBy($search);
338 424 }
@@ -348,8 +434,10 @@
348 434 }
349 435
350 436 public function getBookingActivities(Request $request, $bookingId)
351 437 {
438 + $this->resolveOwnedBookingOrFail($bookingId);
439 +
352 440 $activities = BookingActivity::where('booking_id', $bookingId)
353 441 ->orderBy('id', 'DESC')
354 442 ->get();
355 443
@@ -359,32 +447,52 @@
359 447 }
360 448
361 449 public function getBookingMetaInfo(Request $request, $bookingId)
362 450 {
363 - $booking = Booking::findOrFail($bookingId);
451 + $booking = $this->resolveOwnedBookingOrFail($bookingId);
364 452
365 453 $activities = BookingActivity::where('booking_id', $booking->id)
366 454 ->orderBy('id', 'DESC')
367 455 ->get();
456 +
457 + $activities->each(function ($activity) {
458 + $activity->description = wp_unslash($activity->description);
459 + });
368 460
369 461 $sidebarContents = [];
370 462 $mainBodyContents = [];
371 463
372 - if (defined('FLUENTCRM')) {
373 - $profileHtml = fluentcrm_get_crm_profile_html($booking->email, false);
374 - if ($profileHtml) {
375 - $sidebarContents[] = [
376 - 'id' => 'fluent_crm_profule',
377 - 'title' => __('CRM Profile', 'fluent-booking'),
378 - 'content' => $profileHtml
379 - ];
380 - }
464 + $canReadCrm = CrmContactService::isActive() && CrmPermissionManager::currentUserCan('fcrm_read_contacts');
465 + $crmProfile = $canReadCrm ? CrmContactService::getProfileData($booking->email) : null;
466 + if ($crmProfile) {
467 + $sidebarContents[] = [
468 + 'id' => 'fluent_crm_profule',
469 + 'title' => __('CRM Profile', 'fluent-booking'),
470 + 'type' => 'crm_profile',
471 + 'profile' => $crmProfile,
472 + ];
381 473 }
382 474
475 + $cartProfile = CustomerProfileService::canView()
476 + ? CustomerProfileService::getProfileData($booking->email)
477 + : null;
478 + if ($cartProfile) {
479 + $sidebarContents[] = [
480 + 'id' => 'fluent_cart_profile',
481 + 'title' => __('Cart Profile', 'fluent-booking'),
482 + 'type' => 'cart_profile',
483 + 'profile' => $cartProfile,
484 + ];
485 + }
486 +
383 487 $order = null;
384 - if ($booking->payment_method && $booking->payment_order) {
488 + if ($booking->payment_status && $booking->payment_order) {
385 489 $order = $booking->payment_order;
386 - $order->load(['items', 'transaction']);
490 + $relations = ['items', 'transaction'];
491 + if (method_exists($order, 'discounts')) {
492 + $relations[] = 'discounts';
493 + }
494 + $order->load($relations);
387 495 $order->currency_sign = CurrenciesHelper::getCurrencySign($order->currency);
388 496 }
389 497
390 498 $mainBodyContents = apply_filters('fluent_booking/booking_meta_info_main_meta', $mainBodyContents, $booking);
@@ -397,8 +505,198 @@
397 505 'main_body_contents' => $mainBodyContents
398 506 ];
399 507 }
400 508
509 + /**
510 + * Return the CRM contact state for a booking plus the full tag/list option
511 + * sets, so the admin can manage tags/lists inline from the CRM Profile card.
512 + */
513 + public function getCrmContact(Request $request, $bookingId)
514 + {
515 + $booking = $this->resolveOwnedBookingOrFail($bookingId);
516 +
517 + if (!CrmContactService::isActive()) {
518 + return $this->sendError([
519 + 'message' => __('FluentCRM is not active.', 'fluent-booking')
520 + ]);
521 + }
522 +
523 + if (!CrmPermissionManager::currentUserCan('fcrm_read_contacts')) {
524 + return $this->sendError([
525 + 'message' => __('You do not have permission to read CRM contacts.', 'fluent-booking')
526 + ], 403);
527 + }
528 +
529 + $state = CrmContactService::getContactState($booking->email);
530 +
531 + if (!$state) {
532 + return $this->sendError([
533 + 'message' => __('No CRM contact found for this booking.', 'fluent-booking')
534 + ], 404);
535 + }
536 +
537 + return $state;
538 + }
539 +
540 + /**
541 + * Guest-field prefill for the CRM "Book Appointment" action.
542 + * Keyed by contact id, so it carries its own CRM-read gate.
543 + */
544 + public function getCrmContactPrefill(Request $request)
545 + {
546 + if (!CrmContactService::isActive()) {
547 + return $this->sendError([
548 + 'message' => __('FluentCRM is not active.', 'fluent-booking')
549 + ]);
550 + }
551 +
552 + if (!CrmPermissionManager::currentUserCan('fcrm_read_contacts')) {
553 + return $this->sendError([
554 + 'message' => __('You do not have permission to read CRM contacts.', 'fluent-booking')
555 + ], 403);
556 + }
557 +
558 + $contactId = absint($request->get('contact_id'));
559 +
560 + if (!$contactId) {
561 + return $this->sendError([
562 + 'message' => __('Invalid contact.', 'fluent-booking')
563 + ], 422);
564 + }
565 +
566 + $prefill = CrmContactService::getBookingPrefillData($contactId);
567 +
568 + if (!$prefill) {
569 + return $this->sendError([
570 + 'message' => __('No CRM contact found.', 'fluent-booking')
571 + ], 404);
572 + }
573 +
574 + return [
575 + 'prefill' => $prefill,
576 + ];
577 + }
578 +
579 + /**
580 + * Typeahead search for the admin booking modal's CRM contact picker.
581 + * Same intersection gate as getCrmContactPrefill: booking access (policy) AND fcrm_read_contacts.
582 + */
583 + public function searchCrmContacts(Request $request)
584 + {
585 + if (!CrmContactService::isActive()) {
586 + return $this->sendError([
587 + 'message' => __('FluentCRM is not active.', 'fluent-booking')
588 + ]);
589 + }
590 +
591 + if (!CrmPermissionManager::currentUserCan('fcrm_read_contacts')) {
592 + return $this->sendError([
593 + 'message' => __('You do not have permission to read CRM contacts.', 'fluent-booking')
594 + ], 403);
595 + }
596 +
597 + $search = sanitize_text_field($request->get('search', ''));
598 +
599 + return [
600 + 'contacts' => CrmContactService::searchContacts($search),
601 + ];
602 + }
603 +
604 + /**
605 + * Bounded, searchable tag/list options for the CRM Profile picker.
606 + */
607 + public function getCrmOptions(Request $request, $bookingId)
608 + {
609 + $this->resolveOwnedBookingOrFail($bookingId);
610 +
611 + if (!CrmContactService::isActive()) {
612 + return $this->sendError([
613 + 'message' => __('FluentCRM is not active.', 'fluent-booking')
614 + ]);
615 + }
616 +
617 + if (!CrmPermissionManager::currentUserCan('fcrm_read_contacts')) {
618 + return $this->sendError([
619 + 'message' => __('You do not have permission to read CRM contacts.', 'fluent-booking')
620 + ], 403);
621 + }
622 +
623 + $type = $request->get('type') === 'lists' ? 'lists' : 'tags';
624 + $search = sanitize_text_field($request->get('search', ''));
625 +
626 + return [
627 + 'options' => CrmContactService::getOptions($type, $search),
628 + ];
629 + }
630 +
631 + public function updateCrmTags(Request $request, $bookingId)
632 + {
633 + return $this->updateCrmTaxonomy($request, $bookingId, 'tags');
634 + }
635 +
636 + public function updateCrmLists(Request $request, $bookingId)
637 + {
638 + return $this->updateCrmTaxonomy($request, $bookingId, 'lists');
639 + }
640 +
641 + private function updateCrmTaxonomy(Request $request, $bookingId, $type)
642 + {
643 + $booking = $this->resolveOwnedBookingOrFail($bookingId);
644 +
645 + if (!CrmContactService::isActive()) {
646 + return $this->sendError([
647 + 'message' => __('FluentCRM is not active.', 'fluent-booking')
648 + ]);
649 + }
650 +
651 + if (!CrmPermissionManager::currentUserCan('fcrm_manage_contacts')) {
652 + return $this->sendError([
653 + 'message' => __('You do not have permission to manage CRM contacts.', 'fluent-booking')
654 + ], 403);
655 + }
656 +
657 + $requestKey = $type === 'tags' ? 'tag_ids' : 'list_ids';
658 + $desired = (array) $request->get($requestKey, []);
659 +
660 + $result = CrmContactService::syncTaxonomy($booking->email, $type, $desired);
661 +
662 + if ($result === null) {
663 + return $this->sendError([
664 + 'message' => __('No CRM contact found for this booking.', 'fluent-booking')
665 + ], 404);
666 + }
667 +
668 + return $this->sendSuccess(array_merge([
669 + 'message' => __('CRM contact updated successfully.', 'fluent-booking'),
670 + ], $result));
671 + }
672 +
673 + private function resolveOwnedBookingOrFail($bookingId)
674 + {
675 + $booking = Booking::findOrFail($bookingId);
676 +
677 + if (PermissionManager::userCanSeeAllBookings()) {
678 + return $booking;
679 + }
680 +
681 + $allowedIds = $booking->getHostIds();
682 +
683 + if (PermissionManager::userCan('manage_own_calendar')) {
684 + if ($event = CalendarSlot::find($booking->event_id)) {
685 + $allowedIds = array_merge($allowedIds, $event->getHostIds());
686 + }
687 + }
688 +
689 + if (in_array(get_current_user_id(), $allowedIds)) {
690 + return $booking;
691 + }
692 +
693 + $exception = new ModelNotFoundException();
694 + $exception->setModel(Booking::class, [$bookingId]);
695 + // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
696 + throw $exception;
697 + }
698 +
401 699 private function formatBooking(&$booking)
402 700 {
403 701 $autoCompleteTimeOut = (int) Helper::getGlobalAdminSetting('auto_complete_timing', 60) * 60; // 10 minutes
404 702
@@ -405,9 +703,10 @@
405 703 if (in_array($booking->status, ['scheduled', 'pending']) && (time() - strtotime($booking->end_time)) > $autoCompleteTimeOut) {
406 704 $bookingStatus = $booking->status == 'pending' ? 'cancelled' : 'completed';
407 705 $booking->status = $bookingStatus;
408 706 $booking->save();
409 - do_action('fluent_booking/booking_schedule_' . $bookingStatus, $booking, $booking->calendar_event);
707 + $hookName = $bookingStatus === 'cancelled' ? 'auto_cancelled' : $bookingStatus;
708 + do_action('fluent_booking/booking_schedule_' . $hookName, $booking, $booking->calendar_event);
410 709 }
411 710
412 711 if ($booking->isMultiHostBooking()) {
413 712 $booking->host_profiles = $booking->getHostProfiles();
@@ -421,8 +720,9 @@
421 720 }
422 721
423 722 $booking->title = $booking->getBookingTitle(true);
424 723 $booking->author = $booking->getHostDetails(false);
724 + $booking->details = $booking->getConfirmationData(true);
425 725 $booking->location = $booking->getLocationDetailsHtml();
426 726 $booking->reschedule_url = $booking->getRescheduleUrl();
427 727 $booking->happening_status = $booking->getOngoingStatus();
428 728 $booking->booking_status_text = $booking->getBookingStatus();
@@ -433,8 +733,19 @@
433 733
434 734 return $booking;
435 735 }
436 736
737 + private function getConfirmedBy()
738 + {
739 + $confirmedBy = 'host';
740 + $userId = get_current_user_id();
741 + if ($userId && $user = get_user_by('ID', $userId)) {
742 + $confirmedBy = $user->display_name;
743 + }
744 +
745 + return $confirmedBy;
746 + }
747 +
437 748 private function getPaymentPaidLog($bookingId)
438 749 {
439 750 return [
440 751 'booking_id' => $bookingId,
@@ -440,9 +751,9 @@
440 751 'booking_id' => $bookingId,
441 752 'status' => 'closed',
442 753 'type' => 'success',
443 754 'title' => __('Payment Successfully Completed', 'fluent-booking'),
444 - 'description' => __('Payment marked as paid by admin', 'fluent-booking')
755 + 'description' => __('Payment marked as paid by ', 'fluent-booking') . $this->getConfirmedBy()
445 756 ];
446 757 }
447 758
448 759 private function getPaymentPendingLog($bookingId)
@@ -451,25 +762,19 @@
451 762 'booking_id' => $bookingId,
452 763 'status' => 'closed',
453 764 'type' => 'success',
454 765 'title' => __('Payment Successfully Marked as Pending', 'fluent-booking'),
455 - 'description' => __('Payment marked as pending by admin', 'fluent-booking')
766 + 'description' => __('Payment marked as pending by ', 'fluent-booking') . $this->getConfirmedBy()
456 767 ];
457 768 }
458 769
459 770 private function getConfirmLog($bookingId)
460 771 {
461 - $confirmedBy = 'host';
462 - $userId = get_current_user_id();
463 - if ($userId && $user = get_user_by('ID', $userId)) {
464 - $confirmedBy = $user->display_name;
465 - }
466 -
467 772 return [
468 773 'booking_id' => $bookingId,
469 774 'status' => 'closed',
470 775 'type' => 'success',
471 776 'title' => __('Booking Confirmed', 'fluent-booking'),
472 - 'description' => __('Booking has been confirmed by ', 'fluent-booking') . $confirmedBy
777 + 'description' => __('Booking has been confirmed by ', 'fluent-booking') . $this->getConfirmedBy()
473 778 ];
474 779 }
475 780 }