id = $id;
}
public static function instance( $appointment ) {
if ( $appointment instanceof SSA_Appointment_Object ) {
return $appointment;
}
if ( is_array( $appointment ) ) {
$appointment = new SSA_Appointment_Object( $appointment['id'] );
return $appointment;
}
$appointment = new SSA_Appointment_Object( $appointment );
return $appointment;
}
/**
* Factory function to create from a pre-loaded data array.
* Bypasses lazy loading — avoids N+1 queries when building collections.
*
* @param array $data Full appointment data array (must include 'id').
* @param int $recursive_level The recursive level of the pre-loaded data (default 0 for flat query results).
* @return SSA_Appointment_Object
*/
public static function from_data( array $data, int $recursive_level = 0 ): self {
$obj = new self( $data['id'] );
$obj->data = $data;
$obj->recursive_fetched = $recursive_level;
// Pre-populate the request cache so any new SSA_Appointment_Object( $id )
// created later (e.g. inside template-var filters) skips the DB entirely.
self::$data_cache[ $data['id'] ] = array(
'data' => $data,
'level' => $recursive_level,
);
return $obj;
}
/**
* Factory function to create with explicit data
*
* @param array $data
* @return SSA_Appointment_Object
* @author
**/
public static function create( SSA_Appointment_Type_Object $appointment_type, array $data ) {
$appointment_object = new SSA_Appointment_Object( 'transient' );
$appointment_object->appointment_type = $appointment_type;
$data['appointment_type_id'] = $appointment_type->id;
$appointment_object->data = $data;
return $appointment_object;
}
/**
* Magic getter for our object.
*
* @since 0.0.0
*
* @param string $field Field to get.
* @throws Exception Throws an exception if the field is invalid.
* @return mixed Value of the field.
*/
public function __get( $field ) {
if ( empty( $this->data ) && $field !== 'id' ) {
$this->get();
}
switch ( $field ) {
case 'id':
case 'data':
return $this->$field;
case 'start_date_datetime':
case 'end_date_datetime':
$date_time = ssa_datetime( $this->data[str_replace('_datetime', '', $field)] );
return $date_time;
case 'start_date_timestamp':
case 'end_date_timestamp':
return ssa_gmtstrtotime( $this->data[str_replace('_timestamp', '', $field)] );
case 'web_meeting_url':
if ( isset( $this->data[$field] ) ) {
return trim( $this->data[$field] );
}
case 'web_meeting_id':
if ( isset( $this->data[$field] ) ) {
return trim( $this->data[$field] );
}
case 'web_meeting_password':
if ( isset( $this->data[$field] ) ) {
return trim( $this->data[$field] );
}
default:
if ( isset( $this->data[$field] ) ) {
return $this->data[$field];
}
throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field );
}
}
public function refresh( $recursive = -1 ) {
$this->recursive_fetched = -2;
$this->get( $recursive );
}
public function get( $recursive = -1 ) {
if ( $recursive > $this->recursive_fetched ) {
// Read-only check of the pre-load cache (written exclusively by from_data()).
// from_data() is only called during bulk ICS fetches, so for every other code
// path in the app this cache is empty and this check is a no-op.
if ( isset( self::$data_cache[ $this->id ] ) && $recursive <= self::$data_cache[ $this->id ]['level'] ) {
$this->data = array_merge( $this->data ?? array(), self::$data_cache[ $this->id ]['data'] );
$this->recursive_fetched = self::$data_cache[ $this->id ]['level'];
return;
}
if ( null === $this->data ) {
$this->data = array();
}
$model_data = ssa()->appointment_model->get( $this->id, $recursive );
if ( empty( $model_data['id'] ) ) {
if ( ! isset( $model_data['id'] ) || ! in_array( $model_data['id'], array( '0', 0 ), true ) ) {
throw new Exception( 'Appointment ID ' . $this->id . ' not found' );
}
}
$this->data = array_merge( $this->data, $model_data );
$this->recursive_fetched = $recursive;
// Intentionally NOT writing back to $data_cache here.
// The cache is exclusively managed by from_data() for bulk ICS pre-loading.
}
}
public function get_appointment_period() {
$start_date = $this->__get( 'start_date' );
$end_date = $this->__get( 'end_date' );
if ( $end_date < $start_date ) {
ssa_debug_log( __CLASS__ . ' ' . __FUNCTION__ . '():' . __LINE__ );
ssa_debug_log( 'The ending datepoint must be greater or equal to the starting datepoint in appointment ID ' . $this->id, 10 );
return new Period(
$start_date,
$start_date
);
}
return new Period(
$start_date,
$end_date
);
}
public function get_buffer_before_period() {
$buffer_before = $this->get_appointment_type()->buffer_before;
if ( empty( $buffer_before ) ) {
return false;
}
$start_date = ssa_datetime( $this->__get( 'start_date' ) );
$calculated_period = new Period( $start_date->sub( new DateInterval( 'PT'.absint( $buffer_before ).'M' ) ), $start_date );
return $calculated_period;
}
public function get_buffer_after_period() {
$buffer_after = $this->get_appointment_type()->buffer_after;
if ( empty( $buffer_after ) ) {
return false;
}
$end_date = ssa_datetime( $this->__get( 'end_date' ) );
$calculated_period = new Period( $end_date, $end_date->add( new DateInterval( 'PT'.absint( $buffer_after ).'M' ) ) );
return $calculated_period;
}
public function get_buffered_period() {
$period = $this->get_appointment_period();
$buffer_before_period = $this->get_buffer_before_period();
$buffer_after_period = $this->get_buffer_after_period();
if ( false === $buffer_before_period && false === $buffer_after_period ) {
return $period;
}
if ( false !== $buffer_before_period ) {
if ( $buffer_before_period->getStartDate() < $period->getStartDate() ) {
$period = new Period( $buffer_before_period->getStartDate(), $period->getEndDate() );
}
// TODO: else { Log error (we should never end up here), but at least we have prevented a fatal error }
}
if ( false !== $buffer_after_period ) {
if ( $period->getEndDate() < $buffer_after_period->getEndDate() ) {
$period = new Period( $period->getStartDate(), $buffer_after_period->getEndDate() );
}
// TODO: else { Log error (we should never end up here), but at least we have prevented a fatal error }
}
return $period;
}
public function get_buffered_query_period() {
$period = $this->get_appointment_period();
$buffer_before = $this->get_appointment_type()->buffer_before;
$buffer_after = $this->get_appointment_type()->buffer_after;
$buffer_max = max( $buffer_before, $buffer_after );
if ( empty( $buffer_max ) ) {
return $period;
}
$start_date = ssa_datetime($this->__get('start_date'));
$end_date = ssa_datetime($this->__get('end_date'));
$period = new Period(
$start_date->sub(new DateInterval('PT' . absint($buffer_max) . 'M')),
$end_date->add(new DateInterval('PT' . absint($buffer_max) . 'M'))
);
return $period;
}
public function get_data( $recursive = -1, $fetch_fields = array() ) {
$this->get( $recursive );
if ( $recursive >= 0 ) {
if ( !isset( $fetch_fields['public_edit_url'] ) ) {
$fetch_fields['public_edit_url'] = true;
}
if ( !isset( $fetch_fields['date_timezone'] ) ) {
$fetch_fields['date_timezone'] = true;
}
}
if ( !empty( $fetch_fields ) ) {
$this->fetch_fields( $fetch_fields );
}
return $this->data;
}
public function fetch_fields( $fetch_fields = array() ) {
if ( !is_array( $fetch_fields ) ) {
throw new SSA_Exception("$fetch_fields must be an array", 1);
}
foreach ( $fetch_fields as $fetch_field => $fetch_options ) {
if ( is_int( $fetch_field ) ) {
$fetch_field = $fetch_options;
$fetch_options = array();
}
$method_name = 'fetch_'.$fetch_field;
if ( !method_exists( $this, $method_name ) ) {
throw new SSA_Exception(__CLASS__ . "->" . $method_name . "() not implemented", 1);
}
$this->$method_name( $fetch_options );
}
}
public function fetch_add_to_calendar_links( $atts = array() ) {
if ( !is_array( $atts ) ) {
$atts = array();
}
$atts = shortcode_atts( array(
'customer' => true,
), $atts );
if ( !empty( $atts['customer'] ) ) {
$this->data['ics']['customer'] = $this->get_ics_download_url( 'customer' );
$this->data['gcal']['customer'] = $this->get_gcal_add_link( 'customer' );
}
}
public function fetch_date_timezone( $atts = array() ) {
$this->data['date_timezone'] = $this->get_date_timezone();
}
public function fetch_public_edit_url( $atts = array() ) {
$this->data['public_edit_url'] = $this->get_public_edit_url();
}
public function get_appointment_type() {
if ( ! empty( $this->appointment_type ) ) {
return $this->appointment_type;
}
$this->appointment_type = new SSA_Appointment_Type_Object( $this->appointment_type_id );
return $this->appointment_type;
}
public function get_label_id() {
return ssa()->appointment_type_model->get_label_id_for_appointment_type_id( $this->appointment_type_id );
}
public function get_staff_members() {
if ( ! empty( $this->staff_members ) ) {
return $this->staff_members;
}
$is_enabled = ssa()->settings_installed->is_enabled( 'staff' );
if ( ! $is_enabled ) {
return;
}
$staff_ids = ssa()->staff_appointment_model->get_staff_ids( $this->id );
if ( empty( $staff_ids ) ) {
$this->staff_members = null;
return;
}
$staff_members = array();
foreach ($staff_ids as $staff_id) {
$staff_members[] = new SSA_Staff_Object( $staff_id );
}
$this->staff_members = $staff_members;
return $this->staff_members;
}
public function get_date_timezone( $for_type = '', $for_id = '' ) {
if ( $for_type === 'staff' ) {
// TODO: Customize for staff ID
// TODO: Customize for location ID
// TODO: Customize for customer
// TODO: Customize for admin
} else {
$settings = ssa()->settings->get();
$date_timezone = new DateTimeZone( $settings['global']['timezone_string'] );
}
return $date_timezone;
}
public function get_customer_name() {
$customer_information = $this->__get( 'customer_information' );
$customer_name = '';
if ( ! empty( $customer_information['name'] ) ) {
$customer_name = $customer_information['name'];
} elseif ( ! empty( $customer_information['Name'] ) ) {
$customer_name = $customer_information['Name'];
}
return $customer_name;
}
public function get_customer_email() {
$customer_information = $this->__get( 'customer_information' );
$customer_email = '';
if ( ! empty( $customer_information['email'] ) ) {
$customer_email = $customer_information['email'];
} elseif ( ! empty( $customer_information['Email'] ) ) {
$customer_email = $customer_information['Email'];
}
return $customer_email;
}
/**
* Given an appointment, get the customer timezone string.
*
* @since 4.9.1
*
* @return string
*/
public function get_customer_timezone_string() {
$customer_timezone = $this->__get( 'customer_timezone' );
return $customer_timezone;
}
/**
* Given an appointment, get the customer timezone object.
*
* @since 4.9.1
*
* @return DateTimeZone
*/
public function get_customer_timezone() {
$customer_timezone = $this->get_customer_timezone_string();
if ( empty( $customer_timezone ) ) {
return null;
}
return SSA_Utils::safe_timezone( $customer_timezone );
}
/**
* Given a specific recipient type, get's the right twig template to
* populate the event title, and parses the content.
*
* @since 5.4.0
*
* @param SSA_Recipient $recipient The recipient object.
* @return string the event title.
*/
public function get_calendar_event_title( SSA_Recipient $recipient ) {
$event_type = $this->get_calendar_event_type( $recipient );
$calendar_event = new SSA_Calendar_Events_Object( $event_type );
$title = $calendar_event->get_calendar_event_content( 'title', $this->id, true );
// if appointment is canceled, prefix with "Canceled: ".
if ( $this->is_individual_appointment() && $this->is_canceled() ) {
$title = __('Canceled', 'simply-schedule-appointments' ) . ': ' . $title;
}
if ( $this->is_group_event() && $this->is_group_canceled() ) {
$title = __('Canceled', 'simply-schedule-appointments' ) . ': ' . $title;
}
return $title;
}
/**
* Given a specific recipient type, get's the right twig template to
* populate the event location, and parses the content.
*
* @since 5.4.0
*
* @param SSA_Recipient $recipient The recipient object.
* @return string the event location.
*/
public function get_calendar_event_location( SSA_Recipient $recipient ) {
$event_type = $this->get_calendar_event_type( $recipient );
$calendar_event = new SSA_Calendar_Events_Object( $event_type );
$location = $calendar_event->get_calendar_event_content( 'location', $this->id, true );
return $location;
}
/**
* Given a specific recipient type, get's the right twig template to
* populate the event description, and parses the content.
*
* @since 5.4.0
*
* @param SSA_Recipient $recipient The recipient object.
* @return string the event description.
*/
public function get_calendar_event_description( SSA_Recipient $recipient ) {
$event_type = $this->get_calendar_event_type( $recipient );
$calendar_event = new SSA_Calendar_Events_Object( $event_type );
$description = $calendar_event->get_calendar_event_content( 'details', $this->id );
$clear_map = array(
'
' => "\r\n",
'
' => "\r\n",
'
' => "\r\n",
'
' => "\r\n",
);
// Remove all html tags and turn paragraphs or
into line breaks.
// Required to avoid html issues with Google Calendar and other calendar apps.
$description = str_replace( array_keys( $clear_map ), array_values( $clear_map ), $description );
$description = strip_tags( $description, '' );
return $description;
}
/**
* Returns the event title for a specific template.
*
* @since 5.4.0
*
* @param string $template The template name.
* @return string The event title.
*/
public function get_title( $template ) {
if ( 'customer' === $template ) {
$recipient = SSA_Recipient_Customer::create();
}
if ('staff' === $template ) {
$recipient = SSA_Recipient_Staff::create();
}
return $this->get_calendar_event_title( $recipient );
}
/**
* Returns the event location for a specific template.
*
* @since 5.4.0
*
* @param string $template The template name.
* @return string The event location.
*/
public function get_location( $template ) {
if ( 'customer' === $template ) {
$recipient = SSA_Recipient_Customer::create();
}
if ( 'staff' === $template ) {
$recipient = SSA_Recipient_Staff::create();
}
return $this->get_calendar_event_location( $recipient );
}
public function get_description( $template, $eol = "\r\n" ) {
if ( 'customer' === $template ) {
$recipient = SSA_Recipient_Customer::create();
}
if ( 'staff' === $template ) {
$recipient = SSA_Recipient_Staff::create();
}
return $this->get_calendar_event_description( $recipient );
}
/**
* Returns a list of attendees for the this appointment.
*
* @since 5.6.0
*
* @return array The list of attendees.
*/
public function get_attendees() {
$attendees = array();
// Add customer if it's a shared calendar event.
$shared_calendar_event = $this->get_appointment_type()->shared_calendar_event;
if(!empty($shared_calendar_event)){
$new_attendee = array(
'email' => $this->get_customer_email(),
'name' => $this->get_customer_name(),
);
if ( ! empty( $new_attendee['email'] ) && ! empty( $new_attendee['name'] ) ) {
// avoids edge cases with gravity/formidable forms that don't have a proper name/email field
$attendees[] = $new_attendee;
}
}
// Add team members if any is set to the appointment.
$staff_ids = ssa()->staff_appointment_model->get_staff_ids( $this->id );
if ( ! empty( $staff_ids ) ) {
foreach ( $staff_ids as $staff_id ) {
$staff = new SSA_Staff_Object( $staff_id );
$attendees[] = array(
'email' => $staff->email,
'name' => $staff->display_name,
);
}
}
/**
* Filters the list of attendees for an appointment.
*
* @since 5.6.0
*
* @param array $attendees The list of attendees.
* @param int $appointment_id The appointment ID.
*/
$attendees = apply_filters( 'ssa/appointment/attendees', $attendees, $this->id ); //@codingStandardsIgnoreLine (WordPress doesn't like hook names with slashes).
return $attendees;
}
public function get_calendar_id() {
$group = $this->get_group_appointment();
if ( ! empty( $group ) ) {
return $group->__get( 'google_calendar_id' );
}
return $this->__get( 'google_calendar_id' );
}
public function get_calendar_event_id() {
$group = $this->get_group_appointment();
if ( ! empty( $group ) ) {
return $group->google_calendar_event_id;
}
return $this->__get( 'google_calendar_event_id' );
}
/**
* Set an SSA_Ics_Exporter instance and define the template.
*
* @param string $template The template name.
* @return SSA_Ics_Exporter
*/
public function get_ics_exporter( $template = 'customer' ) {
$ics_exporter = new SSA_Ics_Exporter();
$ics_exporter->template = $template;
return $ics_exporter;
}
/**
* Get .ics file contents and headers.
*
* @param string $template The template name.
* @return array The .ics file contents and headers.
*/
public function get_ics( $template = 'customer' ) {
$ics_exporter = $this->get_ics_exporter( $template );
$ics = $ics_exporter->get_ics_for_appointment( $this );
return $ics;
}
/**
* Return the download url for the .ics file.
*
* @since 5.4.4
*
* @param string $type The user type.
*
* @return string The download url.
*/
public function get_ics_download_url( $type = 'customer' ) {
// Get the rest api root url.
$base = ssa()->appointment_model->get_ics_endpoints_base();
$url = $base . $this->id . '/ics/download/' . $type;
return $url;
}
public function get_gcal_add_link( $template = 'customer' ) {
$link = ssa()->gcal_exporter->get_add_link_from_appointment( $this, $template );
return $link;
}
public function is_all_day() {
return false;
}
public function get_public_edit_url() {
$url = ssa()->appointment_model->get_public_edit_url( $this->id );
return $url;
}
public function get_admin_edit_url() {
$url = ssa()->appointment_model->get_admin_edit_url( $this->id );
return $url;
}
public function is_unavailable() {
return in_array( $this->__get( 'status' ), SSA_Appointment_Model::get_unavailable_statuses() );
}
public function is_available() {
return ! $this->is_unavailable();
}
public function is_reserved() {
return in_array( $this->__get( 'status' ), SSA_Appointment_Model::get_reserved_statuses() );
}
public function is_booked() {
return in_array( $this->__get( 'status' ), SSA_Appointment_Model::get_booked_statuses() );
}
public function is_canceled() {
return in_array( $this->__get( 'status' ), SSA_Appointment_Model::get_canceled_statuses() );
}
public function is_group_canceled() {
if ( ! $this->is_group_event() ) {
return null;
}
$group_id = $this->__get( 'group_id' );
if ( empty( $group_id ) ) {
return false;
}
$appointment_arrays = ssa()->appointment_model->query( array(
'number' => -1,
'group_id' => $group_id,
) );
if ( empty( $appointment_arrays ) ) {
return false;
}
$is_group_canceled = true;
foreach ($appointment_arrays as $appointment_array) {
if ( in_array( $appointment_array['status'], SSA_Appointment_Model::get_booked_statuses() ) ) {
return false;
}
}
return $is_group_canceled;
}
public function get_group_appointment() {
if ( ! $this->is_group_event() ) {
return;
}
$group_id = $this->__get( 'group_id' );
if ( empty( $group_id ) ) {
return;
}
$group = new SSA_Appointment_Object( $group_id );
return $group;
}
public function query_group_appointments() {
if ( ! $this->is_group_event() ) {
return;
}
$group_id = $this->__get( 'group_id' );
if ( empty( $group_id ) ) {
return;
}
$groups = ssa()->appointment_model->query( array(
'number' => -1,
'group_id' => $group_id,
) );
$group_objects = array();
foreach ($groups as $group) {
$group_objects[] = new SSA_Appointment_Object( $group['id'] );
}
return $group_objects;
}
public function is_group_event() {
$capacity_type = $this->get_appointment_type()->capacity_type;
return ( $capacity_type === 'group' );
}
public function is_group_parent() {
if ( ! $this->is_group_event() ) {
return false;
}
$group_id = $this->__get( 'group_id' );
if ( $group_id == $this->id ) {
return true;
}
return false;
}
public function is_individual_appointment() {
$capacity_type = $this->get_appointment_type()->capacity_type;
return ( $capacity_type === 'individual' );
}
/**
* Given a specific recipient type, returns the calendar event type slug.
*
* @since 5.4.0
*
* @param SSA_Recipient_Admin|SSA_Recipient_Customer|SSA_Recipient_Shared|SSA_Recipient_Staff $recipient the recipient class.
* @return string|boolean the event type slug.
*/
public function get_calendar_event_type( $recipient ) {
if (
! $recipient instanceof SSA_Recipient_Admin &&
! $recipient instanceof SSA_Recipient_Customer &&
! $recipient instanceof SSA_Recipient_Shared &&
! $recipient instanceof SSA_Recipient_Staff
) {
return null;
}
if ( $recipient->is_customer() && $recipient->is_business() ) {
if ( $this->is_group_event() ) {
return 'group_shared';
} elseif ( $this->is_individual_appointment() ) {
return 'individual_shared';
}
} elseif ( $recipient->is_customer() ) {
return 'customer';
} elseif ( $recipient->is_business() ) {
if ( $this->is_group_event() ) {
return 'group_admin';
} elseif ( $this->is_individual_appointment() ) {
return 'individual_admin';
}
}
}
public function format_webhook_payload( $payload ) {
$payload['appointment'] = shortcode_atts( array(
'id' => '',
'appointment_type_id' => '',
'appointment_type_slug' => '',
'customer_id' => '',
'customer_information' => array(),
'post_information' => array(),
'customer_timezone' => '',
'start_date' => '',
'end_date' => '',
'status' => '',
'date_created' => '',
'date_modified' => '',
'public_edit_url' => '',
'payment_method' => '',
'web_meeting_url' => '',
'web_meeting_password' => '',
), $payload['appointment'] );
$dates_to_localize = array(
'start_date',
'end_date',
'date_created',
'date_modified',
);
if ( empty( $payload['appointment']['appointment_type_slug'] ) && !empty( $payload['appointment']['appointment_type_id'] ) ) {
$appointment_type_object = $this->get_appointment_type();
$payload['appointment']['appointment_type_slug'] = $appointment_type_object->slug;
}
if ( empty( $payload['appointment']['appointment_type_title'] ) && !empty( $payload['appointment']['appointment_type_id'] ) ) {
$appointment_type_object = $this->get_appointment_type();
$payload['appointment']['appointment_type_title'] = $appointment_type_object->title;
}
$settings_global = ssa()->settings->get()['global'];
foreach ( $dates_to_localize as $key ) {
if ( empty( $payload['appointment'][$key] ) ) {
continue;
}
/* Raw */
$payload['appointment']['local_time_for']['appointment_type']['raw'][$key] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'Y-m-d H:i:s' );
$payload['appointment']['local_time_for']['appointment_type']['raw_parts'][$key]['date'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'Y-m-d' );
$payload['appointment']['local_time_for']['appointment_type']['raw_parts'][$key]['time'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'H:i:s' );
$payload['appointment']['local_time_for']['appointment_type']['raw_parts'][$key]['timezone'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'e' );
$payload['appointment']['local_time_for']['appointment_type']['raw_parts'][$key]['timezone_offset'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'O' );
/* Formatted */
$payload['appointment']['local_time_for']['appointment_type']['formatted'][$key] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( $settings_global['date_format'].' '.$settings_global['time_format']. ' T' );
$payload['appointment']['local_time_for']['appointment_type']['formatted_parts'][$key]['date'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( $settings_global['date_format'] );
$payload['appointment']['local_time_for']['appointment_type']['formatted_parts'][$key]['time'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( $settings_global['time_format'] );
$payload['appointment']['local_time_for']['appointment_type']['formatted_parts'][$key]['timezone'] = ssa()->utils->get_datetime_as_local_datetime( $payload['appointment'][$key], $payload['appointment']['appointment_type_id'] )->format( 'T' );
}
if( ! empty( $payload['meta']['booking_url'] ) ) {
$payload['post_information']['booking_url'] = $payload['meta']['booking_url'];
}
if( ! empty( $payload['meta']['booking_title'] ) ) {
$payload['post_information']['booking_title'] = $payload['meta']['booking_title'];
}
if( ! empty( $payload['meta']['booking_post_id'] ) ) {
$payload['post_information']['booking_post_id'] = $payload['meta']['booking_post_id'];
}
// Memberpress integration
if( ! empty( $payload['meta']['mepr_membership_id'] ) && class_exists( 'SSA_Mepr_Membership' ) && class_exists( 'MeprProduct' ) ) {
$membership = new SSA_Mepr_Membership( $payload['meta']['mepr_membership_id'] );
if ( $membership->exists() ) {
$payload['mepr_membership'] = array(
'id' => $membership->get_product_id(),
'title' => $membership->get_title()
);
}
unset( $payload['meta']['mepr_membership_id'] );
}
return $payload;
}
public function get_webhook_payload( $action ) {
$action_noun = '';
$action_verb = '';
if ( false !== strpos( $action, '_' ) ) {
$action_noun = explode( '_', $action )[0];
$action_verb = explode( '_', $action )[1];
}
$payload = array(
'action' => $action,
'action_noun' => $action_noun,
'action_verb' => $action_verb,
'appointment' => $this->get_data( 0 ),
'team_members'=> $this->get_staff_members_to_webhook(),
'meta' => ssa()->appointment_model->get_metas( $this->id ),
);
$payload = $this->format_webhook_payload( $payload );
return $payload;
}
public function get_staff_members_to_webhook() {
$staff = $this->get_staff_members();
if ( empty($staff) ) {
return [];
}
$output = [];
for ($i=0 ; $i $staff[$i]->id,
'wp_user_id' => $staff[$i]->user_id,
'name' => $staff[$i]->name ? $staff[$i]->name : $staff[$i]->get_name(),
'display_name' => $staff[$i]->get_name(),
'email' => $staff[$i]->get_email(),
];
}
return $output;
}
public function cancel( $metas=array() ) {
if ( $this->is_canceled() ) return;
$this->status = 'canceled';
ssa()->appointment_model->update( $this->id, array(
'status' => $this->status,
));
if ( ! empty( $metas['cancelation_note'] ) ) {
$meta_keys_and_values = array();
$meta_keys_and_values['cancelation_note'] = esc_attr( trim( $metas['cancelation_note'] ) );
ssa()->appointment_meta_model->bulk_meta_update( $this->id, $meta_keys_and_values );
}
}
/**
* Watch out! This method does not check if the appointment type has the opt-in notifications enabled.
*/
public function customer_has_not_opted_in() {
$meta = ssa()->appointment_model->get_metas( $this->id );
return empty( $meta['opt_in_notifications'] );
}
}