We have a client keen on replacing their current payment methods including Payflow Link and PayPal WPS with Braintree in order to be PCI DSS 3.0 SAQ A compliant.

As the current Drop-in UI product does not allow to customise UI, so we are heading to provide Hosted Fields integration. We have created a sandbox project by forking the current commerce_braintree module here:

https://www.drupal.org/sandbox/cityreader/2534858

After implementing both Hosted Fields and PayPal integration, we have found all three implementation including Drop-in UI, PayPal and Hosted Fields could be just included in one module with different settings.

As our client has a small budget to allow us maintain code of this new project, we think if possible we can create a version 3 branch and develop new features in it.

If we can develop in this version 3 branch, we plans to :

  • move Transparent Direct from main module to a separate sub module, as it is not SAQ A compliant anymore.
  • make Braintree.js integration more generic to include existing Drop-in UI in dev, and new Hosted Fields and PayPal in one module
  • add some API function to main module to allow add-on features supplied by other contributed modules as we have plan to add account management and subscription management based on Braintree

Any advices are welcome. Thanks:D

Comments

luksak’s picture

Title: Development Interest to provide Hosted Fields integration as version 3 » Provide Hosted Fields integration

I am sorry for replying late...

There is a discussion at #2483675: [meta] 7.x-2.0 stable release about a stable release, which has some ideas.

How is your development progressing? I see there is some development going on...

In my opinion we should provide the three different integrations as submodules, fix all critical issues and get to a 2.x stable release.

A 3.x release needs a discussion of all maintainers. Most importantly we need to discuss a D8 port, which could involve integrating with https://www.drupal.org/project/payment since the first D8 ports of payment providers happen there. It could also involve integrating through Omnipay according to https://drupalcommerce.org/blog/14871/launching-commerce-drupal-8 What do the others think?

Renaming the issue accordingly.

eric.chenchao’s picture

Hi @Lukas,

Thanks you for the reply. We also had some discussion inside our project about how we want to structure and separate functions by module in the last week.

The current work we have done in the sandbox is adding integration with Hosted fields and PayPal by borrowing some code from commerce_braintree_dropin module as we do not want to make dropin as dependency. Also we have found the integration of both Hosted fields and PayPal share majority of logic except settings and some js code. So we add both integrations to one module commerce_braintree_web. Also, Drop-in UI is a capsulation of both credit card and PayPal payment methods. When users use Drop-in UI, they are most likely not to use Hosted Field and PayPal as separate payment methods any more.

Due to the restriction of no destroy function of braintree function during the time of development, we cannot create more than one braintree instance when change payment method via Ajax. That's why we have to do the monkey patching and reload page when user change from Hosted Fields to PayPal and etc. It is probably they will launch newer version with destroy method next week so we hope get rid of monkey patching at that time. Read more here.

Byond payment method in commerce, in our project we also need to implement subscription and payment method management in Drupal. So we decide to create a braintree module as core dependency and move basic functions including credit card form by Hosted Fields, global settings page and etc into it. Then adding submodules to include other features. We want to make that module for general use although we reckon not too many sites need that function.

Regarding the stable release of branch version 2, we will keep an eye on it and see we can help to fix bugs.

luksak’s picture

So let's keep the scope of this issue to create a patch for 2.x providing a separate module providing Hosted Fields integration. We don't need to fix having both payments enabled since this is not really a use case. Or is it? Could you create a patch?

eric.chenchao’s picture

Hi @Lukas, yes in our project, we use both Hosted Fields and PayPal integration. It works quite like Drop in UI with credit card and PayPal payment methods. And it allows us to custom style of the credit card form.

Also most of functions used in hosted fields module would be very close or even same as those used in dropin module, do you reckon just create clone copy of different function names or move some utility functions from dropin module to commerce_braintree for sharing?

aaronbauman’s picture

Any updates here?
commerce_stripe has managed to figure it out, but I would rather use Braintree. Does the 3.x API solve the javascript issue?

luksak’s picture

commerce_braintree integrates with Braintree's Drop-in payment solution which is more prowerful than Stripe's Checkout.

aaronbauman’s picture

Oh, I see commerce_braintree_dropin in the dev release.
I was looking at 2.0-beta1 -- derp.

Also: I suppose one could use a hook_js_alter to replace commerce_braintree_dropin.js and implement their own Hosted Fields API, yeah?

eric.chenchao’s picture

@aaronbauman I have written a module braintree integration to support this hosted fields. We use this in our client websites. You may be interested to check https://github.com/cityreader/braintree/blob/7.x-1.x/modules/braintree_p...

