3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
37 * This class provides the common functionality for sending sms to
38 * one or a group of contact ids.
40 class CRM_Contact_Form_Task_SMSCommon
{
41 CONST RECIEVED_SMS_ACTIVITY_SUBJECT
= "SMS Received";
43 public $_contactDetails = array();
45 public $_allContactDetails = array();
47 public $_toContactPhone = array();
50 static function preProcessProvider(&$form) {
51 $form->_single
= FALSE;
52 $className = CRM_Utils_System
::getClassName($form);
54 if (property_exists($form, '_context') &&
55 $form->_context
!= 'search' &&
56 $className == 'CRM_Contact_Form_Task_SMS'
58 $form->_single
= TRUE;
61 $providersCount = CRM_SMS_BAO_Provider
::activeProviderCount();
63 if (!$providersCount) {
64 CRM_Core_Error
::statusBounce(ts('There are no SMS providers configured, or no SMS providers are set active'));
67 if ($className == 'CRM_Activity_Form_Task_SMS') {
69 foreach ($form->_activityHolderIds
as $value) {
70 if (CRM_Core_DAO
::getFieldValue('CRM_Activity_DAO_Activity', $value, 'subject', 'id') != self
::RECIEVED_SMS_ACTIVITY_SUBJECT
) {
74 if ($activityCheck == count($form->_activityHolderIds
)) {
75 CRM_Core_Error
::statusBounce(ts("The Reply SMS Could only be sent for activities with '%1' subject.",
76 array(1 => self
::RECIEVED_SMS_ACTIVITY_SUBJECT
)
89 static function buildQuickForm(&$form) {
93 $form->assign('max_sms_length', CRM_SMS_Provider
::MAX_SMS_CHAR
);
95 $providers = CRM_SMS_BAO_Provider
::getProviders(NULL, NULL, TRUE, 'is_default desc');
97 $providerSelect = array();
98 foreach ($providers as $provider) {
99 $providerSelect[$provider['id']] = $provider['title'];
102 //here we are getting logged in user id as array but we need target contact id. CRM-5988
103 $cid = $form->get('cid');
106 $form->_contactIds
= array($cid);
109 $to = $form->add('text', 'to', ts('To'), '', TRUE);
110 $form->add('text', 'activity_subject', ts('Name The SMS'), '', TRUE);
112 $toSetDefault = TRUE;
113 if (property_exists($form, '_context') && $form->_context
== 'standalone') {
114 $toSetDefault = FALSE;
117 // when form is submitted recompute contactIds
119 if ($to->getValue()) {
120 $allToPhone = explode(',', $to->getValue());
122 $form->_contactIds
= array();
123 foreach ($allToPhone as $value) {
124 list($contactId, $phone) = explode('::', $value);
126 $form->_contactIds
[] = $contactId;
127 $form->_toContactPhone
[] = $phone;
130 $toSetDefault = TRUE;
133 //get the group of contacts as per selected by user in case of Find Activities
134 if (!empty($form->_activityHolderIds
)) {
135 $extendTargetContacts = 0;
136 $invalidActivity = 0;
137 $validActivities = 0;
138 foreach ($form->_activityHolderIds
as $key => $id) {
139 //valid activity check
140 if (CRM_Core_DAO
::getFieldValue('CRM_Activity_DAO_Activity', $id, 'subject', 'id') != self
::RECIEVED_SMS_ACTIVITY_SUBJECT
) {
145 $activityContacts = CRM_Core_OptionGroup
::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
146 $targetID = CRM_Utils_Array
::key('Activity Targets', $activityContacts);
147 //target contacts limit check
148 $ids = array_keys(CRM_Activity_BAO_ActivityContact
::getNames($id, $targetID));
150 if (count($ids) > 1) {
151 $extendTargetContacts++
;
155 $form->_contactIds
= empty($form->_contactIds
) ?
$ids : array_unique(array_merge($form->_contactIds
, $ids));
158 if (!$validActivities) {
160 if ($extendTargetContacts) {
161 $errorMess = ts('One selected activity consists of more than one target contact.', array(
162 'count' => $extendTargetContacts,
163 'plural' => '%count selected activities consist of more than one target contact.'));
165 if ($invalidActivity) {
166 $errorMess = ($errorMess ?
' ' : '');
167 $errorMess .= ts('The selected activity is invalid.', array(
168 'count' => $invalidActivity,
169 'plural' => '%count selected activities are invalid.'));
171 CRM_Core_Error
::statusBounce(ts("%1: SMS Reply will not be sent.", array(1 => $errorMess)));
175 if (is_array($form->_contactIds
) && !empty($form->_contactIds
) && $toSetDefault) {
176 $returnProperties = array(
184 list($form->_contactDetails
) = CRM_Utils_Token
::getTokenDetails($form->_contactIds
,
190 // make a copy of all contact details
191 $form->_allContactDetails
= $form->_contactDetails
;
193 foreach ($form->_contactIds
as $key => $contactId) {
194 $value = $form->_contactDetails
[$contactId];
196 //to check if the phone type is "Mobile"
197 $phoneTypes = CRM_Core_OptionGroup
::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name');
199 if (CRM_Utils_System
::getClassName($form) == 'CRM_Activity_Form_Task_SMS') {
200 //to check for "if the contact id belongs to a specified activity type"
201 $actDetails = CRM_Activity_BAO_Activity
::getContactActivity($contactId);
202 if (self
::RECIEVED_SMS_ACTIVITY_SUBJECT
!=
203 CRM_Utils_Array
::retrieveValueRecursive($actDetails, 'subject')
206 unset($form->_contactDetails
[$contactId]);
211 if ((isset($value['phone_type_id']) && $value['phone_type_id'] != CRM_Utils_Array
::value('Mobile', $phoneTypes)) ||
$value['do_not_sms'] ||
empty($value['phone']) || CRM_Utils_Array
::value('is_deceased', $value)) {
213 //if phone is not primary check if non-primary phone is "Mobile"
214 if (!empty($value['phone'])
215 && $value['phone_type_id'] != CRM_Utils_Array
::value('Mobile', $phoneTypes)
216 && !CRM_Utils_Array
::value('is_deceased', $value)
218 $filter = array('do_not_sms' => 0);
219 $contactPhones = CRM_Core_BAO_Phone
::allPhones($contactId, FALSE, 'Mobile', $filter);
220 if (count($contactPhones) > 0) {
221 $mobilePhone = CRM_Utils_Array
::retrieveValueRecursive($contactPhones, 'phone');
222 $form->_contactDetails
[$contactId]['phone_id'] = CRM_Utils_Array
::retrieveValueRecursive($contactPhones, 'id');
223 $form->_contactDetails
[$contactId]['phone'] = $mobilePhone;
224 $form->_contactDetails
[$contactId]['phone_type_id'] = CRM_Utils_Array
::value('Mobile', $phoneTypes);
228 unset($form->_contactDetails
[$contactId]);
234 unset($form->_contactDetails
[$contactId]);
239 if (isset($mobilePhone)) {
240 $phone = $mobilePhone;
242 elseif (empty($form->_toContactPhone
)) {
243 $phone = $value['phone'];
246 $phone = CRM_Utils_Array
::value($key, $form->_toContactPhone
);
251 'name' => '"' . $value['sort_name'] . '" <' . $phone . '>',
252 'id' => "$contactId::{$phone}",
257 if (empty($toArray)) {
258 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'));
262 //activity related variables
263 if (isset($invalidActivity)) {
264 $form->assign('invalidActivity', $invalidActivity);
266 if (isset($extendTargetContacts)) {
267 $form->assign('extendTargetContacts', $extendTargetContacts);
271 $form->assign('toContact', json_encode($toArray));
272 $form->assign('suppressedSms', $suppressedSms);
273 $form->assign('totalSelectedContacts', count($form->_contactIds
));
275 $form->add('select', 'sms_provider_id', ts('From'), $providerSelect, TRUE);
277 CRM_Mailing_BAO_Mailing
::commonCompose($form);
279 if ($form->_single
) {
280 // also fix the user context stack
281 if ($form->_context
) {
282 $url = CRM_Utils_System
::url('civicrm/dashboard', 'reset=1');
285 $url = CRM_Utils_System
::url('civicrm/contact/view',
286 "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity"
290 $session = CRM_Core_Session
::singleton();
291 $session->replaceUserContext($url);
292 $form->addDefaultButtons(ts('Send SMS'), 'upload', 'cancel');
295 $form->addDefaultButtons(ts('Send SMS'), 'upload');
298 $form->addFormRule(array('CRM_Contact_Form_Task_SMSCommon', 'formRule'), $form);
304 * @param array $fields the input form values
305 * @param array $dontCare
306 * @param array $self additional values form 'this'
308 * @return true if no errors, else array of errors
312 static function formRule($fields, $dontCare, $self) {
315 $template = CRM_Core_Smarty
::singleton();
317 if (!CRM_Utils_Array
::value('text_message', $fields)) {
318 $errors['text_message'] = ts('Please provide Text message.');
321 if (CRM_Utils_Array
::value('text_message', $fields)) {
322 $messageCheck = CRM_Utils_Array
::value('text_message', $fields);
323 $messageCheck = str_replace("\r\n", "\n", $messageCheck);
324 if ($messageCheck && (strlen($messageCheck) > CRM_SMS_Provider
::MAX_SMS_CHAR
)) {
325 $errors['text_message'] = ts("You can configure the SMS message body up to %1 characters", array(1 => CRM_SMS_Provider
::MAX_SMS_CHAR
));
331 if (CRM_Utils_Array
::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) {
332 $errors['saveTemplateName'] = ts("Enter name to save message template");
335 return empty($errors) ?
TRUE : $errors;
339 * process the form after the input has been submitted and validated
345 static function postProcess(&$form) {
347 // check and ensure that
348 $thisValues = $form->controller
->exportValues($form->getName());
350 $fromSmsProviderId = $thisValues['sms_provider_id'];
352 // process message template
353 if (CRM_Utils_Array
::value('saveTemplate', $thisValues)
354 || CRM_Utils_Array
::value('updateTemplate', $thisValues)
356 $messageTemplate = array(
357 'msg_text' => $thisValues['text_message'],
361 if (CRM_Utils_Array
::value('saveTemplate', $thisValues)) {
362 $messageTemplate['msg_title'] = $thisValues['saveTemplateName'];
363 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
366 if (CRM_Utils_Array
::value('template', $thisValues) &&
367 CRM_Utils_Array
::value('updateTemplate', $thisValues)
369 $messageTemplate['id'] = $thisValues['template'];
370 unset($messageTemplate['msg_title']);
371 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
375 // format contact details array to handle multiple sms from same contact
376 $formattedContactDetails = array();
377 $tempPhones = array();
379 foreach ($form->_contactIds
as $key => $contactId) {
380 $phone = $form->_toContactPhone
[$key];
383 $phoneKey = "{$contactId}::{$phone}";
384 if (!in_array($phoneKey, $tempPhones)) {
385 $tempPhones[] = $phoneKey;
386 if (CRM_Utils_Array
::value($contactId, $form->_contactDetails
)) {
387 $formattedContactDetails[] = $form->_contactDetails
[$contactId];
393 // $smsParams carries all the arguments provided on form (or via hooks), to the provider->send() method
394 // this gives flexibity to the users / implementors to add their own args via hooks specific to their sms providers
395 $smsParams = $thisValues;
396 unset($smsParams['text_message']);
397 $smsParams['provider_id'] = $fromSmsProviderId;
398 $contactIds = array_keys($form->_contactDetails
);
399 $allContactIds = array_keys($form->_allContactDetails
);
401 list($sent, $activityId, $countSuccess) = CRM_Activity_BAO_Activity
::sendSMS($formattedContactDetails,
407 if ($countSuccess > 0) {
408 CRM_Core_Session
::setStatus(ts('One message was sent successfully.', array('plural' => '%count messages were sent successfully.', 'count' => $countSuccess)), ts('Message Sent', array('plural' => 'Messages Sent', 'count' => $countSuccess)), 'success');
411 if (is_array($sent)) {
412 // At least one PEAR_Error object was generated.
413 // Display the error messages to the user.
415 foreach ($sent as $errMsg) {
416 $status .= '<li>' . $errMsg . '</li>';
419 CRM_Core_Session
::setStatus($status, ts('One Message Not Sent', array('count' => count($sent), 'plural' => '%count Messages Not Sent')), 'info');
421 //Display the name and number of contacts for those sms is not sent.
422 $smsNotSent = array_diff_assoc($allContactIds, $contactIds);
424 if (!empty($smsNotSent)) {
426 foreach ($smsNotSent as $index => $contactId) {
427 $displayName = $form->_allContactDetails
[$contactId]['display_name'];
428 $phone = $form->_allContactDetails
[$contactId]['phone'];
429 $contactViewUrl = CRM_Utils_System
::url('civicrm/contact/view', "reset=1&cid=$contactId");
430 $not_sent[] = "<a href='$contactViewUrl' title='$phone'>$displayName</a>";
432 $status = '(' . ts('because no phone number on file or communication preferences specify DO NOT SMS or Contact is deceased');
433 if (CRM_Utils_System
::getClassName($form) == 'CRM_Activity_Form_Task_SMS') {
434 $status .= ' ' . ts("or the contact is not part of the activity '%1'", array(1 => self
::RECIEVED_SMS_ACTIVITY_SUBJECT
));
436 $status .= ')<ul><li>' . implode('</li><li>', $not_sent) . '</li></ul>';
437 CRM_Core_Session
::setStatus($status, ts('One Message Not Sent', array('count' => count($smsNotSent), 'plural' => '%count Messages Not Sent')), 'info');