Using Negative Values for the Product Quantity in Magento 2

5 min read

Send to you:

When we deal with product quantity in Magento® 2, and it’s less than zero, we face the challenge. Sometimes we need to order the products in the online stores when they are not available at the moment. These products are in stock in Magento 2 but Merchants order them from the manufacturers and shippers after we place the order. In eCommerce, we call this back-order or drop-ship. In this case, the number of product quantity in the online store inventory can be less than 0. Yet, the products are available for the ordering.

Magento 2 includes this functionality. We can turn on the support for Qty field values which are less than 0 in Inventory Management Configuration. But there is one small catch. If the product quantity in Magento 2 is less than zero, the online shop administrator can’t edit and resave this product. The following error will appear in Qty field:

“Please enter a valid number in this field.”

You can find the description of this issue and the possible solution to it on GitHub. But you should know that it doesn’t work on the latest Magento versions (checked on Magento 2.1.7). We’ll cover the reason for this issues and the solution to it below.

The product editing form is implemented with UI-component. It is useful in case we need to do customization with different modules. For example, the form is claimed in the Catalog module. However, Cataloginventory module handles the quantity management.

Cataloginventory Module for Product Quantity in Magento 2

It’s possible to implement customization with classes-modifiers. They fit into Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool virtual type with di.xml.

If we take the Cataloginventory module, this modifier is claimed in the following way there:

<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="advancedInventory" xsi:type="array">
                    <item name="class" xsi:type="string">Magento\CatalogInventory\Ui\DataProvider\Product\Form\Modifier\AdvancedInventory</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                </item>
            </argument>
        </arguments>
    </virtualType>

The modifier class should implement \Magento\Ui\DataProvider\Modifier\ModifierInterface which must create two methods: modifyData($data) and modifyMeta($meta).

The component configuration is implemented in modifyMeta($meta) method, including its frontend part (javascript). In the solution from GitHub, the developer recommended turning off the digital validation with a custom modifier. We can implement it in the following way:

<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="hf_quantity" xsi:type="array">
                    <item name="class" xsi:type="string">Web4pro\Defaultproduct\Ui\DataProvider\Product\Modifier\Quantity</item>
                    <item name="sortOrder" xsi:type="number">10000000</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
class Quantity implements \Magento\Ui\DataProvider\Modifier\ModifierInterface {

    protected $arrayManager;

    public function __construct(\Magento\Framework\Stdlib\ArrayManager $arrayManager){
        $this->arrayManager =$arrayManager;
    }

public function modifyMeta(array $meta)
{
    if ($path = $this->arrayManager->findPath('quantity_and_stock_status_qty', $meta, null, 'children')) {
        $this->arrayManager->remove(
            $path . '/children/qty/arguments/data/config/validation/validate-digits',
            $meta
        );
    }

    if ($path = $this->arrayManager->findPath('advanced_inventory_modal', $meta)) {
        $meta = $this->arrayManager->merge(
            $path . '/children/stock_data/children/qty/arguments/data/config',
            $meta,
            ['validation' => ['validate-digits' => false]]
        );
    }

    return $meta;
}


    public function modifyData(array $data){
        return $data;
    }
}

In the latest Magento versions (Magento 2.1.7) this code will not work. The reason is the following. Magento has the implementation of support for integers and fractions. For example, the fractions work in case of product drop-shipping by weight.

The Solution for Product Quantity in Magento 2

Magento_CatalogInventory/js/components/qty-validator-changer component was implemented for the quantity validation. This is its code:

define([
    'Magento_Ui/js/form/element/abstract'
], function (Abstract) {
    'use strict';

    return Abstract.extend({
        defaults: {
            valueUpdate: 'input'
        },

        /**
         * Change validator
         */
        handleChanges: function (value) {
            var isDigits = value !== 1;

            this.validation['validate-number'] = !isDigits;
            this.validation['validate-digits'] = isDigits;
            this.validation['less-than-equals-to'] = isDigits ? 99999999 : 99999999.9999;
            this.validate();
        }
    });
});

handleChanges method checks the configuration value transmitted to the component. If the integers are used for the quantity, we should apply validate-digits validator. If we deal with fractions, we should apply validate-number. So, it’s not enough to turn off the validate-digits validator. We also should set the needed value of handleChanges function’s parameter. It allows us to avoid choosing this validator by the other function.

We describe this function’s parameter in Magento\CatalogInventory\Ui\DataProvider\Product\Form\Modifier\AdvancedInventory modifier the following way:

...
'imports' => [
                    'handleChanges' => '${$.provider}:data.product.stock_data.is_qty_decimal',
                ],
.

As we can see, we can get its values in both cases, whether we use integers or fractions for quantity. We set that in the configuration. So, let’s implement modifyMeta($meta) method in our modifier:

  public function modifyMeta(array $meta)
    {
        if ($path = $this->arrayManager->findPath('quantity_and_stock_status_qty', $meta, null, 'children')) {
            $this->arrayManager->remove(
                $path . '/children/qty/arguments/data/config/validation/validate-digits',
                $meta
            );
            $this->arrayManager->merge($path . '/children/qty/arguments/data/config/imports',$meta,
                                       array('handleChanges'=>"1"));
        }

        if ($path = $this->arrayManager->findPath('advanced_inventory_modal', $meta)) {
            $meta = $this->arrayManager->merge(
                $path . '/children/stock_data/children/qty/arguments/data/config',
                $meta,
                ['validation' => ['validate-digits' => false],'imports'=>['handleChanges'=>'1']]
            );
        }

        return $meta;
    }

Finally, we have the next results:

  • we turned off the validate-digits validator;
  • we set ‘handleChanges’ equal to 1.

It will cause the use of the right frontend validator. Furthermore, it won’t break the backend logic for the products which are on sales by item not by weight. We should repeat this twice because we can find the link under the Qty field. This link opens the advanced_inventory_modal pop-up.

As a result, the online store administrator will be able to save the products of which quantity is less than 0 without any problems.

This case is new to Magento 2. We make everything possible to make your journey with Magento 2 easier. If you have any questions regarding Magento 2 Extension Development, please, contact us. We’ll take care of your project.

5.0/5.0

Article rating (1 Reviews)

Do you find this article useful? Please, let us know your opinion and rate the post!

  • Not bad
  • Good
  • Very Good
  • Great
  • Awesome