Current File : /var/www/vinorea/modules/ipexportimport/classes/import/order/EIAOrdersImport.php
<?php
/**
 *
 * NOTICE OF LICENSE
 *
 *  @author    SmartPresta <tehran.alishov@gmail.com>
 *  @copyright 2024 SmartPresta
 *  @license   Commercial License
 */

if (!defined('_PS_VERSION_')) {
    exit;
}

//require_once dirname(__FILE__) . '/EIAImportProcess.php';
require_once dirname(__FILE__) . '/EIAOrder.php';
require_once dirname(__FILE__) . '/EIAPayment.php';
require_once dirname(__FILE__) . '/EIAError.php';
require_once dirname(__FILE__) . '/EIAOrderHistory.php';

use PhpOffice\PhpSpreadsheet\IOFactory;

class EIAOrdersImport
{

    public static $column_mask;
    public $path;
    public $importDir;
    public $entity;
    public $file;
    public $fields;
    public $module;
    public $context;
    public $shops;
    public $orderIdentifier;
    public $customerIdentifier;
    public $addressIdentifier;
    public $createNewCustomer;
    public $createNewAddress;
    public $productIdentifier;
    public $combinationIdentifier;
    public $errors;
    public $warnings;
    public $available_fields = [];
    public $required_fields = [];
    public static $custom_type_value;
    public static $default_values = [];
    public static $validators = [
        'order.valid' => ['EIAOrdersImport', 'getBoolean'],
        'order.conversion_rate' => ['EIAOrdersImport', 'getPrice'],
        'order.total_discounts' => ['EIAOrdersImport', 'getPrice'],
        'order.total_discounts_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_discounts_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_paid' => ['EIAOrdersImport', 'getPrice'],
        'order.total_paid_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_paid_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_paid_real' => ['EIAOrdersImport', 'getPrice'],
        'order.total_products' => ['EIAOrdersImport', 'getPrice'],
        'order.total_products_wt' => ['EIAOrdersImport', 'getPrice'],
        'order.total_shipping' => ['EIAOrdersImport', 'getPrice'],
        'order.total_shipping_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_shipping_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order.carrier_tax_rate' => ['EIAOrdersImport', 'getPrice'],
        'order.total_wrapping' => ['EIAOrdersImport', 'getPrice'],
        'order.total_wrapping_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order.total_wrapping_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        
        'order_detail.reduction_percent' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.reduction_amount' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.reduction_amount_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.reduction_amount_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.group_reduction' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.product_weight' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.tax_rate' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.ecotax' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.ecotax_tax_rate' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.total_price_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.total_price_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.unit_price_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.unit_price_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.total_shipping_price_tax_incl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.total_shipping_price_tax_excl' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.purchase_supplier_price' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.original_product_price' => ['EIAOrdersImport', 'getPrice'],
        'order_detail.original_wholesale_price' => ['EIAOrdersImport', 'getPrice'],
        
        'order.history' => ['EIAOrdersImport', 'split'],
        'order.cart_rule_name' => ['EIAOrdersImport', 'split'],
        'order.cart_rule_code' => ['EIAOrdersImport', 'split'],
        'order.cart_rule_value' => ['EIAOrdersImport', 'split'],
        'order.cart_rule_value_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.cart_rule_free_shipping' => ['EIAOrdersImport', 'split'],
        'order.id_order_invoice' => ['EIAOrdersImport', 'split'],
        'order.inv_number' => ['EIAOrdersImport', 'split'],
        'order.invoice_delivery_number' => ['EIAOrdersImport', 'split'],
        'order.invoice_delivery_date' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_discount_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_discount_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_paid_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_paid_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_products' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_products_wt' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_shipping_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_shipping_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.invoice_shipping_tax_computation_method' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_wrapping_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.invoice_total_wrapping_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.invoice_shop_address' => ['EIAOrdersImport', 'split'],
        'order.invoice_address' => ['EIAOrdersImport', 'split'],
        'order.invoice_delivery_address' => ['EIAOrdersImport', 'split'],
        'order.invoice_note' => ['EIAOrdersImport', 'split'],
        'order.invoice_date_add' => ['EIAOrdersImport', 'split'],
        'order.invoice_tax' => ['EIAOrdersImport', 'split'],
        'order.id_invoice_payment' => ['EIAOrdersImport', 'split'],
        'order.id_order_slip' => ['EIAOrdersImport', 'split'],
        'order.order_slip_total_products_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.order_slip_total_products_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.order_slip_total_shipping_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.order_slip_total_shipping_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.order_slip_amount' => ['EIAOrdersImport', 'split'],
        'order.order_slip_shipping_cost' => ['EIAOrdersImport', 'split'],
        'order.order_slip_shipping_cost_amount' => ['EIAOrdersImport', 'split'],
        'order.order_slip_partial' => ['EIAOrdersImport', 'split'],
        'order.order_slip_type' => ['EIAOrdersImport', 'split'],
        'order.order_slip_date_add' => ['EIAOrdersImport', 'split'],
        'order_detail.id_tax' => ['EIAOrdersImport', 'split'],
        'order_detail.tax_name_new' => ['EIAOrdersImport', 'split'],
        'order_detail.unit_amount_tax' => ['EIAOrdersImport', 'split'],
        'order_detail.total_amount_tax' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_product_quantity' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_unit_price_tax_excl' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_unit_price_tax_incl' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_total_price_tax_excl' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_total_price_tax_incl' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_amount_tax_excl' => ['EIAOrdersImport', 'split'],
        'order_detail.order_slip_amount_tax_incl' => ['EIAOrdersImport', 'split'],
        'payment.id_order_payment' => ['EIAOrdersImport', 'split'],
        'payment.id_currency' => ['EIAOrdersImport', 'split'],
        'payment.currency_iso_code' => ['EIAOrdersImport', 'split'],
        'payment.amount' => ['EIAOrdersImport', 'split'],
        'payment.date_add' => ['EIAOrdersImport', 'split'],
        'payment.payment_method' => ['EIAOrdersImport', 'split'],
        'payment.conversion_rate' => ['EIAOrdersImport', 'split'],
        'payment.transaction_id' => ['EIAOrdersImport', 'split'],
        'payment.card_number' => ['EIAOrdersImport', 'split'],
        'payment.card_brand' => ['EIAOrdersImport', 'split'],
        'payment.card_expiration' => ['EIAOrdersImport', 'split'],
        'payment.card_holder' => ['EIAOrdersImport', 'split'],
        'order.ids_order_carrier' => ['EIAOrdersImport', 'split'],
        'order.ids_carrier' => ['EIAOrdersImport', 'split'],
        'order.ids_reference' => ['EIAOrdersImport', 'split'],
        'order.carrier_names' => ['EIAOrdersImport', 'split'],
        'order.carrier_weight' => ['EIAOrdersImport', 'split'],
        'order.carrier_tracking_number' => ['EIAOrdersImport', 'split'],
        'order.carrier_shipping_cost_tax_excl' => ['EIAOrdersImport', 'split'],
        'order.carrier_shipping_cost_tax_incl' => ['EIAOrdersImport', 'split'],
        'order.carrier_date_add' => ['EIAOrdersImport', 'split'],
        'customer.groups' => ['EIAOrdersImport', 'split'],

    ];
    
