<?php if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'OsDashboardController' ) ) : class OsDashboardController extends OsController { private $booking; function __construct(){ parent::__construct(); $this->views_folder = LATEPOINT_VIEWS_ABSPATH . 'dashboard/'; $this->vars['page_header'] = __('Dashboard', 'latepoint'); } public function pro_agents(){ } /* Index */ public function index(){ $this->vars['page_header'] = false; ob_start(); $this->widget_bookings_and_availability_timeline(); $this->vars['widget_bookings_and_availability_timeline'] = ob_get_clean(); ob_start(); $this->widget_daily_bookings_chart(); $this->vars['widget_daily_bookings_chart'] = ob_get_clean(); ob_start(); $this->widget_upcoming_appointments(3); $this->vars['widget_upcoming_appointments'] = ob_get_clean(); $this->set_layout('admin'); $this->format_render(__FUNCTION__); } public function widget_upcoming_appointments($limit = 3){ $agents = new OsAgentModel(); $services = new OsServiceModel(); $bookings = new OsBookingModel(); $locations = new OsLocationModel(); $selected_agent_id = isset($this->params['agent_id']) ? OsAuthHelper::get_current_user()->check_if_allowed_record_id($this->params['agent_id'], 'agent') : false; $selected_service_id = isset($this->params['service_id']) ? OsAuthHelper::get_current_user()->check_if_allowed_record_id($this->params['service_id'], 'service') : false; $selected_location_id = isset($this->params['location_id']) ? OsAuthHelper::get_current_user()->check_if_allowed_record_id($this->params['location_id'], 'location') : false; $this->vars['upcoming_bookings'] = $bookings->get_upcoming_bookings($selected_agent_id, false, $selected_service_id, $selected_location_id, $limit); $this->vars['agents'] = $agents->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['services'] = $services->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['locations'] = $locations->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['selected_agent_id'] = $selected_agent_id; $this->vars['selected_service_id'] = $selected_service_id; $this->vars['selected_location_id'] = $selected_location_id; $this->set_layout('none'); $this->format_render(__FUNCTION__); } public function widget_daily_bookings_chart($date_from = false, $date_to = false){ if($date_from == false){ $date_from = isset($this->params['date_from']) ? OsWpDateTime::os_createFromFormat('Y-m-d', $this->params['date_from']) : new OsWpDateTime('-1 week'); } if($date_to == false){ $date_to = isset($this->params['date_to']) ? OsWpDateTime::os_createFromFormat('Y-m-d', $this->params['date_to']) : new OsWpDateTime('now'); } $filter = new \LatePoint\Misc\Filter(); $filter = OsRolesHelper::filter_allowed_records_from_arguments_or_filter($filter); if(!empty($this->params['agent_id'])) $filter->agent_id = $this->params['agent_id']; if(!empty($this->params['service_id'])) $filter->service_id = $this->params['service_id']; if(!empty($this->params['location_id'])) $filter->location_id = $this->params['location_id']; if(!OsRolesHelper::are_all_records_allowed()){ if(!OsRolesHelper::are_all_records_allowed('agent')) $agent_id = OsRolesHelper::get_allowed_records('agent'); } $daily_bookings = OsBookingHelper::get_total_bookings_per_day_for_period($date_from->format('Y-m-d'), $date_to->format('Y-m-d'), $filter); $daily_chart_data = []; // fill data array with all the days for($day_date=clone $date_from; $day_date<=$date_to; $day_date->modify('+1 day')){ $daily_chart_data[OsTimeHelper::get_nice_date_with_optional_year($day_date->format('Y-m-d'), false, true)] = 0; } // update the days with count of bookings foreach($daily_bookings as $bookings_for_day){ $daily_chart_data[OsTimeHelper::get_nice_date_with_optional_year(gmdate( 'Y-m-d', strtotime($bookings_for_day->start_date)), false, true)] = $bookings_for_day->bookings_per_day; } $this->vars['total_bookings'] = OsBookingHelper::get_stat_for_period('bookings', $date_from->format('Y-m-d'), $date_to->format('Y-m-d'), $filter); $this->vars['total_price'] = OsBookingHelper::get_stat_for_period('price', $date_from->format('Y-m-d'), $date_to->format('Y-m-d'), $filter); $this->vars['total_duration'] = OsBookingHelper::get_stat_for_period('duration', $date_from->format('Y-m-d'), $date_to->format('Y-m-d'), $filter); $this->vars['total_new_customers'] = OsBookingHelper::get_new_customer_stat_for_period($date_from, $date_to, $filter); $day_difference = $date_from->diff($date_to); $day_difference = ($day_difference->d > 0) ? $day_difference->d : 1; $prev_date_from = clone $date_from; $prev_date_from->modify('-'.$day_difference.' days'); $prev_date_to = clone $date_to; $prev_date_to->modify('-'.$day_difference.' days'); $this->vars['prev_total_bookings'] = OsBookingHelper::get_stat_for_period('bookings', $prev_date_from->format('Y-m-d'), $prev_date_to->format('Y-m-d'), $filter); $this->vars['prev_total_price'] = OsBookingHelper::get_stat_for_period('price', $prev_date_from->format('Y-m-d'), $prev_date_to->format('Y-m-d'), $filter); $this->vars['prev_total_duration'] = OsBookingHelper::get_stat_for_period('duration', $prev_date_from->format('Y-m-d'), $prev_date_to->format('Y-m-d'), $filter); $this->vars['prev_total_new_customers'] = OsBookingHelper::get_new_customer_stat_for_period($prev_date_from, $prev_date_to, $filter); $agents = new OsAgentModel(); $services = new OsServiceModel(); $locations = new OsLocationModel(); $this->vars['agents'] = $agents->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['services'] = $services->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['locations'] = $locations->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['filter'] = $filter; $this->vars['date_from'] = $date_from->format('Y-m-d'); $this->vars['date_to'] = $date_to->format('Y-m-d'); $this->vars['daily_bookings_chart_labels_string'] = implode(',', array_keys($daily_chart_data)); $this->vars['daily_bookings_chart_data_values_string'] = implode(',', array_values($daily_chart_data)); $pie_labels = []; $pie_colors = []; $pie_values = []; $pie_chart_data = OsBookingHelper::get_stat_for_period('bookings', $date_from->format('Y-m-d'), $date_to->format('Y-m-d'), $filter,'service_id'); foreach($pie_chart_data as $pie_data){ $service = new OsServiceModel($pie_data['service_id']); $pie_labels[] = $service->name; $pie_colors[] = $service->bg_color; $pie_values[] = $pie_data['stat']; } $this->vars['pie_chart_data'] = ['labels' => $pie_labels, 'colors' => $pie_colors, 'values' => $pie_values]; $this->vars['date_period_string'] = OsTimeHelper::format_date_with_locale(OsSettingsHelper::get_readable_date_format(true, true), $date_from).' - '.OsTimeHelper::format_date_with_locale(OsSettingsHelper::get_readable_date_format(true, true), $date_to); $this->set_layout('none'); $this->format_render(__FUNCTION__); } public function widget_bookings_and_availability_timeline(){ $target_date = isset($this->params['date_from']) ? OsWpDateTime::os_createFromFormat('Y-m-d', $this->params['date_from']) : new OsWpDateTime('now'); $services = new OsServiceModel(); $agents = new OsAgentModel(); $locations = new OsLocationModel(); $agents_models = $agents->should_be_active()->filter_allowed_records()->get_results_as_models(); $services_models = $services->should_be_active()->filter_allowed_records()->get_results_as_models(); $locations_models = $locations->should_be_active()->filter_allowed_records()->get_results_as_models(); $this->vars['services'] = $services_models; $this->vars['locations'] = $locations_models; $this->vars['agents'] = $agents_models; if($services_models && !empty($this->params['service_id'])){ $selected_service = $services->load_by_id($this->params['service_id']); }else{ $selected_service = false; } if($locations_models){ // show all locations option if agent can only be present at one place - because it means he does not have overlapping appointments on the calendar $default_location_id = OsSettingsHelper::is_on('one_location_at_time') ? false : $locations_models[0]->id; $selected_location_id = !empty($this->params['location_id']) ? $this->params['location_id'] : $default_location_id; }else{ $selected_location_id = false; } $this->vars['selected_location'] = $selected_location_id ? new OsLocationModel($selected_location_id) : false; $this->vars['selected_location_id'] = $selected_location_id; $timeblock_interval = OsSettingsHelper::get_default_timeblock_interval(); $selected_service_id = ($selected_service) ? $selected_service->id : false; $this->vars['selected_service'] = $selected_service; $this->vars['selected_service_id'] = $selected_service_id; // we are using two separate booking requests because the calendar on top has to generate availability timeline, // which can only be generated if we know service to check for. The second booking request is used to retrieve // shared resources for all services and locations (unless specific location is selected) $availability_booking_request = new \LatePoint\Misc\BookingRequest(['start_date' => $target_date->format('Y-m-d')]); $general_booking_request = new \LatePoint\Misc\BookingRequest(['start_date' => $target_date->format('Y-m-d')]); if($selected_location_id){ $availability_booking_request->location_id = $selected_location_id; $general_booking_request->location_id = $selected_location_id; } if($selected_service){ $availability_booking_request->service_id = $selected_service->id; // TODO add capacity and duration select box and POST params if multiple durations in a service $availability_booking_request->duration = $selected_service->duration; $timeblock_interval = $selected_service->get_timeblock_interval(); } if(count($agents_models) == 1) { $availability_booking_request->agent_id = $agents_models[0]->id; $general_booking_request->agent_id = $agents_models[0]->id; } $settings = ['accessed_from_backend' => true]; $resources = OsResourceHelper::get_resources_grouped_by_day($general_booking_request, $target_date, $target_date, $settings); $availability_resources = OsResourceHelper::get_resources_grouped_by_day($availability_booking_request, $target_date, $target_date, $settings); $work_boundaries = OsResourceHelper::get_work_boundaries_for_resources($resources[$target_date->format('Y-m-d')]); $work_total_minutes = $work_boundaries->end_time - $work_boundaries->start_time; $this->vars['timeblock_interval'] = $timeblock_interval; $bookings = []; $agent_work_time_periods = []; if($agents_models){ foreach($agents_models as $agent){ $agent_work_time_periods[$agent->id] = []; $args = ['agent_id' => $agent->id]; if($selected_location_id) $args['location_id'] = $selected_location_id; $args['status'] = OsCalendarHelper::get_booking_statuses_to_display_on_calendar(); $args = OsRolesHelper::filter_allowed_records_from_arguments_or_filter($args); $bookings[$agent->id] = OsBookingHelper::get_bookings_for_date($target_date->format('Y-m-d'), $args); } foreach($availability_resources[$target_date->format('Y-m-d')] as $resource){ if(isset($agent_work_time_periods[$resource->agent_id])) $agent_work_time_periods[$resource->agent_id] = array_merge($agent_work_time_periods[$resource->agent_id], $resource->work_time_periods); } } $this->vars['agent_work_time_periods'] = $agent_work_time_periods; $this->vars['availability_booking_request'] = $availability_booking_request; $this->vars['general_booking_request'] = $general_booking_request; $agents_resources = []; foreach ($agents_models as $agent) { $agent_booking_request = clone $availability_booking_request; $agent_booking_request->agent_id = $agent->id; $daily_resources = OsResourceHelper::get_resources_grouped_by_day($agent_booking_request, $target_date, null, $settings); $agents_resources['agent_' . $agent->id] = $daily_resources[$target_date->format('Y-m-d')]; } $this->vars['agents_resources'] = $agents_resources; $this->vars['timeline_boundaries'] = OsResourceHelper::get_work_boundaries_for_groups_of_resources($agents_resources); $this->vars['work_total_minutes'] = $work_total_minutes; $this->vars['work_boundaries'] = $work_boundaries; $this->vars['show_day_info'] = OsAuthHelper::is_admin_logged_in(); $this->vars['target_date_obj'] = $target_date; $this->vars['target_date'] = $target_date->format('Y-m-d'); $this->vars['target_date_string'] = OsTimeHelper::get_readable_date($target_date); $this->vars['what_to_show'] = isset($this->params['what_to_show']) ? $this->params['what_to_show'] : 'appointments'; $today_date = new OsWpDateTime('today'); if($target_date->format('Y-m-d') == $today_date->format('Y-m-d')){ $time_now = OsTimeHelper::now_datetime_object(); $time_now_in_minutes = OsTimeHelper::convert_datetime_to_minutes($time_now); if(($time_now_in_minutes<=$work_boundaries->end_time && $time_now_in_minutes>=$work_boundaries->start_time)){ $this->vars['time_now_label'] = $time_now->format(OsTimeHelper::get_time_format()); // agents row with avatars and margin below - offset that needs to be accounted for when calculating "time now" indicator position $this->vars['time_now_indicator_left_offset'] = ($time_now_in_minutes - $work_boundaries->start_time) / $work_total_minutes * 100; $this->vars['show_today_indicator'] = true; }else{ $this->vars['show_today_indicator'] = false; } }else{ $this->vars['show_today_indicator'] = false; } $this->set_layout('none'); $this->format_render(__FUNCTION__); } } endif;