EE 1.14.2 / CE 1.9.2: les articles de devis ne sont pas fusionnés correctement lors de la connexion (produits en double dans le panier)


16

J'ai trouvé un bug bizarre dans Magento EE 1.14.2 (affecte également CE 1.9.2) avec le panier.

Étapes à reproduire:

  1. Connectez-vous en tant que client A
  2. Ajouter le produit X au panier
  3. Passer à un autre navigateur
  4. Ajouter le produit X au panier
  5. Connectez-vous en tant que client A

Panier prévu:

  • 2 x produit X

Panier réel:

  • 1 x produit X
  • 1 x produit X

C'est-à-dire que les produits ne sont pas fusionnés.

Au lieu de changer de navigateur, vous pouvez également effacer le cookie de session ou choisir une quantité différente pour le produit.

Le pire effet secondaire est que la quantité maximale de commande est appliquée par article. Dans mon cas, il y avait une remise de 100% sur un produit mais vous ne pouviez le commander qu'une seule fois. Avec cette petite astuce, vous pouvez le commander gratuitement en n'importe quelle quantité.

Pourquoi cela se produit-il et comment puis-je l'empêcher?

Réponses:


18

Joli résumé du bug ci-dessus, Fabian!

Pour tous les autres utilisateurs qui rencontreront ce bogue, il existe déjà un correctif de Magento pour cela.

En tant que client Enterprise, vous pouvez demander / télécharger PATCH_SUPEE-6190_EE_1.14.2.0_v1.shpour résoudre ce problème.

Mise à jour 24.02.2016: cela a également été résolu dans le dernier correctif SUPEE-7405 v 1.1. Selon Fabian sur Twitter (voir ceci et les tweets suivants ), il est possible que ce ne soit toujours pas complètement résolu. Veuillez également le tester vous-même.

Comme pour EE 1.14.2.0, la solution est:

diff --git a/app/code/core/Mage/Sales/Model/Quote/Item.php b/app/code/core/Mage/Sales/Model/Quote/Item.php
index 3554faa..d759249 100644
--- a/app/code/core/Mage/Sales/Model/Quote/Item.php
+++ b/app/code/core/Mage/Sales/Model/Quote/Item.php
@@ -502,8 +502,8 @@ class Mage_Sales_Model_Quote_Item extends Mage_Sales_Model_Quote_Item_Abstract
                         $itemOptionValue = $_itemOptionValue;
                         $optionValue = $_optionValue;
                         // looks like it does not break bundle selection qty
-                        unset($itemOptionValue['qty'], $itemOptionValue['uenc']);
-                        unset($optionValue['qty'], $optionValue['uenc']);
+                        unset($itemOptionValue['qty'], $itemOptionValue['uenc'], $itemOptionValue['form_key']);
+                        unset($optionValue['qty'], $optionValue['uenc'], $optionValue['form_key']);
                     }
                 }

Remarque: Habituellement, je ne publierais pas de code EE ici, mais comme le problème / les fichiers sont les mêmes que dans CE et n'affectent pas une fonctionnalité EE uniquement, j'espère que c'est ok.


4
J'approuve cela.
philwinkle

5
Nous allons le laisser glisser.
benmarks

1
Faites-le glisser alors.
Marius

Cela fonctionne mieux que ma solution, ce qui a causé des problèmes avec les produits groupés. Merci d'avoir partagé!
Fabian Schmengler

1
Malheureusement, cela peut toujours être contourné si vous ajoutez le produit une fois via la liste des produits et une fois via la page de détails du produit, car le paramètre "related_products" n'est présent que dans ce dernier cas. Vous pouvez également ajouter "related_products" aux unset()appels, mais ce n'est toujours pas sûr car tout paramètre POST arbitraire est également ajouté à l'option buyRequest. Je vais ignorer complètement cette option à la place.
Fabian Schmengler

15

Il s'est avéré qu'il s'agit d'un bogue Mage_Sales_Model_Quote_Item::compare()introduit dans Magento CE 1.9.2 / EE 1.14.2. La méthode est utilisée pour comparer les articles pour décider s'ils sont le même produit et peuvent être fusionnés (lors de la connexion et lors de l'ajout de produits au panier).

Lors de la comparaison de toutes les options personnalisées, il doit ignorer les options qui ne sont pas représentatives ( _notRepresentOptions), à savoir l' option info_buyRequest .

Dans les versions précédentes de Magento, cela ressemblait à ceci:

