public function postProcess()
 {
     global $cookie;
     if (Tools::isSubmit('rebuildStock')) {
         StockMvt::addMissingMvt((int) $cookie->id_employee, false);
     }
     return parent::postProcess();
 }
Esempio n. 2
0
 protected function reinjectQuantity($order_detail, $qty_cancel_product)
 {
     // Reinject product
     $reinjectable_quantity = (int) $order_detail->product_quantity - (int) $order_detail->product_quantity_reinjected;
     $quantity_to_reinject = $qty_cancel_product > $reinjectable_quantity ? $reinjectable_quantity : $qty_cancel_product;
     // @since 1.5.0 : Advanced Stock Management
     $product_to_inject = new Product($order_detail->product_id, false, (int) $this->context->language->id, (int) $order_detail->id_shop);
     $product = new Product($order_detail->product_id, false, (int) $this->context->language->id, (int) $order_detail->id_shop);
     if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $product->advanced_stock_management && $order_detail->id_warehouse != 0) {
         $manager = StockManagerFactory::getManager();
         $movements = StockMvt::getNegativeStockMvts($order_detail->id_order, $order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject);
         $left_to_reinject = $quantity_to_reinject;
         foreach ($movements as $movement) {
             if ($left_to_reinject > $movement['physical_quantity']) {
                 $quantity_to_reinject = $movement['physical_quantity'];
             }
             $left_to_reinject -= $quantity_to_reinject;
             $manager->addProduct($order_detail->product_id, $order_detail->product_attribute_id, new Warehouse($movement['id_warehouse']), $quantity_to_reinject, null, $movement['price_te'], true);
         }
         StockAvailable::synchronize($order_detail->product_id);
     } elseif ($order_detail->id_warehouse == 0) {
         StockAvailable::updateQuantity($order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject, $order_detail->id_shop);
     } else {
         $this->errors[] = Tools::displayError('This product cannot be re-stocked.');
     }
 }
 /**
  * AdminController::renderForm() override
  * @see AdminController::renderForm()
  */
 public function renderForm()
 {
     // gets the product
     $id_product = (int) Tools::getValue('id_product');
     $id_product_attribute = (int) Tools::getValue('id_product_attribute');
     // gets warehouses
     $warehouses_add = $warehouses_remove = Warehouse::getWarehousesByProductId($id_product, $id_product_attribute);
     // displays warning if no warehouses
     if (!$warehouses_add) {
         $this->displayWarning($this->l('You must choose a warehouses before adding stock. See Stock/Warehouses.'));
     }
     //get currencies list
     $currencies = Currency::getCurrencies();
     $id_default_currency = Configuration::get('PS_CURRENCY_DEFAULT');
     $default_currency = Currency::getCurrency($id_default_currency);
     if ($default_currency) {
         $currencies = array_merge(array($default_currency, '-'), $currencies);
     }
     // switch, in order to display the form corresponding to the current action
     switch ($this->display) {
         case 'addstock':
             // gets the last stock mvt for this product, so we can display the last unit price te and the last quantity added
             $last_sm_unit_price_te = $this->l('N/A');
             $last_sm_quantity = 0;
             $last_sm_quantity_is_usable = -1;
             $last_sm = StockMvt::getLastPositiveStockMvt($id_product, $id_product_attribute);
             // if there is a stock mvt
             if ($last_sm != false) {
                 $last_sm_currency = new Currency((int) $last_sm['id_currency']);
                 $last_sm_quantity = (int) $last_sm['physical_quantity'];
                 $last_sm_quantity_is_usable = (int) $last_sm['is_usable'];
                 if (Validate::isLoadedObject($last_sm_currency)) {
                     $last_sm_unit_price_te = Tools::displayPrice((double) $last_sm['price_te'], $last_sm_currency);
                 }
             }
             $this->displayInformation($this->l('Moving the mouse cursor over the quantity and price fields will give you the details about the last stock movement.'));
             // fields in the form
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Add a product to your stock.'), 'icon' => 'icon-long-arrow-up'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference'), 'name' => 'reference', 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN-13 or JAN barcode'), 'name' => 'ean13', 'disabled' => true), array('type' => 'text', 'label' => $this->l('UPC barcode'), 'name' => 'upc', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name'), 'name' => 'name', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to add'), 'name' => 'quantity', 'maxlength' => 6, 'required' => true, 'hint' => array($this->l('Indicate the physical quantity of this product that you want to add.'), $this->l('Last physical quantity added: %s items (usable for sale: %s).'), $last_sm_quantity > 0 ? $last_sm_quantity : $this->l('N/A'), $last_sm_quantity > 0 ? $last_sm_quantity_is_usable >= 0 ? $this->l('Yes') : $this->l('No') : $this->l('N/A'))), array('type' => 'switch', 'label' => $this->l('Usable for sale?'), 'name' => 'usable', 'required' => true, 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'hint' => $this->l('Is this quantity ready to be displayed in your shop, or is it reserved in the warehouse for other purposes?')), array('type' => 'select', 'label' => $this->l('Warehouse'), 'name' => 'id_warehouse', 'required' => true, 'options' => array('query' => $warehouses_add, 'id' => 'id_warehouse', 'name' => 'name'), 'hint' => $this->l('Please select the warehouse that you\'ll be adding products to.')), array('type' => 'text', 'label' => $this->l('Unit price (tax excl.)'), 'name' => 'price', 'required' => true, 'size' => 10, 'maxlength' => 10, 'hint' => array($this->l('Unit purchase price or unit manufacturing cost for this product (tax excl.).'), sprintf($this->l('Last unit price (tax excl.): %s.'), $last_sm_unit_price_te))), array('type' => 'select', 'label' => $this->l('Currency'), 'name' => 'id_currency', 'required' => true, 'options' => array('query' => $currencies, 'id' => 'id_currency', 'name' => 'name'), 'hint' => $this->l('The currency associated to the product unit price.')), array('type' => 'select', 'label' => $this->l('Label'), 'name' => 'id_stock_mvt_reason', 'required' => true, 'options' => array('query' => StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_TO')), 1), 'id' => 'id_stock_mvt_reason', 'name' => 'name'), 'hint' => $this->l('Label used in stock movements.'))), 'submit' => array('title' => $this->l('Add to stock')));
             $this->fields_value['usable'] = 1;
             break;
         case 'removestock':
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Remove the product from your stock.'), 'icon' => 'icon-long-arrow-down'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference'), 'name' => 'reference', 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN-13 or JAN barcode'), 'name' => 'ean13', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name'), 'name' => 'name', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to remove'), 'name' => 'quantity', 'maxlength' => 6, 'required' => true, 'hint' => $this->l('Indicate the physical quantity of this product that you want to remove.')), array('type' => 'switch', 'label' => $this->l('Usable for sale'), 'name' => 'usable', 'required' => true, 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'hint' => $this->l('Do you want to remove this quantity from the usable quantity (yes) or the physical quantity (no)?')), array('type' => 'select', 'label' => $this->l('Warehouse'), 'name' => 'id_warehouse', 'required' => true, 'options' => array('query' => $warehouses_remove, 'id' => 'id_warehouse', 'name' => 'name'), 'hint' => $this->l('Select the warehouse you\'d like to remove the product from.')), array('type' => 'select', 'label' => $this->l('Label'), 'name' => 'id_stock_mvt_reason', 'required' => true, 'options' => array('query' => StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_FROM')), -1), 'id' => 'id_stock_mvt_reason', 'name' => 'name'), 'hint' => $this->l('Label used in stock movements.'))), 'submit' => array('title' => $this->l('Remove from stock')));
             break;
         case 'transferstock':
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Transfer a product from one warehouse to another'), 'icon' => 'icon-share-alt'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference'), 'name' => 'reference', 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN-13 or JAN barcode'), 'name' => 'ean13', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name'), 'name' => 'name', 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to transfer'), 'name' => 'quantity', 'maxlength' => 6, 'required' => true, 'hint' => $this->l('Indicate the physical quantity of this product that you want to transfer.')), array('type' => 'select', 'label' => $this->l('Source warehouse'), 'name' => 'id_warehouse_from', 'required' => true, 'options' => array('query' => $warehouses_remove, 'id' => 'id_warehouse', 'name' => 'name'), 'hint' => $this->l('Select the warehouse you\'d like to transfer the product from.')), array('type' => 'switch', 'label' => $this->l('Is this product usable for sale in your source warehouse?'), 'name' => 'usable_from', 'required' => true, 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Yes')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('No'))), 'hint' => $this->l('Is this the usable quantity for sale?')), array('type' => 'select', 'label' => $this->l('Destination warehouse'), 'name' => 'id_warehouse_to', 'required' => true, 'options' => array('query' => $warehouses_add, 'id' => 'id_warehouse', 'name' => 'name'), 'hint' => $this->l('Select the warehouse you\'d like to transfer your product(s) to. ')), array('type' => 'switch', 'label' => $this->l('Is this product usable for sale in your destination warehouse?'), 'name' => 'usable_to', 'required' => true, 'class' => 't', 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Yes')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('No'))), 'hint' => $this->l('Do you want it to be for sale/usable?'))), 'submit' => array('title' => $this->l('Transfer')));
             break;
     }
     $this->initToolbar();
 }
 protected function reinjectQuantity($order_detail, $qty_cancel_product, $delete = false)
 {
     // Reinject product
     $reinjectable_quantity = (int) $order_detail->product_quantity - (int) $order_detail->product_quantity_reinjected;
     $quantity_to_reinject = $qty_cancel_product > $reinjectable_quantity ? $reinjectable_quantity : $qty_cancel_product;
     // @since 1.5.0 : Advanced Stock Management
     $product_to_inject = new Product($order_detail->product_id, false, (int) $this->context->language->id, (int) $order_detail->id_shop);
     $product = new Product($order_detail->product_id, false, (int) $this->context->language->id, (int) $order_detail->id_shop);
     if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $product->advanced_stock_management && $order_detail->id_warehouse != 0) {
         $manager = StockManagerFactory::getManager();
         $movements = StockMvt::getNegativeStockMvts($order_detail->id_order, $order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject);
         $left_to_reinject = $quantity_to_reinject;
         foreach ($movements as $movement) {
             if ($left_to_reinject > $movement['physical_quantity']) {
                 $quantity_to_reinject = $movement['physical_quantity'];
             }
             $left_to_reinject -= $quantity_to_reinject;
             if (Pack::isPack((int) $product->id)) {
                 // 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) $product->id, (int) Configuration::get('PS_LANG_DEFAULT'));
                     // Foreach item
                     foreach ($products_pack as $product_pack) {
                         if ($product_pack->advanced_stock_management == 1) {
                             $manager->addProduct($product_pack->id, $product_pack->id_pack_product_attribute, new Warehouse($movement['id_warehouse']), $product_pack->pack_quantity * $quantity_to_reinject, null, $movement['price_te'], true);
                         }
                     }
                 }
                 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)) {
                     $manager->addProduct($order_detail->product_id, $order_detail->product_attribute_id, new Warehouse($movement['id_warehouse']), $quantity_to_reinject, null, $movement['price_te'], true);
                 }
             } else {
                 $manager->addProduct($order_detail->product_id, $order_detail->product_attribute_id, new Warehouse($movement['id_warehouse']), $quantity_to_reinject, null, $movement['price_te'], true);
             }
         }
         $id_product = $order_detail->product_id;
         if ($delete) {
             $order_detail->delete();
         }
         StockAvailable::synchronize($id_product);
     } elseif ($order_detail->id_warehouse == 0) {
         StockAvailable::updateQuantity($order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject, $order_detail->id_shop);
         if ($delete) {
             $order_detail->delete();
         }
     } else {
         $this->errors[] = Tools::displayError('This product cannot be re-stocked.');
     }
 }
