PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.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 All 34 releases
← All changes | app/Models/CalendarSlot.php +337 -66 1.5.0 → 2.5.0 View file →
@@ -2,19 +2,17 @@
2 2
3 3 namespace FluentBooking\App\Models;
4 4
5 5 use FluentBooking\App\Models\Model;
6 +use FluentBooking\Framework\Support\Arr;
6 7 use FluentBooking\App\Services\SanitizeService;
7 8 use FluentBooking\App\Services\AvailabilityService;
8 9 use FluentBooking\App\Services\BookingFieldService;
9 10 use FluentBooking\App\Services\DateTimeHelper;
10 11 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;
12 +use FluentBooking\App\Services\CurrenciesHelper;
15 13 use FluentBooking\App\Services\LocationService;
16 -use FluentBooking\Framework\Support\Arr;
14 +use FluentBooking\App\Services\Integrations\FluentCart\CartHelper;
17 15
18 16 class CalendarSlot extends Model
19 17 {
20 18 protected $table = 'fcal_calendar_events';
@@ -53,9 +51,12 @@
53 51 static::creating(function ($model) {
54 52 if (empty($model->user_id)) {
55 53 $model->user_id = get_current_user_id();
56 54 }
57 - $model->hash = md5(wp_generate_uuid4() . time());
55 +
56 + if (empty($model->hash)) {
57 + $model->hash = md5(wp_generate_uuid4() . time());
58 + }
58 59 });
59 60 }
60 61
61 62 public function setSettingsAttribute($settings)
@@ -85,8 +86,19 @@
85 86 {
86 87 return \maybe_unserialize($locationSettings);
87 88 }
88 89
90 + public function getShortDescriptionAttribute()
91 + {
92 + $description = preg_replace('/<[^>]*>/', ' ', $this->getDescription());
93 +
94 + $maxLength = apply_filters('fluent_booking/event_short_description_length', 160, $this);
95 +
96 + $description = Helper::excerpt($description, $maxLength);
97 +
98 + return apply_filters('fluent_booking/event_short_description', $description, $this);
99 + }
100 +
89 101 public function calendar()
90 102 {
91 103 return $this->belongsTo(Calendar::class, 'calendar_id');
92 104 }
@@ -100,8 +112,19 @@
100 112 {
101 113 return $this->belongsTo(User::class, 'user_id');
102 114 }
103 115
116 + public function event_metas()
117 + {
118 + return $this->hasMany(Meta::class, 'object_id', 'id')
119 + ->whereIn('object_type', ['calendar_event', 'integration']);
120 + }
121 +
122 + public function isOneToOne()
123 + {
124 + return $this->event_type == 'single';
125 + }
126 +
104 127 public function isGroup()
105 128 {
106 129 return $this->event_type == 'group';
107 130 }
@@ -115,8 +138,18 @@
115 138 {
116 139 return $this->event_type == 'group_event';
117 140 }
118 141
142 + /**
143 + * Every value event_type can hold, on both fcal_calendar_slots and fcal_bookings.
144 + *
145 + * @return array
146 + */
147 + public static function getEventTypes()
148 + {
149 + return ['single', 'group', 'round_robin', 'collective', 'single_event', 'group_event'];
150 + }
151 +
119 152 public function isRoundRobin()
120 153 {
121 154 return $this->event_type == 'round_robin';
122 155 }
@@ -150,13 +183,33 @@
150 183 {
151 184 return $this->isGroup() || $this->isGroupEvent();
152 185 }
153 186
187 + public function isRecurringEvent()
188 + {
189 + return Arr::isTrue($this->getRecurringConfig(), 'enabled');
190 + }
191 +
154 192 public function isProEvent()
155 193 {
156 - return $this->isGroup() || $this->isTeamEvent() || $this->isOneOffEvent();
194 + return $this->isGroup() || $this->isTeamEvent() || $this->isOneOffEvent() || $this->allowMultiBooking();
157 195 }
158 196
197 + public function isMultiBooking()
198 + {
199 + return Arr::isTrue($this->settings, 'multiple_booking.enabled');
200 + }
201 +
202 + public function allowMultiBooking()
203 + {
204 + return $this->isMultiBooking() || $this->isRecurringEvent();
205 + }
206 +
207 + public function multiBookingLimit()
208 + {
209 + return Arr::get($this->settings, 'multiple_booking.limit', 5);
210 + }
211 +
159 212 public function getAuthorProfile($public = true, $userID = null)
160 213 {
161 214 $userID = $userID ?: $this->user_id;
162 215
@@ -185,14 +238,22 @@
185 238 }
186 239
187 240 public function getAuthorProfiles($public = true)
188 241 {
189 - $teamMembers = [];
242 + $teamMembers = [];
190 243 $teamMemberIds = $this->getHostIds();
191 244
245 + cache_users($teamMemberIds);
246 +
247 + $calendars = Calendar::whereIn('user_id', $teamMemberIds)
248 + ->where('type', 'simple')
249 + ->orderBy('id', 'desc')
250 + ->with(['metas', 'user', 'user.metas'])
251 + ->get()
252 + ->keyBy('user_id');
253 +
192 254 foreach ($teamMemberIds as $teamMemberId) {
193 - $calendar = Calendar::where('user_id', $teamMemberId)->where('type', 'simple')->first();
194 - if ($calendar) {
255 + if ($calendar = $calendars->get($teamMemberId)) {
195 256 $teamMembers[] = $calendar->getAuthorProfile($public);
196 257 }
197 258 }
198 259
@@ -198,8 +259,13 @@
198 259
199 260 return $teamMembers;
200 261 }
201 262
263 + public function getRecurringConfig()
264 + {
265 + return Arr::get($this->settings, 'recurring_config', []);
266 + }
267 +
202 268 public function isLocationFieldRequired()
203 269 {
204 270 $locationSettings = Arr::get($this, 'location_settings');
205 271
@@ -229,11 +295,83 @@
229 295 }
230 296
231 297 public function isGuestFieldRequired()
232 298 {
233 - return !$this->isGroup();
299 + return true;
234 300 }
235 301
302 + public function getEventDefaultData($calendar)
303 + {
304 + $weeklySchedule = Helper::getWeeklyScheduleSchema();
305 +
306 + $availability = AvailabilityService::maybeCreateAvailability($calendar, $weeklySchedule);
307 +
308 + $defaultData = [
309 + 'title' => '',
310 + 'calendar_id' => $calendar->id,
311 + 'user_id' => $calendar->user_id,
312 + 'status' => 'active',
313 + 'event_type' => 'single',
314 + 'description' => '',
315 + 'duration' => '30',
316 + 'color_schema' => '#0099ff',
317 + 'availability_type' => 'existing_schedule',
318 + 'availability_id' => (int)$availability->id,
319 + 'max_book_per_slot' => 1,
320 + 'is_display_spots' => false,
321 + 'location_settings' => [
322 + [
323 + 'type' => '',
324 + 'title' => '',
325 + 'description' => '',
326 + 'host_phone_number' => ''
327 + ]
328 + ],
329 + 'settings' => [
330 + 'schedule_type' => 'weekly_schedules',
331 + 'weekly_schedules' => $weeklySchedule,
332 + 'date_overrides' => [],
333 + 'range_type' => 'range_days',
334 + 'range_days' => 60,
335 + 'range_date_between' => ['', ''],
336 + 'schedule_conditions' => [
337 + 'value' => 4,
338 + 'unit' => 'hours'
339 + ]
340 + ]
341 + ];
342 +
343 + return $defaultData;
344 + }
345 +
346 + public function getEventSchema($calendar)
347 + {
348 + $userCalendarId = $calendar->type == 'simple' ? $calendar->id : null;
349 +
350 + $settingsSchema = $this->getSlotSettingsSchema($userCalendarId);
351 +
352 + $schema = [
353 + 'title' => '',
354 + 'status' => 'active',
355 + 'description' => '',
356 + 'duration' => '30',
357 + 'color_schema' => '#0099ff',
358 + 'calendar' => $calendar,
359 + 'settings' => $settingsSchema,
360 + 'max_book_per_slot' => 1,
361 + 'location_settings' => [
362 + [
363 + 'type' => '',
364 + 'title' => '',
365 + 'description' => '',
366 + 'host_phone_number' => ''
367 + ]
368 + ]
369 + ];
370 +
371 + return $schema;
372 + }
373 +
236 374 public function getSlotSettingsSchema($calendarId = null)
237 375 {
238 376 $calendarEvent = $calendarId ? CalendarSlot::where('calendar_id', $calendarId)->first() : null;
239 377
@@ -259,13 +397,15 @@
259 397 if ($statuses) {
260 398
261 399 $defaults = Helper::getDefaultEmailNotificationSettings();
262 400
263 - if ($isEdit) {
264 - foreach ($defaults as $key => $default) {
265 - if (isset($statuses[$key])) {
401 + foreach ($defaults as $key => $default) {
402 + if (isset($statuses[$key])) {
403 + if ($isEdit) {
266 404 $statuses[$key]['title'] = $default['title'];
267 405 }
406 + $emailBody = str_replace('fluent-booking-pro/core', 'fluent-booking', $statuses[$key]['email']['body']);
407 + $statuses[$key]['email']['body'] = $emailBody;
268 408 }
269 409 }
270 410
271 411 if (!Arr::get($statuses, 'rescheduled_by_host')) {
@@ -274,9 +414,9 @@
274 414
275 415 if (!Arr::get($statuses, 'rescheduled_by_attendee')) {
276 416 $statuses['rescheduled_by_attendee'] = $defaults['rescheduled_by_attendee'];
277 417 }
278 -
418 +
279 419 if (!Arr::get($statuses, 'booking_request_host')) {
280 420 $statuses['booking_request_host'] = $defaults['booking_request_host'];
281 421 }
282 422
@@ -311,15 +451,17 @@
311 451
312 452 public function getScheduleTimezone($hostId = null)
313 453 {
314 454 if ($hostId && !$this->isTeamCommonSchedule()) {
315 - $schedule = AvailabilityService::getDefaultSchedule($hostId);
455 + $schedule = $this->getHostSchedule($hostId);
316 456 return Arr::get($schedule, 'value.timezone', 'UTC');
317 457 }
318 458
319 459 if ($this->availability_type == 'existing_schedule') {
320 - $schedule = Availability::findOrFail($this->availability_id);
321 - return Arr::get($schedule, 'value.timezone', 'UTC');
460 + $schedule = Availability::find($this->availability_id);
461 + if ($schedule) {
462 + return Arr::get($schedule, 'value.timezone', 'UTC');
463 + }
322 464 }
323 465
324 466 return $this->calendar->author_timezone;
325 467 }
@@ -346,9 +488,9 @@
346 488 {
347 489 if ($this->isMultiDurationEnabled()) {
348 490 return Arr::get($this->settings, 'multi_duration.default_duration', '');
349 491 }
350 -
492 +
351 493 return $this->duration;
352 494 }
353 495
354 496 public function getAvailableDurations()
@@ -363,9 +505,9 @@
363 505 }
364 506
365 507 $durationLookup = Helper::getDurationLookup();
366 508
367 - $duration = $durationLookup[$this->duration] ?? $this->duration;
509 + $duration = $durationLookup[$this->duration] ?? Helper::formatDuration($this->duration);
368 510
369 511 return [$duration];
370 512 }
371 513
@@ -440,8 +582,12 @@
440 582 public function getMinBookableDateTime($startDate = null, $timeZone = null)
441 583 {
442 584 $startDate = $startDate ?: gmdate('Y-m-d H:i:s'); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
443 585
586 + if ($timeZone) {
587 + $startDate = DateTimeHelper::convertToTimeZone($startDate, $timeZone, 'UTC');
588 + }
589 +
444 590 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
445 591
446 592 if ($rangeType == 'range_date_between') {
447 593 $range = Arr::get($this->settings, 'range_date_between', []);
@@ -447,8 +593,9 @@
447 593 $range = Arr::get($this->settings, 'range_date_between', []);
448 594 if (is_array($range) && count(array_filter($range)) == 2) {
449 595 if (strtotime($range[0]) >= strtotime($startDate)) {
450 596 $startDate = gmdate('Y-m-d H:i:s', strtotime($range[0])); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
597 + $startDate = DateTimeHelper::convertToTimeZone($startDate, $this->calendar->author_timezone, 'UTC');
451 598 }
452 599 }
453 600 }
454 601
@@ -489,9 +636,9 @@
489 636
490 637 if ($rangeType == 'range_date_between') {
491 638 $range = Arr::get($this->settings, 'range_date_between', []);
492 639 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
640 + $minDate = gmdate('Y-m-d H:i:s', strtotime($range[0])); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
494 641 }
495 642 }
496 643
497 644 if ($timeZone != 'UTC') {
@@ -508,9 +655,11 @@
508 655 if (!$conditions || empty($conditions['unit'])) {
509 656 return 0;
510 657 }
511 658
512 - return strtotime('+' . $conditions['value'] . ' ' . $conditions['unit'], 0) - strtotime('+0 seconds', 0);
659 + $value = max(0, (int) Arr::get($conditions, 'value', 0));
660 +
661 + return strtotime('+' . $value . ' ' . $conditions['unit'], 0) - strtotime('+0 seconds', 0);
513 662 }
514 663
515 664 public function getHostIds($hostId = null)
516 665 {
@@ -590,9 +739,25 @@
590 739 {
591 740 return apply_filters('fluent_booking/get_location_fields', [
592 741 'conferencing' => [
593 742 'label' => __('Conferencing', 'fluent-booking'),
594 - 'options' => [],
743 + 'options' => [
744 + 'google_meet' => [
745 + 'title' => __('Google Meet (Pro)', 'fluent-booking'),
746 + 'disabled' => true,
747 + 'location_type' => 'conferencing'
748 + ],
749 + 'ms_teams' => [
750 + 'title' => __('MS Teams (Pro)', 'fluent-booking'),
751 + 'disabled' => true,
752 + 'location_type' => 'conferencing'
753 + ],
754 + 'zoom_meeting' => [
755 + 'title' => __('Zoom Video (Pro)', 'fluent-booking'),
756 + 'disabled' => true,
757 + 'location_type' => 'conferencing'
758 + ],
759 + ],
595 760 ],
596 761 'in_person' => [
597 762 'label' => __('In Person', 'fluent-booking'),
598 763 'options' => [
@@ -633,8 +798,20 @@
633 798 ],
634 799 ], $calendarEvent ?: $this);
635 800 }
636 801
802 + public function isDisplaySpots()
803 + {
804 + return $this->is_display_spots == true;
805 + }
806 +
807 + public function isAdditionalGuestEnabled()
808 + {
809 + $guestField = BookingFieldService::getBookingFieldByName($this, 'guests');
810 +
811 + return Arr::isTrue($guestField, 'enabled', false);
812 + }
813 +
637 814 public function isConfirmationEnabled()
638 815 {
639 816 return Arr::isTrue($this->settings, 'requires_confirmation.enabled');
640 817 }
@@ -640,28 +817,31 @@
640 817 }
641 818
642 819 public function isConfirmationRequired($bookingStartTime, $bookingCreatedTime = null)
643 820 {
644 - if ($this->isConfirmationEnabled()) {
645 - $type = Arr::get($this->settings, 'requires_confirmation.type', 'always');
646 - if ($type == 'always') {
647 - return true;
648 - }
649 -
650 - $bookingStartTime = strtotime($bookingStartTime);
651 - $bookingCreatedTime = $bookingCreatedTime ? strtotime($bookingCreatedTime) : time();
821 + if (!$this->isConfirmationEnabled() || !is_string($bookingStartTime)) {
822 + return false;
823 + }
652 824
653 - $conditionUnit = Arr::get($this->settings, 'requires_confirmation.condition.unit', 'minutes');
654 - $conditionValue = Arr::get($this->settings, 'requires_confirmation.condition.value', 0);
825 + $type = Arr::get($this->settings, 'requires_confirmation.type', 'always');
826 + if ($type == 'always') {
827 + return true;
828 + }
655 829
656 - $conditionTime = $conditionValue * 60;
657 - if ($conditionUnit == 'hours') {
658 - $conditionTime = $conditionTime * 60;
659 - }
830 + $bookingStartTime = strtotime($bookingStartTime);
831 + $bookingCreatedTime = $bookingCreatedTime ? strtotime($bookingCreatedTime) : time();
660 832
661 - return $bookingStartTime - $bookingCreatedTime < $conditionTime;
833 + $conditionUnit = Arr::get($this->settings, 'requires_confirmation.condition.unit', 'minutes');
834 + $conditionValue = Arr::get($this->settings, 'requires_confirmation.condition.value', 0);
835 +
836 + $conditionTime = $conditionValue * 60;
837 + if ($conditionUnit == 'hours') {
838 + $conditionTime = $conditionTime * 60;
839 + } elseif ($conditionUnit == 'days') {
840 + $conditionTime = $conditionTime * 60 * 24;
662 841 }
663 - return false;
842 +
843 + return $bookingStartTime - $bookingCreatedTime < $conditionTime;
664 844 }
665 845
666 846 public function getCanNotCancelSettings()
667 847 {
@@ -700,11 +880,13 @@
700 880
701 881 return LocationService::getLocationIconHeadingHtml($default, $this);
702 882 }
703 883
704 - public function defaultPaymentIcon($currency, $amount)
884 + public function defaultPaymentIcon($amount, $currencySettings = [])
705 885 {
706 - $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>';
886 + $formattedAmount = $currencySettings ? fluentbookingFormattedAmount((float)$amount * 100, $currencySettings) : $amount;
887 + $svg = '<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>';
888 + $html = '<span class="fcal_slot_payment_icon">' . $svg . $formattedAmount . '</span>';
707 889 return $html;
708 890 }
709 891
710 892 public function isPaymentEnabled($duration = null)
@@ -712,9 +894,9 @@
712 894 if ($this->isMultiDurationEnabled()) {
713 895 $paymentSettings = $this->getPaymentSettings();
714 896 if (Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes') {
715 897 $duration = $duration ?? $this->getDefaultDuration();
716 - if (!Arr::get($paymentSettings, 'multi_payment_items.'. $duration .'.value')) {
898 + if (!Arr::get($paymentSettings, 'multi_payment_items.' . $duration . '.value')) {
717 899 return false;
718 900 }
719 901 }
720 902 }
@@ -721,13 +903,25 @@
721 903
722 904 return $this->type == 'paid' && Helper::isPaymentEnabled();
723 905 }
724 906
907 + public function isPaidEvent()
908 + {
909 + $paymentSettings = $this->getPaymentSettings();
910 +
911 + return $this->type != 'free' && Arr::get($paymentSettings, 'enabled') == 'yes';
912 + }
913 +
725 914 public function isWooEnabled()
726 915 {
727 916 return $this->type == 'woo' && defined('WC_PLUGIN_FILE');
728 917 }
729 918
919 + public function isCartEnabled()
920 + {
921 + return $this->type == 'cart' && defined('FLUENTCART_VERSION');
922 + }
923 +
730 924 public function getPaymentItems($duration = null)
731 925 {
732 926 $paymentSettings = $this->getPaymentSettings();
733 927
@@ -733,31 +927,50 @@
733 927
734 928 $isMultiEnabled = Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes';
735 929
736 930 if ($this->isMultiDurationEnabled() && $isMultiEnabled) {
737 - $duration = $duration ?? $this->getDefaultDuration();
738 - return [Arr::get($paymentSettings, 'multi_payment_items.'. $duration)];
931 + $duration = $duration ?: $this->getDefaultDuration();
932 + return [Arr::get($paymentSettings, 'multi_payment_items.' . $duration)];
739 933 }
740 934
741 935 return Arr::get($paymentSettings, 'items', []);
742 936 }
743 937
744 - public function getPricingTotal()
938 + public function getEventPrice($duration = null)
745 939 {
940 + if (!$this->isPaidEvent()) {
941 + return 0;
942 + }
943 +
944 + $paymentSettings = $this->getPaymentSettings();
945 +
946 + if ($this->isCartEnabled()) {
947 + return CartHelper::getCartProductPrice($paymentSettings, $duration, false);
948 + }
949 +
950 + if ($this->isWooEnabled()) {
951 + return $this->getWooProductPrice($duration);
952 + }
953 +
954 + return $this->getPricingTotal($duration);
955 + }
956 +
957 + public function getPricingTotal($duration = null)
958 + {
746 959 if (!$this->isPaymentEnabled()) {
747 960 return 0;
748 961 }
749 962
750 963 $total = 0;
751 - $items = $this->getPaymentItems();
964 + $items = $this->getPaymentItems($duration);
752 965 foreach ($items as $item) {
753 - $total += (int)$item['value'];
966 + $total += $item['value'];
754 967 }
755 968
756 969 return $total;
757 970 }
758 971
759 - public function getWooProductPrice()
972 + public function getWooProductPrice($duration = null)
760 973 {
761 974 $paymentSettings = $this->getPaymentSettings();
762 975
763 976 $productId = $paymentSettings['woo_product_id'];
@@ -762,9 +975,9 @@
762 975
763 976 $productId = $paymentSettings['woo_product_id'];
764 977
765 978 if (Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes') {
766 - $duration = $this->getDefaultDuration();
979 + $duration = $duration ?? $this->getDefaultDuration();
767 980 $productId = Arr::get($paymentSettings, 'multi_payment_woo_ids.' . $duration);
768 981 }
769 982
770 983 $price = 0;
@@ -771,9 +984,9 @@
771 984 $product = wc_get_product($productId);
772 985 if ($product) {
773 986 $price = $product->get_price();
774 987 }
775 -
988 +
776 989 return $price;
777 990 }
778 991
779 992 public function getWooProductPriceByDuration($productIds = [])
@@ -783,9 +996,9 @@
783 996 foreach ($productIds as $duration => $productId) {
784 997 $product = wc_get_product($productId);
785 998 if ($product) {
786 999 $productPrices[$duration] = [
787 - 'value' => $product->get_price()
1000 + 'value' => wc_price($product->get_price())
788 1001 ];
789 1002 }
790 1003 }
791 1004
@@ -791,8 +1004,28 @@
791 1004
792 1005 return $productPrices;
793 1006 }
794 1007
1008 + public function getPaymentHtml()
1009 + {
1010 + $paymentHtml = '';
1011 +
1012 + $driver = Arr::get($this->getPaymentSettings(), 'driver');
1013 +
1014 + if ($driver == 'native' && $this->isPaymentEnabled()) {
1015 + $currencySettings = CurrenciesHelper::getGlobalCurrencySettings();
1016 + $totalPayment = $this->getPricingTotal();
1017 + $paymentHtml = $this->defaultPaymentIcon($totalPayment, $currencySettings);
1018 + }
1019 +
1020 + if ($driver == 'woo' && $this->isWooEnabled()) {
1021 + $totalPayment = wc_price($this->getWooProductPrice());
1022 + $paymentHtml = $this->defaultPaymentIcon($totalPayment);
1023 + }
1024 +
1025 + return $paymentHtml;
1026 + }
1027 +
795 1028 public function isTeamDefaultSchedule()
796 1029 {
797 1030 if ($this->isTeamEvent()) {
798 1031 if (!Arr::isTrue($this->settings, 'common_schedule', false)) {
@@ -811,16 +1044,23 @@
811 1044 }
812 1045 return false;
813 1046 }
814 1047
815 - public function isRoundRobinDefaultSchedule() {
1048 + public function isRoundRobinDefaultSchedule()
1049 + {
816 1050 return $this->isRoundRobin() && $this->isTeamDefaultSchedule();
817 1051 }
818 1052
819 - public function isRoundRobinCommonSchedule() {
1053 + public function isRoundRobinCommonSchedule()
1054 + {
820 1055 return $this->isRoundRobin() && $this->isTeamCommonSchedule();
821 1056 }
822 1057
1058 + public function isCollectiveDefaultSchedule()
1059 + {
1060 + return $this->isCollective() && $this->isTeamDefaultSchedule();
1061 + }
1062 +
823 1063 private function getProcessedWeeklySlots($schedule)
824 1064 {
825 1065 $scheduleData = Arr::get($schedule, 'value.weekly_schedules', []);
826 1066 $scheduleTimezone = Arr::get($schedule, 'value.timezone', 'UTC');
@@ -840,18 +1080,20 @@
840 1080
841 1081 public function getWeeklySlots($hostId = null)
842 1082 {
843 1083 if ($hostId && !$this->isTeamCommonSchedule()) {
844 - $schedule = AvailabilityService::getDefaultSchedule($hostId);
1084 + $schedule = $this->getHostSchedule($hostId);
845 1085 return $this->getProcessedWeeklySlots($schedule);
846 1086 }
847 1087
848 1088 if ($this->availability_type === 'existing_schedule') {
849 - $schedule = Availability::findOrFail($this->availability_id);
850 - return $this->getProcessedWeeklySlots($schedule);
1089 + $schedule = Availability::find($this->availability_id);
1090 + if ($schedule) {
1091 + return $this->getProcessedWeeklySlots($schedule);
1092 + }
851 1093 }
852 1094
853 - $scheduleData = Arr::get($this->settings,'weekly_schedules',[]);
1095 + $scheduleData = Arr::get($this->settings, 'weekly_schedules', []);
854 1096 $schedule = SanitizeService::weeklySchedules($scheduleData, 'UTC', $this->calendar->author_timezone);
855 1097 return AvailabilityService::getUtcWeeklySchedules($schedule, $this->calendar->author_timezone);
856 1098 }
857 1099
@@ -857,18 +1099,20 @@
857 1099
858 1100 public function getDateOverrides($hostId = null)
859 1101 {
860 1102 if ($hostId && !$this->isTeamCommonSchedule()) {
861 - $schedule = AvailabilityService::getDefaultSchedule($hostId);
1103 + $schedule = $this->getHostSchedule($hostId);
862 1104 return $this->getProcessedDateOverrides($schedule);
863 1105 }
864 1106
865 1107 if ($this->availability_type === 'existing_schedule') {
866 - $schedule = Availability::findOrFail($this->availability_id);
867 - return $this->getProcessedDateOverrides($schedule);
1108 + $schedule = Availability::find($this->availability_id);
1109 + if ($schedule) {
1110 + return $this->getProcessedDateOverrides($schedule);
1111 + }
868 1112 }
869 1113
870 - $scheduleData = Arr::get($this->settings,'date_overrides',[]);
1114 + $scheduleData = Arr::get($this->settings, 'date_overrides', []);
871 1115 $schedule = SanitizeService::slotDateOverrides($scheduleData, 'UTC', $this->calendar->author_timezone);
872 1116 $overrideSlots = AvailabilityService::getUtcDateOverrides($schedule, $this->calendar->author_timezone);
873 1117 $overrideDays = AvailabilityService::getDateOverrideDays($schedule, $this->calendar->author_timezone);
874 1118 return [$overrideSlots, $overrideDays];
@@ -883,10 +1127,10 @@
883 1127 }
884 1128
885 1129 $hostBookings = [];
886 1130 foreach ($hostIds as $hostId) {
887 - $dayStart = gmdate('Y-m-d 00:00:00',strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
888 - $dayEnd = gmdate('Y-m-d 23:59:59',strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
1131 + $dayStart = gmdate('Y-m-d 00:00:00', strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
1132 + $dayEnd = gmdate('Y-m-d 23:59:59', strtotime($startDate)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
889 1133 $hostBookings[$hostId] = Booking::getHostTotalBooking($this->id, [$hostId], [$dayStart, $dayEnd]);
890 1134 }
891 1135 usort($hostIds, function ($a, $b) use ($hostBookings) {
892 1136 return $hostBookings[$a] - $hostBookings[$b];
@@ -905,8 +1149,9 @@
905 1149 'enabled' => 'no',
906 1150 'multi_payment_enabled' => 'no',
907 1151 'stripe_enabled' => 'no',
908 1152 'paypal_enabled' => 'no',
1153 + 'offline_enabled' => 'no',
909 1154 'driver' => 'native',
910 1155 'items' => [
911 1156 [
912 1157 'title' => __('Booking Fee', 'fluent-booking'),
@@ -913,8 +1158,9 @@
913 1158 'value' => 100
914 1159 ]
915 1160 ],
916 1161 'woo_product_id' => '',
1162 + 'cart_product_id' => '',
917 1163 'multi_payment_items' => [
918 1164 $duration => [
919 1165 'title' => __('Booking Fee', 'fluent-booking'),
920 1166 'value' => 0
@@ -921,24 +1167,49 @@
921 1167 ]
922 1168 ],
923 1169 'multi_payment_woo_ids' => [
924 1170 $duration => ''
1171 + ],
1172 + 'multi_payment_cart_ids' => [
1173 + $duration => ''
925 1174 ]
926 1175 ];
927 1176
1177 + $defaults = apply_filters('fluent_booking/event_payment_settings_defaults', $defaults, $this);
1178 +
928 1179 if (!$settings) {
929 1180 $settings = $defaults;
930 1181 }
931 1182
932 - return wp_parse_args($settings, $defaults);
1183 + $settings = wp_parse_args($settings, $defaults);
1184 +
1185 + return apply_filters('fluent_booking/get_event_payment_settings', $settings, $this);
933 1186 }
934 1187
1188 + public function getHostSchedule($hostId)
1189 + {
1190 + $hostSchedules = Arr::get($this->settings, 'hosts_schedules', []);
1191 + if (isset($hostSchedules[$hostId])) {
1192 + return Availability::find($hostSchedules[$hostId]);
1193 + }
1194 + return AvailabilityService::getDefaultSchedule($hostId);
1195 + }
1196 +
1197 + public function getHostsSchedules() {
1198 + $hostIds = $this->getHostIds();
1199 + $hostSchedules = Arr::get($this->settings, 'hosts_schedules', []);
1200 + foreach ($hostIds as $hostId) {
1201 + $hostSchedules[$hostId] = $hostSchedules[$hostId] ?? AvailabilityService::getDefaultSchedule($hostId)['id'];
1202 + }
1203 + return $hostSchedules;
1204 + }
1205 +
935 1206 public function getCalendarEventsMeta()
936 1207 {
937 1208 $eventsMeta = Meta::where('object_id', $this->id)
938 1209 ->where('object_type', 'calendar_event')
939 1210 ->get();
940 -
1211 +
941 1212 return $eventsMeta;
942 1213 }
943 1214
944 1215 public function getIntegrationsMeta()
@@ -945,9 +1216,9 @@
945 1216 {
946 1217 $integrationsMeta = Meta::where('object_id', $this->id)
947 1218 ->where('object_type', 'integration')
948 1219 ->get();
949 -
1220 +
950 1221 return $integrationsMeta;
951 1222 }
952 1223
953 1224 /**