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)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
if (!isset($currency)) {
$defaultCurrency = Currency::getDefaultCurrency();
$currency = $defaultCurrency->id;
}
$info_version = Configuration::get('OMNIBUSEUFREE_INFORMATION_VERSION', null, null, null, 2);
$NumberOfDays = (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30);
$date = new DateTime();
$date->modify('-' . $NumberOfDays . ' days');
$CutOffDate = $date->format('Y-m-d');
$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('id_currency = ' . (int) $currency);
$sql->where('date_add >= "'.$CutOffDate.' 00:00:00"');
if ($info_version == 2) {
$sql->where('is_last = 0');
}
$sql->orderBy('price ASC');
$sql->limit(1);
$sqlResult = Db::getInstance()->executeS($sql);
return (!empty($sqlResult)) ? $sqlResult[0] : array();
}
public function hookDisplayOmnibusEuFree($params)
{
$currency = $this->context->currency;
$lastMinimalPrice = $this->getLastMinimalPrice($params['product']['id_product'], $params['product']['id_product_attribute'], $currency->id);
$regularPrice = isset($params['product']['regular_price']) ? $params['product']['regular_price'] : null;
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'],
'OmnibuseufreeProductPriceRegular' => $regularPrice,
'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'] = 'done';
}
$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, 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'),
'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 .= '
' . $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 .= '
' . $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 addProductPrice($id_product = null)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
$product = new Product($id_product);
$product_price = $product->getPrice();
if($product_price != 0){
$omnibus_price = array();
$omnibus_price = $this->getLastPrice($id_product, 0);
$check_currency = $this->checkCurrencyConversionRate($id_product, 0);
if (empty($omnibus_price) || $product_price != $omnibus_price[0]['price'] || (bool) $check_currency == true) {
$this->clearLastPrice($id_product);
$currencies = Currency::getCurrencies();
$defaultCurrency = Currency::getDefaultCurrency();
foreach ($currencies as $currency) {
if ($currency['id_currency'] == $defaultCurrency->id) {
$isDefaultCurrency = 1;
$product_price_currency = $product_price;
}
else {
$isDefaultCurrency = 0;
$product_price_currency = Tools::convertPrice($product_price, $currency);
}
$this->insertToOmnibusTable($id_product, 0, $product_price_currency, $currency['id_currency'], $isDefaultCurrency, $currency['conversion_rate']);
}
}
}
}
protected function addProductPriceWithCombinations($id_product = null)
{
if (!isset($id_product)) {
throw new Exception('Missing parameter: $id_product');
}
$product = new Product($id_product);
$product_combinations = $product->getAttributeCombinations();
if (!empty($product_combinations)) {
$currencies = Currency::getCurrencies();
$defaultCurrency = Currency::getDefaultCurrency();
foreach ($product_combinations as $combination) {
$product_price = $product->getPrice(true, $combination['id_product_attribute']);
if($product_price != 0){
$omnibus_price = array();
$omnibus_price = $this->getLastPrice($id_product, $combination['id_product_attribute']);
$check_currency = $this->checkCurrencyConversionRate($id_product, $combination['id_product_attribute']);
if (empty($omnibus_price) || $product_price != $omnibus_price[0]['price'] || (bool) $check_currency == true) {
$this->clearLastPrice($id_product, $combination['id_product_attribute']);
foreach ($currencies as $currency) {
if ($currency['id_currency'] == $defaultCurrency->id) {
$isDefaultCurrency = 1;
$product_price_currency = $product_price;
}
else {
$isDefaultCurrency = 0;
$product_price_currency = Tools::convertPrice($product_price, $currency);
}
$this->insertToOmnibusTable($id_product, $combination['id_product_attribute'], $product_price_currency, $currency['id_currency'], $isDefaultCurrency, $currency['conversion_rate']);
}
}
}
}
}
}
protected function insertToOmnibusTable($id_product = 0, $id_product_attribute = 0, $product_price = 0, $currency = 0, $isDefaultCurrency = 0, $CurrencyConversionRate = 0)
{
$result = Db::getInstance()->insert('omnibus_eu_free', [
'id_product' => (int) $id_product,
'id_product_attribute' => (int) $id_product_attribute,
'price' => pSQL($product_price),
'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();
}
}