Jump to content

Add a product with customization field to the cart in a custom module


Recommended Posts

Hey there,

I'm first would like to apologize for this thread because it is possible the answer already exist somewhere else.

I'm making a Custom Module for Prestashop 8, what I'm trying to achieve is a button that adds a Product with a Custom Parameter which I'll handle myself in the backend of my module. What I've done yet is a button on my template linked to my module php file through an ajax function. I have the product I want to add as a variable and right now I'm using the cart->updateQty() method but it doesn't seem to be the proper way of doing it nowadays. I'm really confused and the more I read the more I feel lost about this whole Prestashop 8 update.

Here is my ajax method:

public function _ajax_add_plinths($quantity) {
  $context = Context::getContext();
  $id_cart = $context->cookie->__get('id_cart');

  if (!$id_cart) {
    $cart = new Cart();
    $cart->id_customer = (int)($context->cookie->__get('id_customer'));
    $cart->id_address_delivery = (int)(Address::getFirstCustomerAddressId($cart->id_customer));
    $cart->id_address_invoice = $cart->id_address_delivery;
    $cart->id_lang = (int)($context->cookie->__get('id_lang'));
    $cart->id_currency = (int)($context->cookie->__get('id_currency'));
    $cart->id_carrier = 1;
    $cart->recyclable = 0;
    $cart->gift = 0;
    $cart->add();
    $context->cookie->__set('id_cart', (int)($cart->id));
    $context->cart = $cart;
  } else {
  	$cart = new Cart($id_cart);
  }
  $cart->id_currency = 1;
  $cart->id_lang = 1;

  $product = $this->getProductByProductName('Plinthes associées');

  if ($product) {
    $cart->updateQty($quantity, $product['id_product'], false, null, 'up', 0, null, true);
    $context->smarty->assign(array(
    	'confirmation' => 1
    ));
  } else {
    $context->smarty->assign(array(
    	'confirmation' => 0
    ));
  }
}

Am I on the good path or should I refactor my whole module because what I've made is deprecated ?

Don't hesitate to ask if you need me to provide more information,

Any help would be appreciated,

Padrox

Link to comment
Share on other sites

Hey, I'm back with more information, here is my updated add to cart Ajax method in my Custom Module main class.

public function _ajax_add_plinths($currentProductName, $quantity) {
        $returnMap = array("Initialization" => "Success");

        $cart = $this->context->cart;

        // Retrieve the plinths Product
        $plinths = $this->GetProductByProductId(3);
        $plinthsId = $plinths['id_product'];
        $plinthsAttributeId = $plinths['product_attribute_id'];

        $plinthsProduct = new Product($plinthsId);

        //Get the customization field ID for "Carrelage associé"
        $customizationFields = $plinthsProduct->getCustomizationFields();
        $returnMap["CustomizationFields"] = $customizationFields;
        $carrelageAssociéFound = false;
        $fieldId = null;
        foreach ($customizationFields as $field) {
            $returnMap[$field["3"]["1"]['name']] = "Field Name";
            if ($field["3"]["1"]['name'] === 'Carrelage associé') {
                $carrelageAssociéFound = true;
                $fieldId = $field["3"]["1"]['id_customization_field'];
                break;
            }
        }
        $returnMap['Carrelage Associé Found'] = $carrelageAssociéFound;
        $returnMap["FieldId"] = $fieldId;

        // Set the customization value for the field "Carrelage associé"
        if ($fieldId) {
            $customizationValue = $currentProductName;
            $returnMap['customizationValue'] = $customizationValue;

            $cart->update();

            $cart->updateQty($quantity, $plinthsId, null, false);
            $returnMap['updateQty'] = "Called";
            $cart->_addCustomization($plinthsId, $plinthsAttributeId, $fieldId, $plinthsProduct::CUSTOMIZE_TEXTFIELD, $customizationValue, $quantity, false);
            $returnMap['_addCustomization'] = "Called";
        }

        // Save the cart
        $cart->update();
        $returnMap['Cart Status'] = "Updated!";

        echo json_encode($returnMap);
    }

My product is successfully added to the cart but there is not notification. To display the update of the cart I have to reload the page.

One more thing the Customization isn't applied on my newly added product.

Please help

Link to comment
Share on other sites

It won't work for you that way 😉
I'll give you an example for javascript and ajax.php.

javascript:

