Skip to content
This repository has been archived by the owner on Dec 19, 2019. It is now read-only.

Commit

Permalink
Generate nonce from public hash server-side
Browse files Browse the repository at this point in the history
This simplifies the implementation requirements when setting the payment
method to Braintree Vault.

In the current frontend implementation the nonce is created server-side, but
using an ajax request when the place order button is activated. The current
storefront flow executes:
1. User selects vault method and places order
2. Ajax request with public hash is made to server returning the nonce
3. Nonce is submitted with order placement request in payment details

The second step is uncessecary and is removed from the graphql flow with this
commit.
  • Loading branch information
pmclain committed Jul 10, 2019
1 parent a6e32e8 commit c4609cc
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 23 deletions.
76 changes: 76 additions & 0 deletions app/code/Magento/BraintreeGraphQl/Plugin/SetVaultPaymentNonce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\BraintreeGraphQl\Plugin;

use Magento\Braintree\Gateway\Command\GetPaymentNonceCommand;
use Magento\Braintree\Model\Ui\ConfigProvider;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Psr\Log\LoggerInterface;

/**
* Plugin creating nonce from Magento Vault Braintree public hash
*/
class SetVaultPaymentNonce
{
/**
* @var GetPaymentNonceCommand
*/
private $command;

/**
* @var LoggerInterface
*/
private $logger;

/**
* @param GetPaymentNonceCommand $command
* @param LoggerInterface $logger
*/
public function __construct(
GetPaymentNonceCommand $command,
LoggerInterface $logger
) {
$this->command = $command;
$this->logger = $logger;
}

/**
* Set Braintree nonce from public hash
*
* @param \Magento\QuoteGraphQl\Model\Cart\SetPaymentMethodOnCart $subject
* @param \Magento\Quote\Model\Quote $quote
* @param array $paymentData
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function beforeExecute(
\Magento\QuoteGraphQl\Model\Cart\SetPaymentMethodOnCart $subject,
\Magento\Quote\Model\Quote $quote,
array $paymentData
): array {
if ($paymentData['code'] !== ConfigProvider::CC_VAULT_CODE) {
return [$quote, $paymentData];
}

$subject = [
'public_hash' => $paymentData[ConfigProvider::CC_VAULT_CODE]['public_hash'],
'customer_id' => $quote->getCustomerId(),
'store_id' => $quote->getStoreId(),
];

try {
$result = $this->command->execute($subject)->get();
$paymentData[ConfigProvider::CC_VAULT_CODE]['payment_method_nonce'] = $result['paymentMethodNonce'];
} catch (\Exception $e) {
$this->logger->critical($e);
throw new GraphQlInputException(__('Sorry, but something went wrong'));
}

return [$quote, $paymentData];
}
}
3 changes: 3 additions & 0 deletions app/code/Magento/BraintreeGraphQl/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"require": {
"php": "~7.1.3||~7.2.0",
"magento/framework": "*",
"magento/module-braintree": "*",
"magento/module-store": "*",
"magento/module-quote": "*",
"magento/module-quote-graph-ql": "*"
},
"suggest": {
Expand Down
3 changes: 3 additions & 0 deletions app/code/Magento/BraintreeGraphQl/etc/graphql/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
</argument>
</arguments>
</type>
<type name="Magento\QuoteGraphQl\Model\Cart\SetPaymentMethodOnCart">
<plugin name="braintree_generate_vault_nonce" type="Magento\BraintreeGraphQl\Plugin\SetVaultPaymentNonce" />
</type>
</config>
2 changes: 0 additions & 2 deletions app/code/Magento/BraintreeGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ input BraintreeInput {
}

input BraintreeCcVaultInput {
payment_method_nonce: String!
public_hash: String!
is_active_payment_token_enabler: Boolean!
device_data: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public function sale(array $attributes)
/**
* @param array $params
* @return string|\Braintree\Result\Error
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function generate(array $params = [])
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,26 @@ public function __construct(
* Create mock sale response for testing
*
* @param array $attributes
* @return \Braintree\Instance
* @return \Braintree\Result\Error|\Braintree\Result\Successful
*/
public function generateMockSaleResponse(array $attributes): \Braintree\Instance
public function generateMockSaleResponse(array $attributes)
{
if (empty($attributes['paymentMethodNonce'])) {
return new \Braintree\Result\Error(
[
'errors' => [
[
'errorData' => [
'code' => 2019,
'message' => 'Your transaction has been declined.'
]
]
],
'transaction' => $this->createTransaction($attributes)->jsonSerialize(),
]
);
}

$transaction = $this->createTransaction($attributes);

return new \Braintree\Result\Successful([$transaction]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,19 +169,9 @@ public function testPlaceOrderWithVault()
$reservedOrderId = 'test_quote';
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);

$nonceResult = $this->getNonceCommand->execute(
[
'customer_id' => 1,
'public_hash' => 'braintree_public_hash',
]
);
$nonce = $nonceResult->get()['paymentMethodNonce'];

$setPaymentQuery = $this->getSetPaymentBraintreeVaultQuery(
$maskedQuoteId,
'braintree_public_hash',
$nonce,
true
'braintree_public_hash'
);
$setPaymentResponse = $this->graphQlMutation($setPaymentQuery, [], '', $this->getHeaderMap());

Expand Down Expand Up @@ -243,26 +233,19 @@ private function getSetPaymentBraintreeQuery(string $maskedQuoteId, bool $saveIn
/**
* @param string $maskedQuoteId
* @param string $publicHash
* @param string $nonce
* @param bool $saveInVault
* @return string
*/
private function getSetPaymentBraintreeVaultQuery(
string $maskedQuoteId,
string $publicHash,
string $nonce,
bool $saveInVault = false
string $publicHash
): string {
$saveInVault = json_encode($saveInVault);
return <<<QUERY
mutation {
setPaymentMethodOnCart(input:{
cart_id:"{$maskedQuoteId}"
payment_method:{
code:"braintree_cc_vault"
braintree_cc_vault:{
is_active_payment_token_enabler:{$saveInVault}
payment_method_nonce:"{$nonce}"
public_hash:"{$publicHash}"
}
}
Expand Down

0 comments on commit c4609cc

Please sign in to comment.