Jump to content

Adding product to cart programatically - Fatal error


Jurist
 Share

Recommended Posts

Hello,

I am trying to create a small module that adds another products to the shopping cart through ajax call to module's controller.

It works, however I get fatal error:

Fatal error: Uncaught PrestaShopException: Fatal error in /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Tools.php:1175 Stack trace: #0 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Product.php(3170): ToolsCore::displayError() 

#1 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Product.php(4780): ProductCore::getPriceStatic(786, false, 0, 6, NULL, false, true, 2) 

#2 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Cart.php(790): ProductCore::getProductProperties(1, Array) 

#3 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Cart.php(1467): CartCore->getProducts(true) 

#4 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/modules/productAsCombination/productAsCombination.php(242): CartCore->updateQty(2, 786, 0, false) 

#5 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/modules/productAsCombination/controllers/front/ProductAsCombinationController.php(9): ProductAsCombination->addProductToCart(786, 2, NULL) 

#6 /home/xxxxyyyy/dev.xxxxyyyy.co.uk/modules/productAsCombination/controllers/front/Pro in /home/xxxxyyyy/dev.xxxxyyyy.co.uk/classes/Tools.php on line 1175

I found that if I comment out:

        if (!is_object($cur_cart) || (Validate::isUnsignedInt($id_cart) && $id_cart && $cur_cart->id != $id_cart)) {
            /*
            * When a user (e.g., guest, customer, Google...) is on PrestaShop, he has already its cart as the global (see /init.php)
            * When a non-user calls directly this method (e.g., payment module...) is on PrestaShop, he does not have already it BUT knows the cart ID
            * When called from the back office, cart ID can be inexistant
            */
            if (!$id_cart && !isset($context->employee)) {
                //die(Tools::displayError());
            }
            $cur_cart = new Cart($id_cart);
            // Store cart in context to avoid multiple instantiations in BO
            if (!Validate::isLoadedObject($context->cart)) {
                $context->cart = $cur_cart;
            }
        }

Line die(Tools::displayError()); the error is no more. My controller:

	public function addToCart($id_product, $quantity, $attribute)
	{
		$productsAsCombination = new productAsCombination();
		if(!$productsAsCombination->addProductToCart($id_product, $quantity, $attribute))
			return false;
		$price = Product::getPriceStatic($id_product);
		// $price = 69;
		return $price;
	}
}
	if(isset($_GET['function'])) 
	{
		if($_GET['function'] == 'addToCart' && $_GET['id_product'] && $_GET['quantity'])
		{
			$ProductAsCombinationController = new ProductAsCombinationController();
			$id_product = (int)$_GET['id_product'];
			$quantity = (int)$_GET['quantity'];
			$attribute = null;
			$data = $ProductAsCombinationController->addToCart($id_product, $quantity, $attribute);
			echo json_encode($data);
		} 
	}

and module's class:

	public function addProductToCart($id_product, $quantity, $attribute = null)
	{
		$context=Context::getContext();
		if ($this->context->cookie->id_cart)
		{
			$cart = new Cart($this->context->cookie->id_cart);
		}
		// create new cart if needed
		if (!isset($cart) OR !$cart->id)
		{
			$cart = new Cart($this->context->cookie->id_cart);
			$cart->id_customer = (int)($this->context->cookie->id_customer);
			$cart->id_address_delivery = (int) (Address::getFirstCustomerAddressId($cart->id_customer));
			$cart->id_address_invoice = $cart->id_address_delivery;
			$cart->id_lang = (int)($this->context->cookie->id_lang);
			$cart->id_currency = (int)($this->context->cookie->id_currency);
			$cart->id_carrier = 1;
			$cart->recyclable = 0;
			$cart->gift = 0;
			$cart->add();
			$this->context->cookie->id_cart = (int)($cart->id);
		}
		$cart->update();
		$cart->updateQty((int)$quantity, (int)$id_product, $attribute, false);
		$cart->update();
	}

Anybody could tip where there's a problem?

Apparently $id_cart is not defined when Product::getPriceStatic is called by CartCore. 