// customize product in your module
function addToCartInMyModule() {
  // call ajax function
  $.ajax({
    type: "POST",
    url: your_ajax_url, // /modules/mymodule/ajax.php
    data:'action=addTocart',
    async: false,
    cache: false,
    dataType: 'json',
    success: function(data){
      if (data !== ''){ 
        if (data['id_product'] !== '' && data['id_product_attribute'] !== '' && data['quantity'] !== '' && data['operand'] !== '') {
          // OK, data
          myAjaxAddToCart(data['id_product'], data['id_product_attribute'], data['quantity'], data['operand']) ; 
        }  
      } 
    }
  });
}

// add to cart and refresh page
function myAjaxAddToCart(id_product, id_product_attribute, quantity, operand) {
  // operand up / down
  const token = prestashop.static_token; 
  const actionURL = prestashop.urls.pages.cart;
  var query= 'controller=cart&add=1&action=update&ajax=true&qty='+quantity+'&op='+operand+'&token='+token+'&id_product='+id_product+'&ipa='+id_product_attribute; 
  $.post(actionURL, query, null, 'json').then((resp) => {
    prestashop.emit('updateCart', {
      reason: {}, resp: resp
    });
    console.log(resp);
  }).fail((resp) => {
    prestashop.emit('handleError', {eventType: 'addProductToCart', resp: resp});
  });
}

 

ajax.php:

<?php
include('../../config/config.inc.php');
include('../../init.php');

$module_name = 'mymodule';
$module = Module::getInstanceByName($module_name);

if (!Module::isInstalled($module->name) || !$module->active) {
    echo($module->l('Ajax Error'));
    return;
}

if (Tools::getValue('action') == 'addTocart') {
    $response = array();
    $myLog = '';
    // call your module function or add here

	$response['id_product'] = $id_product;
    $response['id_product_attribute'] = $id_product_attribute;
    $response['quantity'] = $quantity;
    $response['operand'] = 'up' // or down;
    $response['log'] = $myLog;
    
    echo json_encode($response);
}

 

Link to comment
Share on other sites

Hey,

Thank you so much for your answer.

I'm starting to feel completely lost and depressed about my progression curve on Prestashop because I feel like I'm doing a total non-sense...
I really appreciate your help.

First, I've made a lot of changes recently so I wouldn't know how to adapt my newly pseudo fonctionnal code to the example you've provided me with.

