Пример #1
0
 function preProcess()
 {
     if (!CRM_Core_Permission::check('merge duplicate contacts')) {
         CRM_Core_Error::fatal(ts('You do not have access to this page'));
     }
     $rows = array();
     $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
     $oid = CRM_Utils_Request::retrieve('oid', 'Positive', $this, TRUE);
     $flip = CRM_Utils_Request::retrieve('flip', 'Positive', $this, FALSE);
     $this->_rgid = $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE);
     $this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE);
     $this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE);
     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 <a href=\'%1\'>Dedupe Exceptions</a> page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1'))));
     }
     //load cache mechanism
     $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'contact_type');
     $cacheKey = "merge {$contactType}";
     $cacheKey .= $rgid ? "_{$rgid}" : '_0';
     $cacheKey .= $gid ? "_{$gid}" : '_0';
     $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND\n                                                             pn.entity_id2 = de.contact_id2 )";
     $where = "de.id IS NULL";
     $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;
     $viewUser = CRM_Core_Permission::check('access user profiles');
     $mainUfId = CRM_Core_BAO_UFMatch::getUFId($cid);
     $mainUser = NULL;
     if ($mainUfId) {
         // d6 compatible
         if ($config->userSystem->is_drupal == '1') {
             $mainUser = user_load($mainUfId);
         } elseif ($config->userFramework == 'Joomla') {
             $mainUser = JFactory::getUser($mainUfId);
         }
         $this->assign('mainUfId', $mainUfId);
         $this->assign('mainUfName', $mainUser ? $mainUser->name : NULL);
     }
     $flipUrl = CRM_Utils_System::url('civicrm/contact/merge', "reset=1&action=update&cid={$oid}&oid={$cid}&rgid={$rgid}&gid={$gid}");
     if (!$flip) {
         $flipUrl .= '&flip=1';
     }
     $this->assign('flip', $flipUrl);
     $this->prev = $this->next = NULL;
     foreach (array('prev', 'next') as $position) {
         if (!empty($pos[$position])) {
             if ($pos[$position]['id1'] && $pos[$position]['id2']) {
                 $urlParam = "reset=1&cid={$pos[$position]['id1']}&oid={$pos[$position]['id2']}&mergeId={$pos[$position]['mergeId']}&action=update";
                 if ($rgid) {
                     $urlParam .= "&rgid={$rgid}";
                 }
                 if ($gid) {
                     $urlParam .= "&gid={$gid}";
                 }
                 $this->{$position} = CRM_Utils_System::url('civicrm/contact/merge', $urlParam);
                 $this->assign($position, $this->{$position});
             }
         }
     }
     // get user info of other contact.
     $otherUfId = CRM_Core_BAO_UFMatch::getUFId($oid);
     $otherUser = NULL;
     if ($otherUfId) {
         // d6 compatible
         if ($config->userSystem->is_drupal == '1') {
             $otherUser = user_load($otherUfId);
         } elseif ($config->userFramework == 'Joomla') {
             $otherUser = JFactory::getUser($otherUfId);
         }
         $this->assign('otherUfId', $otherUfId);
         $this->assign('otherUfName', $otherUser ? $otherUser->name : NULL);
     }
     $cmsUser = $mainUfId && $otherUfId ? TRUE : FALSE;
     $this->assign('user', $cmsUser);
     $session = CRM_Core_Session::singleton();
     // context fixed.
     if ($rgid) {
         $urlParam = "reset=1&action=browse&rgid={$rgid}";
         if ($gid) {
             $urlParam .= "&gid={$gid}";
         }
         $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlParam));
     }
     // 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 =& $rowsElementsAndInfo['main_details'];
     $other =& $rowsElementsAndInfo['other_details'];
     if ($main['contact_id'] != $cid) {
         CRM_Core_Error::fatal(ts('The main contact record does not exist'));
     }
     if ($other['contact_id'] != $oid) {
         CRM_Core_Error::fatal(ts('The other contact record does not exist'));
     }
     $subtypes = CRM_Contact_BAO_ContactType::subTypePairs(NULL, TRUE, '');
     $this->assign('contact_type', $main['contact_type']);
     if (!empty($main['contact_sub_type'])) {
         $this->assign('main_contact_subtype', CRM_Utils_Array::value('contact_sub_type', $subtypes[$main['contact_sub_type'][0]]));
     }
     if (!empty($other['contact_sub_type'])) {
         $this->assign('other_contact_subtype', CRM_Utils_Array::value('contact_sub_type', $subtypes[$other['contact_sub_type'][0]]));
     }
     $this->assign('main_name', $main['display_name']);
     $this->assign('other_name', $other['display_name']);
     $this->assign('main_cid', $main['contact_id']);
     $this->assign('other_cid', $other['contact_id']);
     $this->assign('rgid', $rgid);
     $this->_cid = $cid;
     $this->_oid = $oid;
     $this->_rgid = $rgid;
     $this->_contactType = $main['contact_type'];
     $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('onclick' => "return toggleCheckboxVals('move_',this);"));
     $this->assign('mainLocBlock', json_encode($rowsElementsAndInfo['main_loc_block']));
     $this->assign('rows', $rowsElementsAndInfo['rows']);
     $this->_locBlockIds = array('main' => $rowsElementsAndInfo['main_details']['loc_block_ids'], 'other' => $rowsElementsAndInfo['other_details']['loc_block_ids']);
     // add elements
     foreach ($rowsElementsAndInfo['elements'] as $element) {
         $this->addElement($element[0], $element[1], array_key_exists('2', $element) ? $element[2] : NULL, array_key_exists('3', $element) ? $element[3] : NULL, array_key_exists('4', $element) ? $element[4] : NULL, array_key_exists('5', $element) ? $element[5] : NULL);
     }
     // add related table elements
     foreach ($rowsElementsAndInfo['rel_table_elements'] as $relTableElement) {
         $element = $this->addElement($relTableElement[0], $relTableElement[1]);
         $element->setChecked(TRUE);
     }
     $this->assign('rel_tables', $rowsElementsAndInfo['rel_tables']);
     $this->assign('userContextURL', $session->readUserContext());
 }
