File manager - Edit - /home/premiey/www/wp-includes/images/media/_capacity.tar
Back
where_to_save.php 0000666 00000052077 15165546743 0010146 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // --------------------------------------------------------------------------------------------------------------------- // Check where to save the booking // --------------------------------------------------------------------------------------------------------------------- /** * Get booking resources for each selected date, where we can save the booking, or false if we can not save it * * @param array $params = [ * 'resource_id' => 2 * 'skip_booking_id' => '', | 125 if edit booking * 'dates_only_sql_arr' => [ "2023-10-18", "2023-10-25", "2023-11-25" ] * 'time_as_seconds_arr' => [ 36000, 39600 ] * 'how_many_items_to_book' => 1 * 'request_uri' => 'http://beta/resource-id2/' // Optional default -> DOING_AJAX ? $_SERVER['HTTP_REFERER'] : $_SERVER['REQUEST_URI'] * 'as_single_resource' => false, // Optional default false * 'is_use_booking_recurrent_time' => false // Optional default ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) * ] * @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" ] ] * Note. 'main__resource_id' - it's first booking resource in the list, basically needed for saving in wp_booking DB table. * OR * = [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ] */ function wpbc__where_to_save_booking( $local_params ){ $defaults = array( '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 'as_single_resource' => false, 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ), 'aggregate_resource_id_arr' => array(), 'custom_form' => '' //FixIn: 10.0.0.10 // Required for checking all available time-slots and compare with booked time slots ); $local_params = wp_parse_args( $local_params, $defaults ); $time_as_seconds_arr = $local_params['time_as_seconds_arr']; $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 $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 if ( ( 0 != $time_as_seconds_arr[0] ) && ( ( 24 * 60 * 60 ) == $time_as_seconds_arr[1] ) ) { //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 $time_as_seconds_arr[1] += - 8; } $local_params['time_as_his_arr'] = array( wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ), wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] ) ); // If we are using the unavailable before/after booking dates, then we need to extend "$local_params['dates_only_sql_arr']" to such dates. if ( function_exists( 'wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after' ) ) { $maybe_extended__dates_to_check_arr = wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after( $local_params['dates_only_sql_arr'] ); } else { $maybe_extended__dates_to_check_arr = $local_params['dates_only_sql_arr']; } // [ "dates": [ "2023-11-05": [ "day_availability":4, ... "2": [ "is_day_unavailable":false, ...]], '2023-11-06':[...] ] ,"resources_id_arr__in_dates":[2,12,10,11]} $availability_per_days = wpbc_get_availability_per_days_arr( array( 'resource_id' => $local_params['resource_id'], 'skip_booking_id' => $local_params['skip_booking_id'], 'dates_to_check' => $maybe_extended__dates_to_check_arr, 'request_uri' => $local_params['request_uri'], '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' 'additional_bk_types' => $local_params['aggregate_resource_id_arr'], '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 'custom_form' => $local_params['custom_form'] //FixIn: 10.0.0.10 ) ); // Get value of how many booking resources to book $how_many_items_to_book = $local_params['how_many_items_to_book']; // ------------------------------------------------------------------------------------------------------------- // [ 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: [...] ] $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array( 'dates_sql__arr' => $local_params['dates_only_sql_arr'], 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], 'availability_per_days' => $availability_per_days ) ); $main__resource_id = 0; // == In SAME 'child' booking resources ============================================================ if ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) { $availability_in_same_child_resources = $availability_per_days['resources_id_arr__in_dates']; foreach ( $availability_per_days['resources_id_arr__in_dates'] as $child_resource_id ) { foreach ( $local_params['dates_only_sql_arr'] as $day_sql_key ) { foreach ( $available_slots[ $day_sql_key ] as $available_slot ) { if ( ( $child_resource_id == $available_slot['resource_id'] ) && ( ! $available_slot['is_available'] ) ){ $availability_in_same_child_resources = array_diff( $availability_in_same_child_resources, array( $child_resource_id ) ); // Remove $child_resource_id from array break; } } } } // Reset indexes in this array for ability to get first [0] element in this arr. $availability_in_same_child_resources = array_values( $availability_in_same_child_resources ); $main__resource_id = ( ! empty( $availability_in_same_child_resources ) ) ? $availability_in_same_child_resources[0] : 0; // [ 2, 12, 11 ] <- ID of child booking resources, where we can save our booking in the same child booking resource! if ( count( $availability_in_same_child_resources ) >= $how_many_items_to_book ) { $availability_in_same_child_resources_by_dates = array(); foreach ( $local_params['dates_only_sql_arr'] as $day_sql_key ) { $availability_in_same_child_resources_by_dates[ $day_sql_key ] = $availability_in_same_child_resources; } // Good Save it return array( 'result' => 'ok', 'resources_in_dates' => $availability_in_same_child_resources_by_dates, // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ] 'time_to_book' => $local_params['time_as_his_arr'], // [ "00:00:00", "24:00:00" ] 'main__resource_id' => $main__resource_id ); } else { // Bad not save return array( 'result' => 'error', 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' ) . ' <br> ' . __( 'It is not possible to store this sequence of the dates into the one same resource.' , 'booking' ) . ' <br> ' . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' ) . ' <a href="javascript:void(0)" onclick="' .'jQuery( this ).next().toggle();' .'jQuery( this).hide();' .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});' .'">' . __( 'Show more details' ) . '</a>' . ' <div style="display:none;">' . '<p><hr><code>' . json_encode( $available_slots ) . '</code></p>' . '</div>' . ' <div style="display:none;">' . json_encode( $available_slots ) . '</div>' ); } } else { // == In ANY 'child' booking resources ========================================================= $availability_in_any_child_resources = array(); foreach ( $available_slots as $day_sql_key => $available_slot ) { // '2023-09-10': [], '2023-09-14': [], $availability_in_any_child_resources[ $day_sql_key ] = array(); foreach ( $available_slot as $ind => $slot_value ) { // [ 0:{ resource_id: 2, is_available: false,...} , .... ] if ( $slot_value['is_available'] ) { if ( empty( $main__resource_id ) ) { $main__resource_id = $slot_value['resource_id']; } $availability_in_any_child_resources[ $day_sql_key ][] = $slot_value['resource_id']; } } } /** * { "2023-09-10": [ 2, 10, 11 ] <- available ID of child resources in this date "2023-09-14": [ 4 ] <- available ID of child resources in this date } */ foreach ( $availability_in_any_child_resources as $day_sql_key2 => $available_res_in_day_arr ) { if ( count( $available_res_in_day_arr ) < $how_many_items_to_book ) { // Bad not save // We can not store booking in this date day_sql_key2, number of available child booking resources less than required return array( 'result' => 'error', 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' ) . ' <br> ' . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' ) . ' <a href="javascript:void(0)" onclick="' .'jQuery( this ).next().toggle();' .'jQuery( this).hide();' .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});' .'">' . __( 'Show more details' ) . '</a>' . ' <div style="display:none;">' . '<p><strong>' . 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' ) , $day_sql_key2, count( $available_res_in_day_arr ), $how_many_items_to_book ) . '</strong><hr><code>' . json_encode( $available_slots ) . '</code></p>' . '</div>' ); } } // Good Save it return array( 'result' => 'ok', 'resources_in_dates' => $availability_in_any_child_resources, // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ] 'time_to_book' => $local_params['time_as_his_arr'], // [ "00:00:00", "24:00:00" ] 'main__resource_id' => $main__resource_id ); } } /** * Get available slots per each date in each slot (child resource). It's checking times as well. * * @param $params [ * dates_sql__arr = [ "2023-10-18", "2023-10-25", "2023-11-25" ] * time_as_seconds_arr = [ 36030, 39570 ] * availability_per_days = [ dates = [...], resources_id_arr__in_dates = [...] ] * ] * * @return array [ * 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 = [...] * ] */ function wpbc__get_available_slots__for_selected_dates_times__bl( $params ) { $defaults = array( 'dates_sql__arr' => array(), 'time_as_seconds_arr' => array(), 'availability_per_days' => array(), 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) ); $params = wp_parse_args( $params, $defaults ); $time_as_seconds_arr = $params['time_as_seconds_arr']; // Shift time interval in 30 seconds $shift__30sec = array( 30, 30 ); $time_as_seconds_arr[ 0 ] = $time_as_seconds_arr[ 0 ] + $shift__30sec[0]; $time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 1 ] - $shift__30sec[1]; $available_resources_arr = array(); foreach ( $params['dates_sql__arr'] as $sql_class_day_number => $sql_class_day ) { $available_resources_arr[ $sql_class_day ] = array(); $date_shift__30sec = $shift__30sec; if ( isset( $params['availability_per_days']['dates'][ $sql_class_day ] ) ) { $this_date_time_as_seconds_arr = $time_as_seconds_arr; //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 ? // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Duplicated part of code, as in ../do_search.php //FixIn: 2024-05-12_11:58 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if ( ( ! $params['is_use_booking_recurrent_time'] ) && ( count( $params['dates_sql__arr'] ) > 1 ) ) { if ( 0 == $sql_class_day_number ) { // check in $this_date_time_as_seconds_arr[1] = 24 * 60 * 60; $date_shift__30sec[1] = 0; } else if ( ( count( $params['dates_sql__arr'] ) - 1 ) == $sql_class_day_number ) { // check out $this_date_time_as_seconds_arr[0] = 0; $date_shift__30sec[0] = 0; } else { $this_date_time_as_seconds_arr = array( 0, 24 * 60 * 60 ); $date_shift__30sec = array( 0, 0 ); } } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ $date_bookings_obj = $params['availability_per_days']['dates'][ $sql_class_day ]; foreach ( $params['availability_per_days']['resources_id_arr__in_dates'] as $child_resource_id ) { $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ] ); $is_intersect = wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds_arr['merged_seconds'], $this_date_time_as_seconds_arr ); $this_date_available_resource = array( 'resource_id' => $child_resource_id, 'is_available' => (! $is_intersect), 'booked__seconds' => $merged_seconds_arr['merged_seconds'], 'booked__readable' => $merged_seconds_arr['merged_readable'], 'time_to_book__seconds' => $this_date_time_as_seconds_arr, 'time_to_book__readable'=> array() ); $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his( ( ( ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] ) < 0 ) ? 0 : ( $this_date_time_as_seconds_arr[0] - $date_shift__30sec[0] ) ) ); $this_date_available_resource['time_to_book__readable'][] = wpbc_transform__seconds__in__24_hours_his( ( ( ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] ) > 86400 ) ? 86400 : ( $this_date_time_as_seconds_arr[1] + $date_shift__30sec[1] ) ) ); $available_resources_arr[ $sql_class_day ][] = $this_date_available_resource; } } } return $available_resources_arr; } /** * Get Merged Seconds Array from object -> $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ] * * @param $date_booking_obj - date_bookings_obj from $params['availability_per_days']['dates'] * * @return array - [ * 'merged_seconds' => $merged_seconds, * 'merged_readable' => $merged_readable * ] */ function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj ) { if ( $date_booking_obj->is_day_unavailable ){ $merged_seconds = array( array( 0, 24 * 60 * 60 ) ); // Unavailable $merged_readable = array( wpbc_transform_timerange__seconds_arr__in__formated_hours( array( 0, 24 * 60 * 60 ) ) ); } else { $merged_seconds = $date_booking_obj->booked_time_slots['merged_seconds']; // [ [ 25211, 27002 ], [ 36011, 86400 ] ] // Time slots or Available $merged_readable = $date_booking_obj->booked_time_slots['merged_readable']; } return array( 'merged_seconds' => $merged_seconds, 'merged_readable' => $merged_readable ); } /** * Check if merged_seconds in $params['availability_per_days']['dates'][ $sql_class_day ][ $child_resource_id ] intersect with $time_as_seconds_arr * * @param $merged_seconds - [ [ 0, 86400 ] ] * @param $this_date_time_as_seconds_arr - [ 36030, 39570 ] | [ 0, 24*60*60 ] * * @return bool */ function wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds, $this_date_time_as_seconds_arr ) { $is_intersect = wpbc_is_intersect__range_time_interval( array( array( intval( $this_date_time_as_seconds_arr[ 0 ] ) + 20 , intval( $this_date_time_as_seconds_arr[ 1 ] ) - 20 ) ) , $merged_seconds ); return $is_intersect; } /** * Is these array of intervals intersected ? - overlay of Math function * * @param array $time_interval_A array( array( 21600, 23400 ) ) * @param array $time_interval_B array( array( 25211, 27002 ), array( 36011, 86400 ) ) * * @return bool */ function wpbc_is_intersect__range_time_interval( $time_interval_A, $time_interval_B ){ for ( $i = 0; $i < count($time_interval_A); $i++ ){ for ( $j = 0; $j < count($time_interval_B); $j++ ){ $is_intersect = wpbc_is__intervals__intersected( $time_interval_A[ $i ], $time_interval_B[ $j ] ); if ( $is_intersect ){ return true; } } } return false; } resource_support.php 0000666 00000024334 15165546743 0010732 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 class WPBC_RESOURCE_SUPPORT { public $resource_id_arr; public $as_single_resource; private $bookings_sql_obj_arr; function __construct( $params =array() ) { $defaults = array( 'resource_id' => 1 // CSD | D , 'as_single_resource' => false // If true, then skip child booking resources ); $params = wp_parse_args( $params, $defaults ); $this->resource_id_arr = $params['resource_id']; $this->as_single_resource = $params['as_single_resource']; if ( ! class_exists( 'wpdev_bk_personal' ) ) { $this->bookings_sql_obj_arr = $this->get_free_resource(); } else { $this->bookings_sql_obj_arr = $this->get__sql__booking_resources__arr(); } $this->reindex_booking_resources__by__resource_id(); $this->update__capacity__in_booking_resources(); } /** * Get default data for Free version * @return array */ private function get_free_resource() { $free_resource_obj = new stdClass(); $free_resource_obj->booking_type_id = 1; $free_resource_obj->default_form = 'standard'; $free_resource_obj->title = __( 'Default', 'booking' ); $free_resource_obj->users = 1; $free_resource_obj->import = ''; $free_resource_obj->export = ''; $free_resource_obj->cost = 0; $free_resource_obj->prioritet = 1; $free_resource_obj->parent = 0; $free_resource_obj->visitors = 1; $free_resource_obj->capacity = 1; return array( $free_resource_obj ); } /** * Get booking resources from the DB, based on request parameters * * @return array|mixed|object|stdClass[]|null */ function get__sql__booking_resources__arr() { // CACHE - GET :: check if such request was cached and get it ----------------------------------------------- //FixIn: 9.7.3.14 $params_for_cache = maybe_serialize( $this->resource_id_arr ); $cache_result = wpbc_cache__get( 'WPBC_RESOURCE_SUPPORT__sql', $params_for_cache ); if ( ! is_null( $cache_result ) ) { return $cache_result; } // ----------------------------------------------------------------------------------------------------------------- global $wpdb; // Init params $params = array( 'resource_id' => implode( ',', $this->resource_id_arr ) ); // S a n i t i z e $params_rules = array( 'resource_id' => array( 'validate' => 'digit_or_csd', 'default' => 1 ) ); $params = wpbc_sanitize_params_in_arr( $params, $params_rules ); // S Q L $sql = array(); $sql_args = array(); $sql['start_select'] = "SELECT * "; // "SELECT DISTINCT calendar_date "; $sql['from'] = "FROM {$wpdb->prefix}bookingtypes "; // W H E R E $sql['where'] = 'WHERE ( 1 = 1 ) '; if ( ! empty( $params['resource_id'] ) ) { $sql['where'] .= " AND ( "; $sql['where'] .= " booking_type_id IN ( {$params['resource_id']} ) "; if ( ( class_exists( 'wpdev_bk_biz_l' ) ) && ( ! $this->as_single_resource ) ) { $sql['where'] .= " OR parent IN ( {$params['resource_id']} ) "; } $sql['where'] .= " ) "; } /** * if ( '' != $params['prop_value'] ) { $sql['where'] .= " AND ( prop_value = %s ) "; $sql_args[] = $params['prop_value']; } */ // O R D E R if ( class_exists( 'wpdev_bk_biz_l' ) ) { $sql['order'] = " ORDER BY parent, prioritet, title, booking_type_id"; } else { $sql['order'] = " ORDER BY title, booking_type_id"; } // L I M I T $sql['limit'] = ''; /** * $sql['limit'] = " LIMIT %d, %d "; * $sql_args[] = ( $params['page_num'] - 1 ) * $params['page_items_count']; * $sql_args[] = $params['page_items_count']; */ /** * Good Practice: https://blog.ircmaxell.com/2017/10/disclosure-wordpress-wpdb-sql-injection-technical.html * * $sql['where'] .= "( bk.form LIKE %s ) "; * $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%'; * * if ( is_numeric( $params['keyword'] ) ) { * $sql['where'] .= " OR ( bk.booking_id = %d ) "; * $sql_args[] = intval( $params['keyword'] ); * } * */ if ( empty( $sql_args ) ) { $sql_prepared = $sql['start_select'] . $sql['from'] . $sql['where'] . $sql['order'] . $sql['limit']; } else { $sql_prepared = $wpdb->prepare( $sql['start_select'] . $sql['from'] . $sql['where'] . $sql['order'] . $sql['limit'] , $sql_args ); } $bookings_sql_obj = $wpdb->get_results( $sql_prepared ); // CACHE - SAVE :: ------------------------------------------------------------------------------------------------ $cache_result = wpbc_cache__save( 'WPBC_RESOURCE_SUPPORT__sql', $params_for_cache, $bookings_sql_obj ); return $bookings_sql_obj; } /** * Update capacity property to all booking resources * @return void */ private function update__capacity__in_booking_resources(){ foreach ( $this->bookings_sql_obj_arr as $key => $resource_obj ) { $is_this_child = ( ( isset( $resource_obj->parent ) ) && ( 0 != $resource_obj->parent ) ) ? true : false; $resource_id = $resource_obj->booking_type_id; $capacity_count = 1; if ( ( ! $is_this_child ) && ( class_exists( 'wpdev_bk_biz_l' ) ) ) { foreach ( $this->bookings_sql_obj_arr as $child_key => $child_resource_obj ) { if ( ( isset( $resource_obj->parent ) ) && ( $resource_id == $child_resource_obj->parent ) ) { $capacity_count++; } } } $this->bookings_sql_obj_arr[ $key ]->capacity = $capacity_count; } } /** * Reindex booking resource - set keys as resource_id * @return array */ private function reindex_booking_resources__by__resource_id (){ $resource__arr = array(); foreach ( $this->bookings_sql_obj_arr as $sort_key => $resource_obj ) { $resource_obj->sort_key=$sort_key; $resource__arr[ $resource_obj->booking_type_id ] = $resource_obj; } $this->bookings_sql_obj_arr = $resource__arr; return $this->bookings_sql_obj_arr; } /** * Get booking resource object with all properties from DB * * @param int $resource_id * * @return false|mixed|stdClass if not fount then false */ function get__booking_resource_obj( $resource_id ) { if ( isset( $this->bookings_sql_obj_arr[ $resource_id ] ) ) { return $this->bookings_sql_obj_arr[ $resource_id ]; } else { return false; } } /** * Get title of booking resource * * @param int $resource_id * * @return string */ function get_resource_title( $resource_id ) { $resource_title = ''; $resource_obj = $this->get__booking_resource_obj( $resource_id ); if ( false !== $resource_obj ) { $resource_title = $resource_obj->title; $resource_title = wpbc_lang( $resource_title ); } return $resource_title; } /** * Get ID of all booking resources [ 2, 10, 11, 12 ] * * @return array // [ 2, 10, 11, 12 ] */ function get_resource_id_arr() { $resource_id_arr = array_keys( $this->bookings_sql_obj_arr ); return $resource_id_arr; } /** * Get cost of all booking resources [ 'resource_id' => cost, ... ] * * @return array // [ 2=>20, 10>100, 12=>101, 13=>120 ] */ function get_resources_base_cost_arr() { $resource__arr = array(); foreach ( $this->bookings_sql_obj_arr as $key => $resource_obj ) { $resource__arr[ $resource_obj->booking_type_id ] = isset( $resource_obj->cost ) ? $resource_obj->cost : 0; } return $resource__arr; } public function get_resources_obj_arr(){ return $this->bookings_sql_obj_arr; } } // <editor-fold defaultstate="collapsed" desc=" == Support for booking resource IDs == " > // ----------------------------------------------------------------------------------------------------------------- // Support for booking resource IDs // ----------------------------------------------------------------------------------------------------------------- /** * Convert $resource_id and $additional_bk_types to one array * * in BL this $params['additional_bk_types'] is INT or CSD ,in low version it ARRAY * * @param mixed $resource_id - array, CSD, int * @param mixed $additional_bk_types - array, CSD, int * * @return array unique array of booking resource array( 1 ) | array( 3, 9, 10, 11 ) */ function wpbc_get_unique_array_of_resources_id( $resource_id = '', $additional_bk_types = '' ){ // in BL this $params['additional_bk_types'] is INT or CSD // in low version $params['additional_bk_types'] is ARRAY // If we do not pass any parameters, then use default booking resource with ID = 1 if ( ( empty( $resource_id ) ) && ( empty( $additional_bk_types ) ) ) { $resource_id = '1'; } // Get strings from parameters if ( is_array( $resource_id ) ) { $resource_id = implode( ',', $resource_id ); } else { $resource_id = (string) $resource_id; } if ( is_array( $additional_bk_types ) ) { $additional_bk_types = implode( ',', $additional_bk_types ); } else { $additional_bk_types = (string) $additional_bk_types; } $resource_id_csd = $resource_id . ',' . $additional_bk_types; // Concat 2 lists $resource_id_csd = str_replace( ';', ',', $resource_id_csd ); // Check for possible mistakes in separators $resource_id__arr = explode( ',', $resource_id_csd ); // Get one array of booking resources $resource_id__arr = array_unique( $resource_id__arr ); // Removes duplicate values from an array $resource_id__arr = array_filter( $resource_id__arr ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. // Sanitize ID values foreach ( $resource_id__arr as $resource_key => $resource_value ) { $resource_id__arr[ $resource_key ] = intval( $resource_value ); } return $resource_id__arr; } // </editor-fold> captcha_simple_text.php 0000666 00000014403 15165546743 0011323 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // --------------------------------------------------------------------------------------------------------------------- // Main function for ajax_ WPBC_AJX_BOOKING__CREATE // --------------------------------------------------------------------------------------------------------------------- /** * Check CAPTCHA during Ajax request from booking form and if it's incorrect, then STOP execution and send request to show warning * * @param $request_params [ 'captcha_user_input'=> '...', 'captcha_chalange'=> '...'] * @param $is_from_admin_panel true | false * @param $original_ajx_search_params usually $_REQUEST[ $request_prefix ] * * @return void wp_send_json() TO front-end or skip and continue */ function wpbc_captcha__in_ajx__check( $request_params, $is_from_admin_panel , $original_ajx_search_params ) { if ( ( 'On' === get_bk_option( 'booking_is_use_captcha' ) ) && ( ! $is_from_admin_panel ) && ( ( isset( $original_ajx_search_params['captcha_user_input'] ) ) && ( isset( $original_ajx_search_params['captcha_chalange'] ) ) ) ) { if ( ! wpbc_captcha__simple__is_ansfer_correct( $request_params['captcha_user_input'], $request_params['captcha_chalange'] ) ) { $captcha_arr = wpbc_captcha__simple__generate_new(); $ajx_data_arr = array(); $ajx_data_arr['status'] = 'error'; $ajx_data_arr['status_error'] = 'captcha_simple_wrong'; $ajx_data_arr['captcha__simple'] = $captcha_arr; $ajx_data_arr['ajx_after_action_message'] = __( 'The code you entered is incorrect', 'booking' ); $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; wp_send_json( array( 'ajx_data' => $ajx_data_arr, 'ajx_search_params' => $original_ajx_search_params, 'ajx_cleaned_params' => $request_params, 'resource_id' => $request_params['resource_id'] ) ); // After this page will die; } } } // --------------------------------------------------------------------------------------------------------------------- // CAPTCHA Support // --------------------------------------------------------------------------------------------------------------------- /** * Is entered CAPTCHA correct ? * * @param string $captcha_user_input user entrance * @param string $captcha_chalange chalange * * @return bool */ function wpbc_captcha__simple__is_ansfer_correct( $captcha_user_input, $captcha_chalange ) { if ( ( empty( $captcha_user_input ) ) || ( empty( $captcha_chalange ) ) ) { return false; } $captcha_instance = new wpdevReallySimpleCaptcha(); $correct = $captcha_instance->check( $captcha_chalange, $captcha_user_input ); return $correct; } /** * Generate new CAPTCHA image and return URL to this image and challenge code * * @return array [ 'url' => $captcha_url, 'challenge' => $captcha_challenge ] */ function wpbc_captcha__simple__generate_new() { $captcha_instance = new wpdevReallySimpleCaptcha(); // Clean up dead files older than 2 minutes $captcha_instance->cleanup( 2 ); //FixIn: 7.0.1.67 //$captcha_instance->img_size = array( 72, 24 ); /* Background color of CAPTCHA image. RGB color 0-255 */ //$captcha_instance->bg = array( 0, 0, 0 );//array( 255, 255, 255 ); /* Foreground (character) color of CAPTCHA image. RGB color 0-255 */ //$captcha_instance->fg = array( 255, 255, 255 );//array( 0, 0, 0 ); /* Coordinates for a text in an image. I don't know the meaning. Just adjust. */ //$captcha_instance->base = array( 6, 18 ); /* Font size */ //$captcha_instance->font_size = 14; /* Width of a character */ //$captcha_instance->font_char_width = 15; /* Image type. 'png', 'gif' or 'jpeg' */ //$captcha_instance->img_type = 'png'; $word = $captcha_instance->generate_random_word(); $prefix = mt_rand(); $captcha_instance->generate_image( $prefix, $word ); $filename = $prefix . '.png'; $captcha_url = WPBC_PLUGIN_URL . '/js/captcha/tmp/' . $filename; $captcha_challenge = substr( $filename, 0, strrpos( $filename, '.' ) ); return array( 'url' => $captcha_url, 'challenge' => $captcha_challenge ); } /** * Generate initial HTML content for CAPTCHA in booking form * * @param $resource_id * * @return string|true */ function wpbc_captcha__simple__generate_html_content( $resource_id ) { if ( true !== wpbc_captcha__simple__is_installed() ) { return wpbc_captcha__simple__is_installed(); } $captcha_arr = wpbc_captcha__simple__generate_new(); $captcha_url = $captcha_arr['url']; $captcha_challenge = $captcha_arr['challenge']; $html = '<span class="wpbc_text_captcha_container">'; $html .= '<input autocomplete="off" type="hidden" name="wpdev_captcha_challenge_' . $resource_id . '" id="wpdev_captcha_challenge_' . $resource_id . '" value="' . $captcha_challenge . '" />'; $html .= '<input autocomplete="off" type="text" class="captachinput" value="" name="captcha_input' . $resource_id . '" id="captcha_input' . $resource_id . '" />'; $html .= '<img class="captcha_img" id="captcha_img' . $resource_id . '" alt="To show CAPTCHA, please deactivate cache plugin or exclude this page from caching or disable CAPTCHA at WP Booking Calendar - Settings General page in Form Options section." src="' . $captcha_url . '" />'; $html .= '</span>'; return $html; } /** * Check if captcha can work here * * @return string|true if true then can work, Otherwise return error message */ function wpbc_captcha__simple__is_installed() { //FixIn: 8.8.3.5 if ( function_exists( 'gd_info' ) ) { return true; /* $gd_info = gd_info(); if ( isset( $gd_info['GD Version'] ) ) { $gd_info = $gd_info['GD Version']; } else { $gd_info = json_encode( $gd_info ); } */ } else { return '<strong>Error!</strong> CAPTCHA requires the GD library activated in your PHP configuration.' .'Please check more <a href="https://wpbookingcalendar.com/faq/captcha-showing-problems/">here</a>.'; } } dates_times_support.php 0000666 00000213265 15165546743 0011407 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 if ( ! defined( 'WPBC_FULL_DAY_TIME_IN' ) ) { define( 'WPBC_FULL_DAY_TIME_IN' , 1 ); } // = +1 sec. '00:00:01' if ( ! defined( 'WPBC_FULL_DAY_TIME_OUT' ) ) { define( 'WPBC_FULL_DAY_TIME_OUT' , 86392 ); } // = 24 * 60 * 60 = 86400 - 10 sec. + 2 sec. '23:59:52' // --------------------------------------------------------------------------------------------------------------------- // Intervals // --------------------------------------------------------------------------------------------------------------------- /** * Merge several intersected intervals or return not intersected: [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]] * * @param array $intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ] * * @return array [ [1,8],[9,10] ] * * Example: wpbc_merge_intersected_intervals( array( array(1,3), array(2,4), array(6,8), array(9,10), array(3,7) ); -> array( array(1,8), array(9,10) ) */ function wpbc_merge_intersected_intervals( $intervals ){ if ( empty( $intervals ) ) { return array(); } $merged = array(); // Sort array by first value in a list [[8,10],[1,3],[15,18],[2,6]] -> [[1,3],[2,6],[8,10],[15,18]] usort( $intervals, function ( $compare_A, $compare_B ) { if ( $compare_A[0] > $compare_B[0] ) { return 1; } elseif ( $compare_A[0] < $compare_B[0] ) { return - 1; } return 0; } ); $merged_interval = $intervals[0]; // [1,3] for ( $i = 1; $i < count( $intervals ); $i ++ ) { $next_element = $intervals[ $i ]; // [2,6] if ( $next_element[0] <= $merged_interval[1] ) { $merged_interval[1] = max( $merged_interval[1], $next_element[1] ); } else { $merged[] = $merged_interval; $merged_interval = $next_element; } } $merged[] = $merged_interval; return $merged; } /** * Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected ) * * Good explanation here https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap * * @param array $interval_A array( 36011, 86392 ) * @param array $interval_B array( 1, 43192 ) * * @return bool */ function wpbc_is__intervals__intersected( $interval_A, $interval_B ) { if ( ( empty( $interval_A ) ) || ( empty( $interval_B ) ) ){ return false; } $is_intersected = max( $interval_A[0], $interval_B[0] ) - min( $interval_A[1], $interval_B[1] ); // if ( 0 == $is_intersected ) { // // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ] // } if ( $is_intersected < 0 ) { return true; // INTERSECTED } return false; // Not intersected } // --------------------------------------------------------------------------------------------------------------------- // Time - Slots functions // --------------------------------------------------------------------------------------------------------------------- /** * Get time in seconds from SQL date format '2024-01-28 12:00:02' -> 1706443192 * * @param $sql_date__ymd_his '2024-01-28 12:00:02' Date in SQL format * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec * * @return int * * if $is_apply__check_in_out__10s == true (it's default) * * then apply +10 seconds for check in time it's time, that ended with 1 * and apply -10 seconds for check out time it's time, that ended with 2 */ function wpbc_convert__sql_date__to_seconds( $sql_date__ymd_his, $is_apply__check_in_out__10s = true ){ list( $sql_date_ymd, $sql_time_his ) = explode( ' ', $sql_date__ymd_his ); // '2024-01-28', '12:00:02' $date_in_seconds = wpbc_convert__date_ymd__to_seconds( $sql_date_ymd ); $time_in_seconds = wpbc_convert__time_his__to_seconds( $sql_time_his, $is_apply__check_in_out__10s ); $in_seconds = $date_in_seconds + $time_in_seconds; return $in_seconds; } /** * Get date in seconds from SQL only_date format '2024-01-28' -> 1706400000 * * @param $sql_date_ymd '2024-01-28' * * @return int */ function wpbc_convert__date_ymd__to_seconds( $sql_date_ymd ){ // DATE $sql_date_time = $sql_date_ymd . ' 00:00:00'; $in_seconds = strtotime( $sql_date_time ); return $in_seconds; } /** * Get time in seconds from SQL time format '12:00:02' -> 43192 * * @param string $sql_time_his '12:00:02' * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec * * @return int * * if $is_apply__check_in_out__10s == true (it's default) * * then apply +10 seconds for check in time it's time, that ended with 1 * and apply -10 seconds for check out time it's time, that ended with 2 */ function wpbc_convert__time_his__to_seconds( $sql_time_his, $is_apply__check_in_out__10s = true ){ // TIME $in_seconds = explode( ':', $sql_time_his ); $in_seconds = intval( $in_seconds[0] ) * 60 * 60 + intval( $in_seconds[1] ) * 60 + intval( $in_seconds[2] ); // 43202 if ( $is_apply__check_in_out__10s ) { $is_check_in_out__or_full = $in_seconds % 10; // 0, 1, 2 if ( 1 == $is_check_in_out__or_full ) { $in_seconds += 10; } if ( 2 == $is_check_in_out__or_full ) { $in_seconds -= 10; } } $in_seconds = intval( $in_seconds ); return $in_seconds; } /** * Get time in SQL time format from seconds 43192 -> '12:00:02' * * @param int $in_seconds 43192 * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec * * @return int * * if $is_apply__check_in_out__10s == true (it's default) * * then apply +10 seconds for check in time it's time, that ended with 1 * and apply -10 seconds for check out time it's time, that ended with 2 */ function wpbc_convert__seconds__to_time_his( $in_seconds, $is_apply__check_in_out__10s = true ){ //$is_check_in_out__or_full = $seconds__this__booking % 10; // 1, 2 (not 0) $is_check_in_out__or_full = substr( ( (string) $in_seconds ), -1 ); // '1', '2' (not '0') if ( '1' == $is_check_in_out__or_full ) { if ( WPBC_FULL_DAY_TIME_IN == $in_seconds ) { // situation: 00:00 e.g. 1 sec. $in_seconds = 0; } else { $in_seconds = $in_seconds - 10 - 1; } } if ( '2' == $is_check_in_out__or_full ) { if ( WPBC_FULL_DAY_TIME_OUT == $in_seconds ) { // situation: 24:00 e.g. 86400 -10 +2 sec. $in_seconds = 86400; } else { $in_seconds = $in_seconds + 10 - 2; } } $rest_without_hours_as_seconds = $in_seconds % ( 60 * 60 ); $in_hours = ( $in_seconds - $rest_without_hours_as_seconds ) / ( 60 * 60 ); // 43200 $in_hours = intval( $in_hours ); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN ); $in_minutes = $rest_without_hours_as_seconds / 60; // 43200 $in_minutes = intval( $in_minutes ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1. $in_only_seconds = $in_seconds - ( $in_hours * 60 * 60 ) - ( $in_minutes * 60 ); // 43200 $in_only_seconds = intval( $in_only_seconds ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1. if ( '1' == $is_check_in_out__or_full ) { $in_only_seconds += 1; } if ( '2' == $is_check_in_out__or_full ) { $in_only_seconds += 2; } $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours; $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes; $in_only_seconds = ( $in_only_seconds < 10 ) ? '0' . $in_only_seconds : $in_only_seconds; $sql_time_his = $in_hours . ':' . $in_minutes . ':'. $in_only_seconds; return $sql_time_his; } /** * Convert date timestamp (date in seconds) to SQL date format 1706400000 -> '2024-01-28 00:00:00' * * @param int $in_seconds 1706400000 * @param bool $is_apply__check_in_out__10s true : check_in_time = -10sec check_out_time = +10sec * @param string $sql_date_format 'Y-m-d H:i:s' : sometimes need to have ''Y-m-d 00:00:01' or other... * * @return false|string '2024-01-28 00:00:00' */ function wpbc_convert__seconds__to_sql_date( $in_seconds, $is_apply__check_in_out__10s = true, $sql_date_format = 'Y-m-d H:i:s' ){ if ( $is_apply__check_in_out__10s ) { $is_check_in_out__or_full = $in_seconds % 10; // 0, 1, 2 if ( 1 == $is_check_in_out__or_full ) { $in_seconds -= 10; } if ( 2 == $is_check_in_out__or_full ) { $in_seconds += 10; } } $sql_date = date( $sql_date_format, $in_seconds ); return $sql_date; } // ----------------------------------------------------------------------------------------------------------------- /** * Convert usual to seconds time range "10:15 - 12:00" -> "36911 - 43192" * * It's means that "10:15 - 12:00" in seconds "36900 - 43200" and with intersection fix: "(36900 +10 +1) - (43200 -10 +2)" e.g. "36911 - 43192" * * @param string $readable_time_slot "10:15 - 12:00" * * @return string time_range_in_seconds "36911 - 43192" */ function wpbc_convert__readable_time_slot__to__time_range_in_seconds( $readable_time_slot ) { $rangeA_arr = explode( '-', $readable_time_slot ); $rangeA_arr[0] = trim( $rangeA_arr[0] ); $rangeA_arr[1] = trim( $rangeA_arr[1] ); $time_range_in_seconds = array(); foreach ( $rangeA_arr as $is_end_time => $only_time ) { // $is_end_time = 0 | 1 $in_seconds = explode( ':', $only_time ); $in_seconds = intval( $in_seconds[0] ) * 60 * 60 + intval( $in_seconds[1] ) * 60; // 43200 if ( ! $is_end_time ) { if ( 0 == $in_seconds ) { // situation: 00:00 e.g. 0 sec. $in_seconds = WPBC_FULL_DAY_TIME_IN; } else { $in_seconds = $in_seconds + 10 + 1; } } else { if ( 86400 == $in_seconds ) { // situation: 24:00 e.g. 86400 sec. $in_seconds = WPBC_FULL_DAY_TIME_OUT; } else { $in_seconds = $in_seconds - 10 + 2; } } $time_range_in_seconds[] = $in_seconds; } $time_range_in_seconds = implode( ' - ', $time_range_in_seconds ); return $time_range_in_seconds; } /** * Convert seconds to usual time range: "36911 - 43192" -> "10:15 - 12:00" * * It's means "36911 - 43192" with intersection fix: "(36900 +10 +1) - (43200 -10 +2)" e.g. in seconds "36900 - 43200" is equal to "10:15 - 12:00" * * @param string $time_range_in_seconds "36911 - 43192" * * @return string $time_slot "10:15 - 12:00" */ function wpbc_convert__time_range_in_seconds__to__readable_time_slot( $time_range_in_seconds ) { $rangeA_arr = explode( '-', $time_range_in_seconds ); $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) ); $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) ); $time_slot = array(); foreach ( $rangeA_arr as $is_end_time => $in_seconds ) { // $is_end_time = 0 | 1 if ( ! $is_end_time ) { if ( WPBC_FULL_DAY_TIME_IN == $in_seconds ) { // situation: 00:00 e.g. 1 sec. $in_seconds = 0; } else { $in_seconds = $in_seconds - 10 - 1; } } else { if ( WPBC_FULL_DAY_TIME_OUT == $in_seconds ) { // situation: 24:00 e.g. 86400 -10 +2 sec. $in_seconds = 86400; } else { $in_seconds = $in_seconds + 10 - 2; } } $just_minutes_as_seconds = $in_seconds % ( 60 * 60 ); $in_hours = ( $in_seconds - $just_minutes_as_seconds ) / ( 60 * 60 ); // 43200 $in_minutes = $just_minutes_as_seconds / 60; // 43200 $in_hours = intval($in_hours); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN ); $in_minutes = intval($in_minutes); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1. $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours; $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes; $time_slot[] = $in_hours . ':' . $in_minutes; } $time_slot = implode( ' - ', $time_slot ); return $time_slot; } /** * Get SQL TIME from SECONDS 43211 -> '12:00:11' * * @param int $in_seconds 43201 * * @return string '10:00:02' */ function wpbc_transform__seconds__in__24_hours_his( $in_seconds ){ $rest_without_hours_as_seconds = $in_seconds % ( 60 * 60 ); $in_hours = ( $in_seconds - $rest_without_hours_as_seconds ) / ( 60 * 60 ); // 12 $in_hours = intval( $in_hours ); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN ); $in_minutes = $rest_without_hours_as_seconds / 60; // 43200 $in_minutes = intval( $in_minutes ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1. $in_only_seconds = $in_seconds - ( $in_hours * 60 * 60 ) - ( $in_minutes * 60 ); // 43200 $in_only_seconds = intval( $in_only_seconds ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1. $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours; $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes; $in_only_seconds = ( $in_only_seconds < 10 ) ? '0' . $in_only_seconds : $in_only_seconds; $sql_time_his = $in_hours . ':' . $in_minutes . ':'. $in_only_seconds; return $sql_time_his; } /** * Get time in seconds from SQL time format '12:00:02' -> 43192 * * @param string $sql_time_his '12:00:02' * * @return int */ function wpbc_transform__24_hours_his__in__seconds( $in_24_hours_his ) { $is_apply__check_in_out__10s = false; return wpbc_convert__time_his__to_seconds( $in_24_hours_his, $is_apply__check_in_out__10s ); } /** * Get AM/PM or 24 hour TIME from SECONDS 43211 -> '12:00 PM' | 86400 -> '12:00 AM' * * @param int $in_seconds 43201 * @param string $time_format '' (optional) time format, like 'H:i:s' otherwise get from Booking > Settings General * * @return string '10:00:02' | '10:00 AM' */ function wpbc_transform__seconds__in__formated_hours( $in_seconds, $time_format = '' ) { if ( empty( $time_format ) ) { $time_format = get_bk_option( 'booking_time_format' ); // get from Booking Calendar if ( empty( $time_format ) ) { $time_format = get_option( 'time_format' ); // Get WordPress default } } if ( $in_seconds >= 86400 ) { // if we have 24:00 then instead of 00:00 show 24:00 ... Please check more here https://www.php.net/manual/en/datetime.format.php $time_format = str_replace( array( 'H', 'G' ), '24', $time_format ); } $s_tm = date_i18n( $time_format, $in_seconds ); return $s_tm; } // ----------------------------------------------------------------------------------------------------------------- /** * Union 2 time-slot ranges: "100 - 900" & "500 - 3500" -> [ "100 - 3500" ] OR "10 - 70" & "100 - 500" -> [ "10 - 70", "100 - 500" ] * * @param $timeslot_A_in_range_seconds '36011 - 86392' it is means: "'Start time1 in seconds' - 'End time1 in seconds'" e.g. "10:00 - 24:00" * @param $timeslot_B_in_range_seconds '1 - 43192' it is means: "'Start time2 in seconds' - 'End time2 in seconds'" e.g. "00:00 - 12:00" * * @return array [ "1 - 86392" ] one or two ranges * */ function wpbc_union__timeslots_seconds( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) { if ( ! wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) ) { return array( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ); } if ( ( '0' == $timeslot_A_in_range_seconds ) || ( '0' == $timeslot_B_in_range_seconds ) ) { return array( '0 - 86400' ); // Old Full day booking, it is means always intersect. } $rangeA_arr = explode( '-', $timeslot_A_in_range_seconds ); $rangeB_arr = explode( '-', $timeslot_B_in_range_seconds ); $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) ); $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) ); $rangeB_arr[0] = intval( trim( $rangeB_arr[0] ) ); $rangeB_arr[1] = intval( trim( $rangeB_arr[1] ) ); $start = min( $rangeA_arr[0], $rangeB_arr[0] ); $end = max( $rangeA_arr[1], $rangeB_arr[1] ); $result = array( $start . ' - ' . $end ); return $result; } /** * Is 2 time-slots ranges intersected: "36011 - 86392" <=> "1 - 43192" = true ( intersected ) * * Good explanation here https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap * * @param $timeslot_A_in_range_seconds '36011 - 86392' it is means: "'Start time1 in seconds' - 'End time1 in seconds'" e.g. "10:00 - 24:00" * @param $timeslot_B_in_range_seconds '1 - 43192' it is means: "'Start time2 in seconds' - 'End time2 in seconds'" e.g. "00:00 - 12:00" * * @return bool * * * Some exceptions: * if range = '0' - it is means Full day booking, it's always intersected ! * all start times ended with "1" second and previously was added +10 seconds, that's why 36011 is means 36011 - 10 - 1 = 36000 e.g. = 10:00 * all end times ended with "2" second and previously was -10 seconds, that's why 43192 is means 43192 + 10 - 2 = 43200 e.g. = 12:00 * * When in some date we have ONLY start time or end time, it's means that this time start from 00:00 or end at 24:00 (because usually such bookings for SEVERAL days) * and we autofill such times by adding start time or end time: * Autofilled start time is always 1 = 0 +1 - 00:01 * Autofilled end time is always 86392 = 86400 -10 +2 - 23:59:58 */ function wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) { // Full day booking, it is means always intersect. if ( ( '0' == $timeslot_A_in_range_seconds ) || ( '0' == $timeslot_B_in_range_seconds ) ) { return true; // Time ranges INTERSECTED } $rangeA_arr = explode( '-', $timeslot_A_in_range_seconds ); $rangeB_arr = explode( '-', $timeslot_B_in_range_seconds ); $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) ); $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) ); $rangeB_arr[0] = intval( trim( $rangeB_arr[0] ) ); $rangeB_arr[1] = intval( trim( $rangeB_arr[1] ) ); $is_intersected = max( $rangeA_arr[0], $rangeB_arr[0] ) - min( $rangeA_arr[1], $rangeB_arr[1] ); // if ( 0 == $is_intersected ) { // // Such ranges going one after other, e.g.: "12:00 - 15:00" and "15:00 - 21:00" // } if ( $is_intersected < 0 ) { return true; // Time ranges INTERSECTED } return false; // Otherwise time slot not intersected } /** * Is 2 time-slots ranges intersected: "10:00 - 24:00" <=> "00:00 - 12:00" = true ( intersected ) * * * @param $timeslot_A_readable '10:00 - 24:00' * @param $timeslot_B_readable '00:00 - 12:00' * * @return bool * * * See more here: wpbc_is__timeslots_seconds__intersected() */ function wpbc_is__timeslots_readable__intersected( $timeslot_A_readable, $timeslot_B_readable ) { // Full day booking, it is means always intersect. if ( ( '0' == $timeslot_A_readable ) || ( '0' == $timeslot_B_readable ) ) { return true; // Time ranges INTERSECTED } $timeslot_A_in_range_seconds = wpbc_convert__readable_time_slot__to__time_range_in_seconds( $timeslot_A_readable ); $timeslot_B_in_range_seconds = wpbc_convert__readable_time_slot__to__time_range_in_seconds( $timeslot_B_readable ); return wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ); } // ----------------------------------------------------------------------------------------------------------------- /** * Check if BOOKING_FORM time-slots available and not intersect with booked time slots from bookings * * * @param array $checking__timerange_sec__arr [ '36011 - 43192', '56011 - 86392' ] * @param array $booked__timerange_sec__arr [ '36011 - 43192' ] * * @return bool true | false * * * if $checking__timerange_sec__arr EMPTY then TRUE * */ function wpbc_is_some_timeslot__available__in_arr( $checking__timerange_sec__arr, $booked__timerange_sec__arr ) { if ( empty( $checking__timerange_sec__arr ) ) { return true; } $is_available__timeslots__arr = array(); // Available_Form time-slots: [ "10:00 - 12:00", "12:00 - 14:00", "14:00 - 16:00" ] foreach ( $checking__timerange_sec__arr as $checking__timeslot__key => $checking__timeslot__value ) { $is_available__timeslots__arr[ $checking__timeslot__key ] = true; // Booked time-slots: [ "12:00 - 14:00", "14:00 - 16:00" ] foreach ( $booked__timerange_sec__arr as $booked__timeslot_value ) { $is_time_intersected = wpbc_is__timeslots_seconds__intersected( $booked__timeslot_value, $checking__timeslot__value ); // '36011 - 43192', '56011 - 86392' if ( $is_time_intersected ) { $is_available__timeslots__arr[ $checking__timeslot__key ] = false; break; } } } // If at least one time slot available then day still available $is_some_timeslot_available = false; foreach ( $is_available__timeslots__arr as $is__timeslot_available ) { if ( $is__timeslot_available ) { $is_some_timeslot_available = true; break; } } return $is_some_timeslot_available; } // ----------------------------------------------------------------------------------------------------------------- /** * '43211 - 86392' into [43201, 86400] * * @param string $booked_times__key_arr * @param bool $is_apply_end_time_correction * * @return array|string[] */ function wpbc_transform_timerange__s_range__in__seconds_arr( $booked_times__key_arr, $is_apply_end_time_correction = true ){ $booked_times__key_arr = explode( ' - ', $booked_times__key_arr ); $booked_times__key_arr[0] = intval( trim( $booked_times__key_arr[0] ) ); $booked_times__key_arr[1] = intval( trim( $booked_times__key_arr[1] ) ); if ( $is_apply_end_time_correction ) { // Fix when we have 10:00:11 seconds, and we need to show the 14:00:02 if ( '1' == substr( (string) $booked_times__key_arr[0], - 1 ) ) { $booked_times__key_arr[0] = $booked_times__key_arr[0] - 10; } $booked_times__key_arr[0] = ( $booked_times__key_arr[0] < 0 ) ? 1 : $booked_times__key_arr[0]; // Fix when we have 13:59:52 seconds, and we need to show the 14:00:02 if ( '2' == substr( (string) $booked_times__key_arr[1], - 1 ) ) { $booked_times__key_arr[1] = $booked_times__key_arr[1] + 10; } $booked_times__key_arr[1] = ( $booked_times__key_arr[1] > 86400 ) ? 86400 : $booked_times__key_arr[1]; } return $booked_times__key_arr; } /** * [43211, 86400] -> '12:00:11 - 24:00:00' * * @param $booked_times__key_arr * * @return string */ function wpbc_transform_timerange__seconds_arr__in__24_hours_range( $booked_times__key_arr ){ $readable_time_slot_formatted = wpbc_transform__seconds__in__24_hours_his( $booked_times__key_arr[0] ) . ' - ' . wpbc_transform__seconds__in__24_hours_his( $booked_times__key_arr[1] ) ; return $readable_time_slot_formatted; } /** * [43211, 86400] -> '12:00 PM - 12:00 AM' - transform time-range in General Settings - Time Format * * @param $booked_times__key_arr * * @return string */ function wpbc_transform_timerange__seconds_arr__in__formated_hours( $booked_times__key_arr ){ $readable_time_slot_formatted = wpbc_transform__seconds__in__formated_hours( $booked_times__key_arr[0] ) . ' - ' . wpbc_transform__seconds__in__formated_hours( $booked_times__key_arr[1] ) ; return $readable_time_slot_formatted; } /** * Converts a period of time in seconds into a human-readable format representing the interval. * * @param int $time_interval_in_seconds : 90 - A period of time in seconds. * * @return string : '1 minute 30 seconds' * * Example: * * echo wpbc_get_readable_time_interval( 90 ); <- 1 minute 30 seconds * */ function wpbc_get_readable_time_interval( $time_interval_in_seconds ) { // Array of time period chunks. $chunks = array( /* translators: 1: The number of years in an interval of time. */ array( 60 * 60 * 24 * 365, _n_noop( '%s year', '%s years', 'booking' ) ), /* translators: 1: The number of months in an interval of time. */ array( 60 * 60 * 24 * 30, _n_noop( '%s month', '%s months', 'booking' ) ), /* translators: 1: The number of weeks in an interval of time. */ array( 60 * 60 * 24 * 7, _n_noop( '%s week', '%s weeks', 'booking' ) ), /* translators: 1: The number of days in an interval of time. */ array( 60 * 60 * 24, _n_noop( '%s day', '%s days', 'booking' ) ), /* translators: 1: The number of hours in an interval of time. */ array( 60 * 60, _n_noop( '%s hour', '%s hours', 'booking' ) ), /* translators: 1: The number of minutes in an interval of time. */ array( 60, _n_noop( '%s minute', '%s minutes', 'booking' ) ), /* translators: 1: The number of seconds in an interval of time. */ array( 1, _n_noop( '%s second', '%s seconds', 'booking' ) ), ); if ( ( $time_interval_in_seconds <= 0 ) || ( ! is_int( $time_interval_in_seconds ) ) ) { return __( 'now', 'booking' ); } /** * We only want to output two chunks of time here, eg: * x years, xx months * x days, xx hours * so there's only two bits of calculation below: */ $j = count( $chunks ); // Step one: the first chunk. for ( $i = 0; $i < $j; $i++ ) { $seconds = $chunks[ $i ][0]; $name = $chunks[ $i ][1]; // Finding the biggest chunk (if the chunk fits, break). $count = floor( $time_interval_in_seconds / $seconds ); if ( $count ) { break; } } // Set output var. $output = sprintf( translate_nooped_plural( $name, $count, 'booking' ), $count ); // Step two: the second chunk. if ( $i + 1 < $j ) { $seconds2 = $chunks[ $i + 1 ][0]; $name2 = $chunks[ $i + 1 ][1]; $count2 = floor( ( $time_interval_in_seconds - ( $seconds * $count ) ) / $seconds2 ); if ( $count2 ) { // Add to output var. $output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'booking' ), $count2 ); } } return $output; } // ===================================================================================================================== // == D A T E S M a i n l y === // ===================================================================================================================== /** * Conception: - Time-Slots A - B '10:00:01 - 12:00:02' '10:00:01 - 12:00:02' * * - Check in A - ... '14:00:01 - ... ' '14:00:01 - 24:00:00' * - Check out ... - B ' ... - 12:00:02' '00:00:00 - 12:00:02' * * - Full day ... - ... ' ... - ... ' '00:00:00 - 24:00:00' * * - Full IN ..1 - ... '00:00:01 - ... ' '00:00:01 - 24:00:00' * - Full OUT ... - ..2 ' ... - 24:00:02' '00:00:00 - 24:00:02' * * * 1) Always in one specific date, can be start & end times. * 2) Such start end times can define * */ // --------------------------------------------------------------------------------------------------------------------- // Support Transformation functions for dates arrays // --------------------------------------------------------------------------------------------------------------------- /** * From SQL dates array generate new Extended Dates Array: [ > resource_id < ][ > booking_id < ] => Obj( 'sql__booking_dates__arr':[ * [ >seconds< ] => > SQL DATE < * [1693303211] => 2023-08-29 10:00:01 * [1693353600] => 2023-08-30 00:00:00 * [1693483192] => 2023-08-31 12:00:02 * ] * , ... ) * @param array $params = array [ 'sql_dates_arr' = [ [0] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 1 [date_res_type] => [booking_id] => 45 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^... [parent] => 0 [prioritet] => 20 [type] => 2 ) [1] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 0 [date_res_type] => [booking_id] => 46 [form] => selectbox-one^rangetime10^10:00 - 12:00~text^... [parent] => 2 [prioritet] => 1 [type] => 10 ), ... , ...] , 'is_sort__dates_arr' => true , 'is_apply__check_in_out__10s' => true ] * * @return array = [ > resource_id < ][ > booking_id < ] => obj( ... ) Example: [ [3] = [ [64] = obj{ booking_date = "2023-09-26 14:00:01" approved = "0" date_res_type = null booking_id = "64" form = "text^selected_short_dates_hint3^... parent = "0" prioritet = "30" type = "3" __summary__booking = [ sql__booking_dates__arr = [ 1695736811 = "2023-09-26 14:00:01" 1695772800 = "2023-09-27 00:00:00" 1695902392 = "2023-09-28 12:00:02" ] ] } [47] => stdClass Object(...) ... ] ... ] * * * Each such booking is date object with additional property: -> __summary__booking[ 'sql__booking_dates__arr' ] * It is array of ALL Dates (in SQL date format) for specific booking * Then if needed, we extend booked dates on specific number of times or hours/minutes * * * Relative this: ['__summary__booking']['sql__booking_dates__arr'] = [ 1695736811 = "2023-09-26 14:00:01" 1695772800 = "2023-09-27 00:00:00" 1695902392 = "2023-09-28 12:00:02" ] * '1695736811' - timestamp of check in/out dates on 10 seconds less/higher than SQL date '2023-09-26 14:00:01' * */ function wpbc_support__transform__into__resource_booking_dates__arr( $params ){ $defaults = array( 'sql_dates_arr' => array() , 'is_sort__dates_arr' => true , 'is_apply__check_in_out__10s' => true ); $params = wp_parse_args( $params, $defaults ); $result_arr = array(); foreach ( $params['sql_dates_arr'] as $date_object ) { $booking_id = $date_object->booking_id; // '43' $resource_id = ( ! empty( $date_object->date_res_type ) ) ? $date_object->date_res_type : $date_object->type; // '12' if ( empty( $result_arr[ $resource_id ] ) ) { $result_arr[ $resource_id ] = array(); } if ( empty( $result_arr[ $resource_id ][$booking_id] ) ) { $result_arr[ $resource_id ][$booking_id] = $date_object; $result_arr[ $resource_id ][$booking_id]->__summary__booking = array( 'sql__booking_dates__arr' => array() ); // New '__summary__booking' property } // Get seconds timestamp $in_seconds = wpbc_convert__sql_date__to_seconds( $date_object->booking_date, $params['is_apply__check_in_out__10s'] ); $result_arr[ $resource_id ][ $booking_id ]->__summary__booking[ 'sql__booking_dates__arr' ][ $in_seconds ] = $date_object->booking_date; // Sort new array with dates if ( $params['is_sort__dates_arr'] ) { ksort( $result_arr[ $resource_id ][ $booking_id ]->__summary__booking[ 'sql__booking_dates__arr' ] ); } } return $result_arr; } /** * Transform Into: ['2024-01-28'][ > resource_id < ][ > booking_id < ][ > only_time_seconds_int < ] => obj( booking_date: "2024-01-28 10:00:01", ... ) * * @param array $params = [ * 'is_apply__check_in_out__10s' => true * 'resource_booking_dates_arr' => array = [ > resource_id < ][ > booking_id < ] => obj( ... ) * ] * * Example: * * $params['resource_booking_dates_arr'] = [ * [3] = [ * [64] = obj{ * booking_date = "2023-09-26 14:00:01" * approved = "0" * date_res_type = null * booking_id = "64" * form = "text^selected_short_dates_hint3^... * parent = "0" * prioritet = "30" * type = "3" * __summary__booking = [ * sql__booking_dates__arr = [ 1695736811 = "2023-09-26 14:00:01" * 1695772800 = "2023-09-27 00:00:00" * 1695902392 = "2023-09-28 12:00:02" * ] * ] * } * [47] => stdClass Object(...) * ... * ] * ... * ] * * @return array - ['2024-01-28'][ > resource_id < ][ > booking_id < ][ > only_time_seconds < ] => obj( booking_date: "2024-01-28 10:00:01", ... ) * * Example: * result = [ * 2023-08-01 = [ * 3 = [ * 62 = [ * 36011 = {stdClass} * 43192 = { * booking_date = "2023-08-01 12:00:02" * approved = "0" * date_res_type = null * booking_id = "62" * form = "selectbox-multiple^rangetime3[]^10:00 - 12:00~... * parent = "0" * prioritet = "30" * type = "3" * __summary__booking = [ * sql__booking_dates__arr = [ * 1690884011 = "2023-08-01 10:00:01" * 1690891192 = "2023-08-01 12:00:02" * ] * ] * } * ] * ] * ] * 2023-08-05 = [ ... ] * ] */ function wpbc_support__transform__into__date_resource_booking_timesec__arr( $params ){ $defaults = array( 'resource_booking_dates_arr' => array() , 'is_apply__check_in_out__10s' => true ); $params = wp_parse_args( $params, $defaults ); $result__arr = array(); foreach ( $params['resource_booking_dates_arr'] as $resource_id => $bookings_arr ) { foreach ( $bookings_arr as $booking_id => $booking_obj ) { $extended_dates_arr = ( isset( $booking_obj->__summary__booking['sql__booking_dates__arr__extended'] ) ) ? $booking_obj->__summary__booking['sql__booking_dates__arr__extended'] : $booking_obj->__summary__booking['sql__booking_dates__arr']; foreach ( $extended_dates_arr as $extended_date_time_stamp => $extended_date_sql ) { $new_extended_date_obj = wpbc_clone_array_of_objects( $booking_obj ); $new_extended_date_obj->booking_date = $extended_date_sql; list( $date_without_time, $only_time ) = explode( ' ', $new_extended_date_obj->booking_date ); // '2024-01-28', '12:00:02' $seconds_int = wpbc_convert__time_his__to_seconds( $only_time, $params['is_apply__check_in_out__10s'] ); // 43202 if ( ! isset( $result__arr[ $date_without_time ] ) ) { $result__arr[ $date_without_time ] = array(); } if ( ! isset( $result__arr[ $date_without_time ][ $resource_id ] ) ) { $result__arr[ $date_without_time ][ $resource_id ] = array(); } if ( ! isset( $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ] ) ) { $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ] = array(); } $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ][ $seconds_int ] = $new_extended_date_obj; } } } return $result__arr; /** 2024-01-28 = [ > resource_id < 12 => [ > booking_id < 43 => [ > seconds < 36001 => Obj[ booking_date = "2024-01-28 10:00:01" date_res_type = null booking_id = "43" approved = "0" form = "selectbox-one^rangetime12^10:00 - 12:00~text^..." parent = "2" type = "12" ... ] 43202 => Obj[ type = "12" */ } /** * Transform Into: ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ... * * @param array $params [ * 'is_apply__check_in_out__10s' => true * 'date_resource_booking_timesec_arr' => [ * 2023-08-01 = [ * 3 = [ * 62 = [ * 36011 = {stdClass} * 43192 = { * booking_date = "2023-08-01 12:00:02" * approved = "0" * date_res_type = null * booking_id = "62" * form = "selectbox-multiple^rangetime3[]^10:00 - 12:00~... * parent = "0" * prioritet = "30" * type = "3" * __summary__booking = [ * sql__booking_dates__arr = [ * 1690884011 = "2023-08-01 10:00:01" * 1690891192 = "2023-08-01 12:00:02" * ] * ] * } * ] * ] * ] * 2023-08-05 = [ ... ] * ] * * @return array = ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ... * * Example: [ [2023-08-08] => [ [2] => [ [36011 - 86392] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 , .... ) ] [10] => [ [36011 - 86392] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 , .... ) ] ] [2023-08-09] => [ [2] => [ [0] => stdClass Object ( [booking_date] => 2023-08-09 00:00:00, .... ) ] [10] => [ [36011 - 43192] => stdClass Object ( [booking_date] => 2023-08-30 12:00:02 , .... __summary__booking = [ sql__booking_dates__arr = [ 1690884011 = "2023-08-01 10:00:01" 1690891192 = "2023-08-01 12:00:02" ] ] ) ] ] ] */ function wpbc_support__transform__into__date_resource_timesec_range__arr( $params ){ $defaults = array( 'date_resource_booking_timesec_arr' => array() , 'is_apply__check_in_out__10s' => true ); $params = wp_parse_args( $params, $defaults ); $result__arr = array(); foreach ( $params[ 'date_resource_booking_timesec_arr' ] as $a_only_date => $a_resources_arr ) { // '2023-07-25' => array( resource_id => bookings_arr ) foreach ( $a_resources_arr as $a_resource_id => $a_bookings_arr ) { // 1 => array( booking_id => times_arr ) foreach ( $a_bookings_arr as $a_booking_id => $a_seconds_arr_in_1_booking ) { // 10 => array ( second => stdObj( booking_date obj from DB ) if ( ! isset( $result__arr[ $a_only_date ] ) ) { $result__arr[ $a_only_date ] = array(); } if ( ! isset( $result__arr[ $a_only_date ][ $a_resource_id ] ) ) { $result__arr[ $a_only_date ][ $a_resource_id ] = array(); } // Check all TIMES for SAME booking: $all_seconds_for_this_booking_arr = array(); foreach ( $a_seconds_arr_in_1_booking as $a_second => $a_booking_obj ) { // 0 => stdObj( booking_date obj from DB ) $all_seconds_for_this_booking_arr[] = $a_second; } /** * [ 36011 ] -> '36011 - 86392' | [36011, 43192] -> '36011 - 43192' * * In case if we have only start time or end time for specific SAME Booking, then we need to fill times: .. - 10:00 or 14:00 - .. */ $all_seconds__key__time_range = wpbc__get_time_range__from_times_arr( $all_seconds_for_this_booking_arr ); // For debugging only ! ------------------------------------------------------------------------------- $test_unexpected = explode( '-', $all_seconds__key__time_range ); if ( count( $test_unexpected ) > 2 ) { echo "WPBC. Unexpected situation. We have more than 2 times for the booking {$a_booking_id}: {$all_seconds__key__time_range}"; debuge( '$a_only_date, $a_resource_id, $a_booking_id, $all_seconds_for_this_booking_arr', $a_only_date, $a_resource_id, $a_booking_id, $all_seconds_for_this_booking_arr, __FILE__, __LINE__ ); } // For debugging only ! ------------------------------------------------------------------------------- $result__arr[ $a_only_date ][ $a_resource_id ][ $all_seconds__key__time_range ] = $a_booking_obj; } } } return $result__arr; } /** * Transform [ 36011 ] -> '36011 - 86392' | [36011, 43192] -> '36011 - 43192' * * @param array $all_seconds_for_this_booking_arr [ 36011 ] [36011, 43192] * * @return string '36011 - 86392' '36011 - 43192' */ function wpbc__get_time_range__from_times_arr( $all_seconds_for_this_booking_arr ){ // In case if we have only start time or end time for specific SAME Booking, then we need to fill times: .. - 10:00 or 14:00 - .. if ( 1 == count( $all_seconds_for_this_booking_arr ) ) { $seconds__this__booking = $all_seconds_for_this_booking_arr[0]; //$is_check_in_out__or_full = $seconds__this__booking % 10; // 1, 2 (not 0) $is_check_in_out__or_full = substr( ( (string) $seconds__this__booking ), -1 ); // '1', '2' (not '0') if ( '1' == $is_check_in_out__or_full ) { $all_seconds_for_this_booking_arr = array( $seconds__this__booking, WPBC_FULL_DAY_TIME_OUT ); // 24 hours - 10 seconds + 2 seconds (2 sec. - because check out) } if ( '2' == $is_check_in_out__or_full ) { $all_seconds_for_this_booking_arr = array( WPBC_FULL_DAY_TIME_IN, $seconds__this__booking ); // + 1 second (1 sex. - because check in) } } if ( count( $all_seconds_for_this_booking_arr ) > 2 ) { // Non standard situation ??? !!! } $all_seconds__key__time_range = implode( ' - ', $all_seconds_for_this_booking_arr ); return $all_seconds__key__time_range; } // --------------------------------------------------------------------------------------------------------------------- // Get READABLE_DATES_ARR & create WPBC_BOOKING_DATE for each bookings in [ > resource_id < ][ > booking_id < ][ ... ] // --------------------------------------------------------------------------------------------------------------------- // GOOD /** * Loop all Resources / Bookings to set 'WPBC_BOOKING_DATE' Objects: [ > resource_id < ][ > booking_id < ] => ['__summary__booking']['sql__booking_dates__arr']['_readable_dates'] = [ 2023-09-01: [ 0: "00:00:01 - 24:00:00" ] , ... ] * * @param $resources__booking_id__obj = [ > resource_id < ][ > booking_id < ] => obj( ... ) * * @return $resources__booking_id__obj = [ * 3 = [ * 62 = {stdClass} * 63 = { * booking_date = "2023-09-01 00:00:00" * approved = "0" * date_res_type = null * booking_id = "63" * form = "text^selected_short_dates_hint3^September 1, 2023... * parent = "0" * prioritet = "30" * type = "3" * __summary__booking = [ * sql__booking_dates__arr = [ * * .... */ function wpbc__in_all_bookings__create_WPBC_BOOKING_DATE( $resources__booking_id__obj ){ // [ > resource_id < ][ > booking_id < ] => obj( ['__summary__booking']['sql__booking_dates__arr'] [ ... , [ ' >seconds< '] => ' > SQL DATE < ' , ... ] ) foreach ( $resources__booking_id__obj as $resource_id => $bookings_arr ) { foreach ( $bookings_arr as $booking_id => $booking_obj ) { $readable_datestimeslots_arr = wpbc__get__readable_dates_arr__from_timestamp_arr( $booking_obj->__summary__booking[ 'sql__booking_dates__arr' ] ); // New Dates Object - for this booking ID $boking_dates_obj = new WPBC_BOOKING_DATE( $readable_datestimeslots_arr ); $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj' ] = $boking_dates_obj; if ( $boking_dates_obj->is_debug ) { $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__24_hour_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_24_hour_arr' ); $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__seconds_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_seconds_arr' ); $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__timestamps_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_timestamps_arr' ); } } } return $resources__booking_id__obj; } // ===================================================================================================================== // Transform SQL dates INTO Readable time-slots by Dates // // All these below 5 functions required for transformation booked SQL dates: [ 1690884011 : "2023-08-01 10:00:01", ... ] // Into readable time slots by dates: [ '2023-08-01': [ "10:00:01 - 12:00:02" ], '2023-08-05': [ "10:00:01 - 12:00:02" ] ] // ===================================================================================================================== // GOOD /** * Transform SQL dates INTO Readable time-slots by Dates. Transform linear [ 1690884011 = "2023-08-01 10:00:01" , ... ] -> [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...] * * @param array $sql_dates_arr [ * 1690884011 = "2023-08-01 10:00:01" * 1690891192 = "2023-08-01 12:00:02" * ... * ] * * @return array * [ * 2023-08-01 = [ 0 = "10:00:01 - 12:00:02" ] * 2023-08-05 = [ 0 = "10:00:01 - 12:00:02" ] * ] * OR * [ * 2023-09-01 = [ 0 = "00:00:01 - 24:00:00" ] * 2023-09-03 = [ 0 = "00:00:00 - 24:00:00" ] * 2023-09-14 = [ 0 = "00:00:00 - 24:00:02" ] * ] * */ function wpbc__get__readable_dates_arr__from_timestamp_arr( $sql_dates_arr ){ // Full Dates $is_all_dates_full = wpbc_is_all__fulldays__in_dates_arr( $sql_dates_arr ); if ( $is_all_dates_full ) { $sql_dates_arr = wpbc__add_to__fulldays__check_in_out( $sql_dates_arr ); } /** * Convert timestamps to -> [ '2023-08-01' : [ 36011 = "10:00:01", 43192 = "12:00:02" ] , '2023-08-05' : [...] ... ] */ $times_arr___by_dates = wpbc__transform__timestamp_arr__in__times_by_dates__arr( $sql_dates_arr ); /** * Convert to our concept times: -> [ '2023-08-01' : [ 0 = "10:00:01 - 12:00:02" ], '2023-08-05' : [ 0 = "10:00:01 - 12:00:02" ] ] */ $times_arr___by_dates = wpbc__transform__times_by_dates__in__readable_dates_arr( $times_arr___by_dates ); return $times_arr___by_dates; } // GOOD /** * Convert times by dates: [ '2023-08-01': [ 36011: "10:00:01", ... ] ... ] -> [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...] * * @param $times_arr___by_dates = [ * 2023-08-01 = [ * 36001 = "10:00:01" * 43202 = "12:00:02" * ] * 2023-08-05 = [ * 36001 = "10:00:01" * 43202 = "12:00:02" * ] * ] * * @return array * [ * 2023-08-01 = [ 0 = "10:00:01 - 12:00:02" ] * 2023-08-05 = [ 0 = "10:00:01 - 12:00:02" ] * ] * OR * [ * 2023-09-01 = [ 0 = "00:00:01 - 24:00:00" ] * 2023-09-03 = [ 0 = "00:00:00 - 24:00:00" ] * 2023-09-14 = [ 0 = "00:00:00 - 24:00:02" ] * ] * * * * * from this: * * $times_arr___by_dates = [ * 2023-09-01 = [ * 1 = "00:00:01" * ] * 2023-09-03 = [ * 0 = "00:00:00" * ] * 2023-09-14 = [ * 86402 = "24:00:02" * ] * ] * OR this: * [ * 2023-08-01 = [ * 36001 = "10:00:01" * 43202 = "12:00:02" * ] * 2023-08-05 = [ * 36001 = "10:00:01" * 43202 = "12:00:02" * ] * ] * OR * [ * 2023-09-26 = [ * 50401 = "14:00:01" * ] * 2023-09-27 = [ * 0 = "00:00:00" * ] * 2023-09-28 = [ * 43202 = "12:00:02" * ] * ] * INTO * * - Time-Slots A - B '10:00:01 - 12:00:02' * * - Check in A - ... '14:00:01 - 24:00:00' * - Check out ... - B '00:00:00 - 12:00:02' * * - Full day ... - ... '00:00:00 - 24:00:00' * * - Full IN ..1 - ... '00:00:01 - 24:00:00' * - Full OUT ... - ..2 '00:00:00 - 24:00:02' * */ function wpbc__transform__times_by_dates__in__readable_dates_arr( $times_arr___by_dates ) { foreach ( $times_arr___by_dates as $only_date_key => $times_arr ) { /** * Because it's dates_times from 1 booking, then in each date we have only 1 or 2 times. */ if ( 1 == count( $times_arr___by_dates[ $only_date_key ] ) ) { // One Loop only, to get the $time_only_24hours value foreach ( $times_arr___by_dates[ $only_date_key ] as $time_only_seconds => $time_only_24hours ) { if ( '00:00:00' == $time_only_24hours ) { // Full Day $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', '24:00:00' ); } else if( '00:00:01' == $time_only_24hours ) { // Check In ___ full day $times_arr___by_dates[ $only_date_key ] = array( '00:00:01', '24:00:00' ); } else if( '24:00:02' == $time_only_24hours ) { // Check Out ___ full day $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', '24:00:02' ); } else { // Check in / out $is_check_in_out__or_full = substr( $time_only_24hours, -1 ); // '1', '2' (not '0') if ( '1' == $is_check_in_out__or_full ) { // Check In $times_arr___by_dates[ $only_date_key ] = array( $time_only_24hours, '24:00:00' ); } else if ( '2' == $is_check_in_out__or_full ) { // Check Out $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', $time_only_24hours ); } else { // Unexpected ? echo "WPBC. Unexpected data value: {$time_only_24hours} Timestamp ended with value different than: 1|2 for the day {$only_date_key} in one booking "; } } } } if ( 2 == count( $times_arr___by_dates[ $only_date_key ] ) ) { // Time slots or already defined check in / out times $times_his_values = implode( ' - ', $times_arr___by_dates[ $only_date_key ] ); $times_arr___by_dates[ $only_date_key ] = array(); $times_arr___by_dates[ $only_date_key ][] = $times_his_values; } else { // Something wrong ???? Check it. echo "WPBC. Unexpected data value. We have more than 2 time slots for single day {$only_date_key} in one booking "; debuge( $times_arr___by_dates, __FILE__, __LINE__ ); } } return $times_arr___by_dates; } // GOOD /** * Transform linear [ 1690884011 = "2023-08-01 10:00:01" , ... ] -> [ '2023-08-01' : [ 36011 = "10:00:01", 43192 = "12:00:02", ... ] , '2023-08-05' : [...] ... ] * * @param array $datetimestamps_datesql_arr [ * 1690884011 = "2023-08-01 10:00:01" * 1690891192 = "2023-08-01 12:00:02" * 1691229611 = "2023-08-05 10:00:01" * 1691236792 = "2023-08-05 12:00:02" * ] * * @return array [ * 2023-08-01 = [ * 36011 = "10:00:01" * 43192 = "12:00:02" * 2023-08-05 = [ * 36011 = "10:00:01" * 43192 = "12:00:02" * ] */ function wpbc__transform__timestamp_arr__in__times_by_dates__arr( $datetimestamps_datesql_arr ) { ksort( $datetimestamps_datesql_arr ); $by_dates__timestamp_datesql__arr = array(); foreach ( $datetimestamps_datesql_arr as $this_datetime_stamp => $this_date_sql ) { // '2023-08-01' '10:00:01' list( $only_day_sql, $only_time_sql ) = explode( ' ', $this_date_sql ); $only_day_sql = trim( $only_day_sql ); // '2023-08-01' $only_time_sql = trim( $only_time_sql ); // '10:00:01' if ( ! isset( $by_dates__timestamp_datesql__arr[ $only_day_sql ] ) ) { $by_dates__timestamp_datesql__arr[ $only_day_sql ] = array(); // [ '2023-08-01': [] ] } $only_time_in_sec = wpbc_convert__time_his__to_seconds( $only_time_sql, false ); // 36001, false <- $is_apply__check_in_out__10s // '2023-08-01' 36001 '10:00:01' $by_dates__timestamp_datesql__arr[ $only_day_sql ][ $only_time_in_sec ] = $only_time_sql; } return $by_dates__timestamp_datesql__arr; } // GOOD /** * Add to the first and last dates the check in/out times * * @param array $sql_dates_arr * * @return array $sql_dates_arr */ function wpbc__add_to__fulldays__check_in_out( $sql_dates_arr ){ // Add check in/out to first and last dates ! $is_apply__check_in_out__10s = false; // EVEN if we have only 1 day, it has to work! from $all_timestamps_arr = array_keys( $sql_dates_arr ); // CHECK_IN date, - lowest timestamp: ------------------------------------------------------------------- $check_in_timestamp = min( $all_timestamps_arr ); // Remove this date if ( isset( $sql_dates_arr[ $check_in_timestamp ] ) ) { unset( $sql_dates_arr[ $check_in_timestamp ] ); } // Add new date: see definition of WPBC_FULL_DAY_TIME_IN <- 00:00:01 $real__check_in__date_sql = date( 'Y-m-d', $check_in_timestamp ) . ' 00:00:01'; $real__check_in_timestamp_new = wpbc_convert__sql_date__to_seconds( date( 'Y-m-d', $check_in_timestamp ) . ' 00:00:01', $is_apply__check_in_out__10s ); $sql_dates_arr[ $real__check_in_timestamp_new ] = $real__check_in__date_sql; // CHECK_OUT date, - highest timestamp: ------------------------------------------------------------------ $check_out_timestamp = max( $all_timestamps_arr ); // Remove this date if ( isset( $sql_dates_arr[ $check_out_timestamp ] ) ) { unset( $sql_dates_arr[ $check_out_timestamp ] ); } // Add new date: see definition of WPBC_FULL_DAY_TIME_OUT <- 23:59:52 $real__check_out__date_sql = date( 'Y-m-d', $check_out_timestamp ) . ' 24:00:02'; $real__check_out_timestamp_new = wpbc_convert__sql_date__to_seconds( date( 'Y-m-d', $check_out_timestamp ) . ' 23:59:52', $is_apply__check_in_out__10s ); $sql_dates_arr[ $real__check_out_timestamp_new ] = $real__check_out__date_sql; // Sort such dates again, because we changed the order --------------------------------------------------- ksort( $sql_dates_arr ); return $sql_dates_arr; } // GOOD /** * Check if all dates in array it is full dates e.g. 2023-07-25 00:00:00 * and not the check in/out, such as 2023-07-25 12:00:02 * * @param array $booking_sqldates_arr [ * 1690884011 = "2023-08-01 10:00:01" * 1690891192 = "2023-08-01 12:00:02" * ... * ] * * @return bool */ function wpbc_is_all__fulldays__in_dates_arr( $booking_sqldates_arr ) { $is_all_dates_full = true; foreach ( $booking_sqldates_arr as $date_sql ) { $is_check_in_out__or_full = (string) $date_sql; $is_check_in_out__or_full = substr( $is_check_in_out__or_full, - 1 ); // '0', '1', '2' from "2023-08-01 12:00:02" if ( '0' !== $is_check_in_out__or_full ) { $is_all_dates_full = false; break; } } return $is_all_dates_full; } // ===================================================================================================================== /** * Convert [ "2023-10-20", "2023-10-25", "2023-11-23" ] -> [ '20.10.2023', '25.10.2023', '23.11.2023' ] * * @param $dates_arr__yyyy_mm_dd [ "2023-10-20", "2023-10-25", "2023-11-23" ] * * @return [] [ '20.10.2023', '25.10.2023', '23.11.2023' ] */ function wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $dates_arr__yyyy_mm_dd ) { $dates_arr__dd_mm_yyyy = array_map( function ( $value ) { $value_arr = explode( '-', $value ); return ( count( $value_arr ) > 2 ) ? $value_arr[2] . '.' . $value_arr[1] . '.' . $value_arr[0] : ''; } , $dates_arr__yyyy_mm_dd ); // [ "2023-10-20", "2023-10-25", "2023-11-23" ] $dates_arr__dd_mm_yyyy = array_filter( $dates_arr__dd_mm_yyyy ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. return $dates_arr__dd_mm_yyyy; } /** * Convert '20.10.2023, 25.10.2023, 23.10.2023' -> '2023-10-20,2023-10-23,2023-10-25' * * or even: '20.10.2023 - 23.10.2023' -> '2023-10-20,2023-10-21,2023-10-22,2023-10-23' * * @param $str_dates__dd_mm_yyyy '20.10.2023, 25.10.2023, 23.10.2023' * * @return string '2023-10-20,2023-10-23,2023-10-25' */ function wpbc_convert_dates_str__dd_mm_yyyy__to__yyyy_mm_dd( $str_dates__dd_mm_yyyy ) { $str_dates__dd_mm_yyyy = str_replace( '|', ',', $str_dates__dd_mm_yyyy ); // Check this for some old versions of plugin if ( strpos( $str_dates__dd_mm_yyyy, ' - ' ) !== false ) { // Recheck for any type of Range Days Formats $arr_check_in_out_dates = explode( ' - ', $str_dates__dd_mm_yyyy ); $str_dates__dd_mm_yyyy = wpbc_get_comma_seprated_dates_from_to_day( $arr_check_in_out_dates[0], $arr_check_in_out_dates[1] ); } $dates_arr__dd_mm_yyyy = explode( ',', $str_dates__dd_mm_yyyy ); // Create dates Array $dates_arr__yyyy_mm_dd = array_map( function ( $value ) { $value = trim( $value ); $value_arr = explode( '.', $value ); return ( count( $value_arr ) > 2 ) ? $value_arr[2] . '-' . $value_arr[1] . '-' . $value_arr[0] : ''; } , $dates_arr__dd_mm_yyyy ); // [ '20.10.2023', '25.10.2023', '23.11.2023' ] $dates_arr__yyyy_mm_dd = array_filter( $dates_arr__yyyy_mm_dd ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. // Remove duplicates $dates_arr__yyyy_mm_dd = array_unique( $dates_arr__yyyy_mm_dd ); // Sort Dates sort( $dates_arr__yyyy_mm_dd ); $dates_str__yyyy_mm_dd = implode( ',', $dates_arr__yyyy_mm_dd ); return $dates_str__yyyy_mm_dd; // '2023-10-20,2023-10-23,2023-10-25' } booking_date_class.php 0000666 00000025021 15165546743 0011113 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 /** * Conception: - Time-Slots A - B '10:00:01 - 12:00:02' '10:00:01 - 12:00:02' * * - Check in A - ... '14:00:01 - ... ' '14:00:01 - 24:00:00' * - Check out ... - B ' ... - 12:00:02' '00:00:00 - 12:00:02' * * - Full day ... - ... ' ... - ... ' '00:00:00 - 24:00:00' * * - Full IN ..1 - ... '00:00:01 - ... ' '00:00:01 - 24:00:00' * - Full OUT ... - ..2 ' ... - 24:00:02' '00:00:00 - 24:00:02' * * * 1) Always in one specific date, can be start & end times. * 2) Such start end times can define * */ class WPBC_BOOKING_DATE { public $readable_dates; public $is_debug; /** * Define booking date object by readable dates array >> [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...] * @param $boking_dates_arr */ function __construct( $boking_dates_arr ) { // [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...] $this->readable_dates = $boking_dates_arr; $this->is_debug = false; // Gathering additional data into the variables } /** * Is this readable_time 'Check In' '10:00:01 - 12:00:02' | '14:00:01 - 24:00:00' | '00:00:01 - 24:00:00' -> true * * @param $readable_time_range '10:00:01 - 12:00:02' * * @return bool true | false */ public function is_time_check_in( $readable_time_range ){ $time_24_hours_arr = explode( '-', $readable_time_range ); $time_24_hours_slot = (string) trim( $time_24_hours_arr[0] ); $is_check_in_out__or_full = substr( $time_24_hours_slot, -1 ); // '1', '2' (not '0') $result = ( '1' === $is_check_in_out__or_full ) ? true : false; return $result; } /** * Is this readable_time 'Check Out' '10:00:01 - 12:00:02' | '00:00:00 - 12:00:02' | '00:00:00 - 24:00:02' -> true * * @param $readable_time_range '10:00:01 - 12:00:02' * * @return bool true | false */ public function is_time_check_out( $readable_time_range ){ $time_24_hours_arr = explode( '-', $readable_time_range ); $time_24_hours_slot = (string) trim( $time_24_hours_arr[1] ); $is_check_in_out__or_full = substr( $time_24_hours_slot, -1 ); // '1', '2' (not '0') $result = ( '2' === $is_check_in_out__or_full ) ? true : false; return $result; } /** * Is this readable_time 'Full Day' '00:00:00 - 24:00:00' => true * * @param $readable_time_range '10:00:01 - 12:00:02' * * @return bool true | false */ public function is_time_full_day( $readable_time_range ){ $result = ( '00:00:00 - 24:00:00' === $readable_time_range ) ? true : false; return $result; } /** * Loop all dates, and APPLY_SPECIFIC_ACTION to Times Arr of specific dates * * @param string $filter_action 'get_times__as_24_hour_arr' | 'get_times__as_seconds_arr' | 'get_times__as_timestamps_arr' * * @return array */ public function loop_all_dates( $filter_action ){ $result = array(); foreach ( $this->readable_dates as $only_date_sql => $readable_times_arr ) { switch ( $filter_action ) { case 'get_times__as_24_hour_arr': $result[$only_date_sql] = $this->get__filtered_times__as_arr( $only_date_sql ); break; case 'get_times__as_seconds_arr': $result[ $only_date_sql ] = $this->get__filtered_times__as_arr( $only_date_sql, array( 'filter' => 'as_seconds' ) ); break; case 'get_times__as_timestamps_arr': $result[ $only_date_sql ] = $this->get__filtered_times__as_arr( $only_date_sql, array( 'filter' => 'as_timestamps' ) ); break; default: // Default } } return $result; } /** * Get times in different formats: [ "10:00:01", "12:00:02" ] | [ 36001, 43202 ] * * @param $date_sql '2023-07-30' * @param $params [] | [ 'filter' => 'as_seconds' ] * * @return array [ "10:00:01", "12:00:02" ] | [ 36001, 43202 ] */ protected function get__filtered_times__as_arr( $date_sql, $params = array() ){ if ( ! isset( $this->readable_dates[ $date_sql ] ) ) { return array(); } $defaults = array( 'filter' => '' ); $params = wp_parse_args( $params, $defaults ); $times_as_arr = array(); foreach ( $this->readable_dates[ $date_sql ] as $time_range ) { $time_24_hours_arr = explode( '-', $time_range ); foreach ( $time_24_hours_arr as $time_24_hour ) { // [ '10:00:01', '14:00:02' ] $time_24_hour = trim( $time_24_hour ); switch ( $params['filter'] ) { case 'as_seconds': $filtered_time = $this->transform__24_hours__in__seconds( $time_24_hour ); break; case 'as_timestamps': $filtered_time = $this->transform__24_hours__in__timestamp( $date_sql, $time_24_hour ); break; default: $filtered_time = $time_24_hour; } $times_as_arr[] = $filtered_time; } } return $times_as_arr; } // ------------------------------------------------------------------------------------------------------------- /** * Get timestamp from SQL DATE '2023-07-30 10:00:01' -> 1690884001 * * @param $sql_date_ymd_his '2023-08-02 22:14:01' * * @return false|int */ protected function transform__sql_date_ymd_his__in__timestamp( $sql_date_ymd_his ){ $date_ymd__in_seconds = strtotime( $sql_date_ymd_his ); return $date_ymd__in_seconds; } /** * Get timestamp '2023-08-01', '10:00:01' -> 1690884001 * * @param $only_date_sql '2023-08-01' * @param $time_24_hour '10:00:01' * * @return float|int 1690884001 */ protected function transform__24_hours__in__timestamp( $only_date_sql, $time_24_hour ){ $date_ymd__in_seconds = $this->transform__only_date_ymd__in__timestamp( $only_date_sql ); $time_in_seconds = $this->transform__24_hours__in__seconds( $time_24_hour ); $timestamp = $date_ymd__in_seconds + $time_in_seconds; return $timestamp; } /** * Get timestamp from SQL only DATE '2023-07-30' -> 1690884001 * * @param $only_date_sql * * @return false|int */ protected function transform__only_date_ymd__in__timestamp( $only_date_sql ){ // $date_ymd__in_seconds = wpbc_convert__date_ymd__to_seconds( $date_sql ); $date_ymd__in_seconds = strtotime( $only_date_sql . ' 00:00:00' ); return $date_ymd__in_seconds; } /** * Get SQL DATE from timestamp 1690884001 -> '2023-07-30 10:00:01' * * @param int $in_seconds * @param string $sql_date_format 'Y-m-d H:i:s' | 'Y-m-d 00:00:00' * * @return false|string */ protected function transform__timestamp__to_sql_date( $in_seconds, $sql_date_format = 'Y-m-d H:i:s' ){ $sql_date = date( $sql_date_format, $in_seconds ); return $sql_date; } // ------------------------------------------------------------------------------------------------------------- /** * Get SQL TIME from SECONDS 43201 -> '10:00:02' * * @param int $in_seconds 43201 * * @return string '10:00:02' */ protected function transform__seconds__in__24_hours_his( $in_seconds ){ return wpbc_transform__seconds__in__24_hours_his( $in_seconds ); } /** * Get seconds '10:00:01' -> 36001 * * @param $time_24_hour '10:00:01' * * @return float|int 36001 */ protected function transform__24_hours__in__seconds( $time_24_hour ){ $time_24_hour_arr = explode( ':', $time_24_hour ); // 43202 $in_seconds = intval( $time_24_hour_arr[0] ) * 60 * 60 // Hours + intval( $time_24_hour_arr[1] ) * 60 // Minutes + intval( $time_24_hour_arr[2] ); // Seconds return $in_seconds; } /** * Convert Readable dates to SQL dates array for using in Calendar: [ "2023-09-30":["10:00:01 - 24:00:00"],"2023-10-01":["00:00:00 - 24:00:00"], .. ] -> [ [1696068001] => 2023-09-30 10:00:01, [1696118400] => 2023-10-01 00:00:00, [1696204800] => 2023-10-02 00:00:00 ... ] * * @return array [ * [1696068001] => 2023-09-30 10:00:01 * [1696118400] => 2023-10-01 00:00:00 * [1696204800] => 2023-10-02 00:00:00 * [1696334402] => 2023-10-03 12:00:02 * ... * ] */ public function convert_readable_dates__into__sql_dates__arr(){ $sql_dates_times_arr = array(); // Get unavailable extended time_ranges arr foreach ( $this->readable_dates as $only_date_sql => $readable_times_arr ) { foreach ( $this->readable_dates[ $only_date_sql ] as $readable_time_range ) { $time_24_hours_arr = explode( ' - ', $readable_time_range ); $only_date_timestamp = $this->transform__only_date_ymd__in__timestamp( $only_date_sql ); $check_in_seconds = $this->transform__24_hours__in__seconds( $time_24_hours_arr[0] ); $check_out_seconds = $this->transform__24_hours__in__seconds( $time_24_hours_arr[1] ); $is_add_check_in = true; $is_add_check_out = true; if ( ( '00:00:00 - 24:00:00' == $readable_time_range ) // Full Day || ( $check_out_seconds >= 86400 ) // Check out >= '24:00:00' then skip end time ){ $is_add_check_out = false; } if ( ( '00:00:00' == $time_24_hours_arr[0] ) && ( $check_out_seconds > 0 ) && ( $check_out_seconds < 86400 ) // '00:00:00 - 12:00:02' ){ $is_add_check_in = false; } // Check In if ( $is_add_check_in ) { $sql_dates_times_arr[ $only_date_timestamp + $check_in_seconds ] = $only_date_sql . ' ' . $time_24_hours_arr[0]; } // Check out if ( $is_add_check_out ) { $sql_dates_times_arr[ $only_date_timestamp + $check_out_seconds ] = $only_date_sql . ' ' . $time_24_hours_arr[1]; } } } return $sql_dates_times_arr; } } confirmation.php 0000666 00000050706 15165546743 0010001 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // --------------------------------------------------------------------------------------------------------------------- // == Get Booking Confirmation Data // --------------------------------------------------------------------------------------------------------------------- /** * Get confirmation parameters for booking confimration window * * @param array $params_arr = [ * 'booking_id' => 0, // 16102023 * 'resource_id' => 1, * 'form_data' => '', // 'text^selected_short_dates_hint11^Sun...', * 'dates_ymd_arr' => array(), // [ '2023-10-20', '2023-10-25' ] * 'times_his_arr' => array(), // [ '16:00:01', '18:00:02' ] * * 'total_cost' => 0, Optional. * 'deposit_cost' => 0, Optional. * * 'booking_summary' => '', Optional. * 'gateway_rows' => '' Optional. * ] * * @return array */ function wpbc_booking_confirmation( $params_arr ){ $defaults = array( 'booking_id' => 0, // 16102023 'resource_id' => 1, 'form_data' => '', // 'text^selected_short_dates_hint11^Sun...', 'dates_ymd_arr' => array(), // [ '2023-10-20', '2023-10-25' ] 'times_his_arr' => array(), // [ '16:00:01', '18:00:02' ] 'total_cost' => 0, // 143.991 'deposit_cost' => 0, // 14.3991 'booking_summary' => '', // '<p>Dear John, please make payment for your booking...' 'gateway_rows' => '', // [ [ gateway_id = "stripe_v3", payment_params = [...] , is_for_deposit = 0, output = '<div class="stripe_v3_div...' ], .... ] // Optional ! 'is_show_coupon_discount_text' => true, 'ty_is_redirect' => esc_js( get_bk_option( 'booking_type_of_thank_you_message' ) ) // 'message' | 'page' ); $params_arr = wp_parse_args( $params_arr, $defaults ); $str_dates__dd_mm_yyyy = wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $params_arr['dates_ymd_arr'] ); // ['2023-10-20','2023-10-25'] => ['20.10.2023','25.10.2023'] $params_arr['str_dates__dd_mm_yyyy'] = implode( ',', $str_dates__dd_mm_yyyy ); // REQUIRED -- '14.11.2023, 15.11.2023, 16.11.2023, 17.11.2023' $params_arr['times_array'] = array( explode( ':', $params_arr['times_his_arr'][0] ), // ["10","00","00"] explode( ':', $params_arr['times_his_arr'][1] ) // ["12","00","00"] ); // -- Booking Hash ------------------------------------------------------------------------------------------------- $booking_hash = ''; $hash__arr = wpbc_hash__get_booking_hash__resource_id( $params_arr['booking_id'] ); // Get booking hash if ( ! empty( $hash__arr ) ) { list( $booking_hash, $resource_id ) = $hash__arr; } $confirmation = array(); // $confirmation['hash'] = $booking_hash; $confirmation['ty_is_redirect'] = $params_arr['ty_is_redirect']; if ( 0 ) { // TODO: Probably all this info, we already had? (2023-10-06 18:10). Optimize and refactor this function, which used in page-gateways.php file in wpbc_get_gateway_forms( $blank, $params ) during generating payment forms. // $replace_params = wpbc_get_booking_different_params_arr( $params_arr['booking_id'], $params_arr['form_data'], $params_arr['resource_id'] ); // TODO: make this function universal for all emails and for other purpose // $booking_params_like_in_email = wpbc__get_replace_shortcodes__email_new_admin( $params_arr['booking_id'] , $params_arr['resource_id'] , $params_arr['form_data'] ); /** * [ booking_id = {int} 3945 id = {int} 3945 dates = "Wed, Nov 1, 2023 10:00 - Wed, Nov 1, 2023 12:00" ... is_new = "1" status = "" sort_date = "2023-11-01 10:00:01" creation_date = "2023-10-06 17:51:49" pay_status = "169660391431.09" pay_request = "0" booking_featured_image = {int} 0 * ] */ } // ================================================================================================================= // == Confirmation data == / TY - Thank you / // ================================================================================================================= $replace_arr = wpbc__get_replace_shortcodes__email_new_visitor( $params_arr['booking_id'], $params_arr['resource_id'], $params_arr['form_data'] ); $replace_arr['readable_dates'] = '<div class="wpbc_ty__section_text_dates">'. wpbc_get_redable_dates( $params_arr['dates_ymd_arr'] ) . '</div>'; $replace_arr['readable_times'] = ''; if ( ( wpbc_transform__24_hours_his__in__seconds( $params_arr['times_his_arr'][0] ) > 0 ) && ( wpbc_transform__24_hours_his__in__seconds( $params_arr['times_his_arr'][0] ) < 86400 ) ) { // -- Times text -- $replace_arr['readable_times'] = '<div class="wpbc_ty__section_text_times">' . wpbc_get_redable_times( $params_arr['dates_ymd_arr'], $params_arr['times_his_arr'] ) . '</div>'; } // Top - Thank you $title_after_reservation = html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_title_after_reservation' ) ) ) ); $title_after_reservation = wpbc_replace_booking_shortcodes( $title_after_reservation, $replace_arr, ' --- ' ); $title_after_reservation = stripslashes( $title_after_reservation ); $confirmation['ty_message'] = $title_after_reservation; // 'Thank you for booking!' // ----------------------------------------------------------------------------------------------------------------- // Booking ID // ----------------------------------------------------------------------------------------------------------------- $confirmation['ty_message_booking_id'] = ''; if ( 'Off' !== get_bk_option( 'booking_confirmation_header_enabled' ) ) { $confirmation['ty_message_booking_id'] .= ( false !== get_bk_option( 'booking_confirmation_header' ) ) ? html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_confirmation_header' ) ) ) ) : sprintf( __( 'Your booking id: %s', 'booking' ), '<strong>[booking_id]</strong>' ); } $confirmation['ty_message_booking_id'] = wpbc_replace_booking_shortcodes( $confirmation['ty_message_booking_id'], $replace_arr, ' --- ' ); $confirmation['ty_message_booking_id'] = stripslashes( $confirmation['ty_message_booking_id'] ); //$confirmation['ty_message_booking_id'] = str_replace( '[booking_id]', $params_arr['booking_id'], $confirmation['ty_message_booking_id'] ); // ----------------------------------------------------------------------------------------------------------------- // -- Customer details -- // ----------------------------------------------------------------------------------------------------------------- //$plain_form_data_show = wpbc_get__booking_form_data__show( $params_arr['form_data'], $params_arr['resource_id'], array( 'unknown_shortcodes_replace_by' => ' ... ' ) ); $confirmation['ty_customer_details'] = ''; if ( 'Off' !== get_bk_option( 'booking_confirmation__personal_info__header_enabled' ) ) { // Title $section_title = html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_confirmation__personal_info__title' ) ) ) ); $confirmation['ty_customer_details'] .= '<div class="wpbc_ty__section_header">' . $section_title . '</div>'; // Content $confirmation['ty_customer_details'] .= html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_confirmation__personal_info__content' ) ) ) ); $confirmation['ty_customer_details'] = str_replace( array( "\\n", "\n" ), '<br>', $confirmation['ty_customer_details'] ); $confirmation['ty_customer_details'] = wpbc_replace_booking_shortcodes( $confirmation['ty_customer_details'], $replace_arr, ' --- ' ); } // ----------------------------------------------------------------------------------------------------------------- // -- Booking details -- // ----------------------------------------------------------------------------------------------------------------- $confirmation['ty_booking_details'] = ''; if ( 'Off' !== get_bk_option( 'booking_confirmation__booking_details__header_enabled' ) ) { // Title $section_title = html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_confirmation__booking_details__title' ) ) ) ); $confirmation['ty_booking_details'] .= '<div class="wpbc_ty__section_header">' . $section_title . '</div>'; // Content $confirmation['ty_booking_details'] .= html_entity_decode( esc_js( wpbc_lang( get_bk_option( 'booking_confirmation__booking_details__content' ) ) ) ); $confirmation['ty_booking_details'] = str_replace( array( "\\n", "\n" ), '<br>', $confirmation['ty_booking_details'] ); $confirmation['ty_booking_details'] = wpbc_replace_booking_shortcodes( $confirmation['ty_booking_details'], $replace_arr, ' --- ' ); } // ----------------------------------------------------------------------------------------------------------------- // -- Costs text -- // ----------------------------------------------------------------------------------------------------------------- $confirmation['ty_booking_costs'] = ''; $confirmation['payment_cost'] = ''; if ( class_exists('wpdev_bk_biz_s')) { $is_deposit = ( $params_arr['total_cost'] != $params_arr['deposit_cost'] ); if ($is_deposit){ $confirmation['payment_cost'] = $params_arr['deposit_cost']; } else { $confirmation['payment_cost'] = $params_arr['total_cost']; } $confirmation['ty_booking_costs'] .= '<div class="wpbc_ty__section_text_costs">'; // ------------------------------------------------------------------------------------------------------------- // -- Coupon Code Discounts -- // ------------------------------------------------------------------------------------------------------------- $coupon_discount_value = false; if ( ( class_exists( 'wpdev_bk_biz_l' ) ) && ( $params_arr['is_show_coupon_discount_text'] ) ){ // Get al fields (again?) ? -> $payment_params['structured_booking_data_arr'] <- Use this or get the info again ? $structured_booking_data_arr = wpbc_get_parsed_booking_data_arr( $params_arr['form_data'], $params_arr['resource_id'] ); // Find filled coupon code field - if not found then we get [] otherwise [ 'discount' => ['value' => 'test', ... ] ] $filtered_booking_data_arr = array_filter( $structured_booking_data_arr , function ( $v ) { return ( ( ! empty( $v['value'] ) ) && ( 'coupon' == $v['type'] ) ); } ); if ( ! empty( $filtered_booking_data_arr ) ) { // Get total cost without discount. $total_cost_without_discount = wpbc_calc__booking_cost( array( 'resource_id' => $params_arr['resource_id'] // '2' , 'str_dates__dd_mm_yyyy' => $params_arr['str_dates__dd_mm_yyyy'] // '14.11.2023, 15.11.2023, 16.11.2023, 17.11.2023' , 'times_array' => $params_arr['times_array'] // [ ["10","00","00"], ["12","00","00"] ] , 'form_data' => $params_arr['form_data'] // 'text^selected_short_timedates_hint4^06/11/2018 14:00...' , 'is_discount_calculate' => ! true // Default true , 'is_only_original_cost' => false // Default false ) ); $total_cost_without_discount = floatval( $total_cost_without_discount ); // from double > float $coupon_text_info = apply_bk_filter( 'wpdev_get_additional_description_about_coupons', '' , $params_arr['resource_id'], $params_arr['str_dates__dd_mm_yyyy'], $params_arr['times_his_arr'], $params_arr['form_data'] ); $coupon_discount_value = apply_bk_filter( 'wpbc_get_coupon_code_discount_value', '' , $params_arr['resource_id'], $params_arr['str_dates__dd_mm_yyyy'], $params_arr['times_his_arr'], $params_arr['form_data'] ); $coupon_text_info = str_replace( array( '[', ']' ), '', $coupon_text_info ); $confirmation['ty_booking_costs'] .= '<div class="wpbc_ty__section_text_costs_header">'; $confirmation['ty_booking_costs'] .= __( 'Total Cost', 'booking' ) . ': '; $confirmation['ty_booking_costs'] .= wpbc_get_cost_with_currency_for_user( $total_cost_without_discount , $params_arr['resource_id'] ); // $confirmation['ty_booking_costs'] .= '<br/>'; // $confirmation['ty_booking_costs'] .= __( 'Discount', 'booking' ) . ': '; // $confirmation['ty_booking_costs'] .= wpbc_get_cost_with_currency_for_user( $coupon_discount_value // , $params_arr['resource_id'] // ); $confirmation['ty_booking_costs'] .= '<br/>'; $confirmation['ty_booking_costs'] .= $coupon_text_info; $confirmation['ty_booking_costs'] .= '<br/>'; $confirmation['ty_booking_costs'] .= '</div>'; } } // -- Deposit | Balance | Total -- if ( $is_deposit ){ $confirmation['ty_booking_costs'] .= '<div class="wpbc_ty__section_text_costs_header">'; $confirmation['ty_booking_costs'] .= ( empty( $coupon_discount_value ) ) ? __( 'Total cost', 'booking' ) . ': ' : __( 'Subtotal cost', 'booking' ) . ': '; $confirmation['ty_booking_costs'] .= wpbc_get_cost_with_currency_for_user( $params_arr['total_cost'] , $params_arr['resource_id'] ); $confirmation['ty_booking_costs'] .= '<br/>'; $confirmation['ty_booking_costs'] .= __( 'Deposit Due', 'booking' ). ': '; $confirmation['ty_booking_costs'] .= wpbc_get_cost_with_currency_for_user( $params_arr['deposit_cost'] , $params_arr['resource_id'] ); $confirmation['ty_booking_costs'] .= '<br/>'; $confirmation['ty_booking_costs'] .= __( 'Balance Remaining', 'booking' ). ': '; $confirmation['ty_booking_costs'] .= wpbc_get_cost_with_currency_for_user( ($params_arr['total_cost'] - $params_arr['deposit_cost'] ) , $params_arr['resource_id'] ); $confirmation['ty_booking_costs'] .= '<br/>'; $confirmation['ty_booking_costs'] .= '</div>'; } $confirmation['ty_booking_costs'] .= '</div>'; // --------------------------------------------------------------------------------------------------------- // "Update Note" in booking with all datails. Again ? // --------------------------------------------------------------------------------------------------------- $cost_booking_note = preg_replace( "@(<|<)br\s*/?(>|>)(\r\n)?@", "\n", $confirmation['ty_booking_costs'] ); $cost_booking_note = strip_tags( $cost_booking_note ); $cost_booking_note = str_replace( array( ' ', "\n " ), array( ' ', "\n" ), $cost_booking_note ); if ( ! empty( $params_arr['gateway_rows'] ) ) { $is_add_timezone_offset = true; $booking_note = wpbc_date_localized( gmdate( 'Y-m-d H:i:s' ), '[Y-m-d H:i]', $is_add_timezone_offset ) . ' '; $booking_note .= ' ' . __( 'Payment section displayed', 'booking' ); if ( empty( $cost_booking_note ) ) { foreach ( $params_arr['gateway_rows'] as $row_num => $gateway_row ) { $booking_note .= ' | ' . strip_tags( html_entity_decode( $gateway_row['header'] ) ); } } $booking_note .= "\n"; if ( false !== strpos( $cost_booking_note, "\n" ) ) { $booking_note .= '-----------------------------------------' . "\n"; } $booking_note .= $cost_booking_note; if ( false !== strpos( $cost_booking_note, "\n" ) ) { $booking_note .= "\n" . '-----------------------------------------' . "\n"; } make_bk_action( 'wpdev_make_update_of_remark', $params_arr['booking_id'], $booking_note, true ); } // TODO: 2. what about additional calendars payment forms ?. It has to be returned from wpbc_get_gateway_forms() with -> 'payment_form_target': ' target="_blank" ' // ------------------------------------------------------------------------------------------------------------- // -- Payment gateways // ------------------------------------------------------------------------------------------------------------- $confirmation['ty_payment_gateways'] = ''; $confirmation['ty_payment_payment_description'] = ''; if ( ! empty( $params_arr['booking_summary'] ) ) { $confirmation['ty_payment_payment_description'] = $params_arr['booking_summary']; } if ( ( ( 'On' !== get_bk_option( 'booking_payment_form_in_request_only' ) ) || ( ! empty( $params_arr['booking_payment_form_in_request_only'] ) ) ) && ( ! empty( $params_arr['gateway_rows'] ) ) ){ $is_show_both_deposit_and_total = ( ( 'On' == get_bk_option( 'booking_show_deposit_and_total_payment' ) ) && ( $is_deposit ) ); foreach ( $params_arr['gateway_rows'] as $row_num => $gateway_row ) { $ty_payment_gateways_before = ''; $ty_payment_gateways_after = ''; // Cost Header $ty_payment_gateways_before .= '<div class="wpbc_ty__gateway ">'; $ty_payment_gateways_before .= '<h4 class="wpbc_ty__section_text_costs_header" style="margin-left: auto;margin-right: 1.5em;">'; $ty_payment_gateways_before .= $params_arr['gateway_rows'][ $row_num ]['header']; $ty_payment_gateways_before .= '</h4>'; $ty_payment_gateways_before .= '</div>'; // Gateways Buttons foreach ( $params_arr['gateway_rows'][ $row_num ]['gateways_arr'] as $payment_gateway ) { /** * $payment_gateway['payment_params'] = [ booking_id = "3842" id = "3842" days_input_format = "10.12.2023" days_only_sql = "2023-12-10" ... visitorbookingediturl = "http://beta/wpbc-my-booking/?booking_hash=65410858c2dcab4298ad7494d65b8ab0" ] * $payment_gateway['gateway_id'] = stripe_v3 */ if ( ! in_array( $payment_gateway['gateway_id'], array( 'bank_transfer', 'pay_cash' ) ) ) { if ( ( $is_show_both_deposit_and_total ) && ( $params_arr['gateway_rows'][ $row_num ]['is_for_deposit'] ) && ( in_array( $payment_gateway['gateway_id'], array( 'stripe_v3' ) ) ) ) { // Skip 'Stripe' for showing total cost, if activated both "Total | Deposit", because we can show only 1 button } else { $ty_payment_gateways_before .= '<div class="wpbc_ty__gateway wpbc_col_auto_width">' . $payment_gateway['output'] . '</div>'; } } else { $ty_payment_gateways_after .= '<div class="wpbc_ty__gateway">' . $payment_gateway['output'] . '</div>'; } } $confirmation['ty_payment_gateways'] .= $ty_payment_gateways_before . $ty_payment_gateways_after; } } } // If showing payment form, that we do not make redirection and show Message only if ( ! empty( $confirmation['ty_payment_gateways'] ) ) { $confirmation['ty_is_redirect'] = 'message'; } if ( 'page' == $confirmation['ty_is_redirect'] ) { //FixIn: 9.9.0.3 if ( ! empty( $params_arr['ty_url'] ) ) { $confirmation['ty_url'] = $params_arr['ty_url']; } else { $confirmation['ty_url'] = wpbc_make_link_absolute( wpbc_lang( get_bk_option( 'booking_thank_you_page_URL' ) ) ); // '/thank-you' $confirmation['ty_url'] .= ( ( false === strpos( $confirmation['ty_url'], '?' ) ) ? '?' : '&' ) . 'booking_hash=' . $booking_hash; } } else { $confirmation['ty_url'] = ''; } return $confirmation; } _src/create_booking.js 0000666 00000066772 15165546743 0011051 0 ustar 00 "use strict"; // --------------------------------------------------------------------------------------------------------------------- // A j a x A d d N e w B o o k i n g // --------------------------------------------------------------------------------------------------------------------- /** * Submit new booking * * @param params = { 'resource_id' : resource_id, 'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value, 'formdata' : formdata, 'booking_hash' : my_booking_hash, 'custom_form' : my_booking_form, 'captcha_chalange' : captcha_chalange, 'captcha_user_input' : user_captcha, 'is_emails_send' : is_send_emeils, 'active_locale' : wpdev_active_locale } * */ function wpbc_ajx_booking__create( params ){ console.groupCollapsed( 'WPBC_AJX_BOOKING__CREATE' ); console.groupCollapsed( '== Before Ajax Send ==' ); console.log( params ); console.groupEnd(); params = wpbc_captcha__simple__maybe_remove_in_ajx_params( params ); // Start Ajax jQuery.post( wpbc_url_ajax, { action : 'WPBC_AJX_BOOKING__CREATE', wpbc_ajx_user_id: _wpbc.get_secure_param( 'user_id' ), nonce : _wpbc.get_secure_param( 'nonce' ), wpbc_ajx_locale : _wpbc.get_secure_param( 'locale' ), calendar_request_params : params /** * Usually params = { 'resource_id' : resource_id, * 'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value, * 'formdata' : formdata, * 'booking_hash' : my_booking_hash, * 'custom_form' : my_booking_form, * * 'captcha_chalange' : captcha_chalange, * 'user_captcha' : user_captcha, * * 'is_emails_send' : is_send_emeils, * 'active_locale' : wpdev_active_locale * } */ }, /** * S u c c e s s * * @param response_data - its object returned from Ajax - class-live-searcg.php * @param textStatus - 'success' * @param jqXHR - Object */ function ( response_data, textStatus, jqXHR ) { console.log( ' == Response WPBC_AJX_BOOKING__CREATE == ' ); for ( var obj_key in response_data ){ console.groupCollapsed( '==' + obj_key + '==' ); console.log( ' : ' + obj_key + ' : ', response_data[ obj_key ] ); console.groupEnd(); } console.groupEnd(); // <editor-fold defaultstate="collapsed" desc=" = Error Message! Server response with String. -> E_X_I_T " > // ------------------------------------------------------------------------------------------------- // This section execute, when server response with String instead of Object -- Usually it's because of mistake in code ! // ------------------------------------------------------------------------------------------------- if ( (typeof response_data !== 'object') || (response_data === null) ){ var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data ); var jq_node = '#booking_form' + calendar_id; if ( '' == response_data ){ response_data = '<strong>' + 'Error! Server respond with empty string!' + '</strong> ' ; } // Show Message wpbc_front_end__show_message( response_data , { 'type' : 'error', 'show_here': {'jq_node': jq_node, 'where': 'after'}, 'is_append': true, 'style' : 'text-align:left;', 'delay' : 0 } ); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable( calendar_id ); return; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == This section execute, when we have KNOWN errors from Booking Calendar. -> E_X_I_T " > // ------------------------------------------------------------------------------------------------- // This section execute, when we have KNOWN errors from Booking Calendar // ------------------------------------------------------------------------------------------------- if ( 'ok' != response_data[ 'ajx_data' ][ 'status' ] ) { switch ( response_data[ 'ajx_data' ][ 'status_error' ] ){ case 'captcha_simple_wrong': wpbc_captcha__simple__update( { 'resource_id': response_data[ 'resource_id' ], 'url' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'url' ], 'challenge' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'challenge' ], 'message' : response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) } ); break; case 'resource_id_incorrect': // Show Error Message - incorrect booking resource ID during submit of booking. var message_id = wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ), { 'type' : ('undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ])) ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'warning', 'delay' : 0, 'show_here': { 'where': 'after', 'jq_node': '#booking_form' + params[ 'resource_id' ] } } ); break; case 'booking_can_not_save': // We can not save booking, because dates are booked or can not save in same booking resource all the dates var message_id = wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ), { 'type' : ('undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ])) ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'warning', 'delay' : 0, 'show_here': { 'where': 'after', 'jq_node': '#booking_form' + params[ 'resource_id' ] } } ); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable( response_data[ 'resource_id' ] ); break; default: // <editor-fold defaultstate="collapsed" desc=" = For debug only ? -- Show Message under the form = " > // -------------------------------------------------------------------------------------------------------------------------------- if ( ( 'undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message' ]) ) && ( '' != response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) ) ){ var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data ); var jq_node = '#booking_form' + calendar_id; var ajx_after_booking_message = response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ); console.log( ajx_after_booking_message ); /** * // Show Message var ajx_after_action_message_id = wpbc_front_end__show_message( ajx_after_booking_message, { 'type' : ('undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ])) ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info', 'delay' : 10000, 'show_here': { 'jq_node': jq_node, 'where' : 'after' } } ); */ } // </editor-fold> } // ------------------------------------------------------------------------------------------------- // Reactivate calendar again ? // ------------------------------------------------------------------------------------------------- // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable( response_data[ 'resource_id' ] ); // Unselect dates wpbc_calendar__unselect_all_dates( response_data[ 'resource_id' ] ); // 'resource_id' => $params['resource_id'], // 'booking_hash' => $booking_hash, // 'request_uri' => $_SERVER['REQUEST_URI'], // Is it the same as window.location.href or // 'custom_form' => $params['custom_form'], // Optional. // 'aggregate_resource_id_str' => implode( ',', $params['aggregate_resource_id_arr'] ) // Optional. Resource ID from aggregate parameter in shortcode. // Load new data in calendar. wpbc_calendar__load_data__ajx( { 'resource_id' : response_data[ 'resource_id' ] // It's from response ...AJX_BOOKING__CREATE of initial sent resource_id , 'booking_hash': response_data[ 'ajx_cleaned_params' ]['booking_hash'] // ?? we can not use it, because HASH chnaged in any case! , 'request_uri' : response_data[ 'ajx_cleaned_params' ]['request_uri'] , 'custom_form' : response_data[ 'ajx_cleaned_params' ]['custom_form'] // Aggregate booking resources, if any ? , 'aggregate_resource_id_str' : _wpbc.booking__get_param_value( response_data[ 'resource_id' ], 'aggregate_resource_id_arr' ).join(',') } ); // Exit return; } // </editor-fold> /* // Show Calendar wpbc_calendar__loading__stop( response_data[ 'resource_id' ] ); // ------------------------------------------------------------------------------------------------- // Bookings - Dates _wpbc.bookings_in_calendar__set_dates( response_data[ 'resource_id' ], response_data[ 'ajx_data' ]['dates'] ); // Bookings - Child or only single booking resource in dates _wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'resources_id_arr__in_dates', response_data[ 'ajx_data' ][ 'resources_id_arr__in_dates' ] ); // ------------------------------------------------------------------------------------------------- // Update calendar wpbc_calendar__update_look( response_data[ 'resource_id' ] ); */ // Hide spin loader wpbc_booking_form__spin_loader__hide( response_data[ 'resource_id' ] ); // Hide booking form wpbc_booking_form__animated__hide( response_data[ 'resource_id' ] ); // Show Confirmation | Payment section wpbc_show_thank_you_message_after_booking( response_data ); setTimeout( function (){ wpbc_do_scroll( '#wpbc_scroll_point_' + response_data[ 'resource_id' ], 10 ); }, 500 ); } ).fail( // <editor-fold defaultstate="collapsed" desc=" = This section execute, when NONCE field was not passed or some error happened at server! = " > function ( jqXHR, textStatus, errorThrown ) { if ( window.console && window.console.log ){ console.log( 'Ajax_Error', jqXHR, textStatus, errorThrown ); } // ------------------------------------------------------------------------------------------------- // This section execute, when NONCE field was not passed or some error happened at server! // ------------------------------------------------------------------------------------------------- // Get Content of Error Message var error_message = '<strong>' + 'Error!' + '</strong> ' + errorThrown ; if ( jqXHR.status ){ error_message += ' (<b>' + jqXHR.status + '</b>)'; if (403 == jqXHR.status ){ error_message += '<br> Probably nonce for this page has been expired. Please <a href="javascript:void(0)" onclick="javascript:location.reload();">reload the page</a>.'; error_message += '<br> Otherwise, please check this <a style="font-weight: 600;" href="https://wpbookingcalendar.com/faq/request-do-not-pass-security-check/?after_update=10.1.1">troubleshooting instruction</a>.<br>' } } if ( jqXHR.responseText ){ // Escape tags in Error message error_message += '<br><strong>Response</strong><div style="padding: 0 10px;margin: 0 0 10px;border-radius:3px; box-shadow:0px 0px 1px #a3a3a3;">' + jqXHR.responseText.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'") +'</div>'; } error_message = error_message.replace( /\n/g, "<br />" ); var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data ); var jq_node = '#booking_form' + calendar_id; // Show Message wpbc_front_end__show_message( error_message , { 'type' : 'error', 'show_here': {'jq_node': jq_node, 'where': 'after'}, 'is_append': true, 'style' : 'text-align:left;', 'delay' : 0 } ); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable( calendar_id ); } // </editor-fold> ) // .done( function ( data, textStatus, jqXHR ) { if ( window.console && window.console.log ){ console.log( 'second success', data, textStatus, jqXHR ); } }) // .always( function ( data_jqXHR, textStatus, jqXHR_errorThrown ) { if ( window.console && window.console.log ){ console.log( 'always finished', data_jqXHR, textStatus, jqXHR_errorThrown ); } }) ; // End Ajax return true; } // <editor-fold defaultstate="collapsed" desc=" == CAPTCHA == " > /** * Update image in captcha and show warning message * * @param params * * Example of 'params' : { * 'resource_id': response_data[ 'resource_id' ], * 'url' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'url' ], * 'challenge' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'challenge' ], * 'message' : response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) * } */ function wpbc_captcha__simple__update( params ){ document.getElementById( 'captcha_input' + params[ 'resource_id' ] ).value = ''; document.getElementById( 'captcha_img' + params[ 'resource_id' ] ).src = params[ 'url' ]; document.getElementById( 'wpdev_captcha_challenge_' + params[ 'resource_id' ] ).value = params[ 'challenge' ]; // Show warning After CAPTCHA Img var message_id = wpbc_front_end__show_message__warning( '#captcha_input' + params[ 'resource_id' ] + ' + img', params[ 'message' ] ); // Animate jQuery( '#' + message_id + ', ' + '#captcha_input' + params[ 'resource_id' ] ).fadeOut( 350 ).fadeIn( 300 ).fadeOut( 350 ).fadeIn( 400 ).animate( {opacity: 1}, 4000 ); // Focus text field jQuery( '#captcha_input' + params[ 'resource_id' ] ).trigger( 'focus' ); //FixIn: 8.7.11.12 // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable( params[ 'resource_id' ] ); } /** * If the captcha elements not exist in the booking form, then remove parameters relative captcha * @param params * @returns obj */ function wpbc_captcha__simple__maybe_remove_in_ajx_params( params ){ if ( ! wpbc_captcha__simple__is_exist_in_form( params[ 'resource_id' ] ) ){ delete params[ 'captcha_chalange' ]; delete params[ 'captcha_user_input' ]; } return params; } /** * Check if CAPTCHA exist in the booking form * @param resource_id * @returns {boolean} */ function wpbc_captcha__simple__is_exist_in_form( resource_id ){ return ( (0 !== jQuery( '#wpdev_captcha_challenge_' + resource_id ).length) || (0 !== jQuery( '#captcha_input' + resource_id ).length) ); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Send Button | Form Spin Loader == " > /** * Disable Send button | Show Spin Loader * * @param resource_id */ function wpbc_booking_form__on_submit__ui_elements_disable( resource_id ){ // Disable Submit wpbc_booking_form__send_button__disable( resource_id ); // Show Spin loader in booking form wpbc_booking_form__spin_loader__show( resource_id ); } /** * Enable Send button | Hide Spin Loader * * @param resource_id */ function wpbc_booking_form__on_response__ui_elements_enable(resource_id){ // Enable Submit wpbc_booking_form__send_button__enable( resource_id ); // Hide Spin loader in booking form wpbc_booking_form__spin_loader__hide( resource_id ); } /** * Enable Submit button * @param resource_id */ function wpbc_booking_form__send_button__enable( resource_id ){ // Activate Send button jQuery( '#booking_form_div' + resource_id + ' input[type=button]' ).prop( "disabled", false ); jQuery( '#booking_form_div' + resource_id + ' button' ).prop( "disabled", false ); } /** * Disable Submit button and show spin * * @param resource_id */ function wpbc_booking_form__send_button__disable( resource_id ){ // Disable Send button jQuery( '#booking_form_div' + resource_id + ' input[type=button]' ).prop( "disabled", true ); jQuery( '#booking_form_div' + resource_id + ' button' ).prop( "disabled", true ); } /** * Disable 'This' button * * @param _this */ function wpbc_booking_form__this_button__disable( _this ){ // Disable Send button jQuery( _this ).prop( "disabled", true ); } /** * Show booking form Spin Loader * @param resource_id */ function wpbc_booking_form__spin_loader__show( resource_id ){ // Show Spin Loader jQuery( '#booking_form' + resource_id ).after( '<div id="wpbc_booking_form_spin_loader' + resource_id + '" class="wpbc_booking_form_spin_loader" style="position: relative;"><div class="wpbc_spins_loader_wrapper"><div class="wpbc_spins_loader_mini"></div></div></div>' ); } /** * Remove / Hide booking form Spin Loader * @param resource_id */ function wpbc_booking_form__spin_loader__hide( resource_id ){ // Remove Spin Loader jQuery( '#wpbc_booking_form_spin_loader' + resource_id ).remove(); } /** * Hide booking form wth animation * * @param resource_id */ function wpbc_booking_form__animated__hide( resource_id ){ // jQuery( '#booking_form' + resource_id ).slideUp( 1000 // , function (){ // // // if ( document.getElementById( 'gateway_payment_forms' + response_data[ 'resource_id' ] ) != null ){ // // wpbc_do_scroll( '#submiting' + resource_id ); // // } else // if ( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).length > 0 ){ // //wpbc_do_scroll( '#booking_form' + resource_id + ' + .submiting_content' ); // // var hideTimeout = setTimeout(function () { // wpbc_do_scroll( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).get( 0 ) ); // }, 100); // // } // } // ); jQuery( '#booking_form' + resource_id ).hide(); // var hideTimeout = setTimeout( function (){ // // if ( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).length > 0 ){ // var random_id = Math.floor( (Math.random() * 10000) + 1 ); // jQuery( '#booking_form' + resource_id ).parent().before( '<div id="scroll_to' + random_id + '"></div>' ); // console.log( jQuery( '#scroll_to' + random_id ) ); // // wpbc_do_scroll( '#scroll_to' + random_id ); // //wpbc_do_scroll( jQuery( '#booking_form' + resource_id ).parent().get( 0 ) ); // } // }, 500 ); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Mini Spin Loader == " > /** * * @param parent_html_id */ /** * Show micro Spin Loader * * @param id ID of Loader, for later hide it by using wpbc__spin_loader__micro__hide( id ) OR wpbc__spin_loader__mini__hide( id ) * @param jq_node_where_insert such as '#estimate_booking_night_cost_hint10' OR '.estimate_booking_night_cost_hint10' */ function wpbc__spin_loader__micro__show__inside( id , jq_node_where_insert ){ wpbc__spin_loader__mini__show( id, { 'color' : '#444', 'show_here': { 'where' : 'inside', 'jq_node': jq_node_where_insert }, 'style' : 'position: relative;display: inline-flex;flex-flow: column nowrap;justify-content: center;align-items: center;margin: 7px 12px;', 'class' : 'wpbc_one_spin_loader_micro' } ); } /** * Remove spinner * @param id */ function wpbc__spin_loader__micro__hide( id ){ wpbc__spin_loader__mini__hide( id ); } /** * Show mini Spin Loader * @param parent_html_id */ function wpbc__spin_loader__mini__show( parent_html_id , params = {} ){ var params_default = { 'color' : '#0071ce', 'show_here': { 'jq_node': '', // any jQuery node definition 'where' : 'after' // 'inside' | 'before' | 'after' | 'right' | 'left' }, 'style' : 'position: relative;min-height: 2.8rem;', 'class' : 'wpbc_one_spin_loader_mini 0wpbc_spins_loader_mini' }; for ( var p_key in params ){ params_default[ p_key ] = params[ p_key ]; } params = params_default; if ( ('undefined' !== typeof (params['color'])) && ('' != params['color']) ){ params['color'] = 'border-color:' + params['color'] + ';'; } var spinner_html = '<div id="wpbc_mini_spin_loader' + parent_html_id + '" class="wpbc_booking_form_spin_loader" style="' + params[ 'style' ] + '"><div class="wpbc_spins_loader_wrapper"><div class="' + params[ 'class' ] + '" style="' + params[ 'color' ] + '"></div></div></div>'; if ( '' == params[ 'show_here' ][ 'jq_node' ] ){ params[ 'show_here' ][ 'jq_node' ] = '#' + parent_html_id; } // Show Spin Loader if ( 'after' == params[ 'show_here' ][ 'where' ] ){ jQuery( params[ 'show_here' ][ 'jq_node' ] ).after( spinner_html ); } else { jQuery( params[ 'show_here' ][ 'jq_node' ] ).html( spinner_html ); } } /** * Remove / Hide mini Spin Loader * @param parent_html_id */ function wpbc__spin_loader__mini__hide( parent_html_id ){ // Remove Spin Loader jQuery( '#wpbc_mini_spin_loader' + parent_html_id ).remove(); } // </editor-fold> //TODO: what about showing only Thank you. message without payment forms. /** * Show 'Thank you'. message and payment forms * * @param response_data */ function wpbc_show_thank_you_message_after_booking( response_data ){ if ( ('undefined' !== typeof (response_data[ 'ajx_confirmation' ][ 'ty_is_redirect' ])) && ('undefined' !== typeof (response_data[ 'ajx_confirmation' ][ 'ty_url' ])) && ('page' == response_data[ 'ajx_confirmation' ][ 'ty_is_redirect' ]) && ('' != response_data[ 'ajx_confirmation' ][ 'ty_url' ]) ){ jQuery( 'body' ).trigger( 'wpbc_booking_created', [ response_data[ 'resource_id' ] , response_data ] ); //FixIn: 10.0.0.30 window.location.href = response_data[ 'ajx_confirmation' ][ 'ty_url' ]; return; } var resource_id = response_data[ 'resource_id' ] var confirm_content =''; if ( 'undefined' === typeof (response_data[ 'ajx_confirmation' ][ 'ty_message' ]) ){ response_data[ 'ajx_confirmation' ][ 'ty_message' ] = ''; } if ( 'undefined' === typeof (response_data[ 'ajx_confirmation' ][ 'ty_payment_payment_description' ] ) ){ response_data[ 'ajx_confirmation' ][ 'ty_payment_payment_description' ] = ''; } if ( 'undefined' === typeof (response_data[ 'ajx_confirmation' ][ 'payment_cost' ] ) ){ response_data[ 'ajx_confirmation' ][ 'payment_cost' ] = ''; } if ( 'undefined' === typeof (response_data[ 'ajx_confirmation' ][ 'ty_payment_gateways' ] ) ){ response_data[ 'ajx_confirmation' ][ 'ty_payment_gateways' ] = ''; } var ty_message_hide = ('' == response_data[ 'ajx_confirmation' ][ 'ty_message' ]) ? 'wpbc_ty_hide' : ''; var ty_payment_payment_description_hide = ('' == response_data[ 'ajx_confirmation' ][ 'ty_payment_payment_description' ].replace( /\\n/g, '' )) ? 'wpbc_ty_hide' : ''; var ty_booking_costs_hide = ('' == response_data[ 'ajx_confirmation' ][ 'payment_cost' ]) ? 'wpbc_ty_hide' : ''; var ty_payment_gateways_hide = ('' == response_data[ 'ajx_confirmation' ][ 'ty_payment_gateways' ].replace( /\\n/g, '' )) ? 'wpbc_ty_hide' : ''; if ( 'wpbc_ty_hide' != ty_payment_gateways_hide ){ jQuery( '.wpbc_ty__content_text.wpbc_ty__content_gateways' ).html( '' ); // Reset all other possible gateways before showing new one. } confirm_content += `<div id="wpbc_scroll_point_${resource_id}"></div>`; confirm_content += ` <div class="wpbc_after_booking_thank_you_section">`; confirm_content += ` <div class="wpbc_ty__message ${ty_message_hide}">${response_data[ 'ajx_confirmation' ][ 'ty_message' ]}</div>`; confirm_content += ` <div class="wpbc_ty__container">`; if ( '' !== response_data[ 'ajx_confirmation' ][ 'ty_message_booking_id' ] ){ confirm_content += ` <div class="wpbc_ty__header">${response_data[ 'ajx_confirmation' ][ 'ty_message_booking_id' ]}</div>`; } confirm_content += ` <div class="wpbc_ty__content">`; confirm_content += ` <div class="wpbc_ty__content_text wpbc_ty__payment_description ${ty_payment_payment_description_hide}">${response_data[ 'ajx_confirmation' ][ 'ty_payment_payment_description' ].replace( /\\n/g, '' )}</div>`; if ( '' !== response_data[ 'ajx_confirmation' ][ 'ty_customer_details' ] ){ confirm_content += ` <div class="wpbc_ty__content_text wpbc_cols_2">${response_data['ajx_confirmation']['ty_customer_details']}</div>`; } if ( '' !== response_data[ 'ajx_confirmation' ][ 'ty_booking_details' ] ){ confirm_content += ` <div class="wpbc_ty__content_text wpbc_cols_2">${response_data['ajx_confirmation']['ty_booking_details']}</div>`; } confirm_content += ` <div class="wpbc_ty__content_text wpbc_ty__content_costs ${ty_booking_costs_hide}">${response_data[ 'ajx_confirmation' ][ 'ty_booking_costs' ]}</div>`; confirm_content += ` <div class="wpbc_ty__content_text wpbc_ty__content_gateways ${ty_payment_gateways_hide}">${response_data[ 'ajx_confirmation' ][ 'ty_payment_gateways' ].replace( /\\n/g, '' ).replace( /ajax_script/gi, 'script' )}</div>`; confirm_content += ` </div>`; confirm_content += ` </div>`; confirm_content += `</div>`; jQuery( '#booking_form' + resource_id ).after( confirm_content ); //FixIn: 10.0.0.30 // event name // Resource ID - '1' jQuery( 'body' ).trigger( 'wpbc_booking_created', [ resource_id , response_data ] ); // To catch this event: jQuery( 'body' ).on('wpbc_booking_created', function( event, resource_id, params ) { console.log( event, resource_id, params ); } ); } _out/create_booking.js 0000666 00000260041 15165546743 0011052 0 ustar 00 "use strict"; // --------------------------------------------------------------------------------------------------------------------- // A j a x A d d N e w B o o k i n g // --------------------------------------------------------------------------------------------------------------------- /** * Submit new booking * * @param params = { 'resource_id' : resource_id, 'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value, 'formdata' : formdata, 'booking_hash' : my_booking_hash, 'custom_form' : my_booking_form, 'captcha_chalange' : captcha_chalange, 'captcha_user_input' : user_captcha, 'is_emails_send' : is_send_emeils, 'active_locale' : wpdev_active_locale } * */ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function wpbc_ajx_booking__create(params) { console.groupCollapsed('WPBC_AJX_BOOKING__CREATE'); console.groupCollapsed('== Before Ajax Send =='); console.log(params); console.groupEnd(); params = wpbc_captcha__simple__maybe_remove_in_ajx_params(params); // Start Ajax jQuery.post(wpbc_url_ajax, { action: 'WPBC_AJX_BOOKING__CREATE', wpbc_ajx_user_id: _wpbc.get_secure_param('user_id'), nonce: _wpbc.get_secure_param('nonce'), wpbc_ajx_locale: _wpbc.get_secure_param('locale'), calendar_request_params: params /** * Usually params = { 'resource_id' : resource_id, * 'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value, * 'formdata' : formdata, * 'booking_hash' : my_booking_hash, * 'custom_form' : my_booking_form, * * 'captcha_chalange' : captcha_chalange, * 'user_captcha' : user_captcha, * * 'is_emails_send' : is_send_emeils, * 'active_locale' : wpdev_active_locale * } */ }, /** * S u c c e s s * * @param response_data - its object returned from Ajax - class-live-searcg.php * @param textStatus - 'success' * @param jqXHR - Object */ function (response_data, textStatus, jqXHR) { console.log(' == Response WPBC_AJX_BOOKING__CREATE == '); for (var obj_key in response_data) { console.groupCollapsed('==' + obj_key + '=='); console.log(' : ' + obj_key + ' : ', response_data[obj_key]); console.groupEnd(); } console.groupEnd(); // <editor-fold defaultstate="collapsed" desc=" = Error Message! Server response with String. -> E_X_I_T " > // ------------------------------------------------------------------------------------------------- // This section execute, when server response with String instead of Object -- Usually it's because of mistake in code ! // ------------------------------------------------------------------------------------------------- if (_typeof(response_data) !== 'object' || response_data === null) { var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url(this.data); var jq_node = '#booking_form' + calendar_id; if ('' == response_data) { response_data = '<strong>' + 'Error! Server respond with empty string!' + '</strong> '; } // Show Message wpbc_front_end__show_message(response_data, { 'type': 'error', 'show_here': { 'jq_node': jq_node, 'where': 'after' }, 'is_append': true, 'style': 'text-align:left;', 'delay': 0 }); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable(calendar_id); return; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == This section execute, when we have KNOWN errors from Booking Calendar. -> E_X_I_T " > // ------------------------------------------------------------------------------------------------- // This section execute, when we have KNOWN errors from Booking Calendar // ------------------------------------------------------------------------------------------------- if ('ok' != response_data['ajx_data']['status']) { switch (response_data['ajx_data']['status_error']) { case 'captcha_simple_wrong': wpbc_captcha__simple__update({ 'resource_id': response_data['resource_id'], 'url': response_data['ajx_data']['captcha__simple']['url'], 'challenge': response_data['ajx_data']['captcha__simple']['challenge'], 'message': response_data['ajx_data']['ajx_after_action_message'].replace(/\n/g, "<br />") }); break; case 'resource_id_incorrect': // Show Error Message - incorrect booking resource ID during submit of booking. var message_id = wpbc_front_end__show_message(response_data['ajx_data']['ajx_after_action_message'].replace(/\n/g, "<br />"), { 'type': 'undefined' !== typeof response_data['ajx_data']['ajx_after_action_message_status'] ? response_data['ajx_data']['ajx_after_action_message_status'] : 'warning', 'delay': 0, 'show_here': { 'where': 'after', 'jq_node': '#booking_form' + params['resource_id'] } }); break; case 'booking_can_not_save': // We can not save booking, because dates are booked or can not save in same booking resource all the dates var message_id = wpbc_front_end__show_message(response_data['ajx_data']['ajx_after_action_message'].replace(/\n/g, "<br />"), { 'type': 'undefined' !== typeof response_data['ajx_data']['ajx_after_action_message_status'] ? response_data['ajx_data']['ajx_after_action_message_status'] : 'warning', 'delay': 0, 'show_here': { 'where': 'after', 'jq_node': '#booking_form' + params['resource_id'] } }); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable(response_data['resource_id']); break; default: // <editor-fold defaultstate="collapsed" desc=" = For debug only ? -- Show Message under the form = " > // -------------------------------------------------------------------------------------------------------------------------------- if ('undefined' !== typeof response_data['ajx_data']['ajx_after_action_message'] && '' != response_data['ajx_data']['ajx_after_action_message'].replace(/\n/g, "<br />")) { var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url(this.data); var jq_node = '#booking_form' + calendar_id; var ajx_after_booking_message = response_data['ajx_data']['ajx_after_action_message'].replace(/\n/g, "<br />"); console.log(ajx_after_booking_message); /** * // Show Message var ajx_after_action_message_id = wpbc_front_end__show_message( ajx_after_booking_message, { 'type' : ('undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ])) ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info', 'delay' : 10000, 'show_here': { 'jq_node': jq_node, 'where' : 'after' } } ); */ } // </editor-fold> } // ------------------------------------------------------------------------------------------------- // Reactivate calendar again ? // ------------------------------------------------------------------------------------------------- // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable(response_data['resource_id']); // Unselect dates wpbc_calendar__unselect_all_dates(response_data['resource_id']); // 'resource_id' => $params['resource_id'], // 'booking_hash' => $booking_hash, // 'request_uri' => $_SERVER['REQUEST_URI'], // Is it the same as window.location.href or // 'custom_form' => $params['custom_form'], // Optional. // 'aggregate_resource_id_str' => implode( ',', $params['aggregate_resource_id_arr'] ) // Optional. Resource ID from aggregate parameter in shortcode. // Load new data in calendar. wpbc_calendar__load_data__ajx({ 'resource_id': response_data['resource_id'] // It's from response ...AJX_BOOKING__CREATE of initial sent resource_id , 'booking_hash': response_data['ajx_cleaned_params']['booking_hash'] // ?? we can not use it, because HASH chnaged in any case! , 'request_uri': response_data['ajx_cleaned_params']['request_uri'], 'custom_form': response_data['ajx_cleaned_params']['custom_form'] // Aggregate booking resources, if any ? , 'aggregate_resource_id_str': _wpbc.booking__get_param_value(response_data['resource_id'], 'aggregate_resource_id_arr').join(',') }); // Exit return; } // </editor-fold> /* // Show Calendar wpbc_calendar__loading__stop( response_data[ 'resource_id' ] ); // ------------------------------------------------------------------------------------------------- // Bookings - Dates _wpbc.bookings_in_calendar__set_dates( response_data[ 'resource_id' ], response_data[ 'ajx_data' ]['dates'] ); // Bookings - Child or only single booking resource in dates _wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'resources_id_arr__in_dates', response_data[ 'ajx_data' ][ 'resources_id_arr__in_dates' ] ); // ------------------------------------------------------------------------------------------------- // Update calendar wpbc_calendar__update_look( response_data[ 'resource_id' ] ); */ // Hide spin loader wpbc_booking_form__spin_loader__hide(response_data['resource_id']); // Hide booking form wpbc_booking_form__animated__hide(response_data['resource_id']); // Show Confirmation | Payment section wpbc_show_thank_you_message_after_booking(response_data); setTimeout(function () { wpbc_do_scroll('#wpbc_scroll_point_' + response_data['resource_id'], 10); }, 500); }).fail( // <editor-fold defaultstate="collapsed" desc=" = This section execute, when NONCE field was not passed or some error happened at server! = " > function (jqXHR, textStatus, errorThrown) { if (window.console && window.console.log) { console.log('Ajax_Error', jqXHR, textStatus, errorThrown); } // ------------------------------------------------------------------------------------------------- // This section execute, when NONCE field was not passed or some error happened at server! // ------------------------------------------------------------------------------------------------- // Get Content of Error Message var error_message = '<strong>' + 'Error!' + '</strong> ' + errorThrown; if (jqXHR.status) { error_message += ' (<b>' + jqXHR.status + '</b>)'; if (403 == jqXHR.status) { error_message += '<br> Probably nonce for this page has been expired. Please <a href="javascript:void(0)" onclick="javascript:location.reload();">reload the page</a>.'; error_message += '<br> Otherwise, please check this <a style="font-weight: 600;" href="https://wpbookingcalendar.com/faq/request-do-not-pass-security-check/?after_update=10.1.1">troubleshooting instruction</a>.<br>'; } } if (jqXHR.responseText) { // Escape tags in Error message error_message += '<br><strong>Response</strong><div style="padding: 0 10px;margin: 0 0 10px;border-radius:3px; box-shadow:0px 0px 1px #a3a3a3;">' + jqXHR.responseText.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'") + '</div>'; } error_message = error_message.replace(/\n/g, "<br />"); var calendar_id = wpbc_get_resource_id__from_ajx_post_data_url(this.data); var jq_node = '#booking_form' + calendar_id; // Show Message wpbc_front_end__show_message(error_message, { 'type': 'error', 'show_here': { 'jq_node': jq_node, 'where': 'after' }, 'is_append': true, 'style': 'text-align:left;', 'delay': 0 }); // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable(calendar_id); } // </editor-fold> ) // .done( function ( data, textStatus, jqXHR ) { if ( window.console && window.console.log ){ console.log( 'second success', data, textStatus, jqXHR ); } }) // .always( function ( data_jqXHR, textStatus, jqXHR_errorThrown ) { if ( window.console && window.console.log ){ console.log( 'always finished', data_jqXHR, textStatus, jqXHR_errorThrown ); } }) ; // End Ajax return true; } // <editor-fold defaultstate="collapsed" desc=" == CAPTCHA == " > /** * Update image in captcha and show warning message * * @param params * * Example of 'params' : { * 'resource_id': response_data[ 'resource_id' ], * 'url' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'url' ], * 'challenge' : response_data[ 'ajx_data' ][ 'captcha__simple' ][ 'challenge' ], * 'message' : response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) * } */ function wpbc_captcha__simple__update(params) { document.getElementById('captcha_input' + params['resource_id']).value = ''; document.getElementById('captcha_img' + params['resource_id']).src = params['url']; document.getElementById('wpdev_captcha_challenge_' + params['resource_id']).value = params['challenge']; // Show warning After CAPTCHA Img var message_id = wpbc_front_end__show_message__warning('#captcha_input' + params['resource_id'] + ' + img', params['message']); // Animate jQuery('#' + message_id + ', ' + '#captcha_input' + params['resource_id']).fadeOut(350).fadeIn(300).fadeOut(350).fadeIn(400).animate({ opacity: 1 }, 4000); // Focus text field jQuery('#captcha_input' + params['resource_id']).trigger('focus'); //FixIn: 8.7.11.12 // Enable Submit | Hide spin loader wpbc_booking_form__on_response__ui_elements_enable(params['resource_id']); } /** * If the captcha elements not exist in the booking form, then remove parameters relative captcha * @param params * @returns obj */ function wpbc_captcha__simple__maybe_remove_in_ajx_params(params) { if (!wpbc_captcha__simple__is_exist_in_form(params['resource_id'])) { delete params['captcha_chalange']; delete params['captcha_user_input']; } return params; } /** * Check if CAPTCHA exist in the booking form * @param resource_id * @returns {boolean} */ function wpbc_captcha__simple__is_exist_in_form(resource_id) { return 0 !== jQuery('#wpdev_captcha_challenge_' + resource_id).length || 0 !== jQuery('#captcha_input' + resource_id).length; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Send Button | Form Spin Loader == " > /** * Disable Send button | Show Spin Loader * * @param resource_id */ function wpbc_booking_form__on_submit__ui_elements_disable(resource_id) { // Disable Submit wpbc_booking_form__send_button__disable(resource_id); // Show Spin loader in booking form wpbc_booking_form__spin_loader__show(resource_id); } /** * Enable Send button | Hide Spin Loader * * @param resource_id */ function wpbc_booking_form__on_response__ui_elements_enable(resource_id) { // Enable Submit wpbc_booking_form__send_button__enable(resource_id); // Hide Spin loader in booking form wpbc_booking_form__spin_loader__hide(resource_id); } /** * Enable Submit button * @param resource_id */ function wpbc_booking_form__send_button__enable(resource_id) { // Activate Send button jQuery('#booking_form_div' + resource_id + ' input[type=button]').prop("disabled", false); jQuery('#booking_form_div' + resource_id + ' button').prop("disabled", false); } /** * Disable Submit button and show spin * * @param resource_id */ function wpbc_booking_form__send_button__disable(resource_id) { // Disable Send button jQuery('#booking_form_div' + resource_id + ' input[type=button]').prop("disabled", true); jQuery('#booking_form_div' + resource_id + ' button').prop("disabled", true); } /** * Disable 'This' button * * @param _this */ function wpbc_booking_form__this_button__disable(_this) { // Disable Send button jQuery(_this).prop("disabled", true); } /** * Show booking form Spin Loader * @param resource_id */ function wpbc_booking_form__spin_loader__show(resource_id) { // Show Spin Loader jQuery('#booking_form' + resource_id).after('<div id="wpbc_booking_form_spin_loader' + resource_id + '" class="wpbc_booking_form_spin_loader" style="position: relative;"><div class="wpbc_spins_loader_wrapper"><div class="wpbc_spins_loader_mini"></div></div></div>'); } /** * Remove / Hide booking form Spin Loader * @param resource_id */ function wpbc_booking_form__spin_loader__hide(resource_id) { // Remove Spin Loader jQuery('#wpbc_booking_form_spin_loader' + resource_id).remove(); } /** * Hide booking form wth animation * * @param resource_id */ function wpbc_booking_form__animated__hide(resource_id) { // jQuery( '#booking_form' + resource_id ).slideUp( 1000 // , function (){ // // // if ( document.getElementById( 'gateway_payment_forms' + response_data[ 'resource_id' ] ) != null ){ // // wpbc_do_scroll( '#submiting' + resource_id ); // // } else // if ( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).length > 0 ){ // //wpbc_do_scroll( '#booking_form' + resource_id + ' + .submiting_content' ); // // var hideTimeout = setTimeout(function () { // wpbc_do_scroll( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).get( 0 ) ); // }, 100); // // } // } // ); jQuery('#booking_form' + resource_id).hide(); // var hideTimeout = setTimeout( function (){ // // if ( jQuery( '#booking_form' + resource_id ).parent().find( '.submiting_content' ).length > 0 ){ // var random_id = Math.floor( (Math.random() * 10000) + 1 ); // jQuery( '#booking_form' + resource_id ).parent().before( '<div id="scroll_to' + random_id + '"></div>' ); // console.log( jQuery( '#scroll_to' + random_id ) ); // // wpbc_do_scroll( '#scroll_to' + random_id ); // //wpbc_do_scroll( jQuery( '#booking_form' + resource_id ).parent().get( 0 ) ); // } // }, 500 ); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Mini Spin Loader == " > /** * * @param parent_html_id */ /** * Show micro Spin Loader * * @param id ID of Loader, for later hide it by using wpbc__spin_loader__micro__hide( id ) OR wpbc__spin_loader__mini__hide( id ) * @param jq_node_where_insert such as '#estimate_booking_night_cost_hint10' OR '.estimate_booking_night_cost_hint10' */ function wpbc__spin_loader__micro__show__inside(id, jq_node_where_insert) { wpbc__spin_loader__mini__show(id, { 'color': '#444', 'show_here': { 'where': 'inside', 'jq_node': jq_node_where_insert }, 'style': 'position: relative;display: inline-flex;flex-flow: column nowrap;justify-content: center;align-items: center;margin: 7px 12px;', 'class': 'wpbc_one_spin_loader_micro' }); } /** * Remove spinner * @param id */ function wpbc__spin_loader__micro__hide(id) { wpbc__spin_loader__mini__hide(id); } /** * Show mini Spin Loader * @param parent_html_id */ function wpbc__spin_loader__mini__show(parent_html_id) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var params_default = { 'color': '#0071ce', 'show_here': { 'jq_node': '', // any jQuery node definition 'where': 'after' // 'inside' | 'before' | 'after' | 'right' | 'left' }, 'style': 'position: relative;min-height: 2.8rem;', 'class': 'wpbc_one_spin_loader_mini 0wpbc_spins_loader_mini' }; for (var p_key in params) { params_default[p_key] = params[p_key]; } params = params_default; if ('undefined' !== typeof params['color'] && '' != params['color']) { params['color'] = 'border-color:' + params['color'] + ';'; } var spinner_html = '<div id="wpbc_mini_spin_loader' + parent_html_id + '" class="wpbc_booking_form_spin_loader" style="' + params['style'] + '"><div class="wpbc_spins_loader_wrapper"><div class="' + params['class'] + '" style="' + params['color'] + '"></div></div></div>'; if ('' == params['show_here']['jq_node']) { params['show_here']['jq_node'] = '#' + parent_html_id; } // Show Spin Loader if ('after' == params['show_here']['where']) { jQuery(params['show_here']['jq_node']).after(spinner_html); } else { jQuery(params['show_here']['jq_node']).html(spinner_html); } } /** * Remove / Hide mini Spin Loader * @param parent_html_id */ function wpbc__spin_loader__mini__hide(parent_html_id) { // Remove Spin Loader jQuery('#wpbc_mini_spin_loader' + parent_html_id).remove(); } // </editor-fold> //TODO: what about showing only Thank you. message without payment forms. /** * Show 'Thank you'. message and payment forms * * @param response_data */ function wpbc_show_thank_you_message_after_booking(response_data) { if ('undefined' !== typeof response_data['ajx_confirmation']['ty_is_redirect'] && 'undefined' !== typeof response_data['ajx_confirmation']['ty_url'] && 'page' == response_data['ajx_confirmation']['ty_is_redirect'] && '' != response_data['ajx_confirmation']['ty_url']) { jQuery('body').trigger('wpbc_booking_created', [response_data['resource_id'], response_data]); //FixIn: 10.0.0.30 window.location.href = response_data['ajx_confirmation']['ty_url']; return; } var resource_id = response_data['resource_id']; var confirm_content = ''; if ('undefined' === typeof response_data['ajx_confirmation']['ty_message']) { response_data['ajx_confirmation']['ty_message'] = ''; } if ('undefined' === typeof response_data['ajx_confirmation']['ty_payment_payment_description']) { response_data['ajx_confirmation']['ty_payment_payment_description'] = ''; } if ('undefined' === typeof response_data['ajx_confirmation']['payment_cost']) { response_data['ajx_confirmation']['payment_cost'] = ''; } if ('undefined' === typeof response_data['ajx_confirmation']['ty_payment_gateways']) { response_data['ajx_confirmation']['ty_payment_gateways'] = ''; } var ty_message_hide = '' == response_data['ajx_confirmation']['ty_message'] ? 'wpbc_ty_hide' : ''; var ty_payment_payment_description_hide = '' == response_data['ajx_confirmation']['ty_payment_payment_description'].replace(/\\n/g, '') ? 'wpbc_ty_hide' : ''; var ty_booking_costs_hide = '' == response_data['ajx_confirmation']['payment_cost'] ? 'wpbc_ty_hide' : ''; var ty_payment_gateways_hide = '' == response_data['ajx_confirmation']['ty_payment_gateways'].replace(/\\n/g, '') ? 'wpbc_ty_hide' : ''; if ('wpbc_ty_hide' != ty_payment_gateways_hide) { jQuery('.wpbc_ty__content_text.wpbc_ty__content_gateways').html(''); // Reset all other possible gateways before showing new one. } confirm_content += "<div id=\"wpbc_scroll_point_".concat(resource_id, "\"></div>"); confirm_content += " <div class=\"wpbc_after_booking_thank_you_section\">"; confirm_content += " <div class=\"wpbc_ty__message ".concat(ty_message_hide, "\">").concat(response_data['ajx_confirmation']['ty_message'], "</div>"); confirm_content += " <div class=\"wpbc_ty__container\">"; if ('' !== response_data['ajx_confirmation']['ty_message_booking_id']) { confirm_content += " <div class=\"wpbc_ty__header\">".concat(response_data['ajx_confirmation']['ty_message_booking_id'], "</div>"); } confirm_content += " <div class=\"wpbc_ty__content\">"; confirm_content += " <div class=\"wpbc_ty__content_text wpbc_ty__payment_description ".concat(ty_payment_payment_description_hide, "\">").concat(response_data['ajx_confirmation']['ty_payment_payment_description'].replace(/\\n/g, ''), "</div>"); if ('' !== response_data['ajx_confirmation']['ty_customer_details']) { confirm_content += " \t<div class=\"wpbc_ty__content_text wpbc_cols_2\">".concat(response_data['ajx_confirmation']['ty_customer_details'], "</div>"); } if ('' !== response_data['ajx_confirmation']['ty_booking_details']) { confirm_content += " \t<div class=\"wpbc_ty__content_text wpbc_cols_2\">".concat(response_data['ajx_confirmation']['ty_booking_details'], "</div>"); } confirm_content += " <div class=\"wpbc_ty__content_text wpbc_ty__content_costs ".concat(ty_booking_costs_hide, "\">").concat(response_data['ajx_confirmation']['ty_booking_costs'], "</div>"); confirm_content += " <div class=\"wpbc_ty__content_text wpbc_ty__content_gateways ".concat(ty_payment_gateways_hide, "\">").concat(response_data['ajx_confirmation']['ty_payment_gateways'].replace(/\\n/g, '').replace(/ajax_script/gi, 'script'), "</div>"); confirm_content += " </div>"; confirm_content += " </div>"; confirm_content += "</div>"; jQuery('#booking_form' + resource_id).after(confirm_content); //FixIn: 10.0.0.30 // event name // Resource ID - '1' jQuery('body').trigger('wpbc_booking_created', [resource_id, response_data]); // To catch this event: jQuery( 'body' ).on('wpbc_booking_created', function( event, resource_id, params ) { console.log( event, resource_id, params ); } ); } //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5jbHVkZXMvX2NhcGFjaXR5L19vdXQvY3JlYXRlX2Jvb2tpbmcuanMiLCJuYW1lcyI6WyJfdHlwZW9mIiwib2JqIiwiU3ltYm9sIiwiaXRlcmF0b3IiLCJjb25zdHJ1Y3RvciIsInByb3RvdHlwZSIsIndwYmNfYWp4X2Jvb2tpbmdfX2NyZWF0ZSIsInBhcmFtcyIsImNvbnNvbGUiLCJncm91cENvbGxhcHNlZCIsImxvZyIsImdyb3VwRW5kIiwid3BiY19jYXB0Y2hhX19zaW1wbGVfX21heWJlX3JlbW92ZV9pbl9hanhfcGFyYW1zIiwialF1ZXJ5IiwicG9zdCIsIndwYmNfdXJsX2FqYXgiLCJhY3Rpb24iLCJ3cGJjX2FqeF91c2VyX2lkIiwiX3dwYmMiLCJnZXRfc2VjdXJlX3BhcmFtIiwibm9uY2UiLCJ3cGJjX2FqeF9sb2NhbGUiLCJjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyIsInJlc3BvbnNlX2RhdGEiLCJ0ZXh0U3RhdHVzIiwianFYSFIiLCJvYmpfa2V5IiwiY2FsZW5kYXJfaWQiLCJ3cGJjX2dldF9yZXNvdXJjZV9pZF9fZnJvbV9hanhfcG9zdF9kYXRhX3VybCIsImRhdGEiLCJqcV9ub2RlIiwid3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZSIsIndwYmNfYm9va2luZ19mb3JtX19vbl9yZXNwb25zZV9fdWlfZWxlbWVudHNfZW5hYmxlIiwid3BiY19jYXB0Y2hhX19zaW1wbGVfX3VwZGF0ZSIsInJlcGxhY2UiLCJtZXNzYWdlX2lkIiwiYWp4X2FmdGVyX2Jvb2tpbmdfbWVzc2FnZSIsIndwYmNfY2FsZW5kYXJfX3Vuc2VsZWN0X2FsbF9kYXRlcyIsIndwYmNfY2FsZW5kYXJfX2xvYWRfZGF0YV9fYWp4IiwiYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlIiwiam9pbiIsIndwYmNfYm9va2luZ19mb3JtX19zcGluX2xvYWRlcl9faGlkZSIsIndwYmNfYm9va2luZ19mb3JtX19hbmltYXRlZF9faGlkZSIsIndwYmNfc2hvd190aGFua195b3VfbWVzc2FnZV9hZnRlcl9ib29raW5nIiwic2V0VGltZW91dCIsIndwYmNfZG9fc2Nyb2xsIiwiZmFpbCIsImVycm9yVGhyb3duIiwid2luZG93IiwiZXJyb3JfbWVzc2FnZSIsInN0YXR1cyIsInJlc3BvbnNlVGV4dCIsImRvY3VtZW50IiwiZ2V0RWxlbWVudEJ5SWQiLCJ2YWx1ZSIsInNyYyIsIndwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmciLCJmYWRlT3V0IiwiZmFkZUluIiwiYW5pbWF0ZSIsIm9wYWNpdHkiLCJ0cmlnZ2VyIiwid3BiY19jYXB0Y2hhX19zaW1wbGVfX2lzX2V4aXN0X2luX2Zvcm0iLCJyZXNvdXJjZV9pZCIsImxlbmd0aCIsIndwYmNfYm9va2luZ19mb3JtX19vbl9zdWJtaXRfX3VpX2VsZW1lbnRzX2Rpc2FibGUiLCJ3cGJjX2Jvb2tpbmdfZm9ybV9fc2VuZF9idXR0b25fX2Rpc2FibGUiLCJ3cGJjX2Jvb2tpbmdfZm9ybV9fc3Bpbl9sb2FkZXJfX3Nob3ciLCJ3cGJjX2Jvb2tpbmdfZm9ybV9fc2VuZF9idXR0b25fX2VuYWJsZSIsInByb3AiLCJ3cGJjX2Jvb2tpbmdfZm9ybV9fdGhpc19idXR0b25fX2Rpc2FibGUiLCJfdGhpcyIsImFmdGVyIiwicmVtb3ZlIiwiaGlkZSIsIndwYmNfX3NwaW5fbG9hZGVyX19taWNyb19fc2hvd19faW5zaWRlIiwiaWQiLCJqcV9ub2RlX3doZXJlX2luc2VydCIsIndwYmNfX3NwaW5fbG9hZGVyX19taW5pX19zaG93Iiwid3BiY19fc3Bpbl9sb2FkZXJfX21pY3JvX19oaWRlIiwid3BiY19fc3Bpbl9sb2FkZXJfX21pbmlfX2hpZGUiLCJwYXJlbnRfaHRtbF9pZCIsImFyZ3VtZW50cyIsInVuZGVmaW5lZCIsInBhcmFtc19kZWZhdWx0IiwicF9rZXkiLCJzcGlubmVyX2h0bWwiLCJodG1sIiwibG9jYXRpb24iLCJocmVmIiwiY29uZmlybV9jb250ZW50IiwidHlfbWVzc2FnZV9oaWRlIiwidHlfcGF5bWVudF9wYXltZW50X2Rlc2NyaXB0aW9uX2hpZGUiLCJ0eV9ib29raW5nX2Nvc3RzX2hpZGUiLCJ0eV9wYXltZW50X2dhdGV3YXlzX2hpZGUiLCJjb25jYXQiXSwic291cmNlcyI6WyJpbmNsdWRlcy9fY2FwYWNpdHkvX3NyYy9jcmVhdGVfYm9va2luZy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcInVzZSBzdHJpY3RcIjtcclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyAgQSBqIGEgeCAgICBBIGQgZCAgICBOIGUgdyAgICBCIG8gbyBrIGkgbiBnXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHJcbi8qKlxyXG4gKiBTdWJtaXQgbmV3IGJvb2tpbmdcclxuICpcclxuICogQHBhcmFtIHBhcmFtcyAgID0gICAgIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncmVzb3VyY2VfaWQnICAgICAgICA6IHJlc291cmNlX2lkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkYXRlc19kZG1teXlfY3N2JyAgIDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS52YWx1ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnZm9ybWRhdGEnICAgICAgICAgICA6IGZvcm1kYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdib29raW5nX2hhc2gnICAgICAgIDogbXlfYm9va2luZ19oYXNoLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdjdXN0b21fZm9ybScgICAgICAgIDogbXlfYm9va2luZ19mb3JtLFxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnY2FwdGNoYV9jaGFsYW5nZScgICA6IGNhcHRjaGFfY2hhbGFuZ2UsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2NhcHRjaGFfdXNlcl9pbnB1dCcgOiB1c2VyX2NhcHRjaGEsXHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdpc19lbWFpbHNfc2VuZCcgICAgIDogaXNfc2VuZF9lbWVpbHMsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2FjdGl2ZV9sb2NhbGUnICAgICAgOiB3cGRldl9hY3RpdmVfbG9jYWxlXHJcblx0XHRcdFx0XHRcdH1cclxuICpcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWp4X2Jvb2tpbmdfX2NyZWF0ZSggcGFyYW1zICl7XHJcblxyXG5jb25zb2xlLmdyb3VwQ29sbGFwc2VkKCAnV1BCQ19BSlhfQk9PS0lOR19fQ1JFQVRFJyApO1xyXG5jb25zb2xlLmdyb3VwQ29sbGFwc2VkKCAnPT0gQmVmb3JlIEFqYXggU2VuZCA9PScgKTtcclxuY29uc29sZS5sb2coIHBhcmFtcyApO1xyXG5jb25zb2xlLmdyb3VwRW5kKCk7XHJcblxyXG5cdHBhcmFtcyA9IHdwYmNfY2FwdGNoYV9fc2ltcGxlX19tYXliZV9yZW1vdmVfaW5fYWp4X3BhcmFtcyggcGFyYW1zICk7XHJcblxyXG5cdC8vIFN0YXJ0IEFqYXhcclxuXHRqUXVlcnkucG9zdCggd3BiY191cmxfYWpheCxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHRhY3Rpb24gICAgICAgICAgOiAnV1BCQ19BSlhfQk9PS0lOR19fQ1JFQVRFJyxcclxuXHRcdFx0XHRcdHdwYmNfYWp4X3VzZXJfaWQ6IF93cGJjLmdldF9zZWN1cmVfcGFyYW0oICd1c2VyX2lkJyApLFxyXG5cdFx0XHRcdFx0bm9uY2UgICAgICAgICAgIDogX3dwYmMuZ2V0X3NlY3VyZV9wYXJhbSggJ25vbmNlJyApLFxyXG5cdFx0XHRcdFx0d3BiY19hanhfbG9jYWxlIDogX3dwYmMuZ2V0X3NlY3VyZV9wYXJhbSggJ2xvY2FsZScgKSxcclxuXHJcblx0XHRcdFx0XHRjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyA6IHBhcmFtc1xyXG5cclxuXHRcdFx0XHRcdC8qKlxyXG5cdFx0XHRcdFx0ICogIFVzdWFsbHkgIHBhcmFtcyA9IHsgJ3Jlc291cmNlX2lkJyAgICAgICAgOiByZXNvdXJjZV9pZCxcclxuXHRcdFx0XHRcdCAqXHRcdFx0XHRcdFx0J2RhdGVzX2RkbW15eV9jc3YnICAgOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnZhbHVlLFxyXG5cdFx0XHRcdFx0ICpcdFx0XHRcdFx0XHQnZm9ybWRhdGEnICAgICAgICAgICA6IGZvcm1kYXRhLFxyXG5cdFx0XHRcdFx0ICpcdFx0XHRcdFx0XHQnYm9va2luZ19oYXNoJyAgICAgICA6IG15X2Jvb2tpbmdfaGFzaCxcclxuXHRcdFx0XHRcdCAqXHRcdFx0XHRcdFx0J2N1c3RvbV9mb3JtJyAgICAgICAgOiBteV9ib29raW5nX2Zvcm0sXHJcblx0XHRcdFx0XHQgKlxyXG5cdFx0XHRcdFx0ICpcdFx0XHRcdFx0XHQnY2FwdGNoYV9jaGFsYW5nZScgICA6IGNhcHRjaGFfY2hhbGFuZ2UsXHJcblx0XHRcdFx0XHQgKlx0XHRcdFx0XHRcdCd1c2VyX2NhcHRjaGEnICAgICAgIDogdXNlcl9jYXB0Y2hhLFxyXG5cdFx0XHRcdFx0ICpcclxuXHRcdFx0XHRcdCAqXHRcdFx0XHRcdFx0J2lzX2VtYWlsc19zZW5kJyAgICAgOiBpc19zZW5kX2VtZWlscyxcclxuXHRcdFx0XHRcdCAqXHRcdFx0XHRcdFx0J2FjdGl2ZV9sb2NhbGUnICAgICAgOiB3cGRldl9hY3RpdmVfbG9jYWxlXHJcblx0XHRcdFx0XHQgKlx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0ICovXHJcblx0XHRcdFx0fSxcclxuXHJcblx0XHRcdFx0LyoqXHJcblx0XHRcdFx0ICogUyB1IGMgYyBlIHMgc1xyXG5cdFx0XHRcdCAqXHJcblx0XHRcdFx0ICogQHBhcmFtIHJlc3BvbnNlX2RhdGFcdFx0LVx0aXRzIG9iamVjdCByZXR1cm5lZCBmcm9tICBBamF4IC0gY2xhc3MtbGl2ZS1zZWFyY2cucGhwXHJcblx0XHRcdFx0ICogQHBhcmFtIHRleHRTdGF0dXNcdFx0LVx0J3N1Y2Nlc3MnXHJcblx0XHRcdFx0ICogQHBhcmFtIGpxWEhSXHRcdFx0XHQtXHRPYmplY3RcclxuXHRcdFx0XHQgKi9cclxuXHRcdFx0XHRmdW5jdGlvbiAoIHJlc3BvbnNlX2RhdGEsIHRleHRTdGF0dXMsIGpxWEhSICkge1xyXG5jb25zb2xlLmxvZyggJyA9PSBSZXNwb25zZSBXUEJDX0FKWF9CT09LSU5HX19DUkVBVEUgPT0gJyApO1xyXG5mb3IgKCB2YXIgb2JqX2tleSBpbiByZXNwb25zZV9kYXRhICl7XHJcblx0Y29uc29sZS5ncm91cENvbGxhcHNlZCggJz09JyArIG9ial9rZXkgKyAnPT0nICk7XHJcblx0Y29uc29sZS5sb2coICcgOiAnICsgb2JqX2tleSArICcgOiAnLCByZXNwb25zZV9kYXRhWyBvYmpfa2V5IF0gKTtcclxuXHRjb25zb2xlLmdyb3VwRW5kKCk7XHJcbn1cclxuY29uc29sZS5ncm91cEVuZCgpO1xyXG5cclxuXHJcblx0XHRcdFx0XHQvLyA8ZWRpdG9yLWZvbGQgICAgIGRlZmF1bHRzdGF0ZT1cImNvbGxhcHNlZFwiICAgICBkZXNjPVwiID0gRXJyb3IgTWVzc2FnZSEgU2VydmVyIHJlc3BvbnNlIHdpdGggU3RyaW5nLiAgLT4gIEVfWF9JX1QgIFwiICA+XHJcblx0XHRcdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdFx0XHQvLyBUaGlzIHNlY3Rpb24gZXhlY3V0ZSwgIHdoZW4gc2VydmVyIHJlc3BvbnNlIHdpdGggIFN0cmluZyBpbnN0ZWFkIG9mIE9iamVjdCAtLSBVc3VhbGx5ICBpdCdzIGJlY2F1c2Ugb2YgbWlzdGFrZSBpbiBjb2RlICFcclxuXHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0XHRcdGlmICggKHR5cGVvZiByZXNwb25zZV9kYXRhICE9PSAnb2JqZWN0JykgfHwgKHJlc3BvbnNlX2RhdGEgPT09IG51bGwpICl7XHJcblxyXG5cdFx0XHRcdFx0XHR2YXIgY2FsZW5kYXJfaWQgPSB3cGJjX2dldF9yZXNvdXJjZV9pZF9fZnJvbV9hanhfcG9zdF9kYXRhX3VybCggdGhpcy5kYXRhICk7XHJcblx0XHRcdFx0XHRcdHZhciBqcV9ub2RlID0gJyNib29raW5nX2Zvcm0nICsgY2FsZW5kYXJfaWQ7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoICcnID09IHJlc3BvbnNlX2RhdGEgKXtcclxuXHRcdFx0XHRcdFx0XHRyZXNwb25zZV9kYXRhID0gJzxzdHJvbmc+JyArICdFcnJvciEgU2VydmVyIHJlc3BvbmQgd2l0aCBlbXB0eSBzdHJpbmchJyArICc8L3N0cm9uZz4gJyA7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0Ly8gU2hvdyBNZXNzYWdlXHJcblx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIHJlc3BvbnNlX2RhdGEgLCB7ICd0eXBlJyAgICAgOiAnZXJyb3InLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJzogeydqcV9ub2RlJzoganFfbm9kZSwgJ3doZXJlJzogJ2FmdGVyJ30sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdpc19hcHBlbmQnOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fSApO1xyXG5cdFx0XHRcdFx0XHQvLyBFbmFibGUgU3VibWl0IHwgSGlkZSBzcGluIGxvYWRlclxyXG5cdFx0XHRcdFx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fb25fcmVzcG9uc2VfX3VpX2VsZW1lbnRzX2VuYWJsZSggY2FsZW5kYXJfaWQgKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0Ly8gPC9lZGl0b3ItZm9sZD5cclxuXHJcblxyXG5cdFx0XHRcdFx0Ly8gPGVkaXRvci1mb2xkICAgICBkZWZhdWx0c3RhdGU9XCJjb2xsYXBzZWRcIiAgICAgZGVzYz1cIiAgPT0gIFRoaXMgc2VjdGlvbiBleGVjdXRlLCAgd2hlbiB3ZSBoYXZlIEtOT1dOIGVycm9ycyBmcm9tIEJvb2tpbmcgQ2FsZW5kYXIuICAtPiAgRV9YX0lfVCAgXCIgID5cclxuXHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0XHRcdC8vIFRoaXMgc2VjdGlvbiBleGVjdXRlLCAgd2hlbiB3ZSBoYXZlIEtOT1dOIGVycm9ycyBmcm9tIEJvb2tpbmcgQ2FsZW5kYXJcclxuXHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0XHRcdFx0XHRpZiAoICdvaycgIT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnc3RhdHVzJyBdICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3dpdGNoICggcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnc3RhdHVzX2Vycm9yJyBdICl7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNhc2UgJ2NhcHRjaGFfc2ltcGxlX3dyb25nJzpcclxuXHRcdFx0XHRcdFx0XHRcdHdwYmNfY2FwdGNoYV9fc2ltcGxlX191cGRhdGUoIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQncmVzb3VyY2VfaWQnOiByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3VybCcgICAgICAgIDogcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnY2FwdGNoYV9fc2ltcGxlJyBdWyAndXJsJyBdLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdjaGFsbGVuZ2UnICA6IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2NhcHRjaGFfX3NpbXBsZScgXVsgJ2NoYWxsZW5nZScgXSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbWVzc2FnZScgICAgOiByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2UnIF0ucmVwbGFjZSggL1xcbi9nLCBcIjxiciAvPlwiIClcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjYXNlICdyZXNvdXJjZV9pZF9pbmNvcnJlY3QnOlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gU2hvdyBFcnJvciBNZXNzYWdlIC0gaW5jb3JyZWN0ICBib29raW5nIHJlc291cmNlIElEIGR1cmluZyBzdWJtaXQgb2YgYm9va2luZy5cclxuXHRcdFx0XHRcdFx0XHRcdHZhciBtZXNzYWdlX2lkID0gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZSggcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlJyBdLnJlcGxhY2UoIC9cXG4vZywgXCI8YnIgLz5cIiApLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyA6ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChyZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdKSlcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ/IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9zdGF0dXMnIF0gOiAnd2FybmluZycsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMCxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7ICd3aGVyZSc6ICdhZnRlcicsICdqcV9ub2RlJzogJyNib29raW5nX2Zvcm0nICsgcGFyYW1zWyAncmVzb3VyY2VfaWQnIF0gfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjYXNlICdib29raW5nX2Nhbl9ub3Rfc2F2ZSc6XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBXZSBjYW4gbm90IHNhdmUgYm9va2luZywgYmVjYXVzZSBkYXRlcyBhcmUgYm9va2VkIG9yIGNhbiBub3Qgc2F2ZSBpbiBzYW1lIGJvb2tpbmcgcmVzb3VyY2UgYWxsIHRoZSBkYXRlc1xyXG5cdFx0XHRcdFx0XHRcdFx0dmFyIG1lc3NhZ2VfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2UnIF0ucmVwbGFjZSggL1xcbi9nLCBcIjxiciAvPlwiICksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3R5cGUnIDogKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgKHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9zdGF0dXMnIF0pKVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdD8gcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlX3N0YXR1cycgXSA6ICd3YXJuaW5nJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgOiAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZSc6IHsgJ3doZXJlJzogJ2FmdGVyJywgJ2pxX25vZGUnOiAnI2Jvb2tpbmdfZm9ybScgKyBwYXJhbXNbICdyZXNvdXJjZV9pZCcgXSB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIEVuYWJsZSBTdWJtaXQgfCBIaWRlIHNwaW4gbG9hZGVyXHJcblx0XHRcdFx0XHRcdFx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fb25fcmVzcG9uc2VfX3VpX2VsZW1lbnRzX2VuYWJsZSggcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cclxuXHRcdFx0XHRcdFx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIDxlZGl0b3ItZm9sZCAgICAgZGVmYXVsdHN0YXRlPVwiY29sbGFwc2VkXCIgICAgICAgICAgICAgICAgICAgICAgICBkZXNjPVwiID0gRm9yIGRlYnVnIG9ubHkgPyAtLSAgU2hvdyBNZXNzYWdlIHVuZGVyIHRoZSBmb3JtID0gXCIgID5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0KCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChyZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2UnIF0pIClcclxuXHRcdFx0XHRcdFx0XHRcdFx0ICYmICggJycgIT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlJyBdLnJlcGxhY2UoIC9cXG4vZywgXCI8YnIgLz5cIiApIClcclxuXHRcdFx0XHRcdFx0XHRcdCl7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHR2YXIgY2FsZW5kYXJfaWQgPSB3cGJjX2dldF9yZXNvdXJjZV9pZF9fZnJvbV9hanhfcG9zdF9kYXRhX3VybCggdGhpcy5kYXRhICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdHZhciBqcV9ub2RlID0gJyNib29raW5nX2Zvcm0nICsgY2FsZW5kYXJfaWQ7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHR2YXIgYWp4X2FmdGVyX2Jvb2tpbmdfbWVzc2FnZSA9IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZScgXS5yZXBsYWNlKCAvXFxuL2csIFwiPGJyIC8+XCIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUubG9nKCBhanhfYWZ0ZXJfYm9va2luZ19tZXNzYWdlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHQvKipcclxuXHRcdFx0XHRcdFx0XHRcdFx0ICogLy8gU2hvdyBNZXNzYWdlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0dmFyIGFqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIGFqeF9hZnRlcl9ib29raW5nX21lc3NhZ2UsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyA6ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChyZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdKSlcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdD8gcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlX3N0YXR1cycgXSA6ICdpbmZvJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDEwMDAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJzoge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcV9ub2RlJzoganFfbm9kZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdhZnRlcidcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0ICovXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHQvLyA8L2VkaXRvci1mb2xkPlxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHRcdFx0XHQvLyBSZWFjdGl2YXRlIGNhbGVuZGFyIGFnYWluID9cclxuXHRcdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHRcdFx0XHQvLyBFbmFibGUgU3VibWl0IHwgSGlkZSBzcGluIGxvYWRlclxyXG5cdFx0XHRcdFx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fb25fcmVzcG9uc2VfX3VpX2VsZW1lbnRzX2VuYWJsZSggcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBVbnNlbGVjdCAgZGF0ZXNcclxuXHRcdFx0XHRcdFx0d3BiY19jYWxlbmRhcl9fdW5zZWxlY3RfYWxsX2RhdGVzKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdC8vICdyZXNvdXJjZV9pZCcgICAgPT4gJHBhcmFtc1sncmVzb3VyY2VfaWQnXSxcclxuXHRcdFx0XHRcdFx0Ly8gJ2Jvb2tpbmdfaGFzaCcgICA9PiAkYm9va2luZ19oYXNoLFxyXG5cdFx0XHRcdFx0XHQvLyAncmVxdWVzdF91cmknICAgID0+ICRfU0VSVkVSWydSRVFVRVNUX1VSSSddLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSXMgaXQgdGhlIHNhbWUgYXMgd2luZG93LmxvY2F0aW9uLmhyZWYgb3JcclxuXHRcdFx0XHRcdFx0Ly8gJ2N1c3RvbV9mb3JtJyAgICA9PiAkcGFyYW1zWydjdXN0b21fZm9ybSddLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9wdGlvbmFsLlxyXG5cdFx0XHRcdFx0XHQvLyAnYWdncmVnYXRlX3Jlc291cmNlX2lkX3N0cicgPT4gaW1wbG9kZSggJywnLCAkcGFyYW1zWydhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJ10gKSAgICAgLy8gT3B0aW9uYWwuIFJlc291cmNlIElEICAgZnJvbSAgYWdncmVnYXRlIHBhcmFtZXRlciBpbiBzaG9ydGNvZGUuXHJcblxyXG5cdFx0XHRcdFx0XHQvLyBMb2FkIG5ldyBkYXRhIGluIGNhbGVuZGFyLlxyXG5cdFx0XHRcdFx0XHR3cGJjX2NhbGVuZGFyX19sb2FkX2RhdGFfX2FqeCgge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAncmVzb3VyY2VfaWQnIDogcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdXHRcdFx0XHRcdFx0XHQvLyBJdCdzIGZyb20gcmVzcG9uc2UgLi4uQUpYX0JPT0tJTkdfX0NSRUFURSBvZiBpbml0aWFsIHNlbnQgcmVzb3VyY2VfaWRcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCwgJ2Jvb2tpbmdfaGFzaCc6IHJlc3BvbnNlX2RhdGFbICdhanhfY2xlYW5lZF9wYXJhbXMnIF1bJ2Jvb2tpbmdfaGFzaCddIFx0Ly8gPz8gd2UgY2FuIG5vdCB1c2UgaXQsICBiZWNhdXNlIEhBU0ggY2huYWdlZCBpbiBhbnkgIGNhc2UhXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQsICdyZXF1ZXN0X3VyaScgOiByZXNwb25zZV9kYXRhWyAnYWp4X2NsZWFuZWRfcGFyYW1zJyBdWydyZXF1ZXN0X3VyaSddXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQsICdjdXN0b21fZm9ybScgOiByZXNwb25zZV9kYXRhWyAnYWp4X2NsZWFuZWRfcGFyYW1zJyBdWydjdXN0b21fZm9ybSddXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gQWdncmVnYXRlIGJvb2tpbmcgcmVzb3VyY2VzLCAgaWYgYW55ID9cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCwgJ2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9zdHInIDogX3dwYmMuYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0sICdhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJyApLmpvaW4oJywnKVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0XHRcdC8vIEV4aXRcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIDwvZWRpdG9yLWZvbGQ+XHJcblxyXG5cclxuLypcclxuXHQvLyBTaG93IENhbGVuZGFyXHJcblx0d3BiY19jYWxlbmRhcl9fbG9hZGluZ19fc3RvcCggcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdICk7XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBCb29raW5ncyAtIERhdGVzXHJcblx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldF9kYXRlcyggIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSwgcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWydkYXRlcyddICApO1xyXG5cclxuXHQvLyBCb29raW5ncyAtIENoaWxkIG9yIG9ubHkgc2luZ2xlIGJvb2tpbmcgcmVzb3VyY2UgaW4gZGF0ZXNcclxuXHRfd3BiYy5ib29raW5nX19zZXRfcGFyYW1fdmFsdWUoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSwgJ3Jlc291cmNlc19pZF9hcnJfX2luX2RhdGVzJywgcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAncmVzb3VyY2VzX2lkX2Fycl9faW5fZGF0ZXMnIF0gKTtcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cdC8vIFVwZGF0ZSBjYWxlbmRhclxyXG5cdHdwYmNfY2FsZW5kYXJfX3VwZGF0ZV9sb29rKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0gKTtcclxuKi9cclxuXHJcblx0XHRcdFx0XHQvLyBIaWRlIHNwaW4gbG9hZGVyXHJcblx0XHRcdFx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fc3Bpbl9sb2FkZXJfX2hpZGUoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSApO1xyXG5cclxuXHRcdFx0XHRcdC8vIEhpZGUgYm9va2luZyBmb3JtXHJcblx0XHRcdFx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fYW5pbWF0ZWRfX2hpZGUoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSApO1xyXG5cclxuXHRcdFx0XHRcdC8vIFNob3cgQ29uZmlybWF0aW9uIHwgUGF5bWVudCBzZWN0aW9uXHJcblx0XHRcdFx0XHR3cGJjX3Nob3dfdGhhbmtfeW91X21lc3NhZ2VfYWZ0ZXJfYm9va2luZyggcmVzcG9uc2VfZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0XHRcdFx0XHR3cGJjX2RvX3Njcm9sbCggJyN3cGJjX3Njcm9sbF9wb2ludF8nICsgcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdLCAxMCApO1xyXG5cdFx0XHRcdFx0fSwgNTAwICk7XHJcblxyXG5cclxuXHJcblx0XHRcdFx0fVxyXG5cdFx0XHQgICkuZmFpbChcclxuXHRcdFx0XHQgIC8vIDxlZGl0b3ItZm9sZCAgICAgZGVmYXVsdHN0YXRlPVwiY29sbGFwc2VkXCIgICAgICAgICAgICAgICAgICAgICAgICBkZXNjPVwiID0gVGhpcyBzZWN0aW9uIGV4ZWN1dGUsICB3aGVuICBOT05DRSBmaWVsZCB3YXMgbm90IHBhc3NlZCBvciBzb21lIGVycm9yIGhhcHBlbmVkIGF0ICBzZXJ2ZXIhID0gXCIgID5cclxuXHRcdFx0XHQgIGZ1bmN0aW9uICgganFYSFIsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duICkgeyAgICBpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLmxvZyApeyBjb25zb2xlLmxvZyggJ0FqYXhfRXJyb3InLCBqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24gKTsgfVxyXG5cclxuXHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0XHRcdC8vIFRoaXMgc2VjdGlvbiBleGVjdXRlLCAgd2hlbiAgTk9OQ0UgZmllbGQgd2FzIG5vdCBwYXNzZWQgb3Igc29tZSBlcnJvciBoYXBwZW5lZCBhdCAgc2VydmVyIVxyXG5cdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHRcdFx0XHRcdC8vIEdldCBDb250ZW50IG9mIEVycm9yIE1lc3NhZ2VcclxuXHRcdFx0XHRcdHZhciBlcnJvcl9tZXNzYWdlID0gJzxzdHJvbmc+JyArICdFcnJvciEnICsgJzwvc3Ryb25nPiAnICsgZXJyb3JUaHJvd24gO1xyXG5cdFx0XHRcdFx0aWYgKCBqcVhIUi5zdGF0dXMgKXtcclxuXHRcdFx0XHRcdFx0ZXJyb3JfbWVzc2FnZSArPSAnICg8Yj4nICsganFYSFIuc3RhdHVzICsgJzwvYj4pJztcclxuXHRcdFx0XHRcdFx0aWYgKDQwMyA9PSBqcVhIUi5zdGF0dXMgKXtcclxuXHRcdFx0XHRcdFx0XHRlcnJvcl9tZXNzYWdlICs9ICc8YnI+IFByb2JhYmx5IG5vbmNlIGZvciB0aGlzIHBhZ2UgaGFzIGJlZW4gZXhwaXJlZC4gUGxlYXNlIDxhIGhyZWY9XCJqYXZhc2NyaXB0OnZvaWQoMClcIiBvbmNsaWNrPVwiamF2YXNjcmlwdDpsb2NhdGlvbi5yZWxvYWQoKTtcIj5yZWxvYWQgdGhlIHBhZ2U8L2E+Lic7XHJcblx0XHRcdFx0XHRcdFx0ZXJyb3JfbWVzc2FnZSArPSAnPGJyPiBPdGhlcndpc2UsIHBsZWFzZSBjaGVjayB0aGlzIDxhIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDYwMDtcIiBocmVmPVwiaHR0cHM6Ly93cGJvb2tpbmdjYWxlbmRhci5jb20vZmFxL3JlcXVlc3QtZG8tbm90LXBhc3Mtc2VjdXJpdHktY2hlY2svP2FmdGVyX3VwZGF0ZT0xMC4xLjFcIj50cm91Ymxlc2hvb3RpbmcgaW5zdHJ1Y3Rpb248L2E+Ljxicj4nXHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGlmICgganFYSFIucmVzcG9uc2VUZXh0ICl7XHJcblx0XHRcdFx0XHRcdC8vIEVzY2FwZSB0YWdzIGluIEVycm9yIG1lc3NhZ2VcclxuXHRcdFx0XHRcdFx0ZXJyb3JfbWVzc2FnZSArPSAnPGJyPjxzdHJvbmc+UmVzcG9uc2U8L3N0cm9uZz48ZGl2IHN0eWxlPVwicGFkZGluZzogMCAxMHB4O21hcmdpbjogMCAwIDEwcHg7Ym9yZGVyLXJhZGl1czozcHg7IGJveC1zaGFkb3c6MHB4IDBweCAxcHggI2EzYTNhMztcIj4nICsganFYSFIucmVzcG9uc2VUZXh0LnJlcGxhY2UoLyYvZywgXCImYW1wO1wiKVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAucmVwbGFjZSgvPC9nLCBcIiZsdDtcIilcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgLnJlcGxhY2UoLz4vZywgXCImZ3Q7XCIpXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IC5yZXBsYWNlKC9cIi9nLCBcIiZxdW90O1wiKVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAucmVwbGFjZSgvJy9nLCBcIiYjMzk7XCIpXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Kyc8L2Rpdj4nO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0ZXJyb3JfbWVzc2FnZSA9IGVycm9yX21lc3NhZ2UucmVwbGFjZSggL1xcbi9nLCBcIjxiciAvPlwiICk7XHJcblxyXG5cdFx0XHRcdFx0dmFyIGNhbGVuZGFyX2lkID0gd3BiY19nZXRfcmVzb3VyY2VfaWRfX2Zyb21fYWp4X3Bvc3RfZGF0YV91cmwoIHRoaXMuZGF0YSApO1xyXG5cdFx0XHRcdFx0dmFyIGpxX25vZGUgPSAnI2Jvb2tpbmdfZm9ybScgKyBjYWxlbmRhcl9pZDtcclxuXHJcblx0XHRcdFx0XHQvLyBTaG93IE1lc3NhZ2VcclxuXHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIGVycm9yX21lc3NhZ2UgLCB7ICd0eXBlJyAgICAgOiAnZXJyb3InLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZSc6IHsnanFfbm9kZSc6IGpxX25vZGUsICd3aGVyZSc6ICdhZnRlcid9LFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lzX2FwcGVuZCc6IHRydWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDBcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0XHQvLyBFbmFibGUgU3VibWl0IHwgSGlkZSBzcGluIGxvYWRlclxyXG5cdFx0XHRcdFx0d3BiY19ib29raW5nX2Zvcm1fX29uX3Jlc3BvbnNlX191aV9lbGVtZW50c19lbmFibGUoIGNhbGVuZGFyX2lkICk7XHJcblx0XHRcdCAgXHQgfVxyXG5cdFx0XHRcdCAvLyA8L2VkaXRvci1mb2xkPlxyXG5cdFx0XHQgIClcclxuXHQgICAgICAgICAgLy8gLmRvbmUoICAgZnVuY3Rpb24gKCBkYXRhLCB0ZXh0U3RhdHVzLCBqcVhIUiApIHsgICBpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLmxvZyApeyBjb25zb2xlLmxvZyggJ3NlY29uZCBzdWNjZXNzJywgZGF0YSwgdGV4dFN0YXR1cywganFYSFIgKTsgfSAgICB9KVxyXG5cdFx0XHQgIC8vIC5hbHdheXMoIGZ1bmN0aW9uICggZGF0YV9qcVhIUiwgdGV4dFN0YXR1cywganFYSFJfZXJyb3JUaHJvd24gKSB7ICAgaWYgKCB3aW5kb3cuY29uc29sZSAmJiB3aW5kb3cuY29uc29sZS5sb2cgKXsgY29uc29sZS5sb2coICdhbHdheXMgZmluaXNoZWQnLCBkYXRhX2pxWEhSLCB0ZXh0U3RhdHVzLCBqcVhIUl9lcnJvclRocm93biApOyB9ICAgICB9KVxyXG5cdFx0XHQgIDsgIC8vIEVuZCBBamF4XHJcblxyXG5cdHJldHVybiB0cnVlO1xyXG59XHJcblxyXG5cclxuXHQvLyA8ZWRpdG9yLWZvbGQgICAgIGRlZmF1bHRzdGF0ZT1cImNvbGxhcHNlZFwiICAgICAgICAgICAgICAgICAgICAgICAgZGVzYz1cIiAgPT0gIENBUFRDSEEgPT0gIFwiICA+XHJcblxyXG5cdC8qKlxyXG5cdCAqIFVwZGF0ZSBpbWFnZSBpbiBjYXB0Y2hhIGFuZCBzaG93IHdhcm5pbmcgbWVzc2FnZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHBhcmFtc1xyXG5cdCAqXHJcblx0ICogRXhhbXBsZSBvZiAncGFyYW1zJyA6IHtcclxuXHQgKlx0XHRcdFx0XHRcdFx0J3Jlc291cmNlX2lkJzogcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdLFxyXG5cdCAqXHRcdFx0XHRcdFx0XHQndXJsJyAgICAgICAgOiByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdjYXB0Y2hhX19zaW1wbGUnIF1bICd1cmwnIF0sXHJcblx0ICpcdFx0XHRcdFx0XHRcdCdjaGFsbGVuZ2UnICA6IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2NhcHRjaGFfX3NpbXBsZScgXVsgJ2NoYWxsZW5nZScgXSxcclxuXHQgKlx0XHRcdFx0XHRcdFx0J21lc3NhZ2UnICAgIDogcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlJyBdLnJlcGxhY2UoIC9cXG4vZywgXCI8YnIgLz5cIiApXHJcblx0ICpcdFx0XHRcdFx0XHR9XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYXB0Y2hhX19zaW1wbGVfX3VwZGF0ZSggcGFyYW1zICl7XHJcblxyXG5cdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdjYXB0Y2hhX2lucHV0JyArIHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdICkudmFsdWUgPSAnJztcclxuXHRcdGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnY2FwdGNoYV9pbWcnICsgcGFyYW1zWyAncmVzb3VyY2VfaWQnIF0gKS5zcmMgPSBwYXJhbXNbICd1cmwnIF07XHJcblx0XHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ3dwZGV2X2NhcHRjaGFfY2hhbGxlbmdlXycgKyBwYXJhbXNbICdyZXNvdXJjZV9pZCcgXSApLnZhbHVlID0gcGFyYW1zWyAnY2hhbGxlbmdlJyBdO1xyXG5cclxuXHRcdC8vIFNob3cgd2FybmluZyBcdFx0QWZ0ZXIgQ0FQVENIQSBJbWdcclxuXHRcdHZhciBtZXNzYWdlX2lkID0gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggJyNjYXB0Y2hhX2lucHV0JyArIHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdICsgJyArIGltZycsIHBhcmFtc1sgJ21lc3NhZ2UnIF0gKTtcclxuXHJcblx0XHQvLyBBbmltYXRlXHJcblx0XHRqUXVlcnkoICcjJyArIG1lc3NhZ2VfaWQgKyAnLCAnICsgJyNjYXB0Y2hhX2lucHV0JyArIHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdICkuZmFkZU91dCggMzUwICkuZmFkZUluKCAzMDAgKS5mYWRlT3V0KCAzNTAgKS5mYWRlSW4oIDQwMCApLmFuaW1hdGUoIHtvcGFjaXR5OiAxfSwgNDAwMCApO1xyXG5cdFx0Ly8gRm9jdXMgdGV4dCAgZmllbGRcclxuXHRcdGpRdWVyeSggJyNjYXB0Y2hhX2lucHV0JyArIHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdICkudHJpZ2dlciggJ2ZvY3VzJyApOyAgICBcdFx0XHRcdFx0XHRcdFx0XHQvL0ZpeEluOiA4LjcuMTEuMTJcclxuXHJcblxyXG5cdFx0Ly8gRW5hYmxlIFN1Ym1pdCB8IEhpZGUgc3BpbiBsb2FkZXJcclxuXHRcdHdwYmNfYm9va2luZ19mb3JtX19vbl9yZXNwb25zZV9fdWlfZWxlbWVudHNfZW5hYmxlKCBwYXJhbXNbICdyZXNvdXJjZV9pZCcgXSApO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIElmIHRoZSBjYXB0Y2hhIGVsZW1lbnRzIG5vdCBleGlzdCAgaW4gdGhlIGJvb2tpbmcgZm9ybSwgIHRoZW4gIHJlbW92ZSBwYXJhbWV0ZXJzIHJlbGF0aXZlIGNhcHRjaGFcclxuXHQgKiBAcGFyYW0gcGFyYW1zXHJcblx0ICogQHJldHVybnMgb2JqXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYXB0Y2hhX19zaW1wbGVfX21heWJlX3JlbW92ZV9pbl9hanhfcGFyYW1zKCBwYXJhbXMgKXtcclxuXHJcblx0XHRpZiAoICEgd3BiY19jYXB0Y2hhX19zaW1wbGVfX2lzX2V4aXN0X2luX2Zvcm0oIHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdICkgKXtcclxuXHRcdFx0ZGVsZXRlIHBhcmFtc1sgJ2NhcHRjaGFfY2hhbGFuZ2UnIF07XHJcblx0XHRcdGRlbGV0ZSBwYXJhbXNbICdjYXB0Y2hhX3VzZXJfaW5wdXQnIF07XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gcGFyYW1zO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIENoZWNrIGlmIENBUFRDSEEgZXhpc3QgaW4gdGhlIGJvb2tpbmcgZm9ybVxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FwdGNoYV9fc2ltcGxlX19pc19leGlzdF9pbl9mb3JtKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdHJldHVybiAoXHJcblx0XHRcdFx0XHRcdCgwICE9PSBqUXVlcnkoICcjd3BkZXZfY2FwdGNoYV9jaGFsbGVuZ2VfJyArIHJlc291cmNlX2lkICkubGVuZ3RoKVxyXG5cdFx0XHRcdFx0IHx8ICgwICE9PSBqUXVlcnkoICcjY2FwdGNoYV9pbnB1dCcgKyByZXNvdXJjZV9pZCApLmxlbmd0aClcclxuXHRcdFx0XHQpO1xyXG5cdH1cclxuXHJcblx0Ly8gPC9lZGl0b3ItZm9sZD5cclxuXHJcblxyXG5cdC8vIDxlZGl0b3ItZm9sZCAgICAgZGVmYXVsdHN0YXRlPVwiY29sbGFwc2VkXCIgICAgICAgICAgICAgICAgICAgICAgICBkZXNjPVwiICA9PSAgU2VuZCBCdXR0b24gfCBGb3JtIFNwaW4gTG9hZGVyICA9PSAgXCIgID5cclxuXHJcblx0LyoqXHJcblx0ICogRGlzYWJsZSBTZW5kIGJ1dHRvbiAgfCAgU2hvdyBTcGluIExvYWRlclxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19ib29raW5nX2Zvcm1fX29uX3N1Ym1pdF9fdWlfZWxlbWVudHNfZGlzYWJsZSggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHQvLyBEaXNhYmxlIFN1Ym1pdFxyXG5cdFx0d3BiY19ib29raW5nX2Zvcm1fX3NlbmRfYnV0dG9uX19kaXNhYmxlKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdC8vIFNob3cgU3BpbiBsb2FkZXIgaW4gYm9va2luZyBmb3JtXHJcblx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fc3Bpbl9sb2FkZXJfX3Nob3coIHJlc291cmNlX2lkICk7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBFbmFibGUgU2VuZCBidXR0b24gIHwgICBIaWRlIFNwaW4gTG9hZGVyXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9fb25fcmVzcG9uc2VfX3VpX2VsZW1lbnRzX2VuYWJsZShyZXNvdXJjZV9pZCl7XHJcblxyXG5cdFx0Ly8gRW5hYmxlIFN1Ym1pdFxyXG5cdFx0d3BiY19ib29raW5nX2Zvcm1fX3NlbmRfYnV0dG9uX19lbmFibGUoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0Ly8gSGlkZSBTcGluIGxvYWRlciBpbiBib29raW5nIGZvcm1cclxuXHRcdHdwYmNfYm9va2luZ19mb3JtX19zcGluX2xvYWRlcl9faGlkZSggcmVzb3VyY2VfaWQgKTtcclxuXHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBFbmFibGUgU3VibWl0IGJ1dHRvblxyXG5cdFx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHdwYmNfYm9va2luZ19mb3JtX19zZW5kX2J1dHRvbl9fZW5hYmxlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdFx0Ly8gQWN0aXZhdGUgU2VuZCBidXR0b25cclxuXHRcdFx0alF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKyAnIGlucHV0W3R5cGU9YnV0dG9uXScgKS5wcm9wKCBcImRpc2FibGVkXCIsIGZhbHNlICk7XHJcblx0XHRcdGpRdWVyeSggJyNib29raW5nX2Zvcm1fZGl2JyArIHJlc291cmNlX2lkICsgJyBidXR0b24nICkucHJvcCggXCJkaXNhYmxlZFwiLCBmYWxzZSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogRGlzYWJsZSBTdWJtaXQgYnV0dG9uICBhbmQgc2hvdyAgc3BpblxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9fc2VuZF9idXR0b25fX2Rpc2FibGUoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0XHQvLyBEaXNhYmxlIFNlbmQgYnV0dG9uXHJcblx0XHRcdGpRdWVyeSggJyNib29raW5nX2Zvcm1fZGl2JyArIHJlc291cmNlX2lkICsgJyBpbnB1dFt0eXBlPWJ1dHRvbl0nICkucHJvcCggXCJkaXNhYmxlZFwiLCB0cnVlICk7XHJcblx0XHRcdGpRdWVyeSggJyNib29raW5nX2Zvcm1fZGl2JyArIHJlc291cmNlX2lkICsgJyBidXR0b24nICkucHJvcCggXCJkaXNhYmxlZFwiLCB0cnVlICk7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBEaXNhYmxlICdUaGlzJyBidXR0b25cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gX3RoaXNcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19ib29raW5nX2Zvcm1fX3RoaXNfYnV0dG9uX19kaXNhYmxlKCBfdGhpcyApe1xyXG5cclxuXHRcdFx0Ly8gRGlzYWJsZSBTZW5kIGJ1dHRvblxyXG5cdFx0XHRqUXVlcnkoIF90aGlzICkucHJvcCggXCJkaXNhYmxlZFwiLCB0cnVlICk7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBTaG93IGJvb2tpbmcgZm9ybSAgU3BpbiBMb2FkZXJcclxuXHRcdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9fc3Bpbl9sb2FkZXJfX3Nob3coIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0XHQvLyBTaG93IFNwaW4gTG9hZGVyXHJcblx0XHRcdGpRdWVyeSggJyNib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQgKS5hZnRlcihcclxuXHRcdFx0XHQnPGRpdiBpZD1cIndwYmNfYm9va2luZ19mb3JtX3NwaW5fbG9hZGVyJyArIHJlc291cmNlX2lkICsgJ1wiIGNsYXNzPVwid3BiY19ib29raW5nX2Zvcm1fc3Bpbl9sb2FkZXJcIiBzdHlsZT1cInBvc2l0aW9uOiByZWxhdGl2ZTtcIj48ZGl2IGNsYXNzPVwid3BiY19zcGluc19sb2FkZXJfd3JhcHBlclwiPjxkaXYgY2xhc3M9XCJ3cGJjX3NwaW5zX2xvYWRlcl9taW5pXCI+PC9kaXY+PC9kaXY+PC9kaXY+J1xyXG5cdFx0XHQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogUmVtb3ZlIC8gSGlkZSBib29raW5nIGZvcm0gIFNwaW4gTG9hZGVyXHJcblx0XHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19ib29raW5nX2Zvcm1fX3NwaW5fbG9hZGVyX19oaWRlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdFx0Ly8gUmVtb3ZlIFNwaW4gTG9hZGVyXHJcblx0XHRcdGpRdWVyeSggJyN3cGJjX2Jvb2tpbmdfZm9ybV9zcGluX2xvYWRlcicgKyByZXNvdXJjZV9pZCApLnJlbW92ZSgpO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEhpZGUgYm9va2luZyBmb3JtIHd0aCBhbmltYXRpb25cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19ib29raW5nX2Zvcm1fX2FuaW1hdGVkX19oaWRlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdFx0Ly8galF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLnNsaWRlVXAoICAxMDAwXHJcblx0XHRcdC8vIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCwgZnVuY3Rpb24gKCl7XHJcblx0XHRcdC8vXHJcblx0XHRcdC8vIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBpZiAoIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnZ2F0ZXdheV9wYXltZW50X2Zvcm1zJyArIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSApICE9IG51bGwgKXtcclxuXHRcdFx0Ly8gXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFx0d3BiY19kb19zY3JvbGwoICcjc3VibWl0aW5nJyArIHJlc291cmNlX2lkICk7XHJcblx0XHRcdC8vIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyB9IGVsc2VcclxuXHRcdFx0Ly8gXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLnBhcmVudCgpLmZpbmQoICcuc3VibWl0aW5nX2NvbnRlbnQnICkubGVuZ3RoID4gMCApe1xyXG5cdFx0XHQvLyBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvL3dwYmNfZG9fc2Nyb2xsKCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCArICcgKyAuc3VibWl0aW5nX2NvbnRlbnQnICk7XHJcblx0XHRcdC8vXHJcblx0XHRcdC8vIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCB2YXIgaGlkZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0Ly8gXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgd3BiY19kb19zY3JvbGwoIGpRdWVyeSggJyNib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQgKS5wYXJlbnQoKS5maW5kKCAnLnN1Ym1pdGluZ19jb250ZW50JyApLmdldCggMCApICk7XHJcblx0XHRcdC8vIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9LCAxMDApO1xyXG5cdFx0XHQvL1xyXG5cdFx0XHQvLyBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHQvLyBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgIH1cclxuXHRcdFx0Ly8gXHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0alF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLmhpZGUoKTtcclxuXHJcblx0XHRcdC8vIHZhciBoaWRlVGltZW91dCA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0XHQvL1xyXG5cdFx0XHQvLyBcdGlmICggalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLnBhcmVudCgpLmZpbmQoICcuc3VibWl0aW5nX2NvbnRlbnQnICkubGVuZ3RoID4gMCApe1xyXG5cdFx0XHQvLyBcdFx0dmFyIHJhbmRvbV9pZCA9IE1hdGguZmxvb3IoIChNYXRoLnJhbmRvbSgpICogMTAwMDApICsgMSApO1xyXG5cdFx0XHQvLyBcdFx0alF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLnBhcmVudCgpLmJlZm9yZSggJzxkaXYgaWQ9XCJzY3JvbGxfdG8nICsgcmFuZG9tX2lkICsgJ1wiPjwvZGl2PicgKTtcclxuXHRcdFx0Ly8gXHRcdGNvbnNvbGUubG9nKCBqUXVlcnkoICcjc2Nyb2xsX3RvJyArIHJhbmRvbV9pZCApICk7XHJcblx0XHRcdC8vXHJcblx0XHRcdC8vIFx0XHR3cGJjX2RvX3Njcm9sbCggJyNzY3JvbGxfdG8nICsgcmFuZG9tX2lkICk7XHJcblx0XHRcdC8vIFx0XHQvL3dwYmNfZG9fc2Nyb2xsKCBqUXVlcnkoICcjYm9va2luZ19mb3JtJyArIHJlc291cmNlX2lkICkucGFyZW50KCkuZ2V0KCAwICkgKTtcclxuXHRcdFx0Ly8gXHR9XHJcblx0XHRcdC8vIH0sIDUwMCApO1xyXG5cdFx0fVxyXG5cdC8vIDwvZWRpdG9yLWZvbGQ+XHJcblxyXG5cclxuXHQvLyA8ZWRpdG9yLWZvbGQgICAgIGRlZmF1bHRzdGF0ZT1cImNvbGxhcHNlZFwiICAgICAgICAgICAgICAgICAgICAgICAgZGVzYz1cIiAgPT0gIE1pbmkgU3BpbiBMb2FkZXIgID09ICBcIiAgPlxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSBwYXJlbnRfaHRtbF9pZFxyXG5cdFx0ICovXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBTaG93IG1pY3JvIFNwaW4gTG9hZGVyXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIGlkXHRcdFx0XHRcdFx0SUQgb2YgTG9hZGVyLCAgZm9yIGxhdGVyICBoaWRlIGl0IGJ5ICB1c2luZyBcdFx0d3BiY19fc3Bpbl9sb2FkZXJfX21pY3JvX19oaWRlKCBpZCApIE9SIHdwYmNfX3NwaW5fbG9hZGVyX19taW5pX19oaWRlKCBpZCApXHJcblx0XHQgKiBAcGFyYW0ganFfbm9kZV93aGVyZV9pbnNlcnRcdFx0c3VjaCBhcyAnI2VzdGltYXRlX2Jvb2tpbmdfbmlnaHRfY29zdF9oaW50MTAnICAgT1IgICcuZXN0aW1hdGVfYm9va2luZ19uaWdodF9jb3N0X2hpbnQxMCdcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19fc3Bpbl9sb2FkZXJfX21pY3JvX19zaG93X19pbnNpZGUoIGlkICwganFfbm9kZV93aGVyZV9pbnNlcnQgKXtcclxuXHJcblx0XHRcdFx0d3BiY19fc3Bpbl9sb2FkZXJfX21pbmlfX3Nob3coIGlkLCB7XHJcblx0XHRcdFx0XHQnY29sb3InICA6ICcjNDQ0JyxcclxuXHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7XHJcblx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2luc2lkZScsXHJcblx0XHRcdFx0XHRcdCdqcV9ub2RlJzoganFfbm9kZV93aGVyZV9pbnNlcnRcclxuXHRcdFx0XHRcdH0sXHJcblx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3Bvc2l0aW9uOiByZWxhdGl2ZTtkaXNwbGF5OiBpbmxpbmUtZmxleDtmbGV4LWZsb3c6IGNvbHVtbiBub3dyYXA7anVzdGlmeS1jb250ZW50OiBjZW50ZXI7YWxpZ24taXRlbXM6IGNlbnRlcjttYXJnaW46IDdweCAxMnB4OycsXHJcblx0XHRcdFx0XHQnY2xhc3MnICAgIDogJ3dwYmNfb25lX3NwaW5fbG9hZGVyX21pY3JvJ1xyXG5cdFx0XHRcdH0gKTtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFJlbW92ZSBzcGlubmVyXHJcblx0XHQgKiBAcGFyYW0gaWRcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19fc3Bpbl9sb2FkZXJfX21pY3JvX19oaWRlKCBpZCApe1xyXG5cdFx0ICAgIHdwYmNfX3NwaW5fbG9hZGVyX19taW5pX19oaWRlKCBpZCApO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFNob3cgbWluaSBTcGluIExvYWRlclxyXG5cdFx0ICogQHBhcmFtIHBhcmVudF9odG1sX2lkXHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHdwYmNfX3NwaW5fbG9hZGVyX19taW5pX19zaG93KCBwYXJlbnRfaHRtbF9pZCAsIHBhcmFtcyA9IHt9ICl7XHJcblxyXG5cdFx0XHR2YXIgcGFyYW1zX2RlZmF1bHQgPSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdCdjb2xvcicgICAgOiAnIzAwNzFjZScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxX25vZGUnOiAnJyxcdFx0XHRcdFx0Ly8gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdhZnRlcidcdFx0XHRcdC8vICdpbnNpZGUnIHwgJ2JlZm9yZScgfCAnYWZ0ZXInIHwgJ3JpZ2h0JyB8ICdsZWZ0J1xyXG5cdFx0XHRcdFx0XHRcdFx0XHR9LFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3Bvc2l0aW9uOiByZWxhdGl2ZTttaW4taGVpZ2h0OiAyLjhyZW07JyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J2NsYXNzJyAgICA6ICd3cGJjX29uZV9zcGluX2xvYWRlcl9taW5pIDB3cGJjX3NwaW5zX2xvYWRlcl9taW5pJ1xyXG5cdFx0XHRcdFx0XHRcdFx0fTtcclxuXHRcdFx0Zm9yICggdmFyIHBfa2V5IGluIHBhcmFtcyApe1xyXG5cdFx0XHRcdHBhcmFtc19kZWZhdWx0WyBwX2tleSBdID0gcGFyYW1zWyBwX2tleSBdO1xyXG5cdFx0XHR9XHJcblx0XHRcdHBhcmFtcyA9IHBhcmFtc19kZWZhdWx0O1xyXG5cclxuXHRcdFx0aWYgKCAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAocGFyYW1zWydjb2xvciddKSkgJiYgKCcnICE9IHBhcmFtc1snY29sb3InXSkgKXtcclxuXHRcdFx0XHRwYXJhbXNbJ2NvbG9yJ10gPSAnYm9yZGVyLWNvbG9yOicgKyBwYXJhbXNbJ2NvbG9yJ10gKyAnOyc7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZhciBzcGlubmVyX2h0bWwgPSAnPGRpdiBpZD1cIndwYmNfbWluaV9zcGluX2xvYWRlcicgKyBwYXJlbnRfaHRtbF9pZCArICdcIiBjbGFzcz1cIndwYmNfYm9va2luZ19mb3JtX3NwaW5fbG9hZGVyXCIgc3R5bGU9XCInICsgcGFyYW1zWyAnc3R5bGUnIF0gKyAnXCI+PGRpdiBjbGFzcz1cIndwYmNfc3BpbnNfbG9hZGVyX3dyYXBwZXJcIj48ZGl2IGNsYXNzPVwiJyArIHBhcmFtc1sgJ2NsYXNzJyBdICsgJ1wiIHN0eWxlPVwiJyArIHBhcmFtc1sgJ2NvbG9yJyBdICsgJ1wiPjwvZGl2PjwvZGl2PjwvZGl2Pic7XHJcblxyXG5cdFx0XHRpZiAoICcnID09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKXtcclxuXHRcdFx0XHRwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdID0gJyMnICsgcGFyZW50X2h0bWxfaWQ7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIFNob3cgU3BpbiBMb2FkZXJcclxuXHRcdFx0aWYgKCAnYWZ0ZXInID09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ3doZXJlJyBdICl7XHJcblx0XHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYWZ0ZXIoIHNwaW5uZXJfaHRtbCApO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmh0bWwoIHNwaW5uZXJfaHRtbCApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBSZW1vdmUgLyBIaWRlIG1pbmkgU3BpbiBMb2FkZXJcclxuXHRcdCAqIEBwYXJhbSBwYXJlbnRfaHRtbF9pZFxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX19zcGluX2xvYWRlcl9fbWluaV9faGlkZSggcGFyZW50X2h0bWxfaWQgKXtcclxuXHJcblx0XHRcdC8vIFJlbW92ZSBTcGluIExvYWRlclxyXG5cdFx0XHRqUXVlcnkoICcjd3BiY19taW5pX3NwaW5fbG9hZGVyJyArIHBhcmVudF9odG1sX2lkICkucmVtb3ZlKCk7XHJcblx0XHR9XHJcblxyXG5cdC8vIDwvZWRpdG9yLWZvbGQ+XHJcblxyXG4vL1RPRE86IHdoYXQgIGFib3V0IHNob3dpbmcgb25seSAgVGhhbmsgeW91LiBtZXNzYWdlIHdpdGhvdXQgcGF5bWVudCBmb3Jtcy5cclxuLyoqXHJcbiAqIFNob3cgJ1RoYW5rIHlvdScuIG1lc3NhZ2UgYW5kIHBheW1lbnQgZm9ybXNcclxuICpcclxuICogQHBhcmFtIHJlc3BvbnNlX2RhdGFcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfc2hvd190aGFua195b3VfbWVzc2FnZV9hZnRlcl9ib29raW5nKCByZXNwb25zZV9kYXRhICl7XHJcblxyXG5cdGlmIChcclxuIFx0XHQgICAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9pc19yZWRpcmVjdCcgXSkpXHJcblx0XHQmJiAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV91cmwnIF0pKVxyXG5cdFx0JiYgKCdwYWdlJyA9PSByZXNwb25zZV9kYXRhWyAnYWp4X2NvbmZpcm1hdGlvbicgXVsgJ3R5X2lzX3JlZGlyZWN0JyBdKVxyXG5cdFx0JiYgKCcnICE9IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfdXJsJyBdKVxyXG5cdCl7XHJcblx0XHRqUXVlcnkoICdib2R5JyApLnRyaWdnZXIoICd3cGJjX2Jvb2tpbmdfY3JlYXRlZCcsIFsgcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdICwgcmVzcG9uc2VfZGF0YSBdICk7XHRcdFx0Ly9GaXhJbjogMTAuMC4wLjMwXHJcblx0XHR3aW5kb3cubG9jYXRpb24uaHJlZiA9IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfdXJsJyBdO1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcblx0dmFyIHJlc291cmNlX2lkID0gcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdXHJcblx0dmFyIGNvbmZpcm1fY29udGVudCA9Jyc7XHJcblxyXG5cdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9tZXNzYWdlJyBdKSApe1xyXG5cdFx0XHRcdFx0ICBcdFx0XHQgcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9tZXNzYWdlJyBdID0gJyc7XHJcblx0fVxyXG5cdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9wYXltZW50X3BheW1lbnRfZGVzY3JpcHRpb24nIF0gKSApe1xyXG5cdFx0IFx0XHRcdCAgXHRcdFx0IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfcGF5bWVudF9wYXltZW50X2Rlc2NyaXB0aW9uJyBdID0gJyc7XHJcblx0fVxyXG5cdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICdwYXltZW50X2Nvc3QnIF0gKSApe1xyXG5cdFx0XHRcdFx0ICBcdFx0XHQgcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICdwYXltZW50X2Nvc3QnIF0gPSAnJztcclxuXHR9XHJcblx0aWYgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChyZXNwb25zZV9kYXRhWyAnYWp4X2NvbmZpcm1hdGlvbicgXVsgJ3R5X3BheW1lbnRfZ2F0ZXdheXMnIF0gKSApe1xyXG5cdFx0XHRcdFx0ICBcdFx0XHQgcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9wYXltZW50X2dhdGV3YXlzJyBdID0gJyc7XHJcblx0fVxyXG5cdHZhciB0eV9tZXNzYWdlX2hpZGUgXHRcdFx0XHRcdFx0PSAoJycgPT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9tZXNzYWdlJyBdKSA/ICd3cGJjX3R5X2hpZGUnIDogJyc7XHJcblx0dmFyIHR5X3BheW1lbnRfcGF5bWVudF9kZXNjcmlwdGlvbl9oaWRlIFx0PSAoJycgPT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9wYXltZW50X3BheW1lbnRfZGVzY3JpcHRpb24nIF0ucmVwbGFjZSggL1xcXFxuL2csICcnICkpID8gJ3dwYmNfdHlfaGlkZScgOiAnJztcclxuXHR2YXIgdHlfYm9va2luZ19jb3N0c19oaWRlIFx0XHRcdFx0PSAoJycgPT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICdwYXltZW50X2Nvc3QnIF0pID8gJ3dwYmNfdHlfaGlkZScgOiAnJztcclxuXHR2YXIgdHlfcGF5bWVudF9nYXRld2F5c19oaWRlIFx0XHRcdD0gKCcnID09IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfcGF5bWVudF9nYXRld2F5cycgXS5yZXBsYWNlKCAvXFxcXG4vZywgJycgKSkgPyAnd3BiY190eV9oaWRlJyA6ICcnO1xyXG5cclxuXHRpZiAoICd3cGJjX3R5X2hpZGUnICE9IHR5X3BheW1lbnRfZ2F0ZXdheXNfaGlkZSApe1xyXG5cdFx0alF1ZXJ5KCAnLndwYmNfdHlfX2NvbnRlbnRfdGV4dC53cGJjX3R5X19jb250ZW50X2dhdGV3YXlzJyApLmh0bWwoICcnICk7XHQvLyBSZXNldCAgYWxsICBvdGhlciBwb3NzaWJsZSBnYXRld2F5cyBiZWZvcmUgc2hvd2luZyBuZXcgb25lLlxyXG5cdH1cclxuXHJcblx0Y29uZmlybV9jb250ZW50ICs9IGA8ZGl2IGlkPVwid3BiY19zY3JvbGxfcG9pbnRfJHtyZXNvdXJjZV9pZH1cIj48L2Rpdj5gO1xyXG5cdGNvbmZpcm1fY29udGVudCArPSBgICA8ZGl2IGNsYXNzPVwid3BiY19hZnRlcl9ib29raW5nX3RoYW5rX3lvdV9zZWN0aW9uXCI+YDtcclxuXHRjb25maXJtX2NvbnRlbnQgKz0gYCAgICA8ZGl2IGNsYXNzPVwid3BiY190eV9fbWVzc2FnZSAke3R5X21lc3NhZ2VfaGlkZX1cIj4ke3Jlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfbWVzc2FnZScgXX08L2Rpdj5gO1xyXG4gICAgY29uZmlybV9jb250ZW50ICs9IGAgICAgPGRpdiBjbGFzcz1cIndwYmNfdHlfX2NvbnRhaW5lclwiPmA7XHJcblx0aWYgKCAnJyAhPT0gcmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9tZXNzYWdlX2Jvb2tpbmdfaWQnIF0gKXtcclxuXHRcdGNvbmZpcm1fY29udGVudCArPSBgICAgICAgPGRpdiBjbGFzcz1cIndwYmNfdHlfX2hlYWRlclwiPiR7cmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9tZXNzYWdlX2Jvb2tpbmdfaWQnIF19PC9kaXY+YDtcclxuXHR9XHJcbiAgICBjb25maXJtX2NvbnRlbnQgKz0gYCAgICAgIDxkaXYgY2xhc3M9XCJ3cGJjX3R5X19jb250ZW50XCI+YDtcclxuXHRjb25maXJtX2NvbnRlbnQgKz0gYCAgICAgICAgPGRpdiBjbGFzcz1cIndwYmNfdHlfX2NvbnRlbnRfdGV4dCB3cGJjX3R5X19wYXltZW50X2Rlc2NyaXB0aW9uICR7dHlfcGF5bWVudF9wYXltZW50X2Rlc2NyaXB0aW9uX2hpZGV9XCI+JHtyZXNwb25zZV9kYXRhWyAnYWp4X2NvbmZpcm1hdGlvbicgXVsgJ3R5X3BheW1lbnRfcGF5bWVudF9kZXNjcmlwdGlvbicgXS5yZXBsYWNlKCAvXFxcXG4vZywgJycgKX08L2Rpdj5gO1xyXG5cdGlmICggJycgIT09IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfY3VzdG9tZXJfZGV0YWlscycgXSApe1xyXG5cdFx0Y29uZmlybV9jb250ZW50ICs9IGAgICAgICBcdDxkaXYgY2xhc3M9XCJ3cGJjX3R5X19jb250ZW50X3RleHQgd3BiY19jb2xzXzJcIj4ke3Jlc3BvbnNlX2RhdGFbJ2FqeF9jb25maXJtYXRpb24nXVsndHlfY3VzdG9tZXJfZGV0YWlscyddfTwvZGl2PmA7XHJcblx0fVxyXG5cdGlmICggJycgIT09IHJlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfYm9va2luZ19kZXRhaWxzJyBdICl7XHJcblx0XHRjb25maXJtX2NvbnRlbnQgKz0gYCAgICAgIFx0PGRpdiBjbGFzcz1cIndwYmNfdHlfX2NvbnRlbnRfdGV4dCB3cGJjX2NvbHNfMlwiPiR7cmVzcG9uc2VfZGF0YVsnYWp4X2NvbmZpcm1hdGlvbiddWyd0eV9ib29raW5nX2RldGFpbHMnXX08L2Rpdj5gO1xyXG5cdH1cclxuXHRjb25maXJtX2NvbnRlbnQgKz0gYCAgICAgICAgPGRpdiBjbGFzcz1cIndwYmNfdHlfX2NvbnRlbnRfdGV4dCB3cGJjX3R5X19jb250ZW50X2Nvc3RzICR7dHlfYm9va2luZ19jb3N0c19oaWRlfVwiPiR7cmVzcG9uc2VfZGF0YVsgJ2FqeF9jb25maXJtYXRpb24nIF1bICd0eV9ib29raW5nX2Nvc3RzJyBdfTwvZGl2PmA7XHJcblx0Y29uZmlybV9jb250ZW50ICs9IGAgICAgICAgIDxkaXYgY2xhc3M9XCJ3cGJjX3R5X19jb250ZW50X3RleHQgd3BiY190eV9fY29udGVudF9nYXRld2F5cyAke3R5X3BheW1lbnRfZ2F0ZXdheXNfaGlkZX1cIj4ke3Jlc3BvbnNlX2RhdGFbICdhanhfY29uZmlybWF0aW9uJyBdWyAndHlfcGF5bWVudF9nYXRld2F5cycgXS5yZXBsYWNlKCAvXFxcXG4vZywgJycgKS5yZXBsYWNlKCAvYWpheF9zY3JpcHQvZ2ksICdzY3JpcHQnICl9PC9kaXY+YDtcclxuICAgIGNvbmZpcm1fY29udGVudCArPSBgICAgICAgPC9kaXY+YDtcclxuICAgIGNvbmZpcm1fY29udGVudCArPSBgICAgIDwvZGl2PmA7XHJcblx0Y29uZmlybV9jb250ZW50ICs9IGA8L2Rpdj5gO1xyXG5cclxuIFx0alF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLmFmdGVyKCBjb25maXJtX2NvbnRlbnQgKTtcclxuXHJcblxyXG5cdC8vRml4SW46IDEwLjAuMC4zMFx0XHQvLyBldmVudCBuYW1lXHRcdFx0Ly8gUmVzb3VyY2UgSURcdC1cdCcxJ1xyXG5cdGpRdWVyeSggJ2JvZHknICkudHJpZ2dlciggJ3dwYmNfYm9va2luZ19jcmVhdGVkJywgWyByZXNvdXJjZV9pZCAsIHJlc3BvbnNlX2RhdGEgXSApO1xyXG5cdC8vIFRvIGNhdGNoIHRoaXMgZXZlbnQ6IGpRdWVyeSggJ2JvZHknICkub24oJ3dwYmNfYm9va2luZ19jcmVhdGVkJywgZnVuY3Rpb24oIGV2ZW50LCByZXNvdXJjZV9pZCwgcGFyYW1zICkgeyBjb25zb2xlLmxvZyggZXZlbnQsIHJlc291cmNlX2lkLCBwYXJhbXMgKTsgfSApO1xyXG59XHJc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 create_booking.php 0000666 00000237420 15165546743 0010264 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // --------------------------------------------------------------------------------------------------------------------- // == Ajax Response on creation of new booking // --------------------------------------------------------------------------------------------------------------------- /** * Response to Ajax request, about loading calendar data * * @return void */ function ajax_WPBC_AJX_BOOKING__CREATE() { /** * Tip / translation / * Please note, translation was loaded on hook add_action( 'plugins_loaded', 'wpbc_load_translation', 1000 ); and use $_REQUEST['wpbc_ajx_locale'], so do not worry about it. */ // Security ------------------------------------------------------------------------------------------------------ // in Ajax Post: 'nonce': _wpbc.get_secure_param( 'nonce' ), $action_name = 'wpbc_calendar_load_ajx' . '_wpbcnonce'; $nonce_post_key = 'nonce'; if ( wpbc_is_use_nonce_at_front_end() ) { //FixIn: 10.1.1.2 $result_check = check_ajax_referer( $action_name, $nonce_post_key ); } // Response AJAX parameters $ajx_data_arr = array(); $ajx_data_arr['status'] = 'ok'; $admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // 'wp-admin/admin.php?' // Local parameters $local_params = array(); $local_params['is_from_admin_panel'] = ( false !== strpos( $_SERVER['HTTP_REFERER'], $admin_uri ) ); // true | false $local_params['user_id'] = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // 1 // Request parameters $user_request = new WPBC_AJX__REQUEST( array( // Using this class here only for escaping variables 'db_option_name' => 'booking__wpbc_booking_create__request_params', // Not necessary, because we not save request, only sanitize it 'user_id' => $local_params['user_id'], // Not necessary, because we not save request, only sanitize it 'request_rules_structure' => array( 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // 'digit_or_csd' 'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ), 'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), //FixIn: 9.9.1.1 'formdata' => array( 'validate' => 'strong', 'default' => '' ), 'booking_hash' => array( 'validate' => 'strong', 'default' => '' ), 'custom_form' => array( 'validate' => 'strong', 'default' => '' ), 'captcha_chalange' => array( 'validate' => 'strong', 'default' => '' ), 'captcha_user_input' => array( 'validate' => 'strong', 'default' => '' ), 'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ), 'active_locale' => array( 'validate' => 'strong', 'default' => '' ) ) )); // Escape of request params in Ajax Post. We use prefix 'calendar_request_params', if Ajax sent - $_REQUEST['calendar_request_params']['resource_id'], ... $request_prefix = 'calendar_request_params'; //$_REQUEST['calendar_request_params']['dates_ddmmyy_csv'] .= "'%2b(select+'box'+from(select+sleep(2)+from+dual+where+1=1*)a)%2b'-02-21+00:00:00"; $request_params = $user_request->get_sanitized__in_request__value_or_default( $request_prefix ); // NOT Direct: $_REQUEST['calendar_request_params']['resource_id'] $request_params['request_uri'] = $_SERVER['HTTP_REFERER']; // Parameter needed for Error in booking saving and reloading calendar again with these actual parameters. // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CAPTCHA " > wpbc_captcha__in_ajx__check( $request_params, $local_params['is_from_admin_panel'], $_REQUEST[ $request_prefix ] ); // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING_RESOURCE ID " > if ( $request_params['resource_id'] <= 0 ) { $ajx_data_arr['status'] = 'error'; $ajx_data_arr['status_error'] = 'resource_id_incorrect'; $ajx_data_arr['ajx_after_action_message'] = 'Wrong ID of booking resource: ' . ' [ request ID: ' . $_REQUEST['calendar_request_params']['resource_id'] . ' | parsed ID: ' . $request_params['resource_id'] . ' ]'; $ajx_data_arr['ajx_after_action_message_status'] = 'error'; wp_send_json( array( 'ajx_data' => $ajx_data_arr, 'ajx_search_params' => $_REQUEST[ $request_prefix ], 'ajx_cleaned_params' => $request_params, 'resource_id' => $request_params['resource_id'] ) ); } // </editor-fold> $request_save_params = array( 'resource_id' => $request_params['resource_id'], 'dates_ddmmyy_csv' => $request_params['dates_ddmmyy_csv'], 'form_data' => $request_params['formdata'], 'aggregate_resource_id_arr' => $request_params['aggregate_resource_id_arr'], // Optional can be '' 'booking_hash' => $request_params['booking_hash'], 'custom_form' => $request_params['custom_form'], 'is_emails_send' => $request_params['is_emails_send'], 'is_show_payment_form' => 1, 'user_id' => $local_params['user_id'], 'request_uri' => $_SERVER['HTTP_REFERER'] ); $booking_save_arr = wpbc_booking_save( $request_save_params ); // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING " > if ( 'ok' !== $booking_save_arr['ajx_data']['status'] ) { wp_send_json( array( 'ajx_data' => $booking_save_arr['ajx_data'], 'ajx_search_params' => $_REQUEST[ $request_prefix ], 'ajx_cleaned_params' => $request_params, 'resource_id' => $request_params['resource_id'] )); } // </editor-fold> $ajx_data_arr = $booking_save_arr['ajx_data']; // TODO: If we have the calendar with specific capacity, then maybe showing by dots (the booked child booking resources) the slots and not the time slot ! if ( empty( $ajx_data_arr['ajx_after_action_message_status'] ) ) { $ajx_data_arr['ajx_after_action_message_status'] = 'success'; } if ( empty( $ajx_data_arr['ajx_after_action_message'] ) ) { $ajx_data_arr['ajx_after_action_message'] = ''; } // $ajx_data_arr['ajx_after_action_message'] .= __( 'Booking was created with ID: ' . $booking_save_arr[ 'booking_id' ] , 'booking' ); // $ajx_data_arr['ajx_after_action_message'] .= '<hr>Total time: <strong>' . $booking_save_arr['php_performance']['total'] . ' s. </strong>'; // $ajx_data_arr['ajx_after_action_message'] .= str_replace( array( ',', '{', '}' ), '<br>', json_encode( $booking_save_arr['php_performance'] ) ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* if admin edit ? var my_message = '<?php echo html_entity_decode( esc_js( __('Updated successfully' ,'booking') ),ENT_QUOTES) ; ?>'; wpbc_admin_show_message( my_message, 'success', 3000 ); location.href='<?php echo wpbc_get_bookings_url() ;?>&view_mode=vm_listing&tab=actions&wh_booking_id=<?php echo $is_edit_booking['booking_id'] ; ?>'; */ // ----------------------------------------------------------------------------------------------------------------- // == Ajax === // ----------------------------------------------------------------------------------------------------------------- /** * Send JSON. It will make "wp_json_encode" - so pass only array, and This function call wp_die( '', '', array( 'response' => null, ) ) . * Pass JS OBJ: response_data in "jQuery.post " function on success. * * Other End Ajax actions: * $error_obj = new WP_Error( 'WPBC_CREATE', __( 'test error.' ), 'some/data' ); wp_send_json_error( $error_obj ); * wp_send_json_error( array( 'message' => 'invalid-api-key' ) ); * wp_send_json_success( array( 'message' =>'Ok:)' ) ); */ wp_send_json( array( 'booking_id' => $booking_save_arr['booking_id'], 'resource_id' => $request_params['resource_id'], 'ajx_data' => $ajx_data_arr, 'ajx_confirmation' => $booking_save_arr['confirmation'], // For debug purpose <- comment in live serv 'php_process_times' => $booking_save_arr['php_performance'], 'booking_arr' => $booking_save_arr ['booking_arr'], // Not needed ? // 'ajx_search_params' => $_REQUEST[ $request_prefix ], // 'ajx_cleaned_params' => $request_params, ) ); } // Ajax Hooks if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) { add_action( 'wp_ajax_nopriv_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Client (not logged in) add_action( 'wp_ajax_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Logged In users (or admin panel) } // --------------------------------------------------------------------------------------------------------------------- // == Save Booking // --------------------------------------------------------------------------------------------------------------------- /** * Save Booking - ADD NEW or UPDATE exist booking * * @param $request_params = [ * resource_id = 2 REQUIRED Default: 1 * dates_ddmmyy_csv = '27.10.2023, 28.10.2023, 29.10.2023' REQUIRED * form_data = 'text^selected_short_dates_hint2^Fri, ...9, 2023~text^...' REQUIRED * booking_hash = '' Optional Default: '' * custom_form = '' Optional Default: '' * is_emails_send = 1 Optional Default: 1 * is_show_payment_form => 1 Optional Default: 1 * user_id = 1 Optional Default: 0 or ID of logged-in user * request_uri = 'http://beta/resource-id2/', // Optional Default: for front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER'] * * 'sync_gid' => 'ghjgjgjgh5f5f45f' // Really Optional: can be passed only during import .ics * 'is_approve_booking' => 0 // Really Optional: 0 | 1 * 'save_booking_even_if_unavailable' => 0 // Really Optional: 0 | 1, if 1 then force save booking even if dates unavailable. * ] * * @return [] ok: [ * * ] * error: [ * 'ajx_data': [ 'status':'error', 'status_error':'booking_can_not_save', 'ajx_after_action_message': 'Can not save booking', 'ajx_after_action_message_status': 'warning' ] * ] * * Example: * * wpbc_booking_save( array( * 'resource_id' => 2, * 'dates_ddmmyy_csv' => '04.10.2023, 05.10.2023, 06.10.2023', * 'form_data' => 'text^cost_hint2^150.00฿~selectbox-multiple^rangetime2[]^14:00 - 16:00~text^name2^John~text^secondname2^Smith~email^email2^john.smith@server.com~selectbox-one^visitors2^2~selectbox-one^children2^0~textarea^details2^test', * 'booking_hash' => '', * 'custom_form' => '', * 'is_emails_send' => 1, * 'is_show_payment_form' => 1, * 'user_id' => 1, * 'request_uri' => 'http://beta/resource-id2/' * ) ); * */ function wpbc_booking_save( $request_params ){ // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_START( 'total', array() ); // </editor-fold> $ajx_data_arr = array(); $ajx_data_arr['status'] = 'ok'; // ----------------------------------------------------------------------------------------------------------------- // 1. Direct Clean Params // ----------------------------------------------------------------------------------------------------------------- $validate_arr_rules = array( 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // INT 'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), //FixIn: 9.9.1.1 'form_data' => array( 'validate' => 'strong', 'default' => '' ), 'booking_hash' => array( 'validate' => 'strong', 'default' => '' ), 'custom_form' => array( 'validate' => 'strong', 'default' => '' ), 'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1 'is_show_payment_form' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1 'user_id' => array( 'validate' => 'd', 'default' => wpbc_get_current_user_id() ), // INT 'request_uri' => array( 'validate' => 'strong', 'default' => ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $_SERVER['HTTP_REFERER'] : $_SERVER['REQUEST_URI'] ), // front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER'] // Really Optional: 'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ), //TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' //FixIn: 10.0.0.7 'aggregate_type' => array( 'validate' => 'strong', 'default' => 'bookings_only' ), // Optional. 'all' | 'bookings_only' <- it is depends on shortcode parameter: options="{aggregate type=bookings_only}" 'is_approve_booking' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1 'save_booking_even_if_unavailable' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1 'sync_gid' => array( 'validate' => 'strong', 'default' => '' ), 'is_use_booking_recurrent_time' => array( 'validate' => 'd', 'default' => intval( ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) ) ) ); $re_cleaned_params = wpbc_sanitize_params_in_arr( $request_params, $validate_arr_rules ); $admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // wp-admin/admin.php? // ----------------------------------------------------------------------------------------------------------------- // Local parameters // ----------------------------------------------------------------------------------------------------------------- $local_params = array(); $local_params['is_from_admin_panel'] = ( false !== strpos( $re_cleaned_params['request_uri'], $admin_uri ) ); // true | false $local_params['user_id'] = $re_cleaned_params['user_id']; // 1 $local_params['sync_gid'] = $re_cleaned_params['sync_gid']; // '' $local_params['is_approve_booking'] = $re_cleaned_params['is_approve_booking']; // 0 | 1 $local_params['is_use_booking_recurrent_time'] = ( 1 === $re_cleaned_params['is_use_booking_recurrent_time'] ); // false | true // ----------------------------------------------------------------------------------------------------------------- // Parse Local parameters for later use // ----------------------------------------------------------------------------------------------------------------- /** * Get parsed booking form: = [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ] */ $local_params['structured_booking_data_arr'] = wpbc_get_parsed_booking_data_arr( $re_cleaned_params["form_data"], $re_cleaned_params["resource_id"], array( 'get' => 'value' ) ); $local_params['all_booking_data_arr'] = wpbc_get_parsed_booking_data_arr( $re_cleaned_params["form_data"], $re_cleaned_params["resource_id"] ); // Important! : [ 64800, 72000 ] $local_params['time_as_seconds_arr'] = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $local_params['structured_booking_data_arr'] ); // [ "18:00:00", "20:00:00" ] $time_as_seconds_arr = $local_params['time_as_seconds_arr']; $time_as_seconds_arr[0] = ( 0 != $time_as_seconds_arr[0] ) ? $time_as_seconds_arr[0] + 1 : $time_as_seconds_arr[0]; // set check in time with ended 1 second $time_as_seconds_arr[1] = ( ( 24 * 60 * 60 ) != $time_as_seconds_arr[1] ) ? $time_as_seconds_arr[1] + 2 : $time_as_seconds_arr[1]; // set check out time with ended 2 seconds if ( ( 0 != $time_as_seconds_arr[0] ) && ( ( 24 * 60 * 60 ) == $time_as_seconds_arr[1] ) ) { //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 $time_as_seconds_arr[1] += - 8; } $local_params['time_as_his_arr'] = array( wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ), wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] ) ); // [ '2023-09-10', '2023-09-11' ] $local_params['dates_only_sql_arr'] = wpbc_convert_dates_str__dd_mm_yyyy__to__yyyy_mm_dd( $re_cleaned_params["dates_ddmmyy_csv"] ); $local_params['dates_only_sql_arr'] = explode( ',', $local_params['dates_only_sql_arr'] ); $local_params['is_show_payment_form'] = $re_cleaned_params["is_show_payment_form"]; //FixIn: 9.9.0.35 if ( $local_params['is_show_payment_form'] ) { $local_params['is_show_payment_form'] = ( false !== strpos( $re_cleaned_params['request_uri'], 'is_show_payment_form=Off' ) ) ? 0 : $local_params['is_show_payment_form']; // 1|0 } // Get EDIT booking data $local_params['edit_resource_id'] = ''; $local_params['skip_booking_id'] = ''; $local_params['is_edit_booking'] = 0; $local_params['is_duplicate_booking'] = 0; $is_edit_booking = wpbc_get_data__if_edit_booking( $re_cleaned_params['booking_hash'], $re_cleaned_params['request_uri'] ); if ( false !== $is_edit_booking ) { $local_params['edit_resource_id'] = $is_edit_booking['resource_id']; // can be parent booking resource, where we edit the booking $local_params['skip_booking_id'] = $is_edit_booking['booking_id']; // booking ID $local_params['is_edit_booking'] = $is_edit_booking['booking_id']; // booking ID if ( ( ! empty( $local_params['structured_booking_data_arr']['wpbc_other_action'] ) ) && ( 'duplicate_booking' === $local_params['structured_booking_data_arr']['wpbc_other_action'] ) ){ $local_params['is_duplicate_booking'] = 1; } } // It can be request resource ID or if we edit booking, it can be 'edit resource' - (e.g. child resource) $local_params['initial_resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) ? $local_params['edit_resource_id'] : $re_cleaned_params['resource_id']; // 2 $local_params['how_many_items_to_book'] = wpbc_get__how_many_items_to_book__in_booking_form( $local_params['structured_booking_data_arr'], $local_params['initial_resource_id'] ); $local_params['aggregate_resource_id_arr'] = explode( ',', $re_cleaned_params['aggregate_resource_id_arr'] ); $local_params['aggregate_resource_id_arr'] = array_filter( $local_params['aggregate_resource_id_arr'] ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. $local_params['aggregate_resource_id_arr'] = array_unique( $local_params['aggregate_resource_id_arr'] ); // Erase duplicates // ----------------------------------------------------------------------------------------------------------------- // Here GO // ----------------------------------------------------------------------------------------------------------------- // Force - resource saving parameters, instead of wpbc__where_to_save_booking() if ( ! empty( $re_cleaned_params["save_booking_even_if_unavailable"] ) ) { $local_params['how_many_items_to_book'] = 1; $dates_keys_arr = array_values( $local_params['dates_only_sql_arr'] ); // [ '2023-09-23', '2023-09-24' ] $resources_in_dates = array_fill_keys( $dates_keys_arr , array( $local_params['initial_resource_id'] ) ); // [ 2023-09-23 = [ 2 ], 2023-09-24 = [ 2 ] ] $where_to_save_booking = array(); $where_to_save_booking['result'] = 'ok'; $where_to_save_booking['resources_in_dates'] = $resources_in_dates; // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ] $where_to_save_booking['time_to_book'] = $local_params['time_as_his_arr']; // [ "00:00:00", "24:00:00" ] $where_to_save_booking['main__resource_id'] = $local_params['initial_resource_id']; // here edit or request (parent/single) resource } else { // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_START( 'wpbc__where_to_save_booking' , $php_performance ); // </editor-fold> /** * Get slots [] where we can save booking = [ 'resources_in_dates' => [ 2023-10-18 = [ 2, 12, 10, 11 ] * 2023-10-19 = [ 2, 12, 10, 11 ] * 2023-10-20 = [ 2, 12, 10, 11 ] * ], * 'time_to_book' => [ "14:00:01" , "12:00:01" ], * 'result' => 'ok' * 'main__resource_id' => 2 * ] * OR * [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ] */ $where_to_save_booking = wpbc__where_to_save_booking( array( 'resource_id' => $local_params['initial_resource_id'], // 2 //TODO: If edit booking. What to pass 'edit' or 'parent' resource ID? 'skip_booking_id' => $local_params['skip_booking_id'], // '', | 125 if edit booking 'dates_only_sql_arr' => $local_params['dates_only_sql_arr'], // [ "2023-10-18", "2023-10-25", "2023-11-25" ] 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], // [ 36000, 39600 ] 'how_many_items_to_book' => $local_params['how_many_items_to_book'], // 1 'request_uri' => $re_cleaned_params['request_uri'], // 'http://beta/resource-id2/' 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], // true | false 'as_single_resource' => false, // false 'aggregate_resource_id_arr' => $local_params['aggregate_resource_id_arr'], // Optional can be '' 'aggregate_type' => $re_cleaned_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 'custom_form' => $re_cleaned_params['custom_form'] //FixIn: 10.0.0.10 )); // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- NO SLOTS TO SAVE " > if ( 'error' == $where_to_save_booking['result'] ) { $ajx_data_arr['status'] = 'error'; $ajx_data_arr['status_error'] = 'booking_can_not_save'; $ajx_data_arr['ajx_after_action_message'] = $where_to_save_booking['message']; $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; return array( 'ajx_data' => $ajx_data_arr ); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'wpbc__where_to_save_booking' , $php_performance ); // </editor-fold> } // Get parameters, from REQUEST $create_params = $local_params; $create_params['resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) ? $local_params['edit_resource_id'] // If we edit, then use original resource ??? : $where_to_save_booking['main__resource_id']; // Here is important TIP, resource can be where is free, and not where we submit /** * TODO: I think it's resolved! Just test about this situation, when we edit the booking - and it's means that we have $local_params['edit_resource_id'] * but what, if $where_to_save_booking do not contain this $local_params['edit_resource_id'] as available resource. * or even we have $local_params['edit_resource_id'] = 2 and $where_to_save_booking contain resources like [ 1, 2, 3, 4 ] * we make booking for 3 slots * in this case, main resource will be 2 * but then when we loop resources in wpbc_db__booking_save() we will save child booking resources for dates like: 2, 3, 4 ( and it's wrong ) * "(205, '2023-10-04 00:00:00', 0, NULL)" <- main resource '2' e.g. $local_params['edit_resource_id'] = 2 * "(205, '2023-10-04 00:00:00', 0, 2)" ? <- child resource '2' e.g. [ .., 2, .. ] in $where_to_save_booking WHICH IS WRONG */ $create_params['is_emails_send'] = $re_cleaned_params['is_emails_send']; $create_params['custom_form'] = $re_cleaned_params['custom_form']; make_bk_action( 'check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Activate working with specific user in WP MU // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_START( 'wpbc_db__booking_save' , $php_performance ); // </editor-fold> // ----------------------------------------------------------------------------------------------------------------- // == CREATE_THE 'NEW_BOOKING' == // ----------------------------------------------------------------------------------------------------------------- $create_booking_params = array( 'resource_id' => $create_params['resource_id'], 'custom_form' => $create_params['custom_form'], 'all_booking_data_arr' => $create_params['all_booking_data_arr'], 'dates_only_sql_arr' => $create_params['dates_only_sql_arr'], 'time_as_his_arr' => $create_params['time_as_his_arr'], 'is_from_admin_panel' => $create_params['is_from_admin_panel'], 'is_edit_booking' => $create_params['is_edit_booking'], 'is_duplicate_booking' => $create_params['is_duplicate_booking'], 'is_approve_booking' => $create_params['is_approve_booking'], 'how_many_items_to_book' => $create_params['how_many_items_to_book'], 'is_use_booking_recurrent_time' => $create_params['is_use_booking_recurrent_time'] // true | false ); if ( ! empty( $create_params['sync_gid'] ) ) { $create_booking_params['sync_gid'] = $create_params['sync_gid']; } $booking_new_arr = wpbc_db__booking_save( $create_booking_params, $where_to_save_booking ); // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING CREATION " > if ( 'ok' !== $booking_new_arr['status'] ) { $ajx_data_arr['status'] = $booking_new_arr['status']; $ajx_data_arr['status_error'] = 'booking_can_not_save'; $ajx_data_arr['ajx_after_action_message'] = $booking_new_arr['message']; $ajx_data_arr['ajx_after_action_message_status'] = 'error'; return array( 'ajx_data' => $ajx_data_arr ); } // </editor-fold> //FixIn: 9.9.0.36 if ( ( 0 !== $create_params['is_edit_booking'] ) // If edit booking && ( 1 != $create_params['is_duplicate_booking'] ) // If not duplicate ) { // Log the cost info. $is_add_timezone_offset = true; $booking_note = wpbc_date_localized( gmdate( 'Y-m-d H:i:s' ), '[Y-m-d H:i]', $is_add_timezone_offset ) . ' '; $booking_note .= __( 'The booking has been edited', 'booking' ) . '. | Edit URL: ' . esc_url_raw( $re_cleaned_params['request_uri'] ) . ''; make_bk_action( 'wpdev_make_update_of_remark', $booking_new_arr['booking_id'], $booking_note, true ); } // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'wpbc_db__booking_save' , $php_performance ); // </editor-fold> // ----------------------------------------------------------------------------------------------------------------- // Get payment form(s) and Update COST of the booking // ----------------------------------------------------------------------------------------------------------------- $payment_params = array(); // Usually we have this: ( $str_dates__dd_mm_yyyy == $create_params['dates_only_sql_arr'] ) - but for ensure, use saved dates, e.g. $str_dates__dd_mm_yyyy $payment_params['booked_dates_times_arr'] = array( 'dates_ymd_arr' => array_keys( $where_to_save_booking['resources_in_dates'] ), // [ 2023-10-20=>[], 2023-10-25=>[] ] -> [ "2023-10-20", "2023-10-25" ] 'times_his_arr' => $where_to_save_booking['time_to_book'] // ['16:00:01', '18:00:02'] ); $str_dates__dd_mm_yyyy = wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $payment_params['booked_dates_times_arr']['dates_ymd_arr'] ); // ['2023-10-20','2023-10-25'] => ['20.10.2023','25.10.2023'] $payment_params['str_dates__dd_mm_yyyy'] = implode( ',', $str_dates__dd_mm_yyyy ); // REQUIRED -- '14.11.2023, 15.11.2023, 16.11.2023, 17.11.2023' $payment_params['booking_id'] = $booking_new_arr['booking_id']; // REQUIRED -- '2' $payment_params['resource_id'] = $create_params['resource_id']; // REQUIRED -- '2' can be child resource (changed in wpbc_where_to_save() ) $payment_params['initial_resource_id'] = $local_params['initial_resource_id']; // REQUIRED -- '2' initial calendar - parent resource $payment_params['form_data'] = $booking_new_arr['form_data']; // we re-save it, because here can be sync_guid and custom form new data from wpbc_db__booking_save(..) // REQUIRED -- 'text^selected_short_timedates_hint4^06/11/2018 14:00...' $payment_params['times_array'] = array( explode( ':', $where_to_save_booking['time_to_book'][0] ), // ["10","00","00"] explode( ':', $where_to_save_booking['time_to_book'][1] ) // ["12","00","00"] ); // Additional options $payment_params['is_edit_booking'] = $create_params['is_edit_booking']; // => 0 0 | int - ID of the booking $payment_params['custom_form'] = $create_params['custom_form']; // => '' '' | 'some_name' $payment_params['is_duplicate_booking'] = $create_params['is_duplicate_booking']; // => 0 0 | 1 $payment_params['is_from_admin_panel'] = $create_params['is_from_admin_panel']; // => false true | false $payment_params['is_show_payment_form'] = $create_params['is_show_payment_form']; // => 1 0 | 1 if ( $payment_params['is_from_admin_panel'] ) { // $payment_params['is_show_payment_form'] = 0; //FixIn: 9.9.0.21 } // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_START( 'wpbc_maybe_get_payment_form' , $php_performance ); // </editor-fold> // GET PAYMENT FORMS =============================================================================================== if ( function_exists( 'wpbc_maybe_get_payment_form' ) ) { $response__payment_form__arr = wpbc_maybe_get_payment_form( $payment_params ); // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- COSTS || PAYMENT_SYSTEMS " > if ( ( ! empty( $response__payment_form__arr['status'] ) ) && ( 'ok' != $response__payment_form__arr['status'] ) ) { $ajx_data_arr['status'] = $response__payment_form__arr['status']; $ajx_data_arr['status_error'] = 'booking_can_not_save'; $ajx_data_arr['ajx_after_action_message'] = $response__payment_form__arr['message']; $ajx_data_arr['ajx_after_action_message_status'] = 'error'; return array( 'ajx_data' => $ajx_data_arr ); } // </editor-fold> if ( ! empty( $response__payment_form__arr['costs_arr']['form_data'] ) ) { $payment_params['form_data'] = $response__payment_form__arr['costs_arr']['form_data']; // we re-save it, because here can be [cost_correction] shortcode data } //TODO: Do we really need this in output $ajx_data_arr ???, because it stored in $confirmation if ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) { $ajx_data_arr['gateways_output_arr'] = $response__payment_form__arr['gateways_output_arr']; } if ( function_exists( 'wpbc_if_zero_cost__approve_booking_dates' ) ) { wpbc_if_zero_cost__approve_booking_dates( $payment_params['booking_id'] ); } } else { $response__payment_form__arr = $payment_params; $response__payment_form__arr['status'] = 'ok'; } // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'wpbc_maybe_get_payment_form' , $php_performance ); $php_performance = php_performance_START( 'emails_sending' , $php_performance ); // </editor-fold> // ----------------------------------------------------------------------------------------------------------------- // == Emails === // ----------------------------------------------------------------------------------------------------------------- if ( 1 == $re_cleaned_params['is_emails_send'] ) { $email_content = $payment_params['form_data']; // If we output any text, then probably it's errors or warnings, we need to catch them ob_start(); ob_clean(); if ( ( 0 === $local_params['is_edit_booking'] ) || ( 1 === $local_params['is_duplicate_booking'] ) //FixIn: 10.0.0.42 ){ // New booking to Admin wpbc_send_email_new_admin( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ); // New pending to Visitor wpbc_send_email_new_visitor( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ) ; $is_booking_approved = wpbc_is_booking_approved( $payment_params['booking_id'] ); if ( $is_booking_approved ) { // New approved to Visitor / Admin wpbc_send_email_approved( $payment_params['booking_id'], 1 ); } // Payment request from admin panel, if needed if( ( $payment_params['is_from_admin_panel'] ) && ( 'On' == get_bk_option( 'booking_payment_request_auto_send_in_bap' ) ) && ( function_exists( 'wpbc_send_email_payment_request' ) ) ){ $payment_reason = ''; $is_send = wpbc_send_email_payment_request( $payment_params['booking_id'], $payment_params['resource_id'], $email_content , $payment_reason ); } do_action( 'wpbc_booking_approved' , $payment_params['booking_id'] , (int) $is_booking_approved ); } else { // Edited booking to Visitor / Admin if ( function_exists( 'wpbc_send_email_modified' ) ) { wpbc_send_email_modified( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ); } } $errors_on_email_sending_html = ob_get_contents(); ob_end_clean(); if ( ! empty( $errors_on_email_sending_html ) ) { // Show these messages as warning after creation of the booking $errors_on_email_sending_html = strip_tags( $errors_on_email_sending_html ); $errors_on_email_sending_html = esc_attr( $errors_on_email_sending_html ); $errors_on_email_sending_html = str_replace( "\\n", '', $errors_on_email_sending_html ); $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; $ajx_data_arr['ajx_after_action_message'] = $errors_on_email_sending_html; } } // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'emails_sending' , $php_performance ); // </editor-fold> // ----------------------------------------------------------------------------------------------------------------- // == Track booking - New | Edit === // ----------------------------------------------------------------------------------------------------------------- /** * Useful hook for Google Ads Conversion tracking. How to use this hook? * * Add code similar to this in your functions.php file in your theme, or in some other php file: * // Track adding new booking // // @param $params = array ( // 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023', // 'booking_id' => 254, // 'resource_id' => 11, // child or parent or single // 'initial_resource_id' => 2, // parent or single // 'form_data' => 'text^selected_short_dates_hint11^Sun...', // 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ), // 'is_edit_booking' => 0, // 'custom_form' => '', // 'is_duplicate_booking' => 0, // 'is_from_admin_panel' => false, // 'is_show_payment_form' => 1 // ) function my_booking_tracking( $params ){ // Your code here ?><!-- Google Code for Booking Conversion Page --> <script type="text/javascript"> // Insert bellow your Google Conversion Code </script><?php } add_action( 'wpbc_track_new_booking', 'my_booking_tracking' ); * * * * Useful hook booking edit tracking * * Add code similar to this in your functions.php file in your theme, or in some other php file: * // Track edit existing booking // // @param $params = array ( // 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023', // 'booking_id' => 254, // 'resource_id' => 11, // child or parent or single // 'initial_resource_id' => 2, // parent or single // 'form_data' => 'text^selected_short_dates_hint11^Sun...', // 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ), // 'is_edit_booking' => 1, // 'custom_form' => '', // 'is_duplicate_booking' => 0, // 'is_from_admin_panel' => false, // 'is_show_payment_form' => 1 // ) function my_edit_booking_tracking( $params ){ // Your code here ?><!-- Google Code for Booking Conversion Page --> <script type="text/javascript"> // Insert bellow your Google Conversion Code </script><?php } add_action( 'wpbc_track_edit_booking', 'my_edit_booking_tracking' ); */ if ( 0 === $local_params['is_edit_booking'] ) { do_action( 'wpbc_track_new_booking', $payment_params ); } else { do_action( 'wpbc_track_edit_booking', $payment_params ); } // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_START( 'confirmation' , $php_performance ); // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Confirmation data == " > $confirmation_params_arr = array( 'is_from_admin_panel' => $payment_params['is_from_admin_panel'], 'booking_id' => $booking_new_arr['booking_id'], // 16102023 'resource_id' => $payment_params['resource_id'], // 1 'form_data' => $payment_params['form_data'], // 'text^selected_short_dates_hint11^Sun...', 'dates_ymd_arr' => $payment_params['booked_dates_times_arr']['dates_ymd_arr'], // [ '2023-10-20', '2023-10-25' ] 'times_his_arr' => $payment_params['booked_dates_times_arr']['times_his_arr'], // [ '16:00:01', '18:00:02' ] 'total_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['total_cost'] ) ) ? $response__payment_form__arr['costs_arr']['total_cost'] : 0, 'deposit_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['deposit_cost'] ) ) ? $response__payment_form__arr['costs_arr']['deposit_cost'] : 0, 'booking_summary' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['booking_summary'] ) ) ) ? $response__payment_form__arr['gateways_output_arr']['booking_summary'] : '', 'gateway_rows' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['gateway_rows'] ) ) ) ? $response__payment_form__arr['gateways_output_arr']['gateway_rows'] : '' ); // It will not show payment form in Booking > Add booking page and if defined, do not make redirect if ( $payment_params['is_from_admin_panel'] ) { $confirmation_params_arr['ty_is_redirect'] = 'message'; // Do not make redirect, if it's in admin panel! // But if we edit / duplicate the booking, then do redirection to Booking Listing page //FixIn: 9.9.0.3 if ( ( 0 !== $local_params['is_edit_booking'] ) // && ( empty( $local_params['is_duplicate_booking'] ) ) ){ $confirmation_params_arr['ty_is_redirect'] = 'page'; $confirmation_params_arr['ty_url'] = wpbc_get_bookings_url() . '&view_mode=vm_listing&tab=actions&wh_booking_id=' . $confirmation_params_arr['booking_id']; } } $confirmation = wpbc_booking_confirmation( $confirmation_params_arr ); // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'confirmation' , $php_performance ); // </editor-fold> make_bk_action( 'finish_check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Deactivate working with specific user in WP MU // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > $php_performance = php_performance_END( 'total' , $php_performance ); $php_performance['other_code'] = - 1 * array_reduce( $php_performance, function ( $sum, $item ) { $sum += $item; return $sum; } , - 2 * $php_performance['total'] ); // PERFORMANCE OTHER - after TOTAL // </editor-fold> return array( 'ajx_data' => $ajx_data_arr, // [ 'status' => "ok", 'wpbc_payment_output' => "<p>Dear John<br..." ] 'booking_id' => $booking_new_arr['booking_id'], // 254 'booking_arr' => $payment_params, 'php_performance' => $php_performance, // [ ... ] 'confirmation' => $confirmation // [ ] ); } // --------------------------------------------------------------------------------------------------------------------- // New booking creation sub functions // --------------------------------------------------------------------------------------------------------------------- /** * Save booking in DB * * @param array $create_params = [ * 'resource_id' => 10, * 'dates_only_sql_arr' => [ '2023-10-04', '2023-10-05', '2023-10-06'], * 'time_as_his_arr' => [ '14:00:01', '16:00:02' ], * 'is_from_admin_panel' => false, * 'is_edit_booking' => 0, * 'is_duplicate_booking' => 0, * 'is_approve_booking' => 0, * 'how_many_items_to_book' => 2, * 'custom_form' => '', * 'is_use_booking_recurrent_time' => false, * 'all_booking_data_arr' => [ 'rangetime' => [ * 'type' => 'selectbox-multiple', * 'original_name' => 'rangetime2[]', //NOTE: here RESOURCE ID (2) can be from Parent resource, but resource_id can rely on child (10) resource * 'name' => 'rangetime', * 'value' => '14:00 - 16:00', * ], * 'name' => [ 'type' => 'text', 'original_name' => 'name2', ... ], * ... * ] * ] * * @param $where_to_save_booking = [ * 'result' = 'ok', * 'main__resource_id' = 2 * 'resources_in_dates' = [ 2023-10-18 = [ 2, 12, 10, 11 ] * 2023-10-19 = [ 2, 12, 10, 11 ] * 2023-10-20 = [ 2, 12, 10, 11 ] * ], * 'time_to_book' = [ "14:00:01" , "16:00:02" ] * ] * * @return [ * 'status' => 'ok' 'ok' | 'error' | 'warning' * 'booking_id' => 100 int * 'message' => '' 'If error, then here can be description of error' * 'form_data' => If 'ok' form data can be different here, 'custom_form' parameter, so it can add 'wpbc_custom_booking_form' field for identification, what custom booking form was used, * ] */ function wpbc_db__booking_save( $create_params, $where_to_save_booking ) { /** * Tip: $create_params['all_booking_data_arr'] - contain: [ 'field_name' => [ 'type' = "checkbox", 'original_name' = "fixed_fee2[]", 'name' = "fixed_fee", 'value' = "true" ] , ... ] * $create_params['structured_booking_data_arr'] - contain: [ 'field_name' => 'field_value' , ... ] */ // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- 'Wrong resource ID " > if ( empty( $create_params['resource_id'] ) ) { return array( 'status' => 'error', 'message' => 'Wrong ID of booking resource: ' . $create_params['resource_id'] ); } // </editor-fold> $defaults = array( 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) ); $create_params = wp_parse_args( $create_params, $defaults ); $sql_field_arr = array(); // Is it was used custom booking form ? if ( ! empty( $create_params['custom_form'] ) ) { $create_params['all_booking_data_arr']['wpbc_custom_booking_form'] = array( 'type' => 'text', 'original_name' => 'wpbc_custom_booking_form' . $create_params['resource_id'], 'name' => 'wpbc_custom_booking_form', 'value' => $create_params['custom_form'] ); } if ( ! empty( $create_params['sync_gid'] ) ) { /** * Such fields are comming from '../wp-content/plugins/booking/core/sync/wpbc-gcal-class.php' in function run() */ // Escape any XSS injection from values in booking form list( $create_params['sync_gid'] ) = wpbc_escape_any_xss_in_arr( array( $create_params['sync_gid'] ) ); $sql_field_arr[] = array( 'name' => 'sync_gid', 'type' => '%s', 'value' => $create_params['sync_gid'] ); } // Escape any XSS injection from values in booking form $create_params['all_booking_data_arr'] = wpbc_escape_any_xss_in_arr( $create_params['all_booking_data_arr'] ); //Set LAST check out day as AVAILABLE - remove it if ( ( 'On' === get_bk_option( 'booking_last_checkout_day_available' ) ) && ( ! empty( $create_params['dates_only_sql_arr'] ) ) && ( count( $create_params['dates_only_sql_arr'] ) > 1 ) ) { unset( $create_params['dates_only_sql_arr'][ ( count( $create_params['dates_only_sql_arr'] ) - 1 ) ] ); // Remove LAST selected day in calendar //FixIn: 6.2.3.6 // Delete last item //FixIn: 9.9.0.19 $resources_in_dates_last_key = key( array_slice( $where_to_save_booking['resources_in_dates'], - 1, 1, true ) ); unset( $where_to_save_booking['resources_in_dates'][ $resources_in_dates_last_key ] ); } // :: ERROR :: if ( empty( $create_params['dates_only_sql_arr'] ) ) { // No dates :? return array( 'status' => 'error', 'message' => 'Sent request with no dates.' ); } // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CHECK_IN_DATE_OLDER_THAN_CHECK_OUT " > if ( count( $create_params['dates_only_sql_arr'] ) == 1 ) { // Is it single selected date ? // Is 'check in' date/time older than 'check out' date/time when SINGLE day for booking? Then show error. /** * If we are having "change over" days activated and selected only 1 day in calendar, * then we can have error: "Warning! Number of check in != check out times.", because "check in" day older than "check out" date. */ $is_apply__check_in_out__10s = false; $datestamp_check_in = wpbc_convert__sql_date__to_seconds( $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][0], $is_apply__check_in_out__10s ); $datestamp_check_out = wpbc_convert__sql_date__to_seconds( $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][1], $is_apply__check_in_out__10s ); if ( $datestamp_check_in > $datestamp_check_out ) { $error_message = sprintf( 'Error! Your check in date %s older than check out date %s. <br>Try to select more dates or use different time.' , '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_in, $is_apply__check_in_out__10s ) . '</strong>' , '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_out, $is_apply__check_in_out__10s ) . '</strong>' ); $error_message .= '<br>' . '<strong>Settings that can be reason of the issue:</strong> '; if( 'On' === get_bk_option( 'booking_last_checkout_day_available' )){ $error_message .= '<br>' . 'You have enabled <strong>"Set check out date as available"</strong> option at Booking > Settings General page in "Calendar" section. '; } if ( 'On' === get_bk_option( 'booking_range_selection_time_is_active' ) ){ $error_message .= '<br>' . 'You have enabled <strong>"Use changeover days"</strong> option at Booking > Settings General page in "Calendar" section with check-in/out times: ' . get_bk_option( 'booking_range_selection_start_time' ) . '/' . get_bk_option( 'booking_range_selection_end_time' ); } if ( $create_params['is_use_booking_recurrent_time'] ) { $error_message .= '<br>' . 'You have enabled <strong>"Use time selections as recurrent time slots"</strong> option at Booking > Settings General page in "Calendar" section. '; } return array( 'status' => 'error', 'message' => $error_message ); } } // </editor-fold> // Compose form data for DB. Can be different resource: 'selectbox-multiple^rangetime10[]^14..' <-> 'selectbox-multiple^rangetime2[]^14..' -> 'rangetime10' - child res. Previously 'rangetime2' - parent $form_data = wpbc_encode_booking_data_to_string( $create_params['all_booking_data_arr'], $create_params['resource_id'] ); // ----------------------------------------------------------------------------------------------------------------- // APPROVED / PENDING // ----------------------------------------------------------------------------------------------------------------- // Is approve booking $auto_approve_new_bookings_is_active = trim( get_bk_option( 'booking_auto_approve_new_bookings_is_active' ) ); $is_approved_dates = ( $auto_approve_new_bookings_is_active == 'On' ) ? 1 : intval( $create_params['is_approve_booking'] ); // Auto approve only for specific booking resources /** * How to use "Auto approve bookings only for specific booking resources" ? * Add code similar to this in your functions.php file in your theme, or in some other php file: * function my_wpbc_get_booking_resources_arr_to_auto_approve( $resources_to_approve ) { $resources_to_approve = array( 9, 12, 33 ); // Array of booking resources ID, which you need to auto approve return $resources_to_approve; } add_filter( 'wpbc_get_booking_resources_arr_to_auto_approve', 'my_wpbc_get_booking_resources_arr_to_auto_approve' ); */ $booking_resources_to_approve = array(); $booking_resources_to_approve = apply_filters( 'wpbc_get_booking_resources_arr_to_auto_approve', $booking_resources_to_approve ); //FixIn: 8.5.2.27 if ( in_array( $create_params['resource_id'], $booking_resources_to_approve ) ) { $is_approved_dates = 1; } if ( ( $create_params['is_from_admin_panel'] ) // true | false && ( get_bk_option( 'booking_auto_approve_bookings_if_added_in_admin_panel' ) == 'On' ) ){ //FixIn: 8.1.3.27 $is_approved_dates = 1; } // <editor-fold defaultstate="collapsed" desc=" == Save Booking == " > // ----------------------------------------------------------------------------------------------------------------- // Save Booking // ----------------------------------------------------------------------------------------------------------------- global $wpdb; $sql_field_arr[] = array( 'name' => 'form', 'type' => '%s', 'value' => $form_data ); $sql_field_arr[] = array( 'name' => 'booking_type', 'type' => '%d', 'value' => $create_params['resource_id'] ); $sql_field_arr[] = array( 'name' => 'modification_date', 'type' => '%s', 'value' => gmdate( 'Y-m-d H:i:s' ) ); $sql_field_arr[] = array( 'name' => 'sort_date', 'type' => '%s', 'value' => $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][0] ); $sql_field_arr[] = array( 'name' => 'hash', 'type' => 'MD5(%s)', 'value' => time() . '_' . rand( 1000, 1000000 ) ); if ( ( 0 == $create_params['is_edit_booking'] ) // If not edit, then INSERT || ( 1 == $create_params['is_duplicate_booking'] ) // If duplicate, then INSERT ){ // Saved only for new booking creation. $sql_field_arr[] = array( 'name' => 'creation_date', 'type' => '%s', 'value' => gmdate( 'Y-m-d H:i:s' ) ); $sql_prepare_arr = array(); $sql_prepare_arr['name'] = array_map( function ( $value ) { return $value['name']; }, $sql_field_arr ); $sql_prepare_arr['type'] = array_map( function ( $value ) { return $value['type']; }, $sql_field_arr ); $sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr ); $sql_prepare_arr['name'] = implode( ', ', $sql_prepare_arr['name'] ); $sql_prepare_arr['type'] = implode( ', ', $sql_prepare_arr['type'] ); $sql = $wpdb->prepare( "INSERT INTO {$wpdb->prefix}booking " . " ( {$sql_prepare_arr['name']} )" . " VALUES ( {$sql_prepare_arr['type']} )" , $sql_prepare_arr['value'] ); if ( false === $wpdb->query( $sql ) ) { return array( 'status' => 'error','message' => 'Error. INSERT New Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql ); } // Get ID of booking $booking_id = (int) $wpdb->insert_id; } else { // Edit - UPDATE $booking_id = (int) $create_params['is_edit_booking']; $sql_prepare_arr = array(); $sql_prepare_arr['set'] = array_map( function ( $value ) { return $value['name'] . '=' . $value['type']; }, $sql_field_arr ); $sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr ); $sql_prepare_arr['set'] = implode( ', ', $sql_prepare_arr['set'] ); $sql = $wpdb->prepare( "UPDATE {$wpdb->prefix}booking SET " . " {$sql_prepare_arr['set']} " . " WHERE booking_id={$booking_id};" , $sql_prepare_arr['value'] ); if ( false === $wpdb->query( $sql ) ){ return array( 'status' => 'error','message' => 'Error. UPDATE Exist Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql ); } // Check if dates previously was approved. $slct_sql = "SELECT approved FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id}) LIMIT 0,1"; $slct_sql_results = $wpdb->get_results( $slct_sql ); $is_approved_dates = ( count( $slct_sql_results ) > 0 ) ? $slct_sql_results[0]->approved : $is_approved_dates; $delete_sql = "DELETE FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id})"; if ( false === $wpdb->query( $delete_sql ) ){ return array( 'status' => 'error','message' => 'Error. DELETE Old Dates in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $delete_sql ); } } // </editor-fold> // <editor-fold defaultstate="collapsed" desc=" == Compose D A T E S for DB == " > // ----------------------------------------------------------------------------------------------------------------- // Compose D A T E S for DB // ----------------------------------------------------------------------------------------------------------------- if ( class_exists( 'wpdev_bk_biz_l' ) ) { $field_names_arr = array( 'booking_id', 'booking_date', 'approved', 'type_id' ); } else { $field_names_arr = array( 'booking_id', 'booking_date', 'approved' ); } $field_names = implode( ', ', $field_names_arr ); $dates_sql = "INSERT INTO {$wpdb->prefix}bookingdates ( {$field_names} ) VALUES "; $insert_dates_arr = array(); $how_many_items_to_book = $create_params['how_many_items_to_book']; // $i - INDEX of child booking resource to book (if $how_many_items_to_book=1, then index always = 0 ) in [ 'resources_in_dates' = [ '2023-10-18' = [ 9, 12, 10, 11 ], ... ]...] - e.g. here = 9 for( $i = 0; $i < $how_many_items_to_book; $i++) { $date_number = 0; foreach ( $where_to_save_booking['resources_in_dates'] as $only_date_sql => $resources_in_date_arr ) { $date_resource_id = $resources_in_date_arr[ $i ]; // $create_params['resource_id'] <- Main resource (saved in wp_booking ) // $only_date_sql <- '2023-09-12' // $date_resource_id <- Child resource (need to save in wp_bookingdates) OR if ( $create_params['resource_id'] == $date_resource_id ) then NULL // --------------------------------------------------------------------------------------------------------- // Is full day booking: if ( ( '00:00' === substr( $where_to_save_booking['time_to_book'][0], 0, 5 ) ) && ( ( '24:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) ) || ( '00:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) ) ) ){ // Full days ******************************************************************************************* $full_date_sql = $only_date_sql . ' 00:00:00'; $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); } else { // Times if ( ( $create_params['is_use_booking_recurrent_time'] ) // Activated option to book times as 'time-slots' OR || ( 1 === count( $where_to_save_booking['resources_in_dates'] ) ) // Selected only 1 date, so use time as time-slot ) { // Time slots in each day ************************************************************************** // Start Time $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0]; $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); // End Time $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1]; $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); } else { // Check in/out ************************************************************************************ if ( 0 == $date_number ) { // Is check in ? $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0]; } else if ( ( count( $where_to_save_booking['resources_in_dates'] ) - 1 ) == $date_number ) { // Is check out ? $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1]; } else { // Middle date - Full Date $full_date_sql = $only_date_sql . ' 00:00:00'; } $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] ); } } // --------------------------------------------------------------------------------------------------------- $date_number++; } } $dates_sql .= implode( ', ', $insert_dates_arr ); if ( false === $wpdb->query( $dates_sql ) ) { return array( 'status' => 'error','message' => 'Error. INSERT "D A T E S" in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $dates_sql ); } // ----------------------------------------------------------------------------------------------------------------- // End D A T E S // ----------------------------------------------------------------------------------------------------------------- // </editor-fold> return array( 'status' => 'ok' , 'booking_id' => $booking_id , 'form_data' => $form_data , 'message' => '' ); } /** * Get SQL ROWs of VALUES for INSERT to DB * * @param int $booking_id 101 ID of the booking * @param string $full_date_sql '2023-09-12 10:00:01' SQL date * @param int $is_approved_dates 1 1 - approved, 0 - pending * @param int $date_resource_id ( >= biz_l ): 4 ID of child booking resource (if we save ONE booking in SEVERAL booking resources) field 'type_id' in wp_bookingdates * @param int $main_resource_id ( >= biz_l ): 1 ID of main (parent booking resource) * * @return string - SQL for dates VALUES to insert */ function wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $main_resource_id ) { global $wpdb; if ( class_exists( 'wpdev_bk_biz_l' ) ) { $insert_dates_arr = ( $main_resource_id != $date_resource_id ) ? $wpdb->prepare( "(%d, %s, %d, %d)", $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id ) : $wpdb->prepare( "(%d, %s, %d, NULL)", $booking_id, $full_date_sql, $is_approved_dates ); } else { $insert_dates_arr = $wpdb->prepare( "(%d, %s, %d)", $booking_id, $full_date_sql, $is_approved_dates ); } return $insert_dates_arr; } // --------------------------------------------------------------------------------------------------------------------- // Support // --------------------------------------------------------------------------------------------------------------------- /** * Get booking_id and resource_id if we are editing the booking, by booking hash * * @param $booking_hash * @param $server_request_url * * @return array | false false if not edit Otherwise [ 'booking_id': 100, 'resource_id': 3 ] */ function wpbc_get_data__if_edit_booking( $booking_hash, $server_request_url ) { $is_edit_booking = false; if ( ! empty( $booking_hash ) ) { $my_booking_id_type = wpbc_hash__get_booking_id__resource_id( $booking_hash ); if ( $my_booking_id_type !== false ) { $is_edit_booking = array(); $is_edit_booking['booking_id'] = intval( $my_booking_id_type[0] ); $is_edit_booking['resource_id'] = intval( $my_booking_id_type[1] ); //TODO: test it. Check situation when we have editing "child booking resource", so need to re-update calendar and form to have it for parent resource. //FixIn: 6.1.1.9 if ( strpos( $server_request_url, 'resource_no_update' ) === false ) { //FixIn: 9.4.2.3 if ( ( function_exists( 'wpbc_is_this_child_resource' ) ) && ( wpbc_is_this_child_resource( $is_edit_booking['resource_id'] ) ) ) { $bk_parent_br_id = wpbc_get_parent_resource( $is_edit_booking['resource_id'] ); $is_edit_booking['resource_id'] = intval( $bk_parent_br_id ); } } } } return $is_edit_booking; } /** * Get how many items to book. Usually it's from [selectbox visitors "1" ... ] field. * * @param booking_form_data__arr = [ * selected_short_dates_hint = "September 27, 2023 - September 28, 2023" * days_number_hint = "2" * rangetime = "16:00 - 18:00" * starttime = "21:00" * durationtime = "00:30" * name = "John" * secondname = "Smith" * email = "john.smith@server.com" * visitors = "1" * children = "0" * details = "" * ] * * @return int */ function wpbc_get__how_many_items_to_book__in_booking_form( $booking_form_data__arr, $resource_id ){ $how_many_items_to_book = 1; //TODO: Check about some URL parameter: '&resource_no_update' to book parent resource as single resource! if ( ( class_exists( 'wpdev_bk_biz_l' ) ) && ( 0 !== wpbc_get_child_resources_number( $resource_id ) ) // Here several child booking resources ) { $booking_capacity_field = wpbc_get__booking_capacity_field__name(); if ( ( ! empty( $booking_capacity_field ) ) && ( isset( $booking_form_data__arr[ $booking_capacity_field ] ) ) ){ $how_many_items_to_book = intval( $booking_form_data__arr[ $booking_capacity_field ] ); // Get value of how many booking resources to book $how_many_items_to_book = ( $how_many_items_to_book > 0 ) ? $how_many_items_to_book : 1; } } return $how_many_items_to_book; } /** * Get capacity field -- 'pure name' * * @return string - field name, or empty string - '' if not defined * * In DB, we are saved field name type and possible name of custom booking form in format: 'custom_form_name^field_type^capacity_field_name' -> 'minimal^select^adults' * or for standard form: 'select^visitors' * and here we get only field name: 'visitors' */ function wpbc_get__booking_capacity_field__name() { if ( class_exists( 'wpdev_bk_biz_l' ) ) { if ( 'On' == get_bk_option( 'booking_quantity_control' ) ) { $booking_capacity_field = get_bk_option( 'booking_capacity_field' ); if ( ! empty( $booking_capacity_field ) ) { $booking_capacity_field = explode( '^', $booking_capacity_field ); if ( ! empty( $booking_capacity_field ) ) { $booking_capacity_field_name = $booking_capacity_field[ count( $booking_capacity_field ) - 1 ]; return $booking_capacity_field_name; } } } } return ''; } /** * Get time for booking from the booking form, as array of seconds: [ 0, 24 * 60 * 60 ] OR [ 10*60*60, 14*60*60 ]. If timefields not exist, then get time for full day booking. * @param $booking_form_data__arr * * @return array [ 0, 24 * 60 * 60 ] OR [ 10*60*60, 14*60*60 ] <- start and end time in seconds * * Example: * * // Firstly, we need to Get parsed booking form: [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ] * $structured_booking_data_arr = wpbc_get_parsed_booking_data_arr( $params["form_data"], $params["resource_id"], array( 'get' => 'value' ) ); * * // Now get start/end times as seconds: [ 64800, 72000 ] * $time_as_seconds_arr = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $structured_booking_data_arr ); */ function wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $booking_form_data__arr ){ $selected_time_fields = wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr ); // 2.2 Get selected SECONDS to book --------------------------------------------------------------------------- $time_as_seconds_arr = array( 0, 24 * 60 * 60 ); // Full day booking by default foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600, 23400 ], value_option_24h: '06:00 - 06:30', name: 'rangetime'} if ( false !== strpos( $time_fields_obj['name'], 'rangetime' ) ) { $time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ]; $time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 1 ]; //break; // If we have range-time then skip this loop } if ( false !== strpos( $time_fields_obj['name'], 'starttime' ) ) { $time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ]; } if ( false !== strpos( $time_fields_obj['name'], 'endtime' ) ) { $time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 0 ]; } } // For duration time we need to make a new loop, because we need to be sure that was defined START_TIME before this, // and end time was NOT defined, e.g. == (otherwise it's means that we already used END_TIME or RANGE_TIME) if ( ( ( 0 ) !== $time_as_seconds_arr[ 0 ] ) && ( (24 * 60 * 60 ) === $time_as_seconds_arr[ 1 ] ) ){ foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600 ], value_option_24h: '06:00', name: 'durationtime'} if ( false !== strpos( $time_fields_obj['name'], 'durationtime' ) ) { $time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 0 ] + $time_fields_obj['times_as_seconds'][ 0 ]; break; } } } return $time_as_seconds_arr; } /** * Get all time fields in the booking form as array of objects * * @param booking_form_data__arr = [ * selected_short_dates_hint = "September 27, 2023 - September 28, 2023" * days_number_hint = "2" * rangetime = "16:00 - 18:00" * starttime = "21:00" * durationtime = "00:30" * name = "John" * secondname = "Smith" * email = "john.smith@server.com" * visitors = "1" * children = "0" * details = "" * ] * @returns [] * * Example: * [ * [ * name = "rangetime" * value_option_24h = "16:00 - 18:00" * times_as_seconds = [ 57600, 64800 ] * ] * [ * name = "starttime" * value_option_24h = "21:00" * times_as_seconds = [ 75600 ] * ] * [ * name = "durationtime" * value_option_24h = "00:30" * times_as_seconds = [ 1800 ] * ] * ] */ function wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr ){ /** * Fields with [] like this select[name="rangetime1[]"] * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ] */ $time_fields_arr = array( 'rangetime', 'starttime', 'endtime', 'durationtime' ); $time_fields_obj_arr = array(); // Loop all Time Fields for ( $ctf = 0; $ctf < count( $time_fields_arr ); $ctf ++ ) { $time_field = $time_fields_arr[ $ctf ]; if ( isset( $booking_form_data__arr[ $time_field ] ) ) { $value_option_seconds_arr = explode( '-', $booking_form_data__arr[ $time_field ] ); $times_as_seconds_arr = array(); foreach ( $value_option_seconds_arr as $time_val ) { $time_val = trim( $time_val ); if ( ! empty( $time_val ) ) { $start_end_times_arr = explode( ':', $time_val ); $time_in_seconds = intval( $start_end_times_arr[0] ) * 60 * 60 + intval( $start_end_times_arr[1] ) * 60; $times_as_seconds_arr[] = $time_in_seconds; } } if (! empty($times_as_seconds_arr)) { $time_fields_obj_arr[] = array( 'name' => $time_field, 'value_option_24h' => $booking_form_data__arr[ $time_field ], 'times_as_seconds' => $times_as_seconds_arr ); } } } return $time_fields_obj_arr; } //TODO: 2023-10-13 16:37 // - create new function for confirmation section // - Update payment request // - create redirection to the "Thank you." page and show there conformation, and payment request" // - define in the settings new Stripe and PayPal button design as default ! // - Be sure that 'booking_log_booking_actions' active by default // - test it in dark theme // - test closing booked dates if all time slot was booked - it's relative to 'different time slots in dif dates' // - add migrate support old dates selection variables // - check and remove other global Js vars // - Create wizard booking form style with steps ? // - Check Booking > Availability page relative new functionality of calendar_load ! // - Update last func in wpbc-booking-new.php and remove it. // - Test capacity in dates and time slots // - Next 9.9 Customizer Wizard // - Next 9.9 Update search admin UI // - Next 9.9 - update functionality in Search functionality based on similar to where_to_save function. // - Next 9.9 refactor Dates functions. // Done. - Next 9.9 Update Booking > Settings General page to show tabs vertically in left column // Create the same navigation panel at the Pro Booking > Settings > Form page. At left column custom forms, at top tolbar selectio of Booking form and "Content of booking fields data" form. // Create the same navigation for Emails. /** * TODO: Performance improvement: * "other_code": 0.003080129623413086 * "wpbc__where_to_save_booking": 0.060331106185913086 * "wpbc_db__booking_save": 0.023384809494018555 * "wpbc_maybe_get_payment_form": 1.3650128841400146 <- * "emails_sending": 1.5024309158325195 <- * "total": 2.9542438983917236 */ capacity.php 0000666 00000304504 15165546743 0007104 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // <editor-fold defaultstate="collapsed" desc=" == SQL - Get Dates array from DB == " > // ----------------------------------------------------------------------------------------------------------------- // SQL - Get Dates array from DB // ----------------------------------------------------------------------------------------------------------------- /** * Get SQL dates array from DB as: [ [0] => std_object( booking_date:'2023-08-08 10:00:01', approved:0, booking_id:45, type:1 ... ), [1] => std_object( ), ... ] * * @param array $params = array( 'approved' => 'all' | 0 | 1 default 'all' , 'resource_id' => array, CSD, int if empty then default '1' , 'additional_bk_types' => array, CSD, int OPTIONAL default array() , 'skip_booking_id' => CSD default '' ) * * @return array Array ( [0] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 0 [date_res_type] => [booking_id] => 45 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^selected_short_dates_hint2^... [parent] => 0 [prioritet] => 20 [type] => 2 ) [1] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 0 [date_res_type] => [booking_id] => 46 [form] => selectbox-one^rangetime10^10:00 - 12:00~text^selected_short_dates_hint10^... [parent] => 2 [prioritet] => 1 [type] => 10 ), ... * * * Example: $sql_dates_params = array( 'approved' => ( ( 'On' == get_bk_option( 'booking_is_show_pending_days_as_available' ) ) ? '1' : 'all' ) , 'resource_id' => $type_id , 'skip_booking_id' => wpbc_get_booking_id__from_hash_in_url() // int | '' // Booking IDs to skip getting from DB ); $dates_approve = wpbc__sql__get_booking_dates( $sql_dates_params ); */ function wpbc__sql__get_booking_dates( $params ){ //TODO: think about pre-caching SQL request for all booking resources - useful for [bookingselect shortcode ...] $params['resource_id'] = implode(',',range(1,17)); // <editor-fold defaultstate="collapsed" desc=" = CACHE - GET :: check if such request was cached and get it = " > $params_for_cache = maybe_serialize( $params ); $cache_result = wpbc_cache__get( 'wpbc__sql__get_booking_dates', $params_for_cache ); if ( ! is_null( $cache_result ) ) { return $cache_result; } // </editor-fold> global $wpdb; $defaults = array( 'dates_to_check' => 'CURDATE' // 'CURDATE' | 'ALL' | [ '2023-07-15' , '2023-07-21' ] , 'approved' => 'all' // 'all' | 0 | 1 , 'resource_id' => '' // INT , 'additional_bk_types' => array() // arrays only , 'skip_booking_id' => '' // CSD '3,5' , 'as_single_resource' => false // get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources' ); $params = wp_parse_args( $params, $defaults ); // Convert $params['additional_bk_types'] and $params['resource_id'] to one CSD variable or default '1' if all empty $resource_id__arr = wpbc_get_unique_array_of_resources_id( $params['resource_id'], $params['additional_bk_types'] ); $resource_id__csd = implode( ',', $resource_id__arr ); // S a n i t i z e $resource_id__csd = wpbc_sanitize_digit_or_csd( $resource_id__csd ); $params['skip_booking_id'] = wpbc_sanitize_digit_or_csd( $params['skip_booking_id'] ); $params['approved'] = ( 'all' == $params['approved'] ) ? 'all' : intval( $params['approved'] ); $sql_trash_bookings = ' AND bk.trash != 1 '; $sql_skip_bookings = ( '' == $params['skip_booking_id'] ) ? '' : " AND dt.booking_id NOT IN ( {$params['skip_booking_id']} ) "; $sql_approved_bookings = ( 'all' == $params['approved'] ) ? '' : " AND dt.approved = {$params['approved']} "; $or__sql_child_bookings_4_parent = ( ! $params['as_single_resource'] ) ? " OR bt.parent IN ( {$resource_id__csd} ) " : '' ; $where_dates = wpbc_get__sql_where__for__dates( $params ); /** * Description: * OR dt.type_id IN ( {$resource_id__csd} ) * It is means that sometimes bookings can be started in one booking resource, * and in future dates can be finished in other 'child' booking resource(s). * It's possible, when 'main' booking resource, where booking was started * has future dates as 'unavailable' or booked * * OR dt.type_id IN ( {$resource_id__csd} ) * It's means that this booking belong to child booking resource, and do not belong to parent booking resource! */ if ( class_exists('wpdev_bk_biz_l') ) { $my_sql = "SELECT DISTINCT dt.booking_date, dt.approved, dt.type_id as date_res_type, dt.booking_id, bk.form, bt.parent, bt.prioritet, bt.booking_type_id as type FROM {$wpdb->prefix}bookingdates as dt INNER JOIN {$wpdb->prefix}booking as bk ON bk.booking_id = dt.booking_id INNER JOIN {$wpdb->prefix}bookingtypes as bt ON bk.booking_type = bt.booking_type_id WHERE 1 = 1 {$where_dates} AND ( bk.booking_type IN ( {$resource_id__csd} ) OR dt.type_id IN ( {$resource_id__csd} ) {$or__sql_child_bookings_4_parent} ) {$sql_approved_bookings} {$sql_trash_bookings} {$sql_skip_bookings} ORDER BY dt.booking_date"; // Explanation: // OR bt.parent IN ( ... ) -> Bookings from CHILD booking resources // OR dt.type_id IN ( ... ) -> Dates from other booking resources, which belong to this booking resource } else if ( class_exists('wpdev_bk_biz_m') ) { // Here we get form for booking details. $my_sql = "SELECT DISTINCT dt.booking_date, dt.approved, dt.booking_id, bk.booking_type as type, bk.form FROM {$wpdb->prefix}bookingdates as dt INNER JOIN {$wpdb->prefix}booking as bk ON bk.booking_id = dt.booking_id WHERE 1 = 1 {$where_dates} AND bk.booking_type IN ( {$resource_id__csd} ) {$sql_approved_bookings} {$sql_trash_bookings} {$sql_skip_bookings} ORDER BY dt.booking_date"; } else { // Fast request only for dates $my_sql = "SELECT DISTINCT dt.booking_date, dt.approved, dt.booking_id, bk.booking_type as type FROM {$wpdb->prefix}bookingdates as dt INNER JOIN {$wpdb->prefix}booking as bk ON bk.booking_id = dt.booking_id WHERE 1 = 1 {$where_dates} AND bk.booking_type IN ( {$resource_id__csd} ) {$sql_approved_bookings} {$sql_trash_bookings} {$sql_skip_bookings} ORDER BY dt.booking_date"; } // Show past bookings, as well // $my_sql = str_replace( 'AND dt.booking_date >= CURDATE()', '', $my_sql ); $sql__dates_obj__arr = $wpdb->get_results( $my_sql ); // <editor-fold defaultstate="collapsed" desc=" = CACHE - SAVE :: = " > $cache_result = wpbc_cache__save( 'wpbc__sql__get_booking_dates', $params_for_cache, $sql__dates_obj__arr ); // </editor-fold> return $sql__dates_obj__arr; } /** * Get SQL WHERE condition for Dates * * @param array $params [ 'dates_to_check' => 'CURDATE' ] | [ 'dates_to_check' => 'ALL' ] | [ 'dates_to_check' => [ '2023-07-15' , '2023-07-21' ] ] * * @return string ' AND ( dt.booking_date >= CURDATE() ) ' */ function wpbc_get__sql_where__for__dates( $params ){ $defaults = array( 'dates_to_check' => 'CURDATE' // 'CURDATE' | 'ALL' | [ '2023-07-15' , '2023-07-21' ] ); $params = wp_parse_args( $params, $defaults ); if ( 'ALL' == $params['dates_to_check'] ) { // All dates -> '' return ''; } else if ( 'CURDATE' == $params['dates_to_check'] ) { // Current dates -> CURDATE() return ' AND ( dt.booking_date >= CURDATE() ) ' ; } else if ( is_array( $params['dates_to_check'] ) ) { // Specific Date(s) -> [ '2023-07-15' , '2023-07-21' ] $dates_sql_array = array(); for( $i = 0; $i < count( $params['dates_to_check'] ); $i++) { $dates_sql_array[] = "( ( dt.booking_date >= '{$params['dates_to_check'][$i]} 00:00:00' ) AND ( dt.booking_date <= '{$params['dates_to_check'][$i]} 23:59:59' ) )"; } $dates_sql_str = implode( ' OR ', $dates_sql_array ); return " AND ( {$dates_sql_str} ) " ; } // Default CURDATE return ' AND ( dt.booking_date >= CURDATE() ) '; } /** * Get array of "Booked Dates" as: ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ... * * @param array $params array( * 'approved' => 'all' // 'all' | 0 | 1 * , 'resource_id' => '1' // arrays | CSD | int * , 'additional_bk_types' => array() OPTIONAL // arrays | CSD | int * , 'skip_booking_id' => '' // CSD '3,5' * ) * * @return array [ [2023-08-09]: [ [3]: [ '43211 - 86392': object( 'booking_date' => 2023-08-09 12:00:01 ... ), ... ], ... ], [2023-08-10]: ... ] * * Explanation: * [2023-08-09]: [ * [3]: [ * '43211 - 86392': object( * [booking_date] => 2023-08-09 12:00:01 * [approved] => 0 * [date_res_type] => * [booking_id] => 65 * [form] => text^selected_short_dates_hint3^August 10... * [parent] => 0 * [prioritet] => 30 * [type] => 3 * [__summary__booking] : [ * * [sql__booking_dates__arr] : [ * [1691668811] => 2023-08-10 12:00:01 * [1691675992] => 2023-08-10 14:00:02 * ] * [__dates_obj] => WPBC_BOOKING_DATE Object( * [readable_dates]: [ '2023-08-10': [ 12:00:01 - 14:00:02 ] ] * [is_debug] => 0 * ) * [__dates_obj__bm__extended] => WPBC_BOOKING_DATE_EXTENDED Object ( * [readable_dates] : [ * [2023-08-09] : [ 12:00:01 - 24:00:00 ] * [2023-08-10] : [ 00:00:00 - 24:00:00 ] * [2023-08-11] : [ 00:00:00 - 24:00:00 ] * [2023-08-12] : [ 00:00:00 - 24:00:00 ] * [2023-08-13] : [ 00:00:00 - 14:00:02 ] * ] * [is_debug] => 0 * [extended_dates_times_arr] : [] * [debug_dates_times_arr] : [] * ) * [sql__booking_dates__arr__extended] : [ * [1691582401] => 2023-08-09 12:00:01 * [1691625600] => 2023-08-10 00:00:00 * [1691712000] => 2023-08-11 00:00:00 * [1691798400] => 2023-08-12 00:00:00 * [1691935202] => 2023-08-13 14:00:02 * ] * * ] * ) * '64811 - 86392': object( * [booking_date] => 2023-08-09 18:00:01 * [approved] => 0 * [date_res_type] => * [booking_id] => 66 * .... * ) * * ] * * ] * * [2023-08-10]: [ ... ] * ... * * Example 1: * $booked_dates__per_resources__arr = wpbc_get__booked_dates__per_resources__arr( array( 'resource_id' => $type_id ) ); * Example 2: * $booked_dates__per_resources__arr = wpbc_get__booked_dates__per_resources__arr( * 'approved' => 'all' // 'all' | 0 | 1 * , 'resource_id' => '1' // arrays | CSD | int * , 'additional_bk_types' => array() // arrays | CSD | int * , 'skip_booking_id' => '' // int | '' // CSD * ); * * * * * $booked_dates__resources__seconds__arr[ '2023-08-08' ][ 'resource_id' ][ 'time_seconds_range' ] = Booking Date Object() * * Seconds: [36011 - 43192] - [start_time_second - end_time_second] * Seconds: [0] - FULL DAY Booking * * Day start at ( 10 + 1 ) second * Day End at ( ( 24 * 60 * 60 ) - 10 + 2 ) second * * To prevent intersections: * Each booking Start time has +10 seconds * Each booking End time has -10 seconds * So real time here [36011 - 43192] is [ 36001 - 43202 ] * * Full day booking end with 0 * Start time booking end with 1 * End time booking end with 2 */ function wpbc_get__booked_dates__per_resources__arr( $params ){ $defaults = array( 'dates_to_check' => 'CURDATE' // 'CURDATE' | 'ALL' | [ '2023-07-15' , '2023-07-21' ] , 'approved' => ( ( get_bk_option( 'booking_is_show_pending_days_as_available' ) == 'On' ) ? '1' : 'all' ) // 'all' | 0 | 1 , 'resource_id' => '1' // arrays | CSD | int , 'additional_bk_types' => array() // arrays | CSD | int // OPTIONAL , 'skip_booking_id' => wpbc_get_booking_id__from_hash_in_url() // int | '' // CSD '3,5' , 'as_single_resource' => false // get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources' , 'is_days_always_available' => ( ( 'On' == get_bk_option( 'booking_is_days_always_available' ) ) ? true : false ) , 'aggregate_params' => array() //Optional. It can contain: [ 'aggregate_resource_id_arr' => [ 4 ] , 'resource_id__with_children__arr' => [3,25] ] ); $params_for_dates = wp_parse_args( $params, $defaults ); if ( $params_for_dates['is_days_always_available'] ) { // All bookings showing as available dates. return array(); } /** * 1. SQL - get array of all booked dates for our booking resource(s): [ [0] => date_object{ [booking_date] => 2023-08-08 10:00:01, [approved] => 0, .. }, .. ] * * Example: [ [0] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 0 [date_res_type] => [booking_id] => 45 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^selected_short_dates_hint2^... [parent] => 0 [prioritet] => 20 [type] => 2 ) [1] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 [approved] => 0 [date_res_type] => [booking_id] => 46 [form] => selectbox-one^rangetime10^10:00 - 12:00~text^selected_short_dates_hint10^... [parent] => 2 [prioritet] => 1 [type] => 10 ), ... ] */ $sql__b_dates__arr = wpbc__sql__get_booking_dates( $params_for_dates ); /** * 2. From SQL dates into: [ > resource_id < ][ > booking_id < ] -> __summary__booking['sql__booking_dates__arr'] = [ [ '>seconds<' ]: '> SQL DATE <' , ... ] * [1693303211] => 2023-08-29 10:00:01 * [1693353600] => 2023-08-30 00:00:00 * [1693483192] => 2023-08-31 12:00:02 * ] */ $resources__booking_id__obj = wpbc_support__transform__into__resource_booking_dates__arr( array( 'sql_dates_arr' => wpbc_clone_array_of_objects( $sql__b_dates__arr ) , 'is_sort__dates_arr' => true , 'is_apply__check_in_out__10s' => true ) ); /** * 2.0 Transfer AGGREGATE resource bookings to Main resources * * */ if ( ! empty( $params['aggregate_params'] ) ) { $resources__booking_id__obj = wpbc_aggregate__merge_bookings__from_aggregate__in_source_resource__arr( $resources__booking_id__obj, $params['aggregate_params']['resource_id__with_children__arr'], $params['aggregate_params']['aggregate_resource_id_arr'] ); } /** * 2.1 Get [ > resource_id < ][ > booking_id < ] -> __summary__booking[ '_readable_dates' ] = [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], ... * '2023-08-05': [ 0: "10:00:01 - 12:00:02" ], ... * ] */ $resources__booking_id__obj = wpbc__in_all_bookings__create_WPBC_BOOKING_DATE( $resources__booking_id__obj ); /** * 2.2 Extend check in/out dates [ > resource_id < ][ > booking_id < ] -> __summary__booking[ 'sql__booking_dates__arr__extended' ] */ if ( function_exists( 'wpbc__extend_availability__before_after__check_in_out' ) ) { $resources__booking_id__obj = wpbc__extend_availability__before_after__check_in_out( $resources__booking_id__obj ); } /** * 3. Into: ['2024-01-28'][ > resource_id < ][ > booking_id < ][ > only_time_seconds < ] => obj( booking_date: "2024-01-28 10:00:01", ... ) * * From: [ > resource_id < ][ > booking_id < ] => obj( booking_date: "2024-01-28 10:00:01", ['__summary__booking']['sql__booking_dates__arr'][] , ... ) */ $dt__res__bk__seconds__arr = wpbc_support__transform__into__date_resource_booking_timesec__arr( array( 'resource_booking_dates_arr' => $resources__booking_id__obj , 'is_apply__check_in_out__10s' => true ) ); /** * 4. Into: ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ... * * , where 'time_seconds_range' can be: '0' | '36011 - 43192', ... */ $dt__res__time_seconds_range__arr = wpbc_support__transform__into__date_resource_timesec_range__arr( array( 'date_resource_booking_timesec_arr' => $dt__res__bk__seconds__arr , 'is_apply__check_in_out__10s' => true ) ); return $dt__res__time_seconds_range__arr; } // </editor-fold> // ----------------------------------------------------------------------------------------------------------------- // Get Resource array filled by booked Dates // ----------------------------------------------------------------------------------------------------------------- /** * Get all dates STATUSES as: ['2023-08-30'][ 'summary']['status_for_day':'available', 'day_availability':3, [ > resource_id < ] => std_object( '_day_status':'full_day_booking', '__booked__times__details':[ '1 - 43192': std_object( booking_id:46, 'approved':0, ... ), '50300 - 63192': ], 'is_day_unavailable':1, ... * * @param int $single_or_parent__resource_id // 1 --- INT (currently it's works only for one resource (single or parent) * array $params[ 'timeslots_to_check_intersect' ] // [ '10:00 - 12:00' ] if bookings intersect with all time slots in array, then the date unavailable, if empty array then it's skipped * * @return array { * calendar_2: { * id: 2 * dates: { "2023-07-21": {…} * "2023-07-22": { * ['summary']['status_for_bookings']: "pending" * ['summary']['status_for_day']: "available" * day_availability: 4 * max_capacity: 4 * statuses: Object { day: "check_in|check_in|available|available", bookings: "approved|pending||" } * * 2: Object { is_day_unavailable: false, _day_status: "check_in", check_in_out: "check_in", … } * 10: Object { is_day_unavailable: false, _day_status: "check_in", check_in_out: "check_in", … } * 11: Object { is_day_unavailable: false, _day_status: "available", pending_approved: [] } * 12: Object { is_day_unavailable: false, _day_status: "available", pending_approved: [] } * } * , "2023-07-23": {…} * , … * } * } * calendar_5: {...} * , ... * } * * * Important Dates properties: * * ['summary']['status_for_bookings']: "" | "pending" | "approved" * ['summary']['status_for_day']: | 'available'; * | 'time_slots_booking'; * | 'full_day_booking'; * | 'season_filter'; * | 'resource_availability'; * | 'weekday_unavailable'; 'from_today_unavailable' | 'limit_available_from_today' * | 'change_over'; * | 'check_in'; * | 'check_out'; * | 'change_over check_out' .... variations.... * * * @return array array( 'dates' => $availability_per_day like ['2023-08-17'] = ... , 'resources_id_arr__in_dates' => $source__resource_id_arr like [ 1,10,11,12,14] ) */ function wpbc_get_availability_per_days_arr( $params ) { if ( 0 ) { //FixIn: 9.8.3.1 ? wpbc_set_limit_php( 300 ); // Set 300 seconds for php execution. } $defaults = array( 'dates_to_check' => 'CURDATE' // 'CURDATE' | 'ALL' | [ '2023-07-15' , '2023-07-21' ] , 'approved' => ( ( get_bk_option( 'booking_is_show_pending_days_as_available' ) == 'On' ) ? '1' : 'all' ) // 'all' | 0 | 1 , 'resource_id' => '1' // Single or parent booking resource!!!! // arrays | CSD | int ??? , 'additional_bk_types' => array() // arrays | CSD | int // OPTIONAL -> aggregate_resource_id_arr ... it is array of booking resources from aggregate shortcode parameter , 'skip_booking_id' => wpbc_get_booking_id__from_hash_in_url() // int | '' // CSD '3,5' , 'as_single_resource' => false // get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources' , 'max_days_count' => wpbc_get_max_visible_days_in_calendar() // 365 , 'timeslots_to_check_intersect' => array() // array( '12:20 - 12:55', '13:00 - 14:00' ) //TODO: ? do we really need it, because below we get it from function , '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 , 'custom_form' => '' // Required for checking all available time-slots and compare with booked time slots ); $params = wp_parse_args( $params, $defaults ); // ----------------------------------------------------------------------------------------------------------------- // R e s o u r c e (s) D a t a // ----------------------------------------------------------------------------------------------------------------- // Get array of booking resource ID [1, 13, 8, 6, 7] or default: [ 1 ] $source__resource_id_arr = wpbc_get_unique_array_of_resources_id( $params['resource_id'] ); // [1, 13, 8, 6, 7] //$source__resource_id_arr = wpbc_get_unique_array_of_resources_id( $params['resource_id'], $params['additional_bk_types'] ); // [1, 13, 8, 6, 7] $first_resource_id = $source__resource_id_arr[0]; // First from the list, or 1 if not provided. // Get here Obj. of booking resource (which can include CHILD booking resources) $resources_obj = new WPBC_RESOURCE_SUPPORT( array( 'resource_id' => $source__resource_id_arr, //CSD | D 'as_single_resource' => $params['as_single_resource'] // If true, then skip child booking resources )); // Resource ID arr (Can be Parent and Child resource ID) $resource_id__with_children__arr = $resources_obj->get_resource_id_arr(); // [ 2, 10, 11, 12 ] // Get Maximum capacity of resource $resource_obj = $resources_obj->get__booking_resource_obj( $first_resource_id ); $max_resource_capacity_int = empty( $resource_obj ) ? 1 : $resource_obj->capacity; // 1 | 4 // Get base cost of resource $resource_base_cost = $resources_obj->get_resources_base_cost_arr(); // [ 0, 25, 100, 99] // ----------------------------------------------------------------------------------------------------------------- // Get real AGGREGATE resource ID arr // ----------------------------------------------------------------------------------------------------------------- $real_resource_id_arr = wpbc_get_unique_array_of_resources_id( $params['resource_id'] ); // [ 1 ] if ( empty( $params['additional_bk_types'] ) ) { $aggregate_resource_id_arr = array(); } else { $aggregate_resource_id_arr = wpbc_get_unique_array_of_resources_id( $params['additional_bk_types'] ); // [1, 13, 8, 6, 7] } // Excluding from 'additional_bk_types' all resources in 'resource_id' $aggregate_resource_id_arr = array_diff( $aggregate_resource_id_arr, $real_resource_id_arr ); // [ 13, 8, 6, 7 ] $aggregate_resource_id_arr = array_values( $aggregate_resource_id_arr ); // reindex array, for ability to transfer array instead of obj to JS client side. $params['aggregate_params'] = array( 'aggregate_resource_id_arr' => $aggregate_resource_id_arr, 'resource_id__with_children__arr' => $resource_id__with_children__arr ); // ----------------------------------------------------------------------------------------------------------------- // B o o k i n g s // ----------------------------------------------------------------------------------------------------------------- // Main function to get "Bookings": ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ... $bookings__in_dates = wpbc_get__booked_dates__per_resources__arr( $params ); // ----------------------------------------------------------------------------------------------------------------- // Booking > Availability page // ----------------------------------------------------------------------------------------------------------------- $search_dates = $params['dates_to_check']; // 'CURDATE' | 'ALL' | [ "2023-08-03" , "2023-08-04" , "2023-08-05" ] //FixIn: 9.8.15.10 Aggregate or not Aggregate Booking > Availability ? aggregate_type = 'all' | 'bookings_only' if ( ( ! empty( $params['aggregate_type'] ) ) && ( 'bookings_only' === $params['aggregate_type'] ) ) { //FixIn: 9.9.0.16 $unavailable_dates__per_resources__arr = wpbc_for_resources_arr__get_unavailable_dates( $resource_id__with_children__arr, // Only One Primary Resource !! $search_dates ); // [ 2: ['2023-08-01', '2023-08-02'], 10: ['2023-08-05', '2023-08-06'] ] } else { $unavailable_dates__per_resources__arr = wpbc_for_resources_arr__get_unavailable_dates( wpbc_get_unique_array_of_resources_id( $resource_id__with_children__arr, $aggregate_resource_id_arr ), // Get unavailable dates for primary and aggregate booking resources $search_dates ); // [ 2: ['2023-08-01', '2023-08-02'], 10: ['2023-08-05', '2023-08-06'] ] } $unavailable_dates__per_resources__arr = wpbc_aggregate_merge_availability( $unavailable_dates__per_resources__arr, $resource_id__with_children__arr, $aggregate_resource_id_arr ); // ----------------------------------------------------------------------------------------------------------------- // Booking > Resources > Availability page // ----------------------------------------------------------------------------------------------------------------- $season_filters_availability = array(); if ( class_exists('wpdev_bk_biz_m') ) { foreach ( $resource_id__with_children__arr as $resource_id_for_season ) { $season_filters_availability[ $resource_id_for_season ] = apply_bk_filter( 'get_available_days', $resource_id_for_season ); } } // ----------------------------------------------------------------------------------------------------------------- // P a r a m e t e r s f o r L O O P // ----------------------------------------------------------------------------------------------------------------- // - Is this Booking > Add booking page ? -------------------------------------------------------------------------- $is_this_bap_page = ( false !== strpos( $params['request_uri'], 'page=wpbc-new' ) ) ? true : false; $is_this_hash_page = ( false !== strpos( $params['request_uri'], 'booking_hash' ) ) ? true : false; // Set it to TRUE for adding booking in past at Booking > Add booking page if ( ( $is_this_bap_page ) && ( $is_this_hash_page ) ) { // Start days in calendar from = PAST $params['dates_to_check'] = 'ALL'; } if ( 'ALL' == $params['dates_to_check'] ) { // All dates -> '' $start_day_number = - 1 * $params['max_days_count']; //$today_inix_timestamp = strtotime( '-' . intval( $params['max_days_count'] ) . ' days' ); // - 300 days // Get time, relative to Timezone from WordPress > Settings General page //FixIn: 9.9.0.17 $start_date_unix = strtotime( '-' . intval( $params['max_days_count'] ) . ' days' ); // - 365 days $date_with_wp_timezone = wpbc_datetime_localized__use_wp_timezone( date( 'Y-m-d H:i:s', $start_date_unix ), 'Y-m-d 00:00:00' ); $today_inix_timestamp = strtotime( $date_with_wp_timezone ); } else if ( 'CURDATE' == $params['dates_to_check'] ) { // Current dates -> CURDATE() $start_day_number = 1; // $today_inix_timestamp = strtotime( date( 'Y-m-d 00:00:00', strtotime( 'now' ) ) ); // Today 00:00:00 // Get time, relative to Timezone from WordPress > Settings General page //FixIn: 9.9.0.17 $start_date_unix = strtotime( 'now' ); $date_with_wp_timezone = wpbc_datetime_localized__use_wp_timezone( date( 'Y-m-d H:i:s', $start_date_unix ), 'Y-m-d 00:00:00' ); $today_inix_timestamp = strtotime( $date_with_wp_timezone ); } else if ( is_array( $params['dates_to_check'] ) ) { $start_day_number = 1; $today_inix_timestamp = strtotime( $params['dates_to_check'][0] . ' 00:00:00' ); // '2023-09-03 00:00:00' $dif_in_days = strtotime( $params['dates_to_check'][ ( count( $params['dates_to_check'] ) - 1 ) ] . ' 00:00:00' ) - strtotime( $params['dates_to_check'][0] . ' 00:00:00' ); $dif_in_days = $dif_in_days / ( 24 * 60 * 60 ); $params['max_days_count'] = ceil( $dif_in_days ) + 1; } // Get Time Slots from booking form for Each date: [ '2023-10-25' => [ '12:20 - 12:55', '13:00 - 14:00' ], '2023-10-26' => [ ... ], ... ] $readable_timeslots_arr__in_dates_arr__to_check_intersect = wpbc_get_times_fields_configuration__by_dates( $first_resource_id, // Resource ID (used in case of MultiUser version for getting specific form for regular users) $params['custom_form'], // Form name for getting time slots configuration $today_inix_timestamp, // start_date_unix_timestamp ( $params['max_days_count'] - $start_day_number ) // days_count ); // ================================================================================================================= // -- Here are GO // ================================================================================================================= $availability_per_day = array(); for ( $day_num = $start_day_number; $day_num <= $params['max_days_count']; $day_num ++ ) { $my_day_tag = date( 'Y-m-d', $today_inix_timestamp ); // '2023-07-19' //-------------------------------------------------------------------------------------------------------------- // Get Time-Slots from booking form to CHECK INTERSECT :: Convert readable time slot to time slot as seconds [ '12:20 - 12:55', '13:00 - 14:00' ] OR [] if not time slots $as_seconds_timeslots_arr__to_check_intersect = wpbc_get__time_range_in_seconds_arr__for_date( $readable_timeslots_arr__in_dates_arr__to_check_intersect, $my_day_tag ); /* // TODO: check this, if it's required ? // If empty, maybe get default 'timeslots_to_check_intersect' from root of this function parameters ???? if ( empty( $as_seconds_timeslots_arr__to_check_intersect ) ) { if ( ! is_array( $params[ 'timeslots_to_check_intersect' ] ) ) { // Root parameters from this function $params[ 'timeslots_to_check_intersect' ] = array( $params[ 'timeslots_to_check_intersect' ] ); } $as_seconds_timeslots_arr__to_check_intersect = array(); foreach ( $params[ 'timeslots_to_check_intersect' ] as $time_slot_readable ) { $as_seconds_timeslots_arr__to_check_intersect[] = wpbc_convert__readable_time_slot__to__time_range_in_seconds( $time_slot_readable ); } } */ //-------------------------------------------------------------------------------------------------------------- $availability_per_day[ $my_day_tag ] = array(); // Helpful tip. Definition here variables in such order, useful for having such order in _wpbc JS variable for showing it with _wpbc.bookings_in_calendars__get_all(); command $availability_per_day[ $my_day_tag ]['day_availability'] = $max_resource_capacity_int; // 4 $availability_per_day[ $my_day_tag ]['max_capacity'] = $max_resource_capacity_int; // 4 $availability_per_day[ $my_day_tag ]['statuses'] = array(); $availability_per_day[ $my_day_tag ]['statuses']['day_status'] = array(); // per each child booking resource $availability_per_day[ $my_day_tag ]['statuses']['bookings_status'] = array(); // per each child booking resource $availability_per_day[ $my_day_tag ]['summary'] = array(); $availability_per_day[ $my_day_tag ]['summary']['status_for_day'] = ''; // available | time_slots_booking | full_day_booking | ... $availability_per_day[ $my_day_tag ]['summary']['status_for_bookings'] = ''; // pending | approved | CO: pending_pending | pending_approved | approved_pending | approved_approved $availability_per_day[ $my_day_tag ]['summary']['tooltip_times'] = ''; $availability_per_day[ $my_day_tag ]['summary']['tooltip_availability'] = ''; $availability_per_day[ $my_day_tag ]['summary']['tooltip_day_cost'] = ''; $availability_per_day[ $my_day_tag ]['summary']['tooltip_booking_details'] = ''; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // R E S O U R C E S - S t a r t // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ foreach ( $resource_id__with_children__arr as $resource_id ) { // [1, 13, 8, 6, 7] $availability_per_day[ $my_day_tag ][ $resource_id ] = new stdClass(); $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = false; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'available'; $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved = array(); $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips = array( 'resource_title' => $resources_obj->get_resource_title( $resource_id ), 'times' => '', 'details' => array() ); $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots = array( 'in_seconds' => array(), // seconds 'readable24h' => array(), // readable 24H - for debug only 'merged_seconds' => array(), // seconds (reduced number of time_ranges) 'merged_readable' => array() // readable 12AM ); // Day Cost / Rates --------------------------------------------------------------------------------------- $fin_day_cost = wpbc_support_capacity__get_day_cost( $my_day_tag, $resource_id, $resource_base_cost[ $resource_id ] ); $availability_per_day[ $my_day_tag ][ $resource_id ]->date_cost_rate = $fin_day_cost; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // B O O K I N G S - S t a r t // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if ( ( isset( $bookings__in_dates[ $my_day_tag ] ) ) && ( isset( $bookings__in_dates[ $my_day_tag ][ $resource_id ] ) ) ){ $this_date_bookings = $bookings__in_dates[ $my_day_tag ][ $resource_id ]; // [ [36011 - 86392] => stdClass Object( [approved] => 1 , ... ) ,... ] ksort( $this_date_bookings ); $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = $this_date_bookings; } else { $this_date_bookings = array(); } /** * If bookings exist then: * 1. Removing some properties here to hide personal details, * 2. Set Approved / Pending status of the bookings * 3. By default, set "_day_status" as 'time_slots_booking' ( later we will change to 'full_day_booking', if applied ) */ if ( ! empty( $this_date_bookings ) ) { // ===================================================================================================== // T i m e s - Start // ===================================================================================================== foreach ( $this_date_bookings as $booked_times__key => $booked_times__value ) { // By default, set "_day_status" as 'time_slots_booking' ( later we will change to 'full_day_booking', if applied ) $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'time_slots_booking'; // ------------------------------------------------------------------------------------------------- // Get Time-Slot if ( false === strpos( $booked_times__key, '-' ) ) { // Full day ? - 0 == $booked_times__key $time_range__seconds__arr = array( 0, 86400 ); // 24 * 60 * 60 } else { $time_range__seconds__arr = wpbc_transform_timerange__s_range__in__seconds_arr( $booked_times__key ); // '43211 - 86392' into [43211, 86400] } // Real time: [43211, 86400] $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['in_seconds'][] = $time_range__seconds__arr; // For DEBUG only -- Readable 24H: '10:00:01 - 12:30:02' $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['readable24h'][] = wpbc_transform_timerange__seconds_arr__in__24_hours_range( $time_range__seconds__arr ); // ------------------------------------------------------------------------------------------------- // Pending | Approved :: for correct order of all statuses - make it based on start time index / $time_range__seconds__arr[0] == 0 in situation of FULL day booking $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved[ $time_range__seconds__arr[0] ] = ( '1' == $booked_times__value->approved ) ? 'approved' : 'pending'; // T O O L T I P :: Booking Details $booked_time_title = ( ( 0 == $time_range__seconds__arr[0] ) && ( $time_range__seconds__arr[1] >= 86400 ) ) ? __( 'Full day', 'booking' ) : wpbc_transform_timerange__seconds_arr__in__formated_hours( $time_range__seconds__arr ); $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__tooltip__set_for_details( $availability_per_day, $my_day_tag, $resource_id, $this_date_bookings, $booked_times__key, $resources_obj, $booked_time_title ); // Unset ...->form and other fields... $this_date_bookings[ $booked_times__key ] = wpbc_support_capacity__unset_some_fields( $this_date_bookings[ $booked_times__key ] ); } // T i m e s - E n d Booked Times Loop - for current resource // ===================================================================================================== // Merge intersected time intervals = // ===================================================================================================== $merged_seconds_arr = wpbc_merge_intersected_intervals( $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['in_seconds'] ); $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['merged_seconds'] = $merged_seconds_arr; foreach ( $merged_seconds_arr as $booked_time_slots__in_seconds ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['merged_readable'][] = wpbc_transform_timerange__seconds_arr__in__formated_hours( $booked_time_slots__in_seconds ); } // T O O L T I P :: Times $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__tooltip_times__set_for_times( $availability_per_day, $my_day_tag, $resource_id, $resource_id__with_children__arr ); // ===================================================================================================== // End times // ===================================================================================================== // For correct order of all booking statuses - we will make it based on start time index - Sort array starting from 1 second 00:00 to 12:00 to 23:00 etc... ksort( $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved ); // array_keys( $booked_time_slots ) can be: [0] -> 'Full day' | ['36011 - 43192', '56011 - 86392'] -> '10:00 - 12:00', '15:55 - 24:00' $booked_time_slots = array_keys( $this_date_bookings ); // ===================================================================================================== // Full day booking ----------------------------------------------------------------------------------- full_by_bookings // ===================================================================================================== if ( in_array( '0', $booked_time_slots ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'full_day_booking'; // Reset all other possible time slot statuses, in general they must not exist, but for some case $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved = array(); // Pending or approved, for full day booking: $this_date_bookings['0'] $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved[] = ( '1' == $this_date_bookings['0']->approved ) ? 'approved' : 'pending'; // T O O L T I P :: Times - Full Day Booked $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__tooltip_times__set_full_day( $availability_per_day, $my_day_tag, $resource_id , $resource_id__with_children__arr, __( 'Full day', 'booking' ) ); } // end 'full day' if // ===================================================================================================== // All time slots booked ? ----------------------------------------------------------------------------- // ===================================================================================================== if ( ( ! empty( $as_seconds_timeslots_arr__to_check_intersect ) ) // We need to check intersection with some time slot '36011 - 43192' && ( ! $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable ) // And this date still free false ){ $is_some_timeslot_available = wpbc_is_some_timeslot__available__in_arr( $as_seconds_timeslots_arr__to_check_intersect, $booked_time_slots ); // ------------------------------------------------------------------------------------------------- full_by_bookings if ( ! $is_some_timeslot_available ) { // All time slots booked !!! $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'full_day_booking'; $availability_per_day[ $my_day_tag ][ $resource_id ]->_booking_form_timeslots_unavailable = implode( '|', $params[ 'timeslots_to_check_intersect' ] ); // T O O L T I P :: Times - Full Day Booked $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__tooltip_times__set_full_day( $availability_per_day, $my_day_tag, $resource_id , $resource_id__with_children__arr, __( 'Full day', 'booking' ) ); } else { // Some time slots available or there is no time slot passed in this function } } // end 'all time slots booked' if // ===================================================================================================== // Change over days = // ===================================================================================================== if ( ( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) ) && ( wpbc_is_booking_used_check_in_out_time( $params[ 'request_uri' ] ) ) && ( ! $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable ) // And this date still free false ) { /** * "Change over days" - possible situations: check_in | check_out | change_over | ... * * $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = check_in * | check_out * | change_over * | 'mixed' * 'mixed' - e.g. 'change_over check_out' where several child resources and some is 'change_over' and others are 'check_out' * * * Possible situations for change-over days: * * // A. If in $booked_time_slots array one of values (or in $this_date_bookings one of keys) * // 1. Started with time that is ended with 1 second * // 2. and Ended with '24:00' it is means '86392', like this: '28811 - 86392' * // then it's means that we have 'check_in' time here * * // B. If in $booked_time_slots array one of values (or in $this_date_bookings one of keys) * // 1. Started with '00:00' it is means '1' * // 2. and Ended time that is ended with 2 second * // like this: '1 - 32402' * // then it's means that we have 'check_out' time here * * // C. If we have A. and B. then we have 'change_over' here */ $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out = array(); foreach ( $this_date_bookings as $booked_times__key => $booked_times__value ) { if ( false === strpos( $booked_times__key, '-' ) ) { continue; // for situation with FULL day booking, here $booked_times__key = 0 } $rangeA_arr = explode( '-', $booked_times__key ); $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) ); $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) ); // start time $is_starttime__check_in = $rangeA_arr[0] % 10; // 0, 1, 2 $is_starttime__check_in = ( 1 == $is_starttime__check_in ) ? true : false; // end time $is_endtime__check_out = $rangeA_arr[1] % 10; $is_endtime__check_out = ( 2 == $is_endtime__check_out ) ? true : false; if ( ( $is_starttime__check_in ) && ( WPBC_FULL_DAY_TIME_OUT == $rangeA_arr[1] ) ) { // A :: start_time - 86392 e.g. 14:00 - 24:00 // only "check in" time here $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out[] = 'check_in'; } else if ( ( WPBC_FULL_DAY_TIME_IN == $rangeA_arr[0] ) && ( $is_endtime__check_out ) ) { // B :: 1 - end_time e.g. 00:00 - 10:00 // only "check out" time here $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out[] = 'check_out'; } } $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out = array_unique( $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ); $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out = array_filter( $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. if ( ( in_array( 'check_in', $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ) ) && ( in_array( 'check_out', $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ) ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out = array( 'change_over' ); // both check in / out times here $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; // Possible statuses: pending_pending | pending_approved | approved_pending | approved_approved $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved = array( implode( '_', $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved ) ); } $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out = implode( '|', $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ); if ( ! empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = $availability_per_day[ $my_day_tag ][ $resource_id ]->check_in_out; } } // end change-over if } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // B O O K I N G S - E n d // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //========================================================================================================== // $availability_per_day[..]->_day_status = 'season_filter' | ... //========================================================================================================== // Booking > Resources > Availability page >>> 'season_filter' $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__day_status__season_filter( $availability_per_day, $my_day_tag, $resource_id, $season_filters_availability ); // Booking > Availability page >>> 'resource_availability' $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__day_status__resource_availability( $availability_per_day, $my_day_tag, $resource_id, $unavailable_dates__per_resources__arr ); // Week Days unavailable >>> 'weekday_unavailable' $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__day_status__weekday_unavailable( $availability_per_day, $my_day_tag, $resource_id ); if ( ( ! $is_this_bap_page ) || ( ! $is_this_hash_page ) ) { // Do not apply these settings at Booking > Add booking page, when we edit booking - e.g. exist 'booking_hash' // Unavailable days from today >>> 'from_today_unavailable' $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__day_status__from_today_unavailable( $availability_per_day, $my_day_tag, $resource_id ); // Limit available days from today >>> 'limit_available_from_today' $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__day_status__limit_available_from_today( $availability_per_day, $my_day_tag, $resource_id ); } //========================================================================================================== // T O O L T I P :: Times - Unavailable Day if ( in_array( $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status, array( 'season_filter', 'resource_availability', 'weekday_unavailable', 'from_today_unavailable', 'limit_available_from_today' ) ) ){ $availability_per_day[ $my_day_tag ][ $resource_id ] = wpbc_support_capacity__tooltip_times__set_full_day( $availability_per_day, $my_day_tag, $resource_id , $resource_id__with_children__arr, __( 'Unavailable', 'booking' ) ); } // ========================================================================================================= // Entire D A Y statuses // ========================================================================================================= if ( $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable ) { // Reduce DAY day_availability, if some season or days unavailable or full by bookings $availability_per_day[ $my_day_tag ][ 'day_availability' ]--; } // 'resource_availability' | 'weekday_unavailable' | 'from_today_unavailable' | 'limit_available_from_today' | 'season_filter' | 'full_day_booking' | 'time_slots_booking' | 'available' $availability_per_day[ $my_day_tag ]['statuses']['day_status'][] = $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status; // 'approved' | 'pending' $availability_per_day[ $my_day_tag ]['statuses']['bookings_status'][] = implode( '|', $availability_per_day[ $my_day_tag ][ $resource_id ]->pending_approved ); // Go to next child booking resource } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // R E S O U R C E S - E n d // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ------------------------------------------------------------------------------------------------------------- // Day summary : // ------------------------------------------------------------------------------------------------------------- $availability_per_day[ $my_day_tag ] = wpbc_update_summary_availability_per_this_day( $availability_per_day[ $my_day_tag ], $my_day_tag, $resource_id__with_children__arr ); // Go next day + 1 day $today_inix_timestamp += 24 * 60 * 60; } return array( 'dates' => $availability_per_day , 'resources_id_arr__in_dates' => $resource_id__with_children__arr , 'aggregate_resource_id_arr' => $aggregate_resource_id_arr ); } // <editor-fold defaultstate="collapsed" desc=" == S U P P O R T == " > // S U P P O R T /** * Update Summary statuses for the Day * * @param $availability_per_this_day * @param $my_day_tag * @param $resource_id_arr * * @return mixed * * * Dates Status Concept Strategy :: * * Check date booking status based on 'all booking resources': * ( and as one common situation, when we have only 1 resource ) * * | 'approved' - when all booking resources has approved FULL day bookings or some booking resource unavailable * | 'pending' - when at least one booking in one booking resource has pending status and there is no available booking resources * | 'times_partially_booked' - when at least one booking in one booking resource has time bookings and there is no available booking resources * and if all time slot approved then status approved * otherwise if at least one time slot booking has pending status then it has pending status * * if all 'time_slots' booked (it's time slot passed into function as parameter) * then such date in specific booking resource has pending or approved status, based on 'pending'|'approved' rule * * | 'check_in' - if activated 'change over days' and all bookings have 'check-in' status * | 'check_out' - if activated 'change over days' and all bookings have 'check-out' status * | if in booking resource exist both check in/out bookings, and activated 'change over days' * then such booking resource date has approved or pending status depends on from status of these bookings * | 'season_unavailable' - if all booking resources defined as unavailable at Booking > Resources > Availability page * | 'resource_unavailable' - if all booking resources defined as unavailable at Booking > Availability page * | 'other_unavailable' - if all booking resources defined as unavailable at Booking > Settings General page in "Availability" section * */ function wpbc_update_summary_availability_per_this_day( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ // ------------------------------------------------------------------------------------------------------------- // Summary Tooltips // ------------------------------------------------------------------------------------------------------------- $availability_per_this_day['summary']['tooltip_times'] = wpbc_support_capacity__tooltip__summary__times( $availability_per_this_day, $my_day_tag, $resource_id_arr ); $availability_per_this_day['summary']['tooltip_booking_details'] = wpbc_support_capacity__tooltip__summary__booked_details( $availability_per_this_day, $my_day_tag, $resource_id_arr ); $availability_per_this_day['summary']['tooltip_day_cost'] = wpbc_support_capacity__tooltip__summary__day_cost( $availability_per_this_day, $my_day_tag, $resource_id_arr ); $availability_per_this_day['summary']['tooltip_availability'] = wpbc_support_capacity__tooltip__summary__availability( $availability_per_this_day, $my_day_tag, $resource_id_arr ); $availability_per_this_day['summary']['hint__in_day__cost'] = wpbc_support_capacity__in_day_hint__summary__day_cost( $availability_per_this_day, $my_day_tag, $resource_id_arr ); // ------------------------------------------------------------------------------------------------------------- // ['summary']['status_for_day'] // ------------------------------------------------------------------------------------------------------------- $temp_status = array(); foreach ( $availability_per_this_day['statuses']['day_status'] as $bookings_status_arr ) { $bookings_status_arr = explode( '|', $bookings_status_arr ); foreach ( $bookings_status_arr as $bookings_status_element ) { $temp_status[] = $bookings_status_element; } } $temp_status = array_filter( $temp_status ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. $temp_status = array_unique( $temp_status ); // Erase duplicates $availability_per_this_day['summary']['status_for_day'] = $temp_status; /** * Possible day statuses (searched by value of _day_status): * * available * time_slots_booking * full_day_booking * * limit_available_from_today * from_today_unavailable * weekday_unavailable * resource_availability * season_filter * * change_over * check_out * check_in * 'mixed' from check_in/check_out/change_over */ // Priority: available > time_slots_booking > full_day_booking // > season_filter > resource_availability // > weekday_unavailable > from_today_unavailable > limit_available_from_today // if at least one booking "available" then day has this status if ( in_array( 'available', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'available'; } else if ( in_array( 'time_slots_booking', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'time_slots_booking'; } else if ( ( ! in_array( 'check_out', $availability_per_this_day['summary']['status_for_day'] ) ) && ( in_array( 'check_in', $availability_per_this_day['summary']['status_for_day'] ) ) ) { $availability_per_this_day['summary']['status_for_day'] = 'check_in'; } else if ( ( ! in_array( 'check_in', $availability_per_this_day['summary']['status_for_day'] ) ) && ( in_array( 'check_out', $availability_per_this_day['summary']['status_for_day'] ) ) ) { $availability_per_this_day['summary']['status_for_day'] = 'check_out'; } else if ( in_array( 'full_day_booking', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'full_day_booking'; } else if ( in_array( 'season_filter', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'season_filter'; } else if ( in_array( 'resource_availability', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'resource_availability'; } else if ( in_array( 'weekday_unavailable', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'weekday_unavailable'; } else if ( in_array( 'from_today_unavailable', $availability_per_this_day['summary']['status_for_day'] ) ) { $availability_per_this_day['summary']['status_for_day'] = 'from_today_unavailable'; } else if ( in_array( 'limit_available_from_today', $availability_per_this_day['summary']['status_for_day'])){ $availability_per_this_day['summary']['status_for_day'] = 'limit_available_from_today'; } else { $availability_per_this_day['summary']['status_for_day'] = implode( ' ', $availability_per_this_day['summary']['status_for_day'] ); } // ------------------------------------------------------------------------------------------------------------- // ['summary']['status_for_bookings'] // ------------------------------------------------------------------------------------------------------------- $temp_status = array(); foreach ( $availability_per_this_day['statuses']['bookings_status'] as $bookings_status_arr ) { $bookings_status_arr = explode( '|', $bookings_status_arr ); foreach ( $bookings_status_arr as $bookings_status_element ) { $temp_status[] = $bookings_status_element; } } $temp_status = array_filter( $temp_status ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. $temp_status = array_unique( $temp_status ); $availability_per_this_day['summary']['status_for_bookings'] = $temp_status; // Priority: pending > approved > '' // if at least one booking pending then day is pending if ( in_array( 'pending', $availability_per_this_day['summary']['status_for_bookings'] ) ) { $availability_per_this_day['summary']['status_for_bookings'] = 'pending'; } else if ( in_array( 'pending_pending', $availability_per_this_day['summary']['status_for_bookings'] ) ) { $availability_per_this_day['summary']['status_for_bookings'] = 'pending_pending'; // Usual situations for change over days: pending_pending | pending_approved | approved_pending | approved_approved } else { $availability_per_this_day['summary']['status_for_bookings'] = implode( ' ', $availability_per_this_day['summary']['status_for_bookings'] ); } // ------------------------------------------------------------------------------------------------------------- return $availability_per_this_day; } // T O O L T I P s /** * Set tooltip summary -- Time-Slots * * @param $availability_per_this_day * @param $my_day_tag * @param $resource_id_arr * * @return string - tooltip content or '' */ function wpbc_support_capacity__tooltip__summary__times( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ $tooltip = ''; if ( 'On' != get_bk_option( 'booking_disable_timeslots_in_tooltip' ) ) { //FixIn: 9.5.0.2.2 $tooltip_title_word = get_bk_option( 'booking_highlight_timeslot_word' ); $tooltip_title_word = wpbc_lang( $tooltip_title_word ); $tooltip_title_word = ( empty( $tooltip_title_word ) ) ? '' : '<div class="wpbc_tooltip_title">' . $tooltip_title_word . '</div>' . ' '; $status_summary_tooltip_times = array(); foreach ( $resource_id_arr as $resource_id ) { if ( ! empty( $availability_per_this_day[ $resource_id ]->tooltips['times'] ) ) { $status_summary_tooltip_times[] = $availability_per_this_day[ $resource_id ]->tooltips['times']; } } if ( ! empty( $status_summary_tooltip_times ) ) { $tooltip = '<div class="wpbc_tooltip_section tooltip__times">' . $tooltip_title_word . implode( '', $status_summary_tooltip_times ) . '</div>'; } } return $tooltip; } function wpbc_support_capacity__tooltip__summary__availability( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ $tooltip = ''; if ( ( 'On' == get_bk_option( 'booking_is_show_availability_in_tooltips' ) ) && ( $availability_per_this_day['max_capacity'] > 1 ) ) { $tooltip_title_word = get_bk_option( 'booking_highlight_availability_word' ); $tooltip_title_word = wpbc_lang( $tooltip_title_word ); $tooltip_title_word = ( empty( $tooltip_title_word ) ) ? '' : '<div class="wpbc_tooltip_title">' . $tooltip_title_word . '</div>' . ' '; $tooltip_content_header = ''; if ( ! empty( $availability_per_this_day['day_availability'] ) ) { $tooltip = '<div class="wpbc_tooltip_section tooltip__availability">' . $tooltip_title_word . '<div class="wpbc_tooltip_resource_container">' . $tooltip_content_header . '<div class="wpbc_tooltip_item">' . $availability_per_this_day['day_availability'] . '</div>' . '</div>' . '</div>'; } } return $tooltip; } function wpbc_support_capacity__tooltip__summary__day_cost( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ $tooltip = ''; if ( ( ! empty( $availability_per_this_day['day_availability'] ) ) && ( 'On' == get_bk_option( 'booking_is_show_cost_in_tooltips' ) ) ){ $tooltip_title_word = get_bk_option( 'booking_highlight_cost_word' ); $tooltip_title_word = wpbc_lang( $tooltip_title_word ); $tooltip_title_word = ( empty( $tooltip_title_word ) ) ? '' : '<div class="wpbc_tooltip_title">' . $tooltip_title_word . '</div>' . ' '; $id_of_first_resource = $resource_id_arr[0]; $tooltip_content_header = ''; if ( ! empty( $availability_per_this_day[ $id_of_first_resource ]->date_cost_rate ) ) { $cur_sym = get_bk_option( 'booking_cost_in_date_cell_currency' ); // in Booking > Settings General page in "Calendar" section //$cur_sym = wpbc_get_currency_symbol(); // in Booking > Settings > Payment page $cost_text = wpbc_formate_cost_hint__no_html( $availability_per_this_day[ $id_of_first_resource ]->date_cost_rate, $cur_sym ); $cost_text = html_entity_decode( $cost_text ); $tooltip = '<div class="wpbc_tooltip_section tooltip__day_cost">' . $tooltip_title_word . '<div class="wpbc_tooltip_resource_container">' . $tooltip_content_header . '<div class="wpbc_tooltip_item">' . $cost_text . '</div>' . '</div>' . '</div>'; } } return $tooltip; } function wpbc_support_capacity__in_day_hint__summary__day_cost( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ $tooltip = ''; if ( ( ! empty( $availability_per_this_day['day_availability'] ) ) && ( 'On' == get_bk_option( 'booking_is_show_cost_in_date_cell' ) ) ){ $id_of_first_resource = $resource_id_arr[0]; if ( ! empty( $availability_per_this_day[ $id_of_first_resource ]->date_cost_rate ) ) { $cur_sym = get_bk_option( 'booking_cost_in_date_cell_currency' ); // in Booking > Settings General page in "Calendar" section //$cur_sym = wpbc_get_currency_symbol(); // in Booking > Settings > Payment page $cost_text = $availability_per_this_day[ $id_of_first_resource ]->date_cost_rate; $cost_text = number_format( floatval( $cost_text ), wpbc_get_cost_decimals(), '.', '' ); $cost_text = strip_tags( wpbc_cost_show( $cost_text, array( 'currency' => 'CURRENCY_SYMBOL' ) ) ); $cost_text = str_replace( array( 'CURRENCY_SYMBOL', '&' ), array( $cur_sym, '&' ), $cost_text ); $cost_text = html_entity_decode($cost_text); $tooltip = $cost_text; } } return $tooltip; } /** * Set tooltip summary -- Booking Details * * @param $availability_per_this_day * @param $my_day_tag * @param $resource_id_arr * * @return string - tooltip content or '' */ function wpbc_support_capacity__tooltip__summary__booked_details( $availability_per_this_day, $my_day_tag, $resource_id_arr ){ $tooltip = ''; if ( 'On' == get_bk_option( 'booking_is_show_booked_data_in_tooltips' ) ) { //FixIn: 9.5.0.2.2 $tooltip_title_word = '<div class="wpbc_tooltip_title">' . __('Booking details','booking') . '</div>'; $status_summary_tooltip_times = array(); foreach ( $resource_id_arr as $resource_id ) { if ( ! empty( $availability_per_this_day[ $resource_id ]->tooltips['details'] ) ) { if ( ! empty( $availability_per_this_day[ $resource_id ]->tooltips['resource_title'] ) ){ $tooltip_content_header = '<div class="wpbc_tooltip_header">' . $availability_per_this_day[ $resource_id ]->tooltips['resource_title'] . ': ' . '</div>'; } else{ $tooltip_content_header = ''; } $booking_details_text = '<div class="wpbc_tooltip_resource_container">' . $tooltip_content_header . implode( ' ', $availability_per_this_day[ $resource_id ]->tooltips['details'] ) . '</div>'; $status_summary_tooltip_times[] = $booking_details_text; } } if ( ! empty( $status_summary_tooltip_times ) ) { $tooltip = '<div class="wpbc_tooltip_section tooltip__booking_details">' . $tooltip_title_word . implode( '', $status_summary_tooltip_times ) . '</div>'; } } return $tooltip; } /** * Set Tooltip -- Booking Details * * @param $availability_per_day * @param $my_day_tag * @param $resource_id * @param $this_date_bookings * @param $booked_times__key * @param $resources_obj * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ]; */ function wpbc_support_capacity__tooltip__set_for_details( $availability_per_day, $my_day_tag, $resource_id, $this_date_bookings, $booked_times__key, $resources_obj, $booked_time ) { // Get booking details for tooltip, if needed if ( 'On' == get_bk_option( 'booking_is_show_booked_data_in_tooltips' ) ) { $booking_id = $this_date_bookings[ $booked_times__key ]->booking_id; $this_booking_resource_id = $this_date_bookings[ $booked_times__key ]->type; $booking_details_text = wpbc_support_capacity__get_booking_details( $this_date_bookings[ $booked_times__key ], $resources_obj->get__booking_resource_obj( $this_booking_resource_id ) ); $tooltip_text = ''; $tooltip_text .= '<div class="wpbc_tooltip_item tooltip_booked_time">' . $booked_time . '</div>'; // Booked time $tooltip_text .= '<div class="wpbc_tooltip_item">' . $booking_details_text . '</div>'; // Booking details $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips['details'][ $booking_id ] = $tooltip_text; } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set Tooltip Times -- Time-Slots * * @param $availability_per_day * @param $my_day_tag * @param $resource_id * @param $resource_id_arr * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ]; */ function wpbc_support_capacity__tooltip_times__set_for_times( $availability_per_day, $my_day_tag, $resource_id, $resource_id_arr ){ // Times Tooltip - time slot list -------------------------------------------------------------------- $tooltip_content_header = ''; if ( count( $resource_id_arr ) > 1 ) { $class_name = 'tooltip_items_count_' . count( $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['merged_readable'] ); $tooltip_content_header = '<div class="wpbc_tooltip_header ' . $class_name . ' ">' . $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips['resource_title'] . ': ' . '</div>'; } $tooltip_content_arr = array_map( function ( $item ) { return '<div class="wpbc_tooltip_item">' . $item . '</div>'; } , $availability_per_day[ $my_day_tag ][ $resource_id ]->booked_time_slots['merged_readable'] ); $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips['times'] = '<div class="wpbc_tooltip_resource_container">' . $tooltip_content_header . implode( '', $tooltip_content_arr ) . '</div>'; return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set Tooltip Times -- Full Day * * @param $availability_per_day * @param $my_day_tag * @param $resource_id * @param $resource_id_arr * @param $status_title * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ]; */ function wpbc_support_capacity__tooltip_times__set_full_day( $availability_per_day, $my_day_tag, $resource_id, $resource_id_arr, $status_title ){ // Times Tooltip - FULL DAY -------------------------------------------------------------------- $tooltip_content_header = ''; if ( count( $resource_id_arr ) > 1 ) { $class_name = 'tooltip_items_count_1'; $tooltip_content_header = '<div class="wpbc_tooltip_header ' . $class_name . ' ">' . $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips['resource_title'] . ': ' . '</div>'; } $tooltip_content_text = '<div class="wpbc_tooltip_item">' . $status_title . '</div>'; $availability_per_day[ $my_day_tag ][ $resource_id ]->tooltips['times'] = '<div class="wpbc_tooltip_resource_container">' . $tooltip_content_header . $tooltip_content_text . '</div>'; return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Get parsed booking data, if required * * @param object $this_date_bookings * @param object $resource_obj * * @return string */ function wpbc_support_capacity__get_booking_details( $this_date_bookings, $resource_obj ) { if ( ( ! class_exists( 'wpdev_bk_biz_m' ) ) || ( 'On' !== get_bk_option( 'booking_is_show_booked_data_in_tooltips' ) ) ){ return ''; } $booking_details_for_hint = ''; if ( isset( $this_date_bookings->form ) ) { // Get shortcodes $booking_shortcodes_in_tooltips = get_bk_option( 'booking_booked_data_in_tooltips' ); // '[name] [secondname]' $resource_id = $this_date_bookings->type; // Get parsed booking data field values -- e.g.: [ "rangetime":"12:00 - 14:00", "secondname":"Smith",... ] $booking_data_arr = wpbc_get_parsed_booking_data_arr( $this_date_bookings->form, $resource_id, array( 'get' => 'value' ) ); $booking_data_arr['booking_id'] = $this_date_bookings->booking_id; $booking_data_arr['resource_id'] = $resource_id; $booking_data_arr['resource_title'] = ( ! empty( $resource_obj ) ) ? wpbc_lang( $resource_obj->title ) : ''; // Replace existing shortcodes foreach ( $booking_data_arr as $replace_shortcode => $replace_value ) { if ( is_null( $replace_value ) ) { $replace_value = ''; }; $replace_value = wpbc_replace__true_false__to__yes_no( $replace_value ); //FixIn: 9.8.9.1 $booking_shortcodes_in_tooltips = str_replace( array( '[' . $replace_shortcode . ']' , '{' . $replace_shortcode . '}' ) , $replace_value , $booking_shortcodes_in_tooltips ); } $booking_details_for_hint = $booking_shortcodes_in_tooltips; // Remove all shortcodes, which is not replaced early. $booking_details_for_hint = preg_replace( '/[\[\{][a-zA-Z0-9.,_-]{0,}[\]\}]/', '', $booking_details_for_hint ); } return $booking_details_for_hint; } /** * Unset some fields from booking data for do not show personal data at front-end side * * @param object $this_date_bookings * * @return object */ function wpbc_support_capacity__unset_some_fields( $this_date_bookings ) { if ( isset( $this_date_bookings->form ) ) { unset( $this_date_bookings->form ); // Hide booking details } if ( isset( $this_date_bookings->booking_date ) ) { unset( $this_date_bookings->booking_date ); // Confusing property of last end booking date, because we have 'sql summary booking dates arrays' for all dates and times } return $this_date_bookings; } // D A Y S T A T U S U N A V A I L A B L E /** * Set > _day_status = 'limit_available_from_today' depends on Booking > Settings General page ---> "Limit available days from today" * * @param $availability_per_day [ ... ] * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ] */ function wpbc_support_capacity__day_status__limit_available_from_today( $availability_per_day, $my_day_tag, $resource_id ){ // ----------------------------------------------------------------------------------------------------- // limit_available_from_today // 3. Limit available days from today if ( function_exists( 'wpbc_is_day_available__relative__limit_available_from_today' ) ) { if ( ! wpbc_is_day_available__relative__limit_available_from_today( $my_day_tag ) ) { // this date unavailable $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'limit_available_from_today'; if ( empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = array(); // Reset bookings details } } } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set > _day_status = 'from_today_unavailable' depends on Booking > Settings General page ---> "Unavailable days from today" * * @param $availability_per_day [ ... ] * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ] */ function wpbc_support_capacity__day_status__from_today_unavailable( $availability_per_day, $my_day_tag, $resource_id ){ // ----------------------------------------------------------------------------------------------------- // from_today_unavailable // 2. Unavailable days from today $unavailable_days_num_from_today = get_bk_option( 'booking_unavailable_days_num_from_today' ); //FixIn: 9.9.0.17 $start_date_unix = strtotime( '+' . intval( $unavailable_days_num_from_today ) . ' days' ); // + 0 days $date_with_wp_timezone = wpbc_datetime_localized__use_wp_timezone( date( 'Y-m-d H:i:s', $start_date_unix ), 'Y-m-d 00:00:00' ); $today_timestamp_wp_timezone = strtotime( $date_with_wp_timezone ); $days_number = intval( ( $today_timestamp_wp_timezone - strtotime( $my_day_tag ) ) / 86400 ); //$days_number = intval( ( strtotime( '+' . intval( $unavailable_days_num_from_today ) . ' days' ) - strtotime( $my_day_tag ) ) / 86400 ); if ( $days_number > 0 ) { // this date unavailable $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'from_today_unavailable'; if ( empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = array(); // Reset bookings details } } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set > _day_status = 'weekday_unavailable' depends on Booking > Settings General page ---> "Week Days unavailable" * * @param $availability_per_day [ ... ] * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ] */ function wpbc_support_capacity__day_status__weekday_unavailable( $availability_per_day, $my_day_tag, $resource_id ){ // 1. Week Days unavailable -------------------------------------------------------------------------------- // weekday_unavailable $unavailable_weekdays = array(); foreach ( range( 0, 6 ) as $week_day_num ) { $unavailable_weekdays[ $week_day_num ] = ( 'On' == get_bk_option( 'booking_unavailable_day' . $week_day_num ) ) ? true : false; } $this_day_week_num = date( 'w', strtotime( $my_day_tag ) ); // 0 - 6 if ( $unavailable_weekdays[ $this_day_week_num ] ) { // this date unavailable $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'weekday_unavailable'; if ( empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = array(); // Reset bookings details } } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set > _day_status = 'resource_availability' depends on Booking > Availability page * * @param $availability_per_day [ ... ] * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * @param array $unavailable_dates__per_resources__arr - [ 2: ['2023-08-01', '2023-08-02'], 10: ['2023-08-05', '2023-08-06'] ] * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ] */ function wpbc_support_capacity__day_status__resource_availability( $availability_per_day, $my_day_tag, $resource_id, $unavailable_dates__per_resources__arr ){ // Booking > Availability page ----------------------------------------------------------------------------- // resource_availability /** * $unavailable_dates__per_resources__arr = Array ( [2] => Array( [0] => 2023-08-01 [1] => 2023-08-02 ) [10] => Array( [0] => 2023-08-05 [1] => 2023-08-06 ) ) */ if ( ( isset( $unavailable_dates__per_resources__arr[ $resource_id ] ) ) && ( in_array( $my_day_tag, $unavailable_dates__per_resources__arr[ $resource_id ] ) ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'resource_availability'; if ( empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = array(); // Reset bookings details } } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } /** * Set > _day_status = 'season_filter' depends on Booking > Resources > Availability page * * @param $availability_per_day [ ... ] * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * @param array $season_filters_availability - [...] * * @return array - $availability_per_day[ $my_day_tag ][ $resource_id ] */ function wpbc_support_capacity__day_status__season_filter( $availability_per_day, $my_day_tag, $resource_id, $season_filters_availability ){ if ( function_exists( 'wpbc_is_this_day_available_in_season_filters' ) ) { // BM and higher $is_date_available = wpbc_is_this_day_available_in_season_filters( $my_day_tag, $resource_id, $season_filters_availability[ $resource_id ] ); // Get availability if ( ! $is_date_available ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->is_day_unavailable = true; $availability_per_day[ $my_day_tag ][ $resource_id ]->_day_status = 'season_filter'; if ( empty( $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details ) ) { $availability_per_day[ $my_day_tag ][ $resource_id ]->__booked__times__details = array(); // Reset bookings details } } } return $availability_per_day[ $my_day_tag ][ $resource_id ]; } // D A Y C O S T /** * Get day cost depend on Rates * @param $my_day_tag - '2023-08-08' * @param $resource_id - 2 * @param $base_cost - 25 * * @return int|string */ function wpbc_support_capacity__get_day_cost( $my_day_tag, $resource_id, $base_cost ) { $fin_day_cost = 0; if ( function_exists( 'wpbc_get_1_day_cost_apply_rates' ) ) { list( $year, $month, $day ) = explode( '-', $my_day_tag ); $day = intval( $day ); $month = intval( $month ); $year = intval( $year ); $fin_day_cost = wpbc_get_1_day_cost_apply_rates( $resource_id, $base_cost, $day, $month, $year ); } return $fin_day_cost; } // </editor-fold> //TODO: M I G R A T E to 9.8 // . // instead of this: <script type="text/javascript"> wpbc_settings.set_option( 'pending_days_selectable', true ); </script> // use this: <script type="text/javascript"> _wpbc.calendar__set_param_value( " . intval( $resource_id ) . ", 'pending_days_selectable' , true ); </script> // Booking Calendar - JavaScript Settings // Example or redefine some settings: // <script type="text/javascript"> wpbc_settings.set_option( 'pending_days_selectable', true ); </script> // [booking type=1] // . // . // 1. Define parameters for calendar(s): // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'days_select_mode': 'single'} ); // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'days_select_mode': 'multiple'} ); // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'days_select_mode': 'fixed'} ); // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'fixed__days_num' : 7 } ); // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'fixed__week_days__start': [-1] } ); // { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } // _wpbc.calendar__set_parameters( " . intval( $resource_id ) . ", {'days_select_mode': 'dynamic'} ); // _wpbc.calendar__set_param_value( " . intval( $resource_id ) . ", 'dynamic__days_min' , 7 ); // _wpbc.calendar__set_param_value( " . intval( $resource_id ) . ", 'dynamic__days_max' , 14 ); // _wpbc.calendar__set_param_value( " . intval( $resource_id ) . ", 'dynamic__days_specific' , [] ); // Example [5,7] // _wpbc.calendar__set_param_value( " . intval( $resource_id ) . ", 'dynamic__week_days__start' , [-1] ); // { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } // JavaScript functions changes: // wpbc_unselect_all_days( resource_id ) -> wpbc_calendar__unselect_all_dates( resource_id ) // showErrorMessage( element , errorMessage , isScrollStop ); -> wpbc_front_end__show_message__warning( jq_node, message ); // showMessageUnderElement( element , errorMessage , message_type); -> wpbc_front_end__show_message__warning_under_element( jq_node, message ); // makeScroll( object_name ); -> wpbc_do_scroll( jq_node ); // . // JavaScript hooks changes: // jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, date ] ); // become // jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, mouse_clicked_dates, all_selected_dates_arr ] ); // where: // mouse_clicked_dates Can be: "05.10.2023 - 07.10.2023" | "10.10.2023 - 10.10.2023" | // all_selected_dates_arr Can be: [ "2023-10-05", "2023-10-06", "2023-10-07", … ] // PHP actions: // from: make_bk_action('wpdev_booking_post_inserted', $booking_id, $bktype, $str_dates__dd_mm_yyyy, array($start_time, $end_time ) , $formdata ); // removed! // . // from: apply_filters('wpdev_booking_form_content', $form , $resource_id); // to: apply_filters( 'wpbc_booking_form_html__update__append_change_over_times', $form, $resource_id ); // . // Removed PHP actions: // . 'show_payment_forms__for_ajax' // * make_bk_action('wpbc_ add_new_booking' , array( // * 'bktype' => 1 // * , 'dates' => '27.08.2014, 28.08.2014, 29.08.2014' // * , 'form' => 'selectbox-one^rangetime1^10:00 - 12:00~text^name1^Jo~text^secondname1^Smith~email^email1^smith@gmail.com~text^phone1^678676678~text^address1^Linkoln Street~text^city1^London~text^postcode1^78788~selectbox-one^country1^GB~selectbox-one^visitors1^1~selectbox-one^children1^1~textarea^details1^Rooms with sea view~checkbox^term_and_condition1[]^I Accept term and conditions' // * , 'is_send_emeils' => 0 // * // , 'booking_form_type' => '' // * // , 'wpdev_active_locale' => 'en_US' // * ) ); // . // add_bk_filter('wpbc_add_new_booking_filter' , 'wpbc_add_new_booking' ); // TODO: recheck hooks in wpbc-dev-api.php get_times_fields.php 0000666 00000041405 15165546743 0010613 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 /** * Get Time Slots from booking form for Each date: [ '2023-10-25' => [ '12:20 - 12:55', '13:00 - 14:00' ], '2023-10-26' => [ ... ], ... ] * * @param $resource_id // Resource ID (used in case of MultiUser version for getting specific form for regular users) * @param $custom_form_name // Form name for getting time slots configuration * @param $start_date_unix_timestamp // Unix Timestamp to start dates count * @param $days_count // Int number of how many dates to check * * @return array [ '2023-10-25' => [ '12:20 - 12:55', '13:00 - 14:00' ], '2023-10-26' => [ ... ], ... ] * * Example: * $timeslots_arr = wpbc_get_times_fields_configuration( * 1, * 'my_custom_form_name', * strtotime( date( 'Y-m-d 00:00:00', strtotime( 'now' ) ) ), * 365 * ); */ function wpbc_get_times_fields_configuration__by_dates( $resource_id, $custom_form_name, $start_date_unix_timestamp, $days_count ){ // Get booking form configuration CONTENT $booking_form_fields = wpbc_get__booking_form_fields__configuration( $resource_id, $custom_form_name ); // ----------------------------------------------------------------------------------------------------------------- // Get conditional sections, if exist // ----------------------------------------------------------------------------------------------------------------- /** * result=[ weekday-condition=[ 0=[ * type = "weekday" * value = "*" * options = false * content = "\r\n Default: [selectbox rangetime "10:00 - 11:00" "11:00 - 12:00" "12:00 - 13:00" "13:00 - 14:00" "14:00 - 15:00" "15:00 - 16:00" "16:00 - 17:00" "17:00 - 18:00"]\r\n" * structure = "[condition name="weekday-condition" type="weekday" value="*"]\r\n Default: [selectbox rangetime "10:00 - 11:00" "11:00 - 12:00" "12:00 - 13:00" "13:00 - 14:00" "14:00 - 15:00" "15:00 - 16:00" "16:00 - 17:00" "17:00 - 18:00"]\r\n[/condition]" * 1 = [ * type = "weekday" * value = "1,2" * options = false * content = " \r\n Monday, Tuesday: [selectbox rangetime "10:00 - 12:00" "12:00 - 14:00"]\r\n" * structure = "[condition name="weekday-condition" type="weekday" value="1,2"] \r\n Monday, Tuesday: [selectbox rangetime "10:00 - 12:00" "12:00 - 14:00"]\r\n[/condition]" * 2 = [ ... ] */ $cached__sql_data__season_filters_arr = array(); if ( function_exists( 'wpbc_conditions_form__get_sections' ) ) { $conditions = wpbc_conditions_form__get_sections( $booking_form_fields ); if ( ! empty( $conditions ) ) { // ["High season", "Weekend season"] $season_names_arr = wpbc_conditions_get_season_titles_arr( $booking_form_fields ); // Load all seasons from DB to cache them - for having only one SQL request to DB, if needed $cached__sql_data__season_filters_arr = wpbc_db_get_season_data_arr__for_these_season_names( $season_names_arr ); } } else { $conditions = array(); } // ----------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------- // Get Time Slots [ "10:30 - 10:45", "11:00 - 11:15", "11:30 - 12:00", ... ] if NO conditional sections - time slot the same for all dates. Get them once here. // ----------------------------------------------------------------------------------------------------------------- if ( empty( $conditions ) ) { $time_slots_arr = wpbc_get_timeslots__from_content( $booking_form_fields ); } else { $time_slots_arr = array(); } // ----------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------- // Here Go for each DATE // ----------------------------------------------------------------------------------------------------------------- $dates_times_fields_arr = array(); for ( $day_num = 0; $day_num <= $days_count; $day_num ++ ) { $my_day_tag = date( 'Y-m-d', $start_date_unix_timestamp ); // '2023-07-19' if ( ( ! empty( $conditions ) ) && ( function_exists( 'wpbc_conditions_form__get_section__depend_from_date' ) ) ){ // Get booking form conditional section depends on DATE $section_content = wpbc_conditions_form__get_section__depend_from_date( $conditions, $my_day_tag , $cached__sql_data__season_filters_arr ); // Get Time Slots [ "10:30 - 10:45", "11:00 - 11:15", "11:30 - 12:00", ... ] $time_slots_in_section_arr = wpbc_get_timeslots__from_content( $section_content ); $dates_times_fields_arr[ $my_day_tag ] = $time_slots_in_section_arr; } else { $dates_times_fields_arr[ $my_day_tag ] = $time_slots_arr; } // DEBUG: $dates_times_fields_arr[$my_day_tag] = array( '00:00 - 24:00', '10:00 - 12:00', '12:00 - 14:00', '14:00 - 16:00', '16:00 - 18:00', '18:00 - 20:00' , '09:01 - 09:02' ); $start_date_unix_timestamp += 24 * 60 * 60; // Go next day + 1 day } return $dates_times_fields_arr; } /** * Get Time-Slots (CONVERT READABLE to SECONDS) seconds range array for the specified date from array of dates, where each date include readable time-ranges array * * @param $dates_arr__with__readable_time_slots_arr = [ * 2023-10-25 = [], * 2023-10-26 = [ * 0 => '00:00 - 24:00', * 1 => '10:00 - 12:00', * 2 => '12:00 - 14:00', * 3 => '14:00 - 16:00', * 4 => '16:00 - 18:00', * 5 => '18:00 - 20:00', * 6 => '09:01 - 09:02', * ], * 2023-10-27 = [], ... * ] * @param $my_day_tag = '2023-10-25' * * @return array|string[] IF ( $my_day_tag == '2023-10-25' ) => [] * OR ( $my_day_tag == '2023-10-26' ) => [ * 0 => '1 - 86392', * 1 => '36011 - 43192', * 2 => '43211 - 50392', * 3 => '50411 - 57592', * 4 => '57611 - 64792', * 5 => '64811 - 71992', * 6 => '32471 - 32512', * ] */ function wpbc_get__time_range_in_seconds_arr__for_date( $dates_arr__with__readable_time_slots_arr, $my_day_tag ) { if ( isset( $dates_arr__with__readable_time_slots_arr[ $my_day_tag ] ) ) { $bookingform__available_timeslots_in_sec__arr = array_map( function ( $time_slot_readable ) { return wpbc_convert__readable_time_slot__to__time_range_in_seconds( $time_slot_readable ); } , $dates_arr__with__readable_time_slots_arr[ $my_day_tag ] ); return $bookingform__available_timeslots_in_sec__arr; } return array(); } // ===================================================================================================================== // Get Time-Slots from CONTENT (booking form configuration) // ===================================================================================================================== /** * Get Time-Slots ["10:30 - 10:45", "11:00 - 11:15", "11:30 - 12:00", ... ] time slot values from booking form content ( or part of booking form configuration) * * @param string $content '[calendar]... <p>Time: [select* rangetime "Full Day@@00:00 - 24:00" "10:00 AM - 12:00 PM@@10:00 - 12:00"] ...' * * @return array */ function wpbc_get_timeslots__from_content( $content ){ $time_slots_arr =array(); // == RANGE TIME == [ '10:00 - 12:00', '12:00 - 14:00' ... ] ------------------------------------------------- if ( false !== strpos( $content, ' rangetime ' ) ) { $time_slots_arr = wpbc_get_timeslots__for_rangetime( $content ); } else { // == START TIME | END TIME == -------------------------------------------------------------------------------- if ( ( false !== strpos( $content, ' starttime ' ) ) // Important to have empty space at the beginning, because it will search for [selectbox starttime and skip this [starttime] && ( false !== strpos( $content, ' endtime ' ) ) // Important to have empty space at the beginning, because it will search for [selectbox endtime and skip this [endtime] ){ // Now we need to create the smallest time intervals ( 60 sec. ) for each start / end times. // == START TIME == [ '10:00 - 10:01', '12:00 - 12:01' ... ] $start_time_slots_arr = wpbc_get_timeslots__for_starttime( $content , 60 ); foreach ( $start_time_slots_arr as $ts ) { $time_slots_arr[] = $ts; } // == END TIME == [ '09:59 - 10:00', '11:59 - 12:00' ... ] $end_time_slots_arr = wpbc_get_timeslots__for_endtime( $content , 60 ); foreach ( $end_time_slots_arr as $ts ) { $time_slots_arr[] = $ts; } } // == START TIME | DURATION TIME == --------------------------------------------------------------------------- if ( ( false !== strpos( $content, ' starttime ' ) ) // Important to have empty space at the beginning, because it will search for [selectbox starttime and skip this [starttime] && ( false !== strpos( $content, ' durationtime ' ) ) ){ // 900 -> e.g.: '00:15' $min_time_duration = wpbc_get__min_time_duration__in_seconds( $content ); if ( false !== $min_time_duration ) { // == START TIME == [ '10:00 - 10:15', '12:00 - 12:15' ... ] $start_time_slots_arr = wpbc_get_timeslots__for_starttime( $content, $min_time_duration ); foreach ( $start_time_slots_arr as $ts ) { $time_slots_arr[] = $ts; } } } } return $time_slots_arr; } /** * Get Time-Slots == RANGE TIME == [ '10:00 - 12:00', '12:00 - 14:00' ... ] from provided booking form configuration content * * @param $bookingform_configuration_content - '[calendar]... <p>Time: [select* rangetime "Full Day@@00:00 - 24:00" "10:00 AM - 12:00 PM@@10:00 - 12:00"] ...' * * @return array * * $time_slots_arr = [ * [0] => 00:00 - 24:00 * [1] => 10:00 - 12:00 * [2] => 12:00 - 14:00 * [3] => 14:00 - 16:00 * [4] => 16:00 - 18:00 * [5] => 18:00 - 20:00 * ] * OR * [] */ function wpbc_get_timeslots__for_rangetime( $bookingform_configuration_content ) { $time_slots_arr = array(); $shortcode_values = wpbc_parse_form__get_first_shortcode_values( 'rangetime', $bookingform_configuration_content ); if ( ! empty( $shortcode_values ) ) { foreach ( $shortcode_values as $timeslot_value ) { if ( ! empty( $timeslot_value['value'] ) ) { $time_slots_arr[] = $timeslot_value['value']; } } } return $time_slots_arr; } /** * Get Time-Slots from == START TIME == [ '10:00 - 10:01', '12:00 - 12:01' ... ] searching in provided booking form configuration content * * @param string $bookingform_configuration_content '[calendar]... <p>Time: [select* rangetime "Full Day@@00:00 - 24:00" "10:00 AM - 12:00 PM@@10:00 - 12:00"] ...' * @param int $time_shift_duration_in_seconds 60 * * @return array * * $time_slots_arr = [ * [1] => 10:00 - 10:01 * [2] => 12:00 - 12:01 * [3] => 14:00 - 14:01 * [4] => 16:00 - 16:01 * [5] => 18:00 - 18:01 * ] * OR * [] */ function wpbc_get_timeslots__for_starttime( $bookingform_configuration_content , $time_shift_duration_in_seconds = 60 ) { $time_slots_arr = array(); $shortcode_values = wpbc_parse_form__get_first_shortcode_values( 'starttime', $bookingform_configuration_content ); if ( ! empty( $shortcode_values ) ) { foreach ( $shortcode_values as $timeslot_value ) { if ( ! empty( $timeslot_value['value'] ) ) { // '12:00:00' -> 43190 $time_in_seconds = wpbc_transform__24_hours_his__in__seconds( $timeslot_value['value'] . ':00' ); $time_in_seconds += $time_shift_duration_in_seconds; // 43250 -> '12:01:00' $time_his = wpbc_transform__seconds__in__24_hours_his( $time_in_seconds ); $time_his = substr( $time_his, 0, 5 ); // '12:00 - 12:01' $time_slots_arr[] = $timeslot_value['value'] . ' - ' . $time_his; } } } return $time_slots_arr; } /** * Get Time-Slots from == END TIME == [ '09:59 - 10:00', '11:59 - 12:00' ... ] searching in provided booking form configuration content * * @param string $bookingform_configuration_content '[calendar]... <p>Time: [select* rangetime "Full Day@@00:00 - 24:00" "10:00 AM - 12:00 PM@@10:00 - 12:00"] ...' * @param int $time_shift_duration_in_seconds 60 * * @return array * * $time_slots_arr = [ * [1] => 09:59 - 10:00 * [2] => 11:59 - 12:00 * [3] => 13:59 - 14:00 * [4] => 15:59 - 16:00 * [5] => 17:59 - 18:00 * ] * OR * [] */ function wpbc_get_timeslots__for_endtime( $bookingform_configuration_content , $time_shift_duration_in_seconds = 60 ) { $time_slots_arr = array(); $shortcode_values = wpbc_parse_form__get_first_shortcode_values( 'endtime', $bookingform_configuration_content ); if ( ! empty( $shortcode_values ) ) { foreach ( $shortcode_values as $timeslot_value ) { if ( ! empty( $timeslot_value['value'] ) ) { // '12:00:00' -> 43190 $time_in_seconds = wpbc_transform__24_hours_his__in__seconds( $timeslot_value['value'] . ':00' ); $time_in_seconds -= $time_shift_duration_in_seconds; // 43130 -> '11:59:00' $time_his = wpbc_transform__seconds__in__24_hours_his( $time_in_seconds ); $time_his = substr( $time_his, 0, 5 ); // '11:59 - 12:00' $time_slots_arr[] = $time_his . ' - ' . $timeslot_value['value']; } } } return $time_slots_arr; } /** * Get minimum duration of time ( from [selectbox durationtime ... ] ) or FALSE, if no such shortcode or no values. * * @param $bookingform_configuration_content * * @return false|int */ function wpbc_get__min_time_duration__in_seconds( $bookingform_configuration_content ){ $min_time_duration = false; $time_duration_in_seconds_arr = array(); $shortcode_values = wpbc_parse_form__get_first_shortcode_values( 'durationtime', $bookingform_configuration_content ); if ( ! empty( $shortcode_values ) ) { foreach ( $shortcode_values as $timeslot_value ) { if ( ! empty( $timeslot_value['value'] ) ) { // '00:15' -> 900 $time_in_seconds = wpbc_transform__24_hours_his__in__seconds( $timeslot_value['value'] . ':00' ); // [ 900 , ... ] $time_duration_in_seconds_arr[] = $time_in_seconds; } } } if ( ! empty( $time_duration_in_seconds_arr ) ) { $min_time_duration = min( $time_duration_in_seconds_arr ); } return $min_time_duration; } calendar_load.php 0000666 00000052455 15165546743 0010064 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 /** * Define parameters for calendar -- which is required for JS calendar show * * @param $params * * @return string */ function wpbc__calendar__set_js_params__before_show( $params ) { $start_script_code = ''; // Server Balancer ------------------------------------------------------------------------------------------- //FixIn: //FixIn: 9.8.6.2 $balancer_max_threads = intval( get_bk_option( 'booking_load_balancer_max_threads' ) ); $balancer_max_threads = ( empty( $balancer_max_threads ) ) ? 1 : $balancer_max_threads; $start_script_code .= " _wpbc.balancer__set_max_threads( " . $balancer_max_threads . " ); "; $resource_id = isset( $params['resource_id'] ) ? intval( $params['resource_id'] ) : 1; // Start Month ---------------------------------------------------------------------------------------------------- $calendar_scroll_to = ( ( isset( $params['start_month_calendar'] ) ) && ( is_array( $params['start_month_calendar'] ) ) && ( count( $params['start_month_calendar'] ) > 0 ) ) ? "[ " . strval( intval( $params['start_month_calendar'][0] ) ) . "," . strval( intval( $params['start_month_calendar'][1] ) ) . " ]" : 'false'; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_scroll_to' , " . $calendar_scroll_to . " ); "; // Max months to scroll ------------------------------------------------------------------------------------------- $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_max_monthes_in_calendar' , '" . get_bk_option( 'booking_max_monthes_in_calendar' ) . "' ); "; // Start of WeekDay ----------------------------------------------------------------------------------------------- $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_start_day_weeek' , '" . get_bk_option( 'booking_start_day_weeek' ) . "' ); "; // Number of visible months ----------------------------------------------------------------------------------------------- $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_number_of_months' , '" . $params['calendar_number_of_months'] . "' ); "; // ----------------------------------------------------------------------------------------------------------------- // Days Selection // ----------------------------------------------------------------------------------------------------------------- $days_selection_arr = wpbc__calendar__js_params__get_days_selection_arr(); $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'days_select_mode', '" . $days_selection_arr['days_select_mode'] . "' ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__days_num', " . $days_selection_arr['fixed__days_num'] . " ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__week_days__start', [" .$days_selection_arr['fixed__week_days__start'] . "] ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_min', " . $days_selection_arr['dynamic__days_min'] . " ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_max', " . $days_selection_arr['dynamic__days_max'] . " ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_specific', [" .$days_selection_arr['dynamic__days_specific'] . "] ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__week_days__start', [" .$days_selection_arr['dynamic__week_days__start'] . "] ); "; /** * For Debug :: // $start_script_code .= " _wpbc.calendar__set_parameters( " . $resource_id . ", { // 'days_select_mode' : 'dynamic', // 'dynamic__days_min' : 7, // 'dynamic__days_max' : 14, // 'dynamic__days_specific' : [7,10,14], // 'dynamic__week_days__start' : [-1] // } ); "; // Calendar - Set calendar parameter and value // $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'days_select_mode' , 'multiple' ); "; // $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'days_select_mode' , 'fixed' ); "; // $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__days_num' , 7 ); "; // $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__week_days__start' , [-1] ); "; */ // Date / Time formats: $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'booking_date_format', '" . esc_js( get_bk_option( 'booking_date_format' ) ) . "' ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'booking_time_format', '" . esc_js( get_bk_option( 'booking_time_format' ) ) . "' ); "; // Capacity | availability ---------------------------------------------------------------------------------------- if ( class_exists( 'wpdev_bk_biz_l' ) ) { $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'is_parent_resource' , " . ( wpbc_get_child_resources_number( $resource_id ) ? 1 : 0 ) . " ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_capacity_field' , '" . wpbc_get__booking_capacity_field__name() . "' ); "; $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_is_dissbale_booking_for_different_sub_resources' , '" . get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) . "' ); "; } if ( class_exists( 'wpdev_bk_biz_s' ) ) { $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_recurrent_time' , '" . get_bk_option( 'booking_recurrent_time' ) . "' ); "; } // ----------------------------------------------------------------------------------------------------------------- // Save initial values of days selection for later use in conditional day logic $start_script_code .= " if ( 'function' === typeof ( wpbc__conditions__SAVE_INITIAL__days_selection_params__bm ) ){ wpbc__conditions__SAVE_INITIAL__days_selection_params__bm( " . $resource_id . " ); } "; if ( ( ! empty( $params['shortcode_options'] ) ) && ( function_exists( 'wpbc_parse_shortcode_option__set_days_selection_conditions' ) ) ){ $days_selection_conditions = wpbc_parse_shortcode_option__set_days_selection_conditions( $resource_id, $params['shortcode_options'] ); if ( ! empty( $days_selection_conditions ) ) { $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'conditions', " . wp_json_encode( $days_selection_conditions['conditions'] ). " ); "; $start_script_code .= " _wpbc.seasons__set( " . $resource_id . ", " . wp_json_encode( $days_selection_conditions['seasons'] ) . " ); "; } } return $start_script_code; } /** * Get days selection parameters, which saved in database * * @return array */ function wpbc__calendar__js_params__get_days_selection_arr(){ $specific_days_selection = ( function_exists( 'wpbc_get_specific_range_dates__as_comma_list' ) ) ? wpbc_get_specific_range_dates__as_comma_list( get_bk_option( 'booking_range_selection_days_specific_num_dynamic' ) ) : ''; $data_arr = array(); // Modes :: Selection of Days $data_arr['days_select_mode'] = ( 'range' === get_bk_option('booking_type_of_day_selections') ) ? get_bk_option('booking_range_selection_type') : get_bk_option( 'booking_type_of_day_selections'); $data_arr['fixed__days_num'] = intval( get_bk_option( 'booking_range_selection_days_count' ) ); /* Number of days selection with 1 mouse click */ $data_arr['fixed__week_days__start'] = get_bk_option( 'booking_range_start_day' ); /* { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } */ $data_arr['dynamic__days_min'] = intval( get_bk_option( 'booking_range_selection_days_count_dynamic' ) ); /* Min. Number of days selection with 2 mouse clicks */ $data_arr['dynamic__days_max'] = intval( get_bk_option( 'booking_range_selection_days_max_count_dynamic' ) ); /* Max. Number of days selection with 2 mouse clicks */ $data_arr['dynamic__days_specific'] = $specific_days_selection; /* Example: '5,7' */ $data_arr['dynamic__week_days__start'] = get_bk_option( 'booking_range_start_day_dynamic' ); /* { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } */ return $data_arr; } /** * Get JavaScript for Calendar Loading: 1.Show Calendar 2. Send Ajax to Load bookings / availability / data for calendar * * @param $params * * @return string */ function wpbc__calendar__load( $params = array() ){ $defaults = array( 'resource_id' => '1', // $resource_id 'aggregate_resource_id_arr' => array(), // It is array of booking resources from aggregate parameter() 'selected_dates_without_calendar' => '', // $my_selected_dates_without_calendar 'calendar_number_of_months' => 1, // $my_boook_count 'start_month_calendar' => false, // $start_month_calendar 'shortcode_options' => '', // options from the Booking Calendar shortcode. Usually it's conditional dates selection parameters 'custom_form' => 'standard' ); $params = wp_parse_args( $params, $defaults ); // Resource ID $params['resource_id'] = (int) $params['resource_id']; $start_script_code = '<script type="text/javascript"> ' . wpbc_jq_ready_start(); //FixIn: 10.1.3.7 //$start_script_code .= " wpbc_calendar__loading__start( {$params['resource_id']} ); "; $start_script_code .= wpbc__calendar__set_js_params__before_show( $params ); // ----------------------------------------------------------------------------------------------------------------- // Show calendar $start_script_code .= " wpbc_calendar_show( '" . $params['resource_id'] . "' ); "; // ----------------------------------------------------------------------------------------------------------------- // Set Security - Nonce for Ajax - Listing $start_script_code .= " _wpbc.set_secure_param( 'nonce', '" . wp_create_nonce( 'wpbc_calendar_load_ajx' . '_wpbcnonce' ) . "' ); "; $start_script_code .= " _wpbc.set_secure_param( 'user_id', '" . wpbc_get_current_user_id() . "' ); "; $start_script_code .= " _wpbc.set_secure_param( 'locale', '" . get_user_locale() . "' ); "; // ----------------------------------------------------------------------------------------------------------------- // Get parameters for Ajax request $booking_hash = isset( $_GET['booking_hash'] ) ? $_GET['booking_hash'] : ''; //FixIn: 9.8.15.10 $aggregate_type = 'all'; if ( ( ! empty( $params['shortcode_options'] ) ) && ( function_exists( 'wpbc_parse_calendar_options__aggregate_param' ) ) ) { $aggregate_type = wpbc_parse_calendar_options__aggregate_param( $params['shortcode_options'] ); if ( ( ! empty( $aggregate_type ) ) && ( ! empty( $aggregate_type['type'] ) ) ) { $aggregate_type = $aggregate_type['type']; } else { $aggregate_type = 'all'; } } /** * About ['request_uri']: * At ( front-end ) side the $_SERVER['REQUEST_URI'] = '/resource-id2/' which is good * but in Ajax Response (admin side ) we will have: * $_SERVER['REQUEST_URI'] = '/wp-admin/admin-ajax.php' * $_SERVER['HTTP_REFERER'] = 'http://beta/resource-id2/' * that is why we define 'request_uri' here at front-end side. */ $params_for_request = array( 'resource_id' => $params['resource_id'], 'booking_hash' => $booking_hash, 'request_uri' => $_SERVER['REQUEST_URI'], // Is it the same as window.location.href or 'custom_form' => $params['custom_form'], // Optional. 'aggregate_resource_id_str' => implode( ',', $params['aggregate_resource_id_arr'] ), // Optional. Resource ID from aggregate parameter in shortcode. 'aggregate_type' => $aggregate_type // Optional. 'all' | 'bookings_only' <- it is depends on shortcode parameter: options="{aggregate type=bookings_only}" ); $params_for_request = wp_json_encode( $params_for_request ); // ----------------------------------------------------------------------------------------------------------------- // Send Ajax request to load bookings $start_script_code .= " wpbc_calendar__load_data__ajx( {$params_for_request} ); "; $start_script_code .= wpbc_jq_ready_end() . '</script>'; //FixIn: 10.1.3.7 return $start_script_code; } /** * Response to Ajax request, about loading calendar data * * @return void */ function ajax_WPBC_AJX_CALENDAR_LOAD() { // Security ------------------------------------------------------------------------------------------------------ // in Ajax Post: 'nonce': _wpbc.get_secure_param( 'nonce' ), $action_name = 'wpbc_calendar_load_ajx' . '_wpbcnonce'; $nonce_post_key = 'nonce'; if ( wpbc_is_use_nonce_at_front_end() ) { //FixIn: 10.1.1.2 $result_check = check_ajax_referer( $action_name, $nonce_post_key ); } $user_id = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); /** * SQL --------------------------------------------------------------------------- * * in Ajax Post: 'search_params': _wpbc.search_get_all_params() * * Use prefix "search_params", if Ajax sent - $_REQUEST['search_params']['page_num'], $_REQUEST['search_params']['page_items_count'], ... */ /** * Using this class here only for escaping variables */ $user_request = new WPBC_AJX__REQUEST( array( 'db_option_name' => 'booking__wpbc_calendar_load__request_params', 'user_id' => $user_id, 'request_rules_structure' => array( 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // 'digit_or_csd' 'booking_hash' => array( 'validate' => 's', 'default' => '' ), 'request_uri' => array( 'validate' => 's', 'default' => '' ), 'custom_form' => array( 'validate' => 's', 'default' => 'standard' ), 'aggregate_resource_id_str' => array( 'validate' => 'digit_or_csd', 'default' => '' ), // Comma separated string of resource ID, which was used in 'aggregate' parameter. 'aggregate_type' => array( 'validate' => 's', 'default' => 'all' ) // 'all' | 'bookings_only' //FixIn: 9.8.15.10 ) ) ); $request_prefix = 'calendar_request_params'; $request_params = $user_request->get_sanitized__in_request__value_or_default( $request_prefix ); // NOT Direct: $_REQUEST['search_params']['resource_id'] // Do Job here !! ------------------------------------------------------------------------------------------------- make_bk_action( 'check_pending_unpaid_bookings__do_auto_cancel', $request_params['resource_id'] ); $skip_booking_id = wpbc_get_booking_id__from_hash_in_url( $request_params['booking_hash'] ); // Booking ID ( like 1101 ) to skip in calendar $max_days_count = wpbc_get_max_visible_days_in_calendar(); // 365 - number of visible days // Resource ID from aggregate parameter in booking shortcode! $aggregate_resource_id_arr = explode( ',', $request_params['aggregate_resource_id_str'] ); $aggregate_resource_id_arr = array_filter( $aggregate_resource_id_arr ); // All entries of array equal to FALSE (0, '', '0' ) will be removed. $aggregate_resource_id_arr = array_unique( $aggregate_resource_id_arr ); // Remove duplicates //FixIn: 9.8.15.10 if ( ( $resource_id_key = array_search( $request_params['resource_id'], $aggregate_resource_id_arr ) ) !== false ) { unset( $aggregate_resource_id_arr[ $resource_id_key ] ); // Remove source booking resource from aggregate ARR. //FixIn: 9.8.15.10 } $aggregate_resource_id_arr = array_values($aggregate_resource_id_arr); // Reset keys $availability_per_days__params = array( 'resource_id' => $request_params['resource_id'], 'max_days_count' => $max_days_count, 'skip_booking_id' => $skip_booking_id, 'request_uri' => $request_params['request_uri'], // It different in Ajax requests than $_SERVER['REQUEST_URI'] . It's used for change-over days to detect for exception at specific pages 'custom_form' => $request_params['custom_form'] , 'additional_bk_types' => $aggregate_resource_id_arr // It is array of booking resources from aggregate parameter() // arrays | CSD | int // OPTIONAL , 'aggregate_type' => $request_params['aggregate_type'] // It is string: 'all' | 'bookings_only' // OPTIONAL // , 'as_single_resource' => true // get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources' // , 'max_days_count' => wpbc_get_max_visible_days_in_calendar() // 365 // , 'timeslots_to_check_intersect' => $timeslots_to_check_intersect //TODO 2023-10-25: delete it, because we get it in wpbc_get_availability_per_days_arr() //array( '12:20 - 12:55', '13:00 - 14:00' ) ); // If in Booking > Add booking page we use in URL .../wp-admin/admin.php?page=wpbc-new&booking_type=2&as_single_resource=1 then get availability only for single resource. if ( ( ! empty( $request_params['request_uri'] ) ) && ( strpos( $request_params['request_uri'], 'as_single_resource=1' ) !== false ) ){ $availability_per_days__params['as_single_resource'] = true; } /** * Tricks: * if ( strpos( $request_params['request_uri'],'page=wpbc-new' ) !== false ) { $availability_per_days__params['is_days_always_available'] = true; } * * // Set dates in calendar always available only for specific resources with specific ID * if ( in_array( $request_params['resource_id'], array( 12, 15, 17 ) ) ) { $availability_per_days__params['is_days_always_available'] = true; } */ // Get unavailable dates for calendar $availability_per_days_arr = wpbc_get_availability_per_days_arr( $availability_per_days__params ); // Show message under calendar, if needed. //$availability_per_days_arr['ajx_after_action_message'] = 'Ta Da :))'; //$availability_per_days_arr['ajx_after_action_message_status'] = 'warning'; // Ajax ------------------------------------------------------------------------------------------------------------ wp_send_json( array( /** * Send JSON. It will make "wp_json_encode" - so pass only array, and This function call wp_die( '', '', array( 'response' => null, ) ) . * Pass JS OBJ: response_data in "jQuery.post( " function on success. */ 'ajx_data' => $availability_per_days_arr, 'ajx_search_params' => $_REQUEST[ $request_prefix ], 'ajx_cleaned_params' => $request_params, 'resource_id' => $request_params['resource_id'] ) ); } if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) { add_action( 'wp_ajax_nopriv_' . 'WPBC_AJX_CALENDAR_LOAD', 'ajax_' . 'WPBC_AJX_CALENDAR_LOAD' ); // Client (not logged in) add_action( 'wp_ajax_' . 'WPBC_AJX_CALENDAR_LOAD', 'ajax_' . 'WPBC_AJX_CALENDAR_LOAD' ); // Logged In users (or admin panel) } aggregate.php 0000666 00000014544 15165546743 0007237 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly /** * Bookings from AGGREGATE parameter adding ONLY to PARENT booking resource !. But unavailable dates from Booking > Availability page added to PARENT and CHILDREN booking resources. */ /** * Merge unavailable dates from AGGREGATE resources into REAL resource * * @param $unavailable_dates__per_resources__arr = [ 3 => [ 0 => '2023-12-01', 1 => '2023-12-02', 2 => '2023-12-03' ], 4 => [ 0 => '2023-12-03', 1 => '2023-12-04', 2 => '2023-12-05', ], 25 =>[ 0 => '2023-12-09', 1 => '2023-12-10', ] ] * @param $aggregate_resource_id_arr = [ 3, 25 ] * @param $aggregate_resource_id_arr = [ 4 ] * * @return mixed */ function wpbc_aggregate_merge_availability( $unavailable_dates__per_resources__arr, $source_res_id__with_children__arr, $aggregate_resource_id_arr ) { $new_resource_arr__dates_arr = array(); // Get availability only for Real Resource foreach ( $source_res_id__with_children__arr as $source_res_id ) { if ( ! in_array( $source_res_id, $aggregate_resource_id_arr ) ) { $new_resource_arr__dates_arr[ $source_res_id ] = array(); if ( ! empty( $unavailable_dates__per_resources__arr[ $source_res_id ] ) ) { $new_resource_arr__dates_arr[ $source_res_id ] = $unavailable_dates__per_resources__arr[ $source_res_id ]; } } } // Add aggregate resources availability foreach ( $aggregate_resource_id_arr as $aggregate_res_id ) { if ( ! empty( $unavailable_dates__per_resources__arr[ $aggregate_res_id ] ) ) { // Go by dates foreach ( $unavailable_dates__per_resources__arr[ $aggregate_res_id ] as $date_unavailable ) { // Now need to add this date into all Real resources (which can be parent and child resources ) foreach ( $new_resource_arr__dates_arr as $merged_resource_id => $dates_array ) { $new_resource_arr__dates_arr[ $merged_resource_id ][] = $date_unavailable; // Append date to merged real resource array $dates_array = array_unique( $new_resource_arr__dates_arr[ $merged_resource_id ] ); // Remove Duplicates sort( $new_resource_arr__dates_arr[ $merged_resource_id ] ); // Sort } } } } return $new_resource_arr__dates_arr; } /** * Merge all bookings from AGGREGATE resources into REAL resources * * @param $resources__booking_id__obj = [ * 3 = [ * 5370 = {stdClass} * ] * 4 = [ * 5369 = {stdClass} * 5364 = {stdClass} * 5367 = {stdClass} * 5366 = {stdClass} * 5368 = {stdClass} * ] * ] * @param $source_res_id__with_children__arr [ 3, 25 ] * @param $aggregate_resource_id_arr [ 4 ] * * @return array = [ * 4 = [ * 5370 = {stdClass} * 5369 = {stdClass} * 5364 = {stdClass} * 5367 = {stdClass} * 5366 = {stdClass} * 5368 = {stdClass} * ] * ] */ function wpbc_aggregate__merge_bookings__from_aggregate__in_source_resource__arr( $resources__booking_id__obj, $source_res_id__with_children__arr, $aggregate_resource_id_arr ) { $new_resource_arr__bookings_arr = array(); // Get availability only for Real Resource foreach ( $source_res_id__with_children__arr as $source_res_id ) { if ( ! in_array( $source_res_id, $aggregate_resource_id_arr ) ) { $new_resource_arr__bookings_arr[ $source_res_id ] = array(); if ( ! empty( $resources__booking_id__obj[ $source_res_id ] ) ) { $new_resource_arr__bookings_arr[ $source_res_id ] = wpbc_clone_array_of_objects( $resources__booking_id__obj[ $source_res_id ] ); } } } // Add aggregate resources bookings into ALL source resources foreach ( $aggregate_resource_id_arr as $aggregate_res_id ) { if ( ! empty( $resources__booking_id__obj[ $aggregate_res_id ] ) ) { // Go by bookings foreach ( $resources__booking_id__obj[ $aggregate_res_id ] as $aggregate_booking_id => $aggregate_booking_obj ) { // Now need to add this $aggregate_bookings_arr into all Real resources (which can be parent and child resources ) foreach ( $new_resource_arr__bookings_arr as $merged_resource_id => $bookings_array ) { /* // $aggregate_booking_obj->form it has ID as $aggregate_res_id but we need to have NEW as $merged_resource_id $new_resource_id = $merged_resource_id; $old_resource_id = $aggregate_res_id; $aggregate_booking_obj->form = wpbc_get__form_data__with_replaced_id( $aggregate_booking_obj->form, $new_resource_id, $old_resource_id ); $aggregate_booking_obj->type = $new_resource_id; */ $new_resource_arr__bookings_arr[ $merged_resource_id ][ $aggregate_booking_id ] = wpbc_clone_array_of_objects( $aggregate_booking_obj ); } } } } return $new_resource_arr__bookings_arr; } confirmation_page.php 0000666 00000040731 15165546743 0010772 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4 // --------------------------------------------------------------------------------------------------------------------- // == Confirmation Page // --------------------------------------------------------------------------------------------------------------------- /* //Delete it. function wpbc_shortcode__booking_confirmation_debug($attr, $content, $tag) { // Normalize attribute keys, lowercase $atts = array_change_key_case( (array) $attr, CASE_LOWER ); // override default attributes with user attributes $wpbc_atts = shortcode_atts( array( 'mode' => 'calendar', 'id' => 0 ) , $atts, $tag ); $attr = wpbc_escape_shortcode_params( $wpbc_atts ); $content = preg_replace( '/\R+/', '', $content ); $content_utf = mb_convert_encoding( html_entity_decode( $content ), 'HTML-ENTITIES', 'UTF-8' ); $search = array( '‘', '’', '“', '”', '—' ); $replace = array( "'", "'", '"', '"', '-' ); $content_utf2 = str_replace($search, $replace, $content_utf); $content_utf2 = strip_tags( $content_utf2 ); $content_json = json_decode( $content_utf2 ); debuge($content_json); die; $content_str = json_encode( $content_json ); $content_str = str_replace(',', ",\n", $content_str); $return = json_encode( $attr ) . '<p><pre>' . $content_str . '</pre></p>' . $tag; $return .= '<hr/>'; return $return ; } */ /** * Load shortcode checking correctly * @return void */ function wpbc_init_shortcode__wpbc_booking_confirmation() { // Docs: https://developer.wordpress.org/plugins/shortcodes/basic-shortcodes/ // Universal shortcode 'wpbc' with 'mode' parameter: // Example #1: [wpbc mode="booking_confirm"] <- Get Hash from $_GET['booking_hash'] // Example #2: [wpbc mode="booking_confirm" booking_hash="b190e1a1fc6480c03a59444956d3ed22"] <- Always use this HASH from parameter add_shortcode( 'wpbc', 'wpbc_shortcode__booking_confirmation' ); // ShortHand add_shortcode( 'booking_confirm', 'wpbc_do_shortcode__booking_confirm' ); } add_action( 'init', 'wpbc_init_shortcode__wpbc_booking_confirmation', 9999 ); // <- priority to load it last /** * Universal shortcode worker * * @param array $attr * @param string|null $content * @param string $tag * * @return string */ function wpbc_shortcode__booking_confirmation( $attr = array(), $content = null, $tag = '' ) { // ob_start(); $atts = array_change_key_case( (array) $attr, CASE_LOWER ); // Changes the case of all keys in an array /* $wpbc_atts = shortcode_atts( array( 'mode' => 'calendar', 'id' => 1 ) , $atts ); // Override default attributes with user attributes $attr = wpbc_escape_shortcode_params( $wpbc_atts ); // My escaping */ $return = ''; switch ( $attr['mode'] ) { case 'booking_confirm': $return .= wpbc_do_shortcode__booking_confirm( $attr ); break; default: $return = '<p style="font-size:9px;">' . 'Invalid shortcode configuration: <strong>[' . $tag . ' ... ]</strong> with the following parameters: ' . json_encode( $attr ) . '. ' . sprintf( __( 'Find more in the %sFAQ%s', 'booking' ), '<a href="https://wpbookingcalendar.com/faq/">', '</a>.' ) . '</p>'; } // $possible_output = ob_get_clean(); // $return .= $possible_output; return $return ; } function wpbc_do_shortcode__booking_confirm( $attr ){ if ( wpbc_is_on_edit_page() ) { return wpbc_get_preview_for_shortcode( 'booking_confirm', array() ); //FixIn: 9.9.0.39 } ob_start(); $atts = array_change_key_case( (array) $attr, CASE_LOWER ); // Changes the case of all keys in an array $wpbc_atts = shortcode_atts( array( //'mode' => 'calendar', // ? //'id' => 1, // ? 'booking_hash' => '' // Optional!. Required only for specific situation to show always SAME booking at this page without the $_REQUEST['booking_hash'] ) , $atts ); // Override default attributes with user attributes $attr = wpbc_escape_shortcode_params( $wpbc_atts ); // My escaping $booking_resource_id__arr = wpbc_get_booking_arr__from_hash_in_url( $attr['booking_hash'] ); // <- $attr['booking_hash'] Optional and usually it == '', required only for specific situation to show always SAME booking at this page! $booking_id = intval( $booking_resource_id__arr['booking_id'] ); $resource_id = intval( $booking_resource_id__arr['resource_id'] ); if ( empty( $booking_id ) ) { return '<strong>' . __('Oops!' ,'booking') . '</strong> ' . __('We could not find your booking. The link you used may be incorrect or has expired. If you need assistance, please contact our support team.' ,'booking'); } else { // DB Booking Details $booking_data = wpbc_db_get_booking_details( $booking_id ); // {... , "form":"text^cost_hint4^\u20ac76.49~text^original_cost_hint4^...","booking_type":"4","remark":"---","cost":"7.65" ... } // DB Booking Dates $booking_dates = wpbc_db_get_booking_dates( $booking_id ); // [ {"booking_dates_id":"10236","booking_id":"4195","booking_date":"2023-11-27 18:00:01","approved":"0","type_id":null} ,...] // Parse dates $dates_ymd_arr = array_map( function ( $value ) { $sql_booking_date = $value->booking_date; $value_arr = explode( ' ', $sql_booking_date ); return $value_arr[0]; }, $booking_dates ); // ["2023-11-27","2023-11-28","2023-11-29"] // Remove duplicates $dates_ymd_arr = array_unique( $dates_ymd_arr ); // Sort Dates sort( $dates_ymd_arr ); // [ '2023-10-20', '2023-10-25' ] $params_arr = array(); $params_arr['booking_id'] = $booking_id; $params_arr['resource_id'] = $resource_id; $params_arr['form_data'] = $booking_data->form; // 'text^selected_short_dates_hint11^Sun...', $params_arr['dates_ymd_arr'] = $dates_ymd_arr; // [ '2023-10-20', '2023-10-25' ] $params_arr['times_his_arr'] = wpbc_get_times_his_arr__in_form_data( $params_arr['form_data'], $params_arr['resource_id'] ); // [ '16:00:01', '18:00:02' ] /** * Another way of get data * // 3. Get booking dates (sql) * $bookings_obj = array( $booking_data ); * $booking_dates_obj = wpbc_ajx_get__booking_dates_obj__sql( $bookings_obj ); * * // 4. Include dates into bookings (Wide and Short dates view) * $bookings_with_dates = wpbc_ajx_include_bookingdates_in_bookings( $bookings_obj, $booking_dates_obj ); * * // 5. Parse forms * $parsed_bookings = wpbc_ajx_parse_bookings( $bookings_with_dates, $resources_arr ); ?? * * wpbc_get_booking_different_params_arr( $booking_data->booking_id, $booking_data->form, $booking_resource_id__arr['resource_id'] ); * * $booking_data = wpbc_api_get_booking_by_id( $booking_id ); * * $params_arr['form_data'] = $bookings_with_dates[ $booking_id ]->booking_db->form; // 'text^selected_short_dates_hint11^Sun...', * * $params_arr['dates_ymd_arr'] = array_map( function ( $value ) { * $value_arr = explode( ' ', $value ); * return $value_arr[0]; * }, $bookings_with_dates[ $booking_id ]->dates ); // .->booking_db->dates = [ "2023-11-27 18:00:01", "2023-11-28 00:00:00", "2023-11-29 20:00:02" ] * // Remove duplicates * $params_arr['dates_ymd_arr'] = array_unique( $params_arr['dates_ymd_arr'] ); * * // Sort Dates * sort( $params_arr['dates_ymd_arr'] ); // [ '2023-10-20', '2023-10-25' ] */ // $booking_data_arr = wpbc_get_parsed_booking_data_arr( $params_arr['form_data'], $params_arr['resource_id'], array( 'get' => 'value' ) ); // Get parsed booking form: = [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ] // $time_as_seconds_arr = wpbc_get_times_his_arr__in_form_data( $params_arr['form_data'], $params_arr['resource_id'], array( 'get' => 'time_as_seconds_arr' ) ); // [ 64800, 72000 ] $payment_cost = ( class_exists( 'wpdev_bk_biz_s' ) ) ? ( (float) $booking_data->cost ) : 0; $params_arr['payment_cost'] = $payment_cost; // $bookings_with_dates[ $booking_id ]->booking_db->cost; $params_arr['total_cost'] = $payment_cost; $params_arr['deposit_cost'] = $payment_cost; $params_arr['is_deposit'] = false; // Optional. $params_arr['booking_summary'] = ''; // Optional. $params_arr['gateways_arr'] = ''; // Optional. $params_arr['is_show_coupon_discount_text'] = false; // Because we are at the 'Thank you' page, it can be request, and we do not show this coupon discount ?? // ============================================================================================================= // Get payment form(s) and Update COST of the booking // ============================================================================================================= $payment_params = array(); // Usually we have this: ( $str_dates__dd_mm_yyyy == $create_params['dates_only_sql_arr'] ) - but for ensure, use saved dates, e.g. $str_dates__dd_mm_yyyy $payment_params['booked_dates_times_arr'] = array( 'dates_ymd_arr' => $params_arr['dates_ymd_arr'], // [ '2023-10-20', '2023-10-25' ] 'times_his_arr' => $params_arr['times_his_arr'] // ['16:00:01', '18:00:02'] ); $str_dates__dd_mm_yyyy = wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $params_arr['dates_ymd_arr'] ); // ['2023-10-20','2023-10-25'] => ['20.10.2023','25.10.2023'] $payment_params['str_dates__dd_mm_yyyy'] = implode( ',', $str_dates__dd_mm_yyyy ); // REQUIRED -- '14.11.2023, 15.11.2023, 16.11.2023, 17.11.2023' $payment_params['booking_id'] = $params_arr['booking_id']; // REQUIRED -- '2' $payment_params['resource_id'] = $params_arr['resource_id']; // REQUIRED -- '2' can be child resource (changed in wpbc_where_to_save() ) // This field required only for make cost calculation based on PARENT booking resource. But here we already have the cost from DB, so no need to use parent booking resource $payment_params['initial_resource_id'] = $params_arr['resource_id']; // REQUIRED -- '2' initial calendar - parent resource $payment_params['form_data'] = $params_arr['form_data']; // we re-save it, because here can be sync_guid and custom form new data from wpbc_db__booking_save(..) // REQUIRED -- 'text^selected_short_timedates_hint4^06/11/2018 14:00...' $payment_params['times_array'] = array( explode( ':', $params_arr['times_his_arr'][0] ), explode( ':', $params_arr['times_his_arr'][1] ) ); // [ ["10","00","00"], ["12","00","00"] ] $payment_params['custom_form'] = wpbc_get__custom_booking_form_name( $params_arr['resource_id'], $params_arr['form_data'] ); // => '' '' | 'some_name' // <editor-fold defaultstate="collapsed" desc=" -- Trick for legacy code -- " > $_POST['booking_form_type'] = $payment_params['custom_form']; // Trick for legacy code for correct cost calculation, relative to "Advanced cost". Required in biz_m.php file in function advanced_cost_apply( $summ , $form , $bktype , $days_array , $is_get_description = false ) // </editor-fold> // Additional options $payment_params['is_edit_booking'] = 0; // => 0 0 | int - ID of the booking $payment_params['is_duplicate_booking'] = 0; // => 0 0 | 1 $payment_params['is_from_admin_panel'] = false; // => false true | false $payment_params['is_show_payment_form'] = 1; // => 1 0 | 1 //FixIn: 9.9.0.35 if ( ( ! empty( $_GET['is_show_payment_form'] ) ) && ( 'Off' === $_GET['is_show_payment_form'] ) ) { $payment_params['is_show_payment_form'] = 0; } $payment_params['costs_arr'] = array( 'total_cost' => $params_arr['payment_cost'], 'deposit_cost' => $params_arr['payment_cost'] ); if ( ( ! empty( $_GET['booking_pay'] ) ) && ( 1 == intval( $_GET['booking_pay'] ) ) ) { $payment_params['booking_payment_form_in_request_only'] = 1; $params_arr['booking_payment_form_in_request_only'] = 1; } // Situation, when we show payment form for "child booking resources", and need to recalculate total booking cost, based on cost of parent resource for "Cash payment" - calc_cost_hint | calc_deposit_hint | calc_original_cost_hint ... if( ( function_exists( 'wpbc_is_this_child_resource' ) ) && ( wpbc_is_this_child_resource( $payment_params['resource_id'] ) ) ){ $bk_parent_br_id = wpbc_get_parent_resource( $payment_params['resource_id'] ); $payment_params['initial_resource_id'] = $bk_parent_br_id; //$payment_params['resource_id'] = $payment_params['resource_id']; } // GET PAYMENT FORMS if ( function_exists( 'wpbc_maybe_get_payment_form' ) ) { $response__payment_form__arr = wpbc_maybe_get_payment_form( $payment_params ); if ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['gateway_rows'] ) ) ) { $params_arr['gateway_rows'] = $response__payment_form__arr['gateways_output_arr']['gateway_rows']; } if ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['booking_summary'] ) ) ) { $params_arr['booking_summary'] = $response__payment_form__arr['gateways_output_arr']['booking_summary']; } } else { $response__payment_form__arr = $payment_params; $response__payment_form__arr['status'] = 'ok'; } // ============================================================================================================= $confirmation_arr = wpbc_booking_confirmation( $params_arr ); $confirmation_arr['ty_is_redirect'] = 'message'; // We already at this page, so do not make redirect $confirmation_arr['ty_message'] = ''; // Reset "Thank you" message, because it is oin the Thank you | Payment request page now. $json_arr = array(); $json_arr['ajx_confirmation'] = $confirmation_arr; $json_arr['resource_id'] = $resource_id; $return_str = '<div class="wpbc_container ">' . '<div id="booking_form' . $resource_id . '"></div>' . '<script type="text/javascript"> ' . wpbc_jq_ready_start() //FixIn: 10.1.3.7 . ' wpbc_show_thank_you_message_after_booking(' .wp_json_encode( $json_arr ) . '); ' . ' setTimeout( function (){ wpbc_do_scroll( "#wpbc_scroll_point_' . intval( $resource_id ) . '", 10 ); }, 500 ); ' . wpbc_jq_ready_end() . '</script>' //FixIn: 10.1.3.7 . '</div>'; } $possible_output = ob_get_clean(); $return_str .= $possible_output; return $return_str; // return '<pre>' . var_export($confirmation_arr, true) . '</pre>'; } wpbc_cache.php 0000666 00000010751 15165546743 0007363 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly global $wpbc_global_cache; //FixIn: 9.7.3.14 $wpbc_global_cache = array(); // GET Saved request --------------------------------------------------------------------------------------------------- /** * GET saved cache request result, if exists otherwise return null * * @param string $function_name 'wpbc__sql__get_booking_dates' - name of function, where saved DB request * @param string|array $params [ array with parameters in this function, that saved ] * * @return array|mixed|object|null if not saved previously then returned null */ function wpbc_cache__get( $function_name, $params ){ // return null; // Stop caching hack global $wpbc_global_cache; if ( ! is_serialized( $params ) ) { $params_cache = maybe_serialize( $params ); } else { $params_cache = $params; } if ( ( isset( $wpbc_global_cache[ $function_name ] ) ) && ( isset( $wpbc_global_cache[ $function_name ][ $params_cache ] ) ) ){ //return $wpbc_global_cache[ $function_name ][ $params_cache ]; // CLONING array of objects $clone_array_of_objects = wpbc_clone_array_of_objects( $wpbc_global_cache[ $function_name ][ $params_cache ] ); return $clone_array_of_objects; } return null; } // SAVE ---------------------------------------------------------------------------------------------------------------- /** * SAVE request result to CACHE var * * @param string $function_name 'wpbc__sql__get_booking_dates' - name of function, where saved DB request * @param string|array $params [ array with parameters in this function, that saved ] * @param mixed $value_to_save value to save -- usually it's result from DB * * @return mixed return CLONED $value_to_save */ function wpbc_cache__save( $function_name, $params, $value_to_save ){ global $wpbc_global_cache; if ( ! is_serialized( $params ) ) { $params_cache = maybe_serialize( $params ); } else { $params_cache = $params; } if ( ! isset( $wpbc_global_cache[ $function_name ] ) ) { $wpbc_global_cache[ $function_name ] = array(); } //$wpbc_global_cache[ $function_name ][ $params_cache ] = $value_to_save; // CLONING array of objects $wpbc_global_cache[ $function_name ][ $params_cache ] = wpbc_clone_array_of_objects( $value_to_save ); return $wpbc_global_cache[ $function_name ][ $params_cache ]; } /** * Clone array of Objects * Return independent array instances, instead of reference to previous objects. * Useful, if we do not need to apply changes in original array * * @param array|object|mixed $object_arr * * @return array|object|mixed * * * CLONING tips... * We clone array of booking Objects, because later we make manipulations with some properties, e.g. unset() for example on this line: unset( $this_date_bookings[ $booked_times__key ]->form ); // Hide booking details and for having (not changed Cache object from DB $wpbc_global_cache['wpbc__sql__get_booking_dates'][ $params_cache ] ) During loading bookings in wpbc_get__booked_dates__per_resources__arr(...) we need to clone each such object, otherwise if we change something in this variable, it will be changed in cache $wpbc_global_cache['wpbc__sql__get_booking_dates'][ $params_cache ] ), as well Otherwise, if we will not clone and use this, then we do not need to unset some properties: $this_date_bookings = $booked_dates__per_resources__arr[ $my_day_tag ][ $resource_id ]; v.s. $this_date_bookings = array_map( function ( $object ) { return clone $object; } , $booked_dates__per_resources__arr[ $my_day_tag ][ $resource_id ] ); */ function wpbc_clone_array_of_objects( $object_arr ){ $cloned_result = false; if ( is_array( $object_arr ) ) { $cloned_result = array_map( function ( $object ) { return ( ( is_object( $object ) ) ? ( clone $object ) : $object ); } , $object_arr ); } else if ( is_object( $object_arr ) ) { $cloned_result = ( clone $object_arr ); } else { $cloned_result = $object_arr; } return $cloned_result; }
| ver. 1.4 |
Github
|
.
| PHP 5.4.45 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings