PluginProbe
Booking Calendar / 10.10
Booking Calendar v10.10
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 10.11.3 All 202 releases
booking / includes / _capacity / where_to_save.php

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

397 lines 21.7 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 . '</code></p>'
190 . '</div>'
191
192 );
193 }
194 }
195
196 // Good Save it
197 return array(
198 'result' => 'ok',
199 'resources_in_dates' => $availability_in_any_child_resources, // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ]
200 'time_to_book' => $local_params['time_as_his_arr'], // [ "00:00:00", "24:00:00" ]
201 'main__resource_id' => $main__resource_id
202 );
203 }
204 }
205
206
207 /**
208 * Get available slots per each date in each slot (child resource). It's checking times as well.
209 *
210 * @param $params [
211 * dates_sql__arr = [ "2023-10-18", "2023-10-25", "2023-11-25" ]
212 * time_as_seconds_arr = [ 36030, 39570 ]
213 * availability_per_days = [ dates = [...], resources_id_arr__in_dates = [...] ]
214 * ]
215 *
216 * @return array [
217 * 2023-10-18 = [
218 * 0 = [
219 * resource_id = 2
220 * is_available = true
221 * booked__seconds = []
222 * booked__readable = []
223 * time_to_book__seconds = [ 36030, 39570 ]
224 * time_to_book__readable = "10:00:00", "11:00:00" ]
225 * ]
226 * 1 = [...]
227 * 2 = [...]
228 * 3 = [...]
229 * ]
230 * 2023-10-25 = [...]
231 * 2023-11-25 = [...]
232 * ]
233 */
234 function wpbc__get_available_slots__for_selected_dates_times__bl( $params ) {
235
236 $defaults = array(
237 'dates_sql__arr' => array(),
238 'time_as_seconds_arr' => array(),
239 'availability_per_days' => array(),
240 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
241 );
242 $params = wp_parse_args( $params, $defaults );
243
244 $time_as_seconds_arr = $params['time_as_seconds_arr'];
245
246 // Shift time interval in 30 seconds
247 $shift__30sec = array( 30, 30 );
248 $time_as_seconds_arr[ 0 ] = $time_as_seconds_arr[ 0 ] + $shift__30sec[0];
249 $time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 1 ] - $shift__30sec[1];
250
251 $available_resources_arr = array();
252
253 foreach ( $params['dates_sql__arr'] as $sql_class_day_number => $sql_class_day ) {
254 $available_resources_arr[ $sql_class_day ] = array();
255 $date_shift__30sec = $shift__30sec;
256
257 if ( isset( $params['availability_per_days']['dates'][ $sql_class_day ] ) ) {
258
259 $this_date_time_as_seconds_arr = $time_as_seconds_arr;
260
261 //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 ?
262
263 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
264 // Duplicated part of code, as in ../do_search.php //FixIn: 2024-05-12_11:58
265 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
266 if (
267 ( ! $params['is_use_booking_recurrent_time'] )
268 && ( count( $params['dates_sql__arr'] ) > 1 )
269 ) {
270 if ( 0 == $sql_class_day_number ) { // check in
271 $this_date_time_as_seconds_arr[1] = 24 * 60 * 60;
272 $date_shift__30sec[1] = 0;
273 } else if ( ( count( $params['dates_sql__arr'] ) - 1 ) == $sql_class_day_number ) { // check out
274 $this_date_time_as_seconds_arr[0] = 0;
275 $date_shift__30sec[0] = 0;
276 } else {
277 $this_date_time_as_seconds_arr = array( 0, 24 * 60 * 60 );
278 $date_shift__30sec = array( 0, 0 );
279 }
280 }
281 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
282
283 $date_bookings_obj = $params['availability_per_days']['dates'][ $sql_class_day ];
284
285 foreach ( $params['availability_per_days']['resources_id_arr__in_dates'] as $child_resource_id ) {
286
287 $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ] );
288
289 $is_intersect = wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds_arr['merged_seconds'], $this_date_time_as_seconds_arr );
290
291 $this_date_available_resource = array(
292 'resource_id' => $child_resource_id,
293 'is_available' => (! $is_intersect),
294 'booked__seconds' => $merged_seconds_arr['merged_seconds'],
295 'booked__readable' => $merged_seconds_arr['merged_readable'],
296 'time_to_book__seconds' => $this_date_time_as_seconds_arr,
297 'time_to_book__readable'=> array()
298 );
299 $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his(
300 (
301 ( ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] ) < 0 )
302 ? 0
303 : ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] )
304 )
305 );
306 $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his(
307 (
308 ( ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] ) > 86400 )
309 ? 86400
310 : ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] )
311 )
312 );
313
314 $available_resources_arr[ $sql_class_day ][] = $this_date_available_resource;
315 }
316 }
317 }
318
319 return $available_resources_arr;
320 }
321
322
323 /**
324 * Get Merged Seconds Array from object -> $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ]
325 *
326 * @param $date_booking_obj - date_bookings_obj from $params['availability_per_days']['dates']
327 *
328 * @return array - [
329 * 'merged_seconds' => $merged_seconds,
330 * 'merged_readable' => $merged_readable
331 * ]
332 */
333 function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj ) {
334
335 if ( $date_booking_obj->is_day_unavailable ){
336 $merged_seconds = array( array( 0, 24 * 60 * 60 ) ); // Unavailable
337 $merged_readable = array( wpbc_transform_timerange__seconds_arr__in__formated_hours( array( 0, 24 * 60 * 60 ) ) );
338 } else {
339 $merged_seconds = $date_booking_obj->booked_time_slots['merged_seconds']; // [ [ 25211, 27002 ], [ 36011, 86400 ] ] // Time slots or Available
340 $merged_readable = $date_booking_obj->booked_time_slots['merged_readable'];
341 }
342
343 return array(
344 'merged_seconds' => $merged_seconds,
345 'merged_readable' => $merged_readable
346 );
347 }
348
349
350 /**
351 * Check if merged_seconds in $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ] intersect with $time_as_seconds_arr
352 *
353 * @param $merged_seconds - [ [ 0, 86400 ] ]
354
355 * @param $this_date_time_as_seconds_arr - [ 36030, 39570 ] | [ 0, 24*60*60 ]
356 *
357 * @return bool
358 */
359 function wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds, $this_date_time_as_seconds_arr ) {
360
361 $is_intersect = wpbc_is_intersect__range_time_interval(
362 array(
363 array(
364 intval( $this_date_time_as_seconds_arr[ 0 ] ) + 20
365 , intval( $this_date_time_as_seconds_arr[ 1 ] ) - 20
366 )
367 )
368 , $merged_seconds );
369 return $is_intersect;
370 }
371
372
373 /**
374 * Is these array of intervals intersected ? - overlay of Math function
375 *
376 * @param array $time_interval_A array( array( 21600, 23400 ) )
377 * @param array $time_interval_B array( array( 25211, 27002 ), array( 36011, 86400 ) )
378 *
379 * @return bool
380 */
381 function wpbc_is_intersect__range_time_interval( $time_interval_A, $time_interval_B ){
382
383 for ( $i = 0; $i < count($time_interval_A); $i++ ){
384
385 for ( $j = 0; $j < count($time_interval_B); $j++ ){
386
387 $is_intersect = wpbc_is__intervals__intersected( $time_interval_A[ $i ], $time_interval_B[ $j ] );
388
389 if ( $is_intersect ){
390 return true;
391 }
392 }
393 }
394
395 return false;
396 }
397