    public $separator;
    public $enclosure;
    public $convert;
    public $multivalueSeparator;
    public $importMethod;
    public $nameExists;
    public $updateBy;
    public static $keepOldValue;
    public $eIOHelper;

    public function __construct($that)
    {
        $this->module = $that->module;
        $this->context = Context::getContext();

        $this->importDir = dirname(__FILE__) . '/../../import/';

        $this->eIOHelper = $that->eIOHelper;
        $this->entity = $that->eIOHelper->entity;
        $this->fields = $that->eIOHelper->fields;
        $this->available_fields = $that->eIOHelper->available_fields;
        $this->required_fields = $that->eIOHelper->required_fields;

        switch ($this->entity) {
            case 'orders':
                self::$default_values = [
                    'order.valid' => '1',
                    'order_detail.product_weight' => 0.000000,
                ];
                break;
        }
    }

    public function import()
    {
//        if (session_status() === PHP_SESSION_NONE) {
//            session_start();
//        }

        $filename = Tools::getValue('filename');
        $this->file = $this->importDir . $this->entity . '/' . $filename;

        if (!file_exists($this->file)) {
            die(json_encode(['errors' => [sprintf($this->module->l('File "%s" does not exist!', 'EIAOrdersImport'), $this->file)]]));
        }

        $this->separator = Tools::getValue('csv_separator');
        if ($this->separator === 'other') {
            $this->separator = Tools::getValue('custom_separator');
        }
        if ($this->separator === 't') {
            $this->separator = "\t";
        }
        $this->enclosure = '"';
        $this->multivalueSeparator = Tools::getValue('multivalue_separator') ?: ',';

        //        if ($this->enclosure === 'none') {
        //            $this->enclosure = '';
        //        } elseif ($this->enclosure === 'quot') {
        //            $this->enclosure = '"';
        //        }

        if (in_array(Tools::strtolower(pathinfo($filename, PATHINFO_EXTENSION)), ['xls', 'xlsx', 'ods'])) {
            if (file_exists($newFile = $this->importDir . 'tmp/' . pathinfo($filename, PATHINFO_FILENAME) . '.csv')) {
                $this->file = $newFile;
            } elseif (file_exists($this->file)) {
//                require_once dirname(__FILE__) . '/../../vendor/autoload.php';
                $spreadsheet = IOFactory::load($this->file);
                $writer = IOFactory::createWriter($spreadsheet, 'Csv');
                $writer->setDelimiter($this->separator);
                $writer->setEnclosure($this->enclosure);
                $writer->save($this->file = $newFile);
            }
        }

        $this->shops = [];
        if (Shop::isFeatureActive() && ($shops = Tools::getValue('shops'))) {
            foreach ($shops as $shop => $true) {
                if ($true) {
                    $this->shops[] = $shop;
                }
            }
        }
        if (empty($this->shops)) {
            $this->shops[] = (int) $this->context->shop->id;
        }

        $this->convert = (int) Tools::getValue('convert');

        $offset = (int) Tools::getValue('offset');
        $limit = (int) Tools::getValue('limit');
        $validateOnly = ((int) Tools::getValue('validateOnly') == 1);
        $moreStep = (int) Tools::getValue('moreStep');

        if (!$offset && !$moreStep) {
            $_SESSION['ip_import'] = [
                'accessories' => [],
                'redirects' => []
            ];
        }

        $results = [];
        $this->importByGroups($offset, $limit, $results, $validateOnly, $moreStep);

        // Retrieve errors/warnings if any
        if (isset($this->errors) && count($this->errors) > 0) {
            $results['errors'] = $this->errors;
        }
        if (isset($this->warnings) && count($this->warnings) > 0) {
            $results['warnings'] = $this->warnings;
        }
        if (isset($this->informations) && count($this->informations) > 0) {
            $results['informations'] = $this->informations;
        }

        if (!$validateOnly && (bool) $results['isFinished'] && !isset($results['oneMoreStep'])) {
            if (isset($_SESSION['ip_import'])) {
                unset($_SESSION['ip_import']);
            }
            if ((bool) Tools::getValue('send_email')) {
                // Mail::Send() can sometimes throw an error...
                try {
                    // Mail send in last step because in case of failure, does NOT throw an error.
                    $mail_iso = $this->context->language->iso_code;
                    if (!file_exists(dirname(__FILE__) . '/../../mails/' . $mail_iso . '/import.txt') ||
                            !file_exists(dirname(__FILE__) . '/../../mails/' . $mail_iso . '/import.html')
                    ) {
                        $this->copyDir(dirname(__FILE__) . '/../../mails/en', dirname(__FILE__) . '/../../mails/' . $mail_iso);
                    }
                    $mail_dir = dirname(__FILE__) . '/../../mails/';

                    if ($this->context->employee) {
                        $templateVars = [
                            '{firstname}' => $this->context->employee->firstname,
                            '{lastname}' => $this->context->employee->lastname,
                            '{filename}' => Tools::getValue('filename'),
                        ];
                        $conf = [
                            'id_lang' => (int) $this->context->employee->id_lang,
                            'email' => $this->context->employee->email,
                            'name' => $this->context->employee->firstname . ' ' . $this->context->employee->lastname,
                        ];
                    } else {
                        $employee = new Employee((int) Tools::getValue('id_employee'));
                        $templateVars = [
                            '{firstname}' => $employee->firstname,
                            '{lastname}' => $employee->lastname,
                            '{filename}' => Tools::getValue('filename'),
                        ];
                        $conf = [
                            'id_lang' => (int) $employee->id_lang,
                            'email' => $employee->email,
                            'name' => $employee->firstname . ' ' . $employee->lastname,
                        ];
                    }

                    $mailSuccess = @Mail::Send(
                                    $conf['id_lang'],
                                    'import',
                                    $this->module->l('Import complete', 'EIAOrdersImport'),
                                    $templateVars,
                                    $conf['email'],
                                    $conf['name'],
                                    null,
                                    null,
                                    null,
                                    null,
                                    $mail_dir,
                                    false, // do not die in failed! Warn only, it's not an import error, because import finished in fact.
                                    (int) $this->context->shop->id
                    );
                    if (!$mailSuccess) {
                        $results['warnings'][] = $this->module->l('The confirmation email couldn\'t be sent, but the import is successful. Yay!', 'EIAOrdersImport');
                    }
                } catch (\Exception $e) {
                    $results['warnings'][] = $this->module->l('The confirmation email couldn\'t be sent, but the import is successful. Yay!', 'EIAOrdersImport');
                }
            }
        }

        die(json_encode($results));
    }

