PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.11
Booking for Appointments and Events Calendar – Amelia v1.2.11
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 / Services / Placeholder / AppointmentPlaceholderService.php
ameliabooking / src / Application / Services / Placeholder Last commit date
AppointmentPlaceholderService.php 1 year ago AppointmentsPlaceholderService.php 1 year ago BasicPackagePlaceholderService.php 2 years ago EventPlaceholderService.php 1 year ago PlaceholderService.php 1 year ago PlaceholderServiceInterface.php 1 year ago
AppointmentPlaceholderService.php
1081 lines
1 <?php
2 /**
3 * @copyright © TMS-Plugins. All rights reserved.
4 * @licence See LICENCE.md for license details.
5 */
6
7 namespace AmeliaBooking\Application\Services\Placeholder;
8
9 use AmeliaBooking\Application\Services\Booking\AppointmentApplicationService;
10 use AmeliaBooking\Application\Services\Helper\HelperService;
11 use AmeliaBooking\Domain\Collection\Collection;
12 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
13 use AmeliaBooking\Domain\Entity\Bookable\AbstractBookable;
14 use AmeliaBooking\Domain\Entity\Bookable\Service\Category;
15 use AmeliaBooking\Domain\Entity\Bookable\Service\Extra;
16 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
17 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
18 use AmeliaBooking\Domain\Entity\Coupon\Coupon;
19 use AmeliaBooking\Domain\Entity\Entities;
20 use AmeliaBooking\Domain\Entity\Location\Location;
21 use AmeliaBooking\Domain\Entity\User\AbstractUser;
22 use AmeliaBooking\Domain\Entity\User\Provider;
23 use AmeliaBooking\Domain\Factory\Bookable\Service\ServiceFactory;
24 use AmeliaBooking\Domain\Factory\Booking\Appointment\CustomerBookingFactory;
25 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
26 use AmeliaBooking\Domain\Services\Reservation\ReservationServiceInterface;
27 use AmeliaBooking\Domain\Services\Settings\SettingsService;
28 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
29 use AmeliaBooking\Domain\ValueObjects\String\PaymentStatus;
30 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
31 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
32 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\CategoryRepository;
33 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ExtraRepository;
34 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ServiceRepository;
35 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingRepository;
36 use AmeliaBooking\Infrastructure\Repository\Coupon\CouponRepository;
37 use AmeliaBooking\Infrastructure\Repository\Location\LocationRepository;
38 use AmeliaBooking\Infrastructure\Repository\User\UserRepository;
39 use AmeliaBooking\Infrastructure\WP\Translations\BackendStrings;
40 use DateTime;
41 use Exception;
42 use Interop\Container\Exception\ContainerException;
43 use Slim\Exception\ContainerValueNotFoundException;
44
45 /**
46 * Class AppointmentPlaceholderService
47 *
48 * @package AmeliaBooking\Application\Services\Placeholder
49 */
50 class AppointmentPlaceholderService extends PlaceholderService
51 {
52 /**
53 *
54 * @return array
55 *
56 * @throws ContainerException
57 */
58 public function getEntityPlaceholdersDummyData($type)
59 {
60 /** @var SettingsService $settingsService */
61 $settingsService = $this->container->get('domain.settings.service');
62
63 /** @var HelperService $helperService */
64 $helperService = $this->container->get('application.helper.service');
65
66 $companySettings = $settingsService->getCategorySettings('company');
67
68 $dateFormat = $settingsService->getSetting('wordpress', 'dateFormat');
69 $timeFormat = $settingsService->getSetting('wordpress', 'timeFormat');
70
71 $timeZone = get_option('timezone_string');
72
73 if (empty($timeZone)) {
74 $gmtOffset = get_option('gmt_offset');
75 $timeZone = sprintf('Etc/GMT%+d', -$gmtOffset);
76 }
77
78 $dateTime = new DateTime("now", new \DateTimeZone($timeZone));
79
80 $appointment_date = $dateTime->format($dateFormat);
81 $appointment_date_time = $dateTime->format($dateFormat . ' ' . $timeFormat);
82 $appointment_start_time = $dateTime->format($timeFormat);
83 $appointment_end_time = (new DateTime("now +1 hour", new \DateTimeZone($timeZone)))->format($timeFormat);
84
85 return [
86 'appointment_id' => '1',
87 'appointment_date' => $appointment_date,
88 'appointment_date_time' => $appointment_date_time,
89 'appointment_start_time' => $appointment_start_time,
90 'appointment_end_time' => $appointment_end_time,
91 'appointment_notes' => 'Appointment note',
92 'appointment_price' => $helperService->getFormattedPrice(100),
93 'payment_due_amount' => $helperService->getFormattedPrice(80),
94 'appointment_cancel_url' => 'http://cancel_url.com',
95 'appointment_approve_url' => 'http://approve_url.com',
96 'appointment_reject_url' => 'http://reject_url.com',
97 'zoom_join_url' => $type === 'email' ?
98 '<a href="#">' . BackendStrings::getCommonStrings()['zoom_click_to_join'] . '</a>' : 'https://join_zoom_link.com',
99 'zoom_host_url' => $type === 'email' ?
100 '<a href="#">' . BackendStrings::getCommonStrings()['zoom_click_to_start'] . '</a>' : 'https://start_zoom_link.com',
101 'google_meet_url' => $type === 'email' ?
102 '<a href="#">' . BackendStrings::getCommonStrings()['google_meet_join'] . '</a>' : 'https://join_google_meet_link.com',
103 'lesson_space_url' => $type === 'email' ?
104 '<a href="#">' . BackendStrings::getCommonStrings()['lesson_space_join'] . '</a>' : 'https://lessonspace.com/room-id',
105 'appointment_duration' => $helperService->secondsToNiceDuration(1800),
106 'appointment_deposit_payment' => $helperService->getFormattedPrice(20),
107 'appointment_status' => BackendStrings::getCommonStrings()['approved'],
108 'category_name' => 'Category Name',
109 'service_description' => 'Service Description',
110 'reservation_description' => 'Service Description',
111 'service_duration' => $helperService->secondsToNiceDuration(5400),
112 'service_name' => 'Service Name',
113 'service_id' => '123',
114 'reservation_name' => 'Service Name',
115 'service_price' => $helperService->getFormattedPrice(100),
116 'service_extras' => 'Extra1, Extra2, Extra3',
117 'service_extras_details' => '<p>Extra1: ($1.00 x 1) x 3</p><p>Extra2: ($2.00 x 2)</p><p>Extra3: ($3.00 x 3)</p>' .
118 '<p>-------------------------</p>' . '<p>' . BackendStrings::getCommonStrings()['extras_total_price'] . ' $16.00</p>'
119
120 ];
121 }
122
123 /**
124 * @param array $appointment
125 * @param int $bookingKey
126 * @param string $type
127 *
128 * @return array
129 *
130 * @throws InvalidArgumentException
131 * @throws ContainerValueNotFoundException
132 * @throws NotFoundException
133 * @throws QueryExecutionException
134 * @throws ContainerException
135 * @throws Exception
136 */
137 public function getAppointmentPlaceholderData($appointment, $bookingKey = null, $type = null, $token = null, $invoice = false)
138 {
139 $data = [];
140
141 $this->setData($appointment, $bookingKey);
142
143 $data = array_merge($data, $this->getAppointmentData($appointment, $bookingKey, $type));
144 $data = array_merge($data, $this->getServiceData($appointment, $bookingKey, $type));
145 $data = array_merge($data, $this->getEmployeeData($appointment, $bookingKey));
146 $data = array_merge($data, $this->getBookingData($appointment, $type, $bookingKey, $token, $data['deposit'], null, $invoice));
147 $data = array_merge($data, $this->getCustomFieldsData($appointment, $type, $bookingKey));
148 $data = array_merge($data, $this->getCouponsData($appointment, $type, $bookingKey));
149
150 return $data;
151 }
152
153 /**
154 * @param array $appointment
155 * @param int $bookingKey
156 * @param string $type
157 * @param AbstractUser $customer
158 *
159 * @return array
160 *
161 * @throws InvalidArgumentException
162 * @throws ContainerValueNotFoundException
163 * @throws NotFoundException
164 * @throws QueryExecutionException
165 * @throws ContainerException
166 * @throws Exception
167 */
168 public function getPlaceholdersData($appointment, $bookingKey = null, $type = null, $customer = null, $allBookings = null)
169 {
170 /** @var CustomerBookingRepository $bookingRepository */
171 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
172
173 $bookingKeyForEmployee = null;
174
175 if ($bookingKey === null) {
176 $bookingKeyForEmployee = $this->getBookingKeyForEmployee($appointment);
177 }
178
179 $token = isset($appointment['bookings'][$bookingKey]) ?
180 $bookingRepository->getToken($appointment['bookings'][$bookingKey]['id']) :
181 ($bookingKeyForEmployee ? $bookingRepository->getToken($bookingKeyForEmployee) : null);
182
183 $token = isset($token['token']) ? $token['token'] : null;
184
185 $data = [];
186
187 $this->setData($appointment, $bookingKey);
188
189 $locale = $this->getLocale($appointment, $bookingKey);
190
191 $data = array_merge($data, $this->getAppointmentPlaceholderData($appointment, $bookingKey, $type, $token));
192 $data = array_merge($data, $this->getRecurringAppointmentsData($appointment, $bookingKey, $type, 'recurring', $bookingKeyForEmployee));
193 if (empty($customer)) {
194 $data = array_merge($data, $this->getGroupedAppointmentData($appointment, $bookingKey, $type, $token));
195 }
196 $data = array_merge($data, $this->getCompanyData($bookingKey !== null ? $locale : null));
197 $data = array_merge($data, $this->getCustomersData($appointment, $type, $bookingKey, $customer));
198
199 return $data;
200 }
201
202
203 /**
204 * @param array $reservationData
205 *
206 * @return array
207 *
208 * @throws InvalidArgumentException
209 * @throws ContainerValueNotFoundException
210 * @throws NotFoundException
211 * @throws QueryExecutionException
212 * @throws ContainerException
213 * @throws Exception
214 */
215 public function getInvoicePlaceholdersData($reservationData)
216 {
217 $type = 'email';
218
219 $data = [];
220
221 $appointment = $reservationData['appointment'];
222 $bookingKey = array_search($reservationData['booking']['id'], array_column($appointment['bookings'], 'id'));
223
224 $this->setData($appointment, $bookingKey);
225
226 $locale = $this->getLocale($appointment, $bookingKey);
227
228 $appointments = array_merge([['appointment' => $appointment, 'booking' => $reservationData['booking']]], $reservationData['recurring']);
229
230 foreach ($appointments as $recurringAppointment) {
231 $appointment = $recurringAppointment['appointment'];
232 $bookingKey = array_search($recurringAppointment['booking']['id'], array_column($appointment['bookings'], 'id'));
233
234 $placeholders = $this->getAppointmentPlaceholderData($appointment, $bookingKey, $type, null, true);
235 $invoiceItem = $placeholders['invoice_items_booking'][0];
236
237 $data['invoice_number'] = $placeholders['payment_invoice_number'];
238 $data['invoice_method'] = !empty($placeholders['payment_gateway_title']) ? $placeholders['payment_gateway_title'] : $placeholders['payment_type'];
239 $data['invoice_issued'] = $placeholders['payment_created'];
240
241 $index = "service_{$appointment['serviceId']}_{$recurringAppointment['booking']['price']}";
242 if (!empty($data['items'][$index])) {
243 $data['items'][$index]['invoice_qty'] += $invoiceItem['invoice_qty'];
244 $data['items'][$index]['invoice_subtotal'] += $invoiceItem['invoice_subtotal'];
245 $data['items'][$index]['invoice_discount'] += $invoiceItem['invoice_discount'];
246 $data['items'][$index]['invoice_tax'] += $invoiceItem['invoice_tax'];
247 $data['items'][$index]['invoice_paid_amount'] += $invoiceItem['invoice_paid_amount'];
248 } else {
249 $data['items'][$index] = $invoiceItem;
250 $data['items'][$index]['item_name'] = $placeholders['service_name'];
251 }
252
253 $extraItems = $placeholders['invoice_items_extras'];
254 $extraItemsTaxes = $invoiceItem['invoice_extras_tax'];
255 foreach ($extraItems as $extraItem) {
256 $index = $extraItem['item_index'];
257 if (!empty($data['items'][$index])) {
258 $data['items'][$index]['invoice_qty'] += $extraItem['invoice_qty'];
259 $data['items'][$index]['invoice_subtotal'] += $extraItems['invoice_subtotal'];
260 $data['items'][$index]['invoice_tax'] += $extraItems['invoice_tax']['amount'];
261 $data['items'][$index]['invoice_tax_rate'] += $extraItems['invoice_tax']['rate'];
262 } else {
263 $data['items'][$index] = array_merge(
264 $extraItem,
265 !empty($extraItemsTaxes[$extraItem['item_id']]) ?
266 ['invoice_tax' => $extraItemsTaxes[$extraItem['item_id']]['amount'], 'invoice_tax_rate' => $extraItemsTaxes[$extraItem['item_id']]['rate'], 'invoice_tax_excluded' => $extraItemsTaxes[$extraItem['item_id']]['excluded']] :
267 []
268 );
269 }
270 }
271 }
272
273 $data['items'] = array_values($data['items']);
274
275 $data = array_merge($data, $this->getCompanyData($bookingKey !== null ? $locale : null));
276 $data = array_merge($data, $this->getCustomersData($appointment, $type, $bookingKey));
277
278 return $data;
279 }
280
281 /**
282 * @param $appointment
283 * @param null $bookingKey
284 * @param string $type
285 *
286 * @return array
287 *
288 * @throws Exception
289 */
290 protected function getAppointmentData($appointment, $bookingKey = null, $type = null)
291 {
292 /** @var UserRepository $userRepository */
293 $userRepository = $this->container->get('domain.users.repository');
294
295 /** @var SettingsService $settingsService */
296 $settingsService = $this->container->get('domain.settings.service');
297
298 $dateFormat = $settingsService->getSetting('wordpress', 'dateFormat');
299 $timeFormat = $settingsService->getSetting('wordpress', 'timeFormat');
300
301 if ($appointment['providerId'] && empty($appointment['provider'])) {
302 /** @var Provider $user */
303 $user = $userRepository->getById($appointment['providerId']);
304
305 $appointment['provider'] = $user->toArray();
306 }
307
308 if ($bookingKey !== null && $appointment['bookings'][$bookingKey]['utcOffset'] !== null
309 && $settingsService->getSetting('general', 'showClientTimeZone')
310 ) {
311 $info = !empty($appointment['bookings'][$bookingKey]['info'])
312 ? json_decode($appointment['bookings'][$bookingKey]['info'], true)
313 : null;
314
315 $timeZone = !empty($info['timeZone']) ? $info['timeZone'] : '';
316
317 $bookingStart = DateTimeService::getClientUtcCustomDateTimeObject(
318 DateTimeService::getCustomDateTimeInUtc($appointment['bookingStart']),
319 $appointment['bookings'][$bookingKey]['utcOffset']
320 );
321
322 $bookingEnd = DateTimeService::getClientUtcCustomDateTimeObject(
323 DateTimeService::getCustomDateTimeInUtc($appointment['bookingEnd']),
324 $appointment['bookings'][$bookingKey]['utcOffset']
325 );
326
327 $oldBookingStart = !empty($appointment['initialAppointmentDateTime']) ? DateTimeService::getClientUtcCustomDateTimeObject(
328 DateTimeService::getCustomDateTimeInUtc($appointment['initialAppointmentDateTime']['bookingStart']),
329 $appointment['bookings'][$bookingKey]['utcOffset']
330 ) : '';
331
332 $oldBookingEnd = !empty($appointment['initialAppointmentDateTime']) ? DateTimeService::getClientUtcCustomDateTimeObject(
333 DateTimeService::getCustomDateTimeInUtc($appointment['initialAppointmentDateTime']['bookingEnd']),
334 $appointment['bookings'][$bookingKey]['utcOffset']
335 ) : '';
336 } else if ($bookingKey === null && !empty($appointment['provider']['timeZone'])) {
337 $timeZone = $appointment['provider']['timeZone'];
338
339 $bookingStart = DateTimeService::getDateTimeObjectInTimeZone(
340 DateTimeService::getCustomDateTimeObject(
341 $appointment['bookingStart']
342 )->setTimezone(new \DateTimeZone($timeZone))->format('Y-m-d H:i:s'),
343 'UTC'
344 );
345
346 $bookingEnd = DateTimeService::getDateTimeObjectInTimeZone(
347 DateTimeService::getCustomDateTimeObject(
348 $appointment['bookingEnd']
349 )->setTimezone(new \DateTimeZone($timeZone))->format('Y-m-d H:i:s'),
350 'UTC'
351 );
352
353 $oldBookingStart = !empty($appointment['initialAppointmentDateTime']) ?
354 DateTimeService::getDateTimeObjectInTimeZone(
355 DateTimeService::getCustomDateTimeObject(
356 $appointment['initialAppointmentDateTime']['bookingStart']
357 )->setTimezone(new \DateTimeZone($timeZone))->format('Y-m-d H:i:s'),
358 'UTC'
359 ) : '';
360
361 $oldBookingEnd = !empty($appointment['initialAppointmentDateTime']) ?
362 DateTimeService::getDateTimeObjectInTimeZone(
363 DateTimeService::getCustomDateTimeObject(
364 $appointment['initialAppointmentDateTime']['bookingEnd']
365 )->setTimezone(new \DateTimeZone($timeZone))->format('Y-m-d H:i:s'),
366 'UTC'
367 ) : '';
368 } else {
369 $timeZone = get_option('timezone_string');
370
371 $bookingStart = DateTime::createFromFormat('Y-m-d H:i:s', $appointment['bookingStart']);
372
373 $bookingEnd = DateTime::createFromFormat('Y-m-d H:i:s', $appointment['bookingEnd']);
374
375 $oldBookingStart = !empty($appointment['initialAppointmentDateTime']) ?
376 DateTime::createFromFormat('Y-m-d H:i:s', $appointment['initialAppointmentDateTime']['bookingStart']) : '';
377
378 $oldBookingEnd = !empty($appointment['initialAppointmentDateTime']) ?
379 DateTime::createFromFormat('Y-m-d H:i:s', $appointment['initialAppointmentDateTime']['bookingEnd']) : '';
380 }
381
382 $zoomStartUrl = '';
383 $zoomJoinUrl = '';
384
385 $lessonSpaceLink = '';
386 if (array_key_exists('lessonSpace', $appointment) && $appointment['lessonSpace']) {
387 $lessonSpaceLink = $type === 'email' ?
388 '<a href="' . $appointment['lessonSpace'] . '">' . BackendStrings::getCommonStrings()['lesson_space_join'] . '</a>'
389 : $appointment['lessonSpace'];
390 }
391
392 if (isset($appointment['zoomMeeting']['joinUrl'], $appointment['zoomMeeting']['startUrl'])) {
393 $zoomStartUrl = $appointment['zoomMeeting']['startUrl'];
394 $zoomJoinUrl = $appointment['zoomMeeting']['joinUrl'];
395 }
396
397 $googleMeetUrl = '';
398 if (array_key_exists('googleMeetUrl', $appointment) && $appointment['googleMeetUrl']) {
399 $googleMeetUrl = $type === 'email' ?
400 '<a href="' . $appointment['googleMeetUrl'] . '">' . BackendStrings::getCommonStrings()['google_meet_join'] . '</a>'
401 : $appointment['googleMeetUrl'];
402 }
403
404 return [
405 'appointment_id' => !empty($appointment['id']) ? $appointment['id'] : '',
406 'appointment_status' => BackendStrings::getCommonStrings()[$appointment['status']],
407 'appointment_notes' => !empty($appointment['internalNotes']) ? $appointment['internalNotes'] : '',
408 'appointment_date' => date_i18n($dateFormat, $bookingStart->getTimestamp()),
409 'appointment_date_time' => date_i18n($dateFormat . ' ' . $timeFormat, $bookingStart->getTimestamp()),
410 'appointment_start_time' => date_i18n($timeFormat, $bookingStart->getTimestamp()),
411 'appointment_end_time' => date_i18n($timeFormat, $bookingEnd->getTimestamp()),
412 'initial_appointment_date' => !empty($oldBookingStart) ? date_i18n($dateFormat, $oldBookingStart->getTimestamp()) : '',
413 'initial_appointment_date_time' => !empty($oldBookingStart) ? date_i18n($dateFormat . ' ' . $timeFormat, $oldBookingStart->getTimestamp()) : '',
414 'initial_appointment_start_time' => !empty($oldBookingStart) ? date_i18n($timeFormat, $oldBookingStart->getTimestamp()) : '',
415 'initial_appointment_end_time' => !empty($oldBookingEnd) ? date_i18n($timeFormat, $oldBookingEnd->getTimestamp()) : '',
416 'lesson_space_url' => $lessonSpaceLink,
417 'zoom_host_url' => $zoomStartUrl && $type === 'email' ?
418 '<a href="' . $zoomStartUrl . '">' . BackendStrings::getCommonStrings()['zoom_click_to_start'] . '</a>'
419 : $zoomStartUrl,
420 'zoom_join_url' => $zoomJoinUrl && $type === 'email' ?
421 '<a href="' . $zoomJoinUrl . '">' . BackendStrings::getCommonStrings()['zoom_click_to_join'] . '</a>'
422 : $zoomJoinUrl,
423 'google_meet_url' => $googleMeetUrl,
424 'time_zone' => $timeZone,
425 ];
426 }
427
428 /**
429 * @param $appointmentArray
430 * @param $bookingKey
431 *
432 * @return array
433 * @throws ContainerValueNotFoundException
434 * @throws NotFoundException
435 * @throws QueryExecutionException
436 * @throws ContainerException
437 * @throws InvalidArgumentException
438 */
439 private function getServiceData($appointmentArray, $bookingKey, $type)
440 {
441 /** @var CategoryRepository $categoryRepository */
442 $categoryRepository = $this->container->get('domain.bookable.category.repository');
443 /** @var ServiceRepository $serviceRepository */
444 $serviceRepository = $this->container->get('domain.bookable.service.repository');
445
446 /** @var HelperService $helperService */
447 $helperService = $this->container->get('application.helper.service');
448 /** @var AppointmentApplicationService $appointmentAS */
449 $appointmentAS = $this->container->get('application.booking.appointment.service');
450
451 /** @var Service $service */
452 $service = $serviceRepository->getByIdWithExtras($appointmentArray['serviceId']);
453 /** @var Category $category */
454 $category = $categoryRepository->getById($service->getCategoryId()->getValue());
455
456 $locale = $this->getLocale($appointmentArray, $bookingKey);
457
458 $categoryName = $helperService->getBookingTranslation(
459 $bookingKey !== null ? $locale : null,
460 $category->getTranslations() ? $category->getTranslations()->getValue() : null,
461 'name'
462 ) ?: $category->getName()->getValue();
463
464 $serviceName = $helperService->getBookingTranslation(
465 $bookingKey !== null ? $locale : null,
466 $service->getTranslations() ? $service->getTranslations()->getValue() : null,
467 'name'
468 ) ?: $service->getName()->getValue();
469
470 $serviceDescription = $helperService->getBookingTranslation(
471 $bookingKey !== null ? $locale : null,
472 $service->getTranslations() ? $service->getTranslations()->getValue() : null,
473 'description'
474 ) ?: ($service->getDescription() ? $service->getDescription()->getValue() : '');
475
476 $servicePrices = [];
477
478 $serviceDurations = [];
479
480 if ($bookingKey === null) {
481 foreach ($appointmentArray['bookings'] as $booking) {
482 if ($booking['status'] === BookingStatus::CANCELED || $booking['status'] === BookingStatus::REJECTED) {
483 continue;
484 }
485
486 $duration = $booking['duration'] ? $booking['duration'] : $service->getDuration()->getValue();
487
488 $price = $appointmentAS->getBookingPriceForServiceDuration(
489 $service,
490 $duration
491 );
492
493 $servicePrices[] = $helperService->getFormattedPrice($price);
494
495 $serviceDurations[$duration] = $helperService->secondsToNiceDuration($duration);
496 }
497 } else {
498 $duration = !empty($appointmentArray['bookings'][$bookingKey]['duration'])
499 ? $appointmentArray['bookings'][$bookingKey]['duration'] : $service->getDuration()->getValue();
500
501 $price = $appointmentAS->getBookingPriceForServiceDuration(
502 $service,
503 $duration
504 );
505
506 $servicePrices[] = $helperService->getFormattedPrice(
507 $price
508 );
509
510 $serviceDurations[$duration] = $helperService->secondsToNiceDuration(
511 $duration
512 );
513 }
514
515 $data = [
516 'category_name' => $categoryName,
517 'category_id' => $category->getId()->getValue(),
518 'service_description' => $serviceDescription,
519 'reservation_description' => $serviceDescription,
520 'service_duration' => implode(', ', $serviceDurations),
521 'service_name' => $serviceName,
522 'service_id' => $service->getId()->getValue(),
523 'reservation_name' => $serviceName,
524 'service_price' => implode(', ', array_unique($servicePrices)),
525 ];
526
527 $bookingExtras = [];
528
529 $persons = 1;
530
531 foreach ((array)$appointmentArray['bookings'] as $key => $booking) {
532 if (($bookingKey === null && ($booking['isChangedStatus'] || $booking['status'] === BookingStatus::APPROVED
533 || $booking['status'] === BookingStatus::PENDING)) || $bookingKey === $key
534 ) {
535 foreach ((array)$booking['extras'] as $bookingExtra) {
536 $bookingExtras[$bookingExtra['extraId']] = [
537 'quantity' => $bookingExtra['quantity'],
538 'price' => $bookingExtra['price']
539 ];
540 }
541
542 $persons = $booking['persons'];
543 }
544 }
545
546 /** @var ExtraRepository $extraRepository */
547 $extraRepository = $this->container->get('domain.bookable.extra.repository');
548
549 /** @var Collection $extras */
550 $extras = $extraRepository->getAllIndexedById();
551
552 $duration = $service->getDuration()->getValue();
553
554 if ($bookingKey !== null) {
555 $duration = !empty($appointmentArray['bookings'][$bookingKey]['duration']) ?
556 $appointmentArray['bookings'][$bookingKey]['duration'] : $duration;
557
558 foreach ($appointmentArray['bookings'][$bookingKey]['extras'] as $bookingExtra) {
559 /** @var Extra $extra */
560 $extra = $extras->getItem($bookingExtra['extraId']);
561
562 $duration += $extra->getDuration() ? $extra->getDuration()->getValue() * $bookingExtra['quantity'] : 0;
563 }
564 } else {
565 $maxBookingDuration = 0;
566
567 foreach ($appointmentArray['bookings'] as $booking) {
568 $bookingDuration = $booking['duration'] ? $booking['duration'] : $duration;
569
570 foreach ($booking['extras'] as $bookingExtra) {
571 /** @var Extra $extra */
572 $extra = $extras->getItem($bookingExtra['extraId']);
573
574 $bookingDuration += $extra->getDuration() ?
575 $extra->getDuration()->getValue() * $bookingExtra['quantity'] : 0;
576 }
577
578 if ($bookingDuration > $maxBookingDuration &&
579 ($booking['status'] === BookingStatus::APPROVED || $booking['status'] === BookingStatus::PENDING)
580 ) {
581 $maxBookingDuration = $bookingDuration;
582 }
583 }
584
585 $duration = $maxBookingDuration;
586 }
587
588 $data['appointment_duration'] = $helperService->secondsToNiceDuration($duration);
589
590 /** @var string $break */
591 $break = $type === 'whatsapp' ? '; ' : PHP_EOL;
592
593 $lastBookingExtraIds = [];
594 if ($bookingKey === null) {
595 $lastBookingId = $this->getBookingKeyForEmployee($appointmentArray);
596
597 $lastBooking = array_filter(
598 $appointmentArray['bookings'],
599 function ($b) use ($lastBookingId) {
600 return $b['id'] === $lastBookingId;
601 }
602 );
603
604 foreach ($lastBooking ? array_shift($lastBooking)['extras'] : [] as $ex) {
605 $lastBookingExtraIds[$ex['extraId']] = $ex;
606 }
607 }
608
609 $allExtraNames = "";
610 $allExtraDetails = "";
611 $allExtraSum = 0;
612
613 $invoiceItems = [];
614
615 /** @var Extra $extra */
616 foreach ($extras->getItems() as $extra) {
617 $extraId = $extra->getId()->getValue();
618
619 $data["service_extra_{$extraId}_name"] =
620 array_key_exists($extraId, $bookingExtras) ? $extra->getName()->getValue() : '';
621
622 $data["service_extra_{$extraId}_name"] = $helperService->getBookingTranslation(
623 $bookingKey !== null ? $locale : null,
624 $data["service_extra_{$extraId}_name"] && $extra->getTranslations() ?
625 $extra->getTranslations()->getValue() : null,
626 'name'
627 ) ?: $data["service_extra_{$extraId}_name"];
628
629 $data["service_extra_{$extraId}_quantity"] =
630 array_key_exists($extraId, $bookingExtras) ? $bookingExtras[$extraId]['quantity'] : '';
631
632 $data["service_extra_{$extraId}_price"] = array_key_exists($extraId, $bookingExtras) ?
633 $helperService->getFormattedPrice($extra->getPrice()->getValue()) : '';
634
635 $multiplyByNumberOfPeople = ($extra->getAggregatedPrice() === null ? $service->getAggregatedPrice()->getValue()
636 : $extra->getAggregatedPrice()->getValue()) && $persons !== 1;
637
638 if (!empty($data["service_extra_{$extraId}_name"])) {
639 $allExtraNames .= $data["service_extra_{$extraId}_name"].', ';
640 }
641
642 if (array_key_exists($extraId, $bookingExtras) && $bookingExtras[$extraId]['quantity'] !== 0) {
643 if ($bookingKey === null) {
644 if (!array_key_exists($extraId, $lastBookingExtraIds)) {
645 continue;
646 }
647 }
648 $allExtraDetails .= ($type === 'email' ? '<p>' : '') . $extra->getName()->getValue() . ': (' .
649 $helperService->getFormattedPrice($extra->getPrice()->getValue()) . ' x ' .
650 $bookingExtras[$extraId]['quantity'] . ') ' .
651 ($multiplyByNumberOfPeople ? ('x ' . $persons) : '') .
652 ($type === 'email' ? '</p>' : $break);
653
654 $allExtraSum += $extra->getPrice()->getValue() * $bookingExtras[$extraId]['quantity'] *
655 ($multiplyByNumberOfPeople ? $persons : 1);
656
657 $invoiceItems[] = [
658 'item_id' => $extraId,
659 'item_index' => "extra_{$extraId}_{$bookingExtras[$extraId]['price']}",
660 'item_name' => $extra->getName()->getValue(),
661 'invoice_qty' => $bookingExtras[$extraId]['quantity'] * $persons,
662 'invoice_unit_price' => $bookingExtras[$extraId]['price'],
663 'invoice_subtotal' => $bookingExtras[$extraId]['quantity'] * $bookingExtras[$extraId]['price'] *
664 ($multiplyByNumberOfPeople ? $persons : 1),
665 'invoice_tax' => 0
666 ];
667 }
668 }
669
670 $data["service_extras"] = substr($allExtraNames, 0, -2);
671
672 $data['deposit'] = $service->getDeposit() && $service->getDeposit()->getValue();
673
674 $data['invoice_items_extras'] = $invoiceItems;
675
676 $data["service_extras_details"] = $allExtraDetails ? ($allExtraDetails . ($type !== 'whatsapp' ?
677 ($type === 'email' ? '<p>' : $break) . "-------------------------" . ($type === 'email' ? '</p>' : $break) : '') .
678 ($type === 'email' ? '<p>' : '') . BackendStrings::getCommonStrings()['extras_total_price'] .
679 " {$helperService->getFormattedPrice($allExtraSum)}" . ($type === 'email' ? '</p>' : '')) : "";
680
681 return $data;
682 }
683
684 /**
685 * @param $appointment
686 * @param $bookingKey
687 *
688 * @return array
689 *
690 * @throws ContainerValueNotFoundException
691 * @throws NotFoundException
692 * @throws QueryExecutionException
693 */
694 public function getEmployeeData($appointment, $bookingKey = null)
695 {
696 /** @var HelperService $helperService */
697 $helperService = $this->container->get('application.helper.service');
698
699 /** @var UserRepository $userRepository */
700 $userRepository = $this->container->get('domain.users.repository');
701
702 /** @var LocationRepository $locationRepository */
703 $locationRepository = $this->container->get('domain.locations.repository');
704
705 /** @var SettingsService $settingsService */
706 $settingsService = $this->container->get('domain.settings.service');
707
708 /** @var Provider $user */
709 $user = $userRepository->getById($appointment['providerId']);
710
711 $locale = $this->getLocale($appointment, $bookingKey);
712
713 if (!empty($appointment['locationId'])) {
714 $locationId = $appointment['locationId'];
715 } else {
716 $locationId = $user->getLocationId() ? $user->getLocationId()->getValue() : null;
717 }
718
719 /** @var Location $location */
720 $location = $locationId ? $locationRepository->getById($locationId) : null;
721
722 $locationName = $settingsService->getSetting('company', 'address');
723
724 $locationDescription = '';
725
726 if ($location) {
727 $locationName = $helperService->getBookingTranslation(
728 $bookingKey !== null ? $locale : null,
729 $location->getTranslations() ? $location->getTranslations()->getValue() : null,
730 'name'
731 ) ?: $location->getName()->getValue();
732
733 $locationDescription = $helperService->getBookingTranslation(
734 $bookingKey !== null ? $locale : null,
735 $location->getTranslations() ? $location->getTranslations()->getValue() : null,
736 'description'
737 ) ?: ($location->getDescription() ? $location->getDescription()->getValue() : '');
738 }
739
740 $firstName = $helperService->getBookingTranslation(
741 $bookingKey !== null ? $locale : null,
742 $user->getTranslations() ? $user->getTranslations()->getValue() : null,
743 'firstName'
744 ) ?: $user->getFirstName()->getValue();
745
746 $lastName = $helperService->getBookingTranslation(
747 $bookingKey !== null ? $locale : null,
748 $user->getTranslations() ? $user->getTranslations()->getValue() : null,
749 'lastName'
750 ) ?: $user->getLastName()->getValue();
751
752 $userDescription = $helperService->getBookingTranslation(
753 $bookingKey !== null ? $locale : null,
754 $user->getTranslations() ? $user->getTranslations()->getValue() : null,
755 'description'
756 ) ?: ($user->getDescription() ? $user->getDescription()->getValue() : '');
757
758 return [
759 'employee_id' => $user->getId()->getValue(),
760 'employee_email' => $user->getEmail()->getValue(),
761 'employee_first_name' => $firstName,
762 'employee_last_name' => $lastName,
763 'employee_full_name' => $firstName . ' ' . $lastName,
764 'employee_phone' => $user->getPhone()->getValue(),
765 'employee_note' => $user->getNote() ? $user->getNote()->getValue() : '',
766 'employee_description' => $userDescription,
767 'employee_panel_url' => trim(
768 $this->container->get('domain.settings.service')
769 ->getSetting('roles', 'providerCabinet')['pageUrl']
770 ),
771 'location_address' => !$location ?
772 $settingsService->getSetting('company', 'address') : $location->getAddress()->getValue(),
773 'location_phone' => !$location ?
774 $settingsService->getSetting('company', 'phone') : $location->getPhone()->getValue(),
775 'location_id' => $locationId,
776 'location_name' => $locationName,
777 'location_description' => $locationDescription,
778 'location_latitude' => $location && $location->getCoordinates() ? $location->getCoordinates()->getLatitude() : null,
779 'location_longitude' => $location && $location->getCoordinates() ? $location->getCoordinates()->getLongitude() : null,
780 ];
781 }
782
783 /**
784 * @param array $appointment
785 * @param int $bookingKey
786 * @param string $type
787 * @param string $placeholderType
788 *
789 * @return array
790 *
791 * @throws ContainerValueNotFoundException
792 * @throws NotFoundException
793 * @throws QueryExecutionException
794 * @throws ContainerException
795 * @throws Exception
796 */
797 public function getRecurringAppointmentsData($appointment, $bookingKey, $type, $placeholderType, $bookingKeyForEmployee = null)
798 {
799 if (!array_key_exists('recurring', $appointment)) {
800 return [
801 "{$placeholderType}_appointments_details" => ''
802 ];
803 }
804
805 /** @var CustomerBookingRepository $bookingRepository */
806 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
807
808 /** @var PlaceholderService $placeholderService */
809 $placeholderService = $this->container->get("application.placeholder.appointment.service");
810
811 /** @var SettingsService $settingsService */
812 $settingsService = $this->container->get('domain.settings.service');
813
814 $appointmentsSettings = $settingsService->getCategorySettings('appointments');
815
816 $recurringAppointmentDetails = [];
817
818 foreach ($appointment['recurring'] as $recurringData) {
819 $recurringBookingKey = null;
820 $recurringBookingKeyForEmployee = null;
821
822 $isForCustomer =
823 $bookingKey !== null ||
824 (isset($appointment['isForCustomer']) && $appointment['isForCustomer']);
825
826 if ($isForCustomer) {
827 foreach ($recurringData['appointment']['bookings'] as $key => $recurringBooking) {
828 if (isset($recurringData['booking']['id'])) {
829 if ($recurringBooking['id'] === $recurringData['booking']['id']) {
830 $recurringBookingKey = $key;
831 }
832 } else if ($recurringBooking['customerId'] === $appointment['bookings'][$bookingKey]['customerId']) {
833 $recurringBookingKey = $key;
834 }
835 }
836
837 if ($recurringBookingKey === null) {
838 return [];
839 }
840 } elseif ($bookingKeyForEmployee !== null) {
841 foreach ($recurringData['appointment']['bookings'] as $key => $recurringBooking) {
842 if (isset($recurringData['booking']['id'])) {
843 if ($recurringBooking['id'] === $recurringData['booking']['id']) {
844 $recurringBookingKeyForEmployee = $key;
845 }
846 } else {
847 $recurringBookingKeyForEmployee = $bookingKeyForEmployee;
848 }
849 }
850 }
851
852 $token =
853 $recurringBookingKey !== null &&
854 isset(
855 $recurringData['appointment']['bookings'][$recurringBookingKey],
856 $recurringData['appointment']['bookings'][$recurringBookingKey]['id']
857 ) ? $bookingRepository->getToken($recurringData['appointment']['bookings'][$recurringBookingKey]['id']) :(
858 $recurringBookingKeyForEmployee !== null &&
859 isset(
860 $recurringData['appointment']['bookings'][$recurringBookingKeyForEmployee],
861 $recurringData['appointment']['bookings'][$recurringBookingKeyForEmployee]['id']
862 ) ? $bookingRepository->getToken($recurringData['appointment']['bookings'][$recurringBookingKeyForEmployee]['id']) :
863 null);
864
865 $recurringPlaceholders = [];
866
867 $recurringPlaceholders = array_merge(
868 $recurringPlaceholders,
869 $this->getEmployeeData($recurringData['appointment'], $recurringBookingKey)
870 );
871
872 $recurringPlaceholders = array_merge(
873 $recurringPlaceholders,
874 $this->getAppointmentData($recurringData['appointment'], $recurringBookingKey, $type)
875 );
876
877 $recurringPlaceholders = array_merge(
878 $recurringPlaceholders,
879 $this->getServiceData($recurringData['appointment'], $recurringBookingKey, $type)
880 );
881
882 $recurringPlaceholders = array_merge(
883 $recurringPlaceholders,
884 $this->getCustomFieldsData($recurringData['appointment'], $type, $recurringBookingKey)
885 );
886
887 $recurringPlaceholders = array_merge(
888 $recurringPlaceholders,
889 $this->getBookingData(
890 $recurringData['appointment'],
891 $type,
892 $recurringBookingKey,
893 isset($token['token']) ? $token['token'] : null,
894 $recurringPlaceholders['deposit']
895 )
896 );
897
898 unset($recurringPlaceholders['icsFiles']);
899
900 if (!$isForCustomer) {
901 if (isset($recurringPlaceholders['appointment_cancel_url'])) {
902 $recurringPlaceholders['appointment_cancel_url'] = '';
903 }
904
905 $recurringPlaceholders['zoom_join_url'] = '';
906 } else {
907 $recurringPlaceholders['employee_panel_url'] = '';
908
909 $recurringPlaceholders['zoom_host_url'] = '';
910 }
911
912 $placeholderString =
913 $placeholderType .
914 'Placeholders' .
915 ($isForCustomer && $placeholderType === 'package' ? 'Customer' : '') .
916 ($isForCustomer && $placeholderType === 'recurring' ? 'Customer' : '') .
917 ($isForCustomer && $placeholderType === 'cart' ? 'Customer' : '') .
918 ($type === 'email' ? '' : 'Sms');
919
920 /** @var HelperService $helperService */
921 $helperService = $this->container->get('application.helper.service');
922
923 $content = $helperService->getBookingTranslation(
924 $recurringBookingKey !== null ? $helperService->getLocaleFromBooking($recurringData['appointment']['bookings'][$recurringBookingKey]['info']) : null,
925 json_encode($appointmentsSettings['translations']),
926 $placeholderString
927 ) ?: $appointmentsSettings[$placeholderString];
928
929 if ($type === 'whatsapp') {
930 $content = str_replace(array("\n","\r"), '; ', $content);
931 $content = preg_replace('!\s+!', ' ', $content);
932 }
933
934 $recurringAppointmentDetails[] = $placeholderService->applyPlaceholders(
935 $content,
936 $recurringPlaceholders
937 );
938 }
939
940 return [
941 "{$placeholderType}_appointments_details" => $recurringAppointmentDetails ? implode(
942 $type === 'email' ? '<p><br></p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL),
943 $recurringAppointmentDetails
944 ) : ''
945 ];
946 }
947
948 /**
949 * @param array $appointment
950 * @param int $bookingKey
951 * @param string $type
952 *
953 * @return array
954 *
955 * @throws ContainerValueNotFoundException
956 * @throws NotFoundException
957 * @throws QueryExecutionException
958 * @throws ContainerException
959 * @throws Exception
960 */
961 public function getGroupedAppointmentData($appointment, $bookingKey, $type)
962 {
963 /** @var PlaceholderService $placeholderService */
964 $placeholderService = $this->container->get("application.placeholder.appointment.service");
965
966 /** @var SettingsService $settingsService */
967 $settingsService = $this->container->get('domain.settings.service');
968
969 $appointmentsSettings = $settingsService->getCategorySettings('appointments');
970
971 $groupAppointmentDetails = [];
972
973 if ($bookingKey) {
974 return [
975 "group_appointment_details" => ''
976 ];
977 }
978
979 foreach ($appointment['bookings'] as $bookingId => $booking) {
980 if ($booking['status'] === BookingStatus::CANCELED || $booking['status'] === BookingStatus::REJECTED || $booking['status'] === BookingStatus::NO_SHOW) {
981 continue;
982 }
983
984 /** @var CustomerBookingRepository $bookingRepository */
985 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
986
987 $token = $bookingRepository->getToken($appointment['bookings'][$bookingId]['id']);
988
989 $groupPlaceholders = array_merge(
990 $this->getAppointmentData($appointment, $bookingId, $type),
991 $this->getServiceData($appointment, $bookingId, $type),
992 $this->getCustomFieldsData($appointment, $type, $bookingId),
993 $this->getCustomersData($appointment, $type, $bookingId),
994 $this->getBookingData(
995 $appointment,
996 $type,
997 $bookingId,
998 isset($token['token']) ? $token['token'] : null,
999 null,
1000 true
1001 )
1002 );
1003
1004 $content = $appointmentsSettings['groupAppointmentPlaceholder' . ($type === null || $type === 'email' ? '' : 'Sms')] ;
1005 if ($type === 'email') {
1006 $content = str_replace(array("\n","\r"), '', $content);
1007 } else if ($type === 'whatsapp') {
1008 $content = str_replace(array("\n","\r"), '; ', $content);
1009 $content = preg_replace('!\s+!', ' ', $content);
1010 }
1011
1012 $groupAppointmentDetails[] = $placeholderService->applyPlaceholders(
1013 $content,
1014 $groupPlaceholders
1015 );
1016 }
1017
1018 return [
1019 "group_appointment_details" => $groupAppointmentDetails ? implode(
1020 $type === 'email' ? '<p><br></p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL),
1021 $groupAppointmentDetails
1022 ) : ''
1023 ];
1024 }
1025
1026 /**
1027 * @param array $bookingArray
1028 * @param array $entity
1029 *
1030 * @return array
1031 * @throws InvalidArgumentException
1032 * @throws NotFoundException
1033 * @throws QueryExecutionException
1034 */
1035 public function getAmountData(&$bookingArray, $entity, $invoice = false)
1036 {
1037 /** @var ReservationServiceInterface $reservationService */
1038 $reservationService = $this->container->get('application.reservation.service')->get(Entities::APPOINTMENT);
1039
1040 if (!empty($bookingArray['couponId']) && empty($bookingArray['coupon'])) {
1041 /** @var CouponRepository $couponRepository */
1042 $couponRepository = $this->container->get('domain.coupon.repository');
1043
1044 /** @var Coupon $coupon */
1045 $coupon = $couponRepository->getById($bookingArray['couponId']);
1046
1047 $bookingArray['coupon'] = $coupon ? $coupon->toArray() : null;
1048 }
1049
1050 $extras = [];
1051
1052 foreach ($bookingArray['extras'] as $extra) {
1053 $extras[$extra['extraId']] = [
1054 'price' => $extra['price'],
1055 'aggregatedPrice' => !!$extra['aggregatedPrice'],
1056 ];
1057 }
1058
1059 /** @var AbstractBookable $bookable */
1060 $bookable = ServiceFactory::create(
1061 [
1062 'price' => $bookingArray['price'],
1063 'aggregatedPrice' => !!$bookingArray['aggregatedPrice'],
1064 'extras' => $extras,
1065 ]
1066 );
1067
1068 /** @var CustomerBooking $booking */
1069 $booking = CustomerBookingFactory::create(
1070 [
1071 'persons' => $bookingArray['persons'],
1072 'coupon' => $bookingArray['coupon'],
1073 'extras' => $bookingArray['extras'],
1074 'tax' => $bookingArray['tax'],
1075 ]
1076 );
1077
1078 return $reservationService->getPaymentAmount($booking, $bookable, $invoice);
1079 }
1080 }
1081