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