PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.5.2
LatePoint – Calendar Booking Plugin for Appointments and Events v5.5.2
5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / models / booking_model.php
latepoint / lib / models Last commit date
activity_model.php 3 months ago agent_meta_model.php 3 months ago agent_model.php 3 months ago booking_meta_model.php 3 months ago booking_model.php 3 months ago bundle_meta_model.php 3 months ago bundle_model.php 3 months ago cart_item_model.php 3 months ago cart_meta_model.php 3 months ago cart_model.php 3 months ago connector_model.php 3 months ago customer_meta_model.php 3 months ago customer_model.php 1 month ago invoice_model.php 3 months ago join_bundles_services_model.php 3 months ago location_category_model.php 3 months ago location_model.php 3 months ago meta_model.php 3 months ago model.php 3 months ago off_period_model.php 3 months ago order_intent_meta_model.php 3 months ago order_intent_model.php 3 months ago order_item_model.php 3 months ago order_meta_model.php 3 months ago order_model.php 3 months ago otp_model.php 3 months ago payment_request_model.php 3 months ago process_job_model.php 3 months ago process_model.php 3 months ago recurrence_model.php 3 months ago service_category_model.php 3 months ago service_meta_model.php 3 months ago service_model.php 3 months ago session_model.php 3 months ago settings_model.php 3 months ago step_settings_model.php 3 months ago transaction_intent_model.php 3 months ago transaction_model.php 3 months ago transaction_refund_model.php 3 months ago work_period_model.php 3 months ago
booking_model.php
1316 lines
1 <?php
2
3 /**
4 * @property OsCustomerModel $customer
5 * @property OsAgentModel $agent
6 * @property OsServiceModel $service
7 * @property OsLocationModel $location
8 */
9 class OsBookingModel extends OsModel {
10 public $id,
11 $booking_code,
12 $service_id,
13 $customer_id,
14 $agent_id,
15 $location_id,
16 $recurrence_id,
17 $buffer_before = 0,
18 $buffer_after = 0,
19 $status,
20 $start_date,
21 $end_date,
22 $start_time,
23 $end_time,
24 $start_datetime_utc,
25 $end_datetime_utc,
26 $duration,
27 $total_attendees = 1,
28 $total_attendees_sum = 1,
29 $total_customers = 1,
30 $cart_item_id = null,
31 $order_item_id,
32 $server_timezone,
33 $customer_timezone,
34 $meta_class = 'OsBookingMetaModel',
35 $keys_to_manage = [],
36 $generate_recurrent_sequence = [],
37 $updated_at,
38 $created_at;
39
40 function __construct( $id = false ) {
41 parent::__construct();
42 $this->table_name = LATEPOINT_TABLE_BOOKINGS;
43 $this->nice_names = array(
44 'service_id' => __( 'Service', 'latepoint' ),
45 'agent_id' => __( 'Agent', 'latepoint' ),
46 );
47
48 if ( $id ) {
49 $this->load_by_id( $id );
50 }
51 }
52
53
54 /**
55 * @return mixed|void
56 *
57 * Returns full amount to charge in database format 1999.0000
58 *
59 */
60 public function full_amount_to_charge() {
61 return OsBookingHelper::calculate_full_amount_for_booking( $this );
62 }
63
64 /**
65 * @return mixed|void
66 *
67 * Returns deposit amount to charge in database format 1999.0000
68 *
69 */
70 public function deposit_amount_to_charge() {
71 return OsBookingHelper::calculate_deposit_amount_to_charge( $this );
72 }
73
74
75 public function get_key_to_manage_for( string $for ): string {
76 if ( $this->is_new_record() ) {
77 return '';
78 }
79 if ( ! empty( $this->keys_to_manage[ $for ] ) ) {
80 return $this->keys_to_manage[ $for ];
81 }
82 $key = OsMetaHelper::get_booking_meta_by_key( 'key_to_manage_for_' . $for, $this->id );
83 if ( empty( $key ) ) {
84 $key = OsUtilHelper::generate_key_to_manage();
85 OsMetaHelper::save_booking_meta_by_key( 'key_to_manage_for_' . $for, $key, $this->id );
86 }
87 $this->keys_to_manage[ $for ] = $key;
88 return $key;
89 }
90
91 public function manage_by_key_url( string $for = 'customer' ): string {
92 return OsBookingHelper::generate_direct_manage_booking_url( $this, $for );
93 }
94
95 public function get_service_name_for_summary() {
96 $service_name = $this->service_id ? $this->service->name : '';
97
98 /**
99 * Get service name to be displayed on a booking summary
100 *
101 * @param {string} $service_name Service name to be filtered
102 * @param {OsBookingModel} $booking Booking model which service name is requested
103 *
104 * @returns {string} Filtered service name
105 * @since 5.0.0
106 * @hook latepoint_booking_get_service_name_for_summary
107 *
108 */
109 return apply_filters( 'latepoint_booking_get_service_name_for_summary', $service_name, $this );
110 }
111
112 public function get_order() {
113 if ( $this->order_item_id ) {
114 if ( ! isset( $this->order_item ) || ( $this->order_item->id != $this->order_item_id ) ) {
115 $this->order_item = new OsOrderItemModel( $this->order_item_id );
116 if ( ! isset( $this->order ) || ( $this->order->id != $this->order_item->order_id ) ) {
117 $this->order = new OsOrderModel( $this->order_item->order_id );
118 }
119 }
120 } else {
121 $this->order = new OsOrderModel();
122 }
123
124 return $this->order;
125 }
126
127 public function get_order_item() {
128 if ( ! isset( $this->order_item ) ) {
129 $this->order_item = new OsOrderItemModel( $this->order_item_id );
130 }
131 return $this->order_item;
132 }
133
134 public function filter_allowed_records(): OsModel {
135 if ( ! OsRolesHelper::are_all_records_allowed() ) {
136 if ( ! OsRolesHelper::are_all_records_allowed( 'agent' ) ) {
137 $this->filter_where_conditions( [ 'agent_id' => OsRolesHelper::get_allowed_records( 'agent' ) ] );
138 }
139 if ( ! OsRolesHelper::are_all_records_allowed( 'location' ) ) {
140 $this->filter_where_conditions( [ 'location_id' => OsRolesHelper::get_allowed_records( 'location' ) ] );
141 }
142 if ( ! OsRolesHelper::are_all_records_allowed( 'service' ) ) {
143 $this->filter_where_conditions( [ 'service_id' => OsRolesHelper::get_allowed_records( 'service' ) ] );
144 }
145 }
146
147 return $this;
148 }
149
150 public function properties_to_query(): array {
151 return [
152 'service_id' => __( 'Service', 'latepoint' ),
153 'agent_id' => __( 'Agent', 'latepoint' ),
154 'status' => __( 'Status', 'latepoint' ),
155 'start_datetime_utc' => __( 'Start Time', 'latepoint' ),
156 ];
157 }
158
159 public function generate_item_data() {
160 return wp_json_encode( $this->generate_params_for_booking_form() );
161 }
162
163
164 public function generate_params_for_booking_form() {
165 $params = [
166 'id' => $this->id,
167 'customer_id' => $this->customer_id,
168 'agent_id' => $this->agent_id,
169 'location_id' => $this->location_id,
170 'service_id' => $this->service_id,
171 'recurrence_id' => $this->recurrence_id,
172 'start_date' => $this->start_date,
173 'start_time' => $this->start_time,
174 'end_date' => $this->end_date,
175 'end_time' => $this->end_time,
176 'status' => $this->status,
177 'buffer_before' => $this->buffer_before,
178 'buffer_after' => $this->buffer_after,
179 'duration' => $this->duration,
180 'generate_recurrent_sequence' => $this->generate_recurrent_sequence,
181 ];
182
183 /**
184 * Returns an array of params generated from OsBookingModel to be used in a booking form
185 *
186 * @param {array} $params Array of booking params
187 * @param {OsBookingModel} $booking Instance of <code>OsBookingModel</code> that params are being generated for
188 *
189 * @returns {array} Filtered array of booking params
190 * @since 5.0.0
191 * @hook latepoint_generated_params_for_booking_form
192 *
193 */
194 return apply_filters( 'latepoint_generated_params_for_booking_form', $params, $this );
195 }
196
197 public function get_formatted_price() {
198 $order_item = new OsOrderItemModel( $this->order_item_id );
199 return OsMoneyHelper::format_price( $order_item->get_total() );
200 }
201
202 public function generate_first_level_data_vars(): array {
203 $vars = [
204 'id' => $this->id,
205 'booking_code' => $this->booking_code,
206 'start_datetime' => $this->format_start_date_and_time_rfc3339(),
207 'end_datetime' => $this->format_end_date_and_time_rfc3339(),
208 'service_name' => $this->service->name,
209 'duration' => $this->duration,
210 'customer_comment' => $this->order->customer_comment,
211 'status' => $this->status,
212 'start_date' => $this->format_start_date(),
213 'start_time' => OsTimeHelper::minutes_to_hours_and_minutes( $this->start_time ),
214 'timezone' => OsTimeHelper::get_wp_timezone_name(),
215 'agent' => $this->agent->get_data_vars(),
216 'created_datetime' => $this->format_created_datetime_rfc3339(),
217 'manage_booking_for_agent' => OsBookingHelper::generate_direct_manage_booking_url( $this, 'agent' ),
218 'manage_booking_for_customer' => OsBookingHelper::generate_direct_manage_booking_url( $this, 'customer' ),
219 ];
220 return $vars;
221 }
222
223 public function generate_data_vars(): array {
224 $vars = $this->get_first_level_data_vars();
225
226 $vars['customer'] = $this->customer->get_data_vars();
227 $vars['transactions'] = [];
228 $vars['order'] = $this->order->get_first_level_data_vars();
229
230 $transactions = $this->order->get_transactions();
231 if ( $transactions ) {
232 foreach ( $transactions as $transaction ) {
233 $vars['transactions'][] = $transaction->get_data_vars();
234 }
235 }
236
237 return $vars;
238 }
239
240
241 public function is_ready_for_summary() {
242 return ( $this->agent_id && $this->agent_id != LATEPOINT_ANY_AGENT && OsAgentHelper::count_agents() > 1 ) || $this->service_id;
243 }
244
245 public function is_part_of_bundle(): bool {
246 if ( $this->order_item_id ) {
247 $order_item = new OsOrderItemModel( $this->order_item_id );
248
249 return $order_item->is_bundle();
250 }
251
252 return false;
253 }
254
255 public function is_upcoming(): bool {
256 if ( empty( $this->start_datetime_utc ) ) {
257 return false;
258 }
259 $start_time_utc = new OsWpDateTime( $this->start_datetime_utc, new DateTimeZone( 'UTC' ) );
260 $now_time_utc = new OsWpDateTime( 'now', new DateTimeZone( 'UTC' ) );
261
262 return ( $start_time_utc > $now_time_utc );
263 }
264
265 public function set_utc_datetimes( bool $save = false ) {
266 if ( empty( $this->start_date ) || empty( $this->end_date ) || empty( $this->start_time ) || empty( $this->end_time ) ) {
267 return;
268 }
269 $this->start_datetime_utc = $this->get_start_datetime( 'UTC' )->format( LATEPOINT_DATETIME_DB_FORMAT );
270 $this->end_datetime_utc = $this->get_end_datetime( 'UTC' )->format( LATEPOINT_DATETIME_DB_FORMAT );
271 if ( $save ) {
272 $this->update_attributes(
273 [
274 'start_datetime_utc' => $this->start_datetime_utc,
275 'end_datetime_utc' => $this->end_datetime_utc,
276 ]
277 );
278 }
279 }
280
281
282 public function delete( $id = false ) {
283 if ( ! $id && isset( $this->id ) ) {
284 $id = $this->id;
285 }
286
287 $booking_metas = new OsBookingMetaModel();
288 $booking_metas->delete_where( [ 'object_id' => $id ] );
289 $process_jobs = new OsProcessJobModel();
290 $process_jobs->delete_where(
291 [
292 'object_id' => $id,
293 'object_model_type' => 'booking',
294 ]
295 );
296
297
298 return parent::delete( $id );
299 }
300
301 public function delete_meta_by_key( $meta_key ) {
302 if ( $this->is_new_record() ) {
303 return true;
304 }
305
306 $meta = new OsBookingMetaModel();
307
308 return $meta->delete_by_key( $meta_key, $this->id );
309 }
310
311 public function get_url_for_add_to_calendar_button( string $calendar_type ): string {
312 switch ( $calendar_type ) {
313 case 'google':
314 $url = 'https://calendar.google.com/calendar/render';
315 $params = [
316 'action' => 'TEMPLATE',
317 'text' => $this->service->name,
318 'dates' => $this->get_start_datetime_object( new DateTimeZone( 'UTC' ) )->format( 'Ymd\THis\Z' ) . '/' . $this->get_end_datetime_object( new DateTimeZone( 'UTC' ) )->format( 'Ymd\THis\Z' ),
319 ];
320 if ( ! empty( $this->location->full_address ) ) {
321 $params['location'] = $this->location->full_address;
322 }
323 break;
324 case 'outlook':
325 $url = 'https://outlook.office.com/calendar/0/deeplink/compose';
326 $params = [
327 'path' => '/calendar/action/compose',
328 'rru' => 'addevent',
329 'startdt' => $this->get_start_datetime_object( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d\TH:i:s\Z' ),
330 'enddt' => $this->get_end_datetime_object( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d\TH:i:s\Z' ),
331 'subject' => $this->service->name,
332 ];
333 break;
334 }
335 /**
336 * Generate params for the add to calendar link
337 *
338 * @param {array} $params Array of parameters that will be converted into a param query
339 * @param {string} $calendar_type Type of calendar the link is requested for
340 * @param {OsBookingModel} $booking A booking object
341 * @returns {array} The filtered array of appointment attributes
342 *
343 * @since 4.8.1
344 * @hook latepoint_build_add_to_calendar_link_params
345 *
346 */
347 $params = apply_filters( 'latepoint_build_add_to_calendar_link_params', $params, $calendar_type, $this );
348
349 $url = $url . '?' . http_build_query( $params );
350
351 /**
352 * URL for the link for a button to add appointment to calendar
353 *
354 * @param {array} $params Array of parameters that will be converted into a param query
355 * @param {string} $calendar_type Type of calendar the link is requested for
356 * @param {OsBookingModel} $booking A booking object
357 * @returns {string} The filtered url of adding appointment to calendar
358 *
359 * @since 4.8.1
360 * @hook latepoint_build_add_to_calendar_link_url
361 *
362 */
363 return apply_filters( 'latepoint_build_add_to_calendar_link_url', $url, $calendar_type, $this );
364 }
365
366 public function get_ical_download_link( $key = false ) {
367 return ( $key ) ? OsRouterHelper::build_admin_post_link(
368 [
369 'manage_booking_by_key',
370 'ical_download',
371 ],
372 [ 'key' => $key ]
373 ) : OsRouterHelper::build_admin_post_link(
374 [
375 'customer_cabinet',
376 'ical_download',
377 ],
378 [ 'latepoint_booking_id' => $this->id ]
379 );
380 }
381
382 public function get_print_link( $key = false ) {
383 return ( $key ) ? OsRouterHelper::build_admin_post_link( [ 'manage_booking_by_key', 'print' ], [ 'key' => $key ] ) : OsRouterHelper::build_admin_post_link( [ 'customer_cabinet', 'print_booking_info' ], [ 'latepoint_booking_id' => $this->id ] );
384 }
385
386 public function get_meta_by_key( $meta_key, $default = false ) {
387 if ( $this->is_new_record() ) {
388 return $default;
389 }
390
391 $meta = new OsBookingMetaModel();
392
393 return $meta->get_by_key( $meta_key, $this->id, $default );
394 }
395
396 public function get_coupon_code() {
397 $order = $this->get_order();
398 return $order->coupon_code;
399 }
400
401 public function get_coupon_discount(): string {
402 $order_item = $this->get_order_item();
403 $coupon_discount = $order_item->get_coupon_discount();
404 return $coupon_discount > 0 ? OsMoneyHelper::format_price( $order_item->get_coupon_discount() ) : '';
405 }
406
407 public function save_meta_by_key( $meta_key, $meta_value ) {
408 if ( $this->is_new_record() ) {
409 return false;
410 }
411
412 $meta = new OsBookingMetaModel();
413
414 return $meta->save_by_key( $meta_key, $meta_value, $this->id );
415 }
416
417 public function calculate_end_date() {
418 if ( empty( $this->start_time ) || empty( $this->start_date ) ) {
419 return $this->start_date;
420 }
421 if ( ( $this->start_time + $this->get_total_duration() ) >= ( 24 * 60 ) ) {
422 $date_obj = new OsWpDateTime( $this->start_date );
423 $end_date = $date_obj->modify( '+1 day' )->format( 'Y-m-d' );
424 } else {
425 $end_date = $this->start_date;
426 }
427
428 return $end_date;
429 }
430
431
432 public function calculate_end_time() {
433 $end_time = (int) $this->start_time + (int) $this->get_total_duration();
434 // continues to next day?
435 if ( $end_time > ( 24 * 60 ) ) {
436 $end_time = $end_time - ( 24 * 60 );
437 }
438
439 return $end_time;
440 }
441
442 public function calculate_end_date_and_time() {
443 $this->end_time = $this->calculate_end_time();
444 $this->end_date = $this->calculate_end_date();
445 }
446
447 public function after_data_was_set( $data ) {
448 if ( empty( $this->end_time ) ) {
449 $this->calculate_end_date_and_time();
450 }
451 if ( empty( $this->end_date ) ) {
452 $this->calculate_end_date();
453 }
454 }
455
456 public function set_buffers() {
457 if ( $this->service_id ) {
458 $service = new OsServiceModel( $this->service_id );
459 if ( $service ) {
460 $this->buffer_before = $service->buffer_before;
461 $this->buffer_after = $service->buffer_after;
462 }
463 }
464 }
465
466 public function get_total_duration( $calculate_from_start_and_end = false ) {
467 if ( $calculate_from_start_and_end ) {
468 if ( $this->start_date == $this->end_date ) {
469 // same day
470 $total_duration = $this->end_time - $this->start_time;
471 } else {
472 // TODO calculate how many days difference there is, if difference is more than 1 day - account for that
473 $total_duration = 60 * 24 - $this->start_time + $this->end_time;
474 }
475 } else {
476 if ( $this->duration ) {
477 $total_duration = $this->duration;
478 } else {
479 $total_duration = ( $this->service_id ) ? $this->service->duration : 60;
480 }
481 $total_duration = apply_filters( 'latepoint_calculated_total_duration', $total_duration, $this );
482 }
483
484 return (int) $total_duration;
485 }
486
487
488 public function get_nice_created_at( $include_time = true ) {
489 $format = $include_time ? OsSettingsHelper::get_readable_date_format() . ' ' . OsSettingsHelper::get_readable_time_format() : OsSettingsHelper::get_readable_date_format();
490 $utc_date = date_create_from_format( LATEPOINT_DATETIME_DB_FORMAT, $this->created_at );
491 $wp_timezone_date = $utc_date->setTimezone( OsTimeHelper::get_wp_timezone() );
492
493 return date_format( $wp_timezone_date, $format );
494 }
495
496 public function is_bookable( array $settings = [] ): bool {
497
498 $defaults = [
499 'skip_customer_check' => false,
500 'log_errors' => true,
501 ];
502
503 $settings = OsUtilHelper::merge_default_atts( $defaults, $settings );
504
505 $customer = $this->customer_id ? new OsCustomerModel( $this->customer_id ) : false;
506 // check if customer has to be assigned to a booking, or a guest booking is fine at this point
507 if ( $settings['skip_customer_check'] ) {
508 $customer_requirement_satisfied = true;
509 } else {
510 $customer_requirement_satisfied = ( $this->customer_id && $customer && $customer->id && ( $this->customer_id == $customer->id ) );
511 }
512
513 // agent, service and customer should be set
514 if ( $this->service_id && $this->agent_id && $customer_requirement_satisfied ) {
515
516 if ( $this->agent_id == LATEPOINT_ANY_AGENT && $this->location_id == LATEPOINT_ANY_LOCATION ) {
517 // both location and agent are set to any
518 $connections = new OsConnectorModel();
519 $connection_groups = $connections->select( LATEPOINT_TABLE_AGENTS_SERVICES . '.agent_id, ' . LATEPOINT_TABLE_AGENTS_SERVICES . '.location_id' )
520 ->where(
521 [
522 'service_id' => $this->service_id,
523 LATEPOINT_TABLE_AGENTS . '.status' => LATEPOINT_AGENT_STATUS_ACTIVE,
524 LATEPOINT_TABLE_LOCATIONS . '.status' => LATEPOINT_LOCATION_STATUS_ACTIVE,
525 ]
526 )
527 ->join( LATEPOINT_TABLE_AGENTS, [ 'id' => LATEPOINT_TABLE_AGENTS_SERVICES . '.agent_id' ] )
528 ->join( LATEPOINT_TABLE_LOCATIONS, [ 'id' => LATEPOINT_TABLE_AGENTS_SERVICES . '.location_id' ] )
529 ->get_results( ARRAY_A );
530 if ( empty( $connection_groups ) ) {
531 // no active locations and agents are connected to this service
532 $this->add_error( 'send_to_step', __( 'Unfortunately there are no active resources that can offer selected service, please select another service.', 'latepoint' ), 'booking__service' );
533
534 return false;
535 } else {
536 foreach ( $connection_groups as $connection ) {
537 $this->location_id = $connection['location_id'];
538 $this->agent_id = OsBookingHelper::get_any_agent_for_booking_by_rule( $this );
539 // available agent found in this location - break the loop
540 if ( $this->agent_id ) {
541 break;
542 }
543 }
544 if ( ! $this->agent_id ) {
545 $this->add_error( 'send_to_step', __( 'Unfortunately the selected time slot is not available anymore, please select another timeslot.', 'latepoint' ), 'booking__datepicker' );
546
547 return false;
548 }
549 }
550 } elseif ( $this->agent_id == LATEPOINT_ANY_AGENT ) {
551 $this->agent_id = OsBookingHelper::get_any_agent_for_booking_by_rule( $this );
552 if ( ! $this->agent_id ) {
553 $this->add_error( 'send_to_step', __( 'Unfortunately the selected time slot is not available anymore, please select another timeslot.', 'latepoint' ), 'booking__datepicker' );
554
555 return false;
556 }
557 } elseif ( $this->location_id == LATEPOINT_ANY_LOCATION ) {
558 $this->location_id = OsBookingHelper::get_any_location_for_booking_by_rule( $this );
559 if ( ! $this->location_id ) {
560 $this->add_error( 'send_to_step', __( 'Unfortunately the selected time slot is not available anymore, please select another timeslot.', 'latepoint' ), 'booking__datepicker' );
561
562 return false;
563 }
564 } else {
565 // check if booking time is still available
566 if ( ! OsBookingHelper::is_booking_request_available( \LatePoint\Misc\BookingRequest::create_from_booking_model( $this ) ) ) {
567 // translators: %1$s is the timeslot date and time
568 // translators: %2$s is the service name
569 $error_message = sprintf( __( 'Unfortunately the selected time slot "%1$s" for "%2$s" is not available anymore, please select another timeslot.', 'latepoint' ), $this->get_nice_start_datetime_for_customer(), $this->service->name );
570 $this->add_error( 'send_to_step', $error_message, 'booking__datepicker' );
571
572 return false;
573 }
574 }
575
576 if ( ! $this->validate( false, [ 'order_item_id', 'status', 'customer_id' ] ) ) {
577 return false;
578 }
579
580 return true;
581 } else {
582 if ( ! $this->service_id ) {
583 $this->add_error( 'missing_service', __( 'You have to select a service', 'latepoint' ) );
584 }
585 if ( ! $this->agent_id ) {
586 $this->add_error( 'missing_agent', __( 'You have to select an agent', 'latepoint' ) );
587 }
588 if ( ! $this->customer_id && ! $settings['skip_customer_check'] ) {
589 $this->add_error( 'missing_customer', __( 'Customer Not Found', 'latepoint' ) );
590 if ( $settings['log_errors'] ) {
591 OsDebugHelper::log( 'Customer not found', 'customer_error', print_r( $customer, true ) );
592 }
593 }
594 if ( ! $customer && ! $settings['skip_customer_check'] ) {
595 $this->add_error( 'missing_customer', __( 'You have to be logged in', 'latepoint' ) );
596 if ( $settings['log_errors'] ) {
597 OsDebugHelper::log( 'Customer not logged in', 'customer_error', print_r( $customer, true ) );
598 }
599 }
600 if ( $settings['log_errors'] ) {
601 OsDebugHelper::log( 'Error saving booking', 'booking_error', 'Agent: ' . $this->agent_id . ', Service: ' . $this->service_id . ', Booking Customer: ' . $this->customer_id );
602 }
603
604 return false;
605 }
606 }
607
608
609 public function get_nice_status() {
610 return OsBookingHelper::get_nice_status_name( $this->status );
611 }
612
613 public function get_latest_bookings_sorted_by_status( $args = array() ) {
614 $args = array_merge(
615 array(
616 'service_id' => false,
617 'customer_id' => false,
618 'agent_id' => false,
619 'location_id' => false,
620 'limit' => false,
621 'offset' => false,
622 ),
623 $args
624 );
625
626 $bookings = new OsBookingModel();
627 $query_args = array();
628 if ( $args['service_id'] ) {
629 $query_args['service_id'] = $args['service_id'];
630 }
631 if ( $args['customer_id'] ) {
632 $query_args['customer_id'] = $args['customer_id'];
633 }
634 if ( $args['agent_id'] ) {
635 $query_args['agent_id'] = $args['agent_id'];
636 }
637 if ( $args['location_id'] ) {
638 $query_args['location_id'] = $args['location_id'];
639 }
640 if ( $args['limit'] ) {
641 $bookings->set_limit( $args['limit'] );
642 }
643 if ( $args['offset'] ) {
644 $bookings->set_offset( $args['offset'] );
645 }
646
647 return $bookings->where( $query_args )->should_not_be_cancelled()->order_by( "status != '" . LATEPOINT_BOOKING_STATUS_PENDING . "' asc, start_date asc, start_time asc" )->get_results_as_models();
648 }
649
650
651 public function should_not_be_cancelled() {
652 return $this->where( [ $this->table_name . '.status !=' => LATEPOINT_BOOKING_STATUS_CANCELLED ] );
653 }
654
655 public function should_be_cancelled() {
656 return $this->where( [ $this->table_name . '.status' => LATEPOINT_BOOKING_STATUS_CANCELLED ] );
657 }
658
659 public function should_be_approved() {
660 return $this->where( [ $this->table_name . '.status' => LATEPOINT_BOOKING_STATUS_APPROVED ] );
661 }
662
663 public function should_be_in_future() {
664 return $this->where(
665 [
666 'OR' => [
667 'start_date >' => OsTimeHelper::today_date( 'Y-m-d' ),
668 'AND' => [
669 'start_date' => OsTimeHelper::today_date( 'Y-m-d' ),
670 'start_time >' => OsTimeHelper::get_current_minutes(),
671 ],
672 ],
673 ]
674 );
675 }
676
677
678 public function get_upcoming_bookings( $agent_id = false, $customer_id = false, $service_id = false, $location_id = false, int $limit = 3 ) {
679 $bookings = new OsBookingModel();
680 $args = array(
681 'OR' => array(
682 'start_date >' => OsTimeHelper::today_date( 'Y-m-d' ),
683 'AND' => array(
684 'start_date' => OsTimeHelper::today_date( 'Y-m-d' ),
685 'start_time >' => OsTimeHelper::get_current_minutes(),
686 ),
687 ),
688 );
689 if ( $service_id ) {
690 $args['service_id'] = $service_id;
691 }
692 if ( $customer_id ) {
693 $args['customer_id'] = $customer_id;
694 }
695 if ( $agent_id ) {
696 $args['agent_id'] = $agent_id;
697 }
698 if ( $location_id ) {
699 $args['location_id'] = $location_id;
700 }
701
702 $args = OsAuthHelper::get_current_user()->clean_query_args( $args );
703 $allowed_statuses = OsCalendarHelper::get_booking_statuses_to_display_on_calendar();
704 if ( empty( $allowed_statuses ) ) {
705 return [];
706 }
707
708 return $bookings->select( '*, count(id) as total_customers, sum(total_attendees) as total_attendees_sum' )
709 ->where_in( 'status', $allowed_statuses )
710 ->group_by( 'start_datetime_utc, agent_id, service_id, location_id' )
711 ->where( $args )
712 ->set_limit( $limit )
713 ->order_by( 'start_datetime_utc asc' )
714 ->get_results_as_models();
715 }
716
717 public function get_nice_start_time_for_customer() {
718 return $this->format_start_date_and_time( OsTimeHelper::get_time_format(), false, $this->get_customer_timezone() );
719 }
720
721 public function get_nice_end_time_for_customer() {
722 return $this->format_end_date_and_time( OsTimeHelper::get_time_format(), false, $this->get_customer_timezone() );
723 }
724
725 public function get_nice_start_date_for_customer( $customer_timezone = false, $hide_year = false ) {
726 if ( ! $customer_timezone ) {
727 $customer_timezone = $this->get_customer_timezone();
728 }
729 return OsUtilHelper::translate_months( $this->format_start_date_and_time( OsSettingsHelper::get_readable_date_format( $hide_year ), false, $customer_timezone ) );
730 }
731
732 public function get_nice_start_datetime_for_customer( $customer_timezone = false ) {
733 if ( ! $customer_timezone ) {
734 $customer_timezone = $this->get_customer_timezone();
735 }
736 return OsUtilHelper::translate_months( $this->format_start_date_and_time( OsSettingsHelper::get_readable_datetime_format(), false, $customer_timezone ) );
737 }
738
739 public function get_start_datetime_for_customer(): OsWpDateTime {
740 return $this->get_start_datetime( $this->get_customer_timezone_name() );
741 }
742 public function get_end_datetime_for_customer(): OsWpDateTime {
743 return $this->get_end_datetime( $this->get_customer_timezone_name() );
744 }
745
746 public function get_customer_timezone(): DateTimeZone {
747 if ( OsSettingsHelper::is_on( 'steps_show_timezone_selector' ) ) {
748 return ( $this->customer_id ) ? $this->customer->get_selected_timezone_obj() : OsTimeHelper::get_timezone_from_session();
749 } else {
750 return OsTimeHelper::get_wp_timezone();
751 }
752 }
753 public function get_customer_timezone_name(): string {
754 if ( OsSettingsHelper::is_on( 'steps_show_timezone_selector' ) ) {
755 return ( $this->customer_id ) ? $this->customer->get_selected_timezone_name() : OsTimeHelper::get_timezone_name_from_session();
756 } else {
757 return OsTimeHelper::get_wp_timezone_name();
758 }
759 }
760
761 /**
762 *
763 * Returns time in WP timezone, because start_time is stored in WP timezone, do not use it for customer facing outputs
764 *
765 * @return string|null
766 */
767 public function get_nice_start_time() {
768 return OsTimeHelper::minutes_to_hours_and_minutes( $this->start_time );
769 }
770
771 /**
772 *
773 * Returns time in WP timezone, because end_time is stored in WP timezone, do not use it for customer facing outputs
774 *
775 * @return string|null
776 */
777 public function get_nice_end_time() {
778 return OsTimeHelper::minutes_to_hours_and_minutes( $this->end_time );
779 }
780
781 /**
782 *
783 * Returns time in WP timezone, because start_date is stored in WP timezone, do not use it for customer facing outputs
784 *
785 * @return string|null
786 */
787 public function get_nice_end_date( $hide_year_if_current = false ) {
788 $datetime = OsWpDateTime::os_createFromFormat( 'Y-m-d', $this->end_date );
789 OsTimeHelper::format_to_nice_date( $datetime, $hide_year_if_current );
790 }
791
792 /**
793 *
794 * Returns time in WP timezone, because end_date is stored in WP timezone, do not use it for customer facing outputs
795 *
796 * @return string|null
797 */
798 public function get_nice_start_date( $hide_year_if_current = false ): string {
799 $datetime = OsWpDateTime::os_createFromFormat( 'Y-m-d', $this->start_date );
800 return OsTimeHelper::format_to_nice_date( $datetime, $hide_year_if_current );
801 }
802
803
804
805 /**
806 *
807 * Returns time in WP timezone, because start_date is stored in WP timezone, do not use it for customer facing outputs
808 *
809 * @param $hide_if_today bool
810 * @param $hide_year_if_current bool
811 *
812 * @return string
813 */
814 public function get_nice_start_datetime( bool $hide_if_today = true, bool $hide_year_if_current = true ): string {
815 if ( $hide_if_today && $this->start_date == OsTimeHelper::today_date( 'Y-m-d' ) ) {
816 $date = __( 'Today', 'latepoint' );
817 } else {
818 $date = $this->get_nice_start_date( $hide_year_if_current );
819 }
820
821 return implode( ', ', array_filter( [ $date, $this->get_nice_start_time() ] ) );
822 }
823
824
825 public function is_bundle_scheduling(): bool {
826 return ! empty( $this->order_item_id );
827 }
828
829 public function get_connected_recurring_bookings(): array {
830 if ( empty( $this->recurrence_id ) || $this->is_new_record() ) {
831 return [];
832 }
833 $bookings = new OsBookingModel();
834 return $bookings->where(
835 [
836 'recurrence_id' => $this->recurrence_id,
837 'id !=' => $this->id,
838 ]
839 )->order_by( 'start_datetime_utc asc' )->get_results_as_models();
840 }
841
842 public function get_nice_datetime_for_summary( string $viewer = 'customer' ) {
843 $nice_datetime = '';
844 if ( $this->start_date ) {
845 $nice_datetime = $this->get_nice_start_datetime( false );
846 if ( OsSettingsHelper::is_on( 'show_booking_end_time' ) && ! empty( $this->end_time ) && ! empty( $this->start_time ) ) {
847 $nice_datetime = $nice_datetime . ' - ' . $this->get_nice_end_time();
848 }
849 }
850 /**
851 * Get a formatted start and end time (if needed)
852 *
853 * @since 5.1.0
854 * @hook latepoint_get_nice_datetime_for_summary
855 *
856 * @param {string} $statuses Nice datetime
857 * @param {OsBookingModel} $booking An object of booking model
858 *
859 * @returns {string} Filtered nice datetime
860 */
861 $nice_datetime = apply_filters( 'latepoint_get_nice_datetime_for_summary', $nice_datetime, $this, $viewer );
862 return $nice_datetime;
863 }
864
865
866 public function format_end_date_and_time( $format = LATEPOINT_DATETIME_DB_FORMAT, $input_timezone = false, $output_timezone = false ) {
867 if ( ! $input_timezone ) {
868 $input_timezone = OsTimeHelper::get_wp_timezone();
869 }
870 if ( ! $output_timezone ) {
871 $output_timezone = OsTimeHelper::get_wp_timezone();
872 }
873
874 $date = OsWpDateTime::os_createFromFormat( LATEPOINT_DATETIME_DB_FORMAT, $this->end_date . ' ' . OsTimeHelper::minutes_to_army_hours_and_minutes( $this->end_time ) . ':00', $input_timezone );
875 $date->setTimeZone( $output_timezone );
876
877 return OsUtilHelper::translate_months( $date->format( $format ) );
878 }
879
880 public function format_start_date() {
881 if ( empty( $this->start_date ) ) {
882 $date = new OsWpDateTime();
883 $this->start_date = $date->format( 'Y-m-d' );
884 } else {
885 $date = OsWpDateTime::os_createFromFormat( 'Y-m-d', $this->start_date );
886 }
887
888 return $date->format( OsSettingsHelper::get_date_format() );
889 }
890
891 public function format_start_date_and_time( $format = LATEPOINT_DATETIME_DB_FORMAT, $input_timezone = false, $output_timezone = false ) {
892 if ( ! $input_timezone ) {
893 $input_timezone = OsTimeHelper::get_wp_timezone();
894 }
895 if ( ! $output_timezone ) {
896 $output_timezone = OsTimeHelper::get_wp_timezone();
897 }
898
899 if ( is_null( $this->start_time ) || $this->start_time === '' ) {
900 // no time set yet (could be because summary is reloaded when date is picked, before the time is picked)
901 $date = OsWpDateTime::os_createFromFormat( 'Y-m-d', $this->start_date );
902 if ( $date ) {
903 return OsUtilHelper::translate_months( $date->format( OsSettingsHelper::get_readable_date_format() ) );
904 } else {
905 return __( 'Invalid Date/Time', 'latepoint' );
906 }
907 } else {
908 // both date & time are set, update timezone and translate
909 $date = OsWpDateTime::os_createFromFormat( LATEPOINT_DATETIME_DB_FORMAT, $this->start_date . ' ' . OsTimeHelper::minutes_to_army_hours_and_minutes( $this->start_time ) . ':00', $input_timezone );
910 if ( $date ) {
911 $date->setTimeZone( $output_timezone );
912
913 return OsUtilHelper::translate_months( $date->format( $format ) );
914 } else {
915 return __( 'Invalid Date/Time', 'latepoint' );
916 }
917 }
918 }
919
920 public function format_start_date_and_time_rfc3339() {
921 return $this->format_start_date_and_time( \DateTime::RFC3339 );
922 }
923
924 public function format_end_date_and_time_rfc3339() {
925 return $this->format_end_date_and_time( \DateTime::RFC3339 );
926 }
927
928 public function format_start_date_and_time_for_google() {
929 return $this->format_start_date_and_time( \DateTime::RFC3339 );
930 }
931
932 public function format_end_date_and_time_for_google() {
933 return $this->format_end_date_and_time( \DateTime::RFC3339 );
934 }
935
936 /*
937 * Checks if the booking has passed
938 */
939 public function time_status() {
940 try {
941 $now_datetime = OsTimeHelper::now_datetime_utc();
942 if ( empty( $this->start_datetime_utc ) || empty( $this->end_datetime_utc ) ) {
943 $this->set_utc_datetimes( true );
944 }
945 $booking_start = new OsWpDateTime( $this->start_datetime_utc, new DateTimeZone( 'UTC' ) );
946 $booking_end = new OsWpDateTime( $this->end_datetime_utc, new DateTimeZone( 'UTC' ) );
947 if ( ( $now_datetime <= $booking_end ) && ( $now_datetime >= $booking_start ) ) {
948 return 'now';
949 } elseif ( $now_datetime <= $booking_start ) {
950 return 'upcoming';
951 } else {
952 return 'past';
953 }
954 } catch ( Exception $e ) {
955 return 'past';
956 }
957 }
958
959 public function start_datetime_in_format( string $format, string $output_in_timezone_name ): string {
960 if ( empty( $this->start_datetime_utc ) ) {
961 return '';
962 }
963 $booking_start_datetime = OsTimeHelper::date_from_db( $this->start_datetime_utc );
964 $booking_start_datetime->setTimezone( new DateTimeZone( $output_in_timezone_name ) );
965 return $booking_start_datetime->format( $format );
966 }
967
968 public function is_start_date_and_time_set(): bool {
969 return ( $this->start_date != '' && $this->start_time != '' );
970 }
971
972 protected function get_time_left() {
973 $now_datetime = new OsWpDateTime( 'now' );
974 $booking_datetime = OsWpDateTime::os_createFromFormat( LATEPOINT_DATETIME_DB_FORMAT, $this->format_start_date_and_time() );
975 $css_class = 'left-days';
976
977 if ( $booking_datetime ) {
978 $diff = $now_datetime->diff( $booking_datetime );
979 if ( $diff->d > 0 || $diff->m > 0 || $diff->y > 0 ) {
980 $left = $diff->format( '%a ' . __( 'days', 'latepoint' ) );
981 } else {
982 if ( $diff->h > 0 ) {
983 $css_class = 'left-hours';
984 $left = $diff->format( '%h ' . __( 'hours', 'latepoint' ) );
985 } else {
986 $css_class = 'left-minutes';
987 $left = $diff->format( '%i ' . __( 'minutes', 'latepoint' ) );
988 }
989 }
990 } else {
991 $left = 'n/a';
992 }
993
994 return '<span class="time-left ' . esc_attr( $css_class ) . '">' . esc_html( $left ) . '</span>';
995 }
996
997
998 protected function get_agent() {
999 if ( $this->agent_id ) {
1000 if ( ! isset( $this->agent ) || ( isset( $this->agent ) && ( $this->agent->id != $this->agent_id ) ) ) {
1001 $this->agent = new OsAgentModel( $this->agent_id );
1002 }
1003 } else {
1004 $this->agent = new OsAgentModel();
1005 }
1006
1007 return $this->agent;
1008 }
1009
1010 public function get_agent_full_name() {
1011 if ( $this->agent_id == LATEPOINT_ANY_AGENT ) {
1012 return __( 'Any Available Agent', 'latepoint' );
1013 } else {
1014 return $this->agent->full_name;
1015 }
1016 }
1017
1018
1019 public function get_location() {
1020 if ( $this->location_id ) {
1021 // if location has not been initialized yet, or location_id is different from the one initialized - init again
1022 if ( empty( $this->location ) || ( $this->location->id != $this->location_id ) ) {
1023 $this->location = new OsLocationModel( $this->location_id );
1024 }
1025 } else {
1026 $this->location = new OsLocationModel();
1027 }
1028
1029 return $this->location;
1030 }
1031
1032 protected function get_customer() {
1033 if ( $this->customer_id ) {
1034 if ( ! isset( $this->customer ) || ( isset( $this->customer ) && ( $this->customer->id != $this->customer_id ) ) ) {
1035 $this->customer = new OsCustomerModel( $this->customer_id );
1036 }
1037 } else {
1038 $this->customer = new OsCustomerModel();
1039 }
1040
1041 return $this->customer;
1042 }
1043
1044
1045 protected function get_service() {
1046 if ( $this->service_id ) {
1047 if ( ! isset( $this->service ) || ( isset( $this->service ) && ( $this->service->id != $this->service_id ) ) ) {
1048 $this->service = new OsServiceModel( $this->service_id );
1049 }
1050 } else {
1051 $this->service = new OsServiceModel();
1052 }
1053
1054 return $this->service;
1055 }
1056
1057 public function get_nice_start_date_in_timezone( string $timezone_name = '', $hide_year_if_current = false ): string {
1058 $datetime = $this->get_start_datetime( $timezone_name );
1059 return OsTimeHelper::format_to_nice_date( $datetime, $hide_year_if_current );
1060 }
1061
1062 public function get_nice_end_date_in_timezone( string $timezone_name = '', $hide_year_if_current = false ): string {
1063 $datetime = $this->get_end_datetime( $timezone_name );
1064 return OsTimeHelper::format_to_nice_date( $datetime, $hide_year_if_current );
1065 }
1066
1067 public function get_nice_start_time_in_timezone( string $timezone_name = '' ): string {
1068 $datetime = $this->get_start_datetime( $timezone_name );
1069 return OsTimeHelper::format_to_nice_time( $datetime );
1070 }
1071
1072 public function get_nice_end_time_in_timezone( string $timezone_name = '' ): string {
1073 $datetime = $this->get_end_datetime( $timezone_name );
1074 return OsTimeHelper::format_to_nice_time( $datetime );
1075 }
1076
1077 public function get_start_datetime_object( ?DateTimeZone $timezone = null ) {
1078 if ( empty( $timezone ) ) {
1079 $timezone = OsTimeHelper::get_wp_timezone();
1080 }
1081 if ( empty( $this->start_datetime_utc ) ) {
1082 // fix data, probably an older booking from the time when we didn't store UTC date
1083 $this->start_datetime_utc = $this->generate_start_datetime_in_db_format();
1084 }
1085 $booking_start_datetime = OsTimeHelper::date_from_db( $this->start_datetime_utc );
1086 if ( $booking_start_datetime ) {
1087 $booking_start_datetime->setTimezone( $timezone );
1088 } else {
1089 OsDebugHelper::log( 'Error generating start date and time for booking ID: ' . $this->id, 'corrupt_booking_data' );
1090 }
1091
1092 return $booking_start_datetime;
1093 }
1094
1095 public function get_end_datetime_object( ?DateTimeZone $timezone = null ) {
1096 if ( empty( $timezone ) ) {
1097 $timezone = OsTimeHelper::get_wp_timezone();
1098 }
1099 if ( empty( $this->end_datetime_utc ) ) {
1100 // fix data, probably an older booking from the time when we didn't store UTC date
1101 $this->end_datetime_utc = $this->generate_end_datetime_in_db_format();
1102 }
1103 $booking_end_datetime = OsTimeHelper::date_from_db( $this->end_datetime_utc );
1104 if ( $booking_end_datetime ) {
1105 $booking_end_datetime->setTimezone( $timezone );
1106 } else {
1107 OsDebugHelper::log( 'Error generating end date and time for booking ID: ' . $this->id, 'corrupt_booking_data' );
1108 }
1109
1110 return $booking_end_datetime;
1111 }
1112
1113 public function get_start_datetime( string $set_timezone = 'UTC' ): OsWpDateTime {
1114 try {
1115 // start_time and start_date is legacy stored in wordpress timezone
1116 $dateTime = new OsWpDateTime( $this->start_date . ' 00:00:00', OsTimeHelper::get_wp_timezone() );
1117 if ( $this->start_time > 0 ) {
1118 $dateTime->modify( '+' . $this->start_time . ' minutes' );
1119 }
1120 if ( $set_timezone ) {
1121 $dateTime->setTimezone( new DateTimeZone( $set_timezone ) );
1122 }
1123 return $dateTime;
1124 } catch ( Exception $e ) {
1125 return new OsWpDateTime( 'now' );
1126 }
1127 }
1128
1129 public function get_end_datetime( string $set_timezone = 'UTC' ): OsWpDateTime {
1130 try {
1131 // start_time and start_date is legacy stored in wordpress timezone
1132 $dateTime = new OsWpDateTime( $this->end_date . ' 00:00:00', OsTimeHelper::get_wp_timezone() );
1133 if ( $this->end_time > 0 ) {
1134 $dateTime->modify( '+' . $this->end_time . ' minutes' );
1135 }
1136 if ( $set_timezone ) {
1137 $dateTime->setTimezone( new DateTimeZone( $set_timezone ) );
1138 }
1139 return $dateTime;
1140 } catch ( Exception $e ) {
1141 return new OsWpDateTime( 'now' );
1142 }
1143 }
1144
1145 public function generate_start_datetime_in_db_format( string $timezone = 'UTC' ): string {
1146 $dateTime = $this->get_start_datetime( $timezone );
1147
1148 return $dateTime->format( LATEPOINT_DATETIME_DB_FORMAT );
1149 }
1150
1151
1152 public function generate_end_datetime_in_db_format( string $timezone = 'UTC' ): string {
1153 $dateTime = $this->get_end_datetime( $timezone );
1154
1155 return $dateTime->format( LATEPOINT_DATETIME_DB_FORMAT );
1156 }
1157
1158
1159 protected function before_save() {
1160 // TODO check for uniqueness
1161 if ( empty( $this->booking_code ) ) {
1162 $this->booking_code = strtoupper( OsUtilHelper::random_text( 'distinct', 7 ) );
1163 }
1164 if ( empty( $this->end_date ) ) {
1165 $this->end_date = $this->calculate_end_date();
1166 }
1167 if ( empty( $this->status ) ) {
1168 $this->status = $this->get_default_booking_status();
1169 }
1170 if ( empty( $this->total_attendees ) ) {
1171 $this->total_attendees = 1;
1172 }
1173 if ( empty( $this->duration ) && $this->service_id ) {
1174 $service = new OsServiceModel( $this->service_id );
1175 $this->duration = $service->duration;
1176 }
1177 }
1178
1179 public function get_default_booking_status() {
1180 return OsBookingHelper::get_default_booking_status( $this->service_id );
1181 }
1182
1183 public function update_status( $new_status ) {
1184 if ( $new_status == $this->status ) {
1185 return true;
1186 } else {
1187 if ( ! in_array( $new_status, array_keys( OsBookingHelper::get_statuses_list() ) ) ) {
1188 $this->add_error( 'invalid_booking_status', 'Invalid booking status' );
1189
1190 return false;
1191 }
1192 $old_booking = clone $this;
1193 $this->status = $new_status;
1194 $result = $this->update_attributes( [ 'status' => $new_status ] );
1195 if ( $result ) {
1196 do_action( 'latepoint_booking_updated', $this, $old_booking );
1197
1198 return true;
1199 } else {
1200 return false;
1201 }
1202 }
1203 }
1204
1205 public function convert_start_datetime_into_server_timezone( string $input_timezone, bool $set_as_customer_timezone = true ) {
1206 $this->server_timezone = OsTimeHelper::get_wp_timezone_name();
1207 if ( $set_as_customer_timezone ) {
1208 $this->customer_timezone = $input_timezone;
1209 }
1210 if ( $this->is_start_date_and_time_set() && $this->server_timezone != $input_timezone ) {
1211
1212 try {
1213 // convert from submitted customer timezone into WP timezone
1214 $start_datetime = new OsWpDateTime( $this->start_date . ' 00:00:00', new DateTimeZone( $input_timezone ) );
1215 if ( $this->start_time > 0 ) {
1216 $start_datetime->modify( '+' . $this->start_time . ' minutes' );
1217 }
1218 $start_datetime->setTimezone( OsTimeHelper::get_wp_timezone() );
1219 $this->start_date = $start_datetime->format( 'Y-m-d' );
1220 $this->start_time = OsTimeHelper::convert_datetime_to_minutes( $start_datetime );
1221
1222 } catch ( Exception $e ) {
1223 }
1224 }
1225 }
1226
1227 public function save_avatar( $image_id = false ) {
1228 if ( ( false === $image_id ) && $this->image_id ) {
1229 $image_id = $this->image_id;
1230 }
1231 if ( $image_id && $this->post_id ) {
1232 set_post_thumbnail( $this->post_id, $image_id );
1233 $this->image_id = $image_id;
1234 }
1235
1236 return $this->image_id;
1237 }
1238
1239
1240 protected function allowed_params( $role = 'admin' ) {
1241 $allowed_params = array(
1242 'service_id',
1243 'booking_code',
1244 'agent_id',
1245 'customer_id',
1246 'location_id',
1247 'start_date',
1248 'end_date',
1249 'start_time',
1250 'end_time',
1251 'start_datetime_utc',
1252 'end_datetime_utc',
1253 'buffer_before',
1254 'duration',
1255 'buffer_after',
1256 'total_attendees',
1257 'total_attendees_sum',
1258 'total_customers',
1259 'cart_item_id',
1260 'order_item_id',
1261 'status',
1262 'form_id',
1263 'server_timezone',
1264 'customer_timezone',
1265 'generate_recurrent_sequence',
1266 'recurrence_id',
1267 );
1268
1269 return $allowed_params;
1270 }
1271
1272
1273 protected function params_to_save( $role = 'admin' ) {
1274 $params_to_save = array(
1275 'service_id',
1276 'booking_code',
1277 'agent_id',
1278 'customer_id',
1279 'location_id',
1280 'start_date',
1281 'end_date',
1282 'start_time',
1283 'end_time',
1284 'start_datetime_utc',
1285 'end_datetime_utc',
1286 'duration',
1287 'buffer_before',
1288 'buffer_after',
1289 'total_attendees',
1290 'status',
1291 'order_item_id',
1292 'server_timezone',
1293 'customer_timezone',
1294 'recurrence_id',
1295 );
1296
1297 return $params_to_save;
1298 }
1299
1300
1301 protected function properties_to_validate() {
1302 $validations = array(
1303 'order_item_id' => array( 'presence' ),
1304 'service_id' => array( 'presence' ),
1305 'agent_id' => array( 'presence' ),
1306 'location_id' => array( 'presence' ),
1307 'customer_id' => array( 'presence' ),
1308 'start_date' => array( 'presence' ),
1309 'end_date' => array( 'presence' ),
1310 'status' => array( 'presence' ),
1311 );
1312
1313 return $validations;
1314 }
1315 }
1316