diff --git a/CRM/Contact/Form/Merge.php b/CRM/Contact/Form/Merge.php index ad9a8e6563dc..9445834f0a7c 100644 --- a/CRM/Contact/Form/Merge.php +++ b/CRM/Contact/Form/Merge.php @@ -78,24 +78,25 @@ public function preProcess() { $this->limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this, FALSE); $urlParams = "reset=1&rgid={$this->_rgid}&gid={$this->_gid}&limit=" . $this->limit; - // Sanity check - if ($cid == $oid) { - CRM_Core_Error::statusBounce(ts('Cannot merge a contact with itself.')); - } + $this->bounceIfInvalid($cid, $oid); - if (!CRM_Dedupe_BAO_Rule::validateContacts($cid, $oid)) { - 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 Dedupe Exceptions page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1')))); - } $this->_contactType = civicrm_api3('Contact', 'getvalue', array('id' => $cid, 'return' => 'contact_type')); - $isFromDedupeScreen = TRUE; + + $browseUrl = CRM_Utils_System::url('civicrm/contact/dedupefind', $urlParams . '&action=browse'); + if (!$this->_rgid) { - $isFromDedupeScreen = FALSE; + // Unset browse URL as we have come from the search screen. + $browseUrl = ''; $this->_rgid = civicrm_api3('RuleGroup', 'getvalue', array( 'contact_type' => $this->_contactType, 'used' => 'Supervised', 'return' => 'id', )); } + $this->assign('browseUrl', $browseUrl); + if ($browseUrl) { + CRM_Core_Session::singleton()->pushUserContext($browseUrl); + } $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid); @@ -104,14 +105,6 @@ public function preProcess() { $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $cid, $oid, $this->_mergeId, $join, $where, $flip); - // Block access if user does not have EDIT permissions for both contacts. - if (!(CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT) && - CRM_Contact_BAO_Contact_Permission::allow($oid, CRM_Core_Permission::EDIT) - ) - ) { - CRM_Utils_System::permissionDenied(); - } - // get user info of main contact. $config = CRM_Core_Config::singleton(); $config->doNotResetCache = 1; @@ -176,25 +169,9 @@ public function preProcess() { $session = CRM_Core_Session::singleton(); - // context fixed. - if ($isFromDedupeScreen) { - $browseUrl = CRM_Utils_System::url('civicrm/contact/dedupefind', $urlParams . '&action=browse'); - $session->pushUserContext($browseUrl); - } - $this->assign('browseUrl', empty($browseUrl) ? '' : $browseUrl); - - // ensure that oid is not the current user, if so refuse to do the merge - if ($session->get('userID') == $oid) { - $display_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $oid, 'display_name'); - $message = ts('The contact record which is linked to the currently logged in user account - \'%1\' - cannot be deleted.', - array(1 => $display_name) - ); - CRM_Core_Error::statusBounce($message); - } - $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($cid, $oid); - $main = $this->_mainDetails = &$rowsElementsAndInfo['main_details']; - $other = $this->_otherDetails = &$rowsElementsAndInfo['other_details']; + $main = $this->_mainDetails = $rowsElementsAndInfo['main_details']; + $other = $this->_otherDetails = $rowsElementsAndInfo['other_details']; if ($main['contact_id'] != $cid) { CRM_Core_Error::fatal(ts('The main contact record does not exist')); @@ -222,6 +199,19 @@ public function preProcess() { // add elements foreach ($rowsElementsAndInfo['elements'] as $element) { + // We could push this down to the getRowsElementsAndInfo function but it's + // already so overloaded - let's start moving towards doing form-things + // on the form. + if (substr($element[1], 0, 13) === 'move_location') { + $element[4] = array_merge( + (array) CRM_Utils_Array::value(4, $element, array()), + array('data-location' => substr($element[1], 14), 'data-is_location' => TRUE)); + } + if (substr($element[1], 0, 15) === 'location_blocks') { + // @todo We could add some data elements here to make jquery manipulation more straight-forward + // @todo consider enabling if it is an add & defaulting to true. + $element[4] = array_merge((array) CRM_Utils_Array::value(4, $element, array()), array('disabled' => TRUE)); + } $this->addElement($element[0], $element[1], array_key_exists('2', $element) ? $element[2] : NULL, @@ -241,22 +231,6 @@ public function preProcess() { $this->assign('userContextURL', $session->readUserContext()); } - /** - * This virtual function is used to set the default values of - * various form elements - * - * access public - * - * @return array - * reference to the array of default values - */ - /** - * @return array - */ - public function setDefaultValues() { - return array('deleteOther' => 1); - } - public function addRules() { } @@ -366,4 +340,39 @@ public function postProcess() { CRM_Utils_System::redirect($url); } + /** + * Bounce if the merge action is invalid. + * + * We don't allow the merge if it is nonsensical, marked as a duplicate + * or outside the user's permission. + * + * @param int $cid + * Contact ID to retain + * @param int $oid + * Contact ID to delete. + */ + public function bounceIfInvalid($cid, $oid) { + if ($cid == $oid) { + CRM_Core_Error::statusBounce(ts('Cannot merge a contact with itself.')); + } + + if (!CRM_Dedupe_BAO_Rule::validateContacts($cid, $oid)) { + 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 Dedupe Exceptions page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1')))); + } + + if (!(CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT) && + CRM_Contact_BAO_Contact_Permission::allow($oid, CRM_Core_Permission::EDIT) + ) + ) { + CRM_Utils_System::permissionDenied(); + } + // ensure that oid is not the current user, if so refuse to do the merge + if (CRM_Core_Session::singleton()->getLoggedInContactID() == $oid) { + $message = ts('The contact record which is linked to the currently logged in user account - \'%1\' - cannot be deleted.', + array(1 => CRM_Core_Session::singleton()->getLoggedInContactDisplayName()) + ); + CRM_Core_Error::statusBounce($message); + } + } + } diff --git a/templates/CRM/Contact/Form/Merge.tpl b/templates/CRM/Contact/Form/Merge.tpl index 4541877abfcd..ca2de4c87ad5 100644 --- a/templates/CRM/Contact/Form/Merge.tpl +++ b/templates/CRM/Contact/Form/Merge.tpl @@ -130,9 +130,22 @@ $row.title|substr:0:5 == "Phone"} - {* @TODO check if this is ever an array or a fileName? *} - {* This is on one long line for address formatting *} - {if $row.title|substr:0:7 == "Address"}{else}{/if}{if !is_array($row.main)}{$row.main}{elseif $row.main.fileName}{$row.main.fileName}{else}{', '|implode:$row.main}{/if} + {strip} + {if $row.title|substr:0:7 == "Address"} + + {else} + + {/if} + {* @TODO check if this is ever an array or a fileName? *} + {if !is_array($row.main)} + {$row.main} + {elseif $row.main.fileName} + {$row.main.fileName} + {else} + {', '|implode:$row.main} + {/if} + + {/strip} @@ -220,10 +233,6 @@ {/if} {/foreach} -
- - -
{include file="CRM/common/formButtons.tpl" location="bottom"} @@ -239,7 +248,7 @@ /** * Triggered when a 'location' or 'type' destination is changed, and when * the operation or 'set primary' checkboxes are changed. - * + * * Check to see if the 'main' contact record has a corresponding location * block when the destination of a field is changed. Allow existing location * fields to be overwritten with data from the 'other' contact. @@ -388,29 +397,26 @@ } } - CRM.$(function($) { - - $('table td input.form-checkbox').each(function() { - var ele = null; - var element = $(this).attr('id').split('_',3); + /** + * Toggle the location type and the is_primary on & off depending on whether the merge box is ticked. + * + * @param element + */ + function toggleRelatedLocationFields(element) { + relatedElements = CRM.$(element).parent().siblings('td').find('input,select,label,hidden'); + if (CRM.$(element).is(':checked')) { + relatedElements.removeClass('disabled').attr('disabled', false); - switch ( element['1'] ) { - case 'addressee': - ele = '#' + element['0'] + '_' + element['1']; - break; + } + else { + relatedElements.addClass('disabled').attr('disabled', true); + } - case 'email': - case 'postal': - ele = '#' + element['0'] + '_' + element['1'] + '_' + element['2']; - break; - } + } - if( ele ) { - $(this).on('click', function() { - var val = $(this).prop('checked'); - $('input' + ele + ', input' + ele + '_custom').prop('checked', val); - }); - } + CRM.$(function($) { + $('input.crm-form-checkbox[data-is_location]').on('click', function(){ + toggleRelatedLocationFields(this) }); // Show/hide matching data rows @@ -419,6 +425,8 @@ }); // Call mergeBlock whenever a location type is changed + // (This is applied to the body because the inputs can be added dynamically + // to the form, and we need to catch when they change.) $('body').on('change', 'select[id$="locTypeId"],select[id$="typeTypeId"],input[id$="[operation]"],input[id$="[set_other_primary]"]', function(event){ // All the information we need is held in the id, separated by underscores