* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision: 7331 $
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class AdminProductsControllerCore extends AdminController
{
protected $max_file_size = 20000000;
/** @var integer Max image size for upload
* As of 1.5 it is recommended to not set a limit to max image size
**/
protected $max_image_size;
private $_category;
protected $available_tabs = array(
'Informations',
'Images',
'Prices',
'Combinations',
'Features',
'Customization',
'Attachments',
'Quantities',
'Suppliers',
'Warehouses',
'Accounting');
public function __construct()
{
$this->table = 'product';
$this->className = 'Product';
$this->lang = true;
$this->edit = true;
$this->delete = true;
$this->view = false;
$this->duplicate = true;
$this->imageType = 'jpg';
$this->context = Context::getContext();
$this->_defaultOrderBy = 'position';
$this->fieldsDisplay = array(
'id_product' => array('title' => $this->l('ID'), 'align' => 'center', 'width' => 20),
'image' => array('title' => $this->l('Photo'), 'align' => 'center', 'image' => 'p',
'width' => 70, 'orderby' => false, 'filter' => false, 'search' => false),
'name' => array('title' => $this->l('Name'), 'filter_key' => 'b!name'),
'reference' => array('title' => $this->l('Reference'), 'align' => 'center', 'width' => 80),
'name_category' => array('title' => $this->l('Category'), 'width' => 100, 'filter_key' => 'cl!name'),
'price' => array('title' => $this->l('Base price'), 'width' => 70,
'type' => 'price', 'align' => 'right', 'filter_key' => 'a!price'),
'price_final' => array('title' => $this->l('Final price'), 'width' => 70,
'type' => 'price', 'align' => 'right', 'havingFilter' => true, 'orderby' => false),
'active' => array('title' => $this->l('Displayed'), 'width' => 70, 'active' => 'status',
'filter_key' => 'a!active', 'align' => 'center', 'type' => 'bool', 'orderby' => false),
'position' => array('title' => $this->l('Position'), 'width' => 70,'filter_key' => 'cp!position',
'align' => 'center', 'position' => 'position'),
);
/* Join categories table */
if ($id_category = Tools::getvalue('id_category'))
$this->_category = new Category($id_category);
else
$this->_category = new Category(1);
$this->_join = '
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (a.`id_category_default` = cl.`id_category` AND b.`id_lang` = cl.`id_lang`)
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = a.`id_product` AND i.`cover` = 1)
LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_product` = a.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (a.`id_tax_rules_group` = tr.`id_tax_rules_group`
AND tr.`id_country` = '.(int)$this->context->country->id.' AND tr.`id_state` = 0)
LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`)';
$this->_filter = 'AND cp.`id_category` = '.(int)$this->_category->id;
$this->_select = 'cl.name `name_category`, cp.`position`, i.`id_image`, (a.`price` * ((100 + (t.`rate`))/100)) AS price_final';
parent::__construct();
}
private 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 copyFromPost(&$object, $table)
{
parent::copyFromPost($object, $table);
if (get_class($object) != 'Product')
return;
/* Additional fields */
$languages = Language::getLanguages(false);
foreach ($languages as $language)
if (isset($_POST['meta_keywords_'.$language['id_lang']]))
{
$_POST['meta_keywords_'.$language['id_lang']] = $this->_cleanMetaKeywords(Tools::strtolower($_POST['meta_keywords_'.$language['id_lang']]));
// preg_replace('/ *,? +,* /', ',', strtolower($_POST['meta_keywords_'.$language['id_lang']]));
$object->meta_keywords[$language['id_lang']] = $_POST['meta_keywords_'.$language['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 ($_POST['unit_price'] != null)
$object->unit_price = str_replace(',', '.', $_POST['unit_price']);
if (array_key_exists('ecotax', $_POST) && $_POST['ecotax'] != null)
$object->ecotax = str_replace(',', '.', $_POST['ecotax']);
$object->available_for_order = (int)Tools::isSubmit('available_for_order');
$object->show_price = $object->available_for_order ? 1 : (int)Tools::isSubmit('show_price');
$object->on_sale = Tools::isSubmit('on_sale');
$object->online_only = Tools::isSubmit('online_only');
}
public function getList($id_lang, $orderBy = null, $orderWay = null, $start = 0, $limit = null, $id_lang_shop = null)
{
$orderByPriceFinal = (empty($orderBy) ? ($this->context->cookie->__get($this->table.'Orderby') ? $this->context->cookie->__get($this->table.'Orderby') : 'id_'.$this->table) : $orderBy);
$orderWayPriceFinal = (empty($orderWay) ? ($this->context->cookie->__get($this->table.'Orderway') ? $this->context->cookie->__get($this->table.'Orderby') : 'ASC') : $orderWay);
if ($orderByPriceFinal == 'price_final')
{
$orderBy = 'id_'.$this->table;
$orderWay = 'ASC';
}
parent::getList($id_lang, $orderBy, $orderWay, $start, $limit, $id_lang_shop);
/* update product quantity with attributes ...*/
$nb = count($this->_list);
if ($this->_list)
{
/* update product final price */
for ($i = 0; $i < $nb; $i++)
$this->_list[$i]['price_tmp'] = Product::getPriceStatic($this->_list[$i]['id_product'], true, null, 6, null, false, true, 1, true);
}
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']);
}
}
public function deleteVirtualProduct()
{
if (!($id_product_download = ProductDownload::getIdFromIdAttribute((int)Tools::getValue('id_product'), 0)))
return false;
$productDownload = new ProductDownload((int)($id_product_download));
return $productDownload->deleteFile((int)($id_product_download));
}
public function deleteVirtualProductAttribute()
{
if (!($id_product_download = ProductDownload::getIdFromIdAttribute((int)Tools::getValue('id_product'), (int) Tools::getValue('id_product_attribute'))))
return false;
$productDownload = new ProductDownload((int)($id_product_download));
return $productDownload->deleteFile((int)($id_product_download));
}
/**
* postProcess handle every checks before saving products information
*
* @param mixed $token
* @return void
*/
public function postProcess($token = null)
{
/* Add a new product */
if (Tools::isSubmit('submitAddproduct') || Tools::isSubmit('submitAddproductAndStay') || Tools::isSubmit('submitAddProductAndPreview'))
{
$id_product = Tools::getValue('id_product');
if (($id_product && $this->tabAccess['edit'] === '1')
|| ($this->tabAccess['add'] == 1 && (Tools::isSubmit('submitAddproduct') || Tools::isSubmit('submitAddproductAndStay') ) && !$id_product)
)
$this->submitAddproduct($token);
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
/* Delete a product in the download folder */
else if (Tools::getValue('deleteVirtualProduct'))
{
if ($this->tabAccess['delete'] === '1')
$this->deleteVirtualProduct();
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
else
/* Delete a product in the download folder */
if (Tools::getValue('deleteVirtualProductAttribute'))
{
if ($this->tabAccess['delete'] === '1')
$this->deleteVirtualProductAttribute();
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
/* Update attachments */
else if (Tools::isSubmit('submitAddAttachments'))
{
if ($this->tabAccess['add'] === '1')
{
$languages = Language::getLanguages(false);
$is_attachment_name_valid = false;
foreach ($languages as $language)
{
$attachment_name_lang = Tools::getValue('attachment_name_'.(int)($language['id_lang']));
if (strlen($attachment_name_lang ) > 0)
$is_attachment_name_valid = true;
if (!Validate::isGenericName(Tools::getValue('attachment_name_'.(int)($language['id_lang']))))
$this->_errors[] = Tools::displayError('Invalid Name');
else if (Tools::strlen(Tools::getValue('attachment_name_'.(int)($language['id_lang']))) > 32)
$this->_errors[] = Tools::displayError('Name is too long');
if (!Validate::isCleanHtml(Tools::getValue('attachment_description_'.(int)($language['id_lang']))))
$this->_errors[] = Tools::displayError('Invalid description');
}
if (!$is_attachment_name_valid)
$this->_errors[] = Tools::displayError('Attachment Name Required');
if (empty($this->_errors))
{
if (isset($_FILES['attachment_file']) && is_uploaded_file($_FILES['attachment_file']['tmp_name']))
{
if ($_FILES['attachment_file']['size'] > (Configuration::get('PS_ATTACHMENT_MAXIMUM_SIZE') * 1024 * 1024))
$this->_errors[] = $this->l('File too large, maximum size allowed:').' '.(Configuration::get('PS_ATTACHMENT_MAXIMUM_SIZE') * 1024).' '.$this->l('kb').'. '.$this->l('File size you\'re trying to upload is:').number_format(($_FILES['attachment_file']['size']/1024), 2, '.', '').$this->l('kb');
else
{
do $uniqid = sha1(microtime()); while (file_exists(_PS_DOWNLOAD_DIR_.$uniqid));
if (!copy($_FILES['attachment_file']['tmp_name'], _PS_DOWNLOAD_DIR_.$uniqid))
$this->_errors[] = $this->l('File copy failed');
@unlink($_FILES['attachment_file']['tmp_name']);
}
}
else if ((int)$_FILES['attachment_file']['error'] === 1)
{
$max_upload = (int)(ini_get('upload_max_filesize'));
$max_post = (int)(ini_get('post_max_size'));
$upload_mb = min($max_upload, $max_post);
$this->_errors[] = $this->l('the File').' '.$_FILES['attachment_file']['name'].' '.$this->l('exceeds the size allowed by the server, this limit is set to').' '.$upload_mb.$this->l('Mb').'';
}
if (empty($this->_errors) && isset($uniqid))
{
$attachment = new Attachment();
foreach ($languages as $language)
{
if (isset($_POST['attachment_name_'.(int)($language['id_lang'])]))
$attachment->name[(int)($language['id_lang'])] = pSQL($_POST['attachment_name_'.(int)($language['id_lang'])]);
if (isset($_POST['attachment_description_'.(int)($language['id_lang'])]))
$attachment->description[(int)($language['id_lang'])] = pSQL($_POST['attachment_description_'.(int)($language['id_lang'])]);
}
$attachment->file = $uniqid;
$attachment->mime = $_FILES['attachment_file']['type'];
$attachment->file_name = pSQL($_FILES['attachment_file']['name']);
if (empty($attachment->mime) || Tools::strlen($attachment->mime) > 128)
$this->_errors[] = Tools::displayError('Invalid file extension');
if (!Validate::isGenericName($attachment->file_name))
$this->_errors[] = Tools::displayError('Invalid file name');
if (Tools::strlen($attachment->file_name) > 128)
$this->_errors[] = Tools::displayError('File name too long');
if (!sizeof($this->_errors))
{
$attachment->add();
$this->redirect_after = self::$currentIndex.'&id_product='.(int)(Tools::getValue($this->identifier)).'&id_category='.(int)(Tools::getValue('id_category')).'&addproduct&conf=4&tabs=6&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Invalid file');
}
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
else if (Tools::isSubmit('submitAttachments'))
{
if ($this->tabAccess['edit'] === '1')
if ($id = (int)(Tools::getValue($this->identifier)))
if (Attachment::attachToProduct($id, Tools::getValue('attachments')))
$this->redirect_after = self::$currentIndex.'&id_product='.(int)$id.(isset($_POST['id_category']) ? '&id_category='.(int)$_POST['id_category'] : '').'&conf=4&add'.$this->table.'&tabs=6&token='.($token ? $token : $this->token);
}
/* Product duplication */
else if (isset($_GET['duplicate'.$this->table]))
{
if ($this->tabAccess['add'] === '1')
{
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
$id_product_old = $product->id;
unset($product->id);
unset($product->id_product);
$product->indexed = 0;
$product->active = 0;
if ($product->add()
&& Category::duplicateProductCategories($id_product_old, $product->id)
&& ($combinationImages = 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)
&& Product::duplicateSpecificPrices($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)
&& $product->duplicateShops($id_product_old))
{
if ($product->hasAttributes())
Product::updateDefaultAttribute($product->id);
if (!Tools::getValue('noimage') && !Image::duplicateProductImages($id_product_old, $product->id, $combinationImages))
$this->_errors[] = Tools::displayError('An error occurred while copying images.');
else
{
Hook::exec('addProduct', array('product' => $product));
Search::indexation(false, $product->id);
$this->redirect_after = self::$currentIndex.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&conf=19&token='.($token ? $token : $this->token);
}
}
else
$this->_errors[] = Tools::displayError('An error occurred while creating object.');
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
/* Change object statuts (active, inactive) */
else if (isset($_GET['status']) && Tools::getValue($this->identifier))
{
if ($this->tabAccess['edit'] === '1')
{
if (Validate::isLoadedObject($object = $this->loadObject()))
{
// @todo : redirect to the previous page instead of always product list
if ($object->toggleStatus())
$this->redirect_after = self::$currentIndex.'&conf=5'.((($id_category = (!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1')) && Tools::getValue('id_product')) ? '&id_category='.$id_category : '').'&token='.($token ? $token : $this->token);
else
$this->_errors[] = Tools::displayError('An error occurred while updating status.');
}
else
$this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
/* Delete object */
else if (isset($_GET['delete'.$this->table]))
{
if ($this->tabAccess['delete'] === '1')
{
if (Validate::isLoadedObject($object = $this->loadObject()) && isset($this->fieldImageSettings))
{
// check if request at least one object with noZeroObject
if (isset($object->noZeroObject) && sizeof($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
{
$id_category = Tools::getValue('id_category');
$category_url = empty($id_category) ? '' : '&id_category='.$id_category;
if ($this->deleted)
{
$object->deleteImages();
$object->deleted = 1;
if ($object->update())
$this->redirect_after = self::$currentIndex.'&conf=1&token='.($token ? $token : $this->token).$category_url;
}
else if ($object->delete())
$this->redirect_after = self::$currentIndex.'&conf=1&token='.($token ? $token : $this->token).$category_url;
$this->_errors[] = Tools::displayError('An error occurred during deletion.');
}
}
else
$this->_errors[] = Tools::displayError('An error occurred while deleting object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
/* Delete multiple objects */
else if (Tools::getValue('submitDel'.$this->table))
{
if ($this->tabAccess['delete'] === '1')
{
if (isset($_POST[$this->table.'Box']))
{
$object = new $this->className();
if (isset($object->noZeroObject) &&
// Check if all object will be deleted
(sizeof(call_user_func(array($this->className, $object->noZeroObject))) <= 1 || sizeof($_POST[$this->table.'Box']) == sizeof(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
{
$result = true;
if ($this->deleted)
{
foreach (Tools::getValue($this->table.'Box') as $id)
{
$toDelete = new $this->className($id);
$toDelete->deleted = 1;
$result = $result && $toDelete->update();
}
}
else
$result = $object->deleteSelection(Tools::getValue($this->table.'Box'));
if ($result)
{
$id_category = Tools::getValue('id_category');
$category_url = empty($id_category) ? '' : '&id_category='.$id_category;
$this->redirect_after = self::$currentIndex.'&conf=2&token='.$token.$category_url;
}
$this->_errors[] = Tools::displayError('An error occurred while deleting 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 here.');
}
/* Product images management */
else if (($id_image = (int)(Tools::getValue('id_image'))) && Validate::isUnsignedId($id_image) && Validate::isLoadedObject($image = new Image($id_image)))
{
if ($this->tabAccess['edit'] === '1')
{
/* Update product image/legend */
// @todo : move in processEditProductImage
if (isset($_GET['editImage']))
{
if ($image->cover)
$_POST['cover'] = 1;
$languages = Language::getLanguages(false);
foreach ($languages as $language)
if (isset($image->legend[$language['id_lang']]))
$_POST['legend_'.$language['id_lang']] = $image->legend[$language['id_lang']];
$_POST['id_image'] = $image->id;
}
/* Choose product cover image */
else if (isset($_GET['coverImage']))
{
Image::deleteCover($image->id_product);
$image->cover = 1;
if (!$image->update())
$this->_errors[] = Tools::displayError('Cannot change the product cover');
else
{
$productId = (int)(Tools::getValue('id_product'));
@unlink(_PS_TMP_IMG_DIR_.'/product_'.$productId.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'/product_mini_'.$productId.'.jpg');
$this->redirect_after = self::$currentIndex.'&id_product='.$image->id_product.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&addproduct&tabs=1'.'&token='.($token ? $token : $this->token);
}
}
/* Choose product image position */
else if (isset($_GET['imgPosition']) && isset($_GET['imgDirection']))
{
$image->updatePosition(Tools::getValue('imgDirection'), Tools::getValue('imgPosition'));
$this->redirect_after = self::$currentIndex.'&id_product='.$image->id_product.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=1&token='.($token ? $token : $this->token);
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
/* Product attributes management */
else if (Tools::isSubmit('submitProductAttribute'))
{
if (!Combination::isFeatureActive())
return;
$is_virtual = (int)Tools::getValue('is_virtual');
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
if (!isset($_POST['attribute_price']) || $_POST['attribute_price'] == null)
$this->_errors[] = Tools::displayError('Attribute price required.');
if (!isset($_POST['attribute_combinaison_list']) || !sizeof($_POST['attribute_combinaison_list']))
$this->_errors[] = Tools::displayError('You must add at least one attribute.');
if (!sizeof($this->_errors))
{
if (!isset($_POST['attribute_wholesale_price'])) $_POST['attribute_wholesale_price'] = 0;
if (!isset($_POST['attribute_price_impact'])) $_POST['attribute_price_impact'] = 0;
if (!isset($_POST['attribute_weight_impact'])) $_POST['attribute_weight_impact'] = 0;
if (!isset($_POST['attribute_ecotax'])) $_POST['attribute_ecotax'] = 0;
if (Tools::getValue('attribute_default'))
$product->deleteDefaultAttributes();
// Change existing one
if ($id_product_attribute = (int)(Tools::getValue('id_product_attribute')))
{
if ($this->tabAccess['edit'] === '1')
{
if ($product->productAttributeExists($_POST['attribute_combinaison_list'], $id_product_attribute))
$this->_errors[] = Tools::displayError('This attribute already exists.');
else
{
if (Validate::isDateFormat(Tools::getValue('available_date')))
{
$product->updateAttribute($id_product_attribute,
Tools::getValue('attribute_wholesale_price'),
Tools::getValue('attribute_price') * Tools::getValue('attribute_price_impact'),
Tools::getValue('attribute_weight') * Tools::getValue('attribute_weight_impact'),
Tools::getValue('attribute_unity') * Tools::getValue('attribute_unit_impact'),
Tools::getValue('attribute_ecotax'),
Tools::getValue('id_image_attr'),
Tools::getValue('attribute_reference'),
Tools::getValue('attribute_ean13'),
Tools::getValue('attribute_default'),
Tools::getValue('attribute_location'),
Tools::getValue('attribute_upc'),
Tools::getValue('minimal_quantity'),
Tools::getValue('available_date'));
if ($id_reason = (int)Tools::getValue('id_mvt_reason') && (int)Tools::getValue('attribute_mvt_quantity') > 0 && $id_reason > 0)
{
if (!$product->addStockMvt(Tools::getValue('attribute_mvt_quantity'), $id_reason, $id_product_attribute, null, $this->context->employee->id))
$this->_errors[] = Tools::displayError('An error occurred while updating qty.');
}
Hook::exec('updateProductAttribute', array('id_product_attribute' => (int)$id_product_attribute));
$this->updateDownloadProduct($product, 1, $id_product_attribute);
}
else
{
$this->_errors[] = Tools::displayError('Invalid date format.');
}
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
// Add new
else
{
if ($this->tabAccess['add'] === '1')
{
if ($product->productAttributeExists($_POST['attribute_combinaison_list']))
$this->_errors[] = Tools::displayError('This combination already exists.');
else
$id_product_attribute = $product->addCombinationEntity(
Tools::getValue('attribute_wholesale_price'),
Tools::getValue('attribute_price') * Tools::getValue('attribute_price_impact'),
Tools::getValue('attribute_weight') * Tools::getValue('attribute_weight_impact'),
Tools::getValue('attribute_unity') * Tools::getValue('attribute_unit_impact'),
Tools::getValue('attribute_ecotax'),
Tools::getValue('id_image_attr'),
Tools::getValue('attribute_reference'),
null,
Tools::getValue('attribute_ean13'),
Tools::getValue('attribute_default'),
Tools::getValue('attribute_location'),
Tools::getValue('attribute_upc')
);
$this->updateDownloadProduct($product, 0, $id_product_attribute);
}
else
$this->_errors[] = Tools::displayError('You do not have permission to').'
'.Tools::displayError('Edit here.');
}
if (!sizeof($this->_errors))
{
$product->addAttributeCombinaison($id_product_attribute, Tools::getValue('attribute_combinaison_list'));
$product->checkDefaultAttributes();
}
if (!sizeof($this->_errors))
{
if (!$product->cache_default_attribute)
Product::updateDefaultAttribute($product->id);
if (!empty($is_virtual))
Product::updateIsVirtual($product->id);
$this->redirect_after = self::$currentIndex.'&id_product='.$product->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=3&token='.($token ? $token : $this->token);
}
}
}
}
else if (Tools::isSubmit('deleteProductAttribute'))
{
if (!Combination::isFeatureActive())
return;
if ($this->tabAccess['delete'] === '1')
{
if (($id_product = (int)(Tools::getValue('id_product'))) && Validate::isUnsignedId($id_product) && Validate::isLoadedObject($product = new Product($id_product)))
{
$product->deleteAttributeCombinaison(Tools::getValue('id_product_attribute'));
$id_product_download = ProductDownload::getIdFromIdAttribute((int) $id_product, (int) Tools::getValue('id_product_attribute'));
if ($id_product_download)
{
$productDownload = new ProductDownload((int) $id_product_download);
$this->deleteDownloadProduct((int) $id_product_download);
$productDownload->deleteFile();
}
$product->checkDefaultAttributes();
$product->updateQuantityProductWithAttributeQuantity();
if (!$product->hasAttributes())
{
$product->cache_default_attribute = 0;
$product->update();
}
else
Product::updateDefaultAttribute($id_product);
$this->redirect_after = self::$currentIndex.'&add'.$this->table.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&tabs=3&id_product='.$product->id.'&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Cannot delete attribute');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
else if (Tools::isSubmit('deleteAllProductAttributes'))
{
if (!Combination::isFeatureActive())
return;
if ($this->tabAccess['delete'] === '1')
{
if (($id_product = (int)(Tools::getValue('id_product'))) && Validate::isUnsignedId($id_product) && Validate::isLoadedObject($product = new Product($id_product)))
{
$product->deleteProductAttributes();
$product->updateQuantityProductWithAttributeQuantity();
if ($product->cache_default_attribute)
{
$product->cache_default_attribute = 0;
$product->update();
}
$this->redirect_after = self::$currentIndex.'&add'.$this->table.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&tabs=3&id_product='.$product->id.'&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Cannot delete attributes');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
else if (Tools::isSubmit('defaultProductAttribute'))
{
if (!Combination::isFeatureActive())
return;
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
$product->deleteDefaultAttributes();
$product->setDefaultAttribute((int)(Tools::getValue('id_product_attribute')));
$this->redirect_after = self::$currentIndex.'&add'.$this->table.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&tabs=3&id_product='.$product->id.'&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Cannot make default attribute');
}
/* Product features management */
else if (Tools::isSubmit('submitProductFeature'))
{
if (!Feature::isFeatureActive())
return;
if ($this->tabAccess['edit'] === '1')
{
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
// delete all objects
$product->deleteFeatures();
// add new objects
$languages = Language::getLanguages(false);
foreach ($_POST as $key => $val)
{
if (preg_match('/^feature_([0-9]+)_value/i', $key, $match))
{
if ($val)
$product->addFeaturesToDB($match[1], $val);
else
{
if ($default_value = $this->checkFeatures($languages, $match[1]))
{
$id_value = $product->addFeaturesToDB($match[1], 0, 1);
foreach ($languages as $language)
{
if ($cust = Tools::getValue('custom_'.$match[1].'_'.(int)$language['id_lang']))
$product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust);
else
$product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value);
}
}
else
$id_value = $product->addFeaturesToDB($match[1], 0, 1);
}
}
}
if (!sizeof($this->_errors))
$this->redirect_after = self::$currentIndex.'&id_product='.(int)$product->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=4&conf=4&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Product must be created before adding features.');
}
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
/* Product specific prices management */
else if (Tools::isSubmit('submitPricesModification'))
{
$_POST['tabs'] = 5;
if ($this->tabAccess['edit'] === '1')
{
$id_specific_prices = Tools::getValue('spm_id_specific_price');
$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');
$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 ($this->_validateSpecificPrice($id_shops[$key], $id_currencies[$key], $id_countries[$key], $id_groups[$key], $prices[$key], $from_quantities[$key], $reductions[$key], $reduction_types[$key], $froms[$key], $tos[$key]))
{
$specificPrice = new SpecificPrice((int)($id_specific_price));
$specificPrice->id_shop = (int)$id_shops[$key];
$specificPrice->id_currency = (int)($id_currencies[$key]);
$specificPrice->id_country = (int)($id_countries[$key]);
$specificPrice->id_group = (int)($id_groups[$key]);
$specificPrice->price = (float)($prices[$key]);
$specificPrice->from_quantity = (int)($from_quantities[$key]);
$specificPrice->reduction = (float)($reduction_types[$key] == 'percentage' ? ($reductions[$key] / 100) : $reductions[$key]);
$specificPrice->reduction_type = !$reductions[$key] ? 'amount' : $reduction_types[$key];
$specificPrice->from = !$froms[$key] ? '0000-00-00 00:00:00' : $froms[$key];
$specificPrice->to = !$tos[$key] ? '0000-00-00 00:00:00' : $tos[$key];
if (!$specificPrice->update())
$this->_errors = Tools::displayError('An error occurred while updating the specific price.');
}
if (!sizeof($this->_errors))
$this->redirect_after = self::$currentIndex.'&id_product='.(int)(Tools::getValue('id_product')).'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&update'.$this->table.'&tabs=2&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
else if (Tools::isSubmit('submitPriceAddition'))
{
if ($this->tabAccess['add'] === '1')
{
$id_product = (int)(Tools::getValue('id_product'));
$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');
$price = Tools::getValue('sp_price');
$from_quantity = Tools::getValue('sp_from_quantity');
$reduction = (float)(Tools::getValue('sp_reduction'));
$reduction_type = !$reduction ? 'amount' : Tools::getValue('sp_reduction_type');
$from = Tools::getValue('sp_from');
$to = Tools::getValue('sp_to');
if ($this->_validateSpecificPrice($id_shop, $id_currency, $id_country, $id_group, $price, $from_quantity, $reduction, $reduction_type, $from, $to))
{
$specificPrice = new SpecificPrice();
$specificPrice->id_product = $id_product;
$specificPrice->id_product_attribute = (int)Tools::getValue('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->price = (float)($price);
$specificPrice->from_quantity = (int)($from_quantity);
$specificPrice->reduction = (float)($reduction_type == 'percentage' ? $reduction / 100 : $reduction);
$specificPrice->reduction_type = $reduction_type;
$specificPrice->from = !$from ? '0000-00-00 00:00:00' : $from;
$specificPrice->to = !$to ? '0000-00-00 00:00:00' : $to;
if (!$specificPrice->add())
$this->_errors = Tools::displayError('An error occurred while updating the specific price.');
else
$this->redirect_after = self::$currentIndex.(Tools::getValue('id_category') ? '&id_category='.Tools::getValue('id_category') : '').'&id_product='.$id_product.'&add'.$this->table.'&tabs=2&conf=3&token='.($token ? $token : $this->token);
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
else if (Tools::isSubmit('deleteSpecificPrice'))
{
if ($this->tabAccess['delete'] === '1')
{
if (!($obj = $this->loadObject()))
return;
if (!$id_specific_price = Tools::getValue('id_specific_price') || !Validate::isUnsignedId($id_specific_price))
$this->_errors[] = Tools::displayError('Invalid specific price ID');
else
{
$specificPrice = new SpecificPrice((int)($id_specific_price));
if (!$specificPrice->delete())
$this->_errors[] = Tools::displayError('An error occurred while deleting the specific price');
else
$this->redirect_after = self::$currentIndex.(Tools::getValue('id_category') ? '&id_category='.Tools::getValue('id_category') : '').'&id_product='.$obj->id.'&add'.$this->table.'&tabs=2&conf=1&token='.($token ? $token : $this->token);
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
else if (Tools::isSubmit('submitSpecificPricePriorities'))
{
if (!($obj = $this->loadObject()))
return;
if (!$priorities = Tools::getValue('specificPricePriority'))
$this->_errors[] = Tools::displayError('Please specify priorities');
else if (Tools::isSubmit('specificPricePriorityToAll'))
{
if (!SpecificPrice::setPriorities($priorities))
$this->_errors[] = Tools::displayError('An error occurred while updating priorities.');
else
$this->redirect_after = self::$currentIndex.'&id_product='.$obj->id.'&add'.$this->table.'&tabs=2&conf=4&token='.($token ? $token : $this->token);
}
else if (!SpecificPrice::setSpecificPriority((int)($obj->id), $priorities))
$this->_errors[] = Tools::displayError('An error occurred while setting priorities.');
else
$this->redirect_after = self::$currentIndex.(Tools::getValue('id_category') ? '&id_category='.Tools::getValue('id_category') : '').'&id_product='.$obj->id.'&add'.$this->table.'&tabs=2&conf=4&token='.($token ? $token : $this->token);
}
/* Customization management */
else if (Tools::isSubmit('submitCustomizationConfiguration'))
{
if ($this->tabAccess['edit'] === '1')
{
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
if (!$product->createLabels((int)($_POST['uploadable_files']) - (int)($product->uploadable_files), (int)($_POST['text_fields']) - (int)($product->text_fields)))
$this->_errors[] = Tools::displayError('An error occurred while creating customization fields.');
if (!sizeof($this->_errors) && !$product->updateLabels())
$this->_errors[] = Tools::displayError('An error occurred while updating customization.');
$product->uploadable_files = (int)($_POST['uploadable_files']);
$product->text_fields = (int)($_POST['text_fields']);
$product->customizable = ((int)($_POST['uploadable_files']) > 0 || (int)($_POST['text_fields']) > 0) ? 1 : 0;
if (!sizeof($this->_errors) && !$product->update())
$this->_errors[] = Tools::displayError('An error occurred while updating customization configuration.');
if (!sizeof($this->_errors))
$this->redirect_after = self::$currentIndex.'&id_product='.$product->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=5&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Product must be created before adding customization possibilities.');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
else if (Tools::isSubmit('submitProductCustomization'))
{
if ($this->tabAccess['edit'] === '1')
{
if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product')))))
{
foreach ($_POST as $field => $value)
if (strncmp($field, 'label_', 6) == 0 && !Validate::isLabel($value))
$this->_errors[] = Tools::displayError('Label fields are invalid');
if (!sizeof($this->_errors) && !$product->updateLabels())
$this->_errors[] = Tools::displayError('An error occurred while updating customization.');
if (!sizeof($this->_errors))
$this->redirect_after = self::$currentIndex.'&id_product='.$product->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=5&token='.($token ? $token : $this->token);
}
else
$this->_errors[] = Tools::displayError('Product must be created before adding customization possibilities.');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
else if (isset($_GET['position']))
{
if ($this->tabAccess['edit'] !== '1')
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
else if (!Validate::isLoadedObject($object = $this->loadObject()))
$this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
if (!$object->updatePosition((int)(Tools::getValue('way')), (int)(Tools::getValue('position'))))
$this->_errors[] = Tools::displayError('Failed to update the position.');
else
$this->redirect_after = self::$currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.(($id_category = (!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1')) ? ('&id_category='.$id_category) : '').'&token='.Tools::getAdminTokenLite('AdminProducts');
}
else if (Tools::isSubmit('submitAccountingDetails'))
$this->postProcessFormAccounting();
//Manage suppliers
else if (Tools::isSubmit('submitSuppliers'))
$this->postProcessFormSuppliers();
//Manage suppliers
else if (Tools::isSubmit('submitSupplierReferences'))
$this->postProcessFormSupplierReferences();
//Manage warehouses
else if (Tools::isSubmit('submitProductWarehouses'))
$this->postProcessFormWarehouses();
parent::postProcess(true);
}
// @todo rename to processaddproductimage
public function ajaxProcessAddImage()
{
self::$currentIndex = 'index.php?tab=AdminProducts';
$allowedExtensions = array("jpeg", "gif", "png", "jpg");
// max file size in bytes
$sizeLimit = $this->max_file_size;
$uploader = new FileUploader($allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload();
if (isset($result['success']))
{
$obj = new Image($result['success']['id_image']);
$json = array(
'status' => 'ok',
'id'=>$obj->id,
'path' => $obj->getExistingImgPath(),
'position' => $obj->position,
'cover' => $obj->cover,
);
die(Tools::jsonEncode($json));
}
else
die(Tools::jsonEncode($result));
}
public function ajaxPreProcess()
{
$this->action = Tools::getValue('action');
}
public function ajaxProcessUpdateProductImageShopAsso()
{
if (($id_image = $_GET['id_image']) && ($id_shop = (int)$_GET['id_shop']))
if (Tools::getValue('active') == "true")
die('INSERT INTO '._DB_PREFIX_.'image_shop (`id_image`, `id_shop`) VALUES('.(int)$id_image.', '.(int)$id_shop.')');
else
die(Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'image_shop WHERE `id_image`='.(int)$id_image.' && `id_shop`='.(int)$id_shop));
}
public function ajaxProcessUpdateImagePosition()
{
if ($json = Tools::getValue('json'))
{
$json = stripslashes($json);
$images = Tools::jsonDecode($json, true);
foreach ($images as $id => $position)
{
$img = new Image((int)$id);
$img->position = (int)$position;
$img->update();
}
}
exit();
}
public function ajaxProcessUpdateCover()
{
if ($this->action == 'UpdateCover')
{
Image::deleteCover((int)$_GET['id_product']);
$img = new Image((int)$_GET['id_image']);
$img->cover = 1;
$img->update();
}
}
public function ajaxProcessDeleteProductImage()
{
/* Delete product image */
if (isset($_GET['deleteProductImage']) || $this->action == 'deleteProductImage')
{
$image = new Image((int)Tools::getValue('id_image'));
$image->delete();
if (!Image::getCover($image->id_product))
{
$first_img = Db::getInstance()->getRow('
SELECT `id_image` FROM `'._DB_PREFIX_.'image`
WHERE `id_product` = '.(int)($image->id_product));
Db::getInstance()->Execute('
UPDATE `'._DB_PREFIX_.'image`
SET `cover` = 1
WHERE `id_image` = '.(int)($first_img['id_image']));
}
@unlink(_PS_TMP_IMG_DIR_.'/product_'.$image->id_product.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'/product_mini_'.$image->id_product.'.jpg');
if (!$this->ajax)
$this->redirect_after = $currentIndex.'&id_product='.$image->id_product.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&add'.$this->table.'&tabs=1'.'&token='.($token ? $token : $this->token);
else
$this->content = '{"status":"ok"}';
}
}
protected function _validateSpecificPrice($id_shop, $id_currency, $id_country, $id_group, $price, $from_quantity, $reduction, $reduction_type, $from, $to)
{
if (!Validate::isUnsignedId($id_shop) || !Validate::isUnsignedId($id_currency) || !Validate::isUnsignedId($id_country) || !Validate::isUnsignedId($id_group))
$this->_errors[] = Tools::displayError('Wrong ID\'s');
else if ((empty($price) && empty($reduction)) || (!empty($price) && !Validate::isPrice($price)) || (!empty($reduction) && !Validate::isPrice($reduction)))
$this->_errors[] = Tools::displayError('Invalid price/reduction amount');
else if (!Validate::isUnsignedInt($from_quantity))
$this->_errors[] = Tools::displayError('Invalid quantity');
else if ($reduction && !Validate::isReductionType($reduction_type))
$this->_errors[] = Tools::displayError('Please select a reduction type (amount or percentage)');
else if ($from && $to && (!Validate::isDateFormat($from) || !Validate::isDateFormat($to)))
$this->_errors[] = Tools::displayError('Wrong from/to date');
else
return true;
return false;
}
// Checking customs feature
private function checkFeatures($languages, $feature_id)
{
$rules = call_user_func(array('FeatureValue', 'getValidationRules'), 'FeatureValue');
$feature = Feature::getFeature(Configuration::get('PS_LANG_DEFAULT'), $feature_id);
$val = 0;
foreach ($languages as $language)
if ($val = Tools::getValue('custom_'.$feature_id.'_'.$language['id_lang']))
{
$currentLanguage = new Language($language['id_lang']);
if (Tools::strlen($val) > $rules['sizeLang']['value'])
$this->_errors[] = Tools::displayError('name for feature').' '.$feature['name'].' '.Tools::displayError('is too long in').' '.$currentLanguage->name;
else if (!call_user_func(array('Validate', $rules['validateLang']['value']), $val))
$this->_errors[] = Tools::displayError('Valid name required for feature.').' '.$feature['name'].' '.Tools::displayError('in').' '.$currentLanguage->name;
if (sizeof($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 object $product Product object to add image
*/
public function addProductImage($product, $method = 'auto')
{
/* Updating an existing product image */
if ($id_image = ((int)(Tools::getValue('id_image'))))
{
$image = new Image($id_image);
if (!Validate::isLoadedObject($image))
$this->_errors[] = Tools::displayError('An error occurred while loading object image.');
else
{
if (($cover = Tools::getValue('cover')) == 1)
Image::deleteCover($product->id);
$image->cover = $cover;
$this->validateRules('Image');
$this->copyFromPost($image, 'image');
if (sizeof($this->_errors) || !$image->update())
$this->_errors[] = Tools::displayError('An error occurred while updating image.');
else if (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 (sizeof($this->_errors))
return false;
@unlink(_PS_TMP_IMG_DIR_.'/product_'.$product->id.'.jpg');
@unlink(_PS_TMP_IMG_DIR_.'/product_mini_'.$product->id.'.jpg');
return ((isset($id_image) && is_int($id_image) && $id_image) ? $id_image : true);
}
/**
* Copy a product image
*
* @param integer $id_product Product Id for product image filename
* @param integer $id_image Image Id for product image filename
*/
public function copyImage($id_product, $id_image, $method = 'auto')
{
if (!isset($_FILES['image_product']['tmp_name']))
return false;
if ($error = checkImage($_FILES['image_product']))
$this->_errors[] = $error;
else
{
$image = new Image($id_image);
if (!$new_path = $image->getPathForCreation())
$this->_errors[] = Tools::displayError('An error occurred during new folder creation');
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');
else if (!imageResize($tmpName, $new_path.'.'.$image->image_format))
$this->_errors[] = Tools::displayError('An error occurred while copying image.');
else if ($method == 'auto')
{
$imagesTypes = ImageType::getImagesTypes('products');
foreach ($imagesTypes as $k => $imageType)
if (!imageResize($tmpName, $new_path.'-'.stripslashes($imageType['name']).'.'.$image->image_format, $imageType['width'], $imageType['height'], $image->image_format))
$this->_errors[] = Tools::displayError('An error occurred while copying image:').' '.stripslashes($imageType['name']);
}
@unlink($tmpName);
Hook::exec('watermark', array('id_image' => $id_image, 'id_product' => $id_product));
}
}
/**
* Add or update a product
*/
public function submitAddProduct($token = null)
{
$className = 'Product';
$rules = call_user_func(array($this->className, 'getValidationRules'), $this->className);
$defaultLanguage = new Language((int)(Configuration::get('PS_LANG_DEFAULT')));
$languages = Language::getLanguages(false);
/* Check required fields */
foreach ($rules['required'] as $field)
if (($value = Tools::getValue($field)) == false && $value != '0')
{
if (Tools::getValue('id_'.$this->table) && $field == 'passwd')
continue;
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is required');
}
/* Check multilingual required fields */
foreach ($rules['requiredLang'] as $fieldLang)
if (!Tools::getValue($fieldLang.'_'.$defaultLanguage->id))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' '.$this->l('is required at least in').' '.$defaultLanguage->name;
/* Check fields sizes */
foreach ($rules['size'] as $field => $maxLength)
if ($value = Tools::getValue($field) && Tools::strlen($value) > $maxLength)
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is too long').' ('.$maxLength.' '.$this->l('chars max').')';
if (isset($_POST['description_short']))
{
$saveShort = $_POST['description_short'];
$_POST['description_short'] = strip_tags($_POST['description_short']);
}
/* Check description short size without html */
$limit = (int)Configuration::get('PS_PRODUCT_SHORT_DESC_LIMIT');
if ($limit <= 0) $limit = 400;
foreach ($languages as $language)
if ($value = Tools::getValue('description_short_'.$language['id_lang']))
if (Tools::strlen(strip_tags($value)) > $limit)
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), 'description_short').' ('.$language['name'].') '.$this->l('is too long').' : '.$limit.' '.$this->l('chars max').' ('.$this->l('count now').' '.Tools::strlen(strip_tags($value)).')';
/* Check multilingual fields sizes */
foreach ($rules['sizeLang'] as $fieldLang => $maxLength)
foreach ($languages as $language)
if ($value = Tools::getValue($fieldLang.'_'.$language['id_lang']) && Tools::strlen($value) > $maxLength)
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' ('.$language['name'].') '.$this->l('is too long').' ('.$maxLength.' '.$this->l('chars max').')';
if (isset($_POST['description_short']))
$_POST['description_short'] = $saveShort;
/* Check fields validity */
foreach ($rules['validate'] as $field => $function)
if ($value = Tools::getValue($field))
if (!Validate::$function($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is invalid');
/* Check multilingual fields validity */
foreach ($rules['validateLang'] as $fieldLang => $function)
foreach ($languages as $language)
if ($value = Tools::getValue($fieldLang.'_'.$language['id_lang']))
if (!Validate::$function($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' ('.$language['name'].') '.$this->l('is invalid');
/* Categories */
$productCats = '';
if (!Tools::isSubmit('categoryBox') || !sizeof(Tools::getValue('categoryBox')))
$this->_errors[] = $this->l('product must be in at least one Category');
if (!is_array(Tools::getValue('categoryBox')) || !in_array(Tools::getValue('id_category_default'), Tools::getValue('categoryBox')))
$this->_errors[] = $this->l('product 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[] = $this->l('Tags list').' ('.$language['name'].') '.$this->l('is invalid');
if (!sizeof($this->_errors))
{
$id = (int)Tools::getValue('id_'.$this->table);
$tagError = true;
/* Update an existing product */
if (isset($id) && !empty($id))
{
$object = new $this->className($id);
if (Validate::isLoadedObject($object))
{
$this->_removeTaxFromEcotax();
$this->copyFromPost($object, $this->table);
if ($object->update())
{
$this->addCarriers();
if ($id_reason = (int)Tools::getValue('id_mvt_reason') && Tools::getValue('mvt_quantity') > 0 && $id_reason > 0)
{
if (!$object->addStockMvt(Tools::getValue('mvt_quantity'), $id_reason, null, null, $this->context->employee->id))
$this->_errors[] = Tools::displayError('An error occurred while updating qty.');
}
$this->updateAccessories($object);
$this->updateDownloadProduct($object, 1);
$this->updateAssoShop((int)$object->id);
if (!$this->updatePackItems($object))
$this->_errors[] = Tools::displayError('An error occurred while adding products to the pack.');
else if (!$object->updateCategories($_POST['categoryBox'], true))
$this->_errors[] = Tools::displayError('An error occurred while linking object.').' '.$this->table.' '.Tools::displayError('To categories');
else if (!$this->updateTags($languages, $object))
$this->_errors[] = Tools::displayError('An error occurred while adding tags.');
else if ($id_image = $this->addProductImage($object, Tools::getValue('resizer')))
{
self::$currentIndex .= '&image_updated='.(int)Tools::getValue('id_image');
Hook::exec('updateProduct', array('product' => $object));
Search::indexation(false, $object->id);
if (Tools::getValue('resizer') == 'man' && isset($id_image) && is_int($id_image) && $id_image)
$this->redirect_after = self::$currentIndex.'&id_product='.$object->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&edit='.strval(Tools::getValue('productCreated')).'&id_image='.$id_image.'&imageresize&toconf=4&submitAddAndStay='.((Tools::isSubmit('submitAdd'.$this->table.'AndStay') || Tools::getValue('productCreated') == 'on') ? 'on' : 'off').'&token='.(($token ? $token : $this->token));
// Save and preview
if (Tools::isSubmit('submitAddProductAndPreview'))
{
$preview_url = $this->context->link->getProductLink($this->getFieldValue($object, 'id'), $this->getFieldValue($object, 'link_rewrite', $this->context->language->id), Category::getLinkRewrite($this->getFieldValue($object, 'id_category_default'), $this->context->language->id), null, null, Context::getContext()->shop->getID());
if (!$object->active)
{
$admin_dir = dirname($_SERVER['PHP_SELF']);
$admin_dir = substr($admin_dir, strrpos($admin_dir,'/') + 1);
$token = Tools::encrypt('PreviewProduct'.$object->id);
if (strpos($preview_url, '?') === false)
$preview_url .= '?';
else
$preview_url .= '&';
$preview_url .= 'adtoken='.$token.'&ad='.$admin_dir;
}
$this->redirect_after = $preview_url;
} else if (Tools::isSubmit('submitAdd'.$this->table.'AndStay') || ($id_image && $id_image !== true)) // Save and stay on same form
// Save and stay on same form
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
$this->redirect_after = self::$currentIndex.'&id_product='.$object->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&addproduct&conf=4&tabs='.(int)(Tools::getValue('tabs')).'&token='.($token ? $token : $this->token);
// Default behavior (save and back)
$this->redirect_after = self::$currentIndex.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&conf=4&token='.($token ? $token : $this->token).'&onredirigeici';
}
}
else
$this->_errors[] = Tools::displayError('An error occurred while updating object.').' '.$this->table.' ('.Db::getInstance()->getMsgError().')';
}
else
$this->_errors[] = Tools::displayError('An error occurred while updating object.').' '.$this->table.' ('.Tools::displayError('Cannot load object').')';
}
/* Add a new product */
else
{
$object = new $this->className();
$this->_removeTaxFromEcotax();
$this->copyFromPost($object, $this->table);
if ($object->add())
{
$this->addCarriers();
$this->updateAssoShop((int)$object->id);
$this->updateAccessories($object);
if (!$this->updatePackItems($object))
$this->_errors[] = Tools::displayError('An error occurred while adding products to the pack.');
$this->updateDownloadProduct($object);
if (!sizeof($this->_errors))
{
if (!$object->updateCategories($_POST['categoryBox']))
$this->_errors[] = Tools::displayError('An error occurred while linking object.').' '.$this->table.' '.Tools::displayError('To categories');
else if (!$this->updateTags($languages, $object))
$this->_errors[] = Tools::displayError('An error occurred while adding tags.');
else if ($id_image = $this->addProductImage($object))
{
Hook::exec('addProduct', array('product' => $object));
Search::indexation(false, $object->id);
// Save and preview
if (Tools::isSubmit('submitAddProductAndPreview'))
{
$preview_url = ($this->context->link->getProductLink($this->getFieldValue($object, 'id'), $this->getFieldValue($object, 'link_rewrite', $this->context->language->id), Category::getLinkRewrite($this->getFieldValue($object, 'id_category_default'), $this->context->language->id)));
if (!$object->active)
{
$admin_dir = dirname($_SERVER['PHP_SELF']);
$admin_dir = substr($admin_dir, strrpos($admin_dir,'/') + 1);
$token = Tools::encrypt('PreviewProduct'.$object->id);
$preview_url .= '&adtoken='.$token.'&ad='.$admin_dir;
}
$this->redirect_after = $preview_url;
}
if (Tools::getValue('resizer') == 'man' && isset($id_image) && is_int($id_image) && $id_image)
$this->redirect_after = self::$currentIndex.'&id_product='.$object->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&id_image='.$id_image.'&imageresize&toconf=3&submitAddAndStay='.(Tools::isSubmit('submitAdd'.$this->table.'AndStay') ? 'on' : 'off').'&token='.($token ? $token : $this->token);
// Save and stay on same form
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
$this->redirect_after = self::$currentIndex.'&id_product='.$object->id.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&addproduct&conf=3&tabs='.(int)(Tools::getValue('tabs')).'&token='.($token ? $token : $this->token);
else
// Default behavior (save and back)
$this->redirect_after = self::$currentIndex.'&id_category='.(!empty($_REQUEST['id_category'])?$_REQUEST['id_category']:'1').'&conf=3&token='.($token ? $token : $this->token);
}
}
else
$object->delete();
}
else
$this->_errors[] = Tools::displayError('An error occurred while creating object.').' '.$this->table.'';
}
}
}
private function _removeTaxFromEcotax()
{
$ecotaxTaxRate = Tax::getProductEcotaxRate();
if ($ecotax = Tools::getValue('ecotax'))
$_POST['ecotax'] = Tools::ps_round(Tools::getValue('ecotax') / (1 + $ecotaxTaxRate / 100), 6);
}
private function _applyTaxToEcotax($product)
{
$ecotaxTaxRate = Tax::getProductEcotaxRate();
if ($product->ecotax)
$product->ecotax = Tools::ps_round($product->ecotax * (1 + $ecotaxTaxRate / 100), 2);
}
/**
* Update product download
*
* @param object $product Product
* @return bool
*/
public function updateDownloadProduct($product, $edit = 0, $id_product_attribute = null)
{
$is_virtual_file = (int) Tools::getValue('is_virtual_file');
/* add or update a virtual product */
if (Tools::getValue('is_virtual_good') == 'true')
{
if (!Tools::getValue('virtual_product_name') && !Tools::getValue('virtual_product_name_attribute') && !empty($is_virtual_file))
{
if (!Tools::getValue('virtual_product_name'))
{
if (!Tools::getValue('virtual_product_name_attribute') && !empty($id_product_attribute))
{
$this->_errors[] = $this->l('the field').' '.$this->l('display filename attribute').' '.$this->l('is required');
return false;
}
else if (!empty($id_product_attribute))
{
$this->_errors[] = $this->l('the field').' '.$this->l('display filename').' '.$this->l('is required');
return false;
}
}
}
if (Tools::getValue('virtual_product_nb_days') === false && Tools::getValue('virtual_product_nb_days_attribute') === false && !empty($is_virtual_file))
{
if (!Tools::getValue('virtual_product_nb_days'))
{
if (!Tools::getValue('virtual_product_nb_days_attribute'))
{
if (!empty($edit) && !empty($id_product_attribute))
{
$this->_errors[] = $this->l('the field').' '.$this->l('number of days attribute').' '.$this->l('is required');
return false;
}
}
else if (!empty($id_product_attribute))
{
$this->_errors[] = $this->l('the field').' '.$this->l('number of days').' '.$this->l('is required');
return false;
}
}
}
if (Tools::getValue('virtual_product_expiration_date') && !Validate::isDate(Tools::getValue('virtual_product_expiration_date') && !empty($is_virtual_file))
&& Tools::getValue('virtual_product_expiration_date_attribute') && !Validate::isDate(Tools::getValue('virtual_product_expiration_date_attribute')))
{
if (!Tools::getValue('virtual_product_expiration_date'))
{
if (!Tools::getValue('virtual_product_expiration_date_attribute'))
{
$this->_errors[] = $this->l('the field').' '.$this->l('expiration date attribute').' '.$this->l('is required');
return false;
}
else if (!empty($id_product_attribute))
{
$this->_errors[] = $this->l('the field').' '.$this->l('expiration date').' '.$this->l('is not valid');
return false;
}
}
}
// The oos behavior MUST be "Deny orders" for virtual products
if (Tools::getValue('out_of_stock') != 0)
{
$this->_errors[] = $this->l('The "when out of stock" behavior selection must be "deny order" for virtual products');
return false;
}
// Trick's
if ($edit == 1)
{
$id_product_download_attribute = ProductDownload::getIdFromIdAttribute((int) $product->id, $id_product_attribute);
$id_product_download = ($id_product_download_attribute) ? (int) $id_product_download_attribute : (int) Tools::getValue('virtual_product_id');
} else
$id_product_download = Tools::getValue('virtual_product_id');
$is_shareable = Tools::getValue('virtual_product_is_shareable');
$virtual_product_name = Tools::getValue('virtual_product_name');
$virtual_product_filename = Tools::getValue('virtual_product_filename');
$virtual_product_nb_days = Tools::getValue('virtual_product_nb_days');
$virtual_product_nb_downloable = Tools::getValue('virtual_product_nb_downloable');
$virtual_product_expiration_date = Tools::getValue('virtual_product_expiration_date');
$is_shareable_attribute = Tools::getValue('virtual_product_is_shareable_attribute');
$virtual_product_name_attribute = Tools::getValue('virtual_product_name_attribute');
$virtual_product_filename_attribute = Tools::getValue('virtual_product_filename_attribute');
$virtual_product_nb_days_attribute = Tools::getValue('virtual_product_nb_days_attribute');
$virtual_product_nb_downloable_attribute = Tools::getValue('virtual_product_nb_downloable_attribute');
$virtual_product_expiration_date_attribute = Tools::getValue('virtual_product_expiration_date_attribute');
if (!empty($is_shareable_attribute))
$is_shareable = $is_shareable_attribute;
if (!empty($virtual_product_name_attribute))
$virtual_product_name = $virtual_product_name_attribute;
if (!empty($virtual_product_nb_days_attribute))
$virtual_product_nb_days = $virtual_product_nb_days_attribute;
if (!empty($virtual_product_nb_downloable_attribute))
$virtual_product_nb_downloable = $virtual_product_nb_downloable_attribute;
if (!empty($virtual_product_expiration_date_attribute))
$virtual_product_expiration_date = $virtual_product_expiration_date_attribute;
if (!empty($virtual_product_filename_attribute))
$filename = $virtual_product_filename_attribute;
else if ($virtual_product_filename)
$filename = $virtual_product_filename;
else
$filename = ProductDownload::getNewFilename();
$download = new ProductDownload($id_product_download);
$download->id_product = (int) $product->id;
$download->id_product_attribute = (int) $id_product_attribute;
$download->display_filename = $virtual_product_name;
$download->filename = $filename;
$download->date_add = date('Y-m-d H:i:s');
$download->date_expiration = $virtual_product_expiration_date ? $virtual_product_expiration_date.' 23:59:59' : '';
$download->nb_days_accessible = (int) $virtual_product_nb_days;
$download->nb_downloadable = (int) $virtual_product_nb_downloable;
$download->active = 1;
$download->is_shareable = (int) $is_shareable;
if ($download->save())
return true;
}
else
{
/* unactive download product if checkbox not checked */
if ($edit == 1)
{
$id_product_download_attribute = ProductDownload::getIdFromIdAttribute((int) $product->id, $id_product_attribute);
$id_product_download = ($id_product_download_attribute) ? (int) $id_product_download_attribute : (int) Tools::getValue('virtual_product_id');
}
else
$id_product_download = ProductDownload::getIdFromIdProduct($product->id);
if (!empty($id_product_download))
{
$productDownload = new ProductDownload($id_product_download);
$productDownload->date_expiration = date('Y-m-d H:i:s', time()-1);
$productDownload->active = 0;
return $productDownload->save();
}
}
return false;
}
public function deleteDownloadProduct($id_product_attribute = NULL)
{
if (!empty($id_product_attribute))
{
$productDownload = new ProductDownload($id_product_attribute);
$productDownload->date_expiration = date('Y-m-d H:i:s', time()-1);
$productDownload->active = 0;
return $productDownload->save();
}
return false;
}
/**
* 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 (sizeof($accessories_id))
{
array_pop($accessories_id);
$product->changeAccessories($accessories_id);
}
}
}
/**
* Update product tags
*
* @param array Languages
* @param object $product Product
* @return boolean Update result
*/
public function updateTags($languages, $product)
{
$tagError = true;
/* Reset all tags for THIS product */
if (!Db::getInstance()->Execute('
DELETE FROM `'._DB_PREFIX_.'product_tag`
WHERE `id_product` = '.(int)($product->id)))
return false;
/* Assign tags to this product */
foreach ($languages as $language)
if ($value = Tools::getValue('tags_'.$language['id_lang']))
$tagError &= Tag::addTags($language['id_lang'], (int)($product->id), $value);
return $tagError;
}
public function initContent($token = null)
{
if (Tools::getValue('id_product') || ((Tools::isSubmit('submitAddproduct') OR Tools::isSubmit('submitAddproductAndPreview') OR Tools::isSubmit('submitAddproductAndStay') OR Tools::isSubmit('submitSpecificPricePriorities') OR Tools::isSubmit('submitPriceAddition') OR Tools::isSubmit('submitPricesModification')) AND sizeof($this->_errors)) OR Tools::isSubmit('updateproduct') OR Tools::isSubmit('addproduct'))
{
$this->fields_form = array();
if (empty($this->action))
$this->action = 'Informations';
if(method_exists($this, 'initForm'.$this->action))
$this->tpl_form = 'products/'.strtolower($this->action).'.tpl';
if ($this->ajax)
{
$this->display = 'edit';
$this->content_only = true;
}
else
{
$product_tabs = array();
// action defines which tab to display first
$action = $this->action;
if (empty($action) || !method_exists($this, 'initForm'.$action))
$action = 'Informations';
if(Tools::getValue('id_product'))
{
// i is used as producttab id
$i = 0;
foreach($this->available_tabs as $product_tab)
{
$product_tabs[$product_tab] = array(
'id' => ++$i,
'selected' => (strtolower($product_tab) == strtolower($action)),
// @todo $this->l() instead of product_tab
'name' => $product_tab,
'href' => $this->context->link->getAdminLink('AdminProducts').'&id_product='.Tools::getValue('id_product').'&action='.$product_tab,
);
}
$this->tpl_form_vars['newproduct'] = 0;
}
else
$this->tpl_form_vars['newproduct'] = 1;
$this->tpl_form_vars['product_tabs'] = $product_tabs;
}
$languages = Language::getLanguages(false);
$defaultLanguage = (int)(Configuration::get('PS_LANG_DEFAULT'));
}
else
{
$this->display = 'list';
if ($id_category = (int)Tools::getValue('id_category'))
AdminController::$currentIndex .= '&id_category='.$id_category;
$this->getList($this->context->language->id, !$this->context->cookie->__get($this->table.'Orderby') ? 'position' : null, !$this->context->cookie->__get($this->table.'Orderway') ? 'ASC' : null, 0, null, $this->context->shop->getID(true));
$id_category = Tools::getValue('id_category', 1);
if (!$id_category)
$id_category = 1;
// @todo lot of ergonomy works around here
// @todo : move blockcategories select queries in class Category
$root_categ = Category::getRootCategory();
$children = $root_categ->getAllChildren();
$category_tree = array();
foreach ($children as $k => $categ)
{
$categ = new Category($categ['id_category'],$this->context->language->id);
$categ->selected = $this->_category->id_category == $categ->id;
$categ->dashes = str_repeat(' - ',$categ->level_depth);
$category_tree[] = $categ;
}
$this->tpl_list_vars['category_tree'] = $category_tree;
}
// @todo module free
$this->tpl_form_vars['vat_number'] = file_exists(_PS_MODULE_DIR_.'vatnumber/ajax.php');
parent::initContent();
}
public function ajaxProcessProductManufacturers()
{
$manufacturers = Manufacturer::getManufacturers();
if ($manufacturers)
{
$jsonArray = array();
foreach ($manufacturers AS $manufacturer)
$jsonArray[] = '{"optionValue": "'.$manufacturer['id_manufacturer'].'", "optionDisplay": "'.htmlspecialchars(trim($manufacturer['name'])).'"}';
die('['.implode(',', $jsonArray).']');
}
}
/**
* displayList show ordered list of current category
*
* @param mixed $token
* @return void
*/
public function displayList($token = null)
{
/* Display list header (filtering, pagination and column names) */
// $this->displayListHeader($token);
if (!sizeof($this->_list))
echo '
'.$this->l('No items found').'
';
/* Show the content of the table */
$this->displayListContent($token);
/* Close list table and submit button */
$this->displayListFooter($token);
}
/**
* Build a categories tree
*
* @param array $indexedCategories Array with categories where product is indexed (in order to check checkbox)
* @param array $categories Categories to list
* @param array $current Current category
* @param integer $id_category Current category id
*/
public static function recurseCategoryForInclude($id_obj, $indexedCategories, $categories, $current, $id_category = 1, $id_category_default = null, $has_suite = array())
{
global $done;
static $irow;
$content = '';
if (!isset($done[$current['infos']['id_parent']]))
$done[$current['infos']['id_parent']] = 0;
$done[$current['infos']['id_parent']] += 1;
$todo = sizeof($categories[$current['infos']['id_parent']]);
$doneC = $done[$current['infos']['id_parent']];
$level = $current['infos']['level_depth'] + 1;
$content .= '