PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 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 All 204 releases
← All changes | includes/_capacity/where_to_save.php +132 -11 10.10.111.8.4 View file →
@@ -6,8 +6,33 @@
6 6 // Check where to save the booking
7 7 // ---------------------------------------------------------------------------------------------------------------------
8 8
9 9 /**
10 + * Check if these dates contain marker '2981-01-13', which is means that this booking was submited without dates - as Contact Form.
11 + *
12 + * @param array|string $dates_sql_arr - array of SQL dates.
13 + *
14 + * @return bool
15 + */
16 +function wpbc_is_these_dates__for__no_dates( $dates_sql_arr ){
17 +
18 + // FixIn: 2981-01-13 13 Jan 2981.
19 +
20 + if ( is_array( $dates_sql_arr ) ) {
21 + foreach ( $dates_sql_arr as $date_ymd ) {
22 + if ( '2981-01-13' === gmdate( 'Y-m-d', mysql2date( 'U', $date_ymd ) ) ) {
23 + return true;
24 + }
25 + }
26 + } elseif ( '2981-01-13' === gmdate( 'Y-m-d', mysql2date( 'U', $dates_sql_arr ) ) ) {
27 + return true;
28 + }
29 +
30 + return false;
31 +}
32 +
33 +
34 +/**
10 35 * Get booking resources for each selected date, where we can save the booking, or false if we can not save it
11 36 *
12 37 * @param array $params = [
13 38 * 'resource_id' => 2
@@ -29,10 +54,12 @@
29 54 $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 55 $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 56 $defaults = array(
32 57 '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
58 + 'allow_past' => false,
33 59 'as_single_resource' => false,
34 60 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ),
61 + 'time_override_source' => '',
35 62 'aggregate_resource_id_arr' => array(),
36 63 'custom_form' => '' //FixIn: 10.0.0.10 // Required for checking all available time-slots and compare with booked time slots
37 64 );
38 65 $local_params = wp_parse_args( $local_params, $defaults );
@@ -47,9 +74,13 @@
47 74 $local_params['time_as_his_arr'] = array(
48 75 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ),
49 76 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] )
50 77 );
51 -
78 + // FixIn: 2981-01-13 13 Jan 2981
79 + $availability_per_days_arr__params = array();
80 + if ( ( ! empty( $local_params['dates_only_sql_arr'] ) ) && ( is_array( $local_params['dates_only_sql_arr'] ) ) && ( '2981-01-13' === $local_params['dates_only_sql_arr'][0] ) ) {
81 + $availability_per_days_arr__params['is_days_always_available'] = true;
82 + }
52 83 // 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 84 if ( function_exists( 'wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after' ) ) {
54 85 $maybe_extended__dates_to_check_arr = wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after( $local_params['dates_only_sql_arr'] );
55 86 } else {
@@ -55,21 +86,55 @@
55 86 } else {
56 87 $maybe_extended__dates_to_check_arr = $local_params['dates_only_sql_arr'];
57 88 }
58 89 // [ "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(
90 +
91 + $availability_per_days = wpbc_get_availability_per_days_arr( wp_parse_args( array(
60 92 'resource_id' => $local_params['resource_id'],
61 93 'skip_booking_id' => $local_params['skip_booking_id'],
62 94 'dates_to_check' => $maybe_extended__dates_to_check_arr,
63 95 'request_uri' => $local_params['request_uri'],
96 + 'allow_past' => ! empty( $local_params['allow_past'] ),
64 97 '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 98 'additional_bk_types' => $local_params['aggregate_resource_id_arr'],
66 99 '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 100 'custom_form' => $local_params['custom_form'], // FixIn: 10.0.0.10.
68 - ) );
101 + ) , $availability_per_days_arr__params ) );
69 102
103 + // A contact form has no calendar and uses one synthetic date only to satisfy the booking storage schema.
104 + // Keep its requested resource, because calendar availability rules do not apply to a no-date submission.
105 + $is_no_dates_booking = ( is_array( $local_params['dates_only_sql_arr'] ) && ( 1 === count( $local_params['dates_only_sql_arr'] ) ) &&
106 + wpbc_is_these_dates__for__no_dates( $local_params['dates_only_sql_arr'] ) );
107 + if ( $is_no_dates_booking ) {
108 + $requested_resource_id = absint( $local_params['resource_id'] );
109 + $loaded_resource_ids = isset( $availability_per_days['resources_id_arr__in_dates'] ) ? array_map( 'absint', (array) $availability_per_days['resources_id_arr__in_dates'] ) : array();
110 +
111 + if ( ( 0 === $requested_resource_id ) || ! in_array( $requested_resource_id, $loaded_resource_ids, true ) ) {
112 + return array(
113 + 'result' => 'error',
114 + 'message' => 'Wrong ID of booking resource: ' . $requested_resource_id,
115 + );
116 + }
117 +
118 + $storage_resource_ids = array_values(
119 + array_unique( array_merge( array( $requested_resource_id ), $loaded_resource_ids ) )
120 + );
121 + $resources_in_dates = array_fill_keys(
122 + array_values( $local_params['dates_only_sql_arr'] ),
123 + $storage_resource_ids
124 + );
125 +
126 + return array(
127 + 'result' => 'ok',
128 + 'resources_in_dates' => $resources_in_dates,
129 + 'time_to_book' => $local_params['time_as_his_arr'],
130 + 'main__resource_id' => $requested_resource_id,
131 + );
132 + }
133 +
70 134 // Get value of how many booking resources to book
71 135 $how_many_items_to_book = $local_params['how_many_items_to_book'];
136 +
72 137 // -------------------------------------------------------------------------------------------------------------
73 138 // [ 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 139 $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array(
75 140 'dates_sql__arr' => $local_params['dates_only_sql_arr'],
@@ -74,14 +139,15 @@
74 139 $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array(
75 140 'dates_sql__arr' => $local_params['dates_only_sql_arr'],
76 141 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'],
77 142 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'],
143 + 'time_override_source' => $local_params['time_override_source'],
78 144 'availability_per_days' => $availability_per_days
79 145 ) );
80 146
81 147 $main__resource_id = 0;
82 148 // == In SAME 'child' booking resources ============================================================
83 - if ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) {
149 + if ( class_exists( 'wpdev_bk_biz_l' ) && ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) ) {
84 150
85 151 $availability_in_same_child_resources = $availability_per_days['resources_id_arr__in_dates'];
86 152
87 153 foreach ( $availability_per_days['resources_id_arr__in_dates'] as $child_resource_id ) {
@@ -119,13 +185,13 @@
119 185 } else {
120 186 // Bad not save
121 187 return array(
122 188 'result' => 'error',
123 - 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
189 + 'message' => wpbc_frontend_messages__get( 'message_dates_times_unavailable', array(), $local_params['resource_id'] )
124 190 . ' <br> '
125 - . __( 'It is not possible to store this sequence of the dates into the one same resource.' , 'booking' )
191 + . wpbc_frontend_messages__get( 'message_cannot_save_in_one_resource', array(), $local_params['resource_id'] )
126 192 . ' <br> '
127 - . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
193 + . wpbc_frontend_messages__get( 'message_choose_alternative_dates', array(), $local_params['resource_id'] )
128 194 . ' <a href="javascript:void(0)" onclick="'
129 195 .'jQuery( this ).next().toggle();'
130 196 .'jQuery( this).hide();'
131 197 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
@@ -168,11 +234,11 @@
168 234 // Bad not save
169 235 // We can not store booking in this date day_sql_key2, number of available child booking resources less than required
170 236 return array(
171 237 'result' => 'error',
172 - 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
238 + 'message' => wpbc_frontend_messages__get( 'message_dates_times_unavailable', array(), $local_params['resource_id'] )
173 239 . ' <br> '
174 - . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
240 + . wpbc_frontend_messages__get( 'message_choose_alternative_dates', array(), $local_params['resource_id'] )
175 241 . ' <a href="javascript:void(0)" onclick="'
176 242 .'jQuery( this ).next().toggle();'
177 243 .'jQuery( this).hide();'
178 244 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
@@ -237,8 +303,9 @@
237 303 $defaults = array(
238 304 'dates_sql__arr' => array(),
239 305 'time_as_seconds_arr' => array(),
240 306 'availability_per_days' => array(),
307 + 'time_override_source' => '',
241 308 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
242 309 );
243 310 $params = wp_parse_args( $params, $defaults );
244 311
@@ -284,9 +351,9 @@
284 351 $date_bookings_obj = $params['availability_per_days']['dates'][ $sql_class_day ];
285 352
286 353 foreach ( $params['availability_per_days']['resources_id_arr__in_dates'] as $child_resource_id ) {
287 354
288 - $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ] );
355 + $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ], $params['time_override_source'] );
289 356
290 357 $is_intersect = wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds_arr['merged_seconds'], $this_date_time_as_seconds_arr );
291 358
292 359 $this_date_available_resource = array(
@@ -330,10 +397,24 @@
330 397 * 'merged_seconds' => $merged_seconds,
331 398 * 'merged_readable' => $merged_readable
332 399 * ]
333 400 */
334 - function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj ) {
401 + function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj, $time_override_source = '' ) {
335 402
403 + $is_times_availability_full_day_status = (
404 + ( 'times_availability' === $time_override_source )
405 + && ( ! empty( $date_booking_obj->is_day_unavailable ) )
406 + && ( ! empty( $date_booking_obj->_day_status ) )
407 + && ( 'full_day_booking' === $date_booking_obj->_day_status )
408 + );
409 +
410 + if ( $is_times_availability_full_day_status ) {
411 + $merged_seconds_arr = wpbc_get__booking_obj__booked_details_seconds_arr( $date_booking_obj );
412 + if ( ! empty( $merged_seconds_arr['merged_seconds'] ) ) {
413 + return $merged_seconds_arr;
414 + }
415 + }
416 +
336 417 if ( $date_booking_obj->is_day_unavailable ){
337 418 $merged_seconds = array( array( 0, 24 * 60 * 60 ) ); // Unavailable
338 419 $merged_readable = array( wpbc_transform_timerange__seconds_arr__in__formated_hours( array( 0, 24 * 60 * 60 ) ) );
339 420 } else {
@@ -344,8 +425,48 @@
344 425 return array(
345 426 'merged_seconds' => $merged_seconds,
346 427 'merged_readable' => $merged_readable
347 428 );
429 + }
430 +
431 +
432 + /**
433 + * Rebuild real booked intervals from details after capacity marks the whole day unavailable.
434 + *
435 + * @param object $date_booking_obj Availability object for a date/resource.
436 + *
437 + * @return array
438 + */
439 + function wpbc_get__booking_obj__booked_details_seconds_arr( $date_booking_obj ) {
440 +
441 + $seconds_arr = array();
442 + $readable_arr = array();
443 +
444 + if ( empty( $date_booking_obj->__booked__times__details ) || ! is_array( $date_booking_obj->__booked__times__details ) ) {
445 + return array(
446 + 'merged_seconds' => array(),
447 + 'merged_readable' => array(),
448 + );
449 + }
450 +
451 + foreach ( $date_booking_obj->__booked__times__details as $time_key => $details ) {
452 + if ( '0' === (string) $time_key || false === strpos( (string) $time_key, '-' ) ) {
453 + $seconds_arr[] = array( 0, 24 * 60 * 60 );
454 + } else {
455 + $seconds_arr[] = wpbc_transform_timerange__s_range__in__seconds_arr( $time_key );
456 + }
457 + }
458 +
459 + $seconds_arr = wpbc_merge_intersected_intervals( $seconds_arr );
460 +
461 + foreach ( $seconds_arr as $booked_time_slots__in_seconds ) {
462 + $readable_arr[] = wpbc_transform_timerange__seconds_arr__in__formated_hours( $booked_time_slots__in_seconds );
463 + }
464 +
465 + return array(
466 + 'merged_seconds' => $seconds_arr,
467 + 'merged_readable' => $readable_arr,
468 + );
348 469 }
349 470
350 471
351 472 /**