PluginProbe
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.1.92
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.1.92
5.6.11 5.6.10 5.6.9 5.6.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 All 48 releases
latepoint / lib / controllers / calendars_controller.php
calendars_controller.php
383 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly.
4 }
5
6
7 if ( ! class_exists( 'OsCalendarsController' ) ) :
8
9
10 class OsCalendarsController extends OsController {
11
12 private $booking;
13
14 function __construct() {
15 parent::__construct();
16 $this->views_folder = LATEPOINT_VIEWS_ABSPATH . 'calendars/';
17 $this->vars['page_header'] = OsMenuHelper::get_menu_items_by_id( 'calendar' );
18 $this->vars['breadcrumbs'][] = array( 'label' => __( 'Appointments', 'latepoint' ), 'link' => OsRouterHelper::build_link( [ 'calendars', 'pending_approval' ] ) );
19 }
20
21 public function delete_blocked_period(){
22
23 if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
24 $this->check_nonce( 'delete_blocked_period_' . $this->params['id'] );
25 $off_period = new OsOffPeriodModel( $this->params['id'] );
26 if ( $off_period->delete() ) {
27 $status = LATEPOINT_STATUS_SUCCESS;
28 $response_html = __( 'Blocked Period Removed', 'latepoint' );
29 } else {
30 $status = LATEPOINT_STATUS_ERROR;
31 $response_html = __( 'Error Removing Blocked Period', 'latepoint' );
32 }
33 } else {
34 $status = LATEPOINT_STATUS_ERROR;
35 $response_html = __( 'Error Removing Blocked Period', 'latepoint' );
36 }
37 if ( $this->get_return_format() == 'json' ) {
38 $this->send_json( array( 'status' => $status, 'message' => $response_html ) );
39 }
40 }
41
42 public function apply_period_block() {
43 $blocked_period_settings = $this->params['blocked_period_settings'];
44 $blocked_period_id = $blocked_period_settings['id'] ?? false;
45 $this->check_nonce( 'save_custom_day_schedule_'.($blocked_period_id ? $blocked_period_id : 'new') );
46
47 try {
48 $day_date = new OsWpDateTime( $blocked_period_settings['date'] );
49 if ( $blocked_period_settings['full_day_off'] == 'yes' ) {
50
51 $work_period_obj = new OsWorkPeriodModel();
52
53 $work_period_obj->custom_date = $day_date->format( 'Y-m-d' );
54 $work_period_obj->week_day = $day_date->format( 'N' );
55
56 $work_period_obj->agent_id = $blocked_period_settings['agent_id'];
57 $work_period_obj->service_id = $blocked_period_settings['service_id'];
58 $work_period_obj->location_id = $blocked_period_settings['location_id'];
59
60 $work_period_obj->start_time = 0;
61 $work_period_obj->end_time = 0;
62
63 if ( $work_period_obj->save() ) {
64 // delete old blocked period
65 if($blocked_period_id){
66 $blocked_period = new OsOffPeriodModel($blocked_period_id);
67 if(!$blocked_period->is_new_record()) $blocked_period->delete();
68 }
69 $status = LATEPOINT_STATUS_SUCCESS;
70 $response_html = sprintf( esc_html__( '%s marked as a day off', 'latepoint' ), OsTimeHelper::get_readable_date( $day_date ) );
71 } else {
72 throw new Exception( implode( ',', $work_period_obj->get_error_messages() ?? esc_html__( 'Error', 'latepoint' ) ) );
73 }
74 } else {
75 $blocked_period = $blocked_period_id ? new OsOffPeriodModel($blocked_period_id) : new OsOffPeriodModel();
76 $blocked_period->summary = sanitize_text_field($blocked_period_settings['summary'] ?? esc_html__('Off Duty', 'latepoint'));
77 $blocked_period->start_date = $day_date->format( 'Y-m-d' );
78 $blocked_period->end_date = $day_date->format( 'Y-m-d' );
79
80 $work_periods = $this->params['work_periods'] ?? [];
81 if ( empty( $work_periods ) ) {
82 throw new Exception( esc_html__( 'Invalid period', 'latepoint' ) );
83 }
84 $work_period = reset( $work_periods );
85
86 $start_ampm = $work_period['start_time']['ampm'] ?? false;
87 $end_ampm = $work_period['end_time']['ampm'] ?? false;
88
89 $blocked_period->start_time = OsTimeHelper::convert_time_to_minutes( $work_period['start_time']['formatted_value'], $start_ampm );
90 $blocked_period->end_time = OsTimeHelper::convert_time_to_minutes( $work_period['end_time']['formatted_value'], $end_ampm );
91
92 $blocked_period->agent_id = $blocked_period_settings['agent_id'];
93 $blocked_period->service_id = $blocked_period_settings['service_id'];
94 $blocked_period->location_id = $blocked_period_settings['location_id'];
95
96
97 if ( $blocked_period->save() ) {
98 $status = LATEPOINT_STATUS_SUCCESS;
99 $response_html = sprintf( esc_html__( 'Period blocked for %s', 'latepoint' ), OsTimeHelper::get_readable_date( $day_date ) );
100 } else {
101 throw new Exception( implode( ',', $blocked_period->get_error_messages() ?? esc_html__( 'Error', 'latepoint' ) ) );
102 }
103 }
104
105 } catch ( Exception $e ) {
106 $status = LATEPOINT_STATUS_ERROR;
107 $response_html = $e->getMessage();
108 }
109 wp_send_json( array( 'status' => $status, 'message' => $response_html ) );
110 }
111
112 public function quick_actions() {
113 if(!empty($this->params['blocked_period_id'])){
114 $blocked_period = new OsOffPeriodModel(sanitize_text_field($this->params['blocked_period_id']));
115 if($blocked_period->is_new_record()){
116 wp_send_json( array( 'status' => LATEPOINT_STATUS_ERROR, 'message' => __('Invalid Blocked Period', 'latepoint') ) );
117 }
118 $start_date = new OsWpDateTime($blocked_period->start_date);
119 }else{
120 $blocked_period = new OsOffPeriodModel();
121
122 $start_date = new OsWpDateTime(sanitize_text_field( $this->params['target_date'] ));
123 $blocked_period->start_date = $start_date->format( 'Y-m-d' );
124 $blocked_period->start_time = sanitize_text_field( $this->params['start_time'] ?? 600 );
125 $blocked_period->agent_id = sanitize_text_field( $this->params['agent_id'] ?? 0 );
126 $blocked_period->service_id = sanitize_text_field( $this->params['service_id'] ?? 0 );
127 $blocked_period->location_id = sanitize_text_field( $this->params['location_id'] ?? 0 );
128
129 }
130
131 $this->vars['blocked_period'] = $blocked_period;
132 $this->vars['start_date'] = $start_date;
133 $this->vars['readable_start_date'] = OsTimeHelper::get_readable_date($start_date);
134
135 $this->vars['agents_list'] = OsAgentHelper::get_agents_list( true, [], true );
136 $this->vars['services_list'] = OsServiceHelper::get_services_list( true, [], true );
137 $this->vars['locations_list'] = OsLocationHelper::get_locations_list( true, [], true );
138
139 $response_html = $this->render( $this->views_folder . __FUNCTION__, 'none' );
140 wp_send_json( array( 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ) );
141 }
142
143 public function view() {
144 $this->vars['page_header'] = '';
145
146 $today_date = new OsWpDateTime( 'today' );
147
148
149 $services = ( new OsServiceModel() )->filter_allowed_records()->should_be_active()->get_results_as_models();
150 $locations = ( new OsLocationModel() )->filter_allowed_records()->should_be_active()->get_results_as_models();
151 $agents = ( new OsAgentModel() )->filter_allowed_records()->should_be_active()->get_results_as_models();
152
153 // extract groups from services
154 $service_categories = new OsServiceCategoryModel();
155 $service_categories = $service_categories->get_results_as_models();
156 $categorized_services_list = [];
157 // uncategorized
158 $categorized_services_list['category_none'] = [ 'name' => __( 'Uncategorized', 'latepoint' ), 'items' => [] ];
159
160 if ( $service_categories ) {
161 foreach ( $service_categories as $service_category ) {
162 $categorized_services_list[ 'category_' . $service_category->id ] = [ 'name' => $service_category->name, 'items' => [] ];
163 }
164 }
165 foreach ( $services as $service ) {
166 if ( $service->category_id ) {
167 $categorized_services_list[ 'category_' . $service->category_id ]['items'][] = $service;
168 } else {
169 $categorized_services_list['category_none']['items'][] = $service;
170 }
171 }
172
173 $this->vars['categorized_services_list'] = $categorized_services_list;
174
175 $default_calendar_settings = [
176 'view' => OsAuthHelper::get_current_user()->get_wp_user_meta( 'latepoint_calendar_view', 'day' ),
177 'target_date_string' => $today_date->format( 'Y-m-d' ),
178 'show_service_ids' => OsUtilHelper::get_array_of_ids_from_array_of_models( $services ),
179 'show_agent_ids' => OsUtilHelper::get_array_of_ids_from_array_of_models( $agents ),
180 'show_location_ids' => OsUtilHelper::get_array_of_ids_from_array_of_models( $locations ),
181 'overlay_service_availability' => LATEPOINT_VALUE_OFF,
182 'availability_service_id' => '',
183 'selected_agent_id' => '' // used for weekly calendar only
184 ];
185 $calendar_settings = ! empty( $this->params['calendar_settings'] ) ? array_merge( $default_calendar_settings, $this->params['calendar_settings'] ) : $default_calendar_settings;
186 if ( $default_calendar_settings['view'] != $calendar_settings['view'] ) {
187 // update default view for this user
188 OsAuthHelper::get_current_user()->update_wp_user_meta( 'latepoint_calendar_view', $calendar_settings['view'] );
189 }
190
191
192 if ( $agents ) {
193 // show only agents that offer services and locations that are selected to be shown
194 $connected_agent_ids = OsConnectorHelper::get_connected_object_ids( 'agent_id', [
195 'service_id' => $calendar_settings['show_service_ids'],
196 'location_id' => $calendar_settings['show_location_ids']
197 ] );
198 $connected_agents = [];
199 $connected_show_agents_ids = [];
200 foreach ( $agents as $agent ) {
201 if ( ! in_array( $agent->id, $connected_agent_ids ) || ! in_array( $agent->id, $calendar_settings['show_agent_ids'] ) ) {
202 continue;
203 }
204 $connected_agents[] = $agent;
205 $connected_show_agents_ids[] = $agent->id;
206 }
207 $calendar_settings['show_agent_ids'] = $connected_show_agents_ids;
208 $agents = $connected_agents;
209 if ( $agents && ( empty( $calendar_settings['selected_agent_id'] ) || ! in_array( $calendar_settings['selected_agent_id'], $connected_show_agents_ids ) ) ) {
210 $calendar_settings['selected_agent_id'] = $agents[0]->id;
211 }
212 }
213
214 // CHECK IF BOOKABLE RESOURCES EXIST
215 if ( empty( $services ) || empty( $agents ) || empty( $locations ) ) {
216 if ( $this->get_return_format() == 'json' ) {
217 $response_html = $this->render( $this->views_folder . 'missing_resources.php', 'none' );
218 $this->send_json( [ 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ] );
219 } else {
220 $this->format_render( 'missing_resources' );
221 exit();
222 }
223 }
224
225 $selected_service_for_availability = false;
226 if ( $calendar_settings['overlay_service_availability'] == LATEPOINT_VALUE_ON && ! empty( $calendar_settings['availability_service_id'] ) ) {
227 foreach ( $services as $service ) {
228 if ( $service->id == $calendar_settings['availability_service_id'] ) {
229 $selected_service_for_availability = clone $service;
230 break;
231 }
232 }
233 }
234
235
236 if ( $calendar_settings['view'] == 'list' ) {
237 $per_page = OsSettingsHelper::get_number_of_records_per_page();
238 $bookings = new OsBookingModel();
239 $bookings = $bookings->get_upcoming_bookings( $calendar_settings['show_agent_ids'], false, $calendar_settings['show_service_ids'], $calendar_settings['show_location_ids'], $per_page );
240 $this->vars['bookings'] = $bookings;
241
242 $calendar_start = ( new OsWpDateTime( 'now' ) );
243 $calendar_end = false;
244
245 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F' ), false );
246 } else {
247 switch ( $calendar_settings['view'] ) {
248 case 'day':
249 $calendar_start = new OsWpDateTime( $calendar_settings['target_date_string'] );
250 $calendar_end = new OsWpDateTime( $calendar_settings['target_date_string'] );
251 $this->vars['day_view_calendar_min_height'] = OsSettingsHelper::get_day_calendar_min_height();
252 $prev_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '-1 day' );
253 $next_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '+1 day' );
254 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F j' ), false );
255 break;
256 case 'week':
257 $calendar_start = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'monday this week' );
258 $calendar_end = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'sunday this week' );
259 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F' ), false ) . ' ' . $calendar_start->format( 'j' ) . ' - ' . OsUtilHelper::translate_months( $calendar_end->format( 'F' ), false ) . ' ' . $calendar_end->format( 'j' );
260 $prev_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '-7 days' );
261 $next_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '+7 days' );
262 break;
263 case 'month':
264 $calendar_start = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of this month' );
265 $calendar_end = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'last day of this month' );
266 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F' ), false );
267 $prev_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of previous month' );
268 $next_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of next month' );
269 break;
270 }
271 $booking_request = new \LatePoint\Misc\BookingRequest();
272 $booking_request->agent_id = $calendar_settings['show_agent_ids'];
273 $booking_request->service_id = $calendar_settings['show_service_ids'];
274 $booking_request->location_id = $calendar_settings['show_location_ids'];
275
276 if ( $selected_service_for_availability ) {
277 $booking_request->service_id = $selected_service_for_availability->id;
278 $booking_request->duration = $selected_service_for_availability->duration; // TODO add capacity and duration select box and POST params if multiple durations in a service
279 $timeblock_interval = $selected_service_for_availability->get_timeblock_interval();
280 } else {
281 $timeblock_interval = OsSettingsHelper::get_default_timeblock_interval();
282 }
283
284
285 $resources = OsResourceHelper::get_resources_grouped_by_day( $booking_request, $calendar_start, $calendar_end );
286
287 // if user wants to overlay availability for a specific service - we need to create a separate set of resources
288 // for the work boundaries, since the original one is only querying that service and not all other "shown" services,
289 // we want to show start and work time for all shown services, not just the selected one for the availability overlay
290 // we need to check if there is a single "shown" service - in this case we don't need a separate call for work boundaries
291 if ( count( $calendar_settings['show_service_ids'] ) > 1 && $selected_service_for_availability ) {
292 $booking_request_for_shown_services = clone $booking_request;
293 $booking_request_for_shown_services->service_id = $calendar_settings['show_service_ids'];
294 $resources_for_work_boundaries = OsResourceHelper::get_resources_grouped_by_day( $booking_request_for_shown_services, $calendar_start, $calendar_end );
295 $work_boundaries = OsResourceHelper::get_work_boundaries_for_groups_of_resources( $resources_for_work_boundaries );
296 } else {
297 $work_boundaries = OsResourceHelper::get_work_boundaries_for_groups_of_resources( $resources );
298 }
299
300 $work_time_periods_grouped_by_date_and_agent = [];
301 $bookings_grouped_by_date_and_agent = [];
302 foreach ( $agents as $agent ) {
303 for ( $day_date = clone $calendar_start; $day_date <= $calendar_end; $day_date->modify( '+1 day' ) ) {
304 // fill in all days and agents bookings with blanks
305 $bookings_grouped_by_date_and_agent[ $day_date->format( 'Y-m-d' ) ][ $agent->id ] = [];
306 $work_time_periods_grouped_by_date_and_agent[ $day_date->format( 'Y-m-d' ) ][ $agent->id ] = [];
307 $work_boundaries_grouped_by_date_and_agent[ $day_date->format( 'Y-m-d' ) ][ $agent->id ] = OsResourceHelper::get_work_boundaries_for_groups_of_resources( [ $resources[ $day_date->format( 'Y-m-d' ) ] ] );
308 }
309 }
310 $filter = new \LatePoint\Misc\Filter( [
311 'date_from' => $calendar_start->format( 'Y-m-d' ),
312 'date_to' => $calendar_end->format( 'Y-m-d' ),
313 'service_id' => $calendar_settings['show_service_ids'],
314 'agent_id' => $calendar_settings['show_agent_ids'],
315 'location_id' => $calendar_settings['show_location_ids'],
316 'statuses' => OsCalendarHelper::get_booking_statuses_to_display_on_calendar()
317 ] );
318 $filter = OsRolesHelper::filter_allowed_records_from_arguments_or_filter( $filter );
319
320 // loop bookings to fill in array
321 $bookings = OsBookingHelper::get_bookings( $filter, true );
322 foreach ( $bookings as $booking ) {
323 $bookings_grouped_by_date_and_agent[ $booking->start_date ][ $booking->agent_id ][] = $booking;
324 }
325
326 // loop resources to fill in work periods array
327 foreach ( $resources as $day => $daily_resources ) {
328 foreach ( $daily_resources as $daily_resource ) {
329 $work_time_periods_grouped_by_date_and_agent[ $day ][ $daily_resource->agent_id ] = array_merge( $work_time_periods_grouped_by_date_and_agent[ $day ][ $daily_resource->agent_id ], $daily_resource->work_time_periods );
330 }
331 }
332
333 $this->vars['bookings_grouped_by_date_and_agent'] = $bookings_grouped_by_date_and_agent;
334 $this->vars['work_boundaries_grouped_by_date_and_agent'] = $work_boundaries_grouped_by_date_and_agent;
335 $this->vars['timeblock_interval'] = $timeblock_interval;
336
337 $this->vars['booking_request'] = $booking_request;
338 $this->vars['work_time_periods_grouped_by_date_and_agent'] = $work_time_periods_grouped_by_date_and_agent;
339 $this->vars['prev_target_date'] = $prev_target_date;
340 $this->vars['next_target_date'] = $next_target_date;
341 $this->vars['resources'] = $resources;
342 $this->vars['work_boundaries'] = $work_boundaries;
343 $this->vars['work_total_minutes'] = $work_boundaries->end_time - $work_boundaries->start_time;
344 }
345
346 $top_date_year = ! empty( $calendar_start ) ? $calendar_start->format( 'Y' ) : '';
347
348 $this->vars['calendar_start'] = $calendar_start;
349 $this->vars['calendar_end'] = $calendar_end;
350
351 $this->vars['date_format'] = OsSettingsHelper::get_readable_date_format( true );
352
353 $this->vars['target_date'] = new OsWpDateTime( $calendar_settings['target_date_string'] );
354 $this->vars['today_date'] = $today_date;
355 $this->vars['top_date_label'] = $top_date_label;
356
357 $this->vars['agents'] = $agents;
358 $this->vars['services'] = $services;
359 $this->vars['locations'] = $locations;
360
361 $this->vars['calendar_settings'] = $calendar_settings;
362
363 if ( $this->get_return_format() == 'json' ) {
364 $response_html = $this->render( $this->views_folder . 'scopes/_' . $calendar_settings['view'], 'none' );
365 $this->send_json( [ 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html, 'top_date_label' => $top_date_label, 'top_date_year' => $top_date_year ] );
366 } else {
367 $this->format_render( __FUNCTION__ );
368 }
369 }
370
371
372 public function load_monthly_calendar_days_only() {
373 $target_date = new OsWpDateTime( $this->params['target_date_string'] );
374 $this->vars['target_date'] = $target_date;
375
376 $this->set_layout( 'none' );
377 $this->format_render( __FUNCTION__ );
378 }
379
380
381 }
382
383 endif;