EE 1.14.2 / CE 1.9.2: itens de cotação não foram mesclados corretamente no login (produtos duplicados no carrinho)


16

Encontrei um bug estranho no Magento EE 1.14.2 (também afeta o CE 1.9.2) com o carrinho.

Passos para reproduzir:

  1. Faça login como cliente A
  2. Adicione o produto X ao carrinho
  3. Mudar para um navegador diferente
  4. Adicione o produto X ao carrinho
  5. Faça login como cliente A

Carrinho esperado:

  • 2 x Produto X

Carrinho real:

  • 1 x produto X
  • 1 x produto X

Ou seja, os produtos não são mesclados.

Em vez de mudar o navegador, você também pode limpar o cookie da sessão ou escolher uma quantidade diferente para o produto.

O pior efeito colateral disso é que a quantidade máxima de pedidos é aplicada por item. No meu caso, havia um desconto de 100% em um produto, mas você só podia comprá-lo uma vez. Com este pequeno truque, você pode fazer o pedido em qualquer quantidade, de graça.

Por que isso acontece e como posso evitá-lo?

Respostas:


18

Bom resumo do bug acima, Fabian!

Para outros usuários que encontrarem esse bug, já existe um patch do Magento para isso.

Como cliente corporativo, você pode solicitar / fazer o download PATCH_SUPEE-6190_EE_1.14.2.0_v1.shpara corrigir isso.

Atualização 24.02.2016: Isso também foi abordado no patch SUPEE-7405 v 1.1 mais recente. De acordo com Fabian no Twitter (veja isso e siga os tweets ), há uma chance de ainda não ter sido completamente resolvido. Por favor, teste você também.

Quanto ao EE 1.14.2.0, a solução é:

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']);
                     }
                 }

Nota: Normalmente, eu não publicaria o código EE aqui, mas como o problema / os arquivos são os mesmos do CE e não afetam um recurso exclusivo de EE, espero que esteja tudo bem.


4
Eu aprovo isso.
philwinkle

5
Vamos deixar passar.
benmarks

1
Deslize é então.
Marius

Isso funciona melhor do que minha correção, o que causou problemas nos produtos em pacote. Obrigado por compartilhar!
Fabian Schmengler

1
Infelizmente, isso ainda pode ser ignorado se você adicionar o produto uma vez através da lista de produtos e uma vez através da página de detalhes do produto, porque o parâmetro "related_products" está presente apenas no último caso. Você também pode adicionar "related_products" às unset()chamadas, mas ainda não é seguro porque qualquer parâmetro POST arbitrário também é adicionado à opção buyRequest. Vou ignorar essa opção completamente.
Fabian Schmengler

15

Aconteceu que este é um bug Mage_Sales_Model_Quote_Item::compare()que foi introduzido no Magento CE 1.9.2 / EE 1.14.2. O método é usado para comparar itens para decidir se eles são o mesmo produto e podem ser mesclados (durante o login e ao adicionar produtos ao carrinho).

Ao comparar todas as opções personalizadas, ele deve pular as opções que não são representativas ( _notRepresentOptions), ou seja, a opção info_buyRequest .

Nas versões anteriores do Magento, era assim:

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

e funcionou corretamente. Agora fica assim:

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

e a verificação adicional de hasCustomOptions()causas causa o erro descrito. Por quê? Parece que a verificação foi adicionada para manter sempre os produtos com opções personalizadas separadas. Não acho que faça sentido, pelo menos não da maneira como é implementada, mas haverá algumas razões para isso que não estou ciente.

No entanto, $item->getProduct()->hasCustomOptions()sempre retorna true para itens de cotação!

Este é o método:

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

Mas $this->_customOptionstambém contém a info_buyRequestopção do item de cotação.

Para uma solução discreta, tentei remover a info_buyRequestopção de todos os produtos em um observador sales_quote_merge_before, sem sucesso.

O motivo está no Mage_Sales_Model_Quote_Item_Abstract::getProduct()local em que a opção é copiada novamente do próprio item de cotação:

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

    [...]

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

Solução

Eu criei uma reescrita para Mage_Sales_Model_Quote_Itemcom uma substituição para getProduct()não incluir a info_buyRequestopção neste momento:

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

Isso causou problemas nos produtos de pacote, a alternativa abaixo ou o patch oficial, conforme descrito por @ AnnaVölkl, é uma solução melhor

Alternativo

Você também pode remover a ofensa && !$item->getProduct()->hasCustomOptions()no compare()método se estiver reescrevendo o modelo do item de qualquer maneira. Não sei qual problema ele tentou resolver, mas criou mais ...

Atualização 29 de janeiro de 2016

Eu relatei isso ao Magento e obtive a resposta de que eles não podiam reproduzir o problema, portanto o patch não chegará à edição da comunidade (Submissão APPSEC-1321).

Isso significa que, se você tiver o problema, precisará aplicar o patch corporativo SUPEE-6190 após cada atualização ou usar uma reescrita de classe.


However, $item->getProduct()->hasCustomOptions() always returns true for quote items!Ele está verificando os dados do produto para opções personalizadas não o item Citação :)
kanevbgbe

1
@kanevbgbe surpreendentemente, não. Magento "prepara" o instância do produto associado a um item Citação e adiciona seus valores de opção personalizados
Fabian Schmengler

Sei que na ação add to cart a instância do produto é totalmente carregada (em comparação com a carga da cotação), portanto é definida de fora dos algoritmos da cotação diretamente para a instância do item de cotação através de setProduct (), talvez essa verificação tenha uma saída diferente .
kanevbgbe

1

Como posso ver, a resposta acima já está disponível na versão mais recente do Magento, mas ainda estávamos recebendo o problema. Não funcionou porque fizemos muitas personalizações. Pensou em compartilhar a solução.

Para nós, era muito simples, pois usamos apenas produtos simples. Portanto, estendemos a função de comparação de mesclagem de cotação para isso:

NS_Module_Model_Sales_Quote_Item estende Mage_Sales_Model_Quote_Item {

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

}

e acrescentou

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

mas. para aqueles que também estão usando produtos configuráveis, pode não ser útil para você. Nesse caso, você pode imprimir as duas matrizes: $ itemOptionValue e $ optionValue e ver a diferença. desmarque todas as chaves adicionais que não são comuns em ambas as matrizes. Isso deve resolver o problema.


-1

Você pode apenas adicionar uma opção ao produto no evento sales_quote_add_item:

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

Link de referência: Desativar mesclagem de posições de carrinho?


Essa é uma solução alternativa, mas desabilitar completamente a mesclagem de itens geralmente não é desejável.
Fabian Schmengler
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.