diff --git a/common/modules/language/behaviors/LanguageBehavior.php b/common/modules/language/behaviors/LanguageBehavior.php index 19513db..4a77a82 100755 --- a/common/modules/language/behaviors/LanguageBehavior.php +++ b/common/modules/language/behaviors/LanguageBehavior.php @@ -271,6 +271,9 @@ $this->_transaction->commit(); $this->_transaction_status = true; } + if($owner->hasAttribute('remote_id') && empty($owner->remote_id)) { + $owner->remote_id = (int) $owner->primaryKey; + } } /** diff --git a/common/modules/language/models/Language.php b/common/modules/language/models/Language.php index a542c54..da077d7 100755 --- a/common/modules/language/models/Language.php +++ b/common/modules/language/models/Language.php @@ -17,7 +17,10 @@ */ class Language extends \yii\db\ActiveRecord { - + + /** + * @var null|self + */ public static $current = null; /** diff --git a/common/modules/product/controllers/ManageController.php b/common/modules/product/controllers/ManageController.php index 7ee50f6..fab4238 100755 --- a/common/modules/product/controllers/ManageController.php +++ b/common/modules/product/controllers/ManageController.php @@ -4,6 +4,7 @@ use common\models\ProductCertificate; use common\models\ProductSpec; + use common\modules\language\models\Language; use common\modules\product\models\Export; use common\modules\product\models\Import; use common\modules\product\models\ProductImage; @@ -313,7 +314,19 @@ { $model = new Import(); + $languages = Language::find() + ->select([ + 'name', + 'language_id', + ]) + ->where([ 'status' => 1 ]) + ->orderBy([ 'default' => SORT_DESC ]) + ->asArray() + ->indexBy('language_id') + ->column(); + if($model->load(Yii::$app->request->post())) { + \Yii::$app->session->set('export_lang', $model->lang); $file = UploadedFile::getInstances($model, 'file'); $method = 'go' . ucfirst($model->type); $target = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFile' . ucfirst($model->type)); @@ -337,7 +350,8 @@ } return $this->render('import', [ - 'model' => $model, + 'model' => $model, + 'languages' => $languages, ]); } @@ -349,7 +363,7 @@ if(Yii::$app->request->isAjax) { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - return $model->goProducts($from, 10); + return $model->goProducts($from, 1); } } @@ -371,7 +385,7 @@ $model = new Export(); if(Yii::$app->request->isAjax) { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - return $model->process($filename,$from); + return $model->process($filename, $from); } } @@ -382,8 +396,8 @@ if($model->load(Yii::$app->request->post())) { \Yii::$app->session->set('export_lang', $model->lang); return $this->render('export-process', [ - 'model' => $model, - 'method' => 'export', + 'model' => $model, + 'method' => 'export', ]); } diff --git a/common/modules/product/models/Import.php b/common/modules/product/models/Import.php index 62934b0..c1ecdf2 100755 --- a/common/modules/product/models/Import.php +++ b/common/modules/product/models/Import.php @@ -1,490 +1,714 @@ 'csv'], - ]; - } - - /** - * @inheritdoc - */ - public function attributeLabels() + + namespace common\modules\product\models; + + use common\modules\language\models\Language; + use common\modules\rubrication\models\TaxGroup; + use common\modules\rubrication\models\TaxOption; + use Yii; + use yii\base\Model; + use yii\helpers\ArrayHelper; + + class Import extends Model { - 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; + + public $file; + + public $type; + + public $lang; + + public $errors = []; + + public $output = []; + + /** + * @inheritdoc + */ + public function rules() + { + return [ + [ + [ + 'type', + 'lang', + ], + 'required', + ], + [ + [ 'lang' ], + 'integer', + ], + [ + [ 'type' ], + 'string', + ], + [ + [ 'file' ], + 'file', + 'extensions' => 'csv', + ], + ]; } - - $filesize = filesize(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFilePrices')); - if ($from) { - fseek($handle, $from); + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'file' => Yii::t('product', 'File'), + ]; } - - $j = 0; - - $is_utf = (preg_match('//u', file_get_contents(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFilePrices'), null, null, null, 1000000))); - - while (($data = fgetcsv ($handle, 10000, ";")) !== FALSE && (empty($limit) || $j++ < $limit)) + + public function getType() { - 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(!$this->type) { + $this->type = 'products'; } - // товары в пути - if (empty ($city_name)) - { - $this->output[] = 'Товар '. $product_title . ' в пути'; - continue; + 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; } - - if ( ($productVariant = ProductVariant::find()->filterWhere(['sku' => $modification_code])->one()) === null ) { - $this->output[] = 'Для товара '. $product_title . ' не найдено соотвествие'; - continue; + + $filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices')); + if($from) { + fseek($handle, $from); } - // ===== 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(); + + $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); } - - $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; + + // данные строк + $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; } - $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){ + // товары в пути + 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 { - $quantity = 0; + + $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 . ' успешно сохранен'; } - - if ($price_promo) { - $productVariant->price_old = $price; - $productVariant->price = $price_promo; - } else { - $productVariant->price = $price; - $productVariant->price_old = $price_promo; + + $result = [ + 'end' => feof($handle), + 'from' => ftell($handle), + 'totalsize' => $filesize, + 'items' => $this->output, + + ]; + + fclose($handle); + + if($result[ 'end' ]) { + unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices')); } - - $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; - } - - public function goProducts($from = 0, $limit = null) { - - set_time_limit(0); - - if ( !($handle = $this->getProductsFile('uploadFileProducts')) ) { - $this->errors[] = 'File not found'; - return FALSE; + + return $result; } - - $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 (($data = fgetcsv ($handle, 10000, ";")) !== FALSE && (empty($limit) || $j++ < $limit)) + /** + * @param string $name + * + * @return array + */ + private function parseName(string $name):array { - 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; + $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; } - // 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; - } - - // 4 Описание Укр - $product_body_uk = $data[3]; - - // 5 Описание Рус - $product_body_ru = $data[4]; - - // 6 Фильтр - $filters = explode ('*', $data[5]); - - // 11 Цена акция - $product_cost_old = floatval($data[7]); - - // 10 Цена - if ($product_cost_old) { - $product_cost_old = floatval($data[6]); - $product_cost = floatval($data[7]); - } - - // 12 Акция - $product_akciya = (bool)$data[8]; - - // 13 Сопуд. Тов. - $similar = explode (',', $data[9]); - - // 14 Новинки - $product_new = (bool)$data[10]; - - // 15 Топ продаж - $product_top = (bool)$data[11]; - - // 17 ВИДЕО КОД - $product_video = $data[12]; - - // 18 Галлерея фото - if (trim($data[13])) { - $fotos = explode (',', trim($data[13])); - } - - // 19 Штрих код товара. - // расшифровал - это модификации товара! - - $product_image = explode ('=', $data[14]); - $product_image = @$product_image[3]; - - if ( ($_product = Product::find()->filterWhere(['ilike', 'name', trim($product_name)])->one()) === null ) { - $_product = new Product(); - } - - $is_new_product = empty($_product->product_id); - + 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){ + foreach($catalog_names as $catalog_name) { // ==== Set category ==== - if ( ($category = Category::find()->filterWhere(['ilike', 'name', trim($catalog_name)])->one()) === null ) { + $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->name = trim($catalog_name); + $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; } - - $_product->categories = $category_id; - - // ===== Set brand ==== - if ( $brand_name ) { + 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 ( ($brand = Brand::find()->filterWhere(['ilike', 'name', trim($brand_name)])->one()) !== null ) { - $_product->brand_id = $brand->brand_id; + 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->name = trim($brand_name); + $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(); - $_product->brand_id = $brand->brand_id; + return $brand->brand_id; } } - - $_product->name = $product_name; - $_product->video = $product_video; - $_product->description = $product_body_ru; - $_product->is_top = $product_top; - $_product->akciya = $product_akciya; - $_product->is_new = $product_new; - - if (!$_product->save()) { - $result_items[] = 'Product #'. $_product->name .' not saved' . " (строка $j)"; - continue; - } - - if (!empty($fotos)) { + 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()->andFilterWhere(['ilike', 'image', $foto])->andFilterWhere(['product_id' => $_product->product_id])->one()) === null) { + $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->product_id; + $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 = 14; $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_color = $mod_arr[2]; - $mod_image = $mod_arr[3]; - $mod_stock = isset($mod_arr[4]) ?$mod_arr[4]:1; - $mod_cost = isset($product_cost) ? floatval($product_cost) : 0; + 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 - if ( ($_productVariant = ProductVariant::find()->andFilterWhere(['ilike', 'sku', $mod_art])->andFilterWhere(['product_id' => $_product->product_id])->one()) === null ) { + /** + * @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->product_id; + $_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 ($mod_color)) { - $_productVariant->name = $mod_color; + + if(!empty ( $variant_filters )) { + $variants_options = $this->saveFilters($variant_filters, 1, $category_id); } - - if (! empty ($variant_filters)) { - $variants_options = $this->saveFilters($variant_filters,1,$category_id); - } - - - if (isset($variants_options) && !empty($variants_options)) { + + 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) + { + $start_time = time(); + set_time_limit(0); + + if(!( $handle = $this->getProductsFile('uploadFileProducts') )) { + $this->errors[] = 'File not found'; + return false; + } - if ($mod_image) { - $source_image = Yii::getAlias('@uploadDir') . '/product_images/'. urlencode($mod_image); - if (file_exists($source_image)) { - if (($variantImage = ProductImage::find()->andFilterWhere(['ilike', 'image', $mod_image])->andFilterWhere(['product_variant_id' => $_productVariant->product_variant_id])->one()) === null) { - copy($source_image, Yii::getAlias('@productsDir') . "/" . $mod_image); - $variantImage = new ProductImage(); - $variantImage->product_id = $_product->product_id; - $variantImage->product_variant_id = $_productVariant->product_variant_id; - $variantImage->image = $mod_image; - $variantImage->save(); - } + $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); + $start_time = time(); + $categories = $this->saveCatalog($catalog_names); + $this->debug($start_time, 'Categories'); + $start_time = time(); + $brand_id = $this->saveBrand($brand_name); + $this->debug($start_time, 'Brands'); + + $options = []; + if(!empty ( $filters )) { + $start_time = time(); + $options = $this->saveFilters($filters, 0, $categories); + $this->debug($start_time, 'saveFilters'); + } + $parsed_name = $this->parseName($product_name); + /** + * @var Product $_product + */ + $start_time = time(); + 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; + $this->debug($start_time, 'Product'); + if(!$_product->save()) { + if(!empty( $_product->lang )) { + $product_name_inserted = $_product->lang->name; + } else { + $product_name_inserted = $_product->model_langs[ Language::$current->language_id ]->name; } + $result_items[] = 'Product #' . $product_name_inserted . ' not saved' . " (line $j)"; + continue; } + $start_time = time(); + $this->saveFotos($fotos, $_product->product_id); + $this->debug($start_time, 'saveFotos'); + // нужно для проставления характеристик относящихся к модификациям + $start_time = time(); + $this->saveVariants($data, $product_cost_old, $_product->product_id, $_product->categories, $product_cost); + $this->debug($start_time, 'saveVariants'); + if(!empty( $options )) { + $_product->options = $options; + } + + $_product->save(); + + $result_items[] = "Product {$_product->lang->name} #{$_product->product_id} saved (" . ( $is_new_product ? 'new product' : 'exists product' ) . ")" . " (line $j)"; + + } catch(\Exception $e) { + print $result_items[] = $e->getMessage() . '(line ' . $j . ')'; } + } - - - - if (! empty ($filters)) { - $options = $this->saveFilters($filters,0,$category_id); - } - - - if (isset($options) && !empty($options)) { - $_product->options = $options; + + $result = [ + 'end' => feof($handle), + 'from' => ftell($handle), + 'totalsize' => $filesize, + 'items' => $result_items, + ]; + + fclose($handle); + + if($result[ 'end' ]) { +// unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts')); } - - $_product->save(); - - $result_items[] = "Product {$_product->name} #{$_product->product_id} saved (". ($is_new_product ? 'new product' : 'exists product') .")" . " (строка $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 $result; } - return fopen ($filename, 'r'); - } - - private function saveNotFoundRecord (array $line, $filename) - { - $str = implode (';', $line)."\n"; - $str = iconv ("UTF-8//TRANSLIT//IGNORE", "windows-1251", $str); - $fg = fopen (Yii::getAlias('@uploadDir') .'/'. $filename, 'a+'); - fputs ($fg, $str); - fclose ($fg); - } - - - /** - * @param $filters array of filters like [['pol'='мужской'],['god' = '2013'],['volume'='25 л']*['size'='49 x 30 x 20см'],['composition'='600D полиэстер']] - * @param $level 0 for products and 1 for product variant - * @param $catalog_names array catalogs id - * @return array - */ - private function saveFilters($filters, $level,$catalog_names){ - $options = []; - foreach($filters as $filter) { - - preg_match_all('/\[(.*):(.*)\]/',$filter,$filter); - - if (empty($filter[1][0])) { - continue; - } - $filter_name = trim($filter[1][0]); - - $taxGroup = TaxGroup::find()->where(['alias'=>$filter_name])->one(); - if(!$taxGroup instanceof TaxGroup){ - $taxGroup = new TaxGroup(); - $taxGroup->alias = $filter_name; - $taxGroup->level = $level; - $taxGroup->name = $filter_name; - $taxGroup->categories = $catalog_names; - $taxGroup->is_filter = FALSE; - $taxGroup->save(); + + 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; } - - $filters_options = explode(',',$filter[2][0]); - - foreach($filters_options as $filter_options){ - $option = TaxOption::find()->andFilterWhere(['ilike', 'value', $filters_options])->andFilterWhere(['tax_group_id' => $taxGroup->tax_group_id])->one(); - - if ($option === NULL) { - // Create option - $option = new TaxOption(); - $option->tax_group_id = $taxGroup->tax_group_id; - $option->value = $filter_options; - $option->save(); + 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); + $start_time = time(); + /** + * @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(); + } + print $this->debug($start_time, 'TaxGroup'); + $filters_options = explode(',', $filter[ 2 ][ 0 ]); + foreach($filters_options as $filter_options) { + $parsed_option_name = $this->parseName($filter_options); + /** + * @var TaxOption $option + */ + $start_time = time(); + 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; + print $this->debug($start_time, 'TaxOption'); } - $options[] = $option->tax_option_id; - } + return $options; } - - return $options; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/common/modules/product/models/Product.php b/common/modules/product/models/Product.php index 42e72d4..07cb7fc 100755 --- a/common/modules/product/models/Product.php +++ b/common/modules/product/models/Product.php @@ -344,46 +344,51 @@ ->where([ 'product_id' => $this->product_id ]) ->sum('quantity'); } - + public function afterSave($insert, $changedAttributes) { parent::afterSave($insert, $changedAttributes); - - $this->unlinkAll('categories', true); - $this->unlinkAll('options', true); - - $categories = Category::findAll($this->categories); - $options = TaxOption::findAll($this->options); - - foreach($options as $option) { - $this->link('options', $option); + + + if(!empty($this->categories)){ + $categories = Category::findAll($this->categories); + $this->unlinkAll('categories', true); + foreach($categories as $category){ + $this->link('categories', $category); + } } - foreach($categories as $category) { - $this->link('categories', $category); + + if(!empty($this->options)){ + $options = TaxOption::findAll($this->options); + $this->unlinkAll('options',true); + foreach($options as $option){ + $this->link('options', $option); + } } - - if(!empty( $this->_variants )) { + + + if (!empty($this->_variants)) { $todel = []; - foreach($this->variants ? : [] as $_variant) { - $todel[ $_variant->product_variant_id ] = $_variant->product_variant_id; + foreach ($this->variants ?: [] as $_variant) { + $todel[$_variant->product_variant_id] = $_variant->product_variant_id; } - foreach($this->_variants as $_variant) { - if(!is_array($_variant)) { + foreach ($this->_variants as $_variant) { + if (!is_array($_variant)) { return; } - if(!empty( $_variant[ 'product_variant_id' ] )) { - unset( $todel[ $_variant[ 'product_variant_id' ] ] ); - $model = ProductVariant::findOne($_variant[ 'product_variant_id' ]); + if (!empty($_variant['product_variant_id'])) { + unset($todel[$_variant['product_variant_id']]); + $model = ProductVariant::findOne($_variant['product_variant_id']); } else { $model = new ProductVariant(); } - $_variant[ 'product_id' ] = $this->product_id; - $model->load([ 'ProductVariant' => $_variant ]); + $_variant['product_id'] = $this->product_id; + $model->load(['ProductVariant' => $_variant]); $model->product_id = $this->product_id; $model->save(); } - if(!empty( $todel )) { - ProductVariant::deleteAll([ 'product_variant_id' => $todel ]); + if (!empty($todel)) { + ProductVariant::deleteAll(['product_variant_id' => $todel]); } } } diff --git a/common/modules/product/models/ProductVariant.php b/common/modules/product/models/ProductVariant.php index e48feca..3b3201b 100755 --- a/common/modules/product/models/ProductVariant.php +++ b/common/modules/product/models/ProductVariant.php @@ -333,15 +333,29 @@ ->where([ 'tax_group_to_category.category_id' => $categories ]) ->where([ 'level' => $level ]); } - + public function afterSave($insert, $changedAttributes) { - parent::afterSave($insert, $changedAttributes); - $this->unlinkAll('options', true); - $options = TaxOption::findAll($this->options); - foreach($options as $option) { - $this->link('options', $option); + + if(!empty($this->_options)){ + $options = TaxOption::findAll($this->_options); + $this->unlinkAll('options',true); + foreach($options as $option){ + $this->link('options', $option); + } } + + + if (!empty($this->stocks)) { + ProductStock::deleteAll(['product_variant_id' => $this->product_variant_id]); + $values = []; + foreach ($this->stocks as $id => $quantity) { + $productStock = ProductStock::find()->where(['product_variant_id' => $this->product_variant_id, 'stock_id' => $id])->one(); + $productStock->quantity = $quantity; + $productStock->save(); + } + } + parent::afterSave($insert, $changedAttributes); } public function imagesUpload() diff --git a/common/modules/product/views/manage/import-process.php b/common/modules/product/views/manage/import-process.php index af24fce..cf6972c 100755 --- a/common/modules/product/views/manage/import-process.php +++ b/common/modules/product/views/manage/import-process.php @@ -1,16 +1,6 @@ registerJs(" - -"); -?> - - +"); +//?>

Импорт товаров

diff --git a/common/modules/product/views/manage/import.php b/common/modules/product/views/manage/import.php index 81f9a31..7a7a339 100755 --- a/common/modules/product/views/manage/import.php +++ b/common/modules/product/views/manage/import.php @@ -1,35 +1,47 @@
false, - 'options' => ['enctype' => 'multipart/form-data'] + 'options' => [ 'enctype' => 'multipart/form-data' ], ]); ?> - - errors) :?> -
- \n", $model->errors);?> -
- - - output) :?> + + errors) : ?> +
+ \n", $model->errors); ?> +
+ + + output) : ?>

