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 / Models / CalendarSlot.php

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

993 lines 31.3 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\Models;
4
5 use FluentBooking\App\Models\Model;
6 use FluentBooking\App\Services\SanitizeService;
7 use FluentBooking\App\Services\AvailabilityService;
8 use FluentBooking\App\Services\BookingFieldService;
9 use FluentBooking\App\Services\DateTimeHelper;
10 use FluentBooking\App\Services\Helper;
11 use FluentBooking\App\Services\BookingService;
12 use FluentBooking\App\Services\EditorShortCodeParser;
13 use FluentBooking\App\Services\LandingPage\LandingPageHandler;
14 use FluentBooking\App\Services\LandingPage\LandingPageHelper;
15 use FluentBooking\App\Services\LocationService;
16 use FluentBooking\Framework\Support\Arr;
17
18 class CalendarSlot extends Model
19 {
20 protected $table = 'fcal_calendar_events';
21
22 protected $guarded = ['id'];
23
24 protected $fillable = [
25 'user_id',
26 'hash',
27 'calendar_id',
28 'duration',
29 'title',
30 'slug',
31 'media_id',
32 'description',
33 'settings',
34 'availability_type',
35 'availability_id',
36 'status',
37 'type',
38 'color_schema',
39 'location_type',
40 'location_heading',
41 'location_settings',
42 'event_type',
43 'is_display_spots',
44 'max_book_per_slot',
45 'created_at',
46 'updated_at',
47 ];
48
49 public static function boot()
50 {
51 parent::boot();
52
53 static::creating(function ($model) {
54 if (empty($model->user_id)) {
55 $model->user_id = get_current_user_id();
56 }
57 $model->hash = md5(wp_generate_uuid4() . time());
58 });
59 }
60
61 public function setSettingsAttribute($settings)
62 {
63 $originalSettings = $this->getOriginal('settings');
64
65 $originalSettings = \maybe_unserialize($originalSettings);
66
67 foreach ($settings as $key => $value) {
68 $originalSettings[$key] = $value;
69 }
70
71 $this->attributes['settings'] = \maybe_serialize($originalSettings);
72 }
73
74 public function getSettingsAttribute($settings)
75 {
76 return \maybe_unserialize($settings);
77 }
78
79 public function setLocationSettingsAttribute($locationSettings)
80 {
81 $this->attributes['location_settings'] = \maybe_serialize($locationSettings);
82 }
83
84 public function getLocationSettingsAttribute($locationSettings)
85 {
86 return \maybe_unserialize($locationSettings);
87 }
88
89 public function calendar()
90 {
91 return $this->belongsTo(Calendar::class, 'calendar_id');
92 }
93
94 public function bookings()
95 {
96 return $this->hasMany(Booking::class, 'event_id');
97 }
98
99 public function user()
100 {
101 return $this->belongsTo(User::class, 'user_id');
102 }
103
104 public function isGroup()
105 {
106 return $this->event_type == 'group';
107 }
108
109 public function isSingleEvent()
110 {
111 return $this->event_type == 'single_event';
112 }
113
114 public function isGroupEvent()
115 {
116 return $this->event_type == 'group_event';
117 }
118
119 public function isRoundRobin()
120 {
121 return $this->event_type == 'round_robin';
122 }
123
124 public function isCollective()
125 {
126 return $this->event_type == 'collective';
127 }
128
129 public function isTeamEvent()
130 {
131 return $this->isRoundRobin() || $this->isCollective();
132 }
133
134 public function isOneOffEvent()
135 {
136 return $this->isSingleEvent() || $this->isGroupEvent();
137 }
138
139 public function isMultiHostEvent()
140 {
141 return $this->isTeamEvent() || $this->isOneOffEvent();
142 }
143
144 public function isMultiHostsEvent()
145 {
146 return $this->isCollective() || $this->isOneOffEvent();
147 }
148
149 public function isMultiGuestEvent()
150 {
151 return $this->isGroup() || $this->isGroupEvent();
152 }
153
154 public function isProEvent()
155 {
156 return $this->isGroup() || $this->isTeamEvent() || $this->isOneOffEvent();
157 }
158
159 public function getAuthorProfile($public = true, $userID = null)
160 {
161 $userID = $userID ?: $this->user_id;
162
163 $user = get_user_by('id', $userID);
164 if (!$user) {
165 return false;
166 }
167
168 $name = trim($user->first_name . ' ' . $user->last_name);
169
170 if (!$name) {
171 $name = $user->display_name;
172 }
173
174 $data = [
175 'ID' => $user->ID,
176 'name' => $name,
177 'avatar' => Helper::fluentBookingUserAvatar($user->ID, $user)
178 ];
179
180 if (!$public) {
181 $data['email'] = $user->user_email;
182 }
183
184 return $data;
185 }
186
187 public function getAuthorProfiles($public = true)
188 {
189 $teamMembers = [];
190 $teamMemberIds = $this->getHostIds();
191
192 foreach ($teamMemberIds as $teamMemberId) {
193 $calendar = Calendar::where('user_id', $teamMemberId)->where('type', 'simple')->first();
194 if ($calendar) {
195 $teamMembers[] = $calendar->getAuthorProfile($public);
196 }
197 }
198
199 return $teamMembers;
200 }
201
202 public function isLocationFieldRequired()
203 {
204 $locationSettings = Arr::get($this, 'location_settings');
205
206 if (count($locationSettings) > 1) {
207 return true;
208 }
209
210 return false;
211 }
212
213 public function isPhoneRequired()
214 {
215 if (count($this->location_settings) == 1) {
216 return Arr::get($this->location_settings, '0.type') == 'phone_guest';
217 }
218
219 return false;
220 }
221
222 public function isAddressRequired()
223 {
224 if (count($this->location_settings) == 1) {
225 return Arr::get($this->location_settings, '0.type') == 'in_person_guest';
226 }
227
228 return false;
229 }
230
231 public function isGuestFieldRequired()
232 {
233 return !$this->isMultiGuestEvent();
234 }
235
236 public function getSlotSettingsSchema($calendarId = null)
237 {
238 $calendarEvent = $calendarId ? CalendarSlot::where('calendar_id', $calendarId)->first() : null;
239
240 return [
241 'schedule_type' => 'weekly_schedules',
242 'weekly_schedules' => Helper::getWeeklyScheduleSchema(),
243 'date_overrides' => [],
244 'range_type' => 'range_days',
245 'range_days' => 60,
246 'range_date_between' => ['', ''],
247 'schedule_conditions' => [
248 'value' => 4,
249 'unit' => 'hours'
250 ],
251 'location_fields' => $this->getLocationFields($calendarEvent)
252 ];
253 }
254
255 public function getNotifications($isEdit = false)
256 {
257 $statuses = $this->getMeta('email_notifications');
258
259 if ($statuses) {
260
261 $defaults = Helper::getDefaultEmailNotificationSettings();
262
263 if ($isEdit) {
264 foreach ($defaults as $key => $default) {
265 if (isset($statuses[$key])) {
266 $statuses[$key]['title'] = $default['title'];
267 }
268 }
269 }
270
271 if (!Arr::get($statuses, 'rescheduled_by_host')) {
272 $statuses['rescheduled_by_host'] = $defaults['rescheduled_by_host'];
273 }
274
275 if (!Arr::get($statuses, 'rescheduled_by_attendee')) {
276 $statuses['rescheduled_by_attendee'] = $defaults['rescheduled_by_attendee'];
277 }
278
279 if (!Arr::get($statuses, 'booking_request_host')) {
280 $statuses['booking_request_host'] = $defaults['booking_request_host'];
281 }
282
283 if (!Arr::get($statuses, 'booking_request_attendee')) {
284 $statuses['booking_request_attendee'] = $defaults['booking_request_attendee'];
285 }
286
287 if (!Arr::get($statuses, 'declined_by_host')) {
288 $statuses['declined_by_host'] = $defaults['declined_by_host'];
289 }
290
291 return $statuses;
292 }
293
294 return Helper::getDefaultEmailNotificationSettings();
295 }
296
297 public function setNotifications($notifications)
298 {
299 $this->updateMeta('email_notifications', $notifications);
300 }
301
302 public function getBookingFields()
303 {
304 return BookingFieldService::getBookingFields($this);
305 }
306
307 public function setBookingFields($bookingFields)
308 {
309 return $this->updateMeta('booking_fields', $bookingFields);
310 }
311
312 public function getScheduleTimezone($hostId = null)
313 {
314 if ($hostId && !$this->isTeamCommonSchedule()) {
315 $schedule = AvailabilityService::getDefaultSchedule($hostId);
316 return Arr::get($schedule, 'value.timezone', 'UTC');
317 }
318
319 if ($this->availability_type == 'existing_schedule') {
320 $schedule = Availability::findOrFail($this->availability_id);
321 return Arr::get($schedule, 'value.timezone', 'UTC');
322 }
323
324 return $this->calendar->author_timezone;
325 }
326
327 public function isMultiDurationEnabled()
328 {
329 return Arr::isTrue($this->settings, 'multi_duration.enabled');
330 }
331
332 public function getDuration($duration = null)
333 {
334 if ($this->isMultiDurationEnabled()) {
335 if (in_array($duration, Arr::get($this->settings, 'multi_duration.available_durations', []))) {
336 return $duration;
337 } else {
338 return Arr::get($this->settings, 'multi_duration.default_duration', '');
339 }
340 }
341
342 return $this->duration;
343 }
344
345 public function getDefaultDuration()
346 {
347 if ($this->isMultiDurationEnabled()) {
348 return Arr::get($this->settings, 'multi_duration.default_duration', '');
349 }
350
351 return $this->duration;
352 }
353
354 public function getAvailableDurations()
355 {
356 if ($this->isMultiDurationEnabled()) {
357 $durationLookup = Helper::getDurationLookup(true);
358 $availableDurations = Arr::get($this->settings, 'multi_duration.available_durations', []);
359
360 return array_map(function ($duration) use ($durationLookup) {
361 return $durationLookup[$duration];
362 }, $availableDurations);
363 }
364
365 $durationLookup = Helper::getDurationLookup();
366
367 $duration = $durationLookup[$this->duration] ?? $this->duration;
368
369 return [$duration];
370 }
371
372 public function getDescription()
373 {
374 if ($this->description) {
375 return $this->description;
376 }
377
378 if ($this->isMultiDurationEnabled()) {
379 return __('Choose your duration and book a meeting with me', 'fluent-booking');
380 }
381
382 // translators: %d is the duration of the meeting in minutes
383 return sprintf(__('Book a meeting with me for %d minutes', 'fluent-booking'), $this->duration);
384 }
385
386 public function getSlotInterval($duration = null)
387 {
388 $duration = $duration ?: $this->duration;
389
390 $interval = Arr::get($this->settings, 'slot_interval', '');
391
392 $slotInterval = empty($interval) ? $duration : intval($interval);
393
394 return $slotInterval;
395 }
396
397 public function isReserveTime()
398 {
399 return Arr::isTrue($this->settings, 'reserve_time', false);
400 }
401
402 public function getAvailableTimes()
403 {
404 return Arr::get($this->settings, 'available_times', []);
405 }
406
407 public function getTotalBufferTime()
408 {
409 $bufferTimeBefore = Arr::get($this->settings, 'buffer_time_before', 0);
410 $bufferTimeAfter = Arr::get($this->settings, 'buffer_time_after', 0);
411
412 return $bufferTimeBefore + $bufferTimeAfter;
413 }
414
415 public function getMaxBookableDateTime($startDate, $timeZone = 'UTC', $format = 'Y-m-d 23:59:59')
416 {
417 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
418
419 $lastDay = gmdate('Y-m-t 23:59:59', strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
420
421 if ($timeZone != 'UTC') {
422 $lastDay = DateTimeHelper::convertToTimeZone($lastDay, $timeZone, 'UTC', $format);
423 }
424
425 if ($rangeType == 'range_indefinite') {
426 return $lastDay;
427 }
428
429 $maxLookupDate = $this->getMaxLookUpDate();
430
431 $maxDate = DateTimeHelper::convertToTimeZone($maxLookupDate, $this->calendar->author_timezone, 'UTC');
432
433 if (strtotime($maxDate) > strtotime($lastDay)) {
434 return $lastDay;
435 }
436
437 return $maxDate;
438 }
439
440 public function getMinBookableDateTime($startDate = null, $timeZone = null)
441 {
442 $startDate = $startDate ?: gmdate('Y-m-d H:i:s'); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
443
444 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
445
446 if ($rangeType == 'range_date_between') {
447 $range = Arr::get($this->settings, 'range_date_between', []);
448 if (is_array($range) && count(array_filter($range)) == 2) {
449 if (strtotime($range[0]) >= strtotime($startDate)) {
450 $startDate = gmdate('Y-m-d H:i:s', strtotime($range[0])); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
451 }
452 }
453 }
454
455 $totalCutStamp = DateTimeHelper::getTimestamp() + $this->getCutoutSeconds();
456
457 if (strtotime($startDate) < $totalCutStamp) {
458 $startDate = gmdate('Y-m-d H:i:s', $totalCutStamp); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
459 }
460
461 return $startDate;
462 }
463
464 public function getMaxLookUpDate()
465 {
466 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
467
468 if ($rangeType == 'range_indefinite') {
469 return false;
470 }
471
472 if ($rangeType == 'range_date_between') {
473 $range = Arr::get($this->settings, 'range_date_between', []);
474 if (is_array($range) && count(array_filter($range)) == 2) {
475 return gmdate('Y-m-d 23:59:59', strtotime($range[1])); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
476 }
477 }
478
479 $rangeDays = Arr::get($this->settings, 'range_days', 60) ?: 60;
480
481 return gmdate('Y-m-d 23:59:59', time() + $rangeDays * DAY_IN_SECONDS); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
482 }
483
484 public function getMinLookUpDate($timeZone = 'UTC')
485 {
486 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
487
488 $minDate = gmdate('Y-m-d H:i:s'); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
489
490 if ($rangeType == 'range_date_between') {
491 $range = Arr::get($this->settings, 'range_date_between', []);
492 if (is_array($range) && count(array_filter($range)) == 2) {
493 $minDate = gmdate('Y-m-d H:i:s', strtotime($range[0])); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
494 }
495 }
496
497 if ($timeZone != 'UTC') {
498 $minDate = DateTimeHelper::convertToTimeZone($minDate, $timeZone, 'UTC');
499 }
500
501 return $minDate;
502 }
503
504 public function getCutoutSeconds()
505 {
506 $conditions = Arr::get($this->settings, 'schedule_conditions', []);
507
508 if (!$conditions || empty($conditions['unit'])) {
509 return 0;
510 }
511
512 return strtotime('+' . $conditions['value'] . ' ' . $conditions['unit'], 0) - strtotime('+0 seconds', 0);
513 }
514
515 public function getHostIds($hostId = null)
516 {
517 if ($hostId) {
518 return [$hostId];
519 }
520
521 if ($this->isMultiHostEvent()) {
522 return Arr::get($this->settings, 'team_members', []);
523 }
524
525 return [$this->user_id];
526 }
527
528 public function getMaxBookingPerSlot()
529 {
530 return $this->max_book_per_slot;
531 }
532
533 public function getPublicUrl()
534 {
535 $calendar = $this->calendar;
536 if (!$calendar) {
537 return false;
538 }
539
540 $baseUr = $calendar->getLandingPageUrl();
541
542 if (!$baseUr) {
543 return '';
544 }
545
546 if (defined('FLUENT_BOOKING_LANDING_SLUG')) {
547 return $baseUr . '/' . $this->slug;
548 }
549
550 return $baseUr . '&event=' . $this->slug;
551 }
552
553 public function getMeta($key, $default = null)
554 {
555 $meta = Meta::where('object_type', 'calendar_event')
556 ->where('object_id', $this->id)
557 ->where('key', $key)
558 ->first();
559
560 if (!$meta) {
561 return $default;
562 }
563
564 return $meta->value;
565 }
566
567 public function updateMeta($key, $value)
568 {
569 $exist = Meta::where('object_type', 'calendar_event')
570 ->where('object_id', $this->id)
571 ->where('key', $key)
572 ->first();
573
574 if ($exist) {
575 $exist->value = $value;
576 $exist->save();
577 } else {
578 $exist = Meta::create([
579 'object_type' => 'calendar_event',
580 'object_id' => $this->id,
581 'key' => $key,
582 'value' => $value
583 ]);
584 }
585
586 return $exist;
587 }
588
589 public function getLocationFields($calendarEvent = null)
590 {
591 return apply_filters('fluent_booking/get_location_fields', [
592 'conferencing' => [
593 'label' => __('Conferencing', 'fluent-booking'),
594 'options' => [
595 'google_meet' => [
596 'title' => __('Google Meet (Pro)', 'fluent-booking'),
597 'disabled' => true,
598 'location_type' => 'conferencing'
599 ],
600 'ms_teams' => [
601 'title' => __('MS Teams (Pro)', 'fluent-booking'),
602 'disabled' => true,
603 'location_type' => 'conferencing'
604 ],
605 'zoom_meeting' => [
606 'title' => __('Zoom Video (Pro)', 'fluent-booking'),
607 'disabled' => true,
608 'location_type' => 'conferencing'
609 ],
610 ],
611 ],
612 'in_person' => [
613 'label' => __('In Person', 'fluent-booking'),
614 'options' => [
615 'in_person_guest' => [
616 'title' => __('In Person (Attendee Address)', 'fluent-booking'),
617 ],
618 'in_person_organizer' => [
619 'title' => __('In Person (Organizer Address)', 'fluent-booking'),
620 ],
621 ],
622 ],
623 'phone' => [
624 'label' => __('Phone', 'fluent-booking'),
625 'options' => [
626 'phone_guest' => [
627 'title' => __('Attendee Phone Number', 'fluent-booking'),
628 ],
629 'phone_organizer' => [
630 'title' => __('Organizer Phone Number', 'fluent-booking'),
631 ],
632 ],
633 ],
634 'online' => [
635 'label' => __('Online', 'fluent-booking'),
636 'options' => [
637 'online_meeting' => [
638 'title' => __('Online Meeting', 'fluent-booking'),
639 ],
640 ],
641 ],
642 'other' => [
643 'label' => __('Other', 'fluent-booking'),
644 'options' => [
645 'custom' => [
646 'title' => __('Custom', 'fluent-booking'),
647 ],
648 ],
649 ],
650 ], $calendarEvent ?: $this);
651 }
652
653 public function isConfirmationEnabled()
654 {
655 return Arr::isTrue($this->settings, 'requires_confirmation.enabled');
656 }
657
658 public function isConfirmationRequired($bookingStartTime, $bookingCreatedTime = null)
659 {
660 if ($this->isConfirmationEnabled()) {
661 $type = Arr::get($this->settings, 'requires_confirmation.type', 'always');
662 if ($type == 'always') {
663 return true;
664 }
665
666 $bookingStartTime = strtotime($bookingStartTime);
667 $bookingCreatedTime = $bookingCreatedTime ? strtotime($bookingCreatedTime) : time();
668
669 $conditionUnit = Arr::get($this->settings, 'requires_confirmation.condition.unit', 'minutes');
670 $conditionValue = Arr::get($this->settings, 'requires_confirmation.condition.value', 0);
671
672 $conditionTime = $conditionValue * 60;
673 if ($conditionUnit == 'hours') {
674 $conditionTime = $conditionTime * 60;
675 }
676
677 return $bookingStartTime - $bookingCreatedTime < $conditionTime;
678 }
679 return false;
680 }
681
682 public function getCanNotCancelSettings()
683 {
684 if (!isset($this->settings['can_not_cancel'])) {
685 $enabled = Arr::get($this->settings, 'can_cancel') == 'no' ? true : false;
686 return [
687 'enabled' => $enabled,
688 'type' => 'always',
689 ];
690 }
691 return Arr::get($this->settings, 'can_not_cancel', []);
692 }
693
694 public function getCanNotRescheduleSettings()
695 {
696 if (!isset($this->settings['can_not_reschedule'])) {
697 $enabled = Arr::get($this->settings, 'can_reschedule') == 'no' ? true : false;
698 return [
699 'enabled' => $enabled,
700 'type' => 'always',
701 ];
702 }
703 return Arr::get($this->settings, 'can_not_reschedule', []);
704 }
705
706 public function defaultLocationHtml()
707 {
708 if (empty($this->location_settings)) {
709 return '';
710 }
711
712 $default = Arr::get($this, 'location_settings');
713 if (!$default) {
714 return '';
715 }
716
717 return LocationService::getLocationIconHeadingHtml($default, $this);
718 }
719
720 public function defaultPaymentIcon($currency, $amount)
721 {
722 $html = '<div class="fcal_slot_payment_item"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728=""><path fill="currentColor" d="M256 640v192h640V384H768v-64h150.976c14.272 0 19.456 1.472 24.64 4.288a29.056 29.056 0 0 1 12.16 12.096c2.752 5.184 4.224 10.368 4.224 24.64v493.952c0 14.272-1.472 19.456-4.288 24.64a29.056 29.056 0 0 1-12.096 12.16c-5.184 2.752-10.368 4.224-24.64 4.224H233.024c-14.272 0-19.456-1.472-24.64-4.288a29.056 29.056 0 0 1-12.16-12.096c-2.688-5.184-4.224-10.368-4.224-24.576V640h64z"></path><path fill="currentColor" d="M768 192H128v448h640V192zm64-22.976v493.952c0 14.272-1.472 19.456-4.288 24.64a29.056 29.056 0 0 1-12.096 12.16c-5.184 2.752-10.368 4.224-24.64 4.224H105.024c-14.272 0-19.456-1.472-24.64-4.288a29.056 29.056 0 0 1-12.16-12.096C65.536 682.432 64 677.248 64 663.04V169.024c0-14.272 1.472-19.456 4.288-24.64a29.056 29.056 0 0 1 12.096-12.16C85.568 129.536 90.752 128 104.96 128h685.952c14.272 0 19.456 1.472 24.64 4.288a29.056 29.056 0 0 1 12.16 12.096c2.752 5.184 4.224 10.368 4.224 24.64z"></path><path fill="currentColor" d="M448 576a160 160 0 1 1 0-320 160 160 0 0 1 0 320zm0-64a96 96 0 1 0 0-192 96 96 0 0 0 0 192z"></path></svg>' . $currency . $amount . '</div>';
723 return $html;
724 }
725
726 public function isPaymentEnabled($duration = null)
727 {
728 if ($this->isMultiDurationEnabled()) {
729 $paymentSettings = $this->getPaymentSettings();
730 if (Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes') {
731 $duration = $duration ?? $this->getDefaultDuration();
732 if (!Arr::get($paymentSettings, 'multi_payment_items.'. $duration .'.value')) {
733 return false;
734 }
735 }
736 }
737
738 return $this->type == 'paid' && Helper::isPaymentEnabled();
739 }
740
741 public function isWooEnabled()
742 {
743 return $this->type == 'woo' && defined('WC_PLUGIN_FILE');
744 }
745
746 public function getPaymentItems($duration = null)
747 {
748 $paymentSettings = $this->getPaymentSettings();
749
750 $isMultiEnabled = Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes';
751
752 if ($this->isMultiDurationEnabled() && $isMultiEnabled) {
753 $duration = $duration ?? $this->getDefaultDuration();
754 return [Arr::get($paymentSettings, 'multi_payment_items.'. $duration)];
755 }
756
757 return Arr::get($paymentSettings, 'items', []);
758 }
759
760 public function getPricingTotal()
761 {
762 if (!$this->isPaymentEnabled()) {
763 return 0;
764 }
765
766 $total = 0;
767 $items = $this->getPaymentItems();
768 foreach ($items as $item) {
769 $total += (int)$item['value'];
770 }
771
772 return $total;
773 }
774
775 public function getWooProductPrice()
776 {
777 $paymentSettings = $this->getPaymentSettings();
778
779 $productId = $paymentSettings['woo_product_id'];
780
781 if (Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes') {
782 $duration = $this->getDefaultDuration();
783 $productId = Arr::get($paymentSettings, 'multi_payment_woo_ids.' . $duration);
784 }
785
786 $price = 0;
787 $product = wc_get_product($productId);
788 if ($product) {
789 $price = $product->get_price();
790 }
791
792 return $price;
793 }
794
795 public function getWooProductPriceByDuration($productIds = [])
796 {
797 $productPrices = [];
798
799 foreach ($productIds as $duration => $productId) {
800 $product = wc_get_product($productId);
801 if ($product) {
802 $productPrices[$duration] = [
803 'value' => $product->get_price()
804 ];
805 }
806 }
807
808 return $productPrices;
809 }
810
811 public function isTeamDefaultSchedule()
812 {
813 if ($this->isTeamEvent()) {
814 if (!Arr::isTrue($this->settings, 'common_schedule', false)) {
815 return true;
816 }
817 }
818 return false;
819 }
820
821 public function isTeamCommonSchedule()
822 {
823 if ($this->isTeamEvent()) {
824 if (Arr::isTrue($this->settings, 'common_schedule', false)) {
825 return true;
826 }
827 }
828 return false;
829 }
830
831 public function isRoundRobinDefaultSchedule() {
832 return $this->isRoundRobin() && $this->isTeamDefaultSchedule();
833 }
834
835 public function isRoundRobinCommonSchedule() {
836 return $this->isRoundRobin() && $this->isTeamCommonSchedule();
837 }
838
839 private function getProcessedWeeklySlots($schedule)
840 {
841 $scheduleData = Arr::get($schedule, 'value.weekly_schedules', []);
842 $scheduleTimezone = Arr::get($schedule, 'value.timezone', 'UTC');
843 $schedule = SanitizeService::weeklySchedules($scheduleData, 'UTC', $scheduleTimezone);
844 return AvailabilityService::getUtcWeeklySchedules($schedule, $scheduleTimezone);
845 }
846
847 private function getProcessedDateOverrides($schedule)
848 {
849 $scheduleData = Arr::get($schedule, 'value.date_overrides', []);
850 $scheduleTimezone = Arr::get($schedule, 'value.timezone', 'UTC');
851 $schedule = SanitizeService::slotDateOverrides($scheduleData, 'UTC', $scheduleTimezone);
852 $overrideSlots = AvailabilityService::getUtcDateOverrides($schedule, $scheduleTimezone);
853 $overrideDays = AvailabilityService::getDateOverrideDays($schedule, $scheduleTimezone);
854 return [$overrideSlots, $overrideDays];
855 }
856
857 public function getWeeklySlots($hostId = null)
858 {
859 if ($hostId && !$this->isTeamCommonSchedule()) {
860 $schedule = AvailabilityService::getDefaultSchedule($hostId);
861 return $this->getProcessedWeeklySlots($schedule);
862 }
863
864 if ($this->availability_type === 'existing_schedule') {
865 $schedule = Availability::findOrFail($this->availability_id);
866 return $this->getProcessedWeeklySlots($schedule);
867 }
868
869 $scheduleData = Arr::get($this->settings,'weekly_schedules',[]);
870 $schedule = SanitizeService::weeklySchedules($scheduleData, 'UTC', $this->calendar->author_timezone);
871 return AvailabilityService::getUtcWeeklySchedules($schedule, $this->calendar->author_timezone);
872 }
873
874 public function getDateOverrides($hostId = null)
875 {
876 if ($hostId && !$this->isTeamCommonSchedule()) {
877 $schedule = AvailabilityService::getDefaultSchedule($hostId);
878 return $this->getProcessedDateOverrides($schedule);
879 }
880
881 if ($this->availability_type === 'existing_schedule') {
882 $schedule = Availability::findOrFail($this->availability_id);
883 return $this->getProcessedDateOverrides($schedule);
884 }
885
886 $scheduleData = Arr::get($this->settings,'date_overrides',[]);
887 $schedule = SanitizeService::slotDateOverrides($scheduleData, 'UTC', $this->calendar->author_timezone);
888 $overrideSlots = AvailabilityService::getUtcDateOverrides($schedule, $this->calendar->author_timezone);
889 $overrideDays = AvailabilityService::getDateOverrideDays($schedule, $this->calendar->author_timezone);
890 return [$overrideSlots, $overrideDays];
891 }
892
893 public function getHostIdsSortedByBookings($startDate, $hostId = null)
894 {
895 $hostIds = $this->getHostIds($hostId);
896
897 if (count($hostIds) <= 1) {
898 return $hostIds;
899 }
900
901 $hostBookings = [];
902 foreach ($hostIds as $hostId) {
903 $dayStart = gmdate('Y-m-d 00:00:00',strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
904 $dayEnd = gmdate('Y-m-d 23:59:59',strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
905 $hostBookings[$hostId] = Booking::getHostTotalBooking($this->id, [$hostId], [$dayStart, $dayEnd]);
906 }
907 usort($hostIds, function ($a, $b) use ($hostBookings) {
908 return $hostBookings[$a] - $hostBookings[$b];
909 });
910
911 return $hostIds;
912 }
913
914 public function getPaymentSettings()
915 {
916 $settings = $this->getMeta('payment_settings', []);
917
918 $duration = $this->getDefaultDuration();
919
920 $defaults = [
921 'enabled' => 'no',
922 'multi_payment_enabled' => 'no',
923 'stripe_enabled' => 'no',
924 'paypal_enabled' => 'no',
925 'driver' => 'native',
926 'items' => [
927 [
928 'title' => __('Booking Fee', 'fluent-booking'),
929 'value' => 100
930 ]
931 ],
932 'woo_product_id' => '',
933 'multi_payment_items' => [
934 $duration => [
935 'title' => __('Booking Fee', 'fluent-booking'),
936 'value' => 0
937 ]
938 ],
939 'multi_payment_woo_ids' => [
940 $duration => ''
941 ]
942 ];
943
944 if (!$settings) {
945 $settings = $defaults;
946 }
947
948 return wp_parse_args($settings, $defaults);
949 }
950
951 public function getCalendarEventsMeta()
952 {
953 $eventsMeta = Meta::where('object_id', $this->id)
954 ->where('object_type', 'calendar_event')
955 ->get();
956
957 return $eventsMeta;
958 }
959
960 public function getIntegrationsMeta()
961 {
962 $integrationsMeta = Meta::where('object_id', $this->id)
963 ->where('object_type', 'integration')
964 ->get();
965
966 return $integrationsMeta;
967 }
968
969 /**
970 * Get the attributes that have been changed since last sync.
971 *
972 * @return array
973 */
974 public function getDirty()
975 {
976 $dirty = [];
977 foreach ($this->attributes as $key => $value) {
978 if (!in_array($key, $this->fillable)) {
979 continue;
980 }
981
982 if (!array_key_exists($key, $this->original)) {
983 $dirty[$key] = $value;
984 } elseif ($value !== $this->original[$key] &&
985 !$this->originalIsNumericallyEquivalent($key)) {
986 $dirty[$key] = $value;
987 }
988 }
989
990 return $dirty;
991 }
992 }
993