Magento2: M2.1.2 : JavaScript validate-digits rule doesn't validate negative numbers, making it impossible to save a product with a negative quantity

Created on 11 Nov 2016  路  17Comments  路  Source: magento/magento2

I stumbled upon this issue when a product had a negative stock and it made it impossible to save:

screen shot 2016-11-11 at 10 44 39

It seems that the validate-digits rule doesn't take into account negative numbers:

"validate-digits": [
    function(value) {
        return utils.isEmptyNoTrim(value) || !/[^\d]/.test(value);
    },
    $.mage.__('Please enter a valid number in this field.')
],

To match with negative numbers as well, the regex should be /[^-?\d]/. Or could it be that the validation rule should return false when digits are negative? In that case, the validate-digits-rule should be removed from the quantity box.

Or is it intentional that a product cannot be saved with a stock qty < 0? Because in that case, I would surely like to know why. I got a client who uses the backorder qty as a reference so he knows how much inventory he needs to buy.

Catalog Ready for Work bug report

Most helpful comment

This fix doesn't seem to work anymore in Magento 2.1.3. Could it be that something has changed on how metadata is modified?

All 17 comments

I've now created workaround that products with a qty below zero can be saved, by simple removing the validate-digits filter using a modifier, maybe this can help someone who's running into the same issue:

/**
 * @param array $meta
 */
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;
}

di.xml:

<!--
    Add a modifier to remote the validate-digits - rule from the Quantity box
-->
<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">Vendor\Module\Ui\DataProvider\Product\Form\Modifier\Quantity</item>
                <item name="sortOrder" xsi:type="number">10000</item>
            </item>
        </argument>
    </arguments>
</virtualType>

Please note the sortOrder of 10000. This is required because otherwise the advanced_inventory_modal-node is not yet available.

But the main question is: 'is this a bug or intended behavior'? If It's a bug I can make a pull request that removes the validate-digits-rule from the quantity boxes, but if it's not this ticket can be closed and used as a reference on how to work around this 'feature'.

But if this ticket gets closed, please share with us the reasoning why a product qty can not be below 0.

We are in the process of setting up a website, and we custom build a stock message module that uses negative values to display different stock messages based on how negative the number is. You can import products with a negative value (using something like rapidflow, or other import tools) and it works as expected. However, we manually cannot edit the stock message with a negative value exactly as you have discovered.

I'm pretty sure this is a bug. Because I also agree, why else would you have the entire option of "allow Qty below 0" if that was never an intended available option. It doesn't make sense.

@kanduvisla thank you for your report.
We already have internal ticket for this issue: MAGETWO-60599.
I have added a link to this issue to it.

Is there a scheduled timeline to fix this issue, as it is preventing us from editing ANY product that requires a negative value?
If a fix is posted, before major release, can the patch be posted here?

@kanduvisla - For your work around, where do you implement those code changes. I need to do this ASAP, as we need to get live with a site. I'll revert the code once an official patch has been provided.

Thanks in advance.

@kanduvisla could you please update this ticket with the location this fix should be implemented, like @spyrule requested? Thank you!

@Tristan-N @spyrule it's already in my answer. Add the line to (adminhtml) di.xml and put the PHP code in the file specified there (in my example it's Vendor\Module\Ui\DataProvider\Product\Form\Modifier\Quantity). Just be sure to include \Magento\Framework\Stdlib\ArrayManager as a dependency.

@kanduvisla
Sorry, I am a new M2 developer (and only an occasional php developer atm).

I have created a module (called Patches), its fully loading, but the actual code that is needed isn't implemented.
I created a di.xml in the etc/adminhtml folder, and added the code you referenced.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!--
    Add a modifier to remote the validate-digits - rule from the Quantity box
-->
<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">twmod\Patches\Ui\DataProvider\Product\Form\Modifier\Quantity</item>
                <item name="sortOrder" xsi:type="number">10000</item>
            </item>
        </argument>
    </arguments>
</virtualType>
</config>

I then create the sub-folders Ui\DataProvider\Product\Form\Modifier\ , its here that I am stumped.
Do I create a sub-folder called Quantity, with some file called ??? and copy the provided code within?
Or is it a file called Quantity[.php?] and insert the code?

This is the part that stumps me.

The file is called Quantity.php and should like something like this:

<?php
namespace Vendor\Module\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Framework\Stdlib\ArrayManager;

/**
 * Class Quantity
 * @package Vendor\Module\Ui\DataProvider\Product\Form\Modifier
 */
class Quantity extends AbstractModifier
{
    /**
     * @var ArrayManager
     */
    protected $arrayManager;

    /**
     * Quantity constructor.
     * @param ArrayManager $arrayManager
     */
    public function __construct(
        ArrayManager $arrayManager
    )
    {
        $this->arrayManager = $arrayManager;
    }

    /**
     * @param array $data
     * @return array
     */
    public function modifyData(array $data)
    {
        return $data;
    }

    /**
     * @param array $meta
     */
    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;
    }
}

This fix doesn't seem to work anymore in Magento 2.1.3. Could it be that something has changed on how metadata is modified?

I've tracked the problem down to the JavaScript Magento_CatalogInventory/js/components/qty-validator-changer. Here is the following 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();
        }
    });
});

I think these lines overrule the original settings, effectively eliminating the changes in modifiers. If this is the case I think this should be considered a bug.

I created a workaround now, by overriding the JavaScript in question and removing the line that re-enabled the validate-digits-entry. But for reasons unknown, the other two validators also don't have effect now...

But at least my customer now can use negative qty. Is there any update on someone of the development team on the progress on this ticket?

@kanduvisla thanks for helping me out. I know you're so much more than just a colleague sitting next to me in the office. LOL!

I saw in the developer branche of Magento 2 that the qty-validator-changer.js contains the following code:

/**
 * Copyright 漏 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

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-integer'] = isDigits;
            this.validation['less-than-equals-to'] = isDigits ? 99999999 : 99999999.9999;
            this.validate();
        }
    });
});

This fixes the bug, so I suppose this will be adapted in Magento 2.1.4.

I tested the above code change, and it made no difference, I suspect some other code is changed at the same time as this to complete the change.

This still is an issue in Magento 2.1.5, please fix this as a few of our customers want to be able to accept backorders and still edit products

This issue has already been fixed for ver. 2.1 and the fix will be available in one of the nearest releases.

Well its still happening in 2.1.7 and so this ticket shouldn't be closed until its actually posted.

I've seen this work as expected in 2.1.8

Was this page helpful?
0 / 5 - 0 ratings