Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRM-21311 Credit card type is unset on submission causing credit card payment to fail with CVV validation error message #11137

Closed
wants to merge 5 commits into from

Conversation

jusfreeman
Copy link
Contributor

@jusfreeman jusfreeman commented Oct 14, 2017

Overview

Credit card type is unset on submission causing credit card payment to fail with CVV validation error message. Regression bug introduced in PR #10774

Before

In CiviCRM, change default credit card name for "Amex" to "American Express".
Submit a test credit card transaction using an American Express test credit card number, 378282246310005
Contribution will fail with CVV validation error message.
Existing code does not set the credit card type on submission, causing the CVV not to be validated correctly. American Express uses 4 digit CVV.

After

Credit card type is set correctly, CVV is validated and submission succeeds.

Technical Details

Regression bug introduced in PR #10774 - See https://github.com/civicrm/civicrm-core/pull/10774/files#diff-31a6607a9f03e2336c412d8fad30d711R72

This function has a comment that it was created to be used only for CSS names. Since PR #10774 it is being used to return a json string. Recommend refactor function name and remove comment - since it is not just being used for CSS anymore.

See CRM/Core/Payment/Form.php - public static function getCreditCardCSSNames

https://github.com/civicrm/civicrm-core/pull/10774/files#diff-31f2b294fac11671bf5ae72d8e6d7172R115

Comments

Who uses AMEX anyway?


@civicrm-builder
Copy link

Can one of the admins verify this patch?

@jusfreeman
Copy link
Contributor Author

@monishdeb another one to review buddy!

@monishdeb
Copy link
Member

monishdeb commented Oct 14, 2017

@jusfreeman I have reviewed your changes and it fixes the issues you mentioned above but causes another regression. Let me explain with screencast, where after submission, card type ID is not saved.

After applying the patch do a live contribution with Visa (4111111111111111 / 123)
batch-after

Without patch do a live contribution with Visa (4111111111111111 / 123)
batch-before
As you can see in comparison to the earlier transaction, the card type and card number (last 4 digit) is recorded now.

@monishdeb
Copy link
Member

monishdeb commented Oct 14, 2017

This patch is also affecting backoffice contribution as CC(Credit Card) type id is not recorded. Do a backoffice contribution using CC as payment instrument and use Visa/1111 as CC type and last 4 digit card number. You will find that CC type ID is not saved (you need to look at civicrm_financial_trxn)

@eileenmcnaughton
Copy link
Contributor

I think this HAS TO BE fixed in 4.7.27 - even if at expense of recording credit card type - we can't be not accepting cards.

I'm confused as to why there is a problem with this fix. It seems the array on the form looks like

<select name="credit_card_type" id="credit_card_type" class="crm-form-select" style="display: none;">
	<option value="">- select -</option>
	<option value="Visa">Visa</option>
	<option value="MasterCard">MasterCard</option>
	<option value="Amex">American Express</option>
	<option value="Discover">Discover</option>
</select>

Later on we see

  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);
    }
  }

So we are taking the name field from the option value & using it with 'getKey' - so as long as we are always working with the KEY/ machine_name and never with the label we should be OK. So the js fix changes us from using label to name - which seems a correct part of the fix.

I can't see why the php function change is needed at this stage. We should totally NOT allow anything in the machine_name field that machines don't like

@seamuslee001 ^^

@seamuslee001
Copy link
Contributor

I think that sounds right but not 100% sure, I will try and test this when i am a bit less jetlagged

@jusfreeman
Copy link
Contributor Author

Jenkins please test

@eileenmcnaughton
Copy link
Contributor

So my concern here is whether this now means the format that will be passed to the processors will change slightly (e.g from visa to Visa). Paypal code DOES pass this through to Paypal. Others might too.

I think it makes sense to update the name field in the DB to lower case so that will stay consistent?

UPDATE civicrm_option_value v
INNER JOIN civicrm_option_group g
ON v.option_group_id = g.id AND g.name= 'accept_creditcard'
SET v.name = lower(v.name) ;

@eileenmcnaughton
Copy link
Contributor

(the code changes do seem like a sensible magicobotomy)

@jusfreeman
Copy link
Contributor Author

I think it makes sense to update the name field in the DB to lower case so that will stay consistent?

@eileenmcnaughton Simple solutions are best and yes, I think that's fine to do that too. Still the credit card type key should be lowercased in code before passing to the payment processor - if that's what they accept (or have been given in the past).

It's worth keeping in mind that the problem being solved here really was that the key and the label for the credit card type were assumed to be the same value. And so were used interchangeably throughout the code. Now that users can easily change the label for any credit card type, this breaks credit card type being set and on-line payments is then non-functional.

I noticed that CiviCRM actually ships with pear libraries which have built-in credit card number validation and setting of the credit card type. So all this jiggery pokery could be made simpler by just doing server side validation and setting of the credit card type. And to be honest, I think that would be a more robust solution going forward - the current state is very fragile. Why even ask the user what type of credit card it is, when this can be computed?

I can see there is still a problem on the Contribution confirmation page where the credit card type key is displayed, instead of the label. That should also be changed and all other payment confirmation pages (Event, Contribution, Membership etc.) changed to display the credit card type label.

For changing the confirmation pages, I am not really sure what to do here and would appreciate advise or someone else helping out.

Files:
templates/CRM/Contribute/Form/Contribution/Confirm.tpl
CRM/Contribute/Form/Contribution/Confirm.php

contribution-confirmation-page

@eileenmcnaughton
Copy link
Contributor

"Why even ask the user what type of credit card it is, when this can be computed?" - good question @KarinG @colemanw @JoeMurray - do any of you know?

@KarinG
Copy link
Contributor

KarinG commented Oct 18, 2017

