Jump to content

Value in Cart object deleted when carrier is chosen, I need to pass the value from Cart to Order


Recommended Posts

Hello, 

I made a module where the customer is able to customize a product. On the front page of the module, the product is displayed as an SVG element, the customer can customize this SVG element with Javascript, the SVG element code is change in real time at every actions from the customers.
When the customer add the product to shopping cart, this function is called in the module's front controller :

// Add the product in shopping cart
    public function addToShoppingCart(){

        if ($this->context->cookie->id_cart){
            $cart = $this->context->cart;
        }

        if ($cart->id == null){
            $cart = new 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->gift_message = Tools::getValue('svgTemplateResult');
        $cart->update();
	
        // Update the shopping cart
        $cart->updateQty(1, $this->getProductId(), $id_product_attribute = null, $id_customization = false, $operator = 'up', $id_address_delivery = 0, $shop = null, $auto_add_cart_rule = true);
    }

As you can see, I get the cart if it's already created or create it if not.

I add  Tools::getValue('svgTemplateResult')  which is the SVG element code as a string, to a place in the Cart object and try to get it back in my main php file of the module with the actionValidateOrder hook like this :

public function hookActionValidateOrder($params)
{
    echo "<pre>";
    print_r($params['cart']);
    echo "<pre>";
    
    die();
}

But the value is not in gift_message anymore and by having a look in the database, I found when it's deleted.

In the checkout page, just when i chose a Carrier, BOUM, the value is deleted from the Cart object and cannot be find once the actionValidateOrder is triggered.

Please, how can I do pass this value from the Cart object to the Order object. Is there an actionHook when the Carrier is chosen ? I found some but haven't tried yet. I will now.

Also, I made an override to add a field to OrderDetail object, the field just wait to be filled with this value and finally get the SVG element displayed in the order details summary in Back Office.

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

Hi,
 

public function addToShoppingCart()
{

        if ($this->context->cart->id){
            $id_cart = $this->context->cart->id;
        }

        if (!$id_cart){
            $cart = new 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->gift_message = Tools::getValue('svgTemplateResult');
            $cart->add();
            $this->context->cookie->__set('id_cart', $cart->id);   
        } else {
           $cart = new Cart ((int) $id_cart);
           $cart->gift_message = Tools::getValue('svgTemplateResult');
           $cart->updateQty(1, $this->getProductId(), $id_product_attribute = null, $id_customization = false, $operator = 'up', $id_address_delivery = 0, $shop = null, $auto_add_cart_rule = true);
        }

        
    }

 

Link to comment
Share on other sites

13 hours ago, 4you.software said:

Hi,
 

public function addToShoppingCart()
{

        if ($this->context->cart->id){
            $id_cart = $this->context->cart->id;
        }

        if (!$id_cart){
            $cart = new 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->gift_message = Tools::getValue('svgTemplateResult');
            $cart->add();
            $this->context->cookie->__set('id_cart', $cart->id);   
        } else {
           $cart = new Cart ((int) $id_cart);
           $cart->gift_message = Tools::getValue('svgTemplateResult');
           $cart->updateQty(1, $this->getProductId(), $id_product_attribute = null, $id_customization = false, $operator = 'up', $id_address_delivery = 0, $shop = null, $auto_add_cart_rule = true);
        }

        
    }

 

Thanks for the answer.

The $cart->updateQty() is not firing in the first case, if there is no $id_cart.

It needs to be added in that if too no ?

Link to comment
Share on other sites

And where do you see that $id_cart is not passed?

$cart = new Cart() => return $cart->id !!

You can also directly call Hook::exec

$cart = new Cart();
/* or $cart =  new Cart(int) $id_cart); */
$data = [
            'cart' => $cart,
            '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,
        ];

Hook::exec('actionCartUpdateQuantityBefore', $data);

 

Edited by 4you.software (see edit history)
Link to comment
Share on other sites

And what is your problem?

public function addToShoppingCart()
{

        if ($this->context->cart->id){
            $id_cart = $this->context->cart->id;
        }

        if (!$id_cart){ // not exists, create
            $cart = new Cart();
            $cart->id_customer = (int)($this->context->cookie->id_customer);
            $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->gift_message = Tools::getValue('svgTemplateResult');
            $cart->add();
            $this->context->cookie->__set('id_cart', $cart->id);   
            $data = [
               'cart' => $cart,
               'product' => $product,
               'id_product_attribute' => $id_product_attribute,
               'id_customization' => $id_customization,
               'quantity' => '1',
               'operator' => 'up',
               'id_address_delivery' => (int)(Address::getFirstCustomerAddressId($cart->id_customer)),
               'id_address_invoice' => (int)(Address::getFirstCustomerAddressId($cart->id_customer)),
               'shop' => $this->context->shop->id,
               'auto_add_cart_rule' => true,
            ];

             Hook::exec('actionCartUpdateQuantityBefore', $data);
        } else { // exists, update
           $cart = new Cart ((int) $id_cart);
           $cart->gift_message = Tools::getValue('svgTemplateResult');
           $cart->update();
        }

        
    }

 

Edited by 4you.software (see edit history)
Link to comment
Share on other sites

20 minutes ago, 4you.software said:

And where do you see that $id_cart is not passed?

$cart = new Cart() => return $cart->id !!

You can also directly call Hook::exec

$cart = new Cart();
/* or $cart =  new Cart(int) $id_cart); */
$data = [
            'cart' => $cart,
            '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,
        ];

Hook::exec('actionCartUpdateQuantityBefore', $data);

 

Ok this is interesting.

The problem in your proposition before is that if there is no cart already created the we go in "if(!$id_cart)" and not in the "else" where the updadeQty() is firing. I tried, I need to click 2 times on "Add to shopping cart" to get 1 time the product. The first time we go in "if(!$id_cart)" and create the object, second time we go in "else" as the object is already created and we updateQty().

My problem is not about putting the string in the Cart object, my 1st code does that well. The problem is that when I chose the Carrier in Checkout, the Cart->gift_message data is deleted. And so the hookActionValidateOrder's $params['cart']->gift_message is empty.

I verified in real time in database, the gift_message has my string until the very moment I chose a Carrier.

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

Just now, 4you.software said:

 

./override/classes/Cart.php

 

class Cart extends CartCore

{

    public $my_custom_field;

    public function __construct($id_product = null){

        self::$definition['fields']['my_custom_field'] = array('type' => self::TYPE_STRING);

        parent::__construct();

    }

}

 

 

your module:

 

$cart->my_custom_field = '';

 

And also in the database directly I presume or no need ? I did that for the OrderDetail object (override + manually new field in database)

PS: I need a TYPE_HTML because it's slicing my content if not.

Link to comment
Share on other sites

40 minutes ago, 4you.software said:

Yes, it must exist in the database,
yes, you can change the type to HTML.

self::$definition['fields']['my_custom_field'] = array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml');

 

It doesn't work.

Here's my override in ../override/classes : 

<?php 

class Cart extends CartCore

{

    public $my_custom_field;

    public function __construct($id_product = null){

        self::$definition['fields']['my_custom_field'] = array('type' => self::TYPE_STRING);

        parent::__construct();

    }

}

(I put back TYPE_STRING to first test with a simple word)

When I var_dump($cart->my_custom_field) after adding to cart, it works, I have the word in the my_custom_field.

I show you a screenshot of my database new field.

It stays NULL even when my var_dump() show me the field. Is the override not working ?

Capture d’écran 2022-09-22 à 10.40.17.png

 

 

EDIT: OK I just forgot to empty the cache..

Edited by Florian644 (see edit history)
  • Like 1
Link to comment
Share on other sites

1 hour ago, 4you.software said:

Yes, it must exist in the database,
yes, you can change the type to HTML.

self::$definition['fields']['my_custom_field'] = array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml');

 

Sorry but I have a new issue.

I'm now in the hookActionValidateOrder with the value I needed in Cart so that's reaally nice !

I need now to pass this value in $params['order']->getOrderDetailList()[0]['svgTemplate']

svgTemplate being an added field with override.

Here's my code and it doesn't work..

public function hookActionValidateOrder($params)
    {
        $params['order']->getOrderDetailList()[0]['svgTemplate'] = $params['cart']->my_custom_field;
        $params['order']->update();
     // or $params['order']->save();

		echo "<pre>";
        print_r($params['cart']->my_custom_field);
        echo "<pre>";
        die();
    }

 

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

9 minutes ago, 4you.software said:

Order::getOrderDetailList = OrderDetail::getList($id_order)

so the data from the order_detail table is returned.

But you have your value stored in the cart table.

I don't understand this line.

My point is to display the "my_custom_field" value into the order's summary in Back Office. So I guess OrderDetail object.

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

3 minutes ago, 4you.software said:
public function hookActionValidateOrder($params)
{
    $getDataInCart = Db::getInstance()->getValue('SELECT my_custom_field FROM '._DB_PREFIX_.'cart WHERE id_cart = '.$this->context->cart->id);
	if ($getDataInCart){
        /* add value to smarty variable */
	}
}

 

$params['cart']->my_custom_field gives me the right value, why is it needed to do that ?

Adding the value in the OrderDetail is what's tricking me.

$params['order']->getOrderDetailList() gives me access to the OrderDetails fields but I can't reach to update the svgTemplate field.

Sorry if I don't make myself understandable.

Link to comment
Share on other sites

6 minutes ago, 4you.software said:

So try what returns.

print_r($params['order']->getOrderDetailList()[0]);

 

Yeah I tried this.

It returns this

Capture d’écran 2022-09-22 à 12.50.01.png

Do I need to do something like this ? 

$query = "UPDATE `"._DB_PREFIX_."order_detail` SET svgTemplate=". $params['cart']->my_custom_field;
Db::getInstance()->Execute($query);

 

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

7 minutes ago, 4you.software said:

If you use my proposal, you will load your own variables in the TPL template.

public function hookActionValidateOrder($params)
{
    $this->context->smarty->assign('my_variable_smarty', $params['cart']->my_custom_field);
}

and tpl order-confirmation.tpl add

{$my_variable_smarty}

The simplest solution.

I need it in the Back Office orders.

So in src/PrestaShopBundle/Resources/views/Admin/Sell/Order/Order/Blocks/View/products.html.twig

Link to comment
Share on other sites

Yes that's what I did but for OrderDetail, somebody helped me and told me that I should create a new field in OrderDetail to get the value in the Back Office orders.

class OrderDetail extends OrderDetailCore {

	public $svgTemplate;
 
    public function __construct($id = null) { 

        self::$definition['fields']['svgTemplate'] = [ 'type' => self::TYPE_HTML,
            'required' => false
        ];
        
        parent::__construct($id);
    }
}

 

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

23 minutes ago, 4you.software said:

We keep going round and round.
If you save the svgtemplate in the cart, it applies to all products.
If you save the svgtemplate for each product separately, it must be saved in cart_product.
Once the cart is saved and the order continues, it must be entered in order_detail and indexed by product id and variant id.

This is my first module and seeing that the Prestashop documentation is useless I do what I can...

My thoughts was to save an array in the my_custom_field. Keys would be the product id and values the svgTemplate.

It's kind of difficult to have a fluent talk on forums..

Link to comment
Share on other sites

So the last hint.

your module install function add:

Db::getInstance()->execute('ALTER TABLE `'._DB_PREFIX_.'cart_product` ADD `svgTemplate` TEXT NULL DEFAULT NULL AFTER `id_product`'); 
Db::getInstance()->execute('ALTER TABLE `'._DB_PREFIX_.'order_detail` ADD `svgTemplate` TEXT NULL DEFAULT NULL AFTER `product_id`');

your module uninstall function add:

Db::getInstance()->execute('ALTER TABLE `'._DB_PREFIX_.'cart_product` DROP `svgTemplate`');
Db::getInstance()->execute('ALTER TABLE `'._DB_PREFIX_.'order_detail` DROP `svgTemplate`');

 

your module hook function:

public function hookActionValidateOrder($params)
{
    $getData = Db::getInstance()->executeS('SELECT * FROM '._DB_PREFIX_.'cart_product WHERE id_cart = '.$this->context->cart->id);

    $idOrder = $params['order']->id;

    foreach ($getData as $data){
        Db::getInstance()->execute(
        "UPDATE ".DB_PREFIX_."order_detail 
        SET svgTemplate = '".htmlspecialchars($data['svgTemplateResult'])."' 
        WHERE id_order = ".$idOrder." 
        AND product_id = ".$data['id_product']." 
        AND product_attribute_id = ".$data['id_product_attribute']."
        AND id_shop = ".$this->context->shop->id);
    }

	/* your code to display */
}

 

your front controller:

public function addToShoppingCart()
{
    
    /* your code */
    
    Db::getInstance()->execute(
        "UPDATE ".DB_PREFIX_."cart_product 
        SET svgTemplate = '".htmlspecialchars(Tools::getValue('svgTemplateResult'))."' 
        WHERE id_cart = ".$cart->id." 
        AND id_product = ".Tools::getValue('id_product')." 
        AND id_product_attribute = ".Tools::getValue('id_product_attribute')."
        AND id_shop = ".$this->context->shop->id);
}

 

override OrderDetail.php

class OrderDetail extends OrderDetailCore {

	public $svgTemplate;
 
    public function __construct($id = null) { 

        self::$definition['fields']['svgTemplate'] = [ 'type' => self::TYPE_HTML, 'required' => false];
        
        parent::__construct($id);
    }
}

 

  • Like 1
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...