If you want to take a look, here is what I came up with recently

    public function getProductByProductId($search, $id_shop = 1, $id_lang = 1) {
        return Db::getInstance()->getValue('
        SELECT id_product
        FROM '._DB_PREFIX_.'product_lang
        WHERE id_product LIKE "%'.(string)$search.'%"
        AND id_shop = '.$id_shop.' AND id_lang = '.$id_lang.'
        ');
    }

    public function getProductByProductName($search, $id_shop = 1, $id_lang = 1) {
        return Db::getInstance()->getValue('
        SELECT id_product
        FROM '._DB_PREFIX_.'product_lang
        WHERE name LIKE "%'.(string)$search.'%"
        AND id_shop = '.$id_shop.' AND id_lang = '.$id_lang.'
        ');
    }

    public function getProductVariantIdFromDimension($product, $index) {
        $productAttributesIds = Product::getProductAttributesIds($product['id_product']);
        return (int)$productAttributesIds[$index]['id_product_attribute'];
    }

    public function _ajax_add_plinths($currentProductName, $quantity) {
        $returnMap = [];

        // Accessors
        $context = $this->context;
        $cookie = $context->cookie;

        // Get cart if already exist or create one
        if ($cookie->id_cart)
        {
            $cart = new Cart($cookie->id_cart);
        }

        if (!isset($cart) OR !$cart->id) {
            $cart = new Cart($cookie->id_cart);
            $cart->id_customer = (int)$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)$cookie->id_lang;
            $cart->id_currency = (int)$cookie->id_currency;
            $cart->id_carrier = 1;
            $cart->recyclable = 0;
            $cart->gift = 0;
            $cart->add();
            $cookie->id_cart = (int)$cart->id;
        }

        // Retrive the current Product
        $currentProduct = $this->getProductByProductName($currentProductName);
        $currentId = $currentProduct['id_product'];
        
        // Retrieve the plinths Product
        $plinths = $this->getProductByProductId(3);
        $plinthsId = $plinths['id_product'];
        $plinthsProduct = new Product($plinthsId);

        // This is the ID of the feature that determines what will be the dimension of the newly added plinths
        $featureId = 2;
        $features = Product::getFeaturesStatic($currentId);

        $dimensionFeature = null;
        foreach($features as $feature) {
            if($feature['id_feature'] == $featureId) {
                $dimensionFeature = $feature;
                break;
            }
        }
        if($dimensionFeature == null) {
            $returnMap['ERROR'] = "No dimension feature found on this product. Cannot add the associated plinths to the cart!";
            echo json_encode($returnMap);
            return;
        }

        $attributeId = 0;
        switch($feature['id_feature_value']) {
            case 7: // Manches longues
                $attributeId = $this->getProductVariantIdFromDimension($plinths, 0);
                break;
            case 8: // Manches courtes
                $attributeId = $this->getProductVariantIdFromDimension($plinths, 1);
                break;
            case 9: // Housse amovible
                $attributeId = $this->getProductVariantIdFromDimension($plinths, 2);
                break;
            case 10: // 120 pages
                $attributeId = $this->getProductVariantIdFromDimension($plinths, 2);
                break;
            default:
                $returnMap['ERROR'] = 'id_feature_value cannot be used! ID = ' . $feature['id_feature_value'];
                echo json_encode($returnMap);
                return;
        }

        //Get the customization field ID for "Carrelage associé"
        $customizationFields = $plinthsProduct->getCustomizationFields();
        $fieldId = null;
        foreach ($customizationFields as $field) {
            if ($field["3"]["1"]['name'] === 'Carrelage associé') {
                $fieldId = $field["3"]["1"]['id_customization_field'];
                break;
            }
        }

        // Set the customization value for the field "Carrelage associé"
        if ($fieldId) {

            $cart->update();
            $cart = $context->cart;

            $customizationValue = $currentProductName;
            $id_customization = $cart->_addCustomization((int)$plinthsId, (int)$attributeId, (int)$fieldId, 
                $plinthsProduct::CUSTOMIZE_TEXTFIELD, $customizationValue, (int)$quantity, true);
            $cart->updateQty((int)$quantity, (int)$plinthsId, (int)$attributeId, (int)$id_customization);
        }

        $cart->update();
        echo json_encode($returnMap);

 

Now, I can call my ajax and the product is properly added to the cart with the correct customization (which is defined by myself based on a ProductFeature).

I have one major issue that is the cart isn't updated until I refresh manually. I'd like to have the default popup saying "new product added to cart".

How should I adapt my new code with the example you provided me with ?

Sorry for the confusion ..

 

Link to comment
Share on other sites

Hey

So i've tried to implement what you suggested on my own.

These are the updated correspondiong ajax.php and .tpl

I don't know how and why but the Ajax method seems to be called because I don't have a 404 error when clicking the button but there is absolutely no return no error.

I'm completely lost.

Any suggestion ?

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

The PHP:

<?php
include('../../config/config.inc.php');
include('../../init.php');

$aled = array();
$module_name = 'mymodule';
$module = Module::getInstanceByName($module_name);

$aled['Please work'] = true;

if (Module::isInstalled($module->name) || $module->active) {
    echo($module->l('Ajax Error'));
    return;
}

if (Tools::getValue('action') == 'addTocart') {
    $response = array();
    $myLog = '';
    // call your module function or add here

    $response['HERE'] = "Not working ...";

	// $response['id_product'] = $id_product;
    // $response['id_product_attribute'] = $id_product_attribute;
    // $response['quantity'] = $quantity;
    // $response['operand'] = 'up'; // or down
    // $response['log'] = $myLog;
    
    echo json_encode($response);
}

echo json_encode($aled);
Link to comment
Share on other sites

function addPlinths() {
  // call ajax function
  $.ajax({
    type: "POST",
    url: '../../modules/plinthshandler/ajax/ajax.php', // /modules/mymodule/ajax.php
    data:'action=addTocart',
    async: false,
    cache: false,
    dataType: 'json',
    success: function(data){
        console.log("Returned in the success");
        console.log(JSON.parse(data));
        // if (data !== ''){ 
        //     if (data['id_product'] !== '' && data['id_product_attribute'] !== '' && data['quantity'] !== '' && data['operand'] !== '') {
        //     // OK, data
        //     myAjaxAddToCart(data['id_product'], data['id_product_attribute'], data['quantity'], data['operand']) ; 
        //     }  
        // }
    }
  });
}

 

Link to comment
Share on other sites

Hey,

I checked your module example and it really looks like what I have indeed.

In my module, I successfully add the product with the proper customization in the cart. The only thing is that the product and the cart are not automatically visually updated.

I'd love to add the "A new product has been added to the cart" from the default template. I feel like it must be something easy to add but it seems way more complicated than what I've expected. If you could please enlighten for me where the code responsible for this feature is located.

To be honest, I'm reaching my deadlines, so if I can add this feature as quick as possible, it would be great. Though, if I have to refactor everything I'll do it...

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...