No - I don’t - I’m pretty sure I asked the same question;

@KarinG
Copy link
Contributor

KarinG commented Oct 18, 2017

So what 4.7.x version has this bug? I have a 4.7 site that’s on 4.7.22 - that is happily accepting AMEX (I just checked);

@KarinG
Copy link
Contributor

KarinG commented Oct 18, 2017

It’s more a lookup rather than a compute: https://en.m.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_.28IIN.29

@eileenmcnaughton
Copy link
Contributor

@KarinG the bug only manefests if you change the label on the option value from Amex to American Express

@KarinG
Copy link
Contributor

KarinG commented Oct 19, 2017

Ah I see - thank you; yeah we don’t do that; so that explains why we’ve not seen it;

@eileenmcnaughton
Copy link
Contributor

right - it's kinda edge.

@monishdeb
Copy link
Member

Jenkin test this please

@jusfreeman
Copy link
Contributor Author

right - it's kinda edge.

@eileenmcnaughton as you know, we live on the edge!

@eileenmcnaughton
Copy link
Contributor

You rebel you!

I think the best path to getting this resolved is to update the name field in the DB to be lower case (via upgrade script) and keep the main js change in this PR but cull out a couple of the changes that are about handling the casing change. We might make the option values 'is_reserved' = TRUE too, since the name values are not actually permitted to be amended.

I think there is a case for not having card type but I think it should be resolved as a follow up since it probably involves email discussion and requires at least 6 people to attempt to hijack the change with their pet project before we can be sure everyone is happy with the basic principle of removing the field :-)

@jusfreeman
Copy link
Contributor Author

Jenkin test this please

@jusfreeman
Copy link
Contributor Author

I think the best path to getting this resolved is to update the name field in the DB to be lower case (via upgrade script)

@eileenmcnaughton can you provide some guidance on doing this change?

@eileenmcnaughton
Copy link
Contributor

it can be done in CRM_Upgrade_Incremental_php_FourSeven

… credit card payment to fail with CVV validation error message
…ardCSSNames and replace with CRM_Contribute_PseudoConstant::creditCard for consistency - remove reliance on lowercase credit card names
… remove JS validation of card types which cannot be defined, remove unused call to CRM.config.creditCardTypes
@agilewarealok agilewarealok force-pushed the 4.7-CRM-21311 branch 2 times, most recently from 5c57d5b to f2c8031 Compare December 5, 2017 06:48
@agilewarealok
Copy link
Contributor

@eileenmcnaughton We've updated the PR by adding Update query in CRM_Upgrade_Incremental_php_FourSeven under upgrade_4_7_27

@colemanw
Copy link
Member

colemanw commented Dec 6, 2017

That upgrade function looks correct, except it will need to be moved to function upgrade_4_7_30 because of our release schedule (4.7.28 is going out today. 4.7.27 is already out and 4.7.29-rc is about to be cut). If we consider this critical enough and the PR is complete we could potentially merge it into the 4.7.29-rc, but currently it looks like there are still some outstanding review comments from @eileenmcnaughton about culling case handling changes.

@jusfreeman
Copy link
Contributor Author

For the "culling case handling changes" - all the conversion to lowercase in JS are required for CSS declarations. I recommend leaving as is.

@eileenmcnaughton would mind reviewing this again, thanks.

$.each(CRM.config.creditCardTypes, function(key, val) {
var html = '<a href="#" title="' + val + '" class="crm-credit_card_type-icon-' + key + '"><span>' + val + '</span></a>';
$.each(CRM.config.creditCardTypes, function(card_type_key, val) {
card_type_css = card_type_key.toLowerCase();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line should not be required now - we have a list of names that are already lower case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileenmcnaughton We've just tested against master and logging CRM.config.creditCardTypes return following JSON string.

{Visa: "Visa", MasterCard: "MasterCard", Amex: "Amex", Discover: "Discover"}

So the first character of each keys are still in uppercase.

@@ -117,7 +117,7 @@ public function setDefaultValues() {
*/
public static function addCreditCardJs($paymentProcessorID = NULL, $region = 'billing-block') {
$creditCards = CRM_Financial_BAO_PaymentProcessor::getCreditCards($paymentProcessorID);
$creditCardTypes = CRM_Core_Payment_Form::getCreditCardCSSNames($creditCards);
$creditCardTypes = CRM_Contribute_PseudoConstant::creditCard($creditCards);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we want to be assigning an array of name=>label yeah - ie

[
'visa' =.> 'Visa',
'mastercard' => 'MasterCard'
/....
]

@@ -27,13 +28,14 @@
// set the card type value as default if any found
var cardtype = $('#credit_card_type').val();
if (cardtype) {
$.each(CRM.config.creditCardTypes, function(key, value) {
$.each(CRM.config.creditCardTypes, function(card_type_key, value) {
card_type_css = card_type_key.toLowerCase();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto here - we should be already in lowercase

var card_types = {
'mastercard': '(5[1-5][0-9]{2}|2[3-6][0-9]{2}|22[3-9][0-9]|222[1-9]|27[0-1][0-9]|2720)[0-9]{12}',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure we should be changing this - we should be running off the lower case 'name' field?

@@ -48,21 +48,21 @@ public function testGetCreditCards() {
'domain_id' => 1,
'accepted_credit_cards' => json_encode(array(
'Visa' => 'Visa',
'Mastercard' => 'Mastercard',
'Amex' => 'Amex',
'MasterCard' => 'Mastercard',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't we doing 'mastercard' => 'Mastercard' now?

@jusfreeman
Copy link
Contributor Author

@eileenmcnaughton happy for you to edit this PR so we can get it merged.

@eileenmcnaughton
Copy link
Contributor

Closing in favour of #12615 (which requires review)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants