Support is requested for 3D Secure 2.
Brtaintree overview is here: https://www.braintreepayments.com/blog/ready-for-3d-secure-2-0
Braintree documentation is here: https://developers.braintreepayments.com/guides/3d-secure/overview
Current status:
The current patch #47 works for both logged-in and anonymous users, for both initial transactions with a payment method and subsequent transactions with a stored payment method.
Summary of current progress:
Must do:
Fixed: Fix for logged-in non-guest checkout
Should do:
The verifyCard call should have the customer email address provided in hosted-fields-3ds.js
The verifyCard call should have the customer billing telephone number provided in hosted-fields-3ds.js
(See the Braintree docs)
| Comment | File | Size | Author |
|---|---|---|---|
| #99 | interdiff_97-99.txt | 1.87 KB | jsacksick |
| #99 | 3012225-99.patch | 24.1 KB | jsacksick |
| #98 | interdiff_96-97.txt | 10.64 KB | jsacksick |
| #97 | 3012225-97.patch | 24.24 KB | jsacksick |
| #89 | interdiff-3012225-85-89.txt | 2.32 KB | lisastreeter |
Comments
Comment #2
bojanz commentedAdding related Commerce issue.
Comment #3
luksakBraintree just sent out this mail to customers:
What is the plan regarding 3DS 2.0?
Comment #4
scotwith1tAlso need a plan for a client regarding 3DS/PSD2 jazz. Thanks for any update!
Comment #5
bojanz commentedNobody has offered to sponsor 3DS 2.0 so far, so there is no plan.
The Commerce Guys R&D resources are already assigned to other initiatives for Q1 2019.
So, possibly may/june, but no guarantees yet.
Comment #6
luksak@bojanz thank you for the update! Could Braintree sponsor this?
Comment #7
bojanz commentedI will reach out to them and keep you updated.
Comment #8
sittard commentedAlthough we have until September 2019 to comply Braintree recommends that merchants be ready to integrate 3DS 2.0 into their checkout experience by April 2019. Therefore any chance this could be implemented sooner than May / June?
See also: https://www.braintreepayments.com/blog/ready-for-3d-secure-2-0/
Thanks.
Comment #9
bbuchert commentedComment #10
bojanz commentedWe have been able to secure funding.
The delivery date (Commerce & Braintree releases) is May 1st.
Work will start in March, with the goal of delivering initial results by April, but we can't guarantee completeness or stability at that point.
Comment #11
scotwith1tThat's great news!! Any chance there will also be a back port for D7, ideally in the same timeframe? :-/
Comment #12
bojanz commentedYou would need to ask andyg5000, he develops and maintains the D7 branch, not Commerce Guys.
The issue for that is #2496627: Support 3D Secure.
Comment #13
lisastreeter commentedThe payment gateway configuration setting for "3 D Secure" has three options: Disabled, Enabled, and Required.
When 3DS is enabled in normal/enabled mode, payments are accepted whenever liability is shifted. They are rejected when liability is NOT shifted but liability shift IS possible. In all other cases, the customer is not enrolled in 3DS so liability shift is not possible, and payments are accepted.
If 3DS is configured in strict/required mode, payments are only accepted when liability is shifted. Customers must be enrolled to make a payment and complete checkout.
For information on why certain 3DS result statuses are rejected/accepted, see https://developers.braintreepayments.com/guides/3d-secure/server-side/php
Comment #14
bojanz commentedThanks, Lisa!
Updating status.
Comment #15
lisastreeter commentedPrevious patch didn't apply. Hopefully this one will.
Also, this updated patch changes "three_d" to "3d" and updates Braintree 3Ds library version from 3.31.0 to 3.43.0.
Comment #16
mglamanThis will not work against the latest 2.x as the route match is no longer injected.
Comment #17
sittard commentedMany thanks for all the hard work on this feature it's looking good. How close are we to a release on this feature. Comments above suggest that the delivery date (Commerce & Braintree releases) was May 1st.
Thanks.
Comment #18
ashley george commentedSubscribing
Comment #19
luksak@Ashley George please do not subscribe using a comment. You can use the "Follow" link in the right column at the top.
Comment #20
kristofferromAnyone has plans to do this for the D7-version too?
Comment #21
mglamanWe can backport to 7.x once built for 8.x; once the lessons are learned it will be possible.
Comment #22
scotwith1tD7 issue is here, just FYI #2496627: Support 3D Secure
Comment #23
sittard commentedTesting with patch #13 and #15 and I'm getting the following error when I click the 'Continue to Review' button on the checkout page:
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">InvalidArgumentException</em>: $payment_details must contain the payment_method_nonce key. in <em class="placeholder">Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields->createPaymentMethod()</em> (line <em class="placeholder">309</em> of <em class="placeholder">modules/contrib/commerce_braintree/src/Plugin/Commerce/PaymentGateway/HostedFields.php</em>). <pre class="backtrace">Drupal\commerce_payment\PluginForm\PaymentMethodAddForm->submitConfigurationForm(Array, Object) (Line: 150)Any ideas? Thanks
Comment #24
sittard commentedRealised my error, I was attempting to apply the patch against 8.x-1.1 release and not the latest development branch. Can confirm that patch #15 does apply and works as expected with Commerce 8.x-2.11.
Thanks.
Comment #25
alanhdev commentedAccording to the implementation guide in the Braintree docs here, 3DS 2 support requires version 3.47.0 or higher of the Javascript V3 SDK. However, with patch #15 applied, the libraries loaded are only 3.43.0. According to Braintree docs here, there are new parameters for verify card calls which require the updated SDK.
I could re-roll the patch to update the JS SDK library versions, but there are other issues. For instance, the version is not being specified in braintree.threeDSecure.create as per the docs here meaning that the 3DS 2 protocol isn't being used.
The current Braintree PHP SDK version is 4.2.0 (which also requires PHP 7.2.x). The dependency in the modules's composer.json results in installation of 3.40.
Is anyone actively working on this and, if so, any success using the older PHP library?
Comment #26
bojanz commentedYikes. It's way too early for us to require people to have PHP 7.2. Both 7.0 and 7.1 would have been fine, but 7.2 is still very new.
We need to see if we can get 3DS working with the old SDK (3.4).
If not, we'll need to start notifying people immediately (about the impending requirements change).
Comment #27
alanhdev commentedOkay, here is what I have so far adding 3DS2 to the existing patch #15.
The old Braintree 3.x PHP libraries seem to be functional meaning an upgrade to 4.x and a requirement of PHP 7.2 is not necessary.
Still to do
The verifyCard call needs to have the billing address provided and ideally email address and telephone number too. I've marked this as todo in the hosted-fields-3ds.js file. The billing info is currently pulled directly from the form fields which isn't pretty or robust so that could do with some work.
Patch attached.
Comment #28
sittard commentedTesting with patch #27 (thank you).
Looks good but I noticed that the styling on error messages has disappeared. The commerce_braintree.libraries.yml needs the classy/message dependency added to the hosted-fields-3ds.
As follows:
Sorry not enough time to re-work the patch.
Comment #29
martijn de witIs it an option to support both with a setting or a different sub-module structure?
Comment #30
sittard commentedOK I've had a go at updating the patch #27 (think this is my second or third patch - so hopefully works).
The patch now includes:
- Missing classy/message dependency
- Improvements to UX to scroll error message into view
Also I noticed during testing that the AMEX card was not valid but also did not provide user with an error so I've added some code to display the default 3D error messages to user. See also: https://braintree.github.io/braintree-web/current/three-d-secure_shared_....
@martin I think we are OK with PHP 7.1 requirement please see comments:
https://www.drupal.org/project/commerce_braintree/issues/3012225#comment...
Comment #31
sittard commentedRepost with patch attached - see:
https://www.drupal.org/project/commerce_braintree/issues/3012225#comment...
Comment #32
martijn de witstatus change to trigger the tests.
Sorry had not read that comment well. Than it seems no problem :)
Comment #33
sittard commentedThe AMEX test cards (https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...) don't work with this patch. You will get the client error 'The data passed in `verifyCard` did not pass validation checks. See details for more info'
We've spoken to BrainTree and we may need to implement Amex safe key (for US Merchants).
See: https://developers.braintreepayments.com/guides/3d-secure/configuration#...
Comment #34
alanhdev commentedThe error message object returned by verifyCard has a more helpful error nested further in.
Instead of this in the hosted-fields-3ds.js ...
message = that.errorMsg(verifyCardError);...using something like this will give a nicer message about the card not being supported:
Comment #35
alanhdev commentedI've been testing this on a minimal sandbox install rather than a local copy of our client's dev site and I think there may be an issue with the saved payment method approach which is tripping up the 3DS2 process.
We have implemented a custom guest checkout on the client site which sets the payment method to non-reusable. For those transactions, everything looks good and the 3DS2 verification can be seen in the Braintree sandbox reports.
However, this isn't happening for authorised users and on the sandbox install. With the patch, the 3DS2 verification is called so you see the 3DS2 popup and this will allow a decline or authorisation at this point, but there is no reference to 3DS2 verification on the Braintree sandbox following a successful transaction. I suspect that is due to the payment method being saved and then used for the transaction.
The braintree docs here may be relevant: https://developers.braintreepayments.com/guides/3d-secure/migration/java...(mit)
Comment #36
sittard commentedIf you can you let me know which BrainTree report shows the 3DS2 verification I can check it out in my Sandbox Account.
The other oddity that I've noticed on my Sandbox account under:
Settings > Business > Merchant Account > Account Details (click on an ID)
Under 3D Secure 2.0 it says:
Coming Soon! Learn more about 3DSecure 2.0
Which would suggest that my account is not accepting 3D Secure...
Comment #37
alanhdev commentedOurs also says coming soon but it's accepting 3DS2 transactions.
If you go to Transactions and search for your test transaction, a successful 3DS2 transaction should show a section like this:
3D Secure Information
EnrolledEnrolled (Y)
StatusAuthenticate attempt successful
3DS Version 2.1.0
Liability Shifted true
Liability Shift Possible true
However, I'm only seeing that for non-reusable payment methods (anonymous users) on the custom client checkout. Any created on the sandbox Drupal install resulting in a saved reusable payment method have no reference to 3DS2.
Comment #38
sittard commentedMany thanks I'm not seeing the reference to 3DS2 in any of my test transactions.
So I think your concerns are correct saved reusable payment method as provided by this patch have no 3DS2 verification ;(
Comment #39
alanhdev commentedIf the payment method is set to non-reusable in the createPaymentMethod method in src/Plugin/Commerce/PaymentGateway/HostedFields.php createPaymentMethod, you should see the 3DS2 validation info. I've done this for testing by adding this to the start of the method:
Comment #40
alanhdev commentedComment #41
alanhdev commentedRe-rolled the patch against the latest dev commit #f9395ca with the following changes:
Using this patch, transactions for anonymous guests correctly show the 3DS2 information in the Braintree sandbox. However, it doesn't for logged-in users as per comment #35 so work still needed.
Comment #42
alanhdev commentedUpdated issue description with the current status.
Comment #43
lisastreeter commentedI've been working on, "Transactions for logged-in non-guest checkout are not showing that 3DS 2 is being used." Haven't made much progress, but here's an overview of what's happening.
3DS verification is being properly applied to cards entered by both guest and logged-in users. If the validation fails, the proper exceptions are thrown. On success, a valid payment method nonce is generated, which is a single-use token.
In the case of guest users, we set the "remote ID" of the payment method with the value of the payment method nonce. Then we use that payment method nonce to create the payment. The transaction shows in the Braintree control panel with all the 3DS information.
In the case of logged-in users, we use that payment method nonce to create a payment method stored on Braintree ("vaulted"). After using the nonce for that transaction, we need to generate a new nonce for the actual sale transaction. So we do that in the createPayment method:
This new nonce is valid; if it weren't, the sale transaction wouldn't go through successfully. It does, BUT for this sale transaction, the 3DS information does not show up in the Braintree control panel. I do not know why this is the case. The credit card entered by the logged-in customer is just as fully verified as 3DS as the same credit card for the guest user. After going through the API documentation and reviewing our code in great detail, I'm wondering if this is just a UI error on Braintree's side. It seems like they're either not storing or not reporting on the 3DS status of vaulted credit cards so that when those cards are subsequently used (as is happening here), the 3DS info does not display in the control panel.
Comment #44
lisastreeter commentedI've received a response from Braintree support regarding our issue here. It looks like we're going to have an issue with stored payment methods and 3D secure. Here is the information I've received. (The "second scenario" he refers to is what we're seeing when we create a reusable payment method, store it on Braintree, and then create a sale transaction with the nonce generated from that payment method.)
I haven't looked into that
store_in_vault_on_successoption yet, but it seems like that _could_ work. We just wouldn't create the remote payment method until after the payment is posted. But... then we still have a problem when a customer wants to use that stored payment method. It no longer has the 3D secure information. And "Editing payment methods at checkout is not supported" by Commerce payment, so we have no way to authenticate with 3D secure at that point. So this all requires some more thought.Comment #45
lisastreeter commentedThis patch still needs more work, but it provides a fix for logged-in non-guest checkout. I've only tested "success" scenarios, so if anybody has time to run through test data for both 3ds and normal transactions, that would be helpful https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...
Also, there's a test failure that needs to be investigated/fixed.
The major change in this patch is the addition of a custom checkout pane for the review step. If a stored payment method is being used and 3ds is enabled, then the 3ds authentication modal will launch so that the payment method can be re-authenticated for 3ds (and that authentication data will show up in the merchant control panel.)
Also, whenever a new 3ds-authenticated payment method is created during a non-guest checkout, that payment method is not stored remotely (in the "vault") until after the payment transaction is processed. Non-3ds stored payment methods are still saved to the vault when the payment method is created. I'm not sure whether it's desirable to change this behavior so that we're doing the same thing in both cases. If so, that will mean a rework of the logic in createPaymentMethod() and createPayment().
Comment #46
lisastreeter commentedAll tests are passing (locally) for this updated patch, and I've testing through the UI for various combinations of 3DS/non-3DS/PayPal/PayPal credit/authenticated/guest. The 3D-secure authentication information is getting reported as it should in the Braintress sandbox.
I caught and fixed a couple minor logic bugs in the previous patch, and I've tried to clean up the code to make it more readable.
Comment #47
lisastreeter commentedComment #49
lisastreeter commentedUpdated patch fixes some code styling issues but has no changes to functionality.
Comment #50
lisastreeter commentedComment #51
mglamanI know we had this as an opt-in feature before, but should it be? Based on my work with the Stripe support for 3DS 2.0 and SCA, it jus _is_. There is no way to opt-in.
Has Braintree changed the way 3DS 2.0 works in regards to SCA?
It feels wrong to have a single element with an ID of amount that isn't namedspaced to the module.
Per my earlier comment, this doesn't seem blocked off by the setting.
EDIT: this is the review.js, which assumes we're using 3DS. sorry.
This should be raised somehow. I imagine the error is 3DS auth failure and we need to redirect them somewhere?
We can't use the form trigger of submit here w/ Commerce 2.14 without the trick of passing data of the triggering element.
See #3069640: Profile reuse breaks adding payment method via user page.
Should we add a helper class object?
In stripe we had to make sure $gateway->entity is not empty.
Drive by review. Have to run. I'll try to add tests as I did for Stripe.
Comment #52
lisastreeter commentedUnless somebody knows for sure, I'll dig into the documentation on this. When we initially set up 3DS for a client who already had non-3DS Braintree running in production, everything started failing when we switched on the 3DS. It turned out that the cause was that Braintree required them to use an entirely separate merchant account from the one they had been using. They went through some special process to set up a merchant account that would be compatible with 3DS. The existing merchant account could not be used with 3DS. There was no way for the client to just "turn on" their existing merchant account for 3DS. So if this is still the way things work, I don't know if we'd want to force the 3DS on existing non-3DS merchant accounts? I suppose we could just say, "don't update to this latest version until you've created a 3DS merchant account." Or maybe Braintree has integrated 3DS more seamlessly now. Definitely worth looking into, though, to see if we can/should get rid of the setting for 3DS as an opt-in feature.
Comment #53
lisastreeter commentedLooks like there are several non-namespaced elements in commerce_braintree.form.css:
expiration-month,expiration-year,cvv, andamount. Should we "fix" all of them? Do we need to leave the existing ones as is for BC?UPDATE: actually, this #element isn't even being used, so it should be removed entirely.
Comment #54
lisastreeter commentedI think we need to keep 3DS as an opt-in feature based on the current documentation provided by Braintree.
1. Braintree accounts need to be specifically verified (for either 3DS 1 or 3DS 2). It's not automatic that an account is "enrolled" in 3DS 2. See: https://articles.braintreepayments.com/guides/fraud-tools/3d-secure.
2. Elsewhere in the documentation, it states that there, "may be additional per transaction fee to process 3D Secure transactions". So we may want to allow merchants to opt-out, if they're operating in an environment in which SCA is not a concern and they want to avoid the additional fees?
Generally, it seems like Braintree is still saying that moving to 3DS is something merchants might want to do, if they transact in the EU. It doesn't look like they've fully transitioned everything to 3DS being just "the standard".
Comment #55
mglamanIf Braintree hasn't done a full migration to SCA/3DS by default, then I think we can probably merge this patch, pending CSS notes in #53
Comment #56
lisastreeter commentedNew patch fixes CSS issues described in #53, provides fix for Commerce issue #3069640: Profile reuse breaks adding payment method via user page, replaces console.error() statement with user-facing error message on the form, and ensures $gateway->entity is not empty (see #51).
Comment #57
mglamanStarted from the bottom. Noticed a few things.
Should we inject the current user? or rather we should be checking the owner of the payment method. The owner of the payment method should be reflective of the current user.
It probably needs to be moved to minor units. Let's do so, to be safe, and remove the @todo.
It looks like this is forcing 3DS on the payment add form no matter the configuration, so long as we have a known amount.
Comment #58
lisastreeter commented#57-1
Yes, let's check the owner of the payment method. I think logic will be easier to read here if I flip the order of the if/else conditions and have this instead:
if ($owner && $owner->isAuthenticated() && empty($payment_details['payment_method_3ds']))#57-2 -- yes, good catch. Changing this.
#57-3 Actually, "amount" is only set for 3Ds, so the logic works here. Should I add a comment to make this more clear or change the conditions so that it's more obvious? We have now:
Could change to getting the amount in either case and then checking the condition after:
Comment #59
mglamanMaybe we should only fetch and round the amount if we're using 3DS instead of it being a qualifier for 3DS being activated.
If not empty, get the amount. If the amount is not found and `required` throw an error.
Comment #60
lisastreeter commentedThanks, Matt. That logic update makes sense. I think this patch covers all the review comments.
Using
$this->toMinorUnits()was problematic because it's a protected gateway plugin method. I ended up just copying-and-pasting the entire method intoPaymentMethodAddForm. Perhaps we should open a Commerce core issue to make it a public method so that it can be used in places other than gateway plugins?Comment #61
mglamanThere is an issue, its been open for a bit. I've just copied the logic over as well.
Comment #62
thronedigital commentedIs this being tested against recurring?
Comment #63
mglaman@thronedigital no, Stripe was not either. The main goal is to focus on on-session purchase flows and then handle recurring.
Comment #64
lisastreeter commentedAfter the latest Commerce release, toMinorUnits() is now a public method for payment gateway plugins. I updated the patch to use this method in the payment method add form.
Then while re-testing on my local dev, I discovered a bug related to the interaction between the billing address selection form and the javascript for the hosted fields js. These two lines were added to fix a bug related to payment methods created manually through the UI:
But if the customer attempts to change the billing address during checkout, the payment form breaks. So I applied the same change as in https://www.drupal.org/project/commerce_braintree/issues/3077453, which fixed the bug.
However, the user payment method add form still does not work for 3DS, because 3DS authentication requires the payment amount, which it gets during checkout from the order. The user payment method add form does not have an order, and we no longer fall back to non-3DS version when the order is missing. We could rework the logic to allow users to create non-3DS stored credit cards, but that's probably not what we want. Perhaps it would be better to create with a small, fixed amount? The stored 3DS method would then get re-authenticated whenever the payment method actually gets used.
Comment #65
p.lavelle commentedHi,
May I ask if there has been any futher progress on this?
Comment #66
martijn de witport #64 to a working version for dev 0ddc6fb
@todo apply same check as #3090170: Add subsource integrety for external JS
Comment #67
martijn de witAdded a hash as every file has one now per #3090170: Add subsource integrety for external JS.
Comment #68
martijn de witFixed some typos. Prettifier used singel quotes :|
Comment #69
sittard commentedWe have just upgraded to Drupal Commerce 2.18 and I'm trying to apply patch #68 against the latest commerce_braintree dev a49099d. Patch seems to apply but when we get to the checkout page /checkout/123/order_information I'm getting the following error:
Drupal\Core\Asset\Exception\InvalidLibraryFileException: Invalid library definition in modules/contrib/commerce_braintree/commerce_braintree.libraries.yml: yaml_parse(): parsing error encountered during parsing: did not find expected key (line 60, column 4), context while parsing a block mapping (line 47, column 3) in Drupal\Core\Asset\LibraryDiscoveryParser->parseLibraryInfo() (line 322 of core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php).The braintree checkout appears to work OK without the patch installed. Also tried to install #47 against the latest dev and this won't install for me either. Any ideas?
Thanks.
Comment #70
sittard commentedIt would appear that commerce_braintree.libraries.yml file has an extra indentation around line 60 (dependencies) should be:
Comment #71
sittard commentedFixed indentation issue in commerce_braintree.libraries.yml
Comment #72
sittard commentedThe previous patch was failing in Google Chrome due to invalid subsource integrety for external JS files - https://www.drupal.org/project/commerce_braintree/issues/3090170
I've updated the patch with new SRI hashes using https://www.srihash.org/
Comment #73
sittard commentedDuring testing we noticed that the value being sent to 3DS has a rounding error so instead £55.60 the 3DS modal was displaying £5560.00.
The source of the problem seems to be:
Which we changed back to:
I've not attached a patch as I'm not 100% certain this is the best way forward.
But hopefully that bit of testing helps. Apart from that I think this is now production ready.
Comment #74
luksakHm, Braintree is putting some pressure on us:
To help you prepare for upcoming SCA requirements, part of the European Payment Services Directive (PSD2) regulations, Braintree recommends that merchants integrate 3DS 2 into their checkout experience by December 2020 to ensure there is no disruption to you or your customers at checkout.Is there funding from Braintree to fix this?
Comment #75
lisastreeter commented@sittard I was just reading through the documentation for the "amount" passed as one of the verifyCard options. It should be...
So I agree that it makes sense to not use toMinorUnits(). The only issue is that some currency use precision up to the thousandth's place, so I think we need to do something like:
$amount = Calculator::round($order->getBalance()->getNumber(), 2);So I'm going to make that change, re-roll the patch, and see how that works.
It's been a while since I worked on this issue, so I went through all the comments to try to identify all the to-dos.
1. It seems that adding email address and telephone numbers to verifyCard for 3DS2 is still an issue.
2. Comment #33 describes the need to implement "Amex safe key", but I haven't seen any newer reports of Amex issues.
3. Comment #64 describes an issue related to the User payment method add form not working (because there's no order).
So I'll go through and look at these specifically. Anything else that's missing?
Comment #76
sittard commentedThanks for picking this up. We have been using patch #72 on a production server for a while, the only issue we've found is for orders which have a shipping calculation (majority don't). In these case the shipping was not being added to the 3D secure popup, but was being added to the final payment resulting in a payment error message being displayed.
Partly this is because we have the payment and shipping information on the order information pane in our checkout workflow. However, as noted in the post below a workaround would be to have the shipping on the Review Pane.
https://www.drupal.org/project/commerce_shipping/issues/2849756#comment-...
This issue should probably be dealt with in commerce shipping and I guess goes beyond what is required here.
Comment #77
lisastreeter commented@sittard - thanks for the feedback! I'll add that to the list of things to check.
Patch #72 didn't apply with the latest dev version (conflicts in libraries.yml and paypal.js). So I've rerolled. New patch just fixes those conflicts and does not contain anything new.
Comment #78
lisastreeter commentedThis update addresses a couple of the issues outlined in #75 and #76.
First, I'm not having any issues with AmEx transactions. Everything goes through to the sandbox just like other credit cards. If US merchants want Amex Safe Key, I think that can be a follow-up issue.
Second, there are a couple issues related to the "amount" that gets passed to
verifyCardfor the initial verification. We have been usingtoMinorUnits()to calculate the amount, but that's not what Braintree wants. Per Braintree documentation, the value should be the same as the charge amount (order balance), rounded to two decimal digits. If theverifyCardamount is greater than the amount to be charged, that is problematic since the value displays to the customer on the 3DS modal. If the amount is less than the total order amount, the modal will work but then checkout will fail at the final confirmation due to the amount mismatch.So I've replaced the order balance calculation that resulted in incorrect values displaying on the 3DS modal:
$amount = $plugin->toMinorUnits($order->getBalance());Instead, I use the Calculator service to round the units to 2 decimal places (per Braintree documentation).
The second part of the problem related to the amount relates to having Commerce Shipping enabled or any other functionality that allows customers to update the order amount on the same checkout step as the 3D Secure modal launch (i.e., the Payment Information pane). One workaround is modifying checkout flow so that Shipping method selection is on a separate, earlier step. A better solution would be beyond the scope of this issue, since we can't anticipate all the ways checkout could be configured to allow customers to make changes to the order amount prior to the review step.
What I've done in this patch is add a hidden "order balance" form element on the Payment information checkout pane. The 3d secure javascript grabs the balance amount right before launching the modal, so other contrib/custom modules like Shipping could update the value via javascript.
Comment #79
lisastreeter commentedIn this update, I've investigated the data requirements for the
verifyCardcall. For 3DS 2, the only required values are amount, vin, nonce. Email, billingAddress, and additionalInformation should be included if possible.I've added in email, using the order email value when available. (For guest checkout, the email may not be set yet.) We were already passing in the billing address, though without phone number(s), since they aren't a standard part of billing profiles. However, I've determined that the code for billing address data is no longer functional, due to updates in commerce core related to address book. Also, if commerce shipping is installed, getting the correct address data is further complicated by the "billing same as shipping" option. So... what I've done in this patch is completely remove the billing address data from the
verifyCard. Yes, it would be nice to have that in there, but it's just too complicated to tackle for this issue.To summarize, this patch adds in email when available and removes the billing address data from the
verifyCardcall.Still to-do is fixing the user payment method add form for 3D secure.
Comment #80
lisastreeter commentedOops, attached those interdiff files with .patch extensions. Uploading with .txt now.
Comment #81
lisastreeter commentedUpdated patch supports the user payment method add form.
Comment #82
luksakOk, so the deadline on December 31st is coming closer. I'll be testing this the coming days.
Are there specific things I should be testing?
How can I test this in the sandbox?
Comment #83
sittard commentedSandbox - I think you need to contact braintree to get a sandbox account
https://sandbox.braintreegateway.com
Braintree Test Card Details
https://developers.braintreepayments.com/guides/credit-cards/testing-go-...
3D Secure 2.0 Test Card Details
https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...
Comment #84
luksakA first report of my testing:
In sandbox mode 3DS 2.0 works. When testing in production mode I got this error:
InvalidArgumentException: $payment_details must contain the payment_method_nonce key. in Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields->createPaymentMethod() (line 402 of modules/contrib/commerce_braintree/src/Plugin/Commerce/PaymentGateway/HostedFields.php).Comment #85
lisastreeter commented@Lukas, it's possible that your merchant account was not set up for 3d-secure. We had a client that talked to Braintree about activating their account for 3DS. After testing everything thoroughly on the dev site, we activated 3DS on production and started getting that same error message you're seeing. After hours spent trying to diagnose the problem and requesting support from Braintree, we learned that 3DS functionality was never added to their existing merchant account. Instead, an entirely new merchant account had been created for them, for 3DS.
I'm not sure if Braintree still requires merchants to explicitly request 3DS functionality, but it might be worth trying to verify with Braintree that your production account is actually 3DS-enabled.
Comment #86
luksakI realized that there was a incorrect indent in
commerce_braintree.libraries.ymlcausing the url forthree-d-secure.min.jsbeing incorrect. The attached patch fixes that issue.Comment #87
luksakSorry, the patch went missing...
Comment #88
luksak@lisastreeter Sorry, somehow I had this issue open for days without refreshing. Just saw your comment. According to Braintree support, 3DS is always enabled.
The patch in #87 solved the issue for me. I just processed a 3DS 2.0 payment on production.
The only thing which isn't working is PayPal. The popup opens (after clicking the PayPal button, but that is a different issue) and I can add my PayPal account. When proceeding in the checkout, I get the following error:
In the logs it says:
Unsupported credit card type "".Comment #89
lisastreeter commented@lukas-von-blarer Thanks for the bug report! I was able to reproduce when checking out as a Guest. This new patch should fix.
Any additional testing/feedback would be very helpful!
Comment #90
lisastreeter commented(forgot to update status)
Comment #91
luksakThe patch fixes the issue with PayPal. Thank you so much!
The error I described in #88 doesn't occur either.
What i missing to get this committed? Do we need tests?
Comment #92
jsacksick commentedI've been testing this manually today and realized there are several "issues", not necessarily with the patch itself though.
The patch can only work properly if the payment method is collected right before creating the payment transaction (i.e on the review page).
The main reason for that is that the order total might not be "final" when we create the payment method nonce, if the payment information pane is on the order information step for example.
Alas, we're forced to pass an amount to authorize from the 3DS JS (i.e the call to verifyCard()), and if the amount then differs when creating the transaction, it'll fail.
It can work if the amount is slightly higher (I believe there's a 15% tolerance), or lower, but if more items are added to the cart after the payment method nonce is created, or simply if shipping/taxes are inflecting the order total too much, capturing/authorizing the payment will fail.
So unfortunately once again, the only way for this to work properly would be to put the payment information pane on the review page, sad, but true...
I'm wondering if we should commit the patch as it is... And basically add a note to the project page / documentation saying the payment information pane must be on the review page in order for the 3DS2 implementation to work properly.
@ Lukas von Blarer, @lisastreeter: thoughts?
Comment #93
jsacksick commentedhm... Would it actually be possible to just tokenize the card like before? And fire the 3DS2 verification on the review page?
Comment #94
jsacksick commentedI started making changes to the patch, and basically kept using the regular JS that simply tokenizes the card (instead of the 3DS JS).
That actually creates a reusable payment method, which then makes the 3DS review checkout pane to be visible.
The 3DS modal is then triggered, there's a remaining issue when creating the payment, but this probably simply requires more work...
It seems that it's still possible to tokenize the card first and then worry about 3DS on the review page.
Comment #95
jsacksick commentedSetting back to needs work, I'll try to work on a patch.
Comment #96
jsacksick commentedOk, I've worked on this, removed a lot of code that was introduced (removed the hosted-fields-3ds.js and only do the 3dsecure on review while still doing the regular tokenization... when adding the payment method.
I probably killed the user pages integration (was focused on making the "regular" usecase work"), and I probably removed too much of the introduced code (i.e no more
doCreate3dsPayment()method...But surprisingly, this seems to work, and I got rid of the errors I've experienced myself when making changes to the order after tokenizing the card with 3DS in checkout...
@lisastreeter, @ Lukas von Blarer: Curious to see how testing goes for you guys...
We may need to put back some of the code I've cleaned (testing a very specific usecase), but at least I didn't get issues when trying to create a transaction with a higher amount that was was authorized in the 3DS modal.
Comment #97
jsacksick commentedAttaching a patch with minor changes (Removed the button selector setting on the pane). Since we have access to the form, we can pass the form ID directly.
Also made minor cosmetic changes here and there...
Comment #98
jsacksick commentedAttached 2 times the same patch instead of an interdiff.
Comment #99
jsacksick commentedComment #100
sumi commentedTested the latest patch and it is working as expected.
Comment #102
jsacksick commentedCommitted!!! Thanks everyone! This was long overdue :).
Comment #103
luksakThank you!
I already released the patch in #89 and I cant test the committed patch right now.
We still have this issue on 7.x: #2496627: Support 3D Secure In case you could have a look at the patch, that'd be great!
Comment #104
jsacksick commentedHm, it doesn't really make sense to update this issue "needs review", the patch got committed and a new release was tagged (so there's nothing to review anymore).
From https://www.drupal.org/docs/develop/issues/fields-and-other-parts-of-an-...
Feel free to open a new issue if you need to report a bug, but this is now in, and had to be committed prior to the January 1st deadline.
Comment #106
rob230 commentedCan anyone explain how this is supposed to work? It doesn't seem to do anything. On the payment step three-d-secure.min.js is not added, and it just does a normal payment and processes it. The three-d-secure.min.js script is added to the review step after the payment has been taken and the order is complete. At no point does it ever ask for any additional authentication from the bank.
I've tried with the fail cards from the documentation and it still succeeds. I don't really understand how it's supposed to work.
Comment #107
skitten commentedI'm also having issues with this. Live transactions failing (authentication required 2099), but I can't figure out how to test against the Braintree sandbox.
Comment #108
martijn de wit@Rob230 and Skitten, Best way to get support is to open a new ticket with the category "support".
A closed ticket doesn't pop-up in all dashboard views.
Comment #109
ahir commentedHi
Not working for logged in user witg D9
Error:
Error: Call to a member function getParameter() on null in Drupal\commerce_braintree\PluginForm\HostedFields\PaymentMethodAddForm->buildCreditCardForm() (line 81 of /httpdocs/web/modules/contrib/commerce_braintree/src/PluginForm/HostedFields/PaymentMethodAddForm.php)
here is the code:
if (!empty($configuration['3d_secure'])) {
if ($order = $this->routeMatch->getParameter('commerce_order')) {
$amount = $order->getBalance()->getNumber();
}