Cenniki
Daj firmom i klientom ich własne ceny - procent od ceny katalogowej plus stałe ceny produktów - a Twój sklep dalej trzyma katalog w cache.
Cennik - Gold, Silver, Dealer - daje grupie kupujących ich własne ceny. Przypisujesz go firmie albo klientowi, a cmssy wycenia z niego koszyk, checkout i zamówienia tego kupującego, po stronie serwera. Katalog, który czyta odwiedzający, się nie zmienia, więc strony produktów zostają anonimowe i cache'owalne.
Co zawiera cennik
- Procent od ceny katalogowej, od 0 do 99,99, najwyżej dwa miejsca po przecinku. Działa na każdy produkt, dla którego cennik nie ma stałej ceny, i na każdy próg ilościowy tego produktu. Jest przechowywany w punktach bazowych i liczony na liczbach całkowitych: zaokrąglenie połówkowe w górę do pełnej jednostki minor, darmowy produkt zostaje na 0, a płatny nigdy nie spada poniżej 1 jednostki minor.
- Stałe ceny dla produktów, w jednostkach minor, każda z opcjonalnymi progami ilościowymi. Produkt z wariantami dostaje stałą cenę na wariant, nigdy jedną na cały produkt. Stała cena może być wyższa od katalogowej - cena kontraktowa to też cena.
Stała cena wygrywa z procentem; gdy nie ma żadnego z nich, kupujący płaci cenę katalogową. Walutą jest zawsze waluta produktu - cennik zmienia kwoty, nie waluty. Stała cena dla produktu lub wariantu, który później usunięto, niczego nie wycenia, a cennik oznacza ją jako usuniętą, żebyś mógł ją skasować.
Kto płaci według którego cennika
Jeden cennik na kupującego, nigdy dwa naraz:
- Klient należący do firmy zawsze płaci według cennika firmy - albo cenę katalogową, gdy firma żadnego nie ma. cmssy odmawia przypisania cennika bezpośrednio takiemu klientowi: przypisz go firmie. Cennik, który klient miał przed dołączeniem do firmy, jest ignorowany, dopóki do niej należy.
- Klient bez firmy może mieć własny cennik - VIP albo pojedynczy kupiec hurtowy.
- Gość płaci cenę katalogową.
Zarządzanie cennikami
Cenniki są w Commerce → Cenniki. Utwórz cennik z nazwą i procentem, potem otwórz go i dodaj stałe ceny produktów lub wariantów. Usunięcie cennika kasuje jego stałe ceny i odpina go od wszystkich firm i klientów; zamówienia zachowują nazwę, według której je wyceniono.
Cennik przypisujesz na stronie klienta albo na rekordzie firmy w jej modelu. Uprawnienia:
models:edit- tworzenie, edycja i usuwanie cenników oraz ich stałych cen;models:viewpozwala je czytać.customers:manage- przypisanie cennika klientowi lub firmie.customers:viewwystarczy, żeby widzieć, jakie cenniki istnieją.
Synchronizacja z ERP zapisuje stałe ceny hurtowo: priceList.setEntries w admin API zapisuje do 1000 naraz, wszystko albo nic - jeden zły wiersz odrzuca całe wywołanie, a błąd wskazuje każdy zły wiersz po indeksie.
Ze Spotlight i serwera MCP
Spotlight i serwer MCP (od 0.108.0) mają te same operacje, z tymi samymi uprawnieniami: list_price_lists, get_price_list, create_price_list, update_price_list, delete_price_list, set_price_list_entry, set_price_list_entries, remove_price_list_entries, set_customer_price_list i set_company_price_list.
Ceny w sklepie headless
Cena kupującego jest osobista, więc nigdy nie trafia do zapytania o produkt - każdy odczyt katalogu stałby się zależny od członka i nie dałby się cache'ować. Zamiast tego:
- Renderuj i cache'uj katalog anonimowo. Listy i strony produktów czytają
public.model.recordsdokładnie tak jak dla niezalogowanego odwiedzającego, z cenami katalogowymi. Nigdy nie kluczuj strony w cache po członku. - Po zalogowaniu nałóż ceny kupującego. Zapytaj
account.priceso produkty na ekranie - najwyżej 100 pozycji na wywołanie - z nagłówkiemAuthorization: Bearer <accessToken>członka. Bez tokenu członka wywołanie jest odrzucane. - Nigdy nie cache'uj tej odpowiedzi dla innego odwiedzającego. Żadnego współdzielonego cache fetch, żadnego CDN. Czytaj ją w dynamicznej trasie albo server action i wstaw ceny do już wyrenderowanej strony.
query BuyerPrices($workspaceId: ID!, $items: [PriceQueryItem!]!) {
account {
prices(workspaceId: $workspaceId, items: $items) {
recordId
variantKey
currency
price
priceMax
listed
tiers { minQty price }
}
}
}Każda pozycja to { recordId, variantKey }, gdzie variantKey to ProductVariant.id z API dostawczego. Pomiń go przy produkcie z wariantami, żeby dostać zakres: price to najniższa cena, priceMax najwyższa, a tiers jest puste - cena "od" na karcie listingu. Kwoty są w jednostkach minor. listed jest true, gdy cenę ustawił cennik - pod etykietę "Twoja cena". Nieznany lub ukryty produkt jest pomijany, więc dopasowuj wiersze po recordId i variantKey, nie po pozycji.
Pod plakietkę typu "Twoje ceny: Dealer Gold" przeczytaj nazwę cennika z profilu członka. Jest null, gdy żaden cennik nie obowiązuje, a członek widzi zawsze tylko swój:
query MyPriceList($workspaceId: ID!) {
account {
profile(workspaceId: $workspaceId) {
priceList { name }
}
}
}Z @cmssy/core 19.11.0 lub nowszym zapytanie o ceny wysyła za Ciebie getBuyerPrices.
Koszyk i checkout
Koszyk jest wyceniany dla tego, kto go czyta. Przy każdym odczycie i zapisie koszyka cmssy przelicza linie wycenione według innego cennika - gość, który się zalogował, członek, który się wylogował, cennik przypisany lub odpięty. unitPrice to kwota, która zostanie pobrana; snapshot.basePrice to cena katalogowa przed cennikiem i progami ilościowymi, pod przekreśloną cenę "było". Jest null na linii dodanej, zanim istniały cenniki.
query CartPrices($workspaceId: ID!) {
cart {
get(workspaceId: $workspaceId) {
items {
id
quantity
unitPrice
currentPrice
priceMismatch
snapshot { price basePrice currency }
}
subtotal
}
}
}Zmiana procentu lub stałych cen cennika nie przelicza koszyków już wycenionych z tego cennika. Linia pokazuje nową cenę w currentPrice z priceMismatch: true, a checkout pobiera to, co jest w koszyku.
Gdy checkout odmawia
Jeśli przeliczenie zmieniło koszyk od chwili, gdy kupujący go ostatnio widział, cart.checkout odmawia, zamiast pobrać kwotę, której nikt nie pokazał. Powód jest w extensions.reason błędu GraphQL:
CART_REPRICED(kodBAD_USER_INPUT) - ceny kupującego się zmieniły. Koszyk jest już zapisany z nowymi cenami: przeczytaj go ponownie, pokaż nowe sumy, poproś kupującego o potwierdzenie i wywołajcart.checkoutjeszcze raz.CART_CURRENCY_CHANGED(kodCONFLICT) - linia byłaby teraz wyceniona w innej walucie niż koszyk; wskazuje jąextensions.itemId. Usuń tę linię i dodaj produkt ponownie.
Z @cmssy/core 19.11.0 lub nowszym checkoutErrorReason(error) zwraca każdy z tych powodów.
Kody rabatowe działają na cenę z cennika: rabat odejmuje się od sumy wyliczonej z cennika i do niej porównuje się minimalną wartość koszyka kodu.
Zamówienia
Zamówienie zamraża cennik, z którego je wyceniono. Jego nazwa jest widoczna na zamówieniu w panelu i w get_order i zostaje po zmianie nazwy lub usunięciu cennika. Na każdej pozycji zamówienia:
price- pobrana cena jednostkowa, z cennikiem i progiem ilościowym.listPrice- katalogowa cena jednostkowa przed cennikiem i progami ilościowymi. Bez cennika to cena przed progami, jak dotąd; przy cenie kontraktowej powyżej katalogowej może być niższa niżprice.
Edycja zamówienia w panelu przelicza jego linie produktowe według aktualnych wartości zamrożonego cennika, albo po cenach katalogowych, jeśli cennik usunięto. Ręczne zamówienie jest wyceniane według cennika wybranego klienta.
Następne kroki
- Commerce - koszyk, checkout i zamówienia, które wycenia cennik.
- Klienci - klienci i firmy, którym przypisujesz cennik.
- Uwierzytelnianie członków - logowanie i token dostępu, którego wymaga
account.prices.