Cómo crear un Tipo de Producto en Magento2

Tipos de productos

Hay veces en que dada alguna lógica del negocio, los tipos de producto de Magento pueden no sernos suficiente. Incluso haciendo uso de los Plugins o los Observers, hay proyectos en los que no alcanza.

En esos casos una alternativa puede ser crear un nuevo tipo de producto.

El tener un tipo de producto custom abre todo tipo de posibilidades, ya que no sólo vamos a poder identificar el producto por su tipo, sino que de acá en más podremos tener lógicas diferenciales y específicas para ese producto, sin por eso, afectar el resto del catálogo.

Al mismo tiempo, vamos a poder continuar transaccionando sin problemas, lo cual nos permite hacer uso de todo el potencial de Magento como carrito de compras, como gestor de promociones en los precios, etc, etc.

Vamos a seguir usando Barbanet_SampleModule como si se tratara de un crash test dummy para definir nuestro nuevo tipo de producto.

Primero creamos el archivo etc/product_types.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/product_types.xsd">
    <type name="sample"
          label="Sample Product Type"
          modelInstance="Barbanet\SampleModule\Model\Product\Type\Sample"
          indexPriority="25"
          composite="false"
          isQty="true"
          canUseQtyDecimals="false"
          sortOrder="100">
    </type>
</config>

Luego vamos a crear el modelo, según hemos definido, en Model/Product/Type/Sample.php:

<?php
 
namespace Barbanet\SampleModule\Model\Product\Type;
 
class Sample extends \Magento\Catalog\Model\Product\Type\AbstractType
{
 
    /**
     * Product Type ID
     */
    const TYPE_ID = 'sample';
 
    /**
     * Delete data specific for Simple product type
     *
     * @param \Magento\Catalog\Model\Product $product
     * @return void
     */
    public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product) {}
}

Dado que mi módulo ya había usado el instalador y actualizador de datos, voy a tener que ampliarlo para que aplique los cambios específicos de la versión. Por eso, agregamos el if para la versión 2.20.0, dejando el archivo Setup/UpgradeData.php así:

<?php
 
namespace Barbanet\SampleModule\Setup;
 
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
 
class UpgradeData implements UpgradeDataInterface
{
 
    /**
     * EAV setup factory
     *
     * @var EavSetupFactory
     */
    protected $eavSetupFactory;
 
    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        EavSetupFactory $eavSetupFactory
    )
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }
 
    /**
     * Upgrade Data
     *
     * @param ModuleDataSetupInterface $setup   Module Data Setup
     * @param ModuleContextInterface   $context Module Context
     *
     * @return void
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $installer = $setup;
 
        if (version_compare($context->getVersion(), '2.11.0')) {
 
            if ($installer->getTableRow($installer->getTable('barbanet_samplemodule'), 'row_id', 1)) {
                $installer->updateTableRow(
                    $installer->getTable('barbanet_samplemodule'),
                    'row_id',
                    1,
                    'description',
                    'Actualizado contenido con script'
                );
            }
         }
 
        if (version_compare($context->getVersion(), '2.20.0')) {
 
            /** @var EavSetup $eavSetup */
            $eavSetup = $this->eavSetupFactory->create(
                ['setup' => $setup]
            );
 
            $attributes = [
                'price',
                'special_price',
                'special_from_date',
                'special_to_date',
                'minimal_price',
                'cost',
                'tier_price',
                'weight',
            ];
 
            foreach ($attributes as $attribute) {
 
                $applyTo = explode(
                    ',',
                    $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attribute, 'apply_to')
                );
                if (!in_array(\Barbanet\SampleModule\Model\Product\Type\Sample::TYPE_ID, $applyTo)) {
                    $applyTo[] = \Barbanet\SampleModule\Model\Product\Type\Sample::TYPE_ID;
                    $eavSetup->updateAttribute(
                        \Magento\Catalog\Model\Product::ENTITY,
                        $attribute,
                        'apply_to',
                        implode(',', $applyTo)
                    );
                }
            }
        }
    }
}

Ahora nos vamos a la consola y ejecutamos:

bin/magento cache:clean
bin/magento setup:upgrade

Volvemos al backend y vamos a la gestión de catálogo, en donde al querer agregar un nuevo producto, deberíamos ver nuestro nuevo tipo de producto.

Tipos de productos

Entramos y completamos nuestros datos.

Edición de un porducto de tipo custom

Lo guardamos.

Edición de un porducto de tipo custom

Nos vamos al frontend y en la vista de categoría mi nuevo producto debería aparecer junto al simple que ya tenía creado.

Vista de categoría

Y al entrar al producto, todo debería funcionar como hasta ahora.

Vista de producto

Tendría que poder agregarglo al carrito sin problemas.

Agregando producto de tipo custom al carrito

Y visualizarlo en el cart también.

Vista del carrito de compras

El checkout no debería dar problemas y la compra debería cerrarse correctamente.

Finalización del proceso de compra

Y la orden ha de figurar correctamente en nuestro backend.

Detalle del pedido

Para terminar, este texto que copio y pego cada vez, lo comentado en el post sobre el módulo Barbanet_SampleModule está disponible en GitHub bajo el tag 2.20.0.