Koszyk PrestaShop blokuje zamówienia?Optymalizacja PrestaShop
← Blog
PrestaShop

PrestaShop: „produkt nie jest dostępny” przy zamówieniu, choć wchodzi do koszyka

Produkt dodaje się do koszyka, a przy zamówieniu pojawia się komunikat o braku dostępności. Zerowy stan okazał się fałszywym tropem. Do tego mail „brak produktu” i tysiąc kombinacji na jednym produkcie.

Komunikat „Produkt nie jest dostępny” przy przejściu do zamówienia w PrestaShop, choć produkt wchodzi do koszyka bez problemu, najczęściej oznacza, że produkt ma w bazie active = 0. Walidacja koszyka sprawdza to pole dopiero przy checkoucie. Poniżej pokazujemy, jak to znaleźliśmy w sklepie z modułem gwarancji, kiedy błąd zaczął blokować zamówienia i jakie dwie dodatkowe wady wyszły przy okazji.

Dlaczego PrestaShop dodaje produkt do koszyka, ale blokuje zamówienie?

Klient wybierał gwarancję na karcie produktu i dodawał ją do koszyka. Produkt i gwarancja wchodziły, a w kroku zamówienia pojawiał się komunikat, że produkt nie jest dostępny, i nie dało się iść dalej. Objaw był mylący, bo koszyk wyglądał poprawnie.

Łańcuch w kodzie PrestaShop 1.7:

  1. Cart::getProducts() czyta product_shop.active.
  2. Cart::checkQuantities() ma jako pierwszy warunek !$product['active'] i zwraca takie produkty jako błędne.
  3. CartController::areProductsAvailable() pokazuje komunikat. Komunikat dla nieaktywnego produktu pochodzi z innej gałęzi niż komunikat o złej ilości, więc warto sprawdzić, który z nich widzisz.

Dodanie do koszyka działało, bo updateQty() pola active nie sprawdza. Walidacja jest dopiero przy przejściu do zamówienia.

Kiedy błąd zaczął blokować zamówienia?

Produkt miał active = 0 od dawna, celowo, razem z visibility = none, żeby gwarancja nie pokazywała się w katalogu, i sprzedawał się normalnie. Zamówienia stanęły dzień po poprawce w integracji z systemem sprzedaży, która dopisała brakujące powiązania kombinacji z atrybutami: ostatnia sprzedaż gwarancji była dzień przed poprawką.

Poprawka integracji była prawidłowa i to ona zmieniła zachowanie produktu w koszyku, ale blokadę powodowało wyłączone active. Przez kolejne tygodnie sprzedaż gwarancji spadła niemal do zera.

Jak odróżnić brak stanu od wyłączonego produktu?

Pierwsza hipoteza dotyczyła zerowego stanu magazynowego kombinacji i okazała się błędna. Kombinacje miały out_of_stock = 1 w ps_stock_available, czyli sprzedaż bez stanu była dozwolona, a allow_oosp zwracało prawdę. Blokowało wyłącznie pole active. Zasada: zanim zaczniesz poprawiać stany, sprawdź dane.

SELECT p.id_product, p.active AS p_active, ps.active AS shop_active, ps.visibility AS shop_visibility
FROM ps_product p
JOIN ps_product_shop ps ON ps.id_product = p.id_product AND ps.id_shop = 1
WHERE p.id_product = 123;

Wartości zmieniamy w obu tabelach, ps_product i ps_product_shop, i zostawiamy visibility = none, żeby produkt nadal nie pokazywał się w katalogu. Po zmianie czyścimy cache Smarty i cache stron.

UPDATE ps_product      SET active = 1 WHERE id_product = 123;
UPDATE ps_product_shop SET active = 1 WHERE id_product = 123 AND id_shop = 1;

Skrypt PHP uruchamiany w CLI w kontenerze kończył się u nas błędem krytycznym, więc przebieg zamówienia sprawdzamy żądaniami HTTP z sesją, tokenem i nagłówkiem Referer z karty produktu. Test: karta produktu, dodanie do koszyka, dodanie gwarancji, koszyk bez komunikatu, strona zamówienia z kodem 200 i wszystkimi krokami.

Masz ten sam problem? Koszyk wpuszcza produkt, a zamówienie go blokuje? Sprawdzimy dane i kod, zanim zaczniemy zmieniać stany. Opisz sytuację →

Dlaczego klienci dostają mail „brak produktu” przy dostępnym towarze?

Przy okazji wyszła trzecia wada, niezależna od poprzednich. Klient kupił drogi towar i dostał maila o braku produktu, choć towar był na magazynie. Podejrzenie padło na ujemny stan produktu nadrzędnego w panelu, ale to był tylko artefakt: PrestaShop odejmuje stan przy sprzedaży kombinacji, a stanu rodzica nikt nie uzupełniał.

Rzeczywisty łańcuch:

  1. Moduł tworzył kombinację gwarancji ze stanem 0.
  2. OrderDetail::checkProductStock() odejmuje zamówioną ilość, więc wychodzi −1, a przy włączonym zarządzaniu stanem oznacza to brak towaru.
  3. PaymentModule::validateOrder() ustawia status „brak towaru, nieopłacone” i wysyła mail z szablonu outofstock.

