Contribution import - test notes, cleanup notes, fix regression found in test writing
authorEileen McNaughton <emcnaughton@wikimedia.org>
Tue, 30 Aug 2022 19:51:47 +0000 (07:51 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Tue, 30 Aug 2022 23:05:50 +0000 (11:05 +1200)
CRM/Contribute/Import/Parser/Contribution.php
tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php
tests/phpunit/CRM/Contribute/Import/Parser/data/contributions.csv

index 726b0d372be7dd7421359f24897ad87b9851da3e..d3cb74c69b8ada6d0932ba65b2ab16371c75c55f 100644 (file)
@@ -18,6 +18,7 @@
 use Civi\Api4\Contact;
 use Civi\Api4\Contribution;
 use Civi\Api4\Email;
+use Civi\Api4\Note;
 
 /**
  * Class to parse contribution csv files.
@@ -307,20 +308,21 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
     $rowNumber = (int) ($values[array_key_last($values)]);
     try {
       $entityKeyedParams = $this->getMappedRow($values);
-      $existingContribution = $this->lookupContribution($entityKeyedParams['Contribution']);
-      $entityKeyedParams['Contribution']['id'] = $existingContribution['id'] ?? NULL;
-      if (empty($entityKeyedParams['Contribution']['id']) && $this->isUpdateExisting()) {
+      $contributionParams = $entityKeyedParams['Contribution'];
+      $existingContribution = $this->lookupContribution($contributionParams);
+      if (empty($existingContribution) && $this->isUpdateExisting()) {
+        throw new CRM_Core_Exception(ts('Matching Contribution record not found. Row was skipped.'), CRM_Import_Parser::ERROR);
+      }
+      $contributionParams['id'] = $existingContribution['id'] ?? NULL;
+      if (empty($contributionParams['id']) && $this->isUpdateExisting()) {
         throw new CRM_Core_Exception('Empty Contribution and Invoice and Transaction ID. Row was skipped.', CRM_Import_Parser::ERROR);
       }
-      $contactID = $entityKeyedParams['Contribution']['contact_id'] ?? ($existingContribution['contact_id'] ?? NULL);
-      $entityKeyedParams['Contribution']['contact_id'] = $this->getContactID($entityKeyedParams['Contact'] ?? [], $contactID);
+      $contactID = $contributionParams['contact_id'] ?? ($existingContribution['contact_id'] ?? NULL);
+      $contactID = $contributionParams['contact_id'] = $this->getContactID($entityKeyedParams['Contact'] ?? [], $contactID);
 
-      // @todo - here we flatten the entities back into a single array.
+      // @todo - here we flatten some of the entities back into a single array.
       // The entity format is better but the code below needs to be migrated.
-      $params = [];
-      foreach (['Contribution', 'Note'] as $entity) {
-        $params = array_merge($params, ($entityKeyedParams[$entity] ?? []));
-      }
+      $params = $contributionParams;
       if (isset($entityKeyedParams['soft_credit'])) {
         $params['soft_credit'] = $entityKeyedParams['soft_credit'];
       }
@@ -342,27 +344,6 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
       $this->deprecatedFormatParams($paramValues, $formatted);
 
       if ($this->isUpdateExisting()) {
-        //process note
-        if (!empty($paramValues['note'])) {
-          $noteID = [];
-          $contactID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $paramValues['id'], 'contact_id');
-          $daoNote = new CRM_Core_BAO_Note();
-          $daoNote->entity_table = 'civicrm_contribution';
-          $daoNote->entity_id = $paramValues['id'];
-          if ($daoNote->find(TRUE)) {
-            $noteID['id'] = $daoNote->id;
-          }
-
-          $noteParams = [
-            'entity_table' => 'civicrm_contribution',
-            'note' => $paramValues['note'],
-            'entity_id' => $paramValues['id'],
-            'contact_id' => $contactID,
-          ];
-          CRM_Core_BAO_Note::add($noteParams, $noteID);
-          unset($formatted['note']);
-        }
-
         //need to check existing soft credit contribution, CRM-3968
         if (!empty($formatted['soft_credit'])) {
           $dupeSoftCredit = [
@@ -385,16 +366,19 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
         }
       }
 
-      $newContribution = civicrm_api3('contribution', 'create', $formatted);
+      $contributionID = civicrm_api3('contribution', 'create', $formatted)['id'];
 
+      if (!empty($entityKeyedParams['Note'])) {
+        $this->processNote($contributionID, $contactID, $entityKeyedParams['Note']);
+      }
       //return soft valid since we need to show how soft credits were added
       if (!empty($formatted['soft_credit'])) {
-        $this->setImportStatus($rowNumber, $this->getStatus(self::SOFT_CREDIT), '', $newContribution['id']);
+        $this->setImportStatus($rowNumber, $this->getStatus(self::SOFT_CREDIT), '', $contributionID);
         return;
       }
 
       // process pledge payment assoc w/ the contribution
-      $this->setImportStatus($rowNumber, $this->processPledgePayments($newContribution['id'], $formatted) ? $this->getStatus(self::PLEDGE_PAYMENT) : $this->getStatus(self::VALID), $newContribution['id']);
+      $this->setImportStatus($rowNumber, $this->processPledgePayments($contributionID, $formatted) ? $this->getStatus(self::PLEDGE_PAYMENT) : $this->getStatus(self::VALID), $contributionID);
       return;
 
     }
@@ -414,11 +398,9 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
    */
   private function lookupContribution(array $params): array {
     $where = [];
-    $labels = [];
     foreach (['id' => 'Contribution ID', 'trxn_id' => 'Transaction ID', 'invoice_id' => 'Invoice ID'] as $field => $label) {
       if (!empty($params[$field])) {
         $where[] = [$field, '=', $params[$field]];
-        $labels[] = $label . ' ' . $params[$field];
       }
     }
     if (empty($where)) {
@@ -428,7 +410,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
     if ($contribution['id'] ?? NULL) {
       return $contribution;
     }
-    throw new CRM_Core_Exception('Matching Contribution record not found for ' . implode(' AND ', $labels) . '. Row was skipped.', CRM_Import_Parser::ERROR);
+    return [];
   }
 
   /**
@@ -691,4 +673,30 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
     return array_merge($fields, parent::getOddlyMappedMetadataFields());
   }
 
+  /**
+   * Create or update the note.
+   *
+   * @param int $contributionID
+   * @param int $contactID
+   * @param array $noteParams
+   *
+   * @throws \API_Exception
+   */
+  protected function processNote(int $contributionID, int $contactID, array $noteParams): void {
+    $noteParams = array_merge([
+      'entity_table' => 'civicrm_contribution',
+      'entity_id' => $contributionID,
+      'contact_id' => $contactID,
+    ], $noteParams);
+    if ($this->isUpdateExisting()) {
+      $note = Note::get(FALSE)
+        ->addSelect('entity_table', '=', 'civicrm_contribution')
+        ->addSelect('entity_id', '=', $contributionID)->execute()->first();
+      if (!empty($note)) {
+        $noteParams['id'] = $note['id'];
+      }
+    }
+    Note::save(FALSE)->setRecords([$noteParams])->execute();
+  }
+
 }
index 38f173c51f62cef8aba47036923aa4c4efd8bf29..335f5bc86e6a840ed9f6fe238cef2428bab382b1 100644 (file)
@@ -300,6 +300,18 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase {
       ->addWhere('entity_id', '=', $contribution['id'])
       ->addWhere('entity_table', '=', 'civicrm_contribution')->execute()->first();
     $this->assertEquals('Call him back', $note['note']);
+
+    // Now change the note & re-do it. The same note should be updated.
+    Note::update()
+      ->addWhere('entity_id', '=', $contribution['id'])
+      ->addValue('note', 'changed')
+      ->execute();
+    $this->importContributionsDotCSV(['onDuplicate' => CRM_Import_Parser::DUPLICATE_UPDATE]);
+    $note = Note::get()
+      ->addWhere('entity_id', '=', $contribution['id'])
+      ->addWhere('entity_table', '=', 'civicrm_contribution')->execute()->first();
+    $this->assertEquals('Call him back', $note['note']);
+
   }
 
   /**
@@ -534,7 +546,7 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase {
   /**
    * @return \CRM_Import_DataSource_CSV
    */
-  private function importContributionsDotCSV(): CRM_Import_DataSource_CSV {
+  private function importContributionsDotCSV($submittedValues = []): CRM_Import_DataSource_CSV {
     $this->importCSV('contributions.csv', [
       ['name' => 'first_name'],
       ['name' => 'total_amount'],
@@ -543,7 +555,8 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase {
       ['name' => 'email'],
       ['name' => 'contribution_source'],
       ['name' => 'note'],
-    ]);
+      ['name' => 'trxn_id'],
+    ], $submittedValues);
     return new CRM_Import_DataSource_CSV($this->userJobID);
   }
 
index 135032e217006bcd489e9730b7e985ce667321b7..46f34410b9e9b46c5a8b9b14498c0d3241177b1a 100644 (file)
@@ -1,2 +1,2 @@
-External Identifier,Total Amount,Receive Date,Financial Type,Soft Credit to,Source,Note
-bob,65,2008-09-20,Donation,mum@example.com,Word of mouth,Call him back
+External Identifier,Total Amount,Receive Date,Financial Type,Soft Credit to,Source,Note,Transaction ID
+bob,65,2008-09-20,Donation,mum@example.com,Word of mouth,Call him back,999