Пример #2
0
 /**
  * Merge given set of contacts. Performs core operation.
  *
  * @param array $dupePairs
  *   Set of pair of contacts for whom merge is to be done.
  * @param array $cacheParams
  *   Prev-next-cache params based on which next pair of contacts are computed.
  *                              Generally used with batch-merge.
  * @param string $mode
  *   Helps decide how to behave when there are conflicts.
  *                             A 'safe' value skips the merge if there are any un-resolved conflicts.
  *                             Does a force merge otherwise (aggressive mode).
  * @param bool $autoFlip to let api decide which contact to retain and which to delete.
  *   Wether to let api decide which contact to retain and which to delete.
  *
  *
  * @param bool $redirectForPerformance
  *
  * @return array|bool
  */
 public static function merge($dupePairs = array(), $cacheParams = array(), $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE)
 {
     $cacheKeyString = CRM_Utils_Array::value('cache_key_string', $cacheParams);
     $resultStats = array('merged' => array(), 'skipped' => array());
     // we don't want dupe caching to get reset after every-merge, and therefore set the
     // doNotResetCache flag
     $config = CRM_Core_Config::singleton();
     $config->doNotResetCache = 1;
     while (!empty($dupePairs)) {
         foreach ($dupePairs as $dupes) {
             CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
             $mainId = $dupes['dstID'];
             $otherId = $dupes['srcID'];
             $isAutoFlip = CRM_Utils_Array::value('auto_flip', $dupes, $autoFlip);
             // if we can, make sure that $mainId is the one with lower id number
             if ($isAutoFlip && $mainId > $otherId) {
                 $mainId = $dupes['srcID'];
                 $otherId = $dupes['dstID'];
             }
             if (!$mainId || !$otherId) {
                 // return error
                 return FALSE;
             }
             // Generate var $migrationInfo. The variable structure is exactly same as
             // $formValues submitted during a UI merge for a pair of contacts.
             $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($mainId, $otherId);
             $migrationInfo =& $rowsElementsAndInfo['migration_info'];
             // add additional details that we might need to resolve conflicts
             $migrationInfo['main_details'] =& $rowsElementsAndInfo['main_details'];
             $migrationInfo['other_details'] =& $rowsElementsAndInfo['other_details'];
             $migrationInfo['main_loc_block'] =& $rowsElementsAndInfo['main_loc_block'];
             $migrationInfo['rows'] =& $rowsElementsAndInfo['rows'];
             // go ahead with merge if there is no conflict
             if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode)) {
                 CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo);
                 $resultStats['merged'][] = array('main_id' => $mainId, 'other_id' => $otherId);
             } else {
                 $resultStats['skipped'][] = array('main_id' => $mainId, 'other_id' => $otherId);
             }
             // delete entry from PrevNextCache table so we don't consider the pair next time
             // pair may have been flipped, so make sure we delete using both orders
             CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString);
             CRM_Core_BAO_PrevNextCache::deletePair($otherId, $mainId, $cacheKeyString);
             CRM_Core_DAO::freeResult();
             unset($rowsElementsAndInfo, $migrationInfo);
         }
         if ($cacheKeyString && !$redirectForPerformance) {
             // retrieve next pair of dupes
             $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $cacheParams['join'], $cacheParams['where']);
         } else {
             // do not proceed. Terminate the loop
             unset($dupePairs);
         }
     }
     return $resultStats;
 }
