CRM-19179: Allow primary location block to be changed during manual merge
authorJKingsnorth <john@johnkingsnorth.co.uk>
Thu, 18 Aug 2016 14:52:01 +0000 (15:52 +0100)
committerJKingsnorth <john@johnkingsnorth.co.uk>
Thu, 18 Aug 2016 14:52:01 +0000 (15:52 +0100)
CRM/Dedupe/Merger.php
templates/CRM/Contact/Form/Merge.tpl

index 78460f923f4d1c4a9e881b453b356fe7f1e1cba5..625756223c32eebd954d4882830ac110b8394501 100644 (file)
@@ -1237,6 +1237,9 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
           // Add checkbox to migrate data from 'other' to 'main'
           $elements[] = array('advcheckbox', "move_location_{$blockName}_{$count}");
 
+          // Add checkbox to set the 'other' location as primary
+          $elements[] = array('advcheckbox', "location_blocks[$blockName][$count][set_other_primary]", NULL, ts('Set as primary'));
+
           // Flag up this field to skipMerge function (@todo: do we need to?)
           $migrationInfo["move_location_{$blockName}_{$count}"] = 1;
 
@@ -1275,7 +1278,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
             // @todo Check this logic out
             $migrationInfo['location_blocks'][$blockName][$count]['locTypeId'] = $thisLocId;
             if ($blockName != 'address') {
-              $elements[] = array('advcheckbox', "location_blocks[{$blockName}][$count][operation]", NULL, ts('add new'));
+              $elements[] = array('advcheckbox', "location_blocks[{$blockName}][$count][operation]", NULL, ts('Add new'));
               // always use add operation
               $migrationInfo['location_blocks'][$blockName][$count]['operation'] = 1;
             }
@@ -2083,6 +2086,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
           continue;
         }
         $daoName = 'CRM_Core_DAO_' . $locationBlocks[$name]['label'];
+        $changePrimary = FALSE;
         $primaryDAOId = (array_key_exists($name, $primaryBlockIds)) ? array_pop($primaryBlockIds[$name]) : NULL;
         $billingDAOId = (array_key_exists($name, $billingBlockIds)) ? array_pop($billingBlockIds[$name]) : NULL;
 
@@ -2110,10 +2114,26 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
             $otherBlockDAO->{$locationBlocks[$name]['hasType']} = $typeTypeId;
           }
 
