Files
drmaterac.pl/modules/omnibuseufree/omnibuseufree.php

981 lines
38 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
*
* NOTICE OF LICENSE
*
* This source file is subject to the Apache License, Version 2.0
* that is bundled with this package in the file LICENSE.
* It is also available through the world-wide-web at this URL:
* http://www.apache.org/licenses/LICENSE-2.0
*
* @author presta.studio
* @copyright Copyright (c) 2023 presta.studio
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
if (!defined('_PS_VERSION_')) {
exit;
}
use Omnibus\Compatibility\PrestashopCompatibility;
class OmnibusEuFree extends Module
{
protected $config_form = false;
public function __construct()
{
$this->name = 'omnibuseufree';
$this->tab = 'pricing_promotion';
$this->version = '1.0.2';
$this->author = 'presta.studio';
$this->need_instance = 1;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Omnibus Directive');
$this->description = $this->l('This module will help you meet the requirements of the EU Omnibus Directive in your store.');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall this module? The price history will be deleted.');
$this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
}
public function install()
{
Configuration::updateValue('OMNIBUSEUFREE_INFORMATION_VERSION', 2);
Configuration::updateValue('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK', 1);
Configuration::updateValue('OMNIBUSEUFREE_CRON_STATUS', 2);
Configuration::updateValue('OMNIBUSEUFREE_DAYS', 30);
Configuration::updateValue('OMNIBUSEUFREE_HISTORY_DAYS', 60);
include(dirname(__FILE__) . '/sql/install.php');
return parent::install() &&
$this->registerHook('header') &&
$this->registerHook('displayBackOfficeHeader') &&
$this->registerHook('actionProductSave') &&
$this->registerHook('actionProductAttributeUpdate') &&
$this->registerHook('displayOmnibusEuFree') &&
$this->registerHook('displayProductPriceBlock') &&
$this->registerHook('displayAdminProductsExtra') &&
$this->installTab();
}
public function uninstall()
{
Configuration::deleteByName('OMNIBUSEUFREE_INFORMATION_VERSION');
Configuration::deleteByName('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK');
Configuration::deleteByName('OMNIBUSEUFREE_CRON_STATUS');
Configuration::deleteByName('OMNIBUSEUFREE_DAYS');
Configuration::deleteByName('OMNIBUSEUFREE_HISTORY_DAYS');
include(dirname(__FILE__) . '/sql/uninstall.php');
return parent::uninstall() &&
$this->uninstallTab();
}
private function installTab()
{
$tabId = (int) Tab::getIdFromClassName('OmnibusEuFreeController');
if (!$tabId) {
$tabId = null;
}
$tab = new Tab($tabId);
$tab->active = 1;
$tab->class_name = 'OmnibusEuFreeController';
$tab->route_name = 'admin_link_config';
$tab->icon = 'euro_symbol';
$tab->name = array();
foreach (Language::getLanguages() as $lang) {
$tab->name[$lang['id_lang']] = $this->l('Omnibus Directive');
}
$tab->id_parent = (int) Tab::getIdFromClassName('IMPROVE');
$tab->module = $this->name;
return $tab->save();
}
private function uninstallTab()
{
$tabId = (int) Tab::getIdFromClassName('OmnibusEuFreeController');
if (!$tabId) {
return true;
}
$tab = new Tab($tabId);
return $tab->delete();
}
protected function getLastMinimalPrice($id_product = null, $id_product_attribute = 0, $currency = null, $hasDiscountNow = null)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
if (!isset($currency)) {
$defaultCurrency = Currency::getDefaultCurrency();
$currency = (int)$defaultCurrency->id;
}
$info_version = (int) Configuration::get('OMNIBUSEUFREE_INFORMATION_VERSION', null, null, null, 2);
$NumberOfDays = (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30);
// Jeżeli v2 ma sens tylko przy rabacie - jeśli nie ma rabatu, nie pokazuj
if ($info_version === 2) {
if ($hasDiscountNow === null) {
// pewne sprawdzenie: porównaj regular vs sale w tej walucie
$snap = $this->getPricesSnapshot((int)$id_product, (int)$id_product_attribute, (int)$currency);
$hasDiscountNow = (bool)$snap['has_discount'];
}
if (!$hasDiscountNow) {
return [];
}
// 1) data ostatniego wpisu (bieżący stan)
$sqlLast = new DbQuery();
$sqlLast->select('date_add');
$sqlLast->from('omnibus_eu_free');
$sqlLast->where('id_product = ' . (int)$id_product);
$sqlLast->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlLast->where('id_currency = ' . (int)$currency);
$sqlLast->where('is_default_currency = 1');
$sqlLast->where('is_last = 1');
$lastRow = Db::getInstance()->getRow($sqlLast);
if (empty($lastRow['date_add'])) {
return [];
}
$lastDate = $lastRow['date_add'];
// 2) znajdź ostatni moment przed lastDate, kiedy rabatu NIE było (has_discount=0)
$sqlPrevNoDisc = new DbQuery();
$sqlPrevNoDisc->select('MAX(date_add) AS prev_no_disc');
$sqlPrevNoDisc->from('omnibus_eu_free');
$sqlPrevNoDisc->where('id_product = ' . (int)$id_product);
$sqlPrevNoDisc->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlPrevNoDisc->where('id_currency = ' . (int)$currency);
$sqlPrevNoDisc->where('is_default_currency = 1');
$sqlPrevNoDisc->where('date_add < "' . pSQL($lastDate) . '"');
$sqlPrevNoDisc->where('has_discount = 0');
$rowPrev = Db::getInstance()->getRow($sqlPrevNoDisc);
// 3) start rabatu = pierwszy rekord z has_discount=1 po prev_no_disc
// jeśli nigdy nie było has_discount=0, start = pierwszy rekord w historii z has_discount=1
if (!empty($rowPrev['prev_no_disc'])) {
$sqlStart = new DbQuery();
$sqlStart->select('MIN(date_add) AS disc_start');
$sqlStart->from('omnibus_eu_free');
$sqlStart->where('id_product = ' . (int)$id_product);
$sqlStart->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlStart->where('id_currency = ' . (int)$currency);
$sqlStart->where('is_default_currency = 1');
$sqlStart->where('has_discount = 1');
$sqlStart->where('date_add > "' . pSQL($rowPrev['prev_no_disc']) . '"');
$rowStart = Db::getInstance()->getRow($sqlStart);
} else {
$sqlStart = new DbQuery();
$sqlStart->select('MIN(date_add) AS disc_start');
$sqlStart->from('omnibus_eu_free');
$sqlStart->where('id_product = ' . (int)$id_product);
$sqlStart->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlStart->where('id_currency = ' . (int)$currency);
$sqlStart->where('is_default_currency = 1');
$sqlStart->where('has_discount = 1');
$rowStart = Db::getInstance()->getRow($sqlStart);
}
if (empty($rowStart['disc_start'])) {
return [];
}
$discStart = $rowStart['disc_start'];
// okno 30 dni przed startem rabatu
$startDateTime = (new DateTime($discStart))->modify('-' . $NumberOfDays . ' days')->format('Y-m-d H:i:s');
// minimalna cena REGULARNA w oknie przed rabatem
$sqlMin = new DbQuery();
$sqlMin->select('MIN(price_regular) AS price');
$sqlMin->from('omnibus_eu_free');
$sqlMin->where('id_product = ' . (int)$id_product);
$sqlMin->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlMin->where('id_currency = ' . (int)$currency);
$sqlMin->where('is_default_currency = 1');
$sqlMin->where('date_add >= "' . pSQL($startDateTime) . '"');
$sqlMin->where('date_add < "' . pSQL($discStart) . '"');
$minRow = Db::getInstance()->getRow($sqlMin);
if (empty($minRow) || !isset($minRow['price']) || $minRow['price'] === null) {
$sqlStartPrice = new DbQuery();
$sqlStartPrice->select('price_regular AS price');
$sqlStartPrice->from('omnibus_eu_free');
$sqlStartPrice->where('id_product = ' . (int)$id_product);
$sqlStartPrice->where('id_product_attribute = ' . (int)$id_product_attribute);
$sqlStartPrice->where('id_currency = ' . (int)$currency);
$sqlStartPrice->where('is_default_currency = 1');
$sqlStartPrice->where('has_discount = 1');
$sqlStartPrice->orderBy('date_add ASC, id_omnibuseufree ASC');
$startPriceRow = Db::getInstance()->getRow($sqlStartPrice, false);
return (!empty($startPriceRow) && isset($startPriceRow['price'])) ? $startPriceRow : [];
}
return (!empty($minRow) && isset($minRow['price'])) ? $minRow : [];
}
// v1: najniższa z ostatnich X dni (tu możesz liczyć po regularnej albo po sale zależnie od interpretacji)
$date = new DateTime();
$date->modify('-' . $NumberOfDays . ' days');
$CutOffDate = $date->format('Y-m-d');
$sql = new DbQuery();
$sql->select('MIN(price_sale) AS price');
$sql->from('omnibus_eu_free');
$sql->where('id_product = ' . (int)$id_product);
$sql->where('id_product_attribute = ' . (int)$id_product_attribute);
$sql->where('id_currency = ' . (int)$currency);
$sql->where('is_default_currency = 1');
$sql->where('date_add >= "'.$CutOffDate.' 00:00:00"');
$row = Db::getInstance()->getRow($sql);
return (!empty($row) && isset($row['price'])) ? $row : [];
}
public function hookDisplayOmnibusEuFree($params)
{
$currency = $this->context->currency;
$lastMinimalPrice = $this->getLastMinimalPrice(
(int)$params['product']['id_product'],
(int)$params['product']['id_product_attribute'],
(int)$currency->id,
(bool)$params['product']['has_discount']
);
if (!empty($lastMinimalPrice)) {
$minimalPrice = PrestashopCompatibility::formatPrice(_PS_VERSION_, $lastMinimalPrice['price'], $currency);
}
else {
$minimalPrice = null;
}
$this->context->smarty->assign([
'OmnibuseufreeInfoVersion' => (int) Configuration::get('OMNIBUSEUFREE_INFORMATION_VERSION', null, null, null, 2),
'OmnibuseufreeProductPriceMin' => $minimalPrice,
'OmnibuseufreeProductPriceCurrent' => $params['product']['price'],
'OmnibuseufreeProductDiscount' => (bool) $params['product']['has_discount'],
'OmnibuseufreeNumberOfDays' => (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30),
]);
return $this->display(__FILE__, '/views/templates/hook/presta_studio_omnibus_price.tpl');
}
public function hookDisplayProductPriceBlock($params)
{
return ($params['type'] == 'after_price' && Configuration::get('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK') == 1) ? $this->hookDisplayOmnibusEuFree($params) : '';
}
public function hookDisplayAdminProductsExtra($params)
{
$OmnibusData = array();
$product = new Product((int) $params['id_product']);
$hasCombinations = $product->hasCombinations();
$nameCache = array();
foreach ($this->getOmnibusData($params['id_product']) as $rowId => $rowValue) {
$OmnibusData[$rowId]['price_locale'] = '';
$OmnibusData[$rowId]['currency_iso_code'] = '';
$OmnibusData[$rowId]['name'] = '';
$OmnibusData[$rowId]['is_last_icon'] = '';
foreach ($rowValue as $key => $value) {
if (isset($OmnibusData[$rowId]['price']) && $key == 'id_currency') {
$currency = Currency::getCurrencyInstance((int) $value);
$OmnibusData[$rowId]['price_locale'] = PrestashopCompatibility::formatPrice(_PS_VERSION_, $OmnibusData[$rowId]['price'], $currency);
$OmnibusData[$rowId]['currency_iso_code'] = $currency->iso_code;
}
elseif ($key == 'id_product_attribute') {
$attrId = (int) $value;
if (!isset($nameCache[$attrId])) {
$nameCache[$attrId] = $product->getProductName((int) $params['id_product'], $attrId);
if ($hasCombinations && $attrId === 0) {
$nameCache[$attrId] .= ' ' . $this->l('(default combination)');
}
}
$OmnibusData[$rowId]['name'] = $nameCache[$attrId];
}
elseif ($key == 'is_last' && $value == 1) {
$OmnibusData[$rowId]['is_last_icon'] = '<span class="material-icons text-success">done</span>';
}
$OmnibusData[$rowId][$key] = $value;
}
}
$this->context->smarty->assign([
'OmnibuseufreeData' => $OmnibusData
]);
return $this->display(__FILE__, '/views/templates/admin/products-price-list.tpl');
}
public function hookHeader()
{
$this->context->controller->addCSS($this->_path . '/views/css/omnibuseufree-presta-studio.css');
}
public function hookDisplayBackOfficeHeader()
{
$this->context->controller->addJS($this->_path . 'views/js/back.js');
$this->context->controller->addCSS($this->_path . 'views/css/back.css');
}
public function hookActionProductSave($hook_params)
{
if (Module::isEnabled('omnibuseufree')) {
$id_product = (int) $hook_params['id_product'];
$combinationCount = (int) Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'product_attribute` WHERE `id_product` = ' . $id_product
);
Product::flushPriceCache();
$this->addProductPrice($id_product);
if ($combinationCount <= 30) {
$this->addProductPriceWithCombinations($id_product);
}
}
}
public function hookActionProductAttributeUpdate()
{
if (Module::isEnabled('omnibuseufree')) {
$id_product = (int) Tools::getValue('id_product');
$combinationCount = (int) Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'product_attribute` WHERE `id_product` = ' . $id_product
);
// Skip entirely for products with many combinations.
// hookActionProductSave already handles base price recording.
// This hook fires once PER combination (168x), so running here is wasteful.
if ($combinationCount > 30) {
return;
}
Product::flushPriceCache();
$this->addProductPrice($id_product);
$this->addProductPriceWithCombinations($id_product);
}
}
/**
* Load the configuration form
*/
public function getContent()
{
$confirmation = '';
if (((bool) Tools::isSubmit('submitOmnibusEuFreeModule')) == true) {
$confirmation = $this->postProcess();
}
$token = Configuration::get('OMNIBUSEUFREE_CRON_TOKEN', null, null, null, 'error');
$this->context->smarty->assign([
'module_dir' => $this->_path,
'lang' => $this->context->language->iso_code,
'update_prices' => Context::getContext()->link->getModuleLink('omnibuseufree', 'cron', array('type' => 1, 'token' => $token)),
'delete_outdated_data' => Context::getContext()->link->getModuleLink('omnibuseufree', 'cron', array('type' => 2, 'token' => $token)),
'cron_status' => Configuration::get('OMNIBUSEUFREE_CRON_STATUS', null, null, null, 2)
]);
$output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/configure.tpl');
return $confirmation . $output . $this->renderForm();
}
protected function renderForm()
{
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitOmnibusEuFreeModule';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
. '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFormValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id,
);
return $helper->generateForm(array($this->getConfigForm()));
}
protected function getConfigForm()
{
$NumberOfDays = (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30);
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
),
'input' => array(
array(
'type' => 'switch',
'label' => $this->l('Delete outdated data'),
'name' => 'OMNIBUSEUFREE_OLD_DATA',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => true,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => false,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'switch',
'label' => $this->l('Update prices'),
'name' => 'OMNIBUSEUFREE_UPDATE_DATABASE_PRICE',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => true,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => false,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'select',
'label' => $this->l('Version:'),
'name' => 'OMNIBUSEUFREE_INFORMATION_VERSION',
'class' => 'omnibus-select-version',
'required' => true,
'options' => array(
'query' => array(
array(
'id_option' => 1,
'name' => sprintf($this->l('Lowest price in %d days'),$NumberOfDays)
),
array(
'id_option' => 2,
'name' => sprintf($this->l('Lowest price in %d days before discount'),$NumberOfDays)
),
),
'id' => 'id_option',
'name' => 'name'
)
),
array(
'type' => 'text',
'label' => $this->l('Number of days'),
'desc' => $this->l('Number of days for front-end lowest price display (Omnibus Directive).'),
'name' => 'OMNIBUSEUFREE_DAYS',
'class' => 'omnibus-input-days',
'maxlength' => '3',
'required' => true
),
array(
'type' => 'text',
'label' => $this->l('History retention (days)'),
'desc' => $this->l('How many days of price history to keep and display in admin. Older entries (except current price) will be deleted by CRON.'),
'name' => 'OMNIBUSEUFREE_HISTORY_DAYS',
'class' => 'omnibus-input-days',
'maxlength' => '4',
'required' => true
),
array(
'type' => 'switch',
'label' => $this->l('Display on product page'),
'name' => 'OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK',
'is_bool' => false,
'desc' => $this->l('Hook: ProductPriceBlock type: after_price'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 2,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'switch',
'label' => $this->l('CRON'),
'name' => 'OMNIBUSEUFREE_CRON_STATUS',
'is_bool' => false,
'desc' => $this->l('A new token will be generated if you change the CRON status'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 2,
'label' => $this->l('Disabled')
)
),
),
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
/**
* Set values for the inputs.
*
* OMNIBUSEUFREE_CRON_STATUS since v1.0.2
* OMNIBUSEUFREE_DAYS since v1.0.2
*
*/
protected function getConfigFormValues()
{
return array(
'OMNIBUSEUFREE_OLD_DATA' => false,
'OMNIBUSEUFREE_UPDATE_DATABASE_PRICE' => false,
'OMNIBUSEUFREE_INFORMATION_VERSION' => Configuration::get('OMNIBUSEUFREE_INFORMATION_VERSION', null, null, null, 2),
'OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK' => Configuration::get('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK', null, null, null, 1),
'OMNIBUSEUFREE_CRON_STATUS' => Configuration::get('OMNIBUSEUFREE_CRON_STATUS', null, null, null, 2),
'OMNIBUSEUFREE_DAYS' => Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30),
'OMNIBUSEUFREE_HISTORY_DAYS' => Configuration::get('OMNIBUSEUFREE_HISTORY_DAYS', null, null, null, 60)
);
}
/**
* Save form data.
*/
protected function postProcess()
{
if (Configuration::get('OMNIBUSEUFREE_CRON_STATUS', null, null, null, 2) != Tools::getValue('OMNIBUSEUFREE_CRON_STATUS')) {
Configuration::updateValue('OMNIBUSEUFREE_CRON_TOKEN', Tools::hash(Tools::passwdGen(16)));
}
Configuration::updateValue('OMNIBUSEUFREE_INFORMATION_VERSION', (int) Tools::getValue('OMNIBUSEUFREE_INFORMATION_VERSION'));
Configuration::updateValue('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK', (int) Tools::getValue('OMNIBUSEUFREE_DISPLAY_PRODUCT_PRICE_BLOCK'));
Configuration::updateValue('OMNIBUSEUFREE_CRON_STATUS', (int) Tools::getValue('OMNIBUSEUFREE_CRON_STATUS'));
Configuration::updateValue('OMNIBUSEUFREE_DAYS', (int) Tools::getValue('OMNIBUSEUFREE_DAYS'));
Configuration::updateValue('OMNIBUSEUFREE_HISTORY_DAYS', max(1, (int) Tools::getValue('OMNIBUSEUFREE_HISTORY_DAYS')));
$confirmation = $this->l('The settings have been updated.');
if (Tools::getValue('OMNIBUSEUFREE_OLD_DATA')) {
$OldDataCounter = $this->removeOldDataFromOmnibusTable();
PrestaShopLogger::addLog('Omnibus Directive module by presta.studio - Deleted old data. Number of records deleted in database: ' . $OldDataCounter);
$confirmation .= '<br>' . $this->l('Deleted old data. Number of records deleted in database: ') . $OldDataCounter;
}
if (Tools::getValue('OMNIBUSEUFREE_UPDATE_DATABASE_PRICE')) {
$InsertDataCounter = $this->insertAllProductsToOmnibusTable();
PrestaShopLogger::addLog('Omnibus Directive module by presta.studio - Updated price history. Number of products checked: ' . $InsertDataCounter);
$confirmation .= '<br>' . $this->l('Updated price history. Number of products checked: ') . $InsertDataCounter;
}
return $this->displayConfirmation($confirmation);
}
protected function checkCurrencyConversionRate($id_product = null, $id_product_attribute = 0)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
$sql = new DbQuery();
$sql->select('id_currency, currency_conversion_rate');
$sql->from('omnibus_eu_free');
$sql->where('id_product = ' . (int) $id_product);
$sql->where('id_product_attribute = ' . (int) $id_product_attribute);
$sql->where('is_last = 1');
$SQLResult = Db::getInstance()->executeS($sql);
$ToChange = 0;
$OmnibusCurrencies = array();
foreach ($SQLResult as $row) {
$OmnibusCurrencies[$row['id_currency']] = $row['currency_conversion_rate'];
}
if (!empty($OmnibusCurrencies)) {
$currencies = Currency::getCurrencies();
$AvailableCurrencies = array();
foreach ($currencies as $currency) {
$AvailableCurrencies[$currency['id_currency']] = $currency['conversion_rate'];
}
foreach ($AvailableCurrencies as $CurrencyKey => $CurrencyValue) {
if (!isset($OmnibusCurrencies[$CurrencyKey]) || $CurrencyValue != $OmnibusCurrencies[$CurrencyKey]) {
$ToChange++;
}
}
}
else {
$ToChange++;
}
return $ToChange == 0 ? false : true;
}
protected function getLastSnapshot($id_product = 0, $id_product_attribute = 0, $id_currency = null)
{
$sql = new DbQuery();
$sql->select('price_regular, price_sale, has_discount, currency_conversion_rate');
$sql->from('omnibus_eu_free');
$sql->where('id_product = ' . (int)$id_product);
$sql->where('id_product_attribute = ' . (int)$id_product_attribute);
$sql->where('is_last = 1');
$sql->where('is_default_currency = 1');
if ($id_currency !== null) {
$sql->where('id_currency = ' . (int)$id_currency);
}
$sql->limit(1);
return Db::getInstance()->getRow($sql);
}
protected function getPricesSnapshot($id_product, $id_product_attribute, $id_currency)
{
$context = Context::getContext();
$oldCurrency = $context->currency;
if ((int)$id_currency > 0) {
$context->currency = new Currency((int)$id_currency);
}
// regularna (bez redukcji)
$regular = (float) Product::getPriceStatic(
(int)$id_product,
true,
(int)$id_product_attribute,
6,
null,
false,
false // use_reduction = false
);
// sprzedażowa (z redukcją)
$sale = (float) Product::getPriceStatic(
(int)$id_product,
true,
(int)$id_product_attribute,
6,
null,
false,
true // use_reduction = true
);
// przywróć walutę
$context->currency = $oldCurrency;
$hasDiscount = ($sale > 0 && $regular > 0 && ($sale + 0.0001) < $regular) ? 1 : 0;
$diff = $hasDiscount ? ($regular - $sale) : 0.0;
return [
'regular' => $regular,
'sale' => $sale,
'has_discount' => $hasDiscount,
'diff' => $diff,
];
}
protected function normalizeCurrency($currency)
{
if (is_array($currency)) {
return [
'id' => (int) ($currency['id_currency'] ?? $currency['id'] ?? 0),
'rate' => (float) ($currency['conversion_rate'] ?? $currency['rate'] ?? 0),
];
}
// obiekt Currency
return [
'id' => (int) ($currency->id ?? 0),
'rate' => (float) ($currency->conversion_rate ?? 0),
];
}
protected function addProductPrice($id_product = null)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
$id_product = (int)$id_product;
$currencies = Currency::getCurrencies(true, true);
$defaultCurrency = Currency::getDefaultCurrency();
// snapshot w default walucie do porównania (żeby nie dopisywać non stop)
$snapDefault = $this->getPricesSnapshot($id_product, 0, (int)$defaultCurrency->id);
if ((float)$snapDefault['sale'] != 0.0) {
$last = $this->getLastSnapshot($id_product, 0);
$check_currency = $this->checkCurrencyConversionRate($id_product, 0);
$changed =
empty($last)
|| abs((float)$last['price_regular'] - (float)$snapDefault['regular']) > 0.0001
|| abs((float)$last['price_sale'] - (float)$snapDefault['sale']) > 0.0001
|| (int)$last['has_discount'] !== (int)$snapDefault['has_discount']
|| (bool)$check_currency === true;
if ($changed) {
$this->clearLastPrice($id_product, 0);
foreach ($currencies as $currency) {
$c = $this->normalizeCurrency($currency);
$id_currency = (int)$c['id'];
$conversion_rate = (float)$c['rate'];
if ($id_currency <= 0) {
continue;
}
$isDefaultCurrency = ($id_currency === (int)$defaultCurrency->id) ? 1 : 0;
$snap = $this->getPricesSnapshot($id_product, 0, $id_currency);
if ((float)$snap['sale'] <= 0.0) {
continue;
}
$this->insertToOmnibusTable(
$id_product,
0,
$snap,
$id_currency,
$isDefaultCurrency,
$conversion_rate
);
}
}
}
}
protected function addProductPriceWithCombinations($id_product = null)
{
if (!isset($id_product))
{
throw new Exception('Missing parameter: $id_product');
}
$id_product = (int)$id_product;
Product::flushPriceCache();
$defaultCurrency = Currency::getDefaultCurrency();
$id_default_currency = (int)$defaultCurrency->id;
// Najstabilniejsza lista kombinacji (bez powtórek)
$attributeRows = Product::getProductAttributesIds($id_product);
if (empty($attributeRows))
{
return;
}
// Lista walut (aktywnych)
$currencies = Currency::getCurrencies(true, true);
foreach ($attributeRows as $row)
{
$id_product_attribute = (int)$row['id_product_attribute'];
// Snapshot w default walucie do porównania zmian
$snapDefault = $this->getPricesSnapshot($id_product, $id_product_attribute, $id_default_currency);
if ((float)$snapDefault['sale'] <= 0.0)
{
continue;
}
$last = $this->getLastSnapshot($id_product, $id_product_attribute);
$check_currency = $this->checkCurrencyConversionRate($id_product, $id_product_attribute);
$changed =
empty($last)
|| abs((float)$last['price_regular'] - (float)$snapDefault['regular']) > 0.0001
|| abs((float)$last['price_sale'] - (float)$snapDefault['sale']) > 0.0001
|| (int)$last['has_discount'] !== (int)$snapDefault['has_discount']
|| (bool)$check_currency === true;
if (!$changed)
{
continue;
}
// Zerujemy is_last dla tej kombinacji (dla wszystkich walut)
$this->clearLastPrice($id_product, $id_product_attribute);
// Wstawiamy nowe snapshoty dla wszystkich walut
foreach ($currencies as $currency)
{
$c = $this->normalizeCurrency($currency);
$id_currency = (int)$c['id'];
$conversion_rate = (float)$c['rate'];
if ($id_currency <= 0)
{
continue;
}
$isDefaultCurrency = ($id_currency === $id_default_currency) ? 1 : 0;
$snap = $this->getPricesSnapshot($id_product, $id_product_attribute, $id_currency);
if ((float)$snap['sale'] <= 0.0)
{
continue;
}
$this->insertToOmnibusTable(
$id_product,
$id_product_attribute,
$snap,
$id_currency,
$isDefaultCurrency,
$conversion_rate
);
}
}
}
protected function insertToOmnibusTable($id_product = 0, $id_product_attribute = 0, $snap = [], $currency = 0, $isDefaultCurrency = 0, $CurrencyConversionRate = 0)
{
return Db::getInstance()->insert('omnibus_eu_free', [
'id_product' => (int) $id_product,
'id_product_attribute' => (int) $id_product_attribute,
// zostaw stare price jako "sale" dla kompatybilności szablonu / starego kodu
'price' => pSQL($snap['sale']),
'price_regular' => pSQL($snap['regular']),
'price_sale' => pSQL($snap['sale']),
'has_discount' => (int) $snap['has_discount'],
'discount_diff' => pSQL($snap['diff']),
'id_currency' => (int) $currency,
'is_default_currency' => (int) $isDefaultCurrency,
'is_last' => 1,
'currency_conversion_rate' => pSQL($CurrencyConversionRate)
]);
}
protected function getLastPrice($id_product = 0, $id_product_attribute = 0)
{
$sql = new DbQuery();
$sql->select('price');
$sql->from('omnibus_eu_free');
$sql->where('id_product = ' . (int) $id_product);
$sql->where('id_product_attribute = ' . (int) $id_product_attribute);
$sql->where('is_last = 1');
$sql->where('is_default_currency = 1');
$sql->limit(1);
return Db::getInstance()->executeS($sql);
}
protected function getOmnibusData($id_product = null)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
$historyDays = (int) Configuration::get('OMNIBUSEUFREE_HISTORY_DAYS', null, null, null, 60);
$sql = new DbQuery();
$sql->select('*');
$sql->from('omnibus_eu_free');
$sql->where('id_product = ' . (int) $id_product);
$sql->where('(`is_last` = 1 OR `date_add` >= DATE_SUB(NOW(), INTERVAL ' . $historyDays . ' DAY))');
$sql->orderBy('is_default_currency DESC');
$sql->orderBy('id_currency ASC');
$sql->orderBy('id_product_attribute ASC');
$sql->orderBy('id_omnibuseufree DESC');
return Db::getInstance()->executeS($sql);
}
protected function clearLastPrice($id_product = 0, $id_product_attribute = 0)
{
$result = Db::getInstance()->update('omnibus_eu_free', array(
'is_last' => 0,
), 'id_product = ' . (int) $id_product . ' AND id_product_attribute = ' . (int) $id_product_attribute);
}
public function insertAllProductsToOmnibusTable()
{
$counter = 0;
$ProductClass = new Product();
$ProductClass->flushPriceCache();
$products = $ProductClass->getProducts($this->context->language->id, 0, 0, 'id_product', 'ASC');
foreach ($products as $product) {
$this->addProductPriceWithCombinations($product['id_product']);
$this->addProductPrice($product['id_product']);
$counter++;
}
return $counter;
}
public function removeOldDataFromOmnibusTable()
{
$numberOfDays = (int) Configuration::get('OMNIBUSEUFREE_HISTORY_DAYS', null, null, null, 60);
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'omnibus_eu_free`
WHERE `is_last` = 0
AND `date_add` < DATE_SUB(NOW(), INTERVAL ' . $numberOfDays . ' DAY)'
);
return (int) Db::getInstance()->Affected_Rows();
}
}