Merge pull request #14308 from eileenmcnaughton/uffield
[civicrm-core.git] / CRM / Campaign / Form / Task / Reserve.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
3819f101 35 * This class provides the functionality to add contacts for voter reservation.
6a488035
TO
36 */
37class CRM_Campaign_Form_Task_Reserve extends CRM_Campaign_Form_Task {
38
39 /**
6a488035 40 * @var int
67d19299 41 * Survey id.
6a488035
TO
42 */
43 protected $_surveyId;
44
45 /**
100fef9d 46 * Interviewer id
6a488035
TO
47 *
48 * @var int
49 */
50 protected $_interviewerId;
51
52 /**
100fef9d 53 * Survey details
6a488035
TO
54 *
55 * @var object
56 */
57 protected $_surveyDetails;
58
59 /**
100fef9d 60 * Number of voters
6a488035
TO
61 *
62 * @var int
63 */
64 protected $_numVoters;
65
66 /**
fe482240 67 * Build all the data structures needed to build the form.
6a488035 68 */
00be9182 69 public function preProcess() {
6a488035
TO
70 parent::preProcess();
71
72 //get the survey id from user submitted values.
73 $this->_surveyId = $this->get('surveyId');
74 $this->_interviewerId = $this->get('interviewerId');
75 if (!$this->_surveyId) {
76 CRM_Core_Error::statusBounce(ts("Could not find Survey Id."));
77 }
78 if (!$this->_interviewerId) {
79 CRM_Core_Error::statusBounce(ts("Missing Interviewer contact."));
80 }
81 if (!is_array($this->_contactIds) || empty($this->_contactIds)) {
82 CRM_Core_Error::statusBounce(ts("Could not find contacts for reservation."));
83 }
84
be2fb01f 85 $params = ['id' => $this->_surveyId];
6a488035
TO
86 CRM_Campaign_BAO_Survey::retrieve($params, $this->_surveyDetails);
87
88 //get the survey activities.
89 $activityStatus = CRM_Core_PseudoConstant::activityStatus('name');
be2fb01f
CW
90 $statusIds = [];
91 foreach (['Scheduled'] as $name) {
6a488035
TO
92 if ($statusId = array_search($name, $activityStatus)) {
93 $statusIds[] = $statusId;
94 }
95 }
96
97 // these are the activities count that are linked to the current
98 // interviewer and current survey and not the list of ALL survey activities
99 $this->_numVoters = CRM_Campaign_BAO_Survey::getSurveyActivities($this->_surveyId,
100 $this->_interviewerId,
101 $statusIds,
102 NULL,
103 TRUE
104 );
105 //validate the selected survey.
106 $this->validateSurvey();
107 $this->assign('surveyTitle', $this->_surveyDetails['title']);
108 $this->assign('activityType', $this->_surveyDetails['activity_type_id']);
109 $this->assign('surveyId', $this->_surveyId);
110
111 //append breadcrumb to survey dashboard.
112 if (CRM_Campaign_BAO_Campaign::accessCampaign()) {
113 $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey');
be2fb01f 114 CRM_Utils_System::appendBreadCrumb([['title' => ts('Survey(s)'), 'url' => $url]]);
6a488035
TO
115 }
116
117 //set the title.
118 CRM_Utils_System::setTitle(ts('Reserve Respondents'));
119 }
120
00be9182 121 public function validateSurvey() {
6a488035
TO
122 $errorMsg = NULL;
123 $maxVoters = CRM_Utils_Array::value('max_number_of_contacts', $this->_surveyDetails);
124 if ($maxVoters) {
125 if ($maxVoters <= $this->_numVoters) {
126 $errorMsg = ts('The maximum number of contacts is already reserved for this interviewer.');
127 }
128 elseif (count($this->_contactIds) > ($maxVoters - $this->_numVoters)) {
99483ce8 129 $errorMsg = ts('You can reserve a maximum of %count contact at a time for this survey.',
be2fb01f 130 [
99483ce8
CW
131 'plural' => 'You can reserve a maximum of %count contacts at a time for this survey.',
132 'count' => $maxVoters - $this->_numVoters,
be2fb01f 133 ]
6a488035
TO
134 );
135 }
136 }
137
138 $defaultNum = CRM_Utils_Array::value('default_number_of_contacts', $this->_surveyDetails);
139 if (!$errorMsg && $defaultNum && (count($this->_contactIds) > $defaultNum)) {
99483ce8 140 $errorMsg = ts('You can reserve a maximum of %count contact at a time for this survey.',
be2fb01f 141 [
99483ce8
CW
142 'plural' => 'You can reserve a maximum of %count contacts at a time for this survey.',
143 'count' => $defaultNum,
be2fb01f 144 ]
6a488035
TO
145 );
146 }
147
148 if ($errorMsg) {
149 CRM_Core_Error::statusBounce($errorMsg);
150 }
151 }
152
153 /**
fe482240 154 * Build the form object.
6a488035 155 */
00be9182 156 public function buildQuickForm() {
6a488035
TO
157 // allow to add contact to either new or existing group.
158 $this->addElement('text', 'ActivityType', ts('Activity Type'));
159 $this->addElement('text', 'newGroupName', ts('Name for new group'));
160 $this->addElement('text', 'newGroupDesc', ts('Description of new group'));
24431f7b 161 $groups = CRM_Core_PseudoConstant::nestedGroup();
6a488035
TO
162 $hasExistingGroups = FALSE;
163 if (is_array($groups) && !empty($groups)) {
164 $hasExistingGroups = TRUE;
165 $this->addElement('select', 'groups', ts('Add respondent(s) to existing group(s)'),
be2fb01f 166 $groups, ['multiple' => "multiple", 'class' => 'crm-select2']
6a488035
TO
167 );
168 }
169 $this->assign('hasExistingGroups', $hasExistingGroups);
170
be2fb01f
CW
171 $buttons = [
172 [
353ffa53 173 'type' => 'done',
6a488035
TO
174 'name' => ts('Reserve'),
175 'subName' => 'reserve',
176 'isDefault' => TRUE,
be2fb01f
CW
177 ],
178 ];
6a488035
TO
179
180 if (CRM_Core_Permission::check('manage campaign') ||
181 CRM_Core_Permission::check('administer CiviCampaign') ||
182 CRM_Core_Permission::check('interview campaign contacts')
183 ) {
be2fb01f 184 $buttons[] = [
6a488035
TO
185 'type' => 'next',
186 'name' => ts('Reserve and Interview'),
187 'subName' => 'reserveToInterview',
be2fb01f 188 ];
6a488035 189 }
be2fb01f 190 $buttons[] = [
6a488035
TO
191 'type' => 'back',
192 'name' => ts('Cancel'),
be2fb01f 193 ];
6a488035
TO
194
195 $this->addButtons($buttons);
be2fb01f 196 $this->addFormRule(['CRM_Campaign_Form_Task_Reserve', 'formRule'], $this);
6a488035
TO
197 }
198
199 /**
fe482240 200 * Global validation rules for the form.
6a488035 201 *
7aaf6db0
TO
202 * @param array $fields
203 * Posted values of the form.
6a488035 204 *
da6b46f4
EM
205 * @param $files
206 * @param $self
207 *
a6c01b45
CW
208 * @return array
209 * list of errors to be posted back to the form
6a488035 210 */
00be9182 211 public static function formRule($fields, $files, $self) {
be2fb01f 212 $errors = [];
6a488035 213 $invalidGroupName = FALSE;
a7488080 214 if (!empty($fields['newGroupName'])) {
353ffa53
TO
215 $title = trim($fields['newGroupName']);
216 $name = CRM_Utils_String::titleToVar($title);
217 $query = 'select count(*) from civicrm_group where name like %1 OR title like %2';
be2fb01f
CW
218 $grpCnt = CRM_Core_DAO::singleValueQuery($query, [
219 1 => [$name, 'String'],
220 2 => [$title, 'String'],
221 ]);
6a488035
TO
222 if ($grpCnt) {
223 $invalidGroupName = TRUE;
be2fb01f 224 $errors['newGroupName'] = ts('Group \'%1\' already exists.', [1 => $fields['newGroupName']]);
6a488035
TO
225 }
226 }
227 $self->assign('invalidGroupName', $invalidGroupName);
228
229 return empty($errors) ? TRUE : $errors;
230 }
231
232 /**
fe482240 233 * Process the form after the input has been submitted and validated.
67d19299 234 */
6a488035
TO
235 public function postProcess() {
236 //add reservation.
353ffa53
TO
237 $countVoters = 0;
238 $maxVoters = CRM_Utils_Array::value('max_number_of_contacts', $this->_surveyDetails);
6a488035 239 $activityStatus = CRM_Core_PseudoConstant::activityStatus('name');
353ffa53 240 $statusHeld = array_search('Scheduled', $activityStatus);
6a488035 241
be2fb01f 242 $reservedVoterIds = [];
6a488035 243 foreach ($this->_contactIds as $cid) {
58438e5b 244 $subject = $this->_surveyDetails['title'] . ' - ' . ts('Respondent Reservation');
353ffa53 245 $session = CRM_Core_Session::singleton();
be2fb01f 246 $activityParams = [
353ffa53 247 'source_contact_id' => $session->get('userID'),
be2fb01f
CW
248 'assignee_contact_id' => [$this->_interviewerId],
249 'target_contact_id' => [$cid],
6a488035
TO
250 'source_record_id' => $this->_surveyId,
251 'activity_type_id' => $this->_surveyDetails['activity_type_id'],
252 'subject' => $subject,
253 'activity_date_time' => date('YmdHis'),
254 'status_id' => $statusHeld,
255 'skipRecentView' => 1,
256 'campaign_id' => CRM_Utils_Array::value('campaign_id', $this->_surveyDetails),
be2fb01f 257 ];
6a488035
TO
258 $activity = CRM_Activity_BAO_Activity::create($activityParams);
259 if ($activity->id) {
260 $countVoters++;
261 $reservedVoterIds[$cid] = $cid;
262 }
263 if ($maxVoters && ($maxVoters <= ($this->_numVoters + $countVoters))) {
264 break;
265 }
266 }
267
268 //add reserved voters to groups.
269 $groupAdditions = $this->_addRespondentToGroup($reservedVoterIds);
270
271 // Success message
272 if ($countVoters > 0) {
be2fb01f 273 $status = '<p>' . ts("%count contact has been reserved.", ['plural' => '%count contacts have been reserved.', 'count' => $countVoters]) . '</p>';
6a488035 274 if ($groupAdditions) {
99483ce8 275 $status .= '<p>' . ts('They have been added to %1.',
be2fb01f 276 [1 => implode(' ' . ts('and') . ' ', $groupAdditions)]
353ffa53 277 ) . '</p>';
6a488035
TO
278 }
279 CRM_Core_Session::setStatus($status, ts('Reservation Added'), 'success');
280 }
281 // Error message
282 if (count($this->_contactIds) > $countVoters) {
99483ce8 283 CRM_Core_Session::setStatus(ts('Reservation did not add for %count contact.',
be2fb01f 284 [
99483ce8
CW
285 'plural' => 'Reservation did not add for %count contacts.',
286 'count' => (count($this->_contactIds) - $countVoters),
be2fb01f 287 ]
6a488035
TO
288 ), ts('Notice'));
289 }
290
291 //get ready to jump to voter interview form.
292 $buttonName = $this->controller->getButtonName();
293 if (!empty($reservedVoterIds) &&
294 $buttonName == '_qf_Reserve_next_reserveToInterview'
295 ) {
296 $this->controller->set('surveyId', $this->_surveyId);
297 $this->controller->set('contactIds', $reservedVoterIds);
298 $this->controller->set('interviewerId', $this->_interviewerId);
299 $this->controller->set('reserveToInterview', TRUE);
300 }
301 }
302
30c4e065
EM
303 /**
304 * @param $contactIds
305 *
306 * @return array
307 */
6a488035 308 private function _addRespondentToGroup($contactIds) {
be2fb01f 309 $groupAdditions = [];
6a488035
TO
310 if (empty($contactIds)) {
311 return $groupAdditions;
312 }
313
353ffa53 314 $params = $this->controller->exportValues($this->_name);
be2fb01f 315 $groups = CRM_Utils_Array::value('groups', $params, []);
6a488035
TO
316 $newGroupName = CRM_Utils_Array::value('newGroupName', $params);
317 $newGroupDesc = CRM_Utils_Array::value('newGroupDesc', $params);
318
319 $newGroupId = NULL;
320 //create new group.
321 if ($newGroupName) {
be2fb01f 322 $grpParams = [
6a488035
TO
323 'title' => $newGroupName,
324 'description' => $newGroupDesc,
325 'is_active' => TRUE,
be2fb01f 326 ];
6a488035
TO
327 $group = CRM_Contact_BAO_Group::create($grpParams);
328 $groups[] = $newGroupId = $group->id;
329 }
330
331 //add the respondents to groups.
332 if (is_array($groups)) {
333 $existingGroups = CRM_Core_PseudoConstant::group();
334 foreach ($groups as $groupId) {
335 $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId);
336 $totalCount = CRM_Utils_Array::value(1, $addCount);
337 if ($groupId == $newGroupId) {
338 $name = $newGroupName;
339 $new = TRUE;
340 }
341 else {
342 $name = $existingGroups[$groupId];
343 $new = FALSE;
344 }
345 if ($totalCount) {
346 $url = CRM_Utils_System::url('civicrm/group/search',
347 'reset=1&force=1&context=smog&gid=' . $groupId
348 );
349 $groupAdditions[] = '<a href="' . $url . '">' . $name . '</a>';
350 }
351 }
352 }
353
354 return $groupAdditions;
355 }
96025800 356
6a488035 357}