* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
use PhpOffice\PhpSpreadsheet\IOFactory;
@ini_set('max_execution_time', 0);
/* No max line limit since the lines can be more than 4096. Performance impact is not significant. */
define('MAX_LINE_SIZE', 0);
/* Used for validatefields diying without user friendly error or not */
define('UNFRIENDLY_ERROR', false);
/* this value set the number of columns visible on each page */
define('MAX_COLUMNS', 6);
/* correct Mac error on eof */
@ini_set('auto_detect_line_endings', '1');
class AdminImportControllerCore extends AdminController
{
public static $column_mask;
public $entities = array();
public $available_fields = array();
public $required_fields = array();
public static $default_values = array();
public static $validators = array(
'active' => array('AdminImportController', 'getBoolean'),
'tax_rate' => array('AdminImportController', 'getPrice'),
/* Tax excluded */
'price_tex' => array('AdminImportController', 'getPrice'),
/* Tax included */
'price_tin' => array('AdminImportController', 'getPrice'),
'reduction_price' => array('AdminImportController', 'getPrice'),
'reduction_percent' => array('AdminImportController', 'getPrice'),
'wholesale_price' => array('AdminImportController', 'getPrice'),
'ecotax' => array('AdminImportController', 'getPrice'),
'name' => array('AdminImportController', 'createMultiLangField'),
'description' => array('AdminImportController', 'createMultiLangField'),
'description_short' => array('AdminImportController', 'createMultiLangField'),
'meta_title' => array('AdminImportController', 'createMultiLangField'),
'meta_keywords' => array('AdminImportController', 'createMultiLangField'),
'meta_description' => array('AdminImportController', 'createMultiLangField'),
'link_rewrite' => array('AdminImportController', 'createMultiLangField'),
'available_now' => array('AdminImportController', 'createMultiLangField'),
'available_later' => array('AdminImportController', 'createMultiLangField'),
'category' => array('AdminImportController', 'split'),
'online_only' => array('AdminImportController', 'getBoolean'),
'accessories' => array('AdminImportController', 'split'),
'image_alt' => array('AdminImportController', 'split'),
'delivery_in_stock' => array('AdminImportController', 'createMultiLangField'),
'delivery_out_stock' => array('AdminImportController', 'createMultiLangField'),
);
public $separator;
public $convert;
public $multiple_value_separator;
/**
* This flag shows if import was executed in current request.
* Used for symfony migration purposes.
*
* @var bool
*/
private $importExecuted = false;
public function __construct()
{
$this->bootstrap = true;
parent::__construct();
$this->entities = array(
$this->trans('Categories', array(), 'Admin.Global'),
$this->trans('Products', array(), 'Admin.Global'),
$this->trans('Combinations', array(), 'Admin.Global'),
$this->trans('Customers', array(), 'Admin.Global'),
$this->trans('Addresses', array(), 'Admin.Global'),
$this->trans('Brands', array(), 'Admin.Global'),
$this->trans('Suppliers', array(), 'Admin.Global'),
$this->trans('Alias', array(), 'Admin.Shopparameters.Feature'),
$this->trans('Store contacts', array(), 'Admin.Advparameters.Feature'),
);
// @since 1.5.0
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
$this->entities = array_merge(
$this->entities,
array(
$this->trans('Supply Orders', array(), 'Admin.Advparameters.Feature'),
$this->trans('Supply Order Details', array(), 'Admin.Advparameters.Feature'),
)
);
}
$this->entities = array_flip($this->entities);
switch ((int) Tools::getValue('entity')) {
case $this->entities[$this->trans('Combinations', array(), 'Admin.Global')]:
$this->required_fields = array(
'group',
'attribute',
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id_product' => array('label' => $this->trans('Product ID', array(), 'Admin.Advparameters.Feature')),
'product_reference' => array('label' => $this->trans('Product Reference', array(), 'Admin.Advparameters.Feature')),
'group' => array(
'label' => $this->trans('Attribute (Name:Type:Position)', array(), 'Admin.Advparameters.Feature') . '*',
),
'attribute' => array(
'label' => $this->trans('Value (Value:Position)', array(), 'Admin.Advparameters.Feature') . '*',
),
'supplier_reference' => array('label' => $this->trans('Supplier reference', array(), 'Admin.Advparameters.Feature')),
'reference' => array('label' => $this->trans('Reference', array(), 'Admin.Global')),
'ean13' => array('label' => $this->trans('EAN13', array(), 'Admin.Advparameters.Feature')),
'upc' => array('label' => $this->trans('UPC', array(), 'Admin.Advparameters.Feature')),
'wholesale_price' => array('label' => $this->trans('Cost price', array(), 'Admin.Catalog.Feature')),
'price' => array('label' => $this->trans('Impact on price', array(), 'Admin.Catalog.Feature')),
'ecotax' => array('label' => $this->trans('Ecotax', array(), 'Admin.Catalog.Feature')),
'quantity' => array('label' => $this->trans('Quantity', array(), 'Admin.Global')),
'minimal_quantity' => array('label' => $this->trans('Minimal quantity', array(), 'Admin.Advparameters.Feature')),
'low_stock_threshold' => array('label' => $this->trans('Low stock level', array(), 'Admin.Catalog.Feature')),
'low_stock_alert' => array('label' => $this->trans('Send me an email when the quantity is under this level', array(), 'Admin.Catalog.Feature')),
'weight' => array('label' => $this->trans('Impact on weight', array(), 'Admin.Catalog.Feature')),
'default_on' => array('label' => $this->trans('Default (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'available_date' => array('label' => $this->trans('Combination availability date', array(), 'Admin.Advparameters.Feature')),
'image_position' => array(
'label' => $this->trans('Choose among product images by position (1,2,3...)', array(), 'Admin.Advparameters.Feature'),
),
'image_url' => array('label' => $this->trans('Image URLs (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'image_alt' => array('label' => $this->trans('Image alt texts (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'shop' => array(
'label' => $this->trans('ID / Name of shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
'advanced_stock_management' => array(
'label' => $this->trans('Advanced Stock Management', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Enable Advanced Stock Management on product (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Help'),
),
'depends_on_stock' => array(
'label' => $this->trans('Depends on stock', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('0 = Use quantity set in product, 1 = Use quantity from warehouse.', array(), 'Admin.Advparameters.Help'),
),
'warehouse' => array(
'label' => $this->trans('Warehouse', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('ID of the warehouse to set as storage.', array(), 'Admin.Advparameters.Help'),
),
);
self::$default_values = array(
'reference' => '',
'supplier_reference' => '',
'ean13' => '',
'upc' => '',
'wholesale_price' => 0,
'price' => 0,
'ecotax' => 0,
'quantity' => 0,
'minimal_quantity' => 1,
'low_stock_threshold' => null,
'low_stock_alert' => false,
'weight' => 0,
'default_on' => null,
'advanced_stock_management' => 0,
'depends_on_stock' => 0,
'available_date' => date('Y-m-d'),
);
break;
case $this->entities[$this->trans('Categories', array(), 'Admin.Global')]:
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'name' => array('label' => $this->trans('Name', array(), 'Admin.Global')),
'parent' => array('label' => $this->trans('Parent category', array(), 'Admin.Catalog.Feature')),
'is_root_category' => array(
'label' => $this->trans('Root category (0/1)', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('A category root is where a category tree can begin. This is used with multistore.', array(), 'Admin.Advparameters.Help'),
),
'description' => array('label' => $this->trans('Description', array(), 'Admin.Global')),
'meta_title' => array('label' => $this->trans('Meta title', array(), 'Admin.Global')),
'meta_keywords' => array('label' => $this->trans('Meta keywords', array(), 'Admin.Global')),
'meta_description' => array('label' => $this->trans('Meta description', array(), 'Admin.Global')),
'link_rewrite' => array('label' => $this->trans('Rewritten URL', array(), 'Admin.Shopparameters.Feature')),
'image' => array('label' => $this->trans('Image URL', array(), 'Admin.Advparameters.Feature')),
'shop' => array(
'label' => $this->trans('ID / Name of shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
);
self::$default_values = array(
'active' => '1',
'parent' => Configuration::get('PS_HOME_CATEGORY'),
'link_rewrite' => '',
);
break;
case $this->entities[$this->trans('Products', array(), 'Admin.Global')]:
self::$validators['image'] = array(
'AdminImportController',
'split',
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'name' => array('label' => $this->trans('Name', array(), 'Admin.Global')),
'category' => array('label' => $this->trans('Categories (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'price_tex' => array('label' => $this->trans('Price tax excluded', array(), 'Admin.Advparameters.Feature')),
'price_tin' => array('label' => $this->trans('Price tax included', array(), 'Admin.Advparameters.Feature')),
'id_tax_rules_group' => array('label' => $this->trans('Tax rule ID', array(), 'Admin.Advparameters.Feature')),
'wholesale_price' => array('label' => $this->trans('Cost price', array(), 'Admin.Catalog.Feature')),
'on_sale' => array('label' => $this->trans('On sale (0/1)', array(), 'Admin.Advparameters.Feature')),
'reduction_price' => array('label' => $this->trans('Discount amount', array(), 'Admin.Advparameters.Feature')),
'reduction_percent' => array('label' => $this->trans('Discount percent', array(), 'Admin.Advparameters.Feature')),
'reduction_from' => array('label' => $this->trans('Discount from (yyyy-mm-dd)', array(), 'Admin.Advparameters.Feature')),
'reduction_to' => array('label' => $this->trans('Discount to (yyyy-mm-dd)', array(), 'Admin.Advparameters.Feature')),
'reference' => array('label' => $this->trans('Reference #', array(), 'Admin.Advparameters.Feature')),
'supplier_reference' => array('label' => $this->trans('Supplier reference #', array(), 'Admin.Advparameters.Feature')),
'supplier' => array('label' => $this->trans('Supplier', array(), 'Admin.Global')),
'manufacturer' => array('label' => $this->trans('Brand', array(), 'Admin.Global')),
'ean13' => array('label' => $this->trans('EAN13', array(), 'Admin.Advparameters.Feature')),
'upc' => array('label' => $this->trans('UPC', array(), 'Admin.Advparameters.Feature')),
'ecotax' => array('label' => $this->trans('Ecotax', array(), 'Admin.Catalog.Feature')),
'width' => array('label' => $this->trans('Width', array(), 'Admin.Global')),
'height' => array('label' => $this->trans('Height', array(), 'Admin.Global')),
'depth' => array('label' => $this->trans('Depth', array(), 'Admin.Global')),
'weight' => array('label' => $this->trans('Weight', array(), 'Admin.Global')),
'delivery_in_stock' => array(
'label' => $this->trans(
'Delivery time of in-stock products:',
array(),
'Admin.Catalog.Feature'
),
),
'delivery_out_stock' => array(
'label' => $this->trans(
'Delivery time of out-of-stock products with allowed orders:',
array(),
'Admin.Advparameters.Feature'
),
),
'quantity' => array('label' => $this->trans('Quantity', array(), 'Admin.Global')),
'minimal_quantity' => array('label' => $this->trans('Minimal quantity', array(), 'Admin.Advparameters.Feature')),
'low_stock_threshold' => array('label' => $this->trans('Low stock level', array(), 'Admin.Catalog.Feature')),
'low_stock_alert' => array('label' => $this->trans('Send me an email when the quantity is under this level', array(), 'Admin.Catalog.Feature')),
'visibility' => array('label' => $this->trans('Visibility', array(), 'Admin.Catalog.Feature')),
'additional_shipping_cost' => array('label' => $this->trans('Additional shipping cost', array(), 'Admin.Advparameters.Feature')),
'unity' => array('label' => $this->trans('Unit for the price per unit', array(), 'Admin.Advparameters.Feature')),
'unit_price' => array('label' => $this->trans('Price per unit', array(), 'Admin.Advparameters.Feature')),
'description_short' => array('label' => $this->trans('Summary', array(), 'Admin.Catalog.Feature')),
'description' => array('label' => $this->trans('Description', array(), 'Admin.Global')),
'tags' => array('label' => $this->trans('Tags (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'meta_title' => array('label' => $this->trans('Meta title', array(), 'Admin.Global')),
'meta_keywords' => array('label' => $this->trans('Meta keywords', array(), 'Admin.Global')),
'meta_description' => array('label' => $this->trans('Meta description', array(), 'Admin.Global')),
'link_rewrite' => array('label' => $this->trans('Rewritten URL', array(), 'Admin.Advparameters.Feature')),
'available_now' => array('label' => $this->trans('Label when in stock', array(), 'Admin.Catalog.Feature')),
'available_later' => array('label' => $this->trans('Label when backorder allowed', array(), 'Admin.Advparameters.Feature')),
'available_for_order' => array('label' => $this->trans('Available for order (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'available_date' => array('label' => $this->trans('Product availability date', array(), 'Admin.Advparameters.Feature')),
'date_add' => array('label' => $this->trans('Product creation date', array(), 'Admin.Advparameters.Feature')),
'show_price' => array('label' => $this->trans('Show price (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'image' => array('label' => $this->trans('Image URLs (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'image_alt' => array('label' => $this->trans('Image alt texts (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'delete_existing_images' => array(
'label' => $this->trans('Delete existing images (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature'),
),
'features' => array('label' => $this->trans('Feature (Name:Value:Position:Customized)', array(), 'Admin.Advparameters.Feature')),
'online_only' => array('label' => $this->trans('Available online only (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'condition' => array('label' => $this->trans('Condition', array(), 'Admin.Catalog.Feature')),
'customizable' => array('label' => $this->trans('Customizable (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'uploadable_files' => array('label' => $this->trans('Uploadable files (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'text_fields' => array('label' => $this->trans('Text fields (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'out_of_stock' => array('label' => $this->trans('Action when out of stock', array(), 'Admin.Advparameters.Feature')),
'is_virtual' => array('label' => $this->trans('Virtual product (0 = No, 1 = Yes)', array(), 'Admin.Advparameters.Feature')),
'file_url' => array('label' => $this->trans('File URL', array(), 'Admin.Advparameters.Feature')),
'nb_downloadable' => array(
'label' => $this->trans('Number of allowed downloads', array(), 'Admin.Catalog.Feature'),
'help' => $this->trans('Number of days this file can be accessed by customers. Set to zero for unlimited access.', array(), 'Admin.Catalog.Help'),
),
'date_expiration' => array('label' => $this->trans('Expiration date (yyyy-mm-dd)', array(), 'Admin.Advparameters.Feature')),
'nb_days_accessible' => array(
'label' => $this->trans('Number of days', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Number of days this file can be accessed by customers. Set to zero for unlimited access.', array(), 'Admin.Catalog.Help'),
),
'shop' => array(
'label' => $this->trans('ID / Name of shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
'advanced_stock_management' => array(
'label' => $this->trans('Advanced Stock Management', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Enable Advanced Stock Management on product (0 = No, 1 = Yes).', array(), 'Admin.Advparameters.Help'),
),
'depends_on_stock' => array(
'label' => $this->trans('Depends on stock', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('0 = Use quantity set in product, 1 = Use quantity from warehouse.', array(), 'Admin.Advparameters.Help'),
),
'warehouse' => array(
'label' => $this->trans('Warehouse', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('ID of the warehouse to set as storage.', array(), 'Admin.Advparameters.Help'),
),
'accessories' => array('label' => $this->trans('Accessories (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
);
self::$default_values = array(
'id_category' => array((int) Configuration::get('PS_HOME_CATEGORY')),
'id_category_default' => null,
'active' => '1',
'width' => 0.000000,
'height' => 0.000000,
'depth' => 0.000000,
'weight' => 0.000000,
'visibility' => 'both',
'additional_shipping_cost' => 0.00,
'unit_price' => 0,
'quantity' => 0,
'minimal_quantity' => 1,
'low_stock_threshold' => null,
'low_stock_alert' => false,
'price' => 0,
'id_tax_rules_group' => 0,
'description_short' => array((int) Configuration::get('PS_LANG_DEFAULT') => ''),
'link_rewrite' => array((int) Configuration::get('PS_LANG_DEFAULT') => ''),
'online_only' => 0,
'condition' => 'new',
'available_date' => date('Y-m-d'),
'date_add' => date('Y-m-d H:i:s'),
'date_upd' => date('Y-m-d H:i:s'),
'customizable' => 0,
'uploadable_files' => 0,
'text_fields' => 0,
'advanced_stock_management' => 0,
'depends_on_stock' => 0,
'is_virtual' => 0,
);
break;
case $this->entities[$this->trans('Customers', array(), 'Admin.Global')]:
//Overwrite required_fields AS only email is required whereas other entities
$this->required_fields = array('email', 'passwd', 'lastname', 'firstname');
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'id_gender' => array('label' => $this->trans('Titles ID (Mr = 1, Ms = 2, else 0)', array(), 'Admin.Advparameters.Feature')),
'email' => array('label' => $this->trans('Email', array(), 'Admin.Global') . '*'),
'passwd' => array('label' => $this->trans('Password', array(), 'Admin.Global') . '*'),
'birthday' => array('label' => $this->trans('Birth date (yyyy-mm-dd)', array(), 'Admin.Advparameters.Feature')),
'lastname' => array('label' => $this->trans('Last name', array(), 'Admin.Global') . '*'),
'firstname' => array('label' => $this->trans('First name', array(), 'Admin.Global') . '*'),
'newsletter' => array('label' => $this->trans('Newsletter (0/1)', array(), 'Admin.Advparameters.Feature')),
'optin' => array('label' => $this->trans('Partner offers (0/1)', array(), 'Admin.Advparameters.Feature')),
'date_add' => array('label' => $this->trans('Registration date (yyyy-mm-dd)', array(), 'Admin.Advparameters.Feature')),
'group' => array('label' => $this->trans('Groups (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'id_default_group' => array('label' => $this->trans('Default group ID', array(), 'Admin.Advparameters.Feature')),
'id_shop' => array(
'label' => $this->trans('ID / Name of shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
);
self::$default_values = array(
'active' => '1',
'id_shop' => Configuration::get('PS_SHOP_DEFAULT'),
);
break;
case $this->entities[$this->trans('Addresses', array(), 'Admin.Global')]:
//Overwrite required_fields
$this->required_fields = array(
'alias',
'lastname',
'firstname',
'address1',
'postcode',
'country',
'customer_email',
'city',
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'alias' => array('label' => $this->trans('Alias', array(), 'Admin.Shopparameters.Feature') . '*'),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'customer_email' => array('label' => $this->trans('Customer email', array(), 'Admin.Advparameters.Feature') . '*'),
'id_customer' => array('label' => $this->trans('Customer ID', array(), 'Admin.Advparameters.Feature')),
'manufacturer' => array('label' => $this->trans('Brand', array(), 'Admin.Global')),
'supplier' => array('label' => $this->trans('Supplier', array(), 'Admin.Global')),
'company' => array('label' => $this->trans('Company', array(), 'Admin.Global')),
'lastname' => array('label' => $this->trans('Last name', array(), 'Admin.Global') . '*'),
'firstname' => array('label' => $this->trans('First name ', array(), 'Admin.Global') . '*'),
'address1' => array('label' => $this->trans('Address', array(), 'Admin.Global') . '*'),
'address2' => array('label' => $this->trans('Address (2)', array(), 'Admin.Global')),
'postcode' => array('label' => $this->trans('Zip/postal code', array(), 'Admin.Global') . '*'),
'city' => array('label' => $this->trans('City', array(), 'Admin.Global') . '*'),
'country' => array('label' => $this->trans('Country', array(), 'Admin.Global') . '*'),
'state' => array('label' => $this->trans('State', array(), 'Admin.Global')),
'other' => array('label' => $this->trans('Other', array(), 'Admin.Global')),
'phone' => array('label' => $this->trans('Phone', array(), 'Admin.Global')),
'phone_mobile' => array('label' => $this->trans('Mobile Phone', array(), 'Admin.Global')),
'vat_number' => array('label' => $this->trans('VAT number', array(), 'Admin.Orderscustomers.Feature')),
'dni' => array('label' => $this->trans('Identification number', array(), 'Admin.Orderscustomers.Feature')),
);
self::$default_values = array(
'alias' => 'Alias',
'postcode' => 'X',
);
break;
case $this->entities[$this->trans('Brands', array(), 'Admin.Global')]:
case $this->entities[$this->trans('Suppliers', array(), 'Admin.Global')]:
//Overwrite validators AS name is not MultiLangField
self::$validators = array(
'description' => array('AdminImportController', 'createMultiLangField'),
'short_description' => array('AdminImportController', 'createMultiLangField'),
'meta_title' => array('AdminImportController', 'createMultiLangField'),
'meta_keywords' => array('AdminImportController', 'createMultiLangField'),
'meta_description' => array('AdminImportController', 'createMultiLangField'),
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'name' => array('label' => $this->trans('Name', array(), 'Admin.Global')),
'description' => array('label' => $this->trans('Description', array(), 'Admin.Global')),
'short_description' => array('label' => $this->trans('Short description', array(), 'Admin.Catalog.Feature')),
'meta_title' => array('label' => $this->trans('Meta title', array(), 'Admin.Global')),
'meta_keywords' => array('label' => $this->trans('Meta keywords', array(), 'Admin.Global')),
'meta_description' => array('label' => $this->trans('Meta description', array(), 'Admin.Global')),
'image' => array('label' => $this->trans('Image URL', array(), 'Admin.Advparameters.Feature')),
'shop' => array(
'label' => $this->trans('ID / Name of group shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
);
self::$default_values = array(
'shop' => Shop::getGroupFromShop(Configuration::get('PS_SHOP_DEFAULT')),
);
break;
case $this->entities[$this->trans('Alias', array(), 'Admin.Shopparameters.Feature')]:
//Overwrite required_fields
$this->required_fields = array(
'alias',
'search',
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'alias' => array('label' => $this->trans('Alias', array(), 'Admin.Shopparameters.Feature') . '*'),
'search' => array('label' => $this->trans('Search', array(), 'Admin.Shopparameters.Feature') . '*'),
'active' => array('label' => $this->trans('Active', array(), 'Admin.Global')),
);
self::$default_values = array(
'active' => '1',
);
break;
case $this->entities[$this->trans('Store contacts', array(), 'Admin.Advparameters.Feature')]:
self::$validators['hours'] = array('AdminImportController', 'split');
self::$validators['address1'] = array('AdminImportController', 'createMultiLangField');
self::$validators['address2'] = array('AdminImportController', 'createMultiLangField');
$this->required_fields = array(
'address1',
'city',
'country',
'latitude',
'longitude',
);
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'active' => array('label' => $this->trans('Active (0/1)', array(), 'Admin.Advparameters.Feature')),
'name' => array('label' => $this->trans('Name', array(), 'Admin.Global')),
'address1' => array('label' => $this->trans('Address', array(), 'Admin.Global') . '*'),
'address2' => array('label' => $this->trans('Address (2)', array(), 'Admin.Advparameters.Feature')),
'postcode' => array('label' => $this->trans('Zip/postal code', array(), 'Admin.Global')),
'state' => array('label' => $this->trans('State', array(), 'Admin.Global')),
'city' => array('label' => $this->trans('City', array(), 'Admin.Global') . '*'),
'country' => array('label' => $this->trans('Country', array(), 'Admin.Global') . '*'),
'latitude' => array('label' => $this->trans('Latitude', array(), 'Admin.Advparameters.Feature') . '*'),
'longitude' => array('label' => $this->trans('Longitude', array(), 'Admin.Advparameters.Feature') . '*'),
'phone' => array('label' => $this->trans('Phone', array(), 'Admin.Global')),
'fax' => array('label' => $this->trans('Fax', array(), 'Admin.Global')),
'email' => array('label' => $this->trans('Email address', array(), 'Admin.Global')),
'note' => array('label' => $this->trans('Note', array(), 'Admin.Advparameters.Feature')),
'hours' => array('label' => $this->trans('Hours (x,y,z...)', array(), 'Admin.Advparameters.Feature')),
'image' => array('label' => $this->trans('Image URL', array(), 'Admin.Advparameters.Feature')),
'shop' => array(
'label' => $this->trans('ID / Name of shop', array(), 'Admin.Advparameters.Feature'),
'help' => $this->trans('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.', array(), 'Admin.Advparameters.Help'),
),
);
self::$default_values = array(
'active' => '1',
);
break;
}
// @since 1.5.0
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
switch ((int) Tools::getValue('entity')) {
case $this->entities[$this->trans('Supply Orders', array(), 'Admin.Advparameters.Feature')]:
// required fields
$this->required_fields = array(
'id_supplier',
'id_warehouse',
'reference',
'date_delivery_expected',
);
// available fields
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'id' => array('label' => $this->trans('ID', array(), 'Admin.Global')),
'id_supplier' => array('label' => $this->trans('Supplier ID *', array(), 'Admin.Advparameters.Feature')),
'id_lang' => array('label' => $this->trans('Lang ID', array(), 'Admin.Advparameters.Feature')),
'id_warehouse' => array('label' => $this->trans('Warehouse ID *', array(), 'Admin.Advparameters.Feature')),
'id_currency' => array('label' => $this->trans('Currency ID *', array(), 'Admin.Advparameters.Feature')),
'reference' => array('label' => $this->trans('Supply Order Reference *', array(), 'Admin.Advparameters.Feature')),
'date_delivery_expected' => array('label' => $this->trans('Delivery Date (Y-M-D)*', array(), 'Admin.Advparameters.Feature')),
'discount_rate' => array('label' => $this->trans('Discount rate', array(), 'Admin.Advparameters.Feature')),
'is_template' => array('label' => $this->trans('Template', array(), 'Admin.Advparameters.Feature')),
);
// default values
self::$default_values = array(
'id_lang' => (int) Configuration::get('PS_LANG_DEFAULT'),
'id_currency' => Currency::getDefaultCurrency()->id,
'discount_rate' => '0',
'is_template' => '0',
);
break;
case $this->entities[$this->trans('Supply Order Details', array(), 'Admin.Advparameters.Feature')]:
// required fields
$this->required_fields = array(
'supply_order_reference',
'id_product',
'unit_price_te',
'quantity_expected',
);
// available fields
$this->available_fields = array(
'no' => array('label' => $this->trans('Ignore this column', array(), 'Admin.Advparameters.Feature')),
'supply_order_reference' => array('label' => $this->trans('Supply Order Reference *', array(), 'Admin.Advparameters.Feature')),
'id_product' => array('label' => $this->trans('Product ID *', array(), 'Admin.Advparameters.Feature')),
'id_product_attribute' => array('label' => $this->trans('Product Attribute ID', array(), 'Admin.Advparameters.Feature')),
'unit_price_te' => array('label' => $this->trans('Unit Price (tax excl.)*', array(), 'Admin.Advparameters.Feature')),
'quantity_expected' => array('label' => $this->trans('Quantity Expected *', array(), 'Admin.Advparameters.Feature')),
'discount_rate' => array('label' => $this->trans('Discount Rate', array(), 'Admin.Advparameters.Feature')),
'tax_rate' => array('label' => $this->trans('Tax Rate', array(), 'Admin.Advparameters.Feature')),
);
// default values
self::$default_values = array(
'discount_rate' => '0',
'tax_rate' => '0',
);
break;
}
}
$this->separator = ($separator = Tools::substr((string) (trim(Tools::getValue('separator'))), 0, 1)) ? $separator : ';';
$this->convert = false;
$this->multiple_value_separator = ($separator = Tools::substr((string) (trim(Tools::getValue('multiple_value_separator'))), 0, 1)) ? $separator : ',';
}
public function setMedia($isNewTheme = false)
{
$bo_theme = ((Validate::isLoadedObject($this->context->employee)
&& $this->context->employee->bo_theme) ? $this->context->employee->bo_theme : 'default');
if (!file_exists(_PS_BO_ALL_THEMES_DIR_ . $bo_theme . DIRECTORY_SEPARATOR
. 'template')) {
$bo_theme = 'default';
}
// We need to set parent media first, so that jQuery is loaded before the dependant plugins
parent::setMedia($isNewTheme);
$this->addJs(__PS_BASE_URI__ . $this->admin_webpath . '/themes/' . $bo_theme . '/js/jquery.iframe-transport.js');
$this->addJs(__PS_BASE_URI__ . $this->admin_webpath . '/themes/' . $bo_theme . '/js/jquery.fileupload.js');
$this->addJs(__PS_BASE_URI__ . $this->admin_webpath . '/themes/' . $bo_theme . '/js/jquery.fileupload-process.js');
$this->addJs(__PS_BASE_URI__ . $this->admin_webpath . '/themes/' . $bo_theme . '/js/jquery.fileupload-validate.js');
$this->addJs(__PS_BASE_URI__ . 'js/vendor/spin.js');
$this->addJs(__PS_BASE_URI__ . 'js/vendor/ladda.js');
}
public function renderForm()
{
// If import was executed - collect errors or success message
// and send them to the migrated controller.
if ($this->importExecuted) {
$session = $this->getSession();
if ($this->errors) {
foreach ($this->errors as $error) {
$session->getFlashBag()->add('error', $error);
}
} else {
foreach ($this->warnings as $warning) {
$session->getFlashBag()->add('warning', $warning);
}
$session->getFlashBag()->add(
'success',
$this->trans(
'Your file has been successfully imported into your shop. Don\'t forget to re-build the products\' search index.',
[],
'Admin.Advparameters.Notification'
)
);
}
}
$request = $this->getSymfonyRequest();
if ($request && $request->isMethod(\Symfony\Component\HttpFoundation\Request::METHOD_GET)) {
// Import form is reworked in Symfony.
// If user tries to access legacy form directly,
// we redirect him to new form.
$symfonyImportForm = $this->context->link->getAdminLink('AdminImport');
Tools::redirectAdmin($symfonyImportForm);
}
if (!is_dir(AdminImportController::getPath())) {
return !($this->errors[] = $this->trans('The import directory doesn\'t exist. Please check your file path.', array(), 'Admin.Advparameters.Notification'));
}
if (!is_writable(AdminImportController::getPath())) {
$this->displayWarning($this->trans('The import directory must be writable (CHMOD 755 / 777).', array(), 'Admin.Advparameters.Notification'));
}
$files_to_import = scandir(AdminImportController::getPath(), SCANDIR_SORT_NONE);
uasort($files_to_import, array('AdminImportController', 'usortFiles'));
foreach ($files_to_import as $k => &$filename) {
//exclude . .. .svn and index.php and all hidden files
if (preg_match('/^\..*|index\.php/i', $filename) || is_dir(AdminImportController::getPath() . $filename)) {
unset($files_to_import[$k]);
}
}
unset($filename);
$this->fields_form = array('');
$this->toolbar_scroll = false;
$this->toolbar_btn = array();
// adds fancybox
$this->addJqueryPlugin(array('fancybox'));
$entity_selected = 0;
if (isset($this->entities[$this->l(Tools::ucfirst(Tools::getValue('import_type')))])) {
$entity_selected = $this->entities[$this->l(Tools::ucfirst(Tools::getValue('import_type')))];
$this->context->cookie->entity_selected = (int) $entity_selected;
} elseif (isset($this->context->cookie->entity_selected)) {
$entity_selected = (int) $this->context->cookie->entity_selected;
}
$csv_selected = '';
if (isset($this->context->cookie->csv_selected) &&
@filemtime(AdminImportController::getPath(
urldecode($this->context->cookie->csv_selected)
))) {
$csv_selected = urldecode($this->context->cookie->csv_selected);
} else {
$this->context->cookie->csv_selected = $csv_selected;
}
$id_lang_selected = '';
if (isset($this->context->cookie->iso_lang_selected) && $this->context->cookie->iso_lang_selected) {
$id_lang_selected = (int) Language::getIdByIso(urldecode($this->context->cookie->iso_lang_selected));
}
$separator_selected = $this->separator;
if (isset($this->context->cookie->separator_selected) && $this->context->cookie->separator_selected) {
$separator_selected = urldecode($this->context->cookie->separator_selected);
}
$multiple_value_separator_selected = $this->multiple_value_separator;
if (isset($this->context->cookie->multiple_value_separator_selected) && $this->context->cookie->multiple_value_separator_selected) {
$multiple_value_separator_selected = urldecode($this->context->cookie->multiple_value_separator_selected);
}
//get post max size
$post_max_size = ini_get('post_max_size');
$bytes = (int) trim($post_max_size);
$last = strtolower($post_max_size[strlen($post_max_size) - 1]);
switch ($last) {
case 'g':
$bytes *= 1024;
// no break to fall-through
case 'm':
$bytes *= 1024;
// no break to fall-through
case 'k':
$bytes *= 1024;
}
if (!isset($bytes) || $bytes == '') {
$bytes = 20971520;
} // 20Mb
$this->tpl_form_vars = array(
'post_max_size' => (int) $bytes,
'module_confirmation' => Tools::isSubmit('import') && (isset($this->warnings) && !count($this->warnings)),
'path_import' => AdminImportController::getPath(),
'entities' => $this->entities,
'entity_selected' => $entity_selected,
'csv_selected' => $csv_selected,
'separator_selected' => $separator_selected,
'multiple_value_separator_selected' => $multiple_value_separator_selected,
'files_to_import' => $files_to_import,
'languages' => Language::getLanguages(false),
'id_language' => ($id_lang_selected) ? $id_lang_selected : $this->context->language->id,
'available_fields' => $this->getAvailableFields(),
'truncateAuthorized' => (Shop::isFeatureActive() && $this->context->employee->isSuperAdmin()) || !Shop::isFeatureActive(),
'PS_ADVANCED_STOCK_MANAGEMENT' => Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'),
);
return parent::renderForm();
}
public function ajaxProcessuploadCsv()
{
$filename_prefix = date('YmdHis') . '-';
if (isset($_FILES['file']) && !empty($_FILES['file']['error'])) {
switch ($_FILES['file']['error']) {
case UPLOAD_ERR_INI_SIZE:
$_FILES['file']['error'] = $this->trans('The uploaded file exceeds the upload_max_filesize directive in php.ini. If your server configuration allows it, you may add a directive in your .htaccess.', array(), 'Admin.Advparameters.Notification');
break;
case UPLOAD_ERR_FORM_SIZE:
$_FILES['file']['error'] = $this->trans('The uploaded file exceeds the post_max_size directive in php.ini. If your server configuration allows it, you may add a directive in your .htaccess, for example:', array(), 'Admin.Advparameters.Notification')
. '
php_value post_max_size 20M ' .
$this->trans('(click to open "Generators" page)', array(), 'Admin.Advparameters.Notification') . '';
break;
break;
case UPLOAD_ERR_PARTIAL:
$_FILES['file']['error'] = $this->trans('The uploaded file was only partially uploaded.', array(), 'Admin.Advparameters.Notification');
break;
break;
case UPLOAD_ERR_NO_FILE:
$_FILES['file']['error'] = $this->trans('No file was uploaded.', array(), 'Admin.Advparameters.Notification');
break;
break;
}
} elseif (!preg_match('#([^\.]*?)\.(csv|xls[xt]?|o[dt]s)$#is', $_FILES['file']['name'])) {
$_FILES['file']['error'] = $this->trans('The extension of your file should be .csv.', array(), 'Admin.Advparameters.Notification');
} elseif (!@filemtime($_FILES['file']['tmp_name']) ||
!@move_uploaded_file($_FILES['file']['tmp_name'], AdminImportController::getPath() . $filename_prefix . str_replace("\0", '', $_FILES['file']['name']))) {
$_FILES['file']['error'] = $this->trans('An error occurred while uploading / copying the file.', array(), 'Admin.Advparameters.Notification');
} else {
@chmod(AdminImportController::getPath() . $filename_prefix . $_FILES['file']['name'], 0664);
$_FILES['file']['filename'] = $filename_prefix . str_replace('\0', '', $_FILES['file']['name']);
}
die(json_encode($_FILES));
}
public function renderView()
{
$this->addJS(_PS_JS_DIR_ . 'admin/import.js');
$handle = $this->openCsvFile();
$nb_column = $this->getNbrColumn($handle, $this->separator);
$nb_table = ceil($nb_column / MAX_COLUMNS);
$res = array();
foreach ($this->required_fields as $elem) {
$res[] = '\'' . $elem . '\'';
}
$data = array();
for ($i = 0; $i < $nb_table; ++$i) {
$data[$i] = $this->generateContentTable($i, $nb_column, $handle, $this->separator);
}
$this->context->cookie->entity_selected = (int) Tools::getValue('entity');
$this->context->cookie->iso_lang_selected = urlencode(Tools::getValue('iso_lang'));
$this->context->cookie->separator_selected = urlencode($this->separator);
$this->context->cookie->multiple_value_separator_selected = urlencode($this->multiple_value_separator);
$this->context->cookie->csv_selected = urlencode(Tools::getValue('csv'));
$this->tpl_view_vars = array(
'import_matchs' => Db::getInstance()->executeS('SELECT * FROM ' . _DB_PREFIX_ . 'import_match', true, false),
'fields_value' => array(
'csv' => Tools::getValue('csv'),
'entity' => (int) Tools::getValue('entity'),
'iso_lang' => Tools::getValue('iso_lang'),
'truncate' => Tools::getValue('truncate'),
'forceIDs' => Tools::getValue('forceIDs'),
'regenerate' => Tools::getValue('regenerate'),
'sendemail' => Tools::getValue('sendemail'),
'match_ref' => Tools::getValue('match_ref'),
'separator' => $this->separator,
'multiple_value_separator' => $this->multiple_value_separator,
),
'nb_table' => $nb_table,
'nb_column' => $nb_column,
'res' => implode(',', $res),
'max_columns' => MAX_COLUMNS,
'no_pre_select' => array('price_tin', 'feature'),
'available_fields' => $this->available_fields,
'data' => $data,
);
return parent::renderView();
}
public function initToolbar()
{
switch ($this->display) {
case 'import':
// Default cancel button - like old back link
$back = Tools::safeOutput(Tools::getValue('back', ''));
if (empty($back)) {
$back = self::$currentIndex . '&token=' . $this->token;
}
$this->toolbar_btn['cancel'] = array(
'href' => $back,
'desc' => $this->trans('Cancel', array(), 'Admin.Actions'),
);
// Default save button - action dynamically handled in javascript
$this->toolbar_btn['save-import'] = array(
'href' => '#',
'desc' => $this->trans('Import .CSV data', array(), 'Admin.Advparameters.Feature'),
);
break;
}
}
protected function generateContentTable($current_table, $nb_column, $handle, $glue)
{
$html = '
';
// Header
for ($i = 0; $i < $nb_column; ++$i) {
if (MAX_COLUMNS * (int) $current_table <= $i && (int) $i < MAX_COLUMNS * ((int) $current_table + 1)) {
$html .= '|
| ';
}
}
$html .= '
';
AdminImportController::setLocale();
for ($current_line = 0; $current_line < 10 && $line = fgetcsv($handle, MAX_LINE_SIZE, $glue); ++$current_line) {
/* UTF-8 conversion */
if ($this->convert) {
$line = $this->utf8EncodeArray($line);
}
$html .= '';
foreach ($line as $nb_c => $column) {
if ((MAX_COLUMNS * (int) $current_table <= $nb_c) && ((int) $nb_c < MAX_COLUMNS * ((int) $current_table + 1))) {
$html .= '| ' . htmlentities(Tools::substr($column, 0, 200), ENT_QUOTES, 'UTF-8') . ' | ';
}
}
$html .= '
';
}
$html .= '
';
AdminImportController::rewindBomAware($handle);
return $html;
}
public function init()
{
parent::init();
if (Tools::isSubmit('submitImportFile')) {
$this->display = 'import';
}
}
public function initContent()
{
if ($this->display == 'import') {
if (Tools::getValue('csv')) {
$this->content .= $this->renderView();
} else {
$this->errors[] = $this->trans('To proceed, please upload a file first.', array(), 'Admin.Advparameters.Notification');
$this->content .= $this->renderForm();
}
} else {
$this->content .= $this->renderForm();
}
$this->context->smarty->assign(array(
'content' => $this->content,
));
}
protected static function rewindBomAware($handle)
{
// A rewind wrapper that skips BOM signature wrongly
if (!is_resource($handle)) {
return false;
}
rewind($handle);
if (($bom = fread($handle, 3)) != "\xEF\xBB\xBF") {
rewind($handle);
}
}
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)) {
return array();
}
$separator = Tools::getValue('multiple_value_separator');
if (null === $separator || trim($separator) == '') {
$separator = ',';
}
$tab = '';
$uniqid_path = false;
// try data:// protocole. If failed, old school file on filesystem.
if (($fd = @fopen('data://text/plain;base64,' . base64_encode($field), 'rb')) === false) {
do {
$uniqid_path = _PS_UPLOAD_DIR_ . uniqid();
} while (file_exists($uniqid_path));
file_put_contents($uniqid_path, $field);
$fd = fopen($uniqid_path, 'rb');
}
if ($fd === false) {
return array();
}
$tab = fgetcsv($fd, MAX_LINE_SIZE, $separator);
fclose($fd);
if ($uniqid_path !== false && file_exists($uniqid_path)) {
@unlink($uniqid_path);
}
if (empty($tab) || (!is_array($tab))) {
return array();
}
return $tab;
}
protected static function createMultiLangField($field)
{
$res = array();
foreach (Language::getIDs(false) as $id_lang) {
$res[$id_lang] = $field;
}
return $res;
}
protected function getTypeValuesOptions($nb_c)
{
$i = 0;
$no_pre_select = array('price_tin', 'feature');
$options = '';
foreach ($this->available_fields as $k => $field) {
$options .= '