PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.10
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.10
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 / Services / AvailabilityService.php

AvailabilityService.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.10, at app/Services/AvailabilityService.php

466 lines 18.7 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\Services;
4
5 use FluentBooking\App\Models\Availability;
6 use FluentBooking\App\Models\Calendar;
7 use FluentBooking\App\Models\CalendarSlot;
8 use FluentBooking\App\Services\DateTimeHelper;
9 use FluentBooking\Framework\Support\Arr;
10
11 class AvailabilityService
12 {
13 public static function availabilitySchedules()
14 {
15 $permissions = ['read_and_use_other_availabilities', 'manage_other_availabilities', 'read_other_calendars', 'manage_other_calendars'];
16
17 $availabilities = Availability::when(
18 !PermissionManager::userCan($permissions),
19 function ($query) {
20 return $query->where('object_id', get_current_user_id());
21 })->get()->toArray();
22
23 $formattedSchedules = [];
24 foreach ($availabilities as $availability) {
25 $toTimezone = Arr::get($availability, 'value.timezone', 'UTC');
26 $formattedSchedules[] = [
27 'id' => Arr::get($availability, 'id'),
28 'object_id' => Arr::get($availability, 'object_id'),
29 'title' => Arr::get($availability, 'key'),
30 'settings' => [
31 'default' => Arr::isTrue($availability, 'value.default'),
32 'timezone' => $toTimezone,
33 'date_overrides' => SanitizeService::slotDateOverrides(Arr::get($availability, 'value.date_overrides', []), 'UTC', $toTimezone),
34 'weekly_schedules' => SanitizeService::weeklySchedules(Arr::get($availability, 'value.weekly_schedules', []), 'UTC', $toTimezone),
35 ]
36 ];
37 }
38 return $formattedSchedules;
39 }
40
41 public static function getFormattedSchedule($schedule)
42 {
43 $timezone = Arr::get($schedule, 'value.timezone', 'UTC');
44
45 $author = $schedule->getAuthor();
46
47 return [
48 'id' => $schedule->id,
49 'host_name' => $author['name'],
50 'host_avatar' => $author['avatar'],
51 'title' => $schedule->key,
52 'created_at' => $schedule->created_at->format('Y-m-d H:i:s'),
53 'usage_count' => self::getAvailabilityUsageCount($schedule->id),
54 'settings' => [
55 'default' => Arr::isTrue($schedule, 'value.default'),
56 'timezone' => $timezone,
57 'date_overrides' => SanitizeService::slotDateOverrides(Arr::get($schedule, 'value.date_overrides', []), 'UTC', $timezone),
58 'weekly_schedules' => SanitizeService::weeklySchedules(Arr::get($schedule, 'value.weekly_schedules'), 'UTC', $timezone)
59 ],
60 ];
61 }
62
63 public static function isTitleAlreadyExist($title, $userId, $currentTitle = '')
64 {
65 if ($title == $currentTitle) {
66 return false;
67 }
68
69 $scheduleTitles = Availability::where('object_id', $userId)
70 ->pluck('key')
71 ->toArray();
72
73 if (in_array($title, $scheduleTitles)) {
74 return true;
75 }
76
77 return false;
78 }
79
80 public static function updateOtherDefaultStatus($schedule, $id)
81 {
82 $schedules = Availability::where('object_id', $schedule->object_id)
83 ->where('id', '!=', $id)
84 ->get();
85
86 foreach ($schedules as $schedule) {
87 $schedule = Availability::findOrFail($schedule->id);
88 $updatedSettings = [
89 'default' => false,
90 'timezone' => Arr::get($schedule, 'value.timezone', 'UTC'),
91 'date_overrides' => Arr::get($schedule, 'value.data_overrides', []),
92 'weekly_schedules' => Arr::get($schedule, 'value.weekly_schedules'),
93 ];
94
95 $schedule->value = $updatedSettings;
96 $schedule->save();
97 }
98 }
99
100 public static function getScheduleOptions()
101 {
102 $permissions = ['read_and_use_other_availabilities', 'manage_other_availabilities', 'read_other_calendars', 'manage_other_calendars'];
103
104 $availabilities = Availability::when(
105 !PermissionManager::userCan($permissions),
106 function ($query) {
107 return $query->where('object_id', get_current_user_id());
108 })->get();
109
110 $scheduleOptions = [];
111 foreach ($availabilities as $availability) {
112 $calendar = Calendar::with(['user'])
113 ->where('type', 'simple')
114 ->where('user_id', $availability->object_id)
115 ->first();
116
117 if ($calendar) {
118 $hostName = $calendar->user->full_name;
119 if ($calendar->user_id == get_current_user_id()) {
120 $hostName = __('My Schedules', 'fluent-booking');
121 }
122 } else {
123 $hostName = __('Deleted User', 'fluent-booking');
124 }
125
126 $scheduleOptions[$hostName] = $scheduleOptions[$hostName] ?? [];
127
128 $default = Arr::isTrue($availability, 'value.default') ? ' (Default)' : '';
129
130 $scheduleOptions[$hostName][] = [
131 'label' => Arr::get($availability, 'key') . $default,
132 'value' => Arr::get($availability, 'id')
133 ];
134 }
135
136 return apply_filters('fluent_booking/availability_schedule_options', $scheduleOptions);
137 }
138
139 public static function getDefaultSchedule($userId)
140 {
141 $schedules = Availability::where('object_id', $userId)->get();
142
143 foreach ($schedules as $schedule) {
144 if (Arr::isTrue($schedule, 'value.default')) {
145 return $schedule;
146 }
147 }
148 return null;
149 }
150
151 public static function createScheduleSchema($userId, $title, $default, $fromTimezone, $toTimezone = 'UTC', $weeklySchedule = [], $dateOverrides = [])
152 {
153 $weeklySchedule = $weeklySchedule ? $weeklySchedule : Helper::getWeeklyScheduleSchema();
154
155 $dateOverrides = $dateOverrides ? SanitizeService::slotDateOverrides($dateOverrides, $fromTimezone, $toTimezone) : [];
156
157 $defaultSchedule = [
158 'object_id' => $userId,
159 'key' => sanitize_text_field($title),
160 'value' => [
161 'default' => (bool)$default,
162 'timezone' => sanitize_text_field($fromTimezone),
163 'date_overrides' => $dateOverrides,
164 'weekly_schedules' => SanitizeService::weeklySchedules($weeklySchedule, $fromTimezone, $toTimezone),
165 ]
166 ];
167 return $defaultSchedule;
168 }
169
170 public static function getAvailabilityUsageCount($scheduleId)
171 {
172 return CalendarSlot::where('availability_type', 'existing_schedule')
173 ->where('availability_id', $scheduleId)
174 ->count();
175 }
176
177 public static function getUtcWeeklySchedules($schedules, $fromTimeZone = false, $toTimeZone = 'UTC')
178 {
179 if (!$schedules) {
180 return [];
181 }
182
183 if (!$fromTimeZone || !$toTimeZone || $fromTimeZone == $toTimeZone) {
184 return $schedules;
185 }
186
187 $weekDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
188
189 $dstTimeZone = $fromTimeZone == 'UTC' ? $toTimeZone : $fromTimeZone;
190
191 $dateWithoutDST = DateTimeHelper::getDateWithoutDST($dstTimeZone);
192
193 foreach ($schedules as $day => &$schedule) {
194 $schedule['enabled'] = Arr::isTrue($schedule, 'enabled');
195 if (!$schedule['enabled'] || empty($schedule['slots'])) {
196 $schedule['slots'] = [];
197 $schedule['enabled'] = false;
198 continue;
199 }
200
201 $schedule['enabled'] = true;
202
203 $nextDayIndex = 0;
204 $dayIndex = array_search($day, $weekDays);
205 foreach ($schedule['slots'] as $index => $slot) {
206 if (!$slot['start'] || !$slot['end']) {
207 unset($schedule['slots'][$index]);
208 continue;
209 }
210
211 if (!empty(Arr::get($slot, 'type', ''))) {
212 continue;
213 }
214
215 $dayDiff = DateTimeHelper::getDayDifference($slot['start'], $fromTimeZone, $toTimeZone, $dateWithoutDST);
216 $slot['start'] = DateTimeHelper::convertToTimeZone($slot['start'], $fromTimeZone, $toTimeZone, 'H:i', $dateWithoutDST);
217 $slot['end'] = DateTimeHelper::convertToTimeZone($slot['end'], $fromTimeZone, $toTimeZone, 'H:i', $dateWithoutDST);
218
219 if ($nextDayIndex) {
220 array_splice($schedules[$nextDay]['slots'], $nextDayIndex, 0, [[
221 'start' => $slot['start'],
222 'end' => $slot['end'],
223 'type' => 'next_day'
224 ]]);
225 unset($schedule['slots'][$index]);
226 $nextDayIndex++;
227 continue;
228 }
229
230 if ($dayDiff > 0) {
231 $nextDayIndex = 1;
232 $nextDay = $weekDays[($dayIndex + $dayDiff) % 7];
233 $schedules[$nextDay]['enabled'] = true;
234 if (strtotime($slot['start']) < strtotime($slot['end'])) {
235 array_unshift($schedules[$nextDay]['slots'], [
236 'start' => $slot['start'],
237 'end' => $slot['end'],
238 'type' => 'next_day'
239 ]);
240 unset($schedule['slots'][$index]);
241 continue;
242 }
243 if ($slot['end'] != '00:00') {
244 array_unshift($schedules[$nextDay]['slots'], [
245 'start' => '00:00',
246 'end' => $slot['end'],
247 'type' => 'next_day'
248 ]);
249 $slot['end'] = '00:00';
250 }
251 } else if ($dayDiff < 0) {
252 $prevDay = $weekDays[($dayIndex + $dayDiff + 7) % 7];
253 $schedules[$prevDay]['enabled'] = true;
254 if (strtotime($slot['start']) < strtotime($slot['end'])) {
255 array_push($schedules[$prevDay]['slots'], [
256 'start' => $slot['start'],
257 'end' => $slot['end'],
258 'type' => 'prev_day'
259 ]);
260 unset($schedule['slots'][$index]);
261 continue;
262 }
263 if ($slot['start'] != '00:00') {
264 array_push($schedules[$prevDay]['slots'], [
265 'start' => $slot['start'],
266 'end' => '00:00',
267 'type' => 'prev_day'
268 ]);
269 $slot['start'] = '00:00';
270 }
271 } else {
272 if (strtotime($slot['start']) > strtotime($slot['end'])) {
273 if ($slot['end'] != '00:00') {
274 $nextDayIndex = 1;
275 $nextDay = $weekDays[($dayIndex + 1) % 7];
276 $schedules[$nextDay]['enabled'] = true;
277 array_unshift($schedules[$nextDay]['slots'], [
278 'start' => '00:00',
279 'end' => $slot['end'],
280 'type' => 'next_day'
281 ]);
282 $slot['end'] = '00:00';
283 }
284 }
285 }
286
287 if ($slot['start'] == '00:00' && $slot['end'] == '00:00') {
288 unset($schedule['slots'][$index]);
289 continue;
290 }
291
292 $schedule['slots'][$index] = $slot;
293 }
294
295 $schedule['slots'] = array_values($schedule['slots']);
296 }
297
298 return $schedules;
299 }
300
301 public static function getUtcDateOverrides($overrides, $fromTimeZone = false, $toTimeZone = 'UTC')
302 {
303 if (!$overrides) {
304 return [];
305 }
306
307 if (!$fromTimeZone || !$toTimeZone) {
308 return $overrides;
309 }
310
311 $dstTimeZone = $fromTimeZone == 'UTC' ? $toTimeZone : $fromTimeZone;
312
313 $dateWithoutDST = DateTimeHelper::getDateWithoutDST($dstTimeZone);
314
315 $todayTimeStamp = strtotime(gmdate('Y-m-d')); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
316
317 $validOverrides = [];
318 foreach ($overrides as $date => $slots) {
319 $dateTimestamp = strtotime($date);
320 if ($dateTimestamp < $todayTimeStamp) {
321 continue;
322 }
323
324 $nextDayIndex = 0;
325 foreach ($slots as $index => $slot) {
326 if (empty($slot['start']) || empty($slot['end']) || $slot['start'] == $slot['end']) {
327 unset($slots[$index]);
328 continue;
329 }
330
331 $dayDiff = DateTimeHelper::getDayDifference($slot['start'], $fromTimeZone, $toTimeZone, $dateWithoutDST);
332 $slot['start'] = DateTimeHelper::convertToTimeZone($slot['start'], $fromTimeZone, $toTimeZone, 'H:i', $dateWithoutDST);
333 $slot['end'] = DateTimeHelper::convertToTimeZone($slot['end'], $fromTimeZone, $toTimeZone, 'H:i', $dateWithoutDST);
334
335 if ($nextDayIndex) {
336 $nextDay = gmdate('Y-m-d', ($dateTimestamp + 86400 * $dayDiff)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
337 array_splice($validOverrides[$nextDay], $nextDayIndex, 0, [[
338 'start' => $slot['start'],
339 'end' => $slot['end']
340 ]]);
341 unset($slots[$index]);
342 $nextDayIndex++;
343 continue;
344 }
345
346 if ($dayDiff > 0) {
347 $nextDayIndex = 1;
348 $nextDay = gmdate('Y-m-d', ($dateTimestamp + 86400 * $dayDiff)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
349 $validOverrides[$nextDay] = $validOverrides[$nextDay] ?? [];
350 if (strtotime($slot['start']) < strtotime($slot['end'])) {
351 array_unshift($validOverrides[$nextDay], [
352 'start' => $slot['start'],
353 'end' => $slot['end']
354 ]);
355 unset($slots[$index]);
356 continue;
357 }
358 if ($slot['end'] != '00:00') {
359 array_unshift($validOverrides[$nextDay], [
360 'start' => '00:00',
361 'end' => $slot['end']
362 ]);
363 $slot['end'] = '00:00';
364 }
365 } else if ($dayDiff < 0) {
366 $prevDay = gmdate('Y-m-d', ($dateTimestamp - 86400 * abs($dayDiff))); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
367 $validOverrides[$prevDay] = $validOverrides[$prevDay] ?? [];
368 if (strtotime($slot['start']) < strtotime($slot['end'])) {
369 array_push($validOverrides[$prevDay], [
370 'start' => $slot['start'],
371 'end' => $slot['end']
372 ]);
373 unset($slots[$index]);
374 continue;
375 }
376 if ($slot['start'] != '00:00') {
377 array_push($validOverrides[$prevDay], [
378 'start' => $slot['start'],
379 'end' => '00:00'
380 ]);
381 $slot['start'] = '00:00';
382 }
383 } else {
384 if (strtotime($slot['start']) > strtotime($slot['end'])) {
385 if ($slot['end'] != '00:00') {
386 $nextDayIndex = 1;
387 $nextDay = gmdate('Y-m-d', ($dateTimestamp + 86400)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
388 $validOverrides[$nextDay] = $validOverrides[$nextDay] ?? [];
389 array_unshift($validOverrides[$nextDay], [
390 'start' => '00:00',
391 'end' => $slot['end']
392 ]);
393 $slot['end'] = '00:00';
394 }
395 }
396 }
397
398 if ($slot['start'] == '00:00' && $slot['end'] == '00:00') {
399 unset($slots[$index]);
400 continue;
401 }
402 $slots[$index] = $slot;
403 }
404
405 if ($slots) {
406 $validOverrides[$date] = $validOverrides[$date] ?? [];
407 $validOverrides[$date] = array_merge($validOverrides[$date], $slots);
408 }
409 }
410
411 return $validOverrides;
412 }
413
414 public static function getDateOverrideDays($overrides, $fromTimeZone, $toTimeZone = 'UTC')
415 {
416 if (!$overrides || !$fromTimeZone || !$toTimeZone) {
417 return [];
418 }
419
420 $overrideDays = [];
421 foreach ($overrides as $date => $slots) {
422 $dayStart = gmdate('Y-m-d 00:00:00', strtotime($date));
423 $dayEnd = gmdate('Y-m-d 24:00:00', strtotime($date));
424
425 $convertedStart = DateTimeHelper::convertToTimeZone($dayStart, $fromTimeZone, $toTimeZone);
426 $convertedEnd = DateTimeHelper::convertToTimeZone($dayEnd, $fromTimeZone, $toTimeZone);
427
428 $startDate = gmdate('Y-m-d', strtotime($convertedStart));
429 $endDate = gmdate('Y-m-d', strtotime($convertedEnd));
430
431 if (strtotime($dayStart) == strtotime($convertedStart)) {
432 $overrideDays[$startDate] = [
433 'start' => '00:00',
434 'end' => '24:00'
435 ];
436 continue;
437 }
438
439 if (isset($overrideDays[$startDate])) {
440 $overrideDays[$startDate] = [
441 'start' =>'00:00',
442 'end' =>'24:00'
443 ];
444 } else {
445 $overrideDays[$startDate] = [
446 'start' => gmdate('H:i', strtotime($convertedStart)),
447 'end' => '24:00'
448 ];
449 }
450
451 if (isset($overrideDays[$endDate])) {
452 $overrideDays[$endDate] = [
453 'start' => '00:00',
454 'end' => '24:00'
455 ];
456 } else {
457 $overrideDays[$endDate] = [
458 'start' => '00:00',
459 'end' => gmdate('H:i', strtotime($convertedEnd))
460 ];
461 }
462 }
463 return $overrideDays;
464 }
465 }
466