Esempio n. 5
0
    /**
     * @see StockManagerInterface::removeProduct()
     */
    public function removeProduct($id_product, $id_product_attribute = null, Warehouse $warehouse, $quantity, $id_stock_mvt_reason, $is_usable = true, $id_order = null)
    {
        $return = array();
        if (!Validate::isLoadedObject($warehouse) || !$quantity || !$id_product) {
            return $return;
        }
        if (!StockMvtReason::exists($id_stock_mvt_reason)) {
            $id_stock_mvt_reason = Configuration::get('PS_STOCK_MVT_DEC_REASON_DEFAULT');
        }
        $context = Context::getContext();
        // Special case of a pack
        if (Pack::isPack((int) $id_product)) {
            // Gets items
            $products_pack = Pack::getItems((int) $id_product, (int) Configuration::get('PS_LANG_DEFAULT'));
            // Foreach item
            foreach ($products_pack as $product_pack) {
                $pack_id_product_attribute = Product::getDefaultAttribute($product_pack->id, 1);
                if ($product_pack->advanced_stock_management == 1) {
                    $this->removeProduct($product_pack->id, $pack_id_product_attribute, $warehouse, $product_pack->pack_quantity * $quantity, $id_stock_mvt_reason, $is_usable, $id_order);
                }
            }
        } else {
            // gets total quantities in stock for the current product
            $physical_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), false);
            $usable_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), true);
            // check quantity if we want to decrement unusable quantity
            if (!$is_usable) {
                $quantity_in_stock = $physical_quantity_in_stock - $usable_quantity_in_stock;
            } else {
                $quantity_in_stock = $usable_quantity_in_stock;
            }
            // checks if it's possible to remove the given quantity
            if ($quantity_in_stock < $quantity) {
                return $return;
            }
            $stock_collection = $this->getStockCollection($id_product, $id_product_attribute, $warehouse->id);
            $stock_collection->getAll();
            // check if the collection is loaded
            if (count($stock_collection) <= 0) {
                return $return;
            }
            $stock_history_qty_available = array();
            $mvt_params = array();
            $stock_params = array();
            $quantity_to_decrement_by_stock = array();
            $global_quantity_to_decrement = $quantity;
            // switch on MANAGEMENT_TYPE
            switch ($warehouse->management_type) {
                // case CUMP mode
                case 'WA':
                    // There is one and only one stock for a given product in a warehouse in this mode
                    $stock = $stock_collection->current();
                    $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $quantity, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'last_wa' => $stock->price_te, 'current_wa' => $stock->price_te, 'id_employee' => $context->employee->id, 'employee_firstname' => $context->employee->firstname, 'employee_lastname' => $context->employee->lastname, 'sign' => -1);
                    $stock_params = array('physical_quantity' => $stock->physical_quantity - $quantity, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $quantity : $stock->usable_quantity);
                    // saves stock in warehouse
                    $stock->hydrate($stock_params);
                    $stock->update();
                    // saves stock mvt
                    $stock_mvt = new StockMvt();
                    $stock_mvt->hydrate($mvt_params);
                    $stock_mvt->save();
                    $return[$stock->id]['quantity'] = $quantity;
                    $return[$stock->id]['price_te'] = $stock->price_te;
                    break;
                case 'LIFO':
                case 'FIFO':
                    // for each stock, parse its mvts history to calculate the quantities left for each positive mvt,
                    // according to the instant available quantities for this stock
                    foreach ($stock_collection as $stock) {
                        $left_quantity_to_check = $stock->physical_quantity;
                        if ($left_quantity_to_check <= 0) {
                            continue;
                        }
                        $resource = Db::getInstance(_PS_USE_SQL_SLAVE_)->query('
							SELECT sm.`id_stock_mvt`, sm.`date_add`, sm.`physical_quantity`,
								IF ((sm2.`physical_quantity` is null), sm.`physical_quantity`, (sm.`physical_quantity` - SUM(sm2.`physical_quantity`))) as qty
							FROM `' . _DB_PREFIX_ . 'stock_mvt` sm
							LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm2 ON sm2.`referer` = sm.`id_stock_mvt`
							WHERE sm.`sign` = 1
							AND sm.`id_stock` = ' . (int) $stock->id . '
							GROUP BY sm.`id_stock_mvt`
							ORDER BY sm.`date_add` DESC');
                        while ($row = Db::getInstance()->nextRow($resource)) {
                            // break - in FIFO mode, we have to retreive the oldest positive mvts for which there are left quantities
                            if ($warehouse->management_type == 'FIFO') {
                                if ($row['qty'] == 0) {
                                    break;
                                }
                            }
                            // converts date to timestamp
                            $date = new DateTime($row['date_add']);
                            $timestamp = $date->format('U');
                            // history of the mvt
                            $stock_history_qty_available[$timestamp] = array('id_stock' => $stock->id, 'id_stock_mvt' => (int) $row['id_stock_mvt'], 'qty' => (int) $row['qty']);
                            // break - in LIFO mode, checks only the necessary history to handle the global quantity for the current stock
                            if ($warehouse->management_type == 'LIFO') {
                                $left_quantity_to_check -= (int) $row['physical_quantity'];
                                if ($left_quantity_to_check <= 0) {
                                    break;
                                }
                            }
                        }
                    }
                    if ($warehouse->management_type == 'LIFO') {
                        // orders stock history by timestamp to get newest history first
                        krsort($stock_history_qty_available);
                    } else {
                        // orders stock history by timestamp to get oldest history first
                        ksort($stock_history_qty_available);
                    }
                    // checks each stock to manage the real quantity to decrement for each of them
                    foreach ($stock_history_qty_available as $entry) {
                        if ($entry['qty'] >= $global_quantity_to_decrement) {
                            $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $global_quantity_to_decrement;
                            $global_quantity_to_decrement = 0;
                        } else {
                            $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $entry['qty'];
                            $global_quantity_to_decrement -= $entry['qty'];
                        }
                        if ($global_quantity_to_decrement <= 0) {
                            break;
                        }
                    }
                    // for each stock, decrements it and logs the mvts
                    foreach ($stock_collection as $stock) {
                        if (array_key_exists($stock->id, $quantity_to_decrement_by_stock) && is_array($quantity_to_decrement_by_stock[$stock->id])) {
                            $total_quantity_for_current_stock = 0;
                            foreach ($quantity_to_decrement_by_stock[$stock->id] as $id_mvt_referrer => $qte) {
                                $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $qte, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'sign' => -1, 'referer' => $id_mvt_referrer, 'id_employee' => $context->employee->id);
                                // saves stock mvt
                                $stock_mvt = new StockMvt();
                                $stock_mvt->hydrate($mvt_params);
                                $stock_mvt->save();
                                $total_quantity_for_current_stock += $qte;
                            }
                            $stock_params = array('physical_quantity' => $stock->physical_quantity - $total_quantity_for_current_stock, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $total_quantity_for_current_stock : $stock->usable_quantity);
                            $return[$stock->id]['quantity'] = $total_quantity_for_current_stock;
                            $return[$stock->id]['price_te'] = $stock->price_te;
                            // saves stock in warehouse
                            $stock->hydrate($stock_params);
                            $stock->update();
                        }
                    }
                    break;
            }
        }
        // if we remove a usable quantity, exec hook
        if ($is_usable) {
            Hook::exec('actionProductCoverage', array('id_product' => $id_product, 'id_product_attribute' => $id_product_attribute, 'warehouse' => $warehouse));
        }
        return $return;
    }