-          // if main contact already has primary & billing, set the flags to 0.
-          if ($primaryDAOId) {
+          // If we're deliberately setting this as primary then add the flag
+          // and remove it from the current primary location (if there is one).
+          // But only once for each entity.
+          $set_primary = CRM_Utils_Array::value('set_other_primary', $migrationInfo['location_blocks'][$name][$blkCount]);
+          if (!$changePrimary && $set_primary == "1"){
+            $otherBlockDAO->is_primary = 1;
+            if ($primaryDAOId) {
+              $removePrimaryDAO = new $daoName();
+              $removePrimaryDAO->id = $primaryDAOId;
+              $removePrimaryDAO->is_primary = 0;
+              $blocksDAO[$name]['update'][$primaryDAOId] = $removePrimaryDAO;
+            }
+            $changePrimary = TRUE;
+          }
+          // Otherwise, if main contact already has primary, set it to 0.
+          elseif ($primaryDAOId) {
             $otherBlockDAO->is_primary = 0;
           }
+
+          // If the main contact already has a billing location, set this to 0.
           if ($billingDAOId) {
             $otherBlockDAO->is_billing = 0;
           }
index c43ff4a0d289470be92bb75106354e7ea7f70dd0..733b515399ee04ffda4c4f54bbb7db29f26192ce 100644 (file)
               {/if}
 
               {* Display the overwrite/add/add new label *}
-              <span id="main_{$blockName}_{$blockId}_overwrite">
-                {if $row.main}
-                  <span class="action_label">
-                  {* Display whether it is primary *}
-                    {if $row.main_is_primary == "1"}
-                      Primary&nbsp;
+              <span id="main_{$blockName}_{$blockId}_overwrite" class="location_block_controls">
+
+                <span class="location_primary">
+                  {if $row.main && $row.main_is_primary == "1"}Primary{/if}
+                </span>
+
+                <span class="location_block_controls_options">
+                  <span class="location_operation_description">
+                    {if $row.main}({ts}overwrite{/ts}){else}({ts}add{/ts}){/if}
+                  </span>
+                  <span style="display: block" class="location_operation_checkbox">
+                    {if $row.main && ($blockName eq 'email' || $blockName eq 'phone')}
+                      {$form.location_blocks.$blockName.$blockId.operation.html}
                     {/if}
-                    ({ts}overwrite{/ts})
                   </span>
-                   {if $blockName eq 'email' || $blockName eq 'phone' }
-                     {$form.location_blocks.$blockName.$blockId.operation.html}&nbsp;
-                   {/if}
-                   <br />
-                {else}
-                  <span class="action_label">({ts}add{/ts})</span>&nbsp;
-                {/if}
+                  <span style="display: block"  class="location_set_other_primary">
+                    {if $blockName neq 'website' && (($row.main && $row.main_is_primary != "1") || !$row.main)}
+                      {$form.location_blocks.$blockName.$blockId.set_other_primary.html}
+                    {/if}
+                  </span>
+                </span>
               </span>
 
             </td>
   var allBlock = {/literal}{$mainLocBlock}{literal};
 
   /**
-   * Triggered when a 'location' or 'type' destination is changed.
+   * Triggered when a 'location' or 'type' destination is changed, and when
+   * the operation or 'set primary' checkboxes are changed.
+   * 
    * Check to see if the 'main' contact record has a corresponding location
    * block when the destination of a field is changed. Allow existing location
    * fields to be overwritten with data from the 'other' contact.
    *
-   * @param blockname string
+   * @param blockName string
    *   The name of the entity.
-   * @param element object
-   *   The element that was changed (location or type dropdown)
    * @param blockId int
    *   The block ID being affected
-   * @param type string
-   *   Location or type (locTypeId / typeTypeId)
    */
-  function mergeBlock(blockname, element, blockId, type) {
+  function updateMainLocationBlock(blockName, blockId) {
 
     // Get type of select list that's been changed (location or type)
-    var locTypeId = '';
-    var typeTypeId = '';
-
-    // If the location was changed, lookup the type if it exists
-    if (type == 'locTypeId') {
-      locTypeId = element.value;
-      typeTypeId = CRM.$( 'select#location_blocks_' + blockname + '_' + blockId + '_typeTypeId' ).val();
-    }
-
-    // Otherwise the type was changed, lookup the location if it exists
-    else {
-      locTypeId = CRM.$( 'select#location_blocks_' + blockname + '_' + blockId + '_locTypeId' ).val();
-      typeTypeId = element.value;
-    }
+    var locTypeId = CRM.$('select#location_blocks_' + blockName + '_' + blockId + '_locTypeId').val();
+    var typeTypeId = CRM.$('select#location_blocks_' + blockName + '_' + blockId + '_typeTypeId').val();
 
     // @todo Fix this 'special handling' for websites (no location id)
-    if (!locTypeId) { locTypeId = 0; }
+    if (!locTypeId) {
+      locTypeId = 0;
+    }
 
     // Look for a matching block on the main contact
     var mainBlockId = 0;
     var mainBlockDisplay = '';
-    var mainBlock = findBlock(blockname, locTypeId, typeTypeId);
-
-    // Create appropriate label / add new link after changing the block
-    if (mainBlock == false) {
-      label = '<span class="action_label">({/literal}{ts}add{/ts}{literal})</span>';
-    }
-    else {
-      // Set display and ID
+    var mainBlock = findBlock(blockName, locTypeId, typeTypeId);
+    if (mainBlock != false) {
       mainBlockDisplay = mainBlock['display'];
       mainBlockId = mainBlock['id'];
+    }
+
+    // Update main location display and id
+    CRM.$("input[name='location_blocks[" + blockName + "][" + blockId + "][mainContactBlockId]']").val(mainBlockId);
+    CRM.$("#main_" + blockName + "_" + blockId).html(mainBlockDisplay);
 
-      // Set label
-      var label = '<span class="action_label">';
+    // Update controls area
 
-      // Check if the main location is primary
-      if (mainBlock['is_primary'] == "1") {
-        label += 'Primary ';
+    // Get the parent block once for speed
+    var this_controls = CRM.$("#main_" + blockName + "_" + blockId + "_overwrite");
+
+    // Update primary label
+    if (mainBlock != false && mainBlock['is_primary'] == '1') {
+      this_controls.find(".location_primary").text('Primary');
+    }
+    else {
+      this_controls.find(".location_primary").text('');
+    }
+
+    // Update operation description
+    var operation_description = "{/literal}{ts}add{/ts}{literal}";
+    var add_new_check_length = this_controls.find(".location_operation_checkbox input:checked").length;
+    if (mainBlock != false) {
+      if (add_new_check_length > 0) {
+        operation_description = "{/literal}{ts}add new{/ts}{literal}";
       }
+      else {
+        operation_description = "{/literal}{ts}overwrite{/ts}{literal}";
+      }
+    }
+    this_controls.find(".location_operation_description").text("(" + operation_description + ")");
+
+    // Skip if the 'add new' or 'set primary' checkboxes were clicked
+    if (event.target.id.match(/(operation|set_other_primary)/) === null) {
+      // Display 'Add new' checkbox if there is a main block, and this is an
+      // email or phone type.
+      if (mainBlock != false && (blockName == 'email' || blockName == 'phone')) {
+        var op_id = 'location_blocks[' + blockName + '][' + blockId + '][operation]';
+        this_controls.find(".location_operation_checkbox").html(
+                '<input id="' + op_id + '" name="' + op_id + '" type="checkbox" value="1" class="crm-form-checkbox"><label for="' + op_id + '">{/literal}{ts}Add new{/ts}{literal}</label>'
+        );
+      }
+      else {
+        this_controls.find(".location_operation_checkbox").html('');
+      }
+    }
 
-      // Display the action
-      label += '({/literal}{ts}overwrite{/ts}{literal})</span> ';
-      if (blockname == 'email' || blockname == 'phone') {
-        var opLabel = 'location_blocks[' + blockname + '][' + blockId + '][operation]';
-        label += '<input id="' + opLabel + '" name="' + opLabel + '" type="checkbox" value="1" class="crm-form-checkbox"> <label for="' + opLabel + '">{/literal}{ts}add new{/ts}{literal}</label><br />';
+    // Skip if 'set primary' was clicked
+    if (event.target.id.match(/(set_other_primary)/) === null) {
+      // Display 'Set primary' checkbox if applicable
+      if (blockName != 'website' && (mainBlock == false || mainBlock['is_primary'] != "1" || add_new_check_length > 0)) {
+        var prim_id = 'location_blocks[' + blockName + '][' + blockId + '][set_other_primary]';
+        this_controls.find(".location_set_other_primary").html(
+                '<input id="' + prim_id + '" name="' + prim_id + '" type="checkbox" value="1" class="crm-form-checkbox"><label for="' + prim_id + '">{/literal}{ts}Set as primary{/ts}{literal}</label>'
+        );
+      }
+      else {
+        this_controls.find(".location_set_other_primary").html('');
       }
-      label += '<br>';
     }
 
-    // Update DOM
-    CRM.$( "input[name='location_blocks[" + blockname + "][" + blockId + "][mainContactBlockId]']" ).val( mainBlockId );
-    CRM.$( "#main_" + blockname + "_" + blockId ).html( mainBlockDisplay );
-    CRM.$( "#main_" + blockname + "_" + blockId + "_overwrite" ).html( label );
   }
 
   /**
 
   CRM.$(function($) {
 
-    $('body').on('change', "input[id*='[operation]']", function() {
-      var originalHtml = $(this).prevAll('span.action_label').html();
-      if ($(this).is(":checked")) {
-        $(this).prevAll('span.action_label').html(originalHtml.replace('({/literal}{ts}overwrite{/ts}{literal})', '({/literal}{ts}add new{/ts}{literal})'));
-      }
-      else {
-        $(this).prevAll('span.action_label').html(originalHtml.replace('({/literal}{ts}add new{/ts}{literal})', '({/literal}{ts}overwrite{/ts}{literal})'));
-      }
-    });
-
     $('table td input.form-checkbox').each(function() {
       var ele = null;
       var element = $(this).attr('id').split('_',3);
     });
 
     // Call mergeBlock whenever a location type is changed
-    jQuery('select[id^="location_blocks_"]').change(function(){
+    $('body').on('change', 'select[id$="locTypeId"],select[id$="typeTypeId"],input[id$="[operation]"],input[id$="[set_other_primary]"]', function(){
       // All the information we need is held in the id, separated by underscores
-      var idSplit = this.id.split('_');
+      var nameSplit = this.name.split('[');
       // Lookup the main value, if any are available
-      if (allBlock[idSplit[2]] != undefined) {
-        mergeBlock(idSplit[2], this, idSplit[3], idSplit[4]);
+      if (allBlock[nameSplit[1].slice(0, -1)] != undefined) {
+        updateMainLocationBlock(nameSplit[1].slice(0, -1), nameSplit[2].slice(0, -1));
       }
     });