    public function importByGroups($offset = false, $limit = false, &$results = null, $validateOnly = false, $moreStep = 0)
    {
        // Check if the file exist
        if (Tools::getValue('filename')) {
            $this->importMethod = Tools::getValue('import_method');
            $this->orderIdentifier = Tools::getValue('order_identifier');
            $this->customerIdentifier = Tools::getValue('customer_identifier');
            $this->addressIdentifier = Tools::getValue('address_identifier');
            $this->createNewCustomer = Tools::getValue('create_new_customer');
            $this->createNewAddress= Tools::getValue('create_new_address');
            $this->productIdentifier= Tools::getValue('product_identifier');
            $this->combinationIdentifier= Tools::getValue('combination_identifier');
            $this->nameExists = Tools::getValue('name_exists');
            $this->updateBy = Tools::getValue('update_by');
            // It must be static, because we access it in the static method "fillInfo"
            self::$keepOldValue = Tools::getValue('keep_old_value');
            $shop_is_feature_active = Shop::isFeatureActive();
            // If i am a superadmin, i can truncate table (ONLY IF OFFSET == 0 or false and NOT FOR VALIDATION MODE!)
            if (!$offset && !$moreStep && !$validateOnly && (($shop_is_feature_active && !empty($this->context->employee) && $this->context->employee->isSuperAdmin()) || !$shop_is_feature_active) && $this->importMethod != 'update' && Tools::getValue('truncate')) {
                $this->truncateTables(Tools::getValue('entity'));
            }
            $import_type = false;
            $doneCount = 0;
            $moreStepLabels = [];
            // Sometime, import will use registers to memorize data across all elements to import (for trees, or else).
            // Since import is splitted in multiple ajax calls, we must keep these data across all steps of the full import.
            $crossStepsVariables = [];
            if (($crossStepsVars = Tools::getValue('crossStepsVars'))) {
                $crossStepsVars = json_decode($crossStepsVars, true);
                if (count($crossStepsVars) > 0) {
                    $crossStepsVariables = $crossStepsVars;
                }
            }
            Db::getInstance()->disableCache();
            $clearCache = false;
            if (Tools::getValue('entity') == 'orders') {
                $doneCount += $this->orderImport($offset, $limit, $validateOnly);
                $clearCache = true;
            }

            if ($results !== null) {
                $results['isFinished'] = ($doneCount < $limit);
                if ($results['isFinished'] && $clearCache && !$validateOnly) {
                    $this->clearSmartyCache();
                }
                $results['doneCount'] = $offset + $doneCount;
                if ($offset === 0) {
                    // compute total count only once, because it takes time
                    $handle = $this->openCsvFile(0);
                    if ($handle) {
                        $count = 0;
                        while (fgetcsv($handle, MAX_LINE_SIZE, $this->separator)) {
                            $count++;
                        }
                        $results['totalCount'] = $count;
                    }
                    $this->closeCsvFile($handle);
                }
                if (!$results['isFinished'] || (!$validateOnly && ($moreStep < count($moreStepLabels)))) {
                    // Since we'll have to POST this array from ajax for the next call, we should care about it size.
                    $nextPostSize = mb_strlen(json_encode($crossStepsVariables));
                    $results['crossStepsVariables'] = $crossStepsVariables;
                    $results['nextPostSize'] = $nextPostSize + (1024 * 64); // 64KB more for the rest of the POST query.
                    $results['postSizeLimit'] = Tools::getMaxUploadSize();
                }
                if ($results['isFinished'] && !$validateOnly && ($moreStep < count($moreStepLabels))) {
                    $results['oneMoreStep'] = $moreStep + 1;
                    $results['moreStepLabel'] = $moreStepLabels[$moreStep];
                }
            }

            if ($import_type !== false) {
                $log_message = sprintf($this->module->l('%s import', 'EIAOrdersImport'), $import_type);
                if ($offset !== false && $limit !== false) {
                    $log_message .= ' ' . sprintf($this->module->l('(from %s to %s)', 'EIAOrdersImport'), $offset, $limit);
                }
                if (Tools::getValue('truncate')) {
                    $log_message .= ' ' . $this->module->l('with truncate', 'EIAOrdersImport');
                }
                PrestaShopLogger::addLog($log_message, 1, null, $import_type, null, true, (int) $this->context->employee->id);
            }

            Db::getInstance()->enableCache();
        } else {
            $this->errors[] = $this->module->l('To proceed, please upload a file first.', 'EIAOrdersImport');
        }
    }

