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