PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.58
Timetics – Appointment Booking Calendar & Scheduling v1.0.58
1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 All 62 releases
timetics / core / appointments / appointment.php

appointment.php in Timetics – Appointment Booking Calendar & Scheduling 1.0.58, at core/appointments/appointment.php

1,063 lines 27.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Apointment
4 *
5 * @since 1.0.0
6 *
7 * @package Timetics
8 */
9 namespace Timetics\Core\Appointments;
10
11 use DateTime;
12 use Timetics\Base\PostModel;
13 use Timetics\Core\Bookings\Booking;
14 use Timetics\Core\Bookings\Booking_Entry;
15 use Timetics\Core\Staffs\Staff;
16 use WP_Query;
17
18 /**
19 * Class Appointments.
20 *
21 * @since 1.0.0
22 */
23 class Appointment extends PostModel {
24 /**
25 * Store post type
26 *
27 * @since 1.0.0
28 *
29 * @var string $post_type
30 */
31 public $post_type = 'timetics-appointment';
32
33 /**
34 * Store timetics custom taxonomy
35 *
36 * @since 1.0.0
37 *
38 * @var string $taxonomy
39 */
40 protected $taxonomy = 'timetics-meeting-category';
41
42 /**
43 * Store id
44 *
45 * @since 1.0.0
46 *
47 * @var int $id
48 */
49 protected $id;
50
51 /**
52 * Store post metadata
53 *
54 * @since 1.0.0
55 *
56 * @var array $data
57 */
58 public $data = [
59 'name' => '',
60 'type' => '',
61 'description' => '',
62 'staff' => '',
63 'locations' => '',
64 'duration' => '',
65 'schedule' => '',
66 'blocked_schedule' => '',
67 'price' => '',
68 'buffer_time' => '',
69 'buffer_time_before_value'=> '',
70 'buffer_time_before_unit' => '',
71 'buffer_time_after_value' => '',
72 'buffer_time_after_unit' => '',
73 'timezone' => '',
74 'availability' => '',
75 'visibility' => '',
76 'capacity' => '',
77 'seat_plan' => '',
78 'duplicate' => 0,
79 'custom_fields' => [],
80 'wc_product_id' => 0,
81 'seat_plan_settings' => '',
82 'fleunt_crm_webhook' => '',
83 'fluent_hook_overwrite' => '',
84 'pabbly_hook_overwrite' => '',
85 'zapier_hook_overwrite' => '',
86 'pabbly_webook' => '',
87 'zapier_webook' => '',
88 'min_notice_time' => '',
89 'notifications' => [
90 'booking_created_email_form' => '',
91 'booking_created_email_title' => '',
92 'booking_created_email_body' => '',
93 'booking_canceled_email_form' => '',
94 'booking_canceled_email_title' => '',
95 'booking_canceled_email_body' => '',
96 'booking_reschedule_email_form' => '',
97 'booking_reschedule_email_title' => '',
98 'booking_reschedule_email_body' => '',
99 'booking_reminder_email_form' => '',
100 'booking_reminder_email_title' => '',
101 'booking_reminder_email_body' => '',
102 'booking_reminder_time' => 30,
103 ],
104 'permalink' => '',
105 'recurring' => false,
106 'recurring_limit' => 0,
107 'recurring_interval' => 1,
108 'recurring_interval_name' => 'day',
109 'guest_enabled' => false,
110 'guest_limit' => 1,
111 ];
112
113 /**
114 * Store meta key prefix
115 *
116 * @since 1.0.0
117 *
118 * @var string $prefix
119 */
120 public $prefix = '_tt_apointment_';
121
122 /**
123 * Appointments Constructor
124 *
125 * @since 1.0.0
126 *
127 * @param int $appointment Optional. Default 0.
128 * @return void
129 */
130 public function __construct( $appointment = 0 ) {
131 if ( $appointment instanceof self ) {
132 $this->set_id( $appointment->get_id() );
133 } elseif ( ! empty( $appointment->ID ) ) {
134 $this->set_id( $appointment->ID );
135 } elseif ( is_numeric( $appointment ) && $appointment > 0 ) {
136 $this->set_id( $appointment );
137 }
138 }
139
140 /**
141 * Get appoint id.
142 *
143 * @since 1.0.0
144 *
145 * @return int
146 */
147 public function get_id() {
148 return $this->id;
149 }
150
151 /**
152 * Get appointment slug
153 *
154 * @return mixed
155 */
156 public function get_slug() {
157 $post = get_post( $this->get_id() );
158
159 if ( $post ) {
160 return $post->post_name;
161 }
162
163 return false;
164 }
165
166 /**
167 * Get woocommerce product id
168 *
169 * @return integer
170 */
171 public function get_wc_product_id() {
172 return $this->get_prop( 'wc_product_id' );
173 }
174
175 /**
176 * Get name.
177 *
178 * @since 1.0.0
179 *
180 * @return string
181 */
182 public function get_name() {
183 return $this->get_prop( 'name' );
184 }
185
186 /**
187 * Get coach
188 *
189 * @since 1.0.0
190 *
191 * @return int
192 */
193 public function get_staff() {
194 $staff_ids = $this->get_prop( 'staff' );
195 $staffs = [];
196
197 if ( $staff_ids ) {
198 foreach ( $staff_ids as $staff_id ) {
199 $staff = new Staff( $staff_id );
200
201 if ( ! $staff->is_staff() ) {
202 continue;
203 }
204
205 $staffs[] = $staff->get_data();
206 }
207 }
208 return $staffs;
209 }
210
211 /**
212 * Get staff ids
213 *
214 * @return array
215 */
216 public function get_staff_ids() {
217 $ids = $this->get_prop( 'staff' );
218
219 return is_array( $ids ) ? array_values( $ids ) : [];
220 }
221
222 /**
223 * Get duplicate number
224 *
225 * @return integer
226 */
227 public function get_duplicate_nuber() {
228 return $this->get_prop( 'duplicate' );
229 }
230
231 /**
232 * Get capacity
233 *
234 * @return integer
235 */
236 public function get_capacity() {
237 return $this->get_prop( 'capacity' );
238 }
239
240 /**
241 * Get the effective booking capacity used for availability checks.
242 *
243 * One-to-One meetings always allow a single booking per slot regardless of
244 * the stored capacity meta (which is only meaningful for group meetings),
245 * matching the one-to-one handling used elsewhere in the booking flow.
246 *
247 * @return integer
248 */
249 public function get_effective_capacity() {
250 if ( 'one-to-one' === strtolower( (string) $this->get_type() ) ) {
251 return 1;
252 }
253
254 return intval( $this->get_capacity() );
255 }
256
257 /**
258 * Get location
259 *
260 * @since 1.0.0
261 *
262 * @return string
263 */
264 public function get_locations() {
265 return $this->get_prop( 'locations' );
266 }
267
268 /**
269 * Get Permalink
270 *
271 * @since 1.0.0
272 *
273 * @return string
274 */
275 public function get_appointment_permalink() {
276 return get_post_permalink( $this->id );
277 }
278
279 /**
280 * Get duration
281 *
282 * @since 1.0.0
283 *
284 * @return string
285 */
286 public function get_duration() {
287 return $this->get_prop( 'duration' );
288 }
289
290 /**
291 * Get interval for the duration
292 *
293 * @return integer
294 */
295 public function get_interval() {
296 $duration = $this->get_duration();
297 if ( $duration ) {
298 $duration = explode( ' ', $duration );
299 $duration = 'hr' === $duration[1] ? intval( $duration[0] ) * 60 * 60 : intval( $duration[0] ) * 60;
300 }
301
302 return $duration;
303 }
304
305 /**
306 * Get schedule
307 *
308 * @since 1.0.0
309 *
310 * @return array
311 */
312 public function get_schedule() {
313 return $this->get_prop( 'schedule' );
314 }
315
316 /**
317 * Get blocked schedule
318 *
319 * @since 1.0.0
320 *
321 * @return array
322 */
323 public function get_blocked_schedule() {
324 return $this->get_prop( 'blocked_schedule' );
325 }
326
327 /**
328 * Get price
329 *
330 * @since 1.0.0
331 *
332 * @return string
333 */
334 public function get_price() {
335 return $this->get_prop( 'price' );
336 }
337
338 /**
339 * Get type
340 *
341 * @since 1.0.0
342 *
343 * @return string
344 */
345 public function get_type() {
346 return $this->get_prop( 'type' );
347 }
348
349 /**
350 * Get description
351 *
352 * @since 1.0.0
353 *
354 * @return string
355 */
356 public function get_description() {
357 return $this->get_prop( 'description' );
358 }
359
360 public function get_buffer_time() {
361 return $this->get_prop( 'buffer_time' );
362 }
363
364 /**
365 * Returns the amount of buffer time before the appointment (without unit like minute or hour)
366 *
367 * @return integer
368 */
369 public function get_buffer_time_before_value() {
370 return $this->get_prop( 'buffer_time_before_value' );
371 }
372
373 /**
374 * Returns the unit of buffer time before the appointment (like minute or hour)
375 *
376 * @return string
377 */
378 public function get_buffer_time_before_unit() {
379 return $this->get_prop( 'buffer_time_before_unit' );
380 }
381
382 /**
383 * Returns the amount of buffer time after the appointment (without unit like minute or hour)
384 *
385 * @return integer
386 */
387 public function get_buffer_time_after_value() {
388 return $this->get_prop( 'buffer_time_after_value' );
389 }
390
391 /**
392 * Returns the unit of buffer time after the appointment (like minute or hour)
393 *
394 * @return string
395 */
396 public function get_buffer_time_after_unit() {
397 return $this->get_prop( 'buffer_time_after_unit' );
398 }
399
400 public function get_timezone() {
401 return $this->get_prop( 'timezone' );
402 }
403
404 public function get_availability() {
405 return $this->get_prop( 'availability' );
406 }
407
408 public function get_visibility() {
409 return $this->get_prop( 'visibility' );
410 }
411 public function get_fleunt_crm_webhook() {
412 return $this->get_prop( 'fleunt_crm_webhook' );
413 }
414 public function get_fluent_hook_overwrite() {
415 return $this->get_prop( 'fluent_hook_overwrite' );
416 }
417 public function get_pabbly_webook() {
418 return $this->get_prop( 'pabbly_webook' );
419 }
420 public function get_pabbly_hook_overwrite() {
421 return $this->get_prop( 'pabbly_hook_overwrite' );
422 }
423 public function get_zapier_webook() {
424 return $this->get_prop( 'zapier_webook' );
425 }
426 public function get_zapier_hook_overwrite() {
427 return $this->get_prop( 'zapier_hook_overwrite' );
428 }
429 public function get_min_notice_time() {
430 return $this->get_prop( 'min_notice_time' );
431 }
432 public function get_guest_enabled() {
433 return $this->get_prop( 'guest_enabled' );
434 }
435 public function get_guest_limit() {
436 return $this->get_prop( 'guest_limit' );
437 }
438
439 /**
440 * Get Custom fields
441 *
442 * @return array
443 */
444 public function get_custom_fields() {
445 return $this->get_prop( 'custom_fields' );
446 }
447
448 /**
449 * Get notifications
450 *
451 * @return array
452 */
453 public function get_notifications() {
454 return $this->get_prop( 'notifications' );
455 }
456
457 /**
458 * Returns the buffer time before the appointment in seconds
459 *
460 * @return integer seconds
461 */
462 public function get_buffer_time_before_in_seconds() {
463 $buffer_time_value = (int) $this->get_buffer_time_before_value() ?? 0;
464
465 if ( 'hr' === $this->get_buffer_time_before_unit() ) {
466 return $buffer_time_value * 60 * 60;
467 }
468
469 return $buffer_time_value * 60;
470 }
471
472 /**
473 * Returns the buffer time after the appointment in seconds
474 *
475 * @return integer seconds
476 */
477 public function get_buffer_time_after_in_seconds() {
478 $buffer_time_value = (int) $this->get_buffer_time_after_value() ?? 0;
479
480 if ( 'hr' === $this->get_buffer_time_after_unit() ) {
481 return $buffer_time_value * 60 * 60;
482 }
483
484 return $buffer_time_value * 60;
485 }
486
487 /**
488 * Get appointment categories
489 *
490 * @since 1.0.0
491 *
492 * @return array
493 */
494 public function get_categories() {
495 $categories = wp_get_post_terms( $this->id, $this->taxonomy );
496
497 if ( is_wp_error( $categories ) ) {
498 return [];
499 }
500
501 return $categories;
502 }
503
504 /**
505 * Get category ids
506 *
507 * @return array
508 */
509 public function get_category_ids() {
510 $categories = $this->get_categories();
511
512 $ids = [];
513
514 foreach ( $categories as $category ) {
515 $ids[] = $category->term_id;
516 }
517
518 return $ids;
519 }
520
521 /**
522 * Get post thumbnail.
523 *
524 * @param string $size Image size
525 *
526 * @return string
527 */
528 public function get_image( $size = 'post-thumbnail' ) {
529 return get_the_post_thumbnail_url( $size );
530 }
531
532 /**
533 * Get permalink
534 *
535 * @return string
536 */
537 public function get_link() {
538 return get_post_permalink( $this->id );
539 }
540
541 /**
542 * Get Seat plan for a meeting
543 *
544 * @return array
545 */
546 public function get_seats() {
547 return $this->get_prop( 'seat_plan' );
548 }
549
550 /**
551 * Get appointment author
552 *
553 * @return integer
554 */
555 public function get_author() {
556 $post = get_post( $this->id );
557
558 return $post->post_author;
559 }
560
561 /**
562 * Get seat plan settings
563 *
564 * @return array
565 */
566 public function get_seat_settings() {
567 return $this->get_prop( 'seat_plan_settings' );
568 }
569
570 // Recurring options.
571
572 /**
573 * Check it is recurring or not
574 *
575 * @return bool
576 */
577 public function is_recurring() {
578 return boolval( $this->get_prop( 'recurring' ) );
579 }
580
581 /**
582 * Get recurring limit
583 *
584 * @return integer
585 */
586 public function get_recurring_limit() {
587 return intval( $this->get_prop( 'recurring_limit' ) );
588 }
589
590 /**
591 * Get recurring interval
592 *
593 * @return integer
594 */
595 public function get_recurring_interval() {
596 return intval( $this->get_prop( 'recurring_interval' ) );
597 }
598
599 /**
600 * Get recurring interval name
601 *
602 * @return string
603 */
604 public function get_recurring_interval_name() {
605 return $this->get_prop( 'recurring_interval_name' );
606 }
607
608 /**
609 * Get appointment data
610 *
611 * @param string $prop
612 *
613 * @return mixed
614 */
615 public function get_prop( $prop = '' ) {
616 return $this->get_metadata( $prop );
617 }
618
619 /**
620 * Get metadata
621 *
622 * @since 1.0.0
623 *
624 * @param string $prop Optional. Default empty string.
625 *
626 * @return mixed
627 */
628 private function get_metadata( $prop = '' ) {
629 $meta_key = $this->prefix . $prop;
630 return get_post_meta( $this->id, $meta_key, true );
631 }
632
633 /**
634 * Set appointment id
635 *
636 * @since 1.0.0
637 *
638 * @param int $id
639 *
640 * @return void
641 */
642 public function set_id( $id ) {
643 $this->id = $id;
644 }
645
646 /**
647 * Set props
648 *
649 * @param array $data Metadata array. Default empty array.
650 *
651 * @return void
652 */
653 public function set_props( $data = [] ) {
654 $this->data = $data;
655 }
656
657 /**
658 * Save appointment
659 *
660 * @since 1.0.0
661 *
662 * @return void
663 */
664 public function save() {
665
666 $args = [
667 'post_title' => $this->data['name'],
668 'post_type' => $this->post_type,
669 'post_status' => 'publish',
670 'post_author' => get_current_user_id(),
671 ];
672
673 if ( ! empty( $this->id ) ) {
674 $args['ID'] = $this->id;
675 }
676
677 // Insert or Update appointment.
678 $appoint_id = wp_insert_post( $args );
679
680 if ( ! is_wp_error( $appoint_id ) ) {
681 $this->set_id( $appoint_id );
682 $this->save_metadata();
683 }
684 }
685
686 /**
687 * Update appointment meta data.
688 *
689 * @since 1.0.0
690 *
691 * @return void
692 */
693 private function save_metadata() {
694 foreach ( $this->data as $key => $value ) {
695 // Prepare meta key.
696 $meta_key = $this->prefix . $key;
697
698 // Update appointment meta data.
699 update_post_meta( $this->id, $meta_key, $value );
700 }
701 }
702
703 /**
704 * Update meeting data
705 *
706 * @param array $args meeting data
707 *
708 * @return bool
709 */
710 public function update( $args = [] ) {
711
712 foreach ( $args as $key => $value ) {
713 if ( ! array_key_exists( $key, $this->data ) ) {
714 continue;
715 }
716
717 // Prepare meta key.
718 $meta_key = $this->prefix . $key;
719
720 // Update appointment meta data.
721 update_post_meta( $this->id, $meta_key, $value );
722 }
723 }
724
725 /**
726 * Delete appointment
727 *
728 * @return bool | WP_Error
729 */
730 public function delete() {
731 return wp_delete_post( $this->id, true );
732 }
733
734 /**
735 * Check the appoint is valid or not
736 *
737 * @return bool
738 */
739 public function is_appointment() {
740 $post = get_post( $this->id );
741
742 if ( $post && $this->post_type === $post->post_type ) {
743 return true;
744 }
745
746 return false;
747 }
748
749 /**
750 * Get all appointments
751 *
752 * @param array $args Appointments args. Default empty array.
753 *
754 * @return array
755 */
756 public static function all( $args = [] ) {
757 $defaults = [
758 'post_type' => ( new self )->post_type,
759 'post_status' => 'publish',
760 'posts_per_page' => 20,
761 'paged' => 1,
762 'orderby' => 'ID',
763 'order' => 'DESC',
764 ];
765
766 $args = wp_parse_args( $args, $defaults );
767
768 if ( ! empty( $args['staff'] ) ) {
769 $args['meta_query'][] = [
770 'key' => '_tt_apointment_staff',
771 'value' => $args['staff'],
772 'compare' => 'LIKE',
773 ];
774 }
775
776 if ( ! empty( $args['visibility'] ) ) {
777 $args['meta_query'][] = [
778 'key' => '_tt_apointment_visibility',
779 'value' => $args['visibility'],
780 'compare' => 'LIKE',
781 ];
782 }
783
784 if ( ! empty( $args['type'] ) ) {
785 $args['meta_query'][] = [
786 'key' => '_tt_apointment_type',
787 'value' => $args['type'],
788 'compare' => 'LIKE',
789 ];
790 }
791
792 if ( ! empty( $args['category'] ) ) {
793 $args['tax_query'][] = [
794 'taxonomy' => 'timetics-meeting-category',
795 'terms' => $args['category'],
796 'include_children' => false,
797 ];
798 }
799
800 $post = new WP_Query( $args );
801
802 return [
803 'total' => $post->found_posts,
804 'items' => $post->posts,
805 ];
806 }
807
808 /**
809 * Duplicate appointment
810 *
811 * @since 1.0.0
812 *
813 * @return void
814 */
815 public function duplicate() {
816 $this->set_props( [
817 'name' => $this->get_name(),
818 'description' => $this->get_description(),
819 'type' => $this->get_type(),
820 'locations' => $this->get_locations(),
821 'staff' => $this->get_staff_ids(),
822 'duplicate' => intval( $this->get_duplicate_nuber() ) + 1,
823 'duration' => $this->get_duration(),
824 'price' => $this->get_price(),
825 'capacity' => $this->get_capacity(),
826 'schedule' => $this->get_schedule(),
827 'categories' => $this->get_categories(),
828 'timezone' => $this->get_timezone(),
829 'availability' => $this->get_availability(),
830 'visibility' => $this->get_visibility(),
831 'buffer_time' => $this->get_buffer_time(),
832 'notifications' => $this->get_notifications(),
833 'fluent_hook_overwrite' => $this->get_fluent_hook_overwrite(),
834 'fleunt_crm_webhook' => $this->get_fleunt_crm_webhook(),
835 'pabbly_hook_overwrite' => $this->get_pabbly_hook_overwrite(),
836 'pabbly_webook' => $this->get_pabbly_webook(),
837 'zapier_webook' => $this->get_zapier_webook(),
838 'min_notice_time' => $this->get_min_notice_time(),
839 'zapier_hook_overwrite' => $this->get_zapier_hook_overwrite(),
840 'guest_enabled' => $this->get_guest_enabled(),
841 'guest_limit' => $this->get_guest_limit(),
842 ] );
843
844 $this->set_id( 0 );
845 $this->save();
846 }
847
848 /**
849 * Prepare meeting schedule
850 *
851 * @param string $start
852 * @param string $end
853 * @param integer $staff_id
854 *
855 * @return array
856 */
857 public function prepare_schedule( $start, $end, $staff_id, $timze_zone = '' ) {
858 $start = new \DateTime( $start );
859 $end = new \DateTime( $end );
860 $schedule = [];
861
862 // Prepare schedule for the current meeting
863 for ( $date = $start; $date <= $end; $date->modify( '+1 day' ) ) {
864 $schedule[] = $this->get_schedule_by_date( $date->format( 'Y-m-d' ), $staff_id, $timze_zone );
865 }
866
867 return $schedule;
868 }
869
870 /**
871 * Get meeting schedule by date
872 *
873 * @param string $date [$date description]
874 * @param integer $staff_id [$staff_id description]
875 * @param string $timze_zone [$timze_zone description]
876 *
877 * @return array
878 */
879 private function get_schedule_by_date( $date, $staff_id, $time_zone = '' ) {
880 $day_name = ucfirst( gmdate( 'D', strtotime( $date ) ) );
881 $schedule = $this->get_schedule();
882 $interval = $this->get_interval();
883 $target_schedule = [];
884
885 $slots = [];
886
887 if ( ! empty( $schedule[$staff_id] ) ) {
888 $target_schedule = $schedule[$staff_id][$day_name];
889 }
890
891 foreach ( $target_schedule as $day ) {
892 $start = strtotime( $day['start'] );
893 $end = strtotime( $day['end'] );
894
895 // Get buffer times in seconds
896 $buffer_before = $this->get_buffer_time_before_in_seconds();
897 $buffer_after = $this->get_buffer_time_after_in_seconds();
898
899 // Adjust the start time to include buffer before
900 $adjusted_start = $start + $buffer_before;
901
902 // Adjust the end time to ensure we have enough time for the slot + buffer after
903 $min_slot_duration = $interval + $buffer_after;
904
905 for ( $time = $adjusted_start; $time + $min_slot_duration <= $end; $time += $interval + $buffer_after + $buffer_before ) {
906 $booked_entry = $this->get_booking_entries( $date, $time, $staff_id );
907 $status = 'available';
908 $capacity = $this->get_effective_capacity();
909 $booked = 0;
910
911 if ( $booked_entry ) {
912 if ( $booked_entry->get_booked() >= $capacity ) {
913 $status = 'unavailable';
914 }
915
916 $booked = $booked_entry->get_booked();
917 }
918
919 $datetime = $this->convert_timezone( $time, $time_zone );
920
921 $slot = [
922 'status' => $status,
923 'start_time' => $datetime->format( 'g:ia' ),
924 'booked' => $booked,
925 ];
926
927 $slot = apply_filters( 'timetics_booking_slot', $slot, $this, $booked_entry );
928
929 $slots[] = $slot;
930 }
931 }
932
933 return [
934 'date' => $date,
935 'status' => empty( $slots ) ? 'unavailable' : 'available',
936 'slots' => $slots,
937 ];
938 }
939
940 /**
941 * Get booked entry status
942 *
943 * @param string $date
944 * @param string $time
945 * @param interger $staff_id
946 *
947 * @return bool
948 */
949 private function get_booking_entries( $date, $time, $staff_id ) {
950 $time = gmdate( 'h:i a', $time );
951 $booking_entries = new Booking_Entry();
952 $entries = $booking_entries->find( [
953 'staff_id' => $staff_id,
954 'date' => $this->convert_timezone( $date, $this->get_timezone())->format('Y-m-d'),
955 ] );
956
957 foreach ( $entries as $entry ) {
958 $booking = new Booking( $entry->get_booking_id() );
959 $start_time = $entry->get_start();
960 $end_time = $entry->get_end();
961
962 // Check if current time slot falls within the booking duration
963 if ( $this->is_time_in_range( $time, $start_time, $end_time ) ) {
964 return $entry;
965 }
966 }
967
968 return false;
969 }
970
971 /**
972 * Check if a time falls within a given time range
973 *
974 * @param string $current_time Current time in h:i a format
975 * @param string $start_time Start time in h:i a format
976 * @param string $end_time End time in h:i a format
977 *
978 * @return bool
979 */
980 private function is_time_in_range( $current_time, $start_time, $end_time ) {
981 $current = strtotime( $current_time );
982 $start = strtotime( $start_time );
983 $end = strtotime( $end_time );
984
985 return $current >= $start && $current < $end;
986 }
987
988 /**
989 * Convert timestamp in target timezone
990 *
991 * @param integer $timestamp
992 * @param string $timze_zone
993 *
994 * @return DateTime
995 */
996 public function convert_timezone( $date, $timze_zone ) {
997 $date = is_int( $date ) ? gmdate( 'Y-m-d g:ia', $date ) : $date;
998
999 // Create a DateTime object with the provided timestamp and time zone
1000 $datetime = new \DateTime( $date, new \DateTimeZone( $this->get_timezone() ) );
1001
1002 // Convert the time zone
1003 $datetime->setTimezone( new \DateTimeZone( $timze_zone ) );
1004
1005 // Get the converted timestamp
1006 return $datetime;
1007 }
1008
1009 /**
1010 * Get appointmentt ids by author id
1011 *
1012 * @param integer $author_id Appointment author id
1013 *
1014 * @return array Appointment ids
1015 */
1016 public static function get_appointment_ids_by_author( $author_id ) {
1017 $query = new WP_Query([
1018 'post_type' => 'timetics-appointment',
1019 'post_status' => 'any',
1020 'author' => $author_id,
1021 'posts_per_page' => -1,
1022 'fields' => 'ids'
1023 ]);
1024
1025 return $query->posts;
1026 }
1027
1028 /**
1029 * Get meeting available time slot
1030 *
1031 * @param string $date Start date
1032 * @param integer $staff_id Meeting assigned staff id
1033 * @param string $timze_zone Booking timezone
1034 *
1035 * @return array Available timeslots
1036 */
1037 public function get_avilable_timeslots( $date, $staff_id, $time_zone = '' ) {
1038 $day_name = ucfirst( gmdate( 'D', strtotime( $date ) ) );
1039 $schedule = $this->get_schedule();
1040 $interval = $this->get_interval();
1041 $tartget_schedule = [];
1042
1043 $slots = [];
1044
1045 if ( isset($schedule[$staff_id]) && ! empty(array_filter($schedule[$staff_id])) ) {
1046 $tartget_schedule = $schedule[$staff_id][$day_name];
1047 }
1048
1049 foreach ( $tartget_schedule as $day ) {
1050 $start = strtotime( $day['start'] );
1051 $end = strtotime( $day['end'] );
1052
1053 for ( $time = $start; $time <= $end; $time += $interval ) {
1054 $datetime = $this->convert_timezone( $time, $time_zone );
1055 $slot = $datetime->format( 'g:ia' );
1056 $slots[] = $slot;
1057 }
1058 }
1059
1060 return $slots;
1061 }
1062 }
1063