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->_customOptions
também contém a info_buyRequest
opção do item de cotação.
Para uma solução discreta, tentei remover a info_buyRequest
opçã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_Item
com uma substituição para getProduct()
não incluir a info_buyRequest
opçã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.