PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.1
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.1
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 9 months ago booking_form_settings_controller.php 1 year ago bookings_controller.php 1 year ago calendars_controller.php 9 months ago carts_controller.php 1 year ago controller.php 9 months ago customer_cabinet_controller.php 9 months ago customers_controller.php 9 months ago dashboard_controller.php 9 months ago default_agent_controller.php 1 year ago events_controller.php 1 year ago form_fields_controller.php 9 months ago integrations_controller.php 9 months 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 9 months ago processes_controller.php 1 year ago search_controller.php 1 year ago services_controller.php 9 months ago settings_controller.php 1 year ago steps_controller.php 9 months ago stripe_connect_controller.php 9 months 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
387 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 if($calendar_start->format( 'M' ) == $calendar_end->format( 'M' )){
260 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F' ), false ) . ' ' . $calendar_start->format( 'j' ) . ' - ' . $calendar_end->format( 'j' );
261 }else{
262 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'M' ), false ) . ' ' . $calendar_start->format( 'j' ) . ' - ' . OsUtilHelper::translate_months( $calendar_end->format( 'M' ), false ) . ' ' . $calendar_end->format( 'j' );
263 }
264 $prev_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '-7 days' );
265 $next_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( '+7 days' );
266 break;
267 case 'month':
268 $calendar_start = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of this month' );
269 $calendar_end = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'last day of this month' );
270 $top_date_label = OsUtilHelper::translate_months( $calendar_start->format( 'F' ), false );
271 $prev_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of previous month' );
272 $next_target_date = ( new OsWpDateTime( $calendar_settings['target_date_string'] ) )->modify( 'first day of next month' );
273 break;
274 }
275 $booking_request = new \LatePoint\Misc\BookingRequest();
276 $booking_request->agent_id = $calendar_settings['show_agent_ids'];
277 $booking_request->service_id = $calendar_settings['show_service_ids'];
278 $booking_request->location_id = $calendar_settings['show_location_ids'];
279
280 if ( $selected_service_for_availability ) {
281 $booking_request->service_id = $selected_service_for_availability->id;
282 $booking_request->duration = $selected_service_for_availability->duration; // TODO add capacity and duration select box and POST params if multiple durations in a service
283 $timeblock_interval = $selected_service_for_availability->get_timeblock_interval();
284 } else {
285 $timeblock_interval = OsSettingsHelper::get_default_timeblock_interval();
286 }
287
288
289 $resources = OsResourceHelper::get_resources_grouped_by_day( $booking_request, $calendar_start, $calendar_end );
290
291 // if user wants to overlay availability for a specific service - we need to create a separate set of resources
292 // for the work boundaries, since the original one is only querying that service and not all other "shown" services,
293 // we want to show start and work time for all shown services, not just the selected one for the availability overlay
294 // we need to check if there is a single "shown" service - in this case we don't need a separate call for work boundaries
295 if ( count( $calendar_settings['show_service_ids'] ) > 1 && $selected_service_for_availability ) {
296 $booking_request_for_shown_services = clone $booking_request;
297 $booking_request_for_shown_services->service_id = $calendar_settings['show_service_ids'];
298 $resources_for_work_boundaries = OsResourceHelper::get_resources_grouped_by_day( $booking_request_for_shown_services, $calendar_start, $calendar_end );
299 $work_boundaries = OsResourceHelper::get_work_boundaries_for_groups_of_resources( $resources_for_work_boundaries );
300 } else {
301 $work_boundaries = OsResourceHelper::get_work_boundaries_for_groups_of_resources( $resources );
302 }
303
304 $work_time_periods_grouped_by_date_and_agent = [];
305 $bookings_grouped_by_date_and_agent = [];
306 foreach ( $agents as $agent ) {
307 for ( $day_date = clone $calendar_start; $day_date <= $calendar_end; $day_date->modify( '+1 day' ) ) {
308 // fill in all days and agents bookings with blanks
309 $bookings_grouped_by_date_and_agent[ $day_date->format( 'Y-m-d' ) ][ $agent->id ] = [];
310 $work_time_periods_grouped_by_date_and_agent[ $day_date->format( 'Y-m-d' ) ][ $agent->id ] = [];
311 $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' ) ] ] );
312 }
313 }
314 $filter = new \LatePoint\Misc\Filter( [
315 'date_from' => $calendar_start->format( 'Y-m-d' ),
316 'date_to' => $calendar_end->format( 'Y-m-d' ),
317 'service_id' => $calendar_settings['show_service_ids'],
318 'agent_id' => $calendar_settings['show_agent_ids'],
319 'location_id' => $calendar_settings['show_location_ids'],
320 'statuses' => OsCalendarHelper::get_booking_statuses_to_display_on_calendar()
321 ] );
322 $filter = OsRolesHelper::filter_allowed_records_from_arguments_or_filter( $filter );
323
324 // loop bookings to fill in array
325 $bookings = OsBookingHelper::get_bookings( $filter, true );
326 foreach ( $bookings as $booking ) {
327 $bookings_grouped_by_date_and_agent[ $booking->start_date ][ $booking->agent_id ][] = $booking;
328 }
329
330 // loop resources to fill in work periods array
331 foreach ( $resources as $day => $daily_resources ) {
332 foreach ( $daily_resources as $daily_resource ) {
333 $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 );
334 }
335 }
336
337 $this->vars['bookings_grouped_by_date_and_agent'] = $bookings_grouped_by_date_and_agent;
338 $this->vars['work_boundaries_grouped_by_date_and_agent'] = $work_boundaries_grouped_by_date_and_agent;
339 $this->vars['timeblock_interval'] = $timeblock_interval;
340
341 $this->vars['booking_request'] = $booking_request;
342 $this->vars['work_time_periods_grouped_by_date_and_agent'] = $work_time_periods_grouped_by_date_and_agent;
343 $this->vars['prev_target_date'] = $prev_target_date;
344 $this->vars['next_target_date'] = $next_target_date;
345 $this->vars['resources'] = $resources;
346 $this->vars['work_boundaries'] = $work_boundaries;
347 $this->vars['work_total_minutes'] = $work_boundaries->end_time - $work_boundaries->start_time;
348 }
349
350 $top_date_year = ! empty( $calendar_start ) ? $calendar_start->format( 'Y' ) : '';
351
352 $this->vars['calendar_start'] = $calendar_start;
353 $this->vars['calendar_end'] = $calendar_end;
354
355 $this->vars['date_format'] = OsSettingsHelper::get_readable_date_format( true );
356
357 $this->vars['target_date'] = new OsWpDateTime( $calendar_settings['target_date_string'] );
358 $this->vars['today_date'] = $today_date;
359 $this->vars['top_date_label'] = $top_date_label;
360
361 $this->vars['agents'] = $agents;
362 $this->vars['services'] = $services;
363 $this->vars['locations'] = $locations;
364
365 $this->vars['calendar_settings'] = $calendar_settings;
366
367 if ( $this->get_return_format() == 'json' ) {
368 $response_html = $this->render( $this->views_folder . 'scopes/_' . $calendar_settings['view'], 'none' );
369 $this->send_json( [ 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html, 'top_date_label' => $top_date_label, 'top_date_year' => $top_date_year ] );
370 } else {
371 $this->format_render( __FUNCTION__ );
372 }
373 }
374
375
376 public function load_monthly_calendar_days_only() {
377 $target_date = new OsWpDateTime( $this->params['target_date_string'] );
378 $this->vars['target_date'] = $target_date;
379
380 $this->set_layout( 'none' );
381 $this->format_render( __FUNCTION__ );
382 }
383
384
385 }
386
387 endif;