EE 1.14.2 / CE 1.9.2: Przypisywanie pozycji niepoprawnie scalonych podczas logowania (duplikaty produktów w koszyku)

16

Znalazłem dziwny błąd w Magento EE 1.14.2 (dotyczy również CE 1.9.2) z wózkiem.

Kroki ku reprodukcji:

  1. Zaloguj się jako klient A.
  2. Dodaj produkt X do koszyka
  3. Przełącz na inną przeglądarkę
  4. Dodaj produkt X do koszyka
  5. Zaloguj się jako klient A.

Oczekiwany koszyk:

  • 2 x Produkt X

Rzeczywisty koszyk:

  • 1 x Produkt X
  • 1 x Produkt X

Oznacza to, że produkty nie zostały scalone.

Zamiast przełączania przeglądarki możesz również wyczyścić sesyjny plik cookie lub wybrać inną ilość dla produktu.

Najgorszym skutkiem ubocznym jest zastosowanie maksymalnej ilości zamówienia na sztukę. W moim przypadku produkt miał 100% zniżki, ale można go było zamówić tylko raz. Dzięki tej małej sztuczce możesz zamówić ją w dowolnej ilości, za darmo.

Dlaczego tak się dzieje i jak mogę temu zapobiec?

Fabian Schmengler
źródło

Odpowiedzi:

18

Fajne podsumowanie powyższego błędu, Fabian!

Dla kolejnych użytkowników, którzy napotkają ten błąd, jest już łatka od Magento.

Jako klient Enterprise możesz poprosić / pobrać, PATCH_SUPEE-6190_EE_1.14.2.0_v1.shaby to naprawić.

Aktualizacja 24.02.2016: Rozwiązano to również w najnowszej łatce SUPEE-7405 v 1.1. Według Fabiana na Twitterze (zobacz to i następne tweety ) istnieje szansa, że ​​nadal nie został całkowicie rozwiązany. Sprawdź to także sam.

W przypadku EE 1.14.2.0 rozwiązaniem jest:

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

Uwaga: zwykle nie umieszczam tutaj kodu EE, ale ponieważ problem / pliki są takie same jak w CE i nie wpływają na funkcję EE, mam nadzieję, że jest w porządku.

Anna Völkl
źródło
4
Akceptuję to.
philwinkle,
5
Pozwolimy mu się zsunąć.
zyskuje
1
Przesuń to jest.
Marius
Działa to lepiej niż moja poprawka, która spowodowała problemy z pakietami produktów. Dzięki za udostępnienie!
Fabian Schmengler
1
Niestety nadal można to obejść, jeśli dodasz produkt raz za pomocą listy produktów i raz na stronie szczegółów produktu, ponieważ parametr „related_products” występuje tylko w tym drugim przypadku. Możesz również dodać „powiązane_produkty” do unset()wywołań, ale nadal nie jest to bezpieczne, ponieważ dowolny parametr POST jest również dodawany do opcji buyRequest. Zamiast tego całkowicie zignoruję tę opcję.
Fabian Schmengler,
15

Okazało się, że jest to błąd, Mage_Sales_Model_Quote_Item::compare()który został wprowadzony w Magento CE 1.9.2 / EE 1.14.2. Ta metoda służy do porównywania produktów w celu ustalenia, czy są one tym samym produktem i mogą zostać połączone (podczas logowania i dodawania produktów do koszyka).

Porównując wszystkie opcje niestandardowe, należy pominąć opcje, które nie są represantatywne ( _notRepresentOptions), a mianowicie opcję info_buyRequest .

W poprzednich wersjach Magento wyglądało to tak:

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

i działał poprawnie. Teraz wygląda to tak:

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

a dodatkowe sprawdzenie hasCustomOptions()powoduje opisany błąd. Dlaczego? Wygląda na to, że czek został dodany, aby zawsze przechowywać osobne produkty z niestandardowymi opcjami. Nie sądzę, żeby miało to sens, przynajmniej nie w sposobie jego implementacji, ale będzie jakiś powód, którego nie jestem świadomy.

Jednak $item->getProduct()->hasCustomOptions()zawsze zwraca true dla pozycji cytując!

To jest metoda:

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

Ale $this->_customOptionszawiera również info_buyRequestopcję z pozycji cytatu.

Aby uzyskać dyskretne rozwiązanie, próbowałem usunąć tę info_buyRequestopcję ze wszystkich produktów w obserwatorze sales_quote_merge_beforebezskutecznie.

Powodem jest Mage_Sales_Model_Quote_Item_Abstract::getProduct()to, że opcja jest kopiowana ponownie z samego cytatu:

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

    [...]

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

Rozwiązanie

Utworzyłem przepisanie Mage_Sales_Model_Quote_Itemz przesłonięciem, getProduct()aby nie uwzględniać info_buyRequestopcji w tym momencie:

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

To spowodowało problemy z pakietami produktów, alternatywą poniżej lub oficjalną łatką opisaną przez @ AnnaVölkl jest lepszym rozwiązaniem

Alternatywny

Możesz również usunąć przestępstwo && !$item->getProduct()->hasCustomOptions()w compare()metodzie, jeśli i tak przepisujesz model przedmiotu. Nie wiem, jaki problem próbował rozwiązać, ale stworzył więcej ...

Aktualizacja 29 stycznia 2016 r

Zgłosiłem to Magento i otrzymałem odpowiedź, że nie mogą odtworzyć problemu, więc łatka nie pojawi się w wydaniu społecznościowym (Submission APPSEC-1321).

Oznacza to, że jeśli masz problem, musisz zastosować poprawkę korporacyjną SUPEE-6190 po każdej aktualizacji lub zamiast tego użyć przepisania klasy.

Fabian Schmengler
źródło
However, $item->getProduct()->hasCustomOptions() always returns true for quote items!Sprawdza dane produktu pod kątem opcji niestandardowych, a nie cytat :)
kanevbgbe
1
@kanevbgbe zaskakująco nie. Magento „przygotowuje” instancję produktu powiązaną z przedmiotem oferty i dodaje niestandardowe wartości opcji
Fabian Schmengler,
Wiem, że po dodaniu do koszyka instancja produktu jest w pełni załadowana (w porównaniu z ładowaniem oferty), więc jest ustawiana spoza algorytmów oferty bezpośrednio w instancji pozycji oferty poprzez setProduct (), być może wtedy to sprawdzenie ma inne wyjście .
kanevbgbe
1

Jak widzę powyższa odpowiedź jest już dostępna w najnowszej wersji Magento, ale problem wciąż występował. Nie działało, ponieważ dokonaliśmy wielu dostosowań. Myśl o udostępnieniu rozwiązania.

Dla nas było to bardzo proste, ponieważ używamy tylko prostych produktów. Rozszerzyliśmy więc funkcję porównywania scalania cytatów o to:

NS_Module_Model_Sales_Quote_Item rozszerza Mage_Sales_Model_Quote_Item {

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

}

i dodał

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

ale. dla tych, którzy również używają produktów konfigurowalnych, może Ci to nie być pomocne. W takim przypadku możesz wydrukować obie tablice: $ itemOptionValue i $ optionValue i zobaczyć różnicę. odznacz wszystkie dodatkowe klucze, które nie są wspólne w obu tablicach. To powinno rozwiązać problem.

Arif Ahmad
źródło
-1

Możesz po prostu dodać opcję do produktu w przypadku sales_quote_add_item:

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

Odnośnik: Wyłącz scalanie pozycji koszyka?

gelanivishal
źródło
Jest to obejście, ale całkowite wyłączenie łączenia elementów zwykle nie jest pożądane.
Fabian Schmengler,