'csv',
],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'file' => Yii::t('product', 'File'),
];
}
public function getType()
{
if(!$this->type) {
$this->type = 'products';
}
return $this->type;
}
public function goPrices($from = 0, $limit = NULL)
{
set_time_limit(0);
if(!( $handle = $this->getProductsFile('uploadFilePrices') )) {
$this->errors[] = 'File not found';
return false;
}
$filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'));
if($from) {
fseek($handle, $from);
}
$j = 0;
$is_utf = ( preg_match('//u', file_get_contents(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'), NULL, NULL, NULL, 1000000)) );
while(( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) {
foreach($data as &$value) {
if(!$is_utf) {
$value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
}
$value = trim($value);
}
// данные строк
$modification_code = @$data[ 0 ];
$price = floatval(@$data[ 1 ]);
$price_promo = floatval(@$data[ 2 ]);
$count = intval(@$data[ 3 ]);
$city_name = @$data[ 4 ];
$product_title = @$data[ 5 ];
if(empty ( $modification_code )) {
continue;
}
// товары в пути
if(empty ( $city_name )) {
$this->output[] = 'Товар ' . $product_title . ' в пути';
continue;
}
if(( $productVariant = ProductVariant::find()
->filterWhere([ 'sku' => $modification_code ])
->one() ) === NULL
) {
$this->output[] = 'Для товара ' . $product_title . ' не найдено соотвествие';
continue;
}
// ===== Set stock ====
if($city_name) {
if(( $stock = Stock::find()
->filterWhere([ 'name' => trim($city_name) ])
->one() ) === NULL
) {
// Create stock
$stock = new Stock();
$stock->name = trim($city_name);
$stock->save();
}
$productStock = ProductStock::find()
->where([
'product_variant_id' => $productVariant->product_variant_id,
'stock_id' => $stock->stock_id,
])
->one();
if(!$productStock instanceof ProductStock) {
$productStock = new ProductStock;
$productStock->product_variant_id = $productVariant->product_variant_id;
$productStock->stock_id = $stock->stock_id;
$productStock->product_id = $productVariant->product_id;
}
$productStock->quantity = $count;
$productStock->save();
$productStocks = ProductStock::find()
->where([ 'product_variant_id' => $productVariant->product_variant_id ])
->andWhere([
'<>',
'stock_id',
$stock->stock_id,
])
->all();
$quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
} else {
$productStocks = ProductStock::find()
->where([ 'product_variant_id' => $productVariant->product_variant_id ])
->all();
if($productStocks instanceof ProductStock) {
$quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
} else {
$quantity = 0;
}
}
if($price_promo) {
$productVariant->price_old = $price;
$productVariant->price = $price_promo;
} else {
$productVariant->price = $price;
$productVariant->price_old = $price_promo;
}
$productVariant->stock = $quantity;
$productVariant->save();
$this->output[] = 'Товар ' . $product_title . ' успешно сохранен';
}
$result = [
'end' => feof($handle),
'from' => ftell($handle),
'totalsize' => $filesize,
'items' => $this->output,
];
fclose($handle);
if($result[ 'end' ]) {
unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'));
}
return $result;
}
/**
* @param string $name
*
* @return array
*/
private function parseName(string $name):array
{
$pattern = '/^(?P.*)(?:\(#(?P\w+)#\))?$/U';
$name = trim($name);
$matches = [];
if(preg_match($pattern, $name, $matches)) {
if(!isset( $matches[ 'remote_id' ] )) {
$matches[ 'remote_id' ] = '';
}
return $matches;
}
return [
'name' => $name,
'remote_id' => '',
];
}
/**
* @param array $catalog_names
*
* @return array
* @throws \Exception
*/
private function saveCatalog(array $catalog_names):array
{
$category_id = [];
foreach($catalog_names as $catalog_name) {
// ==== Set category ====
$parsed_name = $this->parseName($catalog_name);
if(!empty( $parsed_name[ 'remote_id' ] ) && ( $category = Category::find()
->joinWith('lang')
->andFilterWhere([ 'remote_id' => $parsed_name[ 'remote_id' ] ])
->one() ) !== NULL
) {
if(!empty( $category->lang )) {
$category->lang->name = $parsed_name[ 'name' ];
$category->lang->save();
} else {
throw new \Exception('Category with ID ' . $category->category_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
} else {
// Create category
$category = new Category();
$category->generateLangs();
$category_langs = $category->model_langs;
foreach($category_langs as $category_lang) {
$category_lang->name = $parsed_name[ 'name' ];
}
$category->remote_id = $parsed_name[ 'remote_id' ];
$category->save();
}
$category_id[] = $category->category_id;
}
return $category_id;
}
/**
* @param string|NULL $brand_name
*
* @return int|null
* @throws \Exception
*/
private function saveBrand(string $brand_name = NULL):int
{
$parsed_name = $this->parseName($brand_name);
if(!empty( $brand_name )) {
/**
* @var Brand $brand
*/
if(!empty( $parsed_name[ 'remote_id' ] ) && ( $brand = Brand::find()
->joinWith('lang')
->andFilterWhere([ 'remote_id' => $parsed_name[ 'remote_id' ] ])
->one() ) !== NULL
) {
if(!empty( $brand->lang )) {
$brand->lang->name = $parsed_name[ 'name' ];
$brand->lang->save();
} else {
throw new \Exception('Brand with ID ' . $brand->brand_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
return $brand->brand_id;
} else {
// Create brand
$brand = new Brand();
$brand->generateLangs();
$brand_langs = $brand->model_langs;
foreach($brand_langs as $brand_lang) {
$brand_lang->name = $parsed_name[ 'name' ];
}
$brand->remote_id = $parsed_name[ 'remote_id' ];
$brand->save();
return $brand->brand_id;
}
}
return NULL;
}
/**
* @param array $fotos
* @param int $product_id
* @param int $product_variant_id
*/
private function saveFotos(array $fotos, int $product_id, int $product_variant_id = NULL)
{
if(!empty( $fotos )) {
foreach($fotos as $foto) {
$source_image = Yii::getAlias('@uploadDir') . '/product_images/' . urlencode($foto);
if(file_exists($source_image)) {
if(( $productImage = ProductImage::find()
->andWhere([ 'image' => $foto ])
->andWhere([ 'product_id' => $product_id ])
->andFilterWhere([ 'product_variant_id' => $product_variant_id ])
->one() ) === NULL
) {
copy($source_image, Yii::getAlias('@productsDir') . "/" . $foto);
$productImage = new ProductImage();
$productImage->product_id = $product_id;
$productImage->product_variant_id = $product_variant_id;
$productImage->image = $foto;
$productImage->save();
}
}
}
}
}
/**
* @param array $data
* @param float $product_cost_old
* @param float $product_cost
* @param int $product_id
* @param array $category_id
*
* @return array
*/
private function saveVariants(array $data, float $product_cost_old, int $product_id, array $category_id, float $product_cost = NULL):array
{
$MOD_ARRAY = [];
for($i = 13; $i < count($data); $i++) {
if(!empty ( $data[ $i ] )) {
$mod_arr = explode('=', $data[ $i ]);
$mod_art = $mod_arr[ 0 ];
$variant_filters = explode('*', $mod_arr[ 1 ]);
$mod_name = $mod_arr[ 2 ];
if(empty( $mod_name )) {
$mod_name = $mod_art;
}
$mod_image = $mod_arr[ 3 ];
$mod_stock = isset( $mod_arr[ 4 ] ) ? $mod_arr[ 4 ] : 1;
$mod_cost = isset( $product_cost ) ? floatval($product_cost) : 0;
$mod_old_cost = floatval($product_cost_old);
// Check product variant
/**
* @var ProductVariant $_productVariant
*/
if(( $_productVariant = ProductVariant::find()
->joinWith('lang')
->andFilterWhere([ 'sku' => $mod_art ])
->andFilterWhere([ 'product_variant.product_id' => $product_id ])
->one() ) === NULL
) {
$_productVariant = new ProductVariant();
$_productVariant->product_id = $product_id;
$_productVariant->generateLangs();
$product_variant_langs = $_productVariant->model_langs;
foreach($product_variant_langs as $product_variant_lang) {
$product_variant_lang->name = $mod_name;
}
} else {
if(!empty( $_productVariant->lang )) {
$_productVariant->lang->name = $mod_name;
$_productVariant->lang->save();
} else {
throw new \Exception('Product variant with ID ' . $_productVariant->product_variant_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
}
$_productVariant->product_unit_id = 1;
$_productVariant->sku = $mod_art;
$_productVariant->price = $mod_cost;
$_productVariant->price_old = $mod_old_cost;
$_productVariant->stock = $mod_stock;
if(!empty ( $variant_filters )) {
$variants_options = $this->saveFilters($variant_filters, 1, $category_id);
}
if(isset( $variants_options ) && !empty( $variants_options )) {
$_productVariant->options = $variants_options;
}
/**
* @todo set to false
*/
$_productVariant->save(false);
$MOD_ARRAY[] = $_productVariant->product_variant_id;
$this->saveFotos([ $mod_image ], $product_id, $_productVariant->product_variant_id);
}
}
return $MOD_ARRAY;
}
// private function debug($start_time, $message) {
// echo $message.': '.(time()-$start_time).'s passed';
// }
public function goProducts($from = 0, $limit = NULL)
{
set_time_limit(0);
if(!( $handle = $this->getProductsFile('uploadFileProducts') )) {
$this->errors[] = 'File not found';
return false;
}
$filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'));
if($from) {
fseek($handle, $from);
}
$j = 0;
$is_utf = ( preg_match('//u', file_get_contents(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'), NULL, NULL, NULL, 1000000)) );
$result_items = [];
while(( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) {
try {
foreach($data as &$value) {
if(!$is_utf) {
$value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
}
$value = trim($value);
}
// будет всегда 19 элементов
for($i = 0; $i <= 18; $i++) {
if(!isset ( $data[ $i ] )) {
$data[ $i ] = NULL;
}
}
// 1 Группа (категория)
$catalog_names = explode(',', $data[ 0 ]);
if(empty ( $catalog_names )) {
$result_items[] = "Не указана категория (строка $j)";
continue;
}
// 2 Бренд
$brand_name = $data[ 1 ];
// if(empty ( $brand_name )) {
// $result_items[] = "Не указан бренд (строка $j)";
// continue;
// }
// 3 Название товара
$product_name = $data[ 2 ];
if(empty ( $product_name )) {
$result_items[] = "Не указано наименование товара (строка $j)";
continue;
}
// 5 Описание товара
$product_body = $data[ 3 ];
// 6 Фильтр
$filters = explode('*', $data[ 4 ]);
// 11 Цена акция
$product_cost_old = floatval($data[ 6 ]);
$product_cost = NULL;
// 10 Цена
if($product_cost_old) {
$product_cost_old = floatval($data[ 5 ]);
$product_cost = floatval($data[ 6 ]);
}
// 12 Акция
$product_akciya = (bool) $data[ 7 ];
// 13 Сопуд. Тов.
$similar = explode(',', $data[ 8 ]);
// 14 Новинки
$product_new = (bool) $data[ 9 ];
// 15 Топ продаж
$product_top = (bool) $data[ 10 ];
// 17 ВИДЕО КОД
$product_video = $data[ 11 ];
// 18 Галлерея фото
$fotos = [];
if(trim($data[ 12 ])) {
$fotos = explode(',', trim($data[ 12 ]));
}
// $lang = \Yii::$app->session->get('export_lang', Language::getDefaultLanguage()->language_id);
// /**
// * @var Language $language
// */
// $language = Language::find()
// ->where([ 'language_id' => $lang ])
// ->one();
// Language::setCurrent($language->url);
$categories = $this->saveCatalog($catalog_names);
$brand_id = $this->saveBrand($brand_name);
$options = [];
if(!empty ( $filters )) {
$options = $this->saveFilters($filters, 0, $categories);
}
$parsed_name = $this->parseName($product_name);
/**
* @var Product $_product
*/
if(!empty( $parsed_name[ 'remote_id' ] ) && ( $_product = Product::find()
->joinWith('lang')
->andFilterWhere([ 'remote_id' => $parsed_name[ 'remote_id' ] ])
->one() ) !== NULL
) {
if(!empty( $_product->lang )) {
$_product->lang->name = $parsed_name[ 'name' ];
$_product->lang->description = $product_body;
$_product->lang->save();
} else {
throw new \Exception('Product with ID ' . $_product->product_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
} else {
$_product = new Product();
$_product->generateLangs();
$product_langs = $_product->model_langs;
foreach($product_langs as $product_lang) {
$product_lang->name = $parsed_name[ 'name' ];
$product_lang->description = $product_body;
}
}
$is_new_product = empty( $_product->product_id );
$_product->categories = $categories;
$_product->brand_id = $brand_id;
$_product->video = $product_video;
$_product->is_top = $product_top;
$_product->akciya = $product_akciya;
$_product->is_new = $product_new;
if(!empty( $options )) {
$_product->options = $options;
}
if(!empty( $_product->lang )) {
$product_name_inserted = $_product->lang->name;
} else {
$product_name_inserted = $_product->model_langs[ Language::$current->language_id ]->name;
}
if(!$_product->save() || !$_product->transactionStatus) {
$result_items[] = 'Product #' . $product_name_inserted . ' not saved' . " (line $j)";
continue;
}
$this->saveFotos($fotos, $_product->product_id);
// нужно для проставления характеристик относящихся к модификациям
$this->saveVariants($data, $product_cost_old, $_product->product_id, $_product->categories, $product_cost);
// $_product->save();
$result_items[] = "Product {$product_name_inserted} #{$_product->product_id} saved (" . ( $is_new_product ? 'new product' : 'exists product' ) . ")" . " (line $j)";
} catch(\Exception $e) {
$result_items[] = $e->getMessage() . '(line ' . $j . ')';
}
}
$result = [
'end' => feof($handle),
'from' => ftell($handle),
'totalsize' => $filesize,
'items' => $result_items,
];
fclose($handle);
if($result[ 'end' ]) {
// unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'));
}
return $result;
}
private function getProductsFile($file_type)
{
$filename = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@' . $file_type);
if(!is_file($filename)) {
$this->errors[] = "File $filename not found";
return false;
}
return fopen($filename, 'r');
}
/**
* @param $filters array of filters like [['pol'='мужской'],['god' =
* '2013'],['volume'='25 л']*['size'='49 x 30 x
* 20см'],['composition'='600D полиэстер']]
* @param int $level 0 for products and 1 for product variant
* @param $catalog_names array catalogs id
*
* @return array
* @throws \Exception
*/
private function saveFilters(array $filters, int $level, array $catalog_names):array
{
$options = [];
foreach($filters as $filter) {
preg_match_all('/\[(.*):(.*)\]/', $filter, $filter);
if(empty( $filter[ 1 ][ 0 ] )) {
continue;
}
$filter_name = trim($filter[ 1 ][ 0 ]);
$parsed_group_name = $this->parseName($filter_name);
/**
* @var TaxGroup $taxGroup
*/
if(!empty( $parsed_group_name[ 'remote_id' ] ) && ( $taxGroup = TaxGroup::find()
->joinWith('lang')
->andFilterWhere([ 'remote_id' => $parsed_group_name[ 'remote_id' ] ])
->one() ) !== NULL
) {
if(!empty( $taxGroup->lang )) {
$taxGroup->lang->name = $parsed_group_name[ 'name' ];
$taxGroup->lang->save();
} else {
throw new \Exception('Tax group with ID ' . $taxGroup->tax_group_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
} else {
$taxGroup = new TaxGroup();
$taxGroup->generateLangs();
$tax_group_langs = $taxGroup->model_langs;
foreach($tax_group_langs as $tax_group_lang) {
$tax_group_lang->name = $parsed_group_name[ 'name' ];
}
$taxGroup->level = $level;
$taxGroup->categories = $catalog_names;
$taxGroup->is_filter = false;
$taxGroup->save();
}
$filters_options = explode(',', $filter[ 2 ][ 0 ]);
foreach($filters_options as $filter_options) {
$parsed_option_name = $this->parseName($filter_options);
/**
* @var TaxOption $option
*/
if(!empty( $parsed_option_name[ 'remote_id' ] ) && ( $option = TaxOption::find()
->joinWith('lang')
->andFilterWhere([ 'remote_id' => $parsed_option_name[ 'remote_id' ] ])
->andFilterWhere([ 'tax_group_id' => $taxGroup->tax_group_id ])
->one() ) !== NULL
) {
if(!empty( $option->lang )) {
$option->lang->value = $parsed_option_name[ 'name' ];
$option->lang->save();
} else {
throw new \Exception('Tax option with ID ' . $option->tax_option_id . ' and lang ' . Language::getCurrent()->language_id . ' doesn\'t exist');
}
} else {
// Create option
$option = new TaxOption();
$option->generateLangs();
$option_langs = $option->model_langs;
foreach($option_langs as $option_lang) {
$option_lang->value = $parsed_option_name[ 'name' ];
}
$option->tax_group_id = $taxGroup->tax_group_id;
$option->save();
}
$options[] = $option->tax_option_id;
}
}
return $options;
}
}