Пример #3
0
 /**
  * Merge given set of contacts. Performs core operation.
  *
  * @param array $dupePairs
  *   Set of pair of contacts for whom merge is to be done.
  * @param array $cacheParams
  *   Prev-next-cache params based on which next pair of contacts are computed.
  *                              Generally used with batch-merge.
  * @param string $mode
  *   Helps decide how to behave when there are conflicts.
  *                             A 'safe' value skips the merge if there are any un-resolved conflicts.
  *                             Does a force merge otherwise (aggressive mode).
  * @param bool $autoFlip to let api decide which contact to retain and which to delete.
  *   Whether to let api decide which contact to retain and which to delete.
  *
  * @param bool $redirectForPerformance
  *   Redirect to a url for batch processing.
  *
  * @param bool $checkPermissions
  *   Respect logged in user permissions.
  *
  * @return array|bool
  */
 public static function merge($dupePairs = array(), $cacheParams = array(), $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE, $checkPermissions = TRUE)
 {
     $cacheKeyString = CRM_Utils_Array::value('cache_key_string', $cacheParams);
     $resultStats = array('merged' => array(), 'skipped' => array());
     // we don't want dupe caching to get reset after every-merge, and therefore set the
     // doNotResetCache flag
     $config = CRM_Core_Config::singleton();
     $config->doNotResetCache = 1;
     $deletedContacts = array();
     while (!empty($dupePairs)) {
         foreach ($dupePairs as $index => $dupes) {
             if (in_array($dupes['dstID'], $deletedContacts) || in_array($dupes['srcID'], $deletedContacts)) {
                 unset($dupePairs[$index]);
                 continue;
             }
             CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
             $mainId = $dupes['dstID'];
             $otherId = $dupes['srcID'];
             if (!$mainId || !$otherId) {
                 // return error
                 return FALSE;
             }
             // Generate var $migrationInfo. The variable structure is exactly same as
             // $formValues submitted during a UI merge for a pair of contacts.
             $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($mainId, $otherId, $checkPermissions);
             // add additional details that we might need to resolve conflicts
             $rowsElementsAndInfo['migration_info']['main_details'] =& $rowsElementsAndInfo['main_details'];
             $rowsElementsAndInfo['migration_info']['other_details'] =& $rowsElementsAndInfo['other_details'];
             $rowsElementsAndInfo['migration_info']['rows'] =& $rowsElementsAndInfo['rows'];
             self::dedupePair($rowsElementsAndInfo['migration_info'], $resultStats, $deletedContacts, $mode, $checkPermissions, $mainId, $otherId, $cacheKeyString);
         }
         if ($cacheKeyString && !$redirectForPerformance) {
             // retrieve next pair of dupes
             // @todo call getDuplicatePairs.
             $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $cacheParams['join'], $cacheParams['where'], 0, 0, array(), '', FALSE);
         } else {
             // do not proceed. Terminate the loop
             unset($dupePairs);
         }
     }
     CRM_Dedupe_Merger::updateMergeStats($cacheKeyString, $resultStats);
     return $resultStats;
 }
