Problema en la ordenación de productos con el módulo de filtros

Hola amigos, hoy os traigo un problema que nos puede surgir durante estos meses en adelante hasta que desde PrestaShop corrijan el bug existente en el módulo de filtros de producto. Este problema ha sido detectado en una versión de Prestashop con el tema 1.7.7.8.

Es un fallo reconocido en los hilos de dudas y peticiones de Github (Prestashop). El problema radica en que la ordenación de productos no funciona bien con las posiciones de producto en las categorías. Por lo hilos y foros se indican cosas para solucionarlo, pero creerme, no funcionan al 100%. Incluso algunos dicen que quites el módulo, y si se soluciona pero no tienes filtros 😥. Grandes problemas, grandes soluciones, y tan a gusto me quedo… Pero bien sabemos que esa no es la solución, y que a mi siempre me gusta ir más allá.

Bueno después de dedicarle tiempo y un café con leche calentito, he detectado el problema de todo. Nos toca sumergirnos en el core y dar una solución correcta. Recordemos que el módulo de filtros en la versión 1.7.x de PrestaShop se complica por las tantas clases y herencias de estas que tiene, pero he podido añadirle un fragmento de código que da solución.

El problema se basa en las consultas que hace para obtener los productos:

SELECT
    p.id_product,
    p.position
FROM
    (
    SELECT
        p.id_product,
        p.id_manufacturer,
        SUM(sa.quantity) AS quantity,
        p.condition,
        p.weight,
        p.price,
        psales.quantity AS sales,
        cp.position
    FROM
        ps_product p
    LEFT JOIN ps_product_attribute pa ON
        (p.id_product = pa.id_product)
    LEFT JOIN ps_product_attribute_combination pac ON
        (
            pa.id_product_attribute = pac.id_product_attribute
        )
    LEFT JOIN ps_stock_available sa ON
        (
            p.id_product = sa.id_product AND IFNULL(pac.id_product_attribute, 0) = sa.id_product_attribute AND sa.id_shop = 1 AND sa.id_shop_group = 0
        )
    LEFT JOIN ps_product_sale psales ON
        (
            psales.id_product = p.id_product
        )
    INNER JOIN ps_category_product cp ON
        (p.id_product = cp.id_product)
    INNER JOIN ps_category c ON
        (
            cp.id_category = c.id_category AND c.active = 1
        )
    LEFT JOIN ps_category_group cg ON
        (cg.id_category = c.id_category)
    INNER JOIN ps_product_shop ps ON
        (
            p.id_product = ps.id_product AND ps.id_shop = 1 AND ps.active = TRUE
        )
    WHERE
        p.visibility IN('both', 'catalog') AND cg.id_group = '3' AND c.nleft >= 95 AND c.nright <= 112 AND ps.id_shop = '1'
    GROUP BY
        p.id_product
) p
INNER JOIN ps_category_product cp ON
    (p.id_product = cp.id_product)
GROUP BY
    p.id_product
ORDER BY
    p.position ASC,
    p.id_product
DESC
LIMIT 0, 20

Veamos el resultado obtenido…

Como podemos ver, los productos que nos devuelven son distintos pero tienen posiciones iguales, esto no puede ser así. En una categoría un producto único tiene la posición 0, esto se debe a que en la consulta no se tiene en cuenta la categoría real a la que se está accediendo. Siendo así, la consulta encuentra la primera posición que tiene el producto en otra categoría, ya que no se especifica en cual.
Archivo que se ha tocado para solucionar esto dentro del módulo:
modules/ps_facetedsearch/src/Adapter/MySQL.php
Este archivo se encarga de montar la query con mil llamadas y comprobaciones por varios archivo (classes), al desconocer la arquitectura de todo el sistema se hace complicado poder encontrar una solución óptima y rápida, pero se puede solucionar en la función «getQuery()» de este archivo, debemos añadir antes de que devuelva la query, las siguientes líneas:
//HACK para ordenamiento de productos
$id_category = \Tools::getValue('id_category', 0);
if($id_category){
   $query = str_replace('ps_category_product cp ON (p.id_product = cp.id_product', 'ps_category_product cp ON (p.id_product = cp.id_product AND cp.id_category='.(int)$id_category, $query);
}
Estoy de acuerdo, no es lo más correcto, pero es funcional, no provoca problemas, y optimiza la query porque descarta rows en inner join. Además, soluciona nuestro fallo. Como podemos comprobar, es simplemente lo siguiente: si tenemos un id_category y está variables siempre está disponible en las categorías, la obtenemos y en la query añadimos que la categoría dónde se debe extraer las posiciones es ese id_category. De esta forma la consulta obtiene las posiciones reales del producto en la categoría en la estamos.
Espero que esta entrada os haya sido de mucha utilidad.
Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Responsable de los datos: Luis María Jordán Muñoz | Finalidad: Responder a la solicitud que me envíes y ofrecerte información | Legitimación: Tu consentimiento de forma expresa | Destinatario: Nicalia mi proveedor de hosting | Derechos: Tienes derecho al acceso, rectificación, supresión, limitación, portabilidad y olvido, para más información, te dejo enlace a mi política de privacidad ... enlace

Scroll al inicio
Ir arriba