Initial go at cleaning up repeattransaction
authorRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Fri, 1 Jul 2022 15:51:28 +0000 (16:51 +0100)
committerRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Fri, 1 Jul 2022 15:51:28 +0000 (16:51 +0100)
api/v3/Contribution.php

index 6000cd96aec7ac27f728133193ab249832234eac..c456d44f5b59aadcd8640bfa21118d787ab3d842 100644 (file)
@@ -616,84 +616,76 @@ function _civicrm_api3_contribution_completetransaction_spec(&$params) {
  * @throws API_Exception
  */
 function civicrm_api3_contribution_repeattransaction($params) {
+
   civicrm_api3_verify_one_mandatory($params, NULL, ['contribution_recur_id', 'original_contribution_id']);
+
+  // We need a contribution to copy.
   if (empty($params['original_contribution_id'])) {
+    // Find one from the given recur. A template contribution is preferred, otherwise use the latest one added.
     $templateContribution = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($params['contribution_recur_id']);
     if (empty($templateContribution)) {
       throw new CiviCRM_API3_Exception('Contribution.repeattransaction failed to get original_contribution_id for recur with ID: ' . $params['contribution_recur_id']);
     }
-    $params['original_contribution_id'] = $templateContribution['id'];
-  }
-  $contribution = new CRM_Contribute_BAO_Contribution();
-  $contribution->id = $params['original_contribution_id'];
-  if (!$contribution->find(TRUE)) {
-    throw new API_Exception(
-      'A valid original contribution ID is required', 'invalid_data');
   }
-  // We don't support repeattransaction without a related recurring contribution.
-  if (empty($contribution->contribution_recur_id)) {
-    throw new API_Exception(
-      'Repeattransaction API can only be used in the context of contributions that have a contribution_recur_id.',
-      'invalid_data'
-    );
+  else {
+    // A template/original contribution was specified by the params. Load it.
+    $templateContribution = Contribution::get(FALSE)
+      ->addWhere('id', '=', $params['original_contribution_id'])
+      ->addWhere('is_test', 'IN', [0, 1])
+      ->addWhere('contribution_recur_id', 'IS NOT EMPTY')
+      ->execute()->first();
+    if (empty($templateContribution)) {
+      throw new CiviCRM_API3_Exception("Contribution.repeattransaction failed to load the given original_contribution_id ($params[original_contribution_id]) because it does not exist, or because it does not belong to a recurring contribution");
+    }
   }
 
-  $params['payment_processor_id'] = civicrm_api3('contributionRecur', 'getvalue', [
-    'return' => 'payment_processor_id',
-    'id' => $contribution->contribution_recur_id,
-  ]);
-
-  $passThroughParams = [
+  // Collect inputs for CRM_Contribute_BAO_Contribution::completeOrder in $input.
+  $paramsToCopy = [
     'trxn_id',
-    'total_amount',
     'campaign_id',
     'fee_amount',
     'financial_type_id',
     'contribution_status_id',
     'payment_processor_id',
-  ];
-  $input = array_intersect_key($params, array_fill_keys($passThroughParams, NULL));
+    'is_email_receipt',
+    'trxn_date',
+    'receive_date',
+    'card_type_id',
+    'pan_truncation',
+    'payment_instrument_id',
+    // Q. not contribution_page_id ?
+  ];
+  $input = array_intersect_key($params, array_fill_keys($paramsToCopy, NULL));
+  // Ensure certain keys exist with NULL values if they don't already (not sure if this is ACTUALLY necessary?)
+  $input += array_fill_keys(['card_type_id', 'pan_truncation'], NULL);
+
+  // Set amount, use templateContribution if not in params.
+  $input['total_amount'] = $params['total_amount'] ?? $templateContribution['total_amount'];
+  // Why do we need this extra 'amount' key? It's used in CRM_Contribute_BAO_Contribution::completeOrder to pass on to CRM_Contribute_BAO_ContributionRecur::updateRecurLinkedPledge
+  // but it could possibly be removed if that code was adjusted unless anything else uses 'amount'
+  $input['amount'] = $input['total_amount'];
+
+  $input['payment_processor_id'] = civicrm_api3('contributionRecur', 'getvalue', [
+    'return' => 'payment_processor_id',
+    'id' => $templateContribution['contribution_recur_id'],
+  ]);
 
-  $ids = [];
-  if (!$contribution->loadRelatedObjects(['payment_processor_id' => $input['payment_processor_id']], $ids, TRUE)) {
-    throw new API_Exception('failed to load related objects');
-  }
-  unset($contribution->id, $contribution->receive_date, $contribution->invoice_id);
-  $contribution->receive_date = $params['receive_date'];
+  $input['is_test'] = $templateContribution['is_test'];
 
-  // @todo Copied from _ipn_process_transaction - needs cleanup/refactor
-  $objects = $contribution->_relatedObjects;
-  $objects['contribution'] = &$contribution;
-  $input['component'] = $contribution->_component;
-  $input['is_test'] = $contribution->is_test;
-  $input['amount'] = empty($input['total_amount']) ? $contribution->total_amount : $input['total_amount'];
-
-  if (isset($params['is_email_receipt'])) {
-    $input['is_email_receipt'] = $params['is_email_receipt'];
-  }
-  if (!empty($params['trxn_date'])) {
-    $input['trxn_date'] = $params['trxn_date'];
-  }
-  if (!empty($params['receive_date'])) {
-    $input['receive_date'] = $params['receive_date'];
-  }
-  if (empty($contribution->contribution_page_id)) {
+  if (empty($templateContribution['contribution_page_id'])) {
+    // Q. why do we need statics here?
     static $domainFromName;
     static $domainFromEmail;
     if (empty($domainFromEmail) && (empty($params['receipt_from_name']) || empty($params['receipt_from_email']))) {
       [$domainFromName, $domainFromEmail] = CRM_Core_BAO_Domain::getNameAndEmail(TRUE);
     }
-    $input['receipt_from_name'] = CRM_Utils_Array::value('receipt_from_name', $params, $domainFromName);
-    $input['receipt_from_email'] = CRM_Utils_Array::value('receipt_from_email', $params, $domainFromEmail);
-  }
-  $input['card_type_id'] = $params['card_type_id'] ?? NULL;
-  $input['pan_truncation'] = $params['pan_truncation'] ?? NULL;
-  if (!empty($params['payment_instrument_id'])) {
-    $input['payment_instrument_id'] = $params['payment_instrument_id'];
+    $input['receipt_from_name'] = ($params['receipt_from_name'] ?? NULL) ?: $domainFromName;
+    $input['receipt_from_email'] = ($params['receipt_from_email'] ?? NULL) ?: $domainFromEmail;
   }
+
   return CRM_Contribute_BAO_Contribution::completeOrder($input,
-    !empty($objects['contributionRecur']) ? $objects['contributionRecur']->id : NULL,
-    $objects['contribution']->id ?? NULL,
+    $templateContribution['contribution_recur_id'],
+    NULL,
     $params['is_post_payment_create'] ?? NULL);
 }