name = 'deliverydate'; $this->tab = 'shipping_logistics'; $this->version = '1.4.2'; $this->module_key = '512f4d91276fa09d3117008695cb3a3c'; $this->author = 'MARICHAL Emmanuel'; parent::__construct (); $this->displayName = $this->l('Delivery dates'); $this->description = $this->l('Display delivery dates in order process and product page'); $this->bootstrap = true; } public function install() { Configuration::updateValue('DELIVERYDATE_PREP_TIME', 1); $success = Db::getInstance()->Execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'delivery_date` ( `id` int(10) NOT NULL AUTO_INCREMENT, `id_carrier` int(10), `id_zone` int(10), `days` varchar(14) DEFAULT NULL, `min` int(10) DEFAULT 0, `max` int(10) DEFAULT 0, `hours` int(10) DEFAULT 0, `minutes` int(10) DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `DeliveryDateCarrierIndex` (`id_carrier`, `id_zone`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;') && Db::getInstance()->Execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'delivery_date_history` ( `id` int(10) NOT NULL AUTO_INCREMENT, `id_order` int(10), `date_min` date NOT NULL, `date_max` date NOT NULL, PRIMARY KEY (`id`), KEY `DeliveryDateOrderIndex` (`id_order`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;') && $this->createExceptionsTable() && parent::install() && $this->registerHook('displayBeforeCarrier') && $this->registerHook('updateCarrier') && $this->registerHook('actionValidateOrder') && $this->registerHook('displayAdminOrder') && $this->registerHook('displayOrderDetail') && $this->registerHook('header') && $this->registerHook('displayPDFInvoice') && $this->registerHook('productTab') // 1.6-1.5 && $this->registerHook('productTabContent') // 1.6-1.5 && $this->registerHook('displayProductExtraContent') // 1.7 && $this->registerHook('displayProductButtons'); if (version_compare(_PS_VERSION_, '1.6', '>')) return $success && $this->registerHook('displayAdminOrderTabShip') && $this->registerHook('displayAdminOrderContentShip'); else { return $success && $this->registerHook('displayAdminOrder'); } } private function createExceptionsTable() { return Db::getInstance()->Execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'delivery_date_exceptions` ( `id` int(10) NOT NULL AUTO_INCREMENT, `id_carrier` int(10), `id_zone` int(10), `date` date NOT NULL, `delivery` int(1) DEFAULT 0, `preparation` int(1) DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `DeliveryDateException` (`id_carrier`, `id_zone`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;'); } public function hookHeader($params) { if (Context::getContext()->controller instanceof OrderController) { $this->context->controller->addJS($this->_path.'views/js/before_carrier.js'); if (version_compare(_PS_VERSION_, '1.7.0.0', '<')) { $this->context->controller->addCSS($this->_path.'views/css/before_carrier.css'); } else { $this->context->controller->addCSS($this->_path.'views/css/before_carrier_17.css'); } } } public function hookDisplayProductButtons($params) { if (is_array($params['product']) && $params['product']['is_virtual']) return ''; else if (!is_array($params['product']) && $params['product']->is_virtual) return ''; $carriers = $this->getProductPageCarriers(); if (empty($carriers)) return ''; $best_available = 0; $best_oot = 0; // Search for the best date foreach ($carriers as $carrier) { if (!$best_available || $carrier['min'] < $best_available) $best_available = $carrier['min']; if ((isset($carrier['oot_min']) && $carrier['oot_min']) && (!$best_oot || $carrier['oot_min'] < $best_oot)) $best_oot = $carrier['oot_min']; } if (!$best_available) return ''; $this->context->smarty->assign('available_text', str_replace(array('[date_min]'), array(date($this->context->language->date_format_lite, $best_available)), $this->l('Delivery expected from [date_min]'))); if ($best_oot) $this->context->smarty->assign('oot_text', str_replace(array('[date_min]'), array(date($this->context->language->date_format_lite, $best_oot)), $this->l('Delivery expected from [date_min]'))); if (version_compare(_PS_VERSION_, '1.7.0.0', '<')) return $this->display(__FILE__, 'views/templates/hook/add_to_cart_block.tpl'); else return $this->display(__FILE__, 'views/templates/hook/add_to_cart_block_17.tpl'); } public function hookProductTab($params) { if (is_array($params['product']) && (int)$params['product']['is_virtual']) return ''; else if (!is_array($params['product']) && (int)$params['product']->is_virtual) return ''; $carriers = $this->getProductPageCarriers(); if (!empty($carriers) && Configuration::get('DELIVERYDATE_TABS')) return $this->display(__FILE__, 'views/templates/hook/product_tab.tpl'); else return ''; } public function hookProductTabContent($params) { $this->context->controller->addJS($this->_path.'views/js/product.js'); $this->context->smarty->assign('tab', Configuration::get('DELIVERYDATE_TABS')); return $this->hookDisplayFooterProduct($params); } private function getProductTabContent($product, $only_content = false) { if ($product->is_virtual) return ''; $carriers = $this->getProductPageCarriers(); if (empty($carriers)) return ''; $this->context->smarty->assign(array( 'carriers' => $carriers, 'only_content' => $only_content )); return $this->display(__FILE__, 'views/templates/hook/product_tab_content.tpl'); } public function hookDisplayProductExtraContent($params) { $tabs = array(); $content = $this->getProductTabContent($params['product'], true); if (empty($content)) return $tabs; $pec = new PrestaShop\PrestaShop\Core\Product\ProductExtraContent(); $tabs[] = $pec->setTitle($this->l('Delivery'))->setContent($content); $this->context->controller->addJS($this->_path.'views/js/product17.js'); $this->context->controller->addCSS($this->_path.'views/css/product.css'); return $tabs; } public function hookDisplayFooterProduct($params) { return $this->getProductTabContent($params['product']); } public function getFormatedDeliveryText($min, $max, $date_format_lite) { if ($min == $max) $text = str_replace(array('[date_min]'), array(date($date_format_lite, $min)), $this->l('Delivery scheduled the [date_min]')); else $text = str_replace(array('[date_min]', '[date_max]'), array(''.date($date_format_lite, $min).'', ''.date($date_format_lite, $max).''), $this->l('Delivery scheduled between the [date_min] and [date_max]')); return $text; } private function getProductPageCarriers() { static $carriers = null; if ($carriers) return $carriers; $carriers = array(); $config = Configuration::getMultiple(array( 'DELIVERYDATE_PREP_DAYS', 'DELIVERYDATE_PREP_TIME', 'DELIVERYDATE_OUT_OF_STOCK', 'DELIVERYDATE_PRODUCT', 'PS_STOCK_MANAGEMENT', 'DELIVERYDATE_DATE_MAX' )); if (!isset($config['DELIVERYDATE_PREP_DAYS']) || !isset($config['DELIVERYDATE_PRODUCT']) || !$config['DELIVERYDATE_PRODUCT']) return $carriers; // Get preparation days and exit if at least one day is not selected $prep_days = explode(',', $config['DELIVERYDATE_PREP_DAYS']); if (array_search(1, $prep_days) === false) return $carriers; $id_address = $this->context->cart->id_address_delivery; if ($id_address) { $address = new Address($id_address); if (!Validate::isLoadedObject($address)) return false; if (!Address::isCountryActiveById($address->id)) return false; $id_zone = Address::getZoneById($address->id); } else { $country = new Country(Configuration::get('PS_COUNTRY_DEFAULT')); $id_zone = $country->id_zone; } $product = new Product(Tools::getValue('id_product')); if (!Validate::isLoadedObject($product)) return $carriers; $product->loadStockData(); $available_carriers = Carrier::getAvailableCarrierList($product, 0); if (!$available_carriers || !is_array($available_carriers) || empty($available_carriers)) return $carriers; $conditions = Db::getInstance()->ExecuteS(' SELECT dd.*, c.name FROM '._DB_PREFIX_.'delivery_date dd LEFT JOIN '._DB_PREFIX_.'carrier c ON c.id_carrier = dd.id_carrier WHERE dd.id_zone = '.(int)$id_zone.' AND dd.id_carrier IN ('.implode(',', array_map('intval', array_values($available_carriers))).') '); if (!$conditions || empty($conditions)) return $carriers; foreach ($conditions as $condition) { $exceptions = self::getDeliveryExceptions($id_zone, $condition['id_carrier']); $dates = self::getDeliveryDelay($condition, $exceptions, $config, $prep_days, $product->quantity <= 0 ? true : false); $oot_dates = $config['PS_STOCK_MANAGEMENT'] ? self::getDeliveryDelay($condition, $exceptions, $config, $prep_days, true) : false; $carriers[$condition['id_carrier']] = array(); $carriers[$condition['id_carrier']]['logo'] = _THEME_SHIP_DIR_.$condition['id_carrier'].'.jpg'; $carriers[$condition['id_carrier']]['name'] = $condition['name']; $carriers[$condition['id_carrier']]['date'] = $this->getFormatedDeliveryText($dates['start'], $dates['end'], $this->context->language->date_format_lite); $carriers[$condition['id_carrier']]['min'] = $dates['start']; if ($oot_dates) { $carriers[$condition['id_carrier']]['oot_date'] = $this->getFormatedDeliveryText($oot_dates['start'], $oot_dates['end'], $this->context->language->date_format_lite); $carriers[$condition['id_carrier']]['oot_min'] = $oot_dates['start']; } } return $carriers; } public function hookDisplayOrderDetail($params) { $id_order = $params['order']->id; $dates = Db::getInstance()->getRow('SELECT date_min AS min, date_max AS max FROM '._DB_PREFIX_.'delivery_date_history WHERE id_order = '.(int)$id_order); if (!$dates) return ''; $dates['min'] = date($this->context->language->date_format_lite, strtotime($dates['min'])); $dates['max'] = date($this->context->language->date_format_lite, strtotime($dates['max'])); if ($dates['min'] == $dates['max']) $text = str_replace(array('[date_min]'), array($dates['min']), $this->l('Delivery scheduled the [date_min]')); else $text = str_replace(array('[date_min]', '[date_max]'), array($dates['min'], $dates['max']), $this->l('Delivery scheduled between the [date_min] and [date_max]')); $this->context->smarty->assign('text', $text); return $this->display(__FILE__, 'views/templates/hook/order_detail.tpl');; } public function hookPDFInvoice($params) { return $this->hookDisplayPDFInvoice($params); } public function hookDisplayPDFInvoice($params) { $id_order = (_PS_VERSION_ > '1.5' ? $params['object']->id_order : $params['id_order']); $dates = Db::getInstance()->getRow('SELECT date_min AS min, date_max AS max FROM '._DB_PREFIX_.'delivery_date_history WHERE id_order = '.(int)$id_order); if (!$dates) return ''; $dates['min'] = date($this->context->language->date_format_lite, strtotime($dates['min'])); $dates['max'] = date($this->context->language->date_format_lite, strtotime($dates['max'])); $text = str_replace(array('[date_min]', '[date_max]'), array($dates['min'], $dates['max']), $this->l('Delivery scheduled between the [date_min] and [date_max]')); if (_PS_VERSION_ > '1.5') return $text; else { $pdf = $params['pdf']; $pdf->Ln(10); $pdf->Cell(0, 0, utf8_decode($text)); } } public function hookUpdateCarrier($params) { Db::getInstance()->Execute(' UPDATE '._DB_PREFIX_.'delivery_date SET id_carrier = '.(int)$params['carrier']->id.' WHERE id_carrier = '.(int)$params['id_carrier']); } public function hookNewOrder($params) { return $this->hookActionValidateOrder($params); } public function hookActionValidateOrder($params) { $condition = Db::getInstance()->getRow(' SELECT * FROM '._DB_PREFIX_.'delivery_date WHERE id_carrier = '.(int)$params['cart']->id_carrier.' AND id_zone = '.(int)Address::getZoneById($params['cart']->id_address_delivery) ); $config = Configuration::getMultiple(array( 'DELIVERYDATE_PREP_DAYS', 'DELIVERYDATE_PREP_TIME', 'DELIVERYDATE_OUT_OF_STOCK', 'PS_STOCK_MANAGEMENT', 'DELIVERYDATE_DATE_MAX' )); if (!$condition || !isset($config['DELIVERYDATE_PREP_DAYS'])) return; // Get preparation days and exit if at least one day is not selected $prep_days = explode(',', $config['DELIVERYDATE_PREP_DAYS']); if (array_search(1, $prep_days) === false) return; $outofstock = $config['PS_STOCK_MANAGEMENT'] ? $this->cartContainsOutOfStockProducts() : false; $id_zone = Address::getZoneById($params['cart']->id_address_delivery); $exceptions = self::getDeliveryExceptions($id_zone, $params['cart']->id_carrier); $delay = self::getDeliveryDelay($condition, $exceptions, $config, $prep_days, $outofstock); Db::getInstance()->execute(' INSERT INTO '._DB_PREFIX_.'delivery_date_history (id_order, date_min, date_max) VALUES('.(int)$params['order']->id.', "'.date('Y-m-d', $delay['start']).'", "'.date('Y-m-d', $delay['end']).'")'); } public function hookAdminOrder($params) { return $this->hookDisplayAdminOrder($params); } private function getOrderDeliveryDates($id_order) { static $dates = null; if ($dates !== null) return $dates; $dates = Db::getInstance()->getRow(' SELECT UNIX_TIMESTAMP(date_min) AS date_min, UNIX_TIMESTAMP(date_max) AS date_max FROM '._DB_PREFIX_.'delivery_date_history WHERE id_order = '.(int)$id_order ); if ($dates) $dates = array( 'date_min' => date($this->context->language->date_format_lite, $dates['date_min']), 'date_max' => date($this->context->language->date_format_lite, $dates['date_max']) ); return $dates; } public function hookDisplayAdminOrderTabShip($params) { $dates = $this->getOrderDeliveryDates($params['order']->id); if (!$dates) return ''; else return $this->display(__FILE__, 'admin_order_tab_ship.tpl'); } public function hookDisplayAdminOrderContentShip($params) { $dates = $this->getOrderDeliveryDates($params['order']->id); if (!$dates) return ''; else { $this->context->smarty->assign($dates); return $this->display(__FILE__, 'admin_order_content_ship.tpl'); } } public function hookDisplayAdminOrder($params) { if (version_compare(_PS_VERSION_, '1.6.0.0', '>=')) return; $dates = $this->getOrderDeliveryDates($params['id_order']); if (!$dates) return ''; else { $this->context->smarty->assign($dates); return $this->display(__FILE__, 'admin_order.tpl'); } } private static function getDeliveryDelay($condition, $exceptions, $config, $prep_days, $outofstock) { $days = 0; $delay = array(); // Making sure that max is > than min if ($condition['min'] > $condition['max']) { $real_max = $condition['min']; $condition['min'] = $condition['max']; $condition['max'] = $real_max; } // Check if today is count as an expedition day if (strtotime($condition['hours'].':'.$condition['minutes']) < strtotime('now')) $days += 1; // Additionnal time for out of stock if ($outofstock && !$config['DELIVERYDATE_DATE_MAX']) $days += (int)$config['DELIVERYDATE_OUT_OF_STOCK']; // Add preparation time $time = (int)$config['DELIVERYDATE_PREP_TIME']; while ($time) { $index = date('w', strtotime('+'.$days.' day')); $date = date('Y-m-d', strtotime('+'.$days.' day')); if ($prep_days[$index ? $index - 1 : 6] == 1 && !in_array($date, $exceptions['preparation'])) $time -= 1; $days += 1; } // Get delivery days $delivery = explode(',', $condition['days']); // Add days until min delay is reach (-1 because first day is count as a delivery day) $min = (int)$condition['min'] - 1; $index = date('w', strtotime('+'.$days.' day')); while (in_array(date('Y-m-d', strtotime('+'.$days.' day')), $exceptions['delivery']) || $delivery[$index ? $index - 1 : 6] == 0) { $days += 1; $index = date('w', strtotime('+'.$days.' day')); } while ($min > 0) { $index = date('w', strtotime('+'.$days.' day')); $date = date('Y-m-d', strtotime('+'.$days.' day')); if ($delivery[$index ? $index - 1 : 6] == 1 && !in_array($date, $exceptions['delivery'])) $min -= 1; $days += 1; // Making sure that we don't stop on a non-delivery day if ($min == 0) { $index = date('w', strtotime('+'.$days.' day')); while ($delivery[$index ? $index - 1 : 6] == 0 || in_array(date('Y-m-d', strtotime('+'.$days.' day')), $exceptions['delivery'])) { $days += 1; $index = date('w', strtotime('+'.$days.' day')); } } } // Save the date $delay['start'] = strtotime('+'.$days.' day'); // Additionnal time for out of stock if ($outofstock && $config['DELIVERYDATE_DATE_MAX']) $days += (int)$config['DELIVERYDATE_OUT_OF_STOCK']; // Add days until max delay is reach $max = (int)$condition['max'] - (int)$condition['min']; while ($max) { $index = date('w', strtotime('+'.$days.' day')); $date = date('Y-m-d', strtotime('+'.$days.' day')); if ($delivery[$index ? $index - 1 : 6] == 1 && !in_array($date, $exceptions['delivery'])) $max--; $days += 1; // Making sure that we don't stop on a non-delivery day if ($max == 0) { $index = date('w', strtotime('+'.$days.' day')); while ($delivery[$index ? $index - 1 : 6] == 0 || in_array(date('Y-m-d', strtotime('+'.$days.' day')), $exceptions['delivery'])) { $days += 1; $index = date('w', strtotime('+'.$days.' day')); } } } // Save the date $delay['end'] = strtotime('+'.$days.' day'); return $delay; } private function cartContainsOutOfStockProducts() { foreach ($this->context->cart->getProducts() as $product) if ($product['stock_quantity'] < $product['cart_quantity']) return true; return false; } public function hookBeforeCarrier($params) { return $this->hookDisplayBeforeCarrier($params); } public function getDeliveryExceptions($id_zone, $id_carrier) { static $exceptions = null; if ($exceptions === null) $exceptions = Db::getInstance()->ExecuteS('SELECT * FROM '._DB_PREFIX_.'delivery_date_exceptions WHERE id_zone = '.(int)$id_zone); $values = array('preparation' => array(), 'delivery' => array()); if ($exceptions) foreach ($exceptions as $exception) if ($exception['id_carrier'] == $id_carrier) { if (!$exception['preparation']) $values['preparation'][] = $exception['date']; if (!$exception['delivery']) $values['delivery'][] = $exception['date']; } return $values; } public function hookDisplayBeforeCarrier($params) { $id_zone = Address::getZoneById($this->context->cart->id_address_delivery); $conditions = Db::getInstance()->ExecuteS('SELECT * FROM '._DB_PREFIX_.'delivery_date WHERE id_zone = '.(int)$id_zone); $carriers = Carrier::getCarriersForOrder($id_zone, Customer::getGroupsStatic($this->context->cart->id_customer)); $deliveries = array(); $config = Configuration::getMultiple(array( 'DELIVERYDATE_PREP_DAYS', 'DELIVERYDATE_PREP_TIME', 'DELIVERYDATE_OUT_OF_STOCK', 'PS_STOCK_MANAGEMENT', 'DELIVERYDATE_POSITION', 'DELIVERYDATE_REASON', 'DELIVERYDATE_DATE_MAX' )); if (!$conditions || empty($carriers) || !isset($config['DELIVERYDATE_PREP_DAYS'])) return false; $outofstock = $config['PS_STOCK_MANAGEMENT'] ? $this->cartContainsOutOfStockProducts() : false; // Get preparation days and exit if at least one day is not selected $prep_days = explode(',', $config['DELIVERYDATE_PREP_DAYS']); if (array_search(1, $prep_days) === false) return; foreach ($carriers as $carrier) foreach ($conditions as $condition) if ((int)$condition['id_carrier'] == (int)$carrier['id_carrier']) { $exceptions = self::getDeliveryExceptions($id_zone, $carrier['id_carrier']); $delay = self::getDeliveryDelay($condition, $exceptions, $config, $prep_days, $outofstock); $deliveries[$carrier['id_carrier']] = array(); $deliveries[$carrier['id_carrier']]['name'] = $carrier['name']; $deliveries[$carrier['id_carrier']]['start'] = date($this->context->language->date_format_lite, $delay['start']); $deliveries[$carrier['id_carrier']]['end'] = date($this->context->language->date_format_lite, $delay['end']); } $this->context->smarty->assign(array( 'deliveries' => Tools::jsonEncode($deliveries), 'position' => isset($config['DELIVERYDATE_POSITION']) ? $config['DELIVERYDATE_POSITION'] : 'bottom', 'reason' => isset($config['DELIVERYDATE_REASON']) ? $config['DELIVERYDATE_REASON'] : '' )); return $this->display(__FILE__, 'views/templates/hook/before_carrier_js.tpl').$this->display(__FILE__, 'views/templates/hook/before_carrier.tpl'); } private function saveRule() { if (Tools::getValue('min') == 0 || Tools::getValue('max') == 0) { $this->_errors[] = $this->l('Delivery time must be at least 1 day'); return false; } $days = implode(',', array( (int)Tools::getValue('monday'), (int)Tools::getValue('tuesday'), (int)Tools::getValue('wednesday'), (int)Tools::getValue('thursday'), (int)Tools::getValue('friday'), (int)Tools::getValue('saturday'), (int)Tools::getValue('sunday')) ); $errors = array(); $id_carrier = Tools::getValue('carrier'); if (!Validate::isUnsignedInt($id_carrier) || !$id_carrier) $errors[] = $this->l('You must select a carrier'); $id_zone = Tools::getValue('zone'); if (!Validate::isUnsignedInt($id_zone) || !$id_zone) $errors[] = $this->l('You must select a zone'); $min = Tools::getValue('min'); if (!Validate::isUnsignedInt($min) || !$min) $errors[] = $this->l('You must set a min value'); $max = Tools::getValue('max'); if (!Validate::isUnsignedInt($max) || !$max) $errors[] = $this->l('You must set a max value'); $hours = Tools::getValue('hours'); if (!Validate::isUnsignedInt($hours) || !$hours) $errors[] = $this->l('Wrong expedition limit'); $minutes = Tools::getValue('minutes'); if (!Validate::isUnsignedInt($minutes) || !$minutes) $errors[] = $this->l('Wrong expedition limit'); $id_rule = Tools::getValue('id_rule'); if ($id_rule) $sql = 'UPDATE '._DB_PREFIX_.'delivery_date SET id_carrier = '.(int)$id_carrier.', id_zone = '.(int)$id_zone.', days = "'.pSQL($days).'", min = '.(int)$min.', max = '.(int)$max.', hours = '.(int)$hours.', minutes = '.(int)$minutes.' WHERE id = '.(int)$id_rule; else $sql = 'INSERT INTO '._DB_PREFIX_.'delivery_date (id_carrier, id_zone, days, min, max, hours, minutes) VALUES('.(int)$id_carrier.', '.(int)$id_zone.', "'.pSQL($days).'", '.(int)$min.', '.(int)$max.', '.(int)$hours.', '.(int)$min.')'; try { if (!Db::getInstance()->Execute($sql)) throw new PrestaShopDatabaseException(); $this->_confirmations[] = $this->l('Saved with success'); } catch (PrestaShopDatabaseException $e) { $this->_errors[] = $this->l('An error occurred'); return false; } return true; } private function saveException() { $errors = array(); $date = Tools::getValue('date'); if (!$date || !Validate::isDate($date)) $errors[] = $this->l('You must select a date'); $id_carrier = Tools::getValue('carrier'); if (!Validate::isUnsignedInt($id_carrier) || !$id_carrier) $errors[] = $this->l('You must select a carrier'); $id_zone = Tools::getValue('zone'); if (!Validate::isUnsignedInt($id_zone) || !$id_zone) $errors[] = $this->l('You must select a zone'); if (count($errors)) { $this->_errors = array_merge($this->_errors, $errors); return false; } $preparation = Tools::getValue('preparation') ? 1 : 0; $delivery = Tools::getValue('delivery') ? 1 : 0; $id_exception = Tools::getValue('id_exception'); if ($id_exception) $sql = 'UPDATE '._DB_PREFIX_.'delivery_date_exceptions SET id_carrier = '.(int)$id_carrier.', id_zone = '.(int)$id_zone.', date = "'.pSQL($date).'", preparation = '.(int)$preparation.', delivery = '.(int)$delivery.' WHERE id = '.(int)$id_exception; else $sql = 'INSERT INTO '._DB_PREFIX_.'delivery_date_exceptions (id_carrier, id_zone, date, preparation, delivery) VALUES('.(int)$id_carrier.', '.(int)$id_zone.', "'.pSQL($date).'", '.(int)$preparation.', '.(int)$delivery.')'; try { if (!Db::getInstance()->Execute($sql)) throw new PrestaShopDatabaseException(); $this->_confirmations[] = $this->l('Saved with success'); } catch (PrestaShopDatabaseException $e) { $this->_errors[] = $this->l('An error occurred'); return false; } return true; } private function delCondition($id) { $_GET['dd_tab'] = 'rules'; if (Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'delivery_date WHERE id = '.(int)$id)) { $this->_confirmations[] = $this->l('Rule deleted with success'); return true; } else { $this->_errors[] = $this->l('An error occurred'); return false; } } private function delException($id) { $_GET['dd_tab'] = 'exceptions'; if (Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'delivery_date_exceptions WHERE id = '.(int)$id)) { $this->_confirmations[] = $this->l('Exception deleted with success'); return true; } else { $this->_errors[] = $this->l('An error occurred'); return false; } } private function saveSettings() { $errors = array(); if (Tools::getValue('prep_time') == 0) $errors[] = $this->l('Preparation time must be at least 1 day.'); if (!Validate::isMessage(Tools::getValue('reason'))) $errors[] = $this->l('Your message can\'t contain HTML.'); if (count($errors)) { $this->_errors = array_merge($this->_errors, $errors); return false; } Configuration::updateValue('DELIVERYDATE_PREP_DAYS', implode(',', array( (int)Tools::getValue('monday'), (int)Tools::getValue('tuesday'), (int)Tools::getValue('wednesday'), (int)Tools::getValue('thursday'), (int)Tools::getValue('friday'), (int)Tools::getValue('saturday'), (int)Tools::getValue('sunday') ))); Configuration::updateValue('DELIVERYDATE_PREP_TIME', (int)Tools::getValue('prep_time')); Configuration::updateValue('DELIVERYDATE_OUT_OF_STOCK', (int)Tools::getValue('outofstock')); Configuration::updateValue('DELIVERYDATE_POSITION', Tools::getValue('position')); Configuration::updateValue('DELIVERYDATE_REASON', Tools::getValue('reason')); Configuration::updateValue('DELIVERYDATE_PRODUCT', Tools::getValue('product')); Configuration::updateValue('DELIVERYDATE_TABS', (bool)Tools::getValue('tabs')); Configuration::updateValue('DELIVERYDATE_DATE_MAX', (bool)Tools::getValue('max_date')); $this->_confirmations[] = $this->l('Settings saved with success'); return true; } private function renderMainView() { $this->context->controller->addCSS($this->_path.'views/css/settings.css'); $config = Configuration::getMultiple(array( 'DELIVERYDATE_PREP_DAYS', 'DELIVERYDATE_PREP_TIME', 'DELIVERYDATE_OUT_OF_STOCK', 'DELIVERYDATE_POSITION', 'DELIVERYDATE_REASON', 'DELIVERYDATE_TABS', 'DELIVERYDATE_PRODUCT', 'DELIVERYDATE_DATE_MAX' )); $carriers = Carrier::getCarriers((int)$this->context->cookie->lang, false, false, false, null, Carrier::ALL_CARRIERS); if (!$carriers) { $this->_errors[] = $this->l('You must create an active carrier before using this module'); return false; } $zones = Zone::getZones(true); if (!$zones) { $this->_errors[] = $this->l('You must create an active zone before using this module'); return false; } $conditions = Db::getInstance()->ExecuteS(' SELECT dd.id, dd.id_carrier, dd.id_zone, dd.min, dd.max, dd.days, CONCAT(LPAD(dd.hours, 2, 0), CONCAT("h", LPAD(dd.minutes, 2, 0))) time_limit, z.name zone_name, c.name carrier_name FROM '._DB_PREFIX_.'delivery_date dd LEFT JOIN '._DB_PREFIX_.'zone z ON (z.id_zone = dd.id_zone) LEFT JOIN '._DB_PREFIX_.'carrier c ON c.id_carrier = dd.id_carrier ORDER BY dd.id_carrier, dd.id_zone ASC '); foreach ($conditions as &$condition) { $days = explode(',', $condition['days']); $condition['monday'] = isset($days[0]) ? (int)$days[0] : 0; $condition['tuesday'] = isset($days[1]) ? (int)$days[1] : 0; $condition['wednesday'] = isset($days[2]) ? (int)$days[2] : 0; $condition['thursday'] = isset($days[3]) ? (int)$days[3] : 0; $condition['friday'] = isset($days[4]) ? (int)$days[4] : 0; $condition['saturday'] = isset($days[5]) ? (int)$days[5] : 0; $condition['sunday'] = isset($days[6]) ? (int)$days[6] : 0; } $days = isset($config['DELIVERYDATE_PREP_DAYS']) ? explode(',', $config['DELIVERYDATE_PREP_DAYS']) : array(); if (!is_array($days)) $days = array(); $this->context->smarty->assign(array( 'zones' => $zones, 'carriers' => $carriers, 'days' => $days, 'config' => $config )); // Assign rules data $this->smarty->assign(array( 'data_rules' => Tools::jsonEncode(array( 'columns' => array( array('content' => 'ID', 'key' => 'id', 'center' => true), array('content' => $this->l('Carrier'), 'key' => 'carrier_name'), array('content' => $this->l('Zone'), 'key' => 'zone_name'), array('content' => $this->l('Min days'), 'key' => 'min', 'center' => true), array('content' => $this->l('Max days'), 'key' => 'max', 'center' => true), array('content' => $this->l('Monday'), 'key' => 'monday', 'bool' => true, 'center' => true), array('content' => $this->l('Tuesday'), 'key' => 'tuesday', 'bool' => true, 'center' => true), array('content' => $this->l('Wednesday'), 'key' => 'wednesday', 'bool' => true, 'center' => true), array('content' => $this->l('Thursday'), 'key' => 'thursday', 'bool' => true, 'center' => true), array('content' => $this->l('Friday'), 'key' => 'friday', 'bool' => true, 'center' => true), array('content' => $this->l('Saturday'), 'key' => 'saturday', 'bool' => true, 'center' => true), array('content' => $this->l('Sunday'), 'key' => 'sunday', 'bool' => true, 'center' => true), array('content' => $this->l('Expedition limit'), 'key' => 'time_limit', 'center' => true), ), 'rows' => $conditions, 'rows_actions' => array( array('title' => 'Edit', 'action' => 'edit_rule', 'icon' => 'pencil', 'img' => '../img/admin/edit.gif'), array('title' => 'Delete', 'action' => 'delete_rule', 'icon' => 'trash', 'img' => '../img/admin/delete.gif') ), 'top_actions' => array( array('title' => $this->l('Add rule'), 'action' => 'add_rule', 'icon' => 'add', 'img' => 'themes/default/img/process-icon-new.png'), ), 'url_params' => array('configure' => $this->name), 'identifier' => 'id' )) )); $exceptions = Db::getInstance()->ExecuteS(' SELECT dde.id, dde.id_carrier, dde.id_zone, dde.date, dde.preparation, dde.delivery, z.name zone_name, c.name carrier_name FROM '._DB_PREFIX_.'delivery_date_exceptions dde LEFT JOIN '._DB_PREFIX_.'zone z ON (z.id_zone = dde.id_zone) LEFT JOIN '._DB_PREFIX_.'carrier c ON c.id_carrier = dde.id_carrier ORDER BY dde.date, dde.id_carrier, dde.id_zone ASC' ); foreach($exceptions as &$exception) $exception['date'] = Tools::displayDate($exception['date'], $this->context->language->date_format_lite); // Assign exceptions data $this->smarty->assign(array( 'data_exceptions' => Tools::jsonEncode(array( 'columns' => array( array('content' => 'ID', 'key' => 'id', 'center' => true), array('content' => $this->l('Carrier'), 'key' => 'carrier_name'), array('content' => $this->l('Zone'), 'key' => 'zone_name'), array('content' => $this->l('Date'), 'key' => 'date'), array('content' => $this->l('Preparation'), 'key' => 'preparation', 'bool' => true, 'center' => true), array('content' => $this->l('Delivery'), 'key' => 'delivery', 'bool' => true, 'center' => true), ), 'rows' => $exceptions, 'rows_actions' => array( array('title' => 'Edit', 'action' => 'edit_exception', 'icon' => 'pencil', 'img' => '../img/admin/edit.gif'), array('title' => 'Delete', 'action' => 'delete_exception', 'icon' => 'trash', 'img' => '../img/admin/delete.gif') ), 'top_actions' => array( array('title' => $this->l('Add exception'), 'action' => 'add_exception', 'icon' => 'add', 'img' => 'themes/default/img/process-icon-new.png'), ), 'url_params' => array('configure' => $this->name), 'identifier' => 'id' )) )); $modules = $this->getAddonsModules(); if (is_array($modules)) { shuffle($modules); } $this->smarty->assign(array( 'current_url' => $this->context->link->getAdminLink('AdminModules').'&configure='.$this->name.'&tab_module=shipping_logistics&module_name='.$this->name, 'dd_tab' => Tools::getValue('dd_tab'), 'modules' => $modules, 'ps17' => version_compare(_PS_VERSION_, '1.7.0.0', '>='), 'doc_iso' => (file_exists(_PS_MODULE_DIR_.$this->name.'/docs/readme_'.$this->context->language->iso_code.'.pdf') ? $this->context->language->iso_code : 'en') )); return $this->display(__FILE__, 'views/templates/admin/settings.tpl'); } private function renderAddRuleView() { $id_rule = Tools::getValue('id'); if ($id_rule) { $rule = Db::getInstance()->getRow('SELECT * FROM '._DB_PREFIX_.'delivery_date WHERE id = '.(int)$id_rule); if ($rule) { $days = explode(',', $rule['days']); $this->smarty->assign(array( 'rule' => $rule, 'days' => is_array($days) ? $days : array(), 'id_rule' => $id_rule )); } } $current_url = $this->context->link->getAdminLink('AdminModules').'&configure='.$this->name.'&dd_tab=rules&module_name='.$this->name.'&action=add_rule'; if ($id_rule && $rule) $current_url .= '&id_rule='.(int)$id_rule; $cancel_url = $this->context->link->getAdminLink('AdminModules').'&configure='.$this->name.'&tab_module=shipping_logistics&dd_tab=rules&module_name='.$this->name; $this->smarty->assign(array( 'current_url' => $current_url, 'cancel_url' => $cancel_url, 'carriers' => Carrier::getCarriers($this->context->cookie->lang, false, false, false, null, ALL_CARRIERS), 'zones' => Zone::getZones(true), 'doc_iso' => (file_exists(_PS_MODULE_DIR_.$this->name.'/docs/readme_'.$this->context->language->iso_code.'.pdf') ? $this->context->language->iso_code : 'en') )); $this->context->controller->addCSS($this->_path.'views/css/add_rule.css'); return $this->display(__FILE__, 'views/templates/admin/add_rule.tpl'); } private function renderAddExceptionView() { $id_exception = Tools::getValue('id'); $exception = false; if ($id_exception) { $exception = Db::getInstance()->getRow('SELECT * FROM '._DB_PREFIX_.'delivery_date_exceptions WHERE id = '.(int)$id_exception); if ($exception) $this->smarty->assign('exception', $exception); } $current_url = $this->context->link->getAdminLink('AdminModules').'&configure='.$this->name.'&dd_tab=exceptions&module_name='.$this->name.'&action=add_exception'; if ($id_exception && $exception) $current_url .= '&id_exception='.(int)$id_exception; $cancel_url = $this->context->link->getAdminLink('AdminModules').'&configure='.$this->name.'&tab_module=shipping_logistics&dd_tab=exceptions&module_name='.$this->name; $this->smarty->assign(array( 'current_url' => $current_url, 'cancel_url' => $cancel_url, 'carriers' => Carrier::getCarriers($this->context->cookie->lang, false, false, false, null, ALL_CARRIERS), 'zones' => Zone::getZones(true), 'doc_iso' => (file_exists(_PS_MODULE_DIR_.$this->name.'/docs/readme_'.$this->context->language->iso_code.'.pdf') ? $this->context->language->iso_code : 'en') )); $this->context->controller->addJqueryUI('ui.datepicker'); return $this->display(__FILE__, 'views/templates/admin/add_exception.tpl'); } private function getAddonsModules() { if (version_compare(_PS_VERSION_, '1.6.0.0', '<')) return false; $modules = Configuration::get('DELIVERYDATE_MODULES'); $modules_date = Configuration::get('DELIVERYDATE_MODULES_DATE'); if ($modules && strtotime('+1 WEEK', $modules_date) > time()) return Tools::jsonDecode($modules); $post_data = http_build_query(array( 'version' => _PS_VERSION_, 'iso_lang' => Tools::strtolower(Context::getContext()->language->iso_code), 'iso_code' => Tools::strtolower(Country::getIsoById(Configuration::get('PS_COUNTRY_DEFAULT'))), 'module_key' => $this->module_key, 'method' => 'contributor', 'action' => 'all_products' )); $context = stream_context_create(array( 'http' => array( 'method' => 'POST', 'content' => $post_data, 'header' => 'Content-type: application/x-www-form-urlencoded', 'timeout' => 5 ) )); $content = Tools::file_get_contents('https://api.addons.prestashop.com', false, $context); if (!$content) return false; $json = Tools::jsonDecode($content); if (!isset($json->products)) return false; Configuration::updateValue('DELIVERYDATE_MODULES', Tools::jsonEncode($json->products)); Configuration::updateValue('DELIVERYDATE_MODULES_DATE', time()); return $json->products; } public function getContent() { // Checking if exceptions table exists (since 1.2.0) $exceptions_table = Db::getInstance()->ExecuteS('SHOW TABLES LIKE "'._DB_PREFIX_.'delivery_date_exceptions"'); if (!$exceptions_table || empty($exceptions_table)) { $this->createExceptionsTable(); $this->registerHook('displayFooterProduct'); $this->registerHook('productTab'); $this->registerHook('productTabContent'); } // Dispatcher switch (Tools::getValue('action')) { case 'delete_rule': $this->delCondition(Tools::getValue('id')); $html = $this->renderMainView(); break; case 'delete_exception': $this->delException(Tools::getValue('id')); $html = $this->renderMainView(); break; case 'save_settings': $this->saveSettings(); $html = $this->renderMainView(); break; case 'add_rule': case 'edit_rule': if ((Tools::isSubmit('addRule') && !$this->saveRule()) || !Tools::isSubmit('addRule')) $html = $this->renderAddRuleView(); else $html = $this->renderMainView(); break; case 'add_exception': case 'edit_exception': if (!(Tools::isSubmit('addException') && $this->saveException())) { $html = $this->renderAddExceptionView(); break; } default: $html = $this->renderMainView(); } $this->context->controller->addJS($this->_path.'views/js/riot.js'); if (!(int)Configuration::get('PS_DISPLAY_QTIES') && (int)Configuration::get('DELIVERYDATE_PRODUCT')) $this->_warnings[] = $this->l('If you have issues with the dates on the product sheet, try yo activate the "Display available quantities on the product page" option in the "Preferences > Product".'); $this->smarty->assign(array( 'errors' => $this->_errors, 'confirmations' => $this->_confirmations, 'warnings' => $this->_warnings )); $alerts = $this->display(__FILE__, 'views/templates/admin/alerts.tpl'); if (version_compare(_PS_VERSION_, '1.6.0.0', '>=')) $satisfaction = $this->display(__FILE__, 'views/templates/admin/satisfaction.tpl'); else $satisfaction = ''; return $alerts.$html.$satisfaction.$this->display(__FILE__, 'views/templates/admin/prestui/ps-tags.tpl'); } }