diff --git a/admin-dev/ajax.php b/admin-dev/ajax.php index 30ec9ea5c..616072ec5 100644 --- a/admin-dev/ajax.php +++ b/admin-dev/ajax.php @@ -84,21 +84,6 @@ if (Tools::isSubmit('ajaxProductManufacturers')) } } -if (Tools::isSubmit('ajaxProductQuantity')) -{ - require_once(dirname(__FILE__).'/tabs/AdminCatalog.php'); - $catalog = new AdminCatalog(); - $admin = new AdminProducts(); - - $languages = Language::getLanguages(false); - $defaultLanguage = (int)(Configuration::get('PS_LANG_DEFAULT')); - $product = new Product((int)(Tools::getValue('id_product'))); - if (!Validate::isLoadedObject($product)) - die (Tools::displayError('Product cannot be loaded')); - - AdminTab::$currentIndex = 'index.php?tab=AdminCatalog'; - echo $admin->ajaxProductQuantity($product); -} if (Tools::isSubmit('ajaxReferrers')) { @@ -571,7 +556,7 @@ if (Tools::isSubmit('helpAccess')) if (isset($item) AND isset($isoUser) AND isset($country)) die(HelpAccess::displayHelp($item, $isoUser, $country, $version)); - die(); + die('{nohelp}'); } if (Tools::isSubmit('getHookableList')) diff --git a/admin-dev/tabs/AdminProducts.php b/admin-dev/tabs/AdminProducts.php index f12627d57..d3bc3026f 100644 --- a/admin-dev/tabs/AdminProducts.php +++ b/admin-dev/tabs/AdminProducts.php @@ -4772,4 +4772,4 @@ class AdminProducts extends AdminTab $this->displayErrors(); } -} \ No newline at end of file +} diff --git a/admin-dev/themes/default/admin.css b/admin-dev/themes/default/admin.css index 4465c9896..ba119c21c 100644 --- a/admin-dev/themes/default/admin.css +++ b/admin-dev/themes/default/admin.css @@ -36,23 +36,25 @@ input.button[disabled=disabled]:hover{background-color:#FFF6D3} fieldset{background:#FFFFF0;border:1px solid #DFD5C3;font-size:1.1em;margin:0;padding:1em} legend{background:#FFF6D3;border:1px solid #DFD5C3;font-weight:700;margin:0;padding:.2em .5em;text-align:left} #menu{float:left;height:30px;line-height:normal;margin:10px 0 0;*margin:7px 0 0;padding:0;width:100%;padding:0 1px} -#menu li{background:url(bg-tab.png) repeat-x 0 -2px;float:left;height:29px;list-style:none;margin:0 1px 0 0;list-style:none;display:block;border:1px solid #999999;-moz-border-radius-topright:6px;-moz-border-radius-topleft:6px;-webkit-border-top-right-radius:6px;-webkit-border-top-left-radius:6px} -#menu li a{color:#000;display:block;height:20px;padding:8px 6px 4px 0;font-weight:bold;font-size:0.95em;} +#menu li.maintab{background:url(bg-tab.png) repeat-x 0 -2px;float:left;height:29px;list-style:none;margin:0 1px 0 0;list-style:none;display:block;border:1px solid #999999;-moz-border-radius-topright:6px;-moz-border-radius-topleft:6px;-webkit-border-top-right-radius:6px;-webkit-border-top-left-radius:6px} +#menu li.submenu_size .title{color:#000;display:block;height:20px;padding:8px 6px 4px 0;font-weight:bold;font-size:0.95em;} +#menu li.submenu_size .title{_display:inline;_padding:6px 5px 4px 0} +#menu li{_height:32px;_padding-top:3px} #menu img{display:inline;padding:0 3px 0 6px;vertical-align:top;width:16px;height:16px} #menu li.active,#menu li:hover{background-position:0 -38px;white-space:nowrap;} #menu li.active a{color:#000} -#submenu{background:#ECEADE;clear:both;color:#666;margin:0;padding:0;border:1px solid #999999} +.submenu{background:#ECEADE;clear:both;color:#666;margin:0;padding:0;border:1px solid #999999;z-index:9999} .withLeftBorder{background:transparent url(separator_subnav.png) no-repeat 0 5px} -#submenu li{display:inline;list-style:none;margin:0;background:transparent url(separator_subnav.png) no-repeat right 0;padding-left:7px;padding-right:7px;margin-top:8px;float:left;height:29px} -#submenu li a{text-decoration:underline} -#menu li{_height:32px;_padding-top:3px} -#menu li a{_display:inline;_padding:6px 5px 4px 0} -.tab-page {border:1px solid #ccc;background:#FFFFF0} -.tab-row .tab.selected {border:1px solid #ccc;background:#FFF6D3;margin:1px -3px -3px 0px;top:-2px} -.tab-row .tab {background:#EFEFEF} +.submenu li{list-style:none;margin:0;padding-left:7px;padding-right:7px;margin-top:8px;float:left;height:16px;} +.submenu li a{text-decoration:underline} +.tab-row {height:24px;width:100px;margin-left:25px;border:1px solid #cccccc} +.tab-row .tab .selected {background:#FFF6D3;margin:1px -3px -3px 25px;top:-2px;background-color:#eeeeee} +.tab-row .tab {background:#EFEFEF;width:100px;} +.tab-row .tab-page.selected {background:#FFF6D3;font-weight:bold;margin:1px -3px -3px 0px;top:-2px;background-color:#eeeeee} +.tab-row .tab-page {background:#EFEFEF;width:100px;} hr {height: 1px;color:#E0D0B1;background-color:#E0D0B1} #footer {height:40px;background:#ECEADE url(footer-bg.png) repeat-x scroll left bottom;border:1px solid #999999;font-size:12px;clear:both;font-size:0.9em;color:#666666} -#content {background-color:#FFF;border-left:1px solid #999999;border-right:1px solid #999999} +#content {background-color:#FFF;border-left:1px solid #999999;border-right:1px solid #999999; border-top:1px solid #999999} input[type="text"],input[type="password"],input[type="file"],textarea {border:1px solid #E0D0B1} select {border: 1px solid #E0D0B1} select[disabled="disabled"], input[disabled="disabled"],textarea[disabled="disabled"] {border: 1px solid #CCCCCC;color: #AAAAAA} @@ -85,4 +87,6 @@ a.module_toggle_all{color: #268CCD;} .notifs_wrapper ul li {text-decoration: none;list-style: none;font-size:12px;padding:5px 0;} #header_infos .notifs_wrapper a {font-weight: bold;color: black;} .notifs_wrapper p {font-size: 12px;padding-top:8px;margin:0;border-top: 2px solid #E0E0E0;} -.notifs_wrapper p.no_notifs {border: none;} \ No newline at end of file +.notifs_wrapper p.no_notifs {border: none;} +.productTabs ol{padding:0;} +.productTabs{background-color:#e0e0e0;border:1px solid #cccccc;position:absolute;top:100px;left:50px;} diff --git a/admin-dev/themes/template/layout.tpl b/admin-dev/themes/template/layout.tpl index 4f8f6d6a9..13b6da34b 100644 --- a/admin-dev/themes/template/layout.tpl +++ b/admin-dev/themes/template/layout.tpl @@ -23,9 +23,9 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA *} - -{include file='header.tpl'} - +{if $display_header} + {include file='header.tpl'} +{/if} {if isset($conf)}
{$conf} @@ -61,7 +61,7 @@
{/if} -{if count($informations) && $informations} +{if isset($informations) && count($informations) && $informations}
{foreach $informations as $info} {$info} @@ -115,5 +115,6 @@ {/if} {$page} - -{include file='footer.tpl'} +{if $display_footer} + {include file='footer.tpl'} +{/if} diff --git a/admin-dev/themes/template/list_content.tpl b/admin-dev/themes/template/list_content.tpl index bc8044151..d8441fb34 100644 --- a/admin-dev/themes/template/list_content.tpl +++ b/admin-dev/themes/template/list_content.tpl @@ -108,4 +108,4 @@ {/if} -{/foreach} \ No newline at end of file +{/foreach} diff --git a/admin-dev/themes/template/products/content.tpl b/admin-dev/themes/template/products/content.tpl new file mode 100644 index 000000000..524da282b --- /dev/null +++ b/admin-dev/themes/template/products/content.tpl @@ -0,0 +1,181 @@ + + + + + + +{if isset($product_tabs)} +
+
    + {foreach $product_tabs key=numStep item=tab} +
  1. + {$tab.name}{*todo href when nojs*} +
  2. + {/foreach} +
+
+ +{***********************************************} +{********** TO CHECK !!!!!!!!!!!!!!! ***********} + + +
+{$draft_warning} + + +
+
+{$content} +
+ +
+{l s='Back to list'}
+{else} +{$content} +{/if} + diff --git a/admin-dev/themes/template/products/images.tpl b/admin-dev/themes/template/products/images.tpl new file mode 100644 index 000000000..97f6c1af6 --- /dev/null +++ b/admin-dev/themes/template/products/images.tpl @@ -0,0 +1,130 @@ +
+

2. {l s='Images'} ({$countImages})

+ + + + +
{if isset($id_image)}{l s='Edit this product image'}{else}{l s='Add a new image to this product'}{/if}
+

+ + + + '; + + /* 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 .= ' + + + + + '; + + if ($level > 1) + $has_suite[] = ($todo == $doneC ? 0 : 1); + if (isset($categories[$id_category])) + foreach ($categories[$id_category] as $key => $row) + if ($key != 'infos') + $content .= self::recurseCategoryForInclude($id_obj, $indexedCategories, $categories, $categories[$id_category][$key], $key, $id_category_default, $has_suite); + return $content; + } + + public function displayErrors() + { + if ($this->includeSubTab('displayErrors')) + ; + else if ($nbErrors = sizeof($this->_errors)) + { + $this->content .= '
+ + '.$nbErrors.' '.($nbErrors > 1 ? $this->l('errors') : $this->l('error')).' +
    '; + foreach ($this->_errors as $error) + $this->content .= '
  1. '.$error.'
  2. '; + $this->content .= ' +
+
'; + } + } + + private function _displayDraftWarning($active) + { + $content = '
+

+ + + '.$this->l('Your product will be saved as draft').' + + '.$this->l('Save and preview').' + +
+

+
'; + $this->context->smarty->assign('draft_warning',$content); + } + + public function initForm() + { + parent::initForm(); + $this->addJqueryUI('ui.datepicker'); + $this->context->smarty->assign('pos_select', (($tab = Tools::getValue('tabs')) ? $tab : '0')); + $this->context->smarty->assign('token',$this->token); + $this->context->smarty->assign('combinationImagesJs', $this->getCombinationImagesJs()); + $id_product = Tools::getvalue('id_product'); + $this->context->smarty->assign('form_action', $this->context->link->getAdminLink('AdminProducts').'&id_product='.$id_product); + $this->context->smarty->assign('id_product',$id_product); + + if (!($obj = $this->loadObject(true))) + throw new Exception('object not loaded'); + $this->_displayDraftWarning($obj->active); + } + + public function displayForm($isMainTab = true) + { + parent::displayForm(); + if (!($obj = $this->loadObject(true))) + throw new Exception('object not loaded'); + $smarty = $this->context->smarty; + $product_tabs = array(); + foreach($this->available_tabs as $product_tab) + { + $product_tabs[$product_tab] = array( + 'name' => $product_tab, + 'href' => $this->context->link->getAdminLink('AdminProducts').'&id_product='.Tools::getValue('id_product').'&action='.$product_tab, + ); + } + $smarty->assign('product_tabs', $product_tabs); + + if ($id_category_back = (int)(Tools::getValue('id_category'))) + self::$currentIndex .= '&id_category='.$id_category_back; + + if (!($obj = $this->loadObject(true))) + return; + + $currency = Tools::setCurrency($this->context->cookie); +// if ($obj->id) +// self::$currentIndex .= '&id_product='.$obj->id; + + + // $this->addJqueryPlugin('tabpane'); + + $action = $this->action; + if (empty($action) || !method_exists($this,'initForm'.$action)) + $action = 'informations'; + $this->initForm(); + $this->{'initForm'.$action}($obj, null); + /* Tabs */ +/* +switch ($this->action) + { + default: + $this->initFormInformations($obj, $currency); +// $this->initFormImages($obj, $this->token); + } + */ + if (Combination::isFeatureActive()) + $smarty->assign('countAttributes', Db::getInstance()->getValue('SELECT COUNT(id_product) FROM '._DB_PREFIX_.'product_attribute WHERE id_product = '.(int)$obj->id)); + + $smarty->assign('countAttachments', Db::getInstance()->getValue('SELECT COUNT(id_product) FROM '._DB_PREFIX_.'product_attachment WHERE id_product = '.(int)$obj->id)); + + if (Tools::getValue('id_category') > 1) + { + $productIndex = preg_replace('/(&id_product=[0-9]*)/', '', self::$currentIndex); +/** @TODO + $this->content .= ' +

+ + '.$this->l('Back to the category').' +
'; +*/ + } + } + + function initFormPrices($obj, $languages, $defaultLanguage) + { + $content = ''; + if ($obj->id) + { + $this->context->smarty->assign('shops', $shops = Shop::getShops()); + $this->context->smarty->assign('currencies', $currencies = Currency::getCurrencies()); + $this->context->smarty->assign('countries', $countries = Country::getCountries($this->context->language->id)); + $this->context->smarty->assign('groups', $groups = Group::getGroups($this->context->language->id)); +// $currencies = Currency::getCurrencies(); +// $countries = Country::getCountries($this->context->language->id); + //$groups = Group::getGroups($this->context->language->id); + $content .= $this->_displaySpecificPriceAdditionForm( $this->context->currency, $shops, $currencies, $countries, $groups); + $content .= $this->_displaySpecificPriceModificationForm( $this->context->currency, $shops, $currencies, $countries, $groups); + } + else + $content .= ''.$this->l('You must save this product before adding specific prices').'.'; + $this->context->smarty->assign('content',$content); + $this->content = $this->context->smarty->fetch('products/prices.tpl'); + } + + private function _getFinalPrice($specificPrice, $productPrice, $taxRate) + { + $price = Tools::ps_round((float)($specificPrice['price']) ? $specificPrice['price'] : $productPrice, 2); + if (!(float)($specificPrice['reduction'])) + return (float)($specificPrice['price']); + return ($specificPrice['reduction_type'] == 'amount') ? ($price - $specificPrice['reduction'] / (1 + $taxRate / 100)) : ($price - $price * $specificPrice['reduction']); + } + + protected function _displaySpecificPriceModificationForm($defaultCurrency, $shops, $currencies, $countries, $groups) + { + $content = ''; + if (!($obj = $this->loadObject())) + return; + $specificPrices = SpecificPrice::getByProductId((int)($obj->id)); + $specificPricePriorities = SpecificPrice::getPriority((int)($obj->id)); + + $taxRate = $obj->getTaxesRate(Address::initialize()); + + $tmp = array(); + foreach ($shops as $shop) + $tmp[$shop['id_shop']] = $shop; + $shops = $tmp; + $tmp = array(); + foreach ($currencies as $currency) + $tmp[$currency['id_currency']] = $currency; + $currencies = $tmp; + + $tmp = array(); + foreach ($countries as $country) + $tmp[$country['id_country']] = $country; + $countries = $tmp; + + $tmp = array(); + foreach ($groups as $group) + $tmp[$group['id_group']] = $group; + $groups = $tmp; + + $content .= ' +

'.$this->l('Current specific prices').'

+ +
{l s='File:'} +
+ +
+
+ +
    + + + +{$content} diff --git a/admin-dev/themes/template/products/informations.tpl b/admin-dev/themes/template/products/informations.tpl new file mode 100644 index 000000000..2ce887285 --- /dev/null +++ b/admin-dev/themes/template/products/informations.tpl @@ -0,0 +1,90 @@ +
    +

    1. {l s='Info.'}

    + + {l s='Product global information'} -  +

    {l s='Current product:'}{l s='no name'}

    + + +{$content} + + + + diff --git a/admin-dev/themes/template/products/prices.tpl b/admin-dev/themes/template/products/prices.tpl new file mode 100644 index 000000000..f36228a1b --- /dev/null +++ b/admin-dev/themes/template/products/prices.tpl @@ -0,0 +1,59 @@ +{l s='Add a new specific price'} +
    '.$this->l('No items found').'
    + + + '.$id_category.' + '; + for ($i = 2; $i < $level; $i++) + $content .= ''; + $content .= '   +
    + + + + + + + + + + + + + + + '; + if (!is_array($specificPrices) || !sizeof($specificPrices)) + $content .= ' + + + '; + else + { + $i = 0; + foreach ($specificPrices as $specificPrice) + { + $current_specific_currency = $currencies[($specificPrice['id_currency'] ? $specificPrice['id_currency'] : $defaultCurrency->id)]; + if ($specificPrice['reduction_type'] == 'percentage') + $reduction = ($specificPrice['reduction'] * 100).' %'; + else + $reduction = Tools::displayPrice(Tools::ps_round($specificPrice['reduction'], 2), $current_specific_currency); + + if ($specificPrice['from'] == '0000-00-00 00:00:00' && $specificPrice['to'] == '0000-00-00 00:00:00') + $period = $this->l('Unlimited'); + else + $period = $this->l('From').' '.($specificPrice['from'] != '0000-00-00 00:00:00' ? $specificPrice['from'] : '0000-00-00 00:00:00').'
    '.$this->l('To').' '.($specificPrice['to'] != '0000-00-00 00:00:00' ? $specificPrice['to'] : '0000-00-00 00:00:00'); + $content .= ' + + + + + + + + + + + '; + $i++; + } + } + $content .= ' + +
    '.$this->l('Shop').''.$this->l('Currency').''.$this->l('Country').''.$this->l('Group').''.$this->l('Price').' '.($this->context->country->display_tax_label ? $this->l('(tax excl.)') : '').''.$this->l('Reduction').''.$this->l('Period').''.$this->l('From (quantity)').''.$this->l('Final price').' '.($this->context->country->display_tax_label ? $this->l('(tax excl.)') : '').''.$this->l('Action').'
    '.$this->l('No specific prices').'
    '.($specificPrice['id_shop'] ? $shops[$specificPrice['id_shop']]['name'] : $this->l('All shops')).''.($specificPrice['id_currency'] ? $currencies[$specificPrice['id_currency']]['name'] : $this->l('All currencies')).''.($specificPrice['id_country'] ? $countries[$specificPrice['id_country']]['name'] : $this->l('All countries')).''.($specificPrice['id_group'] ? $groups[$specificPrice['id_group']]['name'] : $this->l('All groups')).''.Tools::displayPrice((float)$specificPrice['price'], $current_specific_currency).''.$reduction.''.$period.''.$specificPrice['from_quantity'].' + '.Tools::displayPrice(Tools::ps_round((float)($this->_getFinalPrice($specificPrice, (float)($obj->price), $taxRate)), 2), $current_specific_currency).''.$this->l('Delete').'
    '; + + $content .= ' + + '; + + $content .= ' +
    +

    '.$this->l('Priorities management').'

    +
    + '.$this->l('Sometimes one customer could fit in multiple rules, priorities allows you to define which rule to apply.').' +
    +
    + +
    + + + > + + > + +
    + +
    + +
    + +
    + +
    + '; + return $content; + } + + protected function _displaySpecificPriceAdditionForm($defaultCurrency, $shops, $currencies, $countries, $groups) + { + if (!($product = $this->loadObject())) + return; + $content = ''; + $this->context->smarty->assign('country_display_tax_label', $this->context->country->display_tax_label); + + $content .= ' +
    + '.($defaultCurrency->format == 1 ? ' '.$defaultCurrency->sign : '').' + + '.($defaultCurrency->format == 2 ? ' '.$defaultCurrency->sign : '').' + ('.$this->l('Current:').' '.Tools::displayPrice((float)($product->price), $defaultCurrency).') +
    + '.$this->l('You can set this value at 0 in order to apply the default price').' +
    +
    + + +
    + + + '.$this->l('(if set to "amount", the tax is included)').' +
    + +
    + +
    +
    +
    + '; + return $content; + } + + private function _getCustomizationFieldIds($labels, $alreadyGenerated, $obj) + { + $customizableFieldIds = array(); + if (isset($labels[Product::CUSTOMIZE_FILE])) + foreach ($labels[Product::CUSTOMIZE_FILE] as $id_customization_field => $label) + $customizableFieldIds[] = 'label_'.Product::CUSTOMIZE_FILE.'_'.(int)($id_customization_field); + if (isset($labels[Product::CUSTOMIZE_TEXTFIELD])) + foreach ($labels[Product::CUSTOMIZE_TEXTFIELD] as $id_customization_field => $label) + $customizableFieldIds[] = 'label_'.Product::CUSTOMIZE_TEXTFIELD.'_'.(int)($id_customization_field); + $j = 0; + for ($i = $alreadyGenerated[Product::CUSTOMIZE_FILE]; $i < (int)($this->getFieldValue($obj, 'uploadable_files')); $i++) + $customizableFieldIds[] = 'newLabel_'.Product::CUSTOMIZE_FILE.'_'.$j++; + $j = 0; + for ($i = $alreadyGenerated[Product::CUSTOMIZE_TEXTFIELD]; $i < (int)($this->getFieldValue($obj, 'text_fields')); $i++) + $customizableFieldIds[] = 'newLabel_'.Product::CUSTOMIZE_TEXTFIELD.'_'.$j++; + return implode('¤', $customizableFieldIds); + } + + private function _displayLabelField(&$label, $languages, $defaultLanguage, $type, $fieldIds, $id_customization_field) + { + $fieldsName = 'label_'.$type.'_'.(int)($id_customization_field); + $fieldsContainerName = 'labelContainer_'.$type.'_'.(int)($id_customization_field); + $this->content .= '
    '; + foreach ($languages as $language) + { + $fieldName = 'label_'.$type.'_'.(int)($id_customization_field).'_'.(int)($language['id_lang']); + $text = (isset($label[(int)($language['id_lang'])])) ? $label[(int)($language['id_lang'])]['name'] : ''; + $this->content .= '
    +
    #'.(int)($id_customization_field).'
    +
    '; + } + + $required = (isset($label[(int)($language['id_lang'])])) ? $label[(int)($language['id_lang'])]['required'] : false; + $this->content .= '
    +
    + +
    '; + } + + private function _displayLabelFields(&$obj, &$labels, $languages, $defaultLanguage, $type) + { + $type = (int)($type); + $labelGenerated = array(Product::CUSTOMIZE_FILE => (isset($labels[Product::CUSTOMIZE_FILE]) ? count($labels[Product::CUSTOMIZE_FILE]) : 0), Product::CUSTOMIZE_TEXTFIELD => (isset($labels[Product::CUSTOMIZE_TEXTFIELD]) ? count($labels[Product::CUSTOMIZE_TEXTFIELD]) : 0)); + + $fieldIds = $this->_getCustomizationFieldIds($labels, $labelGenerated, $obj); + if (isset($labels[$type])) + foreach ($labels[$type] as $id_customization_field => $label) + $this->_displayLabelField($label, $languages, $defaultLanguage, $type, $fieldIds, (int)($id_customization_field)); + } + + function initFormCustomization($obj, $languages, $defaultLanguage) + { + $this->content .= parent::displayForm(); + $labels = $obj->getCustomizationFields(); + $defaultIso = Language::getIsoById($defaultLanguage); + + $hasFileLabels = (int)($this->getFieldValue($obj, 'uploadable_files')); + $hasTextLabels = (int)($this->getFieldValue($obj, 'text_fields')); + + $this->content .= ' + + + + +
    '.$this->l('Add or modify customizable properties').'
    +

    + + + + + + + + + + + + '; + + if ($hasFileLabels) + { + $this->content .= ' + + + + + '; + } + + if ($hasTextLabels) + { + $this->content .= ' + + + + + '; + } + + $this->content .= ' + + + +
    '.$this->l('File fields:').' + +

    '.$this->l('Number of upload file fields displayed').'

    +
    '.$this->l('Text fields:').' + +

    '.$this->l('Number of text fields displayed').'

    +
    + +

    '.$this->l('Files fields:').''; + $this->_displayLabelFields($obj, $labels, $languages, $defaultLanguage, Product::CUSTOMIZE_FILE); + $this->content .= ' +

    '.$this->l('Text fields:').''; + $this->_displayLabelFields($obj, $labels, $languages, $defaultLanguage, Product::CUSTOMIZE_TEXTFIELD); + $this->content .= ' +
    '; + if ($hasFileLabels || $hasTextLabels) + $this->content .= ''; + $this->content .= ' +
    '; + } + + function initFormAttachments($obj, $languages, $defaultLanguage) + { + if (!($obj = $this->loadObject(true))) + return; + $languages = Language::getLanguages(false); + $attach1 = Attachment::getAttachments($this->context->language->id, $obj->id, true); + $attach2 = Attachment::getAttachments($this->context->language->id, $obj->id, false); + + $this->content .= ' + '.($obj->id ? '' : '').' +
    '.$this->l('Attachment').' + +
    '; + foreach ($languages as $language) + $this->content .= '
    + * +
    '; + $this->content .= $this->getTranslationsFlags($languages, $defaultLanguage, 'attachment_name¤attachment_description', 'attachment_name'); + $this->content .= '
    +
     
    + +
    '; + foreach ($languages as $language) + $this->content .= '
    + +
    '; + $this->content .= $this->getTranslationsFlags($languages, $defaultLanguage, 'attachment_name¤attachment_description', 'attachment_description'); + $this->content .= '
    +
     
    + +
    +

    +

    '.$this->l('Upload file from your computer').'

    +
    +
     
    +
    + +
    +
    * '.$this->l('Required field').'
    +
    +
     
    + + + + + +
    +

    '.$this->l('Attachments for this product:').'

    +

    + + '.$this->l('Remove').' >> + +
    +

    '.$this->l('Available attachments:').'

    +

    + + << '.$this->l('Add').' + + +
    +
     
    + '; + } + + function initFormInformations($obj, $currency) + { + $content = ''; + $smarty = $this->context->smarty; + $content .= parent::displayForm(); + + $has_attribute = $obj->hasAttributes(); + // @FIXME Stock, need to use StockManagerFactory + $qty = 0; + $cover = Product::getCover($obj->id); + $this->_applyTaxToEcotax($obj); + + /* + * Form for add a virtual product like software, mp3, etc... + */ + $productDownload = new ProductDownload(); + if ($id_product_download = $productDownload->getIdFromIdProduct($this->getFieldValue($obj, 'id'))) + $productDownload = new ProductDownload($id_product_download); + + $hidden = $display_filename = $check = ''; + $this->displayInitInformationAndAttachment(); + if(!$productDownload->id || !$productDownload->active) + $hidden = 'style="display:none;"'; + + $cache_default_attribute = (int) $this->getFieldValue($obj, 'cache_default_attribute'); + $is_virtual = (int) $this->getFieldValue($obj, 'is_virtual'); + + if($is_virtual && $productDownload->active) + $check = 'checked="checked"'; + + if($is_virtual) + $virtual = 1; + else + $virtual = 0; + + $preview_url = ''; + if (isset($obj->id)) + { + $preview_url = ($this->context->link->getProductLink($this->getFieldValue($obj, 'id'), $this->getFieldValue($obj, 'link_rewrite', $this->_defaultFormLanguage), Category::getLinkRewrite($this->getFieldValue($obj, 'id_category_default'), $this->context->language->id))); + if (!$obj->active) + { + $admin_dir = dirname($_SERVER['PHP_SELF']); + $admin_dir = substr($admin_dir, strrpos($admin_dir,'/') + 1); + $token = Tools::encrypt('PreviewProduct'.$obj->id); + + $preview_url .= $obj->active ? '' : '&adtoken='.$token.'&ad='.$admin_dir; + } + + $content .= ' + + '.$this->l('Delete this product').' '.$this->l('Delete this product').' + '.$this->l('View product in shop').' '.$this->l('View product in shop').''; + + if (file_exists(_PS_MODULE_DIR_.'statsproduct/statsproduct.php')) + $content .= ' - '.$this->l('View product sales').' '.$this->l('View product sales').''; + } + $content .= ' +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    '.$this->l('Name:').''; + foreach ($this->_languages as $language) + $content .= '
    + id) ? ' onkeyup="if (isArrowKey(event)) return; copy2friendlyURL();"' : '').' onkeyup="if (isArrowKey(event)) return; updateCurrentText();" onchange="updateCurrentText();" /> * + '.$this->l('Invalid characters:').' <>;=#{}  +
    '; + $content .= '
    '.$this->l('Reference:').' + + '.$this->l('Special characters allowed:').' .-_#\  +
    '.$this->l('Supplier Reference:').' + + '.$this->l('Special characters allowed:').' .-_#\  +
    '.$this->l('EAN13 or JAN:').' + '.$this->l('(Europe, Japan)').' +
    '.$this->l('UPC:').' + '.$this->l('(US, Canada)').' +
    '.$this->l('Location (warehouse):').' + +
    '.$this->l('Width ( package ) :').' + '.Configuration::get('PS_DIMENSION_UNIT').' +
    '.$this->l('Height ( package ) :').' + '.Configuration::get('PS_DIMENSION_UNIT').' +
    '.$this->l('Deep ( package ) :').' + '.Configuration::get('PS_DIMENSION_UNIT').' +
    '.$this->l('Weight ( package ) :').' + '.Configuration::get('PS_WEIGHT_UNIT').' +
    + + + + + + + + + active ? 'style="display:none"' : '').'> + + + + + + + + + + + + + + + +
    '.$this->l('Status:').' + getFieldValue($obj, 'active') ? 'checked="checked" ' : '').'/> + +
    + getFieldValue($obj, 'active') ? 'checked="checked" ' : '').'/> + +
    '.$this->l('Shop association:').''; + $content .= $this->displayAssoShop(); + $content .= '
    '.$this->l('Options:').' + getFieldValue($obj, 'available_for_order') ? 'checked="checked" ' : '').' onclick="if ($(this).is(\':checked\')){$(\'#show_price\').attr(\'checked\', \'checked\');$(\'#show_price\').attr(\'disabled\', \'disabled\');}else{$(\'#show_price\').attr(\'disabled\', \'\');}"/> + +
    + getFieldValue($obj, 'show_price') ? 'checked="checked" ' : '').' /> + +
    + getFieldValue($obj, 'online_only') ? 'checked="checked" ' : '').' /> + +
    '.$this->l('Condition:').' + +
    '.$this->l('Manufacturer:').' +    '.$this->l('Create').' '.$this->l('Create').' +
    '.$this->l('Supplier:').' +    '.$this->l('Create').' '.$this->l('Create').' +
    +
    + + '; + $this->displayPack($obj); + $content .= ' '; + +/* + * Form for add a virtual product like software, mp3, etc... + */ + $productDownload = new ProductDownload(); + if ($id_product_download = $productDownload->getIdFromIdProduct($this->getFieldValue($obj, 'id'))) + $productDownload = new ProductDownload($id_product_download); + $this->displayInitInformationAndAttachment(); + $content .= ' + + + + + '; + + $currency = $this->context->currency; + $content .= ' + + + '; + $content .= ' + + + + '; + $content .= ' + + + + '; + $tax_rules_groups = TaxRulesGroup::getTaxRulesGroups(true); + $taxesRatesByGroup = TaxRulesGroup::getAssociatedTaxRatesByIdCountry($this->context->country->id); + $ecotaxTaxRate = Tax::getProductEcotaxRate(); + $content .= ''; + $content .= ' + + + + + '; + if (Configuration::get('PS_USE_ECOTAX')) + $content .= ' + + + + '; + + if ($this->context->country->display_tax_label) + { + $content .= ' + + + + '; + } + else + $content .= ''; + + $content .= ' + + + + + + + + + + + + + + + + + '; + + + if ((int)Configuration::get('PS_STOCK_MANAGEMENT')) + { + + if (!$has_attribute) + { + if ($obj->id) + { + $content .= ' + + + + + + + '; + } + else + $content .= ' + '; + $content .= ' + + + '; + } + + if ($obj->id) + $content .= ' + + + + '; + if ($has_attribute) + $content .= ' + + + '; + } + else + { + $content .= ' + + '; + + $content .= ' + + + + + '; + } + + $content .= ' + + + + + + + + + + + + + '; + + // Check if product has combination, to display the available date only for the product or for each combination + if (Combination::isFeatureActive()) + $countAttributes = (int)Db::getInstance()->getValue('SELECT COUNT(id_product) FROM '._DB_PREFIX_.'product_attribute WHERE id_product = '.(int)$obj->id); + + if (isset($countAttributes) && $countAttributes == 0) + { + $content .= ' + + + + '; + // date picker include + } + + $content .= ' + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + $images = Image::getImages($this->context->language->id, $obj->id); + if ($images) + { + $content .= ' + + + + '; + $content .= ' + '; + } + $content .= ' + + + + '; + $accessories = Product::getAccessoriesLight($this->context->language->id, $obj->id); + + if ($postAccessories = Tools::getValue('inputAccessories')) + { + $postAccessoriesTab = explode('-', Tools::getValue('inputAccessories')); + foreach ($postAccessoriesTab as $accessoryId) + if (!$this->haveThisAccessory($accessoryId, $accessories) && $accessory = Product::getAccessoryById($accessoryId)) + $accessories[] = $accessory; + } + + $content .= ' + + + + + + + + +


    + +

    +

    +
    + +
    '.$this->l('Does this product has an associated file ?').'
    '; + + // todo handle is_virtual with the value of the product + $exists_file = realpath(_PS_DOWNLOAD_DIR_).'/'.$productDownload->filename; + + if ($productDownload->id && !empty($cache_default_attribute) && !empty($productDownload->display_filename)) + { + $check_yes = 'checked="checked"'; + $check_no = ''; + } + else + { + $check_yes = ''; + $check_no = 'checked="checked"'; + } + + $content .= ''. $this->l('Yes').' + '.$this->l('No').'

    '; + + if (!file_exists($exists_file) && !empty($productDownload->display_filename) && empty($cache_default_attribute)) + { + $msg = sprintf(Tools::displayError('This file "%s" is missing'), $productDownload->display_filename); + $content .= '

    + '.$msg.' :
    + '.realpath(_PS_DOWNLOAD_DIR_) .'/'. $productDownload->filename.'
    +

    '; + } + + if (!ProductDownload::checkWritableDir()) + { + $content .= '

    + '.$this->l('Your download repository is not writable.').'
    + '.realpath(_PS_DOWNLOAD_DIR_).' +

    '; + } + + $content .= ' +
    +

    '.$this->l('Pre-tax wholesale price:').' + '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' + '.$this->l('The wholesale price at which you bought this product').' +
    '.$this->l('Pre-tax retail price:').' + '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' * + '.$this->l('The pre-tax retail price to sell this product').' +
    '.$this->l('Tax rule:').' + + + + '.$this->l('Create').' '.$this->l('Create').' + '; + if (Tax::excludeTaxeOption()) + { + $content .= ''.$this->l('Taxes are currently disabled').' ('.$this->l('Tax options').')'; + $content .= ''; + } + + $content .= '
    '.$this->l('Eco-tax (tax incl.):').' + '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' + ('.$this->l('already included in price').') +
    '.$this->l('Retail price with tax:').' + '.($currency->format % 2 != 0 ? ' '.$currency->sign : '').' '.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' +
    '.$this->l('Unit price without tax:').' + '.($currency->format % 2 != 0 ? ' '.$currency->sign : '').' '.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' '.$this->l('per').' '. + (Configuration::get('PS_TAX') && $this->context->country->display_tax_label ? ''.$this->l('or').' '.($currency->format % 2 != 0 ? ' '.$currency->sign : '').'0.00'.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' '.$this->l('per').' '.$this->getFieldValue($obj, 'unity').' '.$this->l('with tax') : '').' +

    '.$this->l('Eg. $15 per Lb').'

    +
      + getFieldValue($obj, 'on_sale') ? 'checked="checked"' : '').'value="1" />  +
    '.$this->l('Final retail price:').' + + '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' ('.$this->l('tax incl.').') + + '; + + if ($this->context->country->display_tax_label) + $content .= ' / '; + + $content .= ($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' '.($this->context->country->display_tax_label ? '('.$this->l('tax excl.').')' : '').' +
      +
    '.$this->l('You can define many discounts and specific price rules in the Prices tab').'
    +

    '.$this->l('Stock Movement:').' + +    + +
      +
    '.$this->l('Choose the reason and enter the quantity that you want to increase or decrease in your stock').'
    +
    '.$this->l('Initial stock:').' + +
    '.$this->l('Minimum quantity:').' + +

    '.$this->l('The minimum quantity to buy this product (set to 1 to disable this feature)').'

    +
    '.$this->l('Quantity in stock:').''.$qty.'
      +
    '.$this->l('You used combinations, for this reason you can\'t edit your stock quantity here, but in the Combinations tab').'
    +
    '.$this->l('The stock management is disabled').'
    '.$this->l('Minimum quantity:').' + +

    '.$this->l('The minimum quantity to buy this product (set to 1 to disable this feature)').'

    +

    '.$this->l('Additional shipping cost:').' + '.($currency->format % 2 == 0 ? ' '.$currency->sign : ''); + if ($this->context->country->display_tax_label) + $content .= ' ('.$this->l('tax excl.').')'; + + $content .= '

    '.$this->l('Carrier tax will be applied.').'

    +
    '.$this->l('Displayed text when in-stock:').''; + foreach ($this->_languages as $language) + $content .= '
    + + '.$this->l('Forbidden characters:').' <>;=#{}  +
    '; + $content .= '
    '.$this->l('Displayed text when allowed to be back-ordered:').''; + foreach ($this->_languages as $language) + $content .= '
    + + '.$this->l('Forbidden characters:').' <>;=#{}  +
    '; + $content .= '
    '.$this->l('Available date:').' + +

    '.$this->l('The available date when this product is out of stock').'

    +
    '.$this->l('When out of stock:').' + getFieldValue($obj, 'out_of_stock')) == 0 ? 'checked="checked"' : '').'/> +
    getFieldValue($obj, 'out_of_stock') == 1 ? 'checked="checked"' : '').'/> +
    getFieldValue($obj, 'out_of_stock') == 2 ? 'checked="checked"' : '').'/> +
    +
    +
    + + '; + $default_category = Tools::getValue('id_category', 1); + if (!$obj->id) + { + $selectedCat = Category::getCategoryInformations(Tools::getValue('categoryBox', array($default_category)), $this->_defaultFormLanguage); + $content .= ' + '; + } + else + { + if (Tools::isSubmit('categoryBox')) + $selectedCat = Category::getCategoryInformations(Tools::getValue('categoryBox', array($default_category)), $this->_defaultFormLanguage); + else + $selectedCat = Product::getProductCategoriesFull($obj->id, $this->_defaultFormLanguage); + } + + $content .= ' +
    + '; + // Translations are not automatic for the moment ;) + $trads = array( + 'Home' => $this->l('Home'), + 'selected' => $this->l('selected'), + 'Collapse All' => $this->l('Collapse All'), + 'Expand All' => $this->l('Expand All'), + 'Check All' => $this->l('Check All'), + 'Uncheck All' => $this->l('Uncheck All'), + 'search' => $this->l('Search a category') + ); + $content .= Helper::renderAdminCategorieTree($trads, $selectedCat, 'categoryBox', false, true).' +

    + '.$this->l('SEO').''.$this->l('Click here to improve product\'s rank in search engines (SEO)').'
    + +

    '.$this->l('Short description:').'

    ('.$this->l('appears in the product lists and on the top of the product page').')
    '; + foreach ($this->_languages as $language) + $content .= '
    + +
    '; + $content .= '

    +
    '.$this->l('Description:').'

    ('.$this->l('appears in the body of the product page').')
    '; + foreach ($this->_languages as $language) + $content .= '
    + +
    '; + $content .= '

    +
    +
    + '.$this->l('Do you want an image associated with the product in your description?').' + '.$this->l('Click here').'. + + + + + + + + '; + $content .= ' + + + + '; + $content .= ' + + + + '; + $content .= ' + + + + + +
    +

    +
    '.$this->l('Tags:').''; + if ($obj->id) + $obj->tags = Tag::getProductTags((int)$obj->id); + foreach ($this->_languages as $language) + { + $content .= '
    + + '.$this->l('Forbidden characters:').' !<>;?=+#"°{}_$%  +
    '; + } + $content .= '

    '.$this->l('Tags separated by commas (e.g., dvd, dvd player, hifi)').'

    +
    '.$this->l('Accessories:').'

    '.$this->l('(Do not forget to Save the product afterward)').'
    +
    '; + foreach ($accessories as $accessory) + $content .= htmlentities($accessory['name'], ENT_COMPAT, 'UTF-8').(!empty($accessory['reference']) ? ' ('.$accessory['reference'].')' : '').'
    '; + $content .= '
    + + + '; + + $this->addJqueryPlugin('autocomplete'); + + $content .= ' +
    +

    '.$this->l('Begin typing the first letters of the product name, then select the product from the drop-down list:').'

    + + '.$this->l('Add an accessory').' +
    + +

    + +  
    +
    +
    '; + // TinyMCE + $iso = $this->context->language->iso_code; + $isoTinyMCE = (file_exists(_PS_JS_DIR_.'tiny_mce/langs/'.$iso.'.js') ? $iso : 'en'); + $ad = dirname($_SERVER["PHP_SELF"]); + $content .= ' + + + + '; + $categoryBox = Tools::getValue('categoryBox', array()); + $smarty->assign('content', $content); + $this->content = $this->context->smarty->fetch('products/informations.tpl'); + } + + function initFormImages($obj, $token = null) + { + $smarty = $this->context->smarty; + $content = ''; + if (!Tools::getValue('id_product')) + return ''; // TEMPO + global $attributeJs, $images; + $shops = false; + if (Shop::isFeatureActive()) + $shops = Shop::getShops(); + + $countImages = Db::getInstance()->getValue('SELECT COUNT(id_product) FROM '._DB_PREFIX_.'image WHERE id_product = '.(int)$obj->id); + $smarty->assign('countImages', $countImages); + + $images = Image::getImages($this->context->language->id, $obj->id); + $imagesTotal = Image::getImagesTotal($obj->id); + $smarty->assign('id_product', (int)Tools::getValue('id_product')); + $smarty->assign('id_category_default', (int)$this->_category->id); + + $content .= ' +

    + '.$this->l('Format:').' JPG, GIF, PNG. '.$this->l('Filesize:').' '.($this->maxImageSize / 1000).''.$this->l('Kb max.').' +

    + + + + + + '.(Tools::getValue('id_image') ? '' : '').' + + +
    + + + + + + + + + + + '; + if ($shops) + { + $content .= ''; + foreach ($shops as $shop) + $content .= ''; + } + $content .= ' + + + '; + + foreach ($images as $k => $image) + $content .= $this->getLineTableImage($image, $imagesTotal, $token, $shops); + $content .= ' +
    '.$this->l('Image').' '.$this->l('Position').''.$shop['name'].''.$this->l('Cover').''.$this->l('Action').'
    + + + +
    '; + $content .= ' + + '; + $smarty->assign('content',$content); + $this->content = $smarty->fetch('products/images.tpl'); + } + + function initFormQuantities($obj) + { + + // Get all id_product_atribute + $attributes = $obj->getAttributesResume($this->context->language->id); + if (empty($attributes)) + $attributes[] = array( + 'id_product_attribute' => 0, + 'attribute_designation' => '' + ); + + // Get physical quantities & available quantities + $totalQuantity = 0; + $physicalQuantity = array(); + $availableQuantity = array(); + $productDesignation = array(); + foreach ($attributes as $attribute) + { + $physicalQuantity[$attribute['id_product_attribute']] = (int)StockManagerFactory::getManager()->getProductPhysicalQuantities((int)$obj->id, $attribute['id_product_attribute']); + $totalQuantity += $physicalQuantity[$attribute['id_product_attribute']]; + + // @TODO + $availableQuantity[$attribute['id_product_attribute']] = StockAvailable::getStockAvailableForProduct((int)$obj->id, $attribute['id_product_attribute']); + + // Get all product designation + $productDesignation[$attribute['id_product_attribute']] = rtrim($obj->name[$this->context->language->id].' - '.$attribute['attribute_designation'], ' - '); + } + + $return = ' +
    +

    8. '.$this->l('Quantities').'

    + + + + + + +
    + '.$this->l('Available stock in warehouses').' +
    +
    +

    '.sprintf($this->l('There is %s quantities available in stock for this product'), ''.$totalQuantity.'').'

    + + + + + + +
    + + + + + + + + '; + foreach ($attributes as $attribute) + $return .= ' + + + + '; + $return .= ' + +
    '.$this->l('Quantity').''.$this->l('Designation').'
    '.$physicalQuantity[$attribute['id_product_attribute']].''.$productDesignation[$attribute['id_product_attribute']].'
    +
    +
    + + + + + + +
    + '.$this->l('Available quantities for sale').' +
    +
    + + + + '; + $return .= ' + + + + + + + + + + + + + + + +
    + depends_on_stock) ? 'checked="checked"' : '' ).' type="radio" name="depends_on_stock" class="depends_on_stock" id="depends_on_stock_1" value="1"/> + +

    +
    + depends_on_stock) ? 'checked="checked"' : '' ).' type="radio" name="depends_on_stock" class="depends_on_stock" id="depends_on_stock_0" value="0"/> + +

    +
    + + + + + + + + '; + foreach ($attributes as $attribute) + $return .= ' + + + + '; + $return .= ' + +
    '.$this->l('Quantity').''.$this->l('Designation').'
    + '.$availableQuantity[$attribute['id_product_attribute']].' + + '.$productDesignation[$attribute['id_product_attribute']].'
    +
    + + + + + + + +
    '.$this->l('When out of stock:').' + out_of_stock == 0) ? 'checked="checked"' : '' ).' id="out_of_stock_1" type="radio" checked="checked" value="0" class="out_of_stock" name="out_of_stock"> + +
    + out_of_stock == 1) ? 'checked="checked"' : '' ).' id="out_of_stock_2" type="radio" value="1" class="out_of_stock" name="out_of_stock"> + +
    + out_of_stock == 2) ? 'checked="checked"' : '' ).' id="out_of_stock_3" type="radio" value="2" class="out_of_stock" name="out_of_stock"> + +
    +
    '; + $return .= ' +
    + '; + + $this->content = $return; + return $return; + } + + public function ajaxProcessProductQuantity() + { + if(!Tools::getValue('actionQty')) + return Tools::jsonEncode(array('error' => 'Undefined action')); + + $product = new Product((int)(Tools::getValue('id_product'))); + switch(Tools::getValue('actionQty')) + { + case 'depends_on_stock': + if (Tools::getValue('value') === false) + return Tools::jsonEncode(array('error' => 'Undefined value')); + if ((int)Tools::getValue('value') != 0 && (int)Tools::getValue('value') != 1) + return Tools::jsonEncode(array('error' => 'Uncorrect value')); + + StockAvailable::setProductDependsOnStock((int)Tools::getValue('value'), $product->id); + break; + + case 'out_of_stock': + if (Tools::getValue('value') === false) + return Tools::jsonEncode(array('error' => 'Undefined value')); + if (!in_array((int)Tools::getValue('value'), array(0, 1, 2))) + return Tools::jsonEncode(array('error' => 'Uncorrect value')); + + StockAvailable::setProductOutOfStock((int)Tools::getValue('value'), $product->id); + break; + + case 'set_qty': + if (Tools::getValue('value') === false) + return Tools::jsonEncode(array('error' => 'Undefined value')); + if (Tools::getValue('id_product_attribute') === false) + return Tools::jsonEncode(array('error' => 'Undefined id product attribute')); + $stock_available = new StockAvailable(StockAvailable::getIdStockAvailable($product->id, (int)Tools::getValue('id_product_attribute'))); + $stock_available->quantity = (int)Tools::getValue('value'); + $stock_available->save(); + break; + } + $this->content = Tools::jsonEncode(array('error' => false)); + } + + public function getLineTableImage($image, $imagesTotal, $token, $shops) + { + if (Shop::isFeatureActive()) + $imgObj = new Image((int)$image['id_image']); + $image_obj = new Image($image['id_image']); + $img_path = $image_obj->getExistingImgPath(); + $html = ' + + + '.htmlentities(stripslashes($image['legend']), ENT_COMPAT, 'UTF-8').' + + '.(int)($image['position']).' + '; + + $html .= ' + + '; + $html .= ' + '; + if (Shop::isFeatureActive()) + foreach ($shops as $shop) + $html .= ' + isAssociatedToShop($shop['id_shop']) ? 'checked="1"' : '').' />'; + $html .= ' + + + '.$this->l('Delete this image').' + + '; + return $html; + } + + public function getCombinationImagesJS() + { + if (!($obj = $this->loadObject(true))) + return; + + $content = 'var combination_images = new Array();'; + if (!$allCombinationImages = $obj->getCombinationImages($this->context->language->id)) + return $content; + foreach ($allCombinationImages as $id_product_attribute => $combinationImages) + { + $i = 0; + $content .= 'combination_images['.(int)($id_product_attribute).'] = new Array();'; + foreach ($combinationImages as $combinationImage) + $content .= 'combination_images['.(int)($id_product_attribute).']['.$i++.'] = '.(int)($combinationImage['id_image']).';'; + } + return $content; + // $this->context->smarty->assign('co mbinationImagesJs', $content); + } + + public function initFormCombinations($obj, $languages, $defaultLanguage) + { + return $this->initFormAttributes($obj, $languages, $defaultLanguage); + } + public function initFormAttributes($obj, $languages, $defaultLanguage) + { + if (!Combination::isFeatureActive()) + { + $this->displayWarning($this->l('This feature has been disabled, you can active this feature at this page:').' '.$this->l('Performances').''); + return; + } + $content = ''; + + $attributeJs = array(); + $attributes = Attribute::getAttributes($this->context->language->id, true); + foreach ($attributes as $k => $attribute) + $attributeJs[$attribute['id_attribute_group']][$attribute['id_attribute']] = $attribute['name']; + $currency = $this->context->currency; + $attributes_groups = AttributeGroup::getAttributesGroups($this->context->language->id); + $default_country = new Country((int)Configuration::get('PS_COUNTRY_DEFAULT')); + + $productDownload = new ProductDownload(); + $id_product_download = (int) $productDownload->getIdFromIdProduct($this->getFieldValue($obj, 'id')); + if (!empty($id_product_download)) + $productDownload = new ProductDownload($id_product_download); + + $images = Image::getImages($this->context->language->id, $obj->id); + if ($obj->id) + { + $content .= ' + + + + + +
    '.$this->l('Add or modify combinations for this product').' - +  combinations_generator '.$this->l('Product combinations generator').' +
    +

    + + + + + + + + + + + + + + + + + + + + + + + + +
    '.$this->l('Group:').'
    '.$this->l('Attribute:').' + +
    +
    +
    + +

    '.$this->l('Reference:').' + + '.$this->l('EAN13:').' + '.$this->l('UPC:').' + '.$this->l('Special characters allowed:').' .-_#  +
    '.$this->l('Supplier Reference:').' + + '.$this->l('Location:').' + '.$this->l('Special characters allowed:').' .-_#  +

    + + + + + + + + + + + + + + + + + + + + + + '; + if (Configuration::get('PS_USE_ECOTAX')) + $content .= ' + + + + '; + + $content .= ' + + + + + + + + + + + + + + + + + + + + + '; + // date picker include + $content .= ' + + + + + + + + + + + + + + + + + +
    '.$this->l('Wholesale price:').''.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' ('.$this->l('overrides Wholesale price on Information tab').')
    '.$this->l('Impact on price:').' + +   '.$this->l('of').'  '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').' + '.($currency->format % 2 == 0 ? ' '.$currency->sign : ''); + if ($this->context->country->display_tax_label) + { + $content .= ' '.$this->l('(tax excl.)').' '.$this->l('or').' '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').' + '.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' '.$this->l('(tax incl.)').' '.$this->l('final product price will be set to').' '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').'0.00'.($currency->format % 2 == 0 ? $currency->sign.' ' : ''); + } + $content .= ' + +
    '.$this->l('Impact on weight:').' +   '.$this->l('of').'   + '.Configuration::get('PS_WEIGHT_UNIT').'
    '.$this->l('Impact on unit price :').' +   '.$this->l('of').'  '.($currency->format % 2 != 0 ? $currency->sign.' ' : '').' + '.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' / '.$this->getFieldValue($obj, 'unity').' +
    '.$this->l('Eco-tax:').''.($currency->format % 2 != 0 ? $currency->sign.' ' : '').''.($currency->format % 2 == 0 ? ' '.$currency->sign : '').' ('.$this->l('overrides Eco-tax on Information tab').')
    '.$this->l('Initial stock:').'
    '.$this->l('Minimum quantity:').' + +

    '.$this->l('The minimum quantity to buy this product (set to 1 to disable this feature)').'

    +
    '.$this->l('Available date:').' +

    '.$this->l('The available date when this product is out of stock').'

    +

    '.$this->l('Image:').' +
      '; + $i = 0; + $imageType = ImageType::getByNameNType('small', 'products'); + $imageWidth = (isset($imageType['width']) ? (int)($imageType['width']) : 64) + 25; + foreach ($images as $image) + { + $imageObj = new Image($image['id_image']); + $content .= '
    • +
    • '; + ++$i; + } + $content .= '
    + +
    '.$this->l('Default:').'

    +  '.$this->l('Make this the default combination for this product').'

    +
      + + +

    +
    + + + + + + + + + '; + + + if ($id_product_download && !empty($productDownload->display_filename)) + { + $content .= ' + + + + '; + } + + $content .= ' + '; + if ($obj->id) + { + /* Build attributes combinaisons */ + $combinaisons = $obj->getAttributeCombinaisons($this->context->language->id); + $groups = array(); + if (is_array($combinaisons)) + { + $combinationImages = $obj->getCombinationImages($this->context->language->id); + foreach ($combinaisons as $k => $combinaison) + { + $combArray[$combinaison['id_product_attribute']]['wholesale_price'] = $combinaison['wholesale_price']; + $combArray[$combinaison['id_product_attribute']]['price'] = $combinaison['price']; + $combArray[$combinaison['id_product_attribute']]['weight'] = $combinaison['weight']; + $combArray[$combinaison['id_product_attribute']]['unit_impact'] = $combinaison['unit_price_impact']; + $combArray[$combinaison['id_product_attribute']]['reference'] = $combinaison['reference']; + $combArray[$combinaison['id_product_attribute']]['supplier_reference'] = $combinaison['supplier_reference']; + $combArray[$combinaison['id_product_attribute']]['ean13'] = $combinaison['ean13']; + $combArray[$combinaison['id_product_attribute']]['upc'] = $combinaison['upc']; + $combArray[$combinaison['id_product_attribute']]['minimal_quantity'] = $combinaison['minimal_quantity']; + $combArray[$combinaison['id_product_attribute']]['available_date'] = strftime($combinaison['available_date']); + $combArray[$combinaison['id_product_attribute']]['location'] = $combinaison['location']; + $combArray[$combinaison['id_product_attribute']]['quantity'] = $combinaison['quantity']; + $combArray[$combinaison['id_product_attribute']]['id_image'] = isset($combinationImages[$combinaison['id_product_attribute']][0]['id_image']) ? $combinationImages[$combinaison['id_product_attribute']][0]['id_image'] : 0; + $combArray[$combinaison['id_product_attribute']]['default_on'] = $combinaison['default_on']; + $combArray[$combinaison['id_product_attribute']]['ecotax'] = $combinaison['ecotax']; + $combArray[$combinaison['id_product_attribute']]['attributes'][] = array($combinaison['group_name'], $combinaison['attribute_name'], $combinaison['id_attribute']); + if ($combinaison['is_color_group']) + $groups[$combinaison['id_attribute_group']] = $combinaison['group_name']; + } + } + $irow = 0; + if (isset($combArray)) + { + foreach ($combArray as $id_product_attribute => $product_attribute) + { + $list = ''; + $jsList = ''; + + /* In order to keep the same attributes order */ + asort($product_attribute['attributes']); + + foreach ($product_attribute['attributes'] as $attribute) + { + $list .= addslashes(htmlspecialchars($attribute[0])).' - '.addslashes(htmlspecialchars($attribute[1])).', '; + $jsList .= '\''.addslashes(htmlspecialchars($attribute[0])).' : '.addslashes(htmlspecialchars($attribute[1])).'\', \''.$attribute[2].'\', '; + } + $list = rtrim($list, ', '); + $jsList = rtrim($jsList, ', '); + $attrImage = $product_attribute['id_image'] ? new Image($product_attribute['id_image']) : false; + $available_date = ($product_attribute['available_date'] != 0) ? date('Y-m-d', strtotime($product_attribute['available_date'])) : '0000-00-00'; + + $id_product_download = $productDownload->getIdFromIdAttribute((int) $obj->id, (int) $id_product_attribute); + if ($id_product_download) + $productDownload = new ProductDownload($id_product_download); + + $available_date_attribute = substr($productDownload->date_expiration, 0, -9); + + if ($available_date_attribute == '0000-00-00') + $available_date_attribute = ''; + + if ($productDownload->is_shareable == 1) + $is_shareable = $this->l('Yes'); + else + $is_shareable = $this->l('No'); + + $content .= ' + + + + + + + + '; + + if ($id_product_download && !empty($productDownload->display_filename)) + { + $content .= ' + + + '; + } + + $exists_file = realpath(_PS_DOWNLOAD_DIR_).'/'.$productDownload->filename; + + if ($productDownload->id && file_exists($exists_file)) + $filename = $productDownload->filename; + else + $filename = ''; + + $content .= ' + '; + } + $content .= ''; + } + else + $content .= ''; + } + $content .= ' +
    '.$this->l('Attributes').''.$this->l('Impact').''.$this->l('Weight').''.$this->l('Reference').''.$this->l('EAN13').''.$this->l('UPC').''.$this->l('Quantity').''.$this->l('Filename').''.$this->l('Number of downloads').''.$this->l('Number of days').''.$this->l('Share').''.$this->l('Actions').'
    '.stripslashes($list).''.($currency->format % 2 != 0 ? $currency->sign.' ' : '').$product_attribute['price'].($currency->format % 2 == 0 ? ' '.$currency->sign : '').''.$product_attribute['weight'].Configuration::get('PS_WEIGHT_UNIT').''.$product_attribute['reference'].''.$product_attribute['ean13'].''.$product_attribute['upc'].''.$product_attribute['quantity'].''.$productDownload->getHtmlLink(false, true).''.$productDownload->nb_downloadable.''.$productDownload->nb_downloadable.''.$is_shareable.' + + '.$this->l('Modify this combination').'  + '.(!$product_attribute['default_on'] ? ' + '.$this->l('Make this the default combination').'' : '').' + + '.$this->l('Delete this combination').'
    '.$this->l('Delete this combination').' '.$this->l('Delete all combinations').'
    '.$this->l('No combination yet').'.
    +
    '.$this->l('The row in blue is the default combination.').' +
    + '.$this->l('A default combination must be designated for each product.').' +
    + '; + } + else + $content .= ''.$this->l('You must save this product before adding combinations').'.'; + $this->content = $content; + } + + public function initFormFeatures($obj) + { + if (!Feature::isFeatureActive()) + { + $this->displayWarning($this->l('This feature has been disabled, you can active this feature at this page:').' '.$this->l('Performances').''); + return; + } + + $this->content .= parent::displayForm(); + + if ($obj->id) + { + $feature = Feature::getFeatures($this->context->language->id); + $ctab = ''; + foreach ($feature as $tab) + $ctab .= 'ccustom_'.$tab['id_feature'].'¤'; + $ctab = rtrim($ctab, '¤'); + + $this->content .= ' + + + + +
    + '.$this->l('Assign features to this product:').'
    +
      +
    • '.$this->l('You can specify a value for each relevant feature regarding this product, empty fields will not be displayed.').'
    • +
    • '.$this->l('You can either set a specific value, or select among existing pre-defined values you added previously.').'
    • +
    +
    +

    '; + // Header + $nb_feature = Feature::nbFeatures($this->context->language->id); + $this->content .= ' + + + '; + if (!$nb_feature) + $this->content .= ''; + $this->content .= '
    '.$this->l('Feature').' + '.$this->l('Pre-defined value').' + '.$this->l('or').' '.$this->l('Customized value').' +
    '.$this->l('No features defined').'
    '; + + // Listing + if ($nb_feature) + { + $this->content .= ' + '; + + foreach ($feature as $tab_features) + { + $current_item = false; + $custom = true; + foreach ($obj->getFeatures() as $tab_products) + if ($tab_products['id_feature'] == $tab_features['id_feature']) + $current_item = $tab_products['id_feature_value']; + + $featureValues = FeatureValue::getFeatureValuesWithLang($this->context->language->id, (int)$tab_features['id_feature']); + + $this->content .= ' + + + + + '; + } + $this->content .= ' + + + '; + } + $this->content .= '
    '.$tab_features['name'].''; + + if (sizeof($featureValues)) + { + $this->content .= ' + '; + } + else + $this->content .= ''.$this->l('N/A').' - '.$this->l('Add pre-defined values first').''; + + $this->content .= ' + '; + $tab_customs = ($custom ? FeatureValue::getFeatureValueLang($current_item) : array()); + foreach ($this->_languages as $language) + $this->content .= ' +
    + +
    '; + $this->content .= ' +
    +
    +
    + new_features '.$this->l('Add a new feature').' +
    '; + } + else + $this->content .= ''.$this->l('You must save this product before adding features').'.'; + } + + public function haveThisAccessory($accessoryId, $accessories) + { + foreach ($accessories as $accessory) + if ((int)($accessory['id_product']) == (int)($accessoryId)) + return true; + return false; + } + + private function displayPack(Product $obj) + { + $boolPack = (($obj->id && Pack::isPack($obj->id)) || Tools::getValue('ppack')) ? true : false; + $packItems = $boolPack ? Pack::getItems($obj->id, $this->context->language->id) : array(); + + $this->content .= ' + + + + + + + + '; + // param multipleSeparator:'||' ajouté à cause de bug dans lib autocomplete + $this->content .= ''; + + } + + private function addPackItem() + { + return ' + function addPackItem() + { + if ($(\'#curPackItemId\').val() == \'\' || $(\'#curPackItemName\').val() == \'\') + { + alert(\''.$this->l('Thanks to select at least one product.').'\'); + return false; + } + else if ($(\'#curPackItemId\').val() == \'\' || $(\'#curPackItemQty\').val() == \'\') + { + alert(\''.$this->l('Thanks to set a quantity to add a product.').'\'); + return false; + } + + var lineDisplay = $(\'#curPackItemQty\').val()+ \'x \' +$(\'#curPackItemName\').val(); + + var divContent = $(\'#divPackItems\').html(); + divContent += lineDisplay; + divContent += \'
    \'; + + // QTYxID-QTYxID + var line = $(\'#curPackItemQty\').val()+ \'x\' +$(\'#curPackItemId\').val(); + + + $(\'#inputPackItems\').val($(\'#inputPackItems\').val() + line + \'-\'); + $(\'#divPackItems\').html(divContent); + $(\'#namePackItems\').val($(\'#namePackItems\').val() + lineDisplay + \'¤\'); + + $(\'#curPackItemId\').val(\'\'); + $(\'#curPackItemName\').val(\'\'); + + $(\'#curPackItemName\').setOptions({ + extraParams: {excludeIds : getSelectedIds()} + }); + } + '; + } + + private function delPackItem() + { + return ' + function delPackItem(id) + { + var reg = new RegExp(\'-\', \'g\'); + var regx = new RegExp(\'x\', \'g\'); + + var div = getE(\'divPackItems\'); + var input = getE(\'inputPackItems\'); + var name = getE(\'namePackItems\'); + var select = getE(\'curPackItemId\'); + var select_quantity = getE(\'curPackItemQty\'); + + var inputCut = input.value.split(reg); + var nameCut = name.value.split(new RegExp(\'¤\', \'g\')); + + input.value = \'\'; + name.value = \'\'; + div.innerHTML = \'\'; + + for (var i = 0; i < inputCut.length; ++i) + if (inputCut[i]) + { + var inputQty = inputCut[i].split(regx); + if (inputQty[1] != id) + { + input.value += inputCut[i] + \'-\'; + name.value += nameCut[i] + \'¤\'; + div.innerHTML += nameCut[i] + \'
    \'; + } + } + + $(\'#curPackItemName\').setOptions({ + extraParams: {excludeIds : getSelectedIds()} + }); + }'; + } + + public function updatePackItems($product) + { + Pack::deleteItems($product->id); + + // lines format: QTY x ID-QTY x ID + if (Tools::getValue('ppack') && $items = Tools::getValue('inputPackItems') && sizeof($lines = array_unique(explode('-', $items)))) + { + foreach ($lines as $line) + { + // line format QTY x ID + list($qty, $item_id) = explode('x', $line); + if ($qty > 0 && isset($item_id)) + { + if (!Pack::addItem((int)($product->id), (int)($item_id), (int)($qty))) + return false; + } + } + } + return true; + } + + public function getL($key) + { + $trad = array( + 'Default category:' => $this->l('Default category:'), + 'Catalog:' => $this->l('Catalog:'), + 'Consider changing the default category.' => $this->l('Consider changing the default category.'), + 'ID' => $this->l('ID'), + 'Name' => $this->l('Name'), + 'Mark all checkbox(es) of categories in which product is to appear' => $this->l('Mark all checkbox(es) of categories in which product is to appear') + ); + return $trad[$key]; + } + + /** + * Load class object using identifier in $_GET (if possible) + * otherwise return an empty object, or die + * + * @param boolean $opt Return an empty object if load fail + * @return object + */ + protected function loadObject($opt = false) + { + if ($id = (int)(Tools::getValue($this->identifier)) AND Validate::isUnsignedId($id)) + { + if (!$this->_object) + $this->_object = new $this->className($id); + if (Validate::isLoadedObject($this->_object)) + return $this->_object; + $this->_errors[] = Tools::displayError('Object cannot be loaded (not found)'); + } + else if ($opt) + { + $this->_object = new $this->className(); + return $this->_object; + } + else + $this->_errors[] = Tools::displayError('Object cannot be loaded (identifier missing or invalid)'); + + $this->displayErrors(); + } + public function displayInitInformationAndAttachment() + { + $this->addJqueryPlugin('thickbox'); + $this->addJqueryPlugin('ajaxfileupload'); + $this->addJqueryPlugin('date'); + } +} diff --git a/css/admin.css b/css/admin.css index 9a14ff70f..7bfe16cc9 100644 --- a/css/admin.css +++ b/css/admin.css @@ -1713,3 +1713,6 @@ div.progressBarImage text-align: center; float: left; } +#menu .submenu_size .submenu { display: none; position:absolute} +#menu .submenu_size:hover > .submenu { display: block; } +.submenu li{float:none;clear:left;}