Przejdź do treści

Magento dolicza VAT do ceny brutto mimo „ceny zawierają podatek”: stawka sklepu z adresu nadania w USA

Ceny w katalogu są brutto, opcja „ceny w katalogu zawierają podatek” jest włączona, a Magento i tak dolicza VAT na wierzchu: produkt za 123,00 zł brutto kosztuje w koszyku 151,29 zł. W standardowym Magento 2.4.8 VAT zawarty w cenie wyznacza stawka sklepu, liczona z adresu nadania w ustawieniach wysyłki, który po instalacji wskazuje Stany Zjednoczone. Opisuję, z czego to wynika, jak to rozpoznać, które trzy ustawienia trzeba rozróżnić, czym jest osobny przypadek ceny liczonej z adresu klienta i jakimi testami sprawdziliśmy wynik w opisanym sklepie.

W skrócie

Przy cenach z podatkiem i wyłączonym handlu transgranicznym Magento zakłada, że cena zawiera VAT według stawki sklepu, a nalicza VAT według stawki klienta. Stawka sklepu bierze się z adresu nadania w ustawieniach wysyłki. Jeśli dla tego adresu nie ma pasującej stawki, sklep traktuje cenę brutto jak netto i dolicza VAT klienta.

Podsumowanie przypadku: konfiguracja, objaw, przyczyna, zmiany i wynik
KonfiguracjaMagento Open Source 2.4.8, sprzedaż wyłącznie w Polsce, ceny w katalogu brutto, klienci firmowi widzą ceny netto
Objawpo włączeniu „ceny zawierają podatek” VAT dalej doliczany na wierzchu
Przyczynaadres nadania z wartościami fabrycznymi (USA), dla którego nie było stawki: stawka sklepu 0%, stawka klienta 23%
Zmianyadres nadania, domyślny adres podatkowy i handel transgraniczny zmienione razem, stawka i reguła dla Polski
Wynikstawka sklepu i klienta 23%; karta i koszyk zgodne co do grosza; koszyk z rabatem konta liczy VAT po rabacie
01

Objaw: VAT na wierzchu mimo „ceny zawierają podatek”

Punkt wyjścia w opisanym sklepie: ceny przychodziły do katalogu jako brutto, a konfiguracja podatków była fabryczna. Jedynymi stawkami były przykładowe US-CA 8,25% i US-NY 8,375%, które Magento zakłada przy instalacji.

Po dodaniu polskiej stawki 23% i włączeniu opcji „ceny w katalogu zawierają podatek” koszyk doliczał VAT do ceny, która już go zawierała. Przykład umowny: produkt za 123,00 zł brutto kosztował w koszyku 151,29 zł, czyli 123,00 zł plus 23%.

02

Przyczyna: stawka sklepu liczona z adresu nadania

Gdy ceny w katalogu zawierają podatek, Magento musi wiedzieć, jaki VAT w nich siedzi. W standardowym kodzie 2.4.8 odpowiada za to metoda getStoreRate() z klasy Magento\Tax\Model\Calculation. Liczy ona stawkę dla adresu nadania z ustawień wysyłki, czyli kraju, regionu i kodu pocztowego w „Shipping Settings → Origin”. Fabrycznie są to USA, region Kalifornia i kod 90034 (konfiguracja modułu Shipping).

Trzy ustawienia łatwo pomylić, bo wszystkie dotyczą adresów i podatków:

Adresy, które Magento bierze pod uwagę przy liczeniu podatku
UstawienieRola przy podatku
adres nadania (Shipping Settings → Origin)z niego liczy się stawka sklepu, czyli VAT zawarty w cenie katalogowej
domyślny adres podatkowy (Tax → Default Tax Destination Calculation)adres zastępczy dla stawki klienta, gdy brakuje adresu klienta, np. u gościa
adres dostawy albo rozliczeniowy klientapodstawa stawki klienta, zależnie od ustawienia „podatek liczony według”

