PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.31
Booking for Appointments and Events Calendar – Amelia v1.2.31
2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Application / Commands / Booking / Appointment / GetAppointmentsCommandHandler.php
ameliabooking / src / Application / Commands / Booking / Appointment Last commit date
AddAppointmentCommand.php 1 year ago AddAppointmentCommandHandler.php 1 year ago AddBookingCommand.php 1 year ago AddBookingCommandHandler.php 1 year ago ApproveBookingRemotelyCommand.php 1 year ago ApproveBookingRemotelyCommandHandler.php 1 year ago CancelBookingCommand.php 1 year ago CancelBookingCommandHandler.php 1 year ago CancelBookingRemotelyCommand.php 1 year ago CancelBookingRemotelyCommandHandler.php 2 years ago DeleteAppointmentCommand.php 1 year ago DeleteAppointmentCommandHandler.php 1 year ago DeleteBookingCommand.php 1 year ago DeleteBookingCommandHandler.php 1 year ago GetAppointmentCommand.php 7 years ago GetAppointmentCommandHandler.php 1 year ago GetAppointmentsCommand.php 1 year ago GetAppointmentsCommandHandler.php 1 year ago GetIcsCommand.php 1 year ago GetIcsCommandHandler.php 4 years ago GetPackageAppointmentsCommand.php 1 year ago GetPackageAppointmentsCommandHandler.php 1 year ago GetTimeSlotsCommand.php 1 year ago GetTimeSlotsCommandHandler.php 1 year ago ReassignBookingCommand.php 1 year ago ReassignBookingCommandHandler.php 1 year ago RejectBookingRemotelyCommand.php 1 year ago RejectBookingRemotelyCommandHandler.php 1 year ago SuccessfulBookingCommand.php 1 year ago SuccessfulBookingCommandHandler.php 1 year ago UpdateAppointmentCommand.php 1 year ago UpdateAppointmentCommandHandler.php 1 year ago UpdateAppointmentStatusCommand.php 1 year ago UpdateAppointmentStatusCommandHandler.php 1 year ago UpdateAppointmentTimeCommand.php 1 year ago UpdateAppointmentTimeCommandHandler.php 1 year ago UpdateBookingStatusCommand.php 1 year ago UpdateBookingStatusCommandHandler.php 1 year ago
GetAppointmentsCommandHandler.php
472 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Commands\Booking\Appointment;
4
5 use AmeliaBooking\Application\Commands\CommandHandler;
6 use AmeliaBooking\Application\Commands\CommandResult;
7 use AmeliaBooking\Application\Common\Exceptions\AccessDeniedException;
8 use AmeliaBooking\Application\Services\Bookable\AbstractPackageApplicationService;
9 use AmeliaBooking\Application\Services\Booking\AppointmentApplicationService;
10 use AmeliaBooking\Application\Services\Booking\BookingApplicationService;
11 use AmeliaBooking\Application\Services\User\UserApplicationService;
12 use AmeliaBooking\Domain\Collection\Collection;
13 use AmeliaBooking\Domain\Common\Exceptions\AuthorizationException;
14 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
15 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
16 use AmeliaBooking\Domain\Entity\Booking\Appointment\Appointment;
17 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
18 use AmeliaBooking\Domain\Entity\Entities;
19 use AmeliaBooking\Domain\Entity\User\AbstractUser;
20 use AmeliaBooking\Domain\Entity\User\Provider;
21 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
22 use AmeliaBooking\Domain\Services\Settings\SettingsService;
23 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
24 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
25 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ServiceRepository;
26 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
27 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingRepository;
28 use Interop\Container\Exception\ContainerException;
29
30 /**
31 * Class GetAppointmentsCommandHandler
32 *
33 * @package AmeliaBooking\Application\Commands\Booking\Appointment
34 */
35 class GetAppointmentsCommandHandler extends CommandHandler
36 {
37 /**
38 * @param GetAppointmentsCommand $command
39 *
40 * @return CommandResult
41 *
42 * @throws InvalidArgumentException
43 * @throws QueryExecutionException
44 * @throws AccessDeniedException
45 * @throws ContainerException
46 */
47 public function handle(GetAppointmentsCommand $command)
48 {
49 $result = new CommandResult();
50
51 /** @var AppointmentRepository $appointmentRepository */
52 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
53
54 /** @var ServiceRepository $serviceRepository */
55 $serviceRepository = $this->container->get('domain.bookable.service.repository');
56
57 /** @var AbstractPackageApplicationService $packageAS */
58 $packageAS = $this->container->get('application.bookable.package');
59
60 /** @var SettingsService $settingsDS */
61 $settingsDS = $this->container->get('domain.settings.service');
62
63 /** @var UserApplicationService $userAS */
64 $userAS = $this->container->get('application.user.service');
65
66 /** @var BookingApplicationService $bookingAS */
67 $bookingAS = $this->container->get('application.booking.booking.service');
68
69 /** @var AppointmentApplicationService $appointmentAS */
70 $appointmentAS = $this->container->get('application.booking.appointment.service');
71
72 $params = $command->getField('params');
73
74 $isCabinetPage = $command->getPage() === 'cabinet';
75
76 $isCalendarPage = $command->getPage() === 'calendar';
77
78 $isCabinetPackageRequest = $isCabinetPage && isset($params['activePackages']);
79
80 $isDashboardPackageRequest = !$isCabinetPage && (isset($params['packageId']) || !empty($params['packageBookings']));
81
82 try {
83 /** @var AbstractUser $user */
84 $user = $command->getUserApplicationService()->authorization($isCabinetPage ? $command->getToken() : null, $command->getCabinetType());
85 } catch (AuthorizationException $e) {
86 $result->setResult(CommandResult::RESULT_ERROR);
87 $result->setData(
88 [
89 'reauthorize' => true
90 ]
91 );
92
93 return $result;
94 }
95
96 $readOthers = $this->container->getPermissionsService()->currentUserCanReadOthers(Entities::APPOINTMENTS);
97
98 if (!empty($params['dates'])) {
99 !empty($params['dates'][0]) ? $params['dates'][0] .= ' 00:00:00' : null;
100 !empty($params['dates'][1]) ? $params['dates'][1] .= ' 23:59:59' : null;
101
102 if ($isCabinetPage && !empty($params['timeZone'])) {
103 foreach ([0, 1] as $index) {
104 if (!empty($params['dates'][$index])) {
105 $params['dates'][$index] = DateTimeService::getDateTimeObjectInTimeZone(
106 $params['dates'][$index],
107 $params['timeZone']
108 )->setTimezone(DateTimeService::getTimeZone())->format('Y-m-d H:i:s');
109 }
110 }
111 }
112 }
113
114 $entitiesIds = !empty($params['search']) && !$isCabinetPackageRequest ?
115 $appointmentAS->getAppointmentEntitiesIdsBySearchString($params['search']) : [];
116
117 if ($user && $user->getType() === Entities::CUSTOMER) {
118 $params['customerId'] = $user->getId()->getValue();
119 }
120
121 $countParams = $params;
122
123 $appointmentsIds = [];
124
125 if (
126 !empty($params['search']) &&
127 !$entitiesIds['customers'] &&
128 !$entitiesIds['services'] &&
129 !$entitiesIds['providers']
130 ) {
131 $result->setResult(CommandResult::RESULT_SUCCESS);
132 $result->setMessage('Successfully retrieved appointments');
133 $result->setData(
134 [
135 Entities::APPOINTMENTS => [],
136 'availablePackageBookings' => [],
137 'occupied' => [],
138 'total' => 0,
139 'totalApproved' => 0,
140 'totalPending' => 0,
141 ]
142 );
143
144 return $result;
145 }
146
147 $availablePackageBookings = [];
148
149 if (!$isCabinetPackageRequest && !$isDashboardPackageRequest) {
150 $upcomingAppointmentsLimit = $settingsDS->getSetting('general', 'itemsPerPageBackEnd');
151
152 /** @var Collection $periodAppointments */
153 $periodAppointments = $appointmentRepository->getPeriodAppointments(
154 array_merge(
155 [
156 'customers' => $isCabinetPage && $user->getType() === Entities::CUSTOMER ?
157 [$user->getId()->getValue()] : [],
158 'providers' => $user && $user->getType() === Entities::PROVIDER ?
159 [$user->getId()->getValue()] : [],
160 ],
161 array_merge($params, ['endsInDateRange' => $isCalendarPage]),
162 $entitiesIds,
163 ['skipBookings' => !$isCabinetPage && empty($params['customerId']) && empty($entitiesIds['customers'])]
164 ),
165 $upcomingAppointmentsLimit
166 );
167
168 /** @var Appointment $appointment */
169 foreach ($periodAppointments->getItems() as $appointment) {
170 $appointmentsIds[] = $appointment->getId()->getValue();
171 }
172 }
173
174 /** @var Collection $appointments */
175 $appointments = new Collection();
176
177 $customerId = isset($params['customerId']) ? $params['customerId'] : null;
178
179 if (isset($params['customerId'])) {
180 unset($params['customerId']);
181 }
182
183 $customersNoShowCountIds = [];
184
185 $noShowTagEnabled = $settingsDS->getSetting('roles', 'enableNoShowTag');
186
187 if (!$isCabinetPackageRequest && $appointmentsIds) {
188 $appointments = $appointmentRepository->getFiltered(
189 [
190 'ids' => $appointmentsIds,
191 'skipServices' => isset($params['skipServices']) ? $params['skipServices'] : false,
192 'skipProviders' => isset($params['skipProviders']) ? $params['skipProviders'] : false,
193 ]
194 );
195 } elseif ($isDashboardPackageRequest || ($user && $user->getId() && $isCabinetPackageRequest)) {
196 $availablePackageBookings = $packageAS->getPackageAvailability(
197 $appointments,
198 [
199 'purchased' => !empty($params['dates']) ? $params['dates'] : [],
200 'customerId' => $isCabinetPackageRequest ? $user->getId()->getValue() : $customerId,
201 'packageId' => !$isCabinetPackageRequest && !empty($params['packageId']) ?
202 (int)$params['packageId'] : null,
203 ]
204 );
205
206 if ($noShowTagEnabled && !!$availablePackageBookings) {
207 $customersNoShowCountIds[] = $availablePackageBookings[0]['customerId'];
208 }
209 }
210
211 /** @var Collection $services */
212 $services = $serviceRepository->getAllArrayIndexedById();
213
214 if (!$isCabinetPage) {
215 $packageAS->setPackageBookingsForAppointments($appointments);
216 }
217
218 $occupiedTimes = [];
219
220 $currentDateTime = DateTimeService::getNowDateTimeObject();
221
222 $groupedAppointments = [];
223
224 /** @var Appointment $appointment */
225 foreach ($appointments->getItems() as $appointment) {
226 /** @var Service $service */
227 $service = $services->getItem($appointment->getServiceId()->getValue());
228
229 $bookingsCount = 0;
230
231 /** @var CustomerBooking $booking */
232 foreach ($appointment->getBookings()->getItems() as $booking) {
233 // fix for wrongly saved JSON
234 if (
235 $booking->getCustomFields() &&
236 json_decode($booking->getCustomFields()->getValue(), true) === null
237 ) {
238 $booking->setCustomFields(null);
239 }
240
241 if ($bookingAS->isBookingApprovedOrPending($booking->getStatus()->getValue())) {
242 $bookingsCount++;
243 }
244
245 if ($noShowTagEnabled && !in_array($booking->getCustomerId()->getValue(), $customersNoShowCountIds)) {
246 $customersNoShowCountIds[] = $booking->getCustomerId()->getValue();
247 }
248 }
249
250 $providerId = $appointment->getProviderId()->getValue();
251
252 $isGroup = false;
253
254 // skip appointments/bookings for other customers if user is customer, and remember that time/date values
255 if ($userAS->isCustomer($user)) {
256 /** @var CustomerBooking $booking */
257 foreach ($appointment->getBookings()->getItems() as $bookingKey => $booking) {
258 if (!$user->getId() || $booking->getCustomerId()->getValue() !== $user->getId()->getValue()) {
259 /** @var CustomerBooking $otherBooking */
260 $otherBooking = $appointment->getBookings()->getItem($bookingKey);
261
262 if (
263 $otherBooking->getStatus()->getValue() === BookingStatus::APPROVED ||
264 $otherBooking->getStatus()->getValue() === BookingStatus::PENDING
265 ) {
266 $isGroup = true;
267 }
268
269 $appointment->getBookings()->deleteItem($bookingKey);
270 }
271 }
272
273 if ($appointment->getBookings()->length() === 0) {
274 $serviceTimeBefore = $service->getTimeBefore() ?
275 $service->getTimeBefore()->getValue() : 0;
276
277 $serviceTimeAfter = $service->getTimeAfter() ?
278 $service->getTimeAfter()->getValue() : 0;
279
280 $occupiedTimeStart = DateTimeService::getCustomDateTimeObject(
281 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
282 )->modify('-' . $serviceTimeBefore . ' second')->format('H:i:s');
283
284 $occupiedTimeEnd = DateTimeService::getCustomDateTimeObject(
285 $appointment->getBookingEnd()->getValue()->format('Y-m-d H:i:s')
286 )->modify('+' . $serviceTimeAfter . ' second')->format('H:i:s');
287
288 $occupiedTimes[$appointment->getBookingStart()->getValue()->format('Y-m-d')][] =
289 [
290 'employeeId' => $providerId,
291 'startTime' => $occupiedTimeStart,
292 'endTime' => $occupiedTimeEnd,
293 ];
294
295 continue;
296 }
297 }
298
299 // skip appointments for other providers if user is provider
300 if (
301 (!$readOthers || $isCabinetPage) &&
302 $user->getType() === Entities::PROVIDER &&
303 $user->getId()->getValue() !== $providerId
304 ) {
305 continue;
306 }
307
308 $appointmentAS->calculateAndSetAppointmentEnd($appointment, $service);
309
310 $minimumCancelTimeInSeconds = $settingsDS
311 ->getEntitySettings($service->getSettings())
312 ->getGeneralSettings()
313 ->getMinimumTimeRequirementPriorToCanceling();
314
315 $minimumCancelTime = DateTimeService::getCustomDateTimeObject(
316 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
317 )->modify("-{$minimumCancelTimeInSeconds} seconds");
318
319 $date = $appointment->getBookingStart()->getValue()->format('Y-m-d');
320
321 $cancelable = $currentDateTime <= $minimumCancelTime;
322
323 $minimumRescheduleTimeInSeconds = $settingsDS
324 ->getEntitySettings($service->getSettings())
325 ->getGeneralSettings()
326 ->getMinimumTimeRequirementPriorToRescheduling();
327
328 $minimumRescheduleTime = DateTimeService::getCustomDateTimeObject(
329 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
330 )->modify("-{$minimumRescheduleTimeInSeconds} seconds");
331
332 $reschedulable = $currentDateTime <= $minimumRescheduleTime;
333
334
335 if ($isCabinetPage || ($user && $user->getType() === Entities::PROVIDER)) {
336 $timeZone = 'UTC';
337
338 if (!empty($params['timeZone'])) {
339 $timeZone = $params['timeZone'];
340 } elseif (
341 ($user instanceof Provider) &&
342 empty($user->getTimeZone()) && !empty(get_option('timezone_string'))
343 ) {
344 $timeZone = get_option('timezone_string');
345 }
346
347 $appointment->getBookingStart()->getValue()->setTimezone(new \DateTimeZone($timeZone));
348 $appointment->getBookingEnd()->getValue()->setTimezone(new \DateTimeZone($timeZone));
349
350 $date = $appointment->getBookingStart()->getValue()->format('Y-m-d');
351
352 foreach ($availablePackageBookings as &$packageCustomerPurchase) {
353 foreach ($packageCustomerPurchase['packages'] as &$packagePurchase) {
354 foreach ($packagePurchase['services'] as &$packageService) {
355 foreach ($packageService['bookings'] as &$purchase) {
356 $purchasedDate = DateTimeService::getCustomDateTimeObjectInTimeZone(
357 $purchase['purchased'],
358 $timeZone
359 );
360
361 $purchase['purchased'] = $purchasedDate->format('Y-m-d H:i');
362 }
363 }
364 }
365 }
366 }
367
368 $groupedAppointments[$date]['date'] = $date;
369
370 $groupedAppointments[$date]['appointments'][] = array_merge(
371 $appointment->toArray(),
372 [
373 'cancelable' => $cancelable,
374 'reschedulable' => $reschedulable,
375 'past' => $currentDateTime >= $appointment->getBookingStart()->getValue(),
376 'isGroup' => $isGroup,
377 ]
378 );
379 }
380
381 $emptyBookedPackages = null;
382
383 if (
384 !empty($params['packageId']) &&
385 empty($params['services']) &&
386 empty($params['providers']) &&
387 empty($params['locations'])
388 ) {
389 /** @var AbstractPackageApplicationService $packageApplicationService */
390 $packageApplicationService = $this->container->get('application.bookable.package');
391
392 /** @var Collection $emptyBookedPackages */
393 $emptyBookedPackages = $packageApplicationService->getEmptyPackages(
394 [
395 'packages' => [$params['packageId']],
396 'purchased' => !empty($params['dates']) ? $params['dates'] : [],
397 'customerId' => $customerId,
398 ]
399 );
400 }
401
402 $periodsAppointmentsCount = 0;
403
404 $periodsAppointmentsApprovedCount = 0;
405
406 $periodsAppointmentsPendingCount = 0;
407
408 if (!empty($countParams['page']) || (!$isCabinetPackageRequest && !$isCabinetPage && !$isCalendarPage)) {
409 if (
410 (!$readOthers) &&
411 $user->getType() === Entities::PROVIDER
412 ) {
413 $countParams['providerId'] = $user->getId()->getValue();
414 }
415 $periodsAppointmentsCount = $appointmentRepository->getPeriodAppointmentsCount(
416 array_merge($countParams, $entitiesIds)
417 );
418
419 $periodsAppointmentsApprovedCount = $appointmentRepository->getPeriodAppointmentsCount(
420 array_merge(
421 $countParams,
422 ['status' => BookingStatus::APPROVED],
423 $entitiesIds
424 )
425 );
426
427 $periodsAppointmentsPendingCount = $appointmentRepository->getPeriodAppointmentsCount(
428 array_merge(
429 $countParams,
430 ['status' => BookingStatus::PENDING],
431 $entitiesIds
432 )
433 );
434 }
435
436 $customersNoShowCount = [];
437
438 if ($noShowTagEnabled && $customersNoShowCountIds) {
439 /** @var CustomerBookingRepository $bookingRepository */
440 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
441
442 $customersNoShowCount = $bookingRepository->countByNoShowStatus($customersNoShowCountIds);
443 }
444
445 $groupedAppointments = apply_filters('amelia_get_appointments_filter', $groupedAppointments);
446
447 do_action('amelia_get_appointments', $groupedAppointments);
448
449
450 $result->setResult(CommandResult::RESULT_SUCCESS);
451 $result->setMessage('Successfully retrieved appointments');
452 $result->setData(
453 [
454 Entities::APPOINTMENTS =>
455 !empty($params['asArray']) && filter_var($params['asArray'], FILTER_VALIDATE_BOOLEAN) ?
456 $appointments->toArray() :
457 $groupedAppointments,
458 'availablePackageBookings' => $availablePackageBookings,
459 'emptyPackageBookings' => !empty($emptyBookedPackages) ? $emptyBookedPackages->toArray() : [],
460 'occupied' => $occupiedTimes,
461 'total' => $periodsAppointmentsCount,
462 'totalApproved' => $periodsAppointmentsApprovedCount,
463 'totalPending' => $periodsAppointmentsPendingCount,
464 'currentUser' => $user ? $user->toArray() : null,
465 'customersNoShowCount' => $customersNoShowCount
466 ]
467 );
468
469 return $result;
470 }
471 }
472