EE 1.14.2 / CE 1.9.2: Quote degli articoli non unite correttamente all'accesso (prodotti duplicati nel carrello)


16

Ho trovato uno strano bug in Magento EE 1.14.2 (riguarda anche CE 1.9.2) con il carrello.

I passaggi per riprodurre:

  1. Accedi come cliente A
  2. Aggiungi il prodotto X al carrello
  3. Passa a un altro browser
  4. Aggiungi il prodotto X al carrello
  5. Accedi come cliente A

Carrello previsto:

  • 2 x Prodotto X

Carrello effettivo:

  • 1 x Prodotto X
  • 1 x Prodotto X

Cioè i prodotti non vengono uniti.

Invece di cambiare il browser potresti anche cancellare il cookie di sessione o scegliere una quantità diversa per il prodotto.

Il peggior effetto collaterale di ciò è che viene applicata la quantità massima dell'ordine per articolo. Nel mio caso, c'era uno sconto del 100% su un prodotto, ma puoi ordinarlo solo una volta. Con questo piccolo trucco, puoi ordinarlo in qualsiasi quantità, gratuitamente.

Perché succede e come posso prevenirlo?

Risposte:


18

Bello concludere con il bug sopra, Fabian!

Per tutti gli altri utenti che incontreranno questo errore, esiste già una patch di Magento per questo.

Come cliente Enterprise, è possibile richiedere / scaricare PATCH_SUPEE-6190_EE_1.14.2.0_v1.shper risolvere questo problema.

Aggiornamento 24.02.2016: questo problema è stato risolto anche nell'ultima patch SUPEE-7405 v 1.1. Secondo Fabian su Twitter (vedi questo e seguenti tweet ) c'è una possibilità che non sia ancora stato risolto completamente. Per favore, prova anche tu.

Per quanto riguarda EE 1.14.2.0 la soluzione è:

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: di solito non pubblicherei qui il codice EE, ma poiché il problema / i file sono gli stessi di CE e non influiscono su una funzione solo EE, spero sia ok.


4
Lo approvo.
Filwinkle,

5
Lo lasceremo scorrere.
benmarks

1
Scorri quindi.
Marius

Funziona meglio della mia correzione, che ha causato problemi con i prodotti in bundle. Grazie per la condivisione!
Fabian Schmengler,

1
Sfortunatamente questo può ancora essere aggirato se aggiungi il prodotto una volta tramite l'elenco prodotti e una volta tramite la pagina dei dettagli del prodotto, perché il parametro "related_products" è presente solo in quest'ultimo caso. Puoi anche aggiungere "related_products" alle unset()chiamate, ma non è ancora sicuro perché qualsiasi parametro POST arbitrario viene aggiunto anche all'opzione buyRequest. Invece ignorerò completamente questa opzione.
Fabian Schmengler,

15

Si è scoperto che si Mage_Sales_Model_Quote_Item::compare()trattava di un bug introdotto in Magento CE 1.9.2 / EE 1.14.2. Il metodo viene utilizzato per confrontare gli articoli per decidere se sono lo stesso prodotto e possono essere uniti (durante il login e quando si aggiungono prodotti al carrello).

Quando si confrontano tutte le opzioni personalizzate, è necessario saltare le opzioni non rappresentative ( _notRepresentOptions), ovvero l' opzione info_buyRequest .

Nelle precedenti versioni di Magento, era simile al seguente:

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

e ha funzionato correttamente. Ora sembra così:

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

e il controllo aggiuntivo per hasCustomOptions()causa l'errore descritto. Perché? Sembra che il controllo sia stato aggiunto per mantenere sempre separati i prodotti con opzioni personalizzate. Non penso che abbia senso, almeno non nel modo in cui è implementato, ma ci saranno alcuni motivi per cui non sono a conoscenza.

Tuttavia, $item->getProduct()->hasCustomOptions()restituisce sempre true per gli articoli di preventivo!

Questo è il metodo:

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

Ma $this->_customOptionscontiene anche l' info_buyRequestopzione dalla voce di preventivo.

Per una soluzione discreta, ho provato a rimuovere l' info_buyRequestopzione da tutti i prodotti in un osservatore attivo sales_quote_merge_before, senza successo.

Il motivo sta nel fatto che Mage_Sales_Model_Quote_Item_Abstract::getProduct()l'opzione viene copiata nuovamente dall'elemento preventivo stesso:

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

    [...]

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

Soluzione

Ho creato una riscrittura per Mage_Sales_Model_Quote_Itemcon una sostituzione per getProduct()non includere l' info_buyRequestopzione a questo punto:

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

Ciò ha causato problemi con i prodotti in bundle, l'alternativa di seguito o la patch ufficiale descritta da @ AnnaVölkl è una soluzione migliore

Alternativa

È inoltre possibile rimuovere l'offesa && !$item->getProduct()->hasCustomOptions()nel compare()metodo se si riscrive comunque il modello di articoli. Non so quale problema ha cercato di risolvere, ma ha creato di più ...

Aggiornamento del 29 gennaio 2016

Ho segnalato questo a Magento e ho avuto la risposta che non potevano riprodurre il problema, quindi la patch non lo avrebbe trasformato nell'edizione della comunità (Invio APPSEC-1321).

Ciò significa che, se si verifica il problema, è necessario applicare la patch aziendale SUPEE-6190 dopo ogni aggiornamento o utilizzare invece una riscrittura di classe.


However, $item->getProduct()->hasCustomOptions() always returns true for quote items!Sta controllando i dati del prodotto per le opzioni personalizzate e non per l'articolo di preventivo :)
kanevbgbe

1
@kanevbgbe sorprendentemente, no. Magento "prepara" l'istanza del prodotto associata a un articolo di preventivo e aggiunge i suoi valori di opzione personalizzati
Fabian Schmengler,

So che all'azione Aggiungi al carrello l'istanza del prodotto è completamente caricata (rispetto al carico del preventivo), quindi è impostata dall'esterno degli algoritmi del preventivo direttamente all'istanza dell'articolo del preventivo tramite setProduct (), forse questo controllo ha un output diverso .
Kanevbgbe,

1

Come vedo, la risposta sopra è già disponibile nell'ultima versione di Magento, ma il problema continuava a sussistere. Non ha funzionato perché abbiamo fatto molte personalizzazioni. Pensato di condividere la soluzione.

Per noi è stato molto semplice poiché utilizziamo solo prodotti semplici. Quindi, abbiamo esteso la funzione di confronto di fusione quote a questa:

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 aggiunse

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

ma. per coloro che utilizzano anche prodotti configurabili, potrebbe non esserti utile. In tal caso è possibile stampare entrambi gli array: $ itemOptionValue e $ optionValue e vedere la differenza. disattiva tutti i tasti aggiuntivi che non sono comuni in entrambi gli array. Questo dovrebbe risolvere il problema.


-1

Puoi semplicemente aggiungere un'opzione al prodotto nell'evento sales_quote_add_item:

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

Link di riferimento: disabilitare la fusione delle posizioni del carrello?


Questa è una soluzione alternativa, ma in genere non è consigliabile disabilitare completamente la fusione degli articoli.
Fabian Schmengler,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.