From a55e39e9c3f2680c24c8b3aa190de606a000f5cd Mon Sep 17 00:00:00 2001 From: "deb.monish" Date: Wed, 19 Apr 2017 17:55:47 +0530 Subject: [PATCH] CRM-20264 support card_type_id and pan_truncation in all backoffice form --- CRM/Contribute/BAO/Contribution.php | 7 ++ CRM/Contribute/Form/AbstractEditPayment.php | 25 +++-- CRM/Contribute/Form/Contribution.php | 7 +- CRM/Contribute/Form/Contribution/Confirm.php | 19 ++-- CRM/Core/Payment.php | 19 ++++ CRM/Core/Payment/Form.php | 2 +- CRM/Core/Payment/Manual.php | 2 +- CRM/Financial/Form/Payment.php | 1 + CRM/Member/BAO/Membership.php | 2 + CRM/Member/Form/Membership.php | 2 + api/v3/Contribution.php | 19 +++- .../CRM/Contribute/Form/Contribution.tpl | 5 + templates/CRM/Core/BillingBlock.tpl | 1 - templates/CRM/Member/Form/Membership.tpl | 8 -- .../CRM/Member/Form/MembershipCommon.tpl | 11 ++- .../CRM/Contribute/Form/ContributionTest.php | 97 +++++++++++++++++++ 16 files changed, 195 insertions(+), 32 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index fe49c31bca..c18b70b871 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -3135,6 +3135,8 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac $balanceTrxnParams['status_id'] = $statusId; $balanceTrxnParams['payment_instrument_id'] = $params['contribution']->payment_instrument_id; $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params); + $balanceTrxnParams['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $params); + $balanceTrxnParams['card_type_id'] = CRM_Utils_Array::value('card_type_id', $params); if (!empty($balanceTrxnParams['from_financial_account_id']) && ($statusId == array_search('Completed', $contributionStatuses) || $statusId == array_search('Partially paid', $contributionStatuses)) ) { @@ -3199,6 +3201,8 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac 'status_id' => $statusId, 'payment_instrument_id' => CRM_Utils_Array::value('payment_instrument_id', $params, $params['contribution']->payment_instrument_id), 'check_number' => CRM_Utils_Array::value('check_number', $params), + 'pan_truncation' => CRM_Utils_Array::value('pan_truncation', $params), + 'card_type_id' => CRM_Utils_Array::value('card_type_id', $params), ); if ($contributionStatus == 'Refunded' || $contributionStatus == 'Chargeback' || $contributionStatus == 'Cancelled') { $trxnParams['trxn_date'] = !empty($params['contribution']->cancel_date) ? $params['contribution']->cancel_date : date('YmdHis'); @@ -3559,6 +3563,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac return; } } + $trxn = CRM_Core_BAO_FinancialTrxn::create($params['trxnParams']); $params['entity_id'] = $trxn->id; if ($context != 'changePaymentInstrument') { @@ -4464,6 +4469,8 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']}) 'receive_date', 'receipt_date', 'contribution_status_id', + 'card_type_id', + 'pan_truncation', ); if (self::isSingleLineItem($primaryContributionID)) { $inputContributionWhiteList[] = 'financial_type_id'; diff --git a/CRM/Contribute/Form/AbstractEditPayment.php b/CRM/Contribute/Form/AbstractEditPayment.php index 4e0801e91d..62e0514531 100644 --- a/CRM/Contribute/Form/AbstractEditPayment.php +++ b/CRM/Contribute/Form/AbstractEditPayment.php @@ -221,6 +221,7 @@ class CRM_Contribute_Form_AbstractEditPayment extends CRM_Contact_Form_Task { CRM_Core_Resources::singleton()->addVars('coreForm', array('contact_id' => (int) $this->_contactID)); $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); $this->_mode = empty($this->_mode) ? CRM_Utils_Request::retrieve('mode', 'String', $this) : $this->_mode; + $this->assign('isBackOffice', $this->isBackOffice); $this->assignPaymentRelatedVariables(); } @@ -573,15 +574,27 @@ WHERE contribution_id = {$id} $this->assign('credit_card_type', CRM_Utils_Array::value('credit_card_type', $this->_params)); } $this->_params['ip_address'] = CRM_Utils_System::ipAddress(); - if (in_array('credit_card_type', array_keys($this->_params))) { - $this->_params['card_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'card_type_id', $this->_params['credit_card_type']); - } - if (!empty($this->_params['credit_card_number']) && empty($this->_params['pan_truncation'])) { - $this->_params['pan_truncation'] = substr($this->_params['credit_card_number'], -4); - } + self::formatCreditCardDetails($this->_params); } + /** + * Format credit card details like: + * 1. Retrieve last 4 digit from credit card number as pan_truncation + * 2. Retrieve credit card type id from name + * + * @param array $params + * + * @return void + */ + public static function formatCreditCardDetails(&$params) { + if (in_array('credit_card_type', array_keys($params))) { + $params['card_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'card_type_id', $params['credit_card_type']); + } + if (!empty($params['credit_card_number']) && empty($params['pan_truncation'])) { + $params['pan_truncation'] = substr($params['credit_card_number'], -4); + } + } /** * Add the billing address to the contact who paid. diff --git a/CRM/Contribute/Form/Contribution.php b/CRM/Contribute/Form/Contribution.php index 7034a131a3..f9209b94d1 100644 --- a/CRM/Contribute/Form/Contribution.php +++ b/CRM/Contribute/Form/Contribution.php @@ -1274,6 +1274,8 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP 'payment_processor_id' => $this->_paymentProcessor['id'], 'is_transactional' => FALSE, 'fee_amount' => CRM_Utils_Array::value('fee_amount', $result), + 'card_type_id' => CRM_Utils_Array::value('card_type_id', $paymentParams), + 'pan_truncation' => CRM_Utils_Array::value('pan_truncation', $paymentParams), )); // This has now been set to 1 in the DB - declare it here also $contribution->contribution_status_id = 1; @@ -1432,10 +1434,11 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP * @throws \Exception */ protected function submit($submittedValues, $action, $pledgePaymentID) { - $pId = $contribution = $isRelatedId = FALSE; $this->_params = $submittedValues; $this->beginPostProcess(); + // reassign submitted form values if the any information is formatted via beginPostProcess + $submittedValues = $this->_params; if (!empty($submittedValues['price_set_id']) && $action & CRM_Core_Action::UPDATE) { $line = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution'); @@ -1643,6 +1646,8 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP 'cancel_reason', 'source', 'check_number', + 'card_type_id', + 'pan_truncation', ); foreach ($fields as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index 55844c1b68..83ed30a6d9 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -2037,6 +2037,8 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr // fix currency ID $this->_params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency; + CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($this->_params); + // CRM-18854 if (CRM_Utils_Array::value('is_pledge', $this->_params) && !CRM_Utils_Array::value('pledge_id', $this->_values) && CRM_Utils_Array::value('adjust_recur_start_date', $this->_values)) { $pledgeBlock = CRM_Pledge_BAO_PledgeBlock::getPledgeBlock($this->_id); @@ -2434,14 +2436,15 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr 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), - 'receive_date' => CRM_Utils_Array::value('receive_date', $result), - ) - ); + '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), + 'receive_date' => CRM_Utils_Array::value('receive_date', $result), + 'card_type_id' => CRM_Utils_Array::value('card_type_id', $result), + 'pan_truncation' => CRM_Utils_Array::value('pan_truncation', $result), + )); } catch (CiviCRM_API3_Exception $e) { if ($e->getErrorCode() != 'contribution_completed') { diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php index c26f8f4a0c..63657464ad 100644 --- a/CRM/Core/Payment.php +++ b/CRM/Core/Payment.php @@ -60,6 +60,18 @@ abstract class CRM_Core_Payment { BILLING_MODE_BUTTON = 2, BILLING_MODE_NOTIFY = 4; + /** + * Which payment type(s) are we using? + * + * credit card + * direct debit + * or both + * @todo create option group - nb omnipay uses a 3rd type - transparent redirect cc + */ + const + PAYMENT_TYPE_CREDIT_CARD = 1, + PAYMENT_TYPE_DIRECT_DEBIT = 2; + /** * Subscription / Recurring payment Status * START, END @@ -781,6 +793,13 @@ abstract class CRM_Core_Payment { 'maxlength' => 4, 'autocomplete' => 'off', ), + 'rules' => array( + array( + 'rule_message' => ts('Please enter valid last 4 digit card number.'), + 'rule_name' => 'numeric', + 'rule_parameters' => NULL, + ), + ), ), ); } diff --git a/CRM/Core/Payment/Form.php b/CRM/Core/Payment/Form.php index eadec63d93..a2286be568 100644 --- a/CRM/Core/Payment/Form.php +++ b/CRM/Core/Payment/Form.php @@ -67,8 +67,8 @@ class CRM_Core_Payment_Form { $processor['object']->setBackOffice($isBackOffice); $processor['object']->setPaymentInstrumentID($paymentInstrumentID); $paymentTypeName = self::getPaymentTypeName($processor); - $paymentTypeLabel = self::getPaymentTypeLabel($processor); $form->assign('paymentTypeName', $paymentTypeName); + $paymentTypeLabel = self::getPaymentTypeLabel($processor); $form->assign('paymentTypeLabel', $paymentTypeLabel); $form->assign('isBackOffice', $isBackOffice); $form->_paymentFields = $form->billingFieldSets[$paymentTypeName]['fields'] = self::getPaymentFieldMetadata($processor); diff --git a/CRM/Core/Payment/Manual.php b/CRM/Core/Payment/Manual.php index 13657435c3..9024f10cab 100644 --- a/CRM/Core/Payment/Manual.php +++ b/CRM/Core/Payment/Manual.php @@ -95,7 +95,7 @@ class CRM_Core_Payment_Manual extends CRM_Core_Payment { // However there is an ambiguity as that field is an integer & should hence be called // credit_card_type_id, or it should store 'visa' It probably makes sense to fix that before going much // further as the code I've seen makes it clear that it will require work arounds. - return array('pan_truncation'); + return array('credit_card_type', 'pan_truncation'); } elseif ($paymentInstrument === 'Check') { // Really we should render check_number here, but we need to review how we edit diff --git a/CRM/Financial/Form/Payment.php b/CRM/Financial/Form/Payment.php index 0830426248..996e45abc0 100644 --- a/CRM/Financial/Form/Payment.php +++ b/CRM/Financial/Form/Payment.php @@ -37,6 +37,7 @@ class CRM_Financial_Form_Payment extends CRM_Core_Form { */ protected $_paymentProcessorID; protected $currency; + public $_values = array(); /** diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php index ad9338a4d3..746d738d42 100644 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@ -2408,6 +2408,8 @@ WHERE civicrm_membership.is_test = 0"; 'tax_amount', 'skipLineItem', 'contribution_recur_id', + 'pan_truncation', + 'card_type_id', ); foreach ($recordContribution as $f) { $contributionParams[$f] = CRM_Utils_Array::value($f, $params); diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php index 4bc2375003..cfb5a743ca 100644 --- a/CRM/Member/Form/Membership.php +++ b/CRM/Member/Form/Membership.php @@ -1308,6 +1308,8 @@ class CRM_Member_Form_Membership extends CRM_Member_Form { 'check_number', 'campaign_id', 'receive_date', + 'card_type_id', + 'pan_truncation', ); foreach ($recordContribution as $f) { diff --git a/api/v3/Contribution.php b/api/v3/Contribution.php index 2fa6ba7205..aa58066f25 100644 --- a/api/v3/Contribution.php +++ b/api/v3/Contribution.php @@ -160,6 +160,14 @@ function _civicrm_api3_contribution_create_spec(&$params) { 'type' => CRM_Utils_Type::T_STRING, 'description' => 'Transaction ID specific to the refund taking place', ); + $params['card_type_id'] = array( + 'title' => 'Card Type ID', + 'description' => 'Providing Credit Card Type ID', + 'type' => CRM_Utils_Type::T_INT, + 'pseudoconstant' => array( + 'optionGroupName' => 'accept_creditcard', + ), + ); } /** @@ -511,7 +519,6 @@ function _civicrm_api3_contribution_sendconfirmation_spec(&$params) { * @throws \Exception */ function civicrm_api3_contribution_completetransaction(&$params) { - $input = $ids = array(); if (isset($params['payment_processor_id'])) { $input['payment_processor_id'] = $params['payment_processor_id']; @@ -581,6 +588,14 @@ function _civicrm_api3_contribution_completetransaction_spec(&$params) { 'description' => 'Date this transaction occurred', 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, ); + $params['card_type_id'] = array( + 'title' => 'Card Type ID', + 'description' => 'Providing Credit Card Type ID', + 'type' => CRM_Utils_Type::T_INT, + 'pseudoconstant' => array( + 'optionGroupName' => 'accept_creditcard', + ), + ); } /** @@ -693,6 +708,8 @@ function _ipn_process_transaction(&$params, $contribution, $input, $ids, $firstC $input['receipt_from_name'] = CRM_Utils_Array::value('receipt_from_name', $params, $domainFromName); $input['receipt_from_email'] = CRM_Utils_Array::value('receipt_from_email', $params, $domainFromEmail); } + $input['card_type_id'] = CRM_Utils_Array::value('card_type_id', $params); + $input['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $params); $transaction = new CRM_Core_Transaction(); return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction, !empty ($contribution->contribution_recur_id), $contribution, diff --git a/templates/CRM/Contribute/Form/Contribution.tpl b/templates/CRM/Contribute/Form/Contribution.tpl index 3191ccf6e9..193f2a4177 100644 --- a/templates/CRM/Contribute/Form/Contribution.tpl +++ b/templates/CRM/Contribute/Form/Contribution.tpl @@ -235,6 +235,10 @@ {if !$contributionMode} +
+ + {ts}Payment Details{/ts} + @@ -282,6 +286,7 @@
{$form.receive_date.label}{$form.from_email_address.html}
+
{/if} {include file='CRM/Core/BillingBlockWrapper.tpl'} diff --git a/templates/CRM/Core/BillingBlock.tpl b/templates/CRM/Core/BillingBlock.tpl index dda84773bd..1f4d394a89 100644 --- a/templates/CRM/Core/BillingBlock.tpl +++ b/templates/CRM/Core/BillingBlock.tpl @@ -221,4 +221,3 @@ {* Payment processors sometimes need to append something to the end of the billing block. We create a region for clarity - the plan is to move to assigning this through the payment processor to this region *} {/crmRegion} - diff --git a/templates/CRM/Member/Form/Membership.tpl b/templates/CRM/Member/Form/Membership.tpl index b153be9bfd..acad1a9000 100644 --- a/templates/CRM/Member/Form/Membership.tpl +++ b/templates/CRM/Member/Form/Membership.tpl @@ -241,14 +241,6 @@ field_type ="radio" invert = 0 } - {include file="CRM/common/showHideByFieldValue.tpl" - trigger_field_id ="payment_instrument_id" - trigger_value = '4' - target_element_id ="checkNumber" - target_element_type ="table-row" - field_type ="select" - invert = 0 - } {/if} {literal} diff --git a/templates/CRM/Member/Form/MembershipCommon.tpl b/templates/CRM/Member/Form/MembershipCommon.tpl index 2ef6c8f194..52e0d89c20 100644 --- a/templates/CRM/Member/Form/MembershipCommon.tpl +++ b/templates/CRM/Member/Form/MembershipCommon.tpl @@ -97,11 +97,12 @@ - - - {include file='CRM/Core/BillingBlockWrapper.tpl'} - -
{/if} + + + + {include file='CRM/Core/BillingBlockWrapper.tpl'} + + diff --git a/tests/phpunit/CRM/Contribute/Form/ContributionTest.php b/tests/phpunit/CRM/Contribute/Form/ContributionTest.php index 62cc9ec37b..6d9710542b 100644 --- a/tests/phpunit/CRM/Contribute/Form/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/Form/ContributionTest.php @@ -922,4 +922,101 @@ Price Field - Price Field 1 1 $ 100.00 $ 100.00 $this->callAPISuccessGetCount('FinancialItem', array(), 2); } + /** + * function to test card_type and pan truncation. + */ + public function testCardTypeAndPanTruncation() { + $form = new CRM_Contribute_Form_Contribution(); + $form->testSubmit( + array( + 'total_amount' => 100, + 'financial_type_id' => 3, + 'receive_date' => '04/21/2015', + 'receive_date_time' => '11:27PM', + 'contact_id' => $this->_individualId, + 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments), + 'contribution_status_id' => 1, + 'credit_card_type' => 'Visa', + 'pan_truncation' => 4567, + 'price_set_id' => 0, + ), + CRM_Core_Action::ADD + ); + $contribution = $this->callAPISuccessGetSingle('Contribution', + array( + 'contact_id' => $this->_individualId, + 'return' => array('id'), + ) + ); + $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC'); + $financialTrxn = $this->callAPISuccessGetSingle( + 'FinancialTrxn', + array( + 'id' => $lastFinancialTrxnId['financialTrxnId'], + 'return' => array('card_type_id.label', 'pan_truncation'), + ) + ); + $this->assertEquals(CRM_Utils_Array::value('card_type_id.label', $financialTrxn), 'Visa'); + $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 4567); + } + + /** + * function to test card_type and pan truncation. + */ + public function testCardTypeAndPanTruncationLiveMode() { + $visaID = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'card_type_id', 'Visa'); + $form = new CRM_Contribute_Form_Contribution(); + $form->_mode = 'Live'; + $error = FALSE; + $form->testSubmit( + array( + 'total_amount' => 50, + 'financial_type_id' => 1, + 'receive_date' => '04/21/2015', + 'receive_date_time' => '11:27PM', + 'contact_id' => $this->_individualId, + 'credit_card_number' => 4444333322221111, + 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments), + 'cvv2' => 123, + 'credit_card_exp_date' => array( + 'M' => 9, + 'Y' => date('Y', strtotime('+5 years')), + ), + 'credit_card_type' => 'Visa', + 'billing_first_name' => 'Junko', + 'billing_middle_name' => '', + 'billing_last_name' => 'Adams', + 'billing_street_address-5' => '790L Lincoln St S', + 'billing_city-5' => 'Maryknoll', + 'billing_state_province_id-5' => 1031, + 'billing_postal_code-5' => 10545, + 'billing_country_id-5' => 1228, + 'frequency_interval' => 1, + 'frequency_unit' => 'month', + 'installments' => '', + 'hidden_AdditionalDetail' => 1, + 'hidden_Premium' => 1, + 'from_email_address' => '"civi45" ', + 'receipt_date' => '', + 'receipt_date_time' => '', + 'payment_processor_id' => $this->paymentProcessorID, + 'currency' => 'USD', + 'source' => 'bob sled race', + ), + CRM_Core_Action::ADD + ); + $contribution = $this->callAPISuccessGetSingle('Contribution', array('contact_id' => $this->_individualId)); + $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC'); + $financialTrxn = $this->callAPISuccessGetSingle( + 'FinancialTrxn', + array( + 'id' => $lastFinancialTrxnId['financialTrxnId'], + 'return' => array('card_type_id', 'pan_truncation'), + ) + ); + // @todo in test environment FinancialTrxn.getsingle doesn't fetch card_type_id value + //$this->assertEquals(CRM_Utils_Array::value('card_type_id', $financialTrxn), $visaID); + $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 1111); + } + } -- 2.25.1