Magento team constantly addresses security issues when it comes to payment integrations. One of the improvements were changes into the Magento\Payment
module. The Magento\Payment
module is no longer responsible for setting Payment data for the Magento\Sales\Model\Order\Payment
object. Starting from the Magento 2.0.6 release and further Magento 2.1 release custom payment module should be responsible for adding all necessary Payment information into the Payment
object.
In this article, I am going to explain these changes and share advice on how to properly set Additional Payment Data as part of custom integration with a Payment Service Provider.
Overview
Up to Magento 2.0.6 release, the Payment module was responsible for setting Additional Payment Data. Usually, these data come from a payment form which is located on the checkout billing page. Payment form can be found in the vendor/magento/module-payment/view/frontend/web/template/payment/cc-form.html
template file.
JavaScript Component prepares Payment data and puts it inside the array with additional_data
key together with other quote related data once customer submits the payment form.
The vendor/magento/module-payment/view/frontend/web/js/view/payment/cc-form.js
JavaScript Component’s getData
method listed below.
[javascript]
getData: function() {
return {
‘method’: this.item.method,
‘additional_data’: {
‘cc_cid’: this.creditCardVerificationNumber(),
‘cc_ss_start_month’: this.creditCardSsStartMonth(),
‘cc_ss_start_year’: this.creditCardSsStartYear(),
‘cc_type’: this.creditCardType(),
‘cc_exp_year’: this.creditCardExpYear(),
‘cc_exp_month’: this.creditCardExpMonth(),
‘cc_number’: this.creditCardNumber()
}
};
}
[/javascript]
Once prepared, payment data is sent via HTTP POST using vendor/magento/module-checkout/view/frontend/web/js/action/place-order.js
JavaScript Component.
The Magento\Payment\Model\Method\Adapter::assignData()
method used to add all data from the $data
argument (payment form) directly to the Magento\Sales\Model\Order\Payment
object.
[php]
public function assignData(\Magento\Framework\DataObject $data)
{
$this->eventManager->dispatch(
‘payment_method_assign_data_’ . $this->getCode(),
[
‘method’ => $this,
‘data’ => $data
]
);
$this->getInfoInstance()->addData($data->getData());
return $this;
}
[/php]
By using $this->getInfoInstance()->addData($data->getData());
call payment modules (e.g. Magento\Authorize.net, Magento\Braintree, Magento\Paypal and custom ones) were using data assigned by the Adapter::assignData()
method to set it as part of the Payment Gateway request calls.
Magento 2.0.6 and later versions has no $this->getInfoInstance()->addData($data->getData());
call in the Adapter::assignData()
method. Now, Payment module which integrates Magento 2 with Payment Service Provider is responsible for assigning Additional Payment Data.
The following is a Adapter::assignData()
method from the Magento 2.0.6 release.
[php]
public function assignData(\Magento\Framework\DataObject $data)
{
$this->eventManager->dispatch(
‘payment_method_assign_data_’ . $this->getCode(),
[
‘method’ => $this,
‘data’ => $data
]
);
return $this;
}
[/php]
Assigning Additional Payment Data
In order to assign Additional Payment Data to the Magento\Sales\Model\Order\Payment
object we have to create an observer in our payment module and listen to the payment_method_assign_data_<payment_code>
event from the Adapter
class.
The app/code/Pronko/Payment/etc/events.xml
configuration file should look like the following:
[xml]
<config>
<event name="payment_method_assign_data_pronko_custom">
<observer name="pronko_custom_gateway_data_assign" instance="Pronko\Payment\Observer\DataAssignObserver" />
</event>
</config>
[/xml]
The pronko_custom
is a code of your payment method.
The AbstractDataAssignObserver class
The Magento\Payment\Observer\AbstractDataAssignObserver
class provides useful methods for reading variables from the Event object. The class also responsible for verification of the argument provided as part of dispatching payment_method_assign_data_<payment>
event.
Method | Description | Magento Version |
---|---|---|
readMethodArgument | Returns current Magento\Payment\Model\Method\Adater instance | 2.0.x and 2.1 |
readPaymentModelArgument | Returns Magento\Sales\Model\Order\Payment instance | 2.1 |
readDataArgument | Returns Magento\Framework\DataObject instance with all Additional Payment Data | 2.0.x and 2.1 |
The DataAssignObserver class
The DataAssignObserver
observer class extends the AbstractDataAssignObserver
class and listens for the payment_method_assign_data_pronko_custom
event. The following example shows one of ways setting payment data into the Magento\Sales\Model\Order\Payment
object.
[php]
namespace Pronko\Payment\Observer;
use Magento\Framework\DataObject;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
use Magento\Payment\Model\InfoInterface;
class DataAssignObserver extends AbstractDataAssignObserver
{
/**
* @param Observer $observer
* @throws LocalizedException
*/
public function execute(Observer $observer)
{
$data = $this->readDataArgument($observer);
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) {
return;
}
$additionalData = new DataObject($additionalData);
$paymentMethod = $this->readMethodArgument($observer);
$payment = $observer->getPaymentModel();
if (!$payment instanceof InfoInterface) {
$payment = $paymentMethod->getInfoInstance();
}
if (!$payment instanceof InfoInterface) {
throw new LocalizedException(__(‘Payment model does not provided.’));
}
$payment->setCcLast4(substr($additionalData->getData(‘cc_number’), -4));
$payment->setCcType($additionalData->getData(‘cc_type’));
$payment->setCcExpMonth($additionalData->getData(‘cc_exp_month’));
$payment->setCcExpYear($additionalData->getData(‘cc_exp_year’));
}
}
[/php]
You may notice the usage of the getPaymentModel()
method. This is the main difference between Magento 2.0.6 and Magento 2.1 versions. Starting with Magento 2.1 the Adapter::assignData()
method dispatches the payment_method
additional parameter.
The Magento\Payment\Model\Method\Adapter
class.
[php]
public 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;
}
[/php]
If you want to have a backward compatible implementation with Magento 2.0.x releases you have to consider using payment_model
key in the AssignDataObserver
class as optional.
Leave a Reply
You must be logged in to post a comment.