product = $this->getProductPriceHistoryLast($id); } return true; } /** * Ustaw typ zapisywania histroii cen * @return string simple|full - typ zapisywania histroii cen wg konfiguracji */ public function getType() { // $product_config = stConfig::getInstance('stProduct'); // $price_history_type=$product_config->get('price_history_type'); // if ($price_history_type=='full') return 'full'; // else return 'simple'; // po zmianach w STX-1439 system zawsze zwaraca full return 'full'; } /** * Ustaw info jak jest wykonywane zadania z Taska czy Save * @param string $mode task, save */ public function setMode($mode) { $this->mode = $mode; } /** * Odczytaj info jak jest wykonywane zadanie z Taska czy Save * @param string $mode task, save, other */ public function getMode() { if (empty($this->mode)) return 'other'; return $this->mode; } /** * Odczytaj domyślną walutę w sklepie * @return int ID domyślnej waluty w sklepie * @var $default_currency_id */ private function getShopDefaultCurrencyId() { if (!empty($this->default_currency_id)) return $this->default_currency_id; $c = new Criteria(); $c->add(CurrencyPeer::MAIN, 1); $currency = CurrencyPeer::doSelectOne($c); $default_currency_id = $currency->getID(); $this->default_currency_id = $default_currency_id; return $default_currency_id; } /** * Odczytaj Id waluty produktu * Waluta aktualna np. z formularza produktu. Uwaga! Może tej wartosci nie być przy wywołaniu webapi - wtedy wez walutę domyślną * @return int ID waluty lub domyślna sklepu, jeśli wartość nie jest podana */ private function getProductCurrencyId() { $price_currency_id = $this->product->getCurrencyId(); if (empty($price_currency_id)) $price_currency_id = $this->getShopDefaultCurrencyId(); return $price_currency_id; } /** * Sprawdz czy jest wykonywana edycja czy dodawanie produktu * @return string 'add' - dodanie, 'edit' - edycja */ private function getProductAction() { if ($this->product->getID() > 0) return 'edit'; else return 'add'; } /** * Zwróć cenę w walucie. * @return float cena w walucie */ private function getProductPriceBruttoCurrency() { // Jeśli product na walutę domyślną, to ustaw cenę brutto // this_product->getCurrencyPrice() zwraca NULL jeśli nie był wybrana waluta inna niż domyślna // price_brutto_currency ma zawierać cenę brutto w domyślnej walucie $price_brutto_currency = $this->getFrontendPrice($this->product,$this->product->getCurrencyPrice(),'brutto'); if (empty($price_brutto_currency)) { $price_brutto_currency = $this->getFrontendPrice($this->product,$this->product->getPriceBrutto(),'brutto'); } return $price_brutto_currency; } /** * Znajdź ostatni wpis z ceną produktu z stProductPriceHistory * @return object stProductPriceHistory | NULL */ private function getLastProductPriceHistory() { $product_id = $this->product->getId(); $c = new Criteria(); $c->add(ProductPriceHistoryPeer::PRODUCT_ID, $product_id); $c->addDescendingOrderByColumn(ProductPriceHistoryPeer::CREATED_AT); $last_product = ProductPriceHistoryPeer::doSelectOne($c); if (empty($last_product)) return NULL; return $last_product; } /** * Oczytaj rekord z danymi ostatniej ceny prodfuktu * @return object stProductPriceHistoryLast | NULL */ private function getProductPriceHistoryLast() { $product_id = $this->product->getId(); $price_history_last = new stPriceHistoryLast(); if ($price_history_last->isLastProductPrice($product_id)) { $product_last = $price_history_last->getLastProduct($product_id); } else return NULL; return $product_last; } /** * Sprawdz jaka sytuacja jest dla danego produktu. Od tych danych zależą dalsze wykonywane operacje. * change (pph_change): * - true: zmieniła się cena produktu * - false: nie było zmiany ceny * update (pph_update): * - true: aktualizuj ostatni rekord w historii ceny - dotyczy to kolejnej zmiany w tym samym dniu * - false: dodaj nowy wpis, ostatnia zmiana nie była wykonywana dzisiaj * @return array 'product' object stProductPriceHistory, 'change' bool, 'update' bool */ private function checkPriceHistoryChangeUpdate() { $price_history_last = new stPriceHistoryLast(); $price_currency_id = $this->getProductCurrencyId(); $price_brutto_currency = $this->getProductPriceBruttoCurrency(); $is_product_from_last = $price_history_last->isLastProductPrice($this->product->getId()); $product_price_history_last_record = $this->getLastProductPriceHistory(); if (!empty($is_product_from_last)) { $pph_price_brutto_currency = $price_history_last->getLastProductPriceBrutto($this->product->getId()); $pph_currency = $price_history_last->getCurrencyId(); $pph_price_brutto_currency = floatval($pph_price_brutto_currency); if (($pph_price_brutto_currency != $price_brutto_currency) || ($price_currency_id != $pph_currency)) { // cena uległa zmianie // $price_brutto_currency - nowa cena // $pph_price_brutto_currency - cena produktu przed zmianą // odczytaj cenę z wczoraj $price_brutto_yesterday = $this->getPriceBruttoYesterday($this->product->getId(), $pph_price_brutto_currency); if ($price_brutto_currency < $price_brutto_yesterday) { // cena ulegla zmniejszeniu $this->saveLowestPrice($this->product, NULL, 'down'); } elseif ($price_brutto_currency > $price_brutto_yesterday) { // cena ulegla zwiększeniu $this->saveLowestPrice($this->product, NULL, 'up'); } // zapamietaj, ze cena sie zmienila $pph_change = true; // czy ostatni wpis jest z dzisiaj, odczytaj dane z st_product_price_history if (! empty($product_price_history_last_record)) { $pph_date = $product_price_history_last_record->getUpdatedAt(); } else $pph_date = null; $today = date('Y-m-d') . " 00:00:00"; if (($pph_date >= $today) && ($pph_date != null)) { // aktualizuj rekord osttani $pph_update = true; } else { // dodaj nowy rekord $pph_update = false; } } else { $pph_change = false; } } else { // Kiedy nie ma wpisu to dodaj nowy $pph_change = true; $pph_update = false; } return array( 'product'=> $product_price_history_last_record, 'change' => $pph_change, 'update' => $pph_update, ); } /** * Dodaj wpis z aktualną ceną, przed zapisaniem nowej * Jeśli produkt ma cenę np. 100 i dodajemy 150, to musimy zapisać jaka cena była wcześniej i jaka jest nowa cena * cenę wcześniejszą zapisujemy z datą o jeden dzień wcześniej, chyba że produkt był dodany * dzisiaj i ma wartość pola, created_at = today, wtedy nie dodajemy dodatkowego wpisu przez zmianą. * * 1. Pobieramy dane produktu z bazy * 2. Sprawdzamy created_at * 3. jesli created_at = today nic nie robimy * 4. jesli created_at < today sprawdzamy czy możemy dodać nowy wpis * ... * @param object $last ostatni wpis produktu stProduct, stProductPriceHistory * @return NULL; */ private function addDataToPriceHistory($last) { $price_history_last = new stPriceHistoryLast($this->product->getId()); $today = date("Y-m-d H:i:s"); $today_begin_time = date("Y-m-d 00:00:00"); // 00:00:00 oznacza początek dnia, ważne! $yesterday = date('Y-m-d', strtotime('-1 day', strtotime(date('Y-m-d')))) . ' 00:00:00'; $day_before_yesterday = date('Y-m-d', strtotime('-2 day', strtotime(date('Y-m-d')))) . ' 23:59:59'; // 23:59:59 oznacza koniec dnia // Sprawdź, czy $last został przekazany w wywołaniu. Parametr $last jest przekazywany przy zapisie produktu. // Dotyczy sytuacji wywołania zapisania z cron, tam parametr $last nie jest ustawiony. // $product_before - zawiera aktualne dane produktu if (!empty($last)) { $product_before = $last; } else { // odczytaj aktualne dane produktu z bazy $c = new Criteria(); $c->add(ProductPeer::ID, $this->product->getId()); $product_before = ProductPeer::doSelectOne($c); } // Jeśli nie ma produktu w bazie nic nie wykonuj - security option. if (empty($product_before)) return NULL; $product_before_created_at = $product_before->getCreatedAt(); if (!empty($last)) { // dla danych z (last) ProductPriceHistoryLast // wywołaj inną metodę, gdyż cena w walucie jest przechowywana w innym polu w tym modelu $price_brutto_currency_before = $product_before->getPrice(); } else { // dla Product $price_brutto_currency_before = $product_before->getFrontendCurrencyPrice(); } // if (empty($price_brutto_currency_before)) // { // $price_brutto_currency_before = $product_before->getFrontendCurrencyPrice(); // } // Sprawedzamy czy cena wczesniejsza zmieniła się, jeśli nie, to nie dodajemy wpisu z dnia wcześniejszego // Chodzi o uniknięcie sytuacji z STX-893 kiedy cena się nie zmienia i zapisywane sa 2 rekordy z ta sama cena // Dodaj rekord "dzien przed" jesli produkt nie byl oddany dzisiaj, zmienila sie cena i nie ma wpisow dla danego produktu // $product_price_before = $product_before->getPriceBrutto(); $product_price_before = $price_history_last->getLastProductPriceBrutto($this->product->getId()); if (! $product_price_before) $product_price_before = $product_before->getPriceBrutto(); $product_price_before=floatval($product_price_before); $product_price_current = floatval($this->getFrontendPrice($this->product,$this->product->getPriceBrutto(),'brutto')); if (($product_before_created_at < $today_begin_time) && ($product_price_before != $product_price_current)) { // Sprawdz, czy w price_history jest juz wpis z dnia wczorajszego, jak jest to nie dodawaj ddoatkowego wpisu, // gdyz oznacza to, ze wczoraj cena byla juz zapisana. Sprawdzamy datę > 2 dni temu i < dzisiaj. $c = new Criteria(); $c->addAnd(ProductPriceHistoryPeer::PRODUCT_ID, $this->product->getId()); // $c->addAnd(ProductPriceHistoryPeer::CREATED_AT,$day_before_yesterday,Criteria::GREATER_THAN); // $c->addAnd(ProductPriceHistoryPeer::CREATED_AT,$today,Criteria::LESS_THAN); $criterion = $c->getNewCriterion(ProductPriceHistoryPeer::CREATED_AT, $day_before_yesterday, Criteria::GREATER_THAN); $criterion->addAnd($c->getNewCriterion(ProductPriceHistoryPeer::CREATED_AT, $today_begin_time, Criteria::LESS_THAN)); $c->add($criterion); $product_price_history_before_check = ProductPriceHistoryPeer::doSelectOne($c); if (empty($product_price_history_before_check)) { // Nie ma wpsiu z dnia wczorajszego, oznacza to ze zmiana ceny byla wczeniej i trzeba zapisac // cenę poprzednia dzień wcześniej. $product_price_history_before = new ProductPriceHistory(); $product_before_currency_id = $product_before->getCurrencyId(); if (empty($product_before_currency_id)) $product_before_currency_id = $this->product->getCurrencyId(); if (empty($product_before_currency_id)) $product_before_currency_id = $default_currency_id; // Zapisanie poprzedniej ceny // poprawka: te dane odczytaj z last // $frontend_price_before = $this->getFrontendPrice($product_before, $price_brutto_currency_before, 'price'); // $frontend_price_netto_before = $this->getFrontendPrice($product_before, $product_before->getPriceNetto(), 'netto'); // $frontend_price_brutto_before = $this->getFrontendPrice($product_before, $product_before->getPriceBrutto(), 'brutto'); // $main_price_before = $product_before->getMainCurrencyPrice(); // $main_price_netto_before = $product_before->getMainPriceNetto(); // $main_price_brutto_before = $product_before->getMainPriceBrutto(); // // $product_price_history_before->setProductId($this->product->getId()); // $product_price_history_before->setCreatedAt($yesterday); // $product_price_history_before->setUpdatedAt($yesterday); // $product_price_history_before->setCurrencyId($product_before_currency_id); // $product_price_history_before->setPrice($frontend_price_before); // $product_price_history_before->setPriceNetto($frontend_price_netto_before); // $product_price_history_before->setPriceBrutto($frontend_price_brutto_before); // $product_price_history_before->setMainPrice($main_price_before); // $product_price_history_before->setMainPriceNetto($main_price_netto_before); // $product_price_history_before->setMainPriceBrutto($main_price_brutto_before); // $product_price_history_before->save(); $product_price_history_before->setProductId($this->product->getId()); $product_price_history_before->setCreatedAt($yesterday); $product_price_history_before->setUpdatedAt($yesterday); if (! empty($price_history_last->getLastProduct($this->product->getId()))) { // jest wpis w st_product_price_history_last dla danego product_id $product_price_history_before->setCurrencyId($price_history_last->getCurrencyId()); $product_price_history_before->setPrice($price_history_last->getPrice()); $product_price_history_before->setPriceNetto($price_history_last->getPriceNetto()); $product_price_history_before->setPriceBrutto($price_history_last->getPriceBrutto()); $product_price_history_before->setMainPrice($price_history_last->getMainPrice()); $product_price_history_before->setMainPriceNetto($price_history_last->getMainPriceNetto()); $product_price_history_before->setMainPriceBrutto($price_history_last->getMainPriceBrutto()); } else { // nie ma wpisu w st_product_price_history_last dla danego product_id, wez dane dostarczone $frontend_price_before = $this->getFrontendPrice($product_before, $price_brutto_currency_before, 'price'); $frontend_price_netto_before = $this->getFrontendPrice($product_before, $product_before->getPriceNetto(), 'netto'); $frontend_price_brutto_before = $this->getFrontendPrice($product_before, $product_before->getPriceBrutto(), 'brutto'); $main_price_before = $product_before->getMainCurrencyPrice(); $main_price_netto_before = $product_before->getMainPriceNetto(); $main_price_brutto_before = $product_before->getMainPriceBrutto(); $product_price_history_before->setCurrencyId($this->product->getCurrencyId()); $product_price_history_before->setPrice($frontend_price_before); $product_price_history_before->setPriceNetto($frontend_price_netto_before); $product_price_history_before->setPriceBrutto($frontend_price_brutto_before); $product_price_history_before->setMainPrice($main_price_before); $product_price_history_before->setMainPriceNetto($main_price_netto_before); $product_price_history_before->setMainPriceBrutto($main_price_brutto_before); } $product_price_history_before->save(); } // STX-1435 Poprawka zapisania ceny min, jesli nie bylo wpisow w st_product_price_history if ($product_price_before > $product_price_current) { // cena się zmniejszyła $this->saveLowestPrice($this->product, NULL, 'down'); } else { // cena się zwiększyła $this->saveLowestPrice($this->product, NULL, 'up'); } // end STX-1435 } } /** * Zapisz cenę w historii cen produktu. Funkcja przeniesiona z modelu Product.php, gdzie była na początku zaimplementowana. * Wywoływana jest przy zapisie produktu -> odwołanie w Product.php. * * @param object $this_product obiekt produktu $this z modelu Product. Zawiera nowe dane jakie będą zapisane. * @param object $last obiekt produktu z modelu ProductPriceHistoryLast. Zawiera poprzednie wartości - ostatnio zapisane w cron. * * @return NULL */ public function modelUpdate($this_product, $last = NULL) { $this->product = $this_product; // tonen - optyamlizacja ilości wykonań $price_history_token = new stPriceHistoryToken($this->product); $token = $price_history_token->getExecuteToken(); if (!$price_history_token->allowExecuteToken($token)) return NULL; // add czy edit if ($this->getProductAction() == 'add') return NULL; // currency data $default_currency_id = $this->getShopDefaultCurrencyId(); $price_currency_id = $this->getProductCurrencyId(); $price_brutto_currency = $this->getProductPriceBruttoCurrency(); // analiza zapisanych danych $price_history_analyse = $this->checkPriceHistoryChangeUpdate(); $product_price_history_last_record = $price_history_analyse['product']; $pph_change = $price_history_analyse['change']; $pph_update = $price_history_analyse['update']; $mode = $this->getMode(); // mode: save, task, other $type = $this->gettype(); // type: simple, full (dla nowych wersji jest tylko 'full') if (!$pph_change) { // nie było zmiany ceny $price_history_token->saveExecuteToken($token); return NULL; } if ($pph_update) { // zaktualizuj istniejący wpis z dzisiaj $product_price_history = $product_price_history_last_record; } else { // dodaj nowy wpis do st_product_price_history $this->addDataToPriceHistory($last); $product_price_history = new ProductPriceHistory(); } // STX-1439 // Zapisz dane w st_product_price_history_last przy zapisie produktu - ostatnia cena if ($this->getMode() == 'save') { $price_history_last = new stPriceHistoryLast(); $price_history_last->setDefaultCurrency($default_currency_id); // Sprawdzamy, czy jest juz wpis w st_prodcu_price_history_last (last) if ($price_history_last->isLastProductPrice($this->product->getId())) { // Jest wpis w st_product_history_last dla danego id, aktualizuj dane. $price_history_last->updateLastProductPrice($this->product); } else { // Nie ma rekordu w st_product_history_last dla danego id, dodaj wpis. $price_history_last->addLastProductPrice($this->product); } } // Dodaj/aktualizuj cenę dzisiejszą $frontend_price = $this->getFrontendPrice($this_product, $price_brutto_currency, 'price'); $frontend_price_netto = $this->getFrontendPrice($this_product, $this_product->getPriceNetto(), 'netto'); $frontend_price_brutto = $this->getFrontendPrice($this_product, $this_product->getPriceBrutto(), 'brutto'); $main_price = $this_product->getMainCurrencyPrice(); $main_price_netto = $this_product->getMainPriceNetto(); $main_price_brutto = $this_product->getMainPriceBrutto(); $product_price_history->setProductId($this_product->getId()); $product_price_history->setCurrencyId($price_currency_id); $product_price_history->setPrice($frontend_price); $product_price_history->setPriceNetto($frontend_price_netto); $product_price_history->setPriceBrutto($frontend_price_brutto); $product_price_history->setMainPrice($main_price); $product_price_history->setMainPriceNetto($main_price_netto); $product_price_history->setMainPriceBrutto($main_price_brutto); $product_price_history->save(); $price_history_token->saveExecuteToken($token); return NULL; } /** * Zapisz zajniższą cenę produktu z ostatanich 30 dni, po obniżce. Metoda jest wywoływana, kiedy aktualna cena jest obniżona. * * @param object $this_product obiekt produktu $this z modelu Product. Zawiera nowe dane jakie będą zapisane. * @param integer $id product id * @param string $change down - cena spadła, up - cena wzrosła * * @return NULL */ public function saveLowestPrice($this_product, $product_id = NULL, $change) { // Wyszukaj najnizsza cene produktu z ostatnich 30 dni // Dane nowe nie są jeszzcze zapisane, więc w st_price_history najniższa cena z ostatanich 30 dni będzie tą, której szukamy. // data -30 dni $day_before_30d = date('Y-m-d', strtotime('-30 day', strtotime(date('Y-m-d')))) . ' 00:00:00'; $today = date("Y-m-d 00:00:00"); if (empty($product_id)) $product_id = $this_product->getID(); // Id produktu // 1. Wyszukaj wpisy dla danego produktu z ostatnich 30 dni $c = new Criteria(); $c->addAnd(ProductPriceHistoryPeer::PRODUCT_ID, $product_id); $c->addAnd(ProductPriceHistoryPeer::CREATED_AT, $day_before_30d, Criteria::GREATER_EQUAL); $c->addAnd(ProductPriceHistoryPeer::CREATED_AT, $today, Criteria::LESS_THAN); $c->addDescendingOrderByColumn(ProductPriceHistoryPeer::CREATED_AT); $products = ProductPriceHistoryPeer::doSelect($c); if (empty($products)) return NULL; // nie ma wpisów w st_price_history dla danego produktu $min_price = NULL; foreach ($products as $product_price_history) { $pph_id = $product_price_history->getId(); $pph_price_brutto = $product_price_history->getPriceBrutto(); if (empty($min_price)) { // na początku przyjmij pierwszą odczytaną wartość, jako najmniejszą. $min_price = $pph_price_brutto; $product_price_history_min = $product_price_history; // zapamiętaj obiekt z danymi najmniejszej ceny } elseif ($pph_price_brutto < $min_price) { // Jesli cena jest mnniejsza od poprzedniej zapamietanej, staje się ona najmniejszą. $min_price = $pph_price_brutto; $product_price_history_min = $product_price_history; // zapamiętaj obiekt z danymi najmniejszej ceny } } // $min_price zawiera najnizsza cene produktu z ostatnich 30 dni // $product_price_history_min zawiera obiekt product_price_history z najniższą ceną // Zapisz najnizsza cene w tebeli st_product_price_history_min $price_history_min = new stPriceHistoryMin($product_id); // czy jest wpis w st_product_price_history_min dla id produktu if ($price_history_min->isMinProductPrice()) { // jest już wpis, akulizuj $price_history_min->updateMinProductPrice($product_price_history_min, $change); } else { // nie ma wpisu $price_history_min->addMinProductPrice($product_price_history_min, $change); } return NULL; } /** * Zwraca cenę produktu z wczoraj. Sprawdza historię cen i aktualną cenę. * * @param integer $product_id - ID produktu * @param float $price brutto - cena produktu przed zmianą * @return float cena brutto - do porównania brana jest cena brutto * */ public function getPriceBruttoYesterday($product_id, $price_brutto) { // odczytaj cenę produktu jaka obowiązywała wczoraj // sprawdz czy sa wpisy w st_product_price_history $today = date('Y-m-d') . " 00:00:00"; $day_before_30d = date('Y-m-d', strtotime('-30 day', strtotime(date('Y-m-d')))) . ' 00:00:00'; $c = new Criteria(); $c->addAnd(ProductPriceHistoryPeer::PRODUCT_ID, $product_id); $c->addAnd(ProductPriceHistoryPeer::CREATED_AT, $today, Criteria::LESS_THAN); $c->addAnd(ProductPriceHistoryPeer::CREATED_AT, $day_before_30d, Criteria::GREATER_EQUAL); $c->addDescendingOrderByColumn(ProductPriceHistoryPeer::CREATED_AT); $pph_product = ProductPriceHistoryPeer::doSelectOne($c); if (!empty($pph_product)) { // jest wpis w st_product_price_history // pstatni wpis poza dzniem dzisiejszym, reprezentuje ostatnio zapisaną cenę produktu, czyli cenę, która obowiązywała wczoraj $pph_price_brutto = $pph_product->getPriceBrutto(); return $pph_price_brutto; } else { // nie ma wpisu w st_product_price_history, zwróć aktualną cenę return $price_brutto; } return NULL; } /** * Odczytaj cenę po rabacie dla danego produktu STX-1439 * * @param object obiekt produktu z tabeli st_product (nie z historii cen) * @param float $price cena do rabatowania * @param string $mode price, netto, brutto * @return float cena po rabacie */ public function getFrontendPrice($product, $price, $mode) { switch ($mode) { case "netto": $price = $product->getFrontendPriceNetto(); break; case "brutto": $price = $product->getFrontendPriceBrutto(); break; case "price": $price = $product->getFrontendCurrencyPrice(); break; } return $price; } }