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