Cenové hladiny, aneb „kam s nima“
- tatyalien
- Člen | 239
Dobrý den,
vytvářím si eshopík v nette a mám dotaz, jak byste řešili cenové
hladiny. Shopík už mě funguje, ceny pro uživatele se mě načtou z tabulky
zboží, momentálně bez cenových hladin. Teď bych je tam chtěl nějak
dostat. Zatím jsem přišel na 2 možnosti:
- V basePresenteru bych si ve startup vytáhl, pokud je uživatel přihlášený, jeho cenové hladiny a připravil si pro něj registerHelper, kde bych ze šablony volal tento helper a změnil cenu. (náročnost: udělat toto jen v basepresenteru a v šablonách volat tento helper, při ukládání objednávky jen natáhnout správnou cenu za zboží).
- Upravit všechny dotazy, kde se renderuje zboží, přehled, košík tak, aby se načetly už ceny dle jeho cenové hladiny (náročnost: oprava všech dotazů do DB se zohledněním přihlášeného uživatele a jeho cenové hladiny.)
Nebo je ještě nějaká jiná možnost?
Tento shopík mám pouze jako učící pomůcku, tak to prosím tak
berte ;)
- petr.pavel
- Člen | 535
Přikláněl bych se k nějaké podobě (a), tj. mít třídu, která má na starosti stanovení ceny. Řešil bych tedy na úrovni PHP a ne databáze. Teď sice můžeš mít situaci, kdy by to čistě přes db vyřešit šlo, ale radši bych si nechal volnější cestu do budoucna a řešil v PHP.
- tatyalien
- Člen | 239
No třídu na stanovení ceny, abych pravdu řekl, ani nevím jak bych si jí představil, ani kde bych jí přesně volal. V presenteru načtu zboží co se má zobrazit a v renderu ho vykresluji… tak jestli pak v render metodě volat tuto třídu, nebo v šabloně? (do třídy by se předalo například katalogové číslo a id zákazníka, pokud se jedná o nepřihlášeného, vrátila by se základní cena, pokud je přihlášenej, už by se rozhodovalo. To si představit umím, ale kde to přesně volat?)
- petr.pavel
- Člen | 535
Možná mám špatnou představu o tom, co myslíš pod pojmem cenová
hladina. Předpokládám, že některý zákazník má 5% slevu na všechno,
jiný 10% na spotřební materiál, ale na zbytek jen 5%, nebo slevu 15%, ale
jen do konce roku, prostě cokoliv, co je prodejní oddělení schopno vymyslet
:-)
Takže třída CenaVyrobku by měla metodu spocitej(), které bys předával
všechno, co potřebuje. Jestli si navíc uděláš helper, proč ne. Určitě
ale budeš někdy potřebovat získat cenu už v presenteru, takže bych logiku
nedával jen do helperu.
- h4kuna
- Backer | 740
Jen navazuji na to co psal petr.pavel
petr.pavel napsal(a):
Předpokládám, že některý zákazník má 5% slevu na všechno, jiný 10% na spotřební materiál, ale na zbytek jen 5%, nebo slevu 15%
V tomto doplňku je 4. parametr procentní upravení ceny viz ukázka
{!$money|currency:eur:usd:1.1}
a aby se ti nepřepočítávalo tak zachovej výchozí parametry metody format.
{!$money|currency:NULL:NULL:1.1} není potřeba přepočítávat
Přidaná hodnota je že ti to vyřeší formátování měny, oproti helperu number který je v nette má výhodu že si to globálně nastavíš pro celý web a nemusíš pokaždé znovu nastavovat viz ukázka .
Ale já bych to řešil na úrovni databáze a využil jen formátování čísla.
Editoval h4kuna (1. 8. 2012 10:47)
- tatyalien
- Člen | 239
petr.pavel:
Ano máš pravdu, prostě jakékoliv přepočítání základní ceny dle
parametrů. Nejspíš bych dodal metodu do ShopModel kde si beru hodnoty z dtb
na výpis zboží. Jen nevím jak bych měl postupovat. V presenteru si
vytáhnu zboží například:
$this->zbozi = $this->modelShop->getGoods()->select('*')->where('skryteZbozi',0)->order('katalog')->limit($paginator->itemsPerPage, $paginator->offset);
Nyní mám v $this->zbozi například 10 produktů se základní cenou,
toto můžu narvat do template a v template vykreslit.
Měl bych tedy nyní přenastavit v $this->zbozi například
foreach($this->zbozi as $key => $val) {
$this->zbozi[$key]['cena'] = $this->modelShop::nastavCenu(this->zbozi[$key]['cena'], $this->getUser()->getId());
}
(kde by nastavCenu si skontrolovalo, jestli je na daný produkt nějaká pevná sleva, nebo procentuální, případně žádná)
- petr.pavel
- Člen | 535
Jestli vždycky pracuješ se slevou, tak místo nastavCenu() bych napsal zjistiSlevu() a cenu počítal až třeba v šabloně. Cílem je vyčlenit do metody jen to, co je potřeba pro odlišení ceny.
Taky záleží na tom, podle čeho cenu/slevu sestavuješ. Jestli podle kategorie výrobku a sazby zákazníka, předávej metodě tyto dvě, ne prostředníky. Tj. ne cenu a id zákazníka, ale kategorii a sazbu. Bude to logicky průhlednější a líp se ti pak bude metoda testovat.
- tatyalien
- Člen | 239
Ok, nějak si to rozvrhnu a zbastlím jak bude čas ;)
Ohledně počítání, nejspíš bych měl předávat identitu uživatele (kde bude uložena jeho hladina), id produktu). Jen, pokud to bude muset aplikace kontrolovat oproti DB, tak například u výpisu zboží se stránkováním by byl například při 10 položkách 10× dotaz do db pro každý produkt zvlášť :(.
To už by bylo lepší předat získaná data a přenastavit to najednou.
Editoval tatyalien (1. 8. 2012 13:42)
- petr.pavel
- Člen | 535
Proč chceš předávat celou identitu, když už teď víš, že potřebovat budeš jen hladinu? Znáš ten vtip o klavíru?
Jestli používáš Nette Database, tak by to nemuselo být 10 dotazů, ale jen jeden. Tohle lazy zpracování je jedna z jeho hlavních předností.
Existuje takové doporučení, nejdřív programovat čistě z hlediska návrhu, a teprve když to všechno funguje, tak začít optimalizovat výkon.
- tatyalien
- Člen | 239
Něco jsem včera večer ještě spíchl:
/**
* Vrátí přepočítanou cenu zboží. Nepřihlášený uživatel, nebo uživatel bez cenové hladiny obdrží zpět počáteční cenu.
* Pokud má uživatel nastavenou cenovou hladinu, cena se nastaví:
* a) pokud je v tabulce self::TABLE_SLEVAZBOZI zadané katalogové číslo se zvolenou cenovou hladinou, přiřadí se zadaná cena
* b) vytáhne se procentní sleva z tabulky self::TABLE_CENOVAHLADINA a vynásobí se aktuální cena
* c) pokud cenová hladina neexistuje, vrátí se počáteční cena
* @param int|NULL $cenovaHladina
* @param string $katalog
* @param double $cena
* @return double
*/
public function getProduktCena($cenovaHladina, $katalog, $cena)
{
// pokud neexistuje cenová hladina, vracím zpět nezměněnou cenu
if(!isset($cenovaHladina) || is_null($cenovaHladina)) {
return $cena;
}
// pokud existuje pevná sleva na zboží se zvolenou cenovou hladinou
$row = $this->getSlevaZbozi()->select('cena')->where('goods_katalog', $katalog)->where('cenovehladiny_id', $cenovaHladina)->limit(1)->fetch();
if($row) {
return $row['cena'];
}
// pokud neexistuje pevná cena, načtu si cenovou hladinu a přenastavím cenu
$row = $this->getCenovaHladina()->select('sleva')->where('id', $cenovaHladina)->limit(1)->fetch();
if($row) {
return $cena * $row['sleva'];
} else {
// pokud hladina neexistuje, vracím nezměněnou cenu
return $cena;
}
}
v basePresenteru si dodám helper:
$_this = $this;
$this->template->registerHelper('nastavCenu', function($cena, $katalog) use ($_this) {
if($_this->user->isLoggedIn()) {
return $_this->modelShop->getProduktCena($_this->getUser()->getIdentity()->data['cenovehladiny_id'], $katalog, $cena);
} else {
return $cena;
}
});
Kde následně mohu volat v šabloně:
přepočítáno: {$ceny[$value['goods_katalog']]['cenaSdani']|nastavCenu, $value['goods_katalog']}
Editoval tatyalien (2. 8. 2012 8:02)
- petr.pavel
- Člen | 535
Za mě dobrý :-)
Jen mě napadá pár poznámek:
$_this->getUser()->getIdentity()->data['cenovehladiny_id']
jde myslím zapsat jako$_this->user->identity->cenovehladiny_id
. Ostatně, překvapuje mě, že se dostaneš nadata
, když jsou private.if(!isset($cenovaHladina) || is_null($cenovaHladina))
by šlo zapsat jakoif (empty($cenovaHladina))
, pokud bych nechtěl vyloučit 0 a ''.- Je nějaký důvod, proč si předpřipravuješ ceny do pole $ceny? Jestli jsou v samostatné db tabulce a jen je linkuješ, můžeš linkovat rovnou při zobrazování – a lazy zpracování Nette DB ti to spojí do jediného dotazu.
- tatyalien
- Člen | 239
$_this->getUser()->getIdentity()->data['cenovehladiny_id']
– nějak toto používám, v data mám ostatní údaje po autorizaci uživatele. Ale prubnu to tvoje $_this->user->identity->cenovehladiny_idif(!isset($cenovaHladina) || is_null($cenovaHladina))
, zde by „0“ neměla být nastavená, ale raději jsem testoval jestli existuje hladina, a není NULL tak šlapej dál, ale asi bz fakt stačiloempty($cenovaHladina)
- To pole ceny je pouze ve vykreslení košíku. V sessionu/DB košíku si pouze držím: users_id, goods_katalog, goods_nazev, ks, poznamka, datum. Pokud uživatel klikne na košík tak si jen vytáhnu aktuální ceny z DB proto je zde samostatné pole „ceny“. Kdekoliv jinde na stránkách je jinak cena přímo při výpisu z tabulky goods.
Editoval tatyalien (2. 8. 2012 11:23)