fix misfiled pdf merges
authorDemeritCowboy <demeritcowboy@hotmail.com>
Sun, 27 Oct 2019 12:18:35 +0000 (08:18 -0400)
committerDemeritCowboy <demeritcowboy@hotmail.com>
Sun, 27 Oct 2019 13:26:10 +0000 (09:26 -0400)
CRM/Case/Form/Task.php
CRM/Core/Form/Task.php
tests/phpunit/CRM/Case/Form/TaskTest.php [new file with mode: 0644]

index 43d77f1ced672571cebede2d4540d7f6c9b7e3ec..157ce6223d6b6c775608bae035ba8ad0976458a9 100644 (file)
@@ -50,7 +50,9 @@ class CRM_Case_Form_Task extends CRM_Core_Form_Task {
    * @inheritDoc
    */
   public function setContactIDs() {
-    $this->_contactIds = CRM_Core_DAO::getContactIDsFromComponent($this->_entityIds,
+    // @todo Parameters shouldn't be needed and should be class member
+    // variables instead, set appropriately by each subclass.
+    $this->_contactIds = $this->getContactIDsFromComponent($this->_entityIds,
       'civicrm_case_contact', 'case_id'
     );
   }
@@ -64,4 +66,22 @@ class CRM_Case_Form_Task extends CRM_Core_Form_Task {
     return CRM_Contact_BAO_Query::MODE_CASE;
   }
 
+  /**
+   * Override of CRM_Core_Form_Task::orderBy()
+   *
+   * @return string
+   */
+  public function orderBy() {
+    if (empty($this->_entityIds)) {
+      return '';
+    }
+    $order_array = [];
+    foreach ($this->_entityIds as $item) {
+      // Ordering by conditional in mysql. This evaluates to 0 or 1, so we
+      // need to order DESC to get the '1'.
+      $order_array[] = 'case_id = ' . CRM_Core_DAO::escapeString($item) . ' DESC';
+    }
+    return 'ORDER BY ' . implode(',', $order_array);
+  }
+
 }
index d9279d2000725532af65ed958ae34a96e788eb9d..cd659e3a1f64b8700e4ded9a1f44fe574751dd29 100644 (file)
@@ -217,4 +217,55 @@ abstract class CRM_Core_Form_Task extends CRM_Core_Form {
     return $this->queryMode ?: CRM_Contact_BAO_Query::MODE_CONTACTS;
   }
 
+  /**
+   * Given the component id, compute the contact id
+   * since it's used for things like send email.
+   *
+   * @todo At the moment this duplicates a similar function in CRM_Core_DAO
+   * because right now only the case component is using this. Since the
+   * default $orderBy is '' which is what the original does, others should be
+   * easily convertable as NFC.
+   * @todo The passed in variables should be class member variables. Shouldn't
+   * need to have passed in vars.
+   *
+   * @param $componentIDs
+   * @param string $tableName
+   * @param string $idField
+   *
+   * @return array
+   */
+  public function getContactIDsFromComponent($componentIDs, $tableName, $idField = 'id') {
+    $contactIDs = [];
+
+    if (empty($componentIDs)) {
+      return $contactIDs;
+    }
+
+    $orderBy = $this->orderBy();
+
+    $IDs = implode(',', $componentIDs);
+    $query = "
+SELECT contact_id
+  FROM $tableName
+ WHERE $idField IN ( $IDs ) $orderBy
+";
+
+    $dao = CRM_Core_DAO::executeQuery($query);
+    while ($dao->fetch()) {
+      $contactIDs[] = $dao->contact_id;
+    }
+    return $contactIDs;
+  }
+
+  /**
+   * Default ordering for getContactIDsFromComponent. Subclasses can override.
+   *
+   * @return string
+   *   SQL fragment. Either return '' or a valid order clause including the
+   *   words "ORDER BY", e.g. "ORDER BY `{$this->idField}`"
+   */
+  public function orderBy() {
+    return '';
+  }
+
 }