    public function clearSmartyCache()
    {
        Tools::enableCache();
        Tools::clearCache($this->context->smarty);
        Tools::restoreCacheSettings();
    }
    
    public function orderImport($offset = false, $limit = false, $validateOnly = false)
    {
        // Fill self::$column_mask array
        $this->receiveColumns();
        $handle = $this->openCsvFile($offset);
        if (!$handle) {
            return false;
        }

        $default_language_id = (int) Configuration::get('PS_LANG_DEFAULT');
        $id_lang = Tools::getValue('language');
        if (!Validate::isUnsignedId($id_lang)) {
            $id_lang = $default_language_id;
        }

        self::setLocale();

//        $shop_is_feature_active = Shop::isFeatureActive();
//        $force_id = Tools::getValue('keep_id');

        $line_count = 0;
        for ($current_line = 0; ($line = fgetcsv($handle, MAX_LINE_SIZE, $this->separator, $this->enclosure)) && (!$limit || $current_line < $limit); $current_line++) {
            $line_count++;
            if ($this->convert) {
                $line = $this->utf8EncodeArray($line);
            }
            
            $row = $offset + $line_count + 1;

            $isEmpty = true;
            foreach ($line as $ln) {
                if ($ln) {
                    $isEmpty = false;
                    break;
                }
            }

            if ($isEmpty) {
                $this->warnings[] = $this->module->l('There is an empty row in the file that won\'t be imported.', 'EIAImport');

                continue;
            }

            $info = self::getMaskedRow($line);
            
            if (!$this->eIOHelper->passedFilterForImport($info)) {
                continue;
            }

            // Set order lang
            if (empty($info['order']['id_lang']) && !empty($info['order']['lang_iso_code'])) {
                if (($id_lang = Language::getIdByIso(trim($info['order']['lang_iso_code'])))) {
                    $info['order']['id_lang'] = (int) $id_lang;
                }
            }
            
            $objOrderIdentify = new EIAIdentifyOrder($this->importMethod, $this->orderIdentifier, $info['order']);
            $id_order = $objOrderIdentify->identify();
            
            if ($id_order) {
//                $old_state = false;
//                if (is_numeric($id_order)) {
//                    $old_state = $this->getState($id_order);
//                }

                $objOrder = new EIAOrder($id_order, $this->orderIdentifier, $info, $row, 1, $validateOnly);

                $objCustomerIdentify = new EIAIdentifyCustomer($id_order, $objOrder->id_shop, $objOrder->id_lang, $this->customerIdentifier, $this->createNewCustomer, $info['customer'], $row, $validateOnly);
                $id_customer = $objCustomerIdentify->identify();
                if ($id_customer) {
                    $objOrder->id_customer = $id_customer;
                }

                $objShippingAddressIdentify = new EIAIdentifyAddress($id_order, $objOrder->id_shop, $objOrder->id_lang, $this->addressIdentifier, 'shipping', $this->createNewAddress, $info['address_delivery'], $id_customer, $row, $validateOnly);
                $id_address_delivery = $objShippingAddressIdentify->identify();
                if ($id_address_delivery) {
                    $objOrder->id_address_delivery = $id_address_delivery;
                }

                $objInvoiceAddressIdentify = new EIAIdentifyAddress($id_order, $objOrder->id_shop, $objOrder->id_lang, $this->addressIdentifier, 'invoice', $this->createNewAddress, $info['address_invoice'], $id_customer, $row, $validateOnly);
                $id_address_invoice = $objInvoiceAddressIdentify->identify();
                if ($id_address_invoice) {
                    $objOrder->id_address_invoice = $id_address_invoice;
                }

                $idOrder = $objOrder->update();
                if (!is_numeric($id_order) && $idOrder) {
                    $id_order = $idOrder;
                }

                if (!empty($objOrder->reference) && $id_order) {
                    $payment = new EIAPayment($id_order, $objOrder->reference, $info['payment'], $row, 1, $validateOnly);
                    $payment->save();
                }

                if (!empty($objOrder->baseOrderData['inv_number']) && $id_order) {
                    $invoice = new EIAOrderInvoice($id_order, $info['order'], $row, 1, $validateOnly, isset($payment) ? $payment : null);
                    $invoice->save();
                }

                if ((!empty($objOrder->baseOrderData['ids_carrier']) || !empty($objOrder->baseOrderData['carrier_names'])) && $id_order) {
                    $carrier = new EIAOrderCarrier($id_order, $info['order'], $row, 1, $validateOnly, isset($invoice) ? $invoice : null);
                    $carrier->save();
                }

                if ($id_order && is_numeric($id_order)) {
                    $this->saveOrderHistory($id_order, 1, $row, $info['order'], $validateOnly);
                }

                if (is_numeric($id_order) && !empty($info['order_detail'])) {
                    $product = new EIAOrderDetail($objOrder->id_shop, $objOrder->id_lang, $id_order, $this->productIdentifier, $this->combinationIdentifier, $info['order_detail'], $row, 1, $validateOnly);
                    $product->save();
                }
            } elseif ($this->importMethod == EIAConfigurationValidator::ONLY_INSERT_ORDERS && !empty($info['order_detail'])) {
                $id_order = $objOrderIdentify->getOrderId();
                $objOrder = new EIAOrder($id_order, $this->orderIdentifier, $info, $row, 1, $validateOnly);
                $product = new EIAOrderDetail($objOrder->id_shop, $objOrder->id_lang, $id_order, $this->productIdentifier, $this->combinationIdentifier, $info['order_detail'], $row, 1, $validateOnly);
                $product->save();
            } else {
                EIAError::createErrorsFile(EIATranslatorWrapper::l("No orders to import"));
            }
        }
        $this->closeCsvFile($handle);

        return $line_count;
    }
    
