Merge pull request #18934 from eileenmcnaughton/aip
[civicrm-core.git] / CRM / Core / Payment / AuthorizeNetIPN.php
index b02eefb8fc6d8badc47903d371c5424f9915585c..04042b587a8adcb7909c498f088668bc398eb0be 100644 (file)
@@ -30,11 +30,13 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
   }
 
   /**
-   * @param string $component
+   * Main IPN processing function.
    *
    * @return bool|void
+   *
+   * @throws \CiviCRM_API3_Exception
    */
-  public function main($component = 'contribute') {
+  public function main() {
     try {
       //we only get invoice num as a key player from payment gateway response.
       //for ARB we get x_subscription_id and x_subscription_paynum
@@ -45,35 +47,14 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       }
       $ids = $objects = $input = [];
 
-      $input['component'] = $component;
+      $input['component'] = 'contribute';
 
       // load post vars in $input
       $this->getInput($input, $ids);
 
       // load post ids in $ids
       $this->getIDs($ids, $input);
-
-      // Attempt to get payment processor ID from URL
-      if (!empty($this->_inputParameters['processor_id'])) {
-        $paymentProcessorID = $this->_inputParameters['processor_id'];
-      }
-      else {
-        // This is an unreliable method as there could be more than one instance.
-        // Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
-        // processor id & the handleNotification function (which should call the completetransaction api & by-pass this
-        // entirely). The only thing the IPN class should really do is extract data from the request, validate it
-        // & call completetransaction or call fail? (which may not exist yet).
-        Civi::log()->warning('Unreliable method used to get payment_processor_id for AuthNet IPN - this will cause problems if you have more than one instance');
-        $paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
-          'AuthNet', 'id', 'name'
-        );
-        $paymentProcessorID = (int) civicrm_api3('PaymentProcessor', 'getvalue', [
-          'is_test' => 0,
-          'options' => ['limit' => 1],
-          'payment_processor_type_id' => $paymentProcessorTypeID,
-          'return' => 'id',
-        ]);
-      }
+      $paymentProcessorID = $this->getPaymentProcessorID();
 
       // Check if the contribution exists
       // make sure contribution exists and is valid
@@ -96,14 +77,10 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
         $ids['contact'] = $contribution->contact_id;
       }
 
