hide view only custom fields on merge screen
authorJamie McClelland <jm@mayfirst.org>
Tue, 11 Jul 2023 17:18:24 +0000 (13:18 -0400)
committerJamie McClelland <jm@mayfirst.org>
Fri, 14 Jul 2023 15:36:47 +0000 (11:36 -0400)
And, ensure they are not merged. View only fields with values on the
duplicate that is being discarded will be discarded.

CRM/Dedupe/Merger.php
tests/phpunit/CRM/Dedupe/MergerTest.php
tests/phpunit/api/v3/JobTest.php

index f1e54bbaa1e19b4d13b9af537bc97a0ebe500fda..b1e5e44dcc918ac076cc7e85ddc45c3ead3829b9 100644 (file)
@@ -1642,12 +1642,16 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       $checkPermissions ? CRM_Core_Permission::EDIT : FALSE
     );
 
+    $ignoredCustomFields = self::ignoredFields('custom');
     foreach ($otherTree as $gid => $group) {
       if (!isset($group['fields'])) {
         continue;
       }
 
       foreach ($group['fields'] as $fid => $field) {
+        if (in_array($group['name'] . '.' . $field['name'], $ignoredCustomFields)) {
+          continue;
+        }
         $mainContactValue = $mainTree[$gid]['fields'][$fid]['customValue'] ?? NULL;
         $otherContactValue = $otherTree[$gid]['fields'][$fid]['customValue'] ?? NULL;
         if (in_array($fid, $compareFields['custom'])) {
@@ -2031,8 +2035,6 @@ ORDER BY civicrm_custom_group.weight,
       $submitted = [];
     }
 
-    // Move view only custom fields CRM-5362
-    $viewOnlyCustomFields = [];
     foreach ($submitted as $key => $value) {
       if (strpos($key, 'custom_') === 0) {
         $fieldID = (int) substr($key, 7);
@@ -2041,20 +2043,13 @@ ORDER BY civicrm_custom_group.weight,
           $htmlType = (string) $fieldMetadata['html_type'];
           $isSerialized = CRM_Core_BAO_CustomField::isSerialized($fieldMetadata);
           $isView = (bool) $fieldMetadata['is_view'];
-          if ($isView) {
-            $viewOnlyCustomFields[$key] = $value;
+          if (!$isView) {
+            $submitted = self::processCustomFields($mainId, $key, $submitted, $value, $fieldID, $isView, $htmlType, $isSerialized);
           }
-          $submitted = self::processCustomFields($mainId, $key, $submitted, $value, $fieldID, $isView, $htmlType, $isSerialized);
         }
       }
     }
 
-    // special case to set values for view only, CRM-5362
-    if (!empty($viewOnlyCustomFields)) {
-      $viewOnlyCustomFields['entityID'] = $mainId;
-      CRM_Core_BAO_CustomValueTable::setValues($viewOnlyCustomFields);
-    }
-
     // dev/core#996 Ensure that the earliest created date is stored against the kept contact id
     $mainCreatedDate = civicrm_api3('Contact', 'getsingle', [
       'id' => $mainId,
@@ -2761,7 +2756,18 @@ ORDER BY civicrm_custom_group.weight,
         'postal_greeting_display',
         'addressee_display',
       ],
+      'custom' => [],
     ];
+
+    $readOnlyCustomFields = \Civi\Api4\CustomField::get(FALSE)
+      ->addSelect('custom_group_id.name', 'name')
+      ->addWhere('is_view', '=', TRUE)
+      ->addWhere('custom_group_id.extends', 'IN', ['Individual', 'Household', 'Organization', 'Contact'])
+      ->execute();
+    foreach ($readOnlyCustomFields as $field) {
+      $keysToIgnore['custom'][] = $field['custom_group_id.name'] . '.' . $field['name'];
+    }
+
     return $keysToIgnore[$type];
   }
 
index e4466f3e9cd62510116293efb2b2b474abe24d87..0ef8d6cd6cfffed5f264a70a3ef52deb1e392351 100644 (file)
@@ -1046,6 +1046,42 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
     $this->callAPISuccess('CustomGroup', 'delete', ['id' => $activityGroup['id']]);
   }
 
+  /**
+   * Verifies that when two contacts with view only custom fields are merged,
+   * the view only field of the record being deleted is not merged, it is
+   * simply deleted (it should also not be visible on the page).
+   */
+  public function testMigrationOfViewOnlyCustomData() {
+    // Create Custom Fields
+    $createGroup = $this->setupCustomGroupForIndividual();
+    $customField = $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', [
+      'id' => $duplicateContactID,
+      "custom_{$customField['id']}" => 'abc',
+    ]);
+    $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField['id']}");
+
+    // Change custom field to view only.
+    $this->callAPISuccess('CustomField', 'update', ['id' => $customField['id'], 'is_view' => TRUE]);
+
+    // Merge, and ensure that no value was migrated
+    $this->mergeContacts($originalContactID, $duplicateContactID, [
+      "move_custom_{$customField['id']}" => NULL,
+    ]);
+    $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField['id']}");
+
+    // cleanup created custom set
+    $this->callAPISuccess('CustomField', 'delete', ['id' => $customField['id']]);
+    $this->callAPISuccess('CustomGroup', 'delete', ['id' => $createGroup['id']]);
+  }
+
   /**
    * Calls merge method on given contacts, with values given in $params array.
    *
index dd55035deee64f0c11b50d0fc0abfe347eeaee0f..d1b1dee9ed0905165c2e2d97f8dc2a275db90b8e 100644 (file)
@@ -1070,7 +1070,8 @@ class api_v3_JobTest extends CiviUnitTestCase {
   }
 
   /**
-   * Test the batch merge copes with view only custom data field.
+   * Test the batch merge copes with view only custom data field. View Only custom fields
+   * should never be merged.
    */
   public function testBatchMergeCustomDataViewOnlyField(): void {
     CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'edit my contact'];
@@ -1085,7 +1086,7 @@ class api_v3_JobTest extends CiviUnitTestCase {
     $this->assertCount(1, $result['values']['merged']);
     $mouseParams['return'] = 'custom_' . $customField['id'];
     $mouse = $this->callAPISuccess('Contact', 'getsingle', $mouseParams);
-    $this->assertEquals('blah', $mouse['custom_' . $customField['id']]);
+    $this->assertEquals('', $mouse['custom_' . $customField['id']]);
   }
 
   /**