PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.1.91
LatePoint – Calendar Booking Plugin for Appointments and Events v5.1.91
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 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / controllers / calendars_controller.php
latepoint / lib / controllers Last commit date
activities_controller.php 1 year ago auth_controller.php 1 year ago booking_form_settings_controller.php 1 year ago bookings_controller.php 1 year ago calendars_controller.php 1 year ago carts_controller.php 1 year ago controller.php 1 year ago customer_cabinet_controller.php 1 year ago customers_controller.php 1 year ago dashboard_controller.php 1 year ago default_agent_controller.php 1 year ago events_controller.php 1 year ago form_fields_controller.php 1 year ago integrations_controller.php 1 year ago invoices_controller.php 1 year ago manage_booking_by_key_controller.php 1 year ago manage_order_by_key_controller.php 1 year ago notifications_controller.php 1 year ago orders_controller.php 1 year ago pro_controller.php 1 year ago process_jobs_controller.php 1 year ago processes_controller.php 1 year ago search_controller.php 1 year ago services_controller.php 1 year ago settings_controller.php 1 year ago steps_controller.php 1 year ago stripe_connect_controller.php 1 year ago support_topics_controller.php 1 year ago todos_controller.php 1 year ago transactions_controller.php 1 year ago wizard_controller.php 1 year ago
calendars_controller.php
383 lines
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;