Eileen has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/341730 )

Change subject: Restore blanked addresses overwritten on merge.
......................................................................

Restore blanked addresses overwritten on merge.

I feel like this is a pretty cautious approach to restoring the simplest cases 
where
blank addresses overwrote real addresses.

Bug: T159408
Change-Id: I683940498ce5f78ddf8ea89ef0603d3fae508410
---
M sites/all/modules/wmf_civicrm/tests/phpunit/MergeTest.php
A sites/all/modules/wmf_civicrm/update_restore_addresses.php
M sites/all/modules/wmf_civicrm/wmf_civicrm.install
M sites/all/modules/wmf_civicrm/wmf_civicrm.module
4 files changed, 195 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/crm 
refs/changes/30/341730/1

diff --git a/sites/all/modules/wmf_civicrm/tests/phpunit/MergeTest.php 
b/sites/all/modules/wmf_civicrm/tests/phpunit/MergeTest.php
index 5263d4f..fce23fd 100644
--- a/sites/all/modules/wmf_civicrm/tests/phpunit/MergeTest.php
+++ b/sites/all/modules/wmf_civicrm/tests/phpunit/MergeTest.php
@@ -1226,4 +1226,57 @@
     return $contact['id'];
   }
 
+  /**
+   * Test recovery where a blank email has overwritten a non-blank email on 
merge.
+   *
+   * In this case an email existed during merge that held no data. It was used
+   * on the merge, but now we want the lost data.
+   */
+  public function testRepairBlankedEmailOnMerge() {
+    CRM_Core_DAO::executeQuery('DROP TABLE IF EXISTS blank_addresses');
+    require_once __DIR__ . '/../../wmf_civicrm.install';
+    require_once __DIR__ . '/../../update_restore_addresses.php';
+    wmf_civicrm_update_7475();
+    $this->replicateBlankedAddress();
+
+    $address = $this->callAPISuccessGetSingle('Address', array('contact_id' => 
$this->contactID));
+    $this->assertTrue(empty($address['street_address']));
+
+    wmf_civicrm_fix_blanked_address($address['id']);
+    $address = $this->callAPISuccessGetSingle('Address', array('contact_id' => 
$this->contactID));
+    $this->assertEquals('25 Mousey Way', $address['street_address']);
+
+    CRM_Core_DAO::executeQuery('DROP TABLE blank_addresses');
+  }
+
+  /**
+   * Replicate the merge that would result in a blanked address.
+   */
+  protected function replicateBlankedAddress() {
+    $this->contributionCreate(array(
+      'contact_id' => $this->contactID,
+      'receive_date' => '2010-01-01',
+      'invoice_id' => 1,
+      'trxn_id' => 1
+    ));
+    $this->contributionCreate(array(
+      'contact_id' => $this->contactID2,
+      'receive_date' => '2012-01-01',
+      'invoice_id' => 2,
+      'trxn_id' => 2
+    ));
+    $this->callAPISuccess('Address', 'create', array(
+      'street_address' => '25 Mousey Way',
+      'country_id' => 'US',
+      'contact_id' => $this->contactID,
+      'location_type_id' => 'Main',
+    ));
+    $this->callAPISuccess('Address', 'create', array(
+      'street_address' => NULL,
+      'contact_id' => $this->contactID2,
+      'location_type_id' => 'Main',
+    ));
+    $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => 
'safe'));
+  }
+
 }