Przy wyłączonym handlu transgranicznym cena przelicza się ze stawki sklepu na stawkę klienta. W opisanym sklepie dla adresu nadania w USA nie było żadnej pasującej stawki, więc stawka sklepu wynosiła 0%: Magento uznawało 123,00 zł za kwotę netto i doliczało 23% klienta z Polski. Dokumentacja Adobe o ustawieniach wysyłki wskazuje, że adres nadania wpływa na stawkę podatku, i zaleca, żeby w sklepach z podatkami UE domyślny adres podatkowy odpowiadał adresowi nadania. To zalecenie zgodności, a nie jedno ustawienie.

Handel transgraniczny zmienia ten mechanizm. Gdy jest włączony, Magento nie przelicza ceny ze stawki sklepu na stawkę klienta: cena brutto zostaje stała, a zawarty w niej VAT liczy się stawką klienta (dokumentacja Adobe o ustawieniach podatków opisuje oba warianty). Dlatego przy diagnozie zawsze trzeba sprawdzić, który wariant jest włączony.

03

Diagnoza: stawka sklepu, stawka klienta i to, co je łączy

Sygnałem jest różnica między stawką sklepu (getStoreRate()) a stawką dla adresu klienta (getRate()). Sama różnica 0% i 23% nie wystarcza jednak do wskazania winnego ustawienia. Przed zmianą konfiguracji sprawdź po kolei:

  • adres nadania w ustawieniach wysyłki: kraj, region i kod pocztowy
  • czy handel transgraniczny jest włączony, bo od tego zależy, jak liczona jest stawka sklepu
  • czy stawka i reguła podatkowa pasują do adresu nadania oraz do klasy podatkowej produktu i klasy klienta; stawka bez pasującej reguły daje 0% tak samo jak jej brak
  • koszyk gościa: gość nie ma rabatów ani ceny własnej, więc jeśli on też dostaje VAT na wierzchu, przyczyna leży w podatkach, a nie w module rabatów

Wyłączenie ceny własnej pozycji koszyka nie jest dobrą kontrolą, jeśli moduł rabatów ustawia ją ponownie przy każdym przeliczeniu koszyka. Koszyk gościa jest pewniejszy.

04

Ustawienia w opisanym sklepie

Sklep sprzedaje wyłącznie w Polsce, więc poniższa konfiguracja jest właściwa dla tego przypadku, a nie uniwersalną instrukcją dla każdego sklepu. Zmieniono:

  • adres nadania w ustawieniach wysyłki: Polska
  • domyślny adres podatkowy: Polska, z regionem i kodem pocztowym pasującymi do definicji stawki (stawka z kodem * pasuje do każdego kodu)
  • handel transgraniczny: włączony, czyli stała cena brutto niezależnie od stawki klienta; według dokumentacji Adobe wymaga to cen z podatkiem
  • ceny w katalogu z podatkiem, podatek liczony po rabacie
  • stawka 23% dla Polski i reguła łącząca klasę podatkową klienta z klasą produktu; sprawdzone, że każdy produkt ma klasę podatkową, a każda grupa klientów klasę klienta
  • wyświetlanie: ceny netto w katalogu, koszyku i dokumentach, rozbicie VAT tylko w podsumowaniu

Adres nadania, domyślny adres podatkowy i handel transgraniczny zmieniono w jednym kroku, więc nie mierzyliśmy, która z tych zmian sama usunęła objaw. Z kodu wynika, że przy wyłączonym handlu transgranicznym wystarczyłaby zmiana adresu nadania, a przy włączonym cena brutto zostałaby stała nawet z adresem nadania w USA, bo Magento nie przelicza jej między stawkami. Stawka klienta, a u gościa stawka z domyślnego adresu podatkowego, decyduje wtedy tylko o tym, ile VAT siedzi w tej cenie. Sklep sprzedający do kilku krajów musi te decyzje podjąć osobno, razem ze stawkami dla tych krajów.

