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

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