CRM-16417 towards not deleting contributions when a payment failes
authorEileen McNaughton <eileen@fuzion.co.nz>
Wed, 24 Jun 2015 12:13:44 +0000 (00:13 +1200)
committerEileen McNaughton <eileen@fuzion.co.nz>
Wed, 24 Jun 2015 12:51:51 +0000 (00:51 +1200)
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/BAO/Contribution/Utils.php
CRM/Contribute/Form/Contribution.php
CRM/Member/BAO/Membership.php
CRM/Member/Form/Membership.php

index f40b117dd5f2c1294fab6e15235595426449f0ae..0aeae2a123db9a69282e93b929c12b220bcc7653 100644 (file)
@@ -870,13 +870,18 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = civicrm_contribution.conta
    * Prior to CRM-16417 these were simply removed from the database but it has been agreed that seeing attempted
    * payments is important for forensic and outreach reasons.
    *
-   * This function updates the financial transaction records to failed.
-   *
-   * @todo in principle we also think it makes sense to add an activity - this part would be a second step as
-   * the first change is likely to go into the LTS.
+   * @param int $contributionID
+   * @param string $message
    */
-  public static function failPayment($contributionID, $message) {
-
+  public static function failPayment($contributionID, $contactID, $message) {
+    civicrm_api3('activity', 'create', array(
+      'activity_type_id' => 'Failed Payment',
+      'details' => $message,
+      'subject' => ts('Payment failed at payment processor'),
+      'source_record_id' => $contributionID,
+      'source_contact_id' => CRM_Core_Session::getLoggedInContactID() ? CRM_Core_Session::getLoggedInContactID() :
+        $contactID,
+    ));
   }
 
   /**
index ebfa009ddd63d7fd6317fe68ae47808d5af02c00..6e5b6fc540a9d5cd21a94263bc53d1a041e521a3 100644 (file)
@@ -266,11 +266,26 @@ class CRM_Contribute_BAO_Contribution_Utils {
           $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
         }
       }
-      if (is_object($payment)) {
-        $result = $payment->doDirectPayment($paymentParams);
-      }
-      else {
-        CRM_Core_Error::fatal($paymentObjError);
+      try {
+        $result = $payment->doPayment($paymentParams);
+      }
+      catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
+        // Clean up DB as appropriate.
+        if (!empty($paymentParams['contributionID'])) {
+          CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'],
+            $paymentParams['contactID'], $e->getMessage());
+        }
+        if (!empty($paymentParams['contributionRecurID'])) {
+          CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
+        }
+
+        if ($component !== 'membership') {
+          // This is only called from contribution form.
+          // Not sure if there is any reason not to just throw an exception up to it.
+          $result['is_payment_failure'] = TRUE;
+          return $result;
+        }
+        $membershipResult[1] = $result;
       }
     }
 
@@ -278,26 +293,7 @@ class CRM_Contribute_BAO_Contribution_Utils {
       $membershipResult = array();
     }
 
-    if (is_a($result, 'CRM_Core_Error')) {
-      //make sure to cleanup db for recurring case.
-      //@todo this clean up has always been controversial as many orgs prefer to see failed transactions.
-      // most recent discussion has been that they should be retained and this could be altered
-      if (!empty($paymentParams['contributionID'])) {
-        CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']);
-      }
-      if (!empty($paymentParams['contributionRecurID'])) {
-        CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
-      }
-
-      if ($component !== 'membership') {
-        CRM_Core_Error::displaySessionError($result);
-        CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/transact',
-          "_qf_Main_display=true&qfKey={$form->_params['qfKey']}"
-        ));
-      }
-      $membershipResult[1] = $result;
-    }
-    elseif ($result || ($form->_amount == 0.0 && !$form->_params['is_pay_later'])) {
+    if ($result || ($form->_amount == 0.0 && !$form->_params['is_pay_later'])) {
       if ($result) {
         $form->_params = array_merge($form->_params, $result);
       }
index 6bcb35fa5b81f5fe8fe93a4ce90508e29f6894d3..c65bc0c176047c4459b6569d2630a73618092c7b 100644 (file)
@@ -1264,7 +1264,7 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
         }
       }
       catch (PaymentProcessorException $e) {
-        CRM_Contribute_BAO_Contribution::failPayment($contribution->id, $e->getMessage());
+        CRM_Contribute_BAO_Contribution::failPayment($contribution->id, $paymentParams['contactID'], $e->getMessage());
         throw new PaymentProcessorException($e->getMessage());
       }
     }
index ecce3a4a82bd2edb9b1490f739c1ae8ef239d567..16a2dd912a3ebf8016389f9147e8e3fbfb2607dd 100644 (file)
@@ -1136,7 +1136,7 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
   /**
    * Get all exportable fields.
    *
-   * @retun array return array of all exportable fields
+   * @return array return array of all exportable fields
    */
   public static function &exportableFields() {
     $expFieldMembership = CRM_Member_DAO_Membership::export();
@@ -1761,8 +1761,12 @@ WHERE  civicrm_membership.contact_id = civicrm_contact.id
    * @param CRM_Core_DAO $dao
    *   Membership object.
    *
-   * @return null|array
-   *   array of memberships if created
+   * @param bool $reset
+   *
+   * @return array|null
+   *   Membership details, if created.
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function createRelatedMemberships(&$params, &$dao, $reset = FALSE) {
     static $relatedContactIds = array();
index a52018fe422e2b27b45437dc4ca5b4eaa9e49e90..46a327e6eb3c5a69e2738f265c4a47858dcace2d 100644 (file)
@@ -1555,22 +1555,23 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
 
       if ($params['total_amount'] > 0.0) {
         $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this);
-        $result = $payment->doDirectPayment($paymentParams);
-      }
-
-      if (is_a($result, 'CRM_Core_Error')) {
-        //make sure to cleanup db for recurring case.
-        if (!empty($paymentParams['contributionID'])) {
-          CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']);
-        }
-        if (!empty($paymentParams['contributionRecurID'])) {
-          CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
+        try {
+          $result = $payment->doPayment($paymentParams);
         }
+        catch (PaymentProcessorException $e) {
+          if (!empty($paymentParams['contributionID'])) {
+            CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'], $e->getMessage());
+          }
+          if (!empty($paymentParams['contributionRecurID'])) {
+            CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
+          }
 
-        CRM_Core_Error::displaySessionError($result);
-        CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership',
-          "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"
-        ));
+          CRM_Core_Error::displaySessionError($result);
+          CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership',
+            "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"
+          ));
+
+        }
       }
 
       if ($result) {