Esempio n. 6
0
 public function addStockMvt($quantity, $id_reason, $id_product_attribute = null, $id_order = null, $id_employee = null)
 {
     $stockMvt = new StockMvt();
     $stockMvt->id_product = (int) $this->id;
     $stockMvt->id_product_attribute = (int) $id_product_attribute;
     $stockMvt->id_order = (int) $id_order;
     $stockMvt->id_employee = (int) $id_employee;
     $stockMvt->quantity = (int) $quantity;
     $stockMvt->id_stock_mvt_reason = (int) $id_reason;
     // adding stock mouvement, this action update the sotck of product in database only
     if ($stockMvt->add()) {
         // update quantity in object after adding the stock movement
         $this->quantity = $this->getStockAvailable();
         Hook::updateQuantity($this, null);
         return true;
     }
     return false;
 }
Esempio n. 7
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();
    }
 public function __construct($id = null, $id_lang = null, $id_shop = null)
 {
     //self::$definition['fields']['last_quantity'] = array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => true);
     parent::__construct($id, $id_lang, $id_shop);
 }
Esempio n. 9
0
 public function addStockMvt($quantity, $id_reason, $id_product_attribute = NULL, $id_order = NULL, $id_employee = NULL)
 {
     $stockMvt = new StockMvt();
     $stockMvt->id_product = (int) $this->id;
     $stockMvt->id_product_attribute = (int) $id_product_attribute;
     $stockMvt->id_order = (int) $id_order;
     $stockMvt->id_employee = (int) $id_employee;
     $stockMvt->quantity = (int) $quantity;
     $stockMvt->id_stock_mvt_reason = (int) $id_reason;
     $result = $stockMvt->add();
     $last_quantity = $this->quantity;
     // Increase or decrease current product quantity value
     if ($id_reason == 1) {
         $this->quantity += abs($quantity);
     } else {
         if ($id_reason == 2) {
             $this->quantity -= abs($quantity);
         }
     }
     Hook::updateQuantity($this, null);
     //reindex the updated product
     if ($this->quantity < 1 || $last_quantity < 1 && $this->quantity > 0) {
         SolrSearch::updateProduct($this->id);
     }
     return $result;
 }
Esempio n. 10
0
 public function addStockMvt($quantity, $id_reason, $id_product_attribute = NULL, $id_order = NULL, $id_employee = NULL)
 {
     $stockMvt = new StockMvt();
     $stockMvt->id_product = (int) $this->id;
     $stockMvt->id_product_attribute = (int) $id_product_attribute;
     $stockMvt->id_order = (int) $id_order;
     $stockMvt->id_employee = (int) $id_employee;
     $stockMvt->quantity = (int) $quantity;
     $stockMvt->id_stock_mvt_reason = (int) $id_reason;
     return $stockMvt->add();
 }
Esempio n. 11
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));
    }
Esempio n. 12
0
    public static function addMissingMvt($id_employee)
    {
        $products_without_attributes = Db::getInstance()->ExecuteS('
			SELECT p.`id_product`, pa.`id_product_attribute`, (p.`quantity` - SUM(IFNULL(sm.`quantity`, 0))) quantity
			FROM `' . _DB_PREFIX_ . 'product` p
			LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm ON (sm.`id_product` = p.`id_product`)
			LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pa.`id_product` = p.`id_product`)
			WHERE pa.`id_product_attribute` IS NULL
			GROUP BY p.`id_product`
		');
        $products_with_attributes = Db::getInstance()->ExecuteS('
			SELECT p.`id_product`, pa.`id_product_attribute`, SUM(pa.`quantity`) - SUM(IFNULL(sm.`quantity`, 0)) quantity
			FROM `' . _DB_PREFIX_ . 'product` p
			LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pa.`id_product` = p.`id_product`)
			LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm ON (sm.`id_product` = pa.`id_product` AND sm.`id_product_attribute` = pa.`id_product_attribute`)
			WHERE pa.`id_product_attribute` IS NOT NULL
			GROUP BY pa.`id_product_attribute`
		');
        $products = array_merge($products_without_attributes, $products_with_attributes);
        if ($products) {
            foreach ($products as $product) {
                if (!$product['quantity']) {
                    continue;
                }
                $mvt = new StockMvt();
                foreach ($product as $k => $row) {
                    $mvt->{$k} = $row;
                }
                $mvt->id_employee = (int) $id_employee;
                $mvt->id_stock_mvt_reason = _STOCK_MOVEMENT_MISSING_REASON_;
                $mvt->add(true, false, false);
            }
        }
    }
 /**
  * AdminController::renderForm() override
  * @see AdminController::renderForm()
  */
 public function renderForm()
 {
     // gets the product
     $id_product = (int) Tools::getValue('id_product');
     $id_product_attribute = (int) Tools::getValue('id_product_attribute');
     // gets warehouses
     $warehouses_add = Warehouse::getWarehouses(true);
     $warehouses_remove = Warehouse::getWarehousesByProductId($id_product, $id_product_attribute);
     // displays warning if no warehouses
     if (!$warehouses_add) {
         $this->displayWarning($this->l('You have to have Warehouses before adding stock. See Stock/Warehouses'));
     }
     //get currencies list
     $currencies = Currency::getCurrencies();
     $id_default_currency = Configuration::get('PS_CURRENCY_DEFAULT');
     $default_currency = Currency::getCurrency($id_default_currency);
     if ($default_currency) {
         $currencies = array_merge(array($default_currency, '-'), $currencies);
     }
     // switch, in order to display the form corresponding to the current action
     switch ($this->display) {
         case 'addstock':
             // gets the last stock mvt for this product, so we can display the last unit price te and the last quantity added
             $last_sm_unit_price_te = $this->l('N/A');
             $last_sm_quantity = 0;
             $last_sm_quantity_is_usable = -1;
             $last_sm = StockMvt::getLastPositiveStockMvt($id_product, $id_product_attribute);
             // if there is a stock mvt
             if ($last_sm != false) {
                 $last_sm_currency = new Currency((int) $last_sm['id_currency']);
                 $last_sm_quantity = (int) $last_sm['physical_quantity'];
                 $last_sm_quantity_is_usable = (int) $last_sm['is_usable'];
                 if (Validate::isLoadedObject($last_sm_currency)) {
                     $last_sm_unit_price_te = Tools::displayPrice((double) $last_sm['price_te'], $last_sm_currency);
                 }
             }
             $this->displayInformation($this->l('Note that rolling over the quantity and price fields will give you the details of the last stock movement.'));
             // fields in the form
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Add product to stock'), 'image' => '../img/admin/add_stock.png'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference:'), 'name' => 'reference', 'size' => 30, 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN13:'), 'name' => 'ean13', 'size' => 15, 'disabled' => true), array('type' => 'text', 'label' => $this->l('UPC:'), 'name' => 'upc', 'size' => 15, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name:'), 'name' => 'name', 'size' => 75, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to add:'), 'name' => 'quantity', 'size' => 10, 'maxlength' => 6, 'required' => true, 'desc' => $this->l('Physical quantity to add'), 'hint' => sprintf($this->l('Last physical quantity added : %s (%s)'), $last_sm_quantity > 0 ? $last_sm_quantity : $this->l('N/A'), $last_sm_quantity > 0 ? $last_sm_quantity_is_usable >= 0 ? $this->l('usable') : $this->l('not usable') : $this->l('N/A'))), array('type' => 'radio', 'label' => $this->l('Usable for sale?'), 'name' => 'usable', 'required' => true, 'class' => 't', 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'desc' => $this->l('Is this quantity usable for sale on shops, or reserved in the warehouse for other purposes?')), array('type' => 'select', 'label' => $this->l('Warehouse:'), 'name' => 'id_warehouse', 'required' => true, 'options' => array('query' => $warehouses_add, 'id' => 'id_warehouse', 'name' => 'name'), 'desc' => $this->l('Select the warehouse where you want to add the product into')), array('type' => 'text', 'label' => $this->l('Unit price (tax excl.):'), 'name' => 'price', 'required' => true, 'size' => 10, 'maxlength' => 10, 'desc' => $this->l('Unit purchase price or unit manufacturing cost for this product (tax excl.)'), 'hint' => sprintf($this->l('Last unit price (tax excl.): %s'), $last_sm_unit_price_te)), array('type' => 'select', 'label' => $this->l('Currency:'), 'name' => 'id_currency', 'required' => true, 'options' => array('query' => $currencies, 'id' => 'id_currency', 'name' => 'name'), 'desc' => $this->l('The currency associated to the product unit price')), array('type' => 'select', 'label' => $this->l('Label:'), 'name' => 'id_stock_mvt_reason', 'required' => true, 'options' => array('query' => StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_TO')), 1), 'id' => 'id_stock_mvt_reason', 'name' => 'name'), 'desc' => $this->l('Label used in stock movements'))), 'submit' => array('title' => $this->l('Add to stock'), 'class' => 'button'));
             $this->fields_value['usable'] = 1;
             break;
         case 'removestock':
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Remove product from stock'), 'image' => '../img/admin/remove_stock.png'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference:'), 'name' => 'reference', 'size' => 30, 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN13:'), 'name' => 'ean13', 'size' => 15, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name:'), 'name' => 'name', 'size' => 75, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to remove:'), 'name' => 'quantity', 'size' => 10, 'maxlength' => 6, 'required' => true, 'desc' => $this->l('Physical quantity to remove')), array('type' => 'radio', 'label' => $this->l('Usable for sale:'), 'name' => 'usable', 'required' => true, 'class' => 't', 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'desc' => $this->l('Do you want to remove this quantity from the usable quantity (yes) or the physical quantity (no)?')), array('type' => 'select', 'label' => $this->l('Warehouse:'), 'name' => 'id_warehouse', 'required' => true, 'options' => array('query' => $warehouses_remove, 'id' => 'id_warehouse', 'name' => 'name'), 'desc' => $this->l('Select the warehouse from where you want to remove the product')), array('type' => 'select', 'label' => $this->l('Label:'), 'name' => 'id_stock_mvt_reason', 'required' => true, 'options' => array('query' => StockMvtReason::getStockMvtReasonsWithFilter($this->context->language->id, array(Configuration::get('PS_STOCK_MVT_TRANSFER_FROM')), -1), 'id' => 'id_stock_mvt_reason', 'name' => 'name'), 'desc' => $this->l('Label used in stock movements'))), 'submit' => array('title' => $this->l('Remove from stock'), 'class' => 'button'));
             break;
         case 'transferstock':
             $this->fields_form[]['form'] = array('legend' => array('title' => $this->l('Transfer product from one warehouse to another'), 'image' => '../img/admin/transfer_stock.png'), 'input' => array(array('type' => 'hidden', 'name' => 'is_post'), array('type' => 'hidden', 'name' => 'id_product'), array('type' => 'hidden', 'name' => 'id_product_attribute'), array('type' => 'hidden', 'name' => 'check'), array('type' => 'text', 'label' => $this->l('Product reference:'), 'name' => 'reference', 'size' => 30, 'disabled' => true), array('type' => 'text', 'label' => $this->l('EAN13:'), 'name' => 'ean13', 'size' => 15, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Name:'), 'name' => 'name', 'size' => 75, 'disabled' => true), array('type' => 'text', 'label' => $this->l('Quantity to transfer:'), 'name' => 'quantity', 'size' => 10, 'maxlength' => 6, 'required' => true, 'desc' => $this->l('Quantity to transfer:')), array('type' => 'select', 'label' => $this->l('Source Warehouse:'), 'name' => 'id_warehouse_from', 'required' => true, 'options' => array('query' => $warehouses_remove, 'id' => 'id_warehouse', 'name' => 'name'), 'desc' => $this->l('Select the warehouse from which you want to transfer the product.')), array('type' => 'radio', 'label' => $this->l('Usable for sale in source warehouse?'), 'name' => 'usable_from', 'required' => true, 'class' => 't', 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'desc' => $this->l('Is this a usable quantity for sale?')), array('type' => 'select', 'label' => $this->l('Destination Warehouse:'), 'name' => 'id_warehouse_to', 'required' => true, 'options' => array('query' => $warehouses_add, 'id' => 'id_warehouse', 'name' => 'name'), 'desc' => $this->l('Select the warehouse to which to transfer the product.')), array('type' => 'radio', 'label' => $this->l('Usable for sale in destination warehouse?'), 'name' => 'usable_to', 'required' => true, 'class' => 't', 'is_bool' => true, 'values' => array(array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled'))), 'desc' => $this->l('Do you want it to be usable for sale?'))), 'submit' => array('title' => $this->l('Transfer'), 'class' => 'button'));
             break;
     }
     $this->initToolbar();
 }
