// Rule: Catch address conflicts (same address type on both contacts)
if ($fieldName == 'address') {
- $mainNewLocTypeId = $migrationInfo['location_blocks'][$fieldName][$fieldCount]['locTypeId'];
if (
isset($migrationInfo['main_details']['location_blocks']['address']) &&
!empty($migrationInfo['main_details']['location_blocks']['address'])
) {
+ $otherAddresses = $migrationInfo['other_details']['location_blocks']['address'];
+ $otherAddressLookup = array();
+ foreach ($otherAddresses as $otherAddressIndex => $otherAddress) {
+ $otherAddressLookup[$otherAddress['location_type_id']] = $otherAddressIndex;
+ }
// Look for this LocTypeId in the results
// @todo This can be streamlined using array_column() in PHP 5.5+
foreach ($migrationInfo['main_details']['location_blocks']['address'] as $addressKey => $addressRecord) {
- if ($addressRecord['location_type_id'] == $mainNewLocTypeId) {
+ $otherAddressIndex = CRM_Utils_Array::value($addressRecord['location_type_id'], $otherAddressLookup);
+ $hasMatchingAddress = FALSE;
+ foreach ($otherAddresses as $otherAddress) {
+ if (self::addressIsSame($addressRecord, $otherAddress)) {
+ $hasMatchingAddress = TRUE;
+ }
+ }
+ if ($hasMatchingAddress) {
+ unset($migrationInfo[$key]);
+ }
+ elseif (!empty($otherAddresses[$otherAddressIndex]) && !self::addressIsSame($addressRecord, $otherAddresses[$otherAddressIndex])) {
$conflicts[$key] = NULL;
break;
}
}
-
}
}
// For other locations, don't merge/add if the values are the same
return FALSE;
}
+ /**
+ * Compare 2 addresses to see if they are the same.
+ *
+ * @param array $mainAddress
+ * @param array $comparisonAddress
+ *
+ * @return bool
+ */
+ static protected function addressIsSame($mainAddress, $comparisonAddress) {
+ $keysToIgnore = array('id', 'is_primary', 'is_billing', 'manual_geo_code', 'contact_id');
+ foreach ($comparisonAddress as $field => $value) {
+ if (in_array($field, $keysToIgnore)) {
+ continue;
+ }
+ if (!empty($value) && $mainAddress[$field] != $value) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
/**
* A function to build an array of information about location blocks that is
* required when merging location fields
), 4);
}
+ /**
+ * Test the batch merge does not create duplicate emails.
+ *
+ * Test CRM-18546, a 4.7 regression whereby a merged contact gets duplicate emails.
+ */
+ public function testBatchMergeMatchingAddress() {
+ for ($x = 0; $x <= 2; $x++) {
+ $this->individualCreate(array(
+ 'api.address.create' => array(
+ 'location_type_id' => 'Home',
+ 'street_address' => 'Appt 115, The Batcave',
+ 'city' => 'Gotham',
+ 'postal_code' => 'Nananananana',
+ ),
+ ));
+ }
+ // Different location type, still merge, identical.
+ $this->individualCreate(array(
+ 'api.address.create' => array(
+ 'location_type_id' => 'Main',
+ 'street_address' => 'Appt 115, The Batcave',
+ 'city' => 'Gotham',
+ 'postal_code' => 'Nananananana',
+ ),
+ ));
+
+ $this->individualCreate(array(
+ 'api.address.create' => array(
+ 'location_type_id' => 'Home',
+ 'street_address' => 'Appt 115, The Batcave',
+ 'city' => 'Gotham',
+ 'postal_code' => 'Batman',
+ ),
+ ));
+
+ $result = $this->callAPISuccess('Job', 'process_batch_merge', array());
+ $this->assertEquals(3, count($result['values']['merged']));
+ $this->assertEquals(1, count($result['values']['skipped']));
+ $this->callAPISuccessGetCount('Contact', array('street_address' => 'Appt 115, The Batcave'), 2);
+ $contacts = $this->callAPISuccess('Contact', 'get', array('is_deleted' => 0));
+ $deletedContacts = $this->callAPISuccess('Contact', 'get', array('is_deleted' => 1));
+ $this->callAPISuccessGetCount('Address', array(
+ 'street_address' => 'Appt 115, The Batcave',
+ 'contact_id' => array('IN' => array_keys($contacts['values'])),
+ ), 3);
+
+ $this->callAPISuccessGetCount('Address', array(
+ 'street_address' => 'Appt 115, The Batcave',
+ 'contact_id' => array('IN' => array_keys($deletedContacts['values'])),
+ ), 2);
+ }
+
/**
* Test the batch merge by id range.
*