    private function saveOrderHistory($id_order, $id_process, $row, $orderData, $validateOnly)
    {
        if (!isset($orderData['history'])) {
            return;
        }
        
        if (!$validateOnly) {
            $this->deleteHistory($id_order);
        }
        
//        $id_status = $old_state;
//        if (isset($orderData['id_status']) && $orderData['id_status']) {
//            $id_status = $orderData['id_status'];
//        }

        foreach ($orderData['history'] as $state) {
            $state = explode('!', $state);
            $id_state = (int) trim($state[0]);
            $date_add = pSQL(trim($state[1]));
            $history = new EIAOrderHistory($id_order, $id_process, Tools::getValue('customer_notification'), $id_state, $date_add, $row, $validateOnly);
            $history->run();
        }
    }

    private function getState($id_order)
    {
        $sql = "
                SELECT current_state
                FROM " . _DB_PREFIX_ . "orders
                WHERE id_order = " . (int) $id_order . "
               ";
        return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
    }

    private function deleteHistory($id_order)
    {
        $sql = "
                DELETE FROM " . _DB_PREFIX_ . "order_history
                WHERE id_order = " . (int) $id_order . "
               ";
        return Db::getInstance(_PS_USE_SQL_SLAVE_)->execute($sql);
    }
    
    public function validateFields($row, $entity)
    {
        static $ps_allow_html_iframe = null;
        if ($ps_allow_html_iframe === null) {
            $ps_allow_html_iframe = (int) Configuration::get('PS_ALLOW_HTML_IFRAME');
        }

        foreach ($entity::$definition['fields'] as $field => $data) {
            // Check if field is required
            if (!empty($data['required'])) {
                if (Tools::isEmpty($row[$field])) {
                    return 'Property ' . $entity . '->' . $field . ' is empty';
                }
            }

            // Check field values
            if (!empty($data['values']) && is_array($data['values']) && !in_array($row[$field], $data['values'])) {
                return 'Property ' . $entity . '->' . $field . ' has bad value (allowed values are: ' . implode(', ', $data['values']) . ')';
            }

            // Check field size
            if (!empty($data['size'])) {
                $size = $data['size'];
                if (!is_array($data['size'])) {
                    $size = array('min' => 0, 'max' => $data['size']);
                }

                $length = Tools::strlen($row[$field]);
                if ($length < $size['min'] || $length > $size['max']) {
                    return 'Property ' . $entity . '->' . $field . ' length (' . $length . ') must be between ' . $size['min'] . ' and ' . $size['max'];
                }
            }
            // Check field validator
            if (!empty($data['validate'])) {
                if (!method_exists('Validate', $data['validate'])) {
                    throw new PrestaShopException('Validation function not found. ' . $data['validate']);
                }

                if (!empty($row[$field])) {
                    $res = true;
                    if (Tools::strtolower($data['validate']) == 'iscleanhtml') {
                        if (!call_user_func(array('Validate', $data['validate']), $row[$field], $ps_allow_html_iframe)) {
                            $res = false;
                        }
                    } else {
                        if (!call_user_func(array('Validate', $data['validate']), $row[$field])) {
                            $res = false;
                        }
                    }
                    if (!$res) {
                        return 'Property ' . $entity . '->' . $field . ' is not valid';
                    }
                }
            }
        }
        return true;
    }

