skip to Main Content

I got a problem on a Prestashop website (1.7.7.8) , with updating price when changing options.
In some particular cases, an error occured and the price is not displayed.

You can see the bug here : https://bacom.lebonweb.fr/accueil/32-bache.html

This append in a specific scenario, when we have several options ; and not all are availables for all others options (not sure to be clear..). In this case :

  • the type "Roll up" has only 1 dimension available (200cm and 85cm).
  • the type "Bache" has others dimensions available, but not the same as the type ROLL UP

So to see the bug, you can follow those steps :

1/ go to https://bacom.lebonweb.fr/accueil/32-bache.html

2/ by default TYPE is rollup. Change the type select, choosing "Bache"

3/ the selects Hauteur and Largeur are well updated, with the available values for BACHE type (different from the ROLLUP type values). But the price disapears, and the error is "Can not retrieve the id_product_attribute" (debug mode is on)

If you reload the page, the bug disapear.

Some tests confirms the problem comes from the theme ; with classic default theme the same scenario works fine (http://www.lebonweb.fr/dev/bacom-test/femmes/2-42-brown-bear-printed-sweater.html)

I’ve tried, file by file (tpl and js) , to replace custom theme code with default theme code.
But impossible to solve this error….

I’m probably missing something with ajax & JS.
I’ve noticed this warning on console : "jQuery(window).on(‘load’…) called after load event occurred"…

But after 2 days of searching, reading, and testings, still unable to find a solution.
Would you have advice or suggestion on where I should investigate more ?

Thanks a lot


EDIT : To explain diferently (and shortlier ^^) the problem with combinations I’m encountering :

EXEMPLE : We got 3 combinations of a t-shirt :

T shirt – RED – Size : 1

T-shirt – RED – Size 2

T-shirt – BLACK – Size 1

Changing one option may automatically change another option value :

step 1 : choose options : color : RED / Size 2

step 2 : change option color to BLACK = Size change automatically to 1

In my case, it seems that the default combination datas (the one loaded automatically in this exemple scenario) is not sent to the ajax request that gets the price datas.
Wheras in other place in the page, those default datas are well get.

Maybe something like the ajax call to get price is called BEFORE another call that calculate the default combination according to option changes…?

Hope this other presentation of my problem will help 🙂

Thanks !

3

Answers


  1. Chosen as BEST ANSWER

    I finally found how to solve the problem (but didn't understand why) : dis-activate the ttcountdown module and clean ALL caches. The informations given by Patrick were very helpful, so thanks again Patrick for taking time to help ! This solution is okay, because my client doesn't need any countdown functionality.

    But very frustrating, cause I did not clearly understand where and what in the code provocates the bug ; whereas we had quite a lot of elements and datas about it.

    Maybe there's a link with changes on prestashop 1.7 about attributes (see : PrestaShop 1.7 How to get id_product_attribute on product page?) :

    In PrestaShop 1.7.x versions, product attributes (size, color, etc.) IDs selected by the buyer are stored in the group variable within an array, however this variable no longer contains the related id_product_attribute itself.

    With those informations, I've supposed maybe the bugging theme author didn't make clean and stable adaptation of his script after this change...? So I've tried some corrections on ttproductcountdown.php code, just for better understanding, around those lines (function hookPSPC at line 1360 of module/ttproductcountdown/ttproductcountdown.php)

    // Get id_product_attribute
            $id_product_attribute = null;
            if (isset($params['id_product_attribute'])) {
                $id_product_attribute = $params['id_product_attribute'];
            } elseif (Tools::getValue('group')) {
                $groups = Tools::getValue('group');
    
                if (!empty($groups) && method_exists('Product', 'getIdProductAttributesByIdAttributes')) {
                    $id_product_attribute = (int) Product::getIdProductAttributesByIdAttributes(
                        $id_product,
                        $groups
                    );
                }
            }
            if ($id_product_attribute === null) {
                $id_product_attribute = Tools::getValue('id_product_attribute');
            }
            $has_attributes = $this->checkProductHasAttributes($id_product);
            if (!$id_product_attribute && $has_attributes) {
                $id_product_attribute = $this->getDefaultIdProductAttribute($id_product);
            }
    
            $hook = (isset($params['hook']) ? $params['hook'] : '');
    
            // render timers for all combinations at once at the product page in PS1.6
            if ($has_attributes && $this->getPSVersion() < 1.7 && $this->context->controller->php_self == 'product') {
                $ipas = Product::getProductAttributesIds($id_product, true);
                foreach ($ipas as $ipa) {
                    $return .= $this->renderCountdown($id_product, $ipa['id_product_attribute'], $hook);
                }
            } else {
                $return = $this->renderCountdown($id_product, $id_product_attribute, $hook);
            }
    

    Without success... So as long as I don't plan to work often with prestashop ; and a day gets only 24h ; I will "give up" try to understand the problem.

    Patrick, just for information, Prestashop is already using Boostrap. I'd like to make all by myself, but creating a theme for prestashop is quite long cause it covers a lots of pages and functionality (cart, catalog, user account etc..).

    As I said, I avoid to work with CMS... Cause correcting a bug by clicking on a button without learning anything is not the way I like to work.

    Thanks Patrick !


  2. this took some debugging, I don’t know how much this might be helpful to you but thought I would try anyway….

    the js is making a call to

    https://bacom.lebonweb.fr/index.php?controller=product&token=7dc88db1baee0ecae0e917cf624997d0&id_product=32&id_customization=0&group%5B20%5D=112&group%5B22%5D=124&group%5B21%5D=113&group%5B11%5D=52&qty=1'
    

    with the following form data:

    controller  product
    token   7dc88db1baee0ecae0e917cf624997d0
    id_product  32
    id_customization    0
    group[20]   112
    group[22]   124
    group[21]   113
    group[11]   52
    qty 1
    

    and the following body data

    quickview   0
    ajax    1
    action  refresh
    quantity_wanted 1
    

    this api is then throwing the following error:

    Can not retrieve the id_product_attribute
    at line 6582 in file classes/Product.php
    6577.                 );
    6578.             }
    6579.         }
    6580. 
    6581.         if (empty($idProductAttribute)) {
    6582.             throw new PrestaShopObjectNotFoundException('Can not retrieve the id_product_attribute');
    6583.         }
    6584. 
    6585.         return $idProductAttribute;
    6586.     }
    

    The call is coming from

    function ajaxProductCombinationChange(productId, attributes) {
            $.ajax({
                type: 'POST',
                url: prestashopFacebookAjaxController,
                data: {
                    action: 'CustomizeProduct',
                    ajax: true,
                    id_product: productId,
                    attribute_ids: attributes,
                }
            });
        }
    

    So I wonder is this a php error rather than a jquery one as even when I refresh the page in edge, chrome or firefox I always get the error?

    I hope this helps

    Login or Signup to reply.
  3. so i dug into this a bit more, this is a rather long detail so please bare with me, the php stack trace is :

    Can not retrieve the id_product_attribute
    at line 6582 in file classes/Product.php
    
    6577.                 );
    6578.             }
    6579.         }
    6580. 
    6581.         if (empty($idProductAttribute)) {
    6582.             throw new PrestaShopObjectNotFoundException('Can not retrieve the id_product_attribute');
    6583.         }
    6584. 
    6585.         return $idProductAttribute;
    6586.     }
    6587. 
    
        ProductCore::getIdProductAttributeByIdAttributes - [line 6594 - classes/Product.php] - [3 Arguments]
    
        6589.      * @deprecated 1.7.3.1
        6590.      * @see Product::getIdProductAttributeByIdAttributes()
        6591.      */
        6592.     public static function getIdProductAttributesByIdAttributes($id_product, $id_attributes, $find_best = false)
        6593.     {
        6594.         return self::getIdProductAttributeByIdAttributes($id_product, $id_attributes, $find_best);
        6595.     }
        6596. 
        6597.     /**
        6598.      * Get the combination url anchor of the product.
        6599.      *
    
        ProductCore::getIdProductAttributesByIdAttributes - [line 1391 - modules/ttproductcountdown/ttproductcountdown.php] - [2 Arguments]
    
        1386.             $groups = Tools::getValue('group');
        1387. 
        1388.             if (!empty($groups) && method_exists('Product', 'getIdProductAttributesByIdAttributes')) {
        1389.                 $id_product_attribute = (int) Product::getIdProductAttributesByIdAttributes(
        1390.                     $id_product,
        1391.                     $groups
        1392.                 );
        1393.             }
        1394.         }
        1395.         if ($id_product_attribute === null) {
        1396.             $id_product_attribute = Tools::getValue('id_product_attribute');
    
        TTProductCountdown->hookPSPC - [line 1439 - modules/ttproductcountdown/ttproductcountdown.php] - [1 Arguments]
    
        1434.             ($this->product_position == 'displayProductPriceBlock'
        1435.             || $this->product_list_position == 'over_img'
        1436.             || $this->product_list_position == 'displayProductPriceBlock')
        1437.         ) {
        1438.             $params['hook'] = 'displayProductPriceBlock';
        1439.             return $this->hookPSPC($params);
        1440.         }
        1441.     }
        1442. 
        1443.     public function hookDisplayProductButtons($params)
        1444.     {
    

    the call is still/now coming from:

    emit("updateProduct", {
                    eventType: "updatedProductCombination",
                    event: e,
                    resp: {},
                    reason: {
                        productUrl: o.default.urls.pages.product || ""
                    }
                }
    

    there seams to be a function in core.js

     "updatedProductQuantity" === t && (h = 750),
                    u = setTimeout(function() {
                        "" !== f && (s = r.default.ajax({
                            url: n + (-1 === n.indexOf("?") ? "?" : "&") + f + p,
                            method: "POST",
                            data: {
                                quickview: (0,
                                r.default)(".modal.quickview.in").length,
                                ajax: 1,
                                action: "refresh",
                                quantity_wanted: "updatedProductCombination" === t ? c.attr("min") : c.val()
                            },
                            dataType: "json",
                            beforeSend: function() {
                                null !== s && s.abort()
                            },
                            error: function(e, t, n) {
                                "abort" !== t && 0 === (0,
                                r.default)("section#main > .ajax-error").length && l()
                            },
                            success: function(e, n, i) {
                                var a = (0,
                                r.default)("<div>").append(e.product_cover_thumbnails);
                                (0,
                                r.default)(".quickview .images-container, .page-product:not(.modal-open) .row .images-container, .page-product:not(.modal-open) .product-container .images-container").html() !== a.find(".quickview .images-container, .page-product:not(.modal-open) .row .images-container, .page-product:not(.modal-open) .product-container .images-container").html() && (0,
                                r.default)(".quickview .images-container, .page-product:not(.modal-open) .row .images-container, .page-product:not(.modal-open) .product-container .images-container").replaceWith(e.product_cover_thumbnails),
                                (0,
                                r.default)(".quickview .product-prices, .page-product:not(.modal-open) .row .product-prices, .page-product:not(.modal-open) .product-container .product-prices").first().replaceWith(e.product_prices),
                                (0,
                                r.default)(".quickview .product-customization, .page-product:not(.modal-open) .row .product-customization, .page-product:not(.modal-open) .product-container .product-customization").first().replaceWith(e.product_customization),
                                (0,
                                r.default)(".quickview .product-variants, .page-product:not(.modal-open) .row .product-variants, .page-product:not(.modal-open) .product-container .product-variants").first().replaceWith(e.product_variants),
                                (0,
                                r.default)(".quickview .product-discounts, .page-product:not(.modal-open) .row .product-discounts, .page-product:not(.modal-open) .product-container .product-discounts").first().replaceWith(e.product_discounts),
                                (0,
                                r.default)(".quickview .product-additional-info, .page-product:not(.modal-open) .row .product-additional-info, .page-product:not(.modal-open) .product-container .product-additional-info").first().replaceWith(e.product_additional_info),
                                (0,
                                r.default)(".quickview #product-details, #product-details").replaceWith(e.product_details),
                                (0,
                                r.default)(".quickview .product-flags, .page-product:not(.modal-open) .row .product-flags, .page-product:not(.modal-open) .product-container .product-flags").first().replaceWith(e.product_flags),
                                function(e) {
    
    

    this line is where that error message is coming from:

     r.default)(".quickview .product-prices, .page-product:not(.modal-open) .row .product-prices, .page-product:not(.modal-open) .product-container .product-prices").first().replaceWith(e.product_prices)
    

    it is injecting the following htlm :

    'nx3C!-- begin _partials/notifications.tpl -->nn<aside id="notifications">n  <div class="container">n    n          n        <article class="alert alert-warning" role="alert" data-alert="warning">n          <ul>n                          <li>Can not retrieve the id_product_attribute</li>n                      </ul>n        </article>n      n    n    n      </div>n</aside>nnx3C!-- end _partials/notifications.tpl -->n'
    

    if i reply the same ajax call though postman or fiddler i can re-create the error, the

     <script src="https://bacom.lebonweb.fr/themes/core.js"></script>
    

    witch as you say is a theme script I assume this is something that is added by the site host your using or some sort of plug in ?

    when I compare it to the theme that works (http://www.lebonweb.fr/dev/bacom-test/femmes/2-42-brown-bear-printed-sweater.html)

    the request is totally different :

    http://www.lebonweb.fr/dev/bacom-test/index.php?controller=product&token=e75591940fae6ed3e01a3adbbbac3d6c&id_product=2&id_customization=0&group%5B1%5D=2&group%5B2%5D=10&qty=1
    

    moreover the core.js file is totally different, for a start its minimized …so you could try copying the core.js file from the theme that works to the theme that dose not and see what happens, in theory if it’s just a theme script the core functionality should still work, failing that contact the site provider or raise an issue worth the theme provider (assuming that have github or some equivalent) and ask why their theme script is failing as theme script shouldn’t act differently that’s kinda the point of them, better still do away with the theme and use your own, a very good and widely used theme is https://getbootstrap.com/docs/5.0/getting-started/introduction/ it is easy to use and offers very good customisable styling and functionality

    I hope this helps

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search