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

create_booking.php in Booking Calendar 10.11, at includes/_capacity/create_booking.php

1,436 lines 83.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly // FixIn: 9.8.0.4.
4
5 // ---------------------------------------------------------------------------------------------------------------------
6 // == Ajax Response on creation of new booking
7 // ---------------------------------------------------------------------------------------------------------------------
8
9 /**
10 * Response to Ajax request, about loading calendar data
11 *
12 * @return void
13 */
14 function ajax_WPBC_AJX_BOOKING__CREATE() {
15
16 /**
17 * Tip / translation /
18 * 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.
19 */
20
21 // Security ------------------------------------------------------------------------------------------------------ // in Ajax Post: 'nonce': _wpbc.get_secure_param( 'nonce' ),
22 $action_name = 'wpbc_calendar_load_ajx' . '_wpbcnonce';
23 $nonce_post_key = 'nonce';
24 if ( wpbc_is_use_nonce_at_front_end() ) { // FixIn: 10.1.1.2.
25 $result_check = check_ajax_referer( $action_name, $nonce_post_key );
26 }
27
28 // Response AJAX parameters
29 $ajx_data_arr = array();
30 $ajx_data_arr['status'] = 'ok';
31
32 $admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // 'wp-admin/admin.php?'
33 $server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
34 // Local parameters
35 $local_params = array();
36 $local_params['is_from_admin_panel'] = ( false !== strpos( $server_http_referer_uri, $admin_uri ) ); // true | false
37 $local_params['user_id'] = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // 1
38
39 // Request parameters
40 $user_request = new WPBC_AJX__REQUEST( array( // Using this class here only for escaping variables
41 'db_option_name' => 'booking__wpbc_booking_create__request_params', // Not necessary, because we not save request, only sanitize it
42 'user_id' => $local_params['user_id'], // Not necessary, because we not save request, only sanitize it
43 'request_rules_structure' => array(
44 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // 'digit_or_csd'
45
46 'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ),
47
48 'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), // FixIn: 9.9.1.1.
49 'formdata' => array( 'validate' => 'strong', 'default' => '' ),
50 'booking_hash' => array( 'validate' => 'strong', 'default' => '' ),
51 'custom_form' => array( 'validate' => 'strong', 'default' => '' ),
52
53 'captcha_chalange' => array( 'validate' => 'strong', 'default' => '' ),
54 'captcha_user_input' => array( 'validate' => 'strong', 'default' => '' ),
55
56 'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ),
57 'active_locale' => array( 'validate' => 'strong', 'default' => '' )
58 )
59 ));
60
61 // Escape of request params in Ajax Post. We use prefix 'calendar_request_params', if Ajax sent - $_REQUEST['calendar_request_params']['resource_id'], ...
62 $request_prefix = 'calendar_request_params';
63
64 //$_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";
65
66 $request_params = $user_request->get_sanitized__in_request__value_or_default( $request_prefix ); // NOT Direct: $_REQUEST['calendar_request_params']['resource_id']
67 $server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
68 $request_params['request_uri'] = $server_http_referer_uri; // Parameter needed for Error in booking saving and reloading calendar again with these actual parameters.
69
70 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CAPTCHA " >
71 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
72 wpbc_captcha__in_ajx__check( $request_params, $local_params['is_from_admin_panel'], $_REQUEST[ $request_prefix ] );
73 // </editor-fold>
74
75 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING_RESOURCE ID " >
76 if ( $request_params['resource_id'] <= 0 ) {
77 $ajx_data_arr['status'] = 'error';
78 $ajx_data_arr['status_error'] = 'resource_id_incorrect';
79 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
80 $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'] . ' ]';
81 $ajx_data_arr['ajx_after_action_message_status'] = 'error';
82 wp_send_json( array(
83 'ajx_data' => $ajx_data_arr,
84 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
85 'ajx_search_params' => $_REQUEST[ $request_prefix ],
86 'ajx_cleaned_params' => $request_params,
87 'resource_id' => $request_params['resource_id'],
88 ) );
89 }
90 // </editor-fold>
91
92 $server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
93 $request_save_params = array(
94 'resource_id' => $request_params['resource_id'],
95 'dates_ddmmyy_csv' => $request_params['dates_ddmmyy_csv'],
96 'form_data' => $request_params['formdata'],
97 'aggregate_resource_id_arr' => $request_params['aggregate_resource_id_arr'], // Optional can be ''
98
99 'booking_hash' => $request_params['booking_hash'],
100 'custom_form' => $request_params['custom_form'],
101
102 'is_emails_send' => $request_params['is_emails_send'],
103 'is_show_payment_form' => 1,
104 'user_id' => $local_params['user_id'],
105 'request_uri' => $server_http_referer_uri
106 );
107 $booking_save_arr = wpbc_booking_save( $request_save_params );
108
109 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING " >
110 if ( 'ok' !== $booking_save_arr['ajx_data']['status'] ) {
111
112 wp_send_json( array( 'ajx_data' => $booking_save_arr['ajx_data'],
113 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
114 'ajx_search_params' => $_REQUEST[ $request_prefix ],
115 'ajx_cleaned_params' => $request_params,
116 'resource_id' => $request_params['resource_id']
117 ));
118 }
119 // </editor-fold>
120
121 $ajx_data_arr = $booking_save_arr['ajx_data'];
122
123
124
125 // 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 !
126
127 if ( empty( $ajx_data_arr['ajx_after_action_message_status'] ) ) {
128 $ajx_data_arr['ajx_after_action_message_status'] = 'success';
129 }
130 if ( empty( $ajx_data_arr['ajx_after_action_message'] ) ) {
131 $ajx_data_arr['ajx_after_action_message'] = '';
132 }
133
134 // $ajx_data_arr['ajx_after_action_message'] .= __( 'Booking was created with ID: ' . $booking_save_arr[ 'booking_id' ] , 'booking' );
135 // $ajx_data_arr['ajx_after_action_message'] .= '<hr>Total time: <strong>' . $booking_save_arr['php_performance']['total'] . ' s. </strong>';
136 // $ajx_data_arr['ajx_after_action_message'] .= str_replace( array( ',', '{', '}' ), '<br>', wp_json_encode( $booking_save_arr['php_performance'] ) );
137 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138
139
140
141 /* if admin edit ?
142 var my_message = '<?php echo esc_js( __('Updated successfully' ,'booking') ) ; ?>';
143 wpbc_admin_show_message( my_message, 'success', 3000 );
144 location.href='<?php echo wpbc_get_bookings_url() ;?>&tab=vm_booking_listing&wh_booking_id=<?php echo $is_edit_booking['booking_id'] ; ?>';
145 */
146
147
148 // -----------------------------------------------------------------------------------------------------------------
149 // == Ajax ===
150 // -----------------------------------------------------------------------------------------------------------------
151 /**
152 * Send JSON. It will make "wp_json_encode" - so pass only array, and This function call wp_die( '', '', array( 'response' => null, ) ) .
153 * Pass JS OBJ: response_data in "jQuery.post " function on success.
154 *
155 * Other End Ajax actions:
156 * $error_obj = new WP_Error( 'WPBC_CREATE', __( 'test error.' ), 'some/data' ); wp_send_json_error( $error_obj );
157 * wp_send_json_error( array( 'message' => 'invalid-api-key' ) );
158 * wp_send_json_success( array( 'message' =>'Ok:)' ) );
159 */
160 wp_send_json( array(
161 'booking_id' => $booking_save_arr['booking_id'],
162 'resource_id' => $request_params['resource_id'],
163 'ajx_data' => $ajx_data_arr,
164 'ajx_confirmation' => $booking_save_arr['confirmation'],
165
166 // For debug purpose <- comment in live serv
167 'php_process_times' => $booking_save_arr['php_performance'],
168 'booking_arr' => $booking_save_arr ['booking_arr'],
169
170 // Not needed ?
171 // 'ajx_search_params' => $_REQUEST[ $request_prefix ],
172 // 'ajx_cleaned_params' => $request_params,
173
174 ) );
175 }
176
177 // Ajax Hooks
178 if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) {
179 add_action( 'wp_ajax_nopriv_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Client (not logged in)
180 add_action( 'wp_ajax_' . 'WPBC_AJX_BOOKING__CREATE', 'ajax_' . 'WPBC_AJX_BOOKING__CREATE' ); // Logged In users (or admin panel)
181 }
182
183
184 // ---------------------------------------------------------------------------------------------------------------------
185 // == Save Booking
186 // ---------------------------------------------------------------------------------------------------------------------
187
188 /**
189 * Save Booking - ADD NEW or UPDATE exist booking
190 *
191 * @param $request_params = [
192 * resource_id = 2 REQUIRED Default: 1
193 * dates_ddmmyy_csv = '27.10.2023, 28.10.2023, 29.10.2023' REQUIRED
194 * form_data = 'text^selected_short_dates_hint2^Fri, ...9, 2023~text^...' REQUIRED
195 * booking_hash = '' Optional Default: ''
196 * custom_form = '' Optional Default: ''
197 * is_emails_send = 1 Optional Default: 1
198 * is_show_payment_form => 1 Optional Default: 1
199 * user_id = 1 Optional Default: 0 or ID of logged-in user
200 * request_uri = 'http://beta/resource-id2/', // Optional Default: for front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER']
201 *
202 * 'sync_gid' => 'ghjgjgjgh5f5f45f' // Really Optional: can be passed only during import .ics
203 * 'is_approve_booking' => 0 // Really Optional: 0 | 1
204 * 'save_booking_even_if_unavailable' => 0 // Really Optional: 0 | 1, if 1 then force save booking even if dates unavailable.
205 * ]
206 *
207 * @return [] ok: [
208 *
209 * ]
210 * error: [
211 * 'ajx_data': [ 'status':'error', 'status_error':'booking_can_not_save', 'ajx_after_action_message': 'Can not save booking', 'ajx_after_action_message_status': 'warning' ]
212 * ]
213 *
214 * Example:
215 *
216 * wpbc_booking_save( array(
217 * 'resource_id' => 2,
218 * 'dates_ddmmyy_csv' => '04.10.2023, 05.10.2023, 06.10.2023',
219 * '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',
220 * 'booking_hash' => '',
221 * 'custom_form' => '',
222 * 'is_emails_send' => 1,
223 * 'is_show_payment_form' => 1,
224 * 'user_id' => 1,
225 * 'request_uri' => 'http://beta/resource-id2/'
226 * ) );
227 *
228 */
229 function wpbc_booking_save( $request_params ){
230 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
231 $php_performance = php_performance_START( 'total', array() );
232 // </editor-fold>
233 $ajx_data_arr = array();
234 $ajx_data_arr['status'] = 'ok';
235
236 // -----------------------------------------------------------------------------------------------------------------
237 // 1. Direct Clean Params
238 // -----------------------------------------------------------------------------------------------------------------
239 $server_request_uri = ( ( isset( $_SERVER['REQUEST_URI'] ) ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
240 $server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
241 $validate_arr_rules = array(
242 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // INT
243 'dates_ddmmyy_csv' => array( 'validate' => 'csv_dates', 'default' => '' ), // FixIn: 9.9.1.1.
244 'form_data' => array( 'validate' => 'strong', 'default' => '' ),
245 'booking_hash' => array( 'validate' => 'strong', 'default' => '' ),
246 'custom_form' => array( 'validate' => 'strong', 'default' => '' ),
247 'is_emails_send' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1
248 'is_show_payment_form' => array( 'validate' => 'd', 'default' => 1 ), // 0 | 1
249 'user_id' => array( 'validate' => 'd', 'default' => wpbc_get_current_user_id() ), // INT
250 'request_uri' => array( 'validate' => 'strong', 'default' => ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $server_http_referer_uri : $server_request_uri ), // front-end: $server_request_uri | ajax: $server_http_referer_uri
251 // Really Optional:
252 'aggregate_resource_id_arr' => array( 'validate' => 'digit_or_csd', 'default' => '' ),
253 //TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' // FixIn: 10.0.0.7.
254 'aggregate_type' => array( 'validate' => 'strong', 'default' => 'bookings_only' ), // Optional. 'all' | 'bookings_only' <- it is depends on shortcode parameter: options="{aggregate type=bookings_only}"
255 'is_approve_booking' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1
256 'save_booking_even_if_unavailable' => array( 'validate' => 'd', 'default' => 0 ), // 0 | 1
257 'sync_gid' => array( 'validate' => 'strong', 'default' => '' ),
258 'is_use_booking_recurrent_time' => array( 'validate' => 'd', 'default' => intval( ( 'On' === get_bk_option( 'booking_recurrent_time' ) ) ) )
259 );
260 $re_cleaned_params = wpbc_sanitize_params_in_arr( $request_params, $validate_arr_rules );
261
262 $admin_uri = ltrim( str_replace( get_site_url( null, '', 'admin' ), '', admin_url( 'admin.php?' ) ), '/' ); // wp-admin/admin.php?
263
264
265 // -----------------------------------------------------------------------------------------------------------------
266 // Local parameters
267 // -----------------------------------------------------------------------------------------------------------------
268 $local_params = array();
269 $local_params['is_from_admin_panel'] = ( false !== strpos( $re_cleaned_params['request_uri'], $admin_uri ) ); // true | false
270 $local_params['user_id'] = $re_cleaned_params['user_id']; // 1
271 $local_params['sync_gid'] = $re_cleaned_params['sync_gid']; // ''
272 $local_params['is_approve_booking'] = $re_cleaned_params['is_approve_booking']; // 0 | 1
273 $local_params['is_use_booking_recurrent_time'] = ( 1 === $re_cleaned_params['is_use_booking_recurrent_time'] ); // false | true
274
275 // -----------------------------------------------------------------------------------------------------------------
276 // Parse Local parameters for later use
277 // -----------------------------------------------------------------------------------------------------------------
278 /**
279 * Get parsed booking form: = [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ]
280 */
281 $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' ) );
282 $local_params['all_booking_data_arr'] = wpbc_get_parsed_booking_data_arr( $re_cleaned_params["form_data"], $re_cleaned_params["resource_id"] );
283 // Important! : [ 64800, 72000 ]
284 $local_params['time_as_seconds_arr'] = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $local_params['structured_booking_data_arr'] );
285 // [ "18:00:00", "20:00:00" ]
286 $time_as_seconds_arr = $local_params['time_as_seconds_arr'];
287 $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
288 $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
289 if ( ( 0 != $time_as_seconds_arr[0] ) && ( ( 24 * 60 * 60 ) == $time_as_seconds_arr[1] ) ) {
290 //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
291 $time_as_seconds_arr[1] += - 8;
292 }
293 $local_params['time_as_his_arr'] = array(
294 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ),
295 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] )
296 );
297 // [ '2023-09-10', '2023-09-11' ]
298 $local_params['dates_only_sql_arr'] = wpbc_convert_dates_str__dd_mm_yyyy__to__yyyy_mm_dd( $re_cleaned_params["dates_ddmmyy_csv"] );
299 $local_params['dates_only_sql_arr'] = explode( ',', $local_params['dates_only_sql_arr'] );
300
301 $local_params['is_show_payment_form'] = $re_cleaned_params["is_show_payment_form"];
302
303 // FixIn: 9.9.0.35.
304 if ( $local_params['is_show_payment_form'] ) {
305 $local_params['is_show_payment_form'] = ( false !== strpos( $re_cleaned_params['request_uri'], 'is_show_payment_form=Off' ) )
306 ? 0
307 : $local_params['is_show_payment_form']; // 1|0
308 }
309
310 // Get EDIT booking data
311 $local_params['edit_resource_id'] = '';
312 $local_params['skip_booking_id'] = '';
313 $local_params['is_edit_booking'] = 0;
314 $local_params['is_duplicate_booking'] = 0;
315 $is_edit_booking = wpbc_get_data__if_edit_booking( $re_cleaned_params['booking_hash'], $re_cleaned_params['request_uri'] );
316 if ( false !== $is_edit_booking ) {
317 $local_params['edit_resource_id'] = $is_edit_booking['resource_id']; // can be parent booking resource, where we edit the booking
318 $local_params['skip_booking_id'] = $is_edit_booking['booking_id']; // booking ID
319 $local_params['is_edit_booking'] = $is_edit_booking['booking_id']; // booking ID
320 if (
321 ( ! empty( $local_params['structured_booking_data_arr']['wpbc_other_action'] ) )
322 && ( 'duplicate_booking' === $local_params['structured_booking_data_arr']['wpbc_other_action'] )
323 ){
324 $local_params['is_duplicate_booking'] = 1;
325 }
326 }
327 // It can be request resource ID or if we edit booking, it can be 'edit resource' - (e.g. child resource)
328 $local_params['initial_resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) ? $local_params['edit_resource_id'] : $re_cleaned_params['resource_id'];
329
330 // 2
331 $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'] );
332
333
334 $local_params['aggregate_resource_id_arr'] = explode( ',', $re_cleaned_params['aggregate_resource_id_arr'] );
335 $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.
336 $local_params['aggregate_resource_id_arr'] = array_unique( $local_params['aggregate_resource_id_arr'] ); // Erase duplicates
337
338 // -----------------------------------------------------------------------------------------------------------------
339 // Here GO
340 // -----------------------------------------------------------------------------------------------------------------
341
342 // Force - resource saving parameters, instead of wpbc__where_to_save_booking()
343 if ( ! empty( $re_cleaned_params["save_booking_even_if_unavailable"] ) ) {
344
345 $local_params['how_many_items_to_book'] = 1;
346
347 $dates_keys_arr = array_values( $local_params['dates_only_sql_arr'] ); // [ '2023-09-23', '2023-09-24' ]
348
349 $resources_in_dates = array_fill_keys( $dates_keys_arr , array( $local_params['initial_resource_id'] ) ); // [ 2023-09-23 = [ 2 ], 2023-09-24 = [ 2 ] ]
350
351 $where_to_save_booking = array();
352 $where_to_save_booking['result'] = 'ok';
353 $where_to_save_booking['resources_in_dates'] = $resources_in_dates; // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ]
354 $where_to_save_booking['time_to_book'] = $local_params['time_as_his_arr']; // [ "00:00:00", "24:00:00" ]
355 $where_to_save_booking['main__resource_id'] = $local_params['initial_resource_id']; // here edit or request (parent/single) resource
356
357 } else {
358 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
359 $php_performance = php_performance_START( 'wpbc__where_to_save_booking' , $php_performance );
360 // </editor-fold>
361
362 /**
363 * Get slots [] where we can save booking = [ 'resources_in_dates' => [ 2023-10-18 = [ 2, 12, 10, 11 ]
364 * 2023-10-19 = [ 2, 12, 10, 11 ]
365 * 2023-10-20 = [ 2, 12, 10, 11 ]
366 * ],
367 * 'time_to_book' => [ "14:00:01" , "12:00:01" ],
368 * 'result' => 'ok'
369 * 'main__resource_id' => 2
370 * ]
371 * OR
372 * [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ]
373 */
374 $where_to_save_booking = wpbc__where_to_save_booking( array(
375 'resource_id' => $local_params['initial_resource_id'], // 2 //TODO: If edit booking. What to pass 'edit' or 'parent' resource ID?
376 'skip_booking_id' => $local_params['skip_booking_id'], // '', | 125 if edit booking
377 'dates_only_sql_arr' => $local_params['dates_only_sql_arr'], // [ "2023-10-18", "2023-10-25", "2023-11-25" ]
378 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], // [ 36000, 39600 ]
379 'how_many_items_to_book' => $local_params['how_many_items_to_book'], // 1
380 'request_uri' => $re_cleaned_params['request_uri'], // 'http://beta/resource-id2/'
381 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], // true | false
382 'as_single_resource' => false, // false
383 'aggregate_resource_id_arr' => $local_params['aggregate_resource_id_arr'], // Optional can be ''
384 '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.
385 'custom_form' => $re_cleaned_params['custom_form'] // FixIn: 10.0.0.10.
386 ));
387 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- NO SLOTS TO SAVE " >
388 if ( 'error' == $where_to_save_booking['result'] ) {
389 $ajx_data_arr['status'] = 'error';
390 $ajx_data_arr['status_error'] = 'booking_can_not_save';
391 $ajx_data_arr['ajx_after_action_message'] = $where_to_save_booking['message'];
392 $ajx_data_arr['ajx_after_action_message_status'] = 'warning';
393 return array( 'ajx_data' => $ajx_data_arr );
394 }
395 // </editor-fold>
396
397 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
398 $php_performance = php_performance_END( 'wpbc__where_to_save_booking' , $php_performance );
399 // </editor-fold>
400 }
401
402
403 // Get parameters, from REQUEST
404 $create_params = $local_params;
405 $create_params['resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) )
406 ? $local_params['edit_resource_id'] // If we edit, then use original resource ???
407 : $where_to_save_booking['main__resource_id']; // Here is important TIP, resource can be where is free, and not where we submit
408 /**
409 * 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']
410 * but what, if $where_to_save_booking do not contain this $local_params['edit_resource_id'] as available resource.
411 * or even we have $local_params['edit_resource_id'] = 2 and $where_to_save_booking contain resources like [ 1, 2, 3, 4 ]
412 * we make booking for 3 slots
413 * in this case, main resource will be 2
414 * 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 )
415 * "(205, '2023-10-04 00:00:00', 0, NULL)" <- main resource '2' e.g. $local_params['edit_resource_id'] = 2
416 * "(205, '2023-10-04 00:00:00', 0, 2)" ? <- child resource '2' e.g. [ .., 2, .. ] in $where_to_save_booking WHICH IS WRONG
417 */
418 $create_params['is_emails_send'] = $re_cleaned_params['is_emails_send'];
419 $create_params['custom_form'] = $re_cleaned_params['custom_form'];
420
421 make_bk_action( 'check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Activate working with specific user in WP MU
422
423 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
424 $php_performance = php_performance_START( 'wpbc_db__booking_save' , $php_performance );
425 // </editor-fold>
426
427 // -----------------------------------------------------------------------------------------------------------------
428 // == CREATE_THE 'NEW_BOOKING' ==
429 // -----------------------------------------------------------------------------------------------------------------
430 $create_booking_params = array(
431 'resource_id' => $create_params['resource_id'],
432 'custom_form' => $create_params['custom_form'],
433 'all_booking_data_arr' => $create_params['all_booking_data_arr'],
434 'dates_only_sql_arr' => $create_params['dates_only_sql_arr'],
435 'time_as_his_arr' => $create_params['time_as_his_arr'],
436 'is_from_admin_panel' => $create_params['is_from_admin_panel'],
437 'is_edit_booking' => $create_params['is_edit_booking'],
438 'is_duplicate_booking' => $create_params['is_duplicate_booking'],
439 'is_approve_booking' => $create_params['is_approve_booking'],
440 'how_many_items_to_book' => $create_params['how_many_items_to_book'],
441 'is_use_booking_recurrent_time' => $create_params['is_use_booking_recurrent_time'] // true | false
442 );
443 if ( ! empty( $create_params['sync_gid'] ) ) { $create_booking_params['sync_gid'] = $create_params['sync_gid']; }
444
445 $booking_new_arr = wpbc_db__booking_save( $create_booking_params, $where_to_save_booking );
446
447 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING CREATION " >
448 if ( 'ok' !== $booking_new_arr['status'] ) {
449 $ajx_data_arr['status'] = $booking_new_arr['status'];
450 $ajx_data_arr['status_error'] = 'booking_can_not_save';
451 $ajx_data_arr['ajx_after_action_message'] = $booking_new_arr['message'];
452 $ajx_data_arr['ajx_after_action_message_status'] = 'error';
453 return array( 'ajx_data' => $ajx_data_arr );
454 }
455 // </editor-fold>
456
457 // FixIn: 9.9.0.36.
458 if (
459 ( 0 !== $create_params['is_edit_booking'] ) // If edit booking
460 && ( 1 != $create_params['is_duplicate_booking'] ) // If not duplicate
461 ) {
462 // Log the cost info.
463 $is_add_timezone_offset = true;
464 $booking_note = wpbc_date_localized( gmdate( 'Y-m-d H:i:s' ), '[Y-m-d H:i]', $is_add_timezone_offset ) . ' ';
465 $booking_note .= __( 'The booking has been edited', 'booking' ) . '. | Edit URL: ' . esc_url_raw( $re_cleaned_params['request_uri'] ) . '';
466 make_bk_action( 'wpdev_make_update_of_remark', $booking_new_arr['booking_id'], $booking_note, true );
467 }
468 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
469 $php_performance = php_performance_END( 'wpbc_db__booking_save' , $php_performance );
470 // </editor-fold>
471
472 // -----------------------------------------------------------------------------------------------------------------
473 // Get payment form(s) and Update COST of the booking
474 // -----------------------------------------------------------------------------------------------------------------
475 $payment_params = array();
476
477 // 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
478 $payment_params['booked_dates_times_arr'] = array(
479 'dates_ymd_arr' => array_keys( $where_to_save_booking['resources_in_dates'] ), // [ 2023-10-20=>[], 2023-10-25=>[] ] -> [ "2023-10-20", "2023-10-25" ]
480 'times_his_arr' => $where_to_save_booking['time_to_book'] // ['16:00:01', '18:00:02']
481 );
482 $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']
483 $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'
484 $payment_params['booking_id'] = $booking_new_arr['booking_id']; // REQUIRED -- '2'
485 $payment_params['resource_id'] = $create_params['resource_id']; // REQUIRED -- '2' can be child resource (changed in wpbc_where_to_save() )
486 $payment_params['initial_resource_id'] = $local_params['initial_resource_id']; // REQUIRED -- '2' initial calendar - parent resource
487 $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...'
488 $payment_params['times_array'] = array(
489 explode( ':', $where_to_save_booking['time_to_book'][0] ), // ["10","00","00"]
490 explode( ':', $where_to_save_booking['time_to_book'][1] ) // ["12","00","00"]
491 );
492 // Additional options
493 $payment_params['is_edit_booking'] = $create_params['is_edit_booking']; // => 0 0 | int - ID of the booking
494 $payment_params['custom_form'] = $create_params['custom_form']; // => '' '' | 'some_name'
495 $payment_params['is_duplicate_booking'] = $create_params['is_duplicate_booking']; // => 0 0 | 1
496 $payment_params['is_from_admin_panel'] = $create_params['is_from_admin_panel']; // => false true | false
497 $payment_params['is_show_payment_form'] = $create_params['is_show_payment_form']; // => 1 0 | 1
498 if ( $payment_params['is_from_admin_panel'] ) {
499 // $payment_params['is_show_payment_form'] = 0; // FixIn: 9.9.0.21.
500 }
501 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
502 $php_performance = php_performance_START( 'wpbc_maybe_get_payment_form' , $php_performance );
503 // </editor-fold>
504
505 // GET PAYMENT FORMS ===============================================================================================
506 if ( function_exists( 'wpbc_maybe_get_payment_form' ) ) {
507
508 $response__payment_form__arr = wpbc_maybe_get_payment_form( $payment_params );
509
510 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- COSTS || PAYMENT_SYSTEMS " >
511 if (
512 ( ! empty( $response__payment_form__arr['status'] ) )
513 && ( 'ok' != $response__payment_form__arr['status'] )
514 ) {
515 $ajx_data_arr['status'] = $response__payment_form__arr['status'];
516 $ajx_data_arr['status_error'] = 'booking_can_not_save';
517 $ajx_data_arr['ajx_after_action_message'] = $response__payment_form__arr['message'];
518 $ajx_data_arr['ajx_after_action_message_status'] = 'error';
519 return array( 'ajx_data' => $ajx_data_arr );
520 }
521 // </editor-fold>
522
523 if ( ! empty( $response__payment_form__arr['costs_arr']['form_data'] ) ) {
524 $payment_params['form_data'] = $response__payment_form__arr['costs_arr']['form_data']; // we re-save it, because here can be [cost_correction] shortcode data
525 }
526 //TODO: Do we really need this in output $ajx_data_arr ???, because it stored in $confirmation
527 if ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) {
528 $ajx_data_arr['gateways_output_arr'] = $response__payment_form__arr['gateways_output_arr'];
529 }
530 if ( function_exists( 'wpbc_if_zero_cost__approve_booking_dates' ) ) {
531 wpbc_if_zero_cost__approve_booking_dates( $payment_params['booking_id'] );
532 }
533
534 } else {
535 $response__payment_form__arr = $payment_params;
536 $response__payment_form__arr['status'] = 'ok';
537 }
538
539
540 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
541 $php_performance = php_performance_END( 'wpbc_maybe_get_payment_form' , $php_performance );
542
543 $php_performance = php_performance_START( 'emails_sending' , $php_performance );
544 // </editor-fold>
545
546 // -----------------------------------------------------------------------------------------------------------------
547 // == Emails ===
548 // -----------------------------------------------------------------------------------------------------------------
549 if ( 1 == $re_cleaned_params['is_emails_send'] ) {
550
551 $email_content = $payment_params['form_data'];
552
553 // If we output any text, then probably it's errors or warnings, we need to catch them
554 ob_start();
555 ob_clean();
556
557 if (
558 ( 0 === $local_params['is_edit_booking'] )
559 || ( 1 === $local_params['is_duplicate_booking'] ) // FixIn: 10.0.0.42.
560 ){
561
562 // New booking to Admin
563 wpbc_send_email_new_admin( $payment_params['booking_id'], $payment_params['resource_id'], $email_content );
564
565 // New pending to Visitor
566 wpbc_send_email_new_visitor( $payment_params['booking_id'], $payment_params['resource_id'], $email_content ) ;
567
568 $is_booking_approved = wpbc_is_booking_approved( $payment_params['booking_id'] );
569 if ( $is_booking_approved ) {
570 // New approved to Visitor / Admin
571 wpbc_send_email_approved( $payment_params['booking_id'], 1 );
572 }
573
574 do_action( 'wpbc_booking_is_approved_during_creation' , $payment_params['booking_id'] , (int) $is_booking_approved ); // FixIn: 10.10.1.1.
575
576 // Payment request from admin panel, if needed
577 if(
578 ( $payment_params['is_from_admin_panel'] )
579 && ( 'On' == get_bk_option( 'booking_payment_request_auto_send_in_bap' ) )
580 && ( function_exists( 'wpbc_send_email_payment_request' ) )
581 ){
582 $payment_reason = '';
583 $is_send = wpbc_send_email_payment_request( $payment_params['booking_id'], $payment_params['resource_id'], $email_content , $payment_reason );
584 }
585
586
587
588 } else {
589
590 // Edited booking to Visitor / Admin
591 if ( function_exists( 'wpbc_send_email_modified' ) ) {
592 wpbc_send_email_modified( $payment_params['booking_id'], $payment_params['resource_id'], $email_content );
593 }
594 }
595
596 $errors_on_email_sending_html = ob_get_contents();
597 ob_end_clean();
598
599 if ( ! empty( $errors_on_email_sending_html ) ) {
600 // Show these messages as warning after creation of the booking
601 $errors_on_email_sending_html = wp_strip_all_tags( $errors_on_email_sending_html );
602 $errors_on_email_sending_html = esc_attr( $errors_on_email_sending_html );
603 $errors_on_email_sending_html = str_replace( "\\n", '', $errors_on_email_sending_html );
604
605 $ajx_data_arr['ajx_after_action_message_status'] = 'warning';
606 $ajx_data_arr['ajx_after_action_message'] = $errors_on_email_sending_html;
607 }
608 }
609
610 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
611 $php_performance = php_performance_END( 'emails_sending' , $php_performance );
612 // </editor-fold>
613
614 // -----------------------------------------------------------------------------------------------------------------
615 // == Track booking - New | Edit ===
616 // -----------------------------------------------------------------------------------------------------------------
617 /**
618 * Useful hook for Google Ads Conversion tracking. How to use this hook?
619 *
620 * Add code similar to this in your functions.php file in your theme, or in some other php file:
621 *
622 // Track adding new booking
623 //
624 // @param $params = array (
625 // 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023',
626 // 'booking_id' => 254,
627 // 'resource_id' => 11, // child or parent or single
628 // 'initial_resource_id' => 2, // parent or single
629 // 'form_data' => 'text^selected_short_dates_hint11^Sun...',
630 // 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ),
631 // 'is_edit_booking' => 0,
632 // 'custom_form' => '',
633 // 'is_duplicate_booking' => 0,
634 // 'is_from_admin_panel' => false,
635 // 'is_show_payment_form' => 1
636 // )
637 function my_booking_tracking( $params ){
638 // Your code here
639 ?><!-- Google Code for Booking Conversion Page -->
640 <script type="text/javascript">
641 // Insert bellow your Google Conversion Code
642 </script><?php
643 }
644 add_action( 'wpbc_track_new_booking', 'my_booking_tracking' );
645 *
646 *
647 *
648 * Useful hook booking edit tracking
649 *
650 * Add code similar to this in your functions.php file in your theme, or in some other php file:
651 *
652 // Track edit existing booking
653 //
654 // @param $params = array (
655 // 'str_dates__dd_mm_yyyy' => '08.10.2023,09.10.2023,10.10.2023,11.10.2023',
656 // 'booking_id' => 254,
657 // 'resource_id' => 11, // child or parent or single
658 // 'initial_resource_id' => 2, // parent or single
659 // 'form_data' => 'text^selected_short_dates_hint11^Sun...',
660 // 'times_array' => array ( array ( '14', '00', '01' ), array( '12', '00', '02' ) ),
661 // 'is_edit_booking' => 1,
662 // 'custom_form' => '',
663 // 'is_duplicate_booking' => 0,
664 // 'is_from_admin_panel' => false,
665 // 'is_show_payment_form' => 1
666 // )
667 function my_edit_booking_tracking( $params ){
668 // Your code here
669 ?><!-- Google Code for Booking Conversion Page -->
670 <script type="text/javascript">
671 // Insert bellow your Google Conversion Code
672 </script><?php
673
674 }
675 add_action( 'wpbc_track_edit_booking', 'my_edit_booking_tracking' );
676 */
677 if ( 0 === $local_params['is_edit_booking'] ) {
678 do_action( 'wpbc_track_new_booking', $payment_params );
679 } else {
680 do_action( 'wpbc_track_edit_booking', $payment_params );
681 }
682
683
684 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
685 $php_performance = php_performance_START( 'confirmation' , $php_performance );
686 // </editor-fold>
687
688 // <editor-fold defaultstate="collapsed" desc=" == Confirmation data == " >
689
690
691 $confirmation_params_arr = array(
692 'is_from_admin_panel' => $payment_params['is_from_admin_panel'],
693
694 'booking_id' => $booking_new_arr['booking_id'], // 16102023
695 'resource_id' => $payment_params['resource_id'], // 1
696 'form_data' => $payment_params['form_data'], // 'text^selected_short_dates_hint11^Sun...',
697 'dates_ymd_arr' => $payment_params['booked_dates_times_arr']['dates_ymd_arr'], // [ '2023-10-20', '2023-10-25' ]
698 'times_his_arr' => $payment_params['booked_dates_times_arr']['times_his_arr'], // [ '16:00:01', '18:00:02' ]
699
700 'total_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['total_cost'] ) )
701 ? $response__payment_form__arr['costs_arr']['total_cost']
702 : 0,
703 'deposit_cost' => ( isset( $response__payment_form__arr['costs_arr'] ) && isset( $response__payment_form__arr['costs_arr']['deposit_cost'] ) )
704 ? $response__payment_form__arr['costs_arr']['deposit_cost']
705 : 0,
706 'booking_summary' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['booking_summary'] ) ) )
707 ? $response__payment_form__arr['gateways_output_arr']['booking_summary']
708 : '',
709 'gateway_rows' => ( ( ! empty( $response__payment_form__arr['gateways_output_arr'] ) ) && ( ! empty( $response__payment_form__arr['gateways_output_arr']['gateway_rows'] ) ) )
710 ? $response__payment_form__arr['gateways_output_arr']['gateway_rows']
711 : ''
712 );
713 // It will not show payment form in Booking > Add booking page and if defined, do not make redirect
714 if ( $payment_params['is_from_admin_panel'] ) {
715
716 $confirmation_params_arr['ty_is_redirect'] = 'message'; // Do not make redirect, if it's in admin panel!
717
718 // But if we edit / duplicate the booking, then do redirection to Booking Listing page // FixIn: 9.9.0.3.
719 if (
720 ( 0 !== $local_params['is_edit_booking'] )
721 // && ( empty( $local_params['is_duplicate_booking'] ) )
722 ){
723 $confirmation_params_arr['ty_is_redirect'] = 'page';
724 $confirmation_params_arr['ty_url'] = wpbc_get_bookings_url() . '&tab=vm_booking_listing&wh_booking_id=' . $confirmation_params_arr['booking_id'];
725 }
726 }
727 $confirmation = wpbc_booking_confirmation( $confirmation_params_arr );
728
729 // </editor-fold>
730
731 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
732 $php_performance = php_performance_END( 'confirmation' , $php_performance );
733 // </editor-fold>
734
735
736 make_bk_action( 'finish_check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Deactivate working with specific user in WP MU
737
738
739 // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " >
740 $php_performance = php_performance_END( 'total' , $php_performance );
741 $php_performance['other_code'] = - 1 * array_reduce( $php_performance,
742 function ( $sum, $item ) {
743 $sum += $item;
744 return $sum;
745 }
746 , - 2 * $php_performance['total'] ); // PERFORMANCE OTHER - after TOTAL
747 // </editor-fold>
748
749
750 return array( 'ajx_data' => $ajx_data_arr, // [ 'status' => "ok", 'wpbc_payment_output' => "<p>Dear John<br..." ]
751 'booking_id' => $booking_new_arr['booking_id'], // 254
752 'booking_arr' => $payment_params,
753 'php_performance' => $php_performance, // [ ... ]
754 'confirmation' => $confirmation // [ ]
755 );
756 }
757
758
759 // ---------------------------------------------------------------------------------------------------------------------
760 // New booking creation sub functions
761 // ---------------------------------------------------------------------------------------------------------------------
762
763 /**
764 * Save booking in DB
765 *
766 * @param array $create_params = [
767 * 'resource_id' => 10,
768 * 'dates_only_sql_arr' => [ '2023-10-04', '2023-10-05', '2023-10-06'],
769 * 'time_as_his_arr' => [ '14:00:01', '16:00:02' ],
770 * 'is_from_admin_panel' => false,
771 * 'is_edit_booking' => 0,
772 * 'is_duplicate_booking' => 0,
773 * 'is_approve_booking' => 0,
774 * 'how_many_items_to_book' => 2,
775 * 'custom_form' => '',
776 * 'is_use_booking_recurrent_time' => false,
777 * 'all_booking_data_arr' => [ 'rangetime' => [
778 * 'type' => 'selectbox-multiple',
779 * 'original_name' => 'rangetime2[]', //NOTE: here RESOURCE ID (2) can be from Parent resource, but resource_id can rely on child (10) resource
780 * 'name' => 'rangetime',
781 * 'value' => '14:00 - 16:00',
782 * ],
783 * 'name' => [ 'type' => 'text', 'original_name' => 'name2', ... ],
784 * ...
785 * ]
786 * ]
787 *
788 * @param $where_to_save_booking = [
789 * 'result' = 'ok',
790 * 'main__resource_id' = 2
791 * 'resources_in_dates' = [ 2023-10-18 = [ 2, 12, 10, 11 ]
792 * 2023-10-19 = [ 2, 12, 10, 11 ]
793 * 2023-10-20 = [ 2, 12, 10, 11 ]
794 * ],
795 * 'time_to_book' = [ "14:00:01" , "16:00:02" ]
796 * ]
797 *
798 * @return [
799 * 'status' => 'ok' 'ok' | 'error' | 'warning'
800 * 'booking_id' => 100 int
801 * 'message' => '' 'If error, then here can be description of error'
802 * '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,
803 * ]
804 */
805 function wpbc_db__booking_save( $create_params, $where_to_save_booking ) {
806
807 /**
808 * Tip: $create_params['all_booking_data_arr'] - contain: [ 'field_name' => [ 'type' = "checkbox", 'original_name' = "fixed_fee2[]", 'name' = "fixed_fee", 'value' = "true" ] , ... ]
809 * $create_params['structured_booking_data_arr'] - contain: [ 'field_name' => 'field_value' , ... ]
810 */
811
812 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- 'Wrong resource ID " >
813 if ( empty( $create_params['resource_id'] ) ) {
814 return array( 'status' => 'error', 'message' => 'Wrong ID of booking resource: ' . $create_params['resource_id'] );
815 }
816 // </editor-fold>
817
818
819 $defaults = array(
820 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
821 );
822 $create_params = wp_parse_args( $create_params, $defaults );
823
824
825 $sql_field_arr = array();
826
827
828
829 // Is it was used custom booking form ?
830 if ( ! empty( $create_params['custom_form'] ) ) {
831 $create_params['all_booking_data_arr']['wpbc_custom_booking_form'] = array(
832 'type' => 'text',
833 'original_name' => 'wpbc_custom_booking_form' . $create_params['resource_id'],
834 'name' => 'wpbc_custom_booking_form',
835 'value' => $create_params['custom_form']
836 );
837 }
838
839 if ( ! empty( $create_params['sync_gid'] ) ) {
840 /**
841 * Such fields are comming from '../wp-content/plugins/booking/core/sync/wpbc-gcal-class.php' in function run()
842 */
843
844 // Escape any XSS injection from values in booking form
845 list( $create_params['sync_gid'] ) = wpbc_escape_any_xss_in_arr( array( $create_params['sync_gid'] ) );
846
847 $sql_field_arr[] = array( 'name' => 'sync_gid', 'type' => '%s', 'value' => $create_params['sync_gid'] );
848 }
849
850 // Escape any XSS injection from values in booking form
851 $create_params['all_booking_data_arr'] = wpbc_escape_any_xss_in_arr( $create_params['all_booking_data_arr'] );
852
853
854 //Set LAST check out day as AVAILABLE - remove it
855 if (
856 ( 'On' === get_bk_option( 'booking_last_checkout_day_available' ) )
857 && ( ! empty( $create_params['dates_only_sql_arr'] ) )
858 && ( count( $create_params['dates_only_sql_arr'] ) > 1 )
859 ) {
860 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.
861 // Delete last item // FixIn: 9.9.0.19.
862 $resources_in_dates_last_key = key( array_slice( $where_to_save_booking['resources_in_dates'], - 1, 1, true ) );
863 unset( $where_to_save_booking['resources_in_dates'][ $resources_in_dates_last_key ] );
864 }
865
866 // :: ERROR ::
867 if ( empty( $create_params['dates_only_sql_arr'] ) ) { // No dates :?
868 return array( 'status' => 'error', 'message' => 'Sent request with no dates.' );
869 }
870
871 // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- CHECK_IN_DATE_OLDER_THAN_CHECK_OUT " >
872 if ( count( $create_params['dates_only_sql_arr'] ) == 1 ) { // Is it single selected date ?
873
874 // Is 'check in' date/time older than 'check out' date/time when SINGLE day for booking? Then show error.
875
876 /**
877 * If we are having "change over" days activated and selected only 1 day in calendar,
878 * then we can have error: "Warning! Number of check in != check out times.", because "check in" day older than "check out" date.
879 */
880
881 $is_apply__check_in_out__10s = false;
882 $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 );
883 $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 );
884
885
886 if ( $datestamp_check_in > $datestamp_check_out ) {
887 $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.'
888 , '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_in, $is_apply__check_in_out__10s ) . '</strong>'
889 , '<strong>' . wpbc_convert__seconds__to_sql_date( $datestamp_check_out, $is_apply__check_in_out__10s ) . '</strong>'
890 );
891 $error_message .= '<br>' . '<strong>Settings that can be reason of the issue:</strong> ';
892 if( 'On' === get_bk_option( 'booking_last_checkout_day_available' )){
893 $error_message .= '<br>' . 'You have enabled <strong>"Set check out date as available"</strong> option at Booking > Settings General page in "Calendar" section. ';
894 }
895 if ( 'On' === get_bk_option( 'booking_range_selection_time_is_active' ) ){
896 $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' );
897 }
898 if ( $create_params['is_use_booking_recurrent_time'] ) {
899 $error_message .= '<br>' . 'You have enabled <strong>"Use time selections as recurrent time slots"</strong> option at Booking > Settings General page in "Calendar" section. ';
900 }
901 return array( 'status' => 'error', 'message' => $error_message );
902 }
903 }
904 // </editor-fold>
905
906 // Compose form data for DB. Can be different resource: 'selectbox-multiple^rangetime10[]^14..' <-> 'selectbox-multiple^rangetime2[]^14..' -> 'rangetime10' - child res. Previously 'rangetime2' - parent
907 $form_data = wpbc_encode_booking_data_to_string( $create_params['all_booking_data_arr'], $create_params['resource_id'] );
908
909
910 // -----------------------------------------------------------------------------------------------------------------
911 // APPROVED / PENDING
912 // -----------------------------------------------------------------------------------------------------------------
913 // Is approve booking
914 $auto_approve_new_bookings_is_active = trim( get_bk_option( 'booking_auto_approve_new_bookings_is_active' ) );
915 $is_approved_dates = ( $auto_approve_new_bookings_is_active == 'On' ) ? 1 : intval( $create_params['is_approve_booking'] );
916
917 // Auto approve only for specific booking resources
918 /**
919 * How to use "Auto approve bookings only for specific booking resources" ?
920 * Add code similar to this in your functions.php file in your theme, or in some other php file:
921 *
922 function my_wpbc_get_booking_resources_arr_to_auto_approve( $resources_to_approve ) {
923 $resources_to_approve = array( 9, 12, 33 ); // Array of booking resources ID, which you need to auto approve
924 return $resources_to_approve;
925 }
926 add_filter( 'wpbc_get_booking_resources_arr_to_auto_approve', 'my_wpbc_get_booking_resources_arr_to_auto_approve' );
927 */
928 $booking_resources_to_approve = array();
929 $booking_resources_to_approve = apply_filters( 'wpbc_get_booking_resources_arr_to_auto_approve', $booking_resources_to_approve ); // FixIn: 8.5.2.27.
930 if ( in_array( $create_params['resource_id'], $booking_resources_to_approve ) ) {
931 $is_approved_dates = 1;
932 }
933
934 if (
935 ( $create_params['is_from_admin_panel'] ) // true | false
936 && ( get_bk_option( 'booking_auto_approve_bookings_if_added_in_admin_panel' ) == 'On' )
937 ){ // FixIn: 8.1.3.27.
938 $is_approved_dates = 1;
939 }
940
941 // If the booking auto-approved, then we need to mark it as "Read".
942 if ( $is_approved_dates ) {
943 $sql_field_arr[] = array(
944 'name' => 'is_new',
945 'type' => '%d',
946 'value' => 0,
947 );
948 }
949
950 // <editor-fold defaultstate="collapsed" desc=" == Save Booking == " >
951 // -----------------------------------------------------------------------------------------------------------------
952 // Save Booking
953 // -----------------------------------------------------------------------------------------------------------------
954 global $wpdb;
955
956 $sql_field_arr[] = array( 'name' => 'form', 'type' => '%s', 'value' => $form_data );
957 $sql_field_arr[] = array( 'name' => 'booking_type', 'type' => '%d', 'value' => $create_params['resource_id'] );
958 $sql_field_arr[] = array( 'name' => 'modification_date', 'type' => '%s', 'value' => gmdate( 'Y-m-d H:i:s' ) );
959 $sql_field_arr[] = array( 'name' => 'sort_date', 'type' => '%s', 'value' => $create_params['dates_only_sql_arr'][0] . ' ' . $create_params['time_as_his_arr'][0] );
960 $sql_field_arr[] = array( 'name' => 'hash', 'type' => 'MD5(%s)', 'value' => time() . '_' . wp_rand( 1000, 1000000 ) );
961
962
963 if (
964 ( 0 == $create_params['is_edit_booking'] ) || // If not edit, then INSERT.
965 ( 1 == $create_params['is_duplicate_booking'] ) // If duplicate, then INSERT.
966 ) {
967 // Saved only for new booking creation.
968 $sql_field_arr[] = array(
969 'name' => 'creation_date',
970 'type' => '%s',
971 'value' => gmdate( 'Y-m-d H:i:s' ),
972 );
973
974 $sql_prepare_arr = array();
975 $sql_prepare_arr['name'] = array_map( function ( $value ) { return $value['name']; }, $sql_field_arr );
976 $sql_prepare_arr['type'] = array_map( function ( $value ) { return $value['type']; }, $sql_field_arr );
977 $sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr );
978
979 $sql_prepare_arr['name'] = implode( ', ', $sql_prepare_arr['name'] );
980 $sql_prepare_arr['type'] = implode( ', ', $sql_prepare_arr['type'] );
981 /* phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
982 $sql = $wpdb->prepare( "INSERT INTO {$wpdb->prefix}booking " . " ( {$sql_prepare_arr['name']} )" . " VALUES ( {$sql_prepare_arr['type']} )", $sql_prepare_arr['value'] );
983 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
984 if ( false === $wpdb->query( $sql ) ) {
985 return array( 'status' => 'error', 'message' => 'Error. INSERT New Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql );
986 }
987 // Get ID of booking
988 $booking_id = (int) $wpdb->insert_id;
989
990 } else { // Edit - UPDATE
991
992 $booking_id = (int) $create_params['is_edit_booking'];
993
994 $sql_prepare_arr = array();
995 $sql_prepare_arr['set'] = array_map( function ( $value ) { return $value['name'] . '=' . $value['type']; }, $sql_field_arr );
996 $sql_prepare_arr['value'] = array_map( function ( $value ) { return $value['value']; }, $sql_field_arr );
997
998 $sql_prepare_arr['set'] = implode( ', ', $sql_prepare_arr['set'] );
999
1000 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
1001 $sql = $wpdb->prepare( "UPDATE {$wpdb->prefix}booking SET {$sql_prepare_arr['set']} WHERE booking_id={$booking_id};", $sql_prepare_arr['value'] );
1002 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1003 if ( false === $wpdb->query( $sql ) ) {
1004 return array( 'status' => 'error',
1005 'message' => 'Error. UPDATE Exist Data in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $sql,
1006 );
1007 }
1008
1009 // Check if dates previously was approved.
1010 $slct_sql = "SELECT approved FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id}) LIMIT 0,1";
1011 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1012 $slct_sql_results = $wpdb->get_results( $slct_sql );
1013 $is_approved_dates = ( count( $slct_sql_results ) > 0 ) ? $slct_sql_results[0]->approved : $is_approved_dates;
1014
1015
1016 $delete_sql = "DELETE FROM {$wpdb->prefix}bookingdates WHERE booking_id IN ({$booking_id})";
1017 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1018 if ( false === $wpdb->query( $delete_sql ) ) {
1019 return array( 'status' => 'error', 'message' => 'Error. DELETE Old Dates in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $delete_sql );
1020 }
1021 }
1022 // </editor-fold>
1023
1024
1025 // <editor-fold defaultstate="collapsed" desc=" == Compose D A T E S for DB == " >
1026 // -----------------------------------------------------------------------------------------------------------------
1027 // Compose D A T E S for DB
1028 // -----------------------------------------------------------------------------------------------------------------
1029
1030 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1031 $field_names_arr = array( 'booking_id', 'booking_date', 'approved', 'type_id' );
1032 } else {
1033 $field_names_arr = array( 'booking_id', 'booking_date', 'approved' );
1034 }
1035 $field_names = implode( ', ', $field_names_arr );
1036
1037 $dates_sql = "INSERT INTO {$wpdb->prefix}bookingdates ( {$field_names} ) VALUES ";
1038 $insert_dates_arr = array();
1039
1040 $how_many_items_to_book = $create_params['how_many_items_to_book'];
1041 // $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
1042 for( $i = 0; $i < $how_many_items_to_book; $i++) {
1043
1044 $date_number = 0;
1045 foreach ( $where_to_save_booking['resources_in_dates'] as $only_date_sql => $resources_in_date_arr ) {
1046
1047 $date_resource_id = $resources_in_date_arr[ $i ];
1048
1049 // $create_params['resource_id'] <- Main resource (saved in wp_booking )
1050 // $only_date_sql <- '2023-09-12'
1051 // $date_resource_id <- Child resource (need to save in wp_bookingdates) OR if ( $create_params['resource_id'] == $date_resource_id ) then NULL
1052
1053 // ---------------------------------------------------------------------------------------------------------
1054 // Is full day booking:
1055 if (
1056 ( '00:00' === substr( $where_to_save_booking['time_to_book'][0], 0, 5 ) )
1057 && (
1058 ( '24:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) )
1059 || ( '00:00' === substr( $where_to_save_booking['time_to_book'][1], 0, 5 ) )
1060 )
1061 ){
1062 // Full days *******************************************************************************************
1063 $full_date_sql = $only_date_sql . ' 00:00:00';
1064
1065 $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] );
1066
1067 } else { // Times
1068
1069 if (
1070 ( $create_params['is_use_booking_recurrent_time'] ) // Activated option to book times as 'time-slots' OR
1071 || ( 1 === count( $where_to_save_booking['resources_in_dates'] ) ) // Selected only 1 date, so use time as time-slot
1072 ) {
1073 // Time slots in each day **************************************************************************
1074
1075 // Start Time
1076 $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0];
1077 $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] );
1078
1079 // End Time
1080 $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1];
1081 $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] );
1082
1083 } else {
1084 // Check in/out ************************************************************************************
1085
1086 if ( 0 == $date_number ) { // Is check in ?
1087
1088 $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][0];
1089
1090 } else if ( ( count( $where_to_save_booking['resources_in_dates'] ) - 1 ) == $date_number ) { // Is check out ?
1091
1092 $full_date_sql = $only_date_sql . ' ' . $where_to_save_booking['time_to_book'][1];
1093
1094 } else { // Middle date - Full Date
1095 $full_date_sql = $only_date_sql . ' 00:00:00';
1096 }
1097
1098 $insert_dates_arr[] = wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $create_params['resource_id'] );
1099
1100 }
1101 }
1102 // ---------------------------------------------------------------------------------------------------------
1103 $date_number++;
1104 }
1105 }
1106
1107 $dates_sql .= implode( ', ', $insert_dates_arr );
1108 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1109 if ( false === $wpdb->query( $dates_sql ) ) {
1110 return array( 'status' => 'error', 'message' => 'Error. INSERT "D A T E S" in DB.' . ' FILE:' . __FILE__ . ' LINE:' . __LINE__ . ' SQL:' . $dates_sql );
1111 }
1112
1113 // -----------------------------------------------------------------------------------------------------------------
1114 // End D A T E S
1115 // -----------------------------------------------------------------------------------------------------------------
1116 // </editor-fold>
1117
1118
1119 return array(
1120 'status' => 'ok'
1121 , 'booking_id' => $booking_id
1122 , 'form_data' => $form_data
1123 , 'message' => ''
1124 );
1125 }
1126
1127
1128 /**
1129 * Get SQL ROWs of VALUES for INSERT to DB
1130 *
1131 * @param int $booking_id 101 ID of the booking
1132 * @param string $full_date_sql '2023-09-12 10:00:01' SQL date
1133 * @param int $is_approved_dates 1 1 - approved, 0 - pending
1134 * @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
1135 * @param int $main_resource_id ( >= biz_l ): 1 ID of main (parent booking resource)
1136 *
1137 * @return string - SQL for dates VALUES to insert
1138 */
1139 function wpbc_prepare_date_row( $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id, $main_resource_id ) {
1140
1141 global $wpdb;
1142
1143 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1144 $insert_dates_arr = ( $main_resource_id != $date_resource_id )
1145 ? $wpdb->prepare( "(%d, %s, %d, %d)", $booking_id, $full_date_sql, $is_approved_dates, $date_resource_id )
1146 : $wpdb->prepare( "(%d, %s, %d, NULL)", $booking_id, $full_date_sql, $is_approved_dates );
1147 } else {
1148 $insert_dates_arr = $wpdb->prepare( "(%d, %s, %d)", $booking_id, $full_date_sql, $is_approved_dates );
1149 }
1150
1151 return $insert_dates_arr;
1152 }
1153
1154
1155 // ---------------------------------------------------------------------------------------------------------------------
1156 // Support
1157 // ---------------------------------------------------------------------------------------------------------------------
1158
1159 /**
1160 * Get booking_id and resource_id if we are editing the booking, by booking hash
1161 *
1162 * @param $booking_hash
1163 * @param $server_request_url
1164 *
1165 * @return array | false false if not edit Otherwise [ 'booking_id': 100, 'resource_id': 3 ]
1166 */
1167 function wpbc_get_data__if_edit_booking( $booking_hash, $server_request_url ) {
1168
1169 $is_edit_booking = false;
1170 if ( ! empty( $booking_hash ) ) {
1171
1172 $my_booking_id_type = wpbc_hash__get_booking_id__resource_id( $booking_hash );
1173 if ( $my_booking_id_type !== false ) {
1174
1175 $is_edit_booking = array();
1176 $is_edit_booking['booking_id'] = intval( $my_booking_id_type[0] );
1177 $is_edit_booking['resource_id'] = intval( $my_booking_id_type[1] );
1178
1179 //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.
1180 // FixIn: 10.10.1.2
1181 //if ( strpos( $server_request_url, 'resource_no_update' ) === false ) { // FixIn: 9.4.2.3.
1182
1183 if ( ( function_exists( 'wpbc_is_this_child_resource' ) ) && ( wpbc_is_this_child_resource( $is_edit_booking['resource_id'] ) ) ) {
1184 $bk_parent_br_id = wpbc_get_parent_resource( $is_edit_booking['resource_id'] );
1185
1186 $is_edit_booking['resource_id'] = intval( $bk_parent_br_id );
1187 }
1188 //}
1189 }
1190 }
1191 return $is_edit_booking;
1192 }
1193
1194
1195 /**
1196 * Get how many items to book. Usually it's from [selectbox visitors "1" ... ] field.
1197 *
1198 * @param booking_form_data__arr = [
1199 * selected_short_dates_hint = "September 27, 2023 - September 28, 2023"
1200 * days_number_hint = "2"
1201 * rangetime = "16:00 - 18:00"
1202 * starttime = "21:00"
1203 * durationtime = "00:30"
1204 * name = "John"
1205 * secondname = "Smith"
1206 * email = "john.smith@server.com"
1207 * visitors = "1"
1208 * children = "0"
1209 * details = ""
1210 * ]
1211 *
1212 * @return int
1213 */
1214 function wpbc_get__how_many_items_to_book__in_booking_form( $booking_form_data__arr, $resource_id ){
1215
1216 $how_many_items_to_book = 1;
1217
1218 //TODO: Check about some URL parameter: '&resource_no_update' to book parent resource as single resource! // FixIn: 10.10.1.2
1219 if (
1220 ( class_exists( 'wpdev_bk_biz_l' ) )
1221 && ( 0 !== wpbc_get_child_resources_number( $resource_id ) ) // Here several child booking resources
1222 ) {
1223 $booking_capacity_field = wpbc_get__booking_capacity_field__name();
1224 if (
1225 ( ! empty( $booking_capacity_field ) )
1226 && ( isset( $booking_form_data__arr[ $booking_capacity_field ] ) )
1227 ){
1228 $how_many_items_to_book = intval( $booking_form_data__arr[ $booking_capacity_field ] ); // Get value of how many booking resources to book
1229 $how_many_items_to_book = ( $how_many_items_to_book > 0 ) ? $how_many_items_to_book : 1;
1230 }
1231 }
1232
1233 return $how_many_items_to_book;
1234 }
1235
1236
1237 /**
1238 * Get capacity field -- 'pure name'
1239 *
1240 * @return string - field name, or empty string - '' if not defined
1241 *
1242 * 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'
1243 * or for standard form: 'select^visitors'
1244 * and here we get only field name: 'visitors'
1245 */
1246 function wpbc_get__booking_capacity_field__name() {
1247
1248 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1249
1250 if ( 'On' == get_bk_option( 'booking_quantity_control' ) ) {
1251
1252 $booking_capacity_field = get_bk_option( 'booking_capacity_field' );
1253
1254 if ( ! empty( $booking_capacity_field ) ) {
1255
1256 $booking_capacity_field = explode( '^', $booking_capacity_field );
1257
1258 if ( ! empty( $booking_capacity_field ) ) {
1259
1260 $booking_capacity_field_name = $booking_capacity_field[ count( $booking_capacity_field ) - 1 ];
1261
1262 return $booking_capacity_field_name;
1263 }
1264 }
1265 }
1266 }
1267 return '';
1268 }
1269
1270
1271 /**
1272 * 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.
1273 * @param $booking_form_data__arr
1274 *
1275 * @return array [ 0, 24 * 60 * 60 ] OR [ 10*60*60, 14*60*60 ] <- start and end time in seconds
1276 *
1277 * Example:
1278 *
1279 * // Firstly, we need to Get parsed booking form: [ name = "John", secondname = "Smith", email = "john.smith@server.com", visitors = "2",... ]
1280 * $structured_booking_data_arr = wpbc_get_parsed_booking_data_arr( $params["form_data"], $params["resource_id"], array( 'get' => 'value' ) );
1281 *
1282 * // Now get start/end times as seconds: [ 64800, 72000 ]
1283 * $time_as_seconds_arr = wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $structured_booking_data_arr );
1284 */
1285 function wpbc_get_in_booking_form__time_to_book_as_seconds_arr( $booking_form_data__arr ){
1286
1287 $selected_time_fields = wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr );
1288
1289 // 2.2 Get selected SECONDS to book ---------------------------------------------------------------------------
1290 $time_as_seconds_arr = array( 0, 24 * 60 * 60 ); // Full day booking by default
1291
1292 foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600, 23400 ], value_option_24h: '06:00 - 06:30', name: 'rangetime'}
1293
1294 if ( false !== strpos( $time_fields_obj['name'], 'rangetime' ) ) {
1295 $time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ];
1296 $time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 1 ];
1297 //break; // If we have range-time then skip this loop
1298 }
1299 if ( false !== strpos( $time_fields_obj['name'], 'starttime' ) ) {
1300 $time_as_seconds_arr[ 0 ] = $time_fields_obj['times_as_seconds'][ 0 ];
1301 }
1302 if ( false !== strpos( $time_fields_obj['name'], 'endtime' ) ) {
1303 $time_as_seconds_arr[ 1 ] = $time_fields_obj['times_as_seconds'][ 0 ];
1304 }
1305 }
1306
1307 // For duration time we need to make a new loop, because we need to be sure that was defined START_TIME before this,
1308 // and end time was NOT defined, e.g. == (otherwise it's means that we already used END_TIME or RANGE_TIME)
1309 if (
1310 ( ( 0 ) !== $time_as_seconds_arr[ 0 ] )
1311 && ( (24 * 60 * 60 ) === $time_as_seconds_arr[ 1 ] )
1312 ){
1313 foreach ( $selected_time_fields as $time_fields_obj ) { // { times_as_seconds: [ 21600 ], value_option_24h: '06:00', name: 'durationtime'}
1314
1315 if ( false !== strpos( $time_fields_obj['name'], 'durationtime' ) ) {
1316 $time_as_seconds_arr[ 1 ] = $time_as_seconds_arr[ 0 ] + $time_fields_obj['times_as_seconds'][ 0 ];
1317 break;
1318 }
1319 }
1320 }
1321
1322 return $time_as_seconds_arr;
1323 }
1324
1325
1326 /**
1327 * Get all time fields in the booking form as array of objects
1328 *
1329 * @param booking_form_data__arr = [
1330 * selected_short_dates_hint = "September 27, 2023 - September 28, 2023"
1331 * days_number_hint = "2"
1332 * rangetime = "16:00 - 18:00"
1333 * starttime = "21:00"
1334 * durationtime = "00:30"
1335 * name = "John"
1336 * secondname = "Smith"
1337 * email = "john.smith@server.com"
1338 * visitors = "1"
1339 * children = "0"
1340 * details = ""
1341 * ]
1342 * @returns []
1343 *
1344 * Example:
1345 * [
1346 * [
1347 * name = "rangetime"
1348 * value_option_24h = "16:00 - 18:00"
1349 * times_as_seconds = [ 57600, 64800 ]
1350 * ]
1351 * [
1352 * name = "starttime"
1353 * value_option_24h = "21:00"
1354 * times_as_seconds = [ 75600 ]
1355 * ]
1356 * [
1357 * name = "durationtime"
1358 * value_option_24h = "00:30"
1359 * times_as_seconds = [ 1800 ]
1360 * ]
1361 * ]
1362 */
1363 function wpbc_get__selected_time_fields__in_booking_form__as_arr( $booking_form_data__arr ){
1364
1365 /**
1366 * Fields with [] like this select[name="rangetime1[]"]
1367 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
1368 */
1369 $time_fields_arr = array( 'rangetime', 'starttime', 'endtime', 'durationtime' );
1370
1371 $time_fields_obj_arr = array();
1372
1373 // Loop all Time Fields
1374 for ( $ctf = 0; $ctf < count( $time_fields_arr ); $ctf ++ ) {
1375
1376 $time_field = $time_fields_arr[ $ctf ];
1377 if ( isset( $booking_form_data__arr[ $time_field ] ) ) {
1378
1379 $value_option_seconds_arr = explode( '-', $booking_form_data__arr[ $time_field ] );
1380 $times_as_seconds_arr = array();
1381
1382 foreach ( $value_option_seconds_arr as $time_val ) {
1383 $time_val = trim( $time_val );
1384 if ( ! empty( $time_val ) ) {
1385 $start_end_times_arr = explode( ':', $time_val );
1386 $time_in_seconds = intval( $start_end_times_arr[0] ) * 60 * 60 + intval( $start_end_times_arr[1] ) * 60;
1387 $times_as_seconds_arr[] = $time_in_seconds;
1388 }
1389 }
1390
1391 if (! empty($times_as_seconds_arr)) {
1392
1393 $time_fields_obj_arr[] = array(
1394 'name' => $time_field,
1395 'value_option_24h' => $booking_form_data__arr[ $time_field ],
1396 'times_as_seconds' => $times_as_seconds_arr
1397 );
1398 }
1399 }
1400 }
1401
1402 return $time_fields_obj_arr;
1403 }
1404
1405
1406 //TODO: 2023-10-13 16:37
1407 // - create new function for confirmation section
1408 // - Update payment request
1409 // - create redirection to the "Thank you." page and show there conformation, and payment request"
1410 // - define in the settings new Stripe and PayPal button design as default !
1411 // - Be sure that 'booking_log_booking_actions' active by default
1412 // - test it in dark theme
1413 // - test closing booked dates if all time slot was booked - it's relative to 'different time slots in dif dates'
1414 // - add migrate support old dates selection variables
1415 // - check and remove other global Js vars
1416 // - Create wizard booking form style with steps ?
1417 // - Check Booking > Availability page relative new functionality of calendar_load !
1418 // - Update last func in wpbc-booking-new.php and remove it.
1419 // - Test capacity in dates and time slots
1420 // - Next 9.9 Customizer Wizard
1421 // - Next 9.9 Update search admin UI
1422 // - Next 9.9 - update functionality in Search functionality based on similar to where_to_save function.
1423 // - Next 9.9 refactor Dates functions.
1424 // Done. - Next 9.9 Update Booking > Settings General page to show tabs vertically in left column
1425 // 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.
1426 // Create the same navigation for Emails.
1427 /**
1428 * TODO: Performance improvement:
1429 * "other_code": 0.003080129623413086
1430 * "wpbc__where_to_save_booking": 0.060331106185913086
1431 * "wpbc_db__booking_save": 0.023384809494018555
1432 * "wpbc_maybe_get_payment_form": 1.3650128841400146 <-
1433 * "emails_sending": 1.5024309158325195 <-
1434 * "total": 2.9542438983917236
1435 */
1436