    public static function arrayWalk(&$array, $funcname, &$user_data = false)
    {
        if (!is_callable($funcname)) {
            return false;
        }

        foreach ($array as $k => $row) {
            if (!call_user_func_array($funcname, [$row, $k, &$user_data])) {
                return false;
            }
        }

        return true;
    }

    public static function fillInfo($info, $key, &$entity)
    {
        $info = trim($info);
        if (isset(self::$validators[$key][1]) && self::$validators[$key][1] == 'createMultiLangField' && $id_lang = Tools::getValue('language')) {
            $tmp = call_user_func(self::$validators[$key], $info);
            foreach ($tmp as $id_lang_tmp => $value) {
                if (empty($entity->{$key}[$id_lang_tmp]) || $id_lang_tmp == $id_lang) {
                    $entity->{$key}[$id_lang_tmp] = $value;
                }
            }
        } elseif (!empty($info) || $info == '0' || !self::$keepOldValue) { // ($infos == '0') => if you want to disable a product by using "0" in active because empty('0') return true
            $entity->{$key} = isset(self::$validators[$key]) ? call_user_func(self::$validators[$key], $info) : $info;
        }

        return true;
    }

    protected static function getBoolean($field)
    {
        return (bool) $field;
    }

    protected static function getPrice($field)
    {
        $field = ((float) str_replace(',', '.', $field));
        $field = ((float) str_replace('%', '', $field));

        return $field;
    }

