619 lines
20 KiB
PHP
619 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* Simply Schedule Appointments Availability Query.
|
|
*
|
|
* @since 3.6.2
|
|
* @package Simply_Schedule_Appointments
|
|
*/
|
|
|
|
use League\Period\Period;
|
|
|
|
/**
|
|
* Simply Schedule Appointments Availability Query.
|
|
*
|
|
* @since 3.6.2
|
|
*/
|
|
class SSA_Availability_Query {
|
|
/**
|
|
* Parent plugin class.
|
|
*
|
|
* @since 3.6.2
|
|
*
|
|
* @var Simply_Schedule_Appointments
|
|
*/
|
|
|
|
protected $period;
|
|
|
|
protected $appointment_type;
|
|
|
|
protected $args;
|
|
|
|
const args = array(
|
|
'staff_ids_all_required' => array(),
|
|
'staff_ids_any_required' => array(),
|
|
'resources_required' => array(),
|
|
// 'staff_required_count' => 1,
|
|
|
|
// 'location_ids_all_required' => -1,
|
|
// 'location_ids_some_required' => -1,
|
|
// 'any_location_count' => -1,
|
|
|
|
// 'resource_ids_all_required' => -1,
|
|
// 'resource_ids_some_required' => -1,
|
|
// 'any_resource_count' => -1,
|
|
|
|
'cache_level_read' => 1,
|
|
'cache_level_write' => 1,
|
|
|
|
'type' => '',
|
|
'subtype' => '',
|
|
|
|
'appointment_type' => true,
|
|
'appointment_type.min_booking_notice' => true,
|
|
'appointment_type.max_booking_notice' => true,
|
|
'appointment_type.availability_window' => true,
|
|
'appointment_type.max_per_day' => true,
|
|
'appointment_type.separate_appointment_type_availability' => true,
|
|
|
|
// 'appointment_type.booking_window' => true,
|
|
// 'appointment_type.buffers' => true,
|
|
// 'appointment_type.capacity' => true,
|
|
|
|
'appointment_type.appointments' => true,
|
|
'appointment_type.appointments.booked' => true,
|
|
'appointment_type.appointments.pending_form' => true,
|
|
'appointment_type.appointments.pending_payment' => true,
|
|
|
|
'blackout_dates' => true,
|
|
'google_calendar' => true,
|
|
'staff' => true,
|
|
|
|
// MemberPress integration
|
|
'mepr_membership_id' => 0,
|
|
'user_id' => 0,
|
|
|
|
'resources' => true,
|
|
|
|
'excluded_appointment_ids' => array(),
|
|
);
|
|
|
|
|
|
public static function get_default_args() {
|
|
$args = self::args;
|
|
unset( $args['cache_level_write'] );
|
|
unset( $args['cache_level_read'] );
|
|
|
|
return $args;
|
|
}
|
|
|
|
protected $schedule;
|
|
protected $staff_schedules;
|
|
|
|
protected $_queried_appointments;
|
|
protected $_booked_group_appointments;
|
|
|
|
public static function create( SSA_Appointment_Type_Object $appointment_type, Period $period, $args = array() ) {
|
|
$instance = new self( $appointment_type, $period, $args );
|
|
return $instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @since 3.6.2
|
|
*
|
|
* @param Simply_Schedule_Appointments $plugin Main plugin object.
|
|
*/
|
|
public function __construct(
|
|
SSA_Appointment_Type_Object $appointment_type, Period $period, $args = array()
|
|
) {
|
|
$this->period = $period;
|
|
$this->args = array_merge( self::args, $args );
|
|
|
|
$this->appointment_type = $appointment_type;
|
|
}
|
|
|
|
public function get_query_args() {
|
|
return array(
|
|
'period' => $this->period,
|
|
'args' => $this->args,
|
|
'appointment_type_id' => $this->appointment_type->id,
|
|
'query_hash' => $this->get_query_hash(),
|
|
);
|
|
}
|
|
|
|
public function get_query_hash() {
|
|
$args = $this->args;
|
|
unset( $args['cache_level_write'] );
|
|
unset( $args['cache_level_read'] );
|
|
|
|
$json = json_encode( array(
|
|
'period' => $this->period,
|
|
'args' => $args,
|
|
'appointment_type' => $this->appointment_type->id,
|
|
) );
|
|
|
|
return ssa_int_hash( $json );
|
|
}
|
|
|
|
public function get_schedule_for_staff_id( int $staff_id, $args = array() ) {
|
|
if ( ! empty( $this->staff_schedules[$staff_id] ) ) {
|
|
$this->staff_schedules[$staff_id];
|
|
}
|
|
|
|
$staff = new SSA_Staff_Object( $staff_id );
|
|
$this->staff_schedules[$staff_id] = $staff->get_schedule( $this->appointment_type, $this->period, $args );
|
|
return $this->staff_schedules[$staff_id];
|
|
}
|
|
|
|
public function get_schedule( $args = array() ) {
|
|
if ( null !== $this->schedule ) {
|
|
return $this->schedule;
|
|
}
|
|
|
|
$args = array_merge( $this->args, $args );
|
|
|
|
$chunk_interval = new DateInterval( 'P7D' );
|
|
$maximum_chunk_period = $this->period->withDurationAfterStart( $chunk_interval );
|
|
if ( $this->period->durationGreaterThan( $maximum_chunk_period ) ) {
|
|
$schedule = new SSA_Availability_Schedule();
|
|
foreach ( $this->period->split( $chunk_interval ) as $chunk_period ) {
|
|
$chunk_query = new SSA_Availability_Query(
|
|
$this->appointment_type,
|
|
$chunk_period,
|
|
$this->args
|
|
);
|
|
$chunk_schedule = $chunk_query->get_schedule( $args );
|
|
$schedule = $schedule->pushmerge( $chunk_schedule->get_blocks() );
|
|
}
|
|
|
|
$this->schedule = $schedule;
|
|
return $this->schedule;
|
|
}
|
|
|
|
$query_period = $this->period;
|
|
$this->period = new Period(
|
|
$this->period->getStartDate()->sub($this->appointment_type->get_buffered_duration_interval() ),
|
|
$this->period->getEndDate()->add( $this->appointment_type->get_buffered_duration_interval() )
|
|
);
|
|
$this->schedule = $this->appointment_type->get_schedule( $this->period, $args );
|
|
|
|
if ( ! empty( $args['blackout_dates'] ) ) {
|
|
$blackout_dates_schedule = ssa()->blackout_dates->get_schedule( $this->appointment_type, $this->period, $args );
|
|
|
|
if ( null !== $blackout_dates_schedule ) {
|
|
$this->schedule = $this->schedule->merge_min( $blackout_dates_schedule );
|
|
}
|
|
}
|
|
|
|
if ( empty( $this->appointment_type ) ) {
|
|
return $this->schedule;
|
|
}
|
|
|
|
if ( ! empty( $args['google_calendar'] ) ) {
|
|
$google_calendar_schedule = ssa()->google_calendar->get_schedule( $this->appointment_type, $this->period, $args );
|
|
if ( null !== $google_calendar_schedule ) {
|
|
$google_calendar_schedule = $google_calendar_schedule->subrange( $this->period );
|
|
$this->schedule = $this->schedule->merge_min( $google_calendar_schedule );
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['staff'] ) ) {
|
|
if ( ssa()->settings_installed->is_activated( 'staff' ) ) {
|
|
$staff_schedule = ssa()->staff->get_schedule( $this->appointment_type, $this->period, $args );
|
|
|
|
if ( null !== $staff_schedule ) {
|
|
$this->schedule = $this->schedule->merge_min( $staff_schedule );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['mepr_membership_id'] ) && class_exists( 'SSA_Memberpress' ) ) {
|
|
$membership_schedule = ssa()->memberpress->get_schedule( $this->appointment_type, $this->period, $args );
|
|
|
|
if ( null !== $membership_schedule ) {
|
|
$this->schedule = $this->schedule->merge_min( $membership_schedule );
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['resources'] ) ) {
|
|
if ( ssa()->settings_installed->is_activated( 'resources' ) ) {
|
|
$resource_schedule = ssa()->resources->get_schedule( $this->appointment_type, $this->period, $args );
|
|
|
|
if ( null !== $resource_schedule ) {
|
|
$this->schedule = $this->schedule->merge_min( $resource_schedule );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['excluded_appointment_ids'] ) ) {
|
|
$excluded_appointments_schedule = $this->get_excluded_appointments_schedule( $this->appointment_type, $this->period, $args );
|
|
|
|
if ( null !== $excluded_appointments_schedule ) {
|
|
$this->schedule = $this->schedule->merge_max( $excluded_appointments_schedule );
|
|
}
|
|
}
|
|
|
|
|
|
$this->schedule = $this->schedule->subrange( $query_period ); // cut off the edges
|
|
$this->period = $query_period;
|
|
|
|
return $this->schedule;
|
|
}
|
|
|
|
|
|
public function get_excluded_appointments_schedule(SSA_Appointment_Type_Object $appointment_type, Period $query_period, $args) {
|
|
if ( empty( $args['excluded_appointment_ids'] ) ) {
|
|
return;
|
|
}
|
|
|
|
$query_period = SSA_Utils::get_query_period( $query_period );
|
|
$schedule = new SSA_Availability_Schedule();
|
|
|
|
foreach ( $args['excluded_appointment_ids'] as $appointment_id ) {
|
|
$appointment = new SSA_Appointment_Object( $appointment_id );
|
|
$period = $appointment->get_appointment_period();
|
|
|
|
if (!$query_period->overlaps($period)) {
|
|
continue;
|
|
}
|
|
|
|
$schedule = $schedule->pushmerge( SSA_Availability_Block_Factory::available_for_period( $period, array(
|
|
'capacity_available' => 1,
|
|
'buffer_available' => SSA_Constants::CAPACITY_MAX
|
|
) ) );
|
|
}
|
|
|
|
return $schedule;
|
|
}
|
|
|
|
public function why_not_bookable() {
|
|
// TODO // so we can return an error code "blackout dates"
|
|
}
|
|
|
|
public function get_bookable_appointments() {
|
|
if ( empty( $this->appointment_type ) ) {
|
|
throw new SSA_Exception( 'Appointment Type required' );
|
|
}
|
|
|
|
$schedule = $this->get_schedule();
|
|
|
|
$bookable_appointments = array();
|
|
|
|
$availability_interval = $this->appointment_type->get_availability_interval();
|
|
$availability_increment = $this->appointment_type->availability_increment;
|
|
if ( ! $availability_interval instanceof DateInterval ) {
|
|
$availability_interval = new DateInterval( 'PT15M' );
|
|
}
|
|
$availability = $this->appointment_type->availability;
|
|
$timezone = $this->appointment_type->get_timezone();
|
|
$duration = $this->appointment_type->duration;
|
|
$capacity_type = $this->appointment_type->capacity_type;
|
|
if ( 'group' === $capacity_type ) {
|
|
$booked_group_appointments = $this->appointment_type->get_appointment_objects( $this->period, array(
|
|
'status' => SSA_Appointment_Model::get_unavailable_statuses(),
|
|
) );
|
|
}
|
|
|
|
foreach ($schedule->get_blocks() as $block) {
|
|
if ( $block->capacity_available <= 0 ) {
|
|
continue;
|
|
}
|
|
|
|
$starting_minute = (int)$block->get_period()->getStartDate()->setTimezone( $timezone )->format( 'i' );
|
|
$minutes_to_add = 0;
|
|
while( ( $starting_minute + $minutes_to_add ) % $availability_increment !== 0 ) {
|
|
$minutes_to_add++;
|
|
}
|
|
if ( $minutes_to_add ) {
|
|
$start_date = $block->get_period()->getStartDate();
|
|
$end_date = $block->get_period()->getEndDate();
|
|
$new_start_date = $start_date->add( new DateInterval( 'PT'.$minutes_to_add.'M' ) );
|
|
if ( $new_start_date >= $end_date ) {
|
|
continue;
|
|
}
|
|
$block = $block->set_period( new Period( $new_start_date, $end_date ) );
|
|
}
|
|
|
|
foreach ( $block->get_period()->split( $availability_interval ) as $period ) {
|
|
if ( 'start_times' === $this->appointment_type->availability_type ) {
|
|
$start_datetime_tz = $period->getStartDate()->setTimezone( $timezone );
|
|
$day_of_week = $start_datetime_tz->format( 'l' );
|
|
if ( empty( $availability[$day_of_week]['0']['time_start'] ) ) {
|
|
continue; // no start times set for this day of the week
|
|
}
|
|
|
|
$is_available_start_time = false;
|
|
foreach ( $availability[$day_of_week] as $availability_value ) {
|
|
if ( $availability_value['time_start'] === $start_datetime_tz->format( 'H:i:s' ) ) {
|
|
$is_available_start_time = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ! $is_available_start_time ) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( 'group' === $capacity_type ) {
|
|
foreach ( $booked_group_appointments as $booked_group_appointment ) {
|
|
if ( $booked_group_appointment->get_buffered_period()->overlaps( $period ) ) {
|
|
if ( $booked_group_appointment->get_appointment_period()->getStartDate() != $period->getStartDate() ) {
|
|
continue 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$appointment = SSA_Appointment_Factory::create( $this->appointment_type, array(
|
|
'id' => 0,
|
|
'start_date' => $period->getStartDate()->format( 'Y-m-d H:i:s' ),
|
|
) );
|
|
if ( ! $this->is_prospective_appointment_bookable( $appointment ) ) {
|
|
continue;
|
|
}
|
|
|
|
$bookable_appointments[] = $appointment;
|
|
}
|
|
}
|
|
|
|
return $bookable_appointments;
|
|
}
|
|
|
|
public function get_bookable_appointment_periods() {
|
|
$bookable_appointment_periods = array();
|
|
$bookable_appointments = $this->get_bookable_appointments();
|
|
foreach ($bookable_appointments as $appointment) {
|
|
$bookable_appointment_periods[] = $appointment->get_appointment_period();
|
|
}
|
|
|
|
return $bookable_appointment_periods;
|
|
}
|
|
|
|
public function get_bookable_appointment_start_datetime_strings_plucked() {
|
|
$bookable_start_datetime_strings = $this->get_bookable_appointment_start_datetime_strings();
|
|
if ( empty( $bookable_start_datetime_strings['0']['start_date'] ) ) {
|
|
return array();
|
|
}
|
|
$bookable_start_datetime_strings = wp_list_pluck( $bookable_start_datetime_strings, 'start_date' );
|
|
return $bookable_start_datetime_strings;
|
|
}
|
|
|
|
public function get_bookable_appointment_start_datetime_strings() {
|
|
$query_hash = $this->get_query_hash();
|
|
$cache_key = 'availability/'.$query_hash.'/bookable_datetime_strings';
|
|
if ( ! empty( $this->args['cache_level_read'] ) && $this->args['cache_level_read'] == 1 ) {
|
|
if ( ssa()->availability_cache->is_enabled() ) {
|
|
$cached = ssa_cache_get( $cache_key );
|
|
if ( $cached !== false && is_array( $cached ) ) {
|
|
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
|
|
foreach ($cached as &$value) {
|
|
if ( isset( $value['capacity_available'] ) ) {
|
|
unset( $value['capacity_available'] );
|
|
}
|
|
}
|
|
}
|
|
|
|
$excluded_start_datetimes = ssa_cache_get('availability/appointment_type/' . $this->appointment_type->id . '/excluded_start_datetimes');
|
|
if ( ! empty($excluded_start_datetimes) ) {
|
|
$cached = array_filter($cached, function( $value ) use ( $excluded_start_datetimes ) {
|
|
return ! in_array( $value['start_date'], $excluded_start_datetimes );
|
|
});
|
|
$cached = array_values( $cached ); // needed to keep JSON response an array
|
|
}
|
|
|
|
return $cached;
|
|
}
|
|
}
|
|
}
|
|
|
|
$developer_settings = ssa()->developer_settings->get();
|
|
$bookable_start_datetimes = $this->get_bookable_appointment_start_datetimes();
|
|
$data = array();
|
|
$schedule = $this->get_schedule();
|
|
foreach ($bookable_start_datetimes as $start_datetime) {
|
|
$data_array = array(
|
|
'start_date' => $start_datetime->format('Y-m-d H:i:s'),
|
|
);
|
|
if ( ! empty( $developer_settings['display_capacity_available'] ) ) {
|
|
$block = $schedule->get_block_for_date( $start_datetime->format('Y-m-d H:i:s') );
|
|
if ( false === $block ) {
|
|
ssa_debug_log( 'get_bookable_appointment_start_datetime_strings(): block not found in schedule: ' . $start_datetime->format( 'Y-m-d H:i:s' ) );
|
|
} else {
|
|
$data_array['capacity_available'] = $block->capacity_available;
|
|
}
|
|
}
|
|
$data[] = $data_array;
|
|
}
|
|
|
|
if ( ! empty( $this->args['cache_level_write'] ) && $this->args['cache_level_write'] == 1 ) {
|
|
if ( ssa()->availability_cache->is_enabled() ) {
|
|
ssa_cache_set(
|
|
$cache_key,
|
|
$data
|
|
);
|
|
ssa()->availability_cache->remember_recent( 'availability_query_args', $this->get_query_args(), 10 );
|
|
}
|
|
}
|
|
|
|
if ( ! current_user_can( 'ssa_manage_site_settings' ) ) {
|
|
foreach ($data as &$value) {
|
|
if ( isset( $value['capacity_available'] ) ) {
|
|
unset( $value['capacity_available'] );
|
|
}
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
public function get_bookable_appointment_start_datetimes() {
|
|
$bookable_appointment_start_datetimes = array();
|
|
$bookable_appointments = $this->get_bookable_appointments();
|
|
foreach ($bookable_appointments as $appointment) {
|
|
$bookable_appointment_start_datetimes[] = $appointment->get_appointment_period()->getStartDate();
|
|
}
|
|
|
|
return $bookable_appointment_start_datetimes;
|
|
}
|
|
|
|
public function get_queried_appointments() {
|
|
if ( null !== $this->_queried_appointments ) {
|
|
return $this->_queried_appointments;
|
|
}
|
|
|
|
$queried_appointments_array = $this->get_queried_appointments_array();
|
|
|
|
$queried_appointments = array();
|
|
foreach ($queried_appointments_array as $queried_appointment) {
|
|
$queried_appointment = SSA_Appointment_Object::instance( $queried_appointment );
|
|
$queried_appointments[] = $queried_appointment;
|
|
}
|
|
|
|
$this->_queried_appointments = $queried_appointments;
|
|
return $this->_queried_appointments;
|
|
}
|
|
|
|
public function get_queried_appointments_array() {
|
|
$args = array(
|
|
'number' => -1,
|
|
'orderby' => 'start_date',
|
|
// 'appointment_type_id' => $appointment_type->id,
|
|
'intersects_period' => $this->period,
|
|
'status' => SSA_Appointment_Model::get_unavailable_statuses(),
|
|
);
|
|
|
|
$queried_appointments_array = ssa()->appointment_model->query( $args );
|
|
return $queried_appointments_array;
|
|
}
|
|
|
|
public function get_booked_group_appointments() {
|
|
if ( null !== $this->_booked_group_appointments ) {
|
|
return $this->_booked_group_appointments;
|
|
}
|
|
|
|
if ( null === $this->appointment_type ) {
|
|
return;
|
|
}
|
|
|
|
$this->_booked_group_appointments = $this->appointment_type->get_appointment_objects( $this->period, array(
|
|
'status' => SSA_Appointment_Model::get_unavailable_statuses(),
|
|
) );
|
|
|
|
return $this->_booked_group_appointments;
|
|
}
|
|
|
|
public function is_prospective_appointment_bookable( SSA_Appointment_Object $appointment ) {
|
|
global $ssa_staff_unavailable_start_dates;
|
|
|
|
$schedule = $this->get_schedule( array(
|
|
'skip_appointment_id' => $appointment->id,
|
|
) );
|
|
if ( null === $schedule ) {
|
|
return false;
|
|
}
|
|
|
|
if ( ! empty( $this->appointment_type ) ) {
|
|
// We should use the appointment type that we're querying for if it's set (faster than getting appointment type dynamically each run)
|
|
$appointment_type = $this->appointment_type;
|
|
} else {
|
|
$appointment_type = $appointment->get_appointment_type();
|
|
}
|
|
|
|
if ( ! empty( $ssa_staff_unavailable_start_dates[$appointment->start_date] ) ) {
|
|
return false; // staff member is unavailable at this time
|
|
}
|
|
|
|
if ( ! $schedule->is_appointment_period_available( $appointment, $appointment_type ) ) {
|
|
return false;
|
|
}
|
|
|
|
$appointment_buffered_period = $appointment->get_buffered_period();
|
|
$appointment_period = $appointment->get_appointment_period();
|
|
|
|
if ( 'group' === $appointment_type->capacity_type ) {
|
|
$booked_group_appointments = $this->get_booked_group_appointments();
|
|
|
|
if ( ! empty( $booked_group_appointments ) ) {
|
|
foreach ( $booked_group_appointments as $booked_group_appointment ) {
|
|
if ( $booked_group_appointment->get_buffered_period()->overlaps( $appointment_buffered_period ) ) {
|
|
// There might be a potential conflict
|
|
|
|
if ( $booked_group_appointment->get_appointment_period()->getStartDate() != $appointment_period->getStartDate() ) {
|
|
// And we've confirmed it's not the exact same start time (since that would be allowed)
|
|
|
|
if ( $booked_group_appointment->get_buffered_period()->overlaps( $appointment_period ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $booked_group_appointment->get_appointment_period()->overlaps( $appointment_buffered_period ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If `any` team member is selected, we need to check each team member since the merge_max can't cover every scenario
|
|
if (!empty($this->args['staff'])) {
|
|
if (ssa()->settings_installed->is_activated('staff')) {
|
|
$appointment_type_staff_settings = $appointment_type->staff;
|
|
if ( ! empty( $appointment_type_staff_settings ) && ! empty( $appointment_type_staff_settings['required'] ) ) {
|
|
if ( 'any' === $appointment_type_staff_settings['required'] ) {
|
|
// static $total;
|
|
// static $unavailable;
|
|
// ssa_debug_log( $total++ . ': Trying to find staff member for ' . $appointment->start_date, 10 );
|
|
// proactive and effective, but very slow (about 4x slower):
|
|
// TODO: only run the following block in async mode so the slow-building cache can be as correct as possible
|
|
// $data = ssa()->staff->assign_appointment_to_staff( array(
|
|
// 'appointment_type_id' => $appointment_type, // the assign_appointment_to_staff function will use the SSA_Appointment_Type object we're passing as `appointment_type_id` and save a lookup step
|
|
// 'start_date' => $appointment->start_date,
|
|
// // 'availability_query' => $this,
|
|
// ) );
|
|
|
|
// if ( empty( $data['staff_ids'] ) ) {
|
|
// // assigning to a staff member would end up empty, so we shouldn't allow this appointment to be booked
|
|
// ssa_debug_log($unavailable++ . ' UNAVAILABLE: Trying to find staff member for ' . $appointment->start_date, 10);
|
|
// return false;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Other Appointment Types Shared Availability
|
|
$developer_settings = ssa()->developer_settings->get();
|
|
$separate_appointment_type_availability = $developer_settings['separate_appointment_type_availability'];
|
|
if ( empty( $this->args['appointment_type.separate_appointment_type_availability']) || $separate_appointment_type_availability ) {
|
|
return true;
|
|
}
|
|
|
|
// TODO: use cached appointment schedule for all other appointment types?
|
|
$queried_appointments = $this->get_queried_appointments();
|
|
|
|
if ( empty( $queried_appointments ) ) {
|
|
return true;
|
|
}
|
|
|
|
foreach ($queried_appointments as $queried_appointment) {
|
|
if ( $queried_appointment->appointment_type_id == $appointment_type->id ) {
|
|
continue; // this is already checked and accounted for in the appointment_type object's get_schedule() function
|
|
}
|
|
|
|
if ( $appointment_buffered_period->overlaps( $queried_appointment->get_appointment_period() )) {
|
|
return false;
|
|
}
|
|
|
|
if ( $appointment_period->overlaps( $queried_appointment->get_buffered_period() ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
}
|