Magento 2.3: How to Create Order Using Braintree Vaulted Card
-
23-02-2021 - |
Question
I'm trying to create an order programmatically using braintree payment method and the customer's saved credit card.
// prepare adresses, products in quote, shipping method - skipped
$quote->setPaymentMethod('braintree');
$quote->setInventoryProcessed(false);
// Set Sales Order Payment
$quote->getPayment()->importData(array('method' => 'braintree, 'cc_type' => 'AE', 'cc_exp_month' => '05', 'cc_exp_year' => '2022', 'public_hash' => $public_hash));
$customer = $this->customerRepository->get($contact->email);
// prepare customer
$quote->setCustomer($customer);
// Collect Totals & Save Quote
$quote->collectTotals()->save();
$order = $this->quoteManagement->submit($quote);
I have access to all of the saved CC information from the customer, I'm just not sure what info needs to be passed in $quote->getPayment(importData(array(....));
In my payment.log file I see the following error when attempting to create orders using the saved CC:
Cannot determine payment method.
Any ideas how to process payments using Braintree vaulted cards?
Solution
I was able to figure this out, you just need to pass the payment_method_nonce
and public_hash
along with the payment method braintree_cc_vault
:
...
$quote->getPayment()->importData(array('method' => 'braintree_cc_vault', 'public_hash' => $public_hash, 'payment_method_nonce' => $paymentMethodNonce));
...
EDIT, added more info:
To get the public_hash
and payment_method_nonce
for each saved credit card for a given customer, I am doing the following:
...
protected $paymentTokenManagement;
protected $command;
protected $session;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Vault\Api\PaymentTokenManagementInterface $paymentTokenManagement,
\Magento\Braintree\Gateway\Command\GetPaymentNonceCommand $command,
\Magento\Framework\Session\SessionManagerInterface $session,
...
array $data = []
) {
...
$this->paymentTokenManagement = $paymentTokenManagement;
$this->command = $command;
$this->session = $session;
parent::__construct($context);
}
public function execute()
{
$customerId = 1;
// Get Saved CC
$cardList = $this->paymentTokenManagement->getListByCustomerId($customerId);
foreach($cardList as $card) {
if ($card->getIsActive()) {
// Get Card Public Hash for each active card
$public_hash = $card->getData('public_hash');
// Need to pass Customer ID and Store ID below
$paymentMethodNonce = $this->command->execute(['public_hash' => $public_hash, 'customer_id' => $customerId, 'store_id' => $this->session->getStoreId()])->get();
$paymentMethodNonce = $paymentMethodNonce['paymentMethodNonce'];
}
}
}
You can then pass $public_hash
and $paymentMethodNonce
to:
$quote->getPayment()->importData(array('method' => 'braintree_cc_vault', 'public_hash' => $public_hash, 'payment_method_nonce' => $paymentMethodNonce));
Please note, this is just a snippet of my full code -- you may need to alter it to fit into your project.