diff --git a/tests/phpunit/CRM/Case/Form/TaskTest.php b/tests/phpunit/CRM/Case/Form/TaskTest.php
new file mode 100644 (file)
index 0000000..dc6c6f6
--- /dev/null
@@ -0,0 +1,133 @@
+<?php
+require_once 'CiviTest/CiviCaseTestCase.php';
+
+/**
+ * Class CRM_Case_Form_TaskTest
+ * @group headless
+ */
+class CRM_Case_Form_TaskTest extends CiviCaseTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->quickCleanup(['civicrm_case_contact', 'civicrm_case', 'civicrm_contact']);
+  }
+
+  /**
+   * Test the order of the corresponding ids in the output matches the order
+   * of the ids in the input, i.e. case_contacts matches cases.
+   *
+   * @param $input array
+   * @param $selected_search_results array
+   * @param $expected array
+   *
+   * @dataProvider contactIDProvider
+   */
+  public function testSetContactIDs($input, $selected_search_results, $expected) {
+    $this->createCaseContacts($input);
+    $task = new CRM_Case_Form_Task();
+
+    // This simulates the selection from the search results list. What we're
+    // testing is that no matter what order the cases were created or what
+    // mysql feels like doing today, the order of the retrieved contacts ends
+    // up matching the order that the cases came in from search results.
+    $task->_entityIds = $selected_search_results;
+
+    $task->setContactIDs();
+    $this->assertEquals($expected, $task->_contactIds);
+  }
+
+  private function createCaseContacts($caseContacts) {
+    foreach ($caseContacts as $caseContact) {
+      // The corresponding case needs to exist. We don't care about most of
+      // its values, just the case_id.
+      CRM_Core_DAO::executeQuery("INSERT INTO civicrm_case (id, start_date, case_type_id, details, status_id, created_date) VALUES ({$caseContact['case_id']}, '2019-01-01', 1, '', 1, NOW())");
+      // Ditto the contact
+      CRM_Core_DAO::executeQuery("INSERT INTO civicrm_contact (id, contact_type, created_date, image_URL, sort_name) VALUES ({$caseContact['contact_id']}, 'Individual', NOW(), '', 'Contact {$caseContact['contact_id']}')");
+      // And now case_contact
+      CRM_Core_DAO::executeQuery("INSERT INTO civicrm_case_contact (contact_id, case_id) VALUES ({$caseContact['contact_id']}, {$caseContact['case_id']})");
+    }
+  }
+
+  /**
+   * Data provider for testSetContactIDs
+   * @return array
+   */
+  public function contactIDProvider() {
+    return [
+      // empty input
+      [[], [], []],
+      // one input
+      [
+        [
+          ['contact_id' => 1, 'case_id' => 2],
+        ],
+        // the case id's in the order they were passed in from search results
+        [2],
+        // the retrieved contacts listed in the expected order
+        [1],
+      ],
+      // some input
+      [
+        [
+          ['contact_id' => 1, 'case_id' => 2],
+          ['contact_id' => 3, 'case_id' => 4],
+          ['contact_id' => 5, 'case_id' => 6],
+        ],
+        [2, 4, 6],
+        [1, 3, 5],
+      ],
+      [
+        [
+          ['contact_id' => 1, 'case_id' => 2],
+          ['contact_id' => 3, 'case_id' => 4],
+          ['contact_id' => 5, 'case_id' => 6],
+        ],
+        [4, 2, 6],
+        [3, 1, 5],
+      ],
+
+      // some more input
+      [
+        [
+          ['contact_id' => 17, 'case_id' => 12],
+          ['contact_id' => 3, 'case_id' => 8],
+          ['contact_id' => 25, 'case_id' => 45],
+          ['contact_id' => 18, 'case_id' => 33],
+        ],
+        [12, 8, 45, 33],
+        [17, 3, 25, 18],
+      ],
+      [
+        [
+          ['contact_id' => 17, 'case_id' => 12],
+          ['contact_id' => 3, 'case_id' => 8],
+          ['contact_id' => 25, 'case_id' => 45],
+          ['contact_id' => 18, 'case_id' => 33],
+        ],
+        [45, 8, 33, 12],
+        [25, 3, 18, 17],
+      ],
+      [
+        [
+          ['contact_id' => 17, 'case_id' => 12],
+          ['contact_id' => 3, 'case_id' => 8],
+          ['contact_id' => 25, 'case_id' => 45],
+          ['contact_id' => 18, 'case_id' => 33],
+        ],
+        [12, 33, 45, 8],
+        [17, 18, 25, 3],
+      ],
+      [
+        [
+          ['contact_id' => 17, 'case_id' => 12],
+          ['contact_id' => 3, 'case_id' => 8],
+          ['contact_id' => 25, 'case_id' => 45],
+          ['contact_id' => 18, 'case_id' => 33],
+        ],
+        [8, 33, 12, 45],
+        [3, 18, 17, 25],
+      ],
+    ];
+  }
+
+}