Skip to content

Cenotvorba

Stav k 2026-06-21.

Cenotvorba je napříč importy — finální cena produktu závisí na tom, odkud produkt pochází a zda je zároveň v nabídce více dodavatelů.


Cenotvorba EUR — jak to nyní funguje

Všechny ceny jsou v DB uloženy výhradně v CZK. EUR neexistuje jako samostatná cena.

Kdy se zobrazuje EUR

Měna se určuje při každém requestu: - LANG != 'cs' (SK, DE, PL, HU, EN) → EUR - zákazník změní zemi doručení na jinou než CZ → EUR (přes checkChangeCountry()) - jinak → CZK (nebo dle konfigurace)

Měna je uložena v $_SESSION['eshop']['currency'].

Zobrazení EUR ceny — runtime konverze

Funkce price($value) v function.eshop.php převádí CZK na EUR při každém vykreslení ceny:

EUR = CZK × (1 / KURZ_EURO)

KURZ_EURO = SETTING['kurz_euro'] ?: 25 — zadáváno ručně v administraci.

Kurz je záměrně nastaven nižší než tržní — pojistka marže. Fallback: novější skripty 25, starší 27.

EUR v košíku — roundtrip zaokrouhlení

V košíku se EUR nezpracovává přímo. Při EUR měně se provede roundtrip, aby CZK cena uložená v cena_kus odpovídala "hezké" EUR ceně bez ošklivých haléřů:

bezDPH_EUR = round(bezDPH_CZK / KURZ_EURO, 2)   ← zaokrouhlí na 2 des. místa v EUR
cena_kus   = bezDPH_EUR × KURZ_EURO              ← vrátí zpět do CZK

Košík tedy ukládá CZK hodnotu, která po vydělení kurzem dá přesně 2 desetinná místa EUR.

Objednávky v EUR

Objednávka ukládá mena (CZK/EUR) a kurz (hodnota KURZ_EURO v době nákupu). EUR objednávky nezaokrouhlují celkovou částku (zaokrouhleni = 0), CZK objednávky zaokrouhlují na celé koruny.

SK ceny — jiná DPH sazba

SK mutace používá EUR, ale s slovenskou DPH sazbou. Funkce skCenaDPH($cena, $dph) přepočítá CZ cenu (s CZ DPH) na SK cenu (s SK DPH):

SK cena = (CZ cena / (1 + CZ_DPH/100)) × (1 + SK_DPH/100)

SK DPH sazba je napevno v kódu.

Migrace EUR

Co Sylius vyřeší

Každý Channel má vlastní cenu v dané měně — žádné runtime konverze, žádný roundtrip, žádný ruční kurz. EUR cena bude samostatné pole zadané přímo.

Co je nutno rozhodnout

EUR ceny při migraci — dopočítat kurzem z CZK, nebo zadat ručně?

  • Dopočítání kurzem — rychlé, ale kurz se mění a ceny nemusí být "hezké" (3,47 € místo 3,50 €)
  • Ruční zadání — přesné, ale 150 000 produktů × počet EUR Channelů

Pravděpodobné řešení: dopočítat kurzem jako výchozí stav, pak ruční korekce u klíčových produktů.


Kurz EUR — správa


Cenová pole v eshop_produkty

Pole Popis
cena_a prodejní cena zákazníka (s rabátem)
cena_b MOC — doporučená maloobchodní cena
cena_c MOC (shodné s cena_b, historický pozůstatek)
cena_nakup nákupní cena / VOC (velkoobchod)
cena_eshop finální zobrazovaná cena — výsledek MariaDB funkce cena_eshop(), není uložena jako sloupec, počítá se z cena_a/b, akce_procent, vyprodej_procent

Marže

Marže je klíčová pro SEO (zbožové srovnávače), sledování prodejů a rozhodování co zobrazovat v e-shopu. Produkty s příliš nízkou marží se skrývají nebo nevystavují.

Kdy je marže přesně známá — pokud dodavatel poskytne obě ceny (VOC i MOC):

marže = (MOC - VOC) / MOC × 100

Příklad: Astra počítá marži z CSV ceníku a označí nizka_marze = 1 pro produkty pod 18 %.

Kdy je marže pouze odhadnutá — pokud je k dispozici jen jedna cena (např. z Pohody bez dodavatelského ceníku), marže se přímo nepočítá. Lze ji zpětně odvodit z cena_nakup a cena_a, ale není explicitně uložena na staging úrovni.


Cenová priorita (waterfall)