luksak’s picture

Status: Active » Needs work

Unexpectedly i am going to build one more D7 commerce site. I will test this when developing it next year.

@eric.chenchao could you please post a patch? Otherwise I won't be able to test this. Looking at your repository you made lots of changes to the module providing functionality not related to the Hosted fields integration.

iampuma’s picture

StatusFileSize
new3.78 KB

For a project we also needed the Hosted Fields integration to settle/void/refund transactions.

We have updated sandbox module mentioned above to support that (https://www.drupal.org/node/2852166)
and patched the commerce_braintree module to support the sandbox modules new payment (diff attached)

mglaman’s picture

Assigned: Unassigned » mglaman
Category: Plan » Feature request

The 8.x version of this module is the HPF approach. I'll be working to backport this into the 7.x branch.

It looks like we have three efforts which were never formalized into a single patch

Also, I'm not sure how any of the patches provided here can truly implement HPF since it involves embedded individual <div> elements for the JS to render as iframes.

mglaman’s picture

Title: Provide Hosted Fields integration » Add Hosted Fields integration
mglaman’s picture

Status: Needs work » Needs review
StatusFileSize
new20.42 KB

Here is the gateway! Just missing backoffice settlement (capture) and refunds.

mglaman’s picture

StatusFileSize
new2.46 KB
new22.88 KB

Update for access callbacks

mglaman’s picture

StatusFileSize
new26.05 KB

New patch which adds integration with Kount for the Advanced Fraud Detection.

aaronbauman’s picture

Status: Needs review » Needs work

This is getting close, and perfect timing for the project I'm working on - thank you all for your work here!

I'm getting a WSOD on checkout due to an exception when calling ::sale in commerce_braintree_hostedfields_submit_form_submit():

+  catch (Exception $e) {
+    throw new Exception($e->getMessage());
+  }

1. why bother catching, just to throw again?
2. why not log the exception, and show a user-friendly error message?

There's at least one call to debugger left over in commerce_braintree_hostedfields.js

Lastly, why do we need to require Merchant Account ID per currency?
I've implemented Hosted Fields previously with only the API Merchant ID, Pub key, and Private key.
Seems like we should allow it fall back on default if not provided.

I'll submit a new patch when I've got it working.

mglaman’s picture

1. why bother catching, just to throw again?
2. why not log the exception, and show a user-friendly error message?

:( whoops, 2.x-ism; Commerce catches those in new API on D8.

Lastly, why do we need to require Merchant Account ID per currency?
I've implemented Hosted Fields previously with only the API Merchant ID, Pub key, and Private key.
Seems like we should allow it fall back on default if not provided.

That's what the module does in others, just followed suit

aaronbauman’s picture

Status: Needs work » Needs review
StatusFileSize
new26.19 KB
new1.36 KB

That's what the module does in others, just followed suit

Hmm, ok.
Out of scope for this issue then.

Once I entered the correct Merchant ID, this patch is working.

Update for the 2 minor issues discussed above - thanks again!

andyg5000’s picture

Assigned: mglaman » andyg5000
andyg5000’s picture

Assigned: andyg5000 » Unassigned
Status: Needs review » Needs work
StatusFileSize
new50.75 KB

Don't kill me, but here's an update that includes a ton of refactoring so we can recycle methods for dropin and hosted fields. This is 95%, but needs the card on file update for hosted fields fixed or removed. I'll pick back up on this Monday!

andyg5000’s picture

StatusFileSize
new43.55 KB

Forgot to include interdiff and comment that this adds terminal and card on file support for hosted fields.

aaronbauman’s picture

thank you for hook_commerce_braintree_hostedfields_fieldstyles_alter - i was just about to need that.
A few points:
- should probably be named like hook_commerce_braintree_hostedfields_js_alter(), since we're altering (potentially) the entire hostedFields specification.
- do we really want to allow contrib to alter the *entire* specification? Do we really want to provide so much rope for people to shoot themselves in the foot?
- the api.php alter hook needs to take its first arg by reference, like this:

function commerce_braintree_commerce_braintree_hostedfields_fieldstyles_alter(&$js_settings, $payment_method) {
mglaman’s picture

do we really want to allow contrib to alter the *entire* specification? Do we really want to provide so much rope for people to shoot themselves in the foot?

Well nothing's really stopping them from altering the entire JS. But that is a valid point to just scope it to hook_commerce_braintree_hostedfields_js_alter name change and only allow returning / altering the field styles.

andyg5000’s picture

Assigned: Unassigned » andyg5000

Yup. I agree with #23. I was working on this yesterday, but had some issues with Card on File integration. I think I got over the hump and should be able to wrap this up today. We'll need to get a commit for COF to fix one issue, but Glaman can do that.

andyg5000’s picture

Status: Needs work » Needs review
StatusFileSize
new55.24 KB
new62.2 KB

Adds card on file support and fixes issues with transparent redirect. Interdiff is between #18 and this.

andyg5000’s picture

mglaman’s picture

EDIT

+++ b/commerce_braintree.module
@@ -186,6 +185,11 @@ function commerce_braintree_commerce_payment_method_info() {
+    'callbacks' => array(
+      'settings_form' => 'commerce_braintree_settings_form',
+      'redirect_form' => 'commerce_braintree_tr_redirect_form',
+      'redirect_form_validate' => 'commerce_braintree_tr_redirect_form_validate',
+    ),

I'm an idiot and can't read diffs.

andyg5000’s picture

StatusFileSize
new61.95 KB
new2.67 KB

Updates to fix undefined index issues and replace the module_implements_alter implementation with a requirement of #2865117: Add drupal_alter to allow other modules to update payment terminal UI

mglaman’s picture

+++ b/modules/commerce_braintree_hostedfields/commerce_braintree_hostedfields.module
@@ -0,0 +1,284 @@
+  // Remove the Braintree form elements and JavaScript if an existing
+  // card on file was selected.
+  if (($form_state['triggering_element']['#name'] == 'commerce_payment[payment_method]' && $pane['cardonfile']['#default_value'] != 'new' )
+   || (empty($form_state['values']['commerce_payment']['payment_details']['cardonfile']) || $form_state['values']['commerce_payment']['payment_details']['cardonfile'] !== 'new')) {
+    commerce_braintree_hosted_fields_remove_hosted_fields_form($pane, $form_state);
+  }

Locally I got a notice from this. Had to add a check for triggering element first.


  // Remove the Braintree form elements and JavaScript if an existing
  // card on file was selected.
  if (empty($form_state['triggering_element'])
      || ($form_state['triggering_element']['#name'] == 'commerce_payment[payment_method]' && $pane['cardonfile']['#default_value'] != 'new')
      || (empty($form_state['values']['commerce_payment']['payment_details']['cardonfile']) || $form_state['values']['commerce_payment']['payment_details']['cardonfile'] !== 'new')) {
    commerce_braintree_hosted_fields_remove_hosted_fields_form($pane, $form_state);
  }

Fixed locally for pending commit.

  • mglaman committed 34a3d80 on 7.x-2.x authored by andyg5000
    Issue #2540268 by andyg5000, mglaman, aaronbauman, iampuma: Add Hosted...
mglaman’s picture

Status: Needs review » Fixed

Woo! Thanks everyone. I'll wait a few days before tagging a beta (maybe just RC) to release hosted fields.

You'll need https://www.drupal.org/project/commerce_cardonfile/releases/7.x-2.0-beta6 for proper integration with CoF + terminal

dpalmer’s picture

Hi, I have tested the latest release and it working well for me. I have also added a patch to add support for the "descriptor name" field in the sale data. This is needed for anyone running multiple stores with the same braintree account to provide an attribute to filter transactions by store. See https://developers.braintreepayments.com/reference/request/transaction/s...

dpalmer’s picture

"Descriptor name" patch.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

EddyFK’s picture

I have a strange problem using hosted fields:

Payment and shipping services are on the same pane: shipping. When an anonymous user inputs the credit card credentials and selects a payment method and continues to review the order backend shows the correct amount that should be charged.

If i return to the payment and shipping step the whole form is shown again and i need to re-enter my credentials and select maybe a different shipping service. When i continue now again to review braintree throws and error, that the amount shouldn't be negative. In my order backend i see that the first payment is still there and a second with a negative amount. I guess what happened is, that there was a difference between the total amount before and the total amount after the shipping service change (because it costs less) and braintree subtracts that amount to get the correct total.

Is that a hosted fields problem because drupal payment works that way? When is the actual amount charged: After the user completes the last step or as soon as he approves the credit card credentials? Would it be possible to disable re-entering the complete credit card form, as the user maybe just wants to change the shipping service? I think it would make sense to show instead of the form a info showing the message from braintree here and a button that would maybe delete this payment and adds another braintree form...

Can somebody help?