📜 ⬆️ ⬇️

Automatic change of product types in Magento 2

Sometimes for one reason or another, content managers need to convert a particular product from Simple to Virtual or vice versa, change its attribute set and so on ... Most often it falls on the shoulders of developers. And here I would like to describe 1 new and very interesting feature of Magento 2, which is not described in any way in the official documentation.

To change the type of product in Magento 1. * Content managers would have to create new products manually, make copies of the original products, and so on, or ask the developers to do it through code. Magento 2. * introduces a new “feature” to achieve this goal. Before you deal with it (I’ll call it “auto conversion”) you should keep a few points in mind to get the right results.

Auto conversion from user point of view


Let's look at the admin panel, or rather how it works from the point of view of the content manager. As before, you can choose the type of new product before you create it.
')
In Magento 1, this is displayed at Admin> Catalog> Manage Products> The page for selecting the set attribute and product type after clicking on “Add Product”.


In Magento 2, for this, on the Admin> Products> Catalog page, click the arrow on the right of the “Add Product” button.


After selecting the required type, Magento will show you a new product editing page with predefined options and / or new sections for the selected type. If you select the product type “Simple product” or simply click on “Add Product”, you will see the Simple product editing page, but pay attention to the following 3 things:

  1. Weight attribute
  2. Configurations Section
  3. Downloadable Information Section

These 3 sections define the type of product.

Magento 2 can automatically (when saved) change the product types of both new and existing products of the following products:

Consider what you need to do.

Simple and Virtual Products

If you set the weight to "Weight" = "The item has no weight" (there is no weight, and do not just remove the value from the input field), the product will be saved as a Virtual product, but as soon as you return to the product edit page and specify that the goods have weight, then it will be converted into a Simple product immediately after saving.

Downloadable product

In order to turn the Simple product into a Downloadable, you need to set “Weight” = “The item has no weight” and add 1 or more links in the section “Downloadable Information” below. To turn this product back into a Simple product, simply set “Weight” = “The item has weight” and save the product.

Configurable product

To make the Simple Product Configurable, it’s enough to add any subsidiary product to it as described above. And in order to make it Simple again, the product simply deletes all the configurations and click on save. As you already understood, this means that in Magento 2 there can be no Configurable product without children (as it was in Magento 1).

That's all.

On a note


Before you use auto conversion to a configurable product, you need to keep in mind that Magento 2 has changed the principle of getting the price from a Configurable product. Magento 1 Configurable products had their own price and completely ignored the price of related products. Magento 2 takes a different approach. Now Configurable products use a calculated price of tied children. The downside of the medal is that if you remove all associated products, the product is converted into a Simple product, but if you delete all related products from the Grid page in the admin panel, the product is not converted (why this is so, I will describe later). Considering the new logic, that the product is Configurable only if it has children, otherwise it is “converted” into the Simple product, this can lead to some unforeseeable errors in the code, especially if you are working with importing goods.
* In Magento 2.1, some of these errors have been fixed, and when directly accessing the $ product-> getFinalPrice () method, an exception is now thrown.
Fatal error: Uncaught exception 'Magento\Framework\Exception\LocalizedException' with message 'Configurable product "…sku…" does not have sub-products' in vendor\magento\module-configurable-product\Pricing\Price\ConfigurablePriceResolver.php:52 


For developers


Now let's talk about exactly how it all works. I would like to start from the most important, with the class Magento \ Catalog \ Model \ Product \ TypeTransitionManager .
 ... public function __construct( \Magento\Catalog\Model\Product\Edit\WeightResolver $weightResolver, array $compatibleTypes ) { $this->compatibleTypes = $compatibleTypes; $this->weightResolver = $weightResolver; } public function processProduct(Product $product) { if (in_array($product->getTypeId(), $this->compatibleTypes)) { $product->setTypeInstance(null); $productTypeId = $this->weightResolver->resolveProductHasWeight($product) ? Type::TYPE_SIMPLE : Type::TYPE_VIRTUAL; $product->setTypeId($productTypeId); } } ... 

This is a fairly simple class that has 2 methods __construct and processProduct. All magic is enclosed in the second method, processProduct ($ product). As you can see, it checks if there is a type of the transferred product in the array of compatible types, and if the product has weight, then this is a Simple product, if not, then a Virtual product.

In Magento 2.1. As you may have guessed, the following types are compatible:

They are all transmitted via di.xml
 ... <type name="Magento\Catalog\Model\Product\TypeTransitionManager"> <arguments> <argument name="compatibleTypes" xsi:type="array"> <item name="simple" xsi:type="const">Magento\Catalog\Model\Product\Type::TYPE_SIMPLE</item> <item name="virtual" xsi:type="const">Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL</item> </argument> </arguments> </type> ... 

This means that only these types can be converted to Simple or Virtual products.

As mentioned above, the Simple product can be converted into a configurable and downloadable product as well. All the magic in the following classes (plugins):

Magento \ Downloadable \ Model \ Product \ TypeTransitionManager \ Plugin \ Downloadable :: aroundProcessProduct () verifies that the Simple, Virtual, Downloadable product type has been sent data from the frontend with the downloadable key and that this product has no weight. If it is, then it is Downloadable, otherwise the original method is launched.
 ... public function aroundProcessProduct( \Magento\Catalog\Model\Product\TypeTransitionManager $subject, Closure $proceed, \Magento\Catalog\Model\Product $product ) { $isTypeCompatible = in_array( $product->getTypeId(), [ \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL, \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE ] ); $downloadableData = $this->request->getPost('downloadable'); $hasDownloadableData = false; if (isset($downloadableData)) { foreach ($downloadableData as $data) { foreach ($data as $rowData) { if (empty($rowData['is_delete'])) { $hasDownloadableData = true; break 2; } } } } if ($isTypeCompatible && $hasDownloadableData && !$this->weightResolver->resolveProductHasWeight($product)) { $product->setTypeId(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE); return; } $proceed($product); } ... 


Magento \ ConfigurableProduct \ Model \ Product \ TypeTransitionManager \ Plugin \ Configurable :: aroundProcessProduct () plug-in changes the product type to “configurable” if the requester has data with the “attributes” key, otherwise the original method is started.
 ... public function aroundProcessProduct( \Magento\Catalog\Model\Product\TypeTransitionManager $subject, Closure $proceed, \Magento\Catalog\Model\Product $product ) { $attributes = $this->request->getParam('attributes'); if (!empty($attributes)) { $product->setTypeId(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE); return; } $proceed($product); } ... 

How it all works


If you try to save the product from the admin panel, as described above, it will change its type to 1 of the above thanks to this code, but if you just try to save the product model through the save () method, nothing will change. The point is in the controller that handles the preservation of the goods.
Magento \ Catalog \ Controller \ Adminhtml \ Product \ Save :: execute () uses the instance of the class Magento \ Catalog \ Model \ Product \ TypeTransitionManager

 ... $product = $this->initializationHelper->initialize($this->productBuilder->build($this->getRequest())); $this->productTypeManager->processProduct($product); … $product->save(); ... 

As you can see the product conversion is not tied to the save () method and is called just before the product is created.

Instead of conclusion


For users and developers, I think it became a bit clearer how exactly the new feature of Magento 2 works. It surprises me that for all the time Magento 2 has existed, they have not written about it anywhere.
You also want to add that in Magento 2 you just need to add new types of products and if you may need to allow users to convert them among themselves, then you just need to add a couple of lines to your module's di.xml and create your own plugin.

Source: https://habr.com/ru/post/309184/


All Articles