Esempio n. 1
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.');
     }
 }
 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. 3
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. 4
0
    /**
     * Sets the new state of the given order
     *
     * @param int $new_order_state
     * @param int/object $id_order
     * @param bool $use_existing_payment
     */
    public function changeIdOrderState($new_order_state, $id_order, $use_existing_payment = false)
    {
        if (!$new_order_state || !$id_order) {
            return;
        }
        if (!is_object($id_order) && is_numeric($id_order)) {
            $order = new Order((int) $id_order);
        } elseif (is_object($id_order)) {
            $order = $id_order;
        } else {
            return;
        }
        ShopUrl::cacheMainDomainForShop($order->id_shop);
        $new_os = new OrderState((int) $new_order_state, $order->id_lang);
        $old_os = $order->getCurrentOrderState();
        $is_validated = $this->isValidated();
        // executes hook
        if (in_array($new_os->id, array(Configuration::get('PS_OS_PAYMENT'), Configuration::get('PS_OS_WS_PAYMENT')))) {
            Hook::exec('actionPaymentConfirmation', array('id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        }
        // executes hook
        Hook::exec('actionOrderStatusUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        if (Validate::isLoadedObject($order) && $new_os instanceof OrderState) {
            // An email is sent the first time a virtual item is validated
            $virtual_products = $order->getVirtualProducts();
            if ($virtual_products && (!$old_os || !$old_os->logable) && $new_os && $new_os->logable) {
                $context = Context::getContext();
                $assign = array();
                foreach ($virtual_products as $key => $virtual_product) {
                    $id_product_download = ProductDownload::getIdFromIdProduct($virtual_product['product_id']);
                    $product_download = new ProductDownload($id_product_download);
                    // If this virtual item has an associated file, we'll provide the link to download the file in the email
                    if ($product_download->display_filename != '') {
                        $assign[$key]['name'] = $product_download->display_filename;
                        $dl_link = $product_download->getTextLink(false, $virtual_product['download_hash']) . '&id_order=' . (int) $order->id . '&secure_key=' . $order->secure_key;
                        $assign[$key]['link'] = $dl_link;
                        if (isset($virtual_product['download_deadline']) && $virtual_product['download_deadline'] != '0000-00-00 00:00:00') {
                            $assign[$key]['deadline'] = Tools::displayDate($virtual_product['download_deadline']);
                        }
                        if ($product_download->nb_downloadable != 0) {
                            $assign[$key]['downloadable'] = (int) $product_download->nb_downloadable;
                        }
                    }
                }
                $customer = new Customer((int) $order->id_customer);
                $links = '<ul>';
                foreach ($assign as $product) {
                    $links .= '<li>';
                    $links .= '<a href="' . $product['link'] . '">' . Tools::htmlentitiesUTF8($product['name']) . '</a>';
                    if (isset($product['deadline'])) {
                        $links .= '&nbsp;' . Tools::htmlentitiesUTF8(Tools::displayError('expires on', false)) . '&nbsp;' . $product['deadline'];
                    }
                    if (isset($product['downloadable'])) {
                        $links .= '&nbsp;' . Tools::htmlentitiesUTF8(sprintf(Tools::displayError('downloadable %d time(s)', false), (int) $product['downloadable']));
                    }
                    $links .= '</li>';
                }
                $links .= '</ul>';
                $data = array('{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{id_order}' => (int) $order->id, '{order_name}' => $order->getUniqReference(), '{nbProducts}' => count($virtual_products), '{virtualProducts}' => $links);
                // If there's at least one downloadable file
                if (!empty($assign)) {
                    Mail::Send((int) $order->id_lang, 'download_product', Mail::l('Virtual product to download', $order->id_lang), $data, $customer->email, $customer->firstname . ' ' . $customer->lastname, null, null, null, null, _PS_MAIL_DIR_, false, (int) $order->id_shop);
                }
            }
            // @since 1.5.0 : gets the stock manager
            $manager = null;
            if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
                $manager = StockManagerFactory::getManager();
            }
            $errorOrCanceledStatuses = array(Configuration::get('PS_OS_ERROR'), Configuration::get('PS_OS_CANCELED'));
            // foreach products of the order
            if (Validate::isLoadedObject($old_os)) {
                foreach ($order->getProductsDetail() as $product) {
                    // if becoming logable => adds sale
                    if ($new_os->logable && !$old_os->logable) {
                        ProductSale::addProductSale($product['product_id'], $product['product_quantity']);
                        // @since 1.5.0 - Stock Management
                        if (!Pack::isPack($product['product_id']) && in_array($old_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'], (int) $order->id_shop)) {
                            StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int) $product['product_quantity'], $order->id_shop);
                        }
                    } elseif (!$new_os->logable && $old_os->logable) {
                        ProductSale::removeProductSale($product['product_id'], $product['product_quantity']);
                        // @since 1.5.0 - Stock Management
                        if (!Pack::isPack($product['product_id']) && in_array($new_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'])) {
                            StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                        }
                    } elseif (!$new_os->logable && !$old_os->logable && in_array($new_os->id, $errorOrCanceledStatuses) && !in_array($old_os->id, $errorOrCanceledStatuses) && !StockAvailable::dependsOnStock($product['id_product'])) {
                        StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
                    }
                    // @since 1.5.0 : if the order is being shipped and this products uses the advanced stock management :
                    // decrements the physical stock using $id_warehouse
                    if ($new_os->shipped == 1 && $old_os->shipped == 0 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                        // gets the warehouse
                        $warehouse = new Warehouse($product['id_warehouse']);
                        // decrements the stock (if it's a pack, the StockManager does what is needed)
                        $manager->removeProduct($product['product_id'], $product['product_attribute_id'], $warehouse, $product['product_quantity'], Configuration::get('PS_STOCK_CUSTOMER_ORDER_REASON'), true, (int) $order->id);
                    } elseif ($new_os->shipped == 0 && $old_os->shipped == 1 && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && Warehouse::exists($product['id_warehouse']) && $manager != null && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement($product['product_id']))) {
                        // if the product is a pack, we restock every products in the pack using the last negative stock mvts
                        if (Pack::isPack($product['product_id'])) {
                            $pack_products = Pack::getItems($product['product_id'], Configuration::get('PS_LANG_DEFAULT', null, null, $order->id_shop));
                            foreach ($pack_products as $pack_product) {
                                if ($pack_product->advanced_stock_management == 1) {
                                    $mvts = StockMvt::getNegativeStockMvts($order->id, $pack_product->id, 0, $pack_product->pack_quantity * $product['product_quantity']);
                                    foreach ($mvts as $mvt) {
                                        $manager->addProduct($pack_product->id, 0, new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                                    }
                                    if (!StockAvailable::dependsOnStock($product['id_product'])) {
                                        StockAvailable::updateQuantity($pack_product->id, 0, (int) $pack_product->pack_quantity * $product['product_quantity'], $order->id_shop);
                                    }
                                }
                            }
                        } else {
                            $mvts = StockMvt::getNegativeStockMvts($order->id, $product['product_id'], $product['product_attribute_id'], $product['product_quantity']);
                            foreach ($mvts as $mvt) {
                                $manager->addProduct($product['product_id'], $product['product_attribute_id'], new Warehouse($mvt['id_warehouse']), $mvt['physical_quantity'], null, $mvt['price_te'], true);
                            }
                        }
                    }
                }
            }
        }
        $this->id_order_state = (int) $new_order_state;
        // changes invoice number of order ?
        if (!Validate::isLoadedObject($new_os) || !Validate::isLoadedObject($order)) {
            die(Tools::displayError('Invalid new order state'));
        }
        // the order is valid if and only if the invoice is available and the order is not cancelled
        $order->current_state = $this->id_order_state;
        $order->valid = $new_os->logable;
        $order->update();
        if ($new_os->invoice && !$order->invoice_number) {
            $order->setInvoice($use_existing_payment);
        }
        // set orders as paid
        if ($new_os->paid == 1) {
            $invoices = $order->getInvoicesCollection();
            if ($order->total_paid != 0) {
                $payment_method = Module::getInstanceByName($order->module);
            }
            foreach ($invoices as $invoice) {
                $rest_paid = $invoice->getRestPaid();
                if ($rest_paid > 0) {
                    $payment = new OrderPayment();
                    $payment->order_reference = $order->reference;
                    $payment->id_currency = $order->id_currency;
                    $payment->amount = $rest_paid;
                    if ($order->total_paid != 0) {
                        $payment->payment_method = $payment_method->displayName;
                    } else {
                        $payment->payment_method = null;
                    }
                    // Update total_paid_real value for backward compatibility reasons
                    if ($payment->id_currency == $order->id_currency) {
                        $order->total_paid_real += $payment->amount;
                    } else {
                        $order->total_paid_real += Tools::ps_round(Tools::convertPrice($payment->amount, $payment->id_currency, false), 2);
                    }
                    $order->save();
                    $payment->conversion_rate = 1;
                    $payment->save();
                    Db::getInstance()->execute('
					INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_payment`
					VALUES(' . (int) $invoice->id . ', ' . (int) $payment->id . ', ' . (int) $order->id . ')');
                }
            }
        }
        // updates delivery date even if it was already set by another state change
        if ($new_os->delivery) {
            $order->setDelivery();
        }
        // executes hook
        Hook::exec('actionOrderStatusPostUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
        ShopUrl::resetMainDomainCache();
    }
    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();
    }