CRM-17951 add Contribution Status of Chargeback
authoreileen <emcnaughton@wikimedia.org>
Thu, 4 Feb 2016 10:54:31 +0000 (23:54 +1300)
committereileen <emcnaughton@wikimedia.org>
Thu, 4 Feb 2016 12:24:10 +0000 (01:24 +1300)
CRM/Contribute/BAO/Contribution.php
CRM/Financial/BAO/FinancialAccount.php
tests/phpunit/api/v3/ContributionTest.php

index 748099942f21c6a6f0aeba0f785cc3cead100efc..571763a937af3607213f246c64b2b58fdeebdfc5 100644 (file)
@@ -137,7 +137,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     //if contribution is created with cancelled or refunded status, add credit note id
     if (!empty($params['contribution_status_id'])) {
       $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
-
+      // @todo - should we include Chargeback? If so use self::isContributionStatusNegative($params['contribution_status_id'])
       if (($params['contribution_status_id'] == array_search('Refunded', $contributionStatus)
         || $params['contribution_status_id'] == array_search('Cancelled', $contributionStatus))
       ) {
@@ -3122,7 +3122,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
         'payment_instrument_id' => $params['contribution']->payment_instrument_id,
         'check_number' => CRM_Utils_Array::value('check_number', $params),
       );
-      if ($contributionStatus == 'Refunded') {
+      if ($contributionStatus == 'Refunded' || $contributionStatus == 'Chargeback') {
         $trxnParams['trxn_date'] = !empty($params['contribution']->cancel_date) ? $params['contribution']->cancel_date : date('YmdHis');
         if (isset($params['refund_trxn_id'])) {
           // CRM-17751 allow a separate trxn_id for the refund to be passed in via api & form.
@@ -3370,8 +3370,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
       $cancelledTaxAmount = 0;
       if ($previousContributionStatus == 'Completed'
-        && ($params['contribution']->contribution_status_id == array_search('Refunded', $contributionStatus)
-          || $params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus))
+        && (self::isContributionStatusNegative($params['contribution']->contribution_status_id))
       ) {
         $params['trxnParams']['total_amount'] = -$params['total_amount'];
         $cancelledTaxAmount = CRM_Utils_Array::value('tax_amount', $params, '0.00');
@@ -3480,9 +3479,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
             $currency = $params['contribution']->currency;
           }
           $diff = 1;
-          if ($context == 'changeFinancialType' || $params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus)
-            || $params['contribution']->contribution_status_id == array_search('Refunded', $contributionStatus)
-            ) {
+          if ($context == 'changeFinancialType' || self::isContributionStatusNegative($params['contribution']->contribution_status_id)) {
             $diff = -1;
           }
           if (!empty($params['is_quick_config'])) {
@@ -3531,6 +3528,20 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     }
   }
 
+  /**
+   * Is this contribution status a reversal.
+   *
+   * If so we would expect to record a negative value in the financial_trxn table.
+   *
+   * @param int $status_id
+   *
+   * @return bool
+   */
+  public static function isContributionStatusNegative($status_id) {
+    $reversalStatuses = array('Cancelled', 'Chargeback', 'Refunded');
+    return in_array(CRM_Contribute_PseudoConstant::contributionStatus($status_id, 'name'), $reversalStatuses);
+  }
+
   /**
    * Check status validation on update of a contribution.
    *
@@ -3555,7 +3566,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
     $checkStatus = array(
       'Cancelled' => array('Completed', 'Refunded'),
-      'Completed' => array('Cancelled', 'Refunded'),
+      'Completed' => array('Cancelled', 'Refunded', 'Chargeback'),
       'Pending' => array('Cancelled', 'Completed', 'Failed'),
       'In Progress' => array('Cancelled', 'Completed', 'Failed'),
       'Refunded' => array('Cancelled', 'Completed'),
index 79657577d8fb8d83bed8108f4f28b6ca2b90e04d..80ef79e2bd4d515896d50f091faa1a2ed69d2b29 100644 (file)
@@ -238,7 +238,7 @@ WHERE cft.id = %1
 
         $accountRelationshipID = array_search($optionalAccountRelationship, $accountRelationships);
         if (empty(Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$accountRelationshipID])) {
-          Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$accountRelationshipID] =  $incomeAccountFinancialAccountID;
+          Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$accountRelationshipID] = $incomeAccountFinancialAccountID;
         }
       }
 
index 63b1a016dfe1069f6462068dc443691fba0e48d9..513a4b6fe21bbec35cc1b088ca167acca5065810 100644 (file)
@@ -1067,6 +1067,71 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     )));
   }
 
+  /**
+   * Refund a contribution for a financial type with a contra account.
+   *
+   * CRM-17951 the contra account is a financial account with a relationship to a
+   * financial type. It is not always configured but should be reflected
+   * in the financial_trxn & financial_item table if it is.
+   */
+  public function testCreateUpdateChargebackContributionDefaultAccount() {
+    $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
+    $this->callAPISuccess('Contribution', 'create', array(
+      'id' => $contribution['id'],
+      'contribution_status_id' => 'Chargeback',
+    ));
+    $this->callAPISuccessGetSingle('Contribution', array('contribution_status_id' => 'Chargeback'));
+
+    $lineItems = $this->callAPISuccessGetSingle('LineItem', array(
+      'contribution_id' => $contribution['id'],
+      'api.FinancialItem.getsingle' => array('amount' => array('<' => 0)),
+    ));
+    $this->assertEquals(1, $lineItems['api.FinancialItem.getsingle']['financial_account_id']);
+    $this->callAPISuccessGetSingle('FinancialTrxn', array(
+      'total_amount' => -100,
+      'status_id' => 'Chargeback',
+      'to_financial_account_id' => 6,
+    ));
+  }
+
+  /**
+   * Refund a contribution for a financial type with a contra account.
+   *
+   * CRM-17951 the contra account is a financial account with a relationship to a
+   * financial type. It is not always configured but should be reflected
+   * in the financial_trxn & financial_item table if it is.
+   */
+  public function testCreateUpdateChargebackContributionCustomAccount() {
+    $financialAccount = $this->callAPISuccess('FinancialAccount', 'create', array(
+      'name' => 'Chargeback Account',
+      'is_active' => TRUE,
+    ));
+
+    $entityFinancialAccount = $this->callAPISuccess('EntityFinancialAccount', 'create', array(
+      'entity_id' => $this->_financialTypeId,
+      'entity_table' => 'civicrm_financial_type',
+      'account_relationship' => 'Chargeback Account is',
+      'financial_account_id' => 'Chargeback Account',
+    ));
+
+    $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
+    $this->callAPISuccess('Contribution', 'create', array(
+      'id' => $contribution['id'],
+      'contribution_status_id' => 'Chargeback',
+    ));
+    $this->callAPISuccessGetSingle('Contribution', array('contribution_status_id' => 'Chargeback'));
+
+    $lineItems = $this->callAPISuccessGetSingle('LineItem', array(
+      'contribution_id' => $contribution['id'],
+      'api.FinancialItem.getsingle' => array('amount' => array('<' => 0)),
+    ));
+    $this->assertEquals($financialAccount['id'], $lineItems['api.FinancialItem.getsingle']['financial_account_id']);
+
+    $this->callAPISuccess('Contribution', 'delete', array('id' => $contribution['id']));
+    $this->callAPISuccess('EntityFinancialAccount', 'delete', array('id' => $entityFinancialAccount['id']));
+    $this->callAPISuccess('FinancialAccount', 'delete', array('id' => $financialAccount['id']));
+  }
+
   /**
    * Refund a contribution for a financial type with a contra account.
    *
@@ -1093,8 +1158,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
       'contribution_status_id' => 'Refunded',
     ));
 
-    $lineItems = $this->callAPISuccessGetSingle(
-      'LineItem', array(
+    $lineItems = $this->callAPISuccessGetSingle('LineItem', array(
       'contribution_id' => $contribution['id'],
       'api.FinancialItem.getsingle' => array('amount' => array('<' => 0)),
     ));
@@ -1103,7 +1167,6 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->callAPISuccess('Contribution', 'delete', array('id' => $contribution['id']));
     $this->callAPISuccess('EntityFinancialAccount', 'delete', array('id' => $entityFinancialAccount['id']));
     $this->callAPISuccess('FinancialAccount', 'delete', array('id' => $financialAccount['id']));
-
   }
 
   /**
@@ -2354,9 +2417,14 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
   }
 
   /**
+   * Check financial transaction.
+   *
+   * @todo break this down into sensible functions - most calls to it only use a few lines out of the big if.
+   *
    * @param array $contribution
    * @param string $context
    * @param int $instrumentId
+   * @param array $extraParams
    */
   public function _checkFinancialTrxn($contribution, $context, $instrumentId = NULL, $extraParams = array()) {
     $trxnParams = array(