Лог операции

-
- \n", $model->output);?> -
- - - field($model, 'type')->radioList([ - 'products' => Yii::t('product', 'Load products'), - 'prices' => Yii::t('product', 'Load prices'), - ]);?> - - field($model, 'file')->fileInput(['multiple' => false,])?> - +
+ \n", $model->output); ?> +
+ + + field($model, 'type') + ->radioList([ + 'products' => Yii::t('product', 'Load products'), + 'prices' => Yii::t('product', 'Load prices'), + ]); ?> + + field($model, 'lang') + ->dropDownList($languages); ?> + + field($model, 'file') + ->fileInput([ 'multiple' => false, ]) ?> + field($model, 'file')->widget(\kartik\file\FileInput::classname(), [ 'language' => 'ru', 'options' => [ @@ -41,11 +53,11 @@ use yii\widgets\ActiveForm; 'showRemove' => false, 'showUpload' => false, ], - ])*/?> - + ])*/ ?> +
- 'btn btn-primary']) ?> + 'btn btn-primary' ]) ?>
- +
diff --git a/common/modules/rubrication/models/TaxOption.php b/common/modules/rubrication/models/TaxOption.php index b3e7126..b3291e8 100755 --- a/common/modules/rubrication/models/TaxOption.php +++ b/common/modules/rubrication/models/TaxOption.php @@ -63,10 +63,10 @@ ], ], ], - 'artboxtree' => [ - 'class' => ArtboxTreeBehavior::className(), - 'keyNameGroup' => 'tax_group_id', - ], +// 'artboxtree' => [ +// 'class' => ArtboxTreeBehavior::className(), +// 'keyNameGroup' => 'tax_group_id', +// ], 'language' => [ 'class' => LanguageBehavior::className(), ], diff --git a/console/controllers/ImportController.php b/console/controllers/ImportController.php index 886a64b..445a60c 100755 --- a/console/controllers/ImportController.php +++ b/console/controllers/ImportController.php @@ -20,15 +20,15 @@ class ImportController extends Controller { } public function actionProducts() { - if (file_exists(Yii::getAlias('@uploadDir/goProducts.lock'))) { - $this->errors[] = 'Task already executed'; - return Controller::EXIT_CODE_ERROR; - } - $ff = fopen(Yii::getAlias('@uploadDir/goProducts.lock'), 'w+'); - fclose($ff); +// if (file_exists(Yii::getAlias('@uploadDir/goProducts.lock'))) { +// $this->errors[] = 'Task already executed'; +// return Controller::EXIT_CODE_ERROR; +// } +// $ff = fopen(Yii::getAlias('@uploadDir/goProducts.lock'), 'w+'); +// fclose($ff); $model = new Import(); $model->goProducts(0, null); - unlink(Yii::getAlias('@uploadDir/goProducts.lock')); +// unlink(Yii::getAlias('@uploadDir/goProducts.lock')); return Controller::EXIT_CODE_NORMAL; } diff --git a/console/migrations/m161011_104931_create_stock_lang_table.php b/console/migrations/m161011_104931_create_stock_lang_table.php new file mode 100644 index 0000000..f47a7da --- /dev/null +++ b/console/migrations/m161011_104931_create_stock_lang_table.php @@ -0,0 +1,39 @@ +createTable('stock_lang', [ + 'stock_id' => $this->integer() + ->notNull(), + 'language_id' => $this->integer() + ->notNull(), + 'name' => $this->string() + ->notNull(), + ]); + $this->createIndex('stock_lang_stock_language_key', 'stock_lang', [ + 'stock_id', + 'language_id', + ], true); + + $this->addForeignKey('stock_fk', 'stock_lang', 'stock_id', 'stock', 'stock_id', 'CASCADE', 'CASCADE'); + $this->addForeignKey('language_fk', 'stock_lang', 'language_id', 'language', 'language_id', 'RESTRICT', 'CASCADE'); + } + + /** + * @inheritdoc + */ + public function down() + { + $this->dropTable('stock_lang'); + } +} -- libgit2 0.21.4