PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.20
Booking for Appointments and Events Calendar – Amelia v1.2.20
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 / Notification / SMSNotificationService.php
ameliabooking / src / Application / Services / Notification Last commit date
AbstractNotificationService.php 1 year ago AbstractWhatsAppNotificationService.php 2 years ago ApplicationNotificationService.php 1 year ago AppointmentNotificationService.php 1 year ago BasicWhatsAppNotificationService.php 2 years ago EmailNotificationService.php 1 year ago NotificationHelperService.php 4 years ago SMSAPIService.php 2 years ago SMSNotificationService.php 1 year ago
SMSNotificationService.php
497 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\Notification;
8
9 use AmeliaBooking\Application\Services\Helper\HelperService;
10 use AmeliaBooking\Application\Services\Placeholder\PlaceholderService;
11 use AmeliaBooking\Domain\Collection\Collection;
12 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
13 use AmeliaBooking\Domain\Entity\Entities;
14 use AmeliaBooking\Domain\Entity\Notification\Notification;
15 use AmeliaBooking\Domain\Entity\Notification\NotificationLog;
16 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
17 use AmeliaBooking\Domain\Services\Settings\SettingsService;
18 use AmeliaBooking\Domain\ValueObjects\String\NotificationStatus;
19 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
20 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
21 use AmeliaBooking\Infrastructure\Repository\Notification\NotificationLogRepository;
22 use AmeliaBooking\Infrastructure\Repository\Notification\NotificationSMSHistoryRepository;
23 use Exception;
24 use Interop\Container\Exception\ContainerException;
25 use Slim\Exception\ContainerValueNotFoundException;
26
27 /**
28 * Class SMSNotificationService
29 *
30 * @package AmeliaBooking\Application\Services\Notification
31 */
32 class SMSNotificationService extends AbstractNotificationService
33 {
34
35 /** @var bool */
36 private $sentSmsLowEmail = false;
37
38 /** @noinspection MoreThanThreeArgumentsInspection */
39 /**
40 * @param array $appointmentArray
41 * @param Notification $notification
42 * @param bool $logNotification
43 * @param int|null $bookingKey
44 *
45 * @throws NotFoundException
46 * @throws QueryExecutionException
47 * @throws ContainerException
48 * @throws Exception
49 */
50 public function sendNotification(
51 $appointmentArray,
52 $notification,
53 $logNotification,
54 $bookingKey = null,
55 $allBookings = null
56 ) {
57 /** @var \AmeliaBooking\Application\Services\Settings\SettingsService $settingsAS */
58 $settingsAS = $this->container->get('application.settings.service');
59 /** @var PlaceholderService $placeholderService */
60 $placeholderService = $this->container->get("application.placeholder.{$appointmentArray['type']}.service");
61 /** @var HelperService $helperService */
62 $helperService = $this->container->get('application.helper.service');
63
64 $data = $placeholderService->getPlaceholdersData(
65 $appointmentArray,
66 $bookingKey,
67 'sms',
68 null,
69 $allBookings,
70 false,
71 $notification->getName()->getValue()
72 );
73
74 $isCustomerPackage = isset($appointmentArray['isForCustomer']) && $appointmentArray['isForCustomer'];
75
76 if ($appointmentArray['type'] === Entities::PACKAGE) {
77 if (!empty($appointmentArray['recurring'][0]['booking']['info']) && $isCustomerPackage) {
78 $info = $appointmentArray['recurring'][0]['booking']['info'];
79
80 $infoArray = json_decode($info, true);
81
82 if (!empty($infoArray['phone'])) {
83 $appointmentArray['customer']['phone'] = $infoArray['phone'];
84 }
85 } else {
86 $info = $isCustomerPackage ? json_encode($appointmentArray['customer']) : null;
87 }
88 } else {
89 $info = $bookingKey !== null ? $appointmentArray['bookings'][$bookingKey]['info'] : null;
90 }
91
92 $notificationContent = $helperService->getBookingTranslation(
93 $helperService->getLocaleFromBooking($info),
94 $notification->getTranslations() ? $notification->getTranslations()->getValue() : null,
95 'content'
96 ) ?: $notification->getContent()->getValue();
97
98 $text = $placeholderService->applyPlaceholders($notificationContent, $data);
99
100 $users = $this->getUsersInfo(
101 $notification->getSendTo()->getValue(),
102 $appointmentArray,
103 $bookingKey,
104 $data
105 );
106
107 foreach ($users as $user) {
108 if ($user['phone']) {
109 if (!$isCustomerPackage && !empty($data['providersAppointments'][$user['id']])) {
110 $text = $placeholderService->applyPlaceholders(
111 $notificationContent,
112 array_merge(
113 $data,
114 ['cart_appointments_details' => $data['providersAppointments'][$user['id']]]
115 )
116 );
117 }
118
119 $reParsedData = !$isCustomerPackage ?
120 $placeholderService->reParseContentForProvider(
121 $appointmentArray,
122 '',
123 $text,
124 $user['id']
125 ) : [
126 'body' => $text,
127 ];
128
129 try {
130 $this->saveAndSend(
131 $notification,
132 $user,
133 $appointmentArray,
134 $reParsedData,
135 $logNotification,
136 $user['phone']
137 );
138
139 $additionalPhoneNumbers = $settingsAS->getBccSms();
140
141 foreach ($additionalPhoneNumbers as $phoneNumber) {
142 $this->saveAndSend(
143 $notification,
144 null,
145 $appointmentArray,
146 $reParsedData,
147 $logNotification,
148 $phoneNumber
149 );
150 }
151 } catch (QueryExecutionException $e) {
152 } catch (ContainerException $e) {
153 }
154 }
155 }
156 }
157
158
159 private function sendSmsBalanceLowEmail()
160 {
161 /** @var SettingsService $settingsService */
162 $settingsService = $this->container->get('domain.settings.service');
163 /** @var SMSAPIService $smsApiService */
164 $smsApiService = $this->container->get('application.smsApi.service');
165
166 $smsLowEmail = $settingsService->getSetting('notifications', 'smsBalanceEmail');
167 if ($smsLowEmail && $smsLowEmail['enabled']) {
168 try {
169 $userResponse = $smsApiService->getUserInfo();
170 if (!empty($userResponse) && $userResponse->status === 'OK' && !empty($userResponse->user) && $userResponse->user->balance <= $smsLowEmail['minimum']) {
171 /** @var EmailNotificationService $notificationService */
172 $notificationService = $this->container->get('application.emailNotification.service');
173 $notificationService->sendSmsBalanceLowEmail($smsLowEmail['email']);
174
175 $this->sentSmsLowEmail = true;
176 }
177 } catch (\Exception $e) {
178 }
179 }
180 }
181
182 /**
183 * @throws ContainerValueNotFoundException
184 * @throws QueryExecutionException
185 * @throws InvalidArgumentException
186 */
187 public function sendUndeliveredNotifications()
188 {
189 /** @var NotificationLogRepository $notificationLogRepository */
190 $notificationLogRepository = $this->container->get('domain.notificationLog.repository');
191
192 /** @var NotificationSMSHistoryRepository $notificationsSMSHistoryRepo */
193 $notificationsSMSHistoryRepo = $this->container->get('domain.notificationSMSHistory.repository');
194
195 /** @var Collection $undeliveredNotifications */
196 $undeliveredNotifications = $notificationLogRepository->getUndeliveredNotifications('sms');
197
198 /** @var SMSAPIService $smsApiService */
199 $smsApiService = $this->container->get('application.smsApi.service');
200
201 /** @var NotificationLog $undeliveredNotification */
202 foreach ($undeliveredNotifications->getItems() as $undeliveredNotification) {
203 try {
204 $data = json_decode($undeliveredNotification->getData()->getValue(), true);
205
206 if ($history = $notificationsSMSHistoryRepo->getById($data['historyId'])) {
207 $apiResponse = $smsApiService->send(
208 $history['phone'],
209 $data['body'],
210 AMELIA_ACTION_URL . '/notifications/sms/history/' . $data['historyId']
211 );
212
213 if ($apiResponse->status === 'OK') {
214 $this->updateSmsHistory($data['historyId'], $apiResponse);
215
216 $notificationLogRepository->updateFieldById(
217 $undeliveredNotification->getId()->getValue(),
218 1,
219 'sent'
220 );
221 }
222 }
223 } catch (Exception $e) {
224 }
225 }
226 }
227
228 /**
229 * @throws QueryExecutionException
230 * @throws InvalidArgumentException
231 * @throws Exception
232 */
233 public function sendBirthdayGreetingNotifications()
234 {
235 /** @var Collection $notifications */
236 $notifications = $this->getByNameAndType('customer_birthday_greeting', $this->type);
237
238 /** @var Notification $notification */
239 $notification = $notifications->getItem($notifications->keys()[0]);
240
241 // Check if notification is enabled and it is time to send notification
242 if ($notification->getStatus()->getValue() === NotificationStatus::ENABLED &&
243 $notification->getTime() &&
244 DateTimeService::getNowDateTimeObject() >=
245 DateTimeService::getCustomDateTimeObject($notification->getTime()->getValue())
246 ) {
247 /** @var NotificationLogRepository $notificationLogRepo */
248 $notificationLogRepo = $this->container->get('domain.notificationLog.repository');
249 /** @var NotificationSMSHistoryRepository $notificationsSMSHistoryRepo */
250 $notificationsSMSHistoryRepo = $this->container->get('domain.notificationSMSHistory.repository');
251 /** @var SMSAPIService $smsApiService */
252 $smsApiService = $this->container->get('application.smsApi.service');
253 /** @var PlaceholderService $placeholderService */
254 $placeholderService = $this->container->get('application.placeholder.appointment.service');
255 /** @var SettingsService $settingsService */
256 $settingsService = $this->container->get('domain.settings.service');
257
258 $customers = $notificationLogRepo->getBirthdayCustomers($this->type);
259
260 $companyData = $placeholderService->getCompanyData();
261
262 $customersArray = $customers->toArray();
263
264 foreach ($customersArray as $bookingKey => $customerArray) {
265 $data = [
266 'customer_email' => $customerArray['email'],
267 'customer_first_name' => $customerArray['firstName'],
268 'customer_last_name' => $customerArray['lastName'],
269 'customer_full_name' => $customerArray['firstName'] . ' ' . $customerArray['lastName'],
270 'customer_phone' => $customerArray['phone'],
271 'customer_id' => $customerArray['id'],
272 ];
273
274 /** @noinspection AdditionOperationOnArraysInspection */
275 $data += $companyData;
276
277 $text = $placeholderService->applyPlaceholders(
278 $notification->getContent()->getValue(),
279 $data
280 );
281
282 if ($data['customer_phone']) {
283 try {
284 $historyId = $notificationsSMSHistoryRepo->add(
285 [
286 'notificationId' => $notification->getId()->getValue(),
287 'userId' => $data['customer_id'],
288 'text' => $text,
289 'phone' => $data['customer_phone'],
290 'alphaSenderId' => $settingsService->getSetting('notifications', 'smsAlphaSenderId'),
291 ]
292 );
293
294 $smsData = apply_filters(
295 'amelia_manipulate_sms_data',
296 [
297 'text' => $text,
298 'to' => $data['customer_phone']
299 ]
300 );
301
302 $apiResponse = null;
303
304 if (empty($smsData['skipSending'])) {
305 $apiResponse = $smsApiService->send(
306 $smsData['customer_phone'],
307 $smsData['text'],
308 AMELIA_ACTION_URL . '/notifications/sms/history/' . $historyId
309 );
310 }
311
312 if ($apiResponse && $apiResponse->status === 'OK') {
313 $this->updateSmsHistory($historyId, $apiResponse);
314
315 $logNotificationId = $notificationLogRepo->add(
316 $notification,
317 $data['customer_id']
318 );
319
320 if ($logNotificationId) {
321 $notificationLogRepo->updateFieldById($logNotificationId, 1, 'sent');
322 }
323 }
324 } catch (QueryExecutionException $e) {
325 }
326 }
327 }
328 }
329 }
330
331 /** @noinspection MoreThanThreeArgumentsInspection */
332 /**
333 * @param Notification $notification
334 * @param array $user
335 * @param array $appointmentArray
336 * @param array $reParsedData
337 * @param bool $logNotification
338 * @param string $sendTo
339 *
340 * @return void
341 *
342 * @throws QueryExecutionException
343 * @throws InvalidArgumentException
344 */
345 private function saveAndSend($notification, $user, $appointmentArray, $reParsedData, $logNotification, $sendTo)
346 {
347
348 /** @var NotificationLogRepository $notificationsLogRepository */
349 $notificationsLogRepository = $this->container->get('domain.notificationLog.repository');
350 /** @var NotificationSMSHistoryRepository $notificationsSMSHistoryRepo */
351 $notificationsSMSHistoryRepo = $this->container->get('domain.notificationSMSHistory.repository');
352 /** @var SettingsService $settingsService */
353 $settingsService = $this->container->get('domain.settings.service');
354 /** @var SMSAPIService $smsApiService */
355 $smsApiService = $this->container->get('application.smsApi.service');
356
357 if ($user && !empty($appointmentArray['isRetry'])) {
358 /** @var Collection $sentNotifications */
359 $sentNotifications = $notificationsLogRepository->getSentNotificationsByUserAndEntity(
360 $user['id'],
361 'sms',
362 $appointmentArray['type'],
363 $appointmentArray['type'] === Entities::PACKAGE ?
364 $appointmentArray['packageCustomerId'] : $appointmentArray['id']
365 );
366
367 if ($sentNotifications->length()) {
368 return;
369 }
370 }
371
372 $historyId = $notificationsSMSHistoryRepo->add(
373 [
374 'notificationId' => $notification->getId()->getValue(),
375 'userId' => $user ? $user['id'] : null,
376 'appointmentId' =>
377 $appointmentArray['type'] === Entities::APPOINTMENT ? $appointmentArray['id'] : null,
378 'eventId' =>
379 $appointmentArray['type'] === Entities::EVENT ? $appointmentArray['id'] : null,
380 'packageCustomerId' => $appointmentArray['type'] === Entities::PACKAGE ?
381 $appointmentArray['packageCustomerId'] : null,
382 'text' => $reParsedData['body'],
383 'phone' => $user ? $user['phone'] : $sendTo,
384 'alphaSenderId' => $settingsService->getSetting('notifications', 'smsAlphaSenderId')
385 ]
386 );
387
388 $logNotificationId = null;
389
390 if ($logNotification) {
391 $logNotificationId = $notificationsLogRepository->add(
392 $notification,
393 $user ? $user['id'] : null,
394 $appointmentArray['type'] === Entities::APPOINTMENT ? $appointmentArray['id'] : null,
395 $appointmentArray['type'] === Entities::EVENT ? $appointmentArray['id'] : null,
396 $appointmentArray['type'] === Entities::PACKAGE ? $appointmentArray['packageCustomerId'] : null,
397 json_encode(
398 [
399 'subject' => '',
400 'body' => $reParsedData['body'],
401 'icsFiles' => [],
402 'historyId' => $historyId,
403 ]
404 )
405 );
406 }
407
408
409
410 $data = [
411 'sendTo' => $sendTo,
412 'body' => $reParsedData['body'],
413 'historyId' => $historyId,
414 'logNotificationId' => $logNotificationId,
415 ];
416
417 if ($this->getSend()) {
418 $this->sendSms($data);
419 } else {
420 $this->addPreparedNotificationData($data);
421
422 if ($data['logNotificationId']) {
423 $notificationsLogRepository->updateFieldById((int)$data['logNotificationId'], 1, 'sent');
424 }
425 }
426 }
427
428 /**
429 * @param int $historyId
430 * @param mixed $apiResponse
431 * @throws QueryExecutionException
432 */
433 public function updateSmsHistory($historyId, $apiResponse)
434 {
435 /** @var NotificationSMSHistoryRepository $notificationsSMSHistoryRepo */
436 $notificationsSMSHistoryRepo = $this->container->get('domain.notificationSMSHistory.repository');
437
438 $notificationsSMSHistoryRepo->update(
439 $historyId,
440 [
441 'logId' => $apiResponse->message->logId,
442 'status' => $apiResponse->message->status,
443 'price' => $apiResponse->message->price,
444 'dateTime' => DateTimeService::getNowDateTimeInUtc(),
445 'segments' => $apiResponse->message->segments
446 ]
447 );
448 }
449
450 /**
451 * @param $data array
452 *
453 * @return void
454 * @throws QueryExecutionException
455 */
456 protected function sendSms($data)
457 {
458 /** @var NotificationLogRepository $notificationsLogRepository */
459 $notificationsLogRepository = $this->container->get('domain.notificationLog.repository');
460 /** @var SMSAPIService $smsApiService */
461 $smsApiService = $this->container->get('application.smsApi.service');
462
463 $apiResponse = $smsApiService->send(
464 $data['sendTo'],
465 $data['body'],
466 AMELIA_ACTION_URL . '/notifications/sms/history/' . $data['historyId']
467 );
468
469 if ($apiResponse->status === 'OK') {
470 $this->updateSmsHistory($data['historyId'], $apiResponse);
471
472 if ($data['logNotificationId']) {
473 $notificationsLogRepository->updateFieldById((int)$data['logNotificationId'], 1, 'sent');
474 }
475
476 if (!$this->sentSmsLowEmail) {
477 $this->sendSmsBalanceLowEmail();
478 }
479 } else {
480 if ($data['logNotificationId']) {
481 $notificationsLogRepository->updateFieldById((int)$data['logNotificationId'], 0, 'sent');
482 }
483 }
484 }
485
486 /**
487 * @return void
488 * @throws QueryExecutionException
489 */
490 public function sendPreparedNotifications()
491 {
492 foreach ($this->getPreparedNotificationData() as $item) {
493 $this->sendSms($item);
494 }
495 }
496 }
497