PluginProbe ʕ •ᴥ•ʔ
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.2.2
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.2.2
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 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 / helpers / work_periods_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago auth_helper.php 9 months ago blocks_helper.php 1 year ago booking_helper.php 1 year ago bricks_helper.php 1 year ago bundles_helper.php 1 year ago calendar_helper.php 9 months ago carts_helper.php 1 year ago connector_helper.php 1 year ago csv_helper.php 9 months ago customer_helper.php 9 months ago customer_import_helper.php 9 months ago database_helper.php 9 months ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 9 months ago encrypt_helper.php 1 year ago events_helper.php 1 year ago form_helper.php 9 months ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 9 months ago license_helper.php 1 year ago location_helper.php 1 year ago marketing_systems_helper.php 1 year ago meeting_systems_helper.php 1 year ago menu_helper.php 9 months ago meta_helper.php 1 year ago migrations_helper.php 1 year ago money_helper.php 1 year ago notifications_helper.php 9 months ago order_intent_helper.php 9 months ago orders_helper.php 1 year ago otp_helper.php 9 months ago pages_helper.php 1 year ago params_helper.php 1 year ago payments_helper.php 1 year ago price_breakdown_helper.php 1 year ago process_jobs_helper.php 1 year ago processes_helper.php 1 year ago replacer_helper.php 1 year ago resource_helper.php 1 year ago roles_helper.php 9 months ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 1 year ago settings_helper.php 9 months ago short_links_systems_helper.php 9 months ago shortcodes_helper.php 9 months ago sms_helper.php 1 year ago steps_helper.php 9 months ago stripe_connect_helper.php 9 months ago styles_helper.php 9 months ago support_topics_helper.php 1 year ago time_helper.php 9 months ago timeline_helper.php 9 months ago transaction_helper.php 1 year ago transaction_intent_helper.php 1 year ago util_helper.php 9 months ago version_specific_updates_helper.php 9 months ago whatsapp_helper.php 1 year ago work_periods_helper.php 1 year ago wp_datetime.php 1 year ago wp_user_helper.php 1 year ago
work_periods_helper.php
737 lines
1 <?php
2
3 class OsWorkPeriodsHelper {
4
5
6 public static $existing_work_periods;
7
8
9 /**
10 * @param \LatePoint\Misc\Filter $filter
11 * @return array
12 *
13 * Returns an array of WorkPeriod objects, grouped by a weekday 1 (for Monday) through 7 (for Sunday).
14 * example: ['1' => [], '2' => [], ...]
15 *
16 */
17 public static function get_work_periods_grouped_by_weekday(\LatePoint\Misc\Filter $filter): array{
18
19 $work_periods = OsWorkPeriodsHelper::get_work_periods($filter);
20
21 $weekday_periods = ['1' => [], '2' => [], '3' => [], '4' => [], '5' => [], '6' => [], '7' => []];
22
23 if($work_periods){
24 // Loop through the found work periods and group by a week day
25 foreach($work_periods as $work_period){
26 $weekday_periods[$work_period->week_day][] = $work_period;
27 }
28 }
29 return $weekday_periods;
30 }
31
32
33 /**
34 *
35 * Finds work periods that match a filter.
36 *
37 * @param \LatePoint\Misc\Filter $filter
38 * @return \LatePoint\Misc\WorkPeriod[]
39 */
40 public static function get_work_periods(\LatePoint\Misc\Filter $filter, bool $as_models = false): array{
41
42 self::set_default_working_hours();
43
44 $work_periods_model = new OsWorkPeriodModel();
45 $query_args = array();
46
47 // if connections are passed - query by connection
48 if($filter->connections){
49 $connection_conditions = [];
50 foreach($filter->connections as $connection){
51 $connection_conditions[] = ['AND' => ['agent_id' => [0, $connection->agent_id], 'service_id' => [0, $connection->service_id], 'location_id' => [0, $connection->location_id]]];
52 }
53 $query_args['AND'][] = ['OR' => $connection_conditions];
54 }else{
55 // Service query
56 if($filter->exact_match){
57 // search only for schedules that belong to passed service_id
58 $query_args['service_id'] = $filter->service_id;
59 }else{
60 $query_args['service_id'] = array_unique(is_array($filter->service_id) ? array_merge($filter->service_id, [0]) : [$filter->service_id, 0]);
61 }
62
63 // Location query
64 if ($filter->exact_match) {
65 // search only for schedules that belong to passed location_id
66 $query_args['location_id'] = $filter->location_id;
67 } else {
68 $query_args['location_id'] = array_unique(is_array($filter->location_id) ? array_merge($filter->location_id, [0]) : [$filter->location_id, 0]);
69 }
70
71 // Agent query
72 if($filter->exact_match){
73 // search only for schedules that belong to passed agent_id
74 $query_args['agent_id'] = $filter->agent_id;
75 }else{
76 $query_args['agent_id'] = array_unique(is_array($filter->agent_id) ? array_merge($filter->agent_id, [0]) : [$filter->agent_id, 0]);
77 }
78 }
79
80 if($filter->week_day){
81 $query_args['week_day'] = $filter->week_day;
82 }else if($filter->date_from){
83 $date_from_obj = new OsWpDateTime($filter->date_from);
84 // date is provided, try to get week day from it
85 if(!$filter->date_to || ($filter->date_from == $filter->date_to)){
86 // single date
87 $query_args['week_day'] = $date_from_obj->format('N');
88 }else{
89 // date range
90 $date_to_obj = new OsWpDateTime(($filter->date_to));
91 // if difference between dates is less than a week - it means the days include every weekday possible,
92 // otherwise loop through them and find which weekdays we need to query for
93 if($date_to_obj->diff($date_from_obj)->format("%a") < 6){
94 for($day_date=clone $date_from_obj; $day_date<=$date_to_obj; $day_date->modify('+1 day')){
95 $query_args['week_day'][] = $day_date->format('N');
96 }
97 }
98 }
99 }
100
101 if($filter->date_from){
102 if($filter->date_to && ($filter->date_from != $filter->date_to)){
103 # both from and to date provided and are different - means it's a range
104 if($filter->exact_match){
105 # custom date should be exactly in range, can not be NULL
106 $query_args['custom_date >='] = $filter->date_from;
107 $query_args['custom_date <='] = $filter->date_to;
108 }else{
109 # custom date should be in range, or NULL
110 $query_args['AND'][] = ['OR' => ['custom_date' => 'IS NULL', 'AND' => ['custom_date >=' => $filter->date_from, 'custom_date <=' => $filter->date_to]]];
111 }
112 }else{
113 # only date_from provided - means it's a specific date requested
114 if($filter->exact_match) {
115 # custom date should match requested date, can not be NULL
116 $query_args['custom_date'] = $filter->date_from;
117 }else{
118 # custom date should match requested date or NULL
119 $query_args['custom_date']['OR'] = ['IS NULL', $filter->date_from];
120 }
121 }
122 }else{
123 $query_args['custom_date'] = 'IS NULL';
124 }
125
126 $work_periods_model->where($query_args)->order_by('custom_date DESC, agent_id DESC, service_id DESC, location_id DESC, start_time asc');
127 if($as_models){
128 $work_periods = $work_periods_model->get_results_as_models();
129 }else{
130 $work_periods_arr = $work_periods_model->get_results();
131 $work_periods = [];
132 if($work_periods_arr){
133 foreach($work_periods_arr as $work_period){
134 // Convert return row into work period object
135 $work_periods[] = new \LatePoint\Misc\WorkPeriod($work_period);
136 }
137 }
138 }
139 return $work_periods;
140 }
141
142
143
144
145 /**
146 * @param \LatePoint\Misc\BookingRequest $booking_request
147 * @param array $work_periods_arr
148 * @return bool
149 */
150 public static function is_timeframe_in_work_periods(\LatePoint\Misc\BookingRequest $booking_request, array $work_periods_arr): bool{
151 if(empty($work_periods_arr)) return false;
152 foreach($work_periods_arr as $work_period){
153 // loop throught periods and check if it's inside of at least one work period (we ignore buffer here, because you generally don't care about buffer when you start or end work)
154 if(OsBookingHelper::is_period_inside_another($booking_request->start_time, $booking_request->end_time, $work_period->start_time, $work_period->end_time)){
155 return true;
156 }
157 }
158 return false;
159 }
160
161
162 /**
163 * @param $dated_work_periods_arr
164 * @return array
165 *
166 * Returns array in format [start_minutes, end_minutes], example 8:00-18:00 would be returned as [480, 1080]
167 */
168 public static function get_work_start_end_time_for_date_range(array $dated_work_periods): array{
169 $work_periods_arr = [];
170 foreach($dated_work_periods as $date => $work_periods_for_date){
171 $work_periods_arr = array_merge($work_periods_arr, $work_periods_for_date);
172 }
173 $work_periods_arr = array_unique($work_periods_arr);
174 return OsWorkPeriodsHelper::get_work_start_end_time($work_periods_arr);
175 }
176
177
178 /**
179 * @param array $agent_ids
180 * @param \LatePoint\Misc\Filter $filter
181 * @return array
182 *
183 * Returns array in format [start_minutes, end_minutes], for example 08:00-18:00 will be returned as [480, 1080]
184 */
185 public static function get_work_start_end_time_for_date_multi_agent(array $agent_ids, \LatePoint\Misc\Filter $filter): array{
186 $work_start_times = [];
187 $work_end_times = [];
188 $cloned_filter = clone $filter;
189 foreach($agent_ids as $agent_id){
190 $cloned_filter->agent_id = $agent_id;
191 $work_times = OsWorkPeriodsHelper::get_work_start_end_time_for_date($cloned_filter);
192 if($work_times[0] == 0 && $work_times[1] == 0){
193 // day off, do not count
194 }else{
195 $work_start_times[] = $work_times[0];
196 $work_end_times[] = $work_times[1];
197 }
198 }
199 if(empty($work_start_times)) $work_start_times = [0];
200 if(empty($work_end_times)) $work_end_times = [0];
201 return array(min($work_start_times), max($work_end_times));
202 }
203
204
205 /**
206 * @param \LatePoint\Misc\Filter $filter
207 * @return array
208 *
209 * Returns array in format [start_minutes, end_minutes], example 8:00-18:00 would be returned as [480, 1080]
210 */
211 public static function get_work_start_end_time_for_date(\LatePoint\Misc\Filter $filter): array{
212 $work_periods_arr = OsWorkPeriodsHelper::get_work_periods($filter);
213 return OsWorkPeriodsHelper::get_work_start_end_time($work_periods_arr);
214 }
215
216
217 /**
218 * @param \LatePoint\Misc\WorkPeriod[]
219 * @return array
220 *
221 * Returns array in format [start_minutes, end_minutes], example 8:00-18:00 would be returned as [480, 1080]
222 */
223 public static function get_work_start_end_time(array $work_periods_arr): array{
224 $work_start_minutes = 0;
225 $work_end_minutes = 0;
226 foreach($work_periods_arr as $work_period){
227 if($work_period->start_time == $work_period->end_time) continue;
228 $work_start_minutes = ($work_start_minutes > 0) ? min($work_period->start_time, $work_start_minutes) : $work_period->start_time;
229 $work_end_minutes = ($work_end_minutes > 0) ? max($work_period->end_time, $work_end_minutes) : $work_period->end_time;
230 }
231 return array($work_start_minutes, $work_end_minutes);
232 }
233
234
235 // args: period_id, week_day, is_active, start_time, end_time, custom_date, agent_id, service_id
236 public static function generate_work_period_form($args = array(), $allow_remove = true){
237 $default_args = array(
238 'period_id' => false,
239 'week_day' => 1,
240 'allow_remove' => true,
241 'start_time' => 480,
242 'end_time' => 1080,
243 'agent_id' => 0,
244 'location_id' => 0,
245 'service_id' => 0
246 );
247 $args = array_merge($default_args, $args);
248
249 $period_id = (!$args['period_id']) ? 'new_'.$args['week_day'].'_'.OsUtilHelper::random_text() : $args['period_id'];
250 $period_html = '<div class="ws-period">';
251 $period_html.= OsFormHelper::time_field('work_periods['.$period_id.'][start_time]', __('Start', 'latepoint'), $args['start_time'], true);
252 $period_html.= OsFormHelper::time_field('work_periods['.$period_id.'][end_time]', __('Finish', 'latepoint'), $args['end_time'], true);
253 $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][week_day]', $args['week_day']);
254 $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][is_active]', self::is_period_active($args['start_time'], $args['end_time']), array('class' => 'is-active'));
255 $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][agent_id]', $args['agent_id']);
256 $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][location_id]', $args['location_id']);
257 $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][service_id]', $args['service_id']);
258 if(isset($args['custom_date'])) $period_html.= OsFormHelper::hidden_field('work_periods['.$period_id.'][custom_date]', $args['custom_date']);
259 if($allow_remove) $period_html.= '<button class="ws-period-remove"><i class="latepoint-icon latepoint-icon-x"></i></button>';
260 $period_html.= '</div>';
261 return $period_html;
262 }
263
264 public static function is_period_active($start_time, $end_time){
265 return (($start_time == 0) && ($end_time == 0)) ? false : true;
266 }
267
268 public static function save_work_periods($work_periods_to_save, $force_new = false){
269 $ids_to_save = array();
270 $inactive_weekdays = array();
271 // save passed periods
272 if($work_periods_to_save){
273 foreach($work_periods_to_save as $id => $work_period){
274 if(in_array($work_period['week_day'], $inactive_weekdays)) continue;
275 if($work_period['is_active'] == 0){
276 $work_period['start_time'] = 0;
277 $work_period['end_time'] = 0;
278 $inactive_weekdays[] = $work_period['week_day'];
279 }else{
280 $start_ampm = isset($work_period['start_time']['ampm']) ? $work_period['start_time']['ampm'] : false;
281 $end_ampm = isset($work_period['end_time']['ampm']) ? $work_period['end_time']['ampm'] : false;
282
283 $work_period['start_time'] = OsTimeHelper::convert_time_to_minutes($work_period['start_time']['formatted_value'], $start_ampm);
284 $work_period['end_time'] = OsTimeHelper::convert_time_to_minutes($work_period['end_time']['formatted_value'], $end_ampm);
285 }
286 if($force_new || substr( $id, 0, 4 ) === "new_"){
287 // new record
288 $work_period_obj = new OsWorkPeriodModel();
289 $work_period_obj->set_data($work_period);
290 $work_period_obj->save();
291 $ids_to_save[] = $work_period_obj->id;
292 }else{
293 // existing work period
294 $work_period_obj = new OsWorkPeriodModel($id);
295 if(!$work_period_obj){
296 $work_period_obj = new OsWorkPeriodModel();
297 unset($work_period['id']);
298 }
299 $work_period_obj->set_data($work_period);
300 if($work_period_obj->save()){
301 $ids_to_save[] = $work_period_obj->id;
302 }
303 }
304 }
305 }
306 if(!$force_new){
307 // if any periods were saved, get their agent and service info to delete obsolete records
308 $search_args = (isset($work_period_obj)) ? array('agent_id' => $work_period_obj->agent_id, 'service_id' => $work_period_obj->service_id, 'location_id' => $work_period_obj->location_id) : array();
309 if(isset($work_period_obj) && $work_period_obj->custom_date){
310 $search_args['custom_date'] = $work_period_obj->custom_date;
311 }else{
312 $search_args['custom_date'] = 'IS NULL';
313 }
314 $ids_in_db = OsWorkPeriodsHelper::get_periods_ids_by_args($search_args);
315
316 $period_ids_to_remove = array_diff($ids_in_db, $ids_to_save);
317 if(!empty($period_ids_to_remove)){
318 $work_period_obj = new OsWorkPeriodModel();
319 foreach($period_ids_to_remove as $period_id){
320 $work_period_obj->delete($period_id);
321 }
322 }
323 }
324 }
325
326
327
328 public static function get_periods_ids_by_args($args = array()){
329 $default_args = array(
330 'custom_date' => false,
331 'week_day' => false,
332 'service_id' => 0,
333 'location_id' => 0,
334 'agent_id' => 0);
335 $args = array_merge($default_args, $args);
336 if($args['custom_date']) $query_args['custom_date'] = $args['custom_date'];
337 if($args['week_day']) $query_args['week_day'] = $args['week_day'];
338 $query_args['agent_id'] = $args['agent_id'];
339 $query_args['location_id'] = $args['location_id'];
340 $query_args['service_id'] = $args['service_id'];
341
342 $work_periods_model = new OsWorkPeriodModel();
343 $work_periods_rows = $work_periods_model->select('id')->where($query_args)->get_results();
344 if(is_array($work_periods_rows)){
345 $ids = array_map(function($row){return $row->id; }, $work_periods_rows);
346 }else{
347 $ids = array();
348 }
349 return $ids;
350 }
351
352 /**
353 * @param OsWorkPeriodModel[] $work_periods
354 * @return OsWorkPeriodModel[]
355 */
356 public static function filter_periods(array $work_periods): array{
357 // remove overriden periods
358 $filtered_periods = [];
359 if(count($work_periods) > 1){
360 $reference = $work_periods[0];
361 $filtered_periods[] = $reference;
362 for($i = 1; $i < count($work_periods); $i++){
363 if($work_periods[$i]->week_day == $reference->week_day){
364 # periods are ordered by these attributes, loop through them and if
365 if( $work_periods[$i]->agent_id != $reference->agent_id ||
366 $work_periods[$i]->location_id != $reference->location_id ||
367 $work_periods[$i]->service_id != $reference->service_id ||
368 $work_periods[$i]->custom_date != $reference->custom_date)
369 {
370 // conflicting period, skip it
371 }else{
372 $filtered_periods[] = $work_periods[$i];
373 }
374 }else{
375 $reference = $work_periods[$i];
376 $filtered_periods[] = $reference;
377 }
378 }
379 return $filtered_periods;
380 }else{
381 return $work_periods;
382 }
383 }
384
385 public static function set_default_working_hours(){
386 $work_start_minutes = 8 * 60;
387 $work_end_minutes = 17 * 60;
388 $week_days = OsUtilHelper::get_weekday_numbers();
389
390 // Try to find existing work periods in the database
391 $work_periods_model = new OsWorkPeriodModel();
392 if(!self::$existing_work_periods){
393 self::$existing_work_periods = $work_periods_model->select('week_day')->where(array('agent_id' => 0, 'service_id' => 0, 'location_id' => 0))->where(array('custom_date' => 'IS NULL'))->group_by('week_day')->get_results(ARRAY_A);
394 if(self::$existing_work_periods){
395 self::$existing_work_periods = array_map(function($work_period){ return $work_period['week_day']; }, self::$existing_work_periods);
396 $week_days = array_diff($week_days, self::$existing_work_periods);
397 // if already had some work periods - set others to 0/0 because before we used to NOT store non working days in the database, now we set hours to 0/0 instead for day offs
398 $work_start_minutes = 0;
399 $work_end_minutes = 0;
400 }
401 if(!empty($week_days)){
402 foreach($week_days as $week_day){
403 $work_period = new OsWorkPeriodModel();
404 $work_period->service_id = 0;
405 $work_period->agent_id = 0;
406 $work_period->location_id = 0;
407 $work_period->week_day = $week_day;
408 $work_period->start_time = $work_start_minutes;
409 $work_period->end_time = $work_end_minutes;
410 $work_period->save();
411 }
412 }
413 }
414
415 }
416
417 public static function remove_periods_for_chain_id($chain_id){
418 $work_periods_model = new OsWorkPeriodModel();
419 $work_periods = $work_periods_model->delete_where(['chain_id' => $chain_id]);
420 return true;
421 }
422
423 public static function remove_periods_for_date(string $date, $args = array()): bool{
424 $default_args = [ 'agent_id' => 0, 'service_id' => 0, 'location_id' => 0];
425 $args = array_merge($default_args, $args);
426 $args['custom_date'] = $date;
427 $work_periods_model = new OsWorkPeriodModel();
428 $work_periods = $work_periods_model->where($args)->get_results_as_models();
429 if($work_periods){
430 foreach($work_periods as $work_period){
431 $work_period->delete();
432 }
433 }
434 return true;
435 }
436
437
438 public static function generate_days_with_custom_schedule($args = array()){
439 $default_args = [ 'agent_id' => 0, 'service_id' => 0, 'location_id' => 0];
440 $args = array_merge($default_args, $args);
441
442 $work_periods = new OsWorkPeriodModel();
443 $work_periods = $work_periods->where($args)->where([
444 'custom_date' => 'IS NOT NULL',
445 'custom_date >=' => OsTimeHelper::today_date(),
446 'OR' => ['start_time !=' => 0, 'end_time !=' => 0]])->group_by('custom_date, chain_id')->order_by('custom_date asc')->get_results_as_models();
447 $html = '';
448 if($work_periods && isset($work_periods[0])){
449 $date = new OsWpDateTime($work_periods[0]->custom_date);
450 $processing_year = $date->format('Y');
451 if($date->format('Y') != gmdate('Y')) $html.= '<div class="os-form-sub-header sub-level"><h3>'.esc_html($date->format('Y')).'</h3></div>';
452 }
453 $chained_periods = [];
454 $html.= '<div class="custom-day-work-periods">';
455 if($work_periods){
456 $total_periods = count($work_periods);
457 $i = 0;
458 foreach($work_periods as $work_period){
459 $i = $i + 1;
460 if(empty($work_period->custom_date)) continue;
461 if($work_period->chain_id){
462 $chained_periods[$work_period->chain_id][] = $work_period->custom_date;
463 if($i < $total_periods) continue;
464 }
465 if($chained_periods){
466
467 foreach($chained_periods as $chain_id => $chained_period){
468 $range_start_date = new OsWpDateTime(min($chained_period));
469 $range_end_date = new OsWpDateTime(max($chained_period));
470 if($processing_year != $range_start_date->format('Y')){
471 $html.= '</div><div class="os-form-sub-header sub-level"><h3>'.esc_html($range_start_date->format('Y')).'</h3></div><div class="custom-day-work-periods">';
472 $processing_year = $range_start_date->format('Y');
473 }
474 $html.= '<div class="custom-day-work-period is-range">';
475 $html.= '<a href="#" title="'.esc_attr__('Edit Date Range Schedule', 'latepoint').'" class="edit-custom-day" '.self::generate_custom_day_period_action($range_start_date->format('Y-m-d'), false, array_merge($args, ['chain_id' => $chain_id])).'><i class="latepoint-icon latepoint-icon-edit-3"></i></a>';
476 $html.= '<a href="#" data-os-pass-this="yes" data-os-after-call="latepoint_custom_day_removed" data-os-action="'.esc_attr(OsRouterHelper::build_route_name('settings', 'remove_chain_schedule')).'" data-os-params="'.esc_attr(OsUtilHelper::build_os_params(['chain_id' => $chain_id])).'" data-os-prompt="'.esc_attr__('Are you sure you want to remove custom schedule for this date range?', 'latepoint').'" title="'.esc_attr__('Remove Date Range Schedule', 'latepoint').'" class="remove-custom-day"><i class="latepoint-icon latepoint-icon-trash-2"></i></a>';
477 $html.= '<div class="custom-day-work-period-i">';
478 $html.= '<div class="custom-day-number">'.esc_html($range_start_date->format('d').' - '.$range_end_date->format('d')) .'</div>';
479 if($range_start_date->format('n') != $range_end_date->format('n')){
480 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($range_start_date->format('n')).'-'.OsUtilHelper::get_month_name_by_number($range_end_date->format('n'))).'</div>';
481 }else{
482 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($range_start_date->format('n'))).'</div>';
483 }
484 $html.= '</div>';
485 $work_periods_for_date_model = new OsWorkPeriodModel();
486 $work_periods_for_date = $work_periods_for_date_model->where($args)->where(['custom_date' => $range_start_date->format('Y-m-d'), 'chain_id' => $chain_id])->order_by('start_time asc')->get_results_as_models();
487 if($work_periods_for_date){
488 $html.= '<div class="custom-day-periods">';
489 foreach($work_periods_for_date as $work_period_for_date){
490 $html.= '<div class="custom-day-period">'. esc_html($work_period_for_date->nice_start_time.' - '.$work_period_for_date->nice_end_time). '</div>';
491 }
492 $html.= '</div>';
493 }
494 $html.= '</div>';
495 }
496 $chained_periods = [];
497 }
498 if(empty($work_period->chain_id)){
499 $date = new OsWpDateTime($work_period->custom_date);
500 if($processing_year != $date->format('Y')) $html.= '</div><div class="os-form-sub-header sub-level"><h3>'.esc_html($date->format('Y')).'</h3></div><div class="custom-day-work-periods">';
501 $html.= '<div class="custom-day-work-period">';
502 $html.= '<a href="#" title="'.esc_attr__('Edit Day Schedule', 'latepoint').'" class="edit-custom-day" '.self::generate_custom_day_period_action($work_period->custom_date, false, $args).'><i class="latepoint-icon latepoint-icon-edit-3"></i></a>';
503 $html.= '<a href="#" data-os-pass-this="yes" data-os-after-call="latepoint_custom_day_removed" data-os-action="'.esc_attr(OsRouterHelper::build_route_name('settings', 'remove_custom_day_schedule')).'" data-os-params="'.esc_attr(OsUtilHelper::build_os_params(array_merge($args, ['date' => $work_period->custom_date]))).'" data-os-prompt="'.esc_attr__('Are you sure you want to remove custom schedule for this day?', 'latepoint').'" title="'.esc_attr__('Remove Day Schedule', 'latepoint').'" class="remove-custom-day"><i class="latepoint-icon latepoint-icon-trash-2"></i></a>';
504 $html.= '<div class="custom-day-work-period-i">';
505 $html.= '<div class="custom-day-number">'.esc_html($date->format('d')).'</div>';
506 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($date->format('n'))).'</div>';
507 $html.= '</div>';
508 $work_periods_for_date_model = new OsWorkPeriodModel();
509 $work_periods_for_date = $work_periods_for_date_model->where($args)->where(['custom_date' => $work_period->custom_date,
510 'chain_id' => 'IS NULL',
511 'OR' => ['start_time !=' => 0, 'end_time !=' => 0]])->order_by('start_time asc')->get_results_as_models();
512 if($work_periods_for_date){
513 $html.= '<div class="custom-day-periods">';
514 foreach($work_periods_for_date as $work_period_for_date){
515 $html.= '<div class="custom-day-period">'. esc_html($work_period_for_date->nice_start_time.' - '.$work_period_for_date->nice_end_time). '</div>';
516 }
517 $html.= '</div>';
518 }
519 $html.= '</div>';
520 $processing_year = $date->format('Y');
521 }
522 }
523 }
524 $html.= '<a class="add-custom-day-w" '.self::generate_custom_day_period_action(false, false, $args).'>
525 <div class="add-custom-day-i">
526 <div class="add-day-graphic-w"><div class="add-day-plus"><i class="latepoint-icon latepoint-icon-plus4"></i></div></div><div class="add-day-label">'.esc_html__('Add Day', 'latepoint').'</div>
527 </div>
528 </a>';
529
530 $html.= '</div>';
531 echo $html;
532 }
533
534
535 public static function generate_off_days($args = array()){
536 $default_args = [ 'agent_id' => 0, 'service_id' => 0, 'location_id' => 0];
537 $args = array_merge($default_args, $args);
538
539 $work_periods = new OsWorkPeriodModel();
540 $work_periods = $work_periods->where($args)->where(['custom_date' => 'IS NOT NULL',
541 'custom_date >=' => OsTimeHelper::today_date(),
542 'start_time' => 0,
543 'end_time' => 0])->group_by('custom_date, chain_id')->order_by('custom_date asc')->get_results_as_models();
544 $html = '';
545 if($work_periods && isset($work_periods[0])){
546 $date = new OsWpDateTime($work_periods[0]->custom_date);
547 $processing_year = $date->format('Y');
548 if($date->format('Y') != gmdate('Y')) $html.= '<div class="os-form-sub-header sub-level"><h3>'.esc_html($date->format('Y')).'</h3></div>';
549 }
550 $chained_periods = [];
551 $html.= '<div class="custom-day-work-periods">';
552 if($work_periods){
553 $total_periods = count($work_periods);
554 $i = 0;
555 foreach($work_periods as $work_period){
556 $i = $i + 1;
557 if(empty($work_period->custom_date)) continue;
558 if($work_period->chain_id){
559 $chained_periods[$work_period->chain_id][] = $work_period->custom_date;
560 if($i < $total_periods) continue;
561 }
562 if($chained_periods){
563
564 foreach($chained_periods as $chain_id => $chained_period){
565 $range_start_date = new OsWpDateTime(min($chained_period));
566 $range_end_date = new OsWpDateTime(max($chained_period));
567 if($processing_year != $range_start_date->format('Y')){
568 $html.= '</div><div class="os-form-sub-header sub-level"><h3>'.esc_html($range_start_date->format('Y')).'</h3></div><div class="custom-day-work-periods">';
569 $processing_year = $range_start_date->format('Y');
570 }
571 $html.= '<div class="custom-day-work-period is-range custom-day-off">';
572 $html.= '<a href="#" data-os-pass-this="yes" data-os-after-call="latepoint_custom_day_removed" data-os-action="'.esc_attr(OsRouterHelper::build_route_name('settings', 'remove_chain_schedule')).'" data-os-params="'.esc_attr(OsUtilHelper::build_os_params(['chain_id' => $chain_id])).'" data-os-prompt="'.esc_attr__('Are you sure you want to remove day off range?', 'latepoint').'" title="'.esc_attr__('Remove Day Off Range', 'latepoint').'" class="remove-custom-day"><i class="latepoint-icon latepoint-icon-trash-2"></i></a>';
573 $html.= '<div class="custom-day-work-period-i">';
574 $html.= '<div class="custom-day-number">'.esc_html($range_start_date->format('d').' - '.$range_end_date->format('d')) .'</div>';
575 if($range_start_date->format('n') != $range_end_date->format('n')){
576 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($range_start_date->format('n')).'-'.OsUtilHelper::get_month_name_by_number($range_end_date->format('n'))).'</div>';
577 }else{
578 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($range_start_date->format('n'))).'</div>';
579 }
580 $html.= '</div>';
581 $html.= '</div>';
582 }
583 $chained_periods = [];
584 }
585 if(empty($work_period->chain_id)){
586 $date = new OsWpDateTime($work_period->custom_date);
587 if($processing_year != $date->format('Y')) $html.= '</div><div class="os-form-sub-header sub-level"><h3>'.esc_html($date->format('Y')).'</h3></div><div class="custom-day-work-periods">';
588 $html.= '<div class="custom-day-work-period custom-day-off">';
589 $html.= '<a href="#" title="'.esc_attr__('Edit Day Schedule', 'latepoint').'" class="edit-custom-day" '.self::generate_custom_day_period_action($work_period->custom_date, false, $args).'><i class="latepoint-icon latepoint-icon-edit-3"></i></a>';
590 $html.= '<a href="#" data-os-pass-this="yes" data-os-after-call="latepoint_custom_day_removed" data-os-action="'.esc_attr(OsRouterHelper::build_route_name('settings', 'remove_custom_day_schedule')).'" data-os-params="'.esc_attr(OsUtilHelper::build_os_params(array_merge($args, ['date' => $work_period->custom_date]))).'" data-os-prompt="'.esc_attr__('Are you sure you want to remove this day off?', 'latepoint').'" title="'.esc_attr__('Remove Day Off', 'latepoint').'" class="remove-custom-day"><i class="latepoint-icon latepoint-icon-trash-2"></i></a>';
591 $html.= '<div class="custom-day-work-period-i">';
592 $html.= '<div class="custom-day-number">'.esc_html($date->format('d')).'</div>';
593 $html.= '<div class="custom-day-month">'.esc_html(OsUtilHelper::get_month_name_by_number($date->format('n'))).'</div>';
594 $html.= '</div>';
595 $html.= '</div>';
596 $processing_year = $date->format('Y');
597 }
598 }
599 }
600 $html.= '<a class="add-custom-day-w" '.self::generate_custom_day_period_action(false, true, $args).'>
601 <div class="add-custom-day-i">
602 <div class="add-day-graphic-w"><div class="add-day-plus"><i class="latepoint-icon latepoint-icon-plus4"></i></div></div><div class="add-day-label">'.esc_html__('Add Day', 'latepoint').'</div>
603 </div>
604 </a>';
605 $html.= '</div>';
606 echo $html;
607 }
608
609
610 public static function generate_custom_day_period_action($target_date = false, $day_off = false, $args = array()){
611 $os_params = [];
612 if($day_off) $os_params['day_off'] = true;
613 if($target_date){
614 $os_params['target_date'] = $target_date;
615 $hide_schedule_class = '';
616 }else{
617 $hide_schedule_class = ' hide-schedule';
618 }
619 $os_params = array_merge($os_params, $args);
620 $html = 'data-os-after-call="latepoint_init_custom_day_schedule" data-os-lightbox-classes="width-700 '.esc_attr($hide_schedule_class).'" data-os-output-target="lightbox" data-os-action="'.esc_attr(OsRouterHelper::build_route_name('settings', 'custom_day_schedule_form')).'"';
621 if(!empty($os_params)) $html.= ' data-os-params="'.esc_attr(OsUtilHelper::build_os_params($os_params)).'"';
622 return $html;
623 }
624
625
626 /**
627 * @param array $work_periods
628 * @param \LatePoint\Misc\Filter $filter
629 * @param bool $is_new_record
630 * @return void
631 */
632 public static function generate_work_periods(array $work_periods, \LatePoint\Misc\Filter $filter, bool $is_new_record = false){
633 if(!$work_periods) $work_periods = OsWorkPeriodsHelper::get_work_periods($filter, true);
634 $working_periods_with_weekdays = array();
635 if($work_periods){
636 foreach($work_periods as $work_period){
637 $working_periods_with_weekdays['day_'.$work_period->week_day][] = $work_period;
638 }
639 }
640 for($i=1; $i<=7; $i++){
641 $is_day_off = true;
642 $period_forms_html = '';
643 if(isset($working_periods_with_weekdays['day_'.$i])){
644 $is_day_off = false;
645 // EXISTING WORK PERIOD
646 $allow_remove = false;
647 foreach($working_periods_with_weekdays['day_'.$i] as $work_period){
648 if($work_period->start_time === $work_period->end_time){
649 $is_day_off = true;
650 }
651 if($filter->agent_id && ($work_period->agent_id !== $filter->agent_id)){
652 $work_period->agent_id = $filter->agent_id;
653 $work_period->id = false;
654 }
655 if($filter->service_id && ($work_period->service_id !== $filter->service_id)){
656 $work_period->service_id = $filter->service_id;
657 $work_period->id = false;
658 }
659 if($filter->location_id && ($work_period->location_id !== $filter->location_id)){
660 $work_period->location_id = $filter->location_id;
661 $work_period->id = false;
662 }
663 if($is_new_record){
664 $work_period->id = false;
665 }
666 $period_forms_html.= OsWorkPeriodsHelper::generate_work_period_form(array('period_id' => $work_period->id,
667 'week_day' => $i,
668 'is_active' => $work_period->is_active,
669 'agent_id' => $work_period->agent_id,
670 'service_id' => $work_period->service_id,
671 'location_id' => $work_period->location_id,
672 'start_time' => $work_period->start_time,
673 'end_time' => $work_period->end_time), $allow_remove);
674 $allow_remove = true;
675 }
676 }else{
677 // NEW WORK PERIOD
678 $period_forms_html.= OsWorkPeriodsHelper::generate_work_period_form(array( 'period_id' => false,
679 'week_day' => $i,
680 'start_time' => 0,
681 'end_time' => 0), false);
682 } ?>
683 <div class="weekday-schedule-w <?php echo $is_day_off ? 'day-off' : ''; ?>">
684 <div class="ws-head-w">
685 <div class="os-toggler <?php echo $is_day_off ? 'off' : 'on'; ?>">
686 <div class="toggler-rail"><div class="toggler-pill"></div></div>
687 </div>
688 <div class="ws-head">
689 <div class="ws-day-name"><?php echo esc_html(OsBookingHelper::get_weekday_name_by_number($i, true)); ?></div>
690 <div class="ws-day-hours">
691 <?php
692 if(isset($working_periods_with_weekdays['day_'.$i])){
693 foreach($working_periods_with_weekdays['day_'.$i] as $index => $work_period){
694 if($work_period->start_time === $work_period->end_time) continue;
695 if($index >= 2) {
696 // translators: %d number of work periods
697 echo esc_html('<span>'.sprintf(__('+%d More', 'latepoint'), count($working_periods_with_weekdays['day_'.$i]) - 2)).'</span>';
698 break;
699 }
700 echo '<span>'.esc_html($work_period->nice_start_time.'-'.$work_period->nice_end_time).'</span>';
701 }
702 }
703 ?>
704 </div>
705 <div class="wp-edit-icon">
706 <i class="latepoint-icon latepoint-icon-edit-3"></i>
707 </div>
708 </div>
709 </div>
710 <div class="weekday-schedule-form">
711 <?php
712 echo $period_forms_html;
713 $params = ['week_day' => $i];
714 if($filter->agent_id) $params['agent_id'] = $filter->agent_id;
715 if($filter->service_id) $params['service_id'] = $filter->service_id;
716 if($filter->location_id) $params['location_id'] = $filter->location_id;
717 ?>
718 <div class="ws-period-add"
719 data-os-params="<?php echo esc_attr(OsUtilHelper::build_os_params($params)); ?>"
720 data-os-before-after="before"
721 data-os-after-call="latepoint_init_work_period_form"
722 data-os-action="<?php echo esc_attr(OsRouterHelper::build_route_name('settings', 'load_work_period_form')); ?>">
723 <div class="add-period-graphic-w">
724 <div class="add-period-plus"><i class="latepoint-icon latepoint-icon-plus-square"></i></div>
725 </div>
726 <div class="add-period-label">
727 <?php
728 // translators: %s name of a weekday
729 echo esc_html(sprintf(__('Add another work period for %s', 'latepoint'), OsBookingHelper::get_weekday_name_by_number($i, true))); ?>
730 </div>
731 </div>
732 </div>
733 </div>
734 <?php
735 }
736 }
737 }