CRM-15374 - exclude fee-related financial_trxn rows from balance calculations and...
[civicrm-core.git] / CRM / Contribute / BAO / Contribution.php
index 285945e374d3c2110f078c09dd6319e8d19582dd..fde8e741e67d224f747121fe397a66556b3fa19e 100644 (file)
@@ -149,7 +149,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
 
     // contribution status is missing, choose Completed as default status
     // do this for create mode only
-    if (empty($ids['contribution']) && empty($params['contribution_status_id'])) {
+    if (!$contributionID && empty($params['contribution_status_id'])) {
       $params['contribution_status_id'] = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
     }
     $setPrevContribution = TRUE;
@@ -238,6 +238,31 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     return NULL;
   }
 
+  /**
+   * Get the number of terms for this contribution for a given membership type
+   * based on querying the line item table and relevant price field values
+   * Note that any one contribution should only be able to have one line item relating to a particular membership
+   * type
+   * @param int $membershipTypeID
+   *
+   * @return int
+   */
+  public function getNumTermsByContributionAndMembershipType($membershipTypeID) {
+    if (!is_numeric($membershipTypeID)) {
+      //precautionary measure - this is being introduced to a mature release hence adding extra checks that
+      // might be removed later
+      return 1;
+    }
+    $numTerms = CRM_Core_DAO::singleValueQuery("
+      SELECT membership_num_terms FROM civicrm_line_item li
+      LEFT JOIN civicrm_price_field_value v ON li.price_field_value_id = v.id
+      WHERE contribution_id = %1 AND membership_type_id = %2",
+      array(1 => array($this->id, 'Integer') , 2 => array($membershipTypeID, 'Integer'))
+    );
+    // default of 1 is precautionary
+    return empty($numTerms) ? 1 : $numTerms;
+  }
+
   /**
    * takes an associative array and creates a contribution object
    *
@@ -2132,7 +2157,7 @@ WHERE  contribution_id = %1 ";
       if (!empty($this->_relatedObjects['membership'])) {
         foreach ($this->_relatedObjects['membership'] as $membership) {
           if ($membership->id) {
-            $values['membership_id'] = $membership->id;
+            $values['isMembership'] = TRUE;
 
             // need to set the membership values here
             $template->assign('membership_assign', 1);
@@ -2302,6 +2327,14 @@ WHERE  contribution_id = %1 ";
    * function & breaking it down into manageable chunks. Eventually it will be refactored into something else
    * Note we send directly from this function in some cases because it is only partly refactored
    * Don't call this function directly as the signature will change
+   *
+   * @param $values
+   * @param $input
+   * @param $template CRM_Core_SMARTY
+   * @param bool $recur
+   * @param bool $returnMessageText
+   *
+   * @return mixed
    */
   function _assignMessageVariablesToTemplate(&$values, $input, &$template, $recur = FALSE, $returnMessageText = True) {
     $template->assign('first_name', $this->_relatedObjects['contact']->first_name);
@@ -2310,7 +2343,7 @@ WHERE  contribution_id = %1 ";
     if (!empty($values['lineItem']) && !empty($this->_relatedObjects['membership'])) {
       $template->assign('useForMember', true);
     }
-    //assign honor infomation to receiptmessage
+    //assign honor information to receipt message
     $softRecord = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->id);
 
     if (isset($softRecord['soft_credit'])) {
@@ -2543,16 +2576,15 @@ WHERE  contribution_id = %1 ";
    * @param array $params contribution object, line item array and params for trxn
    *
    *
-   * @param null $financialTrxnVals
+   * @param array $financialTrxnValues
    *
    * @return null|object
    * @access public
    * @static
    */
-  static function recordFinancialAccounts(&$params, $financialTrxnVals = NULL) {
-    $skipRecords = $update = FALSE;
-    // in few scenarios we require the trxn record details which has got created
-    $return = NULL;
+  static function recordFinancialAccounts(&$params, $financialTrxnValues = NULL) {
+    $skipRecords = $update = $return = $isRelatedId = FALSE;
+
     $additionalParticipantId = array();
     $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
 
@@ -2572,6 +2604,10 @@ WHERE  contribution_id = %1 ";
       $entityTable = 'civicrm_contribution';
     }
 
+    if (CRM_Utils_Array::value('contribution_mode', $params) == 'membership') {
+      $isRelatedId = TRUE;
+    }
+
     $entityID[] = $entityId;
     if (!empty($additionalParticipantId)) {
       $entityID += $additionalParticipantId;
@@ -2622,7 +2658,7 @@ WHERE  contribution_id = %1 ";
 
     // build line item array if its not set in $params
     if (empty($params['line_item']) || $additionalParticipantId) {
-      CRM_Price_BAO_LineItem::getLineItemArray($params, $entityID, str_replace('civicrm_', '', $entityTable));
+      CRM_Price_BAO_LineItem::getLineItemArray($params, $entityID, str_replace('civicrm_', '', $entityTable), $isRelatedId);
     }
 
     if (CRM_Utils_Array::value('contribution_status_id', $params) != array_search('Failed', $contributionStatuses) &&
@@ -2674,8 +2710,8 @@ WHERE  contribution_id = %1 ";
       }
 
       // consider external values passed for recording transaction entry
-      if (!empty($financialTrxnVals)) {
-        $trxnParams = array_merge($trxnParams, $financialTrxnVals);
+      if (!empty($financialTrxnValues)) {
+        $trxnParams = array_merge($trxnParams, $financialTrxnValues);
       }
 
       $params['trxnParams'] = $trxnParams;
@@ -2686,8 +2722,14 @@ WHERE  contribution_id = %1 ";
         $params['trxnParams']['net_amount'] = $params['prevContribution']->net_amount;
         $params['trxnParams']['trxn_id'] = $params['prevContribution']->trxn_id;
         $params['trxnParams']['status_id'] = $params['prevContribution']->contribution_status_id;
-        $params['trxnParams']['payment_instrument_id'] = $params['prevContribution']->payment_instrument_id;
-        $params['trxnParams']['check_number'] = $params['prevContribution']->check_number;
+
+
+        if (!(($params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatuses)
+          || $params['prevContribution']->contribution_status_id == array_search('In Progress', $contributionStatuses))
+          && $params['contribution']->contribution_status_id == array_search('Completed', $contributionStatuses))) {
+          $params['trxnParams']['payment_instrument_id'] = $params['prevContribution']->payment_instrument_id;
+          $params['trxnParams']['check_number'] = $params['prevContribution']->check_number;
+        }
 
         //if financial type is changed
         if (!empty($params['financial_type_id']) &&
@@ -3107,7 +3149,17 @@ WHERE  contribution_id = %1 ";
       $toFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($contributionDAO->financial_type_id, $relationTypeId);
 
       $trxnId = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId, $contributionDAO->financial_type_id);
-      $trxnId = $trxnId['trxn_id'];
+      if (!empty($trxnId)) {
+        $trxnId = $trxnId['trxn_id'];
+      }
+      elseif (!empty($contributionDAO->payment_instrument_id)) {
+        $trxnId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contributionDAO->payment_instrument_id);
+      }
+      else {
+        $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' "));
+        $queryParams = array(1 => array($relationTypeId, 'Integer'));
+        $trxnId = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = %1", $queryParams);
+      }
 
       // update statuses
       // criteria for updates contribution total_amount == financial_trxns of partial_payments
@@ -3124,15 +3176,23 @@ WHERE eft.entity_table = 'civicrm_contribution'
 
       // update statuses
       if ($contributionDAO->total_amount == $sumOfPayments) {
-        // update contribution status
-        $contributionUpdate['id'] = $contributionId;
-        $contributionUpdate['contribution_status_id'] = $statusId;
-        $contributionUpdate['skipLineItem'] = TRUE;
+        // update contribution status and
+        // clean cancel info (if any) if prev. contribution was updated in case of 'Refunded' => 'Completed'
+        $contributionDAO->contribution_status_id = $statusId;
+        $contributionDAO->cancel_date = 'null';
+        $contributionDAO->cancel_reason = NULL;
+        $netAmount = !empty($trxnsData['net_amount']) ? $trxnsData['net_amount'] : $trxnsData['total_amount'];
+        $contributionDAO->net_amount = $contributionDAO->net_amount + $netAmount;
+        $contributionDAO->save();
+
+        //Change status of financial record too
+        $financialTrxn->status_id = $statusId;
+        $financialTrxn->save();
+
         // note : not using the self::add method,
         // the reason because it performs 'status change' related code execution for financial records
         // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates
         // are coded below i.e. just updating financial_item status to 'Paid'
-        $contributionDetails = CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $statusId);
 
         if ($participantId) {
           // update participant status
@@ -3274,6 +3334,8 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
   }
 
   /**
+   * function to get list of payments displayed by Contribute_Page_PaymentInfo
+   *
    * @param $id
    * @param $component
    * @param bool $getTrxnInfo
@@ -3325,6 +3387,11 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
 
     $paymentBalance = CRM_Core_BAO_FinancialTrxn::getPartialPaymentWithType($id, $entity, FALSE, $total);
     $contributionIsPayLater = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'is_pay_later');
+
+    $feeRelationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Expense Account is' "));
+    $financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'financial_type_id');
+    $feeFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($financialTypeId, $feeRelationTypeId);
+
     if ($paymentBalance == 0 && $contributionIsPayLater) {
       $paymentBalance = $total;
     }
@@ -3337,11 +3404,12 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
     $info['payLater'] = $contributionIsPayLater;
     $rows = array();
     if ($getTrxnInfo && $baseTrxnId) {
+      // Need to exclude fee trxn rows so filter out rows where TO FINANCIAL ACCOUNT is expense account
       $sql = "
 SELECT ft.total_amount, con.financial_type_id, ft.payment_instrument_id, ft.trxn_date, ft.trxn_id, ft.status_id, ft.check_number
 FROM civicrm_contribution con
   LEFT JOIN civicrm_entity_financial_trxn eft ON (eft.entity_id = con.id AND eft.entity_table = 'civicrm_contribution')
-  LEFT JOIN civicrm_financial_trxn ft ON ft.id = eft.financial_trxn_id
+  LEFT JOIN civicrm_financial_trxn ft ON ft.id = eft.financial_trxn_id AND ft.to_financial_account_id != {$feeFinancialAccount}
 WHERE con.id = {$contributionId}
 ";