Uwaga: out_of_stock = 1 tego nie blokuje. Ta flaga decyduje tylko o możliwości sprzedaży przy zerowym stanie, a nie o warunku w checkProductStock(). To dwa różne mechanizmy i łatwo je pomylić. W 40 dni zdarzyło się to 14 razy, a poprawka to jedna linia po utworzeniu kombinacji:

StockAvailable::setQuantity((int) $product->id, (int) $idProductAttribute, 1);

Jak kombinacje tworzone przy koszyku spowalniają sklep?

Moduł tworzył nową kombinację przy każdym dodaniu gwarancji do koszyka i nie kasował jej po porzuceniu koszyka. Liczba rosła z ruchem, nie ze sprzedażą: na jednym produkcie było 1298 kombinacji. Bije to w hasAttributes() i getAttributesGroups() przy każdym renderze koszyka.

Czyszczenie robimy skryptem, który ma tryb --dry-run i kasuje tylko kombinacje, które jednocześnie:

  • nie występują w zamówieniach (743 zostały nietknięte),
  • nie leżą w koszyku młodszym niż 30 dni (próg 30 dni dał 544 kasacje, a próg „jakikolwiek koszyk” tylko 199).

Kolejność kasowania to dzieci przed rodzicem, bo PrestaShop nie ma kaskad. Po kasacji kontrolujemy brak osieroconych zamówień i śmieci w tabelach powiązanych, a skrypt uruchamia cron raz w tygodniu. Przed kasacją robimy kopię SQL.

Pułapka z panelem. Otwarcie karty takiego produktu w panelu wieszało panel i sklep na kilka minut: karta wysyłała 64 równoległe żądania z listą kombinacji, a przy sesjach w plikach PHP blokuje plik sesji na czas każdego żądania. Dopóki sesje nie trafią do Redisa, takiego produktu nie otwieramy w panelu i sprawdzamy go SQL-em.

Kiedy zlecić to specjalistom?

Gdy sklep blokuje zamówienia bez widocznej przyczyny, a poprawki stanów nic nie dają. W ASAPDevs zaczynamy od danych i kodu, a potem sprawdzamy całą ścieżkę zamówienia, w ramach optymalizacji PrestaShop i utrzymania sklepu na PrestaShop. O innych awariach tego typu piszemy w artykule o błędzie 500 po wyczyszczeniu cache.

Źródła: dokumentacja deweloperska PrestaShop (klasy Cart, Carrier, OrderDetail); kod PrestaShop 1.7.8 użyty w diagnozie.

Kamil Perzowski
Kamil Perzowski
CEO i co-founder ASAPDevs. Programuje i utrzymuje sklepy, aplikacje webowe i serwery klientów. LinkedIn · Optymalizacja PrestaShop
Masz ten sam problem?

Koszyk PrestaShop blokuje zamówienia?

Kamil Perzowski, ASAPDevs
Kamil Perzowski
CEO & Co-founder, ASAPDevs
Znajdujemy przyczynę w danych i kodzie, naprawiamy ją bez ukrywania objawu i sprawdzamy całą ścieżkę zamówienia.
★★★★★
Polecam ! Wszystko perfekcyjnie !
Mateusz W., opinia w Google
  1. Czytam zgłoszenie i odpisuję z pytaniami albo propozycją terminu rozmowy.
  2. Krótka rozmowa o zakresie, dostępach i terminie.
  3. Dostajesz plan i wycenę. Decydujesz, bez zobowiązań.

Wolisz od razu porozmawiać? +48 884 220 764 · [email protected]

Wysyłając formularz, przekazujesz nam dane, żebyśmy mogli odpowiedzieć. Szczegóły w polityce prywatności.

FAQ

Pytania i odpowiedzi

Dlaczego PrestaShop dodaje produkt do koszyka, a przy zamówieniu pisze, że nie jest dostępny?

+
Dodanie do koszyka nie sprawdza pola active produktu, a walidacja przy przejściu do zamówienia sprawdza je jako pierwszy warunek. Produkt wyłączony w bazie (active = 0) wchodzi więc do koszyka, ale blokuje checkout.

Czy zerowy stan magazynowy też tak blokuje zamówienie?

+
Tylko wtedy, gdy sprzedaż bez stanu jest zabroniona. Przy włączonej sprzedaży bez stanu (out_of_stock = 1, czyli allow_oosp) zero w magazynie nie blokuje koszyka. Walidacja sprawdza też inne pola, na przykład available_for_order, więc zanim zaczniesz poprawiać stany, sprawdź active w ps_product i ps_product_shop.

Jak ukryć produkt w katalogu, nie blokując go w koszyku?

+
Zostaw active = 1 i ustaw visibility = none. Produkt nie pokazuje się wtedy w katalogu i wyszukiwarce, ale da się go kupić jako dodatek, na przykład gwarancję.

Dlaczego mail „brak produktu” dostają klienci, którzy kupili towar dostępny na magazynie?

+
Jeśli zamówienie zawiera produkt z kombinacją o stanie 0, odejmowanie daje wartość ujemną i PrestaShop ustawia status „brak towaru”, który wysyła ten mail. Nowa kombinacja dodatku powinna powstawać ze stanem 1.

Czy wiele kombinacji jednego produktu spowalnia sklep?

+
Tak. Każdy render koszyka wywołuje funkcje ładujące atrybuty produktu, więc przy tysiącu kombinacji na jednym produkcie rośnie czas odpowiedzi. Kombinacje tworzone przy każdym dodaniu do koszyka trzeba okresowo czyścić.

Przeczytaj też