From 8f12b459d06c19de467a60ed2dbf5bcc5bed6ea4 Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Thu, 21 Jul 2016 22:36:17 +0200 Subject: [PATCH] Integrated the multiple attendants in the availabilities generation (#109). --- src/application/controllers/Appointments.php | 75 ++++++++++++++++--- .../controllers/api/v1/Availabilities.php | 67 +++++++++++++---- src/application/models/Appointments_model.php | 16 ++++ 3 files changed, 135 insertions(+), 23 deletions(-) diff --git a/src/application/controllers/Appointments.php b/src/application/controllers/Appointments.php index 5712b9d1..6e7ac7c3 100755 --- a/src/application/controllers/Appointments.php +++ b/src/application/controllers/Appointments.php @@ -11,9 +11,9 @@ * @since v1.0.0 * ---------------------------------------------------------------------------- */ -use \EA\Engine\Types\String; -use \EA\Engine\Types\Email; -use \EA\Engine\Types\Url; +use \EA\Engine\Types\String; +use \EA\Engine\Types\Email; +use \EA\Engine\Types\Url; /** * Appointments Controller @@ -194,8 +194,8 @@ class Appointments extends CI_Controller { // :: SEND NOTIFICATION EMAILS TO CUSTOMER AND PROVIDER try { - $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + $this->config->load('email'); + $email = new \EA\Engine\Notifications\Email($this, $this->config->config); $send_provider = filter_var($this->providers_model ->get_setting('notifications', $provider['id']), FILTER_VALIDATE_BOOLEAN); @@ -315,14 +315,20 @@ class Appointments extends CI_Controller { } $availabilities_type = $this->services_model->get_value('availabilities_type', $_POST['service_id']); + $attendants_number = $this->services_model->get_value('attendants_number', $_POST['service_id']); $empty_periods = $this->_get_provider_available_time_periods($_POST['provider_id'], $_POST['selected_date'], $exclude_appointments); $available_hours = $this->_calculate_available_hours($empty_periods, $_POST['selected_date'], - $_POST['service_duration'], filter_var($_POST['manage_mode'], FILTER_VALIDATE_BOOLEAN), + $_POST['service_duration'], filter_var($_POST['manage_mode'], FILTER_VALIDATE_BOOLEAN), $availabilities_type); + if ($attendants_number > 1) { + $this->_get_multiple_attendants_hours($available_hours, $attendants_number, $_POST['service_id'], + $_POST['selected_date']); + } + echo json_encode($available_hours); } catch(Exception $exc) { @@ -422,7 +428,7 @@ class Appointments extends CI_Controller { // :: SEND NOTIFICATION EMAILS TO BOTH CUSTOMER AND PROVIDER try { $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + $email = new \EA\Engine\Notifications\Email($this, $this->config->config); if ($post_data['manage_mode'] == FALSE) { $customer_title = new String($this->lang->line('appointment_booked')); @@ -548,6 +554,7 @@ class Appointments extends CI_Controller { */ protected function _check_datetime_availability() { $this->load->model('services_model'); + $this->load->model('appointments_model'); $appointment = $_POST['post_data']['appointment']; @@ -555,6 +562,22 @@ class Appointments extends CI_Controller { $exclude_appointments = (isset($appointment['id'])) ? array($appointment['id']) : array(); + $attendants_number = $this->services_model->get_value('attendants_number', $appointment['id_services']); + + if ($attendants_number > 1) { + // Exclude all the appointments that will are currently registered. + $exclude = $this->appointments_model->get_batch([ + 'id_services' => $appointment['id_services'], + 'start_datetime' => $appointment['start_datetime'] + ]); + + if (!empty($exclude) && count($exclude) < $attendants_number) { + foreach ($exclude as $entry) { + $exclude_appointments[] = $entry['id']; + } + } + } + if ($appointment['id_users_provider'] === ANY_PROVIDER) { $appointment['id_users_provider'] = $this->_search_any_provider($appointment['id_services'], date('Y-m-d', strtotime($appointment['start_datetime']))); @@ -759,7 +782,7 @@ class Appointments extends CI_Controller { foreach($provider['services'] as $provider_service_id) { if ($provider_service_id == $service_id) { // Check if the provider is available for the requested date. $empty_periods = $this->_get_provider_available_time_periods($provider['id'], $selected_date); - $available_hours = $this->_calculate_available_hours($empty_periods, $selected_date, + $available_hours = $this->_calculate_available_hours($empty_periods, $selected_date, $service['duration'], false, $service['availabilities_type']); if (count($available_hours) > $max_hours_count) { $provider_id = $provider['id']; @@ -797,7 +820,7 @@ class Appointments extends CI_Controller { foreach ($empty_periods as $period) { $start_hour = new DateTime($selected_date . ' ' . $period['start']); $end_hour = new DateTime($selected_date . ' ' . $period['end']); - $interval = $availabilities_type === AVAILABILITIES_TYPE_FIXED ? (int)$service_duration : 15; + $interval = $availabilities_type === AVAILABILITIES_TYPE_FIXED ? (int)$service_duration : 15; $current_hour = $start_hour; $diff = $current_hour->diff($end_hour); @@ -830,6 +853,40 @@ class Appointments extends CI_Controller { return $available_hours; } + + /** + * Get multiple attendants hours. + * + * This method will add the extra appointment hours whenever a service accepts multiple attendants. + * + * @param array $available_hours The previously calculated appointment hours. + * @param int $attendants_number Service attendants number. + * @param int $service_id Selected service ID. + * @param string $selected_date The selected appointment date. + */ + protected function _get_multiple_attendants_hours(&$available_hours, $attendants_number, $service_id, + $selected_date) { + $this->load->model('appointments_model'); + + $appointments = $this->appointments_model->get_batch( + 'id_services = ' . $this->db->escape($service_id) . ' AND DATE(start_datetime) = DATE(' + . $this->db->escape(date('Y-m-d', strtotime($selected_date))) . ')'); + + $hours = []; + + foreach($appointments as $appointment) { + $hour = date('H:i', strtotime($appointment['start_datetime'])); + $current_attendants_number = $this->appointments_model->appointment_count_for_hour($service_id, + $selected_date, $hour); + if ($current_attendants_number < $attendants_number && !in_array($hour, $available_hours)) { + $available_hours[] = $hour; + } + } + + $available_hours = array_values($available_hours); + sort($available_hours, SORT_STRING ); + $available_hours = array_values($available_hours); + } } /* End of file appointments.php */ diff --git a/src/application/controllers/api/v1/Availabilities.php b/src/application/controllers/api/v1/Availabilities.php index 8b3e983b..03f2b91b 100644 --- a/src/application/controllers/api/v1/Availabilities.php +++ b/src/application/controllers/api/v1/Availabilities.php @@ -16,7 +16,7 @@ require_once __DIR__ . '/../../Appointments.php'; use \EA\Engine\Api\V1\Response; use \EA\Engine\Api\V1\Request; -use \EA\Engine\Types\UnsignedInt; +use \EA\Engine\Types\UnsignedInt; /** * Availabilities Controller @@ -32,7 +32,7 @@ class Availabilities extends API_V1_Controller { parent::__construct(); $this->load->model('appointments_model'); $this->load->model('providers_model'); - $this->load->model('services_model'); + $this->load->model('services_model'); $this->load->model('settings_model'); } @@ -44,30 +44,35 @@ class Availabilities extends API_V1_Controller { */ public function get() { try { - $providerId = new UnsignedInt($this->input->get('providerId')); - $serviceId = new UnsignedInt($this->input->get('serviceId')); + $providerId = new UnsignedInt($this->input->get('providerId')); + $serviceId = new UnsignedInt($this->input->get('serviceId')); if ($this->input->get('date')) { - $date = new DateTime($this->input->get('date')); + $date = new DateTime($this->input->get('date')); } else { $date = new DateTime(); } - $service = $this->services_model->get_row($serviceId->get()); + $service = $this->services_model->get_row($serviceId->get()); $emptyPeriods = $this->_getProviderAvailableTimePeriods($providerId->get(), $date->format('Y-m-d'), []); - - $availableHours = $this->_calculateAvailableHours($emptyPeriods, + + $availableHours = $this->_calculateAvailableHours($emptyPeriods, $date->format('Y-m-d'), $service['duration'], false, $service['availabilities_type']); + if ($service['attendants_number'] > 1) { + $this->_getMultipleAttendantsHours($availableHours, $service['attendants_number'], $service['id'], + $date->format('Y-m-d')); + } + $this->output - ->set_content_type('application/json') + ->set_content_type('application/json') ->set_output(json_encode($availableHours)); } catch(\Exception $exception) { - exit($this->_handleException($exception)); - } + exit($this->_handleException($exception)); + } } /** @@ -244,7 +249,7 @@ class Availabilities extends API_V1_Controller { foreach ($empty_periods as $period) { $start_hour = new DateTime($selected_date . ' ' . $period['start']); $end_hour = new DateTime($selected_date . ' ' . $period['end']); - $interval = $availabilities_type === AVAILABILITIES_TYPE_FIXED ? (int)$service_duration : 15; + $interval = $availabilities_type === AVAILABILITIES_TYPE_FIXED ? (int)$service_duration : 15; $current_hour = $start_hour; $diff = $current_hour->diff($end_hour); @@ -277,7 +282,41 @@ class Availabilities extends API_V1_Controller { return $available_hours; } + + /** + * Get multiple attendants hours. + * + * This method will add the extra appointment hours whenever a service accepts multiple attendants. + * + * @param array $available_hours The previously calculated appointment hours. + * @param int $attendants_number Service attendants number. + * @param int $service_id Selected service ID. + * @param string $selected_date The selected appointment date. + */ + protected function _getMultipleAttendantsHours(&$available_hours, $attendants_number, $service_id, + $selected_date) { + $this->load->model('appointments_model'); + + $appointments = $this->appointments_model->get_batch( + 'id_services = ' . $this->db->escape($service_id) . ' AND DATE(start_datetime) = DATE(' + . $this->db->escape(date('Y-m-d', strtotime($selected_date))) . ')'); + + $hours = []; + + foreach($appointments as $appointment) { + $hour = date('H:i', strtotime($appointment['start_datetime'])); + $current_attendants_number = $this->appointments_model->appointment_count_for_hour($service_id, + $selected_date, $hour); + if ($current_attendants_number < $attendants_number && !in_array($hour, $available_hours)) { + $available_hours[] = $hour; + } + } + + $available_hours = array_values($available_hours); + sort($available_hours, SORT_STRING ); + $available_hours = array_values($available_hours); + } } -/* End of file Appointments.php */ -/* Location: ./application/controllers/api/v1/Appointments.php */ +/* End of file Availabilities.php */ +/* Location: ./application/controllers/api/v1/Availabilities.php */ diff --git a/src/application/models/Appointments_model.php b/src/application/models/Appointments_model.php index 25ec2ae1..400ae0e1 100644 --- a/src/application/models/Appointments_model.php +++ b/src/application/models/Appointments_model.php @@ -393,6 +393,22 @@ class Appointments_Model extends CI_Model { $this->db->update('ea_appointments', array('id_google_calendar' => NULL), array('id_users_provider' => $provider_id)); } + + /** + * Get appointment count for the provided start datetime. + * + * @param int $service_id Selected service ID. + * @param string $selected_date Selected date string. + * @param string $hour Selected hour string. + * + * @return int Returns the appointment number at the selected start time. + */ + public function appointment_count_for_hour($service_id, $selected_date, $hour) { + return $this->db->get_where('ea_appointments', [ + 'id_services' => $service_id, + 'start_datetime' => date('Y-m-d H:i:s', strtotime($selected_date . ' ' . $hour . ':00')) + ])->num_rows(); + } } /* End of file appointments_model.php */