public function __construct()
 {
     $this->bootstrap = true;
     $this->table = 'stock_mvt_reason';
     $this->className = 'StockMvtReason';
     $this->lang = true;
     $this->multishop_context = Shop::CONTEXT_ALL;
     parent::__construct();
     // defines fields
     $this->fields_list = array('id_stock_mvt_reason' => array('title' => $this->trans('ID', array(), 'Admin.Global'), 'align' => 'center', 'class' => 'fixed-width-xs', 'search' => false), 'sign' => array('title' => $this->l('Action'), 'align' => 'center', 'type' => 'select', 'filter_key' => 'a!sign', 'list' => array('1' => $this->l('Increase'), '-1' => $this->l('Decrease')), 'icon' => array(-1 => 'remove_stock.png', 1 => 'add_stock.png'), 'orderby' => false, 'class' => 'fixed-width-sm', 'search' => false), 'name' => array('title' => $this->trans('Name', array(), 'Admin.Global'), 'filter_key' => 'b!name', 'search' => false));
     // loads labels (incremenation)
     $reasons_inc = StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_TO')), 1);
     // loads labaels (decremenation)
     $reasons_dec = StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_FROM')), -1);
     // defines options for StockMvt
     $this->fields_options = array('general' => array('title' => $this->trans('Options', array(), 'Admin.Global'), 'fields' => array('PS_STOCK_MVT_INC_REASON_DEFAULT' => array('title' => $this->l('Default label for increasing stock'), 'cast' => 'intval', 'type' => 'select', 'list' => $reasons_inc, 'identifier' => 'id_stock_mvt_reason', 'visibility' => Shop::CONTEXT_ALL), 'PS_STOCK_MVT_DEC_REASON_DEFAULT' => array('title' => $this->l('Default label for decreasing stock'), 'cast' => 'intval', 'type' => 'select', 'list' => $reasons_dec, 'identifier' => 'id_stock_mvt_reason', 'visibility' => Shop::CONTEXT_ALL), 'PS_STOCK_CUSTOMER_ORDER_REASON' => array('title' => $this->l('Default label for decreasing stock when a customer order is shipped'), 'cast' => 'intval', 'type' => 'select', 'list' => $reasons_dec, 'identifier' => 'id_stock_mvt_reason', 'visibility' => Shop::CONTEXT_ALL), 'PS_STOCK_MVT_SUPPLY_ORDER' => array('title' => $this->l('Default label for increasing stock when a supply order is received'), 'cast' => 'intval', 'type' => 'select', 'list' => $reasons_inc, 'identifier' => 'id_stock_mvt_reason', 'visibility' => Shop::CONTEXT_ALL)), 'submit' => array('title' => $this->trans('Save', array(), 'Admin.Actions'))));
 }
 /**
  * AdminController::postProcess() override
  * @see AdminController::postProcess()
  */
 public function postProcess()
 {
     parent::postProcess();
     // Checks access
     if (Tools::isSubmit('addStock') && !($this->tabAccess['add'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to add stock.');
     }
     if (Tools::isSubmit('removeStock') && !($this->tabAccess['delete'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to delete stock');
     }
     if (Tools::isSubmit('transferStock') && !($this->tabAccess['edit'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to transfer stock.');
     }
     if (count($this->errors)) {
         return;
     }
     // Global checks when add / remove / transfer product
     if ((Tools::isSubmit('addstock') || Tools::isSubmit('removestock') || Tools::isSubmit('transferstock')) && Tools::isSubmit('is_post')) {
         // get product ID
         $id_product = (int) Tools::getValue('id_product', 0);
         if ($id_product <= 0) {
             $this->errors[] = Tools::displayError('The selected product is not valid.');
         }
         // get product_attribute ID
         $id_product_attribute = (int) Tools::getValue('id_product_attribute', 0);
         // check the product hash
         $check = Tools::getValue('check', '');
         $check_valid = md5(_COOKIE_KEY_ . $id_product . $id_product_attribute);
         if ($check != $check_valid) {
             $this->errors[] = Tools::displayError('The selected product is not valid.');
         }
         // get quantity and check that the post value is really an integer
         // If it's not, we have nothing to do
         $quantity = Tools::getValue('quantity', 0);
         if (!is_numeric($quantity) || (int) $quantity <= 0) {
             $this->errors[] = Tools::displayError('The quantity value is not valid.');
         }
         $quantity = (int) $quantity;
         $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
         $redirect = self::$currentIndex . '&token=' . $token;
     }
     // Global checks when add / remove product
     if ((Tools::isSubmit('addstock') || Tools::isSubmit('removestock')) && Tools::isSubmit('is_post')) {
         // get warehouse id
         $id_warehouse = (int) Tools::getValue('id_warehouse', 0);
         if ($id_warehouse <= 0 || !Warehouse::exists($id_warehouse)) {
             $this->errors[] = Tools::displayError('The selected warehouse is not valid.');
         }
         // get stock movement reason id
         $id_stock_mvt_reason = (int) Tools::getValue('id_stock_mvt_reason', 0);
         if ($id_stock_mvt_reason <= 0 || !StockMvtReason::exists($id_stock_mvt_reason)) {
             $this->errors[] = Tools::displayError('The reason is not valid.');
         }
         // get usable flag
         $usable = Tools::getValue('usable', null);
         if (is_null($usable)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity is usable for sale on shops or not.');
         }
         $usable = (bool) $usable;
     }
     if (Tools::isSubmit('addstock') && Tools::isSubmit('is_post')) {
         // get product unit price
         $price = str_replace(',', '.', Tools::getValue('price', 0));
         if (!is_numeric($price)) {
             $this->errors[] = Tools::displayError('The product price is not valid.');
         }
         $price = round(floatval($price), 6);
         // get product unit price currency id
         $id_currency = (int) Tools::getValue('id_currency', 0);
         if ($id_currency <= 0 || (!($result = Currency::getCurrency($id_currency)) || empty($result))) {
             $this->errors[] = Tools::displayError('The selected currency is not valid.');
         }
         // if all is ok, add stock
         if (count($this->errors) == 0) {
             $warehouse = new Warehouse($id_warehouse);
             // convert price to warehouse currency if needed
             if ($id_currency != $warehouse->id_currency) {
                 // First convert price to the default currency
                 $price_converted_to_default_currency = Tools::convertPrice($price, $id_currency, false);
                 // Convert the new price from default currency to needed currency
                 $price = Tools::convertPrice($price_converted_to_default_currency, $warehouse->id_currency, true);
             }
             // add stock
             $stock_manager = StockManagerFactory::getManager();
             if ($stock_manager->addProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $price, $usable)) {
                 // Create warehouse_product_location entry if we add stock to a new warehouse
                 $id_wpl = (int) WarehouseProductLocation::getIdByProductAndWarehouse($id_product, $id_product_attribute, $id_warehouse);
                 if (!$id_wpl) {
                     $wpl = new WarehouseProductLocation();
                     $wpl->id_product = (int) $id_product;
                     $wpl->id_product_attribute = (int) $id_product_attribute;
                     $wpl->id_warehouse = (int) $id_warehouse;
                     $wpl->save();
                 }
                 StockAvailable::synchronize($id_product);
                 if (Tools::isSubmit('addstockAndStay')) {
                     $redirect = self::$currentIndex . '&id_product=' . (int) $id_product;
                     if ($id_product_attribute) {
                         $redirect .= '&id_product_attribute=' . (int) $id_product_attribute;
                     }
                     $redirect .= '&addstock&token=' . $token;
                 }
                 Tools::redirectAdmin($redirect . '&conf=1');
             } else {
                 $this->errors[] = Tools::displayError('An error occurred. No stock was added.');
             }
         }
     }
     if (Tools::isSubmit('removestock') && Tools::isSubmit('is_post')) {
         // if all is ok, remove stock
         if (count($this->errors) == 0) {
             $warehouse = new Warehouse($id_warehouse);
             // remove stock
             $stock_manager = StockManagerFactory::getManager();
             $removed_products = $stock_manager->removeProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $usable);
             if (count($removed_products) > 0) {
                 StockAvailable::synchronize($id_product);
                 Tools::redirectAdmin($redirect . '&conf=2');
             } else {
                 $physical_quantity_in_stock = (int) $stock_manager->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), false);
                 $usable_quantity_in_stock = (int) $stock_manager->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), true);
                 $not_usable_quantity = $physical_quantity_in_stock - $usable_quantity_in_stock;
                 if ($usable_quantity_in_stock < $quantity) {
                     $this->errors[] = sprintf(Tools::displayError('You don\'t have enough usable quantity. Cannot remove %d items out of %d.'), (int) $quantity, (int) $usable_quantity_in_stock);
                 } elseif ($not_usable_quantity < $quantity) {
                     $this->errors[] = sprintf(Tools::displayError('You don\'t have enough usable quantity. Cannot remove %d items out of %d.'), (int) $quantity, (int) $not_usable_quantity);
                 } else {
                     $this->errors[] = Tools::displayError('It is not possible to remove the specified quantity. Therefore no stock was removed.');
                 }
             }
         }
     }
     if (Tools::isSubmit('transferstock') && Tools::isSubmit('is_post')) {
         // get source warehouse id
         $id_warehouse_from = (int) Tools::getValue('id_warehouse_from', 0);
         if ($id_warehouse_from <= 0 || !Warehouse::exists($id_warehouse_from)) {
             $this->errors[] = Tools::displayError('The source warehouse is not valid.');
         }
         // get destination warehouse id
         $id_warehouse_to = (int) Tools::getValue('id_warehouse_to', 0);
         if ($id_warehouse_to <= 0 || !Warehouse::exists($id_warehouse_to)) {
             $this->errors[] = Tools::displayError('The destination warehouse is not valid.');
         }
         // get usable flag for source warehouse
         $usable_from = Tools::getValue('usable_from', null);
         if (is_null($usable_from)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity in your source warehouse(s) is ready for sale or not.');
         }
         $usable_from = (bool) $usable_from;
         // get usable flag for destination warehouse
         $usable_to = Tools::getValue('usable_to', null);
         if (is_null($usable_to)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity in your destination warehouse(s) is ready for sale or not.');
         }
         $usable_to = (bool) $usable_to;
         // if we can process stock transfers
         if (count($this->errors) == 0) {
             // transfer stock
             $stock_manager = StockManagerFactory::getManager();
             $is_transfer = $stock_manager->transferBetweenWarehouses($id_product, $id_product_attribute, $quantity, $id_warehouse_from, $id_warehouse_to, $usable_from, $usable_to);
             StockAvailable::synchronize($id_product);
             if ($is_transfer) {
                 Tools::redirectAdmin($redirect . '&conf=3');
             } else {
                 $this->errors[] = Tools::displayError('It is not possible to transfer the specified quantity. No stock was transferred.');
             }
         }
     }
 }