Własne bloki cen potrafią ominąć całą tę konfigurację. W opisanym sklepie blok wyceny na karcie produktu czytał cenę produktu wprost, bez warstwy podatkowej, więc sama zmiana ustawień nic by w nim nie zmieniła. Taki blok trzeba przepiąć na przeliczenie ze stawki z panelu, nigdy z liczby 1,23 wpisanej w kod.
05

Osobny przypadek: cena netto liczona z adresu klienta

Drugi objaw miał inną przyczynę: na listingu cena netto była poprawna, a na karcie produktu u jednego klienta pod etykietą „Twoja cena netto” stała cena brutto minus rabat. Przykład umowny: przy cenie 123,00 zł brutto i rabacie 1% karta pokazywała 121,77 zł zamiast 99,00 zł.

Blok na karcie przeliczał cenę metodą Magento\Catalog\Helper\Data::getTaxPrice(), która bierze adres podatkowy z sesji klienta. To normalne działanie silnika podatkowego, a nie wada tej metody: Magento może liczyć podatek według adresu dostawy, rozliczeniowego albo nadania. Problem dotyczył konta, którego adres miał kraj spoza Unii bez żadnej stawki, więc VAT nie był zdejmowany. Listing był poprawny, bo liczył stawkę sklepu.

  • decyzja dla opisanego sklepu: sprzedaż krajowa i jedna stawka, więc ceny w katalogu przeliczane są stawką sklepu, w jednym wspólnym miejscu; sklep sprzedający za granicę potrzebuje innej zasady
  • diagnoza: gdy „u jednego klienta jest źle, u innych dobrze”, sprawdź kraje w adresach kont
  • test w konsoli tego nie odtworzy, bo bez sesji klienta nie ma jego adresu; trzeba porównać stawki dla adresów konkretnych kont albo sprawdzić stronę w sesji klienta

Taki adres dało się zapisać, bo lista dozwolonych krajów obejmowała wszystkie kraje świata. W sklepie sprzedającym tylko w Polsce warto ją zawęzić.

06

Pułapka: wartości liczone z ceny brutto i netto naraz

Gdy sklep pokazuje cenę katalogową brutto obok ceny klienta netto, psuje się każda wartość pochodna: „oszczędność”, „rabat %”, różnica cen. Odjęcie netto od brutto zawyża rabat o cały VAT.

Przykład umowny: 10 sztuk po 123,00 zł brutto, rabat 1%. Poprawnie: 1 000,00 zł netto przed rabatem, 990,00 zł netto po rabacie, oszczędność 10,00 zł, czyli 1%. Po odjęciu kwoty netto od brutto wychodzi 240,00 zł, czyli około 19,5% „rabatu”. Przed każdą różnicą albo procentem obie kwoty trzeba sprowadzić do netto.

07

Zamówienia z VAT 0,00 złożone przed zmianą konfiguracji

Po wdrożeniu łatwo uznać, że zamówienia z podatkiem 0,00 dowodzą, że poprawka nie działa. Data pozwala to rozstrzygnąć: jeśli zamówienie powstało przed zapisaniem nowej konfiguracji podatków, nie jest dowodem dalszej awarii. W opisanym sklepie wszystkie takie zamówienia były starsze niż zapis ustawień.

Data nie potwierdza jednak, że kwoty w tych zamówieniach są poprawne. Zostały policzone według starej konfiguracji i to, jak je traktować w księgowości, jest osobną decyzją sklepu.

08

Testy odbioru podatków

W opisanym sklepie konfigurację sprawdziliśmy tak:

Testy odbioru konfiguracji podatków
TestWynik
stawka sklepu i stawka dla adresu w Polsceobie 23%
karta produktu: cena netto i cena po rabacie kontanetto = brutto / 1,23; rabat od netto
koszyk z 2 szt.: netto, VAT i sumasuma = 2 × cena brutto, zgodna co do grosza
koszyk z rabatem konta 1%suma = cena brutto × 0,99, VAT 23% liczony po rabacie
klasy podatkowe produktów i grup klientówwszystkie produkty i wszystkie grupy objęte regułą

