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