PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.0.2
Booking for Appointments and Events Calendar – Amelia v2.0.2
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 / Calendar / GetCalendarEventsCommandHandler.php
ameliabooking / src / Application / Commands / Calendar Last commit date
CalendarRescheduleEventCommand.php 6 months ago CalendarRescheduleEventCommandHandler.php 6 months ago GetCalendarEventsCommand.php 6 months ago GetCalendarEventsCommandHandler.php 6 months ago GetCalendarSlotAvailabilityCommand.php 6 months ago GetCalendarSlotAvailabilityHandler.php 6 months ago GetCalendarSlotEntitiesCommand.php 6 months ago GetCalendarSlotEntitiesCommandHandler.php 6 months ago GetCalendarSlotsCommand.php 6 months ago GetCalendarSlotsCommandHandler.php 6 months ago
GetCalendarEventsCommandHandler.php
276 lines
1 <?php
2
3 /**
4 * @copyright © Melograno Ventures. All rights reserved.
5 * @licence See LICENCE.md for license details.
6 */
7
8 namespace AmeliaBooking\Application\Commands\Calendar;
9
10 use AmeliaBooking\Application\Commands\CommandHandler;
11 use AmeliaBooking\Application\Commands\CommandResult;
12 use AmeliaBooking\Application\Common\Exceptions\AccessDeniedException;
13 use AmeliaBooking\Application\Services\Booking\EventApplicationService;
14 use AmeliaBooking\Domain\Entity\Booking\Appointment\Appointment;
15 use AmeliaBooking\Domain\Entity\Booking\Event\Event;
16 use AmeliaBooking\Domain\Entity\Booking\Event\EventPeriod;
17 use AmeliaBooking\Domain\Entity\Entities;
18 use AmeliaBooking\Domain\Entity\User\AbstractUser;
19 use AmeliaBooking\Domain\Services\Settings\SettingsService;
20 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
21 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
22 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
23
24 class GetCalendarEventsCommandHandler extends CommandHandler
25 {
26 /**
27 * @param GetCalendarEventsCommand $command
28 * @return CommandResult
29 * @throws AccessDeniedException
30 * @throws QueryExecutionException
31 */
32 public function handle(GetCalendarEventsCommand $command): CommandResult
33 {
34 $result = new CommandResult();
35 $queryParams = $command->getField('queryParams');
36
37 if (
38 !$command->getPermissionService()->currentUserCanRead(Entities::APPOINTMENTS) &&
39 !$command->getPermissionService()->currentUserCanRead(Entities::EVENTS)
40 ) {
41 throw new AccessDeniedException('You are not allowed to read calendar events.');
42 }
43
44 /** @var AbstractUser $user */
45 $user = $this->container->get('logged.in.user');
46
47 if ($user->getType() === Entities::CUSTOMER) {
48 $queryParams['customers'] = [$user->getId()->getValue()];
49 }
50
51 if ($user->getType() === Entities::PROVIDER) {
52 $queryParams['providers'] = [$user->getId()->getValue()];
53 }
54
55 $appointments = $this->getAppointments($queryParams);
56 $events = $this->getEvents($queryParams);
57 $sortedItems = array_merge($appointments, $events);
58
59 usort(
60 $sortedItems,
61 function ($a, $b) {
62 $startA = $a instanceof Appointment ? $a->getBookingStart()->getValue() : $a['eventPeriod']->getPeriodStart()->getValue();
63 $startB = $b instanceof Appointment ? $b->getBookingStart()->getValue() : $b['eventPeriod']->getPeriodStart()->getValue();
64 return $startA <=> $startB;
65 }
66 );
67
68 $filledDays = [];
69 $maxNumberOfEvents = PHP_INT_MAX;
70
71 if ($queryParams['view'] === 'dayGridMonth') {
72 $maxNumberOfEvents = 4;
73 }
74
75 if (in_array($queryParams['view'], ['dayGridMonthSevenDays', 'dayGridMonthMobile'])) {
76 $maxNumberOfEvents = 2;
77 }
78
79 foreach ($sortedItems as $item) {
80 $itemStartDate = $item instanceof Appointment
81 ? $item->getBookingStart()->getValue()->format('Y-m-d')
82 : $item['eventPeriod']->getPeriodStart()->getValue()->format('Y-m-d');
83
84 if (!isset($filledDays[$itemStartDate])) {
85 $filledDays[$itemStartDate] = ['events' => [], 'count' => 0, 'more' => 0];
86 }
87
88 // Add more button items number
89 if ($filledDays[$itemStartDate]['count'] >= $maxNumberOfEvents) {
90 $filledDays[$itemStartDate]['more']++;
91 $this->processEventDates($filledDays, $item, 'more');
92
93 continue;
94 }
95
96 $filledDays[$itemStartDate]['events'][] = $item instanceof Appointment
97 ? $this->appointmentFormatter($item, $queryParams, $user)
98 : $this->eventFormatter($item['event'], $item['eventPeriod'], $queryParams);
99 $filledDays[$itemStartDate]['count']++;
100 $this->processEventDates($filledDays, $item, 'count');
101 }
102
103 $result->setData(['events' => $filledDays]);
104 return $result;
105 }
106
107 /**
108 * @param array $filledDays
109 * @param array|Appointment $item
110 * @param string $counterKey
111 * @return void
112 */
113 private function processEventDates(array &$filledDays, $item, string $counterKey): void
114 {
115 if (!$item instanceof Appointment) {
116 $eventStartDate = $item['eventPeriod']->getPeriodStart()->getValue()->setTime(0, 0, 0);
117 $eventEndDate = $item['eventPeriod']->getPeriodEnd()->getValue()->setTime(23, 59, 59);
118
119 for ($date = (clone $eventStartDate)->modify('+1 day'); $date <= $eventEndDate; $date->modify('+1 day')) {
120 $formattedDate = $date->format('Y-m-d');
121 if (!isset($filledDays[$formattedDate])) {
122 $filledDays[$formattedDate] = ['events' => [], 'count' => 0, 'more' => 0];
123 }
124 $filledDays[$formattedDate][$counterKey]++;
125 }
126 }
127 }
128
129 /**
130 * @throws QueryExecutionException
131 */
132 private function getAppointments(array $queryParams): array
133 {
134 if (!isset($queryParams['entitiesToShow']) || !in_array('appointments', $queryParams['entitiesToShow']) || !empty($queryParams['events'])) {
135 return [];
136 }
137
138 /** @var AppointmentRepository $appointmentRepository */
139 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
140
141 $queryParams['statuses'] =
142 isset($queryParams['statuses']) && in_array('pendingAppointments', $queryParams['statuses'])
143 ? [BookingStatus::APPROVED, BookingStatus::PENDING]
144 : [BookingStatus::APPROVED];
145
146 $queryParams['dates'] = [$queryParams['calendarStartDate'], $queryParams['calendarEndDate']];
147
148 $appointments = $appointmentRepository->getFiltered($queryParams);
149
150 return $appointments->getItems();
151 }
152
153 private function getEvents(array $queryParams): array
154 {
155 if (!isset($queryParams['entitiesToShow']) || !in_array('events', $queryParams['entitiesToShow']) || !empty($queryParams['services'])) {
156 return [];
157 }
158
159 $eventPeriods = [];
160
161 /** @var EventApplicationService $eventAS */
162 $eventAS = $this->container->get('application.booking.event.service');
163
164 $queryParams['dates'] = [$queryParams['calendarStartDate'], $queryParams['calendarEndDate']];
165
166 if (!empty($queryParams['events'])) {
167 $queryParams['id'] = $queryParams['events'];
168 }
169
170 $events = $eventAS->getEventsByCriteria($queryParams, ['fetchEventsPeriods' => true], -1);
171
172 /** @var Event $event */
173 foreach ($events->getItems() as $event) {
174 /** @var EventPeriod $eventPeriod */
175 foreach ($event->getPeriods()->getItems() as $eventPeriod) {
176 $eventPeriods[] = ['event' => $event, 'eventPeriod' => $eventPeriod];
177 }
178 }
179
180 return $eventPeriods;
181 }
182
183 private function appointmentFormatter(Appointment $appointment, array $queryParams, AbstractUser $user): array
184 {
185 /** @var SettingsService $settingsService */
186 $settingsService = $this->container->get('domain.settings.service');
187 $timeSlotStep = $settingsService->getSetting('general', 'timeSlotLength');
188 $appointmentDurationInSeconds = $appointment->getBookingEnd()->getValue()->getTimestamp() -
189 $appointment->getBookingEnd()->getValue()->getTimestamp();
190 $bufferTimeBefore = $appointment->getService() && $appointment->getService()->getTimeBefore()
191 ? $appointment->getService()->getTimeBefore()->getValue()
192 : 0;
193 $bufferTimeAfter = $appointment->getService() && $appointment->getService()->getTimeAfter()
194 ? $appointment->getService()->getTimeAfter()->getValue()
195 : 0;
196
197 $startWithoutBuffer = $appointment->getBookingStart()->getValue();
198 $start = (clone($startWithoutBuffer))->modify('-' . $bufferTimeBefore . 'seconds');
199
200 $endWithoutBuffer = $appointment->getBookingEnd()->getValue();
201 $end = (clone($endWithoutBuffer))->modify($bufferTimeAfter . 'seconds');
202
203 $title = $appointment->getService()->getName()->getValue();
204 if (!empty($queryParams['showEmployeeName'])) {
205 $title = $appointment->getProvider()->getFullName();
206 }
207
208 return [
209 'uuid' => $appointment->getId()->getValue(),
210 'id' => $appointment->getId()->getValue(),
211 'bookings' => $appointment->getBookings()->toArray(),
212 'title' => $title,
213 'start' => $start->format('Y-m-d H:i:s'),
214 'end' => $end->format('Y-m-d H:i:s'),
215 'startWithoutBuffer' => $startWithoutBuffer->format('Y-m-d H:i:s'),
216 'endWithoutBuffer' => $endWithoutBuffer->format('Y-m-d H:i:s'),
217 'mainColor' => $appointment->getService()->getColor()->getValue(),
218 'numberOfSlots' => $appointmentDurationInSeconds / $timeSlotStep,
219 'serviceId' => $appointment->getService()->getId()->getValue(),
220 'employeeId' => $appointment->getProvider()->getId()->getValue(),
221 'locationId' => $appointment->getLocationId() ?: null,
222 'bufferTimeBefore' => $bufferTimeBefore,
223 'bufferTimeAfter' => $bufferTimeAfter,
224 'notes' => $appointment->getInternalNotes()->getValue(),
225 'integrationCalendarType' => false,
226 'type' => $appointment->getBookings()->length() === 1
227 ? 'singleAppointment'
228 : 'groupAppointment',
229 'editable' => $user->getType() === Entities::CUSTOMER
230 ? $settingsService->getSetting('roles', 'allowCustomerReschedule')
231 : (
232 $user->getType() === Entities::PROVIDER ?
233 $settingsService->getSetting('roles', 'allowWriteAppointments')
234 : true
235 ),
236 ];
237 }
238
239 private function eventFormatter(Event $eventEntity, EventPeriod $eventPeriod, array $queryParams): array
240 {
241 $periodStartDate = clone $eventPeriod->getPeriodStart()->getValue();
242 $periodEndDate = clone $eventPeriod->getPeriodEnd()->getValue();
243
244 $title = $eventEntity->getName()->getValue();
245 if (!empty($queryParams['showEmployeeName'])) {
246 $title = $eventEntity->getOrganizer() ? $eventEntity->getOrganizer()->getFullName() : $title;
247 }
248
249 $event = [
250 'uuid' => $eventEntity->getId()->getValue(),
251 'title' => $title,
252 'mainColor' => $eventEntity->getColor() ? $eventEntity->getColor()->getValue() : '#1788FB',
253 'type' => 'event',
254 'editable' => false,
255 'startWithoutBuffer' => $periodStartDate->format('Y-m-d H:i:s'),
256 'endWithoutBuffer' => $periodEndDate->format('Y-m-d H:i:s'),
257 'notes' => '',
258 ];
259
260 if (in_array($queryParams['view'], ['dayGridMonthSevenDays', 'dayGridMonth', 'dayGridMonthMobile'])) {
261 $event['start'] = $periodStartDate->format('Y-m-d');
262 $event['end'] = $periodEndDate->modify('+1 day')->format('Y-m-d');
263 } else {
264 $event['groupId'] = $eventPeriod->getId()->getValue();
265 $event['startRecur'] = $periodStartDate->format('Y-m-d');
266 $event['endRecur'] = $periodEndDate->modify('+1 day')->format('Y-m-d');
267 $event['startTime'] = $periodStartDate->format('H:i:s');
268 $event['endTime'] = $periodEndDate->format('H:i:s') === '00:00:00'
269 ? '23:59:59'
270 : $periodEndDate->format('H:i:s');
271 }
272
273 return $event;
274 }
275 }
276