CRM-18547 keep group context when marking dupes
[civicrm-core.git] / CRM / Contact / Form / Merge.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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035
TO
32 */
33
86538308 34/**
5a409b50 35 * Class CRM_Contact_Form_Merge.
86538308 36 */
6a488035
TO
37class CRM_Contact_Form_Merge extends CRM_Core_Form {
38 // the id of the contact that tere's a duplicate for; this one will
39 // possibly inherit some of $_oid's properties and remain in the system
40 var $_cid = NULL;
41
42 // the id of the other contact - the duplicate one that will get deleted
43 var $_oid = NULL;
44
45 var $_contactType = NULL;
46
6a488035
TO
47 // FIXME: QuickForm can't create advcheckboxes with value set to 0 or '0' :(
48 // see HTML_QuickForm_advcheckbox::setValues() - but patching that doesn't
49 // help, as QF doesn't put the 0-value elements in exportValues() anyway...
50 // to side-step this, we use the below UUID as a (re)placeholder
8ef12e64 51 var $_qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9';
52
00be9182 53 public function preProcess() {
6a488035
TO
54 if (!CRM_Core_Permission::check('merge duplicate contacts')) {
55 CRM_Core_Error::fatal(ts('You do not have access to this page'));
56 }
57
58 $rows = array();
353ffa53
TO
59 $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
60 $oid = CRM_Utils_Request::retrieve('oid', 'Positive', $this, TRUE);
6a488035
TO
61 $flip = CRM_Utils_Request::retrieve('flip', 'Positive', $this, FALSE);
62
e9299e88 63 $this->_rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE);
353ffa53 64 $this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE);
6a488035
TO
65 $this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE);
66
6d5a3f21
CW
67 // Sanity check
68 if ($cid == $oid) {
69 CRM_Core_Error::statusBounce(ts('Cannot merge a contact with itself.'));
70 }
71
6a488035 72 if (!CRM_Dedupe_BAO_Rule::validateContacts($cid, $oid)) {
cce70162 73 CRM_Core_Error::statusBounce(ts('The selected pair of contacts are marked as non duplicates. If these records should be merged, you can remove this exception on the <a href="%1">Dedupe Exceptions</a> page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1'))));
6a488035 74 }
e9299e88 75 $this->_contactType = civicrm_api3('Contact', 'getvalue', array('id' => $cid, 'return' => 'contact_type'));
4e052b22 76 $isFromDedupeScreen = TRUE;
e9299e88 77 if (!$this->_rgid) {
4e052b22 78 $isFromDedupeScreen = FALSE;
e9299e88 79 $this->_rgid = civicrm_api3('RuleGroup', 'getvalue', array(
80 'contact_type' => $this->_contactType,
81 'used' => 'Supervised',
82 'return' => 'id',
83 ));
84 }
6a488035 85
e9299e88 86 $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid);
2ae26001 87
88 $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
6a488035
TO
89 $where = "de.id IS NULL";
90
91 $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $cid, $oid, $this->_mergeId, $join, $where, $flip);
92
93 // Block access if user does not have EDIT permissions for both contacts.
94 if (!(CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT) &&
353ffa53
TO
95 CRM_Contact_BAO_Contact_Permission::allow($oid, CRM_Core_Permission::EDIT)
96 )
97 ) {
6a488035
TO
98 CRM_Utils_System::permissionDenied();
99 }
100
101 // get user info of main contact.
102 $config = CRM_Core_Config::singleton();
103 $config->doNotResetCache = 1;
104
105 $viewUser = CRM_Core_Permission::check('access user profiles');
106 $mainUfId = CRM_Core_BAO_UFMatch::getUFId($cid);
107 $mainUser = NULL;
108 if ($mainUfId) {
109 // d6 compatible
110 if ($config->userSystem->is_drupal == '1') {
111 $mainUser = user_load($mainUfId);
112 }
113 elseif ($config->userFramework == 'Joomla') {
114 $mainUser = JFactory::getUser($mainUfId);
115 }
116
117 $this->assign('mainUfId', $mainUfId);
118 $this->assign('mainUfName', $mainUser ? $mainUser->name : NULL);
119 }
120
395d8dc6 121 $flipUrl = CRM_Utils_System::url('civicrm/contact/merge',
e9299e88 122 "reset=1&action=update&cid={$oid}&oid={$cid}&rgid={$this->_rgid}&gid={$gid}"
6a488035
TO
123 );
124 if (!$flip) {
125 $flipUrl .= '&flip=1';
126 }
127 $this->assign('flip', $flipUrl);
128
129 $this->prev = $this->next = NULL;
130 foreach (array(
353ffa53 131 'prev',
389bcebf 132 'next',
353ffa53 133 ) as $position) {
6a488035
TO
134 if (!empty($pos[$position])) {
135 if ($pos[$position]['id1'] && $pos[$position]['id2']) {
136 $urlParam = "reset=1&cid={$pos[$position]['id1']}&oid={$pos[$position]['id2']}&mergeId={$pos[$position]['mergeId']}&action=update";
137
e9299e88 138 if ($this->_rgid) {
139 $urlParam .= "&rgid={$this->_rgid}";
6a488035
TO
140 }
141 if ($gid) {
142 $urlParam .= "&gid={$gid}";
143 }
144
395d8dc6 145 $this->$position = CRM_Utils_System::url('civicrm/contact/merge', $urlParam);
6a488035
TO
146 $this->assign($position, $this->$position);
147 }
148 }
149 }
150
151 // get user info of other contact.
152 $otherUfId = CRM_Core_BAO_UFMatch::getUFId($oid);
153 $otherUser = NULL;
154
155 if ($otherUfId) {
156 // d6 compatible
157 if ($config->userSystem->is_drupal == '1') {
158 $otherUser = user_load($otherUfId);
159 }
160 elseif ($config->userFramework == 'Joomla') {
161 $otherUser = JFactory::getUser($otherUfId);
162 }
163
164 $this->assign('otherUfId', $otherUfId);
165 $this->assign('otherUfName', $otherUser ? $otherUser->name : NULL);
166 }
167
168 $cmsUser = ($mainUfId && $otherUfId) ? TRUE : FALSE;
169 $this->assign('user', $cmsUser);
170
171 $session = CRM_Core_Session::singleton();
172
173 // context fixed.
4e052b22 174 if ($isFromDedupeScreen) {
e9299e88 175 $urlParam = "reset=1&action=browse&rgid={$this->_rgid}";
6a488035
TO
176 if ($gid) {
177 $urlParam .= "&gid={$gid}";
178 }
4e052b22 179 $browseUrl = CRM_Utils_System::url('civicrm/contact/dedupefind', $urlParam);
180 $session->pushUserContext($browseUrl);
6a488035 181 }
4e052b22 182 $this->assign('browseUrl', empty($browseUrl) ? '' : $browseUrl);
6a488035
TO
183
184 // ensure that oid is not the current user, if so refuse to do the merge
185 if ($session->get('userID') == $oid) {
186 $display_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $oid, 'display_name');
187 $message = ts('The contact record which is linked to the currently logged in user account - \'%1\' - cannot be deleted.',
188 array(1 => $display_name)
189 );
190 CRM_Core_Error::statusBounce($message);
191 }
192
193 $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($cid, $oid);
471ec338
BS
194 $main = $this->_mainDetails = &$rowsElementsAndInfo['main_details'];
195 $other = $this->_otherDetails = &$rowsElementsAndInfo['other_details'];
6a488035
TO
196
197 if ($main['contact_id'] != $cid) {
198 CRM_Core_Error::fatal(ts('The main contact record does not exist'));
199 }
200
201 if ($other['contact_id'] != $oid) {
202 CRM_Core_Error::fatal(ts('The other contact record does not exist'));
203 }
204
6a488035 205 $this->assign('contact_type', $main['contact_type']);
6a488035
TO
206 $this->assign('main_name', $main['display_name']);
207 $this->assign('other_name', $other['display_name']);
208 $this->assign('main_cid', $main['contact_id']);
209 $this->assign('other_cid', $other['contact_id']);
e9299e88 210 $this->assign('rgid', $this->_rgid);
6a488035 211
353ffa53
TO
212 $this->_cid = $cid;
213 $this->_oid = $oid;
e9299e88 214
d664f648 215 $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('class' => 'select-rows'));
6a488035 216
bf43eaac
J
217 $this->assign('mainLocBlock', json_encode($rowsElementsAndInfo['main_details']['location_blocks']));
218 $this->assign('locationBlockInfo', json_encode(CRM_Dedupe_Merger::getLocationBlockInfo()));
6a488035
TO
219 $this->assign('rows', $rowsElementsAndInfo['rows']);
220
6a488035
TO
221 // add elements
222 foreach ($rowsElementsAndInfo['elements'] as $element) {
223 $this->addElement($element[0],
224 $element[1],
225 array_key_exists('2', $element) ? $element[2] : NULL,
226 array_key_exists('3', $element) ? $element[3] : NULL,
227 array_key_exists('4', $element) ? $element[4] : NULL,
228 array_key_exists('5', $element) ? $element[5] : NULL
229 );
230 }
231
232 // add related table elements
233 foreach ($rowsElementsAndInfo['rel_table_elements'] as $relTableElement) {
234 $element = $this->addElement($relTableElement[0], $relTableElement[1]);
235 $element->setChecked(TRUE);
236 }
237
238 $this->assign('rel_tables', $rowsElementsAndInfo['rel_tables']);
239 $this->assign('userContextURL', $session->readUserContext());
240 }
241
86538308
EM
242 /**
243 * This virtual function is used to set the default values of
244 * various form elements
245 *
246 * access public
247 *
a6c01b45
CW
248 * @return array
249 * reference to the array of default values
86538308
EM
250 */
251 /**
252 * @return array
253 */
00be9182 254 public function setDefaultValues() {
6a488035
TO
255 return array('deleteOther' => 1);
256 }
257
6ea503d4
TO
258 public function addRules() {
259 }
6a488035
TO
260
261 public function buildQuickForm() {
d5be719d 262 CRM_Utils_System::setTitle(ts('Merge %1 contacts', array(1 => $this->_contactType)));
fd66df85
CW
263 $buttons = array();
264
265 $buttons[] = array(
266 'type' => 'next',
3709190a 267 'name' => $this->next ? ts('Merge and go to Next Pair') : ts('Merge'),
fd66df85
CW
268 'isDefault' => TRUE,
269 'icon' => $this->next ? 'circle-triangle-e' : 'check',
270 );
6a488035
TO
271
272 if ($this->next || $this->prev) {
fd66df85
CW
273 $buttons[] = array(
274 'type' => 'submit',
3709190a 275 'name' => ts('Merge and go to Listing'),
6a488035 276 );
fd66df85
CW
277 $buttons[] = array(
278 'type' => 'done',
279 'name' => ts('Merge and View Result'),
0291a521 280 'icon' => 'fa-check-circle',
6a488035
TO
281 );
282 }
283
fd66df85
CW
284 $buttons[] = array(
285 'type' => 'cancel',
286 'name' => ts('Cancel'),
287 );
288
289 $this->addButtons($buttons);
4b87bd02 290 $this->addFormRule(array('CRM_Contact_Form_Merge', 'formRule'), $this);
291 }
292
86538308
EM
293 /**
294 * @param $fields
295 * @param $files
296 * @param $self
297 *
298 * @return array
299 */
00be9182 300 public static function formRule($fields, $files, $self) {
4b87bd02 301 $errors = array();
0653585f 302 $link = CRM_Utils_System::href(ts('Flip between the original and duplicate contacts.'),
b74201e4 303 'civicrm/contact/merge',
304 'reset=1&action=update&cid=' . $self->_oid . '&oid=' . $self->_cid . '&rgid=' . $self->_rgid . '&flip=1'
305 );
4b87bd02 306 if (CRM_Contact_BAO_Contact::checkDomainContact($self->_oid)) {
0653585f 307 $errors['_qf_default'] = ts("The Default Organization contact cannot be merged into another contact record. It is associated with the CiviCRM installation for this domain and contains information used for system functions. If you want to merge these records, you can: %1", array(1 => $link));
4b87bd02 308 }
309 return $errors;
6a488035
TO
310 }
311
312 public function postProcess() {
313 $formValues = $this->exportValues();
8ef12e64 314
6a488035
TO
315 // reset all selected contact ids from session
316 // when we came from search context, CRM-3526
317 $session = CRM_Core_Session::singleton();
318 if ($session->get('selectedSearchContactIds')) {
319 $session->resetScope('selectedSearchContactIds');
320 }
321
471ec338
BS
322 $formValues['main_details'] = $this->_mainDetails;
323 $formValues['other_details'] = $this->_otherDetails;
6a488035
TO
324
325 CRM_Dedupe_Merger::moveAllBelongings($this->_cid, $this->_oid, $formValues);
326
7b99ead3
CW
327 $name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_cid, 'display_name');
328 $message = '<ul><li>' . ts('%1 has been updated.', array(1 => $name)) . '</li><li>' . ts('Contact ID %1 has been deleted.', array(1 => $this->_oid)) . '</li></ul>';
329 CRM_Core_Session::setStatus($message, ts('Contacts Merged'), 'success');
330
6a488035 331 $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_cid}");
a7488080 332 if (!empty($formValues['_qf_Merge_submit'])) {
6a488035
TO
333 $listParamsURL = "reset=1&action=update&rgid={$this->_rgid}";
334 if ($this->_gid) {
335 $listParamsURL .= "&gid={$this->_gid}";
336 }
337 $lisitingURL = CRM_Utils_System::url('civicrm/contact/dedupefind',
338 $listParamsURL
339 );
340 CRM_Utils_System::redirect($lisitingURL);
341 }
353ffa53 342 if (!empty($formValues['_qf_Merge_done'])) {
6a488035
TO
343 CRM_Utils_System::redirect($url);
344 }
345
346 if ($this->next && $this->_mergeId) {
2ae26001 347 $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid);
6a488035 348
2ae26001 349 $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
6a488035
TO
350 $where = "de.id IS NULL";
351
352 $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, NULL, NULL, $this->_mergeId, $join, $where);
353
354 if (!empty($pos) &&
355 $pos['next']['id1'] &&
356 $pos['next']['id2']
357 ) {
358
359 $urlParam = "reset=1&cid={$pos['next']['id1']}&oid={$pos['next']['id2']}&mergeId={$pos['next']['mergeId']}&action=update";
360 if ($this->_rgid) {
361 $urlParam .= "&rgid={$this->_rgid}";
362 }
363 if ($this->_gid) {
364 $urlParam .= "&gid={$this->_gid}";
365 }
366
395d8dc6 367 $url = CRM_Utils_System::url('civicrm/contact/merge', $urlParam);
6a488035
TO
368 }
369 }
370
371 CRM_Utils_System::redirect($url);
372 }
96025800 373
6a488035 374}