Allow specifying merchant id when generating client token.

Created on 3 March 2023, over 1 year ago
Updated 11 July 2023, 12 months ago

Problem/Motivation

When you have at least two merchant IDs on Braintree with different currencies, and only one of them has 3DS enabled, the community Braintree implementation then depends on what is marked as the default merchant id in Braintree. That can cause issues with 3DS implementation.

Steps to reproduce

Create two merchant account id in Braintree
test_usd - set the currency to USD, mark as default merchant account id, do not enroll in 3DS
test_eur - set currency to EUR, enroll in 3DS

When loading an order in EUR currency in the checkout and trying to pay with a credit card through Braintree, you will get an error message: 3D secure version 2 is not enabled for this merchant.

Because we don't specify the merchant account id option inside \Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields::generateClientToken, it's used default specified on Braintree. Which, in this case, is not enrolled in 3DS. Thus blocking any progress on the order.

Proposed resolution

Check if we are on the order route, pull order currency, map by merchant account id, and push during token creation.

Add an optional parameter on \Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields::generateClientToken to accept an array of values.

Braintree docs - https://developer.paypal.com/braintree/docs/reference/request/client-tok...

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Fixed

Version

1.0

Component

Code

Created by

🇭🇷Croatia valic Osijek

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Issue created by @valic
  • @valic opened merge request.
  • 🇭🇷Croatia valic Osijek

    We should have an agnostic determination of which merchant id needs to be used outside of payment forms or 3DS pane review and not make BC if not required.

    The current state of the change is as follows:
    - no breaking changes - no new methods or alteration of existing ones
    - no changes for any of the payment method forms
    - inside method generateClientToken resolve merchantAccountId by current store currency by default, and if we are on order route (aka checkout) resolve per order currency route than)

    We need to resolve this per current store currency for offsite card authorization when no order is attached to the payment.

  • Status changed to Needs review about 1 year ago
  • 🇭🇷Croatia valic Osijek

    Per internal discussion, we are now passing currency to map it on the corresponding merchant id.

    There is one method to fallback to store if the currency is not passed as on the user payment methods tab where there is no order

    
      protected function getMerchantId($currency_code = NULL) {
        // Fallback to current store.
        if (empty($currency_code)) {
          $currency_code = $this->currentStore->getStore()->getDefaultCurrencyCode();
        }
    
        if (empty($this->configuration['merchant_account_id'][$currency_code])) {
          throw new InvalidRequestException(sprintf('No merchant account ID configured for currency %s', $currency_code));
        }
    
        return $this->configuration['merchant_account_id'][$currency_code];
      }
    

    We are missing that ability only during payment method creation in "doCreatePaymentMethod" when we have an active order but no ability to fetch currency. So we fallback to store by logic from getMerchantId

  • Status changed to Needs work about 1 year ago
  • 🇮🇱Israel jsacksick

    Left several comments in the MR, some changes are required before merging this.

  • Status changed to Needs review 12 months ago
  • 🇭🇷Croatia valic Osijek
  • 🇭🇷Croatia valic Osijek

    @jsacksick we show same error message for outside of checkout scenario

  • 🇭🇷Croatia valic Osijek

    To sum up the changes.

    The token is generated based on order currency or fallback to the current store default currency (in cases when the customer is not on the order route)
    During checkout, the currency is pulled from the current order.

    We have a change in method \Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFieldsInterface::generateClientToken
    which not sure we treat as BC, but we probably should. Even payments would work without passing $currency_code for most; custom code should be reviewed.

    If for currency payment gateway is missing merchant_id during checkout on the user payment page, we return this error gracefully.

  • Status changed to Fixed 12 months ago
  • 🇮🇱Israel jsacksick

    Committed, thanks!

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

Production build 0.69.0 2024