PluginProbe
Booking Calendar / 10.10.1
Booking Calendar v10.10.1
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.10.1, at includes/_capacity/where_to_save.php

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