CRM-17275 Import - allow contact WITH external identifier to match one without
authoreileenmcnaugton <eileen@fuzion.co.nz>
Thu, 24 Sep 2015 12:08:10 +0000 (00:08 +1200)
committermonishdeb <monish.deb@webaccessglobal.com>
Wed, 30 Sep 2015 12:50:57 +0000 (18:20 +0530)
CRM/Contact/Import/Parser/Contact.php
CRM/Utils/DeprecatedUtils.php
api/v3/Contact.php
tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php

index 994c4e000cc68dc577416c0a424563609ef0566a..b3f3b8ef59c3769596e89b93839d9076ec5c6dca 100644 (file)
@@ -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
index 361b3625f3bad3103872550e02dc1c30e85c85c6..73bc504b324da4db625736a8257aea6d169ba1f9 100644 (file)
@@ -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']);
index ba2f3dedbd15d968ea4096b0e5b544fb48f26510..8703f3ba35d35bb9e7532c1c6cc6bfc3fb74a930 100644 (file)
@@ -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.
+}
index bb3334540e6ef7e05f93765ae7da464dd85b00df..ffb85d4860a46147c696888b102d29d57797c5a7 100644 (file)
@@ -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.
    *