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.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 / resource_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago auth_helper.php 1 year 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 1 year ago carts_helper.php 1 year ago connector_helper.php 1 year ago csv_helper.php 1 year ago customer_helper.php 1 year ago database_helper.php 1 year ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 1 year ago encrypt_helper.php 1 year ago events_helper.php 1 year ago form_helper.php 1 year ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 1 year 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 1 year ago meta_helper.php 1 year ago migrations_helper.php 1 year ago money_helper.php 1 year ago notifications_helper.php 1 year ago order_intent_helper.php 1 year ago orders_helper.php 1 year 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 1 year ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 1 year ago settings_helper.php 1 year ago shortcodes_helper.php 1 year ago sms_helper.php 1 year ago steps_helper.php 1 year ago stripe_connect_helper.php 1 year ago styles_helper.php 1 year ago support_topics_helper.php 1 year ago time_helper.php 1 year ago timeline_helper.php 1 year ago transaction_intent_helper.php 1 year ago util_helper.php 1 year ago version_specific_updates_helper.php 1 year 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
resource_helper.php
275 lines
1 <?php
2 /*
3 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
4 */
5
6 class OsResourceHelper {
7
8 /**
9 * @param \LatePoint\Misc\BookingRequest $booking_request
10 * @param DateTime $date_from
11 * @param DateTime|null $date_to
12 * @param array $settings
13 *
14 * @return array
15 *
16 *
17 * Returns an array of work periods, grouped by days that were requested in the filter.
18 * example: ['2022-02-24' => [], '2022-02-25' => [], ...]
19 *
20 * | Agent | Service | Location | Date | Hours | Weight
21 * | -----------------------------------------------------------------------------
22 * | 1 | 1 | 1 | 2022-01-15 | 7:00 - 18:00 | 7
23 * | 1 | 0 | 1 | 2022-01-15 | 8:00 - 14:00 | 6
24 * | 1 | 0 | 0 | 2022-01-15 | 8:00 - 14:00 | 5
25 * | 0 | 0 | 1 | 2022-01-15 | 11:00 - 12:00 | 5
26 * | 0 | 0 | 0 | 2022-01-15 | 11:00 - 12:00 | 4
27 * | 1 | 0 | 1 | NULL | 0:00 - 0:00 | 2
28 * | 1 | 0 | 0 | NULL | 9:00 - 12:00 | 1
29 * | 0 | 0 | 0 | NULL | 11:00 - 17:00 | 0
30 *
31 */
32 public static function get_resources_grouped_by_day( \LatePoint\Misc\BookingRequest $booking_request, DateTime $date_from, ?DateTime $date_to = null, array $settings = [] ): array {
33 $defaults = [
34 'now' => OsTimeHelper::now_datetime_object(),
35 'exclude_booking_ids' => [],
36 'timeshift_minutes' => 0,
37 'accessed_from_backend' => false,
38 'consider_cart_items' => false
39 ];
40 $settings = array_merge( $defaults, $settings );
41
42 $connections = OsConnectorHelper::get_connections_that_satisfy_booking_request( $booking_request, $settings['accessed_from_backend'] );
43 $resources = [];
44 foreach ( $connections as $connection ) {
45 $resources[] = \LatePoint\Misc\BookingResource::create_from_connection( $connection );
46 }
47 if ( empty( $date_to ) ) {
48 $date_to = clone $date_from;
49 }
50 if ( $settings['timeshift_minutes'] < 0 ) {
51 $date_to = clone $date_to;
52 $date_to->modify( '+1 day' );
53 } elseif ( $settings['timeshift_minutes'] > 0 ) {
54 $date_from = clone $date_from;
55 $date_from->modify( '-1 day' );
56 }
57 $filter = new \LatePoint\Misc\Filter( [
58 'connections' => $connections,
59 'date_from' => $date_from->format( 'Y-m-d' ),
60 'date_to' => $date_to->format( 'Y-m-d' )
61 ] );
62 $weekday_periods = OsWorkPeriodsHelper::get_work_periods_grouped_by_weekday( $filter );
63 $daily_resources = [];
64 // loop through the requested days and fill in array with work periods that are applicable to that day
65
66 // Booked periods
67 $booked_periods_filter = new \LatePoint\Misc\Filter();
68 $booked_periods_filter->date_from = $date_from->format( 'Y-m-d' );
69 $booked_periods_filter->date_to = $date_to->format( 'Y-m-d' );
70 $booked_periods_filter->statuses = OsBookingHelper::get_timeslot_blocking_statuses();
71 if ( $settings['exclude_booking_ids'] ) {
72 $booked_periods_filter->exclude_booking_ids = $settings['exclude_booking_ids'];
73 }
74 if ( $settings['consider_cart_items'] ) {
75 $booked_periods_filter->consider_cart_items = true;
76 }
77
78 $booked_periods = OsBookingHelper::get_booked_periods_grouped_by_day( $booked_periods_filter );
79 $blocked_periods = OsBookingHelper::get_blocked_periods_grouped_by_day( $filter, $settings['accessed_from_backend'] );
80
81
82 for ( $day_date = clone $date_from; $day_date->format( 'Y-m-d' ) <= $date_to->format( 'Y-m-d' ); $day_date->modify( '+1 day' ) ) {
83 $daily_resources[ $day_date->format( 'Y-m-d' ) ] = [];
84 // fill every day with available resources
85 foreach ( $resources as $resource ) {
86 $last_added_period = false;
87 $available_work_periods_groups = [];
88 $group_index = 0;
89 // loop through available work periods for this week day
90 foreach ( $weekday_periods[ $day_date->format( 'N' ) ] as $period ) {
91 if ( $period->custom_date && ( $period->custom_date != $day_date->format( 'Y-m-d' ) ) ) {
92 continue;
93 } // if this period has a custom date set and if it doesn't match the one we search for - skip it
94 // only add this work period if agent/location/service match or not set
95 if ( ( ! $period->agent_id || $period->agent_id == $resource->agent_id ) && ( ! $period->service_id || $period->service_id == $resource->service_id ) && ( ! $period->location_id || $period->location_id == $resource->location_id ) ) {
96 if ( $last_added_period ) {
97 // if weight of previously added period is different - break, no need to add any other periods
98 if ( $last_added_period->weight != $period->weight ) {
99 break;
100 }
101 if ( ( $last_added_period->service_id != $period->service_id ) || ( $last_added_period->agent_id != $period->agent_id ) || ( $last_added_period->location_id != $period->location_id ) ) {
102 // same weight NOT same exact properties, create a new group of work periods, which will later be used to find intersections
103 $group_index ++;
104 }
105 if ( ( $period->start_time == 0 ) && ( $period->end_time == 0 ) ) {
106 $available_work_periods_groups = [];
107 break;
108 }
109 $available_work_periods_groups[ $group_index ][] = \LatePoint\Misc\TimePeriod::create_from_work_period( $period );
110 $last_added_period = $period;
111 } else {
112 if ( ( $period->start_time == 0 ) && ( $period->end_time == 0 ) ) {
113 $available_work_periods_groups = [];
114 break;
115 }
116 $available_work_periods_groups[ $group_index ][] = \LatePoint\Misc\TimePeriod::create_from_work_period( $period );
117 $last_added_period = $period;
118 }
119 }
120 }
121
122 $day_resource = clone $resource;
123 $day_resource->date = $day_date->format( 'Y-m-d' );
124 $day_resource->add_available_periods( $available_work_periods_groups );
125
126 /// -----------------------------
127 /// LOGIC FOR CALCULATING "BOOKED" PERIODS
128 /// -----------------------------
129 foreach ( $booked_periods[ $day_date->format( 'Y-m-d' ) ] as $booked_period ) {
130
131 if ( ( $day_resource->service_id == $booked_period->service_id ) && ( $day_resource->location_id == $booked_period->location_id ) && ( $day_resource->agent_id == $booked_period->agent_id ) ) {
132 // same service, agent and location is already booked, block no matter what
133 $day_resource->add_booked_period( $booked_period );
134 continue;
135 }
136
137 if ( $day_resource->agent_id == $booked_period->agent_id ) {
138 // Same agent
139 if ( ( $day_resource->location_id != $booked_period->location_id ) && OsSettingsHelper::is_on( 'one_location_at_time' ) ) {
140 // different location is booked, but the same agent, block if "Agents can only be present in one location at a time" is ON
141 $day_resource->add_booked_period( $booked_period, true );
142 continue;
143 }
144 if ( ( $day_resource->service_id != $booked_period->service_id ) && ( $day_resource->location_id == $booked_period->location_id ) && ! OsSettingsHelper::is_on( 'multiple_services_at_time' ) ) {
145 // Different service, but same location, block, if "One agent can perform different services simultaneously" is OFF
146 $day_resource->add_booked_period( $booked_period, true );
147 }
148 } else {
149 // Different agent
150 if ( ( $day_resource->location_id == $booked_period->location_id ) && OsSettingsHelper::is_on( 'one_agent_at_location' ) ) {
151 // same location, so it doesn't matter who's the agent, block, because location can only be used by a single agent at a time
152 // set to max capacity, to block slot even if it still has room
153 $day_resource->add_booked_period( $booked_period, true );
154 }
155 }
156 }
157
158 /// -----------------------------
159 /// LOGIC FOR CALCULATING "BLOCKED" PERIODS
160 /// -----------------------------
161 foreach ( $blocked_periods[ $day_date->format( 'Y-m-d' ) ] as $blocked_period ) {
162 if ( ! $blocked_period->agent_id || $day_resource->agent_id == $blocked_period->agent_id ) {
163 $day_resource->add_blocked_period( $blocked_period );
164 }
165 }
166
167 $day_resource->build_bookable_slots( $booking_request, $day_resource->get_timeblock_interval() );
168 $daily_resources[ $day_date->format( 'Y-m-d' ) ][] = $day_resource;
169 }
170 }
171 $daily_resources = apply_filters( 'latepoint_get_resources_grouped_by_day', $daily_resources, $booking_request, $date_from, $date_to, $settings );
172
173 return $daily_resources;
174 }
175
176
177 /**
178 * @param \LatePoint\Misc\BookingResource[] $resources
179 *
180 * @return array
181 */
182 public static function get_ordered_booking_slots_from_resources( array $resources ): array {
183 $booking_slots = [];
184 foreach ( $resources as $resource ) {
185 $booking_slots = array_merge( $booking_slots, $resource->slots );
186 }
187
188 usort( $booking_slots, function ( $first, $second ) {
189 return $first->start_time <=> $second->start_time;
190 } );
191
192 if ( count( $resources ) > 1 ) {
193 $squashed_booking_slots = [];
194 $last_added_slot = false;
195 foreach ( $booking_slots as $booking_slot ) {
196 if ( $last_added_slot && ( $last_added_slot->start_time == $booking_slot->start_time ) ) {
197 if ( $last_added_slot->available_capacity() < $booking_slot->available_capacity() ) {
198 $squashed_booking_slots[ count( $squashed_booking_slots ) - 1 ] = $booking_slot;
199 $last_added_slot = $booking_slot;
200 }
201 } else {
202 $squashed_booking_slots[] = $booking_slot;
203 $last_added_slot = $booking_slot;
204 }
205 }
206 $booking_slots = $squashed_booking_slots;
207 }
208
209 return $booking_slots;
210 }
211
212 /**
213 * @param \LatePoint\Misc\BookingResource[]
214 *
215 * @return \LatePoint\Misc\TimePeriod
216 */
217 public static function get_work_boundaries_for_resources( $resources ): \LatePoint\Misc\TimePeriod {
218 $times = [];
219 foreach ( $resources as $resource ) {
220 foreach ( $resource->work_time_periods as $work_time_period ) {
221 $times[] = $work_time_period->start_time;
222 $times[] = $work_time_period->end_time;
223 }
224 foreach ( $resource->booked_time_periods as $booked_time_period ) {
225 if ( $booked_time_period->start_date == $booked_time_period->end_date ) {
226 // same day event
227 $times[] = $booked_time_period->start_time;
228 $times[] = $booked_time_period->end_time;
229 } else {
230 // event spans mutiple days, expand boundaries to a full day
231 $times[] = 0;
232 $times[] = 24 * 60;
233 }
234 }
235 }
236 if ( $times ) {
237 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [
238 'start_time' => min( $times ),
239 'end_time' => max( $times )
240 ] );
241 } else {
242 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [ 'start_time' => 0, 'end_time' => 0 ] );
243 }
244
245 return $boundary_time_period;
246 }
247
248 /**
249 * @param array $groups_of_resources
250 *
251 * @return \LatePoint\Misc\TimePeriod
252 */
253 public static function get_work_boundaries_for_groups_of_resources( array $groups_of_resources ): \LatePoint\Misc\TimePeriod {
254 $times = [];
255 foreach ( $groups_of_resources as $resources ) {
256 $time_period = self::get_work_boundaries_for_resources( $resources );
257 if ( $time_period->start_time || $time_period->end_time ) {
258 $times[] = $time_period->start_time;
259 $times[] = $time_period->end_time;
260 }
261 }
262 if ( $times ) {
263 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [
264 'start_time' => min( $times ),
265 'end_time' => max( $times )
266 ] );
267 } else {
268 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [ 'start_time' => 0, 'end_time' => 0 ] );
269 }
270
271 return $boundary_time_period;
272 }
273
274
275 }