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 +115 -30 1.7.1 → 2.5.0 View file →
@@ -2,8 +2,9 @@
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;
@@ -9,9 +10,9 @@
9 10 use FluentBooking\App\Services\DateTimeHelper;
10 11 use FluentBooking\App\Services\Helper;
11 12 use FluentBooking\App\Services\CurrenciesHelper;
12 13 use FluentBooking\App\Services\LocationService;
13 -use FluentBooking\Framework\Support\Arr;
14 +use FluentBooking\App\Services\Integrations\FluentCart\CartHelper;
14 15
15 16 class CalendarSlot extends Model
16 17 {
17 18 protected $table = 'fcal_calendar_events';
@@ -117,8 +118,13 @@
117 118 return $this->hasMany(Meta::class, 'object_id', 'id')
118 119 ->whereIn('object_type', ['calendar_event', 'integration']);
119 120 }
120 121
122 + public function isOneToOne()
123 + {
124 + return $this->event_type == 'single';
125 + }
126 +
121 127 public function isGroup()
122 128 {
123 129 return $this->event_type == 'group';
124 130 }
@@ -132,8 +138,18 @@
132 138 {
133 139 return $this->event_type == 'group_event';
134 140 }
135 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 +
136 152 public function isRoundRobin()
137 153 {
138 154 return $this->event_type == 'round_robin';
139 155 }
@@ -167,16 +183,26 @@
167 183 {
168 184 return $this->isGroup() || $this->isGroupEvent();
169 185 }
170 186
187 + public function isRecurringEvent()
188 + {
189 + return Arr::isTrue($this->getRecurringConfig(), 'enabled');
190 + }
191 +
171 192 public function isProEvent()
172 193 {
173 - return $this->isGroup() || $this->isTeamEvent() || $this->isOneOffEvent();
194 + return $this->isGroup() || $this->isTeamEvent() || $this->isOneOffEvent() || $this->allowMultiBooking();
174 195 }
175 196
197 + public function isMultiBooking()
198 + {
199 + return Arr::isTrue($this->settings, 'multiple_booking.enabled');
200 + }
201 +
176 202 public function allowMultiBooking()
177 203 {
178 - return Arr::isTrue($this->settings, 'multiple_booking.enabled');
204 + return $this->isMultiBooking() || $this->isRecurringEvent();
179 205 }
180 206
181 207 public function multiBookingLimit()
182 208 {
@@ -215,11 +241,19 @@
215 241 {
216 242 $teamMembers = [];
217 243 $teamMemberIds = $this->getHostIds();
218 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 +
219 254 foreach ($teamMemberIds as $teamMemberId) {
220 - $calendar = Calendar::where('user_id', $teamMemberId)->where('type', 'simple')->first();
221 - if ($calendar) {
255 + if ($calendar = $calendars->get($teamMemberId)) {
222 256 $teamMembers[] = $calendar->getAuthorProfile($public);
223 257 }
224 258 }
225 259
@@ -225,8 +259,13 @@
225 259
226 260 return $teamMembers;
227 261 }
228 262
263 + public function getRecurringConfig()
264 + {
265 + return Arr::get($this->settings, 'recurring_config', []);
266 + }
267 +
229 268 public function isLocationFieldRequired()
230 269 {
231 270 $locationSettings = Arr::get($this, 'location_settings');
232 271
@@ -417,10 +456,12 @@
417 456 return Arr::get($schedule, 'value.timezone', 'UTC');
418 457 }
419 458
420 459 if ($this->availability_type == 'existing_schedule') {
421 - $schedule = Availability::findOrFail($this->availability_id);
422 - 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 + }
423 464 }
424 465
425 466 return $this->calendar->author_timezone;
426 467 }
@@ -541,8 +582,12 @@
541 582 public function getMinBookableDateTime($startDate = null, $timeZone = null)
542 583 {
543 584 $startDate = $startDate ?: gmdate('Y-m-d H:i:s'); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
544 585
586 + if ($timeZone) {
587 + $startDate = DateTimeHelper::convertToTimeZone($startDate, $timeZone, 'UTC');
588 + }
589 +
545 590 $rangeType = Arr::get($this->settings, 'range_type', 'range_days');
546 591
547 592 if ($rangeType == 'range_date_between') {
548 593 $range = Arr::get($this->settings, 'range_date_between', []);
@@ -548,16 +593,13 @@
548 593 $range = Arr::get($this->settings, 'range_date_between', []);
549 594 if (is_array($range) && count(array_filter($range)) == 2) {
550 595 if (strtotime($range[0]) >= strtotime($startDate)) {
551 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');
552 598 }
553 599 }
554 600 }
555 601
556 - if ($timeZone) {
557 - $startDate = DateTimeHelper::convertToTimeZone($startDate, $timeZone, 'UTC');
558 - }
559 -
560 602 $totalCutStamp = DateTimeHelper::getTimestamp() + $this->getCutoutSeconds();
561 603
562 604 if (strtotime($startDate) < $totalCutStamp) {
563 605 $startDate = gmdate('Y-m-d H:i:s', $totalCutStamp); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
@@ -613,9 +655,11 @@
613 655 if (!$conditions || empty($conditions['unit'])) {
614 656 return 0;
615 657 }
616 658
617 - 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);
618 662 }
619 663
620 664 public function getHostIds($hostId = null)
621 665 {
@@ -791,8 +835,10 @@
791 835
792 836 $conditionTime = $conditionValue * 60;
793 837 if ($conditionUnit == 'hours') {
794 838 $conditionTime = $conditionTime * 60;
839 + } elseif ($conditionUnit == 'days') {
840 + $conditionTime = $conditionTime * 60 * 24;
795 841 }
796 842
797 843 return $bookingStartTime - $bookingCreatedTime < $conditionTime;
798 844 }
@@ -834,12 +880,13 @@
834 880
835 881 return LocationService::getLocationIconHeadingHtml($default, $this);
836 882 }
837 883
838 - public function defaultPaymentIcon($currency, $amount)
884 + public function defaultPaymentIcon($amount, $currencySettings = [])
839 885 {
886 + $formattedAmount = $currencySettings ? fluentbookingFormattedAmount((float)$amount * 100, $currencySettings) : $amount;
840 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>';
841 - $html = '<span class="fcal_slot_payment_icon">' . $svg . $currency . $amount . '</span>';
888 + $html = '<span class="fcal_slot_payment_icon">' . $svg . $formattedAmount . '</span>';
842 889 return $html;
843 890 }
844 891
845 892 public function isPaymentEnabled($duration = null)
@@ -856,13 +903,25 @@
856 903
857 904 return $this->type == 'paid' && Helper::isPaymentEnabled();
858 905 }
859 906
907 + public function isPaidEvent()
908 + {
909 + $paymentSettings = $this->getPaymentSettings();
910 +
911 + return $this->type != 'free' && Arr::get($paymentSettings, 'enabled') == 'yes';
912 + }
913 +
860 914 public function isWooEnabled()
861 915 {
862 916 return $this->type == 'woo' && defined('WC_PLUGIN_FILE');
863 917 }
864 918
919 + public function isCartEnabled()
920 + {
921 + return $this->type == 'cart' && defined('FLUENTCART_VERSION');
922 + }
923 +
865 924 public function getPaymentItems($duration = null)
866 925 {
867 926 $paymentSettings = $this->getPaymentSettings();
868 927
@@ -868,9 +927,9 @@
868 927
869 928 $isMultiEnabled = Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes';
870 929
871 930 if ($this->isMultiDurationEnabled() && $isMultiEnabled) {
872 - $duration = $duration ?? $this->getDefaultDuration();
931 + $duration = $duration ?: $this->getDefaultDuration();
873 932 return [Arr::get($paymentSettings, 'multi_payment_items.' . $duration)];
874 933 }
875 934
876 935 return Arr::get($paymentSettings, 'items', []);
@@ -875,16 +934,35 @@
875 934
876 935 return Arr::get($paymentSettings, 'items', []);
877 936 }
878 937
879 - public function getPricingTotal()
938 + public function getEventPrice($duration = null)
880 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 + {
881 959 if (!$this->isPaymentEnabled()) {
882 960 return 0;
883 961 }
884 962
885 963 $total = 0;
886 - $items = $this->getPaymentItems();
964 + $items = $this->getPaymentItems($duration);
887 965 foreach ($items as $item) {
888 966 $total += $item['value'];
889 967 }
890 968
@@ -890,9 +968,9 @@
890 968
891 969 return $total;
892 970 }
893 971
894 - public function getWooProductPrice()
972 + public function getWooProductPrice($duration = null)
895 973 {
896 974 $paymentSettings = $this->getPaymentSettings();
897 975
898 976 $productId = $paymentSettings['woo_product_id'];
@@ -897,9 +975,9 @@
897 975
898 976 $productId = $paymentSettings['woo_product_id'];
899 977
900 978 if (Arr::get($paymentSettings, 'multi_payment_enabled') == 'yes') {
901 - $duration = $this->getDefaultDuration();
979 + $duration = $duration ?? $this->getDefaultDuration();
902 980 $productId = Arr::get($paymentSettings, 'multi_payment_woo_ids.' . $duration);
903 981 }
904 982
905 983 $price = 0;
@@ -918,9 +996,9 @@
918 996 foreach ($productIds as $duration => $productId) {
919 997 $product = wc_get_product($productId);
920 998 if ($product) {
921 999 $productPrices[$duration] = [
922 - 'value' => $product->get_price()
1000 + 'value' => wc_price($product->get_price())
923 1001 ];
924 1002 }
925 1003 }
926 1004
@@ -933,17 +1011,16 @@
933 1011
934 1012 $driver = Arr::get($this->getPaymentSettings(), 'driver');
935 1013
936 1014 if ($driver == 'native' && $this->isPaymentEnabled()) {
937 - $currency = CurrenciesHelper::getGlobalCurrencySign();
1015 + $currencySettings = CurrenciesHelper::getGlobalCurrencySettings();
938 1016 $totalPayment = $this->getPricingTotal();
939 - $paymentHtml = $this->defaultPaymentIcon($currency, $totalPayment);
1017 + $paymentHtml = $this->defaultPaymentIcon($totalPayment, $currencySettings);
940 1018 }
941 1019
942 1020 if ($driver == 'woo' && $this->isWooEnabled()) {
943 - $currency = get_woocommerce_currency_symbol();
944 - $totalPayment = $this->getWooProductPrice();
945 - $paymentHtml = $this->defaultPaymentIcon($currency, $totalPayment);
1021 + $totalPayment = wc_price($this->getWooProductPrice());
1022 + $paymentHtml = $this->defaultPaymentIcon($totalPayment);
946 1023 }
947 1024
948 1025 return $paymentHtml;
949 1026 }
@@ -1008,10 +1085,12 @@
1008 1085 return $this->getProcessedWeeklySlots($schedule);
1009 1086 }
1010 1087
1011 1088 if ($this->availability_type === 'existing_schedule') {
1012 - $schedule = Availability::findOrFail($this->availability_id);
1013 - return $this->getProcessedWeeklySlots($schedule);
1089 + $schedule = Availability::find($this->availability_id);
1090 + if ($schedule) {
1091 + return $this->getProcessedWeeklySlots($schedule);
1092 + }
1014 1093 }
1015 1094
1016 1095 $scheduleData = Arr::get($this->settings, 'weekly_schedules', []);
1017 1096 $schedule = SanitizeService::weeklySchedules($scheduleData, 'UTC', $this->calendar->author_timezone);
@@ -1025,10 +1104,12 @@
1025 1104 return $this->getProcessedDateOverrides($schedule);
1026 1105 }
1027 1106
1028 1107 if ($this->availability_type === 'existing_schedule') {
1029 - $schedule = Availability::findOrFail($this->availability_id);
1030 - return $this->getProcessedDateOverrides($schedule);
1108 + $schedule = Availability::find($this->availability_id);
1109 + if ($schedule) {
1110 + return $this->getProcessedDateOverrides($schedule);
1111 + }
1031 1112 }
1032 1113
1033 1114 $scheduleData = Arr::get($this->settings, 'date_overrides', []);
1034 1115 $schedule = SanitizeService::slotDateOverrides($scheduleData, 'UTC', $this->calendar->author_timezone);
@@ -1077,8 +1158,9 @@
1077 1158 'value' => 100
1078 1159 ]
1079 1160 ],
1080 1161 'woo_product_id' => '',
1162 + 'cart_product_id' => '',
1081 1163 'multi_payment_items' => [
1082 1164 $duration => [
1083 1165 'title' => __('Booking Fee', 'fluent-booking'),
1084 1166 'value' => 0
@@ -1085,8 +1167,11 @@
1085 1167 ]
1086 1168 ],
1087 1169 'multi_payment_woo_ids' => [
1088 1170 $duration => ''
1171 + ],
1172 + 'multi_payment_cart_ids' => [
1173 + $duration => ''
1089 1174 ]
1090 1175 ];
1091 1176
1092 1177 $defaults = apply_filters('fluent_booking/event_payment_settings_defaults', $defaults, $this);
@@ -1099,9 +1184,9 @@
1099 1184
1100 1185 return apply_filters('fluent_booking/get_event_payment_settings', $settings, $this);
1101 1186 }
1102 1187
1103 - public function getHostSchedule($hostId)
1188 + public function getHostSchedule($hostId)
1104 1189 {
1105 1190 $hostSchedules = Arr::get($this->settings, 'hosts_schedules', []);
1106 1191 if (isset($hostSchedules[$hostId])) {
1107 1192 return Availability::find($hostSchedules[$hostId]);