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