* @copyright 2007-2017 PrestaShop SA
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
/**
* @property Product $object
*/
class AdminProductsControllerCore extends AdminController
{
/** @var int Max image size for upload
* As of 1.5 it is recommended to not set a limit to max image size
*/
protected $max_file_size = null;
protected $max_image_size = null;
protected $_category;
/**
* @var string name of the tab to display
*/
protected $tab_display;
protected $tab_display_module;
/**
* The order in the array decides the order in the list of tab. If an element's value is a number, it will be preloaded.
* The tabs are preloaded from the smallest to the highest number.
* @var array Product tabs.
*/
protected $available_tabs = array();
protected $default_tab = 'Informations';
protected $available_tabs_lang = array();
protected $position_identifier = 'id_product';
protected $submitted_tabs;
protected $id_current_category;
protected $objLocationsCategory;
protected $locationsAndHotels;
protected $product_name;
protected $product_exists_in_shop;
public function __construct()
{
$this->bootstrap = true;
$this->table = 'product';
$this->className = 'Product';
$this->lang = true;
$this->explicitSelect = true;
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'icon' => 'icon-trash',
'confirm' => $this->l('Delete selected items?')
)
);
if (!Tools::getValue('id_product')) {
$this->multishop_context_group = false;
}
$this->context = Context::getContext();
// START send access query information to the admin controller
$this->access_select = ' SELECT a.`id_product` FROM '._DB_PREFIX_.'product a';
$this->access_join = ' LEFT JOIN '._DB_PREFIX_.'htl_room_type hrt ON (hrt.id_product = a.id_product)';
if ($acsHtls = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1, 1)) {
$this->access_where = ' WHERE (hrt.id_hotel IN ('.implode(',', $acsHtls).') OR hrt.id_hotel IS NULL)';
}
parent::__construct();
$this->imageType = 'jpg';
$this->max_file_size = (int)(Configuration::get('PS_LIMIT_UPLOAD_FILE_VALUE') * 1000000);
$this->max_image_size = (int)Configuration::get('PS_PRODUCT_PICTURE_MAX_SIZE');
$this->allow_export = true;
$this->available_tabs_lang = array(
'Informations' => $this->l('Information'),
'Prices' => $this->l('Prices'),
'Seo' => $this->l('SEO'),
'Images' => $this->l('Images'),
'ServiceProduct' => $this->l('Service Products'),
// 'Associations' => $this->l('Associations'),
'Amenities' => $this->l('Amenities'),
'Features' => $this->l('Features'),
'Configuration' => $this->l('Rooms'),
'Occupancy' => $this->l('Occupancy'),
'LengthOfStay' => $this->l('Length of Stay'),
);
if ($this->context->shop->getContext() != Shop::CONTEXT_GROUP) {
$this->available_tabs = array_merge($this->available_tabs, array(
'Informations' => 0,
'Prices' => 1,
'Seo' => 2,
// 'Associations' => 3,
'Images' => 4,
'Amenities' => 5,
'Features' => 6,
'Configuration' => 7,
'Occupancy' => 8,
'ServiceProduct' => 9,
'LengthOfStay' => 10,
));
}
// Sort the tabs that need to be preloaded by their priority number
asort($this->available_tabs, SORT_NUMERIC);
/* Adding tab if modules are hooked */
$modules_list = Hook::getHookModuleExecList('displayAdminProductsExtra');
if (is_array($modules_list) && count($modules_list) > 0) {
foreach ($modules_list as $m) {
// if module is setting name of the tab at the product edit page
if (Validate::isLoadedObject($objModule = Module::getInstanceById($m['id_module']))) {
if (method_exists($objModule, 'moduleRoomTypeExtraTabName')) {
$this->available_tabs_lang['Module'.ucfirst($m['module'])] = $objModule->moduleRoomTypeExtraTabName();
}
}
// else set the display name of the product name as tab name
if (!isset($this->available_tabs_lang['Module'.ucfirst($m['module'])])) {
$this->available_tabs_lang['Module'.ucfirst($m['module'])] = Module::getModuleName($m['module']);
}
$this->available_tabs['Module'.ucfirst($m['module'])] = 23;
}
}
if (Tools::getValue('productFilter_a!id_category_default') === '') {
$this->context->cookie->id_category_room_types_filter = false;
}
if (Shop::isFeatureActive() && $this->context->cookie->id_category_room_types_filter) {
$category = new Category((int)$this->context->cookie->id_category_room_types_filter);
if (!$category->inShop()) {
$this->context->cookie->id_category_room_types_filter = false;
Tools::redirectAdmin($this->context->link->getAdminLink('AdminProducts'));
}
}
// to support filter URLs with 'id_category' parameter
if ($id_category = (int)Tools::getValue('id_category')) {
$_POST['submitFilter'] = '1';
$_POST['productFilter_a!id_category_default'] = $id_category;
}
$catFilterKey = $this->table.'Filter_a!id_category_default';
if (!Tools::getValue($catFilterKey)) {
$this->context->cookie->id_category_room_types_filter = false;
}
if (($id_category = (int)Tools::getValue('id_category'))
|| ($id_category = (int)Tools::getValue($catFilterKey))
) {
$this->id_current_category = $id_category;
$this->context->cookie->id_category_room_types_filter = $id_category;
if (Tools::isSubmit('submitResetproduct')) {
$this->id_current_category = false;
$this->context->cookie->id_category_room_types_filter = false;
}
} elseif ($id_category = $this->context->cookie->id_category_room_types_filter) {
$this->id_current_category = $id_category;
} else {
$idFilterCategory = false;
if (!Tools::isSubmit($catFilterKey)) {
$prefix = $this->getCookieFilterPrefix();
$idFilterCategory = $this->context->cookie->{$prefix.$catFilterKey};
}
if ($idFilterCategory) {
$this->id_current_category = $idFilterCategory;
$this->context->cookie->id_category_room_types_filter = $idFilterCategory;
} else {
$this->context->cookie->id_category_room_types_filter = false;
}
}
if ($this->id_current_category) {
$this->_category = new Category((int)$this->id_current_category);
$this->position_group_identifier = (int) $this->id_current_category;
} else {
$this->_category = new Category();
}
$join_category = false;
if (Validate::isLoadedObject($this->_category) && empty($this->_filter)) {
$join_category = true;
}
$this->_join .= '
LEFT JOIN `'._DB_PREFIX_.'stock_available` sav ON (sav.`id_product` = a.`id_product` AND sav.`id_product_attribute` = 0
'.StockAvailable::addSqlShopRestriction(null, null, 'sav').') ';
$alias = 'sa';
$alias_image = 'image_shop';
$id_shop = Shop::isFeatureActive() && Shop::getContext() == Shop::CONTEXT_SHOP? (int)$this->context->shop->id : 'a.id_shop_default';
$this->_join .= ' JOIN `'._DB_PREFIX_.'product_shop` sa ON (a.`id_product` = sa.`id_product` AND sa.id_shop = '.$id_shop.')
LEFT JOIN `'._DB_PREFIX_.'htl_room_type` hrt ON (a.`id_product` = hrt.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'htl_branch_info` hb ON (hrt.`id_hotel` = hb.`id`)
LEFT JOIN `'._DB_PREFIX_.'htl_branch_info_lang` hbl ON (hb.`id` = hbl.`id` AND b.`id_lang` = hbl.`id_lang`)
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON ('.$alias.'.`id_category_default` = cl.`id_category` AND b.`id_lang` = cl.`id_lang` AND cl.id_shop = '.$id_shop.')
LEFT JOIN `'._DB_PREFIX_.'shop` shop ON (shop.id_shop = '.$id_shop.')
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop ON (image_shop.`id_product` = a.`id_product` AND image_shop.`cover` = 1 AND image_shop.id_shop = '.$id_shop.')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_image` = image_shop.`id_image`)
LEFT JOIN `'._DB_PREFIX_.'product_download` pd ON (pd.`id_product` = a.`id_product` AND pd.`active` = 1)
LEFT JOIN `'._DB_PREFIX_.'address` aa ON (aa.`id_hotel` = hb.`id`)
LEFT JOIN `'._DB_PREFIX_.'feature_product` fp ON (fp.`id_product` = a.`id_product`)
LEFT JOIN (
SELECT rsp.*, GROUP_CONCAT(pl.`name`) AS service_products
FROM `'._DB_PREFIX_.'htl_room_type_service_product` rsp
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (pl.`id_product` = rsp.`id_product`)
WHERE pl.`id_lang`='.$this->context->language->id.'
GROUP BY rsp.`id_element`)
AS hrtsp ON ((hrtsp.`element_type` = '.(int) RoomTypeServiceProduct::WK_ELEMENT_TYPE_HOTEL.' AND hrtsp.`id_element` = hrt.`id_hotel`) OR (hrtsp.`element_type` = '.(int) RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE.' AND hrtsp.`id_element` = a.`id_product`))
LEFT JOIN `'._DB_PREFIX_.'htl_advance_payment` hap ON (hap.`id_product` = a.`id_product`)';
$this->_select .= ' a.`show_at_front`, (SELECT COUNT(hri.`id`) FROM `'._DB_PREFIX_.'htl_room_information` hri WHERE hri.`id_product` = a.`id_product`) as num_rooms, ';
$this->_select .= 'hrt.`adults`, hrt.`children`, hrt.`max_guests`, hb.`id` as id_hotel, aa.`city`, hbl.`hotel_name`, ';
$this->_select .= 'shop.`name` AS `shopname`, a.`id_shop_default`, ';
$this->_select .= $alias_image.'.`id_image` AS `id_image`, cl.`name` AS `name_category`, '.$alias.'.`price`, 0 AS `price_final`, a.`is_virtual`, pd.`nb_downloadable`, sav.`quantity` AS `sav_quantity`, '.$alias.'.`active`, IF(sav.`quantity`<=0, 1, 0) AS `badge_danger`, a.`id_tourism_tax_rules_group`';
$this->_select .= ', IFNULL(hap.`active`, 0) AS advance_payment';
$this->_select .= ', IF(IFNULL(hap.`active`, 0), 1, 0) badge_success, IF(IFNULL(hap.`active`, 0), 0, 1) badge_danger ';
if ($join_category) {
$this->_join .= ' INNER JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_product` = a.`id_product` AND cp.`id_category` = '.(int)$this->_category->id.') ';
$this->_select .= ' , cp.`position` ';
}
// show the list of the product according to the booking or service products
$this->_where .= ' AND a.`booking_product` = 1';
$this->_group = ' GROUP BY a.`id_product`';
$this->fields_list = array();
$this->fields_list['id_product'] = array(
'title' => $this->l('ID'),
'align' => 'center',
'class' => 'fixed-width-xs',
'type' => 'int'
);
$this->fields_list['image'] = array(
'title' => $this->l('Image'),
'align' => 'center',
'image' => 'p',
'orderby' => false,
'filter' => false,
'search' => false
);
$this->fields_list['name'] = array(
'title' => $this->l('Name'),
'filter_key' => 'b!name'
);
if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_SHOP) {
$this->fields_list['shopname'] = array(
'title' => $this->l('Default shop'),
'filter_key' => 'shop!name',
);
} else {
$hotels = HotelBranchInformation::getProfileAccessedHotels($this->context->employee->id_profile, 1);
$hotelsArray = array();
foreach ($hotels as $hotel) {
$addressInfo = HotelBranchInformation::getAddress($hotel['id_hotel']);
$hotelsArray[$hotel['id_hotel']] = $hotel['hotel_name'].', '.$addressInfo['city'];
}
$this->fields_list['hotel_name'] = array(
'title' => $this->l('Hotel'),
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'hrt!id_hotel',
'list' => $hotelsArray,
'optional' => true,
'class' => 'chosen',
'visible_default' => true,
);
}
$this->fields_list['adults'] = array(
'title' => $this->l('Adults'),
'filter_key' => 'hrt!adults',
'type' => 'range',
'align' => 'center',
);
$this->fields_list['children'] = array(
'title' => $this->l('Children'),
'filter_key' => 'hrt!children',
'type' => 'range',
'align' => 'center',
);
$this->fields_list['max_guests'] = array(
'title' => $this->l('Maximum Occupancy'),
'filter_key' => 'hrt!max_guests',
'type' => 'range',
'align' => 'center',
'optional' => true,
);
// use it for total rooms
$this->fields_list['num_rooms'] = array(
'title' => $this->l('Total Rooms'),
'align' => 'center',
'type' => 'range',
'havingFilter' => true,
);
$this->fields_list['price'] = array(
'title' => $this->l('Base Price'),
'type' => 'range',
'validation' => 'isFloat',
'align' => 'text-left',
'filter_key' => 'a!price',
'callback' => 'displayPrice',
);
$this->fields_list['price_final'] = array(
'title' => $this->l('Final price'),
'type' => 'price',
'align' => 'text-left',
'havingFilter' => true,
'orderby' => false,
'search' => false,
'callback' => 'displayPrice',
);
$this->fields_list['active'] = array(
'title' => $this->l('Status'),
'active' => 'status',
'filter_key' => $alias.'!active',
'align' => 'text-center',
'type' => 'select',
'callback' => 'formatStatusAsLabel',
'list' => array(1 => $this->l('Yes'), 0 => $this->l('No')),
'optional' => true,
'visible_default' => true,
'orderby' => false
);
$this->fields_list['show_at_front'] = array(
'title' => $this->l('Show at front'),
'align' => 'text-center',
'type' => 'bool',
'active' => 'show_at_front',
'callback' => 'formatStatusAsLabel',
'optional' => true,
'havingFilter' => true,
'visible_default' => true,
'orderby' => false,
);
if (Configuration::get('WK_ALLOW_ADVANCED_PAYMENT')) {
$this->fields_list['advance_payment'] = array(
'title' => $this->l('Advance Payment'),
'callback' => 'formatStatusAsLabel',
'badge_success' => true,
'badge_danger' => true,
'align' => 'text-center',
'type' => 'bool',
'optional' => true,
'havingFilter' => true,
'visible_default' => true,
'orderby' => false,
);
}
$taxRulesGroups = array();
foreach (TaxRulesGroup::getTaxRulesGroups(true) as $taxRulesGroup) {
$taxRulesGroups[$taxRulesGroup['id_tax_rules_group']] = $taxRulesGroup['name'];
}
$this->fields_list['id_tax_rules_group'] = array(
'title' => $this->l('Tax Rules'),
'align' => 'text-center',
'type' => 'select',
'multiple' => true,
'operator' => 'or',
'filter_key' => 'a!id_tax_rules_group',
'list' => $taxRulesGroups,
'displayed' => false,
);
$features = array();
foreach (Feature::getFeatures($this->context->language->id) as $feature) {
$features[$feature['id_feature']] = $feature['name'];
}
$this->fields_list['id_feature'] = array(
'title' => $this->l('Features'),
'align' => 'text-center',
'type' => 'select',
'multiple' => true,
'operator' => 'and',
'filter_key' => 'fp!id_feature',
'list' => $features,
'displayed' => false,
);
$objProduct = new Product();
$hotelServiceProducts = $objProduct->getServiceProducts(null, Product::SELLING_PREFERENCE_HOTEL_STANDALONE_AND_WITH_ROOM_TYPE);
$roomTypeServiceProducts = $objProduct->getServiceProducts(null, Product::SELLING_PREFERENCE_WITH_ROOM_TYPE);
$allServiceProducts = array_merge($roomTypeServiceProducts, $hotelServiceProducts);
$serviceProducts = array();
foreach ($allServiceProducts as $serviceProduct) {
$serviceProducts[$serviceProduct['id_product']] = $serviceProduct['name'];
}
$this->fields_list['id_service_product'] = array(
'title' => $this->l('Service Products'),
'align' => 'text-center',
'type' => 'select',
'multiple' => true,
'operator' => 'and',
'filter_key' => 'hrtsp!id_product',
'list' => $serviceProducts,
'displayed' => false,
);
$this->locationsAndHotels = array();
$idLocationsCategory = Configuration::get('PS_LOCATIONS_CATEGORY');
$this->objLocationsCategory = new Category($idLocationsCategory, $this->context->language->id);
$nestedCategories = Category::getNestedCategories($idLocationsCategory);
if (isset($nestedCategories[$idLocationsCategory]['children']) && $nestedCategories[$idLocationsCategory]['children']) {
foreach ($nestedCategories[$idLocationsCategory]['children'] as $childCategory) {
$this->buildCategoryOptions($childCategory);
}
}
$this->fields_list['id_category_default'] = array(
'title' => $this->l('Location/Hotel'),
'align' => 'text-center',
'type' => 'select',
'list' => $this->locationsAndHotels,
'filter_key' => 'a!id_category_default',
'displayed' => false,
);
// display Position column only if it is a hotel category
if ($join_category
&& (int) $this->id_current_category
&& HotelBranchInformation::getHotelIdByIdCategory($this->id_current_category)
) {
$this->_orderBy = 'position';
$this->_orderWay = 'ASC';
$this->fields_list['position'] = array(
'title' => $this->l('Position'),
'filter_key' => 'cp!position',
'align' => 'center',
'position' => 'position'
);
}
}
public function formatStatusAsLabel($val, $row)
{
if ($val) {
$str_return = $this->l('Yes');
} else {
$str_return = $this->l('No');
}
return $str_return;
}
private function buildCategoryOptions($category)
{
$space = str_repeat(' ', 5 * (($category['level_depth'] - $this->objLocationsCategory->level_depth) - 1));
$this->locationsAndHotels[$category['id_category']] = $space.$category['name'];
if (isset($category['children']) && count($category['children'])) {
foreach ($category['children'] as $childCategory) {
$this->buildCategoryOptions($childCategory);
}
}
}
public static function displayPrice($basePrice, $tr)
{
return Tools::displayPrice($basePrice, (int) Configuration::get('PS_CURRENCY_DEFAULT'));
}
public static function getQuantities($hotelName, $tr)
{
if ((int)$tr['is_virtual'] == 1 && $tr['nb_downloadable'] == 0) {
return '∞';
} else {
return $echo;
}
}
public function setMedia()
{
parent::setMedia();
$bo_theme = ((Validate::isLoadedObject($this->context->employee)
&& $this->context->employee->bo_theme) ? $this->context->employee->bo_theme : 'default');
if (!file_exists(_PS_BO_ALL_THEMES_DIR_.$bo_theme.DIRECTORY_SEPARATOR
.'template')) {
$bo_theme = 'default';
}
$this->addJs(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$bo_theme.'/js/jquery.iframe-transport.js');
$this->addJs(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$bo_theme.'/js/jquery.fileupload.js');
$this->addJs(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$bo_theme.'/js/jquery.fileupload-process.js');
$this->addJs(__PS_BASE_URI__.$this->admin_webpath.'/themes/'.$bo_theme.'/js/jquery.fileupload-validate.js');
$this->addJs(__PS_BASE_URI__.'js/vendor/spin.js');
$this->addJs(__PS_BASE_URI__.'js/vendor/ladda.js');
$this->addCSS(_PS_JS_DIR_.'fullcalendar/main.css');
$this->addJs(_PS_JS_DIR_.'fullcalendar/main.js');
$this->addJS(_PS_JS_DIR_.'/datatable/jquery.dataTables.min.js');
$this->addJS(_PS_JS_DIR_.'/datatable/dataTables.bootstrap.js');
}
protected function _cleanMetaKeywords($keywords)
{
if (!empty($keywords) && $keywords != '') {
$out = array();
$words = explode(',', $keywords);
foreach ($words as $word_item) {
$word_item = trim($word_item);
if (!empty($word_item) && $word_item != '') {
$out[] = $word_item;
}
}
return ((count($out) > 0) ? implode(',', $out) : '');
} else {
return '';
}
}
protected function filterToField($key, $filter)
{
if ($key == 'a!id_category_default') {
return false;
}
return parent::filterToField($key, $filter);
}
public function processResetFilters($list_id = null)
{
parent::processResetFilters($list_id);
// reset category filter
$this->context->cookie->id_category_room_types_filter = false;
}
/**
* @param Product|ObjectModel $object
* @param string $table
*/
protected function copyFromPost(&$object, $table)
{
parent::copyFromPost($object, $table);
if (get_class($object) != 'Product') {
return;
}
/* Additional fields */
foreach (Language::getIDs(false) as $id_lang) {
if (isset($_POST['meta_keywords_'.$id_lang])) {
$_POST['meta_keywords_'.$id_lang] = $this->_cleanMetaKeywords(Tools::strtolower($_POST['meta_keywords_'.$id_lang]));
// preg_replace('/ *,? +,* /', ',', strtolower($_POST['meta_keywords_'.$id_lang]));
$object->meta_keywords[$id_lang] = $_POST['meta_keywords_'.$id_lang];
}
}
$_POST['width'] = empty($_POST['width']) ? '0' : str_replace(',', '.', $_POST['width']);
$_POST['height'] = empty($_POST['height']) ? '0' : str_replace(',', '.', $_POST['height']);
$_POST['depth'] = empty($_POST['depth']) ? '0' : str_replace(',', '.', $_POST['depth']);
$_POST['weight'] = empty($_POST['weight']) ? '0' : str_replace(',', '.', $_POST['weight']);
if (Tools::getIsset('unit_price') != null) {
$object->unit_price = str_replace(',', '.', Tools::getValue('unit_price'));
}
if (Tools::getIsset('ecotax') != null) {
$object->ecotax = str_replace(',', '.', Tools::getValue('ecotax'));
}
if ($this->isTabSubmitted('Informations')) {
if ($this->checkMultishopBox('available_for_order', $this->context)) {
$object->available_for_order = (int)Tools::getValue('available_for_order');
}
if ($this->checkMultishopBox('show_price', $this->context)) {
$object->show_price = $object->available_for_order ? 1 : (int)Tools::getValue('show_price');
}
if ($this->checkMultishopBox('online_only', $this->context)) {
$object->online_only = (int)Tools::getValue('online_only');
}
}
if ($this->isTabSubmitted('Prices')) {
$object->on_sale = (int)Tools::getValue('on_sale');
}
}
public function checkMultishopBox($field, $context = null)
{
static $checkbox = null;
static $shop_context = null;
if ($context == null && $shop_context == null) {
$context = Context::getContext();
}
if ($shop_context == null) {
$shop_context = $context->shop->getContext();
}
if ($checkbox == null) {
$checkbox = Tools::getValue('multishop_check', array());
}
if ($shop_context == Shop::CONTEXT_SHOP) {
return true;
}
if (isset($checkbox[$field]) && $checkbox[$field] == 1) {
return true;
}
return false;
}
public function getList($id_lang, $orderBy = null, $orderWay = null, $start = 0, $limit = null, $id_lang_shop = null)
{
$prefix = $this->getCookieFilterPrefix();
$orderByPriceFinal = (empty($orderBy) ? ($this->context->cookie->__get($prefix.$this->table.'Orderby') ? $this->context->cookie->__get($prefix.$this->table.'Orderby') : 'id_'.$this->table) : $orderBy);
$orderWayPriceFinal = (empty($orderWay) ? ($this->context->cookie->__get($prefix.$this->table.'Orderway') ? $this->context->cookie->__get($prefix.$this->table.'Orderway') : 'ASC') : $orderWay);
if ($orderByPriceFinal == 'price_final') {
$orderBy = 'id_'.$this->table;
$orderWay = 'ASC';
}
if ($this->action == 'export' && empty($this->_listsql)) {
$this->_select .= ' , trg.`name` AS `id_tax_rules_group`, `features`';
$this->_join .= ' LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg
ON trg.`id_tax_rules_group` = a.`id_tax_rules_group`
LEFT JOIN (SELECT GROUP_CONCAT(fpl.`name`) AS features, fp.`id_product`
FROM `'._DB_PREFIX_.'feature_lang` fpl
LEFT JOIN `'._DB_PREFIX_.'feature_product` fp
ON (fp.`id_feature` = fpl.`id_feature`)
WHERE fpl.`id_lang`='.(int) $this->context->language->id.'
GROUP BY fp.`id_product`
) AS fpl ON (a.`id_product` = fpl.`id_product`)';
$this->fields_list = array_merge($this->fields_list, array(
'id_tax_rules_group' => array(
'title' => $this->l('Id Tax Rules group'),
'filter_key' => 'a!id_tax_rules_group',
),
'features' => array(
'title' => $this->l('Features'),
),
'service_products' => array(
'title' => $this->l('Services Products'),
),
)
);
unset($this->fields_list['id_category_default']);
unset($this->fields_list['id_feature']);
unset($this->fields_list['id_service_product']);
}
parent::getList($id_lang, $orderBy, $orderWay, $start, $limit, $id_lang_shop ?: $this->context->shop->id);
/* update product quantity with attributes ...*/
$nb = count($this->_list);
if ($this->_list) {
$context = $this->context->cloneContext();
$context->shop = clone($context->shop);
$isAllShopsContext = (Context::getContext()->shop->getContext() != Shop::CONTEXT_SHOP);
$priceDisplayPrecision = (int) Configuration::get('PS_PRICE_DISPLAY_PRECISION');
$useTourismTax = (bool) Configuration::get('QLO_USE_TOURISM_TAX');
$todayDate = date('Y-m-d');
$tomorrowDate = date('Y-m-d', strtotime('+1 day', strtotime($todayDate)));
/* update product final price */
for ($i = 0; $i < $nb; $i++) {
if ($isAllShopsContext) {
$context->shop = new Shop((int)$this->_list[$i]['id_shop_default']);
}
// convert price with the currency from context
$this->_list[$i]['price'] = Tools::convertPrice($this->_list[$i]['price'], $this->context->currency, true, $this->context);
$this->_list[$i]['price_tmp'] = Product::getPriceStatic($this->_list[$i]['id_product'], true, null,
$priceDisplayPrecision, null, false, true, 1, true, null, null, null, $nothing, true, true,
$context);
$idTourismTaxRulesGroup = (int) $this->_list[$i]['id_tourism_tax_rules_group'];
$idHotel = (int) $this->_list[$i]['id_hotel'];
if ($useTourismTax && $idTourismTaxRulesGroup && $idHotel) {
$idProduct = $this->_list[$i]['id_product'];
$vatAddress = new Address(HotelRoomType::getHotelIdAddressByIdProduct($idProduct));
$vatCalculator = TaxManagerFactory::getManager($vatAddress, Product::getIdTaxRulesGroupByIdProduct($idProduct))->getTaxCalculator();
$unitPriceTaxExcl = $vatCalculator->removeTaxes($this->_list[$i]['price_tmp']);
$hotelTaxContext = TaxConfiguration::resolveHotelAddressAndCollectionType($idHotel, $vatAddress);
$taxCalculator = TaxManagerFactory::getManager($hotelTaxContext['address'], $idTourismTaxRulesGroup)->getTaxCalculator();
$this->_list[$i]['price_tmp'] += $taxCalculator->getTaxesTotalAmount(
$unitPriceTaxExcl,
$todayDate,
1,
1,
array(),
$hotelTaxContext['collectionType'],
1,
$this->context->currency->id
);
}
}
}
if ($orderByPriceFinal == 'price_final') {
if (strtolower($orderWayPriceFinal) == 'desc') {
uasort($this->_list, 'cmpPriceDesc');
} else {
uasort($this->_list, 'cmpPriceAsc');
}
}
for ($i = 0; $this->_list && $i < $nb; $i++) {
$this->_list[$i]['price_final'] = $this->_list[$i]['price_tmp'];
unset($this->_list[$i]['price_tmp']);
}
}
protected function loadObject($opt = false)
{
$result = parent::loadObject($opt);
if ($result && Validate::isLoadedObject($this->object)) {
if (Shop::getContext() == Shop::CONTEXT_SHOP && Shop::isFeatureActive() && !$this->object->isAssociatedToShop()) {
$default_product = new Product((int)$this->object->id, false, null, (int)$this->object->id_shop_default);
$def = ObjectModel::getDefinition($this->object);
foreach ($def['fields'] as $field_name => $row) {
if (is_array($default_product->$field_name)) {
foreach ($default_product->$field_name as $key => $value) {
$this->object->{$field_name}[$key] = $value;
}
} else {
$this->object->$field_name = $default_product->$field_name;
}
}
}
$this->object->loadStockData();
}
return $result;
}
public function ajaxProcessGetCategoryTree()
{
$category = Configuration::get('PS_LOCATIONS_CATEGORY');
$full_tree = Tools::getValue('fullTree', 0);
$use_check_box = Tools::getValue('useCheckBox', 1);
$selected = Tools::getValue('selected', array());
$id_tree = Tools::getValue('type');
$input_name = str_replace(array('[', ']'), '', Tools::getValue('inputName', null));
$tree = new HelperTreeCategories('subtree_associated_categories');
$tree->setTemplate('subtree_associated_categories.tpl')
->setUseCheckBox($use_check_box)
->setUseSearch(false)
->setIdTree($id_tree)
->setSelectedCategories($selected)
->setFullTree($full_tree)
->setChildrenOnly(true)
->setNoJS(true)
->setRootCategory($category);
$tree->setTemplate('tree_associated_categories.tpl')
->setHeaderTemplate('tree_associated_header.tpl')
->setRootCategory(Configuration::get('PS_LOCATIONS_CATEGORY'))
->setUseCheckBox(true)
->setUseSearch(false)
->setFullTree(0)
->setSelectedCategories($selected)
->setUseBulkActions(false)
->setDisablAllCategories(true);
if ($input_name) {
$tree->setInputName($input_name);
}
die($tree->render());
}
public function ajaxProcessGetCountriesOptions()
{
if (!$res = Country::getCountriesByIdShop((int)Tools::getValue('id_shop'), (int)$this->context->language->id)) {
return;
}
$tpl = $this->createTemplate('specific_prices_shop_update.tpl');
$tpl->assign(array(
'option_list' => $res,
'key_id' => 'id_country',
'key_value' => 'name'
)
);
$this->content = $tpl->fetch();
}
public function ajaxProcessGetCurrenciesOptions()
{
if (!$res = Currency::getCurrenciesByIdShop((int)Tools::getValue('id_shop'))) {
return;
}
$tpl = $this->createTemplate('specific_prices_shop_update.tpl');
$tpl->assign(array(
'option_list' => $res,
'key_id' => 'id_currency',
'key_value' => 'name'
)
);
$this->content = $tpl->fetch();
}
public function ajaxProcessGetGroupsOptions()
{
if (!$res = Group::getGroups((int)$this->context->language->id, (int)Tools::getValue('id_shop'))) {
return;
}
$tpl = $this->createTemplate('specific_prices_shop_update.tpl');
$tpl->assign(array(
'option_list' => $res,
'key_id' => 'id_group',
'key_value' => 'name'
)
);
$this->content = $tpl->fetch();
}
public function processDeleteVirtualProduct()
{
if (!($id_product_download = ProductDownload::getIdFromIdProduct((int)Tools::getValue('id_product')))) {
$this->errors[] = Tools::displayError('Cannot retrieve file');
} else {
$product_download = new ProductDownload((int)$id_product_download);
if (!$product_download->deleteFile((int)$id_product_download)) {
$this->errors[] = Tools::displayError('Cannot delete file');
} else {
$this->redirect_after = self::$currentIndex.'&id_product='.(int)Tools::getValue('id_product').'&updateproduct&key_tab=VirtualProduct&conf=1&token='.$this->token;
}
}
$this->display = 'edit';
$this->tab_display = 'VirtualProduct';
}
public function processDuplicate()
{
if (Validate::isLoadedObject($product = new Product((int)Tools::getValue('id_product')))) {
$id_product_old = $product->id;
if (empty($product->price) && Shop::getContext() == Shop::CONTEXT_GROUP) {
$shops = ShopGroup::getShopsFromGroup(Shop::getContextShopGroupID());
foreach ($shops as $shop) {
if ($product->isAssociatedToShop($shop['id_shop'])) {
$product_price = new Product($id_product_old, false, null, $shop['id_shop']);
$product->price = $product_price->price;
}
}
}
unset($product->id);
unset($product->id_product);
$product->indexed = 0;
$product->active = 0;
// suffix 'Duplicate' if same hotel
$id_hotel_new = Tools::getValue('id_hotel');
$obj_hotel_room_type = new HotelRoomType();
$room_type_info = $obj_hotel_room_type->getRoomTypeInfoByIdProduct($id_product_old);
$limit = (int)Configuration::get('PS_SHORT_DESC_LIMIT');
if ($limit <= 0) {
$limit = Configuration::PS_SHORT_DESC_LIMIT;
}
$className = 'Product';
if ($room_type_info && $room_type_info['id_hotel'] == $id_hotel_new) {
foreach (Language::getLanguages(true) as $language) {
$product->name[$language['id_lang']] = $product->name[$language['id_lang']].
' - '.$this->l('Duplicate');
if (Tools::strlen(strip_tags($product->description_short[$language['id_lang']])) > $limit) {
$this->errors[] = sprintf(
Tools::displayError('This %1$s field in %2$s is too long: %3$d chars max (current count %4$d).'),
call_user_func(array($className, 'displayFieldName'), 'description_short'),
$language['name'],
$limit,
Tools::strlen(strip_tags($product->description_short[$language['id_lang']]))
);
}
}
}
// update `id_category_default`
$objHotelBranchInformation = new HotelBranchInformation($id_hotel_new);
$product->id_category_default = $objHotelBranchInformation->id_category;
// update lang fields
foreach (Language::getLanguages(true) as $language) {
$product->link_rewrite[$language['id_lang']] = Tools::str2url($product->name[$language['id_lang']]);
}
if (!$this->errors) {
if ($product->add()
// && Category::duplicateProductCategories($id_product_old, $product->id)
&& Product::duplicateSuppliers($id_product_old, $product->id)
&& ($combination_images = Product::duplicateAttributes($id_product_old, $product->id)) !== false
&& GroupReduction::duplicateReduction($id_product_old, $product->id)
&& Product::duplicateAccessories($id_product_old, $product->id)
&& Product::duplicateFeatures($id_product_old, $product->id)
&& Pack::duplicate($id_product_old, $product->id)
&& Product::duplicateCustomizationFields($id_product_old, $product->id)
&& Product::duplicateTags($id_product_old, $product->id)
&& Product::duplicateDownload($id_product_old, $product->id)
) {
$obj_hotel_room_type = new HotelRoomType();
$room_type_info = $obj_hotel_room_type->getRoomTypeInfoByIdProduct($id_product_old);
$id_room_type_old = $room_type_info['id'];
if (!$id_hotel_new) {
$id_hotel_new = $room_type_info['id_hotel'];
}
if ($product->hasAttributes()) {
Product::updateDefaultAttribute($product->id);
} else {
Product::duplicateSpecificPrices($id_product_old, $product->id);
}
$id_room_type_new = HotelRoomType::duplicateRoomType(
$id_product_old,
$product->id,
$id_hotel_new,
true
);
if ($id_room_type_new) {
if (!HotelRoomType::duplicateRooms(
$id_product_old,
$id_room_type_new,
$product->id,
$id_hotel_new
)) {
$this->errors[] = Tools::displayError('An error occurred while duplicating rooms.');
}
} else {
$this->errors[] = Tools::displayError('An error occurred while duplicating room type.');
}
if (!Tools::getValue('noimage') && !Image::duplicateProductImages($id_product_old, $product->id, $combination_images)) {
$this->errors[] = Tools::displayError('An error occurred while copying images.');
} else {
Hook::exec('actionProductAdd', array('id_product' => (int)$product->id, 'product' => $product));
if (in_array($product->visibility, array('both', 'search')) && Configuration::get('PS_SEARCH_INDEXATION')) {
Search::indexation(false, $product->id);
}
$this->redirect_after = self::$currentIndex.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '').'&conf=19&token='.$this->token;
}
} else {
$this->errors[] = Tools::displayError('An error occurred while creating an object.');
}
}
}
}
public function processDelete()
{
if (Validate::isLoadedObject($object = $this->loadObject()) && isset($this->fieldImageSettings)) {
/** @var Product $object */
// check if request at least one object with noZeroObject
if (isset($object->noZeroObject) && count($taxes = call_user_func(array($this->className, $object->noZeroObject))) <= 1) {
$this->errors[] = Tools::displayError('You need at least one object.').' '.$this->table.'
'.Tools::displayError('You cannot delete all of the items.');
} else {
/*
* @since 1.5.0
* It is NOT possible to delete a product if there are currently:
* - physical stock for this product
* - supply order(s) for this product
*/
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $object->advanced_stock_management) {
$stock_manager = StockManagerFactory::getManager();
$physical_quantity = $stock_manager->getProductPhysicalQuantities($object->id, 0);
$real_quantity = $stock_manager->getProductRealQuantities($object->id, 0);
if ($physical_quantity > 0 || $real_quantity > $physical_quantity) {
$this->errors[] = Tools::displayError('You cannot delete this room type because there is physical stock left.');
}
}
if (!count($this->errors)) {
if ($object->delete()) {
$id_category = (int)Tools::getValue('id_category');
$category_url = empty($id_category) ? '' : '&id_category='.(int)$id_category;
PrestaShopLogger::addLog(sprintf($this->l('%s deletion', 'AdminTab', false, false), $this->className), 1, null, $this->className, (int)$object->id, true, (int)$this->context->employee->id);
$this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token.$category_url;
} else {
$this->errors[] = Tools::displayError('An error occurred during deletion.');
}
}
}
} else {
$this->errors[] = Tools::displayError('An error occurred while deleting the object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
}
public function processImage()
{
$id_image = (int)Tools::getValue('id_image');
$image = new Image((int)$id_image);
if (Validate::isLoadedObject($image)) {
/* Update product image/legend */
// @todo : move in processEditProductImage
if (Tools::getIsset('editImage')) {
if ($image->cover) {
$_POST['cover'] = 1;
}
$_POST['id_image'] = $image->id;
} elseif (Tools::getIsset('coverImage')) {
/* Choose product cover image */
Image::deleteCover($image->id_product);
$image->cover = 1;
if (!$image->update()) {
$this->errors[] = Tools::displayError('You cannot change the product\'s cover image.');
} else {
$productId = (int)Tools::getValue('id_product');
@unlink(_PS_TMP_IMG_DIR_.'product_'.$productId.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'product_mini_'.$productId.'_'.$this->context->shop->id.'.jpg');
$this->redirect_after = self::$currentIndex.'&id_product='.$image->id_product.'&id_category='.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '').'&action=Images&addproduct'.'&token='.$this->token;
}
} elseif (Tools::getIsset('imgPosition') && Tools::getIsset('imgDirection')) {
/* Choose product image position */
$image->updatePosition(Tools::getValue('imgDirection'), Tools::getValue('imgPosition'));
$this->redirect_after = self::$currentIndex.'&id_product='.$image->id_product.'&id_category='.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '').'&add'.$this->table.'&action=Images&token='.$this->token;
}
} else {
$this->errors[] = Tools::displayError('The image could not be found. ');
}
}
protected function processBulkDelete()
{
if ($this->tabAccess['delete'] === 1) {
if (is_array($this->boxes) && !empty($this->boxes)) {
$object = new $this->className();
if (isset($object->noZeroObject) &&
// Check if all object will be deleted
(count(call_user_func(array($this->className, $object->noZeroObject))) <= 1 || count($_POST[$this->table.'Box']) == count(call_user_func(array($this->className, $object->noZeroObject))))) {
$this->errors[] = Tools::displayError('You need at least one object.').' '.$this->table.'
'.Tools::displayError('You cannot delete all of the items.');
} else {
$success = 1;
$products = Tools::getValue($this->table.'Box');
if (is_array($products) && ($count = count($products))) {
// Deleting products can be quite long on a cheap server. Let's say 1.5 seconds by product (I've seen it!).
if (intval(ini_get('max_execution_time')) < round($count * 1.5)) {
ini_set('max_execution_time', round($count * 1.5));
}
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
$stock_manager = StockManagerFactory::getManager();
}
foreach ($products as $id_product) {
$product = new Product((int)$id_product);
/*
* @since 1.5.0
* It is NOT possible to delete a product if there are currently:
* - physical stock for this product
* - supply order(s) for this product
*/
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $product->advanced_stock_management) {
$physical_quantity = $stock_manager->getProductPhysicalQuantities($product->id, 0);
$real_quantity = $stock_manager->getProductRealQuantities($product->id, 0);
if ($physical_quantity > 0 || $real_quantity > $physical_quantity) {
$this->errors[] = sprintf(Tools::displayError('You cannot delete the room type #%d because there is physical stock left.'), $product->id);
}
}
if (!count($this->errors)) {
if ($product->delete()) {
PrestaShopLogger::addLog(sprintf($this->l('%s deletion', 'AdminTab', false, false), $this->className), 1, null, $this->className, (int)$product->id, true, (int)$this->context->employee->id);
} else {
$success = false;
}
} else {
$success = 0;
}
}
}
if ($success) {
$id_category = (int)Tools::getValue('id_category');
$category_url = empty($id_category) ? '' : '&id_category='.(int)$id_category;
$this->redirect_after = self::$currentIndex.'&conf=2&token='.$this->token.$category_url;
} else {
$this->errors[] = Tools::displayError('An error occurred while deleting this selection.');
}
}
} else {
$this->errors[] = Tools::displayError('You must select at least one element to delete.');
}
} else {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
}
}
public function processFeatures()
{
if (!Feature::isFeatureActive()) {
return;
}
if (Validate::isLoadedObject($product = new Product((int)Tools::getValue('id_product')))) {
if (!$this->saveRoomTypeFeatures($product)) {
$this->errors[] = Tools::displayError('An error occurred while saving room type features.');
}
} else {
$this->errors[] = Tools::displayError('A room type must be created before adding features.');
}
}
/**
* Save assigned core feature values for a room type.
*
* @param Product $product
*
* @return bool
*/
protected function saveRoomTypeFeatures(Product $product)
{
$product->deleteFeatures();
$featureValues = Tools::getValue('feature_values', array());
if (!is_array($featureValues) || empty($featureValues)) {
return true;
}
foreach ($featureValues as $idFeature => $selectedValues) {
$idFeature = (int)$idFeature;
if (!$idFeature) {
continue;
}
foreach (array_unique(array_map('intval', $selectedValues)) as $idFeatureValue) {
if ($idFeatureValue) {
$product->addFeaturesToDB($idFeature, $idFeatureValue);
}
}
}
return true;
}
/**
* This function is never called at the moment (specific prices cannot be edited)
*/
public function processPricesModification()
{
$id_specific_prices = Tools::getValue('spm_id_specific_price');
$id_combinations = Tools::getValue('spm_id_product_attribute');
$id_shops = Tools::getValue('spm_id_shop');
$id_currencies = Tools::getValue('spm_id_currency');
$id_countries = Tools::getValue('spm_id_country');
$id_groups = Tools::getValue('spm_id_group');
$id_customers = Tools::getValue('spm_id_customer');
$prices = Tools::getValue('spm_price');
$from_quantities = Tools::getValue('spm_from_quantity');
$reductions = Tools::getValue('spm_reduction');
$reduction_types = Tools::getValue('spm_reduction_type');
$froms = Tools::getValue('spm_from');
$tos = Tools::getValue('spm_to');
foreach ($id_specific_prices as $key => $id_specific_price) {
if ($reduction_types[$key] == 'percentage' && ((float)$reductions[$key] <= 0 || (float)$reductions[$key] > 100)) {
$this->errors[] = Tools::displayError('Submitted reduction value (0-100) is out-of-range');
} elseif ($this->_validateSpecificPrice($id_shops[$key], $id_currencies[$key], $id_countries[$key], $id_groups[$key], $id_customers[$key], $prices[$key], $from_quantities[$key], $reductions[$key], $reduction_types[$key], $froms[$key], $tos[$key], $id_combinations[$key])) {
$specific_price = new SpecificPrice((int)($id_specific_price));
$specific_price->id_shop = (int)$id_shops[$key];
$specific_price->id_product_attribute = (int)$id_combinations[$key];
$specific_price->id_currency = (int)($id_currencies[$key]);
$specific_price->id_country = (int)($id_countries[$key]);
$specific_price->id_group = (int)($id_groups[$key]);
$specific_price->id_customer = (int)$id_customers[$key];
$specific_price->price = (float)($prices[$key]);
$specific_price->from_quantity = (int)($from_quantities[$key]);
$specific_price->reduction = (float)($reduction_types[$key] == 'percentage' ? ($reductions[$key] / 100) : $reductions[$key]);
$specific_price->reduction_type = !$reductions[$key] ? 'amount' : $reduction_types[$key];
$specific_price->from = !$froms[$key] ? '0000-00-00 00:00:00' : $froms[$key];
$specific_price->to = !$tos[$key] ? '0000-00-00 00:00:00' : $tos[$key];
if (!$specific_price->update()) {
$this->errors[] = Tools::displayError('An error occurred while updating the specific price.');
}
}
}
if (!count($this->errors)) {
$this->redirect_after = self::$currentIndex.'&id_product='.(int)(Tools::getValue('id_product')).(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '').'&update'.$this->table.'&action=Prices&token='.$this->token;
}
}
public function processAdvancedPayment()
{
if (Configuration::get('WK_ALLOW_ADVANCED_PAYMENT')) {
// Check if a specific price has been submitted
if (Tools::getIsset('submitPriceAddition')) {
return;
}
$id_product = Tools::getValue('id_product');
$id_adv_pmt = Tools::getValue('id_adv_pmt');
if ($id_adv_pmt) {
$obj_adv_pmt = new HotelAdvancedPayment($id_adv_pmt);
} else {
$obj_adv_pmt = new HotelAdvancedPayment();
if ($adv_pmt_info = $obj_adv_pmt->getIdAdvPaymentByIdProduct($id_product)) {
// To prevent duplication from two separate tabs
$obj_adv_pmt = new HotelAdvancedPayment((int) $adv_pmt_info['id']);
}
}
$adv_payment_active = Tools::getValue('adv_payment_active');
$obj_adv_pmt->id_product = $id_product;
$obj_adv_pmt->active = $adv_payment_active;
if ($adv_payment_active) {
$calculate_from = Tools::getValue('cal_from');
$payment_type = Tools::getValue('payment_type');
if ($payment_type == 1) {
$adv_pay_value = Tools::getValue('adv_pay_percent');
} elseif ($payment_type == 2) {
$adv_pay_value = Tools::getValue('adv_pay_amount');
}
$adv_tax_include = Tools::getValue('adv_tax_include');
$obj_adv_pmt->payment_type = $payment_type;
$obj_adv_pmt->value = $adv_pay_value;
if ($payment_type == 2) {
$obj_adv_pmt->id_currency = (int) Configuration::get('PS_CURRENCY_DEFAULT');
} else {
$obj_adv_pmt->id_currency = '';
}
$obj_adv_pmt->tax_include = $adv_tax_include;
$obj_adv_pmt->calculate_from = $calculate_from;
} else {
$obj_adv_pmt->payment_type = '';
$obj_adv_pmt->value = '';
$obj_adv_pmt->id_currency = '';
$obj_adv_pmt->tax_include = '';
$obj_adv_pmt->calculate_from = 0;
}
$obj_adv_pmt->save();
}
return true;
}
public function processPriceAddition()
{
// Check if a specific price has been submitted
if (!Tools::getIsset('submitPriceAddition')) {
return;
}
$id_product = Tools::getValue('id_product');
$id_product_attribute = Tools::getValue('sp_id_product_attribute');
$id_shop = Tools::getValue('sp_id_shop');
$id_currency = Tools::getValue('sp_id_currency');
$id_country = Tools::getValue('sp_id_country');
$id_group = Tools::getValue('sp_id_group');
$id_customer = Tools::getValue('sp_id_customer');
$price = Tools::getValue('leave_bprice') ? '-1' : Tools::getValue('sp_price');
$from_quantity = 1;
$reduction = (float)(Tools::getValue('sp_reduction'));
$reduction_tax = Tools::getValue('sp_reduction_tax');
$reduction_type = !$reduction ? 'amount' : Tools::getValue('sp_reduction_type');
$reduction_type = $reduction_type == '-' ? 'amount' : $reduction_type;
$from = Tools::getValue('sp_from');
if (!$from) {
$from = '0000-00-00 00:00:00';
}
$to = Tools::getValue('sp_to');
if (!$to) {
$to = '0000-00-00 00:00:00';
}
if (($price == '-1') && ((float)$reduction == '0')) {
$this->errors[] = Tools::displayError('No reduction value has been submitted');
} elseif ($to != '0000-00-00 00:00:00' && strtotime($to) < strtotime($from)) {
$this->errors[] = Tools::displayError('Invalid date range');
} elseif ($reduction_type == 'percentage' && ((float)$reduction <= 0 || (float)$reduction > 100)) {
$this->errors[] = Tools::displayError('Submitted reduction value (0-100) is out-of-range');
} elseif ($this->_validateSpecificPrice($id_shop, $id_currency, $id_country, $id_group, $id_customer, $price, $from_quantity, $reduction, $reduction_type, $from, $to, $id_product_attribute)) {
$specificPrice = new SpecificPrice();
$specificPrice->id_product = (int)$id_product;
$specificPrice->id_product_attribute = (int)$id_product_attribute;
$specificPrice->id_shop = (int)$id_shop;
$specificPrice->id_currency = (int)($id_currency);
$specificPrice->id_country = (int)($id_country);
$specificPrice->id_group = (int)($id_group);
$specificPrice->id_customer = (int)$id_customer;
$specificPrice->price = (float)($price);
$specificPrice->from_quantity = (int)($from_quantity);
$specificPrice->reduction = (float)($reduction_type == 'percentage' ? $reduction / 100 : $reduction);
$specificPrice->reduction_tax = $reduction_tax;
$specificPrice->reduction_type = $reduction_type;
$specificPrice->from = $from;
$specificPrice->to = $to;
if (!$specificPrice->add()) {
$this->errors[] = Tools::displayError('An error occurred while updating the specific price.');
}
}
}
public function ajaxProcessDeleteSpecificPrice()
{
if ($this->tabAccess['delete'] === 1) {
$id_specific_price = (int)Tools::getValue('id_specific_price');
if (!$id_specific_price || !Validate::isUnsignedId($id_specific_price)) {
$error = Tools::displayError('The specific price ID is invalid.');
} else {
$specificPrice = new SpecificPrice((int)$id_specific_price);
if (!$specificPrice->delete()) {
$error = Tools::displayError('An error occurred while attempting to delete the specific price.');
}
}
} else {
$error = Tools::displayError('You do not have permission to delete this.');
}
if (isset($error)) {
$json = array(
'status' => 'error',
'message'=> $error
);
} else {
$json = array(
'status' => 'ok',
'message'=> $this->_conf[1]
);
}
die(json_encode($json));
}
public function processSpecificPricePriorities()
{
if (!($obj = $this->loadObject())) {
return;
}
if (!$priorities = Tools::getValue('specificPricePriority')) {
$this->errors[] = Tools::displayError('Please specify priorities.');
} elseif (Tools::isSubmit('specificPricePriorityToAll')) {
if (!SpecificPrice::setPriorities($priorities)) {
$this->errors[] = Tools::displayError('An error occurred while updating priorities.');
} else {
$this->confirmations[] = $this->l('The price rule has successfully updated');
}
} elseif (!SpecificPrice::setSpecificPriority((int)$obj->id, $priorities)) {
$this->errors[] = Tools::displayError('An error occurred while setting priorities.');
}
}
/**
* Overrides parent for custom redirect link
*/
public function processPosition()
{
/** @var Product $object */
if (!Validate::isLoadedObject($object = $this->loadObject())) {
$this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').
' '.$this->table.' '.Tools::displayError('(cannot load object)');
} elseif (!$object->updatePosition((int)Tools::getValue('way'), (int)Tools::getValue('position'))) {
$this->errors[] = Tools::displayError('Failed to update the position.');
} else {
$category = new Category((int)Tools::getValue('id_category'));
if (Validate::isLoadedObject($category)) {
Hook::exec('actionCategoryUpdate', array('category' => $category));
}
$this->redirect_after = self::$currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&action=Customization&conf=5'.(($id_category = (Tools::getIsset('id_category') ? (int)Tools::getValue('id_category') : '')) ? ('&id_category='.$id_category) : '').'&token='.Tools::getAdminTokenLite('AdminProducts');
}
}
public function ajaxProcessChangeServicePosition()
{
$response = array('success' => false);
$idElement = Tools::getValue('id_element');
$idProduct = Tools::getValue('id_product');
if ($idElement && $idProduct) {
$newPosition = Tools::getValue('new_position');
if (RoomTypeServiceProduct::updatePosition(
$idProduct,
$idElement,
$newPosition,
RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE
)) {
$response['msg'] = $this->l('Positions updated successfully.');
$response['success'] = true;
}
}
die(json_encode($response));
}
public function initProcess()
{
if (Tools::isSubmit('submitAddproductAndStay') || Tools::isSubmit('submitAddproduct')) {
$this->id_object = (int)Tools::getValue('id_product');
$this->object = new Product($this->id_object);
if ($this->isTabSubmitted('Informations') && $this->object->is_virtual && (int)Tools::getValue('type_product') != 2) {
if ($id_product_download = (int)ProductDownload::getIdFromIdProduct($this->id_object)) {
$product_download = new ProductDownload($id_product_download);
if (!$product_download->deleteFile($id_product_download)) {
$this->errors[] = Tools::displayError('Cannot delete file');
}
}
}
}
// Delete a product in the download folder
if (Tools::getValue('deleteVirtualProduct')) {
if ($this->tabAccess['delete'] === 1) {
$this->action = 'deleteVirtualProduct';
} else {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
}
}
// Product preview
elseif (Tools::isSubmit('submitAddProductAndPreview')) {
$this->display = 'edit';
$this->action = 'save';
if (Tools::getValue('id_product')) {
$this->id_object = Tools::getValue('id_product');
$this->object = new Product((int)Tools::getValue('id_product'));
}
} elseif (Tools::isSubmit('submitAttachments')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'attachments';
$this->tab_display = 'attachments';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Product duplication
elseif (Tools::getIsset('duplicate'.$this->table)) {
if ($this->tabAccess['add'] === 1) {
$this->action = 'duplicate';
} else {
$this->errors[] = Tools::displayError('You do not have permission to add this.');
}
}
// Toggle Show at front
elseif (Tools::getIsset('show_at_front'.$this->table)) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'toggleShowAtFront';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Product images management
elseif (Tools::getValue('id_image') && Tools::getValue('ajax')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'image';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Product attributes management
elseif (Tools::isSubmit('submitProductAttribute')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'productAttribute';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Product features management
elseif (Tools::isSubmit('submitFeatures') || Tools::isSubmit('submitFeaturesAndStay')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'features';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Product specific prices management NEVER USED
elseif (Tools::isSubmit('submitPricesModification')) {
if ($this->tabAccess['add'] === 1) {
$this->action = 'pricesModification';
} else {
$this->errors[] = Tools::displayError('You do not have permission to add this.');
}
} elseif (Tools::isSubmit('deleteSpecificPrice')) {
if ($this->tabAccess['delete'] === 1) {
$this->action = 'deleteSpecificPrice';
} else {
$this->errors[] = Tools::displayError('You do not have permission to delete this.');
}
} elseif (Tools::isSubmit('submitSpecificPricePriorities')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'specificPricePriorities';
$this->tab_display = 'prices';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Customization management
elseif (Tools::isSubmit('submitCustomizationConfiguration')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'customizationConfiguration';
$this->tab_display = 'customization';
$this->display = 'edit';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
}
// Room bulk deletion process
else if (Tools::isSubmit('submitBulkDeleteRooms')) {
$this->action = 'bulkDeleteRooms';
$this->display = 'edit';
} elseif (Tools::isSubmit('submitProductCustomization')) {
if ($this->tabAccess['edit'] === 1) {
$this->action = 'productCustomization';
$this->tab_display = 'customization';
$this->display = 'edit';
} else {
$this->errors[] = Tools::displayError('You do not have permission to edit this.');
}
} elseif (Tools::isSubmit('id_product')) {
$post_max_size = Tools::getMaxUploadSize(Configuration::get('PS_LIMIT_UPLOAD_FILE_VALUE') * 1024 * 1024);
if ($post_max_size && isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] && $_SERVER['CONTENT_LENGTH'] > $post_max_size) {
$this->errors[] = sprintf(Tools::displayError('The uploaded file exceeds the "Maximum size for a downloadable product" set in preferences (%1$dMB) or the post_max_size/ directive in php.ini (%2$dMB).'), number_format((Configuration::get('PS_LIMIT_UPLOAD_FILE_VALUE'))), ($post_max_size / 1024 / 1024));
}
}
if (!$this->action) {
parent::initProcess();
} else {
$this->id_object = (int)Tools::getValue($this->identifier);
}
if (isset($this->available_tabs[Tools::getValue('key_tab')])) {
$this->tab_display = Tools::getValue('key_tab');
}
// Set tab to display if not decided already
if (!$this->tab_display && $this->action) {
if (in_array($this->action, array_keys($this->available_tabs))) {
$this->tab_display = $this->action;
}
}
// And if still not set, use default
if (!$this->tab_display) {
if (in_array($this->default_tab, $this->available_tabs)) {
$this->tab_display = $this->default_tab;
} else {
$this->tab_display = key($this->available_tabs);
}
}
}
/**
* postProcess handle every checks before saving products information
*
* @return void
*/
public function postProcess()
{
if (!$this->redirect_after) {
parent::postProcess();
}
$this->addJS(array(
_PS_JS_DIR_.'admin/products.js',
));
if (in_array($this->display, array('add', 'edit'))
&& $this->tabAccess['view'] === 1
&& $this->loadObject(true)
) {
$this->addJqueryUI(array(
'ui.core',
'ui.widget',
'ui.tooltip'
));
$this->addjQueryPlugin(array(
'autocomplete',
'tablednd',
'thickbox',
'ajaxfileupload',
'date',
'tagify',
'select2'
));
$this->addJS(array(
_PS_JS_DIR_.'admin/attributes.js',
_PS_JS_DIR_.'admin/price.js',
_PS_JS_DIR_.'tiny_mce/tiny_mce.js',
_PS_JS_DIR_.'admin/tinymce.inc.js',
_PS_JS_DIR_.'admin/dnd.js',
_PS_JS_DIR_.'jquery/ui/jquery.ui.progressbar.min.js',
_PS_JS_DIR_.'vendor/spin.js',
_PS_JS_DIR_.'vendor/ladda.js'
));
$this->addJS(_PS_JS_DIR_.'jquery/plugins/select2/select2_locale_'.$this->context->language->iso_code.'.js');
$this->addJS(_PS_JS_DIR_.'jquery/plugins/validate/localization/messages_'.$this->context->language->iso_code.'.js');
$this->addCSS(_PS_JS_DIR_.'jquery/plugins/timepicker/jquery-ui-timepicker-addon.css');
}
}
public function ajaxPreProcess()
{
if (Tools::getIsset('update'.$this->table) && Tools::getIsset('id_'.$this->table)) {
$this->display = 'edit';
$this->action = Tools::getValue('action');
}
}
public function ajaxProcessUpdateProductImageShopAsso()
{
$id_product = Tools::getValue('id_product');
if (($id_image = Tools::getValue('id_image')) && ($id_shop = (int)Tools::getValue('id_shop'))) {
if (Tools::getValue('active') == 'true') {
$res = Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'image_shop (`id_product`, `id_image`, `id_shop`, `cover`) VALUES('.(int)$id_product.', '.(int)$id_image.', '.(int)$id_shop.', NULL)');
} else {
$res = Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'image_shop WHERE `id_image` = '.(int)$id_image.' AND `id_shop` = '.(int)$id_shop);
}
}
// Clean covers in image table
$count_cover_image = Db::getInstance()->getValue('
SELECT COUNT(*) FROM '._DB_PREFIX_.'image i
INNER JOIN '._DB_PREFIX_.'image_shop ish ON (i.id_image = ish.id_image AND ish.id_shop = '.(int)$id_shop.')
WHERE i.cover = 1 AND i.`id_product` = '.(int)$id_product);
if (!$id_image) {
$id_image = Db::getInstance()->getValue('
SELECT i.`id_image` FROM '._DB_PREFIX_.'image i
INNER JOIN '._DB_PREFIX_.'image_shop ish ON (i.id_image = ish.id_image AND ish.id_shop = '.(int)$id_shop.')
WHERE i.`id_product` = '.(int)$id_product);
}
if ($count_cover_image < 1) {
Db::getInstance()->execute('UPDATE '._DB_PREFIX_.'image i SET i.cover = 1 WHERE i.id_image = '.(int)$id_image.' AND i.`id_product` = '.(int)$id_product.' LIMIT 1');
}
// Clean covers in image_shop table
$count_cover_image_shop = Db::getInstance()->getValue('
SELECT COUNT(*)
FROM '._DB_PREFIX_.'image_shop ish
WHERE ish.`id_product` = '.(int)$id_product.' AND ish.id_shop = '.(int)$id_shop.' AND ish.cover = 1');
if ($count_cover_image_shop < 1) {
Db::getInstance()->execute('UPDATE '._DB_PREFIX_.'image_shop ish SET ish.cover = 1 WHERE ish.id_image = '.(int)$id_image.' AND ish.`id_product` = '.(int)$id_product.' AND ish.id_shop = '.(int)$id_shop.' LIMIT 1');
}
if ($res) {
$this->jsonConfirmation($this->_conf[27]);
} else {
$this->jsonError(Tools::displayError('An error occurred while attempting to associate this image with your shop. '));
}
}
public function ajaxProcessUpdateImagePosition()
{
if ($this->tabAccess['edit'] === '0') {
return die(json_encode(array('error' => $this->l('You do not have the right permission'))));
}
$res = false;
if ($json = Tools::getValue('json')) {
$res = true;
$json = stripslashes($json);
$images = json_decode($json, true);
foreach ($images as $id => $position) {
$img = new Image((int)$id);
$img->position = (int)$position;
$res &= $img->update();
}
}
if ($res) {
$this->jsonConfirmation($this->_conf[25]);
} else {
$this->jsonError(Tools::displayError('An error occurred while attempting to move this picture.'));
}
}
public function ajaxProcessUpdateCover()
{
if ($this->tabAccess['edit'] === '0') {
return die(json_encode(array('error' => $this->l('You do not have the right permission'))));
}
Image::deleteCover((int)Tools::getValue('id_product'));
$img = new Image((int)Tools::getValue('id_image'));
$img->cover = 1;
@unlink(_PS_TMP_IMG_DIR_.'product_'.(int)$img->id_product.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'product_mini_'.(int)$img->id_product.'_'.$this->context->shop->id.'.jpg');
if ($img->update()) {
$this->jsonConfirmation($this->_conf[26]);
} else {
$this->jsonError(Tools::displayError('An error occurred while attempting to update the cover picture.'));
}
}
public function ajaxProcessDeleteProductImage()
{
if ($this->tabAccess['edit'] === '0') {
return die(json_encode(array('error' => $this->l('You do not have the right permission'))));
}
$this->display = 'content';
$res = true;
/* Delete product image */
$image = new Image((int)Tools::getValue('id_image'));
$this->content['id'] = $image->id;
$res &= $image->delete();
// if deleted image was the cover, change it to the first one
if (!Image::getCover($image->id_product)) {
$res &= Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'image_shop` image_shop
SET image_shop.`cover` = 1
WHERE image_shop.`id_product` = '.(int)$image->id_product.'
AND id_shop='.(int)$this->context->shop->id.' LIMIT 1');
}
if (!Image::getGlobalCover($image->id_product)) {
$res &= Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'image` i
SET i.`cover` = 1
WHERE i.`id_product` = '.(int)$image->id_product.' LIMIT 1');
}
if (file_exists(_PS_TMP_IMG_DIR_.'product_'.$image->id_product.'.jpg')) {
$res &= @unlink(_PS_TMP_IMG_DIR_.'product_'.$image->id_product.'.jpg');
}
if (file_exists(_PS_TMP_IMG_DIR_.'product_mini_'.$image->id_product.'_'.$this->context->shop->id.'.jpg')) {
$res &= @unlink(_PS_TMP_IMG_DIR_.'product_mini_'.$image->id_product.'_'.$this->context->shop->id.'.jpg');
}
if ($res) {
$this->jsonConfirmation($this->_conf[7]);
} else {
$this->jsonError(Tools::displayError('An error occurred while attempting to delete the room type image.'));
}
}
protected function _validateSpecificPrice($id_shop, $id_currency, $id_country, $id_group, $id_customer, $price, $from_quantity, $reduction, $reduction_type, $from, $to, $id_combination = 0)
{
if (!Validate::isUnsignedId($id_shop) || !Validate::isUnsignedId($id_currency) || !Validate::isUnsignedId($id_country) || !Validate::isUnsignedId($id_group) || !Validate::isUnsignedId($id_customer)) {
$this->errors[] = Tools::displayError('Wrong IDs');
} elseif ((!isset($price) && !isset($reduction)) || (isset($price) && !Validate::isNegativePrice($price)) || (isset($reduction) && !Validate::isPrice($reduction))) {
$this->errors[] = Tools::displayError('Invalid price/discount amount');
} elseif (!Validate::isUnsignedInt($from_quantity)) {
$this->errors[] = Tools::displayError('Invalid quantity');
} elseif ($reduction && !Validate::isReductionType($reduction_type)) {
$this->errors[] = Tools::displayError('Please select a discount type (amount or percentage).');
} elseif ($from && $to && (!Validate::isDateFormat($from) || !Validate::isDateFormat($to))) {
$this->errors[] = Tools::displayError('The from/to date is invalid.');
} elseif (SpecificPrice::exists((int)$this->object->id, $id_combination, $id_shop, $id_group, $id_country, $id_currency, $id_customer, $from_quantity, $from, $to, false)) {
$this->errors[] = Tools::displayError('A specific price already exists for these parameters.');
} else {
return true;
}
return false;
}
/* Checking customs feature */
protected function checkFeatures($languages, $feature_id)
{
$rules = call_user_func(array('FeatureValue', 'getValidationRules'), 'FeatureValue');
$feature = Feature::getFeature((int)Configuration::get('PS_LANG_DEFAULT'), $feature_id);
foreach ($languages as $language) {
if ($val = Tools::getValue('custom_'.$feature_id.'_'.$language['id_lang'])) {
$current_language = new Language($language['id_lang']);
if (Tools::strlen($val) > $rules['sizeLang']['value']) {
$this->errors[] = sprintf(
Tools::displayError('The name for feature %1$s is too long in %2$s.'),
' '.$feature['name'].'',
$current_language->name
);
} elseif (!call_user_func(array('Validate', $rules['validateLang']['value']), $val)) {
$this->errors[] = sprintf(
Tools::displayError('A valid name required for feature. %1$s in %2$s.'),
' '.$feature['name'].'',
$current_language->name
);
}
if (count($this->errors)) {
return 0;
}
// Getting default language
if ($language['id_lang'] == Configuration::get('PS_LANG_DEFAULT')) {
return $val;
}
}
}
return 0;
}
/**
* Add or update a product image
*
* @param Product $product Product object to add image
* @param string $method
*
* @return int|false
*/
public function addProductImage($product, $method = 'auto')
{
/* Updating an existing product image */
if ($id_image = (int)Tools::getValue('id_image')) {
$image = new Image((int)$id_image);
if (!Validate::isLoadedObject($image)) {
$this->errors[] = Tools::displayError('An error occurred while loading the object image.');
} else {
if (($cover = Tools::getValue('cover')) == 1) {
Image::deleteCover($product->id);
}
$image->cover = $cover;
$this->validateRules('Image');
$this->copyFromPost($image, 'image');
if (count($this->errors) || !$image->update()) {
$this->errors[] = Tools::displayError('An error occurred while updating the image.');
} elseif (isset($_FILES['image_product']['tmp_name']) && $_FILES['image_product']['tmp_name'] != null) {
$this->copyImage($product->id, $image->id, $method);
}
}
}
if (isset($image) && Validate::isLoadedObject($image) && !file_exists(_PS_PROD_IMG_DIR_.$image->getExistingImgPath().'.'.$image->image_format)) {
$image->delete();
}
if (count($this->errors)) {
return false;
}
@unlink(_PS_TMP_IMG_DIR_.'product_'.$product->id.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'product_mini_'.$product->id.'_'.$this->context->shop->id.'.jpg');
return ((isset($id_image) && is_int($id_image) && $id_image) ? $id_image : false);
}
/**
* Copy a product image
*
* @param int $id_product Product Id for product image filename
* @param int $id_image Image Id for product image filename
* @param string $method
*
* @return void|false
* @throws PrestaShopException
*/
public function copyImage($id_product, $id_image, $method = 'auto')
{
if (!isset($_FILES['image_product']['tmp_name'])) {
return false;
}
if ($error = ImageManager::validateUpload($_FILES['image_product'])) {
$this->errors[] = $error;
} else {
$image = new Image($id_image);
if (!$new_path = $image->getPathForCreation()) {
$this->errors[] = Tools::displayError('An error occurred while attempting to create a new folder.');
}
if (!($tmpName = tempnam(_PS_TMP_IMG_DIR_, 'PS')) || !move_uploaded_file($_FILES['image_product']['tmp_name'], $tmpName)) {
$this->errors[] = Tools::displayError('An error occurred during the image upload process.');
} elseif (!ImageManager::resize($tmpName, $new_path.'.'.$image->image_format)) {
$this->errors[] = Tools::displayError('An error occurred while copying the image.');
} elseif ($method == 'auto') {
$imagesTypes = ImageType::getImagesTypes('products');
foreach ($imagesTypes as $k => $image_type) {
if (!ImageManager::resize($tmpName, $new_path.'-'.stripslashes($image_type['name']).'.'.$image->image_format, $image_type['width'], $image_type['height'], $image->image_format)) {
$this->errors[] = Tools::displayError('An error occurred while copying this image:').' '.stripslashes($image_type['name']);
}
}
}
@unlink($tmpName);
Hook::exec('actionWatermark', array('id_image' => $id_image, 'id_product' => $id_product));
}
}
protected function updateAssoShop($id_object)
{
//override AdminController::updateAssoShop() specifically for products because shop association is set with the context in ObjectModel
return;
}
public function processAdd()
{
$this->checkProduct();
if (!empty($this->errors)) {
$this->display = 'add';
return false;
}
$this->object = new $this->className();
$this->_removeTaxFromEcotax();
$this->copyFromPost($this->object, $this->table);
$this->object->booking_product = true;
if ($this->object->add()) {
// associateroom type to hotel
// if ($this->object->is_virtual) {
// }
$this->assignRoomType($this->object);
if ($this->isTabSubmitted('Amenities')) {
$categories = HotelAmenities::getCategories();
if ($categories && !HotelAmenities::getAmenities()) {
$this->errors[] = Tools::displayError('No amenities have been created. Please add amenities to at least one category before assigning them.');
return false;
}
$selectedAmenities = Tools::getValue('room_type_amenities', array());
$featuredAmenities = Tools::getValue('featured_amenities', array());
if (!(new HotelRoomTypeAmenities())->saveRoomTypeAmenities((int)$this->object->id, $selectedAmenities, $featuredAmenities)) {
$this->errors[] = Tools::displayError('An error occurred while saving room type amenities.');
return false;
}
}
if ($this->isTabSubmitted('Features') && !$this->saveRoomTypeFeatures($this->object)) {
$this->errors[] = Tools::displayError('An error occurred while saving room type features.');
return false;
}
PrestaShopLogger::addLog(sprintf($this->l('%s addition', 'AdminTab', false, false), $this->className), 1, null, $this->className, (int)$this->object->id, true, (int)$this->context->employee->id);
if (Configuration::get('PS_FORCE_ASM_NEW_PRODUCT') && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $this->object->getType() != Product::PTYPE_VIRTUAL) {
$this->object->advanced_stock_management = 1;
$this->object->save();
$id_shops = Shop::getContextListShopID();
foreach ($id_shops as $id_shop) {
StockAvailable::setProductDependsOnStock($this->object->id, true, (int)$id_shop, 0);
}
}
if (empty($this->errors)) {
$languages = Language::getLanguages(false);
if ($this->isProductFieldUpdated('category_box') && !$this->object->updateCategories(Tools::getValue('categoryBox'))) {
$this->errors[] = Tools::displayError('An error occurred while linking the object.').' '.$this->table.' '.Tools::displayError('To categories');
} elseif (!$this->updateTags($languages, $this->object)) {
$this->errors[] = Tools::displayError('An error occurred while adding tags.');
} else {
Hook::exec('actionProductAdd', array('id_product' => (int)$this->object->id, 'product' => $this->object));
if (in_array($this->object->visibility, array('both', 'search')) && Configuration::get('PS_SEARCH_INDEXATION')) {
Search::indexation(false, $this->object->id);
}
}
if (Configuration::get('PS_DEFAULT_WAREHOUSE_NEW_PRODUCT') != 0 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
$warehouse_location_entity = new WarehouseProductLocation();
$warehouse_location_entity->id_product = $this->object->id;
$warehouse_location_entity->id_product_attribute = 0;
$warehouse_location_entity->id_warehouse = Configuration::get('PS_DEFAULT_WAREHOUSE_NEW_PRODUCT');
$warehouse_location_entity->location = pSQL('');
$warehouse_location_entity->save();
}
// Apply groups reductions
$this->object->setGroupReduction();
// Save and preview
if (Tools::isSubmit('submitAddProductAndPreview')) {
$this->redirect_after = $this->getPreviewUrl($this->object);
}
// Save and stay on same form
if ($this->display == 'edit') {
$this->redirect_after = self::$currentIndex.'&id_product='.(int)$this->object->id
.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '')
.'&updateproduct&conf=3&key_tab='.Tools::safeOutput(Tools::getValue('key_tab')).'&token='.$this->token;
} else {
// Default behavior (save and back)
$this->redirect_after = self::$currentIndex
.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '')
.'&conf=3&token='.$this->token;
}
} else {
$this->object->delete();
// if errors : stay on edit page
$this->display = 'edit';
}
} else {
$this->errors[] = Tools::displayError('An error occurred while creating an object.').' '.$this->table.'';
}
return $this->object;
}
protected function isTabSubmitted($tab_name)
{
if (!is_array($this->submitted_tabs)) {
$this->submitted_tabs = Tools::getValue('submitted_tabs');
}
if (is_array($this->submitted_tabs) && in_array($tab_name, $this->submitted_tabs)) {
return true;
}
return false;
}
public function processStatus()
{
$this->loadObject(true);
if (!Validate::isLoadedObject($this->object)) {
return false;
}
if (($error = $this->object->validateFields(false, true)) !== true) {
$this->errors[] = $error;
}
if (($error = $this->object->validateFieldsLang(false, true)) !== true) {
$this->errors[] = $error;
}
if (!count($this->errors)) {
$objHotelRoomType = new HotelRoomType();
if ($roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($this->object->id)) {
$objHotelBranchInformation = new HotelBranchInformation((int)$roomTypeInfo['id_hotel']);
if (!$objHotelBranchInformation->active && !$this->object->active) {
$this->errors[] = $this->l('Room type can not be active as long as hotel is disabled.');
}
}
}
if (count($this->errors)) {
return false;
}
$res = parent::processStatus();
$query = trim(Tools::getValue('bo_query'));
$searchType = (int)Tools::getValue('bo_search_type');
if ($query) {
$this->redirect_after = preg_replace('/[\?|&](bo_query|bo_search_type)=([^&]*)/i', '', $this->redirect_after);
$this->redirect_after .= '&bo_query='.$query.'&bo_search_type='.$searchType;
}
return $res;
}
public function processBulkStatusSelection($status)
{
if (!is_array($this->boxes) || empty($this->boxes)) {
return parent::processBulkStatusSelection($status);
}
$disabledHotelRoomTypes = array();
$objHotelRoomType = new HotelRoomType();
$result = true;
$hasSuccessfulUpdate = false;
foreach ($this->boxes as $id) {
$id = (int) $id;
$object = new $this->className($id);
if (!Validate::isLoadedObject($object)) {
$this->errors[] = sprintf($this->l('Invalid room type ID %d.'), $id);
$result = false;
continue;
}
if ($status && ($roomTypeInfo = $objHotelRoomType->getRoomTypeInfoByIdProduct($id))) {
$objHotelBranchInformation = new HotelBranchInformation((int) $roomTypeInfo['id_hotel']);
if (!$objHotelBranchInformation->active) {
$disabledHotelRoomTypes[] = Product::getProductName($id, null, (int)$this->context->language->id);
continue;
}
}
$object->setFieldsToUpdate(array('active' => true));
$object->active = (int) $status;
$isUpdated = (bool) $object->update();
$result = $result && $isUpdated;
$hasSuccessfulUpdate = $hasSuccessfulUpdate || $isUpdated;
if (!$isUpdated) {
$this->errors[] = sprintf($this->l('Can\'t update #%d status.'), $id);
}
}
if ($disabledHotelRoomTypes) {
$this->errors[] =
$this->l('Room types linked to inactive hotels cannot be enabled.');
}
if ($result && $hasSuccessfulUpdate && !$disabledHotelRoomTypes) {
$this->redirect_after = self::$currentIndex.'&conf=5&token='.$this->token;
} elseif ($result && $hasSuccessfulUpdate) {
$this->confirmations[] = $this->l('The status has been updated for the room types linked to active hotels.');
} elseif (!$result) {
$this->errors[] = $this->l('An error occurred while updating the status.');
}
return $result;
}
public function processToggleShowAtFront()
{
if (!$this->loadObject()) {
return false;
}
if (!Product::isBookingProduct($this->object->id)) {
return false;
}
$this->object->show_at_front = !$this->object->show_at_front;
if ($this->object->save()) {
Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token.'&conf=4');
} else {
$this->errors[] = $this->l('An error occurred while updating "show at front".');
}
}
public function processUpdate()
{
$existing_product = $this->object;
$this->checkProduct();
if (!empty($this->errors)) {
$this->display = 'edit';
return false;
}
$id = (int)Tools::getValue('id_'.$this->table);
/* Update an existing product */
if (isset($id) && !empty($id)) {
/** @var Product $object */
$object = new $this->className((int)$id);
$this->object = $object;
if (Validate::isLoadedObject($object)) {
$this->_removeTaxFromEcotax();
$product_type_before = $object->getType();
$this->copyFromPost($object, $this->table);
$object->indexed = 0;
if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_SHOP) {
$object->setFieldsToUpdate((array)Tools::getValue('multishop_check', array()));
}
// Duplicate combinations if not associated to shop
if ($this->context->shop->getContext() == Shop::CONTEXT_SHOP && !$object->isAssociatedToShop()) {
$is_associated_to_shop = false;
$combinations = Product::getProductAttributesIds($object->id);
if ($combinations) {
foreach ($combinations as $id_combination) {
$combination = new Combination((int)$id_combination['id_product_attribute']);
$default_combination = new Combination((int)$id_combination['id_product_attribute'], null, (int)$this->object->id_shop_default);
$def = ObjectModel::getDefinition($default_combination);
foreach ($def['fields'] as $field_name => $row) {
$combination->$field_name = ObjectModel::formatValue($default_combination->$field_name, $def['fields'][$field_name]['type']);
}
$combination->save();
}
}
} else {
$is_associated_to_shop = true;
}
if ($object->update()) {
if ($this->isTabSubmitted('Amenities')) {
$selectedAmenities = Tools::getValue('room_type_amenities', array());
$featuredAmenities = Tools::getValue('featured_amenities', array());
if (!(new HotelRoomTypeAmenities())->saveRoomTypeAmenities((int)$object->id, $selectedAmenities, $featuredAmenities)) {
$this->errors[] = Tools::displayError('An error occurred while saving room type amenities.');
return false;
}
}
if ($this->isTabSubmitted('Features') && !$this->saveRoomTypeFeatures($object)) {
$this->errors[] = Tools::displayError('An error occurred while saving room type features.');
return false;
}
// update position in category
$object->setPositionInCategory(Tools::getValue('category_position'));
// If the product doesn't exist in the current shop but exists in another shop
if (Shop::getContext() == Shop::CONTEXT_SHOP && !$existing_product->isAssociatedToShop($this->context->shop->id)) {
$out_of_stock = StockAvailable::outOfStock($existing_product->id, $existing_product->id_shop_default);
$depends_on_stock = StockAvailable::dependsOnStock($existing_product->id, $existing_product->id_shop_default);
StockAvailable::setProductOutOfStock((int)$this->object->id, $out_of_stock, $this->context->shop->id);
StockAvailable::setProductDependsOnStock((int)$this->object->id, $depends_on_stock, $this->context->shop->id);
}
PrestaShopLogger::addLog(sprintf($this->l('%s modification', 'AdminTab', false, false), $this->className), 1, null, $this->className, (int)$this->object->id, true, (int)$this->context->employee->id);
if (in_array($this->context->shop->getContext(), array(Shop::CONTEXT_SHOP, Shop::CONTEXT_ALL))) {
if ($this->isTabSubmitted('Shipping')) {
// $this->addCarriers();
}
if ($this->isTabSubmitted('Associations')) {
// $this->updateAccessories($object);
}
if ($this->isTabSubmitted('Suppliers')) {
// $this->processSuppliers();
}
if ($this->isTabSubmitted('Combinations')) {
$this->processProductAttribute();
}
if ($this->isTabSubmitted('Prices')) {
$this->processAdvancedPayment();
$this->processPriceAddition();
$this->processSpecificPricePriorities();
}
if ($this->isTabSubmitted('Customization')) {
$this->processCustomizationConfiguration();
}
if ($this->isTabSubmitted('Attachments')) {
$this->processAttachments();
}
if ($this->isTabSubmitted('Images')) {
$this->processImageLegends();
}
if ($this->isTabSubmitted('Occupancy')) {
$this->processOccupancy();
}
if ($this->isTabSubmitted('ServiceProduct')) {
$this->processServiceProduct();
}
if ($this->isTabSubmitted('LengthOfStay')) {
$this->processLengthOfStay();
}
if ($this->isTabSubmitted('Configuration')) {
$this->processConfiguration();
}
// $this->updatePackItems($object);
// Disallow avanced stock management if the product become a pack
if ($product_type_before == Product::PTYPE_SIMPLE && $object->getType() == Product::PTYPE_PACK) {
StockAvailable::setProductDependsOnStock((int)$object->id, false);
}
// $this->updateDownloadProduct($object, 1);
$this->updateTags(Language::getLanguages(false), $object);
if ($this->isProductFieldUpdated('category_box') && !$object->updateCategories(Tools::getValue('categoryBox'))) {
$this->errors[] = Tools::displayError('An error occurred while linking the object.').' '.$this->table.' '.Tools::displayError('To categories');
}
}
if ($this->isTabSubmitted('Warehouses')) {
$this->processWarehouses();
}
if (empty($this->errors)) {
if (in_array($object->visibility, array('both', 'search')) && Configuration::get('PS_SEARCH_INDEXATION')) {
Search::indexation(false, $object->id);
}
// Save and preview
if (Tools::isSubmit('submitAddProductAndPreview')) {
$this->redirect_after = $this->getPreviewUrl($object);
} else {
$page = (int)Tools::getValue('page');
// Save and stay on same form
if ($this->display == 'edit') {
$this->confirmations[] = $this->l('Update successful');
$this->redirect_after = self::$currentIndex.'&id_product='.(int)$this->object->id
.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '')
.'&updateproduct&conf=4&key_tab='.Tools::safeOutput(Tools::getValue('key_tab')).($page > 1 ? '&page='.(int)$page : '').'&token='.$this->token;
} else {
// Default behavior (save and back)
$this->redirect_after = self::$currentIndex.(Tools::getIsset('id_category') ? '&id_category='.(int)Tools::getValue('id_category') : '').'&conf=4'.($page > 1 ? '&submitFilterproduct='.(int)$page : '').'&token='.$this->token;
}
}
}
// if errors : stay on edit page
else {
$this->display = 'edit';
}
} else {
if (!$is_associated_to_shop && $combinations) {
foreach ($combinations as $id_combination) {
$combination = new Combination((int)$id_combination['id_product_attribute']);
$combination->delete();
}
}
$this->errors[] = Tools::displayError('An error occurred while updating an object.').' '.$this->table.' ('.Db::getInstance()->getMsgError().')';
}
} else {
$this->errors[] = Tools::displayError('An error occurred while updating an object.').' '.$this->table.' ('.Tools::displayError('The object cannot be loaded. ').')';
}
return $object;
}
}
/**
* Check that a saved product is valid
*/
public function checkProduct()
{
$className = 'Product';
// @todo : the call_user_func seems to contains only statics values (className = 'Product')
$rules = call_user_func(array($this->className, 'getValidationRules'), $this->className);
$default_language = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$languages = Language::getLanguages(false);
// Check required fields
foreach ($rules['required'] as $field) {
if (!$this->isProductFieldUpdated($field)) {
continue;
}
if (($value = Tools::getValue($field)) == false && $value != '0') {
if (Tools::getValue('id_'.$this->table) && $field == 'passwd') {
continue;
}
$this->errors[] = sprintf(
Tools::displayError('The %s field is required.'),
call_user_func(array($className, 'displayFieldName'), $field, $className)
);
}
}
// Check multilingual required fields
foreach ($rules['requiredLang'] as $fieldLang) {
if ($this->isProductFieldUpdated($fieldLang, $default_language->id) && !Tools::getValue($fieldLang.'_'.$default_language->id)) {
$this->errors[] = sprintf(
Tools::displayError('This %1$s field is required at least in %2$s'),
call_user_func(array($className, 'displayFieldName'), $fieldLang, $className),
$default_language->name
);
}
}
// Check fields sizes
foreach ($rules['size'] as $field => $maxLength) {
if ($this->isProductFieldUpdated($field) && ($value = Tools::getValue($field)) && Tools::strlen($value) > $maxLength) {
$this->errors[] = sprintf(
Tools::displayError('The %1$s field is too long (%2$d chars max).'),
call_user_func(array($className, 'displayFieldName'), $field, $className),
$maxLength
);
}
}
if (Tools::getIsset('description_short') && $this->isProductFieldUpdated('description_short')) {
$saveShort = Tools::getValue('description_short');
$_POST['description_short'] = strip_tags(Tools::getValue('description_short'));
}
// Check description short size without html
$limit = (int)Configuration::get('PS_SHORT_DESC_LIMIT');
if ($limit <= 0) {
$limit = Configuration::PS_SHORT_DESC_LIMIT;
}
foreach ($languages as $language) {
if ($this->isProductFieldUpdated('description_short', $language['id_lang']) && ($value = Tools::getValue('description_short_'.$language['id_lang']))) {
if (Tools::strlen(strip_tags($value)) > $limit) {
$this->errors[] = sprintf(
Tools::displayError('This %1$s field in %2$s is too long: %3$d chars max (current count %4$d).'),
call_user_func(array($className, 'displayFieldName'), 'description_short'),
$language['name'],
$limit,
Tools::strlen(strip_tags($value))
);
}
}
}
// Check multilingual fields sizes
foreach ($rules['sizeLang'] as $fieldLang => $maxLength) {
foreach ($languages as $language) {
$value = Tools::getValue($fieldLang.'_'.$language['id_lang']);
if ($value && Tools::strlen($value) > $maxLength) {
$this->errors[] = sprintf(
Tools::displayError('The %1$s field is too long (%2$d chars max).'),
call_user_func(array($className, 'displayFieldName'), $fieldLang, $className),
$maxLength
);
}
}
}
if ($this->isProductFieldUpdated('description_short') && isset($_POST['description_short'])) {
$_POST['description_short'] = $saveShort;
}
// Check fields validity
foreach ($rules['validate'] as $field => $function) {
if ($this->isProductFieldUpdated($field) && ($value = Tools::getValue($field))) {
$res = true;
if (Tools::strtolower($function) == 'iscleanhtml') {
if (!Validate::{$function}($value, (int)Configuration::get('PS_ALLOW_HTML_IFRAME'))) {
$res = false;
}
} elseif (!Validate::{$function}($value)) {
$res = false;
}
if (!$res) {
if (Tools::strtolower($field) == 'wholesale_price') {
$this->errors[] = Tools::displayError('The Pre-tax operating cost field is invalid.');
} else {
$this->errors[] = sprintf(
Tools::displayError('The %s field is invalid.'),
call_user_func(array($className, 'displayFieldName'), $field, $className)
);
}
}
}
}
// Check multilingual fields validity
foreach ($rules['validateLang'] as $fieldLang => $function) {
foreach ($languages as $language) {
if ($this->isProductFieldUpdated($fieldLang, $language['id_lang']) && ($value = Tools::getValue($fieldLang.'_'.$language['id_lang']))) {
if (!Validate::{$function}($value, (int)Configuration::get('PS_ALLOW_HTML_IFRAME'))) {
$this->errors[] = sprintf(
Tools::displayError('The %1$s field (%2$s) is invalid.'),
call_user_func(array($className, 'displayFieldName'), $fieldLang, $className),
$language['name']
);
}
}
}
}
// if (Tools::getValue('is_virtual')) {
$id_hotel = Tools::getValue('id_hotel');
if (!$id_hotel || !Validate::isUnsignedInt($id_hotel)) {
$this->errors[] = Tools::displayError('Please select a hotel');
} else if (!Validate::isLoadedObject($objHotel = new HotelBranchInformation($id_hotel))) {
$this->errors[] = Tools::displayError('Selected Hotel not found');
} else {
// Prevent enabling a room type when its hotel is disabled
if ((int)Tools::getValue('active') === 1 && isset($objHotel) && !$objHotel->active) {
$this->errors[] = Tools::displayError('Room type can not be active as long as hotel is disabled.');
}
$hotelIdCategory = $objHotel->id_category;
if (Validate::isLoadedObject($objCategory = new Category($hotelIdCategory))) {
foreach($objCategory->getParentsCategories() as $category) {
$_POST['categoryBox'][] = $category['id_category'];
}
if(!Tools::getValue('id_category_default')) {
$_POST['id_category_default'] = $hotelIdCategory;
}
}
}
// } else {
// $rootCategory = Category::getRootCategory();
// $_POST['categoryBox'][] = $rootCategory->id_category;
// if(!Tools::getValue('id_category_default')) {
// $_POST['id_category_default'] = $rootCategory->id_category;
// }
// }
// Categories
if ($this->isProductFieldUpdated('id_category_default') && (!Tools::isSubmit('categoryBox') || !count(Tools::getValue('categoryBox')))) {
$this->errors[] = $this->l('This room type must be in at least one category.');
}
if ($this->isProductFieldUpdated('id_category_default') && (!is_array(Tools::getValue('categoryBox')) || !in_array(Tools::getValue('id_category_default'), Tools::getValue('categoryBox')))) {
$this->errors[] = $this->l('This room type must be in the default category.');
}
// Tags
foreach ($languages as $language) {
if ($value = Tools::getValue('tags_'.$language['id_lang'])) {
if (!Validate::isTagsList($value)) {
$this->errors[] = sprintf(
Tools::displayError('The tags list (%s) is invalid.'),
$language['name']
);
}
}
}
// Category Position
if (Validate::isLoadedObject($this->object)) {
$categoryPositon = Tools::getValue('category_position');
if ($categoryPositon < 0) {
$this->errors[] = $this->l('Position can not be less than 0.');
}
if (isset($objHotel) && Validate::isLoadedObject($objHotel)) {
$maxPosition = Product::getHighestPositionInCategory($objHotel->id_category);
if ($categoryPositon > $maxPosition) {
$this->errors[] = sprintf($this->l('Position can not be greater than %d.'), $maxPosition);
}
}
}
}
/**
* Check if a field is edited (if the checkbox is checked)
* This method will do something only for multishop with a context all / group
*
* @param string $field Name of field
* @param int $id_lang
* @return bool
*/
protected function isProductFieldUpdated($field, $id_lang = null)
{
// Cache this condition to improve performances
static $is_activated = null;
if (is_null($is_activated)) {
$is_activated = Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_SHOP && $this->id_object;
}
if (!$is_activated) {
return true;
}
$def = ObjectModel::getDefinition($this->object);
if (!$this->object->isMultiShopField($field) && is_null($id_lang) && isset($def['fields'][$field])) {
return true;
}
if (is_null($id_lang)) {
return !empty($_POST['multishop_check'][$field]);
} else {
return !empty($_POST['multishop_check'][$field][$id_lang]);
}
}
protected function _removeTaxFromEcotax()
{
if ($ecotax = Tools::getValue('ecotax')) {
$_POST['ecotax'] = Tools::ps_round($ecotax / (1 + Tax::getProductEcotaxRate() / 100), 6);
}
}
protected function _applyTaxToEcotax($product)
{
if ($product->ecotax) {
$product->ecotax = Tools::ps_round($product->ecotax * (1 + Tax::getProductEcotaxRate() / 100), 2);
}
}
/**
* Update product accessories
*
* @param object $product Product
*/
public function updateAccessories($product)
{
$product->deleteAccessories();
if ($accessories = Tools::getValue('inputAccessories')) {
$accessories_id = array_unique(explode('-', $accessories));
if (count($accessories_id)) {
array_pop($accessories_id);
$product->changeAccessories($accessories_id);
}
}
}
/**
* Update product tags
*
* @param array $languages Array languages
* @param object $product Product
* @return bool Update result
*/
public function updateTags($languages, $product)
{
$tag_success = true;
/* Reset all tags for THIS product */
if (!Tag::deleteTagsForProduct((int)$product->id)) {
$this->errors[] = Tools::displayError('An error occurred while attempting to delete previous tags.');
}
/* Assign tags to this product */
foreach ($languages as $language) {
if ($value = Tools::getValue('tags_'.$language['id_lang'])) {
$tag_success &= Tag::addTags($language['id_lang'], (int)$product->id, $value);
}
}
if (!$tag_success) {
$this->errors[] = Tools::displayError('An error occurred while adding tags.');
}
return $tag_success;
}
public function initContent($token = null)
{
if ($this->display == 'edit' || $this->display == 'add') {
$this->fields_form = array();
// Check if Module
if (substr($this->tab_display, 0, 6) == 'Module') {
$this->tab_display_module = strtolower(substr($this->tab_display, 6, Tools::strlen($this->tab_display) - 6));
$this->tab_display = 'Modules';
}
if (method_exists($this, 'initForm'.$this->tab_display)) {
$this->tpl_form = strtolower($this->tab_display).'.tpl';
}
if ($this->ajax) {
$this->content_only = true;
} else {
if (($object = $this->loadObject(true)) && $object->isAssociatedToShop()) {
if (!$object->booking_product) {
$this->errors[] = $this->l('Room type not found.');
return;
}
}
$product_tabs = array();
// tab_display defines which tab to display first
if (!method_exists($this, 'initForm'.$this->tab_display)) {
$this->tab_display = $this->default_tab;
}
$advanced_stock_management_active = Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT');
foreach ($this->available_tabs as $product_tab => $value) {
// if it's the warehouses tab and advanced stock management is disabled, continue
if ($advanced_stock_management_active == 0 && $product_tab == 'Warehouses') {
continue;
}
$product_tabs[$product_tab] = array(
'id' => $product_tab,
'selected' => (strtolower($product_tab) == strtolower($this->tab_display) || (isset($this->tab_display_module) && 'module'.$this->tab_display_module == Tools::strtolower($product_tab))),
'name' => $this->available_tabs_lang[$product_tab],
'href' => $this->context->link->getAdminLink('AdminProducts').'&id_product='.(int)Tools::getValue('id_product').'&action='.$product_tab,
);
}
$this->tpl_form_vars['product_tabs'] = $product_tabs;
}
} else {
// If products from all categories are displayed, we don't want to use sorting by position
if (!(int) $this->id_current_category) {
$this->_defaultOrderBy = $this->identifier;
$prefix = $this->getCookieFilterPrefix();
if ($this->context->cookie->{$prefix.$this->table.'Orderby'} == 'position') {
unset($this->context->cookie->{$prefix.$this->table.'Orderby'});
unset($this->context->cookie->{$prefix.$this->table.'Orderway'});
}
}
}
parent::initContent();
}
public function renderKpis()
{
$time = time();
$helper = new HelperKpi();
$helper->id = 'box-total-rooms';
$helper->icon = 'icon-bed';
$helper->color = 'color3';
$helper->title = $this->l('Total Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=total_rooms';
$helper->tooltip = $this->l('The total number of rooms in all hotels.', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-occupied-rooms';
$helper->icon = 'icon-user';
$helper->color = 'color1';
$helper->title = $this->l('Occupied Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=occupied_rooms';
$helper->tooltip = $this->l('The count of rooms that are currently occupied by guests.', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-vacant-rooms';
$helper->icon = 'icon-check-empty';
$helper->color = 'color3';
$helper->title = $this->l('Vacant Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=vacant_rooms';
$helper->tooltip = $this->l('The count of rooms that are either booked but currently unoccupied or available for booking', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-reserved-rooms';
$helper->icon = 'icon-calendar';
$helper->color = 'color4';
$helper->title = $this->l('Booked Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=booked_rooms';
$helper->tooltip = $this->l('The total number of rooms that are currently booked and awaiting guest check-in', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-disabled-rooms';
$helper->icon = 'icon-ban';
$helper->color = 'color2';
$helper->title = $this->l('Disabled Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=disabled_rooms';
$helper->tooltip = $this->l('The total number of rooms that are currently disabled.', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-online-bookable-rooms';
$helper->icon = 'icon-globe';
$helper->color = 'color4';
$helper->title = $this->l('Online Bookable Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=online_bookable_rooms';
$helper->tooltip = $this->l('The total number of rooms that can be booked directly from the front office.', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-offline-bookable-rooms';
$helper->icon = 'icon-building';
$helper->color = 'color1';
$helper->title = $this->l('Offline Bookable Rooms', null, null, false);
$helper->subtitle = $this->l('Today', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=offline_bookable_rooms';
$helper->tooltip = $this->l('The total number of rooms available for booking through the back office.', null, null, false);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-best-selling-room-type';
$helper->icon = 'icon-star';
$helper->color = 'color1';
$helper->title = $this->l('Best Selling', null, null, false);
$nbDaysBestSelling = Validate::isUnsignedInt(Configuration::get('PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS')) ? Configuration::get('PS_KPI_BEST_SELLING_ROOM_TYPE_NB_DAYS') : 30;
if ($nbDaysBestSelling == 1) {
$helper->subtitle = sprintf($this->l('%d Day', null, null, false), (int) $nbDaysBestSelling);
} else {
$helper->subtitle = sprintf($this->l('%d Days', null, null, false), (int) $nbDaysBestSelling);
}
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=best_selling_room_type';
$helper->tooltip = sprintf($this->l('Displays the best selling room type based on the sales in the last %s day(s).', null, null, false), $nbDaysBestSelling);
$this->kpis[] = $helper;
$helper = new HelperKpi();
$helper->id = 'box-disbled-room-types';
$helper->icon = 'icon-ban';
$helper->color = 'color2';
$helper->title = $this->l('Disabled Room Types', null, null, false);
$helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=disabled_room_types';
$helper->href = Context::getContext()->link->getAdminLink('AdminProducts').'&submitResetproduct&submitFilterproduct=1&productFilter_sa!active=0&submitFilterproduct=1';
$helper->tooltip = $this->l('The total number of room types that are currently disabled.', null, null, false);
$this->kpis[] = $helper;
return parent::renderKpis();
}
public function renderList()
{
$this->addRowAction('edit');
$this->addRowAction('preview');
$this->addRowAction('duplicate');
$this->addRowAction('delete');
$this->tpl_list_vars['title'] = $this->l('Room Types');
$this->_new_list_header_design = true;
return parent::renderList();
}
public function displayDuplicateLink($token, $id, $name = null)
{
return ''.$this->l('Duplicate').'';
}
/**
* Build a categories tree
*
* @param $id_obj
* @param array $indexedCategories Array with categories where product is indexed (in order to check checkbox)
* @param array $categories Categories to list
* @param $current
* @param null $id_category Current category ID
* @param null $id_category_default
* @param array $has_suite
*
* @return string
*/
public static function recurseCategoryForInclude($id_obj, $indexedCategories, $categories, $current, $id_category = null, $id_category_default = null, $has_suite = array())
{
global $done;
static $irow;
$content = '';
if (!$id_category) {
$id_category = (int)Configuration::get('PS_ROOT_CATEGORY');
}
if (!isset($done[$current['infos']['id_parent']])) {
$done[$current['infos']['id_parent']] = 0;
}
$done[$current['infos']['id_parent']] += 1;
$todo = count($categories[$current['infos']['id_parent']]);
$doneC = $done[$current['infos']['id_parent']];
$level = $current['infos']['level_depth'] + 1;
$content .= '
';
}
$content .= '