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