Esempio n. 14
0
{
    /*
     * module: pproperties
     * date: 2015-10-30 20:57:18
     * version: 2.14
     */
    public $physical_quantity_remainder = 0;
    /*
     * module: pproperties
     * date: 2015-10-30 20:57:18
     * version: 2.14
     */
    public static function ppInit()
    {
        self::$definition['fields'] = array_merge(self::$definition['fields'], array('physical_quantity_remainder' => array('type' => self::TYPE_FLOAT, 'validate' => 'isUnsignedFloat')));
    }
    /*
     * module: pproperties
     * date: 2015-10-30 20:57:18
     * version: 2.14
     */
    public function hydrate(array $data, $id_lang = null)
    {
        parent::hydrate($data, $id_lang);
        if (!isset($data['physical_quantity_remainder'])) {
            PP::hydrateQty($this, 'physical_quantity', $data['physical_quantity'] + $this->physical_quantity_remainder);
        }
    }
}
StockMvt::ppInit();
Esempio n. 15
0
    public static function addMissingMvt($id_employee)
    {
        $products_attributes = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
		SELECT p.`id_product`, coalesce(pa.`id_product_attribute`, 0) as id_product_attribute, (coalesce(pa.quantity,p.quantity) - SUM(coalesce(sm.`quantity`, 0))) as quantity
		FROM `' . _DB_PREFIX_ . 'product` p
		LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pa.`id_product` = p.`id_product`)
		LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm ON (sm.`id_product` = p.`id_product` and sm.id_product_attribute = coalesce (pa.id_product_attribute,0))
		WHERE p.`active` = 1
		GROUP BY p.`id_product`, pa.`id_product_attribute`
		HAVING quantity != 0', false);
        while ($product = Db::getInstance()->nextRow($products_attributes)) {
            if (!isset($product) || !is_array($product) || !isset($product['quantity']) || !$product['quantity']) {
                continue;
            }
            $mvt = new StockMvt();
            foreach ($product as $k => $row) {
                $mvt->{$k} = $row;
            }
            $mvt->id_employee = (int) $id_employee;
            $mvt->id_stock_mvt_reason = _STOCK_MOVEMENT_MISSING_REASON_;
            $mvt->add(true, false, false);
        }
    }