My module is working, however Internal server error from ajax call gives me anxiety.

Any help, will be much appreciated.

Share this post


Link to post
Share on other sites

Hi,

Of   course  you  are  calling   the  function   displayError  with  no  argument .

   

 Tools::displayError(' Error  text ');   //you  should this 
 Tools::displayError();  // instead  of  this  with no argument .

And  also  I  see  you  are  calling  :   $context->employee    in  the  front  office,  what  for  ?  

if (!$id_cart && !isset($context->employee)) {
                //die(Tools::displayError());
            }

 

 

Edited by ndiaga (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Hi ndiaga,

Thank you very much for your answer, much appreciated.

You quoted Cart.php core, which I have not edited in any way. 

$cart->updateQty((int)$quantity, (int)$id_product, $attribute, false);

called in my class causes the problem. Not sure why but for some reason, Cart.php, called from my module's class 'doesn't see' $id_cart.

Share this post


Link to post
Share on other sites

Hi @ndiaga,

I have created it other way, without using custom controller and using cartController instead. The problem I have is that sometimes on add to cart button click, the store adds products from my function first, which are then overwritten by the product that the add to cart button is clicked on.

There's code:

function addProduct(id_product, quantity, totalQty)
{
	const token = prestashop.static_token;
	const url = prestashop.urls.pages.cart;
	const query = 'controller=cart&add=1&action=update&ajax=true&token=' + token + '&id_product=' + id_product + '&id_customization=0&qty=' + totalQty;
	var controllerUrl = url.concat(query);
	var functionName = "addToCart";
	// var delay = 10;

	$.ajax({
		// url: controllerUrl,
		headers: { "cache-control": "no-cache" },
		cache: false,
		async: false,
		data: query,
		beforeSend: function () 
		{
			// setTimeout(delay);
		},
		success: function(resp) 
			{
				// console.log(resp);
				prestashop.emit('updateCart', {
					reason: {}, resp: resp
				});
			},
			error: function(resp) {
				// console.log(resp);
				prestashop.emit('handleError', {eventType: 'addProductToCart', resp: resp});
			}
	});
}

Do you have an idea how to fire the event after the original product was added to the shopping cart? So the products added by the function are added after, to an existing cart.

I would be very grateful for your help.

Kind regards

 

Share this post


Link to post
Share on other sites

Hi @ndiaga,

Do you mean _dev/cart.js? File is hard to read and understand, which part is responsible for adding product to shopping cart?

Basically the only problem I have with my function is that it add the product I want to shopping cart, but sometimes adds a new shopping cart which leaves 'original' product behind.

Is there a way to make sure that the event is fired only after previous add to cart action is done?

Maybe I should change query somehow?

Share this post


Link to post
Share on other sites

3 minutes ago, Jurist said:

Hi @ndiaga,

Do you mean _dev/cart.js? File is hard to read and understand, which part is responsible for adding product to shopping cart?

Basically the only problem I have with my function is that it add the product I want to shopping cart, but sometimes adds a new shopping cart which leaves 'original' product behind.

Is there a way to make sure that the event is fired only after previous add to cart action is done?

Maybe I should change query somehow?

Hi,

You  don't   need  to read  any  js   code,  just   call  it  as  the  default   classic   calls  it  in  the  file  :  themes/classic/templates/catalog/_partials/product-add-to-cart.tpl

  • Confused 1

Share this post


Link to post
Share on other sites

4 minutes ago, ndiaga said:

Hi,

You  don't   need  to read  any  js   code,  just   call  it  as  the  default   classic   calls  it  in  the  file  :  themes/classic/templates/catalog/_partials/product-add-to-cart.tpl

I checked that file contents but I think its called elsewhere, it's just template file that generates html content, which may then be used to fire JS event that adds product to shopping cart.

I need to add another product that is not shown on this product page (as accessory), that's why I use JS: if checkbox is selected, then add product id 786 to shopping cart as well.

It works but the problem is, new cart with product id 786 overwrites old cart with original product which means only product id 786 is now in cart.

I need to make sure cart is not empty and add it only after original product is added (which creates appropriate cart as well). I am thinking about setting interval and checking cart quantity...

Share this post


Link to post
Share on other sites

The  function  that  is  called  here  :  themes/classic/templates/catalog/_partials/product-add-to-cart.tpl    can  be   called  anywhere  in  the  website.

 

Share this post


Link to post
Share on other sites

On 5/14/2020 at 12:01 PM, ndiaga said:

The  function  that  is  called  here  :  themes/classic/templates/catalog/_partials/product-add-to-cart.tpl    can  be   called  anywhere  in  the  website.

 

hi ndiaga,

Could you please show me sample how to call it?

I tried reading documentation but couldn't find such info anywhere. I've spent few days on that and cannot solve the problem I have...

Share this post


Link to post
Share on other sites

13 minutes ago, Jurist said:

hi ndiaga,

Could you please show me sample how to call it?

I tried reading documentation but couldn't find such info anywhere. I've spent few days on that and cannot solve the problem I have...

This  call  the  js  :

data-button-action="add-to-cart"   

// the  use  

<button
            class="btn btn-primary add-to-cart"
            data-button-action="add-to-cart"
            type="submit"
            {if !$product.add_to_cart_url}
              disabled
            {/if}
          >
            <i class="material-icons shopping-cart">&#xE547;</i>
            {l s='Add to cart' d='Shop.Theme.Actions'}
          </button>

 

You have  to  use  a  form  with  action   and  required  fields  like  id_product,  id_product_attribute,  id_customization,   quantity  etc.

<form action="{$urls.pages.cart}" method="post" id="add-to-cart-or-refresh">
                  <input type="hidden" name="token" value="{$static_token}">
                  <input type="hidden" name="id_product" value="{$product.id}" id="product_page_product_id">
                  <input type="hidden" name="id_customization" value="{$product.id_customization}" id="product_customization_id">
  <div class="product-quantity clearfix">
        <div class="qty">
          <input
            type="text"
            name="qty"
            id="quantity_wanted"
            value="{$product.quantity_wanted}"
            class="input-group"
            min="{$product.minimal_quantity}"
            aria-label="{l s='Quantity' d='Shop.Theme.Actions'}"
          >
        </div>

        <div class="add">
          <button
            class="btn btn-primary add-to-cart"
            data-button-action="add-to-cart"
            type="submit"
            {if !$product.add_to_cart_url}
              disabled
            {/if}
          >
            <i class="material-icons shopping-cart">&#xE547;</i>
            {l s='Add to cart' d='Shop.Theme.Actions'}
          </button>
        </div>
      </div>
  
  </form>

 

Edited by ndiaga (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Man, I really appreciate your time and help. However I have no possibility of adding extra button / changes to .tpl files.

Please have a look here:

https://dev.wetroomsdesign.co.uk/wet-room-kit-800-x-800-line-ponente

Add to cart button is meant to add another products to the shopping cart if appropriate select options are chosen. 

I am trying to do that with:

function addProduct(id_product, quantity, totalQty, delay)
{
	const token = prestashop.static_token;
	const url = prestashop.urls.pages.cart;
	const query = 'controller=cart&add=1&action=add&ajax=true&token=' + token + '&id_product=' + id_product + '&id_customization=0&qty=' + totalQty;
	var controllerUrl = url.concat(query);
	var functionName = "addToCart";
	
	$.ajax({
		cache: false,
		data: query,
		beforeSend: function () 
		{
			setTimeout(delay);
		},
		success: function(resp) 
			{
				// console.log(resp);
				prestashop.emit('updateCart', {
					reason: {}, resp: resp
				});
			},
			error: function(resp) {
				// console.log(resp);
				prestashop.emit('handleError', {eventType: 'addProductToCart', resp: resp});
			}
	});
}

and it works but only if someone has cart created before.

If user adds to cart for the first time, the original product is overwritten. 

I need to fire it from javascript.

Any ideas?

Share this post


Link to post
Share on other sites

  • 11 months later...

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
 Share

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More