Najniższa cena przed obniżką (Omnibus)
Przepisy o informowaniu o cenach w UE (w Polsce: ustawa o informowaniu o cenach, tzw. dyrektywa Omnibus) każą przy każdej ogłaszanej obniżce pokazać najniższą cenę, po jakiej produkt był sprzedawany w ciągu 30 dni przed wprowadzeniem obniżki. Platforma liczy tę cenę z historii cen i oddaje ją w polu priceReduction — Ty tylko ją renderujesz.
Skąd biorą się dane
ProductVariant.priceReduction— na stronie produktu i w koszyku (variant).Product.priceReduction— na kartach produktów (listing, wyszukiwarka): referencja dla wariantu, którego cena tworzypriceRange.minVariantPrice, czyli tego, którego obniżkę karta ogłasza przezcompareAtPriceRange.
Oba pola są null, gdy: wariant nie jest przeceniony (brak compareAtPrice powyżej ceny), merchant nie włączył w panelu aplikacji „Omnibus", albo platforma nie potrafi udowodnić ceny referencyjnej (np. produkt był oferowany przed rozpoczęciem śledzenia historii, a obniżka zaczęła się zanim minęło 30 dni obserwacji). W każdym z tych przypadków nie pokazuj zdania o najniższej cenie — a przy null mimo przekreślonej ceny rozważ, czy w ogóle eksponować rabat.
Fragment PriceReduction jest już rozwinięty w ProductCard i ProductFull, więc useProduct i listingi z SDK niosą pole automatycznie.
fragment PriceReduction on PriceReductionInfo {
lowestPriorPrice { amount currencyCode }
reductionStartedAt
referenceWindowStartedAt
referenceWindowTruncated
percentageOffLowestPrior
label
}
| Pole | Co znaczy |
|---|---|
lowestPriorPrice | Najniższa cena z okna referencyjnego, w walucie sklepu. Pokaż ją co najmniej tak wyraźnie jak cenę bieżącą. |
lowestPriorPriceWithConversion | Opt-in: ta sama kwota przeliczona na walutę kupującego tym samym kursem co priceWithConversion. |
reductionStartedAt | Kiedy wprowadzono bieżącą obniżkę (każde pogłębienie promocji to nowa obniżka). |
referenceWindowStartedAt / referenceWindowTruncated | Początek okna; true, gdy okno jest krótsze niż 30 dni (produkt oferowany krócej) — referencja liczy się wtedy od początku oferowania. |
percentageOffLowestPrior | Rabat liczony względem najniższej ceny, nie względem przekreślonej. Zero lub mniej = nie reklamuj rabatu. |
label | Gotowe zdanie prawne w języku sklepu z wpisaną kwotą (merchant może nadać własne brzmienie w panelu). Renderuj dosłownie. |
Strona produktu
'use client';
import { useProduct } from '@doswiftly/storefront-sdk/react';
export function VariantPrice({ handle }: { handle: string }) {
const { data: product } = useProduct({ handle });
const variant = product?.variants.nodes[0];
if (!variant?.price) return null;
const reduction = variant.priceReduction;
const onSale = Boolean(variant.compareAtPrice && reduction);
return (
<div>
{onSale ? (
<>
<s>{variant.compareAtPrice!.amount} {variant.compareAtPrice!.currencyCode}</s>{' '}
<strong>{variant.price.amount} {variant.price.currencyCode}</strong>
<p>{reduction!.label}</p>
{reduction!.percentageOffLowestPrior > 0 ? (
<span>-{reduction!.percentageOffLowestPrior}%</span>
) : null}
</>
) : (
<strong>{variant.price.amount} {variant.price.currencyCode}</strong>
)}
</div>
);
}
Dwie zasady, które ten przykład egzekwuje:
- Przekreślona cena tylko razem ze zdaniem prawnym.
onSalewymaga obu pól — samocompareAtPricebezpriceReductionnie ogłasza obniżki. - Procent z backendu, nie z własnego dzielenia.
percentageOffLowestPriorliczy się względem najniższej ceny z okna; rabat „względem przekreślonej" bywa wyższy i to on jest przedmiotem kar.
Karta produktu na listingu
const reduction = product.priceReduction;
{product.compareAtPriceRange && reduction ? (
<small>{reduction.label}</small>
) : null}
Listing ogłasza obniżkę przez compareAtPriceRange, więc obowiązek informacyjny dotyczy także kart — nie tylko strony produktu.
Koszyk
Linie koszyka niosą variant, ale wspólny fragment ProductVariant nie zawiera priceReduction (koszyk nie ogłasza obniżki). Jeśli pokazujesz w koszyku przekreśloną cenę i chcesz przy niej zdania prawnego, dodaj we własnej operacji variant { priceReduction { ...PriceReduction } }.
Wielowalutowość
Kwota w label i w lowestPriorPrice jest w walucie sklepu. Sklep z przełącznikiem walut renderuje lowestPriorPriceWithConversion obok priceWithConversion — obie przeliczone tym samym kursem w tym samym momencie.
Powiązane
- Strona produktu z wariantami — cena, wybór wariantu, dodanie do koszyka.
- Koszyk z rabatami — kody rabatowe i rozbicie rabatów w koszyku.