Esempio n. 3
0
    /**
     * @see StockManagerInterface::removeProduct()
     */
    public function removeProduct($id_product, $id_product_attribute = null, Warehouse $warehouse, $quantity, $id_stock_mvt_reason, $is_usable = true, $id_order = null)
    {
        $return = array();
        if (!Validate::isLoadedObject($warehouse) || !$quantity || !$id_product) {
            return $return;
        }
        if (!StockMvtReason::exists($id_stock_mvt_reason)) {
            $id_stock_mvt_reason = Configuration::get('PS_STOCK_MVT_DEC_REASON_DEFAULT');
        }
        $context = Context::getContext();
        // Special case of a pack
        if (Pack::isPack((int) $id_product)) {
            // Gets items
            $products_pack = Pack::getItems((int) $id_product, (int) Configuration::get('PS_LANG_DEFAULT'));
            // Foreach item
            foreach ($products_pack as $product_pack) {
                $pack_id_product_attribute = Product::getDefaultAttribute($product_pack->id, 1);
                if ($product_pack->advanced_stock_management == 1) {
                    $this->removeProduct($product_pack->id, $pack_id_product_attribute, $warehouse, $product_pack->pack_quantity * $quantity, $id_stock_mvt_reason, $is_usable, $id_order);
                }
            }
        } else {
            // gets total quantities in stock for the current product
            $physical_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), false);
            $usable_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), true);
            // check quantity if we want to decrement unusable quantity
            if (!$is_usable) {
                $quantity_in_stock = $physical_quantity_in_stock - $usable_quantity_in_stock;
            } else {
                $quantity_in_stock = $usable_quantity_in_stock;
            }
            // checks if it's possible to remove the given quantity
            if ($quantity_in_stock < $quantity) {
                return $return;
            }
            $stock_collection = $this->getStockCollection($id_product, $id_product_attribute, $warehouse->id);
            $stock_collection->getAll();
            // check if the collection is loaded
            if (count($stock_collection) <= 0) {
                return $return;
            }
            $stock_history_qty_available = array();
            $mvt_params = array();
            $stock_params = array();
            $quantity_to_decrement_by_stock = array();
            $global_quantity_to_decrement = $quantity;
            // switch on MANAGEMENT_TYPE
            switch ($warehouse->management_type) {
                // case CUMP mode
                case 'WA':
                    // There is one and only one stock for a given product in a warehouse in this mode
                    $stock = $stock_collection->current();
                    $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $quantity, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'last_wa' => $stock->price_te, 'current_wa' => $stock->price_te, 'id_employee' => $context->employee->id, 'employee_firstname' => $context->employee->firstname, 'employee_lastname' => $context->employee->lastname, 'sign' => -1);
                    $stock_params = array('physical_quantity' => $stock->physical_quantity - $quantity, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $quantity : $stock->usable_quantity);
                    // saves stock in warehouse
                    $stock->hydrate($stock_params);
                    $stock->update();
                    // saves stock mvt
                    $stock_mvt = new StockMvt();
                    $stock_mvt->hydrate($mvt_params);
                    $stock_mvt->save();
                    $return[$stock->id]['quantity'] = $quantity;
                    $return[$stock->id]['price_te'] = $stock->price_te;
                    break;
                case 'LIFO':
                case 'FIFO':
                    // for each stock, parse its mvts history to calculate the quantities left for each positive mvt,
                    // according to the instant available quantities for this stock
                    foreach ($stock_collection as $stock) {
                        $left_quantity_to_check = $stock->physical_quantity;
                        if ($left_quantity_to_check <= 0) {
                            continue;
                        }
                        $resource = Db::getInstance(_PS_USE_SQL_SLAVE_)->query('
							SELECT sm.`id_stock_mvt`, sm.`date_add`, sm.`physical_quantity`,
								IF ((sm2.`physical_quantity` is null), sm.`physical_quantity`, (sm.`physical_quantity` - SUM(sm2.`physical_quantity`))) as qty
							FROM `' . _DB_PREFIX_ . 'stock_mvt` sm
							LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm2 ON sm2.`referer` = sm.`id_stock_mvt`
							WHERE sm.`sign` = 1
							AND sm.`id_stock` = ' . (int) $stock->id . '
							GROUP BY sm.`id_stock_mvt`
							ORDER BY sm.`date_add` DESC');
                        while ($row = Db::getInstance()->nextRow($resource)) {
                            // break - in FIFO mode, we have to retreive the oldest positive mvts for which there are left quantities
                            if ($warehouse->management_type == 'FIFO') {
                                if ($row['qty'] == 0) {
                                    break;
                                }
                            }
                            // converts date to timestamp
                            $date = new DateTime($row['date_add']);
                            $timestamp = $date->format('U');
                            // history of the mvt
                            $stock_history_qty_available[$timestamp] = array('id_stock' => $stock->id, 'id_stock_mvt' => (int) $row['id_stock_mvt'], 'qty' => (int) $row['qty']);
                            // break - in LIFO mode, checks only the necessary history to handle the global quantity for the current stock
                            if ($warehouse->management_type == 'LIFO') {
                                $left_quantity_to_check -= (int) $row['physical_quantity'];
                                if ($left_quantity_to_check <= 0) {
                                    break;
                                }
                            }
                        }
                    }
                    if ($warehouse->management_type == 'LIFO') {
                        // orders stock history by timestamp to get newest history first
                        krsort($stock_history_qty_available);
                    } else {
                        // orders stock history by timestamp to get oldest history first
                        ksort($stock_history_qty_available);
                    }
                    // checks each stock to manage the real quantity to decrement for each of them
                    foreach ($stock_history_qty_available as $entry) {
                        if ($entry['qty'] >= $global_quantity_to_decrement) {
                            $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $global_quantity_to_decrement;
                            $global_quantity_to_decrement = 0;
                        } else {
                            $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $entry['qty'];
                            $global_quantity_to_decrement -= $entry['qty'];
                        }
                        if ($global_quantity_to_decrement <= 0) {
                            break;
                        }
                    }
                    // for each stock, decrements it and logs the mvts
                    foreach ($stock_collection as $stock) {
                        if (array_key_exists($stock->id, $quantity_to_decrement_by_stock) && is_array($quantity_to_decrement_by_stock[$stock->id])) {
                            $total_quantity_for_current_stock = 0;
                            foreach ($quantity_to_decrement_by_stock[$stock->id] as $id_mvt_referrer => $qte) {
                                $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $qte, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'sign' => -1, 'referer' => $id_mvt_referrer, 'id_employee' => $context->employee->id);
                                // saves stock mvt
                                $stock_mvt = new StockMvt();
                                $stock_mvt->hydrate($mvt_params);
                                $stock_mvt->save();
                                $total_quantity_for_current_stock += $qte;
                            }
                            $stock_params = array('physical_quantity' => $stock->physical_quantity - $total_quantity_for_current_stock, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $total_quantity_for_current_stock : $stock->usable_quantity);
                            $return[$stock->id]['quantity'] = $total_quantity_for_current_stock;
                            $return[$stock->id]['price_te'] = $stock->price_te;
                            // saves stock in warehouse
                            $stock->hydrate($stock_params);
                            $stock->update();
                        }
                    }
                    break;
            }
        }
        // if we remove a usable quantity, exec hook
        if ($is_usable) {
            Hook::exec('actionProductCoverage', array('id_product' => $id_product, 'id_product_attribute' => $id_product_attribute, 'warehouse' => $warehouse));
        }
        return $return;
    }