foreach ($this->getOptions() as $option) {
    if (in_array($option->getCode(), $this->_notRepresentOptions)) {
        continue;
    }

et a fonctionné correctement. Maintenant, cela ressemble à ceci:

foreach ($this->getOptions() as $option) {
    if (in_array($option->getCode(), $this->_notRepresentOptions)
        && !$item->getProduct()->hasCustomOptions()
    ) {
        continue;
    }

et la vérification supplémentaire des hasCustomOptions()causes du bogue décrit. Pourquoi? Il semble que le chèque ait été ajouté pour toujours séparer les produits avec des options personnalisées. Je ne pense pas que cela ait du sens, du moins pas dans la manière dont il est mis en œuvre, mais il y a une raison à cela que je ne connais pas.

Cependant, $item->getProduct()->hasCustomOptions()renvoie toujours vrai pour les articles de devis!

Voici la méthode:

public function hasCustomOptions()
{
    if (count($this->_customOptions)) {
        return true;
    } else {
        return false;
    }
}

Mais $this->_customOptionscontient également l' info_buyRequestoption de l'élément de devis.

Pour une solution discrète, j'ai essayé de supprimer le info_buyRequest option de tous les produits dans un observateur sales_quote_merge_before, sans succès.

La raison en est Mage_Sales_Model_Quote_Item_Abstract::getProduct() endroit où l'option est à nouveau copiée à partir de l'élément de devis lui-même:

public function getProduct()
{
    $product = $this->_getData('product');

    [...]

    if (is_array($this->_optionsByCode)) {
        $product->setCustomOptions($this->_optionsByCode);
    }
    return $product;
}

Solution

J'ai créé une réécriture pour Mage_Sales_Model_Quote_Itemavec un remplacement pour getProduct()ne pas inclure l' info_buyRequestoption à ce stade:

public function getProduct() { $product = parent::getProduct(); $options = $product->getCustomOptions(); if (isset($options['info_buyRequest'])) { unset($options['info_buyRequest']); $product->setCustomOptions($options); } return $product; }

Cela a causé des problèmes avec les produits groupés, l'alternative ci-dessous ou le patch officiel décrit par @ AnnaVölkl est une meilleure solution

Alternative

Vous pouvez également supprimer l'infraction && !$item->getProduct()->hasCustomOptions()dans lecompare() méthode si vous réécrivez de toute façon le modèle d'élément. Je ne sais pas quel problème il a essayé de résoudre, mais il en a créé plus ...

Mise à jour du 29 janvier 2016

J'ai signalé cela à Magento et j'ai obtenu la réponse qu'ils ne pouvaient pas reproduire le problème, donc le correctif ne sera pas intégré dans l'édition communautaire (Soumission APPSEC-1321).

Cela signifie que si vous rencontrez le problème, vous devez appliquer le correctif d'entreprise SUPEE-6190 après chaque mise à jour ou utiliser une réécriture de classe à la place.


However, $item->getProduct()->hasCustomOptions() always returns true for quote items!Il vérifie les données du produit pour les options personnalisées, pas l'article de devis :)
kanevbgbe

1
@kanevbgbe étonnamment, non. Magento "prépare" l'instance de produit associée à un élément de devis et ajoute ses valeurs d'options personnalisées
Fabian Schmengler

Je sais que lors de l'action d'ajout au panier, l'instance de produit est entièrement chargée (par rapport à la charge du devis), elle est donc définie de l'extérieur des algorithmes du devis directement vers l'instance d'élément de devis via setProduct (), peut-être que cette vérification a une sortie différente .
kanevbgbe

1

Comme je peux le voir, la réponse ci-dessus est déjà disponible dans la dernière version de Magento, mais nous rencontrions toujours le problème. Cela n'a pas fonctionné car nous avons fait beaucoup de personnalisations. Pensé à partager la solution.

Pour nous, c'était très simple car nous n'utilisons que des produits simples. Nous avons donc étendu la fonction de comparaison de fusion de devis à ceci:

NS_Module_Model_Sales_Quote_Item étend Mage_Sales_Model_Quote_Item {

public function compare($item) {
    if ($this->getProductId() == $item->getProductId()) {
        return true;
    }
    return parent::compare($item);
}

}

et ajouté

<models>
   <sales>
      <rewrite>
         <quote_item>NS_Module_Model_Sales_Quote_Item</quote_item>
      </rewrite>
   </sales>
</models>

mais. pour ceux qui utilisent également des produits configurables, cela pourrait ne pas vous être utile. Dans ce cas, vous pouvez imprimer les deux tableaux: $ itemOptionValue et $ optionValue et voir la différence. annule toutes les clés supplémentaires qui ne sont pas communes aux deux tableaux. Cela devrait résoudre le problème.


-1

Vous pouvez simplement ajouter une option au produit dans l'événement sales_quote_add_item:

$data['microtime'] = microtime(true);
$product->addCustomOption('do_not_merge', serialize($data));
$item->addOption($product->getCustomOption('do_not_merge'));

Lien de référence: désactiver la fusion des positions du chariot?


C'est une solution de contournement, mais la désactivation complète de la fusion d'éléments n'est généralement pas souhaitable.
Fabian Schmengler du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.