diff --git a/CRM/Activity/Form/Task/SMS.php b/CRM/Activity/Form/Task/SMS.php index a5217e7f8f86..f9d150c88ca0 100644 --- a/CRM/Activity/Form/Task/SMS.php +++ b/CRM/Activity/Form/Task/SMS.php @@ -61,9 +61,20 @@ public function preProcess() { * Build the form object. */ public function buildQuickForm() { - // Enable form element. - $this->assign('SMSTask', TRUE); - CRM_Contact_Form_Task_SMSCommon::buildQuickForm($this); + $this->buildSmsForm(); + } + + /** + * Get the relevant activity name. + * + * This is likely to be further refactored/ clarified. + * + * @internal + * + * @return string + */ + protected function getActivityName() { + return 'SMS Received'; } } diff --git a/CRM/Contact/Form/Task/SMS.php b/CRM/Contact/Form/Task/SMS.php index 7791876869bb..aba14ba91491 100644 --- a/CRM/Contact/Form/Task/SMS.php +++ b/CRM/Contact/Form/Task/SMS.php @@ -63,8 +63,7 @@ public function preProcess(): void { public function buildQuickForm() { //enable form element $this->assign('suppressForm', FALSE); - $this->assign('SMSTask', TRUE); - CRM_Contact_Form_Task_SMSCommon::buildQuickForm($this); + $this->buildSmsForm(); } } diff --git a/CRM/Contact/Form/Task/SMSCommon.php b/CRM/Contact/Form/Task/SMSCommon.php index 2665744feb11..030e29d16ba1 100644 --- a/CRM/Contact/Form/Task/SMSCommon.php +++ b/CRM/Contact/Form/Task/SMSCommon.php @@ -17,6 +17,8 @@ /** * This class provides the common functionality for sending sms to one or a group of contact ids. + * + * @deprecated since 5.71 will be removed around 5.77. */ class CRM_Contact_Form_Task_SMSCommon { const RECIEVED_SMS_ACTIVITY_SUBJECT = "SMS Received"; @@ -71,6 +73,8 @@ public static function preProcessProvider(&$form) { * Build the form object. * * @param CRM_Core_Form $form + * + * @deprecated since 5.71 will be removed around 5.77. */ public static function buildQuickForm(&$form) { @@ -105,7 +109,7 @@ public static function buildQuickForm(&$form) { $form->_contactIds = []; foreach ($allToPhone as $value) { - list($contactId, $phone) = explode('::', $value); + [$contactId, $phone] = explode('::', $value); if ($contactId) { $form->_contactIds[] = $contactId; $form->_toContactPhone[] = $phone; @@ -314,9 +318,11 @@ public static function formRule($fields, $dontCare, $self) { * Process the form after the input has been submitted and validated. * * @param CRM_Core_Form $form + * + * @deprecated since 5.71 will be removed around 5.77. */ public static function postProcess(&$form) { - + CRM_Core_Error::deprecatedFunctionWarning('no alternative supported for non-core use'); $thisValues = $form->controller->exportValues($form->getName()); $fromSmsProviderId = $thisValues['sms_provider_id']; @@ -367,7 +373,7 @@ public static function postProcess(&$form) { $contactIds = array_keys($form->_contactDetails); $allContactIds = array_keys($form->_allContactDetails); - list($sent, $activityId, $countSuccess) = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails, + [$sent, $activityId, $countSuccess] = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails, $thisValues, $smsParams, $contactIds diff --git a/CRM/Contact/Form/Task/SMSTrait.php b/CRM/Contact/Form/Task/SMSTrait.php index cd305ec3d748..5b8966687200 100644 --- a/CRM/Contact/Form/Task/SMSTrait.php +++ b/CRM/Contact/Form/Task/SMSTrait.php @@ -25,7 +25,7 @@ trait CRM_Contact_Form_Task_SMSTrait { * Process the form after the input has been submitted and validated. */ public function postProcess() { - CRM_Contact_Form_Task_SMSCommon::postProcess($this); + $this->postProcessSms(); } protected function bounceOnNoActiveProviders(): void { @@ -35,6 +35,348 @@ protected function bounceOnNoActiveProviders(): void { } } + /** + * Build the SMS Form + * + * @internal - highly likely to change! + */ + protected function buildSmsForm() { + $form = $this; + $toArray = []; + + $providers = CRM_SMS_BAO_Provider::getProviders(NULL, NULL, TRUE, 'is_default desc'); + + $providerSelect = []; + foreach ($providers as $provider) { + $providerSelect[$provider['id']] = $provider['title']; + } + $suppressedSms = 0; + //here we are getting logged in user id as array but we need target contact id. CRM-5988 + $cid = $form->get('cid'); + + if ($cid) { + $form->_contactIds = [$cid]; + } + + $to = $form->add('text', 'to', ts('To'), ['class' => 'huge'], TRUE); + $form->add('text', 'activity_subject', ts('Name The SMS'), ['class' => 'huge'], TRUE); + + $toSetDefault = TRUE; + if (property_exists($form, '_context') && $form->_context == 'standalone') { + $toSetDefault = FALSE; + } + + // when form is submitted recompute contactIds + $allToSMS = []; + if ($to->getValue()) { + $allToPhone = explode(',', $to->getValue()); + + $form->_contactIds = []; + foreach ($allToPhone as $value) { + list($contactId, $phone) = explode('::', $value); + if ($contactId) { + $form->_contactIds[] = $contactId; + $form->_toContactPhone[] = $phone; + } + } + $toSetDefault = TRUE; + } + + //get the group of contacts as per selected by user in case of Find Activities + if (!empty($form->_activityHolderIds)) { + $extendTargetContacts = 0; + $invalidActivity = 0; + $validActivities = 0; + foreach ($form->_activityHolderIds as $key => $id) { + //valid activity check + if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $id, 'subject', 'id') !== $this->getActivityName()) { + $invalidActivity++; + continue; + } + + $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate'); + $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); + //target contacts limit check + $ids = array_keys(CRM_Activity_BAO_ActivityContact::getNames($id, $targetID)); + + if (count($ids) > 1) { + $extendTargetContacts++; + continue; + } + $validActivities++; + $form->_contactIds = empty($form->_contactIds) ? $ids : array_unique(array_merge($form->_contactIds, $ids)); + } + + if (!$validActivities) { + $errorMess = ""; + if ($extendTargetContacts) { + $errorMess = ts('One selected activity consists of more than one target contact.', [ + 'count' => $extendTargetContacts, + 'plural' => '%count selected activities consist of more than one target contact.', + ]); + } + if ($invalidActivity) { + $errorMess = ($errorMess ? ' ' : ''); + $errorMess .= ts('The selected activity is invalid.', [ + 'count' => $invalidActivity, + 'plural' => '%count selected activities are invalid.', + ]); + } + CRM_Core_Error::statusBounce(ts("%1: SMS Reply will not be sent.", [1 => $errorMess])); + } + } + + if (is_array($form->_contactIds) && !empty($form->_contactIds) && $toSetDefault) { + $form->_contactDetails = civicrm_api3('Contact', 'get', [ + 'id' => ['IN' => $form->_contactIds], + 'return' => ['sort_name', 'phone', 'do_not_sms', 'is_deceased', 'display_name'], + 'options' => ['limit' => 0], + ])['values']; + + // make a copy of all contact details + $form->_allContactDetails = $form->_contactDetails; + + foreach ($form->_contactIds as $key => $contactId) { + $mobilePhone = NULL; + $contactDetails = $form->_contactDetails[$contactId]; + + //to check if the phone type is "Mobile" + $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name'); + + if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') { + //to check for "if the contact id belongs to a specified activity type" + // @todo use the api instead - function is deprecated. + $actDetails = CRM_Activity_BAO_Activity::getContactActivity($contactId); + if ($this->getActivityName() !== + CRM_Utils_Array::retrieveValueRecursive($actDetails, 'subject') + ) { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + } + + // No phone, No SMS or Deceased: then we suppress it. + if (empty($contactDetails['phone']) || $contactDetails['do_not_sms'] || !empty($contactDetails['is_deceased'])) { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + elseif ($contactDetails['phone_type_id'] != ($phoneTypes['Mobile'] ?? NULL)) { + //if phone is not primary check if non-primary phone is "Mobile" + $filter = ['do_not_sms' => 0]; + $contactPhones = CRM_Core_BAO_Phone::allPhones($contactId, FALSE, 'Mobile', $filter); + if (count($contactPhones) > 0) { + $mobilePhone = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'phone'); + $form->_contactDetails[$contactId]['phone_id'] = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'id'); + $form->_contactDetails[$contactId]['phone'] = $mobilePhone; + $form->_contactDetails[$contactId]['phone_type_id'] = $phoneTypes['Mobile'] ?? NULL; + } + else { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + } + + if (isset($mobilePhone)) { + $phone = $mobilePhone; + } + elseif (empty($form->_toContactPhone)) { + $phone = $contactDetails['phone']; + } + else { + $phone = $form->_toContactPhone[$key] ?? NULL; + } + + if ($phone) { + $toArray[] = [ + 'text' => '"' . $contactDetails['sort_name'] . '" (' . $phone . ')', + 'id' => "$contactId::{$phone}", + ]; + } + } + + if (empty($toArray)) { + CRM_Core_Error::statusBounce(ts('Selected contact(s) do not have a valid Phone, or communication preferences specify DO NOT SMS, or they are deceased')); + } + } + + //activity related variables + $form->assign('invalidActivity', $invalidActivity ?? NULL); + $form->assign('extendTargetContacts', $extendTargetContacts ?? NULL); + + $form->assign('toContact', json_encode($toArray)); + $form->assign('suppressedSms', $suppressedSms); + $form->assign('totalSelectedContacts', count($form->_contactIds)); + + $form->add('select', 'sms_provider_id', ts('From'), $providerSelect, TRUE); + + CRM_Mailing_BAO_Mailing::commonCompose($form); + + if ($form->_single) { + // also fix the user context stack + if ($form->_context) { + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', + "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity" + ); + } + + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext($url); + $form->addDefaultButtons(ts('Send SMS'), 'upload', 'cancel'); + } + else { + $form->addDefaultButtons(ts('Send SMS'), 'upload'); + } + + $form->addFormRule([__CLASS__, 'formRuleSms'], $form); + } + + /** + * Process the sms form after the input has been submitted and validated. + * + * @internal likely to change. + */ + protected function postProcessSms() { + $form = $this; + $thisValues = $form->controller->exportValues($form->getName()); + + $fromSmsProviderId = $thisValues['sms_provider_id']; + + // process message template + if (!empty($thisValues['SMSsaveTemplate']) || !empty($thisValues['SMSupdateTemplate'])) { + $messageTemplate = [ + 'msg_text' => $thisValues['sms_text_message'], + 'is_active' => TRUE, + 'is_sms' => TRUE, + ]; + + if (!empty($thisValues['SMSsaveTemplate'])) { + $messageTemplate['msg_title'] = $thisValues['SMSsaveTemplateName']; + CRM_Core_BAO_MessageTemplate::add($messageTemplate); + } + + if (!empty($thisValues['SMStemplate']) && !empty($thisValues['SMSupdateTemplate'])) { + $messageTemplate['id'] = $thisValues['SMStemplate']; + unset($messageTemplate['msg_title']); + CRM_Core_BAO_MessageTemplate::add($messageTemplate); + } + } + + // format contact details array to handle multiple sms from same contact + $formattedContactDetails = []; + $tempPhones = []; + + foreach ($form->_contactIds as $key => $contactId) { + $phone = $form->_toContactPhone[$key]; + + if ($phone) { + $phoneKey = "{$contactId}::{$phone}"; + if (!in_array($phoneKey, $tempPhones)) { + $tempPhones[] = $phoneKey; + if (!empty($form->_contactDetails[$contactId])) { + $formattedContactDetails[] = $form->_contactDetails[$contactId]; + } + } + } + } + + // $smsParams carries all the arguments provided on form (or via hooks), to the provider->send() method + // this gives flexibity to the users / implementors to add their own args via hooks specific to their sms providers + $smsParams = $thisValues; + unset($smsParams['sms_text_message']); + $smsParams['provider_id'] = $fromSmsProviderId; + $contactIds = array_keys($form->_contactDetails); + $allContactIds = array_keys($form->_allContactDetails); + + [$sent, $activityId, $countSuccess] = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails, + $thisValues, + $smsParams, + $contactIds + ); + + if ($countSuccess > 0) { + CRM_Core_Session::setStatus(ts('One message was sent successfully.', [ + 'plural' => '%count messages were sent successfully.', + 'count' => $countSuccess, + ]), ts('Message Sent', ['plural' => 'Messages Sent', 'count' => $countSuccess]), 'success'); + } + + if (is_array($sent)) { + // At least one PEAR_Error object was generated. + // Display the error messages to the user. + $status = '