Merge pull request #8193 from colemanw/scardinius-issue-CRM-16911
[civicrm-core.git] / CRM / Contact / Form / Task / SMSCommon.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28/**
29 *
30 * @package CRM
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035
TO
32 */
33
34/**
424029e3 35 * This class provides the common functionality for sending sms to one or a group of contact ids.
6a488035
TO
36 */
37class CRM_Contact_Form_Task_SMSCommon {
7da04cde 38 const RECIEVED_SMS_ACTIVITY_SUBJECT = "SMS Received";
6a488035
TO
39
40 public $_contactDetails = array();
41
42 public $_allContactDetails = array();
43
44 public $_toContactPhone = array();
45
46
86538308 47 /**
424029e3 48 * Pre process the provider.
49 *
c490a46a 50 * @param CRM_Core_Form $form
86538308 51 */
00be9182 52 public static function preProcessProvider(&$form) {
6a488035
TO
53 $form->_single = FALSE;
54 $className = CRM_Utils_System::getClassName($form);
55
56 if (property_exists($form, '_context') &&
57 $form->_context != 'search' &&
58 $className == 'CRM_Contact_Form_Task_SMS'
59 ) {
60 $form->_single = TRUE;
61 }
62
63 $providersCount = CRM_SMS_BAO_Provider::activeProviderCount();
64
65 if (!$providersCount) {
66 CRM_Core_Error::statusBounce(ts('There are no SMS providers configured, or no SMS providers are set active'));
67 }
68
69 if ($className == 'CRM_Activity_Form_Task_SMS') {
70 $activityCheck = 0;
71 foreach ($form->_activityHolderIds as $value) {
72 if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $value, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) {
73 $activityCheck++;
74 }
75 }
76 if ($activityCheck == count($form->_activityHolderIds)) {
77 CRM_Core_Error::statusBounce(ts("The Reply SMS Could only be sent for activities with '%1' subject.",
353ffa53
TO
78 array(1 => self::RECIEVED_SMS_ACTIVITY_SUBJECT)
79 ));
6a488035
TO
80 }
81 }
82 }
83
84 /**
fe482240 85 * Build the form object.
6a488035 86 *
c490a46a 87 * @param CRM_Core_Form $form
6a488035 88 */
00be9182 89 public static function buildQuickForm(&$form) {
6a488035
TO
90
91 $toArray = array();
92
6a488035
TO
93 $providers = CRM_SMS_BAO_Provider::getProviders(NULL, NULL, TRUE, 'is_default desc');
94
95 $providerSelect = array();
96 foreach ($providers as $provider) {
97 $providerSelect[$provider['id']] = $provider['title'];
98 }
99 $suppressedSms = 0;
100 //here we are getting logged in user id as array but we need target contact id. CRM-5988
101 $cid = $form->get('cid');
102
103 if ($cid) {
104 $form->_contactIds = array($cid);
105 }
106
b792e485
M
107 $to = $form->add('text', 'to', ts('To'), array('class' => 'huge'), TRUE);
108 $form->add('text', 'activity_subject', ts('Name The SMS'), array('class' => 'huge'), TRUE);
6a488035
TO
109
110 $toSetDefault = TRUE;
111 if (property_exists($form, '_context') && $form->_context == 'standalone') {
112 $toSetDefault = FALSE;
113 }
114
115 // when form is submitted recompute contactIds
116 $allToSMS = array();
117 if ($to->getValue()) {
118 $allToPhone = explode(',', $to->getValue());
119
120 $form->_contactIds = array();
121 foreach ($allToPhone as $value) {
122 list($contactId, $phone) = explode('::', $value);
123 if ($contactId) {
124 $form->_contactIds[] = $contactId;
125 $form->_toContactPhone[] = $phone;
126 }
127 }
128 $toSetDefault = TRUE;
129 }
130
131 //get the group of contacts as per selected by user in case of Find Activities
132 if (!empty($form->_activityHolderIds)) {
133 $extendTargetContacts = 0;
134 $invalidActivity = 0;
135 $validActivities = 0;
136 foreach ($form->_activityHolderIds as $key => $id) {
137 //valid activity check
138 if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $id, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) {
139 $invalidActivity++;
140 continue;
141 }
142
e7e657f0 143 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
034500d4 144 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
6a488035 145 //target contacts limit check
034500d4 146 $ids = array_keys(CRM_Activity_BAO_ActivityContact::getNames($id, $targetID));
6a488035
TO
147
148 if (count($ids) > 1) {
149 $extendTargetContacts++;
150 continue;
151 }
152 $validActivities++;
153 $form->_contactIds = empty($form->_contactIds) ? $ids : array_unique(array_merge($form->_contactIds, $ids));
154 }
155
156 if (!$validActivities) {
157 $errorMess = "";
158 if ($extendTargetContacts) {
159 $errorMess = ts('One selected activity consists of more than one target contact.', array(
353ffa53 160 'count' => $extendTargetContacts,
bed98343 161 'plural' => '%count selected activities consist of more than one target contact.',
353ffa53 162 ));
6a488035
TO
163 }
164 if ($invalidActivity) {
165 $errorMess = ($errorMess ? ' ' : '');
166 $errorMess .= ts('The selected activity is invalid.', array(
353ffa53 167 'count' => $invalidActivity,
bed98343 168 'plural' => '%count selected activities are invalid.',
353ffa53 169 ));
6a488035
TO
170 }
171 CRM_Core_Error::statusBounce(ts("%1: SMS Reply will not be sent.", array(1 => $errorMess)));
172 }
173 }
174
f53ea1ce 175 if (is_array($form->_contactIds) && !empty($form->_contactIds) && $toSetDefault) {
6a488035
TO
176 $returnProperties = array(
177 'sort_name' => 1,
178 'phone' => 1,
179 'do_not_sms' => 1,
180 'is_deceased' => 1,
181 'display_name' => 1,
182 );
183
184 list($form->_contactDetails) = CRM_Utils_Token::getTokenDetails($form->_contactIds,
185 $returnProperties,
186 FALSE,
187 FALSE
188 );
189
190 // make a copy of all contact details
191 $form->_allContactDetails = $form->_contactDetails;
192
193 foreach ($form->_contactIds as $key => $contactId) {
194 $value = $form->_contactDetails[$contactId];
195
196 //to check if the phone type is "Mobile"
197 $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name');
198
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')
204 ) {
205 $suppressedSms++;
206 unset($form->_contactDetails[$contactId]);
207 continue;
208 }
209 }
210
8cc574cf 211 if ((isset($value['phone_type_id']) && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes)) || $value['do_not_sms'] || empty($value['phone']) || !empty($value['is_deceased'])) {
6a488035
TO
212
213 //if phone is not primary check if non-primary phone is "Mobile"
214 if (!empty($value['phone'])
353ffa53
TO
215 && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes) && empty($value['is_deceased'])
216 ) {
6a488035
TO
217 $filter = array('do_not_sms' => 0);
218 $contactPhones = CRM_Core_BAO_Phone::allPhones($contactId, FALSE, 'Mobile', $filter);
219 if (count($contactPhones) > 0) {
220 $mobilePhone = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'phone');
353ffa53 221 $form->_contactDetails[$contactId]['phone_id'] = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'id');
6a488035
TO
222 $form->_contactDetails[$contactId]['phone'] = $mobilePhone;
223 $form->_contactDetails[$contactId]['phone_type_id'] = CRM_Utils_Array::value('Mobile', $phoneTypes);
224 }
225 else {
226 $suppressedSms++;
227 unset($form->_contactDetails[$contactId]);
228 continue;
229 }
230 }
231 else {
232 $suppressedSms++;
233 unset($form->_contactDetails[$contactId]);
234 continue;
235 }
236 }
237
238 if (isset($mobilePhone)) {
239 $phone = $mobilePhone;
240 }
241 elseif (empty($form->_toContactPhone)) {
242 $phone = $value['phone'];
243 }
244 else {
245 $phone = CRM_Utils_Array::value($key, $form->_toContactPhone);
246 }
247
248 if ($phone) {
249 $toArray[] = array(
b792e485 250 'text' => '"' . $value['sort_name'] . '" (' . $phone . ')',
6a488035
TO
251 'id' => "$contactId::{$phone}",
252 );
253 }
254 }
255
256 if (empty($toArray)) {
257 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'));
258 }
259 }
260
261 //activity related variables
262 if (isset($invalidActivity)) {
263 $form->assign('invalidActivity', $invalidActivity);
264 }
265 if (isset($extendTargetContacts)) {
266 $form->assign('extendTargetContacts', $extendTargetContacts);
267 }
268
6a488035
TO
269 $form->assign('toContact', json_encode($toArray));
270 $form->assign('suppressedSms', $suppressedSms);
271 $form->assign('totalSelectedContacts', count($form->_contactIds));
272
273 $form->add('select', 'sms_provider_id', ts('From'), $providerSelect, TRUE);
274
275 CRM_Mailing_BAO_Mailing::commonCompose($form);
276
277 if ($form->_single) {
278 // also fix the user context stack
279 if ($form->_context) {
280 $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1');
281 }
282 else {
283 $url = CRM_Utils_System::url('civicrm/contact/view',
284 "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity"
285 );
286 }
287
288 $session = CRM_Core_Session::singleton();
289 $session->replaceUserContext($url);
290 $form->addDefaultButtons(ts('Send SMS'), 'upload', 'cancel');
291 }
292 else {
293 $form->addDefaultButtons(ts('Send SMS'), 'upload');
294 }
295
296 $form->addFormRule(array('CRM_Contact_Form_Task_SMSCommon', 'formRule'), $form);
297 }
298
299 /**
fe482240 300 * Form rule.
6a488035 301 *
77c5b619
TO
302 * @param array $fields
303 * The input form values.
6a488035 304 * @param array $dontCare
77c5b619
TO
305 * @param array $self
306 * Additional values form 'this'.
6a488035 307 *
72b3a70c
CW
308 * @return bool|array
309 * true if no errors, else array of errors
6a488035 310 */
00be9182 311 public static function formRule($fields, $dontCare, $self) {
6a488035
TO
312 $errors = array();
313
314 $template = CRM_Core_Smarty::singleton();
315
1e035d58 316 if (empty($fields['sms_text_message'])) {
317 $errors['sms_text_message'] = ts('Please provide Text message.');
6a488035
TO
318 }
319 else {
1e035d58 320 if (!empty($fields['sms_text_message'])) {
321 $messageCheck = CRM_Utils_Array::value('sms_text_message', $fields);
6a488035
TO
322 $messageCheck = str_replace("\r\n", "\n", $messageCheck);
323 if ($messageCheck && (strlen($messageCheck) > CRM_SMS_Provider::MAX_SMS_CHAR)) {
1e035d58 324 $errors['sms_text_message'] = ts("You can configure the SMS message body up to %1 characters", array(1 => CRM_SMS_Provider::MAX_SMS_CHAR));
6a488035
TO
325 }
326 }
327 }
328
329 //Added for CRM-1393
a7488080 330 if (!empty($fields['saveTemplate']) && empty($fields['saveTemplateName'])) {
6a488035
TO
331 $errors['saveTemplateName'] = ts("Enter name to save message template");
332 }
333
334 return empty($errors) ? TRUE : $errors;
335 }
336
337 /**
fe482240 338 * Process the form after the input has been submitted and validated.
6a488035 339 *
c490a46a 340 * @param CRM_Core_Form $form
6a488035 341 */
00be9182 342 public static function postProcess(&$form) {
6a488035
TO
343
344 // check and ensure that
345 $thisValues = $form->controller->exportValues($form->getName());
346
347 $fromSmsProviderId = $thisValues['sms_provider_id'];
348
349 // process message template
8cc574cf 350 if (!empty($thisValues['saveTemplate']) || !empty($thisValues['updateTemplate'])) {
6a488035 351 $messageTemplate = array(
1e035d58 352 'msg_text' => $thisValues['sms_text_message'],
6a488035
TO
353 'is_active' => TRUE,
354 );
355
a7488080 356 if (!empty($thisValues['saveTemplate'])) {
6a488035 357 $messageTemplate['msg_title'] = $thisValues['saveTemplateName'];
c6327d7d 358 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
6a488035
TO
359 }
360
8cc574cf 361 if (!empty($thisValues['template']) && !empty($thisValues['updateTemplate'])) {
6a488035
TO
362 $messageTemplate['id'] = $thisValues['template'];
363 unset($messageTemplate['msg_title']);
c6327d7d 364 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
6a488035
TO
365 }
366 }
367
368 // format contact details array to handle multiple sms from same contact
369 $formattedContactDetails = array();
370 $tempPhones = array();
371
372 foreach ($form->_contactIds as $key => $contactId) {
373 $phone = $form->_toContactPhone[$key];
374
375 if ($phone) {
376 $phoneKey = "{$contactId}::{$phone}";
377 if (!in_array($phoneKey, $tempPhones)) {
378 $tempPhones[] = $phoneKey;
a7488080 379 if (!empty($form->_contactDetails[$contactId])) {
6a488035
TO
380 $formattedContactDetails[] = $form->_contactDetails[$contactId];
381 }
382 }
383 }
384 }
385
386 // $smsParams carries all the arguments provided on form (or via hooks), to the provider->send() method
387 // this gives flexibity to the users / implementors to add their own args via hooks specific to their sms providers
388 $smsParams = $thisValues;
1e035d58 389 unset($smsParams['sms_text_message']);
6a488035 390 $smsParams['provider_id'] = $fromSmsProviderId;
f53ea1ce
DS
391 $contactIds = array_keys($form->_contactDetails);
392 $allContactIds = array_keys($form->_allContactDetails);
6a488035 393
f53ea1ce 394 list($sent, $activityId, $countSuccess) = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails,
6a488035
TO
395 $thisValues,
396 $smsParams,
f53ea1ce 397 $contactIds
6a488035
TO
398 );
399
c5a6413b 400 if ($countSuccess > 0) {
353ffa53
TO
401 CRM_Core_Session::setStatus(ts('One message was sent successfully.', array(
402 'plural' => '%count messages were sent successfully.',
bed98343 403 'count' => $countSuccess,
353ffa53 404 )), ts('Message Sent', array('plural' => 'Messages Sent', 'count' => $countSuccess)), 'success');
6a488035
TO
405 }
406
c5a6413b
DS
407 if (is_array($sent)) {
408 // At least one PEAR_Error object was generated.
409 // Display the error messages to the user.
410 $status = '<ul>';
411 foreach ($sent as $errMsg) {
412 $status .= '<li>' . $errMsg . '</li>';
6a488035 413 }
c5a6413b 414 $status .= '</ul>';
353ffa53
TO
415 CRM_Core_Session::setStatus($status, ts('One Message Not Sent', array(
416 'count' => count($sent),
bed98343 417 'plural' => '%count Messages Not Sent',
353ffa53 418 )), 'info');
0db6c3e1
TO
419 }
420 else {
c5a6413b
DS
421 //Display the name and number of contacts for those sms is not sent.
422 $smsNotSent = array_diff_assoc($allContactIds, $contactIds);
423
424 if (!empty($smsNotSent)) {
425 $not_sent = array();
426 foreach ($smsNotSent as $index => $contactId) {
353ffa53
TO
427 $displayName = $form->_allContactDetails[$contactId]['display_name'];
428 $phone = $form->_allContactDetails[$contactId]['phone'];
c5a6413b
DS
429 $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$contactId");
430 $not_sent[] = "<a href='$contactViewUrl' title='$phone'>$displayName</a>";
431 }
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));
435 }
436 $status .= ')<ul><li>' . implode('</li><li>', $not_sent) . '</li></ul>';
353ffa53
TO
437 CRM_Core_Session::setStatus($status, ts('One Message Not Sent', array(
438 'count' => count($smsNotSent),
bed98343 439 'plural' => '%count Messages Not Sent',
353ffa53 440 )), 'info');
6a488035 441 }
6a488035 442 }
6a488035 443 }
96025800 444
6a488035 445}