From eb5f72608dc2811d15e2eef1e57c9b77f0e67046 Mon Sep 17 00:00:00 2001 From: eileenmcnaugton Date: Fri, 25 Sep 2015 00:08:10 +1200 Subject: [PATCH] CRM-17275 Import - allow contact WITH external identifier to match one without --- CRM/Contact/Import/Parser/Contact.php | 21 ++++++++++ CRM/Utils/DeprecatedUtils.php | 4 ++ api/v3/Contact.php | 39 +++++++++++++++++++ .../CRM/Contact/Import/Parser/ContactTest.php | 22 +++++++++++ 4 files changed, 86 insertions(+) diff --git a/CRM/Contact/Import/Parser/Contact.php b/CRM/Contact/Import/Parser/Contact.php index 994c4e000c..b3f3b8ef59 100644 --- a/CRM/Contact/Import/Parser/Contact.php +++ b/CRM/Contact/Import/Parser/Contact.php @@ -523,6 +523,27 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser { if ($cid = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['external_identifier'], 'id', 'external_identifier')) { $formatted['id'] = $cid; } + else { + // CRM-17275 - External identifier is treated as a special field/ + // Having it set will inhibit various efforts to retrieve a duplicate + // However, it is valid to update a contact with no external identifier to having + // an external identifier if they match according to the dedupe rules so + // we check for that possibility here. + // There is probably a better approach but this fix is the FIRST (!#!) time + /// unit tests have been added to this & we need to build those up a bit before + // doing much else in here. Remember when you have build a house of card the + // golden rule ... walk away ... carefully. + // (did I mention unit tests...) + $checkParams = array('check_permissions' => FALSE, 'match' => $params); + unset($checkParams['match']['external_identifier']); + $checkParams['match']['contact_type'] = $this->_contactType; + $possibleMatches = civicrm_api3('Contact', 'duplicatecheck', $checkParams); + foreach (array_keys($possibleMatches['values']) as $possibleID) { + if (!CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $possibleID, 'external_identifier', 'id')) { + $formatted['id'] = $cid = $possibleID; + } + } + } } //format common data, CRM-4062 diff --git a/CRM/Utils/DeprecatedUtils.php b/CRM/Utils/DeprecatedUtils.php index 361b3625f3..73bc504b32 100644 --- a/CRM/Utils/DeprecatedUtils.php +++ b/CRM/Utils/DeprecatedUtils.php @@ -1428,6 +1428,10 @@ function _civicrm_api3_deprecated_contact_check_params( } if ($dupeCheck) { + // @todo switch to using api version by uncommenting these lines & removing following 11. + // Any change here is too scary for a stable release. + // $dupes = civicrm_api3('Contact', 'duplicatecheck', (array('match' => $params, 'dedupe_rule_id' => $dedupeRuleGroupID))); + // $ids = $dupes['count'] ? implode(',', array_keys($dupes['values'])) : NULL; // check for record already existing require_once 'CRM/Dedupe/Finder.php'; $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); diff --git a/api/v3/Contact.php b/api/v3/Contact.php index ba2f3dedbd..8703f3ba35 100644 --- a/api/v3/Contact.php +++ b/api/v3/Contact.php @@ -1181,3 +1181,42 @@ function _civicrm_api3_contact_getlist_output($result, $request) { } return $output; } + +/** + * Check for duplicate contacts. + * + * @param array $params + * Params per getfields metadata. + * + * @return array + * API formatted array + */ +function civicrm_api3_contact_duplicatecheck($params) { + $dedupeParams = CRM_Dedupe_Finder::formatParams($params['match'], $params['match']['contact_type']); + + // CRM-6431 + // setting 'check_permission' here means that the dedupe checking will be carried out even if the + // person does not have permission to carry out de-dupes + // this is similar to the front end form + if (isset($params['check_permission'])) { + $dedupeParams['check_permission'] = $params['check_permission']; + } + + $dupes = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['match']['contact_type'], 'Unsupervised', array(), CRM_Utils_Array::value('dedupe_rule_id', $params)); + $values = empty($dupes) ? array() : array_fill_keys($dupes, array()); + return civicrm_api3_create_success($values, $params, 'Contact', 'duplicatecheck'); +} + +/** + * Declare metadata for contact dedupe function. + * + * @param $params + */ +function _civicrm_api3_contact_duplicatecheck_spec(&$params) { + $params['dedupe_rule_id'] = array( + 'title' => 'Dedupe Rule ID (optional)', + 'description' => 'This will default to the built in unsupervised rule', + 'type' => CRM_Utils_Type::T_INT, + ); + // @todo declare 'match' parameter. We don't have a standard for type = array yet. +} diff --git a/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php b/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php index bb3334540e..ffb85d4860 100644 --- a/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php +++ b/tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php @@ -92,6 +92,28 @@ class CRM_Contact_Imports_Parser_ContactTest extends CiviUnitTestCase { $this->callAPISuccessGetSingle('Contact', $originalValues); } + /** + * Test that the import parser updates when a new external identifier is set. + * + * @throws \Exception + */ + public function testImportParserWithUpdateWithNewExternalIdentifier() { + $originalValues = array( + 'first_name' => 'Bill', + 'last_name' => 'Gates', + 'email' => 'bill.gates@microsoft.com', + 'nick_name' => 'Billy-boy', + ); + $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID); + $result = $this->callAPISuccessGetSingle('Contact', $originalValues); + $originalValues['nick_name'] = 'Old Bill'; + $originalValues['external_identifier'] = 'windows'; + $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID); + $originalValues['id'] = $result['id']; + $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $result['id'], 'return' => 'nick_name'))); + $this->callAPISuccessGetSingle('Contact', $originalValues); + } + /** * Run the import parser. * -- 2.25.1