Při Pohoda importu se cena produktu v import_produkty může projít postupnými přepsáními, než se zapíše do eshop_produkty. Pořadí:

  1. Pohoda nastaví základní sellingprice a price.
  2. ceny-pouze-ze-zlatnicke.php (jen CZ) — sjednotí ceny na hodnoty ze skladu SZLAT/KOM. Eliminuje cenové rozdíly, pokud je tentýž produkt ve více skladech.
  3. produkty-bez-5procent.php — pro výrobce bez slevy nastaví price = sellingprice (prodej za MOC). Viz Výrobci bez slev.
  4. srovnat-ceny-od-dodavatelu.php — pro produkty zároveň v Pohodě i v dodavatelské staging tabulce přepíše cenu z dodavatele. Zpracovává: Astra, Pelikán, Hacker, Corfix, Modelimex.
  5. nizke-marze-od-dodavatelu.php — označí nizka_marze = 1 dle Astry a Pelikána.
  6. Základní import — zapíše price jako cena_a, sellingprice jako cena_b/cena_c.

Dodavatelské slevy (aktuální stav)

Dodavatel Koeficient Poznámka
Astra 1.0 (0 %) dříve různé hodnoty, naposledy změna 12/2024
Pelikán 1.0 (0 %) CZ i SK
Hacker 1.0 (0 %)
Corfix — Zvezda 0.9 (−10 %)
Corfix — Airfix 0.86 (−14 %)
Modelimex výsledek roundPeckamodel() bez koeficientu

Koeficienty jsou hardcoded v srovnat-ceny-od-dodavatelu.php.


InStock logika — vlastní zásoba má přednost

Corfix a Modelimex nepřepisují cenu z Pohody, pokud je produkt skladem přímo u Pecky (SZLAT + KOM). Dodavatelská cena se aplikuje pouze na zboží, které Pecka fyzicky nemá.

Týká se značek: Zvezda, Airfix (Corfix) a ICM, MINIART, ARMA HOBBY, RODEN, DORA WINGS, MODELSVIT, IBG MODELS (Modelimex).


Nízká marže — co se se skrýváním děje

Produkty označené nizka_marze = 1 se při plném importu schovají (zobrazovat = 0, vyrazeny = 1), ale jen pokud nejsou na skladě. Pokud produkt fyzicky leží ve skladu, zobrazí se i s nízkou marží — nelze ho schovat, dokud se neprodá.


Výrobci bez slev

Funkce manufacturersWithoutSales() v lib/eshop/function.eshop.php vrací natvrdo zakódovaný seznam aliasů výrobců, jejichž produkty se prodávají za plnou MOC — bez jakéhokoli rabátu.

Používají ji importy Pelikán, Astra i Pohoda import (produkty-bez-5procent.php).

Aktuální seznam

yuneec, dji, foxtoys, staufenbiel, jeti, bungi-bungi, dino-bikes, tamiya, eduard

Výjimka pro slevové akce

Funkce přijímá parametr $discountEvent. Při true se seznam zkrátí — tito výrobci mohou participovat v slevových akcích:

tamiya, foxtoys, eduard  ← při akci mohou mít slevu

Zbývají jen: yuneec, dji, staufenbiel, jeti, bungi-bungi, dino-bikes

Mrtvý kód

V bloku $discountEvent = true existují dvě přiřazení $manufacturers za sebou — druhé přepíše první. První řádek (s gens-ace, acepow-electronics-co-ltd) se nikdy nepoužije.


cena_eshop — MariaDB funkce, ne sloupec

cena_eshop není uložené pole — je to MariaDB funkce volaná v SELECT dotazech. Vstupní parametry:

Parametr Zdroj
cena_a základní prodejní cena (s rabátem)
cena_b MOC
akce_id id aktivní akce na produktu (0 = žádná)
akce_procent % slevy z akce
vyprodej příznak výprodeje
vyprodej_procent % slevy výprodeje

Prioritní logika:

akce + vyprodej → vezme vyšší slevu z obou
jen akce        → ROUND(cena_b * (100 - akce_procent) / 100)
jen vyprodej    → ROUND(cena_b * (100 - vyprodej_procent) / 100)
nic             → cena_a

cena_eshop je tedy vždy výsledek výpočtu v runtime — není nikde cachovaná ani uložená v DB.


Akce a slevy

Viz samostatnou stránku Akce a slevy.


Migrace

Co si pohlídat

  • Cenový waterfall musí být v novém systému explicitní a konfigurovatelný — aktuálně je logika rozházená napříč 4 PHP soubory v cron/pohoda-import/.
  • Koeficienty slev jsou hardcoded — v Syliusu by měly být per-dodavatel nebo per-značka v administraci.
  • InStock logika — priorita vlastní zásoby před dodavatelskou cenou musí být zachována, jinak se produkty budou prodávat za nesprávné ceny.
  • Marže a skrývání — logika "skryj pokud nizka_marze AND není na skladě" musí mít ekvivalent; jinak se buď zobrazí ztrátové produkty nebo zmizí i to, co je fyzicky ve skladu.
  • Seznam výrobců bez slev je hardcoded v PHP — v Syliusu by mělo jít nastavit per výrobce.