Von Oleksandr Lyzun publiziert am 28. Oktober 2016

Restrict Product Payments – comwrap develops new magento extention

For one of our projects we developed Magento 2 extension for restrict payment methods for particular products. The paid version of extension can be found on Magento Marketplace: https://marketplace.magento.com/comwrap-product-payments.html

Magento 2 at the moment is quite young and very fast-developing platform. This creates some difficulties for developers as in internet there are not so many information about code source features and development tricks. (the most useful source at the moment is http://devdocs.magento.com/). So the idea of this article is to show, on some real example, Features that we found during extension development. And also if somebody will need such functionality for his project he can easily reuse it.

In this article I will describe some tips and tricks that may help Magento developers in future. Those tips were learned during development of this extension. We tried to do it as close as possible to Magento Development standards and guess that we succeeded here.

Restrict Payment methods

So for removing or adding some payment methods from checkout (depending on products that are added to the shopping cart), I have to build some own payment method validators.

First idea was to find a place where payment methods are defined and add some restriction code there. After some research, I found out that payment methods has build-in functionality to check their displaying on a frontend. A developer can create a custom validator for all payment methods. 

To add a new validator, you have to insert configuration XML in your di.xml file:

 


<type name="Magento\Payment\Model\Checks\SpecificationFactory">
    <arguments>
        <argument name="mapping" xsi:type="array">
            <item name="restricted_products" xsi:type="object">Comwrap\ProductPayments\Model\Checks\ProductRestrictions</item>
        </argument>
    </arguments>
</type>

 

<argument> is adding a new parameter to a payment specification factory and Comwrap\ProductPayments\Model\Checks\ProductRestrictions - this is our validator that will be executed on checkout for each available payment method. 

But to enable new validator, we have to make a new plugin and add a new keyrule into.

Plugin:


<type name="Magento\Payment\Model\Checks\SpecificationFactory">
    <plugin name="product_restrict_payment" type="Comwrap\ProductPayments\Plugin\Payment\Checks\SpecificationFactory" sortOrder="1" />
</type>

And in this plugin, we should add a new key to the rules' list 


const RESTRICTED_PRODUCTS_CHECK_KEY = "restricted_products";
public function beforeCreate(\Magento\Payment\Model\Checks\SpecificationFactory $subject, $data){
    $data[] = self::RESTRICTED_PRODUCTS_CHECK_KEY;
    return [$data];
}

 

Note: I didn't find the way to do it without plugins. In case if it's possible, I'll be happy to learn it – Drop us some comments if you know how.

So, we defined our validator at Comwrap\ProductPayments\Model\Checks\ProductRestrictions class that implements \Magento\Payment\Model\Checks\SpecificationInterface interface.

At our new class, we have to create a public method isApplicable(MethodInterface $paymentMethod, Quote $quote), where Magento transfer Payment method and Quote, and than it checks if current payment method is available for current quote, and then return it true of false status. 

 

It looks this way: 


public function isApplicable(MethodInterface $paymentMethod, Quote $quote){
    $restrictedMethods = $this->getRestrictedMethods($quote);
	if (in_array($paymentMethod->getCode(), $restrictedMethods)){
            return false;
	}         
            return true; 
	} 

public function getRestrictedMethods($quote){
	if ($this->_restrictedMethods){
            return $this->_restrictedMethods;
	}
	
	$this->_restrictedMethods = [];
	$items = $quote->getAllItems();

	foreach ($items as $item){
            $values = explode(",", $item->getProduct()->getData('restrict_payment'));

            foreach ($values as $value){
                if (!in_array($value, $this->_restrictedMethods)){
                    $this->_restrictedMethods[] = $value;
            }
        }
    }
	
    return $this->_restrictedMethods;
}

 

That's it. So, now each payment method will be checked through our class.

Array in Plugins

As you know, plugins have before, after and around functionality. 

If you don't know, here is a link: http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html

In case of before action, plugin receives as the first parameter $subject (class instance) and then the same parameters that function receives in initial class.

 

For example, plugin for: 


makeSomeAction($param1, $param2, $param3);

will look like: 


beforeMakeSomeAction($subject, $param1, $param2, $param3);

 

From Magento documentation: 

"You can use before methods to change the arguments of an observed method by returning a modified argument. If there are multiple arguments, the method should return an array of those arguments."

So if you have just 1 parameter you can just return its new value, but if you have multiple - you have to return an array for all parameters. 

But in our case the parameter is an already and array. So when we are just returning an array back, we are getting an error, because Magento for get our return parameter is trying to get [0] element from this array.

For make it works you have to return array for your array. Like that: return [$data];

 


public function beforeCreate(\Magento\Payment\Model\Checks\SpecificationFactory $subject, $data){
    $data[] = self::RESTRICTED_PRODUCTS_CHECK_KEY;
    return [$data];
}

 

Add Product attribute to the quote

In case if you have created new product attribute and wanted to make it available in quote item, like:


$item->getProduct()->getSomeCustomAttribute();

you have to create new catalog_attributes.xml file in your etc/ folder and add this attribute to your quote. Like that:

 


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/catalog_attributes.xsd">
    <group name="quote_item">
		<attribute name=“some_custom_attribute”/>
	</group>
</config>

That's all, hope this info will help somebody. Good luck with your Magento 2 :) and give me your comments what you think on this.

 

Dieser Beitrag wurde verfasst von unserem Entwickler ALEX LYZUN - er ist kein professioneller Schreiber, dafür ein begnadeter Entwickler.

Mehr zu den Magento Enterprise E-Commerce Lösungen vom comwrap.