PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.1.6
LatePoint – Calendar Booking Plugin for Appointments and Events v5.1.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 / misc / booking_resource.php
latepoint / lib / misc Last commit date
blocked_period.php 1 year ago booked_period.php 1 year ago booking_request.php 1 year ago booking_resource.php 1 year ago booking_slot.php 1 year ago filter.php 1 year ago process_action.php 1 year ago process_event.php 1 year ago role.php 1 year ago router.php 1 year ago step.php 1 year ago stripe_connect_customer.php 1 year ago time_period.php 1 year ago user.php 1 year ago work_period.php 1 year ago
booking_resource.php
233 lines
1 <?php
2 /*
3 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
4 */
5
6 namespace LatePoint\Misc;
7
8 class BookingResource{
9 public int $agent_id;
10 public int $service_id;
11 public int $location_id;
12 public int $max_capacity;
13 public int $min_capacity;
14 public int $min_capacity_to_be_blocked;
15 public int $timeblock_interval;
16 public string $date;
17 public array $work_time_periods = [];
18 public array $booked_time_periods = [];
19 // time periods that are usually part of work periods but a blocked now for some reason(time past today),
20 // it's different from booked periods, because they have no bookings
21 public array $blocked_time_periods = [];
22 public array $slots = [];
23
24
25 public array $bookable_minutes = [];
26 public array $work_minutes = [];
27
28 function __construct($args = []){
29 $allowed_props = self::allowed_props();
30 foreach($args as $key => $arg){
31 if(in_array($key, $allowed_props)) $this->$key = $arg;
32 }
33 }
34
35 /**
36 * @return \OsAgentModel
37 */
38 function get_agent(): \OsAgentModel{
39 return ($this->agent_id) ? new \OsAgentModel($this->agent_id) : new \OsAgentModel();
40 }
41
42 protected function retrieve_service_data(){
43 $service = new \OsServiceModel($this->service_id);
44 $this->max_capacity = $service->capacity_max;
45 $this->timeblock_interval = $service->timeblock_interval ? intval($service->timeblock_interval) : \OsSettingsHelper::get_default_timeblock_interval();
46 $this->min_capacity_to_be_blocked = $service->get_capacity_needed_before_slot_is_blocked();
47 }
48
49
50 public function get_timeblock_interval(){
51 if(isset($this->timeblock_interval)){
52 return $this->timeblock_interval;
53 }else{
54 $this->retrieve_service_data();
55 return $this->timeblock_interval;
56 }
57 }
58
59
60 public function get_min_capacity_to_be_blocked(){
61 if(isset($this->min_capacity_to_be_blocked)){
62 return $this->min_capacity_to_be_blocked;
63 }else{
64 $this->retrieve_service_data();
65 return $this->min_capacity_to_be_blocked;
66 }
67 }
68
69 public function get_max_capacity(){
70 if(isset($this->max_capacity)){
71 return $this->max_capacity;
72 }else{
73 $this->retrieve_service_data();
74 return $this->max_capacity;
75 }
76 }
77
78 /**
79 * @param BookingRequest $booking_request
80 * @param int $selectable_time_interval
81 * @return void
82 */
83 public function build_bookable_slots(BookingRequest $booking_request, int $selectable_time_interval){
84 $this->slots = [];
85 $this->work_minutes = [];
86 foreach($this->work_time_periods as $time_period){
87 for($minute = $time_period->start_time; $minute <= $time_period->end_time - $booking_request->duration; $minute+= $selectable_time_interval){
88 $period = new TimePeriod(['start_time' => $minute - $booking_request->buffer_before, 'end_time' => $minute + $booking_request->duration + $booking_request->buffer_after]);
89 $this->work_minutes[] = $minute;
90 // add booking slot
91 $slot = new BookingSlot();
92 $slot->start_date = $this->date;
93 $slot->start_time = $minute;
94 $slot->max_capacity = $this->get_max_capacity();
95 $slot->min_capacity_to_be_blocked = $this->get_min_capacity_to_be_blocked();
96
97 // ---------------------
98 // LOGIC FOR "BOOKED" PERIODS
99 // ---------------------
100 foreach($this->booked_time_periods as $booked_period){
101 if ($booked_period->start_time_with_buffer() >= $period->end_time || $booked_period->end_time_with_buffer() <= $period->start_time) {
102 // not intersected
103 }else{
104 // intersects with a booked period, disqualify it
105 if($booked_period->service_id != $this->service_id){
106 // if it's a different service being performed - block full capacity of a slot, because you can't share capacities between different services
107 $slot->booked_capacity = $this->max_capacity;
108 }else{
109 $slot->booked_capacity+= $booked_period->total_attendees;
110 }
111 }
112 }
113 // ---------------------
114 // LOGIC FOR "BLOCKED" PERIODS
115 // ---------------------
116 foreach($this->blocked_time_periods as $blocked_period){
117 if ($blocked_period->start_time >= $period->end_time || $blocked_period->end_time <= $period->start_time) {
118 // not intersected
119 }else{
120 // intersects with a blocked period, disqualify it
121 $slot->booked_capacity = $slot->max_capacity;
122 }
123 }
124 $this->slots[] = $slot;
125 }
126 }
127 }
128
129 // Function to print the intersection
130 private function find_intersection(array $time_periods){
131 // First interval
132 $start = $time_periods[0]->start_time;
133 $end = $time_periods[0]->end_time;
134 // Check rest of the intervals and find the intersection
135 $total = count($time_periods);
136 for ($i = 1; $i < $total; $i++){
137 // If no intersection exists
138 if ($time_periods[$i]->start_time > $end || $time_periods[$i]->end_time < $start){
139 return [];
140 }else{
141 // Else update the intersection
142 $start = max($start, $time_periods[$i]->start_time);
143 $end = min($end, $time_periods[$i]->end_time);
144 }
145 }
146 return new TimePeriod(['start_time' => $start, 'end_time' => $end]);
147 }
148
149 public function add_blocked_period(BlockedPeriod $blocked_period){
150 $this->blocked_time_periods[] = $blocked_period;
151 }
152
153 public function add_booked_period(BookedPeriod $booked_period, $block_full_capacity = false){
154 if($block_full_capacity){
155 $max_capacity_booked_period = clone $booked_period;
156 $max_capacity_booked_period->total_attendees = $this->max_capacity;
157 $this->booked_time_periods[] = $max_capacity_booked_period;
158 }else{
159 $this->booked_time_periods[] = $booked_period;
160 }
161 }
162
163 public function add_available_periods(array $work_period_groups){
164 $available_periods = [];
165 foreach($work_period_groups as $group_work_periods){
166 // loop through groups, if multiple group - add them by comparing them against each other
167 $available_periods = ($available_periods) ? $this->compare_periods($available_periods, $group_work_periods) : $group_work_periods;
168 }
169 $this->work_time_periods = $available_periods;
170 }
171
172
173 private function compare_periods(array $available_periods, array $periods_to_intersect): array{
174 $intersects = [];
175 foreach($available_periods as $available_period){
176 foreach($periods_to_intersect as $intersect_period){
177 $intersect = $this->find_intersection([$available_period, $intersect_period]);
178 if($intersect) $intersects[] = $intersect;
179 }
180 }
181 return $intersects;
182 }
183
184 public function intersect_time_period(TimePeriod $time_period){
185 }
186
187
188 // TODO instead of trying to find overlaps, just add a period and then overlaps can be skipped using array_unique for available minutes
189 public function add_time_period(TimePeriod $time_period_to_add){
190 $overlapped_time_periods = [];
191 $not_overlapped_time_periods = [];
192 // search for all periods that overlap, to later merge them into one
193 foreach($this->work_time_periods as $time_period){
194 if($time_period->check_if_overlaps($time_period_to_add)){
195 $overlapped_time_periods[] = $time_period;
196 }else{
197 $not_overlapped_time_periods[] = $time_period;
198 }
199 }
200 if($overlapped_time_periods){
201 // if overlapping periods were found - find a unified range between them and create a new list of available time
202 // periods which should include those that were not overlapped
203 $this->work_time_periods = $not_overlapped_time_periods;
204 $merged_time_period = TimePeriod::get_unified_period_from_overlapped_periods($merged_time_period);
205 $this->work_time_periods[] = $merged_time_period;
206 }else{
207 // nothing was overlapped, simply add this time period
208 $this->work_time_periods[] = $time_period_to_add;
209 }
210 }
211
212 public function generate_resource_id(): string{
213 return $this->agent_id.'_'.$this->service_id.'_'.$this->location_id;
214 }
215
216 public static function create_from_connection(\OsConnectorModel $connection): BookingResource{
217 $booking_request = new BookingResource([ 'agent_id' => $connection->agent_id,
218 'service_id' => $connection->service_id,
219 'location_id' => $connection->location_id]);
220 $booking_request->retrieve_service_data();
221 return $booking_request;
222 }
223
224
225 public static function allowed_props(): array{
226 return ['agent_id',
227 'service_id',
228 'location_id',
229 'date',
230 'start_time',
231 'end_time'];
232 }
233 }