CRM-17130 fix and refactor soft-credit post processing
[civicrm-core.git] / CRM / Contribute / Form / Contribution / Confirm.php
index 32a5dc2df1902741829d28a3da9de9cf2ef9e1de..4d727c42ac60d5bd57a5c02f7fc725a266c3da5f 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.6                                                |
+ | CiviCRM version 4.7                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
@@ -810,8 +810,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
    *   - thankyou_date (not all forms will set this)
    *
    * @param CRM_Financial_DAO_FinancialType $financialType
-   * @param bool $pending
-   *   The intention is this should always be TRUE and we are refactoring towards any completion happening elsewhere.
    * @param bool $online
    *   Is the form a front end form? If so set a bunch of unpredictable things that should be passed in from the form.
    *
@@ -827,7 +825,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $result,
     $contributionParams,
     $financialType,
-    $pending,
     $online,
     $billingLocationID
   ) {
@@ -835,13 +832,10 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $contactID = $contributionParams['contact_id'];
 
     $isEmailReceipt = !empty($form->_values['is_email_receipt']);
-    // How do these vary from params? These are currently passed to
-    // - custom data function....
-    $formParams = $form->_params;
-    $isSeparateMembershipPayment = empty($formParams['separate_membership_payment']) ? FALSE : TRUE;
-    $pledgeID = empty($formParams['pledge_id']) ? NULL : $formParams['pledge_id'];
+    $isSeparateMembershipPayment = empty($params['separate_membership_payment']) ? FALSE : TRUE;
+    $pledgeID = empty($params['pledge_id']) ? NULL : $params['pledge_id'];
     if (!$isSeparateMembershipPayment && !empty($form->_values['pledge_block_id']) &&
-      (!empty($formParams['is_pledge']) || $pledgeID)) {
+      (!empty($params['is_pledge']) || $pledgeID)) {
       $isPledge = TRUE;
     }
     else {
@@ -871,28 +865,9 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
       $receiptDate = $now;
     }
 
-    // Prepare soft contribution due to pcp or Submit Credit / Debit Card Contribution by admin.
-    if (!empty($params['pcp_made_through_id']) || !empty($params['soft_credit_to'])) {
-      // if its due to pcp
-      if (!empty($params['pcp_made_through_id'])) {
-        $contributionParams['soft_credit_to'] = CRM_Core_DAO::getFieldValue(
-          'CRM_PCP_DAO_PCP',
-          $params['pcp_made_through_id'],
-          'contact_id'
-        );
-        // Pass these details onto with the contribution to make them
-        // available at hook_post_process, CRM-8908
-        // @todo - obsolete?
-        $params['soft_credit_to'] = $contributionParams['soft_credit_to'];
-      }
-      else {
-        $contributionParams['soft_credit_to'] = CRM_Utils_Array::value('soft_credit_to', $params);
-      }
-    }
-
     if (isset($params['amount'])) {
       $contributionParams = array_merge(self::getContributionParams(
-        $params, $financialType->id, $nonDeductibleAmount, $pending,
+        $params, $financialType->id, $nonDeductibleAmount, TRUE,
         $result, $receiptDate,
         $recurringContributionID), $contributionParams
       );
@@ -929,18 +904,18 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
       $form->_contributionID = $contribution->id;
     }
 
-    //CRM-13981, processing honor contact into soft-credit contribution
-    CRM_Contact_Form_ProfileContact::postProcess($form);
+    // process soft credit / pcp params first
+    CRM_Contribute_BAO_ContributionSoft::formatSoftCreditParams($params, $form);
 
-    // process soft credit / pcp pages
-    CRM_Contribute_Form_Contribution_Confirm::processPcpSoft($params, $contribution);
+    //CRM-13981, processing honor contact into soft-credit contribution
+    CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
 
     //handle pledge stuff.
     if ($isPledge) {
       if ($pledgeID) {
         //when user doing pledge payments.
         //update the schedule when payment(s) are made
-        foreach ($form->_params['pledge_amount'] as $paymentId => $dontCare) {
+        foreach ($params['pledge_amount'] as $paymentId => $dontCare) {
           $scheduledAmount = CRM_Core_DAO::getFieldValue(
             'CRM_Pledge_DAO_PledgePayment',
             $paymentId,
@@ -1013,7 +988,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     }
 
     if ($online && $contribution) {
-      CRM_Core_BAO_CustomValueTable::postProcess($form->_params,
+      CRM_Core_BAO_CustomValueTable::postProcess($params,
         'civicrm_contribution',
         $contribution->id,
         'Contribution'
@@ -1278,47 +1253,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     }
   }
 
-  /**
-   * Function used to save pcp / soft credit entry.
-   *
-   * This is used by contribution and also event pcps
-   *
-   * @param array $params
-   * @param object $contribution
-   *   Contribution object.
-   */
-  public static function processPcpSoft(&$params, &$contribution) {
-    // Add soft contribution due to pcp or Submit Credit / Debit Card Contribution by admin.
-    if (!empty($params['soft_credit_to'])) {
-      $contributionSoftParams = array();
-      foreach (array(
-          'pcp_display_in_roll',
-          'pcp_roll_nickname',
-          'pcp_personal_note',
-          'amount',
-        ) as $val) {
-        if (!empty($params[$val])) {
-          $contributionSoftParams[$val] = $params[$val];
-        }
-      }
-
-      $contributionSoftParams['contact_id'] = $params['soft_credit_to'];
-      // add contribution id
-      $contributionSoftParams['contribution_id'] = $contribution->id;
-      // add pcp id
-      $contributionSoftParams['pcp_id'] = $params['pcp_made_through_id'];
-
-      $contributionSoftParams['soft_credit_type_id'] = CRM_Core_OptionGroup::getValue('soft_credit_type', 'pcp', 'name');
-
-      $contributionSoft = CRM_Contribute_BAO_ContributionSoft::add($contributionSoftParams);
-
-      //Send notification to owner for PCP
-      if ($contributionSoft->id && $contributionSoft->pcp_id) {
-        CRM_Contribute_Form_Contribution_Confirm::pcpNotifyOwner($contribution, $contributionSoft);
-      }
-    }
-  }
-
   /**
    * Function used to send notification mail to pcp owner.
    *
@@ -1662,24 +1596,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
       }
       $payment = Civi\Payment\System::singleton()->getByProcessor($form->_paymentProcessor);
       $paymentActionResult = $payment->doPayment($form->_params, 'contribute');
-
-      if (CRM_Utils_Array::value('payment_status_id', $paymentActionResult) == 1) {
-        // Refer to CRM-16737. Payment processors 'should' return payment_status_id
-        // to denote the outcome of the transaction.
-        try {
-          civicrm_api3('contribution', 'completetransaction', array(
-            'id' => $paymentResult['contribution']->id,
-            'trxn_id' => CRM_Utils_Array::value('trxn_id', $paymentActionResult, $paymentResult['contribution']->trxn_id),
-            'is_transactional' => FALSE,
-            'payment_processor_id' => $form->_paymentProcessor['id'],
-          ));
-        }
-        catch (CiviCRM_API3_Exception $e) {
-          if ($e->getErrorCode() != 'contribution_completed') {
-            throw new CRM_Core_Exception('Failed to update contribution in database');
-          }
-        }
-      }
+      $this->completeTransaction($paymentActionResult, $paymentResult['contribution']->id);
       // Do not send an email if Recurring transaction is done via Direct Mode
       // Email will we sent when the IPN is received.
       return;
@@ -1732,19 +1649,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $tempParams['amount'] = $minimumFee;
     $tempParams['invoiceID'] = md5(uniqid(rand(), TRUE));
 
-    $result = NULL;
-    if ($form->_values['is_monetary'] && !$form->_params['is_pay_later'] && $minimumFee > 0.0) {
-      // At the moment our tests are calling this form in a way that leaves 'object' empty. For
-      // now we compensate here.
-      if (empty($form->_paymentProcessor['object'])) {
-        $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
-      }
-      else {
-        $payment = $form->_paymentProcessor['object'];
-      }
-      $result = $payment->doPayment($tempParams, 'contribute');
-    }
-
     //assign receive date when separate membership payment
     //and contribution amount not selected.
     if ($form->_amount == 0) {
@@ -1755,22 +1659,13 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
       $form->assign('receive_date', $receiveDate);
     }
 
-    $form->set('membership_trx_id', $result['trxn_id']);
     $form->set('membership_amount', $minimumFee);
-
-    $form->assign('membership_trx_id', $result['trxn_id']);
     $form->assign('membership_amount', $minimumFee);
 
     // we don't need to create the user twice, so lets disable cms_create_account
     // irrespective of the value, CRM-2888
     $tempParams['cms_create_account'] = 0;
 
-    //CRM-16165, scenarios are
-    // 1) If contribution is_pay_later and if contribution amount is > 0.0 we set pending = TRUE, vice-versa FALSE
-    // 2) If not pay later but auto-renewal membership is chosen then pending = TRUE as it later triggers
-    //   pending recurring contribution, vice-versa FALSE
-    $pending = $form->_params['is_pay_later'] ? (($minimumFee > 0.0) ? TRUE : FALSE) : (!empty($form->_params['auto_renew']) ? TRUE : FALSE);
-
     //set this variable as we are not creating pledge for
     //separate membership payment contribution.
     //so for differentiating membership contribution from
@@ -1788,19 +1683,33 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $isMonetary = !empty($form->_values['is_monetary']);
     if ($isMonetary) {
       if (empty($paymentParams['is_pay_later'])) {
-        // @todo look up payment_instrument_id on payment processor table.
-        $contributionParams['payment_instrument_id'] = 1;
+        $contributionParams['payment_instrument_id'] = $form->_paymentProcessor['payment_instrument_id'];
       }
     }
     $membershipContribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution($form,
       $tempParams,
-      $result,
+      $tempParams,
       $contributionParams,
       $financialType,
-      $pending,
       TRUE,
       $form->_bltID
     );
+
+    if ($form->_values['is_monetary'] && !$form->_params['is_pay_later'] && $minimumFee > 0.0) {
+      // At the moment our tests are calling this form in a way that leaves 'object' empty. For
+      // now we compensate here.
+      if (empty($form->_paymentProcessor['object'])) {
+        $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
+      }
+      else {
+        $payment = $form->_paymentProcessor['object'];
+      }
+      $result = $payment->doPayment($tempParams, 'contribute');
+      $form->set('membership_trx_id', $result['trxn_id']);
+      $form->assign('membership_trx_id', $result['trxn_id']);
+      $this->completeTransaction($result, $membershipContribution->id);
+    }
+
     return $membershipContribution;
   }
 
@@ -2276,27 +2185,13 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         ($this->_mode == 'test') ? 1 : 0
       );
 
-      if (!empty($result['is_payment_failure'])) {
-        return $result;
-      }
-      // @todo move premium processing to complete transaction if it truly is an 'after' action.
-      $this->postProcessPremium($premiumParams, $result['contribution']);
-      if (CRM_Utils_Array::value('payment_status_id', $result) == 1) {
-        try {
-          civicrm_api3('contribution', 'completetransaction', array(
-              'id' => $result['contribution']->id,
-              'trxn_id' => CRM_Utils_Array::value('trxn_id', $result),
-              'payment_processor_id' => $this->_paymentProcessor['id'],
-              'is_transactional' => FALSE,
-            )
-          );
-        }
-        catch (CiviCRM_API3_Exception $e) {
-          if ($e->getErrorCode() != 'contribution_completed') {
-            throw new CRM_Core_Exception('Failed to update contribution in database');
-          }
-        }
-
+      if (empty($result['is_payment_failure'])) {
+        // @todo move premium processing to complete transaction if it truly is an 'after' action.
+        $this->postProcessPremium($premiumParams, $result['contribution']);
+      }
+      if (!empty($result['contribution'])) {
+        // Not quite sure why it would be empty at this stage but tests show it can be ... at least in tests.
+        $this->completeTransaction($result, $result['contribution']->id);
       }
       return $result;
     }
@@ -2404,4 +2299,36 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     }
   }
 
+  /**
+   * Complete transaction if payment has been processed.
+   *
+   * Check the result for a success outcome & if paid then complete the transaction.
+   *
+   * Completing will trigger update of related entities and emails.
+   *
+   * @param array $result
+   * @param int $contributionID
+   *
+   * @throws \CRM_Core_Exception
+   */
+  protected function completeTransaction($result, $contributionID) {
+    if (CRM_Utils_Array::value('payment_status_id', $result) == 1) {
+      try {
+        civicrm_api3('contribution', 'completetransaction', array(
+            'id' => $contributionID,
+            'trxn_id' => CRM_Utils_Array::value('trxn_id', $result),
+            'payment_processor_id' => $this->_paymentProcessor['id'],
+            'is_transactional' => FALSE,
+            'fee_amount' => CRM_Utils_Array::value('fee_amount', $result),
+          )
+        );
+      }
+      catch (CiviCRM_API3_Exception $e) {
+        if ($e->getErrorCode() != 'contribution_completed') {
+          throw new CRM_Core_Exception('Failed to update contribution in database');
+        }
+      }
+    }
+  }
+
 }