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 / PlaceholderService.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
PlaceholderService.php
1109 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\Coupon\CouponApplicationService;
10 use AmeliaBooking\Application\Services\Helper\HelperService;
11 use AmeliaBooking\Domain\Collection\Collection;
12 use AmeliaBooking\Domain\Common\Exceptions\CouponInvalidException;
13 use AmeliaBooking\Domain\Common\Exceptions\CouponExpiredException;
14 use AmeliaBooking\Domain\Common\Exceptions\CouponUnknownException;
15 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
16 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
17 use AmeliaBooking\Domain\Entity\Booking\Event\Event;
18 use AmeliaBooking\Domain\Entity\Coupon\Coupon;
19 use AmeliaBooking\Domain\Entity\CustomField\CustomField;
20 use AmeliaBooking\Domain\Entity\Entities;
21 use AmeliaBooking\Domain\Entity\User\AbstractUser;
22 use AmeliaBooking\Domain\Entity\User\Customer;
23 use AmeliaBooking\Domain\Factory\Booking\Event\EventFactory;
24 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
25 use AmeliaBooking\Domain\Services\Settings\SettingsService;
26 use AmeliaBooking\Domain\ValueObjects\Number\Integer\LoginType;
27 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
28 use AmeliaBooking\Domain\ValueObjects\String\PaymentStatus;
29 use AmeliaBooking\Infrastructure\Common\Container;
30 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
31 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
32 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageCustomerRepository;
33 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
34 use AmeliaBooking\Infrastructure\Repository\Booking\Event\EventRepository;
35 use AmeliaBooking\Infrastructure\Repository\Coupon\CouponRepository;
36 use AmeliaBooking\Infrastructure\Repository\CustomField\CustomFieldRepository;
37 use AmeliaBooking\Infrastructure\Repository\User\UserRepository;
38 use AmeliaBooking\Infrastructure\WP\Translations\BackendStrings;
39 use AmeliaBooking\Infrastructure\WP\Translations\FrontendStrings;
40 use AmeliaBooking\Domain\ValueObjects\String\CustomFieldType;
41 use AmeliaBooking\Infrastructure\WP\Translations\LiteBackendStrings;
42 use Exception;
43 use Interop\Container\Exception\ContainerException;
44 use DateTime;
45 use Slim\Exception\ContainerValueNotFoundException;
46
47 /**
48 * Class PlaceholderService
49 *
50 * @package AmeliaBooking\Application\Services\Placeholder
51 */
52 abstract class PlaceholderService implements PlaceholderServiceInterface
53 {
54 /** @var Container */
55 protected $container;
56
57 /**
58 * ProviderApplicationService constructor.
59 *
60 * @param Container $container
61 *
62 * @throws \InvalidArgumentException
63 */
64 public function __construct(Container $container)
65 {
66 $this->container = $container;
67 }
68
69 /**
70 * @param string $text
71 * @param array $data
72 *
73 * @return mixed
74 */
75 public function applyPlaceholders($text, $data)
76 {
77 unset($data['icsFiles']);
78
79 unset($data['providersAppointments']);
80
81 unset($data['invoice_items_booking']);
82 unset($data['invoice_items_extras']);
83 unset($data['invoice_items_event']);
84
85 $placeholders = array_map(
86 function ($placeholder) {
87 return "%{$placeholder}%";
88 },
89 array_keys($data)
90 );
91
92 if ($text && strpos($text, '%amelia_dynamic_placeholder_') !== false) {
93 $lastPos = 0;
94
95 $dynamicPlaceholderStart = '%amelia_dynamic_placeholder_';
96
97 while (($lastPos = strpos($text, $dynamicPlaceholderStart, $lastPos)) !== false) {
98 $subText = substr($text, $lastPos + 1);
99
100 $dynamicPlaceholder = substr($subText, 0, strpos($subText, '%'));
101
102 $placeholders[] = '%' . $dynamicPlaceholder . '%';
103
104 $data[$dynamicPlaceholder] = apply_filters(
105 $dynamicPlaceholder,
106 $data
107 );
108
109 $lastPos = $lastPos + strlen($dynamicPlaceholderStart);
110 }
111 }
112
113 return str_replace($placeholders, array_values($data), $text);
114 }
115
116 /**
117 * @return array
118 *
119 * @throws ContainerException
120 */
121 public function getPlaceholdersDummyData($type)
122 {
123 /** @var SettingsService $settingsService */
124 $settingsService = $this->container->get('domain.settings.service');
125
126 /** @var string $paragraphStart */
127 $paragraphStart = $type === 'email' ? '<p>' : '';
128
129 /** @var string $paragraphEnd */
130 $paragraphEnd = $type === 'email' ? '</p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL);
131
132 $companySettings = $settingsService->getCategorySettings('company');
133
134 $timezone = get_option('timezone_string');
135
136 return array_merge(
137 [
138 'booked_customer' => $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_full_name'] .': John Micheal Doe ' . $paragraphEnd .
139 $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_phone'] . ': 193-951-2600 ' . $paragraphEnd .
140 $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_email'] . ': customer@domain.com ' . $paragraphEnd,
141 'company_address' => $companySettings['address'],
142 'company_name' => $companySettings['name'],
143 'company_phone' => $companySettings['phone'],
144 'company_website' => $companySettings['website'],
145 'company_email' => !empty($companySettings['email']) ? $companySettings['email'] : '',
146 'customer_email' => 'customer@domain.com',
147 'customer_first_name' => 'John',
148 'customer_last_name' => 'Doe',
149 'customer_full_name' => 'John Doe',
150 'customer_phone' => '193-951-2600',
151 'customer_note' => 'Customer Note',
152 'customer_panel_url' => $this->container->get('domain.settings.service')->getSetting('roles', 'customerCabinet')['pageUrl'],
153 'coupon_used' => 'code123',
154 'number_of_persons' => 2,
155 'time_zone' => $timezone,
156 'employee_email' => 'employee@domain.com',
157 'employee_first_name' => 'Richard',
158 'employee_last_name' => 'Roe',
159 'employee_full_name' => 'Richard Roe',
160 'employee_phone' => '150-698-1858',
161 'employee_note' => 'Employee Note',
162 'employee_description' => 'Employee Description',
163 'employee_panel_url' => 'https://your_site.com/employee-panel',
164 'location_address' => $companySettings['address'] ? $companySettings['address'] : 'Address 123',
165 'location_phone' => $companySettings['phone'],
166 'location_name' => 'Location Name',
167 'location_latitude' => '40.748441',
168 'location_longitude' => '-73.987853',
169 'location_description' => 'Location Description',
170 ],
171 $this->getEntityPlaceholdersDummyData($type)
172 );
173 }
174
175 /**
176 * @param string|null $locale
177 *
178 * @return array
179 */
180 public function getCompanyData($locale = null)
181 {
182 /** @var SettingsService $settingsService */
183 $settingsService = $this->container->get('domain.settings.service');
184
185 /** @var HelperService $helperService */
186 $helperService = $this->container->get('application.helper.service');
187
188 $companySettings = $settingsService->getCategorySettings('company');
189
190 $companyName = $helperService->getBookingTranslation(
191 $locale,
192 json_encode($companySettings['translations']),
193 'name'
194 ) ?: $companySettings['name'];
195
196 return [
197 'company_address' => $companySettings['address'],
198 'company_name' => $companyName,
199 'company_phone' => $companySettings['phone'],
200 'company_website' => $companySettings['website'],
201 'company_email' => !empty($companySettings['email']) ? $companySettings['email'] : null,
202 'company_logo' => $companySettings['pictureThumbPath']
203 ];
204 }
205
206 /**
207 * @param array $appointment
208 * @param string $type
209 * @param null $bookingKey
210 * @param null $token
211 *
212 * @return array
213 *
214 * @throws ContainerException
215 */
216 protected function getBookingData($appointment, $type, $bookingKey = null, $token = null, $depositEnabled = null, $isGroup = null, $invoice = false)
217 {
218 /** @var HelperService $helperService */
219 $helperService = $this->container->get('application.helper.service');
220
221 /** @var string $break */
222 $break = $type === 'email' ? '<p><br></p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL);
223
224 $couponsUsed = [];
225
226 $payment = null;
227
228 $invoiceItem = [];
229
230 $paymentLinks = [
231 'payment_link_woocommerce' => '',
232 'payment_link_stripe' => '',
233 'payment_link_paypal' => '',
234 'payment_link_razorpay' => '',
235 'payment_link_mollie' => '',
236 'payment_link_square' => ''
237 ];
238
239 $couponDiscount = 0;
240
241 $amountData = [
242 'price' => 0,
243 'discount' => 0,
244 'deduction' => 0,
245 ];
246
247 // If notification is for provider: Appointment price will be sum of all bookings prices
248 // If notification is for customer: Appointment price will be price of his booking
249 if ($bookingKey === null) {
250 $numberOfPersonsData = [
251 AbstractUser::USER_ROLE_PROVIDER => [
252 BookingStatus::APPROVED => 0,
253 BookingStatus::PENDING => 0,
254 BookingStatus::CANCELED => 0,
255 BookingStatus::REJECTED => 0,
256 BookingStatus::NO_SHOW => 0,
257 BookingStatus::WAITING => 0,
258 ]
259 ];
260
261 foreach ((array)$appointment['bookings'] as $customerBooking) {
262 $amountData = $this->getAmountData($customerBooking, $appointment);
263
264 $expirationDate = null;
265
266 if (!empty($customerBooking['coupon']['expirationDate'])) {
267 $expirationDate = $customerBooking['coupon']['expirationDate'];
268 }
269
270 if (($amountData['discount'] || $amountData['deduction']) && !empty($customerBooking['info'])) {
271 $customerData = json_decode($customerBooking['info'], true);
272
273 if (!$customerData) {
274 $customerData = [
275 'firstName' => $customerBooking['customer']['firstName'],
276 'lastName' => $customerBooking['customer']['lastName'],
277 ];
278 }
279
280 $couponsUsed[] =
281 BackendStrings::getCommonStrings()['customer'] . ': ' .
282 $customerData['firstName'] . ' ' . $customerData['lastName'] . ' ' .$break .
283 BackendStrings::getFinanceStrings()['code'] . ': ' .
284 $customerBooking['coupon']['code'] . ' ' . $break .
285 ($amountData['discount'] ? BackendStrings::getPaymentStrings()['discount_amount'] . ': ' .
286 $helperService->getFormattedPrice($amountData['discount']) . ' ' . $break : '') .
287 ($amountData['deduction'] ? BackendStrings::getPaymentStrings()['deduction'] . ': ' .
288 $helperService->getFormattedPrice($amountData['deduction']) . ' ' . $break : '') .
289 ($expirationDate ? BackendStrings::getPaymentStrings()['expiration_date'] . ': ' .
290 $expirationDate : '');
291 }
292
293 $numberOfPersonsData[AbstractUser::USER_ROLE_PROVIDER][$customerBooking['status']] +=
294 empty($customerBooking['ticketsData']) ? $customerBooking['persons'] : array_sum(array_column($customerBooking['ticketsData'], 'persons'));
295
296 $payment = !empty($customerBooking['payments'][0]) ? $customerBooking['payments'][0] : null;
297 }
298
299 $numberOfPersons = [];
300
301 foreach ($numberOfPersonsData[AbstractUser::USER_ROLE_PROVIDER] as $key => $value) {
302 if ($value) {
303 $numberOfPersons[] = BackendStrings::getCommonStrings()[$key] . ': ' . $value;
304 }
305 }
306
307 $numberOfPersons = implode($break, $numberOfPersons);
308
309 $icsFiles = !empty($appointment['bookings'][0]['icsFiles']) ? $appointment['bookings'][0]['icsFiles'] : [];
310 } else {
311 $amountData = $this->getAmountData($appointment['bookings'][$bookingKey], $appointment, $invoice);
312
313 $couponDiscount = $amountData['discount'] + $amountData['deduction'];
314
315 $expirationDate = null;
316
317 if (!empty($appointment['bookings'][$bookingKey]['coupon']['expirationDate'])) {
318 $expirationDate = $appointment['bookings'][$bookingKey]['coupon']['expirationDate'];
319 }
320
321 if (!empty($appointment['bookings'][$bookingKey]['coupon']['code'])) {
322 $couponsUsed[] =
323 $appointment['bookings'][$bookingKey]['coupon']['code'] . ' ' . $break .
324 ($amountData['discount'] ? BackendStrings::getPaymentStrings()['discount_amount'] . ': ' .
325 $helperService->getFormattedPrice($amountData['discount']) . ' ' . $break : '') .
326 ($amountData['deduction'] ? BackendStrings::getPaymentStrings()['deduction'] . ': ' .
327 $helperService->getFormattedPrice($amountData['deduction']) . ' ' . $break : '') .
328 ($expirationDate ? BackendStrings::getPaymentStrings()['expiration_date'] . ': ' .
329 $expirationDate : '');
330 }
331
332 $numberOfPersons = empty($appointment['bookings'][$bookingKey]['ticketsData']) ? $appointment['bookings'][$bookingKey]['persons'] : array_sum(array_column($appointment['bookings'][$bookingKey]['ticketsData'], 'persons'));
333
334 $invoiceItem['invoice_qty'] = $amountData['qty'];
335 $invoiceItem['invoice_unit_price'] = $amountData['unit_price'];
336 $invoiceItem['invoice_subtotal'] = $amountData['subtotal'];
337 $invoiceItem['invoice_tax'] = $amountData['tax'];
338 $invoiceItem['invoice_tax_rate'] = $amountData['tax_rate'];
339 $invoiceItem['invoice_tax_excluded'] = $amountData['tax_excluded'];
340 $invoiceItem['invoice_tax_type'] = $amountData['tax_type'];
341 $invoiceItem['invoice_extras_tax'] = !empty($amountData['extras_tax']) ? $amountData['extras_tax'] : null;
342 $invoiceItem['invoice_tickets_tax'] = !empty($amountData['tickets_tax']) ? $amountData['tickets_tax'] : null;
343
344 $icsFiles = !empty($appointment['bookings'][$bookingKey]['icsFiles']) ? $appointment['bookings'][$bookingKey]['icsFiles'] : [];
345
346 $payment = !empty($appointment['bookings'][$bookingKey]['payments'][0]) ? $appointment['bookings'][$bookingKey]['payments'][0] : null;
347
348 $invoiceItem['invoice_paid_amount'] = 0;
349 $invoiceItem['invoice_method'] = '';
350 foreach ($appointment['bookings'][$bookingKey]['payments'] as $p) {
351 if ($p['status'] === PaymentStatus::PARTIALLY_PAID || $p['status'] === PaymentStatus::PAID) {
352 $invoiceItem['invoice_paid_amount'] += $p['amount'];
353 $invoiceItem['invoice_method'] = $p['gateway'];
354 }
355 }
356
357 $invoiceItem['invoice_discount'] = !empty($amountData['full_discount']) && $amountData['full_discount'] > 0 ? $amountData['full_discount'] : 0;
358
359 if (!empty($payment['paymentLinks'])) {
360 foreach ($payment['paymentLinks'] as $paymentType => $paymentLink) {
361 $paymentLinks[$paymentType] = $type === 'email' ? '<a href="' . $paymentLink . '">' . $paymentLink . '</a>' : $paymentLink;
362 }
363 }
364 }
365
366 $depositAmount = null;
367 if (!empty($appointment['deposit']) || $depositEnabled) {
368 $depositAmount = $payment ? $payment['amount'] : 0;
369 }
370 $paymentType = '';
371 if ($payment) {
372 switch ($payment['gateway']) {
373 case 'onSite':
374 $paymentType = BackendStrings::getCommonStrings()['on_site'];
375 break;
376 case 'wc':
377 $paymentType = BackendStrings::getSettingsStrings()['wc_name'];
378 break;
379 case 'square':
380 $paymentType = BackendStrings::getSettingsStrings()['square'];
381 break;
382 default:
383 $paymentType = BackendStrings::getSettingsStrings()[$payment['gateway']];
384 break;
385 }
386 }
387
388 $appointmentPrice = $helperService->getFormattedPrice($amountData['price'] >= 0 ? $amountData['price'] : 0);
389
390 $paymentDueAmount = $payment ?
391 $helperService->getFormattedPrice(
392 ($amountData['price'] >= 0 ? $amountData['price'] : 0) -
393 ($payment['amount'] - (!empty($payment['wcItemTaxValue']) ? $payment['wcItemTaxValue'] : 0))
394 ) : '';
395
396 $bookingKeyForEmployee = null;
397
398 if ($bookingKey === null || $isGroup) {
399 $bookingKeyForEmployee = $isGroup ?
400 $appointment['bookings'][$bookingKey]['id'] : $this->getBookingKeyForEmployee($appointment);
401 }
402
403 /** @var SettingsService $settingsService */
404 $settingsService = $this->container->get('domain.settings.service');
405
406 $dateFormat = $settingsService->getSetting('wordpress', 'dateFormat');
407
408 return array_merge(
409 $paymentLinks,
410 [
411 "appointment_price" => $appointmentPrice,
412 "booking_price" => $appointmentPrice,
413 "{$appointment['type']}_cancel_url" =>
414 $bookingKey !== null && isset($appointment['bookings'][$bookingKey]['id']) ?
415 AMELIA_ACTION_URL . '/bookings/cancel/' . $appointment['bookings'][$bookingKey]['id'] .
416 ($token ? '&token=' . $token : '') . "&type={$appointment['type']}" : '',
417 'appointment_approve_url' =>
418 $bookingKeyForEmployee !== null ? (AMELIA_ACTION_URL . '/bookings/success/' . $bookingKeyForEmployee .
419 '&token=' . $token) : '',
420 'appointment_reject_url' =>
421 $bookingKeyForEmployee !== null ? (AMELIA_ACTION_URL . '/bookings/reject/' . $bookingKeyForEmployee .
422 '&token=' . $token) : '',
423 "{$appointment['type']}_deposit_payment" => $depositAmount !== null ? $helperService->getFormattedPrice($depositAmount) : '',
424 'payment_type' => $paymentType,
425 'payment_status' => $payment ? $payment['status'] : '',
426 'payment_gateway' => $payment ? $payment['gateway'] : '',
427 'payment_created' => $payment ? date_i18n($dateFormat, $payment['created']) : '',
428 'payment_invoice_number' => $payment ? $payment['invoiceNumber'] : '',
429 'payment_gateway_title' => $payment ? $payment['gatewayTitle'] : '',
430 "payment_due_amount" => $paymentDueAmount,
431 'number_of_persons' => $numberOfPersons,
432 'coupon_used' => $couponsUsed ? implode($break, $couponsUsed) : '',
433 'icsFiles' => $icsFiles,
434 'invoice_items_booking' => [$invoiceItem]
435 ]
436 );
437 }
438
439 /** @noinspection MoreThanThreeArgumentsInspection */
440 /**
441 * @param array $appointment
442 * @param string $type
443 * @param null $bookingKey
444 * @param Customer $customerEntity
445 *
446 * @return array
447 *
448 * @throws \Slim\Exception\ContainerException
449 * @throws \InvalidArgumentException
450 * @throws \Slim\Exception\ContainerValueNotFoundException
451 * @throws NotFoundException
452 * @throws QueryExecutionException
453 * @throws ContainerException
454 * @throws \Exception
455 */
456 public function getCustomersData($appointment, $type, $bookingKey = null, $customerEntity = null)
457 {
458 /** @var UserRepository $userRepository */
459 $userRepository = $this->container->get('domain.users.repository');
460
461 /** @var string $paragraphStart */
462 $paragraphStart = $type === 'email' ? '<p>' : '';
463
464 /** @var string $paragraphEnd */
465 $paragraphEnd = $type === 'email' ? '</p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL);
466
467 // If the data is for employee
468 if ($bookingKey === null) {
469 $customers = [];
470 $customerInformationData = [];
471
472 $hasApprovedOrPendingStatus = in_array(
473 BookingStatus::APPROVED,
474 array_column($appointment['bookings'], 'status'),
475 true
476 ) ||
477 in_array(
478 BookingStatus::PENDING,
479 array_column($appointment['bookings'], 'status'),
480 true
481 );
482
483 $bookedCustomerFullName = '';
484 $bookedCustomerEmail = '';
485 $bookedCustomerPhone = '';
486
487 foreach ((array)$appointment['bookings'] as $customerBooking) {
488 /** @var AbstractUser $customer */
489 $customer = $userRepository->getById($customerBooking['customerId']);
490
491 if ((!$hasApprovedOrPendingStatus && $customerBooking['isChangedStatus']) ||
492 ($customerBooking['status'] !== BookingStatus::CANCELED && $customerBooking['status'] !== BookingStatus::REJECTED)
493 ) {
494 if ($customerBooking['info']) {
495 $customerInformationData[] = json_decode($customerBooking['info'], true);
496 } else {
497 $customerInformationData[] = [
498 'firstName' => $customer->getFirstName()->getValue(),
499 'lastName' => $customer->getLastName()->getValue(),
500 'phone' => $customer->getPhone() ? $customer->getPhone()->getValue() : '',
501 ];
502 }
503
504 $customers[] = $customer;
505 }
506
507 if ($customerBooking['isChangedStatus']) {
508 $bookedCustomerFullName = $customer->getFullName();
509 $bookedCustomerEmail = $customer->getEmail() ? $customer->getEmail()->getValue() : '';
510 $bookedCustomerPhone = $customer->getPhone() ? $customer->getPhone()->getValue() : '';
511 }
512 }
513
514 $phones = '';
515 foreach ($customerInformationData as $key => $info) {
516 if ($info['phone']) {
517 $phones .= $info['phone'] . ', ';
518 } else {
519 $phones .= $customers[$key]->getPhone() ? $customers[$key]->getPhone()->getValue() . ', ' : '';
520 }
521 }
522
523 $bookedCustomer = $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_full_name'] . ': ' . $bookedCustomerFullName . $paragraphEnd;
524
525 $bookedCustomer .= $bookedCustomerPhone ? $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_phone'] . ': ' . $bookedCustomerPhone . $paragraphEnd : '';
526 $bookedCustomer .= $bookedCustomerEmail ? $paragraphStart . BackendStrings::getNotificationsStrings()['ph_customer_email'] . ': ' . $bookedCustomerEmail . $paragraphEnd : '';
527
528 return [
529 'booked_customer' => $paragraphStart ?
530 substr($bookedCustomer, 3, strlen($bookedCustomer) - 7) : $bookedCustomer,
531 'customer_email' => implode(
532 ', ',
533 array_map(
534 function ($customer) {
535 /** @var Customer $customer */
536 return $customer->getEmail()->getValue();
537 },
538 $customers
539 )
540 ),
541 'customer_first_name' => implode(
542 ', ',
543 array_map(
544 function ($info) {
545 return $info['firstName'];
546 },
547 $customerInformationData
548 )
549 ),
550 'customer_last_name' => implode(
551 ', ',
552 array_map(
553 function ($info) {
554 return $info['lastName'];
555 },
556 $customerInformationData
557 )
558 ),
559 'customer_full_name' => implode(
560 ', ',
561 array_map(
562 function ($info) {
563 return $info['firstName'] . ' ' . $info['lastName'];
564 },
565 $customerInformationData
566 )
567 ),
568 'customer_phone' => substr($phones, 0, -2),
569 'customer_phone_local' => str_replace('+', '', substr($phones, 0, -2)),
570 'customer_note' => implode(
571 ', ',
572 array_map(
573 function ($customer) {
574 /** @var Customer $customer */
575 return $customer->getNote() ? $customer->getNote()->getValue() : '';
576 },
577 $customers
578 )
579 )
580 ];
581 }
582
583 // If data is for customer
584 /** @var Customer $customer */
585 $customer = $customerEntity ?: $userRepository->getById($appointment['bookings'][$bookingKey]['customerId']);
586
587 $info = !empty($appointment['bookings'][$bookingKey]['info']) ?
588 json_decode($appointment['bookings'][$bookingKey]['info']) : null;
589
590 if ($info && $info->phone) {
591 $phone = $info->phone;
592 } else {
593 $phone = $customer->getPhone() ? $customer->getPhone()->getValue() : '';
594 }
595
596 /** @var HelperService $helperService */
597 $helperService = $this->container->get('application.helper.service');
598
599 return [
600 'customer_email' => $customer->getEmail() ? $customer->getEmail()->getValue() : '',
601 'customer_first_name' => $info ? $info->firstName : $customer->getFirstName()->getValue(),
602 'customer_last_name' => $info ? $info->lastName : $customer->getLastName()->getValue(),
603 'customer_full_name' => $info ? $info->firstName . ' ' . $info->lastName : $customer->getFullName(),
604 'customer_phone' => $phone,
605 'customer_phone_local' => !empty($phone) ? str_replace('+', '', $phone) : '',
606 'customer_note' => $customer->getNote() ? $customer->getNote()->getValue() : '',
607 'customer_panel_url' => $helperService->getCustomerCabinetUrl(
608 $customer->getEmail()->getValue(),
609 $type,
610 !empty($appointment['bookingStart']) ? explode(' ', $appointment['bookingStart'])[0] : null,
611 !empty($appointment['bookingEnd']) ? explode(' ', $appointment['bookingEnd'])[0] : null,
612 $info && property_exists($info, 'locale') ? $info->locale : ''
613 )
614 ];
615 }
616
617 /**
618 * @param array $appointment
619 * @param string $type
620 * @param null $bookingKey
621 *
622 * @return array
623 * @throws \Slim\Exception\ContainerValueNotFoundException
624 * @throws QueryExecutionException
625 * @throws \Exception
626 */
627 public function getCustomFieldsData($appointment, $type, $bookingKey = null)
628 {
629 /** @var SettingsService $settingsService */
630 $settingsService = $this->container->get('domain.settings.service');
631
632 $dateFormat = $settingsService->getSetting('wordpress', 'dateFormat');
633
634 $customFieldsData = [];
635
636 $bookingCustomFieldsKeys = [];
637
638 if ($bookingKey === null) {
639 $sendAllCustomFields = $settingsService->getSetting('notifications', 'sendAllCF') || (array_key_exists('sendCF', $appointment) && $appointment['sendCF']);
640 foreach ($appointment['bookings'] as $booking) {
641 if ((!$booking['isChangedStatus'] || (array_key_exists('isLastBooking', $booking) && !$booking['isLastBooking']))
642 && !(isset($appointment['isRescheduled']) ? $appointment['isRescheduled'] : false) && !$sendAllCustomFields) {
643 continue;
644 }
645
646 if (sizeof($appointment['bookings']) > 1 &&
647 ($booking['status'] === BookingStatus::CANCELED || $booking['status'] === BookingStatus::REJECTED)
648 ) {
649 continue;
650 }
651
652 $bookingCustomFields = !empty($booking['customFields']) ? json_decode($booking['customFields'], true) : null;
653
654 if ($bookingCustomFields) {
655 foreach ($bookingCustomFields as $bookingCustomFieldKey => $bookingCustomField) {
656 if (!empty($bookingCustomField['value']) && !empty($bookingCustomField['type'])) {
657 if ($bookingCustomField['type'] === 'datepicker') {
658 $date = DateTime::createFromFormat('Y-m-d', $bookingCustomField['value']);
659 $bookingCustomField['value'] = date_i18n($dateFormat, $date->getTimestamp());
660 }
661
662 if ($bookingCustomField['type'] === 'file' &&
663 (!empty($appointment['provider']) || !empty($appointment['providers']))
664 ) {
665 /** @var HelperService $helperService */
666 $helperService = $this->container->get('application.helper.service');
667
668 /** @var array $jwtSettings */
669 $jwtSettings = $settingsService->getSetting('roles', 'urlAttachment');
670
671 $provider_email = !empty($appointment['provider']) ?
672 $appointment['provider']['email'] : $appointment['providers'][0]['email'];
673
674 $token = $helperService->getGeneratedJWT(
675 $provider_email,
676 $jwtSettings['headerJwtSecret'],
677 DateTimeService::getNowDateTimeObject()->getTimestamp() + $jwtSettings['tokenValidTime'],
678 LoginType::AMELIA_URL_TOKEN
679 );
680
681 $files = '';
682
683 if ($bookingCustomField['value']) {
684 foreach ($bookingCustomField['value'] as $index => $file) {
685 $files .= '<a href="'
686 . AMELIA_ACTION_URL . '/fields/' . $bookingCustomFieldKey . '/' . $booking['id'] . '/' . $index . '&token=' . $token
687 . '">' . $file['name'] . '</a>';
688 }
689
690 $bookingCustomField['value'] = $files;
691 }
692 }
693
694 if ($bookingCustomField['type'] === 'file' &&
695 (empty($appointment['provider']) && empty($appointment['providers']))
696 ) {
697 continue;
698 }
699
700 if (array_key_exists('custom_field_' . $bookingCustomFieldKey, $customFieldsData)) {
701 $value = $bookingCustomField['type'] === CustomFieldType::ADDRESS ? (
702 $type === 'email' ? '<a href="https://maps.google.com/?q='. $bookingCustomField['value'] .'" target="_blank">'. $bookingCustomField['value'] .'</a>' :
703 'https://maps.google.com/?q=' . str_replace(' ', '+', $bookingCustomField['value'])
704 ) : $bookingCustomField['value'];
705 $customFieldsData['custom_field_' . $bookingCustomFieldKey]
706 .= is_array($value)
707 ? '; ' . implode('; ', $value) :
708 '; ' . $value;
709 } else {
710 $value = $bookingCustomField['type'] === CustomFieldType::ADDRESS ? (
711 $type === 'email' ? '<a href="https://maps.google.com/?q='. $bookingCustomField['value'] .'" target="_blank">' . $bookingCustomField['value'] . '</a>' :
712 'https://maps.google.com/?q=' . str_replace(' ', '+', $bookingCustomField['value'])
713 ) : $bookingCustomField['value'];
714 $customFieldsData['custom_field_' . $bookingCustomFieldKey] =
715 is_array($value)
716 ? implode('; ', $value) : $value;
717 }
718
719 $bookingCustomFieldsKeys[(int)$bookingCustomFieldKey] = true;
720 }
721 }
722 }
723 }
724 } else {
725 if ($appointment['bookings'][$bookingKey]['customFields']) {
726 $bookingCustomFields = !is_array($appointment['bookings'][$bookingKey]['customFields']) ?
727 json_decode($appointment['bookings'][$bookingKey]['customFields'], true) : $appointment['bookings'][$bookingKey]['customFields'];
728 } else {
729 $bookingCustomFields = [];
730 }
731
732 if ($bookingCustomFields) {
733 foreach ((array)$bookingCustomFields as $bookingCustomFieldKey => $bookingCustomField) {
734 $bookingCustomFieldsKeys[(int)$bookingCustomFieldKey] = true;
735
736 if (is_array($bookingCustomField) &&
737 array_key_exists('type', $bookingCustomField) &&
738 $bookingCustomField['type'] === 'file') {
739 continue;
740 }
741
742 if (is_array($bookingCustomField) &&
743 array_key_exists('type', $bookingCustomField) &&
744 $bookingCustomField['type'] === 'datepicker' &&
745 $bookingCustomField['value']
746 ) {
747 $date = DateTime::createFromFormat('Y-m-d', $bookingCustomField['value']);
748 $bookingCustomField['value'] = date_i18n($dateFormat, $date->getTimestamp());
749 }
750
751 if (isset($bookingCustomField['value'])) {
752 $value = $bookingCustomField['type'] === CustomFieldType::ADDRESS ? (
753 $type === 'email' ? '<a href="https://maps.google.com/?q='. $bookingCustomField['value'] .'" target="_blank">'. $bookingCustomField['value'] .'</a>' :
754 'https://maps.google.com/?q=' . str_replace(' ', '+', $bookingCustomField['value'])
755 ) : $bookingCustomField['value'];
756 $customFieldsData['custom_field_' . $bookingCustomFieldKey] = is_array($value)
757 ? implode('; ', $value) : $value;
758 } else {
759 $customFieldsData['custom_field_' . $bookingCustomFieldKey] = '';
760 }
761 }
762 }
763 }
764
765 /** @var CustomFieldRepository $customFieldRepository */
766 $customFieldRepository = $this->container->get('domain.customField.repository');
767
768 /** @var Collection $customFields */
769 $customFields = $customFieldRepository->getAll();
770
771 /** @var CustomField $customField */
772 foreach ($customFields->getItems() as $customField) {
773 if (!array_key_exists($customField->getId()->getValue(), $bookingCustomFieldsKeys)) {
774 $customFieldsData['custom_field_' . $customField->getId()->getValue()] = '';
775 }
776
777 if ($customField->getType()->getValue() === 'content') {
778 switch ($appointment['type']) {
779 case (Entities::APPOINTMENT):
780 /** @var Service $service */
781 foreach ($customField->getServices()->getItems() as $service) {
782 if ($service->getId()->getValue() === $appointment['serviceId']) {
783 $customFieldsData['custom_field_' . $customField->getId()->getValue()] =
784 $customField->getLabel()->getValue();
785 break;
786 }
787 }
788
789 break;
790
791 case (Entities::EVENT):
792 /** @var Event $event */
793 foreach ($customField->getEvents()->getItems() as $event) {
794 if ($event->getId()->getValue() === $appointment['id']) {
795 $customFieldsData['custom_field_' . $customField->getId()->getValue()] =
796 $customField->getLabel()->getValue();
797 break;
798 }
799 }
800
801 break;
802 }
803 }
804 }
805
806 return $customFieldsData;
807 }
808
809 /**
810 * @param array $appointment
811 * @param string $type
812 * @param null $bookingKey
813 *
814 * @return array
815 * @throws ContainerException
816 * @throws QueryExecutionException
817 * @throws InvalidArgumentException
818 */
819 public function getCouponsData($appointment, $type, $bookingKey = null)
820 {
821 $couponsData = [];
822
823 /** @var string $break */
824 $break = $type === 'email' ? '<p><br></p>' : ($type === 'whatsapp' ? '; ' : PHP_EOL);
825
826 if ($bookingKey !== null) {
827 /** @var HelperService $helperService */
828 $helperService = $this->container->get('application.helper.service');
829
830 /** @var CouponRepository $couponRepository */
831 $couponRepository = $this->container->get('domain.coupon.repository');
832
833 /** @var CouponApplicationService $couponAS */
834 $couponAS = $this->container->get('application.coupon.service');
835
836 /** @var Collection $customerReservations */
837 $customerReservations = new Collection();
838
839 $type = $appointment['type'];
840 $customerId = $type !== Entities::PACKAGE ? $appointment['bookings'][$bookingKey]['customerId'] : $appointment['customer']['id'];
841 $couponsCriteria = [];
842
843 if (!$customerId) {
844 return $couponsData;
845 }
846
847 switch ($type) {
848 case Entities::APPOINTMENT:
849 /** @var AppointmentRepository $appointmentRepository */
850 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
851
852 $couponsCriteria['entityIds'] = [$appointment['serviceId']];
853
854 $couponsCriteria['entityType'] = Entities::SERVICE;
855
856 $customerReservations = $appointmentRepository->getPeriodAppointments(
857 [
858 'customerId' => $customerId,
859 'skipServices' => true,
860 'skipProviders' => true,
861 'skipCustomers' => true,
862 'skipPayments' => true,
863 'skipExtras' => true,
864 'skipCoupons' => true,
865 'status' => BookingStatus::APPROVED,
866 'bookingStatus' => BookingStatus::APPROVED,
867 'services' => [
868 $appointment['serviceId']
869 ]
870 ]
871 );
872
873 break;
874
875 case Entities::EVENT:
876 /** @var EventRepository $eventRepository */
877 $eventRepository = $this->container->get('domain.booking.event.repository');
878
879 $couponsCriteria['entityType'] = Entities::EVENT;
880
881 $couponsCriteria['entityIds'] = [$appointment['id']];
882
883 $eventsIds = $eventRepository->getFilteredIds(
884 [
885 'customerId' => $customerId,
886 'customerBookingStatus' => BookingStatus::APPROVED,
887 ],
888 0
889 );
890
891 /** @var Collection $customerReservations */
892 $customerReservations = new Collection();
893
894 foreach ($eventsIds as $eventId) {
895 $customerReservations->addItem(EventFactory::create(['id' => $eventId]), $eventId);
896 }
897
898 break;
899
900 case Entities::PACKAGE:
901 /** @var PackageCustomerRepository $packageCustomerRepository */
902 $packageCustomerRepository = $this->container->get('domain.bookable.packageCustomer.repository');
903
904 $couponsCriteria['entityIds'] = [$appointment['id']];
905
906 $couponsCriteria['entityType'] = Entities::PACKAGE;
907
908 $customerReservations = $packageCustomerRepository->getByEntityId($customerId, 'customerId');
909
910 break;
911 }
912
913 /** @var Collection $entityCoupons */
914 $entityCoupons = $couponRepository->getAllByCriteria($couponsCriteria);
915
916 /** @var Collection $allCoupons */
917 $allCoupons = $couponRepository->getAllIndexedById();
918
919 foreach (array_diff($allCoupons->keys(), $entityCoupons->keys()) as $couponId) {
920 $couponsData["coupon_{$couponId}"] = '';
921 }
922
923 /** @var Coupon $coupon */
924 foreach ($entityCoupons->getItems() as $coupon) {
925 /** @var Collection $reservationsForCheck */
926 $reservationsForCheck = new Collection();
927
928 switch ($type) {
929 case Entities::PACKAGE:
930 case Entities::APPOINTMENT:
931 $reservationsForCheck = $customerReservations;
932
933 break;
934
935 case Entities::EVENT:
936 /** @var Event $reservation */
937 foreach ($customerReservations->getItems() as $reservation) {
938 if ($coupon->getEventList()->keyExists($reservation->getId()->getValue())) {
939 $reservationsForCheck->addItem($reservation, $reservation->getId()->getValue());
940 }
941 }
942
943 break;
944 }
945
946 $sendCoupon = (
947 !$coupon->getNotificationRecurring()->getValue() &&
948 $reservationsForCheck->length() === $coupon->getNotificationInterval()->getValue()
949 ) || (
950 $coupon->getNotificationRecurring()->getValue() &&
951 $reservationsForCheck->length() % $coupon->getNotificationInterval()->getValue() === 0
952 );
953
954 try {
955 if ($sendCoupon && $couponAS->inspectCoupon($coupon, $customerId, true)) {
956 $couponsData["coupon_{$coupon->getId()->getValue()}"] =
957 FrontendStrings::getCommonStrings()['coupon_send_text'] . ' ' .
958 $coupon->getCode()->getValue() . ' ' . $break .
959 ($coupon->getDeduction() && $coupon->getDeduction()->getValue() ?
960 BackendStrings::getFinanceStrings()['deduction'] . ' ' .
961 $helperService->getFormattedPrice($coupon->getDeduction()->getValue()) . $break
962 : ''
963 ) .
964 ($coupon->getDiscount() && $coupon->getDiscount()->getValue() ?
965 BackendStrings::getPaymentStrings()['discount_amount'] . ' ' .
966 $coupon->getDiscount()->getValue() . '% '. $break
967 : '') .
968 ($coupon->getExpirationDate() && $coupon->getExpirationDate()->getValue() ?
969 BackendStrings::getPaymentStrings()['expiration_date'] . ': ' .
970 date_i18n($coupon->getExpirationDate()->getValue()->format('Y-m-d')) : '');
971 } else {
972 $couponsData["coupon_{$coupon->getId()->getValue()}"] = '';
973 }
974 } catch (CouponUnknownException $e) {
975 $couponsData["coupon_{$coupon->getId()->getValue()}"] = '';
976 } catch (CouponInvalidException $e) {
977 $couponsData["coupon_{$coupon->getId()->getValue()}"] = '';
978 } catch (CouponExpiredException $e) {
979 $couponsData["coupon_{$coupon->getId()->getValue()}"] = '';
980 }
981 }
982 }
983
984 return $couponsData;
985 }
986
987 /**
988 * @param array $entity
989 *
990 * @param string $subject
991 * @param string $body
992 * @param int $userId
993 * @return array
994 */
995 public function reParseContentForProvider($entity, $subject, $body, $userId)
996 {
997 $employeeSubject = $subject;
998
999 $employeeBody = $body;
1000
1001 return [
1002 'body' => $employeeBody,
1003 'subject' => $employeeSubject,
1004 ];
1005 }
1006
1007 /**
1008 * @param array $appointment
1009 * @param int|null $bookingKey
1010 *
1011 * @return string
1012 */
1013 protected function getLocale($appointment, $bookingKey)
1014 {
1015 /** @var HelperService $helperService */
1016 $helperService = $this->container->get('application.helper.service');
1017
1018 if (!empty($appointment['bookings'][$bookingKey]['info'])) {
1019 return $helperService->getLocaleFromBooking(
1020 $appointment['bookings'][$bookingKey]['info']
1021 );
1022 } elseif (!empty($appointment['bookings'][$bookingKey]['customer']['translations'])) {
1023 return $helperService->getLocaleFromTranslations(
1024 $appointment['bookings'][$bookingKey]['customer']['translations']
1025 );
1026 }
1027
1028 return null;
1029 }
1030
1031 /**
1032 * @param array $reservation
1033 * @param int|null $bookingKey
1034 *
1035 * @return void
1036 *
1037 * @throws ContainerValueNotFoundException
1038 * @throws NotFoundException
1039 * @throws QueryExecutionException
1040 * @throws ContainerException
1041 * @throws Exception
1042 */
1043 protected function setData(&$reservation, $bookingKey = null)
1044 {
1045 $info = !empty($reservation['bookings'][$bookingKey]['info']) ?
1046 json_decode($reservation['bookings'][$bookingKey]['info'], true) : null;
1047
1048 if ($bookingKey !== null &&
1049 (
1050 !empty($reservation['bookings'][$bookingKey]['customerId']) ||
1051 !empty($reservation['bookings'][$bookingKey]['customer']['id'])
1052 ) &&
1053 (
1054 ($info && empty($info['locale'])) ||
1055 (
1056 !$info &&
1057 !empty($reservation['bookings'][$bookingKey]['customer']) &&
1058 empty($reservation['bookings'][$bookingKey]['customer']['translations'])
1059 )
1060 )
1061 ) {
1062 /** @var UserRepository $userRepository */
1063 $userRepository = $this->container->get('domain.users.repository');
1064
1065 /** @var AbstractUser $customer */
1066 $customer = $userRepository->getById(
1067 !empty($reservation['bookings'][$bookingKey]['customerId']) ?
1068 $reservation['bookings'][$bookingKey]['customerId'] :
1069 $reservation['bookings'][$bookingKey]['customer']['id']
1070 );
1071
1072 if ($customer->getTranslations()) {
1073 if ($info) {
1074 $translations = json_decode($customer->getTranslations()->getValue(), true);
1075
1076 if ($translations && !empty($translations['defaultLanguage'])) {
1077 $info['locale'] = $translations['defaultLanguage'];
1078
1079 $reservation['bookings'][$bookingKey]['info'] = json_encode($info);
1080 }
1081 } else {
1082 $reservation['bookings'][$bookingKey]['customer']['translations'] =
1083 $customer->getTranslations()->getValue();
1084 }
1085 }
1086 }
1087 }
1088
1089 /**
1090 * @param array $appointment
1091 *
1092 * @return int
1093 */
1094 protected function getBookingKeyForEmployee($appointment)
1095 {
1096 foreach ($appointment['bookings'] as $booking) {
1097 if ($booking['isLastBooking'] || $booking['isChangedStatus']) {
1098 return $booking['id'];
1099 }
1100 }
1101
1102 if (!empty($appointment['isRescheduled']) && $appointment['isRescheduled']) {
1103 return $appointment['bookings'][0]['id'];
1104 }
1105
1106 return null;
1107 }
1108 }
1109