Merge pull request #496 from kurund/gen-data
[civicrm-core.git] / CRM / Contact / Form / Task / SMSCommon.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36/**
37 * This class provides the common functionality for sending sms to
38 * one or a group of contact ids.
39 */
40class CRM_Contact_Form_Task_SMSCommon {
41 CONST RECIEVED_SMS_ACTIVITY_SUBJECT = "SMS Received";
42
43 public $_contactDetails = array();
44
45 public $_allContactDetails = array();
46
47 public $_toContactPhone = array();
48
49
50 static function preProcessProvider(&$form) {
51 $form->_single = FALSE;
52 $className = CRM_Utils_System::getClassName($form);
53
54 if (property_exists($form, '_context') &&
55 $form->_context != 'search' &&
56 $className == 'CRM_Contact_Form_Task_SMS'
57 ) {
58 $form->_single = TRUE;
59 }
60
61 $providersCount = CRM_SMS_BAO_Provider::activeProviderCount();
62
63 if (!$providersCount) {
64 CRM_Core_Error::statusBounce(ts('There are no SMS providers configured, or no SMS providers are set active'));
65 }
66
67 if ($className == 'CRM_Activity_Form_Task_SMS') {
68 $activityCheck = 0;
69 foreach ($form->_activityHolderIds as $value) {
70 if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $value, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) {
71 $activityCheck++;
72 }
73 }
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)
77 ));
78 }
79 }
80 }
81
82 /**
83 * Build the form
84 *
85 * @access public
86 *
87 * @return void
88 */
89 static function buildQuickForm(&$form) {
90
91 $toArray = array();
92
93 $form->assign('max_sms_length', CRM_SMS_Provider::MAX_SMS_CHAR);
94
95 $providers = CRM_SMS_BAO_Provider::getProviders(NULL, NULL, TRUE, 'is_default desc');
96
97 $providerSelect = array();
98 foreach ($providers as $provider) {
99 $providerSelect[$provider['id']] = $provider['title'];
100 }
101 $suppressedSms = 0;
102 //here we are getting logged in user id as array but we need target contact id. CRM-5988
103 $cid = $form->get('cid');
104
105 if ($cid) {
106 $form->_contactIds = array($cid);
107 }
108
109 $to = $form->add('text', 'to', ts('To'), '', TRUE);
110 $form->add('text', 'activity_subject', ts('Name The SMS'), '', TRUE);
111
112 $toSetDefault = TRUE;
113 if (property_exists($form, '_context') && $form->_context == 'standalone') {
114 $toSetDefault = FALSE;
115 }
116
117 // when form is submitted recompute contactIds
118 $allToSMS = array();
119 if ($to->getValue()) {
120 $allToPhone = explode(',', $to->getValue());
121
122 $form->_contactIds = array();
123 foreach ($allToPhone as $value) {
124 list($contactId, $phone) = explode('::', $value);
125 if ($contactId) {
126 $form->_contactIds[] = $contactId;
127 $form->_toContactPhone[] = $phone;
128 }
129 }
130 $toSetDefault = TRUE;
131 }
132
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) {
141 $invalidActivity++;
142 continue;
143 }
144
145 //target contacts limit check
146 $ids = array_keys(CRM_Activity_BAO_ActivityTarget::getTargetNames($id));
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(
160 'count' => $extendTargetContacts,
161 'plural' => '%count selected activities consist of more than one target contact.'));
162 }
163 if ($invalidActivity) {
164 $errorMess = ($errorMess ? ' ' : '');
165 $errorMess .= ts('The selected activity is invalid.', array(
166 'count' => $invalidActivity,
167 'plural' => '%count selected activities are invalid.'));
168 }
169 CRM_Core_Error::statusBounce(ts("%1: SMS Reply will not be sent.", array(1 => $errorMess)));
170 }
171 }
172
173 if (is_array($form->_contactIds) && $toSetDefault) {
174 $returnProperties = array(
175 'sort_name' => 1,
176 'phone' => 1,
177 'do_not_sms' => 1,
178 'is_deceased' => 1,
179 'display_name' => 1,
180 );
181
182 list($form->_contactDetails) = CRM_Utils_Token::getTokenDetails($form->_contactIds,
183 $returnProperties,
184 FALSE,
185 FALSE
186 );
187
188 // make a copy of all contact details
189 $form->_allContactDetails = $form->_contactDetails;
190
191 foreach ($form->_contactIds as $key => $contactId) {
192 $value = $form->_contactDetails[$contactId];
193
194 //to check if the phone type is "Mobile"
195 $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name');
196
197 if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') {
198 //to check for "if the contact id belongs to a specified activity type"
199 $actDetails = CRM_Activity_BAO_Activity::getContactActivity($contactId);
200 if (self::RECIEVED_SMS_ACTIVITY_SUBJECT !=
201 CRM_Utils_Array::retrieveValueRecursive($actDetails, 'subject')
202 ) {
203 $suppressedSms++;
204 unset($form->_contactDetails[$contactId]);
205 continue;
206 }
207 }
208
209 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)) {
210
211 //if phone is not primary check if non-primary phone is "Mobile"
212 if (!empty($value['phone'])
213 && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes)
214 && !CRM_Utils_Array::value('is_deceased', $value)
215 ) {
216 $filter = array('do_not_sms' => 0);
217 $contactPhones = CRM_Core_BAO_Phone::allPhones($contactId, FALSE, 'Mobile', $filter);
218 if (count($contactPhones) > 0) {
219 $mobilePhone = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'phone');
220 $form->_contactDetails[$contactId]['phone_id'] = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'id');
221 $form->_contactDetails[$contactId]['phone'] = $mobilePhone;
222 $form->_contactDetails[$contactId]['phone_type_id'] = CRM_Utils_Array::value('Mobile', $phoneTypes);
223 }
224 else {
225 $suppressedSms++;
226 unset($form->_contactDetails[$contactId]);
227 continue;
228 }
229 }
230 else {
231 $suppressedSms++;
232 unset($form->_contactDetails[$contactId]);
233 continue;
234 }
235 }
236
237 if (isset($mobilePhone)) {
238 $phone = $mobilePhone;
239 }
240 elseif (empty($form->_toContactPhone)) {
241 $phone = $value['phone'];
242 }
243 else {
244 $phone = CRM_Utils_Array::value($key, $form->_toContactPhone);
245 }
246
247 if ($phone) {
248 $toArray[] = array(
249 'name' => '"' . $value['sort_name'] . '" &lt;' . $phone . '&gt;',
250 'id' => "$contactId::{$phone}",
251 );
252 }
253 }
254
255 if (empty($toArray)) {
256 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'));
257 }
258 }
259
260 //activity related variables
261 if (isset($invalidActivity)) {
262 $form->assign('invalidActivity', $invalidActivity);
263 }
264 if (isset($extendTargetContacts)) {
265 $form->assign('extendTargetContacts', $extendTargetContacts);
266 }
267
268
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 /**
300 * form rule
301 *
302 * @param array $fields the input form values
303 * @param array $dontCare
304 * @param array $self additional values form 'this'
305 *
306 * @return true if no errors, else array of errors
307 * @access public
308 *
309 */
310 static function formRule($fields, $dontCare, $self) {
311 $errors = array();
312
313 $template = CRM_Core_Smarty::singleton();
314
315 if (!CRM_Utils_Array::value('text_message', $fields)) {
316 $errors['text_message'] = ts('Please provide Text message.');
317 }
318 else {
319 if (CRM_Utils_Array::value('text_message', $fields)) {
320 $messageCheck = CRM_Utils_Array::value('text_message', $fields);
321 $messageCheck = str_replace("\r\n", "\n", $messageCheck);
322 if ($messageCheck && (strlen($messageCheck) > CRM_SMS_Provider::MAX_SMS_CHAR)) {
323 $errors['text_message'] = ts("You can configure the SMS message body up to %1 characters", array(1 => CRM_SMS_Provider::MAX_SMS_CHAR));
324 }
325 }
326 }
327
328 //Added for CRM-1393
329 if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) {
330 $errors['saveTemplateName'] = ts("Enter name to save message template");
331 }
332
333 return empty($errors) ? TRUE : $errors;
334 }
335
336 /**
337 * process the form after the input has been submitted and validated
338 *
339 * @access public
340 *
341 * @return None
342 */
343 static function postProcess(&$form) {
344
345 // check and ensure that
346 $thisValues = $form->controller->exportValues($form->getName());
347
348 $fromSmsProviderId = $thisValues['sms_provider_id'];
349
350 // process message template
351 if (CRM_Utils_Array::value('saveTemplate', $thisValues)
352 || CRM_Utils_Array::value('updateTemplate', $thisValues)
353 ) {
354 $messageTemplate = array(
355 'msg_text' => $thisValues['text_message'],
356 'is_active' => TRUE,
357 );
358
359 if (CRM_Utils_Array::value('saveTemplate', $thisValues)) {
360 $messageTemplate['msg_title'] = $thisValues['saveTemplateName'];
361 CRM_Core_BAO_MessageTemplates::add($messageTemplate);
362 }
363
364 if (CRM_Utils_Array::value('template', $thisValues) &&
365 CRM_Utils_Array::value('updateTemplate', $thisValues)
366 ) {
367 $messageTemplate['id'] = $thisValues['template'];
368 unset($messageTemplate['msg_title']);
369 CRM_Core_BAO_MessageTemplates::add($messageTemplate);
370 }
371 }
372
373 // format contact details array to handle multiple sms from same contact
374 $formattedContactDetails = array();
375 $tempPhones = array();
376
377 foreach ($form->_contactIds as $key => $contactId) {
378 $phone = $form->_toContactPhone[$key];
379
380 if ($phone) {
381 $phoneKey = "{$contactId}::{$phone}";
382 if (!in_array($phoneKey, $tempPhones)) {
383 $tempPhones[] = $phoneKey;
384 if (CRM_Utils_Array::value($contactId, $form->_contactDetails)) {
385 $formattedContactDetails[] = $form->_contactDetails[$contactId];
386 }
387 }
388 }
389 }
390
391 // $smsParams carries all the arguments provided on form (or via hooks), to the provider->send() method
392 // this gives flexibity to the users / implementors to add their own args via hooks specific to their sms providers
393 $smsParams = $thisValues;
394 unset($smsParams['text_message']);
395 $smsParams['provider_id'] = $fromSmsProviderId;
396
397 list($sent, $activityId) = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails,
398 $thisValues,
399 $smsParams,
400 array_keys($form->_contactDetails)
401 );
402
403 if ($sent) {
404 $count_success = count($form->_contactDetails);
405 CRM_Core_Session::setStatus(ts('One message was sent successfully.', array('plural' => '%count messages were sent successfully.', 'count' => $count_success)), ts('Message Sent', array('plural' => 'Messages Sent', 'count' => $count_success)), 'success');
406 }
407
408 //Display the name and number of contacts for those sms is not sent.
409 $smsNotSent = array_diff_assoc($form->_allContactDetails, $form->_contactDetails);
410
411 if (!empty($smsNotSent)) {
412 $not_sent = array();
413 foreach ($smsNotSent as $contactId => $values) {
414 $displayName = $values['display_name'];
415 $phone = $values['phone'];
416 $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$contactId");
417 $not_sent[] = "<a href='$contactViewUrl' title='$phone'>$displayName</a>";
418 }
419 $status = '(' . ts('because no phone number on file or communication preferences specify DO NOT SMS or Contact is deceased');
420 if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') {
421 $status .= ' ' . ts("or the contact is not part of the activity '%1'", array(1 => self::RECIEVED_SMS_ACTIVITY_SUBJECT));
422 }
423 $status .= ')<ul><li>' . implode('</li><li>', $not_sent) . '</li></ul>';
424 CRM_Core_Session::setStatus($status, ts('One Message Not Sent', array('count' => count($smsNotSent), 'plural' => '%count Messages Not Sent')), 'info');
425 }
426
427 }
428}
429