PluginProbe ʕ •ᴥ•ʔ
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.1.8
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.1.8
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 / 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_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
276 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 'accessed_from_backend' => false,
37 'consider_cart_items' => false,
38 'timezone_name' => OsTimeHelper::get_wp_timezone_name()
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
51
52 // all resource management is done in WP timezone, if requested timezone is different - make sure to include couple days on each end to accommodate for timezone differences, which could be up to 26 hours
53 if($settings['timezone_name'] != OsTimeHelper::get_wp_timezone_name()) {
54 $date_from->modify( '-2 days' );
55 $date_to->modify( '+2 days' );
56 }
57
58 $filter = new \LatePoint\Misc\Filter( [
59 'connections' => $connections,
60 'date_from' => $date_from->format( 'Y-m-d' ),
61 'date_to' => $date_to->format( 'Y-m-d' )
62 ] );
63 $weekday_periods = OsWorkPeriodsHelper::get_work_periods_grouped_by_weekday( $filter );
64 $daily_resources = [];
65 // loop through the requested days and fill in array with work periods that are applicable to that day
66
67 // Booked periods
68 $booked_periods_filter = new \LatePoint\Misc\Filter();
69 $booked_periods_filter->date_from = $date_from->format( 'Y-m-d' );
70 $booked_periods_filter->date_to = $date_to->format( 'Y-m-d' );
71 $booked_periods_filter->statuses = OsBookingHelper::get_timeslot_blocking_statuses();
72 if ( $settings['exclude_booking_ids'] ) {
73 $booked_periods_filter->exclude_booking_ids = $settings['exclude_booking_ids'];
74 }
75 if ( $settings['consider_cart_items'] ) {
76 $booked_periods_filter->consider_cart_items = true;
77 }
78
79 $booked_periods = OsBookingHelper::get_booked_periods_grouped_by_day( $booked_periods_filter );
80 $blocked_periods = OsBookingHelper::get_blocked_periods_grouped_by_day( $filter, $settings['accessed_from_backend'] );
81
82
83 for ( $day_date = clone $date_from; $day_date->format( 'Y-m-d' ) <= $date_to->format( 'Y-m-d' ); $day_date->modify( '+1 day' ) ) {
84 $daily_resources[ $day_date->format( 'Y-m-d' ) ] = [];
85 // fill every day with available resources
86 foreach ( $resources as $resource ) {
87 $last_added_period = false;
88 $available_work_periods_groups = [];
89 $group_index = 0;
90 // loop through available work periods for this week day
91 foreach ( $weekday_periods[ $day_date->format( 'N' ) ] as $period ) {
92 if ( $period->custom_date && ( $period->custom_date != $day_date->format( 'Y-m-d' ) ) ) {
93 continue;
94 } // if this period has a custom date set and if it doesn't match the one we search for - skip it
95 // only add this work period if agent/location/service match or not set
96 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 ) ) {
97 if ( $last_added_period ) {
98 // if weight of previously added period is different - break, no need to add any other periods
99 if ( $last_added_period->weight != $period->weight ) {
100 break;
101 }
102 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 ) ) {
103 // same weight NOT same exact properties, create a new group of work periods, which will later be used to find intersections
104 $group_index ++;
105 }
106 if ( ( $period->start_time == 0 ) && ( $period->end_time == 0 ) ) {
107 $available_work_periods_groups = [];
108 break;
109 }
110 $available_work_periods_groups[ $group_index ][] = \LatePoint\Misc\TimePeriod::create_from_work_period( $period );
111 $last_added_period = $period;
112 } else {
113 if ( ( $period->start_time == 0 ) && ( $period->end_time == 0 ) ) {
114 $available_work_periods_groups = [];
115 break;
116 }
117 $available_work_periods_groups[ $group_index ][] = \LatePoint\Misc\TimePeriod::create_from_work_period( $period );
118 $last_added_period = $period;
119 }
120 }
121 }
122
123 $day_resource = clone $resource;
124 $day_resource->date = $day_date->format( 'Y-m-d' );
125 $day_resource->add_available_periods( $available_work_periods_groups );
126
127 /// -----------------------------
128 /// LOGIC FOR CALCULATING "BOOKED" PERIODS
129 /// -----------------------------
130 foreach ( $booked_periods[ $day_date->format( 'Y-m-d' ) ] as $booked_period ) {
131
132 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 ) ) {
133 // same service, agent and location is already booked, block no matter what
134 $day_resource->add_booked_period( $booked_period );
135 continue;
136 }
137
138 if ( $day_resource->agent_id == $booked_period->agent_id ) {
139 // Same agent
140 if ( ( $day_resource->location_id != $booked_period->location_id ) && OsSettingsHelper::is_on( 'one_location_at_time' ) ) {
141 // different location is booked, but the same agent, block if "Agents can only be present in one location at a time" is ON
142 $day_resource->add_booked_period( $booked_period, true );
143 continue;
144 }
145 if ( ( $day_resource->service_id != $booked_period->service_id ) && ( $day_resource->location_id == $booked_period->location_id ) && ! OsSettingsHelper::is_on( 'multiple_services_at_time' ) ) {
146 // Different service, but same location, block, if "One agent can perform different services simultaneously" is OFF
147 $day_resource->add_booked_period( $booked_period, true );
148 }
149 } else {
150 // Different agent
151 if ( ( $day_resource->location_id == $booked_period->location_id ) && OsSettingsHelper::is_on( 'one_agent_at_location' ) ) {
152 // 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
153 // set to max capacity, to block slot even if it still has room
154 $day_resource->add_booked_period( $booked_period, true );
155 }
156 }
157 }
158
159 /// -----------------------------
160 /// LOGIC FOR CALCULATING "BLOCKED" PERIODS
161 /// -----------------------------
162 foreach ( $blocked_periods[ $day_date->format( 'Y-m-d' ) ] as $blocked_period ) {
163 if ( ! $blocked_period->agent_id || $day_resource->agent_id == $blocked_period->agent_id ) {
164 $day_resource->add_blocked_period( $blocked_period );
165 }
166 }
167
168 $day_resource->build_bookable_slots( $booking_request, $day_resource->get_timeblock_interval() );
169 $daily_resources[ $day_date->format( 'Y-m-d' ) ][] = $day_resource;
170 }
171 }
172 $daily_resources = apply_filters( 'latepoint_get_resources_grouped_by_day', $daily_resources, $booking_request, $date_from, $date_to, $settings );
173
174 return $daily_resources;
175 }
176
177
178 /**
179 * @param \LatePoint\Misc\BookingResource[] $resources
180 *
181 * @return array
182 */
183 public static function get_ordered_booking_slots_from_resources( array $resources ): array {
184 $booking_slots = [];
185 foreach ( $resources as $resource ) {
186 $booking_slots = array_merge( $booking_slots, $resource->slots );
187 }
188
189 usort( $booking_slots, function ( $first, $second ) {
190 return $first->start_time <=> $second->start_time;
191 } );
192
193 if ( count( $resources ) > 1 ) {
194 $squashed_booking_slots = [];
195 $last_added_slot = false;
196 foreach ( $booking_slots as $booking_slot ) {
197 if ( $last_added_slot && ( $last_added_slot->start_time == $booking_slot->start_time ) ) {
198 if ( $last_added_slot->available_capacity() < $booking_slot->available_capacity() ) {
199 $squashed_booking_slots[ count( $squashed_booking_slots ) - 1 ] = $booking_slot;
200 $last_added_slot = $booking_slot;
201 }
202 } else {
203 $squashed_booking_slots[] = $booking_slot;
204 $last_added_slot = $booking_slot;
205 }
206 }
207 $booking_slots = $squashed_booking_slots;
208 }
209
210 return $booking_slots;
211 }
212
213 /**
214 * @param \LatePoint\Misc\BookingResource[]
215 *
216 * @return \LatePoint\Misc\TimePeriod
217 */
218 public static function get_work_boundaries_for_resources( $resources ): \LatePoint\Misc\TimePeriod {
219 $times = [];
220 foreach ( $resources as $resource ) {
221 foreach ( $resource->work_time_periods as $work_time_period ) {
222 $times[] = $work_time_period->start_time;
223 $times[] = $work_time_period->end_time;
224 }
225 foreach ( $resource->booked_time_periods as $booked_time_period ) {
226 if ( $booked_time_period->start_date == $booked_time_period->end_date ) {
227 // same day event
228 $times[] = $booked_time_period->start_time;
229 $times[] = $booked_time_period->end_time;
230 } else {
231 // event spans mutiple days, expand boundaries to a full day
232 $times[] = 0;
233 $times[] = 24 * 60 - 1;
234 }
235 }
236 }
237 if ( $times ) {
238 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [
239 'start_time' => min( $times ),
240 'end_time' => max( $times )
241 ] );
242 } else {
243 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [ 'start_time' => 0, 'end_time' => 0 ] );
244 }
245
246 return $boundary_time_period;
247 }
248
249 /**
250 * @param array $groups_of_resources
251 *
252 * @return \LatePoint\Misc\TimePeriod
253 */
254 public static function get_work_boundaries_for_groups_of_resources( array $groups_of_resources ): \LatePoint\Misc\TimePeriod {
255 $times = [];
256 foreach ( $groups_of_resources as $resources ) {
257 $time_period = self::get_work_boundaries_for_resources( $resources );
258 if ( $time_period->start_time || $time_period->end_time ) {
259 $times[] = $time_period->start_time;
260 $times[] = $time_period->end_time;
261 }
262 }
263 if ( $times ) {
264 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [
265 'start_time' => min( $times ),
266 'end_time' => max( $times )
267 ] );
268 } else {
269 $boundary_time_period = new \LatePoint\Misc\TimePeriod( [ 'start_time' => 0, 'end_time' => 0 ] );
270 }
271
272 return $boundary_time_period;
273 }
274
275
276 }