Esempio n. 4
0
 public function initFormAttributes($product)
 {
     $data = $this->createTemplate($this->tpl_form);
     if (!Combination::isFeatureActive()) {
         $this->displayWarning($this->l('This feature has been disabled. ') . ' <a href="index.php?tab=AdminPerformance&token=' . Tools::getAdminTokenLite('AdminPerformance') . '#featuresDetachables">' . $this->l('Performances') . '</a>');
     } else {
         if (Validate::isLoadedObject($product)) {
             if ($this->product_exists_in_shop) {
                 if ($product->is_virtual) {
                     $data->assign('product', $product);
                     $this->displayWarning($this->l('A virtual product cannot have combinations.'));
                 } else {
                     $attribute_js = array();
                     $attributes = Attribute::getAttributes($this->context->language->id, true);
                     foreach ($attributes as $k => $attribute) {
                         $attribute_js[$attribute['id_attribute_group']][$attribute['id_attribute']] = $attribute['name'];
                     }
                     $currency = $this->context->currency;
                     $data->assign('attributeJs', $attribute_js);
                     $data->assign('attributes_groups', AttributeGroup::getAttributesGroups($this->context->language->id));
                     $data->assign('currency', $currency);
                     $images = Image::getImages($this->context->language->id, $product->id);
                     $data->assign('tax_exclude_option', Tax::excludeTaxeOption());
                     $data->assign('ps_weight_unit', Configuration::get('PS_WEIGHT_UNIT'));
                     $data->assign('ps_use_ecotax', Configuration::get('PS_USE_ECOTAX'));
                     $data->assign('field_value_unity', $this->getFieldValue($product, 'unity'));
                     $data->assign('reasons', $reasons = StockMvtReason::getStockMvtReasons($this->context->language->id));
                     $data->assign('ps_stock_mvt_reason_default', $ps_stock_mvt_reason_default = Configuration::get('PS_STOCK_MVT_REASON_DEFAULT'));
                     $data->assign('minimal_quantity', $this->getFieldValue($product, 'minimal_quantity') ? $this->getFieldValue($product, 'minimal_quantity') : 1);
                     $data->assign('available_date', $this->getFieldValue($product, 'available_date') != 0 ? stripslashes(htmlentities($this->getFieldValue($product, 'available_date'), $this->context->language->id)) : '0000-00-00');
                     $i = 0;
                     $type = ImageType::getByNameNType('%', 'products', 'height');
                     if (isset($type['name'])) {
                         $data->assign('imageType', $type['name']);
                     } else {
                         $data->assign('imageType', 'small_default');
                     }
                     $data->assign('imageWidth', (isset($image_type['width']) ? (int) $image_type['width'] : 64) + 25);
                     foreach ($images as $k => $image) {
                         $images[$k]['obj'] = new Image($image['id_image']);
                         ++$i;
                     }
                     $data->assign('images', $images);
                     $data->assign($this->tpl_form_vars);
                     $data->assign(array('list' => $this->renderListAttributes($product, $currency), 'product' => $product, 'id_category' => $product->getDefaultCategory(), 'token_generator' => Tools::getAdminTokenLite('AdminAttributeGenerator'), 'combination_exists' => Shop::isFeatureActive() && Shop::getContextShopGroup()->share_stock && count(AttributeGroup::getAttributesGroups($this->context->language->id)) > 0 && $product->hasAttributes()));
                 }
             } else {
                 $this->displayWarning($this->l('You must save the product in this shop before adding combinations.'));
             }
         } else {
             $data->assign('product', $product);
             $this->displayWarning($this->l('You must save this product before adding combinations.'));
         }
     }
     $this->tpl_form_vars['custom_form'] = $data->fetch();
 }
    function displayFormAttributes($obj, $languages, $defaultLanguage)
    {
        global $currentIndex, $cookie;
        $attributeJs = array();
        $attributes = Attribute::getAttributes((int) $cookie->id_lang, true);
        foreach ($attributes as $k => $attribute) {
            $attributeJs[$attribute['id_attribute_group']][$attribute['id_attribute']] = $attribute['name'];
        }
        $currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT'));
        $attributes_groups = AttributeGroup::getAttributesGroups((int) $cookie->id_lang);
        $default_country = new Country((int) Configuration::get('PS_COUNTRY_DEFAULT'));
        $images = Image::getImages((int) $cookie->id_lang, $obj->id);
        if ($obj->id) {
            echo '
			<script type="text/javascript">
				$(document).ready(function(){
					$(\'#id_mvt_reason\').change(function(){
						updateMvtStatus($(this).val());
					});
					updateMvtStatus($(this).val());
				});
			</script>
			<table cellpadding="5">
				<tr>
					<td colspan="2"><b>' . $this->l('Add or modify combinations for this product') . '</b> -
					&nbsp;<a href="index.php?tab=AdminCatalog&id_product=' . $obj->id . '&id_category=' . (int) Tools::getValue('id_category') . '&attributegenerator&token=' . Tools::getAdminToken('AdminCatalog' . (int) Tab::getIdFromClassName('AdminCatalog') . (int) $cookie->id_employee) . '" onclick="return confirm(\'' . $this->l('Are you sure you want to delete entered product information?', __CLASS__, true, false) . '\');"><img src="../img/admin/appearance.gif" alt="combinations_generator" class="middle" title="' . $this->l('Product combinations generator') . '" />&nbsp;' . $this->l('Product combinations generator') . '</a>
					</td>
				</tr>
			</table>
			<hr style="width:100%;" /><br />
			<table cellpadding="5" style="width:100%">
			<tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" valign="top">' . $this->l('Group:') . '</td>
			  <td style="padding-bottom:5px;"><select name="attribute_group" id="attribute_group" style="width: 200px;" onchange="populate_attrs();">';
            if (isset($attributes_groups)) {
                foreach ($attributes_groups as $k => $attribute_group) {
                    if (isset($attributeJs[$attribute_group['id_attribute_group']])) {
                        echo '
							<option value="' . $attribute_group['id_attribute_group'] . '">
							' . htmlentities(stripslashes($attribute_group['name']), ENT_COMPAT, 'UTF-8') . '&nbsp;&nbsp;</option>';
                    }
                }
            }
            echo '
				</select></td>
		  </tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" valign="top">' . $this->l('Attribute:') . '</td>
			  <td style="padding-bottom:5px;"><select name="attribute" id="attribute" style="width: 200px;">
			  <option value="0">---</option>
			  </select>
			  <script type="text/javascript" language="javascript">populate_attrs();</script>
			  </td>
		  </tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" valign="top">
			  <input style="width: 140px; margin-bottom: 10px;" type="button" value="' . $this->l('Add') . '" class="button" onclick="add_attr();"/><br />
			  <input style="width: 140px;" type="button" value="' . $this->l('Delete') . '" class="button" onclick="del_attr()"/></td>
			  <td align="left">
				  <select id="product_att_list" name="attribute_combinaison_list[]" multiple="multiple" size="4" style="width: 320px;"></select>
				</td>
		  </tr>
		  <tr><td colspan="2"><hr style="width:100%;" /></td></tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Reference:') . '</td>
			  <td style="padding-bottom:5px;">
				<input size="55" type="text" id="attribute_reference" name="attribute_reference" value="" style="width: 130px; margin-right: 44px;" />
				' . $this->l('EAN13:') . '<input size="55" maxlength="13" type="text" id="attribute_ean13" name="attribute_ean13" value="" style="width: 110px; margin-left: 10px; margin-right: 44px;" />
				' . $this->l('UPC:') . '<input size="55" maxlength="12" type="text" id="attribute_upc" name="attribute_upc" value="" style="width: 110px; margin-left: 10px;" />
				<span class="hint" name="help_box">' . $this->l('Special characters allowed:') . ' .-_#<span class="hint-pointer">&nbsp;</span></span>
			  </td>
		  </tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Supplier Reference:') . '</td>
			  <td style="padding-bottom:5px;">
				<input size="55" type="text" id="attribute_supplier_reference" name="attribute_supplier_reference" value="" style="width: 130px; margin-right: 44px;" />
				' . $this->l('Location:') . '<input size="55" type="text" id="attribute_location" name="attribute_location" value="" style="width: 101px; margin-left: 10px;" />
				<span class="hint" name="help_box">' . $this->l('Special characters allowed:') . ' .-_#<span class="hint-pointer">&nbsp;</span></span>
			  </td>
		  </tr>
		  <tr><td colspan="2"><hr style="width:100%;" /></td></tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Wholesale price:') . '</td>
			  <td style="padding-bottom:5px;">' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '<input type="text" size="6"  name="attribute_wholesale_price" id="attribute_wholesale_price" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\');" />' . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '') . ' (' . $this->l('overrides Wholesale price on Information tab') . ')</td>
		  </tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Impact on price:') . '</td>
			  <td colspan="2" style="padding-bottom:5px;">
				<select name="attribute_price_impact" id="attribute_price_impact" style="width: 140px;" onchange="check_impact(); calcImpactPriceTI();">
				  <option value="0">' . $this->l('None') . '</option>
				  <option value="1">' . $this->l('Increase') . '</option>
				  <option value="-1">' . $this->l('Reduction') . '</option>
				</select>
				<span id="span_impact">&nbsp;&nbsp;' . $this->l('of') . '&nbsp;&nbsp;' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '
					<input type="text" size="6" name="attribute_price" id="attribute_price" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\'); calcImpactPriceTI();"/>' . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '');
            if ($default_country->display_tax_label) {
                echo ' ' . $this->l('(tax excl.)') . '<span ' . (Tax::excludeTaxeOption() ? 'style="display:none"' : '') . '> ' . $this->l('or') . ' ' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '
							<input type="text" size="6" name="attribute_priceTI" id="attribute_priceTI" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\'); calcImpactPriceTE();"/>' . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '') . ' ' . $this->l('(tax incl.)') . '</span> ' . $this->l('final product price will be set to') . ' ' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '<span id="attribute_new_total_price">0.00</span>' . ($currency->format % 2 == 0 ? $currency->sign . ' ' : '');
            }
            echo '
				</span>
			</td>
		  </tr>
		  <tr>
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Impact on weight:') . '</td>
			  <td colspan="2" style="padding-bottom:5px;"><select name="attribute_weight_impact" id="attribute_weight_impact" style="width: 140px;" onchange="check_weight_impact();">
			  <option value="0">' . $this->l('None') . '</option>
			  <option value="1">' . $this->l('Increase') . '</option>
			  <option value="-1">' . $this->l('Reduction') . '</option>
			  </select>
			  <span id="span_weight_impact">&nbsp;&nbsp;' . $this->l('of') . '&nbsp;&nbsp;
				<input type="text" size="6" name="attribute_weight" id="attribute_weight" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\');" /> ' . Configuration::get('PS_WEIGHT_UNIT') . '</span></td>
		  </tr>
		  <tr id="tr_unit_impact">
			  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Impact on unit price :') . '</td>
			  <td colspan="2" style="padding-bottom:5px;"><select name="attribute_unit_impact" id="attribute_unit_impact" style="width: 140px;" onchange="check_unit_impact();">
			  <option value="0">' . $this->l('None') . '</option>
			  <option value="1">' . $this->l('Increase') . '</option>
			  <option value="-1">' . $this->l('Reduction') . '</option>
			  </select>
			  <span id="span_unit_impact">&nbsp;&nbsp;' . $this->l('of') . '&nbsp;&nbsp;' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '
				<input type="text" size="6" name="attribute_unity" id="attribute_unity" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\');" />' . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '') . ' / <span id="unity_third">' . $this->getFieldValue($obj, 'unity') . '</span>
			</span></td>
		  </tr>';
            if (Configuration::get('PS_USE_ECOTAX')) {
                echo '
				  <tr>
					  <td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;">' . $this->l('Eco-tax:') . '</td>
					  <td style="padding-bottom:5px;">' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . '<input type="text" size="3" name="attribute_ecotax" id="attribute_ecotax" value="0.00" onKeyUp="if (isArrowKey(event)) return ;this.value = this.value.replace(/,/g, \'.\');" />' . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '') . ' (' . $this->l('overrides Eco-tax on Information tab') . ')</td>
				  </tr>';
            }
            echo '
		  <tr id="initial_stock_attribute">
				<td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" class="col-left">' . $this->l('Initial stock:') . '</td>
				<td><input type="text" name="attribute_quantity" size="3" maxlength="10" value="0"/></td>
		  </tr>
		  </tr>
			<tr id="stock_mvt_attribute" style="display:none;">
				<td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" class="col-left">' . $this->l('Stock movement:') . '</td>
				<td style="padding-bottom:5px;">
					<select id="id_mvt_reason" name="id_mvt_reason">
						<option value="-1">--</option>';
            $reasons = StockMvtReason::getStockMvtReasons((int) $cookie->id_lang);
            foreach ($reasons as $reason) {
                echo '<option rel="' . $reason['sign'] . '" value="' . $reason['id_stock_mvt_reason'] . '" ' . (Configuration::get('PS_STOCK_MVT_REASON_DEFAULT') == $reason['id_stock_mvt_reason'] ? 'selected="selected"' : '') . '>' . $reason['name'] . '</option>';
            }
            echo '</select>
					<input type="text" name="attribute_mvt_quantity" size="3" maxlength="10" value="0"/>&nbsp;&nbsp;
					<span style="display:none;" id="mvt_sign"></span>
					<br />
					<div class="hint clear" style="display: block;width: 70%;">' . $this->l('Choose the reason and enter the quantity that you want to increase or decrease in your stock') . '</div>
				</td>
			</tr>
			<tr>
			<td style="width:150px;vertical-align:top;text-align:right;padding-right:10px;font-weight:bold;" class="col-left">' . $this->l('Minimum quantity:') . '</td>
				<td style="padding-bottom:5px;">
					<input size="3" maxlength="10" name="attribute_minimal_quantity" id="attribute_minimal_quantity" type="text" value="' . ($this->getFieldValue($obj, 'attribute_minimal_quantity') ? $this->getFieldValue($obj, 'attribute_minimal_quantity') : 1) . '" />
					<p>' . $this->l('The minimum quantity to buy this product (set to 1 to disable this feature)') . '</p>
				</td>
			</tr>
		  <tr style="display:none;" id="attr_qty_stock">
			  <td style="width:150px">' . $this->l('Quantity in stock:') . '</td>
			  <td style="padding-bottom:5px;"><b><span style="display:none;" id="attribute_quantity"></span></b></td>
		  </tr>
		  <tr><td colspan="2"><hr style="width:100%;" /></td></tr>
		  <tr>
			  <td style="width:150px">' . $this->l('Image:') . '</td>
			  <td style="padding-bottom:5px;">
				<ul id="id_image_attr">';
            $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']);
                echo '<li style="float: left; width: ' . $imageWidth . 'px;"><input type="checkbox" name="id_image_attr[]" value="' . (int) $image['id_image'] . '" id="id_image_attr_' . (int) $image['id_image'] . '" />
				<label for="id_image_attr_' . (int) $image['id_image'] . '" style="float: none;"><img src="' . _THEME_PROD_DIR_ . $imageObj->getExistingImgPath() . '-small.jpg" alt="' . htmlentities(stripslashes($image['legend']), ENT_COMPAT, 'UTF-8') . '" title="' . htmlentities(stripslashes($image['legend']), ENT_COMPAT, 'UTF-8') . '" /></label></li>';
                ++$i;
            }
            echo '</ul>
				<img id="pic" alt="" title="" style="display: none; width: 100px; height: 100px; float: left; border: 1px dashed #BBB; margin-left: 20px;" />
			  </td>
		  </tr>
			<tr>
			  <td style="width:150px">' . $this->l('Default:') . '<br /><br /></td>
			  <td style="padding-bottom:5px;">
				<input type="checkbox" name="attribute_default" id="attribute_default" value="1" />&nbsp;' . $this->l('Make this the default combination for this product') . '<br /><br />
			  </td>
		  </tr>
		  <tr>
			  <td style="width:150px">&nbsp;</td>
			  <td style="padding-bottom:5px;">
				<span style="float: left;"><input type="submit" name="submitProductAttribute" id="submitProductAttribute" value="' . $this->l('Add this combination') . '" class="button" onclick="attr_selectall(); this.form.action += \'&addproduct&tabs=3\';" /> </span>
				<span id="ResetSpan" style="float: left; margin-left: 8px; display: none;">
				  <input type="reset" name="ResetBtn" id="ResetBtn" onclick="init_elems(); getE(\'submitProductAttribute\').value = \'' . $this->l('Add this attributes group', __CLASS__, true) . '\';
				  getE(\'id_product_attribute\').value = 0; $(\'#ResetSpan\').slideToggle();" class="button" value="' . $this->l('Cancel modification') . '" /></span><span class="clear"></span>
			  </td>
		  </tr>
		  <tr><td colspan="2"><hr style="width:100%;" /></td></tr>
		  <tr>
			  <td colspan="2">
					<br />
					<table border="0" cellpadding="0" cellspacing="0" class="table">
						<tr>
							<th>' . $this->l('Attributes') . '</th>
							<th>' . $this->l('Impact') . '</th>
							<th>' . $this->l('Weight') . '</th>
							<th>' . $this->l('Reference') . '</th>
							<th>' . $this->l('EAN13') . '</th>
							<th>' . $this->l('UPC') . '</th>
							<th class="center">' . $this->l('Quantity') . '</th>
							<th class="center">' . $this->l('Actions') . '</th>
						</tr>';
            if ($obj->id) {
                /* Build attributes combinaisons */
                $combinaisons = $obj->getAttributeCombinaisons((int) $cookie->id_lang);
                $groups = array();
                if (is_array($combinaisons)) {
                    $combinationImages = $obj->getCombinationImages((int) $cookie->id_lang);
                    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']]['attribute_minimal_quantity'] = $combinaison['minimal_quantity'];
                        $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;
                        echo '
						<tr' . ($irow++ % 2 ? ' class="alt_row"' : '') . ($product_attribute['default_on'] ? ' style="background-color:#D1EAEF"' : '') . '>
							<td>' . stripslashes($list) . '</td>
							<td class="right">' . ($currency->format % 2 != 0 ? $currency->sign . ' ' : '') . $product_attribute['price'] . ($currency->format % 2 == 0 ? ' ' . $currency->sign : '') . '</td>
							<td class="right">' . $product_attribute['weight'] . Configuration::get('PS_WEIGHT_UNIT') . '</td>
							<td class="right">' . $product_attribute['reference'] . '</td>
							<td class="right">' . $product_attribute['ean13'] . '</td>
							<td class="right">' . $product_attribute['upc'] . '</td>
							<td class="center">' . $product_attribute['quantity'] . '</td>
							<td class="center">
							<a style="cursor: pointer;">
							<img src="../img/admin/edit.gif" alt="' . $this->l('Modify this combination') . '"
							onclick="javascript:fillCombinaison(\'' . $product_attribute['wholesale_price'] . '\', \'' . $product_attribute['price'] . '\', \'' . $product_attribute['weight'] . '\', \'' . $product_attribute['unit_impact'] . '\', \'' . $product_attribute['reference'] . '\', \'' . $product_attribute['supplier_reference'] . '\', \'' . $product_attribute['ean13'] . '\',
							\'' . $product_attribute['quantity'] . '\', \'' . ($attrImage ? $attrImage->id : 0) . '\', Array(' . $jsList . '), \'' . $id_product_attribute . '\', \'' . $product_attribute['default_on'] . '\', \'' . $product_attribute['ecotax'] . '\', \'' . $product_attribute['location'] . '\', \'' . $product_attribute['upc'] . '\', \'' . $product_attribute['attribute_minimal_quantity'] . '\'); calcImpactPriceTI();" /></a>&nbsp;
							' . (!$product_attribute['default_on'] ? '<a href="' . $currentIndex . '&defaultProductAttribute&id_product_attribute=' . $id_product_attribute . '&id_product=' . $obj->id . '&' . (Tools::isSubmit('id_category') ? 'id_category=' . (int) Tools::getValue('id_category') . '&' : '&') . 'token=' . Tools::getAdminToken('AdminCatalog' . (int) Tab::getIdFromClassName('AdminCatalog') . (int) $cookie->id_employee) . '">
							<img src="../img/admin/asterisk.gif" alt="' . $this->l('Make this the default combination') . '" title="' . $this->l('Make this combination the default one') . '"></a>' : '') . '
							<a href="' . $currentIndex . '&deleteProductAttribute&id_product_attribute=' . $id_product_attribute . '&id_product=' . $obj->id . '&' . (Tools::isSubmit('id_category') ? 'id_category=' . (int) Tools::getValue('id_category') . '&' : '&') . 'token=' . Tools::getAdminToken('AdminCatalog' . (int) Tab::getIdFromClassName('AdminCatalog') . (int) $cookie->id_employee) . '" onclick="return confirm(\'' . $this->l('Are you sure?', __CLASS__, true, false) . '\');">
							<img src="../img/admin/delete.gif" alt="' . $this->l('Delete this combination') . '" /></a></td>
						</tr>';
                    }
                    echo '<tr><td colspan="7" align="center"><a href="' . $currentIndex . '&deleteAllProductAttributes&id_product=' . $obj->id . '&token=' . Tools::getAdminToken('AdminCatalog' . (int) Tab::getIdFromClassName('AdminCatalog') . (int) $cookie->id_employee) . '" onclick="return confirm(\'' . $this->l('Are you sure?', __CLASS__, true, false) . '\');"><img src="../img/admin/delete.gif" alt="' . $this->l('Delete this combination') . '" /> ' . $this->l('Delete all combinations') . '</a></td></tr>';
                } else {
                    echo '<tr><td colspan="7" align="center"><i>' . $this->l('No combination yet') . '.</i></td></tr>';
                }
            }
            echo '
						</table>
						<br />' . $this->l('The row in blue is the default combination.') . '
						<br />
						' . $this->l('A default combination must be designated for each product.') . '
						</td>
						</tr>
					</table>
					<script type="text/javascript">
						var impact = getE(\'attribute_price_impact\');
						var impact2 = getE(\'attribute_weight_impact\');

						var s_attr_group = document.getElementById(\'span_new_group\');
						var s_attr_name = document.getElementById(\'span_new_attr\');
						var s_impact = document.getElementById(\'span_impact\');
						var s_impact2 = document.getElementById(\'span_weight_impact\');

						init_elems();
					</script>
					<hr style="width:100%;" />
					<table cellpadding="5">
						<tr>
							<td class="col-left"><b>' . $this->l('Color picker:') . '</b></td>
							<td style="padding-bottom:5px;">
								<select name="id_color_default">
								<option value="0">' . $this->l('Do not display') . '</option>';
            foreach ($attributes_groups as $k => $attribute_group) {
                if (isset($groups[$attribute_group['id_attribute_group']])) {
                    echo '<option value="' . (int) $attribute_group['id_attribute_group'] . '"
												' . ((int) $attribute_group['id_attribute_group'] == (int) $obj->id_color_default ? 'selected="selected"' : '') . '>' . htmlentities(stripslashes($attribute_group['name']), ENT_COMPAT, 'UTF-8') . '</option>';
                }
            }
            echo '
								</select>
								&nbsp;&nbsp;<input type="submit" value="' . $this->l('OK') . '" name="submitAdd' . $this->table . 'AndStay" class="button" />
								&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.php?tab=AdminAttributesGroups&token=' . Tools::getAdminToken('AdminAttributesGroups' . (int) Tab::getIdFromClassName('AdminAttributesGroups') . (int) $cookie->id_employee) . '" onclick="return confirm(\'' . $this->l('Are you sure you want to delete entered product information?', __CLASS__, true, false) . '\');"><img src="../img/admin/asterisk.gif" alt="" /> ' . $this->l('Color attribute management') . '</a>
								<p >' . $this->l('Activate the color choice by selecting a color attribute group.') . '</p>
							</td>
						</tr>
					</table>';
        } else {
            echo '<b>' . $this->l('You must save this product before adding combinations') . '.</b>';
        }
    }
    public function display()
    {
        global $currentIndex, $cookie;
        $old_post = false;
        if (!isset($_GET['addstock_mvt_reason']) or Tools::isSubmit('submitAddstock_mvt_reason') and Tools::getValue('id_stock_mvt_reason')) {
            if (isset($_POST)) {
                $old_post = $_POST;
            }
            echo '<h2>' . $this->l('Stock movement history') . '</h2>';
            parent::display();
            if (!isset($_GET['view' . $this->table])) {
                echo '
				<fieldset>
					<form method="post" action="' . $currentIndex . '&token=' . $this->token . '&rebuildMvt=1">
						<label for="stock_rebuild">' . $this->l('Calculate the movement of inventory missing') . '</label>
						<div class="margin-form">
							<input class="button" type="submit" name="rebuildStock" value="' . $this->l('Submit') . '" />
						</div>
					</form>
				</fieldset><br />';
            }
        }
        if (isset($_GET['view' . $this->table])) {
            return;
        }
        if ($old_post) {
            $_POST = $old_post;
        }
        $this->table = 'stock_mvt_reason';
        $this->className = 'StockMvtReason';
        $this->identifier = 'id_stock_mvt_reason';
        $this->edit = true;
        $this->delete = true;
        $this->lang = true;
        $this->add = true;
        $this->view = false;
        $this->_listSkipDelete = array(1, 2, 3, 4);
        $this->_defaultOrderBy = $this->identifier;
        $this->fieldsDisplay = array('id_stock_mvt_reason' => array('title' => $this->l('ID'), 'width' => 40), 'sign' => array('title' => $this->l('Sign'), 'width' => 15, 'align' => 'center', 'type' => 'select', 'icon' => array(-1 => 'arrow_down.png', 1 => 'arrow_up.png'), 'orderby' => false), 'name' => array('title' => $this->l('Name'), 'width' => 500));
        $reasons = StockMvtReason::getStockMvtReasons((int) $cookie->id_lang);
        $this->_fieldsOptions = array('PS_STOCK_MVT_REASON_DEFAULT' => array('title' => $this->l('Default Stock Movement reason:'), 'cast' => 'intval', 'type' => 'select', 'list' => $reasons, 'identifier' => 'id_stock_mvt_reason'));
        unset($this->_select, $this->_join, $this->_group, $this->_filterHaving, $this->_filter);
        echo '<h2>' . $this->l('Stock movement reason') . '</h2>';
        $this->postProcess();
        return parent::display();
    }
 public function initContentForCombinations()
 {
     ${${"GLOBALS"}["vmqqtmkyw"]} = $this->object;
     if (!Combination::isFeatureActive()) {
         $this->displayWarning($this->getMessage("This feature has been disabled, you can activate this feature at this page:") . $this->getMessage("link to Performances"));
         return;
     }
     ${"GLOBALS"}["weevwwkl"] = "product";
     if (Validate::isLoadedObject(${${"GLOBALS"}["weevwwkl"]})) {
         self::$smarty->assign("country_display_tax_label", $this->context->country->display_tax_label);
         $zsahvowoo = "lang";
         self::$smarty->assign("tax_exclude_taxe_option", Tax::excludeTaxeOption());
         self::$smarty->assign("id_tax_rules_group", $product->id_tax_rules_group);
         self::$smarty->assign("tax_rules_groups", TaxRulesGroup::getTaxRulesGroups(true));
         ${$zsahvowoo} = new Language($this->id_language);
         self::$smarty->assign("iso_code", $lang->iso_code);
         self::$smarty->assign("combinationImagesJs", $this->getCombinationImagesJs());
         if ($product->is_virtual) {
             $tpkpvyor = "product";
             self::$smarty->assign("product", ${$tpkpvyor});
             $this->displayWarning($this->getMessage("A virtual product cannot have combinations."));
         } else {
             ${"GLOBALS"}["qqjbnscylsi"] = "attribute_js";
             ${"GLOBALS"}["nqxaoftbn"] = "attribute";
             $bcesaxqdqqq = "images";
             ${"GLOBALS"}["zcxmuajd"] = "ps_stock_mvt_reason_default";
             $vmytjghdfi = "attribute_js";
             $nrkrfhirkx = "attributes";
             ${${"GLOBALS"}["qqjbnscylsi"]} = array();
             $cappytc = "k";
             ${"GLOBALS"}["jyaoxpe"] = "attribute";
             ${$nrkrfhirkx} = Attribute::getAttributes($this->context->language->id, true);
             foreach (${${"GLOBALS"}["ecblflvypvt"]} as ${$cappytc} => ${${"GLOBALS"}["jyaoxpe"]}) {
                 ${$vmytjghdfi}[${${"GLOBALS"}["iixdipeiyldv"]}["id_attribute_group"]][${${"GLOBALS"}["iixdipeiyldv"]}["id_attribute"]] = ${${"GLOBALS"}["nqxaoftbn"]}["name"];
             }
             ${"GLOBALS"}["higiwiyuxd"] = "k";
             ${${"GLOBALS"}["sxexnhlq"]} = new Currency((int) Configuration::get("PS_CURRENCY_DEFAULT"));
             self::$smarty->assign("attributeJs", ${${"GLOBALS"}["xenfvrjowsy"]});
             self::$smarty->assign("attributes_groups", AttributeGroup::getAttributesGroups($this->context->language->id));
             self::$smarty->assign("currency", ${${"GLOBALS"}["sxexnhlq"]});
             ${"GLOBALS"}["xzqtsdnlkv"] = "images";
             ${$bcesaxqdqqq} = Image::getImages($this->context->language->id, $product->id);
             self::$smarty->assign("tax_exclude_option", Tax::excludeTaxeOption());
             $rbxbrbxg = "product";
             self::$smarty->assign("ps_weight_unit", Configuration::get("PS_WEIGHT_UNIT"));
             self::$smarty->assign("ps_use_ecotax", Configuration::get("PS_USE_ECOTAX"));
             self::$smarty->assign("field_value_unity", $this->getFieldValue(${${"GLOBALS"}["vmqqtmkyw"]}, "unity"));
             ${"GLOBALS"}["vpcuib"] = "image_type";
             self::$smarty->assign("reasons", ${${"GLOBALS"}["nqegxbae"]} = StockMvtReason::getStockMvtReasons($this->context->language->id));
             self::$smarty->assign("ps_stock_mvt_reason_default", ${${"GLOBALS"}["zcxmuajd"]} = Configuration::get("PS_STOCK_MVT_REASON_DEFAULT"));
             self::$smarty->assign("minimal_quantity", $this->getFieldValue(${${"GLOBALS"}["vmqqtmkyw"]}, "minimal_quantity") ? $this->getFieldValue(${${"GLOBALS"}["vmqqtmkyw"]}, "minimal_quantity") : 1);
             self::$smarty->assign("available_date", $this->getFieldValue(${$rbxbrbxg}, "available_date") != 0 ? stripslashes(htmlentities(Tools::displayDate($this->getFieldValue(${${"GLOBALS"}["vmqqtmkyw"]}, "available_date"), version_compare(_PS_VERSION_, "1.5.5", ">=") ? null : $this->context->language->id))) : "0000-00-00");
             ${${"GLOBALS"}["tqkkuicfgax"]} = 0;
             ${"GLOBALS"}["ucamhp"] = "product";
             self::$smarty->assign("imageType", ImageType::getByNameNType("small_default", "products"));
             self::$smarty->assign("imageWidth", (isset(${${"GLOBALS"}["rvkjjxqs"]}["width"]) ? (int) ${${"GLOBALS"}["vpcuib"]}["width"] : 64) + 25);
             foreach (${${"GLOBALS"}["xzqtsdnlkv"]} as ${${"GLOBALS"}["higiwiyuxd"]} => ${${"GLOBALS"}["inpuwydsyk"]}) {
                 $cshrlmyryz = "image";
                 ${${"GLOBALS"}["dhvuermstcbs"]}[${${"GLOBALS"}["qtxqhylrbsm"]}]["obj"] = new Image(${$cshrlmyryz}["id_image"]);
                 $kcvbkys = "i";
                 ++${$kcvbkys};
             }
             self::$smarty->assign("images", ${${"GLOBALS"}["dhvuermstcbs"]});
             self::$smarty->assign(array("combinationArray" => $this->getCombinations(${${"GLOBALS"}["ucamhp"]}, ${${"GLOBALS"}["sxexnhlq"]}), "product" => ${${"GLOBALS"}["vmqqtmkyw"]}, "id_category" => $product->getDefaultCategory(), "token_generator" => "tokengenerator", "combination_exists" => Shop::isFeatureActive() && Shop::getContextShopGroup()->share_stock && count(AttributeGroup::getAttributesGroups($this->context->language->id)) > 0));
         }
     } else {
         self::$smarty->assign("product", ${${"GLOBALS"}["vmqqtmkyw"]});
         $this->displayWarning($this->getMessage("You must save this product before adding combinations."));
     }
 }
 public function postProcess()
 {
     $this->adminControllerPostProcess();
     if (Tools::isSubmit('addStock') && !($this->tabAccess['add'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to add stock.');
     }
     if (Tools::isSubmit('removeStock') && !($this->tabAccess['delete'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to delete stock');
     }
     if (Tools::isSubmit('transferStock') && !($this->tabAccess['edit'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have the required permission to transfer stock.');
     }
     if (count($this->errors)) {
         return;
     }
     if ((Tools::isSubmit('addstock') || Tools::isSubmit('removestock') || Tools::isSubmit('transferstock')) && Tools::isSubmit('is_post')) {
         $id_product = (int) Tools::getValue('id_product', 0);
         if ($id_product <= 0) {
             $this->errors[] = Tools::displayError('The selected product is not valid.');
         }
         $id_product_attribute = (int) Tools::getValue('id_product_attribute', 0);
         $check = Tools::getValue('check', '');
         $check_valid = md5(_COOKIE_KEY_ . $id_product . $id_product_attribute);
         if ($check != $check_valid) {
             $this->errors[] = Tools::displayError('The selected product is not valid.');
         }
         $quantity = Tools::getValue('quantity', 0);
         $quantity = PP::normalizeProductQty($quantity, $id_product);
         if (!is_numeric($quantity) || $quantity <= 0) {
             $this->errors[] = Tools::displayError('The quantity value is not valid.');
         }
         $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
         $redirect = self::$currentIndex . '&token=' . $token;
     }
     if ((Tools::isSubmit('addstock') || Tools::isSubmit('removestock')) && Tools::isSubmit('is_post')) {
         $id_warehouse = (int) Tools::getValue('id_warehouse', 0);
         if ($id_warehouse <= 0 || !Warehouse::exists($id_warehouse)) {
             $this->errors[] = Tools::displayError('The selected warehouse is not valid.');
         }
         $id_stock_mvt_reason = (int) Tools::getValue('id_stock_mvt_reason', 0);
         if ($id_stock_mvt_reason <= 0 || !StockMvtReason::exists($id_stock_mvt_reason)) {
             $this->errors[] = Tools::displayError('The reason is not valid.');
         }
         $usable = Tools::getValue('usable', null);
         if (is_null($usable)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity is usable for sale on shops or not.');
         }
         $usable = (bool) $usable;
     }
     if (Tools::isSubmit('addstock') && Tools::isSubmit('is_post')) {
         $price = str_replace(',', '.', Tools::getValue('price', 0));
         if (!is_numeric($price)) {
             $this->errors[] = Tools::displayError('The product price is not valid.');
         }
         $price = round((double) $price, 6);
         $id_currency = (int) Tools::getValue('id_currency', 0);
         if ($id_currency <= 0 || (!($result = Currency::getCurrency($id_currency)) || empty($result))) {
             $this->errors[] = Tools::displayError('The selected currency is not valid.');
         }
         if (count($this->errors) == 0) {
             $warehouse = new Warehouse($id_warehouse);
             if ($id_currency != $warehouse->id_currency) {
                 $price_converted_to_default_currency = Tools::convertPrice($price, $id_currency, false);
                 $price = Tools::convertPrice($price_converted_to_default_currency, $warehouse->id_currency, true);
             }
             $stock_manager = StockManagerFactory::getManager();
             if ($stock_manager->addProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $price, $usable)) {
                 $id_wpl = (int) WarehouseProductLocation::getIdByProductAndWarehouse($id_product, $id_product_attribute, $id_warehouse);
                 if (!$id_wpl) {
                     $wpl = new WarehouseProductLocation();
                     $wpl->id_product = (int) $id_product;
                     $wpl->id_product_attribute = (int) $id_product_attribute;
                     $wpl->id_warehouse = (int) $id_warehouse;
                     $wpl->save();
                 }
                 StockAvailable::synchronize($id_product);
                 if (Tools::isSubmit('addstockAndStay')) {
                     $redirect = self::$currentIndex . '&id_product=' . (int) $id_product;
                     if ($id_product_attribute) {
                         $redirect .= '&id_product_attribute=' . (int) $id_product_attribute;
                     }
                     $redirect .= '&addstock&token=' . $token;
                 }
                 Tools::redirectAdmin($redirect . '&conf=1');
             } else {
                 $this->errors[] = Tools::displayError('An error occurred. No stock was added.');
             }
         }
     }
     if (Tools::isSubmit('removestock') && Tools::isSubmit('is_post')) {
         if (count($this->errors) == 0) {
             $warehouse = new Warehouse($id_warehouse);
             $stock_manager = StockManagerFactory::getManager();
             $removed_products = $stock_manager->removeProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $usable);
             if (count($removed_products) > 0) {
                 StockAvailable::synchronize($id_product);
                 Tools::redirectAdmin($redirect . '&conf=2');
             } else {
                 $physical_quantity_in_stock = (int) $stock_manager->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), false);
                 $usable_quantity_in_stock = (int) $stock_manager->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), true);
                 $not_usable_quantity = $physical_quantity_in_stock - $usable_quantity_in_stock;
                 if ($usable_quantity_in_stock < $quantity) {
                     $this->errors[] = sprintf(Tools::displayError('You don\'t have enough usable quantity. Cannot remove %d items out of %d.'), (int) $quantity, (int) $usable_quantity_in_stock);
                 } elseif ($not_usable_quantity < $quantity) {
                     $this->errors[] = sprintf(Tools::displayError('You don\'t have enough usable quantity. Cannot remove %d items out of %d.'), (int) $quantity, (int) $not_usable_quantity);
                 } else {
                     $this->errors[] = Tools::displayError('It is not possible to remove the specified quantity. Therefore no stock was removed.');
                 }
             }
         }
     }
     if (Tools::isSubmit('transferstock') && Tools::isSubmit('is_post')) {
         $id_warehouse_from = (int) Tools::getValue('id_warehouse_from', 0);
         if ($id_warehouse_from <= 0 || !Warehouse::exists($id_warehouse_from)) {
             $this->errors[] = Tools::displayError('The source warehouse is not valid.');
         }
         $id_warehouse_to = (int) Tools::getValue('id_warehouse_to', 0);
         if ($id_warehouse_to <= 0 || !Warehouse::exists($id_warehouse_to)) {
             $this->errors[] = Tools::displayError('The destination warehouse is not valid.');
         }
         $usable_from = Tools::getValue('usable_from', null);
         if (is_null($usable_from)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity in your source warehouse(s) is ready for sale or not.');
         }
         $usable_from = (bool) $usable_from;
         $usable_to = Tools::getValue('usable_to', null);
         if (is_null($usable_to)) {
             $this->errors[] = Tools::displayError('You have to specify whether the product quantity in your destination warehouse(s) is ready for sale or not.');
         }
         $usable_to = (bool) $usable_to;
         if (count($this->errors) == 0) {
             $stock_manager = StockManagerFactory::getManager();
             $is_transfer = $stock_manager->transferBetweenWarehouses($id_product, $id_product_attribute, $quantity, $id_warehouse_from, $id_warehouse_to, $usable_from, $usable_to);
             StockAvailable::synchronize($id_product);
             if ($is_transfer) {
                 Tools::redirectAdmin($redirect . '&conf=3');
             } else {
                 $this->errors[] = Tools::displayError('It is not possible to transfer the specified quantity. No stock was transferred.');
             }
         }
     }
 }