    protected static function split($field)
    {
        if (empty($field) && $field !== "0") {
            return [];
        }

        $separator = Tools::getValue('multivalue_separator');
        if (null === $separator || trim($separator) == '') {
            $separator = ',';
        }

        $tab = explode($separator, $field);

        if (!is_array($tab)) {
            return [];
        }

        return $tab;
    }

    protected static function createMultiLangField($field)
    {
        $res = [];
        foreach (Language::getIDs(false) as $id_lang) {
            $res[$id_lang] = $field;
        }

        return $res;
    }

    protected static function setDefaultValues(&$info)
    {
        foreach (self::$default_values as $k => $v) {
            if (!isset($info[$k]) || $info[$k] == '') {
                $info[$k] = $v;
            }
        }
    }

    protected static function setEntityDefaultValues(&$entity)
    {
        $members = get_object_vars($entity);
        foreach (self::$default_values as $k => $v) {
            if (array_key_exists($k, $members) && $entity->$k === null || !array_key_exists($k, $members)) {
                $entity->$k = $v;
            }
        }
    }

    public static function getMaskedRow($row)
    {
        $res = [
            'order' => [],
            'order_detail' => [],
            'customer' => [],
            'address_invoice' => [],
            'address_delivery' => [],
            'payment' => [],
        ];
        if (is_array(self::$column_mask)) {
            foreach (self::$column_mask as $type => $nb) {
                $parts = explode('.', $type);
                if (!empty(pSQL(self::$custom_type_value[$nb]))) {
                    $res[$parts[0]][$parts[1]] = pSQL(self::$custom_type_value[$nb]);
                } elseif (isset($row[$nb])) {
                    $res[$parts[0]][$parts[1]] = isset(self::$validators[$type]) ? call_user_func(self::$validators[$type], trim($row[$nb])) : trim($row[$nb]);
                } else {
                    $res[$parts[0]][$parts[1]] = null;
                }
            }
        }

        return $res;
    }

    public static function getMaskedRow2($row)
    {
        $res = [];
        if (is_array(self::$column_mask)) {
            foreach (self::$column_mask as $type => $nb) {
                $res[$type] = isset($row[$nb]) ? trim($row[$nb]) : null;
            }
        }

        return $res;
    }

    protected function receiveColumns()
    {
        $type_value = Tools::getValue('type_value') ?: [];
        self::$custom_type_value = Tools::getValue('custom_type_value') ?: [];
        foreach ($type_value as $nb => $type) {
            if ($type != 'no') {
                self::$column_mask[$type] = $nb;
            }
        }
    }