Czego te testy nie objęły: zapisanego zamówienia. Sumy zamówienia Magento kopiuje z sum koszyka, ale ostatecznym potwierdzeniem jest kontrolowane zamówienie testowe złożone po zmianie i sprawdzenie zapisanych w nim kwot netto, VAT i sumy. Osobno trzeba sprawdzić moduły, które liczą ceny poza silnikiem podatkowym Magento, np. własny obieg przedsprzedaży.

09

Kiedy poprawisz to w panelu, a kiedy potrzebny jest przegląd cen

W panelu

Sklep na standardowym wyświetlaniu cen, bez własnych bloków cen i bez rabatów per konto, sprzedający w jednym kraju. Adres nadania, domyślny adres podatkowy, decyzja o handlu transgranicznym, stawka i reguła oraz test koszyka gościa i zamówienia testowego zwykle wystarczą.

Z przeglądem cen

Sklep B2B z cenami netto dla firm, własnymi blokami cen, rabatami per konto, sprzedażą do kilku krajów albo osobnym obiegiem zamówień. Tam każde miejsce, które pokazuje cenę albo liczy z niej różnicę, trzeba przejrzeć osobno i sprawdzić na kontach z różnymi adresami.

Gdy zlecasz nam taki przegląd, dostajesz opis obecnej konfiguracji adresów i stawek, porównanie stawki sklepu i stawek kont, listę miejsc, które pokazują lub przeliczają cenę, poprawki tam, gdzie VAT liczy się inaczej niż przyjęta zasada albo ze stałej w kodzie, oraz raport z testów odbioru z zamówieniem testowym. Więcej o pracy przy sklepach na Magento i przy cenach i rabatach B2B.

FAQ: VAT i ceny brutto w Magento

W standardowym Magento 2.4.8 VAT zawarty w cenie katalogowej wyznacza stawka sklepu, liczona z adresu nadania w ustawieniach wysyłki, który fabrycznie wskazuje USA. Jeśli dla tego adresu nie ma pasującej stawki, a handel transgraniczny jest wyłączony, Magento traktuje cenę brutto jak netto i dolicza VAT według stawki klienta.
Z adresu nadania (Shipping Settings → Origin) liczy się stawka sklepu, czyli VAT zawarty w cenie katalogowej. Domyślny adres podatkowy (Default Tax Destination Calculation) to adres zastępczy dla stawki klienta, gdy brakuje adresu klienta, np. u gościa. Dokumentacja Adobe zaleca ich zgodność w sklepach z podatkami UE, ale to dwa osobne ustawienia.
Porównaj stawkę sklepu i stawkę klienta, sprawdź adres nadania, ustawienie handlu transgranicznego oraz to, czy stawka i reguła pasują do klas podatkowych produktu i klienta. Sama różnica stawek nie wskazuje jeszcze winnego ustawienia. Koszyk gościa pozwala wykluczyć rabaty i cenę własną pozycji.
Przy włączonym handlu transgranicznym Magento nie przelicza ceny między stawką sklepu a stawką klienta, więc cena brutto zostaje stała, a zawarty w niej VAT liczy się stawką klienta. Według dokumentacji Adobe wymaga to cen z podatkiem. Przy wyłączonym cena może się zmieniać zależnie od stawki klienta.
Zwykle dlatego, że cena na stronie jest przeliczana według adresu klienta, a jego konto ma kraj, dla którego nie ma stawki. Liczenie według adresu klienta jest normalnym działaniem Magento. W sklepie sprzedającym tylko w kraju można przyjąć zasadę przeliczania cen w katalogu stawką sklepu, ale sklep sprzedający za granicę potrzebuje innej.
Jeśli powstały przed zapisaniem nowej konfiguracji podatków, nie dowodzą, że poprawka nie działa. Data nie potwierdza jednak, że ich kwoty są poprawne, bo policzono je według starej konfiguracji. Działanie nowej konfiguracji najlepiej potwierdzić kontrolowanym zamówieniem testowym i sprawdzeniem zapisanych kwot.