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/Services/TimeSlotService.php +18 -7 1.10.0 → 2.5.0 View file →
@@ -106,9 +106,9 @@
106 106 continue;
107 107 }
108 108
109 109 if ($isLastDay && strtotime($slot['end']) > $maxBookingTime) {
110 - continue;
110 + break;
111 111 }
112 112
113 113 $isSlotAvailable = $this->isSlotAvailable($slot, $currentBookedSlots, $bufferTime, $hostId);
114 114
@@ -180,12 +180,12 @@
180 180 $duration = $this->calendarSlot->getDuration($duration);
181 181
182 182 list($scheduleTimezone, $dstTime) = $this->getTimezoneInfo();
183 183
184 - $fromStartTime = $this->maybeDayLightSavingTime($fromTime, $dstTime, $scheduleTimezone);
185 184 $toEndTime = $this->maybeDayLightSavingTime($toTime, $dstTime, $scheduleTimezone);
186 185
187 - $fromTime = gmdate('Y-m-d 00:00:00', strtotime($fromStartTime)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
186 + // Start from the requested time, not the DST-shifted one: the shift can cross into the next UTC day and drop that day's bookings.
187 + $fromTime = gmdate('Y-m-d 00:00:00', $fromTimeStamp); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
188 188 $toTime = gmdate('Y-m-d 23:59:59', strtotime($toEndTime)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
189 189
190 190 $slots = $this->getDates($fromTime, $toTime, $duration, true);
191 191
@@ -202,8 +202,15 @@
202 202 }
203 203
204 204 protected function isSlotExists($availableSlots, $fromTimeStamp, $toTimeStamp)
205 205 {
206 + // Slot generation only checks notice on today and the horizon on the last day.
207 + if ($fromTimeStamp < strtotime($this->calendarSlot->getMinBookableDateTime()) ||
208 + $toTimeStamp > $this->getMaxBookingTimestamp(null, gmdate('Y-m-d H:i:s', $toTimeStamp), 'UTC') // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
209 + ) {
210 + return false;
211 + }
212 +
206 213 $left = 0;
207 214 $right = count($availableSlots) - 1;
208 215
209 216 while ($left <= $right) {
@@ -269,16 +276,20 @@
269 276
270 277 $hostIds = $this->calendarSlot->getHostIds($this->hostId);
271 278 $status = ['pending', 'reserved', 'approved', 'scheduled', 'completed'];
272 279
280 + // Single indexed start_time range: widen the lower bound by max booking duration to catch overlaps.
281 + $maxDurationMinutes = (int) apply_filters('fluent_booking/max_booking_duration_minutes', DAY_IN_SECONDS / MINUTE_IN_SECONDS, $this->calendarSlot);
282 +
283 + $rangeLowerBound = gmdate('Y-m-d H:i:s', strtotime($dateRange[0]) - $maxDurationMinutes * MINUTE_IN_SECONDS); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
284 +
273 285 $bookings = Booking::with(['calendar_event'])
274 286 ->whereHas('hosts', function ($query) use ($hostIds) {
275 287 $query->whereIn('user_id', $hostIds);
276 288 })
277 - ->where(function ($query) use ($dateRange) {
278 - $query->whereBetween('start_time', $dateRange)
279 - ->orWhereBetween('end_time', $dateRange);
280 - })
289 + ->where('start_time', '>=', $rangeLowerBound)
290 + ->where('start_time', '<=', $dateRange[1])
291 + ->where('end_time', '>=', $dateRange[0])
281 292 ->orderBy('start_time', 'ASC')
282 293 ->whereIn('status', $status)
283 294 ->get()
284 295 ->groupBy('group_id');