PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.6.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.6.0
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
fluent-booking / app / Http / Controllers / SchedulesController.php

SchedulesController.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.6.0, at app/Http/Controllers/SchedulesController.php

470 lines 16.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Http\Controllers;
4
5 use FluentBooking\App\App;
6 use FluentBooking\App\Models\Booking;
7 use FluentBooking\App\Models\Calendar;
8 use FluentBooking\App\Models\BookingActivity;
9 use FluentBooking\App\Models\Meta;
10 use FluentBooking\App\Services\EmailNotificationService;
11 use FluentBooking\App\Services\Helper;
12 use FluentBooking\App\Services\CurrenciesHelper;
13 use FluentBooking\Framework\Support\Arr;
14 use FluentBooking\Framework\Http\Request\Request;
15 use FluentBooking\App\Services\PermissionManager;
16 use FluentBooking\App\Services\CalendarService;
17
18 class SchedulesController extends Controller
19 {
20 public function index(Request $request)
21 {
22 $filters = $request->get('filters', []);
23
24 $period = Arr::get($filters, 'period', 'upcoming');
25
26 $eventId = Arr::get($filters, 'event');
27
28 $eventType = Arr::get($filters, 'event_type');
29
30 $query = Booking::with(['calendar_event']);
31
32 $author = Arr::get($filters, 'author');
33
34 if ($author !== 'all') {
35 $author = (int)$author;
36 }
37
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 }
47 }
48
49 if ($author && $author !== 'all') {
50 $query->where('calendar_id', $author);
51
52 if ($eventId && $eventId !== 'all') {
53 $query->where('event_id', $eventId);
54 }
55
56 if ($eventType && $eventType !== 'all') {
57 $query->where('event_type', $eventType);
58 }
59 }
60
61 do_action_ref_array('fluent_booking/schedules_query', [&$query]);
62
63 $query->applyComputedStatus($period);
64
65 $query->applyBookingOrderByStatus($period);
66
67 $query->groupBy('group_id');
68
69 $search = Arr::get($filters, 'search');
70
71 if (!empty($search)) {
72 $author = 'all';
73 $query = $query->orderBy('start_time', 'DESC');
74 $query = $query->searchBy($search);
75 }
76
77 $schedules = $query->paginate();
78
79 foreach ($schedules as $schedule) {
80 $this->formatBooking($schedule);
81 }
82
83 $data = [
84 'schedules' => $schedules,
85 'timezone' => 'UTC'
86 ];
87
88 $data['calendar_event_lists'] = CalendarService::getCalendarOptionsByTitle();
89
90 if ($author && $author != 'all') {
91 $slotOptions = CalendarService::getSlotOptions($author);
92 $data['slot_options'] = $slotOptions;
93 }
94
95 if ($request->get('page') == 1) {
96 $pendingQuery = Booking::query()
97 ->whereIn('status', ['pending', 'reserved'])
98 ->distinct('group_id');
99 if ($author && $author !== 'all') {
100 $pendingCount = $pendingQuery->where('calendar_id', $author)->count('group_id');
101 } else {
102 $pendingCount = $pendingQuery->count('group_id');
103 }
104
105 $data['no_show_count'] = Booking::where('status', 'no_show')->count();
106 $data['pending_count'] = $pendingCount;
107 $data['cancelled_count'] = Booking::where('status', 'cancelled')->count();
108 }
109
110 return $data;
111 }
112
113 public function patchBooking(Request $request, $bookingId)
114 {
115 $booking = Booking::findOrFail($bookingId);
116 $oldBooking = clone $booking;
117
118 $data = $request->all();
119
120 $this->validate($data, [
121 'column' => 'required',
122 ]);
123
124 do_action('fluent_booking/before_patch_booking_schedule', $booking, $data);
125
126 $value = $request->get('value');
127
128 $column = $data['column'];
129
130 if ($booking->{$column} == $value) {
131 return $this->sendError(['message' => __('No changes found', 'fluent-booking')]);
132 }
133
134 $validColumns = [
135 'internal_note',
136 'email',
137 'phone',
138 'first_name',
139 'last_name',
140 'status',
141 'payment_status'
142 ];
143
144 if (!in_array($column, $validColumns)) {
145 return $this->sendError(['message' => __('Invalid column', 'fluent-booking')]);
146 }
147
148 if ($column === 'email') {
149 if (!$value || !is_email($value)) {
150 return $this->sendError(['message' => __('Invalid email address', 'fluent-booking')]);
151 }
152 $value = sanitize_email($value);
153 } else {
154 $value = sanitize_text_field($value);
155 }
156
157 if ($column == 'status') {
158 if (!in_array($value, ['scheduled', 'completed', 'cancelled', 'rejected', 'no_show'])) {
159 return $this->sendError(['message' => __('Invalid status', 'fluent-booking')]);
160 }
161
162 if ($value == 'scheduled' && $booking->payment_method && $booking->payment_order) {
163 $order = $booking->payment_order;
164 $order->total_paid = $order->total_amount;
165 $order->completed_at = gmdate('Y-m-d H:i:s'); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
166 $order->status = 'paid';
167 $order->save();
168
169 $updateData['payment_status'] = 'paid';
170
171 do_action('fluent_booking/log_booking_activity', $this->getPaymentPaidLog($booking->id));
172
173 do_action('fluent_booking/payment/update_payment_status_paid', $booking);
174
175 } else if ($value == 'scheduled') {
176 do_action('fluent_booking/log_booking_activity', $this->getConfirmLog($booking->id));
177 }
178
179 if ($value == 'cancelled') {
180 $cancelReason = sanitize_text_field($data['cancel_reason']);
181 $booking->cancelMeeting($cancelReason, 'host', get_current_user_id());
182 return [
183 'message' => __('The booking has been cancelled', 'fluent-booking')
184 ];
185 }
186
187 if ($value == 'rejected') {
188 $rejectReason = sanitize_text_field($data['reject_reason']);
189 $booking->rejectMeeting($rejectReason, get_current_user_id());
190 return [
191 'message' => __('The booking has been rejected', 'fluent-booking')
192 ];
193 }
194
195 if ($booking->payment_method && Arr::get($data, 'refund_payment') == 'yes' && in_array($value, ['cancelled', 'rejected'])) {
196 do_action('fluent_booking/refund_payment_' . $booking->payment_method, $booking, $booking->calendar_event);
197 }
198 }
199
200 if ($column == 'payment_status') {
201 if (!in_array($value, ['pending', 'paid'])) {
202 return $this->sendError(['message' => __('Invalid payment status', 'fluent-booking')]);
203 }
204
205 if ($value == 'paid') {
206 do_action('fluent_booking/log_booking_activity', $this->getPaymentPaidLog($booking->id));
207 }
208
209 if ($value == 'pending') {
210 do_action('fluent_booking/log_booking_activity', $this->getPaymentPendingLog($booking->id));
211 }
212 }
213
214 $updateData[$column] = $value;
215 $booking->fill($updateData);
216 $booking->save();
217
218 if ($column === 'status') {
219 do_action('fluent_booking/booking_schedule_' . $value, $booking, $booking->calendar_event);
220
221 do_action('fluent_booking/pre_after_booking_' . $value, $booking, $booking->calendar_event);
222
223 $booking = Booking::with(['calendar_event', 'calendar'])->find($booking->id);
224
225 do_action('fluent_booking/after_booking_' . $value, $booking, $booking->calendar_event, $booking);
226 }
227
228 do_action('fluent_booking/after_patch_booking_schedule', $booking, $oldBooking);
229
230 do_action('fluent_booking/after_patch_booking_' . $column, $booking, $booking->calendar_event, $oldBooking->{$column});
231
232 return [
233 /* translators: Updated column name */
234 'message' => sprintf(__('%s has been updated', 'fluent-booking'), ucfirst($column))
235 ];
236 }
237
238 public function getBooking(Request $request, $bookingId)
239 {
240 $booking = Booking::with('calendar_event');
241
242 if (!PermissionManager::userCanSeeAllBookings()) {
243 $booking->whereHas('calendar', function ($q) {
244 $q->where('user_id', get_current_user_id());
245 });
246 }
247
248 $booking = $booking->findOrFail($bookingId);
249 $booking = $this->formatBooking($booking);
250
251 do_action_ref_array('fluent_booking/booking_schedule', [&$booking]);
252
253 $data = [
254 'schedule' => $booking
255 ];
256
257 if (in_array('all_data', $this->request->get('with', []))) {
258 $data = array_merge($data, $this->getBookingMetaInfo($request, $bookingId));
259 }
260
261 return $data;
262 }
263
264 public function deleteBooking(Request $request, $bookingId)
265 {
266 $booking = Booking::findOrFail($bookingId);
267
268 do_action('fluent_booking/before_delete_booking', $booking);
269
270 $booking->delete();
271
272 do_action('fluent_booking/after_delete_booking', $bookingId);
273
274 if ($booking->isMultiGuestBooking()) {
275 Booking::where('event_id', $booking->event_id)->where('group_id', $booking->group_id)->delete();
276 }
277
278 return [
279 'message' => __('Booking Deleted Successfully!', 'fluent-booking')
280 ];
281 }
282
283 public function sendConfirmationEmail(Request $request, $bookingId)
284 {
285 $booking = Booking::with(['calendar', 'calendar_event'])->find($bookingId);
286
287 $emailTo = $request->get('email_to', 'guest');
288
289 $notifications = $booking->calendar_event->getNotifications();
290
291 $email = Arr::get($notifications, 'booking_conf_attendee.email', []);
292 if ($emailTo == 'host') {
293 $email = Arr::get($notifications, 'booking_conf_host.email', []);
294 }
295
296 $result = EmailNotificationService::emailOnBooked($booking, $email, $emailTo, 'scheduled', true);
297
298 if (!$result) {
299 return $this->sendError(['message' => __('Notification sending failed', 'fluent-booking')]);
300 }
301
302 return [
303 'message' => __('Notification sent successfully', 'fluent-booking')
304 ];
305 }
306
307 public function getGroupAttendees(Request $request, $groupId)
308 {
309 $booking = Booking::with('slot');
310
311 if (!PermissionManager::userCanSeeAllBookings()) {
312 $booking->whereHas('calendar', function ($q) {
313 $q->where('user_id', get_current_user_id());
314 });
315 }
316
317 $booking = $booking->where('group_id', $groupId)->first();
318
319 if (!$booking || !$booking->isMultiGuestBooking()) {
320 return $this->sendError(['message' => __('Invalid group id or the event is not a group event', 'fluent-booking')]);
321 }
322
323 $attendees = Booking::where('group_id', $booking->group_id);
324 $search = sanitize_text_field($request->get('search'));
325
326 if (!empty($search)) {
327 $attendees = $attendees->searchBy($search);
328 }
329 $attendees = $attendees->paginate();
330
331 foreach ($attendees as $attendee) {
332 $attendee = $this->formatBooking($attendee);
333 }
334
335 return [
336 'attendees' => $attendees
337 ];
338 }
339
340 public function getBookingActivities(Request $request, $bookingId)
341 {
342 $activities = BookingActivity::where('booking_id', $bookingId)
343 ->orderBy('id', 'DESC')
344 ->get();
345
346 return [
347 'activities' => $activities
348 ];
349 }
350
351 public function getBookingMetaInfo(Request $request, $bookingId)
352 {
353 $booking = Booking::findOrFail($bookingId);
354
355 $activities = BookingActivity::where('booking_id', $booking->id)
356 ->orderBy('id', 'DESC')
357 ->get();
358
359 $activities->each(function ($activity) {
360 $activity->description = wp_unslash($activity->description);
361 });
362
363 $sidebarContents = [];
364 $mainBodyContents = [];
365
366 if (defined('FLUENTCRM')) {
367 $profileHtml = fluentcrm_get_crm_profile_html($booking->email, false);
368 if ($profileHtml) {
369 $sidebarContents[] = [
370 'id' => 'fluent_crm_profule',
371 'title' => __('CRM Profile', 'fluent-booking'),
372 'content' => $profileHtml
373 ];
374 }
375 }
376
377 $order = null;
378 if ($booking->payment_method && $booking->payment_order) {
379 $order = $booking->payment_order;
380 $order->load(['items', 'transaction']);
381 $order->currency_sign = CurrenciesHelper::getCurrencySign($order->currency);
382 }
383
384 $mainBodyContents = apply_filters('fluent_booking/booking_meta_info_main_meta', $mainBodyContents, $booking);
385 $mainBodyContents = apply_filters('fluent_booking/booking_meta_info_main_meta_' . $booking->source, $mainBodyContents, $booking);
386
387 return [
388 'activities' => $activities,
389 'sidebar_contents' => $sidebarContents,
390 'payment_order' => $order,
391 'main_body_contents' => $mainBodyContents
392 ];
393 }
394
395 private function formatBooking(&$booking)
396 {
397 $autoCompleteTimeOut = (int) Helper::getGlobalAdminSetting('auto_complete_timing', 60) * 60; // 10 minutes
398
399 if (in_array($booking->status, ['scheduled', 'pending']) && (time() - strtotime($booking->end_time)) > $autoCompleteTimeOut) {
400 $bookingStatus = $booking->status == 'pending' ? 'cancelled' : 'completed';
401 $booking->status = $bookingStatus;
402 $booking->save();
403 do_action('fluent_booking/booking_schedule_' . $bookingStatus, $booking, $booking->calendar_event);
404 }
405
406 if ($booking->isMultiHostBooking()) {
407 $booking->host_profiles = $booking->getHostProfiles();
408 }
409
410 if ($booking->isMultiGuestBooking()) {
411 $booking->booked_count = Booking::where('group_id', $booking->group_id)
412 ->whereIn('status', ['scheduled', 'completed'])->count();
413 } else {
414 $booking->additional_guests = $booking->getAdditionalGuests();
415 }
416
417 $booking->title = $booking->getBookingTitle(true);
418 $booking->author = $booking->getHostDetails(false);
419 $booking->location = $booking->getLocationDetailsHtml();
420 $booking->reschedule_url = $booking->getRescheduleUrl();
421 $booking->happening_status = $booking->getOngoingStatus();
422 $booking->booking_status_text = $booking->getBookingStatus();
423 $booking->payment_status_text = $booking->getPaymentStatus();
424 $booking->custom_form_data = $booking->getCustomFormData();
425
426 do_action_ref_array('fluent_booking/format_booking_schedule', [&$booking]);
427
428 return $booking;
429 }
430
431 private function getPaymentPaidLog($bookingId)
432 {
433 return [
434 'booking_id' => $bookingId,
435 'status' => 'closed',
436 'type' => 'success',
437 'title' => __('Payment Successfully Completed', 'fluent-booking'),
438 'description' => __('Payment marked as paid by admin', 'fluent-booking')
439 ];
440 }
441
442 private function getPaymentPendingLog($bookingId)
443 {
444 return [
445 'booking_id' => $bookingId,
446 'status' => 'closed',
447 'type' => 'success',
448 'title' => __('Payment Successfully Marked as Pending', 'fluent-booking'),
449 'description' => __('Payment marked as pending by admin', 'fluent-booking')
450 ];
451 }
452
453 private function getConfirmLog($bookingId)
454 {
455 $confirmedBy = 'host';
456 $userId = get_current_user_id();
457 if ($userId && $user = get_user_by('ID', $userId)) {
458 $confirmedBy = $user->display_name;
459 }
460
461 return [
462 'booking_id' => $bookingId,
463 'status' => 'closed',
464 'type' => 'success',
465 'title' => __('Booking Confirmed', 'fluent-booking'),
466 'description' => __('Booking has been confirmed by ', 'fluent-booking') . $confirmedBy
467 ];
468 }
469 }
470