diff --git a/sites/all/modules/wmf_civicrm/update_restore_addresses.php 
b/sites/all/modules/wmf_civicrm/update_restore_addresses.php
new file mode 100644
index 0000000..070e512
--- /dev/null
+++ b/sites/all/modules/wmf_civicrm/update_restore_addresses.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Created by IntelliJ IDEA.
+ * User: emcnaughton
+ * Date: 3/8/17
+ * Time: 2:44 PM
+ */
+/**
+ * Fix data loss through blanked address.
+ *
+ * We have a situation where a number of addresses have been overwritten by 
blank addresses.
+ *
+ * Unfortunately some of these have since been merged, resulting in some 
unravelling to be done.
+ *
+ * This update seeks to unravel ones with a single merge since then.
+ *
+ * @param int $addressID
+ */
+function wmf_civicrm_fix_blanked_address($addressID) {
+  $logEntries = CRM_Core_DAO::executeQuery('SELECT * FROM log_civicrm_address 
WHERE id = %1 ORDER BY log_date', array(
+    1 => array(
+      $addressID,
+      'Int'
+    )
+  ))->fetchAll();
+  if (count($logEntries) === 2
+    && (in_array($logEntries[0]['log_action'], array('Insert', 'Initialize'))
+      && $logEntries[1]['log_action'] === 'Update'
+    )
+  ) {
+    // we only have a create & an update, not a long complicated history.
+    $dataFields = array(
+      'street_address',
+      'city',
+      'postal_code',
+      'state_province_id',
+      'country_id',
+      'supplemental_address_1',
+      'supplemental_address_2',
+      'supplemental_address_3',
+      'county_id',
+      'postal_code_suffix',
+      'name'
+    );
+    foreach ($dataFields as $dataField) {
+      if (!empty($logEntries[0][$dataField]) || 
!empty($logEntries[1][$dataField])) {
+        // Not blank enough to process.
+        return;
+      }
+    }
+    if ($logEntries[0]['contact_id'] == $logEntries[1]['contact_id']) {
+      // We are specifically trying to handle merged data at this stage.
+      // May extend if we identify other patterns.
+      return;
+    }
+    // We definitely have a situation where a blank record was inserted & 
then, on merge
+    // was transferred to another contact. We have the log_conn_id & the new 
contact id.
+    // let's make sure the new contact has not since been deleted (merged)
+    // and that they still have no address.
+    //
+    // If all that follows we should have a fairly simple case of address 
rescue.
+    $keptContact = civicrm_api3('Contact', 'get', array(
+      'id' => $logEntries[1]['contact_id'],
+      'sequential' => 1
+    ));
+    if ($keptContact['count'] == 0 || 
!empty($keptContact['values'][0]['is_deleted'])) {
+      // subject to a subsequent merge & deleted, next round for these.
+      return;
+    }
+    $addresses = civicrm_api3('Address', 'get', array(
+      'contact_id' => $logEntries[1]['contact_id'],
+      'sequential' => 1
+    ));
+    if ($addresses['count'] != 1 || $addresses['values'][0]['id'] != 
$addressID) {
+      // Not just dealing with one address = complexity = later.
+      return;
+    }
+    $logs = civicrm_api3('Logging', 'get', array(
+      'tables' => array('civicrm_address'),
+      'log_conn_id' => $logEntries[1]['log_conn_id']
+    ));
+    $updates = array();
+    foreach ($logs['values'] as $log) {
+      // We don't want the blank address id, we know that was always blank
+      if ($log['id'] != $addressID) {
+        if ($log['action'] !== 'Delete') {
+          // Unhandled situation if there is a mix of actions. Skip for now.
+          return;
+        }
+        if (isset($retrievalID) && $log['id'] != $retrievalID) {
+          // another just in case check. Thinking it is only valid for
+          // 2 addresses to be in the update, our blank address & the
+          // one it wiped. Any more, bail.
+          return;
+        }
+        $retrievalID = $log['id'];
+        $fieldName = $log['field'];
+        if (in_array($fieldName, $dataFields)) {
+          $updates[$log['field']] = $log['from'];
+        }
+      }
+    }
+    if (empty($updates)) {
+      // This is probably overkill, can't see how this would occur.
+      return;
+    }
+    $updates['id'] = $addressID;
+    civicrm_api3('Address', 'create', $updates);
+    // Remove from the tracking table.
+    CRM_Core_DAO::executeQuery('DELETE FROM blank_addresses WHERE id = %1', 
array(
+      1 => array(
+        $addressID,
+        'Int'
+      )
+    ));
+
+  }
+}
diff --git a/sites/all/modules/wmf_civicrm/wmf_civicrm.install 
b/sites/all/modules/wmf_civicrm/wmf_civicrm.install
index c3e81b2..9bce2e0 100644
--- a/sites/all/modules/wmf_civicrm/wmf_civicrm.install
+++ b/sites/all/modules/wmf_civicrm/wmf_civicrm.install
@@ -2554,7 +2554,7 @@
 function wmf_civicrm_update_7475() {
   civicrm_initialize();
   CRM_Core_DAO::executeQuery(
-    "CREATE TABLE blank_addresses
+    "CREATE TABLE IF NOT EXISTS blank_addresses
      SELECT *
      FROM log_civicrm_address
      WHERE street_address IS NULL
@@ -2803,3 +2803,25 @@
 function wmf_civicrm_update_7500() {
     wmf_civicrm_create_financial_types(array('Benevity'));
 }
+
+/**
+ * Restore blanked addresses overwritten on merge..
+ *
+ * Bug: T159408
+ */
+function wmf_civicrm_update_7505() {
+  civicrm_initialize();
+  require_once 'update_restore_addresses.php';
+  $batch =  5;
+  $result = CRM_Core_DAO::executeQuery('
+    SELECT id FROM civicrm_address
+    WHERE street_address IS NULL
+     AND city IS NULL
+     AND postal_code IS NULL
+     AND state_province_id IS NULL
+     AND country_id IS NULL
+     LIMIT ' . $batch);
+  while ($result->fetch()) {
+    wmf_civicrm_fix_blanked_address($result->id);
+  }
+}
diff --git a/sites/all/modules/wmf_civicrm/wmf_civicrm.module 
b/sites/all/modules/wmf_civicrm/wmf_civicrm.module
index 546824d..f8a9ba1 100644
--- a/sites/all/modules/wmf_civicrm/wmf_civicrm.module
+++ b/sites/all/modules/wmf_civicrm/wmf_civicrm.module
@@ -2868,7 +2868,7 @@
 
                        // Do we have any geo info for this address?
                        if (
-                               $address['country_id'] == $usId &&
+                               !empty($address['country_id']) &&  
$address['country_id']== $usId &&
                                !empty( $address['postal_code'] )
                        ) {
                                $sql = "SELECT city, s.id AS state_id, 
latitude, longitude, timezone

-- 
To view, visit https://gerrit.wikimedia.org/r/341730
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I683940498ce5f78ddf8ea89ef0603d3fae508410
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/fundraising/crm
Gerrit-Branch: master
Gerrit-Owner: Eileen <emcnaugh...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to