Współczesny handel elektroniczny B2B stawia przed inżynierami oprogramowania wysokie wymagania architektoniczne. Klienci biznesowi oczekują zróżnicowanych cenników kontraktowych, minimalnych ilości zamówienia (MOQ) oraz przejrzystych rabatów zależnych od wolumenu zakupów. Równolegle wyszukiwarki internetowe i asystenci zakupowi oparci na sztucznej inteligencji wymagają ustrukturyzowanych, ustandaryzowanych danych o cenach jednostkowych i progach ilościowych. Niespójność między ceną widoczną w feedzie produktowym a wartością w koszyku prowadzi do odrzucenia produktów w Google Merchant Center.
Wdrożenie skalowalnego systemu cen schodkowych w oparciu o silnik WooCommerce wymaga porzucenia przestarzałych schematów zapisu danych w tabeli metadanych. Konieczne jest zaprojektowanie wydajnych struktur relacyjnych, optymalizacja feedów XML/NDJSON oraz implementacja semantycznego oznaczania danych zgodnie ze standardem Schema.org.
Specyfikacja Google Merchant Center dla cen hurtowych i jednostkowych
Platforma Google Merchant Center precyzyjnie definiuje zasady prezentacji cen dla produktów sprzedawanych na wagę, objętość lub w opakowaniach zbiorczych. W UE, krajach EFTA, Wielkiej Brytanii, Australii i Nowej Zelandii Google wymaga ceny jednostkowej dla produktów, przy których nakazują to lokalne przepisy, aby konsument oraz odbiorca biznesowy mieli możliwość natychmiastowego porównania opłacalności zakupu poprzez wskaźnik ceny jednostkowej (np. cena za 100 g, 1 kg, 1 litr lub 1 m²).
Podstawowe atrybuty wymagane w specyfikacji produktowej obejmują:
unit_pricing_measure: Rzeczywista miara produktu zawarta w opakowaniu handlowym (np.500ml,25kg,100ct). Wartość ta informuje algorytm o fizycznej ilości towaru w pojedynczej jednostce magazynowej.unit_pricing_base_measure: Jednostka bazowa służąca do standaryzowanego wyliczenia ceny porównawczej (np.100ml,1kg,1ct). Google automatycznie dzieli cenę brutto przez ten współczynnik, generując etykietę cenową.auto_pricing_min_price: Najniższa cena, do jakiej Google może obniżyć produkt w automatycznych rabatach i dynamicznych promocjach.loyalty_program: Atrybut grupowy dla cen członkowskich, dostawy dla członków i punktów lojalnościowych. To jedyne miejsce na ceny zależne od przystąpienia do programu; osobnego atrybutu dla progów hurtowych nie ma.
Przekazanie błędnych jednostek miary lub brak korelacji z walutą rozliczeniową skutkuje błędem krytycznym w panelu diagnostycznym Merchant Center. Jeśli sklep oferuje produkt chemii przemysłowej w kanistrze 20 litrów w cenie 400 PLN, atrybut unit_pricing_measure musi wynosić dokładnie 20l, a unit_pricing_base_measure powinien wskazywać 1l, co pozwala robotom Google na wyliczenie stawki 20 PLN za litr.
Jak przekazać ceny schodkowe B2B w feedzie Google Merchant Center
Specyfikacja danych produktowych Google nie ma żadnego atrybutu dla progów ilościowych. Każdy produkt w feedzie ma jedną wartość price, a zasady atrybutu price określają, jaka to ma być liczba. Jeśli obowiązuje minimalna ilość zamówienia, cena w feedzie jest ceną za tę minimalną ilość: Google zaznacza, żeby nie przesyłać ceny jednej sztuki, gdy klient nie może kupić jednej sztuki. W przypadku zestawu lub multipaku utworzonego przez sprzedawcę cena to suma za cały zestaw.
Zostają trzy sensowne sposoby pokazania progów wolumenowych:
- Osobne produkty dla każdego opakowania. Każdy rozmiar (wiadro, karton, paleta) staje się osobnym produktem z własnym
id, własnąpricei własnymunit_pricing_measure, a wszystkie mają wspólnyitem_group_id. Dokumentacja unit_pricing_measure pokazuje ten wzorzec na przykładzie ryżu w workach po 5, 10 i 12 funtów, każdy z miarą bazową 1 funta, dzięki czemu cena jednostkowa pokazuje kupującemu, które opakowanie wychodzi taniej za jednostkę wagi. - Atrybut
multipack. Według strony o multipack dotyczy zestawów, które sprzedawca złożył z identycznych produktów, i jest wymagany w bezpłatnych informacjach o produktach, gdy taki zestaw tworzysz. Przy opakowaniu zbiorczym zdefiniowanym przez producenta nie przesyłaszmultipack, a liczbę sztuk podajesz wunit_pricing_measure. - Tabela progów zostaje w sklepie. Rabaty powyżej minimum są zapisane w WooCommerce i widoczne na karcie produktu, a feed przekazuje cenę wejściową. Ta opcja nie mnoży indeksów i pozostaje spójna, dopóki strona docelowa pokazuje tę samą cenę wejściową.
Dla samej ceny jednostkowej oba atrybuty muszą używać tego samego typu jednostki, a unit_pricing_base_measure przyjmuje tylko określone wartości: 1, 2, 4, 8, 10 lub 100 jednostek, a także 75cl, 750ml, 50kg i 1000kg (unit_pricing_base_measure). Miara może mieć najwyżej dwa miejsca po przecinku. Dla Wielkiej Brytanii Google odczytuje jednostki imperialne jako amerykańskie, więc bezpiecznym wyborem są wartości metryczne. Jeśli produkt ma jednocześnie unit_pricing_measure i klasę efektywności energetycznej, Google pokazuje tylko klasę energetyczną.
Jakie zasady strony docelowej i kasy powodują odrzucenie produktów B2B w Merchant Center
Większość odrzuceń w B2B wynika z różnicy między feedem a tym, co widzi kupujący. Zasady atrybutu price zawierają wymagania, które zderzają się z typową konfiguracją hurtową:
- Cena w feedzie musi być zgodna z ceną na stronie docelowej i w kasie, w walucie kraju docelowego, a “cena widoczna w koszyku” jest niedozwolona.
- Każdy użytkownik w kraju docelowym musi móc kupić produkt po przesłanej cenie. Wymóg założenia konta jest dopuszczalny tylko wtedy, gdy rejestracja jest bezpłatna i prosta, co wyklucza feedy oparte na cenach widocznych wyłącznie dla zatwierdzonych kont firmowych.
- W krajach takich jak Niemcy, Francja czy Wielka Brytania cena zawiera VAT, a Google stosuje to również do ofert hurtowych. W USA i Kanadzie podatki pozostają poza ceną.
- Minimalna wartość zamówienia nie jest częścią ceny. Ustawia się ją w konfiguracji dostawy.
Ceny kontraktowe i członkowskie mają osobny kanał. Google zastrzega, że cen dla członków nie wolno przesyłać w price ani w sale_price. Trafiają do grupowego atrybutu loyalty_program z podatrybutami takimi jak program_label, tier_label, price, loyalty_points i member_price_effective_date. Program trzeba najpierw skonfigurować w Merchant Center, ceny członkowskie muszą być widoczne dla członków w sklepie, a Google pokazuje je w reklamach tylko wtedy, gdy rabat wynosi co najmniej 5% albo 5 jednostek waluty. Przykłady Google to poziomy klientów, takie jak srebrny i złoty, a nie zweryfikowane konta firmowe, więc sklep B2B musi sprawdzić, czy jego cennik hurtowy w ogóle pasuje do tego modelu.
Czasowa promocja na wybrany próg należy do atrybutu sale_price, który musi być niższy niż price. Pełna cena nadal trafia do price, strona docelowa pokazuje obie ceny, kasa tylko cenę promocyjną, a sale_price_effective_date ogranicza okres obowiązywania; bez tego atrybutu cena promocyjna obowiązuje od razu. auto_pricing_min_price to inne narzędzie: atrybut ceny minimalnej jest wymagany przy automatycznych rabatach i dynamicznych promocjach i musi mieścić się między kosztem sprzedanych towarów, jeśli go podajesz, a 95% ceny regularnej.
Aktualizacja, . Gdy cenę B2B negocjujesz przy każdym zamówieniu, tabela progów nie ma czego pokazać, bo ceny nie ma, dopóki nie przygotujesz oferty. Lepiej sprawdza się zapytanie ofertowe: produkt ukrywa cenę, a kupujący wysyła listę produktów i swoje dane kontaktowe, na które odpowiadasz ofertą. Skoro cena w feedzie musi zgadzać się z ceną na stronie produktu, takie produkty zostają poza feedem Shopping. Zapytanie zawiera dane osobowe, więc sklep musi umieć je wyeksportować i usunąć. Jednym ze sposobów jest moja wtyczka Quotlet. Na produktach objętych wyceną zamienia przycisk dodawania do koszyka na przycisk dodawania do zapytania i może ukryć cenę, a takich produktów nie da się kupić bezpośrednio. Klient zbiera produkty na listę zapytania, z wybranym wariantem zapisanym w pozycji, i wysyła krótki formularz z linkiem do polityki prywatności. Każde zapytanie trafia do ciebie mailem i zostaje zapisane jako prywatny rekord w wp-admin, a klient dostaje potwierdzenie z listą produktów. Zapytania są objęte narzędziami WordPressa do eksportu i usuwania danych osobowych: usunięcie anonimizuje dane kontaktowe i zostawia pozycje produktów. Listę i formularz wstawisz też widżetem Elementora. Płatna wersja Quotlet Pro dodaje kontrofertę: na ekranie zapytania wpisujesz wynegocjowaną cenę, datę ważności i notatkę, a klient potwierdza ofertę na osobnej stronie i opłaca zamówienie po tej cenie. Tryb zapytania można też włączyć tylko dla wybranych ról klientów, kategorii albo produktów niedostępnych w magazynie. Od wersji 1.1.0 kupujący może też zadać pytanie o konkretny produkt przyciskiem na jego stronie i dołączyć plik, na przykład rysunek techniczny albo specyfikację (PDF, obraz, Word, Excel, ZIP, do 10 MB). Pytanie zapisuje się jako zapytanie ofertowe, a załącznik pobierasz z ekranu zapytania i znika razem z nim albo po użyciu narzędzia do usuwania danych osobowych.
Dlaczego Google pokazuje przy produkcie spadek ceny, którego sklep nie ustawił
Etykieta spadku ceny nie pochodzi z feedu. Google porównuje bieżącą cenę ze średnią ceną, jaką sklep podawał w ostatnich 60 dniach, i pokazuje plakietkę tylko przy wyraźnym spadku z ceny, która wcześniej była dość stabilna (pomoc Merchant Center o adnotacjach spadku ceny). Progu procentowego Google nie podaje, a strona pomocy nie opisuje, jak tę adnotację wyłączyć. Produkty z plakietką pokazuje filtr Has price drop badge w zakładce ze wszystkimi produktami.
W B2B ten mechanizm łatwo uruchomić przypadkiem. Emina Demiri-Watson opisała w Search Engine Journal sklep, w którym Google złożył obraz promocji z trzech niezależnych sygnałów, a jednym z nich była schema AggregateOffer z tablicą priceSpecification i dwoma progami. Taki znacznik generuje typowa wtyczka cen schodkowych: najniższy próg wygląda dla robota jak nowa, niższa cena.
Co sprawdzam w sklepie WooCommerce, który dostał niechcianą plakietkę:
- Panel
Information found on your siteprzy produkcie w Merchant Center, czyli cenę i dostępność, które Google ostatnio sam pobrał ze strony, niezależnie od feedu. Różnica równa dokładnie 23% oznacza w Polsce prawie zawsze VAT doliczony po jednej stronie, a pominięty po drugiej. - Słowa “promocja”, “było” i “teraz” w HTML i w schemie, gdy żadna akcja nie trwa. Plakietka promocji z motywu i przekreślona cena regularna potrafią zostać na karcie po zakończonej wyprzedaży.
- Zdjęcia wycofanych produktów. Usunięcie produktu w WooCommerce nie kasuje załączników z biblioteki mediów, więc plik zdjęcia dalej odpowiada kodem 200 pod starym adresem, a Google może go nadal używać w reklamach. Pomaga usunięcie pliku albo odpowiedź 404 lub 410 na tym URL-u.
- Archiwum feedu. Eksport z datą w nazwie, zapisywany przy każdym audycie (na przykład w prywatnym repozytorium Git), pozwala sprawdzić, jaką cenę sklep wysyłał trzy miesiące wcześniej, zanim Google pokazał “spadek”.
Ograniczenia tabel wp_postmeta i osobna tabela progów cenowych
Domyślny model danych WordPressa opiera się na architekturze Entity-Attribute-Value (EAV), w której metadane produktów i wariantów trafiają do tabeli wp_postmeta. W przypadku prostego sklepu detalicznego rozwiązanie to jest wystarczające. Jednak w zaawansowanym środowisku B2B, gdzie pojedynczy produkt posiada 5 progów rabatowych dla 8 różnych grup kontrahentów, liczba rekordów w metadanych rośnie lawinowo.
Zapisanie 40 reguł cenowych dla jednego produktu oznacza wygenerowanie 40 wierszy w wp_postmeta. Przy katalogu liczącym 30 000 produktów i 100 000 wariantów tabela metadanych przekracza kilkadziesiąt milionów rekordów. Każde zapytanie o cenę w pętli katalogowej wymaga wielokrotnych operacji LEFT JOIN, co doprowadza do blokowania wątków bazy danych MySQL i drastycznego spadku wydajności serwera.
High-Performance Order Storage (HPOS) samo tego nie rozwiązuje. Według dokumentacji HPOS w WooCommerce przenosi ono zamówienia i adresy zamówień do czterech osobnych tabel (wc_orders, wc_order_addresses, wc_order_operational_data i wc_orders_meta), a produkty zostają w tabelach wpisów. HPOS daje natomiast wzorzec: dane o znanej strukturze dostają własną tabelę z indeksami dopasowanymi do zapytań. Dla progów cenowych oznacza to osobną tabelę z indeksami złożonymi:
-- Dedykowana tabela relacyjna dla progow cenowych b2b w woocommerce
CREATE TABLE IF NOT EXISTS wp_wc_b2b_price_tiers (
tier_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT UNSIGNED NOT NULL,
customer_group VARCHAR(32) NOT NULL DEFAULT 'all',
min_quantity INT UNSIGNED NOT NULL DEFAULT 1,
max_quantity INT UNSIGNED DEFAULT NULL,
price_cents BIGINT NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'PLN',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_product_lookup (product_id, customer_group, min_quantity),
INDEX idx_pricing_search (min_quantity, max_quantity)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;Dzięki indeksowi złożonemu (product_id, customer_group, min_quantity) wyszukanie ceny dla produktu, grupy klientów i ilości staje się jednym odczytem zakresu w indeksie zamiast łańcucha złączeń na wp_postmeta. Wyeliminowanie ciężkich złączeń z wp_postmeta odciąża pamięć podręczną InnoDB Buffer Pool i stabilizuje czasy odpowiedzi sklepu.
Szczegółowe wytyczne dotyczące projektowania wydajnych systemów e-commerce znajdziesz w moim opracowaniu dotyczącym zagadnienia, jakim są integracje woocommerce erp.
Dynamiczne generowanie feedów produktowych XML i NDJSON
Przekazywanie tysięcy produktów wraz z pełną siatką cen jednostkowych i progów ilościowych do Google Merchant Center wymaga wydajnego mechanizmu eksportu. Próba załadowania całej bazy produktów do pojedynczego obiektu PHP za pomocą standardowej funkcji get_posts() lub wc_get_products() skutkuje przekroczeniem limitu memory_limit i przerwaniem procesu.
Profesjonalna architektura feedu B2B opiera się na kursorach bazodanowych oraz generatorach strumieniowych yield, które zapisują dane partiami bezpośrednio do pliku XML na dysku lub przesyłają strumień NDJSON do pamięci masowej w chmurze:
<?php
/**
* Strumieniowy generator feedu produktowego b2b dla google merchant center
*/
declare(strict_types=1);
namespace WPPoland\B2BFeeds;
use Generator;
use wpdb;
class StreamedProductFeedGenerator
{
private wpdb $db;
public function __construct(wpdb $db)
{
$this->db = $db;
}
public function streamCatalogBatch(int $batchSize = 500): Generator
{
$offset = 0;
while (true) {
$query = $this->db->prepare(
"SELECT p.ID, p.post_title, t.min_quantity, t.price_cents, t.currency
FROM {$this->db->posts} p
INNER JOIN wp_wc_b2b_price_tiers t ON p.ID = t.product_id
WHERE p.post_type IN ('product', 'product_variation')
AND p.post_status = 'publish'
AND t.customer_group = 'wholesale_tier_1'
ORDER BY p.ID ASC
LIMIT %d OFFSET %d",
$batchSize,
$offset
);
$rows = $this->db->get_results($query, ARRAY_A);
if (empty($rows)) {
break;
}
foreach ($rows as $row) {
yield $this->formatGoogleXmlNode($row);
}
$offset += $batchSize;
}
}
private function formatGoogleXmlNode(array $product): string
{
$price = number_format($product['price_cents'] / 100, 2, '.', '');
return sprintf(
"<item>\n <g:id>%d</g:id>\n <g:title><![CDATA[%s]]></g:title>\n <g:price>%s %s</g:price>\n <g:min_handling_time>1</g:min_handling_time>\n</item>\n",
$product['ID'],
htmlspecialchars($product['post_title'], ENT_QUOTES, 'UTF-8'),
$price,
$product['currency']
);
}
}Ponieważ w pamięci jest naraz tylko jedna partia 500 wierszy, zużycie pamięci zależy od wielkości partii, a nie od wielkości katalogu. Cykliczne uruchamianie zadania w tle za pośrednictwem kolejki WP-CLI lub systemowego crona eliminuje ryzyko spowolnienia interfejsu sklepu podczas generowania raportów dla wyszukiwarek.
W celu zabezpieczenia punktów końcowych API i ochrony plików eksportowych przed nieautoryzowanym pobraniem zalecam przeprowadzenie procedury takiej jak audyt bezpieczeństwa wordpress.
Modelowanie danych schema.org z PriceSpecification i unitCode
Prawidłowe oznaczenie semantyczne cen jednostkowych i progów ilościowych w kodzie HTML strony produktu ma kluczowe znaczenie dla widoczności w wynikach wyszukiwania oraz w systemach sztucznej inteligencji. Schema.org opisuje ceny jednostkowe typem UnitPriceSpecification zagnieżdżonym w ofercie.
Struktura danych powinna zawierać dokładne odwołania do międzynarodowych kodów jednostek miar UN/CEFACT (np. KGM dla kilogramów, LTR dla litrów, MTK dla metrów kwadratowych, C62 dla sztuk):
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Klej konstrukcyjny poliuretanowy, wiadro 5 kg",
"sku": "ADH-IND-500",
"offers": {
"@type": "Offer",
"price": "975.00",
"priceCurrency": "PLN",
"availability": "https://schema.org/InStock",
"priceSpecification": {
"@type": "UnitPriceSpecification",
"price": "975.00",
"priceCurrency": "PLN",
"referenceQuantity": {
"@type": "QuantitativeValue",
"value": 5,
"unitCode": "KGM",
"valueReference": {
"@type": "QuantitativeValue",
"value": 1,
"unitCode": "KGM"
}
}
}
}
}Dokumentacja Google o informacjach o produktach sprzedawcy zawęża to, na co pozwala Schema.org. Informacje o produktach sprzedawcy wymagają Offer, bo sprzedawca musi być tym, kto sprzedaje; AggregateOffer jest akceptowany tylko we fragmentach produktu. Cena jednostkowa trafia do priceSpecification jako UnitPriceSpecification, gdzie referenceQuantity to ilość sprzedawana za daną cenę, a valueReference to ilość bazowa, czyli odpowiedniki unit_pricing_measure i unit_pricing_base_measure w danych strukturalnych. W przykładzie wiadro zawiera 5 kg, więc cena 975 PLN odpowiada 195 PLN za kilogram. Jedyny priceType, który Google obsługuje, to StrikethroughPrice, ceny członkowskie używają validForMemberTier razem z ceną regularną, a specyfikacja łącząca oba elementy jest ignorowana. Dokumentacja nie wspomina o eligibleQuantity, więc nie należy oczekiwać, że progi powyżej ceny wejściowej pojawią się w wynikach Google; znaczniki przekazują cenę wejściową, tę samą co feed.
Serwerowe buforowanie stron produktowych z uwierzytelnionymi tierami cenowymi
Klasyczne buforowanie całych stron HTML (Full Page Caching w Nginx lub Redis) staje się wyzwaniem w sklepach B2B, gdzie każdy zalogowany kontrahent może posiadać indywidualne warunki handlowe. Wyłączenie buforowania dla zalogowanych użytkowników drastycznie zwiększa obciążenie procesora serwera i wydłuża czas renderowania strony do kilku sekund.
Efektywna architektura serwowania treści opiera się na technologii hybrydowej:
- Buforowanie bazowego szablonu produktu: Treść statyczna, opisy, karty techniczne i zdjęcia są buforowane na poziomie CDN lub serwera proxy Nginx.
- Dynamiczne wstrzykiwanie cennika (Edge Side Includes lub mikro-interfejs REST): Po załadowaniu struktury strony przeglądarka pobiera spersonalizowaną siatkę cenową kontrahenta za pośrednictwem lekkiego zapytania JSON.
- Klonowanie kontenerów cennikowych: Skrypt po stronie klienta natychmiast aktualizuje wyświetlane wartości i przelicza sumy koszyka bez konieczności przeładowania widoku.
W sklepach o zaawansowanej architekturze doskonałe rezultaty przynosi rozdzielenie warstw za pomocą nowoczesnych frameworków. Zobacz, jak realizuję takie projekty w obszarze headless wordpress.
Audyt techniczny feedu i synchronizacja zapasów z systemem ERP
Spójność cenowa między sklepem a Google Merchant Center jest bezpośrednio uzależniona od częstotliwości synchronizacji danych z systemem ERP (np. SAP, Comarch ERP Optima, Subiekt GT). Zmiana ceny bazowej surowca w centralnej bazie musi zostać natychmiast odzwierciedlona w sklepie internetowym oraz w plikach wymiany danych z wyszukiwarkami.
Integracja powinna działać w oparciu o kolejki zadań Action Scheduler oraz asynchroniczne webhooki. Każda zmiana ceny wywołuje zdarzenie aktualizujące wpis w tabeli wp_wc_b2b_price_tiers, a następnie wysyła żądanie do Google Merchant API w celu natychmiastowego zaktualizowania rekordu bez oczekiwania na dobowe przetworzenie pełnego feedu XML.
Zastosowanie dwukierunkowej synchronizacji z buforem transakcyjnym chroni bazę danych przed konfliktami zapisu w godzinach szczytowego ruchu zamówień hurtowych. Wszelkie rozbieżności między systemem magazynowym a stanem w WooCommerce są natychmiast rejestrowane w dzienniku zdarzeń z automatycznym powiadomieniem personelu operacyjnego.
Co mapuje Google for WooCommerce, a co wymaga własnego feedu
Oficjalne rozszerzenie Google for WooCommerce obsługuje część tej konfiguracji. Jego mapowanie atrybutów obejmuje 15 atrybutów Google, w tym Multipack, Is Bundle, GTIN, MPN i Brand. Reguła może dotyczyć wszystkich kategorii, wszystkich poza wybranymi albo jednej kategorii. Reguły uzupełniają tylko puste atrybuty, a wartości ustawione w zakładce Google konkretnego produktu mają pierwszeństwo. Reguły czytają wyłącznie atrybuty globalne, więc atrybuty utworzone na karcie pojedynczego produktu trzeba najpierw zamienić na globalne.
Miary ceny jednostkowej nie ma na tej liście. Sklep sprzedający na wagę, objętość lub powierzchnię potrzebuje więc wartości ustawianych per produkt albo własnej integracji, feedem lub przez API, dla unit_pricing_measure i unit_pricing_base_measure. To samo dotyczy osobnych produktów dla opakowań generowanych z własnej tabeli progów, o której rozszerzenie nic nie wie.
Warstwa transportowa zmieniła się w 2026 roku. Google podaje, że Content API for Shopping zostało wyłączone 18 sierpnia 2026, od 1 września 2026 żądania stopniowo zaczynają zwracać błędy, a następcą jest Merchant API. Google for WooCommerce przeszło na nie w wersji 3.8.1. Własna integracja zapisuje produkty przez zasoby ProductInput metodami insert, patch i delete, odczytuje przetworzone zasoby Product i może zapisywać wyłącznie do źródeł danych typu API, jak opisuje przewodnik po produktach w Merchant API.
Automatyczne testy i weryfikacja reguł naliczania cen
W B2B błędy w naliczaniu cen schodkowych mają skutki finansowe i prawne. Reklamowanie w Google Shopping cen innych niż te, które trafiają na fakturę, łamie opisane wyżej zasady zgodności cen i może skończyć się odrzuceniem produktów albo zawieszeniem konta.
Weryfikacja techniczna wymaga uruchamiania testów automatycznych przy każdym wdrożeniu:
<?php
/**
* Testy integracyjne cen schodkowych i miar jednostkowych B2B
*/
declare(strict_types=1);
namespace WPPoland\Tests\PricingPL;
use PHPUnit\Framework\TestCase;
class TieredPricingCalculationTest extends TestCase
{
public function testProgIlosciowyJestStosowany(): void
{
$kalkulator = new \WPPoland\Pricing\TieredPriceCalculator();
// Produkt z ceną bazową 195 PLN i progiem 145 PLN od 10 sztuk
$cenaPojedyncza = $kalkulator->resolveEffectivePrice(
productId: 5120,
quantity: 3,
customerGroup: 'wholesale_tier_1'
);
$this->assertEquals(19500, $cenaPojedyncza, 'Ilości poniżej progu muszą mieć cenę regularną.');
$cenaProgowa = $kalkulator->resolveEffectivePrice(
productId: 5120,
quantity: 14,
customerGroup: 'wholesale_tier_1'
);
$this->assertEquals(14500, $cenaProgowa, 'Ilości od 10 sztuk muszą mieć cenę progową.');
}
public function testWalidacjaAtrybutowMiary(): void
{
$walidator = new \WPPoland\B2BFeedsPL\FeedAttributeValidator();
$poprawna = $walidator->validateUnitPricingAttributes(
measure: '25kg',
baseMeasure: '1kg'
);
$this->assertTrue($poprawna, 'Jednostki z listy obsługiwanej przez Google muszą przejść walidację.');
$niepoprawna = $walidator->validateUnitPricingAttributes(
measure: '25worków',
baseMeasure: 'kontener'
);
$this->assertFalse($niepoprawna, 'Dowolne etykiety spoza listy muszą zostać odrzucone.');
}
}Taki zestaw testów wyłapuje błędy zaokrągleń walut i rozbieżności podatkowe, zanim dane trafią do sieci reklamowych.
Aktualizacja, . Testy samego kalkulatora nie obejmują miejsc, w których sklepy najczęściej pokazują cenę, jakiej koszyk nie naliczy: tabeli progów na stronie produktu i ceny przy opcji produktu. Obie muszą iść za sposobem wyświetlania podatku w sklepie. Tak działa ten mechanizm: przy cenach wpisywanych bez podatku i wyświetlanych z podatkiem etykieta opcji pokazująca kwotę netto 10,00 rozminie się z koszykiem, który przy 23% VAT doda 12,30. Przy produkcie w promocji tabela ma pokazywać cenę promocyjną, którą nalicza koszyk. Jeśli warianty jednego produktu liczą się razem do progu, tabela musi używać tej samej liczby, a przy produkcie z wariantami pokazywać zakres cen. Moja wtyczka Tiers tak działa: tabela idzie za wyświetlaniem podatku, warianty liczą się razem (3 czerwone i 3 niebieskie osiągają próg 5+), siatki sklepu pokazują podpowiedź “Od X w hurcie”, a tabela podświetla wiersz dla ilości z pola i podaje wartość pozycji. Moja wtyczka do opcji produktu Aldono pokazuje ceny opcji tak, jak sklep wyświetla ceny, z sumą liczoną na bieżąco. Przetestuj to przy cenach “z podatkiem”, na produkcie w promocji i z koszykiem mieszanych wariantów, a każdą liczbę porównaj z wierszem koszyka.
Checklista wdrożeniowa przed publikacją w Google Shopping B2B
Przed uruchomieniem kampanii reklamowych i zgłoszeniem asortymentu hurtowego do Google Merchant Center należy zweryfikować kluczowe elementy infrastruktury technicznej:
- Walidacja jednostek miar: Upewnij się, że atrybuty
unit_pricing_measureorazunit_pricing_base_measureużywają wyłącznie jednostek z listy obsługiwanej przez Google i dozwolonej wartości bazowej. - Zgodność cen w koszyku: Sprawdź, czy po dodaniu do koszyka ilości odpowiadającej drugiemu progowi rabatowemu cena jednostkowa dokładnie odpowiada kwocie zadeklarowanej w ofercie.
- Weryfikacja unikalnych identyfikatorów GTIN: Każdy wariant produktu oraz opakowanie zbiorcze musi posiadać unikalny kod kreskowy EAN/GTIN przypisany przez organizację GS1.
- Testowanie obciążeniowe bazy danych: Wykonaj symulację zapytań SQL dla 1 000 jednoczesnych użytkowników przeglądających katalog produktów z cenami schodkowymi.
- Poprawność schematów JSON-LD: Zweryfikuj kod strony za pomocą oficjalnego narzędzia wyniki rozszerzone Test pod kątem braku konfliktów w zagnieżdżeniach
priceSpecification. - Strumieniowanie feedów XML: Upewnij się, że proces generowania plików wymiany danych utrzymuje stałe szczytowe zużycie pamięci PHP niezależnie od wzrostu katalogu.
- Automatyczne powiadomienia o błędach: Skonfiguruj monitoring logów powiadamiający zespół administratorów o odrzuceniu produktów zgłaszanym w diagnostyce Merchant Center lub przez Merchant API.
- Bezpieczeństwo i szyfrowanie: Zweryfikuj poprawność certyfikatów SSL oraz brak luk w interfejsach REST API obsługujących cenniki.
- Polityka zwrotów i warunków dostawy B2B: Skonfiguruj w panelu Merchant Center dedykowane reguły logistyczne uwzględniające przesyłki paletowe i minimalne wartości koszyka.
- Wyłącznik awaryjny (kill switch): Wdróż mechanizm, który pokaże domyślne statyczne ceny, gdy połączenie z ERP chwilowo przestanie działać.
Optymalizacja procesów sprzedażowych w sektorze B2B wymaga precyzyjnego połączenia inżynierii danych i standardów wyszukiwarek. Jeśli planujesz rozbudowę infrastruktury handlowej lub optymalizację feedów produktowych, napisz do mnie.







