From 52da5b1e5b25a7e7840c8372b250492b169bf33a Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 4 Feb 2016 23:54:31 +1300 Subject: [PATCH] CRM-17951 add Contribution Status of Chargeback --- CRM/Contribute/BAO/Contribution.php | 27 ++++++--- CRM/Financial/BAO/FinancialAccount.php | 2 +- tests/phpunit/api/v3/ContributionTest.php | 74 ++++++++++++++++++++++- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 748099942f..571763a937 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -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'), diff --git a/CRM/Financial/BAO/FinancialAccount.php b/CRM/Financial/BAO/FinancialAccount.php index 79657577d8..80ef79e2bd 100644 --- a/CRM/Financial/BAO/FinancialAccount.php +++ b/CRM/Financial/BAO/FinancialAccount.php @@ -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; } } diff --git a/tests/phpunit/api/v3/ContributionTest.php b/tests/phpunit/api/v3/ContributionTest.php index 63b1a016df..513a4b6fe2 100644 --- a/tests/phpunit/api/v3/ContributionTest.php +++ b/tests/phpunit/api/v3/ContributionTest.php @@ -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( -- 2.25.1