The Payment Provider Gateway documentation uses the Magento 2.3 (now Adobe Commerce and Magento Open Source) of the Braintree module as a reference application. The Braintree module was removed in version 2.4.0. The concepts described in this guide are still applicable to version 2.4.x, but the code samples are not supported.
Get payment information from frontend to backend
To implement transaction authorization our payment should receive some payment details from the payment form, like credit card details, and send received details to payment processor.
Depending on your payment integration, payment details might include credit card details, tokenized cards, payment nonce, and similar information.
However, in any case you should write some code to retrieve payment details from payment form.
Example: Braintree request builder for the payment
part of the request
We have specified BraintreeAuthorizeRequest
builder composite to process authorization and it includes the Magento\Braintree\Gateway\Request\PaymentDataBuilder
builder. This is builder responsible for the payment information part of the request, in other words, the credit card information. Let's look closer at it's implementation.
The Braintree payment provider requires the payment method nonce to process transactions, and our builder should send it for each authorization transaction.
Here is how the Braintree payment builder looks:
Copied to your clipboardclass PaymentDataBuilder implements BuilderInterface{/*** @inheritdoc*/public function build(array $buildSubject){$paymentDO = $this->subjectReader->readPayment($buildSubject);$payment = $paymentDO->getPayment();$order = $paymentDO->getOrder();$result = [self::AMOUNT => $this->formatPrice($this->subjectReader->readAmount($buildSubject)),self::PAYMENT_METHOD_NONCE => $payment->getAdditionalInformation(DataAssignObserver::PAYMENT_METHOD_NONCE),self::ORDER_ID => $order->getOrderIncrementId()];...return $result;}}
As you can see, we get the payment nonce from payment additional information. And so any specific data (like credit card information) can be retrieved.
You should remove any sensitive data (like credit card details) from payment additional information when you do not use it in your code. You can remove it in request builder, after reading, or in response handler, after processing response. In other case it will be stored in database.
Getting payment information from frontend to backend
In most cases, customers fill all required information (credit card, expiration date, billing address, etc) on checkout payment form. So our payment method implementation should provide the ability to display and process payment form on checkout step.
We can send to backend any specific data, just need to override getData()
method in
payment UI component:
Copied to your clipboarddefine([..., 'Magento_Payment/js/view/payment/cc-form', ...],function (..., Component, ...) {'use strict';return Component.extend({defaults: {...paymentMethodNonce: null,},...getData: function () {var data = {'method': this.getCode(),'additional_data': {'payment_method_nonce': this.paymentMethodNonce}};return data;},setPaymentMethodNonce: function (paymentMethodNonce) {this.paymentMethodNonce = paymentMethodNonce;},beforePlaceOrder: function (data) {this.setPaymentMethodNonce(data.nonce);this.placeOrder();},...});});
The getData()
method returns data what we need and depending on payment integration the returned data can be more
complicated. we need last step to retrieve data from storefront in the backend. Adobe Commerce provides some
mechanisms called Observers.
Read additional data
You need to add an observer to retrieve additional data from payment form and store it in the payment additional information. In most cases it will be enough to extend AbstractDataAssignObserver and add custom behavior.
That's how observer might looks:
Copied to your clipboardclass DataAssignObserver extends AbstractDataAssignObserver{const PAYMENT_METHOD_NONCE = 'payment_method_nonce';/*** @var array*/protected $additionalInformationList = [self::PAYMENT_METHOD_NONCE,];/*** @param Observer $observer* @return void*/public function execute(Observer $observer){$data = $this->readDataArgument($observer);$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);if (!is_array($additionalData)) {return;}$paymentInfo = $this->readPaymentModelArgument($observer);foreach ($this->additionalInformationList as $additionalInformationKey) {if (isset($additionalData[$additionalInformationKey])) {$paymentInfo->setAdditionalInformation($additionalInformationKey,$additionalData[$additionalInformationKey]);}}}}
And this observer should be added to list of events (Module_Name/etc/events.xml
):
Copied to your clipboard<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"><event name="payment_method_assign_data_braintree"><observer name="braintree_gateway_data_assign" instance="Magento\Braintree\Observer\DataAssignObserver" /></event></config>
This event will be triggered in Adapter::assignData() method call:
Copied to your clipboardpublic function assignData(\Magento\Framework\DataObject $data){$this->eventManager->dispatch('payment_method_assign_data_' . $this->getCode(),[AbstractDataAssignObserver::METHOD_CODE => $this,AbstractDataAssignObserver::MODEL_CODE => $this->getInfoInstance(),AbstractDataAssignObserver::DATA_CODE => $data]);$this->eventManager->dispatch('payment_method_assign_data',[AbstractDataAssignObserver::METHOD_CODE => $this,AbstractDataAssignObserver::MODEL_CODE => $this->getInfoInstance(),AbstractDataAssignObserver::DATA_CODE => $data]);return $this;}
There are two events:
payment_method_assign_data_payment_code
: specific for current method (placing order using this payment method)payment_method_assign_data
: global for all payments (place order)
What type of event to use depends on your implementation, but in most cases it will be enough to use the event for current payment method.