PluginProbe
Booking Calendar / 10.1.3
Booking Calendar v10.1.3
11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 All 203 releases
booking / includes / _capacity / where_to_save.php

where_to_save.php in Booking Calendar 10.1.3, at includes/_capacity/where_to_save.php

394 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4
4
5 // ---------------------------------------------------------------------------------------------------------------------
6 // Check where to save the booking
7 // ---------------------------------------------------------------------------------------------------------------------
8
9 /**
10 * Get booking resources for each selected date, where we can save the booking, or false if we can not save it
11 *
12 * @param array $params = [
13 * 'resource_id' => 2
14 * 'skip_booking_id' => '', | 125 if edit booking
15 * 'dates_only_sql_arr' => [ "2023-10-18", "2023-10-25", "2023-11-25" ]
16 * 'time_as_seconds_arr' => [ 36000, 39600 ]
17 * 'how_many_items_to_book' => 1
18 * 'request_uri' => 'http://beta/resource-id2/' // Optional default -> DOING_AJAX ? $_SERVER['HTTP_REFERER'] : $_SERVER['REQUEST_URI']
19 * 'as_single_resource' => false, // Optional default false
20 * 'is_use_booking_recurrent_time' => false // Optional default ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
21 * ]
22 * @return array = [ 'result' => 'ok', 'main__resource_id' => 2, 'resources_in_dates' => [ '2023-09-23':[2,10,11], '2023-09-24':[2,10,11] ], 'time_to_book' => [ "00:00:00", "24:00:00" ] ]
23 * Note. 'main__resource_id' - it's first booking resource in the list, basically needed for saving in wp_booking DB table.
24 * OR
25 * = [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ]
26 */
27 function wpbc__where_to_save_booking( $local_params ){
28
29 $defaults = array(
30 'request_uri' => ( ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $_SERVER['HTTP_REFERER'] : $_SERVER['REQUEST_URI'] ), // front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER'] // It different in Ajax requests. It's used for change-over days to detect for exception at specific pages
31 'as_single_resource' => false,
32 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ),
33 'aggregate_resource_id_arr' => array(),
34 'custom_form' => '' //FixIn: 10.0.0.10 // Required for checking all available time-slots and compare with booked time slots
35 );
36 $local_params = wp_parse_args( $local_params, $defaults );
37
38 $time_as_seconds_arr = $local_params['time_as_seconds_arr'];
39 $time_as_seconds_arr[0] = ( 0 != $time_as_seconds_arr[0] ) ? $time_as_seconds_arr[0] + 1 : $time_as_seconds_arr[0]; // +1 s. -- set check in time with ended 1 second
40 $time_as_seconds_arr[1] = ( ( 24 * 60 * 60 ) != $time_as_seconds_arr[1] ) ? $time_as_seconds_arr[1] + 2 : $time_as_seconds_arr[1]; // +2 s. -- set check out time with ended 2 seconds
41 if ( ( 0 != $time_as_seconds_arr[0] ) && ( ( 24 * 60 * 60 ) == $time_as_seconds_arr[1] ) ) {
42 //FixIn: 10.0.0.49 - in case if we have start time != 00:00 and end time as 24:00 then set end time as 23:59:52
43 $time_as_seconds_arr[1] += - 8;
44 }
45 $local_params['time_as_his_arr'] = array(
46 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ),
47 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] )
48 );
49
50 // If we are using the unavailable before/after booking dates, then we need to extend "$local_params['dates_only_sql_arr']" to such dates.
51 if ( function_exists( 'wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after' ) ) {
52 $maybe_extended__dates_to_check_arr = wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after( $local_params['dates_only_sql_arr'] );
53 } else {
54 $maybe_extended__dates_to_check_arr = $local_params['dates_only_sql_arr'];
55 }
56 // [ "dates": [ "2023-11-05": [ "day_availability":4, ... "2": [ "is_day_unavailable":false, ...]], '2023-11-06':[...] ] ,"resources_id_arr__in_dates":[2,12,10,11]}
57 $availability_per_days = wpbc_get_availability_per_days_arr( array(
58 'resource_id' => $local_params['resource_id'],
59 'skip_booking_id' => $local_params['skip_booking_id'],
60 'dates_to_check' => $maybe_extended__dates_to_check_arr,
61 'request_uri' => $local_params['request_uri'],
62 'as_single_resource' => $local_params['as_single_resource'], // default FALSE :: get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources'
63 'additional_bk_types' => $local_params['aggregate_resource_id_arr'],
64 'aggregate_type' => $local_params['aggregate_type'], //TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' //FixIn: 10.0.0.7
65 'custom_form' => $local_params['custom_form'] //FixIn: 10.0.0.10
66 ) );
67
68 // Get value of how many booking resources to book
69 $how_many_items_to_book = $local_params['how_many_items_to_book'];
70 // -------------------------------------------------------------------------------------------------------------
71 // [ 2023-10-18: [ 0:[ resource_id: 2, is_available: true, booked__seconds: [], booked__readable: [], time_to_book__seconds: [ 36030, 39570 ], time_to_book__readable: "10:00:00", "11:00:00" ] ], 1: [...], 2: [...], 3: [...] ], 2023-10-25: [...], 2023-11-25: [...] ]
72 $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array(
73 'dates_sql__arr' => $local_params['dates_only_sql_arr'],
74 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'],
75 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'],
76 'availability_per_days' => $availability_per_days
77 ) );
78
79 $main__resource_id = 0;
80 // == In SAME 'child' booking resources ============================================================
81 if ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) {
82
83 $availability_in_same_child_resources = $availability_per_days['resources_id_arr__in_dates'];
84
85 foreach ( $availability_per_days['resources_id_arr__in_dates'] as $child_resource_id ) {
86 foreach ( $local_params['dates_only_sql_arr'] as $day_sql_key ) {
87 foreach ( $available_slots[ $day_sql_key ] as $available_slot ) {
88 if (
89 ( $child_resource_id == $available_slot['resource_id'] )
90 && ( ! $available_slot['is_available'] )
91 ){
92 $availability_in_same_child_resources = array_diff( $availability_in_same_child_resources, array( $child_resource_id ) ); // Remove $child_resource_id from array
93 break;
94 }
95 }
96 }
97 }
98
99 // Reset indexes in this array for ability to get first [0] element in this arr.
100 $availability_in_same_child_resources = array_values( $availability_in_same_child_resources );
101 $main__resource_id = ( ! empty( $availability_in_same_child_resources ) ) ? $availability_in_same_child_resources[0] : 0;
102
103 // [ 2, 12, 11 ] <- ID of child booking resources, where we can save our booking in the same child booking resource!
104 if ( count( $availability_in_same_child_resources ) >= $how_many_items_to_book ) {
105
106 $availability_in_same_child_resources_by_dates = array();
107 foreach ( $local_params['dates_only_sql_arr'] as $day_sql_key ) {
108 $availability_in_same_child_resources_by_dates[ $day_sql_key ] = $availability_in_same_child_resources;
109 }
110 // Good Save it
111 return array(
112 'result' => 'ok',
113 'resources_in_dates' => $availability_in_same_child_resources_by_dates, // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ]
114 'time_to_book' => $local_params['time_as_his_arr'], // [ "00:00:00", "24:00:00" ]
115 'main__resource_id' => $main__resource_id
116 );
117 } else {
118 // Bad not save
119 return array(
120 'result' => 'error',
121 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
122 . ' <br> '
123 . __( 'It is not possible to store this sequence of the dates into the one same resource.' , 'booking' )
124 . ' <br> '
125 . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
126 . ' <a href="javascript:void(0)" onclick="'
127 .'jQuery( this ).next().toggle();'
128 .'jQuery( this).hide();'
129 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
130 .'">'
131 . __( 'Show more details' )
132 . '</a>'
133 . ' <div style="display:none;">'
134 . '<p><hr><code>'
135 . json_encode( $available_slots )
136 . '</code></p>'
137 . '</div>'
138 . ' <div style="display:none;">' . json_encode( $available_slots ) . '</div>'
139 );
140 }
141
142 } else {
143
144 // == In ANY 'child' booking resources =========================================================
145
146 $availability_in_any_child_resources = array();
147 foreach ( $available_slots as $day_sql_key => $available_slot ) { // '2023-09-10': [], '2023-09-14': [],
148 $availability_in_any_child_resources[ $day_sql_key ] = array();
149 foreach ( $available_slot as $ind => $slot_value ) { // [ 0:{ resource_id: 2, is_available: false,...} , .... ]
150 if ( $slot_value['is_available'] ) {
151 if ( empty( $main__resource_id ) ) {
152 $main__resource_id = $slot_value['resource_id'];
153 }
154 $availability_in_any_child_resources[ $day_sql_key ][] = $slot_value['resource_id'];
155 }
156 }
157 }
158 /**
159 * { "2023-09-10": [ 2, 10, 11 ] <- available ID of child resources in this date
160 "2023-09-14": [ 4 ] <- available ID of child resources in this date
161 }
162 */
163
164 foreach ( $availability_in_any_child_resources as $day_sql_key2 => $available_res_in_day_arr ) {
165 if ( count( $available_res_in_day_arr ) < $how_many_items_to_book ) {
166 // Bad not save
167 // We can not store booking in this date day_sql_key2, number of available child booking resources less than required
168 return array(
169 'result' => 'error',
170 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
171 . ' <br> '
172 . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
173 . ' <a href="javascript:void(0)" onclick="'
174 .'jQuery( this ).next().toggle();'
175 .'jQuery( this).hide();'
176 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
177 .'">'
178 . __( 'Show more details' )
179 . '</a>'
180 . ' <div style="display:none;">'
181 . '<p><strong>'
182 . sprintf( __( 'Booking can not be saved in this date %s, number of available (single or child) booking resource(s) (%d) less than required (%d).', 'booking' )
183 , $day_sql_key2, count( $available_res_in_day_arr ), $how_many_items_to_book )
184 . '</strong><hr><code>'
185 . json_encode( $available_slots )
186 . '</code></p>'
187 . '</div>'
188
189 );
190 }
191 }
192
193 // Good Save it
194 return array(
195 'result' => 'ok',
196 'resources_in_dates' => $availability_in_any_child_resources, // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ]
197 'time_to_book' => $local_params['time_as_his_arr'], // [ "00:00:00", "24:00:00" ]
198 'main__resource_id' => $main__resource_id
199 );
200 }
201 }
202
203
204 /**
205 * Get available slots per each date in each slot (child resource). It's checking times as well.
206 *
207 * @param $params [
208 * dates_sql__arr = [ "2023-10-18", "2023-10-25", "2023-11-25" ]
209 * time_as_seconds_arr = [ 36030, 39570 ]
210 * availability_per_days = [ dates = [...], resources_id_arr__in_dates = [...] ]
211 * ]
212 *
213 * @return array [
214 * 2023-10-18 = [
215 * 0 = [
216 * resource_id = 2
217 * is_available = true
218 * booked__seconds = []
219 * booked__readable = []
220 * time_to_book__seconds = [ 36030, 39570 ]
221 * time_to_book__readable = "10:00:00", "11:00:00" ]
222 * ]
223 * 1 = [...]
224 * 2 = [...]
225 * 3 = [...]
226 * ]
227 * 2023-10-25 = [...]
228 * 2023-11-25 = [...]
229 * ]
230 */
231 function wpbc__get_available_slots__for_selected_dates_times__bl( $params ) {
232
233 $defaults = array(
234 'dates_sql__arr' => array(),
235 'time_as_seconds_arr' => array(),
236 'availability_per_days' => array(),
237 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
238 );
239 $params = wp_parse_args( $params, $defaults );
240
241 $time_as_seconds_arr = $params['time_as_seconds_arr'];
242
243 // Shift time interval in 30 seconds
244 $shift__30sec = array( 30, 30 );
245 $time_as_seconds_arr[ 0 ] = $time_as_seconds_arr[ 0 ] + $shift__30sec[0];
246 $time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 1 ] - $shift__30sec[1];
247
248 $available_resources_arr = array();
249
250 foreach ( $params['dates_sql__arr'] as $sql_class_day_number => $sql_class_day ) {
251 $available_resources_arr[ $sql_class_day ] = array();
252 $date_shift__30sec = $shift__30sec;
253
254 if ( isset( $params['availability_per_days']['dates'][ $sql_class_day ] ) ) {
255
256 $this_date_time_as_seconds_arr = $time_as_seconds_arr;
257
258 //TODO: debug this checking in biz_l.js 2023-09-05 16:40 --- If we are using not time slot but the check in/out times ?
259
260 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
261 // Duplicated part of code, as in ../do_search.php //FixIn: 2024-05-12_11:58
262 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
263 if (
264 ( ! $params['is_use_booking_recurrent_time'] )
265 && ( count( $params['dates_sql__arr'] ) > 1 )
266 ) {
267 if ( 0 == $sql_class_day_number ) { // check in
268 $this_date_time_as_seconds_arr[1] = 24 * 60 * 60;
269 $date_shift__30sec[1] = 0;
270 } else if ( ( count( $params['dates_sql__arr'] ) - 1 ) == $sql_class_day_number ) { // check out
271 $this_date_time_as_seconds_arr[0] = 0;
272 $date_shift__30sec[0] = 0;
273 } else {
274 $this_date_time_as_seconds_arr = array( 0, 24 * 60 * 60 );
275 $date_shift__30sec = array( 0, 0 );
276 }
277 }
278 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
279
280 $date_bookings_obj = $params['availability_per_days']['dates'][ $sql_class_day ];
281
282 foreach ( $params['availability_per_days']['resources_id_arr__in_dates'] as $child_resource_id ) {
283
284 $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ] );
285
286 $is_intersect = wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds_arr['merged_seconds'], $this_date_time_as_seconds_arr );
287
288 $this_date_available_resource = array(
289 'resource_id' => $child_resource_id,
290 'is_available' => (! $is_intersect),
291 'booked__seconds' => $merged_seconds_arr['merged_seconds'],
292 'booked__readable' => $merged_seconds_arr['merged_readable'],
293 'time_to_book__seconds' => $this_date_time_as_seconds_arr,
294 'time_to_book__readable'=> array()
295 );
296 $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his(
297 (
298 ( ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] ) < 0 )
299 ? 0
300 : ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] )
301 )
302 );
303 $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his(
304 (
305 ( ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] ) > 86400 )
306 ? 86400
307 : ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] )
308 )
309 );
310
311 $available_resources_arr[ $sql_class_day ][] = $this_date_available_resource;
312 }
313 }
314 }
315
316 return $available_resources_arr;
317 }
318
319
320 /**
321 * Get Merged Seconds Array from object -> $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ]
322 *
323 * @param $date_booking_obj - date_bookings_obj from $params['availability_per_days']['dates']
324 *
325 * @return array - [
326 * 'merged_seconds' => $merged_seconds,
327 * 'merged_readable' => $merged_readable
328 * ]
329 */
330 function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj ) {
331
332 if ( $date_booking_obj->is_day_unavailable ){
333 $merged_seconds = array( array( 0, 24 * 60 * 60 ) ); // Unavailable
334 $merged_readable = array( wpbc_transform_timerange__seconds_arr__in__formated_hours( array( 0, 24 * 60 * 60 ) ) );
335 } else {
336 $merged_seconds = $date_booking_obj->booked_time_slots['merged_seconds']; // [ [ 25211, 27002 ], [ 36011, 86400 ] ] // Time slots or Available
337 $merged_readable = $date_booking_obj->booked_time_slots['merged_readable'];
338 }
339
340 return array(
341 'merged_seconds' => $merged_seconds,
342 'merged_readable' => $merged_readable
343 );
344 }
345
346
347 /**
348 * Check if merged_seconds in $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ] intersect with $time_as_seconds_arr
349 *
350 * @param $merged_seconds - [ [ 0, 86400 ] ]
351
352 * @param $this_date_time_as_seconds_arr - [ 36030, 39570 ] | [ 0, 24*60*60 ]
353 *
354 * @return bool
355 */
356 function wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds, $this_date_time_as_seconds_arr ) {
357
358 $is_intersect = wpbc_is_intersect__range_time_interval(
359 array(
360 array(
361 intval( $this_date_time_as_seconds_arr[ 0 ] ) + 20
362 , intval( $this_date_time_as_seconds_arr[ 1 ] ) - 20
363 )
364 )
365 , $merged_seconds );
366 return $is_intersect;
367 }
368
369
370 /**
371 * Is these array of intervals intersected ? - overlay of Math function
372 *
373 * @param array $time_interval_A array( array( 21600, 23400 ) )
374 * @param array $time_interval_B array( array( 25211, 27002 ), array( 36011, 86400 ) )
375 *
376 * @return bool
377 */
378 function wpbc_is_intersect__range_time_interval( $time_interval_A, $time_interval_B ){
379
380 for ( $i = 0; $i < count($time_interval_A); $i++ ){
381
382 for ( $j = 0; $j < count($time_interval_B); $j++ ){
383
384 $is_intersect = wpbc_is__intervals__intersected( $time_interval_A[ $i ], $time_interval_B[ $j ] );
385
386 if ( $is_intersect ){
387 return true;
388 }
389 }
390 }
391
392 return false;
393 }
394