Jump to content

How to stop a product from being added to cart programmatically & why out of stock products can be added to my cart ?


Recommended Posts

Hello,

I've been developing a module to add a "Daily Limit" to customer purchase and basically prevent them from completely adding any product in their shopping cart if it surpass that daily limit.

It all went mostly smoothly, except 2 problem I encountered,

  1. How do I prevent the item to be added to the shopping card from the "actionCartUpdateQuantityBefore" hook.
  2. Why is one of my sites still let customer add an item to their shopping cart but another site does not, even tho both of these sites have the same Stock management setting of not allowing backorder.

 

 

I will briefly explain what I did for this module:

What I did was, add this hook "actionCartUpdateQuantityBefore" to the module,

then check where this hook is called, it's from Cart.php, checking the parameters and some code, the important parts is this:

 

        $data = array(
            'cart' => $this,
            'product' => $product,
            'id_product_attribute' => $id_product_attribute,
            'id_customization' => $id_customization,
            'quantity' => $quantity,
            'operator' => $operator,
            'id_address_delivery' => $id_address_delivery,
            'shop' => $shop,
            'auto_add_cart_rule' => $auto_add_cart_rule,
        );

        /* @deprecated deprecated since 1.6.1.1 */
        // Hook::exec('actionBeforeCartUpdateQty', $data);
        Hook::exec('actionCartUpdateQuantityBefore', $data);

        if ((int) $quantity <= 0) {
            return $this->deleteProduct($id_product, $id_product_attribute, (int) $id_customization);
        }

        if (!$product->available_for_order
            || (
                Configuration::isCatalogMode()
                && !defined('_PS_ADMIN_DIR_')
            )
        ) {
            return false;
        }

 

As you can see from the code above, I get the $data and I used them in my module to check if the user surpassed the daily limit or not.

if the "price of his purchase today" + "price of the shopping card" + "price of the product" he is trying to add, is not above the daily limit.

Do nothing, otherwise, some new data will be shown using the "displayCartModalContent" to tell them of the daily limit which works fine.

 

Now we reach the first problem:

  • How do I prevent the item to be added to the shopping card from the "actionCartUpdateQuantityBefore" hook.

To solve this above problem, I did a simple trick,

I simply write

       $data['product']->available_for_order = false;

once this data is changed in my module hook, then the Cart will be returned false.

due to this:

        if (!$product->available_for_order
            || (
                Configuration::isCatalogMode()
                && !defined('_PS_ADMIN_DIR_')
            )
        ) {
            return false;
        }

which should work fine, and it indeed worked fine in localhost and my first site, Prestashop Version 1.7.6.4.

But then I tried to install this in my 2nd site, which a few years ago was the clone of the first site, but changed a bit over time, and it's Version 1.7.6.5 right now.

in this site, while both the "action" and "display" hook from my module works perfectly,

The customer can still add the item to it's shopping cart...

They see my daily limit error from my display hook showing up and telling them they are over the limit.

But their shopping cart still add the product regardless of that.

 

To completely make sure this is not my module's problem,

I created a product out of stock, then using a customer account, tried to add it to cart, the button is "disabled"

but a simple right click and Inspect Elements, removing the "disabled" attribute from the button and you can click it.

Then it will actually add the product to my shopping cart! this is a problem.

Same trick does not work in first site, it give an error and does not add the product.

Both site seems to have similar settings and configuration, the only difference is Version 1.7.6.4 on first  and Version 1.7.6.5 on second site.

 

Any Idea ?

Also, is there another way I could use to prevent a product from being added to the shopping cart from the "actionCartUpdateQuantityBefore" hook ?

Thanks in advance.

 

Edit: I might as well add that I rather do this simply from my module and without touching any of Prestashop core files or overriding anything.

Edited by Pedram
Added Extra Info. (see edit history)
Link to comment
Share on other sites

  • 1 year later...