    protected function truncateTables($entity)
    {
        switch ($entity) {
            case 'orders':
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'orders`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_carrier`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_cart_rule`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_detail`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_detail_tax`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_history`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_invoice`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_invoice_payment`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_invoice_tax`');
                Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'order_payment`');
                break;
        }

        return true;
    }

    public function getConfigs()
    {
        $confs = Db::getInstance()->executeS('SELECT 
                                                    `id_ipordersimport`, 
                                                    `name`,
                                                    `configuration`,
                                                    "' . $this->module->l('Delete', 'EIAOrdersImport') . '" `title`
                                                FROM `' . _DB_PREFIX_ . 'ipordersimport`
                                                ORDER BY `id_ipordersimport` DESC;');
        foreach ($confs as &$conf) {
            $conf['configuration'] = str_replace("'", '&apos;', $conf['configuration']);
        }
        return $confs;
    }

    protected function openCsvFile($offset = false)
    {
        $handle = false;
        if (is_file($this->file) && is_readable($this->file)) {
            //            if (!mb_check_encoding(file_get_contents($this->file), 'UTF-8')) {
            //                $this->convert = true;
            //            }
            $handle = fopen($this->file, 'rb');
        }

        if (!$handle) {
            $this->errors[] = Tools::displayError('Cannot read the file');
        }

        self::rewindBomAware($handle);

        $toSkip = (int) Tools::getValue('skip');
        if ($offset && $offset > 0) {
            $toSkip += $offset;
        }

        for ($i = 0; $i < $toSkip; $i++) {
            $line = fgetcsv($handle, MAX_LINE_SIZE, $this->separator, $this->enclosure);
            if ($line === false) {
                return false; // reached end of file
            }
        }
        return $handle;
    }

    protected function closeCsvFile($handle)
    {
        fclose($handle);
    }

    private function copyDir($src, $dst)
    {
        // open the source directory
        $dir = opendir($src);

        // Make the destination directory if not exist
        @mkdir($dst);

        // Loop through the files in source directory
        while ($file = readdir($dir)) {
            if (($file != '.') && ($file != '..')) {
                if (is_dir($src . '/' . $file)) {
                    // Recursively calling custom copy function
                    // for sub directory
                    $this->copyDir($src . '/' . $file, $dst . '/' . $file);
                } else {
                    copy($src . '/' . $file, $dst . '/' . $file);
                }
            }
        }

        closedir($dir);
    }

    public function utf8EncodeArray($array)
    {
        return (is_array($array) ? array_map(array($this->module, 'my_utf8_encode'), $array) : $this->module->my_utf8_encode($array));
    }

    protected static function rewindBomAware($handle)
    {
        // A rewind wrapper that skips BOM signature wrongly
        if (!is_resource($handle)) {
            return false;
        }
        rewind($handle);
        if (fread($handle, 3) != "\xEF\xBB\xBF") {
            rewind($handle);
        }
    }

    public static function setLocale()
    {
        $iso_lang = Language::getIsoById(Tools::getValue('language'));
        setlocale(LC_COLLATE, Tools::strtolower($iso_lang) . '_' . Tools::strtoupper($iso_lang) . '.UTF-8');
        setlocale(LC_CTYPE, Tools::strtolower($iso_lang) . '_' . Tools::strtoupper($iso_lang) . '.UTF-8');
    }
    
    public static function getCarrierIdByName($carrier_name)
    {
        if (!$carrier_name) {
            return false;
        }

        $sql = "
                SELECT id_carrier
                FROM " . _DB_PREFIX_ . "carrier
                WHERE `name` = '" . pSQL($carrier_name) . "'
                    AND deleted = 0
                    ";

        if (($id_carrier = (int) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql))) {
            return $id_carrier;
        }

        $sql = "
                SELECT id_carrier
                FROM " . _DB_PREFIX_ . "carrier
                WHERE `name` = '" . pSQL($carrier_name) . "'
                    ";

        return (int) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
    }
    
    public static function getCarrierIdByReference($id_reference)
    {
        $id_carrier = Db::getInstance()->getValue('SELECT `id_carrier` FROM `' . _DB_PREFIX_ . 'carrier`
			WHERE id_reference = ' . (int) $id_reference . ' AND deleted = 0 ORDER BY id_carrier DESC');

        return (int) $id_carrier;
    }

    public static function getTaxIdByName($tax_name, $active = 1, $id_lang = null)
    {
        $tax = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('
			SELECT t.`id_tax`
			FROM `' . _DB_PREFIX_ . 'tax` t
			LEFT JOIN `' . _DB_PREFIX_ . 'tax_lang` tl ON (tl.id_tax = t.id_tax)
			WHERE tl.`name` = \'' . pSQL($tax_name) . '\' ' .
                ($active == 1 ? ' AND t.`active` = 1' : '') . 
                ($id_lang ? ' AND tl.`id_lang` = ' . (int) $id_lang : ''));

        return $tax ? (int) $tax['id_tax'] : false;
    }

}