Пример #4
0
 public function preProcess()
 {
     if (!CRM_Core_Permission::check('merge duplicate contacts')) {
         CRM_Core_Error::fatal(ts('You do not have access to this page'));
     }
     $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
     $oid = CRM_Utils_Request::retrieve('oid', 'Positive', $this, TRUE);
     $flip = CRM_Utils_Request::retrieve('flip', 'Positive', $this, FALSE);
     $this->_rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE);
     $this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE);
     $this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE);
     $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.'));
     }
     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 <a href="%1">Dedupe Exceptions</a> 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;
     if (!$this->_rgid) {
         $isFromDedupeScreen = FALSE;
         $this->_rgid = civicrm_api3('RuleGroup', 'getvalue', array('contact_type' => $this->_contactType, 'used' => 'Supervised', 'return' => 'id'));
     }
     $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid);
     $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
     $where = "de.id IS NULL";
     $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;
     $viewUser = CRM_Core_Permission::check('access user profiles');
     $mainUfId = CRM_Core_BAO_UFMatch::getUFId($cid);
     $mainUser = NULL;
     if ($mainUfId) {
         // d6 compatible
         if ($config->userSystem->is_drupal == '1') {
             $mainUser = user_load($mainUfId);
         } elseif ($config->userFramework == 'Joomla') {
             $mainUser = JFactory::getUser($mainUfId);
         }
         $this->assign('mainUfId', $mainUfId);
         $this->assign('mainUfName', $mainUser ? $mainUser->name : NULL);
     }
     $flipUrl = CRM_Utils_System::url('civicrm/contact/merge', "reset=1&action=update&cid={$oid}&oid={$cid}&rgid={$this->_rgid}&gid={$gid}");
     if (!$flip) {
         $flipUrl .= '&flip=1';
     }
     $this->assign('flip', $flipUrl);
     $this->prev = $this->next = NULL;
     foreach (array('prev', 'next') as $position) {
         if (!empty($pos[$position])) {
             if ($pos[$position]['id1'] && $pos[$position]['id2']) {
                 $urlParams .= "&cid={$pos[$position]['id1']}&oid={$pos[$position]['id2']}&mergeId={$pos[$position]['mergeId']}&action=update";
                 $this->{$position} = CRM_Utils_System::url('civicrm/contact/merge', $urlParams);
                 $this->assign($position, $this->{$position});
             }
         }
     }
     // get user info of other contact.
     $otherUfId = CRM_Core_BAO_UFMatch::getUFId($oid);
     $otherUser = NULL;
     if ($otherUfId) {
         // d6 compatible
         if ($config->userSystem->is_drupal == '1') {
             $otherUser = user_load($otherUfId);
         } elseif ($config->userFramework == 'Joomla') {
             $otherUser = JFactory::getUser($otherUfId);
         }
         $this->assign('otherUfId', $otherUfId);
         $this->assign('otherUfName', $otherUser ? $otherUser->name : NULL);
     }
     $cmsUser = $mainUfId && $otherUfId ? TRUE : FALSE;
     $this->assign('user', $cmsUser);
     $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'];
     if ($main['contact_id'] != $cid) {
         CRM_Core_Error::fatal(ts('The main contact record does not exist'));
     }
     if ($other['contact_id'] != $oid) {
         CRM_Core_Error::fatal(ts('The other contact record does not exist'));
     }
     $this->assign('contact_type', $main['contact_type']);
     $this->assign('main_name', $main['display_name']);
     $this->assign('other_name', $other['display_name']);
     $this->assign('main_cid', $main['contact_id']);
     $this->assign('other_cid', $other['contact_id']);
     $this->assign('rgid', $this->_rgid);
     $this->_cid = $cid;
     $this->_oid = $oid;
     $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('class' => 'select-rows'));
     $this->assign('mainLocBlock', json_encode($rowsElementsAndInfo['main_details']['location_blocks']));
     $this->assign('locationBlockInfo', json_encode(CRM_Dedupe_Merger::getLocationBlockInfo()));
     $this->assign('rows', $rowsElementsAndInfo['rows']);
     // add elements
     foreach ($rowsElementsAndInfo['elements'] as $element) {
         $this->addElement($element[0], $element[1], array_key_exists('2', $element) ? $element[2] : NULL, array_key_exists('3', $element) ? $element[3] : NULL, array_key_exists('4', $element) ? $element[4] : NULL, array_key_exists('5', $element) ? $element[5] : NULL);
     }
     // add related table elements
     foreach ($rowsElementsAndInfo['rel_table_elements'] as $relTableElement) {
         $element = $this->addElement($relTableElement[0], $relTableElement[1]);
         $element->setChecked(TRUE);
     }
     $this->assign('rel_tables', $rowsElementsAndInfo['rel_tables']);
     $this->assign('userContextURL', $session->readUserContext());
 }