It's been a year, but this answer may help others because this issue still prevails.

The easiest way to block items from being added to a cart is by killing the php process (aka die/exit the code), rn the current implementation does not allow any other way. It would be awesome if just throwing an exception worked, but exceptions are kinda weird in current prestashop's state (both with and without the debug mode enabled btw; it just crashes and the frontend doesn't care about it).

If you want your frontend to not do something strange, you must return a json with an array containing 'hasError' => true. The problem with this, though, is that the frontend js is as terrible as most of prestashop frontend and it does nor properly handle these errors...

public function hookActionCartUpdateQuantityBefore(array $params)
{
    die(json_encode([
        'errors' => 'whatever.. due to how the frontend js is done, this won\'t be shown anyways',
        'hasError' => true,
    ]));
}

So by adding that "hasError" the only thing you're doing is forbidding prestashop from doing any other requests (like the ps_shoppingcart's modal which opens after adding something to a cart), but, again, it won't show anything on your side.

You'll have to tune the theme js in order to properly show this.

In case you're using the default prestashop "theme-classic" or a variant of it (without any js changed), you have the default modules installed (including ps_shoppingcart), and you have ajax installed, you can do another workaround. Instead of returning that 'hasError' => true, you can inject some js to fix the default behavior and properly show the errors.

So, instead of the previous php code, using something like:

public function hookActionCartUpdateQuantityBefore(array $params)
{
    die(json_encode([
        'errors' => ['ok this time we\'re getting the errors to the front end :)'],
    ]));
}

And then, injecting a custom js file with these contents:

let errors = [];
;jQuery(function ($) {
  // here we locally store the errors into our errors var, for later usage.
  prestashop.on('updateCart', function (event) {
    if (event && event.resp && event.resp.errors.length) {
      errors = event.resp.errors;
      prestashop.emit('showErrorNextToAddtoCartButton', { errorMessage: event.resp.errors.join('<br />')});
      return;
    }
    // remove errors contents for any other update without errors
    errors = [];
  })
});
// ps_shoppingcart modal behavior override (actual fix)
prestashop.blockcart.showModal = function (modal) {
  // if we're getting errors, do not show the modal
  if (errors.length) {
    return;
  }

  var $body = $('body');
  $body.append(modal);
  $body.one('click', '#blockcart-modal', function (event) {
    if (event.target.id === 'blockcart-modal') {
      $(event.target).remove();
    }
  });
}

Will properly show an error in the front-end of your prestashop site:

imatge.png.6513a65caa0865865801f095cc660908.png

Note that this time I defined the return key 'errors' as an array instead of a string, this is because the default behavior of prestashop is to consider that as an array (with no checks on it, so just in case we don't break anything else).

Edited by elboletaire
Added missing part where I explain how to tune the front to properly get this working (see edit history)
Link to comment
Share on other sites

  • 6 months later...

Hello,

Thank for your response @elboletaire 

I have a question

with the custom js like you explain, it show the error message and doesn't show the modal popup, perfect !

But when I have no error on my hookActionCartUpdateQuantityBefore, and the product is well added to the cart, the modal popup doesn't appear either

is this the normal behavior? how can I do to display the modal popup if I have no error on my hookActionCartUpdateQuantityBefore please ?

If I delete this code :

    prestashop.blockcart.showModal = function (modal) {
        // if we're getting errors, do not show the modal
        if (errors.length) {
            return;
        }

        var $body = $('body');
        $body.append(modal);
        $body.one('click', '#blockcart-modal', function (event) {
            if (event.target.id === 'blockcart-modal') {
                $(event.target).remove();
            }
        });
    }

Then the modal popup is well appear if no error on hookActionCartUpdateQuantityBefore  , but appear too if I have error on hookActionCartUpdateQuantityBefore  

Thank you

Autoresponse : by adding 'hasError' => true, it works without adding the custom js

Edited by Hadrien
Resolved (see edit history)
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...