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í:
- Pohoda nastaví základní
sellingpriceaprice. 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.produkty-bez-5procent.php— pro výrobce bez slevy nastavíprice = sellingprice(prodej za MOC). Viz Výrobci bez slev.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.nizke-marze-od-dodavatelu.php— označínizka_marze = 1dle Astry a Pelikána.- Základní import — zapíše
pricejakocena_a,sellingpricejakocena_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.