Пример #5
0
 /**
  * Merge given set of contacts. Performs core operation.
  *
  * @param array $dupePairs
  *   Set of pair of contacts for whom merge is to be done.
  * @param array $cacheParams
  *   Prev-next-cache params based on which next pair of contacts are computed.
  *                              Generally used with batch-merge.
  * @param string $mode
  *   Helps decide how to behave when there are conflicts.
  *                             A 'safe' value skips the merge if there are any un-resolved conflicts.
  *                             Does a force merge otherwise (aggressive mode).
  * @param bool $autoFlip to let api decide which contact to retain and which to delete.
  *   Whether to let api decide which contact to retain and which to delete.
  *
  * @param bool $redirectForPerformance
  *   Redirect to a url for batch processing.
  *
  * @param bool $checkPermissions
  *   Respect logged in user permissions.
  *
  * @return array|bool
  */
 public static function merge($dupePairs = array(), $cacheParams = array(), $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE, $checkPermissions = TRUE)
 {
     $cacheKeyString = CRM_Utils_Array::value('cache_key_string', $cacheParams);
     $resultStats = array('merged' => array(), 'skipped' => array());
     // we don't want dupe caching to get reset after every-merge, and therefore set the
     // doNotResetCache flag
     $config = CRM_Core_Config::singleton();
     $config->doNotResetCache = 1;
     $deletedContacts = array();
     while (!empty($dupePairs)) {
         foreach ($dupePairs as $index => $dupes) {
             if (in_array($dupes['dstID'], $deletedContacts) || in_array($dupes['srcID'], $deletedContacts)) {
                 unset($dupePairs[$index]);
                 continue;
             }
             CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
             $mainId = $dupes['dstID'];
             $otherId = $dupes['srcID'];
             if (!$mainId || !$otherId) {
                 // return error
                 return FALSE;
             }
             // Generate var $migrationInfo. The variable structure is exactly same as
             // $formValues submitted during a UI merge for a pair of contacts.
             $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($mainId, $otherId, $checkPermissions);
             $migrationInfo =& $rowsElementsAndInfo['migration_info'];
             // add additional details that we might need to resolve conflicts
             $migrationInfo['main_details'] =& $rowsElementsAndInfo['main_details'];
             $migrationInfo['other_details'] =& $rowsElementsAndInfo['other_details'];
             $migrationInfo['rows'] =& $rowsElementsAndInfo['rows'];
             // go ahead with merge if there is no conflict
             $conflicts = array();
             if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode, $conflicts)) {
                 CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo, $checkPermissions);
                 $resultStats['merged'][] = array('main_id' => $mainId, 'other_id' => $otherId);
                 $deletedContacts[] = $otherId;
             } else {
                 $resultStats['skipped'][] = array('main_id' => $mainId, 'other_id' => $otherId);
             }
             // store any conflicts
             if (!empty($conflicts)) {
                 foreach ($conflicts as $key => $dnc) {
                     $conflicts[$key] = "{$migrationInfo['rows'][$key]['title']}: '{$migrationInfo['rows'][$key]['main']}' vs. '{$migrationInfo['rows'][$key]['other']}'";
                 }
                 CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts);
             } else {
                 // delete entry from PrevNextCache table so we don't consider the pair next time
                 // pair may have been flipped, so make sure we delete using both orders
                 CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString, TRUE);
             }
             CRM_Core_DAO::freeResult();
             unset($rowsElementsAndInfo, $migrationInfo);
         }
         if ($cacheKeyString && !$redirectForPerformance) {
             // retrieve next pair of dupes
             // @todo call getDuplicatePairs.
             $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $cacheParams['join'], $cacheParams['where'], 0, 0, array(), '', FALSE);
         } else {
             // do not proceed. Terminate the loop
             unset($dupePairs);
         }
     }
     CRM_Dedupe_Merger::updateMergeStats($cacheKeyString, $resultStats);
     return $resultStats;
 }