From b35800bdc374238da1a99dd255b22b7389973b7b Mon Sep 17 00:00:00 2001 From: Eaiman Shoshi Date: Fri, 14 Jul 2017 03:06:34 +0600 Subject: [PATCH 01/14] Fix for jira issue CRM-20858 This PR is for jira issue https://issues.civicrm.org/jira/browse/CRM-20858 --- CRM/Dedupe/Merger.php | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 400d3364c6a..bcd51ea87bc 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -437,15 +437,21 @@ public static function operationSql($mainId, $otherId, $tableName, $tableOperati * @param int $otherId * @param bool $tables * @param array $tableOperations + * @param array $customTableToCopyFrom */ - public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array()) { + public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array(), $customTableToCopyFrom = array()) { $cidRefs = self::cidRefs(); $eidRefs = self::eidRefs(); $cpTables = self::cpTables(); $paymentTables = self::paymentTables(); // CRM-12695: $membershipMerge = FALSE; - + + // getting all custom tables + $customTables = array(); + self::addCustomTablesExtendingContactsToCidRefs($customTables); + $customTables = array_keys($customTables); + $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); if ($tables !== FALSE) { // if there are specific tables, sanitize the list @@ -483,6 +489,11 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $sqls = array(); foreach ($affected as $table) { + // skipping non selected custom table's value migration + if(in_array($table, $customTables) && !in_array($table, $customTableToCopyFrom)){ + continue; + } + // Call custom processing function for objects that require it if (isset($cpTables[$table])) { foreach ($cpTables[$table] as $className => $fnName) { @@ -1464,6 +1475,8 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9'; $relTables = CRM_Dedupe_Merger::relTables(); $moveTables = $locationMigrationInfo = $tableOperations = array(); + // variable for capturing id of civicrm_custom_field id + $submittedCustomValue = array(); foreach ($migrationInfo as $key => $value) { if ($value == $qfZeroBug) { $value = '0'; @@ -1473,6 +1486,8 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che $value != NULL ) { $submitted[substr($key, 5)] = $value; + // capturing id + array_push($submittedCustomValue, substr($key, 12)); } // Set up initial information for handling migration of location blocks @@ -1499,8 +1514,25 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che unset($moveTables, $tableOperations); } + // capturing the custom table names. The table's value we have to merge + // from duplicate contact to original contact + $customTableToCopyValues = array(); + foreach ($submittedCustomValue as $key=>$value){ + $result = civicrm_api3('custom_field', 'get', array('id' => $value, 'is_active' => TRUE)); + if(!$result['is_error']){ + foreach ($result['values'] as $k=>$v){ + $result_ = civicrm_api3('custom_group', 'get', array('id' => $result['values'][$k]['custom_group_id'], 'is_active' => TRUE)); + if(!$result_['is_error']) { + foreach ($result_['values'] as $kk => $vv) { + array_push($customTableToCopyValues, $result_['values'][$kk]['table_name']); + } + } + } + } + } + // **** Do contact related migrations - CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId); + CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTableToCopyValues); // FIXME: fix gender, prefix and postfix, so they're edible by createProfileContact() $names['gender'] = array('newName' => 'gender_id', 'groupName' => 'gender'); From 9af46cc47bed72efc1c60d3328d65277a2142fe3 Mon Sep 17 00:00:00 2001 From: Eaiman Shoshi Date: Sat, 15 Jul 2017 02:11:09 +0600 Subject: [PATCH 02/14] Update Merger.php 1. I think we'll need some more error-handling. The code should probably throw an exception if any of those API calls fail? -Done 2. There are two calls to 'moveContactBelongings' - won't the first call be affected by the additional code you've added that 'ignores' changes in they're not in the array? - Handled --- CRM/Dedupe/Merger.php | 70 ++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index bcd51ea87bc..9ff8398e577 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -439,7 +439,7 @@ public static function operationSql($mainId, $otherId, $tableName, $tableOperati * @param array $tableOperations * @param array $customTableToCopyFrom */ - public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array(), $customTableToCopyFrom = array()) { + public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array(), $customTableToCopyFrom = NULL) { $cidRefs = self::cidRefs(); $eidRefs = self::eidRefs(); $cpTables = self::cpTables(); @@ -448,11 +448,13 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $membershipMerge = FALSE; // getting all custom tables - $customTables = array(); - self::addCustomTablesExtendingContactsToCidRefs($customTables); - $customTables = array_keys($customTables); - - $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); + $customTables = []; + if($customTableToCopyFrom != NULL) { + self::addCustomTablesExtendingContactsToCidRefs($customTables); + $customTables = array_keys($customTables); + } + + $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); if ($tables !== FALSE) { // if there are specific tables, sanitize the list $affected = array_unique(array_intersect($affected, $tables)); @@ -490,7 +492,8 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $sqls = array(); foreach ($affected as $table) { // skipping non selected custom table's value migration - if(in_array($table, $customTables) && !in_array($table, $customTableToCopyFrom)){ + if($customTableToCopyFrom != NULL && in_array($table, $customTables) + && !in_array($table, $customTableToCopyFrom)){ continue; } @@ -1517,19 +1520,46 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che // capturing the custom table names. The table's value we have to merge // from duplicate contact to original contact $customTableToCopyValues = array(); - foreach ($submittedCustomValue as $key=>$value){ - $result = civicrm_api3('custom_field', 'get', array('id' => $value, 'is_active' => TRUE)); - if(!$result['is_error']){ - foreach ($result['values'] as $k=>$v){ - $result_ = civicrm_api3('custom_group', 'get', array('id' => $result['values'][$k]['custom_group_id'], 'is_active' => TRUE)); - if(!$result_['is_error']) { - foreach ($result_['values'] as $kk => $vv) { - array_push($customTableToCopyValues, $result_['values'][$kk]['table_name']); - } - } - } - } - } + foreach ($submittedCustomValue as $value){ + if($value != NULL) { + $result1 = null; + try { + $result1 = civicrm_api3('custom_field', 'get', [ + 'id' => $value, + 'is_active' => TRUE + ]); + } catch (CiviCRM_API3_Exception $e) { + // just ignore and continue + continue; + } + if (!civicrm_error($result1) + && isset($result1['values']) && is_array($result1['values'])) { + foreach ($result1['values'] as $value1) { + if ($value1 != NULL && is_array($value1) && isset($value1['custom_group_id'])) { + $result2 = null; + try { + $result2 = civicrm_api3('custom_group', 'get', [ + 'id' => $value1['custom_group_id'], + 'is_active' => TRUE + ]); + }catch (CiviCRM_API3_Exception $e) { + // just ignore and continue + continue; + } + if (!civicrm_error($result2) + && isset($result2['values']) && is_array($result2['values']) + ) { + foreach ($result2['values'] as $value2) { + if ($value2 != NULL && is_array($value2) && isset($value2['table_name'])) { + array_push($customTableToCopyValues, $value2['table_name']); + } + } + } + } + } + } + } + } // **** Do contact related migrations CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTableToCopyValues); From 674920ca77348c0fa54ca14018f5b07dee9df31f Mon Sep 17 00:00:00 2001 From: Eaiman Shoshi Date: Fri, 28 Jul 2017 16:29:56 +0600 Subject: [PATCH 03/14] Indentation fixed PhpStorm's tabs are now fixed to spaces. --- CRM/Dedupe/Merger.php | 104 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 9ff8398e577..fc98728b427 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -446,15 +446,15 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $paymentTables = self::paymentTables(); // CRM-12695: $membershipMerge = FALSE; - + // getting all custom tables - $customTables = []; - if($customTableToCopyFrom != NULL) { - self::addCustomTablesExtendingContactsToCidRefs($customTables); - $customTables = array_keys($customTables); - } - - $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); + $customTables = array(); + if ($customTableToCopyFrom != NULL) { + self::addCustomTablesExtendingContactsToCidRefs($customTables); + $customTables = array_keys($customTables); + } + + $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); if ($tables !== FALSE) { // if there are specific tables, sanitize the list $affected = array_unique(array_intersect($affected, $tables)); @@ -491,12 +491,11 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $sqls = array(); foreach ($affected as $table) { - // skipping non selected custom table's value migration - if($customTableToCopyFrom != NULL && in_array($table, $customTables) - && !in_array($table, $customTableToCopyFrom)){ + // skipping non selected custom table's value migration + if ($customTableToCopyFrom != NULL && in_array($table, $customTables) && !in_array($table, $customTableToCopyFrom)) { continue; } - + // Call custom processing function for objects that require it if (isset($cpTables[$table])) { foreach ($cpTables[$table] as $className => $fnName) { @@ -1517,50 +1516,49 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che unset($moveTables, $tableOperations); } - // capturing the custom table names. The table's value we have to merge - // from duplicate contact to original contact + // capturing the custom table names. The table's value we have to merge + // from duplicate contact to original contact $customTableToCopyValues = array(); - foreach ($submittedCustomValue as $value){ - if($value != NULL) { - $result1 = null; - try { - $result1 = civicrm_api3('custom_field', 'get', [ - 'id' => $value, - 'is_active' => TRUE - ]); - } catch (CiviCRM_API3_Exception $e) { - // just ignore and continue - continue; + foreach ($submittedCustomValue as $value) { + if ($value != NULL) { + $result1 = NULL; + try { + $result1 = civicrm_api3('custom_field', 'get', [ + 'id' => $value, + 'is_active' => TRUE + ]); + } + catch (CiviCRM_API3_Exception $e) { + // just ignore and continue + continue; } - if (!civicrm_error($result1) - && isset($result1['values']) && is_array($result1['values'])) { - foreach ($result1['values'] as $value1) { - if ($value1 != NULL && is_array($value1) && isset($value1['custom_group_id'])) { - $result2 = null; - try { - $result2 = civicrm_api3('custom_group', 'get', [ - 'id' => $value1['custom_group_id'], - 'is_active' => TRUE - ]); - }catch (CiviCRM_API3_Exception $e) { - // just ignore and continue - continue; - } - if (!civicrm_error($result2) - && isset($result2['values']) && is_array($result2['values']) - ) { - foreach ($result2['values'] as $value2) { - if ($value2 != NULL && is_array($value2) && isset($value2['table_name'])) { - array_push($customTableToCopyValues, $value2['table_name']); - } - } + if (!civicrm_error($result1) && isset($result1['values']) && is_array($result1['values'])) { + foreach ($result1['values'] as $value1) { + if ($value1 != NULL && is_array($value1) && isset($value1['custom_group_id'])) { + $result2 = NULL; + try { + $result2 = civicrm_api3('custom_group', 'get', [ + 'id' => $value1['custom_group_id'], + 'is_active' => TRUE + ]); } - } - } - } - } - } - + catch (CiviCRM_API3_Exception $e) { + // just ignore and continue + continue; + } + if (!civicrm_error($result2) && isset($result2['values']) && is_array($result2['values'])) { + foreach ($result2['values'] as $value2) { + if ($value2 != NULL && is_array($value2) && isset($value2['table_name'])) { + array_push($customTableToCopyValues, $value2['table_name']); + } + } + } + } + } + } + } + } + // **** Do contact related migrations CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTableToCopyValues); From 4651a59c2eee20e856cdc80604cfe3fba99187e5 Mon Sep 17 00:00:00 2001 From: Eaiman Shoshi Date: Fri, 28 Jul 2017 16:40:56 +0600 Subject: [PATCH 04/14] All [] arrays replaced by array() --- CRM/Dedupe/Merger.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index fc98728b427..87391d67838 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -1523,25 +1523,19 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che if ($value != NULL) { $result1 = NULL; try { - $result1 = civicrm_api3('custom_field', 'get', [ - 'id' => $value, - 'is_active' => TRUE - ]); + $result1 = civicrm_api3('custom_field', 'get', array('id' => $value, 'is_active' => TRUE)); } catch (CiviCRM_API3_Exception $e) { // just ignore and continue continue; - } + } if (!civicrm_error($result1) && isset($result1['values']) && is_array($result1['values'])) { foreach ($result1['values'] as $value1) { if ($value1 != NULL && is_array($value1) && isset($value1['custom_group_id'])) { $result2 = NULL; - try { - $result2 = civicrm_api3('custom_group', 'get', [ - 'id' => $value1['custom_group_id'], - 'is_active' => TRUE - ]); - } + try { + $result2 = civicrm_api3('custom_group', 'get', array('id' => $value1['custom_group_id'], 'is_active' => TRUE)); + } catch (CiviCRM_API3_Exception $e) { // just ignore and continue continue; From dba77ae8876d837fe9c9d1a256ad243598f6ce9b Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Tue, 8 Aug 2017 21:45:48 +0000 Subject: [PATCH 05/14] CRM-20858: Add Failing Tests to Verify Merging of Custom Fields If a contact that has values stored in a custom group table is merged into a contact that doesn't have a record in that table, all values in the source target will be merged into the target contact, even if those values were not explicity selected to the merge operation. The merging operation updates all database references from the source contact to the target contact on all tables. When the target contact has a record on a custom group table, this update will fail, since the table's configuration enforces the entity_id (the reference to the contacts table) to be unique. However, when the target contact has no record on that custom group table, the source contact does have a record and the merge is performed, the original record will be updated to reference the target contact, and hence inherit ALL values of the source contact, even if none of the values were selected to be merged. Added two tests, the first one to verify that merging a contact with a record on a custom group table does not merge its values into a target contact with no record in the custom group table; the second one to check that if only some fields of a custom group table are selected to be merged, only those values are copied, leaving all others unset. --- tests/phpunit/CRM/Dedupe/MergerTest.php | 219 +++++++++++++++++++----- 1 file changed, 176 insertions(+), 43 deletions(-) mode change 100644 => 100755 tests/phpunit/CRM/Dedupe/MergerTest.php diff --git a/tests/phpunit/CRM/Dedupe/MergerTest.php b/tests/phpunit/CRM/Dedupe/MergerTest.php old mode 100644 new mode 100755 index 627e5f52651..2638e285374 --- a/tests/phpunit/CRM/Dedupe/MergerTest.php +++ b/tests/phpunit/CRM/Dedupe/MergerTest.php @@ -488,80 +488,213 @@ public function testGetMatchesInGroup() { * selecting/not selecting option to migrate data respectively */ public function testCustomDataOverwrite() { + // Create Custom Field + $createGroup = $this->setupCustomGroupForIndividual(); + $createField = $this->setupCustomField('Graduation', $createGroup); + $customFieldName = "custom_" . $createField['id']; + + // Contacts setup $this->setupMatchData(); $originalContactID = $this->contacts[0]['id']; $duplicateContactID1 = $this->contacts[1]['id']; // used as duplicate contact in 1st use-case $duplicateContactID2 = $this->contacts[2]['id']; // used as duplicate contact in 2nd use-case - // create custom set that extends Individual - $createGroup = $this->callAPISuccess('custom_group', 'create', array( - 'title' => 'Test_Group', - 'name' => 'test_group', - 'extends' => array('Individual'), - 'style' => 'Inline', - 'is_multiple' => FALSE, - 'is_active' => 1, - )); - // create custom field of HTML type 'Text' - $createField = $this->callAPISuccess('custom_field', 'create', array( - 'label' => 'Graduation', - 'data_type' => 'Alphanumeric', - 'html_type' => 'Text', - 'custom_group_id' => $createGroup['id'], - )); - $customFieldName = "custom_" . $createField['id']; // update the text custom field for original contact with value 'abc' $this->callAPISuccess('Contact', 'create', array( 'id' => $originalContactID, - $customFieldName => 'abc', + "{$customFieldName}" => 'abc', )); + $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName); + // update the text custom field for duplicate contact 1 with value 'def' $this->callAPISuccess('Contact', 'create', array( 'id' => $duplicateContactID1, - "custom_{$customFieldName}" => 'def', + "{$customFieldName}" => 'def', )); + $this->assertCustomFieldValue($duplicateContactID1, 'def', $customFieldName); + // update the text custom field for duplicate contact 2 with value 'ghi' $this->callAPISuccess('Contact', 'create', array( 'id' => $duplicateContactID2, - "custom_{$customFieldName}" => 'ghi', + "{$customFieldName}" => 'ghi', )); + $this->assertCustomFieldValue($duplicateContactID2, 'ghi', $customFieldName); /*** USE-CASE 1: DO NOT OVERWRITE CUSTOM FIELD VALUE **/ - $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($originalContactID, $duplicateContactID1); - $migrationData = array( - 'main_details' => $rowsElementsAndInfo['main_details'], - 'other_details' => $rowsElementsAndInfo['other_details'], - "move_{$customFieldName}" => NULL, - ); - // migrate data of duplicate contact - CRM_Dedupe_Merger::moveAllBelongings($originalContactID, $duplicateContactID1, $migrationData); - $data = $this->callAPISuccess('Contact', 'getsingle', array( - 'id' => $originalContactID, - 'return' => array($customFieldName), + $this->mergeContacts($originalContactID, $duplicateContactID1, array( + "move_{$customFieldName}" => null, )); - // ensure that the value is not overridden - $this->assertEquals('abc', $data[$customFieldName], 'Custom field value wasn\'t suppose to be overridden with duplicate contact'); + $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName); /*** USE-CASE 2: OVERWRITE CUSTOM FIELD VALUE **/ - $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($originalContactID, $duplicateContactID2); + $this->mergeContacts($originalContactID, $duplicateContactID2, array( + "move_{$customFieldName}" => 'ghi', + )); + $this->assertCustomFieldValue($originalContactID, 'ghi', $customFieldName); + + // cleanup created custom set + $this->callAPISuccess('CustomField', 'delete', array('id' => $createField['id'])); + $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); + } + + /** + * Verifies that when a contact with a custom field value is merged into a + * contact without a record int its corresponding custom group table, and none + * of the custom fields of that custom table are selected, the value is not + * merged in. + */ + public function testMigrationOfUnselectedCustomDataOnEmptyCustomRecord() { + // Create Custom Fields + $createGroup = $this->setupCustomGroupForIndividual(); + $customField1 = $this->setupCustomField('TestField', $createGroup); + + // Contacts setup + $this->setupMatchData(); + $originalContactID = $this->contacts[0]['id']; + $duplicateContactID = $this->contacts[1]['id']; + + // Update the text custom fields for duplicate contact + $this->callAPISuccess('Contact', 'create', array( + 'id' => $duplicateContactID, + "custom_{$customField1['id']}" => 'abc', + )); + $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}"); + + $this->mergeContacts($originalContactID, $duplicateContactID, array( + "move_custom_{$customField1['id']}" => null, + )); + $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); + + // cleanup created custom set + $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id'])); + $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); + } + + /** + * Tests that if only part of the custom fields of a custom group are selected + * for a merge, only those values are merged, while all other fields of the + * custom group retain their original value, specifically for a contact with + * no records on the custom group table. + */ + public function testMigrationOfSomeCustomDataOnEmptyCustomRecord() { + // Create Custom Fields + $createGroup = $this->setupCustomGroupForIndividual(); + $customField1 = $this->setupCustomField('Test1', $createGroup); + $customField2 = $this->setupCustomField('Test2', $createGroup); + + // Contacts setup + $this->setupMatchData(); + $originalContactID = $this->contacts[0]['id']; + $duplicateContactID = $this->contacts[1]['id']; + + // Update the text custom fields for duplicate contact + $this->callAPISuccess('Contact', 'create', array( + 'id' => $duplicateContactID, + "custom_{$customField1['id']}" => 'abc', + "custom_{$customField2['id']}" => 'def', + )); + $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}"); + $this->assertCustomFieldValue($duplicateContactID, 'def', "custom_{$customField2['id']}"); + + // Perform merge + $this->mergeContacts($originalContactID, $duplicateContactID, array( + "move_custom_{$customField1['id']}" => null, + "move_custom_{$customField2['id']}" => 'def', + )); + $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); + $this->assertCustomFieldValue($originalContactID, 'def', "custom_{$customField2['id']}"); + + // cleanup created custom set + $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id'])); + $this->callAPISuccess('CustomField', 'delete', array('id' => $customField2['id'])); + $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); + } + + /** + * Calls merge method on given contacts, with values given in $params array. + * + * @param $originalContactID + * ID of target contact + * @param $duplicateContactID + * ID of contact to be merged + * @param $params + * Array of fields to be merged from source into target contact, of the form + * ['move_' => ] + */ + private function mergeContacts($originalContactID, $duplicateContactID, $params) { + $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($originalContactID, $duplicateContactID); + $migrationData = array( 'main_details' => $rowsElementsAndInfo['main_details'], 'other_details' => $rowsElementsAndInfo['other_details'], - "move_{$customFieldName}" => 'ghi', ); - // migrate data of duplicate contact - CRM_Dedupe_Merger::moveAllBelongings($originalContactID, $duplicateContactID2, $migrationData); + + // Migrate data of duplicate contact + CRM_Dedupe_Merger::moveAllBelongings($originalContactID, $duplicateContactID, array_merge($migrationData, $params)); + } + + /** + * Checks if the expected value for the given field corresponds to what is + * stored in the database for the given contact ID. + * + * @param $contactID + * @param $expectedValue + * @param $customFieldName + */ + private function assertCustomFieldValue($contactID, $expectedValue, $customFieldName) { $data = $this->callAPISuccess('Contact', 'getsingle', array( - 'id' => $originalContactID, + 'id' => $contactID, 'return' => array($customFieldName), )); - // ensure that value is overridden - $this->assertEquals('ghi', $data[$customFieldName], 'Custom field value was suppose to be overridden with duplicate contact'); - // cleanup created custom set - $this->callAPISuccess('CustomField', 'delete', array('id' => $createField['id'])); - $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); + $this->assertEquals($expectedValue, $data[$customFieldName], "Custom field value was supposed to be '{$expectedValue}', '{$data[$customFieldName]}' found."); + } + + /** + * Creates a custom group to run tests on contacts that are individuals. + * + * @return array + * Data for the created custom group record + */ + private function setupCustomGroupForIndividual() { + $customGroup = $this->callAPISuccess('custom_group', 'get', array( + 'name' => 'test_group', + )); + + if ($customGroup['count'] > 0) { + $this->callAPISuccess('CustomGroup', 'delete', array('id' => $customGroup['id'])); + } + + $customGroup = $this->callAPISuccess('custom_group', 'create', array( + 'title' => 'Test_Group', + 'name' => 'test_group', + 'extends' => array('Individual'), + 'style' => 'Inline', + 'is_multiple' => FALSE, + 'is_active' => 1, + )); + + return $customGroup; + } + + /** + * Creates a custom field on the provided custom group with the given field + * label. + * + * @param $fieldLabel + * @param $createGroup + * + * @return array + * Data for the created custom field record + */ + private function setupCustomField($fieldLabel, $createGroup) { + return $this->callAPISuccess('custom_field', 'create', array( + 'label' => $fieldLabel, + 'data_type' => 'Alphanumeric', + 'html_type' => 'Text', + 'custom_group_id' => $createGroup['id'], + )); } /** From ae2346d481a444de71eaf97b58432a253fe36db1 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Wed, 9 Aug 2017 14:10:02 +0000 Subject: [PATCH 06/14] CRM-20858: Fix Merging of Unselected Custom Fields and Refactor Code When a Custom Group had more than one custom field and only some of those fields were selected to be merged, all the fields in the custom group were merged. This happened exclusively on contacts that had no record on the custom group's table. Fixed this by inserting a record on the custom group table before updating references from source contact to target contact, this way, all values in the custom group will start empty and only submitted values will get assigned. Also refactored the solution to make it easier to read and used more descriptive variable and function names. --- CRM/Dedupe/Merger.php | 124 ++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 48 deletions(-) mode change 100644 => 100755 CRM/Dedupe/Merger.php diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php old mode 100644 new mode 100755 index 87391d67838..9ff1aeae167 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -449,7 +449,7 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, // getting all custom tables $customTables = array(); - if ($customTableToCopyFrom != NULL) { + if ($customTableToCopyFrom !== NULL) { self::addCustomTablesExtendingContactsToCidRefs($customTables); $customTables = array_keys($customTables); } @@ -492,7 +492,7 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $sqls = array(); foreach ($affected as $table) { // skipping non selected custom table's value migration - if ($customTableToCopyFrom != NULL && in_array($table, $customTables) && !in_array($table, $customTableToCopyFrom)) { + if ($customTableToCopyFrom !== NULL && in_array($table, $customTables) && !in_array($table, $customTableToCopyFrom)) { continue; } @@ -523,10 +523,14 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $preOperationSqls = self::operationSql($mainId, $otherId, $table, $tableOperations); $sqls = array_merge($sqls, $preOperationSqls); + if ($customTableToCopyFrom !== NULL && in_array($table, $customTableToCopyFrom) && !self::customRecordExists($mainId, $table, $field)) { + $sqls[] = "INSERT INTO $table ($field) VALUES ($mainId)"; + } $sqls[] = "UPDATE IGNORE $table SET $field = $mainId WHERE $field = $otherId"; $sqls[] = "DELETE FROM $table WHERE $field = $otherId"; } } + if (isset($eidRefs[$table])) { foreach ($eidRefs[$table] as $entityTable => $entityId) { $sqls[] = "UPDATE IGNORE $table SET $entityId = $mainId WHERE $entityId = $otherId AND $entityTable = 'civicrm_contact'"; @@ -551,6 +555,22 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $transaction->commit(); } + private static function customRecordExists($contactID, $table, $idField) { + $sql = " + SELECT COUNT(*) AS count + FROM $table + WHERE $idField = $contactID + "; + $dbResult = CRM_Core_DAO::executeQuery($sql); + $dbResult->fetch(); + + if ($dbResult->count > 0) { + return true; + } + + return false; + } + /** * Load all non-empty fields for the contacts * @@ -1476,9 +1496,8 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9'; $relTables = CRM_Dedupe_Merger::relTables(); - $moveTables = $locationMigrationInfo = $tableOperations = array(); - // variable for capturing id of civicrm_custom_field id - $submittedCustomValue = array(); + $submittedCustomFields = $moveTables = $locationMigrationInfo = $tableOperations = array(); + foreach ($migrationInfo as $key => $value) { if ($value == $qfZeroBug) { $value = '0'; @@ -1488,8 +1507,7 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che $value != NULL ) { $submitted[substr($key, 5)] = $value; - // capturing id - array_push($submittedCustomValue, substr($key, 12)); + $submittedCustomFields[] = substr($key, 12); } // Set up initial information for handling migration of location blocks @@ -1516,45 +1534,9 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che unset($moveTables, $tableOperations); } - // capturing the custom table names. The table's value we have to merge - // from duplicate contact to original contact - $customTableToCopyValues = array(); - foreach ($submittedCustomValue as $value) { - if ($value != NULL) { - $result1 = NULL; - try { - $result1 = civicrm_api3('custom_field', 'get', array('id' => $value, 'is_active' => TRUE)); - } - catch (CiviCRM_API3_Exception $e) { - // just ignore and continue - continue; - } - if (!civicrm_error($result1) && isset($result1['values']) && is_array($result1['values'])) { - foreach ($result1['values'] as $value1) { - if ($value1 != NULL && is_array($value1) && isset($value1['custom_group_id'])) { - $result2 = NULL; - try { - $result2 = civicrm_api3('custom_group', 'get', array('id' => $value1['custom_group_id'], 'is_active' => TRUE)); - } - catch (CiviCRM_API3_Exception $e) { - // just ignore and continue - continue; - } - if (!civicrm_error($result2) && isset($result2['values']) && is_array($result2['values'])) { - foreach ($result2['values'] as $value2) { - if ($value2 != NULL && is_array($value2) && isset($value2['table_name'])) { - array_push($customTableToCopyValues, $value2['table_name']); - } - } - } - } - } - } - } - } - // **** Do contact related migrations - CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTableToCopyValues); + $customTablesToCopyValues = self::getAffectedCustomTables($submittedCustomFields); + CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTablesToCopyValues); // FIXME: fix gender, prefix and postfix, so they're edible by createProfileContact() $names['gender'] = array('newName' => 'gender_id', 'groupName' => 'gender'); @@ -1621,19 +1603,19 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che if (!empty($customfieldValues[$key])) { $existingValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $customfieldValues[$key]); if (is_array($existingValue) && !empty($existingValue)) { - $mergeValue = $submittedCustomValue = array(); + $mergeValue = $submittedCustomFields = array(); if ($value == 'null') { // CRM-19074 if someone has deliberately chosen to overwrite with 'null', respect it. $submitted[$key] = $value; } else { if ($value) { - $submittedCustomValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + $submittedCustomFields = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); } // CRM-19653: overwrite or add the existing custom field value with dupicate contact's // custom field value stored at $submittedCustomValue. - foreach ($submittedCustomValue as $k => $v) { + foreach ($submittedCustomFields as $k => $v) { if ($v != '' && !in_array($v, $mergeValue)) { $mergeValue[] = $v; } @@ -1800,6 +1782,52 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che return TRUE; } + /** + * Builds an Array of Custom tables for given custom field ID's. + * + * @param $customFieldIDs + * + * @return array + * Array of custom table names + */ + private static function getAffectedCustomTables($customFieldIDs) { + $customTableToCopyValues = array(); + + foreach ($customFieldIDs as $fieldID) { + if (!empty($fieldID)) { + $customField = NULL; + try { + $customField = civicrm_api3('custom_field', 'getsingle', array( + 'id' => $fieldID, + 'is_active' => TRUE, + )); + } + catch (CiviCRM_API3_Exception $e) { + continue; + } + if (!civicrm_error($customField) && !empty($customField['custom_group_id'])) { + $customGroup = NULL; + try { + $customGroup = civicrm_api3('custom_group', 'getsingle', array( + 'id' => $customField['custom_group_id'], + 'is_active' => TRUE, + )); + } + catch (CiviCRM_API3_Exception $e) { + // just ignore and continue + continue; + } + + if (!civicrm_error($customGroup) && !empty($customGroup['table_name'])) { + $customTableToCopyValues[] = $customGroup['table_name']; + } + } + } + } + + return $customTableToCopyValues; + } + /** * Get fields in the contact table suitable for merging. * From 4f75197882733ee07495dd718f684e33c8281747 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Wed, 9 Aug 2017 14:21:45 +0000 Subject: [PATCH 07/14] CRM-20858: Add Documentation Block for customRecordExists --- CRM/Dedupe/Merger.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 9ff1aeae167..f8b1dcf1a86 100755 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -555,6 +555,17 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $transaction->commit(); } + /** + * Given a contact ID, will check if a record exists in given table. + * + * @param $contactID + * @param $table + * @param $idField + * Field where the contact's ID is stored in the table + * + * @return bool + * True if a record is found for the given contact ID, false otherwise + */ private static function customRecordExists($contactID, $table, $idField) { $sql = " SELECT COUNT(*) AS count From ee3b1d861b95ce915562ff689a37628c80f6b115 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Wed, 9 Aug 2017 14:46:01 +0000 Subject: [PATCH 08/14] CRM-20858: Fix Style Warnings for Upper Case Constants --- CRM/Dedupe/Merger.php | 4 ++-- tests/phpunit/CRM/Dedupe/MergerTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index f8b1dcf1a86..c227be0cca2 100755 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -576,10 +576,10 @@ private static function customRecordExists($contactID, $table, $idField) { $dbResult->fetch(); if ($dbResult->count > 0) { - return true; + return TRUE; } - return false; + return FALSE; } /** diff --git a/tests/phpunit/CRM/Dedupe/MergerTest.php b/tests/phpunit/CRM/Dedupe/MergerTest.php index 2638e285374..4db2dbd9e59 100755 --- a/tests/phpunit/CRM/Dedupe/MergerTest.php +++ b/tests/phpunit/CRM/Dedupe/MergerTest.php @@ -523,7 +523,7 @@ public function testCustomDataOverwrite() { /*** USE-CASE 1: DO NOT OVERWRITE CUSTOM FIELD VALUE **/ $this->mergeContacts($originalContactID, $duplicateContactID1, array( - "move_{$customFieldName}" => null, + "move_{$customFieldName}" => NULL, )); $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName); @@ -562,7 +562,7 @@ public function testMigrationOfUnselectedCustomDataOnEmptyCustomRecord() { $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}"); $this->mergeContacts($originalContactID, $duplicateContactID, array( - "move_custom_{$customField1['id']}" => null, + "move_custom_{$customField1['id']}" => NULL, )); $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); @@ -599,7 +599,7 @@ public function testMigrationOfSomeCustomDataOnEmptyCustomRecord() { // Perform merge $this->mergeContacts($originalContactID, $duplicateContactID, array( - "move_custom_{$customField1['id']}" => null, + "move_custom_{$customField1['id']}" => NULL, "move_custom_{$customField2['id']}" => 'def', )); $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); From 4b047375cf185613b1ccd8a768eaf1fa646a82de Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Wed, 9 Aug 2017 17:28:54 +0000 Subject: [PATCH 09/14] CRM-20858: Fix Failing Test on Custom Field Merge Test for merging custom fields with is_view flag on was failing. This was happening because the same field was being used on prior tests, setting the is_view flag at the start of the failing test. Fixed by creating a new custom field with the is_view flag set as 1, and using that field on the test. --- tests/phpunit/api/v3/JobTestCustomDataTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 tests/phpunit/api/v3/JobTestCustomDataTest.php diff --git a/tests/phpunit/api/v3/JobTestCustomDataTest.php b/tests/phpunit/api/v3/JobTestCustomDataTest.php old mode 100644 new mode 100755 index 2f656fd5d23..54f6523d2ac --- a/tests/phpunit/api/v3/JobTestCustomDataTest.php +++ b/tests/phpunit/api/v3/JobTestCustomDataTest.php @@ -240,7 +240,8 @@ public function testBatchMergeDateCustomFieldHandling() { */ public function testBatchMergeDateCustomFieldHandlingIsView() { $this->customFieldCreate(array( - 'id' => $this->customFieldID, + 'label' => 'OnlyView', + 'custom_group_id' => $this->customGroupID, 'is_view' => 1, )); $customFieldLabel = 'custom_' . $this->customFieldID; @@ -249,7 +250,7 @@ public function testBatchMergeDateCustomFieldHandlingIsView() { $result = $this->callAPISuccess('Job', 'process_batch_merge', array()); $this->assertEquals(1, count($result['values']['merged'])); $contact = $this->callAPISuccess('Contact', 'getsingle', array('id' => $contactID, 'return' => $customFieldLabel)); - $this->assertEquals('2012-11-03', $contact[$customFieldLabel]); + $this->assertEquals('2012-11-03 00:00:00', $contact[$customFieldLabel]); } /** From 0556db5dbd30f3d109a1685a6f78762bb9ecb9a4 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Mon, 21 Aug 2017 16:12:00 +0000 Subject: [PATCH 10/14] CRM-20858: Call moveContactBelongings Only Once moveContactBelongings() was bing called twice, first to move selected related tables, and the second to move all other tables that reference contacts table. Refactored moveContactBelongings() method so that it can be called only once, by calculating in one go the tables that have to be taken into account when merging, according to what has been selected to move. Basically, it searches for all tables related to the contact, removes related tables, and then includes only those related tables selected to be merged. --- CRM/Dedupe/Merger.php | 53 ++++++++++--------------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index c227be0cca2..e09ef11d04d 100755 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -455,36 +455,16 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, } $affected = array_merge(array_keys($cidRefs), array_keys($eidRefs)); - if ($tables !== FALSE) { - // if there are specific tables, sanitize the list - $affected = array_unique(array_intersect($affected, $tables)); - } - else { - // if there aren't any specific tables, don't affect the ones handled by relTables() - // also don't affect tables in locTables() CRM-15658 - $relTables = self::relTables(); - $handled = self::locTables(); - foreach ($relTables as $params) { - $handled = array_merge($handled, $params['tables']); - } - $affected = array_diff($affected, $handled); - /** - * CRM-12695 - * Set $membershipMerge flag only once - * while doing contact related migration - * to call addMembershipToRealtedContacts() - * function only once. - * Since the current function (moveContactBelongings) is called twice - * with & without parameters $tables & $tableOperations - */ - // retrieve main contact's related table(s) - $activeMainRelTables = CRM_Dedupe_Merger::getActiveRelTables($mainId); - // check if membership table exists in main contact's related table(s) - // set membership flag - CRM-12695 - if (in_array('rel_table_memberships', $activeMainRelTables)) { - $membershipMerge = TRUE; - } + + // if there aren't any specific tables, don't affect the ones handled by relTables() + // also don't affect tables in locTables() CRM-15658 + $relTables = self::relTables(); + $handled = self::locTables(); + + foreach ($relTables as $params) { + $handled = array_merge($handled, $params['tables']); } + $affected = array_diff($affected, $handled); $mainId = (int) $mainId; $otherId = (int) $otherId; @@ -547,11 +527,7 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, foreach ($sqls as $sql) { CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE); } - // CRM-12695 - if ($membershipMerge) { - // call to function adding membership to related contacts - CRM_Dedupe_Merger::addMembershipToRealtedContacts($mainId); - } + CRM_Dedupe_Merger::addMembershipToRealtedContacts($mainId); $transaction->commit(); } @@ -1539,15 +1515,10 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che } self::mergeLocations($mainId, $otherId, $locationMigrationInfo, $migrationInfo); - // **** Do tables related migrations - if (!empty($moveTables)) { - CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, $moveTables, $tableOperations); - unset($moveTables, $tableOperations); - } - // **** Do contact related migrations $customTablesToCopyValues = self::getAffectedCustomTables($submittedCustomFields); - CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, FALSE, array(), $customTablesToCopyValues); + CRM_Dedupe_Merger::moveContactBelongings($mainId, $otherId, $moveTables, $tableOperations, $customTablesToCopyValues); + unset($moveTables, $tableOperations); // FIXME: fix gender, prefix and postfix, so they're edible by createProfileContact() $names['gender'] = array('newName' => 'gender_id', 'groupName' => 'gender'); From 08b000992b37d28ec5bda903080a8991ae09dc46 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Mon, 21 Aug 2017 18:10:44 +0000 Subject: [PATCH 11/14] CRM-20858: Remove Try/Catch Blocks that Ignored Caught Exceptions The try catch blocks were apparently added because not all fields passed were custom fields, generating exceptions when the API call was made to obtain its option group. This happened because actually all fields selected for merge were being inserted into the $submittedCustomFields array, instead of just custom fields. Plus, obtaining the field's ID on a field that was not custom rendered strange strings to be used on search of the field, as this ID is obtained by getting a substring from the field's key, that should have the format 'move_custom_' (fields that are not custom don't have that format). --- CRM/Dedupe/Merger.php | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index e09ef11d04d..3a3204c3797 100755 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -1489,19 +1489,18 @@ public static function moveAllBelongings($mainId, $otherId, $migrationInfo, $che if ($value == $qfZeroBug) { $value = '0'; } - if ((in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) || - substr($key, 0, 12) == 'move_custom_') && - $value != NULL - ) { + + if (substr($key, 0, 12) == 'move_custom_' && $value != NULL) { $submitted[substr($key, 5)] = $value; $submittedCustomFields[] = substr($key, 12); } - + elseif (in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) && $value != NULL) { + $submitted[substr($key, 5)] = $value; + } // Set up initial information for handling migration of location blocks elseif (substr($key, 0, 14) == 'move_location_' and $value != NULL) { $locationMigrationInfo[$key] = $value; } - elseif (substr($key, 0, 15) == 'move_rel_table_' and $value == '1') { $moveTables = array_merge($moveTables, $relTables[substr($key, 5)]['tables']); if (array_key_exists('operation', $migrationInfo)) { @@ -1777,28 +1776,15 @@ private static function getAffectedCustomTables($customFieldIDs) { foreach ($customFieldIDs as $fieldID) { if (!empty($fieldID)) { - $customField = NULL; - try { - $customField = civicrm_api3('custom_field', 'getsingle', array( - 'id' => $fieldID, + $customField = civicrm_api3('custom_field', 'getsingle', array( + 'id' => $fieldID, + 'is_active' => TRUE, + )); + if (!civicrm_error($customField) && !empty($customField['custom_group_id'])) { + $customGroup = civicrm_api3('custom_group', 'getsingle', array( + 'id' => $customField['custom_group_id'], 'is_active' => TRUE, )); - } - catch (CiviCRM_API3_Exception $e) { - continue; - } - if (!civicrm_error($customField) && !empty($customField['custom_group_id'])) { - $customGroup = NULL; - try { - $customGroup = civicrm_api3('custom_group', 'getsingle', array( - 'id' => $customField['custom_group_id'], - 'is_active' => TRUE, - )); - } - catch (CiviCRM_API3_Exception $e) { - // just ignore and continue - continue; - } if (!civicrm_error($customGroup) && !empty($customGroup['table_name'])) { $customTableToCopyValues[] = $customGroup['table_name']; From e3159b0743b9424336dec30e72ee14141f10c989 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Tue, 22 Aug 2017 10:26:49 +0000 Subject: [PATCH 12/14] CRM-20858: Fix Merging of Related Tables Left out selected related tables from affected tables array, which caused several tests to fail. Merged tables array into affected tables array. --- CRM/Dedupe/Merger.php | 1 + 1 file changed, 1 insertion(+) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 3a3204c3797..6c75da25329 100755 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -465,6 +465,7 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $handled = array_merge($handled, $params['tables']); } $affected = array_diff($affected, $handled); + $affected = array_unique(array_merge($affected, $tables)); $mainId = (int) $mainId; $otherId = (int) $otherId; From 597697a7e5e43a2e99376974b4d15e3a6017aad4 Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Tue, 22 Aug 2017 10:46:25 +0000 Subject: [PATCH 13/14] CRM-20858: Set File's Permissions back to 644 --- CRM/Dedupe/Merger.php | 0 tests/phpunit/CRM/Dedupe/MergerTest.php | 0 tests/phpunit/api/v3/JobTestCustomDataTest.php | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 CRM/Dedupe/Merger.php mode change 100755 => 100644 tests/phpunit/CRM/Dedupe/MergerTest.php mode change 100755 => 100644 tests/phpunit/api/v3/JobTestCustomDataTest.php diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php old mode 100755 new mode 100644 diff --git a/tests/phpunit/CRM/Dedupe/MergerTest.php b/tests/phpunit/CRM/Dedupe/MergerTest.php old mode 100755 new mode 100644 diff --git a/tests/phpunit/api/v3/JobTestCustomDataTest.php b/tests/phpunit/api/v3/JobTestCustomDataTest.php old mode 100755 new mode 100644 From ad1b13f4a31d6391bf1b851f6a89205bf335e78c Mon Sep 17 00:00:00 2001 From: Camilo Rodriguez Date: Thu, 31 Aug 2017 13:38:12 +0000 Subject: [PATCH 14/14] CRM-20858: Remove Uneeded Variable --- CRM/Dedupe/Merger.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 6c75da25329..81b80f6658d 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -444,8 +444,6 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $eidRefs = self::eidRefs(); $cpTables = self::cpTables(); $paymentTables = self::paymentTables(); - // CRM-12695: - $membershipMerge = FALSE; // getting all custom tables $customTables = array();