7.0 KiB
Unit Pricing — specyfikacja rozszerzenia adsPRO
Cel: dodać do adsPRO obsługę pól unit_pricing_measure i unit_pricing_base_measure (Google Merchant Center) tak, żeby moduł 14 audytu Google Ads (analiza-produkty) mógł je zapisywać z poziomu agenta AI, analogicznie do title / google_product_category / custom_label_*.
Kontekst: Google Merchant Center wymaga unit_pricing_measure dla kategorii kosmetyki/Health & Beauty. Brak tego pola = 894/3455 SKU u klienta aruba.rzeszow.pl z warning missing_potentially_required_attribute (servability=unaffected, ale ranking ↓ i brak wyświetlania ceny per ml/g).
1. Model danych (DB)
1.1 Tabela products — nowe kolumny
ALTER TABLE products
ADD COLUMN unit_pricing_measure VARCHAR(64) NULL, -- np. "30 ml", "100 g", "1 szt"
ADD COLUMN unit_pricing_base_measure VARCHAR(64) NULL, -- np. "100 ml", "1 kg", "1 szt"
ADD COLUMN unit_pricing_changed_at DATETIME NULL;
Walidacja wartości (po stronie API i UI):
- Format:
<liczba><spacja><jednostka>— regex^\d+(\.\d+)?\s+(ml|l|g|kg|szt|cm|m)$ - Dozwolone jednostki (Google specyfikacja):
ml,l,mg,g,kg,cl,m,cm,sqm,cbm,ct(count = sztuki — Google używactlub osobnego pola; w PL przyjąćszt). unit_pricing_base_measuremusi być w tej samej jednostce comeasure(np. measure=30 ml→ base=100 ml, NIE1 l).- Standardowe wartości
base: dla ml/g →100, dla l/kg →1, dla szt →1.
1.2 Migracja
migrations/YYYY-MM-DD_add_unit_pricing.sql — patrz folder migrations/ projektu.
2. API publiczne (rozszerzenie api.php)
2.1 action=product_unit_pricing_set — zapis
Wzór: kopia product_custom_label_4_set z linii ~336 api.php.
Parametry:
api_key(string, wymagany)client_id(int, wymagany)offer_id(string, wymagany)unit_pricing_measure(string, opcjonalny — pusta wartość czyści pole)unit_pricing_base_measure(string, opcjonalny — j.w.)
Logika:
- Walidacja regex (jw.) — jeśli zła forma → 422
Invalid unit_pricing_measure format. - Walidacja zgodności jednostek (measure unit == base unit) → 422 jeśli niezgodne.
- Update
products.unit_pricing_measure+unit_pricing_base_measure+unit_pricing_changed_at = NOW(). - Wpis w
products_comments:'Zmiana unit_pricing na <m> / <b> (API)'. - HTTP 200 + JSON
{result: ok, product_id, offer_id, unit_pricing_measure, unit_pricing_base_measure}.
Przykład:
curl -X POST https://adspro.projectpro.pl/api.php \
-d action=product_unit_pricing_set \
-d api_key=YOUR_KEY \
-d client_id=3 \
-d offer_id=7792 \
-d unit_pricing_measure="30 ml" \
-d unit_pricing_base_measure="100 ml"
2.2 action=product_unit_pricing_get — odczyt
Wzór: kopia product_custom_label_4_get.
Parametry: api_key, client_id, offer_id.
Odpowiedź:
{
"result": "ok",
"product_id": 987,
"offer_id": "7792",
"unit_pricing_measure": "30 ml",
"unit_pricing_base_measure": "100 ml"
}
2.3 action=products_get_missing_unit_pricing — listing kandydatów (opcjonalne)
Cel: agent może pobrać top N produktów które wymagają unit_pricing (filtr per kategoria) — zamiast skanować per-product.
Parametry: api_key, client_id, opcjonalnie top (default 50), category_filter (np. Skin Care).
Logika: SELECT z products WHERE unit_pricing_measure IS NULL AND (kategoria w listy beauty/cosmetics) ORDER BY clicks_all_time DESC LIMIT N.
Odpowiedź: {result: ok, count: N, products: [{offer_id, default_name, custom_title, google_product_category, clicks_30, ...}]}.
3. Custom feed (zapis do GMC)
Lokalizacja: feeds/ w projekcie. Generator feedu produktowego musi dodać:
<g:unit_pricing_measure>30 ml</g:unit_pricing_measure>
<g:unit_pricing_base_measure>100 ml</g:unit_pricing_base_measure>
— tylko gdy oba pola niepuste w bazie. Pominąć tag jeśli null/empty (Google nie akceptuje pustych wartości).
4. Heurystyka AI (po stronie agenta — NIE w adsPRO)
Agent (np. set_product_unit_pricing.py w projekcie D:\google ads\scripts\actions\) wyciąga measure z tytułu produktu:
| Wzorzec w tytule | measure | base |
|---|---|---|
... 30ml lub ... 30 ml |
30 ml |
100 ml |
... 1000ml lub ... 1l |
1000 ml |
100 ml |
... 100g |
100 g |
100 g |
... 1kg |
1 kg |
1 kg |
... 10szt |
10 szt |
1 szt |
Edge cases (do flagowania jako "wątpliwości" — agent pyta usera):
- Multi-component (zestaw 3 płynów × 200ml) — brak jednoznacznej miary
- Sprzęt (fotel, taboret) — N/A jednostka
- Nieznana pojemność (np. tylko
nr 3)
5. Acceptance criteria
- Migracja DB dodaje 3 kolumny + indeks na
unit_pricing_measure IS NULL api.phpma 3 nowe endpointy (_set,_get,_get_missing— ostatni opcjonalny)- Walidacja formatu regex + jednostek (testy unit)
- Generator feedu zapisuje
<g:unit_pricing_measure>+<g:unit_pricing_base_measure>gdy oba pola wypełnione product_unit_pricing_setzapisuje wpis doproducts_commentsproduct_unit_pricing_setaktualizujeunit_pricing_changed_at- Endpoint
_get_missingfiltruje po kategorii (beauty/cosmetics) i sortuje po klikach - Skrypt
set_product_unit_pricing.pypo stronie agenta (D:\google ads\scripts\actions\) — wzorzec zset_product_custom_label.py - Skrypt
apply_unit_pricing_from_previews.py— batch zapis z tabel preview w raportach M14 (klienci/<dom>/.analysis/reports/analiza-produkty-*.md— etap 1.5)
6. Pilotaż
Klient pilotażowy: aruba.rzeszow.pl (client_id=3).
Pierwsza partia (5 SKU z preview M14 z 2026-05-05):
| product_id | unit_pricing_measure | unit_pricing_base_measure |
|---|---|---|
| 7792 | 30 ml | 100 ml |
| 305 | 10 ml | 100 ml |
| 35 | 60 ml | 100 ml |
| 281 | 100 ml | 100 ml |
| 2288 | 1000 ml | 100 ml |
Sukces pilotażu = 5/5 SKU widocznych w GMC z polami unit_pricing po 24h od pierwszego push feedu.
7. Dokumentacja publiczna
Po wdrożeniu: dopisać sekcję 4.X do docs/api-public-product-management.md (analogicznie do sekcji 4.7 product_custom_label_4_set):
- 4.X.1
product_unit_pricing_set - 4.X.2
product_unit_pricing_get - 4.X.3 (opc.)
products_get_missing_unit_pricing
8. TODO procesowe (po wdrożeniu)
- Backfill agentem AI wszystkich istniejących produktów z brakiem unit_pricing — heurystyka z sekcji 4 + flag wątpliwości na liście do user review.
- Skrypt
apply_unit_pricing_from_previews.pyw projekcie agenta — batch zapis tabel preview z M14 raportów (etap 1.5) dla wszystkich klientów. - Monitoring w
analiza-feed(M2): sprawdzanie liczby SKU bez unit_pricing — cel <5% per klient w branżach beauty/cosmetics.
9. Powiązane
- Kontekst dla agenta:
D:\google ads\.claude\commands\analiza-produkty.md— sekcja "Etap 1.5: Unit pricing (preview)". - Pierwsza preview tabela:
D:\google ads\klienci\aruba.rzeszow.pl\.analysis\reports\analiza-produkty-2026-05-05.md.