protected function supplyOrdersImportOne($info, $force_ids, $current_line, $validateOnly = false)
 {
     // sets default values if needed
     AdminImportController::setDefaultValues($info);
     // if an id is set, instanciates a supply order with this id if possible
     if (array_key_exists('id', $info) && (int) $info['id'] && SupplyOrder::exists((int) $info['id'])) {
         $supply_order = new SupplyOrder((int) $info['id']);
     } elseif (array_key_exists('reference', $info) && $info['reference'] && SupplyOrder::exists(pSQL($info['reference']))) {
         $supply_order = SupplyOrder::getSupplyOrderByReference(pSQL($info['reference']));
     } else {
         // new supply order
         $supply_order = new SupplyOrder();
     }
     // gets parameters
     $id_supplier = (int) $info['id_supplier'];
     $id_lang = (int) $info['id_lang'];
     $id_warehouse = (int) $info['id_warehouse'];
     $id_currency = (int) $info['id_currency'];
     $reference = pSQL($info['reference']);
     $date_delivery_expected = pSQL($info['date_delivery_expected']);
     $discount_rate = (double) $info['discount_rate'];
     $is_template = (bool) $info['is_template'];
     $error = '';
     // checks parameters
     if (!Supplier::supplierExists($id_supplier)) {
         $error = sprintf($this->l('Supplier ID (%d) is not valid (at line %d).'), $id_supplier, $current_line + 1);
     }
     if (!Language::getLanguage($id_lang)) {
         $error = sprintf($this->l('Lang ID (%d) is not valid (at line %d).'), $id_lang, $current_line + 1);
     }
     if (!Warehouse::exists($id_warehouse)) {
         $error = sprintf($this->l('Warehouse ID (%d) is not valid (at line %d).'), $id_warehouse, $current_line + 1);
     }
     if (!Currency::getCurrency($id_currency)) {
         $error = sprintf($this->l('Currency ID (%d) is not valid (at line %d).'), $id_currency, $current_line + 1);
     }
     if (empty($supply_order->reference) && SupplyOrder::exists($reference)) {
         $error = sprintf($this->l('Reference (%s) already exists (at line %d).'), $reference, $current_line + 1);
     }
     if (!empty($supply_order->reference) && ($supply_order->reference != $reference && SupplyOrder::exists($reference))) {
         $error = sprintf($this->l('Reference (%s) already exists (at line %d).'), $reference, $current_line + 1);
     }
     if (!Validate::isDateFormat($date_delivery_expected)) {
         $error = sprintf($this->l('Date format (%s) is not valid (at line %d). It should be: %s.'), $date_delivery_expected, $current_line + 1, $this->l('YYYY-MM-DD'));
     } elseif (new DateTime($date_delivery_expected) <= new DateTime('yesterday')) {
         $error = sprintf($this->l('Date (%s) cannot be in the past (at line %d). Format: %s.'), $date_delivery_expected, $current_line + 1, $this->l('YYYY-MM-DD'));
     }
     if ($discount_rate < 0 || $discount_rate > 100) {
         $error = sprintf($this->l('Discount rate (%d) is not valid (at line %d). %s.'), $discount_rate, $current_line + 1, $this->l('Format: Between 0 and 100'));
     }
     if ($supply_order->id > 0 && !$supply_order->isEditable()) {
         $error = sprintf($this->l('Supply Order (%d) is not editable (at line %d).'), $supply_order->id, $current_line + 1);
     }
     // if no errors, sets supply order
     if (empty($error)) {
         // adds parameters
         $info['id_ref_currency'] = (int) Currency::getDefaultCurrency()->id;
         $info['supplier_name'] = pSQL(Supplier::getNameById($id_supplier));
         if ($supply_order->id > 0) {
             $info['id_supply_order_state'] = (int) $supply_order->id_supply_order_state;
             $info['id'] = (int) $supply_order->id;
         } else {
             $info['id_supply_order_state'] = 1;
         }
         // sets parameters
         AdminImportController::arrayWalk($info, array('AdminImportController', 'fillInfo'), $supply_order);
         // updatesd($supply_order);
         $res = false;
         if ((int) $supply_order->id && ($supply_order->exists((int) $supply_order->id) || $supply_order->exists($supply_order->reference))) {
             $res = $validateOnly || $supply_order->update();
         } else {
             $supply_order->force_id = (bool) $force_ids;
             $res = $validateOnly || $supply_order->add();
         }
         // errors
         if (!$res) {
             $this->errors[] = sprintf($this->l('Supply Order could not be saved (at line %d).'), $current_line + 1);
         }
     } else {
         $this->errors[] = $error;
     }
 }
 /**
  * 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.');
             }
         }
     }
 }
 /**
  * AdminController::postProcess() override
  * @see AdminController::postProcess()
  */
 public function postProcess()
 {
     $this->is_editing_order = false;
     // Checks access
     if (Tools::isSubmit('submitAddsupply_order') && !($this->tabAccess['add'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have permission to add a supply order.');
     }
     if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && !($this->tabAccess['edit'] === '1')) {
         $this->errors[] = Tools::displayError('You do not have permission to edit an order.');
     }
     // Trick to use both Supply Order as template and actual orders
     if (Tools::isSubmit('is_template')) {
         $_GET['mod'] = 'template';
     }
     // checks if supply order reference is unique
     if (Tools::isSubmit('reference')) {
         // gets the reference
         $ref = pSQL(Tools::getValue('reference'));
         if (Tools::getValue('id_supply_order') != 0 && SupplyOrder::getReferenceById((int) Tools::getValue('id_supply_order')) != $ref) {
             if ((int) SupplyOrder::exists($ref) != 0) {
                 $this->errors[] = Tools::displayError('The reference has to be unique.');
             }
         } elseif (Tools::getValue('id_supply_order') == 0 && (int) SupplyOrder::exists($ref) != 0) {
             $this->errors[] = Tools::displayError('The reference has to be unique.');
         }
     }
     if ($this->errors) {
         return;
     }
     // Global checks when add / update a supply order
     if (Tools::isSubmit('submitAddsupply_order') || Tools::isSubmit('submitAddsupply_orderAndStay')) {
         $this->action = 'save';
         $this->is_editing_order = true;
         // get supplier ID
         $id_supplier = (int) Tools::getValue('id_supplier', 0);
         if ($id_supplier <= 0 || !Supplier::supplierExists($id_supplier)) {
             $this->errors[] = Tools::displayError('The selected supplier is not valid.');
         }
         // 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 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.');
         }
         // get delivery date
         if (Tools::getValue('mod') != 'template' && strtotime(Tools::getValue('date_delivery_expected')) <= strtotime('-1 day')) {
             $this->errors[] = Tools::displayError('The specified date cannot be in the past.');
         }
         // gets threshold
         $quantity_threshold = Tools::getValue('load_products');
         if (is_numeric($quantity_threshold)) {
             $quantity_threshold = (int) $quantity_threshold;
         } else {
             $quantity_threshold = null;
         }
         if (!count($this->errors)) {
             // forces date for templates
             if (Tools::isSubmit('is_template') && !Tools::getValue('date_delivery_expected')) {
                 $_POST['date_delivery_expected'] = date('Y-m-d h:i:s');
             }
             // specify initial state
             $_POST['id_supply_order_state'] = 1;
             //defaut creation state
             // specify global reference currency
             $_POST['id_ref_currency'] = Currency::getDefaultCurrency()->id;
             // specify supplier name
             $_POST['supplier_name'] = Supplier::getNameById($id_supplier);
             //specific discount check
             $_POST['discount_rate'] = (double) str_replace(array(' ', ','), array('', '.'), Tools::getValue('discount_rate', 0));
         }
         // manage each associated product
         $this->manageOrderProducts();
         // if the threshold is defined and we are saving the order
         if (Tools::isSubmit('submitAddsupply_order') && Validate::isInt($quantity_threshold)) {
             $this->loadProducts((int) $quantity_threshold);
         }
     }
     // Manage state change
     if (Tools::isSubmit('submitChangestate') && Tools::isSubmit('id_supply_order') && Tools::isSubmit('id_supply_order_state')) {
         if ($this->tabAccess['edit'] != '1') {
             $this->errors[] = Tools::displayError('You do not have permission to change the order status.');
         }
         // get state ID
         $id_state = (int) Tools::getValue('id_supply_order_state', 0);
         if ($id_state <= 0) {
             $this->errors[] = Tools::displayError('The selected supply order status is not valid.');
         }
         // get supply order ID
         $id_supply_order = (int) Tools::getValue('id_supply_order', 0);
         if ($id_supply_order <= 0) {
             $this->errors[] = Tools::displayError('The supply order ID is not valid.');
         }
         if (!count($this->errors)) {
             // try to load supply order
             $supply_order = new SupplyOrder($id_supply_order);
             if (Validate::isLoadedObject($supply_order)) {
                 // get valid available possible states for this order
                 $states = SupplyOrderState::getSupplyOrderStates($supply_order->id_supply_order_state);
                 foreach ($states as $state) {
                     // if state is valid, change it in the order
                     if ($id_state == $state['id_supply_order_state']) {
                         $new_state = new SupplyOrderState($id_state);
                         $old_state = new SupplyOrderState($supply_order->id_supply_order_state);
                         // special case of validate state - check if there are products in the order and the required state is not an enclosed state
                         if ($supply_order->isEditable() && !$supply_order->hasEntries() && !$new_state->enclosed) {
                             $this->errors[] = Tools::displayError('It is not possible to change the status of this order because you did not order any products.');
                         }
                         if (!count($this->errors)) {
                             $supply_order->id_supply_order_state = $state['id_supply_order_state'];
                             if ($supply_order->save()) {
                                 if ($new_state->pending_receipt) {
                                     $supply_order_details = $supply_order->getEntries();
                                     foreach ($supply_order_details as $supply_order_detail) {
                                         $is_present = Stock::productIsPresentInStock($supply_order_detail['id_product'], $supply_order_detail['id_product_attribute'], $supply_order->id_warehouse);
                                         if (!$is_present) {
                                             $stock = new Stock();
                                             $stock_params = array('id_product_attribute' => $supply_order_detail['id_product_attribute'], 'id_product' => $supply_order_detail['id_product'], 'physical_quantity' => 0, 'price_te' => $supply_order_detail['price_te'], 'usable_quantity' => 0, 'id_warehouse' => $supply_order->id_warehouse);
                                             // saves stock in warehouse
                                             $stock->hydrate($stock_params);
                                             $stock->add();
                                         }
                                     }
                                 }
                                 // if pending_receipt,
                                 // or if the order is being canceled,
                                 // or if the order is received completely
                                 // synchronizes StockAvailable
                                 if ($new_state->pending_receipt && !$new_state->receipt_state || ($old_state->receipt_state || $old_state->pending_receipt) && $new_state->enclosed && !$new_state->receipt_state || $new_state->receipt_state && $new_state->enclosed) {
                                     $supply_order_details = $supply_order->getEntries();
                                     $products_done = array();
                                     foreach ($supply_order_details as $supply_order_detail) {
                                         if (!in_array($supply_order_detail['id_product'], $products_done)) {
                                             StockAvailable::synchronize($supply_order_detail['id_product']);
                                             $products_done[] = $supply_order_detail['id_product'];
                                         }
                                     }
                                 }
                                 $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
                                 $redirect = self::$currentIndex . '&token=' . $token;
                                 $this->redirect_after = $redirect . '&conf=5';
                             }
                         }
                     }
                 }
             } else {
                 $this->errors[] = Tools::displayError('The selected supplier is not valid.');
             }
         }
     }
     // updates receipt
     if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && Tools::isSubmit('id_supply_order')) {
         $this->postProcessUpdateReceipt();
     }
     // use template to create a supply order
     if (Tools::isSubmit('create_supply_order') && Tools::isSubmit('id_supply_order')) {
         $this->postProcessCopyFromTemplate();
     }
     if (!count($this->errors) && $this->is_editing_order || !$this->is_editing_order) {
         parent::postProcess();
     }
 }