-      if (!empty($ids['contributionRecur'])) {
-        $contributionRecur = new CRM_Contribute_BAO_ContributionRecur();
-        $contributionRecur->id = $ids['contributionRecur'];
-        if (!$contributionRecur->find(TRUE)) {
-          CRM_Core_Error::debug_log_message("Could not find contribution recur record: {$ids['ContributionRecur']} in IPN request: " . print_r($input, TRUE));
-          echo "Failure: Could not find contribution recur record: {$ids['ContributionRecur']}<p>";
-          return FALSE;
-        }
+      $contributionRecur = new CRM_Contribute_BAO_ContributionRecur();
+      $contributionRecur->id = $ids['contributionRecur'];
+      if (!$contributionRecur->find(TRUE)) {
+        throw new CRM_Core_Exception("Could not find contribution recur record: {$ids['ContributionRecur']} in IPN request: " . print_r($input, TRUE));
       }
 
       $objects['contact'] = &$contact;
@@ -111,39 +88,40 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
 
       $this->loadObjects($input, $ids, $objects, TRUE, $paymentProcessorID);
 
-      if (!empty($ids['paymentProcessor']) && $objects['contributionRecur']->payment_processor_id != $ids['paymentProcessor']) {
-        Civi::log()->warning('Payment Processor does not match the recurring processor id.', ['civi.tag' => 'deprecated']);
+      // check if first contribution is completed, else complete first contribution
+      $first = TRUE;
+      if ($objects['contribution']->contribution_status_id == 1) {
+        $first = FALSE;
+        //load new contribution object if required.
+        // create a contribution and then get it processed
+        $contribution = new CRM_Contribute_BAO_Contribution();
+        $contribution->contact_id = $ids['contact'];
+        $contribution->financial_type_id = $objects['contributionType']->id;
+        $contribution->contribution_page_id = $ids['contributionPage'];
+        $contribution->contribution_recur_id = $ids['contributionRecur'];
+        $contribution->receive_date = $input['receive_date'];
+        $contribution->currency = $objects['contribution']->currency;
+        $contribution->amount_level = $objects['contribution']->amount_level;
+        $contribution->address_id = $objects['contribution']->address_id;
+        $contribution->campaign_id = $objects['contribution']->campaign_id;
+
+        $objects['contribution'] = &$contribution;
       }
-
-      if ($component == 'contribute' && $ids['contributionRecur']) {
-        // check if first contribution is completed, else complete first contribution
-        $first = TRUE;
-        if ($objects['contribution']->contribution_status_id == 1) {
-          $first = FALSE;
-          //load new contribution object if required.
-          // create a contribution and then get it processed
-          $contribution = new CRM_Contribute_BAO_Contribution();
-          $contribution->contact_id = $ids['contact'];
-          $contribution->financial_type_id = $objects['contributionType']->id;
-          $contribution->contribution_page_id = $ids['contributionPage'];
-          $contribution->contribution_recur_id = $ids['contributionRecur'];
-          $contribution->receive_date = $input['receive_date'];
-          $contribution->currency = $objects['contribution']->currency;
-          $contribution->amount_level = $objects['contribution']->amount_level;
-          $contribution->address_id = $objects['contribution']->address_id;
-          $contribution->campaign_id = $objects['contribution']->campaign_id;
-          $contribution->_relatedObjects = $objects['contribution']->_relatedObjects;
-
-          $objects['contribution'] = &$contribution;
-        }
-        $input['payment_processor_id'] = $paymentProcessorID;
-        return $this->recur($input, [
-          'related_contact' => $ids['related_contact'] ?? NULL,
-          'participant' => !empty($objects['participant']) ? $objects['participant']->id : NULL,
-          'contributionRecur' => !empty($objects['contributionRecur']) ? $objects['contributionRecur']->id : NULL,
-          'contact' => $ids['contact'] ?? NULL,
-          'contributionPage' => $ids['contributionPage'] ?? NULL,
-        ], $objects['contributionRecur'], $objects['contribution'], $first);
+      $input['payment_processor_id'] = $paymentProcessorID;
+      $isFirstOrLastRecurringPayment = $this->recur($input, [
+        'related_contact' => $ids['related_contact'] ?? NULL,
+        'participant' => !empty($objects['participant']) ? $objects['participant']->id : NULL,
+        'contributionRecur' => $contributionRecur->id,
+      ], $contributionRecur, $objects['contribution'], $first);
+
+      if ($isFirstOrLastRecurringPayment) {
+        //send recurring Notification email for user
+        CRM_Contribute_BAO_ContributionPage::recurringNotify(TRUE,
+          $ids['contact'],
+          $ids['contributionPage'],
+          $contributionRecur,
+          (bool) $this->getMembershipID($contribution->id, $contributionRecur->id)
+        );
       }
 
       return TRUE;
@@ -214,27 +192,18 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       // so we just fix the recurring contribution and not change any of
       // the existing contributions
       // CRM-9036
-      return TRUE;
+      return FALSE;
     }
 
     // check if contribution is already completed, if so we ignore this ipn
     if ($contribution->contribution_status_id == 1) {
       CRM_Core_Error::debug_log_message("Returning since contribution has already been handled.");
       echo 'Success: Contribution has already been handled<p>';
-      return TRUE;
+      return FALSE;
     }
 
     CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $contribution);
-
-    if ($isFirstOrLastRecurringPayment) {
-      //send recurring Notification email for user
-      CRM_Contribute_BAO_ContributionPage::recurringNotify(TRUE,
-        $ids['contact'],
-        $ids['contributionPage'],
-        $recur,
-        (bool) $this->getMembershipID($contribution->id, $recur->id)
-      );
-    }
+    return $isFirstOrLastRecurringPayment;
   }
 
   /**
@@ -371,4 +340,34 @@ INNER JOIN civicrm_contribution co ON co.contribution_recur_id = cr.id
     return $contRecur;
   }
 
+  /**
+   * Get the payment processor id.
+   *
+   * @return int
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected function getPaymentProcessorID(): int {
+    // Attempt to get payment processor ID from URL
+    if (!empty($this->_inputParameters['processor_id'])) {
+      return (int) $this->_inputParameters['processor_id'];
+    }
+    // This is an unreliable method as there could be more than one instance.
+    // Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
+    // processor id & the handleNotification function (which should call the completetransaction api & by-pass this
+    // entirely). The only thing the IPN class should really do is extract data from the request, validate it
+    // & call completetransaction or call fail? (which may not exist yet).
+    Civi::log()->warning('Unreliable method used to get payment_processor_id for AuthNet IPN - this will cause problems if you have more than one instance');
+    $paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
+      'AuthNet', 'id', 'name'
+    );
+    return (int) civicrm_api3('PaymentProcessor', 'getvalue', [
+      'is_test' => 0,
+      'options' => ['limit' => 1],
+      'payment_processor_type_id' => $paymentProcessorTypeID,
+      'return' => 'id',
+    ]);
+  }
+
 }