Merge pull request #17129 from eileenmcnaughton/email2
[civicrm-core.git] / CRM / Core / BAO / ActionSchedule.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 * $Id$
17 *
18 */
19
20 /**
21 * This class contains functions for managing Scheduled Reminders
22 */
23 class CRM_Core_BAO_ActionSchedule extends CRM_Core_DAO_ActionSchedule {
24
25 /**
26 * @param array $filters
27 * Filter by property (e.g. 'id').
28 *
29 * @return array
30 * Array(scalar $id => Mapping $mapping).
31 * @throws \CRM_Core_Exception
32 */
33 public static function getMappings($filters = NULL) {
34 static $_action_mapping;
35
36 if ($_action_mapping === NULL) {
37 $event = \Civi::dispatcher()
38 ->dispatch(\Civi\ActionSchedule\Events::MAPPINGS,
39 new \Civi\ActionSchedule\Event\MappingRegisterEvent());
40 $_action_mapping = $event->getMappings();
41 }
42
43 if (empty($filters)) {
44 return $_action_mapping;
45 }
46 elseif (isset($filters['id'])) {
47 return [
48 $filters['id'] => $_action_mapping[$filters['id']],
49 ];
50 }
51 else {
52 throw new CRM_Core_Exception("getMappings() called with unsupported filter: " . implode(', ', array_keys($filters)));
53 }
54 }
55
56 /**
57 * @param string|int $id
58 * @return \Civi\ActionSchedule\Mapping|NULL
59 */
60 public static function getMapping($id) {
61 $mappings = self::getMappings();
62 return $mappings[$id] ?? NULL;
63 }
64
65 /**
66 * For each entity, get a list of entity-value labels.
67 *
68 * @return array
69 * Ex: $entityValueLabels[$mappingId][$valueId] = $valueLabel.
70 * @throws CRM_Core_Exception
71 */
72 public static function getAllEntityValueLabels() {
73 $entityValueLabels = [];
74 foreach (CRM_Core_BAO_ActionSchedule::getMappings() as $mapping) {
75 /** @var \Civi\ActionSchedule\Mapping $mapping */
76 $entityValueLabels[$mapping->getId()] = $mapping->getValueLabels();
77 $valueLabel = ['- ' . strtolower($mapping->getValueHeader()) . ' -'];
78 $entityValueLabels[$mapping->getId()] = $valueLabel + $entityValueLabels[$mapping->getId()];
79 }
80 return $entityValueLabels;
81 }
82
83 /**
84 * For each entity, get a list of entity-status labels.
85 *
86 * @return array
87 * Ex: $entityValueLabels[$mappingId][$valueId][$statusId] = $statusLabel.
88 */
89 public static function getAllEntityStatusLabels() {
90 $entityValueLabels = self::getAllEntityValueLabels();
91 $entityStatusLabels = [];
92 foreach (CRM_Core_BAO_ActionSchedule::getMappings() as $mapping) {
93 /** @var \Civi\ActionSchedule\Mapping $mapping */
94 $statusLabel = ['- ' . strtolower($mapping->getStatusHeader()) . ' -'];
95 $entityStatusLabels[$mapping->getId()] = $entityValueLabels[$mapping->getId()];
96 foreach ($entityStatusLabels[$mapping->getId()] as $kkey => & $vval) {
97 $vval = $statusLabel + $mapping->getStatusLabels($kkey);
98 }
99 }
100 return $entityStatusLabels;
101 }
102
103 /**
104 * Retrieve list of Scheduled Reminders.
105 *
106 * @param bool $namesOnly
107 * Return simple list of names.
108 *
109 * @param \Civi\ActionSchedule\Mapping|null $filterMapping
110 * Filter by the schedule's mapping type.
111 * @param int $filterValue
112 * Filter by the schedule's entity_value.
113 *
114 * @return array
115 * (reference) reminder list
116 * @throws \CRM_Core_Exception
117 */
118 public static function &getList($namesOnly = FALSE, $filterMapping = NULL, $filterValue = NULL) {
119 $query = "
120 SELECT
121 title,
122 cas.id as id,
123 cas.mapping_id,
124 cas.entity_value as entityValueIds,
125 cas.entity_status as entityStatusIds,
126 cas.start_action_date as entityDate,
127 cas.start_action_offset,
128 cas.start_action_unit,
129 cas.start_action_condition,
130 cas.absolute_date,
131 is_repeat,
132 is_active
133
134 FROM civicrm_action_schedule cas
135 ";
136 $queryParams = [];
137 $where = " WHERE 1 ";
138 if ($filterMapping and $filterValue) {
139 $where .= " AND cas.entity_value = %1 AND cas.mapping_id = %2";
140 $queryParams[1] = [$filterValue, 'Integer'];
141 $queryParams[2] = [$filterMapping->getId(), 'String'];
142 }
143 $where .= " AND cas.used_for IS NULL";
144 $query .= $where;
145 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
146 while ($dao->fetch()) {
147 /** @var Civi\ActionSchedule\Mapping $filterMapping */
148 $filterMapping = CRM_Utils_Array::first(self::getMappings([
149 'id' => $dao->mapping_id,
150 ]));
151 $list[$dao->id]['id'] = $dao->id;
152 $list[$dao->id]['title'] = $dao->title;
153 $list[$dao->id]['start_action_offset'] = $dao->start_action_offset;
154 $list[$dao->id]['start_action_unit'] = $dao->start_action_unit;
155 $list[$dao->id]['start_action_condition'] = $dao->start_action_condition;
156 $list[$dao->id]['entityDate'] = ucwords(str_replace('_', ' ', $dao->entityDate));
157 $list[$dao->id]['absolute_date'] = $dao->absolute_date;
158 $list[$dao->id]['entity'] = $filterMapping->getLabel();
159 $list[$dao->id]['value'] = implode(', ', CRM_Utils_Array::subset(
160 $filterMapping->getValueLabels(),
161 explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityValueIds)
162 ));
163 $list[$dao->id]['status'] = implode(', ', CRM_Utils_Array::subset(
164 $filterMapping->getStatusLabels($dao->entityValueIds),
165 explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityStatusIds)
166 ));
167 $list[$dao->id]['is_repeat'] = $dao->is_repeat;
168 $list[$dao->id]['is_active'] = $dao->is_active;
169 }
170
171 return $list;
172 }
173
174 /**
175 * Add the schedules reminders in the db.
176 *
177 * @param array $params
178 * (reference ) an assoc array of name/value pairs.
179 * @param array $ids
180 * Unused variable.
181 *
182 * @return CRM_Core_DAO_ActionSchedule
183 */
184 public static function add(&$params, $ids = []) {
185 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
186 $actionSchedule->copyValues($params);
187
188 return $actionSchedule->save();
189 }
190
191 /**
192 * Retrieve DB object based on input parameters.
193 *
194 * It also stores all the retrieved values in the default array.
195 *
196 * @param array $params
197 * (reference ) an assoc array of name/value pairs.
198 * @param array $values
199 * (reference ) an assoc array to hold the flattened values.
200 *
201 * @return CRM_Core_DAO_ActionSchedule|null
202 * object on success, null otherwise
203 */
204 public static function retrieve(&$params, &$values) {
205 if (empty($params)) {
206 return NULL;
207 }
208 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
209
210 $actionSchedule->copyValues($params);
211
212 if ($actionSchedule->find(TRUE)) {
213 $ids['actionSchedule'] = $actionSchedule->id;
214
215 CRM_Core_DAO::storeValues($actionSchedule, $values);
216
217 return $actionSchedule;
218 }
219 return NULL;
220 }
221
222 /**
223 * Delete a Reminder.
224 *
225 * @param int $id
226 * ID of the Reminder to be deleted.
227 *
228 */
229 public static function del($id) {
230 if ($id) {
231 $dao = new CRM_Core_DAO_ActionSchedule();
232 $dao->id = $id;
233 if ($dao->find(TRUE)) {
234 $dao->delete();
235 return;
236 }
237 }
238 CRM_Core_Error::fatal(ts('Invalid value passed to delete function.'));
239 }
240
241 /**
242 * Update the is_active flag in the db.
243 *
244 * @param int $id
245 * Id of the database record.
246 * @param bool $is_active
247 * Value we want to set the is_active field.
248 *
249 * @return bool
250 * true if we found and updated the object, else false
251 */
252 public static function setIsActive($id, $is_active) {
253 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_ActionSchedule', $id, 'is_active', $is_active);
254 }
255
256 /**
257 * @param int $mappingID
258 * @param $now
259 *
260 * @throws CRM_Core_Exception
261 */
262 public static function sendMailings($mappingID, $now) {
263 $mapping = CRM_Utils_Array::first(self::getMappings([
264 'id' => $mappingID,
265 ]));
266
267 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
268 $actionSchedule->mapping_id = $mappingID;
269 $actionSchedule->is_active = 1;
270 $actionSchedule->find(FALSE);
271
272 while ($actionSchedule->fetch()) {
273 $query = CRM_Core_BAO_ActionSchedule::prepareMailingQuery($mapping, $actionSchedule);
274 $dao = CRM_Core_DAO::executeQuery($query,
275 [1 => [$actionSchedule->id, 'Integer']]
276 );
277
278 $multilingual = CRM_Core_I18n::isMultilingual();
279 while ($dao->fetch()) {
280 // switch language if necessary
281 if ($multilingual) {
282 $preferred_language = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $dao->contactID, 'preferred_language');
283 CRM_Core_BAO_ActionSchedule::setCommunicationLanguage($actionSchedule->communication_language, $preferred_language);
284 }
285
286 $errors = [];
287 try {
288 $tokenProcessor = self::createTokenProcessor($actionSchedule, $mapping);
289 $tokenProcessor->addRow()
290 ->context('contactId', $dao->contactID)
291 ->context('actionSearchResult', (object) $dao->toArray());
292 foreach ($tokenProcessor->evaluate()->getRows() as $tokenRow) {
293 if ($actionSchedule->mode == 'SMS' or $actionSchedule->mode == 'User_Preference') {
294 CRM_Utils_Array::extend($errors, self::sendReminderSms($tokenRow, $actionSchedule, $dao->contactID));
295 }
296
297 if ($actionSchedule->mode == 'Email' or $actionSchedule->mode == 'User_Preference') {
298 CRM_Utils_Array::extend($errors, self::sendReminderEmail($tokenRow, $actionSchedule, $dao->contactID));
299 }
300 // insert activity log record if needed
301 if ($actionSchedule->record_activity && empty($errors)) {
302 $caseID = empty($dao->case_id) ? NULL : $dao->case_id;
303 CRM_Core_BAO_ActionSchedule::createMailingActivity($tokenRow, $mapping, $dao->contactID, $dao->entityID, $caseID);
304 }
305 }
306 }
307 catch (\Civi\Token\TokenException $e) {
308 $errors['token_exception'] = $e->getMessage();
309 }
310
311 // update action log record
312 $logParams = [
313 'id' => $dao->reminderID,
314 'is_error' => !empty($errors),
315 'message' => empty($errors) ? "null" : implode(' ', $errors),
316 'action_date_time' => $now,
317 ];
318 CRM_Core_BAO_ActionLog::create($logParams);
319 }
320
321 }
322 }
323
324 /**
325 * @param int $mappingID
326 * @param $now
327 * @param array $params
328 *
329 * @throws API_Exception
330 */
331 public static function buildRecipientContacts($mappingID, $now, $params = []) {
332 $actionSchedule = new CRM_Core_DAO_ActionSchedule();
333 $actionSchedule->mapping_id = $mappingID;
334 $actionSchedule->is_active = 1;
335 if (!empty($params)) {
336 _civicrm_api3_dao_set_filter($actionSchedule, $params, FALSE);
337 }
338 $actionSchedule->find();
339
340 while ($actionSchedule->fetch()) {
341 /** @var \Civi\ActionSchedule\Mapping $mapping */
342 $mapping = CRM_Utils_Array::first(self::getMappings([
343 'id' => $mappingID,
344 ]));
345 $builder = new \Civi\ActionSchedule\RecipientBuilder($now, $actionSchedule, $mapping);
346 $builder->build();
347 }
348 }
349
350 /**
351 * @param null $now
352 * @param array $params
353 *
354 * @return array
355 */
356 public static function processQueue($now = NULL, $params = []) {
357 $now = $now ? CRM_Utils_Time::setTime($now) : CRM_Utils_Time::getTime();
358
359 $mappings = CRM_Core_BAO_ActionSchedule::getMappings();
360 foreach ($mappings as $mappingID => $mapping) {
361 CRM_Core_BAO_ActionSchedule::buildRecipientContacts($mappingID, $now, $params);
362 CRM_Core_BAO_ActionSchedule::sendMailings($mappingID, $now);
363 }
364
365 $result = [
366 'is_error' => 0,
367 'messages' => ts('Sent all scheduled reminders successfully'),
368 ];
369 return $result;
370 }
371
372 /**
373 * @param int $id
374 * @param int $mappingID
375 *
376 * @return null|string
377 */
378 public static function isConfigured($id, $mappingID) {
379 $queryString = "SELECT count(id) FROM civicrm_action_schedule
380 WHERE mapping_id = %1 AND
381 entity_value = %2";
382
383 $params = [
384 1 => [$mappingID, 'String'],
385 2 => [$id, 'Integer'],
386 ];
387 return CRM_Core_DAO::singleValueQuery($queryString, $params);
388 }
389
390 /**
391 * @param int $mappingID
392 * @param $recipientType
393 *
394 * @return array
395 */
396 public static function getRecipientListing($mappingID, $recipientType) {
397 if (!$mappingID) {
398 return [];
399 }
400
401 /** @var \Civi\ActionSchedule\Mapping $mapping */
402 $mapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings([
403 'id' => $mappingID,
404 ]));
405 return $mapping->getRecipientListing($recipientType);
406 }
407
408 /**
409 * @param $communication_language
410 * @param $preferred_language
411 */
412 public static function setCommunicationLanguage($communication_language, $preferred_language) {
413 $currentLocale = CRM_Core_I18n::getLocale();
414 $language = $currentLocale;
415
416 // prepare the language for the email
417 if ($communication_language == CRM_Core_I18n::AUTO) {
418 if (!empty($preferred_language)) {
419 $language = $preferred_language;
420 }
421 }
422 else {
423 $language = $communication_language;
424 }
425
426 // language not in the existing language, use default
427 $languages = CRM_Core_I18n::languages(TRUE);
428 if (!array_key_exists($language, $languages)) {
429 $language = $currentLocale;
430 }
431
432 // change the language
433 $i18n = CRM_Core_I18n::singleton();
434 $i18n->setLocale($language);
435 }
436
437 /**
438 * Save a record about the delivery of a reminder email.
439 *
440 * WISHLIST: Instead of saving $actionSchedule->body_html, call this immediately after
441 * sending the message and pass in the fully rendered text of the message.
442 *
443 * @param object $tokenRow
444 * @param Civi\ActionSchedule\Mapping $mapping
445 * @param int $contactID
446 * @param int $entityID
447 * @param int|null $caseID
448 * @throws CRM_Core_Exception
449 */
450 protected static function createMailingActivity($tokenRow, $mapping, $contactID, $entityID, $caseID) {
451 $session = CRM_Core_Session::singleton();
452
453 if ($mapping->getEntity() == 'civicrm_membership') {
454 // @todo - not required with api
455 $activityTypeID
456 = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Membership Renewal Reminder');
457 }
458 else {
459 // @todo - not required with api
460 $activityTypeID
461 = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Reminder Sent');
462 }
463
464 $activityParams = [
465 'subject' => $tokenRow->render('subject'),
466 'details' => $tokenRow->render('body_html'),
467 'source_contact_id' => $session->get('userID') ? $session->get('userID') : $contactID,
468 'target_contact_id' => $contactID,
469 // @todo - not required with api
470 'activity_date_time' => CRM_Utils_Time::getTime('YmdHis'),
471 // @todo - not required with api
472 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
473 'activity_type_id' => $activityTypeID,
474 'source_record_id' => $entityID,
475 ];
476 // @todo use api, remove all the above wrangling
477 $activity = CRM_Activity_BAO_Activity::create($activityParams);
478
479 //file reminder on case if source activity is a case activity
480 if (!empty($caseID)) {
481 $caseActivityParams = [];
482 $caseActivityParams['case_id'] = $caseID;
483 $caseActivityParams['activity_id'] = $activity->id;
484 CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
485 }
486 }
487
488 /**
489 * @param \Civi\ActionSchedule\MappingInterface $mapping
490 * @param \CRM_Core_DAO_ActionSchedule $actionSchedule
491 * @return string
492 */
493 protected static function prepareMailingQuery($mapping, $actionSchedule) {
494 $select = CRM_Utils_SQL_Select::from('civicrm_action_log reminder')
495 ->select("reminder.id as reminderID, reminder.contact_id as contactID, reminder.entity_table as entityTable, reminder.*, e.id AS entityID")
496 ->join('e', "!casMailingJoinType !casMappingEntity e ON !casEntityJoinExpr")
497 ->select("e.id as entityID, e.*")
498 ->where("reminder.action_schedule_id = #casActionScheduleId")
499 ->where("reminder.action_date_time IS NULL")
500 ->param([
501 'casActionScheduleId' => $actionSchedule->id,
502 'casMailingJoinType' => ($actionSchedule->limit_to == 0) ? 'LEFT JOIN' : 'INNER JOIN',
503 'casMappingId' => $mapping->getId(),
504 'casMappingEntity' => $mapping->getEntity(),
505 'casEntityJoinExpr' => 'e.id = reminder.entity_id',
506 ]);
507
508 if ($actionSchedule->limit_to == 0) {
509 $select->where("e.id = reminder.entity_id OR reminder.entity_table = 'civicrm_contact'");
510 }
511
512 \Civi::dispatcher()
513 ->dispatch(
514 \Civi\ActionSchedule\Events::MAILING_QUERY,
515 new \Civi\ActionSchedule\Event\MailingQueryEvent($actionSchedule, $mapping, $select)
516 );
517
518 return $select->toSQL();
519 }
520
521 /**
522 * @param \Civi\Token\TokenRow $tokenRow
523 * @param CRM_Core_DAO_ActionSchedule $schedule
524 * @param int $toContactID
525 * @throws CRM_Core_Exception
526 * @return array
527 * List of error messages.
528 */
529 protected static function sendReminderSms($tokenRow, $schedule, $toContactID) {
530 $toPhoneNumber = self::pickSmsPhoneNumber($toContactID);
531 if (!$toPhoneNumber) {
532 return ["sms_phone_missing" => "Couldn't find recipient's phone number."];
533 }
534
535 // dev/core#369 If an SMS provider is deleted then the relevant row in the action_schedule_table is set to NULL
536 // So we need to exclude them.
537 if (CRM_Utils_System::isNull($schedule->sms_provider_id)) {
538 return ["sms_provider_missing" => "SMS reminder cannot be sent because the SMS provider has been deleted."];
539 }
540
541 $messageSubject = $tokenRow->render('subject');
542 $sms_body_text = $tokenRow->render('sms_body_text');
543
544 $session = CRM_Core_Session::singleton();
545 $userID = $session->get('userID') ? $session->get('userID') : $tokenRow->context['contactId'];
546 $smsParams = [
547 'To' => $toPhoneNumber,
548 'provider_id' => $schedule->sms_provider_id,
549 'activity_subject' => $messageSubject,
550 ];
551 $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'SMS');
552 $activityParams = [
553 'source_contact_id' => $userID,
554 'activity_type_id' => $activityTypeID,
555 'activity_date_time' => date('YmdHis'),
556 'subject' => $messageSubject,
557 'details' => $sms_body_text,
558 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
559 ];
560
561 $activity = CRM_Activity_BAO_Activity::create($activityParams);
562
563 try {
564 CRM_Activity_BAO_Activity::sendSMSMessage($tokenRow->context['contactId'],
565 $sms_body_text,
566 $smsParams,
567 $activity->id,
568 $userID
569 );
570 }
571 catch (CRM_Core_Exception $e) {
572 return ["sms_send_error" => $e->getMessage()];
573 }
574
575 return [];
576 }
577
578 /**
579 * @param CRM_Core_DAO_ActionSchedule $actionSchedule
580 * @return string
581 * Ex: "Alice <alice@example.org>".
582 */
583 protected static function pickFromEmail($actionSchedule) {
584 $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
585 $fromEmailAddress = "$domainValues[0] <$domainValues[1]>";
586 if ($actionSchedule->from_email) {
587 $fromEmailAddress = "$actionSchedule->from_name <$actionSchedule->from_email>";
588 return $fromEmailAddress;
589 }
590 return $fromEmailAddress;
591 }
592
593 /**
594 * @param \Civi\Token\TokenRow $tokenRow
595 * @param CRM_Core_DAO_ActionSchedule $schedule
596 * @param int $toContactID
597 * @return array
598 * List of error messages.
599 */
600 protected static function sendReminderEmail($tokenRow, $schedule, $toContactID) {
601 $toEmail = CRM_Contact_BAO_Contact::getPrimaryEmail($toContactID, TRUE);
602 if (!$toEmail) {
603 return ["email_missing" => "Couldn't find recipient's email address."];
604 }
605
606 $body_text = $tokenRow->render('body_text');
607 $body_html = $tokenRow->render('body_html');
608 if (!$schedule->body_text) {
609 $body_text = CRM_Utils_String::htmlToText($body_html);
610 }
611
612 // set up the parameters for CRM_Utils_Mail::send
613 $mailParams = [
614 'groupName' => 'Scheduled Reminder Sender',
615 'from' => self::pickFromEmail($schedule),
616 'toName' => $tokenRow->context['contact']['display_name'],
617 'toEmail' => $toEmail,
618 'subject' => $tokenRow->render('subject'),
619 'entity' => 'action_schedule',
620 'entity_id' => $schedule->id,
621 ];
622
623 if (!$body_html || $tokenRow->context['contact']['preferred_mail_format'] == 'Text' ||
624 $tokenRow->context['contact']['preferred_mail_format'] == 'Both'
625 ) {
626 // render the &amp; entities in text mode, so that the links work
627 $mailParams['text'] = str_replace('&amp;', '&', $body_text);
628 }
629 if ($body_html && ($tokenRow->context['contact']['preferred_mail_format'] == 'HTML' ||
630 $tokenRow->context['contact']['preferred_mail_format'] == 'Both'
631 )
632 ) {
633 $mailParams['html'] = $body_html;
634 }
635 $result = CRM_Utils_Mail::send($mailParams);
636 if (!$result || is_a($result, 'PEAR_Error')) {
637 return ['email_fail' => 'Failed to send message'];
638 }
639
640 return [];
641 }
642
643 /**
644 * @param CRM_Core_DAO_ActionSchedule $schedule
645 * @param \Civi\ActionSchedule\Mapping $mapping
646 * @return \Civi\Token\TokenProcessor
647 */
648 protected static function createTokenProcessor($schedule, $mapping) {
649 $tp = new \Civi\Token\TokenProcessor(\Civi::dispatcher(), [
650 'controller' => __CLASS__,
651 'actionSchedule' => $schedule,
652 'actionMapping' => $mapping,
653 'smarty' => TRUE,
654 ]);
655 $tp->addMessage('body_text', $schedule->body_text, 'text/plain');
656 $tp->addMessage('body_html', $schedule->body_html, 'text/html');
657 $tp->addMessage('sms_body_text', $schedule->sms_body_text, 'text/plain');
658 $tp->addMessage('subject', $schedule->subject, 'text/plain');
659 return $tp;
660 }
661
662 /**
663 * Pick SMS phone number.
664 *
665 * @param int $smsToContactId
666 *
667 * @return NULL|string
668 */
669 protected static function pickSmsPhoneNumber($smsToContactId) {
670 $toPhoneNumbers = CRM_Core_BAO_Phone::allPhones($smsToContactId, FALSE, 'Mobile', [
671 'is_deceased' => 0,
672 'is_deleted' => 0,
673 'do_not_sms' => 0,
674 ]);
675 //to get primary mobile ph,if not get a first mobile phONE
676 if (!empty($toPhoneNumbers)) {
677 $toPhoneNumberDetails = reset($toPhoneNumbers);
678 $toPhoneNumber = $toPhoneNumberDetails['phone'] ?? NULL;
679 return $toPhoneNumber;
680 }
681 return NULL;
682 }
683
684 /**
685 * Get the list of generic recipient types supported by all entities/mappings.
686 *
687 * @return array
688 * array(mixed $value => string $label).
689 */
690 public static function getAdditionalRecipients() {
691 return [
692 'manual' => ts('Choose Recipient(s)'),
693 'group' => ts('Select Group'),
694 ];
695 }
696
697 }