Beispiel #4
0
    /**
     * Sets the new state of the given order
     *
     * @param int $new_order_state
     * @param int/object $id_order
     * @param bool $use_existing_payment
     */
    public function changeIdOrderState($new_order_state, $id_order, $use_existing_payment = false)
    {
        if (!$new_order_state || !$id_order) {
            return;
        }
        if (!is_object($id_order) && is_numeric($id_order)) {
            $order = new Order((int) $id_order);
        } elseif (is_object($id_order)) {
            $order = $id_order;
        } else {
            return;
        }
        ShopUrl::cacheMainDomainForShop($order->id_shop);
        $new_os = new OrderState((int) $new_order_state, $order->id_lang);
        $old_os = $order->getCurrentOrderState();
        $is_validated = $this->isValidated();
        // executes hook
        if (in_array($new_os->id, array(Configuration::get('PS_OS_PAYMENT'), Configuration::get('PS_OS_WS_PAYMENT')))) {
            Hook::exec('actionPaymentConfirmation', array('id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        }
        // executes hook
        Hook::exec('actionOrderStatusUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        if (Validate::isLoadedObject($order) && $new_os instanceof OrderState) {
            // An email is sent the first time a virtual item is validated
            $virtual_products = $order->getVirtualProducts();
            if ($virtual_products && (!$old_os || !$old_os->logable) && $new_os && $new_os->logable) {
                $context = Context::getContext();
                $assign = array();
                foreach ($virtual_products as $key => $virtual_product) {
                    $id_product_download = ProductDownload::getIdFromIdProduct($virtual_product['product_id']);
                    $product_download = new ProductDownload($id_product_download);
                    // If this virtual item has an associated file, we'll provide the link to download the file in the email
                    if ($product_download->display_filename != '') {
                        $assign[$key]['name'] = $product_download->display_filename;
                        $dl_link = $product_download->getTextLink(false, $virtual_product['download_hash']) . '&id_order=' . (int) $order->id . '&secure_key=' . $order->secure_key;
                        $assign[$key]['link'] = $dl_link;
                        if (isset($virtual_product['download_deadline']) && $virtual_product['download_deadline'] != '0000-00-00 00:00:00') {
                            $assign[$key]['deadline'] = Tools::displayDate($virtual_product['download_deadline']);
                        }
                        if ($product_download->nb_downloadable != 0) {
                            $assign[$key]['downloadable'] = (int) $product_download->nb_downloadable;
                        }
                    }
                }
                $customer = new Customer((int) $order->id_customer);
                $links = '<ul>';
                foreach ($assign as $product) {
                    $links .= '<li>';
                    $links .= '<a href="' . $product['link'] . '">' . Tools::htmlentitiesUTF8($product['name']) . '</a>';
                    if (isset($product['deadline'])) {
                        $links .= '&nbsp;' . Tools::htmlentitiesUTF8(Tools::displayError('expires on', false)) . '&nbsp;' . $product['deadline'];
                    }
                    if (isset($product['downloadable'])) {
                        $links .= '&nbsp;' . Tools::htmlentitiesUTF8(sprintf(Tools::displayError('downloadable %d time(s)', false), (int) $product['downloadable']));
                    }
                    $links .= '</li>';
                }
                $links .= '</ul>';
                $data = array('{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{id_order}' => (int) $order->id, '{order_name}' => $order->getUniqReference(), '{nbProducts}' => count($virtual_products), '{virtualProducts}' => $links);
                // If there's at least one downloadable file
                if (!empty($assign)) {
                    Mail::Send((int) $order->id_lang, 'download_product', Mail::l('Virtual product to download', $order->id_lang), $data, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, false, (int) $order->id_shop);
                }
            }
            // @since 1.5.0 : gets the stock manager
            $manager = null;
            if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                $manager = StockManagerFactory::getManager();
            }
            $errorOrCanceledStatuses = array(Configuration::get('PS_OS_ERROR'), Configuration::get('PS_OS_CANCELED'));
            // foreach products of the order
            if (Validate::isLoadedObject($old_os)) {
                foreach ($order->getProductsDetail() as $product) {
                    // if becoming logable => adds sale
                    if ($new_os->logable && !$old_os->logable) {
                        ProductSale::addProductSale($product['product_id'], $product['product_quantity']);
                        // @since 1.5.0 - Stock Management
                        if (!Pack::isPack($product['product_id']) && in_array($old_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'], (int) $order->id_shop)) {
                            StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int) $product['product_quantity'], $order->id_shop);
                        }
                    } elseif (!$new_os->logable && $old_os->logable) {
                        ProductSale::removeProductSale($product['product_id'], $product['product_quantity']);
                        // @since 1.5.0 - Stock Management
                        if (!Pack::isPack($product['product_id']) && in_array($new_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'])) {
                            StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                        }
                    } elseif (!$new_os->logable && !$old_os->logable && in_array($new_os->id, $errorOrCanceledStatuses) && !in_array($old_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'])) {
                        StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                    }
                    // @since 1.5.0 : if the order is being shipped and this products uses the advanced stock management :
                    // decrements the physical stock using $id_warehouse
                    if ($new_os->shipped == 1 && $old_os->shipped == 0 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                        // gets the warehouse
                        $warehouse = new Warehouse($product['id_warehouse']);
                        // decrements the stock (if it's a pack, the StockManager does what is needed)
                        $manager->removeProduct($product['product_id'], $product['product_attribute_id'], $warehouse, $product['product_quantity'], Configuration::get('PS_STOCK_CUSTOMER_ORDER_REASON'), true, (int) $order->id);
                    } elseif ($new_os->shipped == 0 && $old_os->shipped == 1 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                        // if the product is a pack, we restock every products in the pack using the last negative stock mvts
                        if (Pack::isPack($product['product_id'])) {
                            $pack_products = Pack::getItems($product['product_id'], Configuration::get('PS_LANG_DEFAULT', null, null, $order->id_shop));
                            foreach ($pack_products as $pack_product) {
                                if ($pack_product->advanced_stock_management == 1) {
                                    $mvts = StockMvt::getNegativeStockMvts($order->id, $pack_product->id, 0, $pack_product->pack_quantity * $product['product_quantity']);
                                    foreach ($mvts as $mvt) {
                                        $manager->addProduct($pack_product->id, 0, new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                                    }
                                    if (!StockAvailable::dependsOnStock($product['id_product'])) {
                                        StockAvailable::updateQuantity($pack_product->id, 0, (int) $pack_product->pack_quantity * $product['product_quantity'], $order->id_shop);
                                    }
                                }
                            }
                        } else {
                            $mvts = StockMvt::getNegativeStockMvts($order->id, $product['product_id'], $product['product_attribute_id'], $product['product_quantity']);
                            foreach ($mvts as $mvt) {
                                $manager->addProduct($product['product_id'], $product['product_attribute_id'], new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                            }
                        }
                    }
                }
            }
        }
        $this->id_order_state = (int) $new_order_state;
        // changes invoice number of order ?
        if (!Validate::isLoadedObject($new_os) || !Validate::isLoadedObject($order)) {
            die(Tools::displayError('Invalid new order state'));
        }
        // the order is valid if and only if the invoice is available and the order is not cancelled
        $order->current_state = $this->id_order_state;
        $order->valid = $new_os->logable;
        $order->update();
        if ($new_os->invoice && !$order->invoice_number) {
            $order->setInvoice($use_existing_payment);
        }
        // set orders as paid
        if ($new_os->paid == 1) {
            $invoices = $order->getInvoicesCollection();
            if ($order->total_paid != 0) {
                $payment_method = Module::getInstanceByName($order->module);
            }
            foreach ($invoices as $invoice) {
                $rest_paid = $invoice->getRestPaid();
                if ($rest_paid > 0) {
                    $payment = new OrderPayment();
                    $payment->order_reference = $order->reference;
                    $payment->id_currency = $order->id_currency;
                    $payment->amount = $rest_paid;
                    if ($order->total_paid != 0) {
                        $payment->payment_method = $payment_method->displayName;
                    } else {
                        $payment->payment_method = null;
                    }
                    // Update total_paid_real value for backward compatibility reasons
                    if ($payment->id_currency == $order->id_currency) {
                        $order->total_paid_real += $payment->amount;
                    } else {
                        $order->total_paid_real += Tools::ps_round(Tools::convertPrice($payment->amount, $payment->id_currency, false), 2);
                    }
                    $order->save();
                    $payment->conversion_rate = 1;
                    $payment->save();
                    Db::getInstance()->execute('
					INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_payment`
					VALUES(' . (int) $invoice->id . ', ' . (int) $payment->id . ', ' . (int) $order->id . ')');
                }
            }
        }
        // updates delivery date even if it was already set by another state change
        if ($new_os->delivery) {
            $order->setDelivery();
        }
        // executes hook
        Hook::exec('actionOrderStatusPostUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        ShopUrl::resetMainDomainCache();
    }
 /**
  * @since 1.5.0
  */
 public function supplyOrdersImport()
 {
     // opens CSV & sets locale
     $this->receiveTab();
     $handle = $this->openCsvFile();
     AdminImportController::setLocale();
     // main loop, for each supply orders to import
     for ($current_line = 0; $line = fgetcsv($handle, MAX_LINE_SIZE, $this->separator); ++$current_line) {
         // if convert requested
         if (Tools::getValue('convert')) {
             $line = $this->utf8EncodeArray($line);
         }
         $info = AdminImportController::getMaskedRow($line);
         // sets default values if needed
         AdminImportController::setDefaultValues($info);
         // if an id is set, instanciates a supply order with this id if possible
         if (array_key_exists('id', $info) && (int) $info['id'] && SupplyOrder::exists((int) $info['id'])) {
             $supply_order = new SupplyOrder((int) $info['id']);
         } elseif (array_key_exists('reference', $info) && $info['reference'] && SupplyOrder::exists(pSQL($info['reference']))) {
             $supply_order = SupplyOrder::getSupplyOrderByReference(pSQL($info['reference']));
         } else {
             // new supply order
             $supply_order = new SupplyOrder();
         }
         // gets parameters
         $id_supplier = (int) $info['id_supplier'];
         $id_lang = (int) $info['id_lang'];
         $id_warehouse = (int) $info['id_warehouse'];
         $id_currency = (int) $info['id_currency'];
         $reference = pSQL($info['reference']);
         $date_delivery_expected = pSQL($info['date_delivery_expected']);
         $discount_rate = (double) $info['discount_rate'];
         $is_template = (bool) $info['is_template'];
         $error = '';
         // checks parameters
         if (!Supplier::supplierExists($id_supplier)) {
             $error = sprintf($this->l('Supplier ID (%d) is not valid (at line %d).'), $id_supplier, $current_line + 1);
         }
         if (!Language::getLanguage($id_lang)) {
             $error = sprintf($this->l('Lang ID (%d) is not valid (at line %d).'), $id_lang, $current_line + 1);
         }
         if (!Warehouse::exists($id_warehouse)) {
             $error = sprintf($this->l('Warehouse ID (%d) is not valid (at line %d).'), $id_warehouse, $current_line + 1);
         }
         if (!Currency::getCurrency($id_currency)) {
             $error = sprintf($this->l('Currency ID (%d) is not valid (at line %d).'), $id_currency, $current_line + 1);
         }
         if (empty($supply_order->reference) && SupplyOrder::exists($reference)) {
             $error = sprintf($this->l('Reference (%s) already exists (at line %d).'), $reference, $current_line + 1);
         }
         if (!empty($supply_order->reference) && ($supply_order->reference != $reference && SupplyOrder::exists($reference))) {
             $error = sprintf($this->l('Reference (%s) already exists (at line %d).'), $reference, $current_line + 1);
         }
         if (!Validate::isDateFormat($date_delivery_expected)) {
             $error = sprintf($this->l('Date (%s) is not valid (at line %d). Format: %s.'), $date_delivery_expected, $current_line + 1, $this->l('YYYY-MM-DD'));
         } elseif (new DateTime($date_delivery_expected) <= new DateTime('yesterday')) {
             $error = sprintf($this->l('Date (%s) cannot be in the past (at line %d). Format: %s.'), $date_delivery_expected, $current_line + 1, $this->l('YYYY-MM-DD'));
         }
         if ($discount_rate < 0 || $discount_rate > 100) {
             $error = sprintf($this->l('Discount rate (%d) is not valid (at line %d). %s.'), $discount_rate, $current_line + 1, $this->l('Format: Between 0 and 100'));
         }
         if ($supply_order->id > 0 && !$supply_order->isEditable()) {
             $error = sprintf($this->l('Supply Order (%d) is not editable (at line %d).'), $supply_order->id, $current_line + 1);
         }
         // if no errors, sets supply order
         if (empty($error)) {
             // adds parameters
             $info['id_ref_currency'] = (int) Currency::getDefaultCurrency()->id;
             $info['supplier_name'] = pSQL(Supplier::getNameById($id_supplier));
             if ($supply_order->id > 0) {
                 $info['id_supply_order_state'] = (int) $supply_order->id_supply_order_state;
                 $info['id'] = (int) $supply_order->id;
             } else {
                 $info['id_supply_order_state'] = 1;
             }
             // sets parameters
             AdminImportController::arrayWalk($info, array('AdminImportController', 'fillInfo'), $supply_order);
             // updatesd($supply_order);
             $res = true;
             if ((int) $supply_order->id && ($supply_order->exists((int) $supply_order->id) || $supply_order->exists($supply_order->reference))) {
                 $res &= $supply_order->update();
             } else {
                 $supply_order->force_id = (bool) Tools::getValue('forceIDs');
                 $res &= $supply_order->add();
             }
             // errors
             if (!$res) {
                 $this->errors[] = sprintf($this->l('Supply Order could not be saved (at line %d).'), $current_line + 1);
             }
         } else {
             $this->errors[] = $error;
         }
     }
     // closes
     $this->closeCsvFile($handle);
 }
    /**
     * @see StockManagerInterface::removeProduct()
     *
     * @param int           $id_product
     * @param int|null      $id_product_attribute
     * @param Warehouse     $warehouse
     * @param int           $quantity
     * @param int           $id_stock_mvt_reason
     * @param bool          $is_usable
     * @param int|null      $id_order
     * @param int           $ignore_pack
     * @param Employee|null $employee
     *
     * @return array
     * @throws PrestaShopException
     */
    public function removeProduct($id_product, $id_product_attribute = null, Warehouse $warehouse, $quantity, $id_stock_mvt_reason, $is_usable = true, $id_order = null, $ignore_pack = 0, $employee = 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) && !$ignore_pack) {
            if (Validate::isLoadedObject($product = new Product((int) $id_product))) {
                // Gets items
                if ($product->pack_stock_type == 1 || $product->pack_stock_type == 2 || $product->pack_stock_type == 3 && Configuration::get('PS_PACK_STOCK_TYPE') > 0) {
                    $products_pack = Pack::getItems((int) $id_product, (int) Configuration::get('PS_LANG_DEFAULT'));
                    // Foreach item
                    foreach ($products_pack as $product_pack) {
                        if ($product_pack->advanced_stock_management == 1) {
                            $product_warehouses = Warehouse::getProductWarehouseList($product_pack->id, $product_pack->id_pack_product_attribute);
                            $warehouse_stock_found = false;
                            foreach ($product_warehouses as $product_warehouse) {
                                if (!$warehouse_stock_found) {
                                    if (Warehouse::exists($product_warehouse['id_warehouse'])) {
                                        $current_warehouse = new Warehouse($product_warehouse['id_warehouse']);
                                        $return[] = $this->removeProduct($product_pack->id, $product_pack->id_pack_product_attribute, $current_warehouse, $product_pack->pack_quantity * $quantity, $id_stock_mvt_reason, $is_usable, $id_order);
                                        // The product was found on this warehouse. Stop the stock searching.
                                        $warehouse_stock_found = !empty($return[count($return) - 1]);
                                    }
                                }
                            }
                        }
                    }
                }
                if ($product->pack_stock_type == 0 || $product->pack_stock_type == 2 || $product->pack_stock_type == 3 && (Configuration::get('PS_PACK_STOCK_TYPE') == 0 || Configuration::get('PS_PACK_STOCK_TYPE') == 2)) {
                    $return = array_merge($return, $this->removeProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $is_usable, $id_order, 1));
                }
            } else {
                return false;
            }
        } 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':
                    /** @var Stock $stock */
                    // 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' => (int) $context->employee->id ? (int) $context->employee->id : $employee->id, 'employee_firstname' => $context->employee->firstname ? $context->employee->firstname : $employee->firstname, 'employee_lastname' => $context->employee->lastname ? $context->employee->lastname : $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) {
                        /** @var Stock $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['qty'];
                                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' => (int) $context->employee->id ? (int) $context->employee->id : $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 (Pack::isPacked($id_product, $id_product_attribute)) {
                $packs = Pack::getPacksContainingItem($id_product, $id_product_attribute, (int) Configuration::get('PS_LANG_DEFAULT'));
                foreach ($packs as $pack) {
                    // Decrease stocks of the pack only if pack is in linked stock mode (option called 'Decrement both')
                    if (!((int) $pack->pack_stock_type == 2) && !((int) $pack->pack_stock_type == 3 && (int) Configuration::get('PS_PACK_STOCK_TYPE') == 2)) {
                        continue;
                    }
                    // Decrease stocks of the pack only if there is not enough items to constituate the actual pack stocks.
                    // How many packs can be constituated with the remaining product stocks
                    $quantity_by_pack = $pack->pack_item_quantity;
                    $stock_available_quantity = $quantity_in_stock - $quantity;
                    $max_pack_quantity = max(array(0, floor($stock_available_quantity / $quantity_by_pack)));
                    $quantity_delta = Pack::getQuantity($pack->id) - $max_pack_quantity;
                    if ($pack->advanced_stock_management == 1 && $quantity_delta > 0) {
                        $product_warehouses = Warehouse::getPackWarehouses($pack->id);
                        $warehouse_stock_found = false;
                        foreach ($product_warehouses as $product_warehouse) {
                            if (!$warehouse_stock_found) {
                                if (Warehouse::exists($product_warehouse)) {
                                    $current_warehouse = new Warehouse($product_warehouse);
                                    $return[] = $this->removeProduct($pack->id, null, $current_warehouse, $quantity_delta, $id_stock_mvt_reason, $is_usable, $id_order, 1);
                                    // The product was found on this warehouse. Stop the stock searching.
                                    $warehouse_stock_found = !empty($return[count($return) - 1]);
                                }
                            }
                        }
                    }
                }
            }
        }
        // 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;
    }
Beispiel #7
0
    /**
     * Sets the new state of the given order
     *
     * @param int $new_order_state
     * @param int $id_order
     * @param bool $use_existing_payment
     */
    public function changeIdOrderState($new_order_state, &$id_order, $use_existing_payment = false)
    {
        if (!$new_order_state || !$id_order) {
            return;
        }
        if (!is_object($id_order) && is_numeric($id_order)) {
            $order = new Order((int) $id_order);
        } elseif (is_object($id_order)) {
            $order = $id_order;
        } else {
            return;
        }
        $new_os = new OrderState((int) $new_order_state, $order->id_lang);
        $old_os = $order->getCurrentOrderState();
        $is_validated = $this->isValidated();
        // executes hook
        if ($new_os->id == Configuration::get('PS_OS_PAYMENT')) {
            Hook::exec('actionPaymentConfirmation', array('id_order' => (int) $order->id));
        }
        // executes hook
        Hook::exec('actionOrderStatusUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id));
        if (Validate::isLoadedObject($order) && $old_os instanceof OrderState && $new_os instanceof OrderState) {
            // @since 1.5.0 : gets the stock manager
            $manager = null;
            if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                $manager = StockManagerFactory::getManager();
            }
            // foreach products of the order
            foreach ($order->getProductsDetail() as $product) {
                // if becoming logable => adds sale
                if ($new_os->logable && !$old_os->logable) {
                    ProductSale::addProductSale($product['product_id'], $product['product_quantity']);
                    // @since 1.5.0 - Stock Management
                    if (!Pack::isPack($product['product_id']) && ($old_os->id == Configuration::get('PS_OS_ERROR') || $old_os->id == Configuration::get('PS_OS_CANCELED')) && !StockAvailable::dependsOnStock($product['id_product'], (int) $order->id_shop)) {
                        StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int) $product['product_quantity'], $order->id_shop);
                    }
                } elseif (!$new_os->logable && $old_os->logable) {
                    ProductSale::removeProductSale($product['product_id'], $product['product_quantity']);
                    // @since 1.5.0 - Stock Management
                    if (!Pack::isPack($product['product_id']) && ($new_os->id == Configuration::get('PS_OS_ERROR') || $new_os->id == Configuration::get('PS_OS_CANCELED')) && !StockAvailable::dependsOnStock($product['id_product'])) {
                        StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                    }
                } elseif (!$new_os->logable && !$old_os->logable && ($new_os->id == Configuration::get('PS_OS_ERROR') || $new_os->id == Configuration::get('PS_OS_CANCELED')) && !StockAvailable::dependsOnStock($product['id_product'])) {
                    StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                }
                // @since 1.5.0 : if the order is being shipped and this products uses the advanced stock management :
                // decrements the physical stock using $id_warehouse
                if ($new_os->shipped == 1 && $old_os->shipped == 0 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                    // gets the warehouse
                    $warehouse = new Warehouse($product['id_warehouse']);
                    // decrements the stock (if it's a pack, the StockManager does what is needed)
                    $manager->removeProduct($product['product_id'], $product['product_attribute_id'], $warehouse, $product['product_quantity'], Configuration::get('PS_STOCK_CUSTOMER_ORDER_REASON'), true, (int) $order->id);
                } elseif ($new_os->shipped == 0 && $old_os->shipped == 1 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                    // if the product is a pack, we restock every products in the pack using the last negative stock mvts
                    if (Pack::isPack($product['product_id'])) {
                        $pack_products = Pack::getItems($product['product_id'], Configuration::get('PS_LANG_DEFAULT'));
                        foreach ($pack_products as $pack_product) {
                            if ($pack_product->advanced_stock_management == 1) {
                                $mvts = StockMvt::getNegativeStockMvts($order->id, $pack_product->id, 0, $pack_product->pack_quantity * $product['product_quantity']);
                                foreach ($mvts as $mvt) {
                                    $manager->addProduct($pack_product->id, 0, new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                                }
                                if (!StockAvailable::dependsOnStock($product['id_product'])) {
                                    StockAvailable::updateQuantity($pack_product->id, 0, (int) $pack_product->pack_quantity * $product['product_quantity'], $order->id_shop);
                                }
                            }
                        }
                    } else {
                        $mvts = StockMvt::getNegativeStockMvts($order->id, $product['product_id'], $product['product_attribute_id'], $product['product_quantity']);
                        foreach ($mvts as $mvt) {
                            $manager->addProduct($product['product_id'], $product['product_attribute_id'], new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                        }
                    }
                }
            }
        }
        $this->id_order_state = (int) $new_order_state;
        // changes invoice number of order ?
        if (!Validate::isLoadedObject($new_os) || !Validate::isLoadedObject($order)) {
            die(Tools::displayError('Invalid new order state'));
        }
        // the order is valid if and only if the invoice is available and the order is not cancelled
        $order->current_state = $this->id_order_state;
        $order->valid = $new_os->logable;
        $order->update();
        if ($new_os->invoice && !$order->invoice_number) {
            $order->setInvoice($use_existing_payment);
        }
        // set orders as paid
        if ($new_os->paid == 1) {
            $invoices = $order->getInvoicesCollection();
            if ($order->total_paid != 0) {
                $payment_method = Module::getInstanceByName($order->module);
            }
            foreach ($invoices as $invoice) {
                $rest_paid = $invoice->getRestPaid();
                if ($rest_paid > 0) {
                    $payment = new OrderPayment();
                    $payment->order_reference = $order->reference;
                    $payment->id_currency = $order->id_currency;
                    $payment->amount = $rest_paid;
                    if ($order->total_paid != 0) {
                        $payment->payment_method = $payment_method->displayName;
                    } else {
                        $payment->payment_method = null;
                    }
                    // Update total_paid_real value for backward compatibility reasons
                    if ($payment->id_currency == $order->id_currency) {
                        $order->total_paid_real += $payment->amount;
                    } else {
                        $order->total_paid_real += Tools::ps_round(Tools::convertPrice($payment->amount, $payment->id_currency, false), 2);
                    }
                    $order->save();
                    $payment->conversion_rate = 1;
                    $payment->save();
                    Db::getInstance()->execute('
					INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_payment`
					VALUES(' . (int) $invoice->id . ', ' . (int) $payment->id . ', ' . (int) $order->id . ')');
                }
            }
        }
        // updates delivery date even if it was already set by another state change
        if ($new_os->delivery) {
            $order->setDelivery();
        }
        // executes hook
        Hook::exec('actionOrderStatusPostUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id));
    }
    public function attributeImport()
    {
        $default_language = Configuration::get('PS_LANG_DEFAULT');
        $groups = array();
        foreach (AttributeGroup::getAttributesGroups($default_language) as $group) {
            $groups[$group['name']] = (int) $group['id_attribute_group'];
        }
        $attributes = array();
        foreach (Attribute::getAttributes($default_language) as $attribute) {
            $attributes[$attribute['attribute_group'] . '_' . $attribute['name']] = (int) $attribute['id_attribute'];
        }
        $this->receiveTab();
        $handle = $this->openCsvFile();
        AdminImportController::setLocale();
        for ($current_line = 0; $line = fgetcsv($handle, MAX_LINE_SIZE, $this->separator); $current_line++) {
            if (count($line) == 1 && empty($line[0])) {
                continue;
            }
            if (Tools::getValue('convert')) {
                $line = $this->utf8EncodeArray($line);
            }
            $info = AdminImportController::getMaskedRow($line);
            $info = array_map('trim', $info);
            if (self::ignoreRow($info)) {
                continue;
            }
            AdminImportController::setDefaultValues($info);
            if (!Shop::isFeatureActive()) {
                $info['shop'] = 1;
            } elseif (!isset($info['shop']) || empty($info['shop'])) {
                $info['shop'] = implode($this->multiple_value_separator, Shop::getContextListShopID());
            }
            // Get shops for each attributes
            $info['shop'] = explode($this->multiple_value_separator, $info['shop']);
            $id_shop_list = array();
            if (is_array($info['shop']) && count($info['shop'])) {
                foreach ($info['shop'] as $shop) {
                    if (!empty($shop) && !is_numeric($shop)) {
                        $id_shop_list[] = Shop::getIdByName($shop);
                    } elseif (!empty($shop)) {
                        $id_shop_list[] = $shop;
                    }
                }
            }
            if (isset($info['id_product']) && is_string($info['id_product'])) {
                $prod = self::findProductByName($default_language, $info['id_product']);
                if ($prod['id_product']) {
                    $info['id_product'] = $prod['id_product'];
                } else {
                    unset($info['id_product']);
                }
            }
            if (!isset($info['id_product']) && Tools::getValue('match_ref') && isset($info['product_reference']) && $info['product_reference']) {
                $datas = Db::getInstance()->getRow('
					SELECT p.`id_product`
					FROM `' . _DB_PREFIX_ . 'product` p
					' . Shop::addSqlAssociation('product', 'p') . '
					WHERE p.`reference` = "' . pSQL($info['product_reference']) . '"
				');
                if (isset($datas['id_product']) && $datas['id_product']) {
                    $info['id_product'] = $datas['id_product'];
                }
            }
            if (isset($info['id_product'])) {
                $product = new Product((int) $info['id_product'], false, $default_language);
            } else {
                continue;
            }
            $id_image = array();
            //delete existing images if "delete_existing_images" is set to 1
            if (array_key_exists('delete_existing_images', $info) && $info['delete_existing_images'] && !isset($this->cache_image_deleted[(int) $product->id])) {
                $product->deleteImages();
                $this->cache_image_deleted[(int) $product->id] = true;
            }
            if (isset($info['image_url']) && $info['image_url']) {
                $info['image_url'] = explode(',', $info['image_url']);
                if (is_array($info['image_url']) && count($info['image_url'])) {
                    foreach ($info['image_url'] as $url) {
                        $url = trim($url);
                        $product_has_images = (bool) Image::getImages($this->context->language->id, $product->id);
                        $image = new Image();
                        $image->id_product = (int) $product->id;
                        $image->position = Image::getHighestPosition($product->id) + 1;
                        $image->cover = !$product_has_images ? true : false;
                        $field_error = $image->validateFields(UNFRIENDLY_ERROR, true);
                        $lang_field_error = $image->validateFieldsLang(UNFRIENDLY_ERROR, true);
                        if ($field_error === true && $lang_field_error === true && $image->add()) {
                            $image->associateTo($id_shop_list);
                            if (!AdminImportController::copyImg($product->id, $image->id, $url, 'products', !Tools::getValue('regenerate'))) {
                                $this->warnings[] = sprintf(Tools::displayError('Error copying image: %s'), $url);
                                $image->delete();
                            } else {
                                $id_image[] = (int) $image->id;
                            }
                        } else {
                            $this->warnings[] = sprintf(Tools::displayError('%s cannot be saved'), isset($image->id_product) ? ' (' . $image->id_product . ')' : '');
                            $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '') . mysql_error();
                        }
                    }
                }
            } elseif (isset($info['image_position']) && $info['image_position']) {
                $info['image_position'] = explode(',', $info['image_position']);
                if (is_array($info['image_position']) && count($info['image_position'])) {
                    foreach ($info['image_position'] as $position) {
                        // choose images from product by position
                        $images = $product->getImages($default_language);
                        if ($images) {
                            foreach ($images as $row) {
                                if ($row['position'] == (int) $position) {
                                    $id_image[] = (int) $row['id_image'];
                                    break;
                                }
                            }
                        }
                        if (empty($id_image)) {
                            $this->warnings[] = sprintf(Tools::displayError('No image was found for combination with id_product = %s and image position = %s.'), $product->id, (int) $position);
                        }
                    }
                }
            }
            $id_attribute_group = 0;
            // groups
            $groups_attributes = array();
            if (isset($info['group'])) {
                foreach (explode($this->multiple_value_separator, $info['group']) as $key => $group) {
                    if (empty($group)) {
                        continue;
                    }
                    $tab_group = explode(':', $group);
                    $group = trim($tab_group[0]);
                    if (!isset($tab_group[1])) {
                        $type = 'select';
                    } else {
                        $type = trim($tab_group[1]);
                    }
                    // sets group
                    $groups_attributes[$key]['group'] = $group;
                    // if position is filled
                    if (isset($tab_group[2])) {
                        $position = trim($tab_group[2]);
                    } else {
                        $position = false;
                    }
                    if (!isset($groups[$group])) {
                        $obj = new AttributeGroup();
                        $obj->is_color_group = false;
                        $obj->group_type = pSQL($type);
                        $obj->name[$default_language] = $group;
                        $obj->public_name[$default_language] = $group;
                        $obj->position = !$position ? AttributeGroup::getHigherPosition() + 1 : $position;
                        if (($field_error = $obj->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $obj->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true) {
                            $obj->add();
                            $obj->associateTo($id_shop_list);
                            $groups[$group] = $obj->id;
                        } else {
                            $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '');
                        }
                        // fills groups attributes
                        $id_attribute_group = $obj->id;
                        $groups_attributes[$key]['id'] = $id_attribute_group;
                    } else {
                        $id_attribute_group = $groups[$group];
                        $groups_attributes[$key]['id'] = $id_attribute_group;
                    }
                }
            }
            // inits attribute
            $id_product_attribute = 0;
            $id_product_attribute_update = false;
            $attributes_to_add = array();
            // for each attribute
            if (isset($info['attribute'])) {
                foreach (explode($this->multiple_value_separator, $info['attribute']) as $key => $attribute) {
                    if (empty($attribute)) {
                        continue;
                    }
                    $tab_attribute = explode(':', $attribute);
                    $attribute = trim($tab_attribute[0]);
                    // if position is filled
                    if (isset($tab_attribute[1])) {
                        $position = trim($tab_attribute[1]);
                    } else {
                        $position = false;
                    }
                    if (isset($groups_attributes[$key])) {
                        $group = $groups_attributes[$key]['group'];
                        if (!isset($attributes[$group . '_' . $attribute]) && count($groups_attributes[$key]) == 2) {
                            $id_attribute_group = $groups_attributes[$key]['id'];
                            $obj = new Attribute();
                            // sets the proper id (corresponding to the right key)
                            $obj->id_attribute_group = $groups_attributes[$key]['id'];
                            $obj->name[$default_language] = str_replace('\\n', '', str_replace('\\r', '', $attribute));
                            $obj->position = !$position && isset($groups[$group]) ? Attribute::getHigherPosition($groups[$group]) + 1 : $position;
                            if (($field_error = $obj->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $obj->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true) {
                                $obj->add();
                                $obj->associateTo($id_shop_list);
                                $attributes[$group . '_' . $attribute] = $obj->id;
                            } else {
                                $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '');
                            }
                        }
                        $info['minimal_quantity'] = isset($info['minimal_quantity']) && $info['minimal_quantity'] ? (int) $info['minimal_quantity'] : 1;
                        $info['wholesale_price'] = str_replace(',', '.', $info['wholesale_price']);
                        $info['price'] = str_replace(',', '.', $info['price']);
                        $info['ecotax'] = str_replace(',', '.', $info['ecotax']);
                        $info['weight'] = str_replace(',', '.', $info['weight']);
                        $info['available_date'] = Validate::isDate($info['available_date']) ? $info['available_date'] : null;
                        if (!Validate::isEan13($info['ean13'])) {
                            $this->warnings[] = sprintf(Tools::displayError('EAN13 "%1s" has incorrect value for product with id %2d.'), $info['ean13'], $product->id);
                            $info['ean13'] = '';
                        }
                        if ($info['default_on']) {
                            $product->deleteDefaultAttributes();
                        }
                        // if a reference is specified for this product, get the associate id_product_attribute to UPDATE
                        if (isset($info['reference']) && !empty($info['reference'])) {
                            $id_product_attribute = Combination::getIdByReference($product->id, (string) $info['reference']);
                            // updates the attribute
                            if ($id_product_attribute) {
                                // gets all the combinations of this product
                                $attribute_combinations = $product->getAttributeCombinations($default_language);
                                foreach ($attribute_combinations as $attribute_combination) {
                                    if ($id_product_attribute && in_array($id_product_attribute, $attribute_combination)) {
                                        $product->updateAttribute($id_product_attribute, (double) $info['wholesale_price'], (double) $info['price'], (double) $info['weight'], 0, Configuration::get('PS_USE_ECOTAX') ? (double) $info['ecotax'] : 0, $id_image, (string) $info['reference'], (string) $info['ean13'], (int) $info['default_on'], 0, (string) $info['upc'], (int) $info['minimal_quantity'], $info['available_date'], null, $id_shop_list);
                                        $id_product_attribute_update = true;
                                        if (isset($info['supplier_reference']) && !empty($info['supplier_reference'])) {
                                            $product->addSupplierReference($product->id_supplier, $id_product_attribute, $info['supplier_reference']);
                                        }
                                    }
                                }
                            }
                        }
                        // if no attribute reference is specified, creates a new one
                        if (!$id_product_attribute) {
                            $id_product_attribute = $product->addCombinationEntity((double) $info['wholesale_price'], (double) $info['price'], (double) $info['weight'], 0, Configuration::get('PS_USE_ECOTAX') ? (double) $info['ecotax'] : 0, (int) $info['quantity'], $id_image, (string) $info['reference'], 0, (string) $info['ean13'], (int) $info['default_on'], 0, (string) $info['upc'], (int) $info['minimal_quantity'], $id_shop_list, $info['available_date']);
                            if (isset($info['supplier_reference']) && !empty($info['supplier_reference'])) {
                                $product->addSupplierReference($product->id_supplier, $id_product_attribute, $info['supplier_reference']);
                            }
                        }
                        // fills our attributes array, in order to add the attributes to the product_attribute afterwards
                        if (isset($attributes[$group . '_' . $attribute])) {
                            $attributes_to_add[] = (int) $attributes[$group . '_' . $attribute];
                        }
                        // after insertion, we clean attribute position and group attribute position
                        $obj = new Attribute();
                        $obj->cleanPositions((int) $id_attribute_group, false);
                        AttributeGroup::cleanPositions();
                    }
                }
            }
            $product->checkDefaultAttributes();
            if (!$product->cache_default_attribute) {
                Product::updateDefaultAttribute($product->id);
            }
            if ($id_product_attribute) {
                // now adds the attributes in the attribute_combination table
                if ($id_product_attribute_update) {
                    Db::getInstance()->execute('
						DELETE FROM ' . _DB_PREFIX_ . 'product_attribute_combination
						WHERE id_product_attribute = ' . (int) $id_product_attribute);
                }
                foreach ($attributes_to_add as $attribute_to_add) {
                    Db::getInstance()->execute('
						INSERT IGNORE INTO ' . _DB_PREFIX_ . 'product_attribute_combination (id_attribute, id_product_attribute)
						VALUES (' . (int) $attribute_to_add . ',' . (int) $id_product_attribute . ')');
                }
                // set advanced stock managment
                if (isset($info['advanced_stock_management'])) {
                    if ($info['advanced_stock_management'] != 1 && $info['advanced_stock_management'] != 0) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management has incorrect value. Not set for product with id %d.'), $product->id);
                    } elseif (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $info['advanced_stock_management'] == 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management is not enabled, cannot enable on product with id %d.'), $product->id);
                    } else {
                        $product->setAdvancedStockManagement($info['advanced_stock_management']);
                    }
                    // automaticly disable depends on stock, if a_s_m set to disabled
                    if (StockAvailable::dependsOnStock($product->id) == 1 && $info['advanced_stock_management'] == 0) {
                        StockAvailable::setProductDependsOnStock($product->id, 0, null, $id_product_attribute);
                    }
                }
                // Check if warehouse exists
                if (isset($info['warehouse']) && $info['warehouse']) {
                    if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management is not enabled, warehouse is not set on product with id %d.'), $product->id);
                    } else {
                        if (Warehouse::exists($info['warehouse'])) {
                            $warehouse_location_entity = new WarehouseProductLocation();
                            $warehouse_location_entity->id_product = $product->id;
                            $warehouse_location_entity->id_product_attribute = $id_product_attribute;
                            $warehouse_location_entity->id_warehouse = $info['warehouse'];
                            if (WarehouseProductLocation::getProductLocation($product->id, $id_product_attribute, $info['warehouse']) !== false) {
                                $warehouse_location_entity->update();
                            } else {
                                $warehouse_location_entity->save();
                            }
                            StockAvailable::synchronize($product->id);
                        } else {
                            $this->warnings[] = sprintf(Tools::displayError('Warehouse did not exist, cannot set on product %1$s.'), $product->name[$default_language]);
                        }
                    }
                }
                // stock available
                if (isset($info['depends_on_stock'])) {
                    if ($info['depends_on_stock'] != 0 && $info['depends_on_stock'] != 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Incorrect value for depends on stock for product %1$s '), $product->name[$default_language]);
                    } elseif ((!$info['advanced_stock_management'] || $info['advanced_stock_management'] == 0) && $info['depends_on_stock'] == 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management is not enabled, cannot set depends on stock %1$s '), $product->name[$default_language]);
                    } else {
                        StockAvailable::setProductDependsOnStock($product->id, $info['depends_on_stock'], null, $id_product_attribute);
                    }
                    // This code allows us to set qty and disable depends on stock
                    if (isset($info['quantity']) && $info['quantity']) {
                        // if depends on stock and quantity, add quantity to stock
                        if ($info['depends_on_stock'] == 1) {
                            $stock_manager = StockManagerFactory::getManager();
                            $price = str_replace(',', '.', $info['wholesale_price']);
                            if ($price == 0) {
                                $price = 1.0E-6;
                            }
                            $price = round((double) $price, 6);
                            $warehouse = new Warehouse($info['warehouse']);
                            if ($stock_manager->addProduct((int) $product->id, $id_product_attribute, $warehouse, $info['quantity'], 1, $price, true)) {
                                StockAvailable::synchronize((int) $product->id);
                            }
                        } else {
                            if (Shop::isFeatureActive()) {
                                foreach ($id_shop_list as $shop) {
                                    StockAvailable::setQuantity((int) $product->id, $id_product_attribute, $info['quantity'], (int) $shop);
                                }
                            } else {
                                StockAvailable::setQuantity((int) $product->id, $id_product_attribute, $info['quantity'], $this->context->shop->id);
                            }
                        }
                    }
                } else {
                    if (Shop::isFeatureActive()) {
                        foreach ($id_shop_list as $shop) {
                            StockAvailable::setQuantity((int) $product->id, $id_product_attribute, (int) $info['quantity'], (int) $shop);
                        }
                    } else {
                        StockAvailable::setQuantity((int) $product->id, $id_product_attribute, (int) $info['quantity'], $this->context->shop->id);
                    }
                }
            }
        }
        $this->closeCsvFile($handle);
    }
 /**
  * AdminController::postProcess() override
  * @see AdminController::postProcess()
  */
 public function postProcess()
 {
     $this->is_editing_order = false;
     // Checks access
     if (Tools::isSubmit('submitAddsupply_order') && !($this->tabAccess['add'] === '1')) {
         $this->errors[] = Tools::displayError($this->l('You do not have permission to add a supply order.'));
     }
     if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && !($this->tabAccess['edit'] === '1')) {
         $this->errors[] = Tools::displayError($this->l('You do not have permission to edit an order.'));
     }
     // Trick to use both Supply Order as template and actual orders
     if (Tools::isSubmit('is_template')) {
         $_GET['mod'] = 'template';
     }
     // checks if supply order reference is unique
     if (Tools::isSubmit('reference')) {
         // gets the reference
         $ref = pSQL(Tools::getValue('reference'));
         if (Tools::getValue('id_supply_order') != 0 && SupplyOrder::getReferenceById((int) Tools::getValue('id_supply_order')) != $ref) {
             if ((int) SupplyOrder::exists($ref) != 0) {
                 $this->errors[] = Tools::displayError($this->l('The reference has to be unique.'));
             }
         } else {
             if (Tools::getValue('id_supply_order') == 0 && (int) SupplyOrder::exists($ref) != 0) {
                 $this->errors[] = Tools::displayError($this->l('The reference has to be unique.'));
             }
         }
     }
     if ($this->errors) {
         return;
     }
     // Global checks when add / update a supply order
     if (Tools::isSubmit('submitAddsupply_order') || Tools::isSubmit('submitAddsupply_orderAndStay')) {
         $this->action = 'save';
         $this->is_editing_order = true;
         // get supplier ID
         $id_supplier = (int) Tools::getValue('id_supplier', 0);
         if ($id_supplier <= 0 || !Supplier::supplierExists($id_supplier)) {
             $this->errors[] = Tools::displayError($this->l('The selected supplier is not valid.'));
         }
         // get warehouse id
         $id_warehouse = (int) Tools::getValue('id_warehouse', 0);
         if ($id_warehouse <= 0 || !Warehouse::exists($id_warehouse)) {
             $this->errors[] = Tools::displayError($this->l('The selected warehouse is not valid.'));
         }
         // get 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($this->l('The selected currency is not valid.'));
         }
         // get delivery date
         $delivery_expected = new DateTime(pSQL(Tools::getValue('date_delivery_expected')));
         // converts date to timestamp
         if ($delivery_expected <= new DateTime('yesterday')) {
             $this->errors[] = Tools::displayError($this->l('The date you specified cannot be in the past.'));
         }
         // gets threshold
         $quantity_threshold = Tools::getValue('load_products');
         if (is_numeric($quantity_threshold)) {
             $quantity_threshold = (int) $quantity_threshold;
         } else {
             $quantity_threshold = null;
         }
         if (!count($this->errors)) {
             // forces date for templates
             if (Tools::isSubmit('is_template') && !Tools::getValue('date_delivery_expected')) {
                 $_POST['date_delivery_expected'] = date('Y-m-d h:i:s');
             }
             // specify initial state
             $_POST['id_supply_order_state'] = 1;
             //defaut creation state
             // specify global reference currency
             $_POST['id_ref_currency'] = Currency::getDefaultCurrency()->id;
             // specify supplier name
             $_POST['supplier_name'] = Supplier::getNameById($id_supplier);
             //specific discount check
             $_POST['discount_rate'] = (double) str_replace(array(' ', ','), array('', '.'), Tools::getValue('discount_rate', 0));
         }
         // manage each associated product
         $this->manageOrderProducts();
         // if the threshold is defined and we are saving the order
         if (Tools::isSubmit('submitAddsupply_order') && Validate::isInt($quantity_threshold)) {
             $this->loadProducts((int) $quantity_threshold);
         }
         //--ERP informations
         // updates/creates erp_supplier_order if it does not exist
         if (Tools::isSubmit('id_erpip_supply_order') && (int) Tools::getValue('id_erpip_supply_order') > 0) {
             $erp_supplier_order = new ErpSupplyOrder((int) Tools::getValue('id_erpip_supply_order'));
         } else {
             $erp_supplier_order = new ErpSupplyOrder();
         }
         // creates erp_supplier_order
         $erp_supplier_order->escompte = Tools::getValue('escompte', null);
         $erp_supplier_order->global_discount_amount = Tools::getValue('global_discount_type', null);
         $erp_supplier_order->global_discount_type = Tools::getValue('global_discount_type', null);
         $erp_supplier_order->shipping_amount = Tools::getValue('shipping_amount', null);
         $erp_supplier_order->description = Tools::getValue('description', null);
         $validation = $erp_supplier_order->validateController();
         // checks erp_supplier_order validity
         if (count($validation) > 0) {
             foreach ($validation as $item) {
                 $this->errors[] = $item;
             }
             $this->errors[] = Tools::displayError('The ErpIllicopresta Supplier Order is not correct. Please make sure all of the required fields are completed.');
         } else {
             if (Tools::isSubmit('id_erpip_supply_order') && Tools::getValue('id_erpip_supply_order') > 0) {
                 $erp_supplier_order->update();
             } else {
                 $erp_supplier_order->save();
                 $_POST['id_erpip_supply_order'] = $erp_supplier_order->id;
             }
         }
     }
     // Manage state change
     if (Tools::isSubmit('submitChangestate') && Tools::isSubmit('id_supply_order') && Tools::isSubmit('id_supply_order_state')) {
         if ($this->tabAccess['edit'] != '1') {
             $this->errors[] = Tools::displayError($this->l('You do not have permission to change the order status.'));
         }
         // get state ID
         $id_state = (int) Tools::getValue('id_supply_order_state', 0);
         if ($id_state <= 0) {
             $this->errors[] = Tools::displayError($this->l('The selected supply order status is not valid.'));
         }
         // get supply order ID
         $id_supply_order = (int) Tools::getValue('id_supply_order', 0);
         if ($id_supply_order <= 0) {
             $this->errors[] = Tools::displayError($this->l('The supply order ID is not valid.'));
         }
         if (!count($this->errors)) {
             // try to load supply order
             $supply_order = new SupplyOrder($id_supply_order);
             if (Validate::isLoadedObject($supply_order)) {
                 // get valid available possible states for this order
                 $states = SupplyOrderState::getSupplyOrderStates($supply_order->id_supply_order_state);
                 foreach ($states as $state) {
                     // if state is valid, change it in the order
                     if ($id_state == $state['id_supply_order_state']) {
                         $new_state = new SupplyOrderState($id_state);
                         $old_state = new SupplyOrderState($supply_order->id_supply_order_state);
                         // special case of validate state - check if there are products in the order and the required state is not an enclosed state
                         if ($supply_order->isEditable() && !$supply_order->hasEntries() && !$new_state->enclosed) {
                             $this->errors[] = Tools::displayError($this->l('It is not possible to change the status of this order because you did not order any product.'));
                         }
                         if (!count($this->errors)) {
                             // send mail to supplier with supply order
                             if ($this->sendMailOnValidateSupplyOrder($supply_order)) {
                                 $supply_order->id_supply_order_state = $state['id_supply_order_state'];
                                 if ($supply_order->save()) {
                                     //-ERP information
                                     // save erp_supply_order additionale information
                                     // loads current erp_supplier` informationfor this supplier - if possible
                                     $erp_supply_order = null;
                                     if (isset($supply_order->id)) {
                                         $id_erpip_supply_order = ErpSupplyOrder::getErpSupplierOrderIdBySupplierOrderId((int) $supply_order->id);
                                         if ($id_erpip_supply_order > 0) {
                                             $erp_supply_order = new ErpSupplyOrder((int) $id_erpip_supply_order);
                                         } else {
                                             $erp_supply_order = new ErpSupplyOrder();
                                         }
                                     }
                                     if ($erp_supply_order != null) {
                                         if (Tools::isSubmit('date_to_invoice')) {
                                             $erp_supply_order->date_to_invoice = Tools::getValue('date_to_invoice', '000-00-00');
                                         }
                                         if (Tools::isSubmit('invoice_number')) {
                                             $erp_supply_order->invoice_number = Tools::getValue('invoice_number', '');
                                         }
                                         $erp_supply_order->id_supply_order = $supply_order->id;
                                         $erp_supply_order->save();
                                     }
                                     // if pending_receipt,
                                     // or if the order is being canceled,
                                     // synchronizes StockAvailable
                                     if ($new_state->pending_receipt && !$new_state->receipt_state || $old_state->receipt_state && $new_state->enclosed && !$new_state->receipt_state) {
                                         $supply_order_details = $supply_order->getEntries();
                                         $products_done = array();
                                         foreach ($supply_order_details as $supply_order_detail) {
                                             if (!in_array($supply_order_detail['id_product'], $products_done)) {
                                                 StockAvailable::synchronize($supply_order_detail['id_product']);
                                                 $products_done[] = $supply_order_detail['id_product'];
                                             }
                                         }
                                     }
                                     $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
                                     $redirect = self::$currentIndex . '&token=' . $token;
                                     $this->redirect_after = $redirect . '&conf=5';
                                 }
                             }
                         }
                     }
                 }
             } else {
                 $this->errors[] = Tools::displayError($this->l('The selected supplier is not valid.'));
             }
         }
     }
     // get id_supplier
     $id_supply_order = (int) Tools::getValue('id_supply_order', null);
     $supply_order = new SupplyOrder($id_supply_order);
     $erp_supplier_order = new ErpSupplyOrder($id_supply_order);
     $this->context->smarty->assign(array('supplier_id' => $supply_order->id_supplier, 'currency' => new CurrencyCore((int) $supply_order->id_currency), 'random' => rand(99999, 150000), 'template_path' => $this->template_path, 'controller_status' => $this->controller_status, 'supply_order_description' => $erp_supplier_order->description));
     $this->getFilters();
     //-ErpIllicopresta
     // Fixed bug : different variable available according Prestashop version
     //      1.5.4.1 => submitFiltersupply_order_detail
     //      1.5.5.0 => submitFiltersupply_order
     // Add an OR to take into account this two version
     // updates receipt
     if (Tools::isSubmit('submitBulkUpdatesupply_order_detail') && Tools::isSubmit('id_supply_order') && (Tools::isSubmit('submitFiltersupply_order') || Tools::isSubmit('submitFiltersupply_order_detail'))) {
         $this->postProcessUpdateReceipt();
     }
     // use template to create a supply order
     if (Tools::isSubmit('create_supply_order') && Tools::isSubmit('id_supply_order')) {
         $this->postProcessCopyFromTemplate();
     }
     // Export PDF of supply order
     if (Tools::isSubmit('submitAction') && Tools::getValue('submitAction') == 'generateSupplyOrderFormPDF') {
         $this->processGenerateSupplyOrderFormPDF();
     }
     // Export PDF of receiving slip
     if (Tools::isSubmit('submitAction') && Tools::getValue('submitAction') == 'generateSupplyReceivingSlipFormPDF') {
         $this->processGenerateSupplyReceivingSlipFormPDF();
     }
     if (!count($this->errors) && $this->is_editing_order || !$this->is_editing_order) {
         parent::postProcess();
     }
 }
    public function productImport()
    {
        // do standard stuff; need to copy/paste
        // because silly PS does not allow to hook inside of the import loop...
        $this->receiveTab();
        $handle = $this->openCsvFile();
        $default_language_id = (int) Configuration::get('PS_LANG_DEFAULT');
        $id_lang = Language::getIdByIso(Tools::getValue('iso_lang'));
        if (!Validate::isUnsignedId($id_lang)) {
            $id_lang = $default_language_id;
        }
        AdminImportController::setLocale();
        $shop_ids = Shop::getCompleteListOfShopsID();
        for ($current_line = 0; $line = fgetcsv($handle, MAX_LINE_SIZE, $this->separator); $current_line++) {
            if (Tools::getValue('convert')) {
                $line = $this->utf8EncodeArray($line);
            }
            $info = AdminImportController::getMaskedRow($line);
            if (Tools::getValue('forceIDs') && isset($info['id']) && (int) $info['id']) {
                $product = new Product((int) $info['id']);
            } elseif (Tools::getValue('match_ref') && array_key_exists('reference', $info)) {
                $datas = Db::getInstance()->getRow('
					SELECT p.`id_product`
					FROM `' . _DB_PREFIX_ . 'product` p
					' . Shop::addSqlAssociation('product', 'p') . '
					WHERE p.`reference` = "' . pSQL($info['reference']) . '"
				');
                if (isset($datas['id_product']) && $datas['id_product']) {
                    $product = new Product((int) $datas['id_product']);
                } else {
                    $product = new Product();
                }
            } elseif (array_key_exists('id', $info) && (int) $info['id'] && Product::existsInDatabase((int) $info['id'], 'product')) {
                $product = new Product((int) $info['id']);
            } else {
                $product = new Product();
            }
            if (isset($product->id) && $product->id && Product::existsInDatabase((int) $product->id, 'product')) {
                $product->loadStockData();
                $category_data = Product::getProductCategories((int) $product->id);
                if (is_array($category_data)) {
                    foreach ($category_data as $tmp) {
                        if (!isset($product->category) || !$product->category || is_array($product->category)) {
                            $product->category[] = $tmp;
                        }
                    }
                }
            }
            AdminImportController::setEntityDefaultValues($product);
            AdminImportController::arrayWalk($info, array('AdminImportController', 'fillInfo'), $product);
            /*
             * 2015-03-26 - JLE SPECIFIC :
             * Import language specific infos
             */
            foreach ($this->csv_translated_fields as $field) {
                foreach ($this->csv_languages as $lang) {
                    if (isset($info[$field . "_" . $lang])) {
                        $lang_id = Language::getIdByIso($lang);
                        $product->{$field}[$lang_id] = $info[$field . "_" . $lang];
                    }
                }
            }
            /*
             * END SPECIFIC
             */
            if (!Shop::isFeatureActive()) {
                $product->shop = 1;
            } elseif (!isset($product->shop) || empty($product->shop)) {
                $product->shop = implode($this->multiple_value_separator, Shop::getContextListShopID());
            }
            if (!Shop::isFeatureActive()) {
                $product->id_shop_default = 1;
            } else {
                $product->id_shop_default = (int) Context::getContext()->shop->id;
            }
            // link product to shops
            $product->id_shop_list = array();
            foreach (explode($this->multiple_value_separator, $product->shop) as $shop) {
                if (!empty($shop) && !is_numeric($shop)) {
                    $product->id_shop_list[] = Shop::getIdByName($shop);
                } elseif (!empty($shop)) {
                    $product->id_shop_list[] = $shop;
                }
            }
            if ((int) $product->id_tax_rules_group != 0) {
                if (Validate::isLoadedObject(new TaxRulesGroup($product->id_tax_rules_group))) {
                    $address = $this->context->shop->getAddress();
                    $tax_manager = TaxManagerFactory::getManager($address, $product->id_tax_rules_group);
                    $product_tax_calculator = $tax_manager->getTaxCalculator();
                    $product->tax_rate = $product_tax_calculator->getTotalRate();
                } else {
                    $this->addProductWarning('id_tax_rules_group', $product->id_tax_rules_group, Tools::displayError('Invalid tax rule group ID. You first need to create a group with this ID.'));
                }
            }
            if (isset($product->manufacturer) && is_numeric($product->manufacturer) && Manufacturer::manufacturerExists((int) $product->manufacturer)) {
                $product->id_manufacturer = (int) $product->manufacturer;
            } elseif (isset($product->manufacturer) && is_string($product->manufacturer) && !empty($product->manufacturer)) {
                if ($manufacturer = Manufacturer::getIdByName($product->manufacturer)) {
                    $product->id_manufacturer = (int) $manufacturer;
                } else {
                    $manufacturer = new Manufacturer();
                    $manufacturer->name = $product->manufacturer;
                    if (($field_error = $manufacturer->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $manufacturer->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true && $manufacturer->add()) {
                        $product->id_manufacturer = (int) $manufacturer->id;
                    } else {
                        $this->errors[] = sprintf(Tools::displayError('%1$s (ID: %2$s) cannot be saved'), $manufacturer->name, isset($manufacturer->id) && !empty($manufacturer->id) ? $manufacturer->id : 'null');
                        $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '') . Db::getInstance()->getMsgError();
                    }
                }
            }
            if (isset($product->supplier) && is_numeric($product->supplier) && Supplier::supplierExists((int) $product->supplier)) {
                $product->id_supplier = (int) $product->supplier;
            } elseif (isset($product->supplier) && is_string($product->supplier) && !empty($product->supplier)) {
                if ($supplier = Supplier::getIdByName($product->supplier)) {
                    $product->id_supplier = (int) $supplier;
                } else {
                    $supplier = new Supplier();
                    $supplier->name = $product->supplier;
                    $supplier->active = true;
                    if (($field_error = $supplier->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $supplier->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true && $supplier->add()) {
                        $product->id_supplier = (int) $supplier->id;
                        $supplier->associateTo($product->id_shop_list);
                    } else {
                        $this->errors[] = sprintf(Tools::displayError('%1$s (ID: %2$s) cannot be saved'), $supplier->name, isset($supplier->id) && !empty($supplier->id) ? $supplier->id : 'null');
                        $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '') . Db::getInstance()->getMsgError();
                    }
                }
            }
            if (isset($product->price_tex) && !isset($product->price_tin)) {
                $product->price = $product->price_tex;
            } elseif (isset($product->price_tin) && !isset($product->price_tex)) {
                $product->price = $product->price_tin;
                // If a tax is already included in price, withdraw it from price
                if ($product->tax_rate) {
                    $product->price = (double) number_format($product->price / (1 + $product->tax_rate / 100), 6, '.', '');
                }
            } elseif (isset($product->price_tin) && isset($product->price_tex)) {
                $product->price = $product->price_tex;
            }
            if (!Configuration::get('PS_USE_ECOTAX')) {
                $product->ecotax = 0;
            }
            if (isset($product->category) && is_array($product->category) && count($product->category)) {
                $product->id_category = array();
                // Reset default values array
                foreach ($product->category as $value) {
                    if (is_numeric($value)) {
                        if (Category::categoryExists((int) $value)) {
                            $product->id_category[] = (int) $value;
                        } else {
                            $category_to_create = new Category();
                            $category_to_create->id = (int) $value;
                            $category_to_create->name = AdminImportController::createMultiLangField($value);
                            $category_to_create->active = 1;
                            $category_to_create->id_parent = Configuration::get('PS_HOME_CATEGORY');
                            // Default parent is home for unknown category to create
                            $category_link_rewrite = Tools::link_rewrite($category_to_create->name[$default_language_id]);
                            $category_to_create->link_rewrite = AdminImportController::createMultiLangField($category_link_rewrite);
                            if (($field_error = $category_to_create->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $category_to_create->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true && $category_to_create->add()) {
                                $product->id_category[] = (int) $category_to_create->id;
                            } else {
                                $this->errors[] = sprintf(Tools::displayError('%1$s (ID: %2$s) cannot be saved'), $category_to_create->name[$default_language_id], isset($category_to_create->id) && !empty($category_to_create->id) ? $category_to_create->id : 'null');
                                $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '') . Db::getInstance()->getMsgError();
                            }
                        }
                    } elseif (is_string($value) && !empty($value)) {
                        $category = Category::searchByPath($default_language_id, trim($value), $this, 'productImportCreateCat');
                        if ($category['id_category']) {
                            $product->id_category[] = (int) $category['id_category'];
                        } else {
                            $this->errors[] = sprintf(Tools::displayError('%1$s cannot be saved'), trim($value));
                        }
                    }
                }
                $product->id_category = array_values(array_unique($product->id_category));
            }
            if (!isset($product->id_category_default) || !$product->id_category_default) {
                $product->id_category_default = isset($product->id_category[0]) ? (int) $product->id_category[0] : (int) Configuration::get('PS_HOME_CATEGORY');
            }
            $link_rewrite = is_array($product->link_rewrite) && isset($product->link_rewrite[$id_lang]) ? trim($product->link_rewrite[$id_lang]) : '';
            $valid_link = Validate::isLinkRewrite($link_rewrite);
            if (isset($product->link_rewrite[$id_lang]) && empty($product->link_rewrite[$id_lang]) || !$valid_link) {
                $link_rewrite = Tools::link_rewrite($product->name[$id_lang]);
                if ($link_rewrite == '') {
                    $link_rewrite = 'friendly-url-autogeneration-failed';
                }
            }
            if (!$valid_link) {
                $this->warnings[] = sprintf(Tools::displayError('Rewrite link for %1$s (ID: %2$s) was re-written as %3$s.'), $product->name[$id_lang], isset($info['id']) && !empty($info['id']) ? $info['id'] : 'null', $link_rewrite);
            }
            if (!(Tools::getValue('match_ref') || Tools::getValue('forceIDs')) || !(is_array($product->link_rewrite) && count($product->link_rewrite) && !empty($product->link_rewrite[$id_lang]))) {
                $product->link_rewrite = AdminImportController::createMultiLangField($link_rewrite);
            }
            // replace the value of separator by coma
            if ($this->multiple_value_separator != ',') {
                if (is_array($product->meta_keywords)) {
                    foreach ($product->meta_keywords as &$meta_keyword) {
                        if (!empty($meta_keyword)) {
                            $meta_keyword = str_replace($this->multiple_value_separator, ',', $meta_keyword);
                        }
                    }
                }
            }
            // Convert comma into dot for all floating values
            foreach (Product::$definition['fields'] as $key => $array) {
                if ($array['type'] == Product::TYPE_FLOAT) {
                    $product->{$key} = str_replace(',', '.', $product->{$key});
                }
            }
            // Indexation is already 0 if it's a new product, but not if it's an update
            $product->indexed = 0;
            $res = false;
            $field_error = $product->validateFields(UNFRIENDLY_ERROR, true);
            $lang_field_error = $product->validateFieldsLang(UNFRIENDLY_ERROR, true);
            if ($field_error === true && $lang_field_error === true) {
                // check quantity
                if ($product->quantity == null) {
                    $product->quantity = 0;
                }
                // If match ref is specified && ref product && ref product already in base, trying to update
                if (Tools::getValue('match_ref') && $product->reference && $product->existsRefInDatabase($product->reference)) {
                    $datas = Db::getInstance()->getRow('
						SELECT product_shop.`date_add`, p.`id_product`
						FROM `' . _DB_PREFIX_ . 'product` p
						' . Shop::addSqlAssociation('product', 'p') . '
						WHERE p.`reference` = "' . pSQL($product->reference) . '"
					');
                    $product->id = (int) $datas['id_product'];
                    $product->date_add = pSQL($datas['date_add']);
                    $res = $product->update();
                } elseif ($product->id && Product::existsInDatabase((int) $product->id, 'product')) {
                    $datas = Db::getInstance()->getRow('
						SELECT product_shop.`date_add`
						FROM `' . _DB_PREFIX_ . 'product` p
						' . Shop::addSqlAssociation('product', 'p') . '
						WHERE p.`id_product` = ' . (int) $product->id);
                    $product->date_add = pSQL($datas['date_add']);
                    $res = $product->update();
                }
                // If no id_product or update failed
                $product->force_id = (bool) Tools::getValue('forceIDs');
                if (!$res) {
                    if (isset($product->date_add) && $product->date_add != '') {
                        $res = $product->add(false);
                    } else {
                        $res = $product->add();
                    }
                }
                if ($product->getType() == Product::PTYPE_VIRTUAL) {
                    StockAvailable::setProductOutOfStock((int) $product->id, 1);
                } else {
                    StockAvailable::setProductOutOfStock((int) $product->id, (int) $product->out_of_stock);
                }
            }
            $shops = array();
            $product_shop = explode($this->multiple_value_separator, $product->shop);
            foreach ($product_shop as $shop) {
                if (empty($shop)) {
                    continue;
                }
                $shop = trim($shop);
                if (!empty($shop) && !is_numeric($shop)) {
                    $shop = Shop::getIdByName($shop);
                }
                if (in_array($shop, $shop_ids)) {
                    $shops[] = $shop;
                } else {
                    $this->addProductWarning(Tools::safeOutput($info['name']), $product->id, $this->l('Shop is not valid'));
                }
            }
            if (empty($shops)) {
                $shops = Shop::getContextListShopID();
            }
            // If both failed, mysql error
            if (!$res) {
                $this->errors[] = sprintf(Tools::displayError('%1$s (ID: %2$s) cannot be saved'), isset($info['name']) && !empty($info['name']) ? Tools::safeOutput($info['name']) : 'No Name', isset($info['id']) && !empty($info['id']) ? Tools::safeOutput($info['id']) : 'No ID');
                $this->errors[] = ($field_error !== true ? $field_error : '') . (isset($lang_field_error) && $lang_field_error !== true ? $lang_field_error : '') . Db::getInstance()->getMsgError();
            } else {
                // Product supplier
                if (isset($product->id) && $product->id && isset($product->id_supplier) && property_exists($product, 'supplier_reference')) {
                    $id_product_supplier = (int) ProductSupplier::getIdByProductAndSupplier((int) $product->id, 0, (int) $product->id_supplier);
                    if ($id_product_supplier) {
                        $product_supplier = new ProductSupplier($id_product_supplier);
                    } else {
                        $product_supplier = new ProductSupplier();
                    }
                    $product_supplier->id_product = (int) $product->id;
                    $product_supplier->id_product_attribute = 0;
                    $product_supplier->id_supplier = (int) $product->id_supplier;
                    $product_supplier->product_supplier_price_te = $product->wholesale_price;
                    $product_supplier->product_supplier_reference = $product->supplier_reference;
                    $product_supplier->save();
                }
                // SpecificPrice (only the basic reduction feature is supported by the import)
                if (!Shop::isFeatureActive()) {
                    $info['shop'] = 1;
                } elseif (!isset($info['shop']) || empty($info['shop'])) {
                    $info['shop'] = implode($this->multiple_value_separator, Shop::getContextListShopID());
                }
                // Get shops for each attributes
                $info['shop'] = explode($this->multiple_value_separator, $info['shop']);
                $id_shop_list = array();
                foreach ($info['shop'] as $shop) {
                    if (!empty($shop) && !is_numeric($shop)) {
                        $id_shop_list[] = (int) Shop::getIdByName($shop);
                    } elseif (!empty($shop)) {
                        $id_shop_list[] = $shop;
                    }
                }
                if (isset($info['reduction_price']) && $info['reduction_price'] > 0 || isset($info['reduction_percent']) && $info['reduction_percent'] > 0) {
                    foreach ($id_shop_list as $id_shop) {
                        $specific_price = SpecificPrice::getSpecificPrice($product->id, $id_shop, 0, 0, 0, 1, 0, 0, 0, 0);
                        if (is_array($specific_price) && isset($specific_price['id_specific_price'])) {
                            $specific_price = new SpecificPrice((int) $specific_price['id_specific_price']);
                        } else {
                            $specific_price = new SpecificPrice();
                        }
                        $specific_price->id_product = (int) $product->id;
                        $specific_price->id_specific_price_rule = 0;
                        $specific_price->id_shop = $id_shop;
                        $specific_price->id_currency = 0;
                        $specific_price->id_country = 0;
                        $specific_price->id_group = 0;
                        $specific_price->price = -1;
                        $specific_price->id_customer = 0;
                        $specific_price->from_quantity = 1;
                        $specific_price->reduction = isset($info['reduction_price']) && $info['reduction_price'] ? $info['reduction_price'] : $info['reduction_percent'] / 100;
                        $specific_price->reduction_type = isset($info['reduction_price']) && $info['reduction_price'] ? 'amount' : 'percentage';
                        $specific_price->from = isset($info['reduction_from']) && Validate::isDate($info['reduction_from']) ? $info['reduction_from'] : '0000-00-00 00:00:00';
                        $specific_price->to = isset($info['reduction_to']) && Validate::isDate($info['reduction_to']) ? $info['reduction_to'] : '0000-00-00 00:00:00';
                        if (!$specific_price->save()) {
                            $this->addProductWarning(Tools::safeOutput($info['name']), $product->id, $this->l('Discount is invalid'));
                        }
                    }
                }
                /*
                 * 2015-03-26 - JLE SPECIFIC :
                 * Import group specific prices
                 */
                foreach ($this->groups as $group) {
                    if (isset($info['group' . $group['id_group'] . "_price"])) {
                        //	$group_price = str_replace(',', '.', $info['group'.$group['id_group']."_price"]);
                        $group_price = (double) str_replace(',', '.', trim($info['group' . $group['id_group'] . "_price"]));
                        foreach ($id_shop_list as $id_shop) {
                            $specific_price = SpecificPrice::getSpecificPrice($product->id, $id_shop, 0, 0, $group['id_group'], 1, 0, 0, 0, 0);
                            if (is_array($specific_price) && isset($specific_price['id_specific_price'])) {
                                $specific_price = new SpecificPrice((int) $specific_price['id_specific_price']);
                            } else {
                                $specific_price = new SpecificPrice();
                            }
                            $specific_price->id_product = (int) $product->id;
                            $specific_price->id_specific_price_rule = 0;
                            $specific_price->id_shop = $id_shop;
                            $specific_price->id_currency = 0;
                            $specific_price->id_country = 0;
                            $specific_price->id_group = $group['id_group'];
                            $specific_price->price = $group_price;
                            $specific_price->id_customer = 0;
                            $specific_price->from_quantity = 1;
                            $specific_price->reduction = 0;
                            $specific_price->reduction_type = 'amount';
                            $specific_price->from = '0000-00-00 00:00:00';
                            $specific_price->to = '0000-00-00 00:00:00';
                            if (!$specific_price->save()) {
                                $this->addProductWarning(Tools::safeOutput($info['name']), $product->id, $this->l('Discount is invalid'));
                            }
                        }
                    }
                }
                /*
                 * END SPECIFIC 2015-03-26
                 */
                if (isset($product->tags) && !empty($product->tags)) {
                    if (isset($product->id) && $product->id) {
                        $tags = Tag::getProductTags($product->id);
                        if (is_array($tags) && count($tags)) {
                            if (!empty($product->tags)) {
                                $product->tags = explode($this->multiple_value_separator, $product->tags);
                            }
                            if (is_array($product->tags) && count($product->tags)) {
                                foreach ($product->tags as $key => $tag) {
                                    if (!empty($tag)) {
                                        $product->tags[$key] = trim($tag);
                                    }
                                }
                                $tags[$id_lang] = $product->tags;
                                $product->tags = $tags;
                            }
                        }
                    }
                    // Delete tags for this id product, for no duplicating error
                    Tag::deleteTagsForProduct($product->id);
                    if (!is_array($product->tags) && !empty($product->tags)) {
                        $product->tags = AdminImportController::createMultiLangField($product->tags);
                        foreach ($product->tags as $key => $tags) {
                            $is_tag_added = Tag::addTags($key, $product->id, $tags, $this->multiple_value_separator);
                            if (!$is_tag_added) {
                                $this->addProductWarning(Tools::safeOutput($info['name']), $product->id, $this->l('Tags list is invalid'));
                                break;
                            }
                        }
                    } else {
                        foreach ($product->tags as $key => $tags) {
                            $str = '';
                            foreach ($tags as $one_tag) {
                                $str .= $one_tag . $this->multiple_value_separator;
                            }
                            $str = rtrim($str, $this->multiple_value_separator);
                            $is_tag_added = Tag::addTags($key, $product->id, $str, $this->multiple_value_separator);
                            if (!$is_tag_added) {
                                $this->addProductWarning(Tools::safeOutput($info['name']), (int) $product->id, 'Invalid tag(s) (' . $str . ')');
                                break;
                            }
                        }
                    }
                }
                //delete existing images if "delete_existing_images" is set to 1
                if (isset($product->delete_existing_images)) {
                    if ((bool) $product->delete_existing_images) {
                        $product->deleteImages();
                    }
                }
                if (isset($product->image) && is_array($product->image) && count($product->image)) {
                    $product_has_images = (bool) Image::getImages($this->context->language->id, (int) $product->id);
                    foreach ($product->image as $key => $url) {
                        $url = trim($url);
                        $error = false;
                        if (!empty($url)) {
                            $url = str_replace(' ', '%20', $url);
                            $image = new Image();
                            $image->id_product = (int) $product->id;
                            $image->position = Image::getHighestPosition($product->id) + 1;
                            $image->cover = !$key && !$product_has_images ? true : false;
                            // file_exists doesn't work with HTTP protocol
                            if (($field_error = $image->validateFields(UNFRIENDLY_ERROR, true)) === true && ($lang_field_error = $image->validateFieldsLang(UNFRIENDLY_ERROR, true)) === true && $image->add()) {
                                // associate image to selected shops
                                $image->associateTo($shops);
                                if (!AdminImportController::copyImg($product->id, $image->id, $url, 'products', !Tools::getValue('regenerate'))) {
                                    $image->delete();
                                    $this->warnings[] = sprintf(Tools::displayError('Error copying image: %s'), $url);
                                }
                            } else {
                                $error = true;
                            }
                        } else {
                            $error = true;
                        }
                        if ($error) {
                            $this->warnings[] = sprintf(Tools::displayError('Product #%1$d: the picture (%2$s) cannot be saved.'), $image->id_product, $url);
                        }
                    }
                }
                if (isset($product->id_category) && is_array($product->id_category)) {
                    $product->updateCategories(array_map('intval', $product->id_category));
                }
                $product->checkDefaultAttributes();
                if (!$product->cache_default_attribute) {
                    Product::updateDefaultAttribute($product->id);
                }
                // Features import
                $features = get_object_vars($product);
                if (isset($features['features']) && !empty($features['features'])) {
                    foreach (explode($this->multiple_value_separator, $features['features']) as $single_feature) {
                        if (empty($single_feature)) {
                            continue;
                        }
                        $tab_feature = explode(':', $single_feature);
                        $feature_name = isset($tab_feature[0]) ? trim($tab_feature[0]) : '';
                        $feature_value = isset($tab_feature[1]) ? trim($tab_feature[1]) : '';
                        $position = isset($tab_feature[2]) ? (int) $tab_feature[2] - 1 : false;
                        $custom = isset($tab_feature[3]) ? (int) $tab_feature[3] : false;
                        if (!empty($feature_name) && !empty($feature_value)) {
                            $id_feature = (int) Feature::addFeatureImport($feature_name, $position);
                            $id_product = null;
                            if (Tools::getValue('forceIDs') || Tools::getValue('match_ref')) {
                                $id_product = (int) $product->id;
                            }
                            $id_feature_value = (int) FeatureValue::addFeatureValueImport($id_feature, $feature_value, $id_product, $id_lang, $custom);
                            Product::addFeatureProductImport($product->id, $id_feature, $id_feature_value);
                        }
                    }
                }
                // clean feature positions to avoid conflict
                Feature::cleanPositions();
                // set advanced stock managment
                if (isset($product->advanced_stock_management)) {
                    if ($product->advanced_stock_management != 1 && $product->advanced_stock_management != 0) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management has incorrect value. Not set for product %1$s '), $product->name[$default_language_id]);
                    } elseif (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $product->advanced_stock_management == 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management is not enabled, cannot enable on product %1$s '), $product->name[$default_language_id]);
                    } else {
                        $product->setAdvancedStockManagement($product->advanced_stock_management);
                    }
                    // automaticly disable depends on stock, if a_s_m set to disabled
                    if (StockAvailable::dependsOnStock($product->id) == 1 && $product->advanced_stock_management == 0) {
                        StockAvailable::setProductDependsOnStock($product->id, 0);
                    }
                }
                // Check if warehouse exists
                if (isset($product->warehouse) && $product->warehouse) {
                    if (!Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management is not enabled, warehouse not set on product %1$s '), $product->name[$default_language_id]);
                    } else {
                        if (Warehouse::exists($product->warehouse)) {
                            // Get already associated warehouses
                            $associated_warehouses_collection = WarehouseProductLocation::getCollection($product->id);
                            // Delete any entry in warehouse for this product
                            foreach ($associated_warehouses_collection as $awc) {
                                $awc->delete();
                            }
                            $warehouse_location_entity = new WarehouseProductLocation();
                            $warehouse_location_entity->id_product = $product->id;
                            $warehouse_location_entity->id_product_attribute = 0;
                            $warehouse_location_entity->id_warehouse = $product->warehouse;
                            if (WarehouseProductLocation::getProductLocation($product->id, 0, $product->warehouse) !== false) {
                                $warehouse_location_entity->update();
                            } else {
                                $warehouse_location_entity->save();
                            }
                            StockAvailable::synchronize($product->id);
                        } else {
                            $this->warnings[] = sprintf(Tools::displayError('Warehouse did not exist, cannot set on product %1$s.'), $product->name[$default_language_id]);
                        }
                    }
                }
                // stock available
                if (isset($product->depends_on_stock)) {
                    if ($product->depends_on_stock != 0 && $product->depends_on_stock != 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Incorrect value for "depends on stock" for product %1$s '), $product->name[$default_language_id]);
                    } elseif ((!$product->advanced_stock_management || $product->advanced_stock_management == 0) && $product->depends_on_stock == 1) {
                        $this->warnings[] = sprintf(Tools::displayError('Advanced stock management not enabled, cannot set "depends on stock" for product %1$s '), $product->name[$default_language_id]);
                    } else {
                        StockAvailable::setProductDependsOnStock($product->id, $product->depends_on_stock);
                    }
                    // This code allows us to set qty and disable depends on stock
                    if (isset($product->quantity) && (int) $product->quantity) {
                        // if depends on stock and quantity, add quantity to stock
                        if ($product->depends_on_stock == 1) {
                            $stock_manager = StockManagerFactory::getManager();
                            $price = str_replace(',', '.', $product->wholesale_price);
                            if ($price == 0) {
                                $price = 1.0E-6;
                            }
                            $price = round(floatval($price), 6);
                            $warehouse = new Warehouse($product->warehouse);
                            if ($stock_manager->addProduct((int) $product->id, 0, $warehouse, (int) $product->quantity, 1, $price, true)) {
                                StockAvailable::synchronize((int) $product->id);
                            }
                        } else {
                            if (Shop::isFeatureActive()) {
                                foreach ($shops as $shop) {
                                    StockAvailable::setQuantity((int) $product->id, 0, (int) $product->quantity, (int) $shop);
                                }
                            } else {
                                StockAvailable::setQuantity((int) $product->id, 0, (int) $product->quantity, (int) $this->context->shop->id);
                            }
                        }
                    }
                } else {
                    if (Shop::isFeatureActive()) {
                        foreach ($shops as $shop) {
                            StockAvailable::setQuantity((int) $product->id, 0, (int) $product->quantity, (int) $shop);
                        }
                    } else {
                        StockAvailable::setQuantity((int) $product->id, 0, (int) $product->quantity, (int) $this->context->shop->id);
                    }
                }
            }
        }
        $this->closeCsvFile($handle);
    }
 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.');
             }
         }
     }
 }