Fix employer not carrying over correctly in merge
authorEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 6 Apr 2023 06:12:24 +0000 (18:12 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 10 Apr 2023 22:31:21 +0000 (10:31 +1200)
This addresses a deduper bug where selecting the employer_id to
carry over in the form does NOT result in the newly
merged contact having that organization's name
in it's organization_name field

CRM/Contact/Form/Merge.php
CRM/Dedupe/Merger.php

index 127731292deb63a3f3270d384d6464c1d39a8397..c59df6e82f6f2ebb2ac9a27687a20b2467e8d9b1 100644 (file)
@@ -168,8 +168,8 @@ class CRM_Contact_Form_Merge extends CRM_Core_Form {
       $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('main_cid', $main['id']);
+      $this->assign('other_cid', $other['id']);
       $this->assign('rgid', $this->_rgid);
       $this->assignSummaryRowsToTemplate($contacts);
 
index 9e11ed3a1c263e5e701359cbf9afdd816fdca5f4..1e1a6d6a0d2de060b9527903b052ba1a1aa42e16 100644 (file)
@@ -1006,6 +1006,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
             ($key === 'current_employer' && empty($params['current_employer']))) {
             // CRM-10128: if auth source is not checksum / login && $value is blank, do not fill $data with empty value
             // to avoid update with empty values
+            CRM_Core_Error::deprecatedWarning('code should be unreachable, slated for removal');
             continue;
           }
           else {
@@ -1528,7 +1529,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    */
   public static function getRowsElementsAndInfo(int $mainID, int $otherID, bool $checkPermissions = TRUE) {
     $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9';
-    $fields = self::getMergeFieldsMetadata();
+    $fields = self::getMergeFieldsMetadata($checkPermissions);
 
     $main = self::getMergeContactDetails($mainID);
     $other = self::getMergeContactDetails($otherID);
@@ -2118,26 +2119,7 @@ ORDER BY civicrm_custom_group.weight,
 
     // **** Update contact related info for the main contact
     if (!empty($submitted)) {
-      $submitted['contact_id'] = $mainId;
-
-      //update current employer field
-      if ($currentEmloyerId = CRM_Utils_Array::value('current_employer_id', $submitted)) {
-        if (!CRM_Utils_System::isNull($currentEmloyerId)) {
-          $submitted['current_employer'] = $submitted['current_employer_id'];
-        }
-        else {
-          $submitted['current_employer'] = '';
-        }
-        unset($submitted['current_employer_id']);
-      }
-
-      //CRM-14312 include prefix/suffix from mainId if not overridden for proper construction of display/sort name
-      if (!isset($submitted['prefix_id']) && !empty($migrationInfo['main_details']['prefix_id'])) {
-        $submitted['prefix_id'] = $migrationInfo['main_details']['prefix_id'];
-      }
-      if (!isset($submitted['suffix_id']) && !empty($migrationInfo['main_details']['suffix_id'])) {
-        $submitted['suffix_id'] = $migrationInfo['main_details']['suffix_id'];
-      }
+      $submitted['id'] = $mainId;
       self::updateContact($mainId, $submitted);
     }
     $transaction->commit();
@@ -2152,26 +2134,11 @@ ORDER BY civicrm_custom_group.weight,
    *
    * @return array
    *   Array of field names to be potentially merged.
+   * @throws \CRM_Core_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public static function getContactFields() {
-    $contactFields = CRM_Contact_DAO_Contact::fields();
-    $invalidFields = [
-      'api_key',
-      'created_date',
-      'display_name',
-      'hash',
-      'id',
-      'modified_date',
-      'primary_contact_id',
-      'sort_name',
-      'user_unique_id',
-    ];
-    foreach ($contactFields as $field => $value) {
-      if (in_array($field, $invalidFields)) {
-        unset($contactFields[$field]);
-      }
-    }
-    return array_keys($contactFields);
+  public static function getContactFields(): array {
+    return array_keys(self::getMergeFieldsMetadata(FALSE));
   }
 
   /**
@@ -2330,49 +2297,57 @@ ORDER BY civicrm_custom_group.weight,
    * This is basically the contact metadata, augmented with fields to
    * represent email greeting, postal greeting & addressee.
    *
+   * @param bool $checkPermissions
+   *
    * @return array
+   * @throws \CRM_Core_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public static function getMergeFieldsMetadata() {
-    if (isset(\Civi::$statics[__CLASS__]) && isset(\Civi::$statics[__CLASS__]['merge_fields_metadata'])) {
-      return \Civi::$statics[__CLASS__]['merge_fields_metadata'];
-    }
-    $fields = CRM_Contact_DAO_Contact::fields();
-    static $optionValueFields = [];
-    if (empty($optionValueFields)) {
+  public static function getMergeFieldsMetadata(bool $checkPermissions = TRUE): array {
+    if (!isset(\Civi::$statics[__CLASS__]['merge_fields_metadata'][(int) $checkPermissions])) {
+      $contactFields = (array) Contact::getFields($checkPermissions)
+        ->execute()
+        ->indexBy('name');
+      $invalidFields = self::ignoredFields('contact');
+      foreach ($contactFields as $field => $value) {
+        if (in_array($field, $invalidFields, TRUE)) {
+          unset($contactFields[$field]);
+        }
+      }
       $optionValueFields = CRM_Core_OptionValue::getFields();
+      foreach ($optionValueFields as $field => $params) {
+        $contactFields[$field]['title'] = $params['title'];
+      }
+      \Civi::$statics[__CLASS__]['merge_fields_metadata'][(int) $checkPermissions] = $contactFields;
     }
-    foreach ($optionValueFields as $field => $params) {
-      $fields[$field]['title'] = $params['title'];
-    }
-    \Civi::$statics[__CLASS__]['merge_fields_metadata'] = $fields;
-    return \Civi::$statics[__CLASS__]['merge_fields_metadata'];
+    return \Civi::$statics[__CLASS__]['merge_fields_metadata'][(int) $checkPermissions];
   }
 
   /**
    * Get the details of the contact to be merged.
    *
-   * @param int $contact_id
+   * @param int $contactID
    *
    * @return array
    *
    * @throws CRM_Core_Exception
    */
-  public static function getMergeContactDetails($contact_id) {
+  public static function getMergeContactDetails($contactID): array {
     $params = [
-      'contact_id' => $contact_id,
+      'contact_id' => $contactID,
       'version' => 3,
       'return' => array_merge(['display_name'], self::getContactFields()),
     ];
-    $result = civicrm_api('contact', 'get', $params);
+    $result = Contact::get(FALSE)->addWhere('id', '=', $contactID)->execute()->first();
 
     // CRM-18480: Cancel the process if the contact is already deleted
-    if (isset($result['values'][$contact_id]['contact_is_deleted']) && !empty($result['values'][$contact_id]['contact_is_deleted'])) {
+    if (isset($result['is_deleted']) && !empty($result['is_deleted'])) {
       throw new CRM_Core_Exception(ts('Cannot merge because one contact (ID %1) has been deleted.', [
-        1 => $contact_id,
+        1 => $contactID,
       ]));
     }
 
-    return $result['values'][$contact_id];
+    return $result;
   }
 
   /**
@@ -2776,19 +2751,38 @@ ORDER BY civicrm_custom_group.weight,
   }
 
   /**
+   * Get fields that should not be transferred.
+   *
+   * This is primarily because they are calculated.
+   *
+   * @param string $type
+   *
    * @return array
    */
-  protected static function ignoredFields(): array {
+  protected static function ignoredFields(string $type = 'location'): array {
     $keysToIgnore = [
-      'id',
-      'is_primary',
-      'is_billing',
-      'manual_geo_code',
-      'contact_id',
-      'reset_date',
-      'hold_date',
+      'location' => [
+        'id',
+        'is_primary',
+        'is_billing',
+        'manual_geo_code',
+        'contact_id',
+        'reset_date',
+        'hold_date',
+      ],
+      'contact' => [
+        'api_key',
+        'created_date',
+        'display_name',
+        'hash',
+        'id',
+        'modified_date',
+        'primary_contact_id',
+        'sort_name',
+        'user_unique_id',
+      ],
     ];
-    return $keysToIgnore;
+    return $keysToIgnore[$type];
   }
 
   /**
@@ -2833,11 +2827,11 @@ ORDER BY civicrm_custom_group.weight,
         $label = ts('[x]');
       }
     }
-    elseif (!empty($fieldSpec['pseudoconstant'])) {
+    elseif (!empty($fieldSpec['options'])) {
       $label = CRM_Core_PseudoConstant::getLabel('CRM_Contact_BAO_Contact', $field, $value);
     }
-    elseif ($field == 'current_employer_id' && !empty($value)) {
-      $label = "$value (" . CRM_Contact_BAO_Contact::displayName($value) . ")";
+    elseif ($field === 'employer_id' && !empty($value)) {
+      $label = "$value (" . CRM_Contact_BAO_Contact::displayName($value) . ')';
     }
     return ['label' => $label, 'value' => $value];
   }