Esempio n. 16
0
    public function postProcess()
    {
        // If id_order is sent, we instanciate a new Order object
        if (Tools::isSubmit('id_order') && Tools::getValue('id_order') > 0) {
            $order = new Order(Tools::getValue('id_order'));
            if (!Validate::isLoadedObject($order)) {
                throw new PrestaShopException('Can\'t load Order object');
            }
        }
        /* Update shipping number */
        if (Tools::isSubmit('submitShippingNumber') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $order_carrier = new OrderCarrier(Tools::getValue('id_order_carrier'));
                if (!Validate::isLoadedObject($order_carrier)) {
                    $this->errors[] = Tools::displayError('Order carrier ID is invalid');
                } elseif (!Validate::isTrackingNumber(Tools::getValue('tracking_number'))) {
                    $this->errors[] = Tools::displayError('Tracking number is incorrect');
                } else {
                    // update shipping number
                    // Keep these two following lines for backward compatibility, remove on 1.6 version
                    $order->shipping_number = Tools::getValue('tracking_number');
                    $order->update();
                    // Update order_carrier
                    $order_carrier->tracking_number = pSQL(Tools::getValue('tracking_number'));
                    if ($order_carrier->update()) {
                        // Send mail to customer
                        $customer = new Customer((int) $order->id_customer);
                        $carrier = new Carrier((int) $order->id_carrier, $order->id_lang);
                        if (!Validate::isLoadedObject($customer)) {
                            throw new PrestaShopException('Can\'t load Customer object');
                        }
                        if (!Validate::isLoadedObject($carrier)) {
                            throw new PrestaShopException('Can\'t load Carrier object');
                        }
                        $templateVars = array('{followup}' => str_replace('@', $order->shipping_number, $carrier->url), '{firstname}' => $customer->firstname, '{lastname}' => $customer->lastname, '{id_order}' => $order->id, '{order_name}' => $order->getUniqReference());
                        if (@Mail::Send((int) $order->id_lang, 'in_transit', Mail::l('Package in transit', (int) $order->id_lang), $templateVars, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, true, (int) $order->id_shop)) {
                            Hook::exec('actionAdminOrdersTrackingNumberUpdate', array('order' => $order));
                            Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
                        } else {
                            $this->errors[] = Tools::displayError('An error occurred while sending e-mail to the customer.');
                        }
                    } else {
                        $this->errors[] = Tools::displayError('Order carrier can\'t be updated');
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::isSubmit('submitState') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $order_state = new OrderState(Tools::getValue('id_order_state'));
                if (!Validate::isLoadedObject($order_state)) {
                    $this->errors[] = Tools::displayError('Invalid new order status');
                } else {
                    $current_order_state = $order->getCurrentOrderState();
                    if ($current_order_state->id != $order_state->id) {
                        // Create new OrderHistory
                        $history = new OrderHistory();
                        $history->id_order = $order->id;
                        $history->id_employee = (int) $this->context->employee->id;
                        $use_existings_payment = false;
                        if (!$order->hasInvoice()) {
                            $use_existings_payment = true;
                        }
                        $history->changeIdOrderState($order_state->id, $order->id, $use_existings_payment);
                        $carrier = new Carrier($order->id_carrier, $order->id_lang);
                        $templateVars = array();
                        if ($history->id_order_state == Configuration::get('PS_OS_SHIPPING') && $order->shipping_number) {
                            $templateVars = array('{followup}' => str_replace('@', $order->shipping_number, $carrier->url));
                        }
                        // Save all changes
                        if ($history->addWithemail(true, $templateVars)) {
                            // synchronizes quantities if needed..
                            if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                                foreach ($order->getProducts() as $product) {
                                    if (StockAvailable::dependsOnStock($product['product_id'])) {
                                        StockAvailable::synchronize($product['product_id'], (int) $product['id_shop']);
                                    }
                                }
                            }
                            Tools::redirectAdmin(self::$currentIndex . '&id_order=' . (int) $order->id . '&vieworder&token=' . $this->token);
                        }
                        $this->errors[] = Tools::displayError('An error occurred while changing the status or was unable to send e-mail to the customer.');
                    } else {
                        $this->errors[] = Tools::displayError('This order is already assigned this status');
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::isSubmit('submitMessage') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $customer = new Customer(Tools::getValue('id_customer'));
                if (!Validate::isLoadedObject($customer)) {
                    $this->errors[] = Tools::displayError('Customer is invalid');
                } elseif (!Tools::getValue('message')) {
                    $this->errors[] = Tools::displayError('Message cannot be blank');
                } else {
                    /* Get message rules and and check fields validity */
                    $rules = call_user_func(array('Message', 'getValidationRules'), 'Message');
                    foreach ($rules['required'] as $field) {
                        if (($value = Tools::getValue($field)) == false && (string) $value != '0') {
                            if (!Tools::getValue('id_' . $this->table) || $field != 'passwd') {
                                $this->errors[] = sprintf(Tools::displayError('field %s is required.'), $field);
                            }
                        }
                    }
                    foreach ($rules['size'] as $field => $maxLength) {
                        if (Tools::getValue($field) && Tools::strlen(Tools::getValue($field)) > $maxLength) {
                            $this->errors[] = sprintf(Tools::displayError('field %1$s is too long (%2$d chars max).'), $field, $maxLength);
                        }
                    }
                    foreach ($rules['validate'] as $field => $function) {
                        if (Tools::getValue($field)) {
                            if (!Validate::$function(htmlentities(Tools::getValue($field), ENT_COMPAT, 'UTF-8'))) {
                                $this->errors[] = sprintf(Tools::displayError('field %s is invalid.'), $field);
                            }
                        }
                    }
                    if (!count($this->errors)) {
                        //check if a thread already exist
                        $id_customer_thread = CustomerThread::getIdCustomerThreadByEmailAndIdOrder($customer->email, $order->id);
                        if (!$id_customer_thread) {
                            $customer_thread = new CustomerThread();
                            $customer_thread->id_contact = 0;
                            $customer_thread->id_customer = (int) $order->id_customer;
                            $customer_thread->id_shop = (int) $this->context->shop->id;
                            $customer_thread->id_order = (int) $order->id;
                            $customer_thread->id_lang = (int) $this->context->language->id;
                            $customer_thread->email = $customer->email;
                            $customer_thread->status = 'open';
                            $customer_thread->token = Tools::passwdGen(12);
                            $customer_thread->add();
                        } else {
                            $customer_thread = new CustomerThread((int) $id_customer_thread);
                        }
                        $customer_message = new CustomerMessage();
                        $customer_message->id_customer_thread = $customer_thread->id;
                        $customer_message->id_employee = (int) $this->context->employee->id;
                        $customer_message->message = htmlentities(Tools::getValue('message'), ENT_COMPAT, 'UTF-8');
                        $customer_message->private = Tools::getValue('visibility');
                        if (!$customer_message->add()) {
                            $this->errors[] = Tools::displayError('An error occurred while saving message');
                        } elseif ($customer_message->private) {
                            Tools::redirectAdmin(self::$currentIndex . '&id_order=' . (int) $order->id . '&vieworder&conf=11&token=' . $this->token);
                        } else {
                            $message = $customer_message->message;
                            if (Configuration::get('PS_MAIL_TYPE') != Mail::TYPE_TEXT) {
                                $message = Tools::nl2br($customer_message->message);
                            }
                            $varsTpl = array('{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{id_order}' => $order->id, '{order_name}' => $order->getUniqReference(), '{message}' => $message);
                            if (@Mail::Send((int) $order->id_lang, 'order_merchant_comment', Mail::l('New message regarding your order', (int) $order->id_lang), $varsTpl, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, true, (int) $order->id_shop)) {
                                Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=11' . '&token=' . $this->token);
                            }
                        }
                        $this->errors[] = Tools::displayError('An error occurred while sending e-mail to the customer.');
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to delete here.');
            }
        } elseif (Tools::isSubmit('partialRefund') && isset($order)) {
            if ($this->tabAccess['edit'] == '1') {
                if (is_array($_POST['partialRefundProduct'])) {
                    $amount = 0;
                    $order_detail_list = array();
                    foreach ($_POST['partialRefundProduct'] as $id_order_detail => $amount_detail) {
                        $order_detail_list[$id_order_detail]['quantity'] = (int) $_POST['partialRefundProductQuantity'][$id_order_detail];
                        if (empty($amount_detail)) {
                            $order_detail = new OrderDetail((int) $id_order_detail);
                            $order_detail_list[$id_order_detail]['amount'] = $order_detail->unit_price_tax_incl * $order_detail_list[$id_order_detail]['quantity'];
                        } else {
                            $order_detail_list[$id_order_detail]['amount'] = (double) $amount_detail;
                        }
                        $amount += $order_detail_list[$id_order_detail]['amount'];
                    }
                    $shipping_cost_amount = (double) str_replace(',', '.', Tools::getValue('partialRefundShippingCost'));
                    if ($shipping_cost_amount > 0) {
                        $amount += $shipping_cost_amount;
                    }
                    if ($amount > 0) {
                        if (!OrderSlip::createPartialOrderSlip($order, $amount, $shipping_cost_amount, $order_detail_list)) {
                            $this->errors[] = Tools::displayError('Cannot generate partial credit slip');
                        }
                        // Generate voucher
                        if (Tools::isSubmit('generateDiscountRefund') && !count($this->errors)) {
                            $cart_rule = new CartRule();
                            $cart_rule->description = sprintf($this->l('Credit Slip for order #%d'), $order->id);
                            $languages = Language::getLanguages(false);
                            foreach ($languages as $language) {
                                // Define a temporary name
                                $cart_rule->name[$language['id_lang']] = sprintf('V0C%1$dO%2$d', $order->id_customer, $order->id);
                            }
                            // Define a temporary code
                            $cart_rule->code = sprintf('V0C%1$dO%2$d', $order->id_customer, $order->id);
                            $cart_rule->quantity = 1;
                            $cart_rule->quantity_per_user = 1;
                            // Specific to the customer
                            $cart_rule->id_customer = $order->id_customer;
                            $now = time();
                            $cart_rule->date_from = date('Y-m-d H:i:s', $now);
                            $cart_rule->date_to = date('Y-m-d H:i:s', $now + 3600 * 24 * 365.25);
                            /* 1 year */
                            $cart_rule->active = 1;
                            $cart_rule->reduction_amount = $amount;
                            $cart_rule->reduction_tax = true;
                            $cart_rule->minimum_amount_currency = $order->id_currency;
                            $cart_rule->reduction_currency = $order->id_currency;
                            if (!$cart_rule->add()) {
                                $this->errors[] = Tools::displayError('Cannot generate voucher');
                            } else {
                                // Update the voucher code and name
                                foreach ($languages as $language) {
                                    $cart_rule->name[$language['id_lang']] = sprintf('V%1$dC%2$dO%3$d', $cart_rule->id, $order->id_customer, $order->id);
                                }
                                $cart_rule->code = sprintf('V%1$dC%2$dO%3$d', $cart_rule->id, $order->id_customer, $order->id);
                                if (!$cart_rule->update()) {
                                    $this->errors[] = Tools::displayError('Cannot generate voucher');
                                } else {
                                    $currency = $this->context->currency;
                                    $params['{voucher_amount}'] = Tools::displayPrice($cart_rule->reduction_amount, $currency, false);
                                    $params['{voucher_num}'] = $cart_rule->code;
                                    $customer = new Customer((int) $order->id_customer);
                                    @Mail::Send((int) $order->id_lang, 'voucher', sprintf(Mail::l('New voucher regarding your order %s', (int) $order->id_lang), $order->reference), $params, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, true, (int) $order->id_shop);
                                }
                            }
                        }
                    } else {
                        $this->errors[] = Tools::displayError('You have to write an amount if you want to do a partial credit slip');
                    }
                    // Redirect if no errors
                    if (!count($this->errors)) {
                        Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=30&token=' . $this->token);
                    }
                } else {
                    $this->errors[] = Tools::displayError('Partial refund data is incorrect');
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to delete here.');
            }
        } elseif (Tools::isSubmit('cancelProduct') && isset($order)) {
            if ($this->tabAccess['delete'] === '1') {
                if (!Tools::isSubmit('id_order_detail')) {
                    $this->errors[] = Tools::displayError('You must select a product');
                } elseif (!Tools::isSubmit('cancelQuantity')) {
                    $this->errors[] = Tools::displayError('You must enter a quantity');
                } else {
                    $productList = Tools::getValue('id_order_detail');
                    if ($productList) {
                        $productList = array_map('intval', $productList);
                    }
                    $customizationList = Tools::getValue('id_customization');
                    if ($customizationList) {
                        $customizationList = array_map('intval', $customizationList);
                    }
                    $qtyList = Tools::getValue('cancelQuantity');
                    if ($qtyList) {
                        $qtyList = array_map('intval', $qtyList);
                    }
                    $customizationQtyList = Tools::getValue('cancelCustomizationQuantity');
                    if ($customizationQtyList) {
                        $customizationQtyList = array_map('intval', $customizationQtyList);
                    }
                    $full_product_list = $productList;
                    $full_quantity_list = $qtyList;
                    if ($customizationList) {
                        foreach ($customizationList as $key => $id_order_detail) {
                            $full_product_list[(int) $id_order_detail] = $id_order_detail;
                            $full_quantity_list[(int) $id_order_detail] += $customizationQtyList[$key];
                        }
                    }
                    if ($productList || $customizationList) {
                        if ($productList) {
                            $id_cart = Cart::getCartIdByOrderId($order->id);
                            $customization_quantities = Customization::countQuantityByCart($id_cart);
                            foreach ($productList as $key => $id_order_detail) {
                                $qtyCancelProduct = abs($qtyList[$key]);
                                if (!$qtyCancelProduct) {
                                    $this->errors[] = Tools::displayError('No quantity selected for product.');
                                }
                                $order_detail = new OrderDetail($id_order_detail);
                                $customization_quantity = 0;
                                if (array_key_exists($order_detail->product_id, $customization_quantities) && array_key_exists($order_detail->product_attribute_id, $customization_quantities[$order_detail->product_id])) {
                                    $customization_quantity = (int) $customization_quantities[$order_detail->product_id][$order_detail->product_attribute_id];
                                }
                                if ($order_detail->product_quantity - $customization_quantity - $order_detail->product_quantity_refunded - $order_detail->product_quantity_return < $qtyCancelProduct) {
                                    $this->errors[] = Tools::displayError('Invalid quantity selected for product.');
                                }
                            }
                        }
                        if ($customizationList) {
                            $customization_quantities = Customization::retrieveQuantitiesFromIds(array_keys($customizationList));
                            foreach ($customizationList as $id_customization => $id_order_detail) {
                                $qtyCancelProduct = abs($customizationQtyList[$id_customization]);
                                $customization_quantity = $customization_quantities[$id_customization];
                                if (!$qtyCancelProduct) {
                                    $this->errors[] = Tools::displayError('No quantity selected for product.');
                                }
                                if ($qtyCancelProduct > $customization_quantity['quantity'] - ($customization_quantity['quantity_refunded'] + $customization_quantity['quantity_returned'])) {
                                    $this->errors[] = Tools::displayError('Invalid quantity selected for product.');
                                }
                            }
                        }
                        if (!count($this->errors) && $productList) {
                            foreach ($productList as $key => $id_order_detail) {
                                $qty_cancel_product = abs($qtyList[$key]);
                                $order_detail = new OrderDetail((int) $id_order_detail);
                                // Reinject product
                                if (!$order->hasBeenDelivered() || $order->hasBeenDelivered() && Tools::isSubmit('reinjectQuantities')) {
                                    $reinjectable_quantity = (int) $order_detail->product_quantity - (int) $order_detail->product_quantity_reinjected;
                                    $quantity_to_reinject = $qty_cancel_product > $reinjectable_quantity ? $reinjectable_quantity : $qty_cancel_product;
                                    // @since 1.5.0 : Advanced Stock Management
                                    $product_to_inject = new Product($order_detail->product_id, false, $this->context->language->id, $order->id_shop);
                                    $product = new Product($order_detail->product_id);
                                    if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $product->advanced_stock_management && $order_detail->id_warehouse != 0) {
                                        $manager = StockManagerFactory::getManager();
                                        $movements = StockMvt::getNegativeStockMvts($order_detail->id_order, $order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject);
                                        foreach ($movements as $movement) {
                                            $manager->addProduct($order_detail->product_id, $order_detail->product_attribute_id, new Warehouse($movement['id_warehouse']), $movement['physical_quantity'], null, $movement['price_te'], true);
                                        }
                                        StockAvailable::synchronize($order_detail->product_id);
                                    } else {
                                        if ($order_detail->id_warehouse == 0) {
                                            StockAvailable::updateQuantity($order_detail->product_id, $order_detail->product_attribute_id, $quantity_to_reinject, $order->id_shop);
                                        } else {
                                            $this->errors[] = Tools::displayError('Cannot re-stock product');
                                        }
                                    }
                                }
                                // Delete product
                                $order_detail = new OrderDetail((int) $id_order_detail);
                                if (!$order->deleteProduct($order, $order_detail, $qtyCancelProduct)) {
                                    $this->errors[] = Tools::displayError('An error occurred during deletion of the product.') . ' <span class="bold">' . $order_detail->product_name . '</span>';
                                }
                                Hook::exec('actionProductCancel', array('order' => $order, 'id_order_detail' => (int) $id_order_detail));
                            }
                        }
                        if (!count($this->errors) && $customizationList) {
                            foreach ($customizationList as $id_customization => $id_order_detail) {
                                $order_detail = new OrderDetail((int) $id_order_detail);
                                $qtyCancelProduct = abs($customizationQtyList[$id_customization]);
                                if (!$order->deleteCustomization($id_customization, $qtyCancelProduct, $order_detail)) {
                                    $this->errors[] = Tools::displayError('An error occurred during deletion of product customization.') . ' ' . $id_customization;
                                }
                            }
                        }
                        // E-mail params
                        if ((Tools::isSubmit('generateCreditSlip') || Tools::isSubmit('generateDiscount')) && !count($this->errors)) {
                            $customer = new Customer((int) $order->id_customer);
                            $params['{lastname}'] = $customer->lastname;
                            $params['{firstname}'] = $customer->firstname;
                            $params['{id_order}'] = $order->id;
                            $params['{order_name}'] = $order->getUniqReference();
                        }
                        // Generate credit slip
                        if (Tools::isSubmit('generateCreditSlip') && !count($this->errors)) {
                            if (!OrderSlip::createOrderSlip($order, $full_product_list, $full_quantity_list, Tools::isSubmit('shippingBack'))) {
                                $this->errors[] = Tools::displayError('Cannot generate credit slip');
                            } else {
                                Hook::exec('actionOrderSlipAdd', array('order' => $order, 'productList' => $full_product_list, 'qtyList' => $full_quantity_list));
                                @Mail::Send((int) $order->id_lang, 'credit_slip', Mail::l('New credit slip regarding your order', $order->id_lang), $params, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, true, (int) $order->id_shop);
                            }
                        }
                        // Generate voucher
                        if (Tools::isSubmit('generateDiscount') && !count($this->errors)) {
                            $cartrule = new CartRule();
                            $languages = Language::getLanguages($order);
                            $cartrule->description = sprintf($this->l('Credit Slip for order #%d'), $order->id);
                            foreach ($languages as $language) {
                                // Define a temporary name
                                $cartrule->name[$language['id_lang']] = 'V0C' . (int) $order->id_customer . 'O' . (int) $order->id;
                            }
                            // Define a temporary code
                            $cartrule->code = 'V0C' . (int) $order->id_customer . 'O' . (int) $order->id;
                            $cartrule->quantity = 1;
                            $cartrule->quantity_per_user = 1;
                            // Specific to the customer
                            $cartrule->id_customer = $order->id_customer;
                            $now = time();
                            $cartrule->date_from = date('Y-m-d H:i:s', $now);
                            $cartrule->date_to = date('Y-m-d H:i:s', $now + 3600 * 24 * 365.25);
                            /* 1 year */
                            $cartrule->active = 1;
                            $products = $order->getProducts(false, $full_product_list, $full_quantity_list);
                            $total = 0;
                            foreach ($products as $product) {
                                $total += $product['unit_price_tax_incl'] * $product['product_quantity'];
                            }
                            if (Tools::isSubmit('shippingBack')) {
                                $total += $order->total_shipping;
                            }
                            $cartrule->reduction_amount = $total;
                            $cartrule->reduction_tax = true;
                            $cartrule->minimum_amount_currency = $order->id_currency;
                            $cartrule->reduction_currency = $order->id_currency;
                            if (!$cartrule->add()) {
                                $this->errors[] = Tools::displayError('Cannot generate voucher');
                            } else {
                                // Update the voucher code and name
                                foreach ($languages as $language) {
                                    $cartrule->name[$language['id_lang']] = 'V' . (int) $cartrule->id . 'C' . (int) $order->id_customer . 'O' . $order->id;
                                }
                                $cartrule->code = 'V' . (int) $cartrule->id . 'C' . (int) $order->id_customer . 'O' . $order->id;
                                if (!$cartrule->update()) {
                                    $this->errors[] = Tools::displayError('Cannot generate voucher');
                                } else {
                                    $currency = $this->context->currency;
                                    $params['{voucher_amount}'] = Tools::displayPrice($cartrule->reduction_amount, $currency, false);
                                    $params['{voucher_num}'] = $cartrule->code;
                                    @Mail::Send((int) $order->id_lang, 'voucher', sprintf(Mail::l('New voucher regarding your order %s', (int) $order->id_lang), $order->reference), $params, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, true, (int) $order->id_shop);
                                }
                            }
                        }
                    } else {
                        $this->errors[] = Tools::displayError('No product or quantity selected.');
                    }
                    // Redirect if no errors
                    if (!count($this->errors)) {
                        Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=31&token=' . $this->token);
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to delete here.');
            }
        } elseif (Tools::isSubmit('messageReaded')) {
            Message::markAsReaded(Tools::getValue('messageReaded'), $this->context->employee->id);
        } elseif (Tools::isSubmit('submitAddPayment') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $amount = str_replace(',', '.', Tools::getValue('payment_amount'));
                $currency = new Currency(Tools::getValue('payment_currency'));
                $order_has_invoice = $order->hasInvoice();
                if ($order_has_invoice) {
                    $order_invoice = new OrderInvoice(Tools::getValue('payment_invoice'));
                } else {
                    $order_invoice = null;
                }
                if (!Validate::isLoadedObject($order)) {
                    $this->errors[] = Tools::displayError('Order can\'t be found');
                } elseif (!Validate::isNegativePrice($amount)) {
                    $this->errors[] = Tools::displayError('Amount is invalid');
                } elseif (!Validate::isString(Tools::getValue('payment_method'))) {
                    $this->errors[] = Tools::displayError('Payment method is invalid');
                } elseif (!Validate::isString(Tools::getValue('payment_transaction_id'))) {
                    $this->errors[] = Tools::displayError('Transaction ID is invalid');
                } elseif (!Validate::isLoadedObject($currency)) {
                    $this->errors[] = Tools::displayError('Currency is invalid');
                } elseif ($order_has_invoice && !Validate::isLoadedObject($order_invoice)) {
                    $this->errors[] = Tools::displayError('Invoice is invalid');
                } elseif (!Validate::isDate(Tools::getValue('payment_date'))) {
                    $this->errors[] = Tools::displayError('Date is invalid');
                } else {
                    if (!$order->addOrderPayment($amount, Tools::getValue('payment_method'), Tools::getValue('payment_transaction_id'), $currency, Tools::getValue('payment_date'), $order_invoice)) {
                        $this->errors[] = Tools::displayError('An error occurred on adding order payment');
                    } else {
                        Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::isSubmit('submitEditNote')) {
            $note = Tools::getValue('note');
            $order_invoice = new OrderInvoice((int) Tools::getValue('id_order_invoice'));
            if (Validate::isLoadedObject($order_invoice) && Validate::isCleanHtml($note)) {
                if ($this->tabAccess['edit'] === '1') {
                    $order_invoice->note = $note;
                    if ($order_invoice->save()) {
                        Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order_invoice->id_order . '&vieworder&conf=4&token=' . $this->token);
                    } else {
                        $this->errors[] = Tools::displayError('Unable to save invoice note.');
                    }
                } else {
                    $this->errors[] = Tools::displayError('You do not have permission to edit here.');
                }
            } else {
                $this->errors[] = Tools::displayError('Unable to load invoice for edit note.');
            }
        } elseif (Tools::isSubmit('submitAddOrder') && ($id_cart = Tools::getValue('id_cart')) && ($module_name = Tools::getValue('payment_module_name')) && ($id_order_state = Tools::getValue('id_order_state')) && Validate::isModuleName($module_name)) {
            if ($this->tabAccess['edit'] === '1') {
                $payment_module = Module::getInstanceByName($module_name);
                $cart = new Cart((int) $id_cart);
                Context::getContext()->currency = new Currency((int) $cart->id_currency);
                Context::getContext()->customer = new Customer((int) $cart->id_customer);
                $employee = new Employee((int) Context::getContext()->cookie->id_employee);
                $payment_module->validateOrder((int) $cart->id, (int) $id_order_state, $cart->getOrderTotal(true, Cart::BOTH), $payment_module->displayName, $this->l('Manual order - Employee:') . Tools::safeOutput(substr($employee->firstname, 0, 1) . '. ' . $employee->lastname), array(), null, false, $cart->secure_key);
                if ($payment_module->currentOrder) {
                    Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $payment_module->currentOrder . '&vieworder' . '&token=' . $this->token);
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to add here.');
            }
        } elseif ((Tools::isSubmit('submitAddressShipping') || Tools::isSubmit('submitAddressInvoice')) && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $address = new Address(Tools::getValue('id_address'));
                if (Validate::isLoadedObject($address)) {
                    // Update the address on order
                    if (Tools::isSubmit('submitAddressShipping')) {
                        $order->id_address_delivery = $address->id;
                    } elseif (Tools::isSubmit('submitAddressInvoice')) {
                        $order->id_address_invoice = $address->id;
                    }
                    $order->update();
                    Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
                } else {
                    $this->errors[] = Tools::displayErrror('This address can\'t be loaded');
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::isSubmit('submitChangeCurrency') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                if (Tools::getValue('new_currency') != $order->id_currency && !$order->valid) {
                    $old_currency = new Currency($order->id_currency);
                    $currency = new Currency(Tools::getValue('new_currency'));
                    if (!Validate::isLoadedObject($currency)) {
                        throw new PrestaShopException('Can\'t load Currency object');
                    }
                    // Update order detail amount
                    foreach ($order->getOrderDetailList() as $row) {
                        $order_detail = new OrderDetail($row['id_order_detail']);
                        $fields = array('ecotax', 'product_price', 'reduction_amount', 'total_shipping', 'total_shipping_tax_excl', 'total_shipping_tax_incl', 'total_products', 'total_products_wt', 'total_paid', 'total_paid_tax_incl', 'total_paid_tax_excl', 'total_paid_real', 'product_quantity_discount', 'purchase_supplier_price', 'reduction_amount_tax_incl', 'reduction_amount_tax_excl');
                        foreach ($fields as $field) {
                            $order_detail->{$field} = Tools::convertPriceFull($order_detail->{$field}, $old_currency, $currency);
                        }
                        $order_detail->update();
                    }
                    $id_order_carrier = Db::getInstance()->getValue('
						SELECT `id_order_carrier`
						FROM `' . _DB_PREFIX_ . 'order_carrier`
						WHERE `id_order` = ' . (int) $order->id);
                    if ($id_order_carrier) {
                        $order_carrier = new OrderCarrier($id_order_carrier);
                        $order_carrier->shipping_cost_tax_excl = (double) Tools::convertPriceFull($order_carrier->shipping_cost_tax_excl, $old_currency, $currency);
                        $order_carrier->shipping_cost_tax_incl = (double) Tools::convertPriceFull($order_carrier->shipping_cost_tax_incl, $old_currency, $currency);
                        $order_carrier->update();
                    }
                    // Update order amount
                    $fields = array('total_discounts', 'total_discounts_tax_incl', 'total_discounts_tax_excl', 'total_paid', 'total_paid_tax_incl', 'total_paid_tax_excl', 'total_paid_real', 'total_products', 'total_products_wt', 'total_shipping', 'total_shipping_tax_incl', 'total_shipping_tax_excl', 'total_wrapping', 'total_wrapping_tax_incl', 'total_wrapping_tax_excl');
                    foreach ($fields as $field) {
                        $order->{$field} = Tools::convertPriceFull($order->{$field}, $old_currency, $currency);
                    }
                    // Update currency in order
                    $order->id_currency = $currency->id;
                    $order->update();
                } else {
                    $this->errors[] = Tools::displayError('You cannot change the currency');
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::isSubmit('submitGenerateInvoice') && isset($order)) {
            if (!Configuration::get('PS_INVOICE')) {
                $this->errors[] = Tools::displayError('Invoice management has been disabled');
            } elseif ($order->hasInvoice()) {
                $this->errors[] = Tools::displayError('This order already has an invoice');
            } else {
                $order->setInvoice(true);
                Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
            }
        } elseif (Tools::isSubmit('submitDeleteVoucher') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                $order_cart_rule = new OrderCartRule(Tools::getValue('id_order_cart_rule'));
                if (Validate::isLoadedObject($order_cart_rule) && $order_cart_rule->id_order == $order->id) {
                    if ($order_cart_rule->id_order_invoice) {
                        $order_invoice = new OrderInvoice($order_cart_rule->id_order_invoice);
                        if (!Validate::isLoadedObject($order_invoice)) {
                            throw new PrestaShopException('Can\'t load Order Invoice object');
                        }
                        // Update amounts of Order Invoice
                        $order_invoice->total_discount_tax_excl -= $order_cart_rule->value_tax_excl;
                        $order_invoice->total_discount_tax_incl -= $order_cart_rule->value;
                        $order_invoice->total_paid_tax_excl += $order_cart_rule->value_tax_excl;
                        $order_invoice->total_paid_tax_incl += $order_cart_rule->value;
                        // Update Order Invoice
                        $order_invoice->update();
                    }
                    // Update amounts of order
                    $order->total_discounts -= $order_cart_rule->value;
                    $order->total_discounts_tax_incl -= $order_cart_rule->value;
                    $order->total_discounts_tax_excl -= $order_cart_rule->value_tax_excl;
                    $order->total_paid += $order_cart_rule->value;
                    $order->total_paid_tax_incl += $order_cart_rule->value;
                    $order->total_paid_tax_excl += $order_cart_rule->value_tax_excl;
                    // Delete Order Cart Rule and update Order
                    $order_cart_rule->delete();
                    $order->update();
                    Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
                } else {
                    $this->errors[] = Tools::displayError('Cannot edit this Order Cart Rule');
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        } elseif (Tools::getValue('submitNewVoucher') && isset($order)) {
            if ($this->tabAccess['edit'] === '1') {
                if (!Tools::getValue('discount_name')) {
                    $this->errors[] = Tools::displayError('You must specify a name in order to create a new discount');
                } else {
                    if ($order->hasInvoice()) {
                        // If the discount is for only one invoice
                        if (!Tools::isSubmit('discount_all_invoices')) {
                            $order_invoice = new OrderInvoice(Tools::getValue('discount_invoice'));
                            if (!Validate::isLoadedObject($order_invoice)) {
                                throw new PrestaShopException('Can\'t load Order Invoice object');
                            }
                        }
                    }
                    $cart_rules = array();
                    switch (Tools::getValue('discount_type')) {
                        // Percent type
                        case 1:
                            if (Tools::getValue('discount_value') < 100) {
                                if (isset($order_invoice)) {
                                    $cart_rules[$order_invoice->id]['value_tax_incl'] = Tools::ps_round($order_invoice->total_paid_tax_incl * Tools::getValue('discount_value') / 100, 2);
                                    $cart_rules[$order_invoice->id]['value_tax_excl'] = Tools::ps_round($order_invoice->total_paid_tax_excl * Tools::getValue('discount_value') / 100, 2);
                                    // Update OrderInvoice
                                    $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                } elseif ($order->hasInvoice()) {
                                    $order_invoices_collection = $order->getInvoicesCollection();
                                    foreach ($order_invoices_collection as $order_invoice) {
                                        $cart_rules[$order_invoice->id]['value_tax_incl'] = Tools::ps_round($order_invoice->total_paid_tax_incl * Tools::getValue('discount_value') / 100, 2);
                                        $cart_rules[$order_invoice->id]['value_tax_excl'] = Tools::ps_round($order_invoice->total_paid_tax_excl * Tools::getValue('discount_value') / 100, 2);
                                        // Update OrderInvoice
                                        $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                    }
                                } else {
                                    $cart_rules[0]['value_tax_incl'] = Tools::ps_round($order->total_paid_tax_incl * Tools::getValue('discount_value') / 100, 2);
                                    $cart_rules[0]['value_tax_excl'] = Tools::ps_round($order->total_paid_tax_excl * Tools::getValue('discount_value') / 100, 2);
                                }
                            } else {
                                $this->errors[] = Tools::displayError('Discount value is invalid');
                            }
                            break;
                            // Amount type
                        // Amount type
                        case 2:
                            if (isset($order_invoice)) {
                                if (Tools::getValue('discount_value') > $order_invoice->total_paid_tax_incl) {
                                    $this->errors[] = Tools::displayError('Discount value is greater than the order invoice total');
                                } else {
                                    $cart_rules[$order_invoice->id]['value_tax_incl'] = Tools::ps_round(Tools::getValue('discount_value'), 2);
                                    $cart_rules[$order_invoice->id]['value_tax_excl'] = Tools::ps_round(Tools::getValue('discount_value') / (1 + $order->getTaxesAverageUsed() / 100), 2);
                                    // Update OrderInvoice
                                    $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                }
                            } elseif ($order->hasInvoice()) {
                                $order_invoices_collection = $order->getInvoicesCollection();
                                foreach ($order_invoices_collection as $order_invoice) {
                                    if (Tools::getValue('discount_value') > $order_invoice->total_paid_tax_incl) {
                                        $this->errors[] = Tools::displayError('Discount value is greater than the order invoice total (Invoice:') . $order_invoice->getInvoiceNumberFormatted(Context::getContext()->language->id) . ')';
                                    } else {
                                        $cart_rules[$order_invoice->id]['value_tax_incl'] = Tools::ps_round(Tools::getValue('discount_value'), 2);
                                        $cart_rules[$order_invoice->id]['value_tax_excl'] = Tools::ps_round(Tools::getValue('discount_value') / (1 + $order->getTaxesAverageUsed() / 100), 2);
                                        // Update OrderInvoice
                                        $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                    }
                                }
                            } else {
                                if (Tools::getValue('discount_value') > $order->total_paid_tax_incl) {
                                    $this->errors[] = Tools::displayError('Discount value is greater than the order total');
                                } else {
                                    $cart_rules[0]['value_tax_incl'] = Tools::ps_round(Tools::getValue('discount_value'), 2);
                                    $cart_rules[0]['value_tax_excl'] = Tools::ps_round(Tools::getValue('discount_value') / (1 + $order->getTaxesAverageUsed() / 100), 2);
                                }
                            }
                            break;
                            // Free shipping type
                        // Free shipping type
                        case 3:
                            if (isset($order_invoice)) {
                                if ($order_invoice->total_shipping_tax_incl > 0) {
                                    $cart_rules[$order_invoice->id]['value_tax_incl'] = $order_invoice->total_shipping_tax_incl;
                                    $cart_rules[$order_invoice->id]['value_tax_excl'] = $order_invoice->total_shipping_tax_excl;
                                    // Update OrderInvoice
                                    $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                }
                            } elseif ($order->hasInvoice()) {
                                $order_invoices_collection = $order->getInvoicesCollection();
                                foreach ($order_invoices_collection as $order_invoice) {
                                    if ($order_invoice->total_shipping_tax_incl <= 0) {
                                        continue;
                                    }
                                    $cart_rules[$order_invoice->id]['value_tax_incl'] = $order_invoice->total_shipping_tax_incl;
                                    $cart_rules[$order_invoice->id]['value_tax_excl'] = $order_invoice->total_shipping_tax_excl;
                                    // Update OrderInvoice
                                    $this->applyDiscountOnInvoice($order_invoice, $cart_rules[$order_invoice->id]['value_tax_incl'], $cart_rules[$order_invoice->id]['value_tax_excl']);
                                }
                            } else {
                                $cart_rules[0]['value_tax_incl'] = $order->total_shipping_tax_incl;
                                $cart_rules[0]['value_tax_excl'] = $order->total_shipping_tax_excl;
                            }
                            break;
                        default:
                            $this->errors[] = Tools::displayError('Discount type is invalid');
                    }
                    $res = true;
                    foreach ($cart_rules as &$cart_rule) {
                        $cartRuleObj = new CartRule();
                        $cartRuleObj->date_from = date('Y-m-d H:i:s', strtotime('-1 hour', strtotime($order->date_add)));
                        $cartRuleObj->date_to = date('Y-m-d H:i:s', strtotime('+1 hour'));
                        $cartRuleObj->name[Configuration::get('PS_LANG_DEFAULT')] = Tools::getValue('discount_name');
                        $cartRuleObj->quantity = 0;
                        $cartRuleObj->quantity_per_user = 1;
                        if (Tools::getValue('discount_type') == 1) {
                            $cartRuleObj->reduction_percent = Tools::getValue('discount_value');
                        } elseif (Tools::getValue('discount_type') == 2) {
                            $cartRuleObj->reduction_amount = $cart_rule['value_tax_excl'];
                        } elseif (Tools::getValue('discount_type') == 3) {
                            $cartRuleObj->free_shipping = 1;
                        }
                        $cartRuleObj->active = 0;
                        if ($res = $cartRuleObj->add()) {
                            $cart_rule['id'] = $cartRuleObj->id;
                        } else {
                            break;
                        }
                    }
                    if ($res) {
                        foreach ($cart_rules as $id_order_invoice => $cart_rule) {
                            // Create OrderCartRule
                            $order_cart_rule = new OrderCartRule();
                            $order_cart_rule->id_order = $order->id;
                            $order_cart_rule->id_cart_rule = $cart_rule['id'];
                            $order_cart_rule->id_order_invoice = $id_order_invoice;
                            $order_cart_rule->name = Tools::getValue('discount_name');
                            $order_cart_rule->value = $cart_rule['value_tax_incl'];
                            $order_cart_rule->value_tax_excl = $cart_rule['value_tax_excl'];
                            $res &= $order_cart_rule->add();
                            $order->total_discounts += $order_cart_rule->value;
                            $order->total_discounts_tax_incl += $order_cart_rule->value;
                            $order->total_discounts_tax_excl += $order_cart_rule->value_tax_excl;
                            $order->total_paid -= $order_cart_rule->value;
                            $order->total_paid_tax_incl -= $order_cart_rule->value;
                            $order->total_paid_tax_excl -= $order_cart_rule->value_tax_excl;
                        }
                        // Update Order
                        $res &= $order->update();
                    }
                    if ($res) {
                        Tools::redirectAdmin(self::$currentIndex . '&id_order=' . $order->id . '&vieworder&conf=4&token=' . $this->token);
                    } else {
                        $this->errors[] = Tools::displayError('An error occurred on OrderCartRule creation');
                    }
                }
            } else {
                $this->errors[] = Tools::displayError('You do not have permission to edit here.');
            }
        }
        parent::postProcess();
    }