Commit a0405ed668e4f096c83064fe6863f761479ef3dd

Authored by Administrator
2 parents 021728bd f02e1203

Merge remote-tracking branch 'origin/master'

backend/controllers/CheckPriceController.php
... ... @@ -8,6 +8,7 @@ use yii\filters\AccessControl;
8 8 use backend\components\base\BaseController;
9 9 use yii\filters\VerbFilter;
10 10 use backend\models\Details;
  11 +use common\models\DetailsCurrency;
11 12 use backend\models\ImportersFiles;
12 13 use backend\models\Importers;
13 14 use yii\base\ErrorException;
... ... @@ -61,7 +62,7 @@ class CheckPriceController extends BaseController
61 62  
62 63 public function actionIndex()
63 64 {
64   - //$query = (new Query())->select('*')->from('{{%importer_files}}')->where(['not', ['time_end' => null]])->orderBy(['upload_time' => SORT_DESC]);
  65 +
65 66 $query = Importers::find()->where(['active' => true])->orderBy(['price_date_update' => SORT_DESC]);
66 67 $provider = new ActiveDataProvider([
67 68 'query' => $query,
... ... @@ -79,11 +80,12 @@ class CheckPriceController extends BaseController
79 80 public function actionView ($id, $date_update)
80 81 {
81 82  
82   - $query = Details::find()->where(['IMPORT_ID' => $id, 'timestamp' => $date_update])->limit(20);
  83 + $query = DetailsCurrency::find()->where(['IMPORT_ID' => $id, 'timestamp' => $date_update])->limit(20);
83 84  
84   - $importer = Importers::findOne($id)->name;
  85 + $importer = Importers::findOne( $id );
85 86 $date = Yii::$app->formatter->asDate( $date_update, 'yyyy-MM-dd' );
86 87  
  88 +
87 89 $provider = new ActiveDataProvider([
88 90 'query' => $query,
89 91 'pagination' => false,
... ...
backend/controllers/CrossingUploadController.php 0 → 100644
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Tsurkanov
  5 + * Date: 15.10.2015
  6 + * Time: 12:27
  7 + */
  8 +
  9 +namespace backend\controllers;
  10 +
  11 +use backend\components\base\BaseController;
  12 +use common\components\CustomVarDamp;
  13 +use yii\filters\AccessControl;
  14 +use backend\models\UploadFileCrossingForm;
  15 +use backend\models\DetailsCrosses;
  16 +use yii\web\UploadedFile;
  17 +use \Yii;
  18 +
  19 +class CrossingUploadController extends BaseController
  20 +{
  21 + public $layout = "/column";
  22 +
  23 + /**
  24 + * @inheritdoc
  25 + */
  26 + public function behaviors()
  27 + {
  28 + return [
  29 + 'access' => [
  30 + 'class' => AccessControl::className(),
  31 + 'rules' => [
  32 + [
  33 + 'actions' => ['index', 'result'],
  34 + 'allow' => true,
  35 + 'roles' => ['@'],
  36 + ],
  37 + ],
  38 + ],
  39 +// 'verbs' => [
  40 +// 'class' => VerbFilter::className(),
  41 +// 'actions' => [
  42 +// 'logout' => ['post'],
  43 +// ],
  44 +// ],
  45 + ];
  46 + }
  47 +
  48 + /**
  49 + * @inheritdoc
  50 + */
  51 + public function actions()
  52 + {
  53 + return [
  54 + 'error' => [
  55 + 'class' => 'yii\web\ErrorAction',
  56 + ],
  57 + ];
  58 + }
  59 +
  60 +
  61 + public function actionIndex()
  62 + {
  63 + $model = new UploadFileCrossingForm();
  64 + return $this->render('index', ['model' => $model]);
  65 + }
  66 +
  67 + public function actionResult()
  68 + {
  69 + $model = new UploadFileCrossingForm();
  70 + $data = [];
  71 + if ($model->load(Yii::$app->request->post())) {
  72 + $model->file = UploadedFile::getInstance($model, 'file');
  73 +
  74 + if ($model->validate()) {
  75 + $file_name = $model->file->name;
  76 + $model->file_path = Yii::getAlias('@temp_upload') . '/' . $file_name;
  77 +
  78 + $model->file->saveAs($model->file_path);
  79 + //запускаем парсинг
  80 + // доп. опции для парсера - удаление префикса в артикулах
  81 + $options['mode'] = 'crosses';
  82 + $fields = [];
  83 + if ($model->delete_prefix1) {
  84 + $fields[] = 'ARTICLE';
  85 + }
  86 + if ($model->delete_prefix2) {
  87 + $fields[] = 'CROSS_ARTICLE';
  88 + }
  89 + if ( $fields ) {
  90 + $options [ 'converter_conf' ] = [ 'configuration' => [ "article" => $fields ,
  91 + "string" => ['ARTICLE', 'CROSS_ARTICLE'],] ];
  92 + } else {
  93 + $options [ 'converter_conf' ] = [ 'configuration' => [ "string" => ['ARTICLE', 'CROSS_ARTICLE'], ] ];
  94 + }
  95 +
  96 + $data = $model->readFile( $options );
  97 + $crosses_model = new DetailsCrosses();
  98 + $crosses_model->ManualInsertWithIgnore( $data );
  99 +
  100 + Yii::$app->session->setFlash('success', 'Файл кроссов успешно загружен');
  101 + return $this->render('index', ['model' => $model]);
  102 + }else{
  103 + // не прошла валидация форма загрузки файлов
  104 + $errors_str = '';
  105 + foreach ($model->getErrors() as $error) {
  106 + $errors_str .= implode( array_values($error) );
  107 + }
  108 + throw new \ErrorException( $errors_str );
  109 + }
  110 +
  111 + } else {
  112 + throw new \ErrorException( 'Ошибка загрузки данных' );
  113 + }
  114 + }
  115 +}
0 116 \ No newline at end of file
... ...
backend/controllers/ParserController.php
... ... @@ -10,7 +10,6 @@ use backend\models\UploadFileParsingForm;
10 10 use yii\web\UploadedFile;
11 11 use yii\data\ArrayDataProvider;
12 12 use yii\multiparser\DynamicFormHelper;
13   -use backend\components\parsers\CustomParserConfigurator;
14 13 use backend\models\ImportersFiles;
15 14 use backend\models\Importers;
16 15 use yii\base\ErrorException;
... ... @@ -101,7 +100,6 @@ class ParserController extends BaseController
101 100 }
102 101  
103 102 $model->file->saveAs($model->file_path);
104   -
105 103 // для авто загрузки, обработка завершена
106 104 if ($model->mode) {
107 105 $model->success = true;
... ... @@ -112,7 +110,10 @@ class ParserController extends BaseController
112 110 // === ручная загрузка ===========
113 111 //запускаем парсинг
114 112 // доп. опции для парсера
115   - $options = [];
  113 + $options = ['converter_conf' =>
  114 + ['importer_id' => $files_model->importer_id]
  115 + ];
  116 +
116 117 if( ! $model->action ) // обработка с кастомным разделителем
117 118 $options['$delimiter'] = $model->delimiter;
118 119  
... ... @@ -124,12 +125,11 @@ class ParserController extends BaseController
124 125  
125 126 } else {
126 127 // не прошла валидация форма загрузки файлов
127   - //@todo - отправка на страницу ошибок
128   - $errors_arr = $model->getErrors();
129   - foreach ($errors_arr as $error) {
130   - CustomVarDamp::dump(array_values($error));
  128 + $errors_str = '';
  129 + foreach ($model->getErrors() as $error) {
  130 + $errors_str .= implode( array_values($error) );
131 131 }
132   - die;
  132 + throw new ErrorException( $errors_str );
133 133 }
134 134 // листаем пагинатором, или повторно вызываем - считываем из кеша отпрасенные данные
135 135 } else if (Yii::$app->getCache()->get('parser_data')) {
... ... @@ -145,8 +145,11 @@ class ParserController extends BaseController
145 145 ],
146 146 ]);
147 147  
  148 +
  149 + $last_index = end( array_flip( $data[0] ) );
  150 + $header_counts = $last_index + 1;
148 151 //формируем заголовок для пользователя, где он сможет выбрать соответсвие полей (выпадающий список)
149   - $header_model = DynamicFormHelper::CreateDynamicModel(count($data[0]));
  152 + $header_model = DynamicFormHelper::CreateDynamicModel( $header_counts );
150 153  
151 154 return $this->render('results',
152 155 ['model' => $data,
... ... @@ -197,7 +200,9 @@ class ParserController extends BaseController
197 200 Yii::$app->getCache()->delete('parser_data');
198 201 Yii::$app->getCache()->delete('parser_configuration');
199 202  
200   - unlink($configuration['file_path']);
  203 + if( file_exists($configuration['file_path']) )
  204 + unlink($configuration['file_path']);
  205 +
201 206 return $this->render('index', ['model' => $configuration]);
202 207  
203 208 };
... ...
backend/models/Currency.php
... ... @@ -15,13 +15,6 @@ use Yii;
15 15 */
16 16 class Currency extends \yii\db\ActiveRecord
17 17 {
18   - /**
19   - * @inheritdoc
20   - */
21   - public static function tableName()
22   - {
23   - return 'w_currency';
24   - }
25 18  
26 19 /**
27 20 * @inheritdoc
... ...
backend/models/Details.php
... ... @@ -2,6 +2,7 @@
2 2  
3 3 namespace backend\models;
4 4  
  5 +use common\components\CustomVarDamp;
5 6 use Yii;
6 7 use backend\components\base\BaseActiveRecord;
7 8  
... ... @@ -22,8 +23,21 @@ use backend\components\base\BaseActiveRecord;
22 23 */
23 24 class Details extends BaseActiveRecord
24 25 {
25   - const KEY_COLUMN = ['IMPORT_ID','BRAND','ARTICLE'];
  26 + /**
  27 + *обязательные колонки
  28 + */
  29 + const KEY_COLUMN = ['IMPORT_ID', 'BRAND', 'ARTICLE'];
  30 +
  31 + /**
  32 + * int - размер пакета запроса
  33 + */
26 34 const BATCH = 500;
  35 +
  36 + /**
  37 + * @var bool - признак необходимости удалить префикс Артикула перед вставкой
  38 + */
  39 + public $delete_price = false;
  40 +
27 41 /**
28 42 * @inheritdoc
29 43 */
... ... @@ -38,8 +52,8 @@ class Details extends BaseActiveRecord
38 52 public function rules()
39 53 {
40 54 return [
41   - [[ 'BRAND', 'ARTICLE', 'PRICE', 'DESCR', 'BOX'], 'required'],
42   - // [['IMPORT_ID', 'BOX', 'ADD_BOX'], 'integer'],
  55 + [['BRAND', 'ARTICLE', 'PRICE', 'DESCR', 'BOX'], 'required'],
  56 + // [['IMPORT_ID', 'BOX', 'ADD_BOX'], 'integer'],
43 57 [['PRICE'], 'number'],
44 58 [['BOX'], 'integer'],
45 59 [['timestamp'], 'safe'],
... ... @@ -69,13 +83,38 @@ class Details extends BaseActiveRecord
69 83 ];
70 84 }
71 85  
72   - public function ManualInsert ($data)
  86 + /**
  87 + *удаление (если $delete_price установлен)б а затем вставка данных с апдейтом прямымыми запросоми SQL
  88 + * @param $data - массив вставляемых данных, вставка будет прозводится пакетами размером указанным в константе BATCH
  89 + * @param $importer_id - (int) - идентификатор поставщика у которого будет сперва удалены прайсы а потом вставлены из массива $data
  90 + * @throws \yii\db\Exception
  91 + */
  92 + public function ManualInsert($data, $importer_id)
  93 + {
  94 + if ($this->delete_price) {
  95 + // запустим пакетное удаление всех прайсов поставщика
  96 + do {
  97 + $query = Yii::$app->db->createCommand()->delete(self::tableName(), "IMPORT_ID = {$importer_id}")->sql . ' Limit ' . $this::BATCH;
  98 + $res = Yii::$app->db->createCommand($query)->execute();
  99 + } while ($res);
  100 +
  101 + }
  102 +
  103 + $this->ManualInsertWithUpdate($data);
  104 + }
  105 +
  106 + /**
  107 + * вставка данных с апдейтом прямым запросом SQL
  108 + * @param $data - массив вставляемых данный, вставка будет прозводится пакетами размером указанным в константе BATCH
  109 + * @throws \yii\db\Exception
  110 + */
  111 + private function ManualInsertWithUpdate($data)
73 112 {
74 113 // \common\components\CustomVarDamp::dumpAndDie($data);
75 114 $table_name = self::tableName();
76   - $keys_arr = array_keys( $data[0] );
  115 + $keys_arr = array_keys($data[0]);
77 116 // найдем те поля которые не являются ключами. Их нужно будет при дубляже апдейтить
78   - $fields_arr_to_update = array_diff( $keys_arr, $this::KEY_COLUMN );
  117 + $fields_arr_to_update = array_diff($keys_arr, $this::KEY_COLUMN);
79 118  
80 119 $query_update = ' on duplicate key update ';
81 120 foreach ($fields_arr_to_update as $field) {
... ... @@ -87,18 +126,16 @@ class Details extends BaseActiveRecord
87 126 // запросы будем выполнять пакетами
88 127 // размер пакета установлен в константе
89 128 // разобъем массив на пакеты и будем их проходить
90   - $data = array_chunk($data, $this::BATCH );
91   - foreach( $data as $current_batch_array ){
  129 + $data = array_chunk($data, $this::BATCH);
  130 + foreach ($data as $current_batch_array) {
92 131  
93   - //воспользуемся пакетной вставкой от фреймворка, плюс сразу с экранированием и защитой от инъекций
  132 + //воспользуемся пакетной вставкой от фреймворка
94 133 $query_insert = Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $current_batch_array)->sql;
95 134 // добавим фрагмент с апдейтом при дубляже
96 135 $query = "{$query_insert} {$query_update}";
97 136 // \common\components\CustomVarDamp::dumpAndDie($query);
98   - $res = Yii::$app->db->createCommand($query)->execute();
  137 + Yii::$app->db->createCommand($query)->execute();
99 138  
100 139 }
101 140 }
102   -
103   -
104 141 }
... ...
backend/models/DetailsCrosses.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\models;
  4 +
  5 +use common\components\CustomVarDamp;
  6 +use Yii;
  7 +
  8 +/**
  9 + * This is the model class for table "{{%details_crosses}}".
  10 + *
  11 + * @property string $ID
  12 + * @property string $ARTICLE
  13 + * @property string $BRAND
  14 + * @property string $CROSS_BRAND
  15 + * @property string $CROSS_ARTICLE
  16 + * @property string $timestamp
  17 + */
  18 +class DetailsCrosses extends \backend\components\base\BaseActiveRecord
  19 +{
  20 + /**
  21 + * int - размер пакета запроса
  22 + */
  23 + const BATCH = 1000;
  24 + /**
  25 + * @inheritdoc
  26 + */
  27 + public static function tableName()
  28 + {
  29 + return '{{%details_crosses}}';
  30 + }
  31 +
  32 + /**
  33 + * @inheritdoc
  34 + */
  35 + public function rules()
  36 + {
  37 + return [
  38 + [['ARTICLE', 'BRAND', 'CROSS_BRAND', 'CROSS_ARTICLE'], 'required'],
  39 + [['timestamp'], 'safe'],
  40 + [['ARTICLE', 'BRAND', 'CROSS_BRAND', 'CROSS_ARTICLE'], 'string', 'max' => 100]
  41 + ];
  42 + }
  43 +
  44 + /**
  45 + * @inheritdoc
  46 + */
  47 + public function attributeLabels()
  48 + {
  49 + return [
  50 + 'ID' => Yii::t('app', 'ID'),
  51 + 'ARTICLE' => Yii::t('app', 'Article'),
  52 + 'BRAND' => Yii::t('app', 'Brand'),
  53 + 'CROSS_BRAND' => Yii::t('app', 'Cross Brand'),
  54 + 'CROSS_ARTICLE' => Yii::t('app', 'Cross Article'),
  55 + 'timestamp' => Yii::t('app', 'Timestamp'),
  56 + ];
  57 + }
  58 +
  59 + /**
  60 + * вставка данных с игнором дублей прямым запросом SQL
  61 + * @param $data - массив вставляемых данный, вставка будет прозводится пакетами размером указанным в константе BATCH
  62 + * @throws \yii\db\Exception
  63 + */
  64 + //@todo - вынести все ручные инсерты в отдельный класс
  65 + public function ManualInsertWithIgnore( $data )
  66 + {
  67 + // \common\components\CustomVarDamp::dumpAndDie($data);
  68 + $table_name = self::tableName();
  69 + $keys_arr = array_keys($data[0]);
  70 +
  71 + // запросы будем выполнять пакетами
  72 + // размер пакета установлен в константе
  73 + // разобъем массив на пакеты и будем их проходить
  74 + $data = array_chunk($data, $this::BATCH);
  75 + foreach ($data as $current_batch_array) {
  76 +
  77 + //воспользуемся пакетной вставкой от фреймворка
  78 + $query = Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $current_batch_array)->sql;
  79 + // добавим ключевое слово - ignore
  80 + $query = preg_replace('/INSERT/','INSERT IGNORE', $query);
  81 + Yii::$app->db->createCommand($query)->execute();
  82 +
  83 + }
  84 + }
  85 +}
... ...
backend/models/Importers.php
... ... @@ -5,6 +5,7 @@ namespace backend\models;
5 5 use common\components\CustomVarDamp;
6 6 use Yii;
7 7 use backend\components\base\BaseActiveRecord;
  8 +use backend\models\Currency;
8 9  
9 10 /**
10 11 *
... ... @@ -89,6 +90,15 @@ class Importers extends BaseActiveRecord
89 90 ];
90 91 }
91 92  
  93 + public function getCurrency ()
  94 + {
  95 + return $this->hasOne(Currency::className(), ['id' => 'currency_id'])->one()->name;
  96 + }
  97 +
  98 + public function getCurrencyRate ()
  99 + {
  100 + return $this->hasOne(Currency::className(), ['id' => 'currency_id'])->one()->rate;
  101 + }
92 102  
93 103 public function getKeys ()
94 104 {
... ...
backend/models/UploadFileCrossingForm.php 0 → 100644
  1 +<?php
  2 +namespace backend\models;
  3 +
  4 +use yii\base\ErrorException;
  5 +use yii\base\Model;
  6 +use yii\web\UploadedFile;
  7 +use Yii;
  8 +use common\components\CustomVarDamp;
  9 +
  10 +/**
  11 + * UploadForm is the model behind the upload form.
  12 + */
  13 +class UploadFileCrossingForm extends Model
  14 +{
  15 + /**
  16 + * @var UploadedFile file attribute
  17 + */
  18 + // атрибуты формы
  19 + public $file;
  20 + public $delete_prefix1;
  21 + public $delete_prefix2;
  22 + public $file_path;
  23 +
  24 +
  25 +
  26 + public function rules()
  27 + {
  28 + return [
  29 + ['file', 'required', 'message' => 'Не выбран файл!' ],
  30 + [['file'], 'file', 'extensions' => 'csv', 'checkExtensionByMimeType'=>false ],
  31 + [['delete_prefix1', 'delete_prefix2'], 'boolean' ],
  32 +
  33 + ];
  34 + }
  35 +
  36 + public function attributeLabels()
  37 + {
  38 + return [
  39 + 'file' => Yii::t('app', 'Источник'),
  40 + 'delete_prefix1' => Yii::t('app', 'Удалять префикс в артикуле товара 1'),
  41 + 'delete_prefix2' => Yii::t('app', 'Удалять префикс в артикуле товара 2'),
  42 + ];
  43 + }
  44 +
  45 + public function readFile( $options = [] ){
  46 +
  47 + $data = Yii::$app->multiparser->parse( $this->file_path, $options );
  48 + if( !is_array( $data ) ){
  49 + throw new ErrorException("Ошибка чтения из файла кроссов {$this->file_path}");
  50 + }
  51 + // файл больше не нужен - данные прочитаны и сохранены в кеш
  52 + if( file_exists($this->file_path) )
  53 + unlink($this->file_path);
  54 +
  55 + return $data;
  56 + }
  57 +
  58 + public function fields()
  59 + {
  60 + return [
  61 +
  62 + 'delete_price1',
  63 + 'delete_price2'
  64 +
  65 + ];
  66 + }
  67 +
  68 +
  69 +}
0 70 \ No newline at end of file
... ...
backend/models/UploadFileParsingForm.php
1 1 <?php
2 2 namespace backend\models;
3 3  
  4 +use yii\base\ErrorException;
4 5 use yii\base\Model;
5 6 use yii\web\UploadedFile;
6 7 use Yii;
... ... @@ -47,9 +48,7 @@ class UploadFileParsingForm extends Model
47 48 return [
48 49 ['importer_id', 'required', 'message' => 'Не указан поставщик!' ],
49 50 ['file', 'required', 'message' => 'Не выбран файл!' ],
50   - //@todo - not working this file validator!!! - fixed
51   - [['file'], 'file'],// 'extensions' => ['csv', 'xml'] ],
52   - // 'wrongMimeType' => 'Указан неподдерживаемый тип файла. Можно выбирать csv, xml файлы.' ],
  51 + [['file'], 'file', 'extensions' => ['csv', 'xml'], 'checkExtensionByMimeType'=>false ],
53 52 ['importer_id', 'integer','max' => 999999, 'min' => 0 ],
54 53 [['action','delete_prefix', 'delete_price', 'success'], 'boolean', 'except' => 'auto' ], // только для ручной загрузки
55 54 ['delimiter', 'string', 'max' => 1],
... ... @@ -73,8 +72,11 @@ class UploadFileParsingForm extends Model
73 72  
74 73 $data = Yii::$app->multiparser->parse( $this->file_path, $options );
75 74 if( !is_array( $data ) ){
76   - $data = ['No results'];
  75 + throw new ErrorException("Ошибка чтения из файла прайса {$this->file_path}");
77 76 }
  77 + // файл больше не нужен - данные прочитаны и сохранены в кеш
  78 + if( file_exists($this->file_path) )
  79 + unlink($this->file_path);
78 80  
79 81 return $data;
80 82 }
... ...
backend/views/check-price/view.php
... ... @@ -8,24 +8,29 @@ use yii\bootstrap\Modal;
8 8 /* @var $this yii\web\View */
9 9 /* @var $searchModel backend\models\CatalogSearch */
10 10 /* @var $dataProvider yii\data\ActiveDataProvider */
11   -$this->title = 'Прайс ' . Html::encode( "{$importer} от {$date}" );
  11 +$this->title = 'Прайс ' . Html::encode("{$importer->name} от {$date}");
12 12 $this->params['breadcrumbs'][] = $this->title;
13 13  
14 14 ?>
15   -<div class="catalog-index">
16   -
17   - <h1><?= Html::encode($this->title) ?></h1>
18   -
19   - <?= GridView::widget( ['dataProvider' => $dataProvider,
20   -
21   - ] );
22   -
23   -
24   - ?>
25   -
26   -
27   -
28   -</div>
  15 + <div class="catalog-index">
  16 +
  17 + <h1><?= Html::encode($this->title) ?></h1>
  18 +
  19 + <?= GridView::widget( ['dataProvider' => $dataProvider,
  20 + 'columns' => [
  21 + ['attribute' => 'FULL_ARTICLE'],
  22 + ['attribute' => 'ARTICLE'],
  23 + ['attribute' => 'BRAND'],
  24 + ['attribute' => 'DESCR'],
  25 + ['attribute' => 'BOX'],
  26 + ['attribute' => 'ADD_BOX'],
  27 + ['attribute' => 'GROUP'],
  28 + ['attribute' => 'name'],
  29 + ['attribute' => 'PRICE'],
  30 + ]
  31 + ] ); ?>
  32 +
  33 + </div>
29 34 <?php
30 35  
31 36 ?>
32 37 \ No newline at end of file
... ...
backend/views/crossing-upload/index.php 0 → 100644
  1 +<?php
  2 +use yii\widgets\ActiveForm;
  3 +use yii\helpers\Html;
  4 +use yii\helpers\ArrayHelper;
  5 +
  6 +?>
  7 +<div class="row">
  8 + <div class="col-lg-5">
  9 + <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['crossing-upload/result']]);
  10 +
  11 + if ($msg = \Yii::$app->session->getFlash('success')) { // вернулись после успешной загрузки данного файла
  12 + echo Html::tag('h3', $msg ,['class'=>'bg-success']);
  13 + }
  14 + ?>
  15 + <h3>Кросс файлы</h3>
  16 +
  17 + <?= $form->field($model, 'delete_prefix1')->checkbox() ?>
  18 + <?= $form->field($model, 'delete_prefix2')->checkbox() ?>
  19 + <?= $form->field($model, 'file')->fileInput()->label(false) ?>
  20 +
  21 + <div class="form-group">
  22 + <?= Html::submitButton(Yii::t( 'app', 'Выполнить' ), ['class' => 'btn btn-primary']) ?>
  23 + </div>
  24 +
  25 + <?php ActiveForm::end() ?>
  26 + </div>
  27 +</div>
  28 +
... ...
backend/views/layouts/column.php
... ... @@ -283,6 +283,7 @@ $this-&gt;beginContent(&#39;@app/views/layouts/main.php&#39;);
283 283 'options' => ['class' => 'sidebar-menu'],
284 284 'items' => [
285 285 ['label' => "Загрузка файлов", 'url' => ['#'], 'items' => [
  286 + ['label' => 'Кросс-файлы', 'url' => ['crossing-upload/index']],
286 287 ['label' => 'Файлы на сервере', 'url' => ['parser/server-files']],
287 288 ['label' => 'Загрузить файл на сервер', 'url' => ['parser/index', 'mode' => 1]],
288 289 ['label' => 'Ручная загрузка', 'url' => ['parser/index']],
... ...
common/components/PriceWriter.php
... ... @@ -14,22 +14,45 @@ use backend\models\ImportersFiles;
14 14 use backend\models\Importers;
15 15 use backend\models\Details;
16 16  
17   -class PriceWriter {
  17 +/**
  18 + * Class PriceWriter
  19 + * @package common\components
  20 + * записывает в БД отпарсенные данные
  21 + * запись происходит в несколько таблиц
  22 + */
  23 +class PriceWriter
  24 +{
  25 + /**
  26 + * @var - int - 0 - интерактивный режим, 1 - консольный
  27 + */
18 28 public $mode;
  29 +
  30 + /**
  31 + * @var - массив с настройками записи
  32 + */
19 33 public $configuration;
  34 +
  35 + /**
  36 + * @var - массив с данными которые нужно записать
  37 + */
20 38 public $data;
21 39  
22   - public function writeDataToDB ()
  40 + function __construct()
  41 + {
  42 + set_time_limit(300);
  43 + }
  44 +
  45 + public function writeDataToDB()
23 46 {
24 47 // 1. запишем дату старта в таблицу файлов поставщика (ImportersFiles)
25 48 // id загруженного файла получим из конфигурации
26   - $files_model = ImportersFiles::findOne( $this->configuration['record_id'] );
  49 + $files_model = ImportersFiles::findOne($this->configuration['record_id']);
27 50  
28 51 $update_date = date('Y-m-d H:i:s');
29 52 $files_model->time_start = $update_date;
30 53 // запишем дату начала загрузки
31 54 if (!$files_model->save()) {
32   - throw new \ErrorException(implode( ', ', $files_model->getErrors()));
  55 + throw new \ErrorException(implode(', ', $files_model->getErrors()));
33 56 }
34 57  
35 58 // 2. запишем полученные данные в таблицу товаров (Details)
... ... @@ -42,8 +65,16 @@ class PriceWriter {
42 65 $row['PRICE'] = \Yii::$app->multiparser->convertToFloat($row['PRICE']);
43 66 $row['BOX'] = \Yii::$app->multiparser->convertToInteger($row['BOX']);
44 67 // присвоим полный артикул
  68 +
45 69 $row['FULL_ARTICLE'] = $row['ARTICLE'];
46   - if(isset($row['ADD_BOX']))
  70 + if ((int)$this->configuration['delete_prefix']) {
  71 + $row = \Yii::$app->multiparser->convertToArticle( $row, $this->configuration['importer_id'] );
  72 + } else {
  73 + $row['ARTICLE'] = \Yii::$app->multiparser->convertToArticle( $row['ARTICLE'] );
  74 + }
  75 +
  76 +
  77 + if (isset($row['ADD_BOX']))
47 78 $row['ADD_BOX'] = \Yii::$app->multiparser->convertToInteger($row['ADD_BOX']);
48 79  
49 80 // проверим все ли обязательные колонки были указаны пользователем
... ... @@ -55,31 +86,32 @@ class PriceWriter {
55 86 }
56 87 }
57 88  
58   - // дополним данные значением импортера и даты обновления цены
59   - $this->data = \Yii::$app->multiparser->addColumns($this->data, ['IMPORT_ID' => $this->configuration['importer_id'], 'timestamp' => $update_date]);
60   -
61   - try {
62   - //@todo add transaction
63   - // попытаемся вставить данные в БД с апдейтом по ключам
64   - $details_model->ManualInsert($this->data);
  89 + // дополним данные значением импортера и даты обновления цены
  90 + $this->data = \Yii::$app->multiparser->addColumns($this->data, ['IMPORT_ID' => $this->configuration['importer_id'], 'timestamp' => $update_date]);
  91 + try {
  92 + //@todo add transaction
65 93  
66   - // 3. зафиксируем дату конца загрузки в файлах поставщика
  94 + if ((int)$this->configuration['delete_price']) {
  95 + $details_model->delete_price = true;
  96 + }
  97 + //2. попытаемся вставить данные в БД с апдейтом по ключам
  98 + $details_model->ManualInsert($this->data, $this->configuration['importer_id']);
67 99  
68   - if (!$files_model->save()) {
69   - throw new \ErrorException(implode( ', ', $files_model->getErrors()));
70   - }
  100 + // 3. зафиксируем дату конца загрузки в файлах поставщика
  101 + if (!$files_model->save()) {
  102 + throw new \ErrorException(implode(', ', $files_model->getErrors()));
  103 + }
71 104  
72   - // 4. зафиксируем дату загрузки в таблице поставщиков
73   - $imp_model = Importers::findOne($this->configuration['importer_id']);
74   - $imp_model->price_date_update = $update_date;
  105 + // 4. зафиксируем дату загрузки в таблице поставщиков
  106 + $imp_model = Importers::findOne($this->configuration['importer_id']);
  107 + $imp_model->price_date_update = $update_date;
75 108  
76   - if (!$imp_model->save()) {
77   - throw new \ErrorException(implode( ', ', $imp_model->getErrors()));
78   - }
79   - } catch (ErrorException $e) {
80   - throw new \ErrorException( $e->getMessage() );
  109 + if (!$imp_model->save()) {
  110 + throw new \ErrorException(implode(', ', $imp_model->getErrors()));
81 111 }
82   -
  112 + } catch (ErrorException $e) {
  113 + throw new \ErrorException($e->getMessage());
  114 + }
83 115  
84 116  
85 117 return true;
... ...
common/components/parsers/CustomConverter.php
1 1 <?php
2 2 namespace common\components\parsers;
  3 +
3 4 use common\components\CustomVarDamp;
4 5 use yii\multiparser\Converter;
5 6 use backend\models\Details;
  7 +use backend\models\DetailsCrosses;
  8 +use backend\models\ImportersPrefix;
6 9  
7   -class CustomConverter extends Converter {
  10 +class CustomConverter extends Converter
  11 +{
8 12  
9 13 /**
10 14 * @param $value_arr - двумерный массив значений, которому нужно присвоить ключи
... ... @@ -13,38 +17,44 @@ class CustomConverter extends Converter {
13 17 */
14 18 public static $sign;
15 19 public static $multiplier;
  20 + public static $importer_id;
  21 + public static $brand;
16 22  
17   - public static function convertToAssocArray ( array $value_arr, array $key_array, $key_prefix = '' )
  23 + public static function convertToAssocArray(array $value_arr, array $key_array, $key_prefix = '')
18 24 {
19 25 // очистка служебного префикса в массиве заголовков
20 26 if ($key_prefix) {
21 27 // @todo оптимизировать - два переворота массива - избыточно
22   - $key_array = array_flip( $key_array );
  28 + $key_array = array_flip($key_array);
23 29  
24   - array_walk( $key_array, function ( &$value, $key, $key_prefix ){ $value = str_replace( $key_prefix, '',$value ); }, $key_prefix );
  30 + array_walk($key_array, function (&$value, $key, $key_prefix) {
  31 + $value = str_replace($key_prefix, '', $value);
  32 + }, $key_prefix);
25 33  
26   - $key_array = array_flip( $key_array );
  34 + $key_array = array_flip($key_array);
27 35 //уберем пустые элементы
28   - $key_array = array_filter($key_array, function ($value){ return $value !==''; });
  36 + $key_array = array_filter($key_array, function ($value) {
  37 + return $value !== '';
  38 + });
29 39 }
30 40  
31   - array_walk( $value_arr,
32   - function ( &$value, $key, $key_array ) {
  41 + array_walk($value_arr,
  42 + function (&$value, $key, $key_array) {
33 43 $res = $value;
34 44 foreach ($res as $sub_key => $sub_value) {
35 45 if (isset($key_array[$sub_key])) {
36 46 // если такой ключ в базовом массиве (массиве ключей) есть, то заменим новым, иначе просто удалим
37 47 $new_key = $key_array[$sub_key];
38   - if( !array_key_exists( $new_key , $res ) ){
39   - $res[ $new_key ] = $value[$sub_key];
  48 + if (!array_key_exists($new_key, $res)) {
  49 + $res[$new_key] = $value[$sub_key];
40 50 }
41 51 }
42   - unset( $res[$sub_key] );
  52 + unset($res[$sub_key]);
43 53 $value = $res;
44 54 }
45 55  
46 56 },
47   - $key_array);
  57 + $key_array);
48 58  
49 59 return $value_arr;
50 60 }
... ... @@ -54,7 +64,7 @@ class CustomConverter extends Converter {
54 64 * @param $add_array - массив с колонками (ключи) и значениями колонок
55 65 * @return mixed
56 66 */
57   - public function addColumns ( array $value_arr , array $add_array )
  67 + public function addColumns(array $value_arr, array $add_array)
58 68 {
59 69 $i = 0;
60 70 while ($i < count($value_arr)) {
... ... @@ -66,7 +76,7 @@ class CustomConverter extends Converter {
66 76 return $value_arr;
67 77 }
68 78  
69   - public static function convertToDetails ( array $row )
  79 + public static function convertToDetails(array $row)
70 80 {
71 81 // присвоим полный артикул
72 82 $row['FULL_ARTICLE'] = $row['ARTICLE'];
... ... @@ -75,19 +85,35 @@ class CustomConverter extends Converter {
75 85 // проверим все ли обязательные колонки были указаны пользователем
76 86 $details_model->load(['Details' => $row]);
77 87  
78   - if (!$details_model->validate()){
  88 + if (!$details_model->validate()) {
79 89 $errors = '';
80   - foreach ( $details_model->errors as $key => $arr_errors ) {
81   - $errors .= "Аттрибут $key - " . implode( ' , ', $arr_errors );
  90 + foreach ($details_model->errors as $key => $arr_errors) {
  91 + $errors .= "Аттрибут $key - " . implode(' , ', $arr_errors);
82 92 }
83   - throw new \ErrorException( $errors );
  93 + throw new \ErrorException($errors);
84 94 }
85 95 return $row;
86 96 }
87 97  
88   - public function ConvertToMultiply ( array $row )
  98 + public static function convertToCrosses( array $row )
  99 + {
  100 +
  101 + $details_model = new DetailsCrosses();
  102 + // проверим все ли обязательные колонки были указаны пользователем
  103 + $details_model->load(['DetailsCrosses' => $row]);
  104 +
  105 + if (!$details_model->validate()) {
  106 + $errors = '';
  107 + foreach ($details_model->errors as $key => $arr_errors) {
  108 + $errors .= "Аттрибут $key - " . implode(' , ', $arr_errors);
  109 + }
  110 + throw new \ErrorException($errors);
  111 + }
  112 + return $row;
  113 + }
  114 + public function ConvertToMultiply(array $row)
89 115 {
90   - $PRICE = $row[ 'PRICE' ];
  116 + $PRICE = $row['PRICE'];
91 117 $sign = self::$sign;
92 118 $multiplier = self::$multiplier;
93 119 //CustomVarDamp::dumpAndDie(self);
... ... @@ -96,29 +122,87 @@ class CustomConverter extends Converter {
96 122 if ($multiplier > 0) {
97 123 $PRICE += $multiplier;
98 124 }
99   - }
100   - else if ($sign == '-') {
  125 + } else if ($sign == '-') {
101 126 if ($multiplier > 0) {
102 127 $PRICE -= $multiplier;
103 128 }
104   - }
105   - else if ($sign == '*') {
  129 + } else if ($sign == '*') {
106 130 if ($multiplier > 0) {
107 131 $PRICE *= $multiplier;
108 132 }
109   - }
110   - else if ($sign == '/') {
  133 + } else if ($sign == '/') {
111 134 if ($multiplier > 0) {
112 135 $PRICE /= $multiplier;
113 136 }
114 137 }
115 138 }
116 139  
117   - $row[ 'PRICE' ] = $PRICE;
  140 + $row['PRICE'] = $PRICE;
118 141  
119 142 return $row;
120 143  
121 144 }
122 145  
  146 + public static function convertToArticle( $value, $importer_id = '' )
  147 + {
  148 + if(isset( $importer_id )){
  149 + self::$importer_id = $importer_id;
  150 + }
  151 +
  152 + if (is_array($value)) {
  153 +
  154 + $row = $value;
  155 + // 1. Уберем префикс который разделен пробелом (если он есть)
  156 + $words = explode(" ", $row['ARTICLE']);
  157 + if (count($words) > 1) {
  158 + array_shift($words);
  159 + $row['ARTICLE'] = implode(" ", $words);
  160 + }
  161 +
  162 + if( isset( $row['BRAND'] ) && isset( self::$importer_id ) ){
  163 + // 2. Уберем брендовый префикс (если он есть)
  164 + self::$brand = $row['BRAND'];
  165 + $prefix = '';
  166 + // запрос закешируем
  167 + $prefix = ImportersPrefix::getDb()->cache( function ($db) {
  168 + return ImportersPrefix::find()->where([ 'importer_id' => self::$importer_id,
  169 + 'brand' => self::$brand ])->one();
  170 + });
  171 +
  172 + if ($prefix) {
  173 + $row['BRAND'] = str_replace($prefix, "", $row['BRAND']);
  174 + }
  175 + }
  176 +
  177 + return $row;
  178 +
  179 + } else {
  180 + $words = explode( " ", $value );
  181 + if ( count( $words ) > 1) {
  182 + array_shift( $words );
  183 + $value = implode( " ", $words );
  184 + }
  185 +
  186 + return $value;
  187 + }
  188 + }
  189 +
  190 + public static function convertToBrand($value)
  191 + {
  192 + $res = parent::convertToEncode($value);;
  193 + $res = trim(strtoupper($res));
  194 + $res = str_replace("Ä", "A", str_replace("Ö", "O", str_replace("Ü", "U", str_replace("Ë", "E", str_replace("Ò", "O", $res)))));
  195 + $res = str_replace(array('@', '#', '~', '"', "'", "?", "!"), '', $res);
  196 +
  197 + return $res;
  198 + }
  199 +
  200 + public static function convertToString($value)
  201 + {
  202 + $value = parent::convertToEncode($value);
  203 +
  204 + return str_replace(array('!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '~', '`', '"', "'", ' ', '№', '%', ';', ':', '[', ']', '{', '}', '*', '?', '/', '\'', '|', '.', ',', '<', '>', '\\'), '', $value);
  205 + }
  206 +
123 207  
124 208 }
125 209 \ No newline at end of file
... ...
common/components/parsers/CustomCsvParser.php
... ... @@ -16,7 +16,7 @@ use yii\base\ErrorException;
16 16  
17 17 class CustomCsvParser extends \yii\multiparser\CsvParser {
18 18  
19   - public $last_line = 10;
  19 + public $last_line = 100;
20 20 //public $hasHeaderRow = true;
21 21 // public $keys = ['first','second', 'third', 'forth', 'fifth'];
22 22 public function setupConverter()
... ...
common/components/parsers/config.php
... ... @@ -5,8 +5,8 @@
5 5 ['class' => 'common\components\parsers\CustomCsvParser',
6 6 'auto_detect_first_line' => true,
7 7 'converter_conf' => [
8   - //'class' => ' common\components\parsers\CustomConverter', // @todo переделать на подключаемый behavior
9   - 'configuration' => ["string" => 'DESCR'],]
  8 + //'class' => ' common\components\parsers\CustomConverter', // @todo переделать на компонент
  9 + 'configuration' => ["encode" => 'DESCR'],]
10 10 ],
11 11 'console' =>
12 12 ['class' => 'common\components\parsers\CustomCsvParser',
... ... @@ -17,10 +17,11 @@
17 17 'hasKey' => 1,
18 18 'configuration' => ["string" => 'DESCR',
19 19 "float" => 'PRICE',
  20 + "brand" => 'BRAND',
20 21 "integer" => ['BOX','ADD_BOX'],
21 22 "multiply" => [],
22   - "details" => [] // @todo сделать отдельно конфигурирование валидации
23   -
  23 + "article" => [],
  24 + "details" => []
24 25 ]
25 26 ],],
26 27  
... ... @@ -34,6 +35,20 @@
34 35 "ADD_BOX"=> 'В пути',
35 36 "GROUP" => 'Группа RG'
36 37 ],
  38 +
  39 + 'crosses' => ['class' => 'common\components\parsers\CustomCsvParser',
  40 + 'auto_detect_first_line' => true,
  41 + 'min_column_quantity' => 4,
  42 + 'hasHeaderRow' => true,
  43 + 'keys' =>['ARTICLE', 'CROSS_ARTICLE', 'BRAND', 'CROSS_BRAND'],
  44 + 'converter_conf' => [
  45 + //'class' => ' common\components\parsers\CustomConverter',
  46 + 'hasKey' => 1,
  47 + 'configuration' => [
  48 + "brand" => ['BRAND', 'CROSS_BRAND'],
  49 + "crosses" => [],
  50 + ]
  51 + ],],
37 52 ],
38 53 'xml' =>
39 54 ['console' =>
... ...
common/config/main-local.php
... ... @@ -2,7 +2,6 @@
2 2 return [
3 3 'components' => [
4 4 'db' => [
5   - //'class' => 'yii\db\Connection',
6 5 'class' => 'backend\components\base\CustomDbConnection',
7 6 'dsn' => 'mysql:host=195.248.225.150;dbname=italautocomua',
8 7 'username' => 'italautocomua',
... ... @@ -10,6 +9,14 @@ return [
10 9 'charset' => 'utf8',
11 10 'tablePrefix' => 'w_',
12 11 ],
  12 + 'full_privileges_db' => [
  13 + 'class' => 'backend\components\base\CustomDbConnection',
  14 + 'dsn' => 'mysql:host=195.248.225.150;dbname=italautocomua',
  15 + 'username' => 'percona',
  16 + 'password' => 'PpvSuMGEnLr4UKnVGUZPRa5wPCHF98Jf',
  17 + 'charset' => 'utf8',
  18 + 'tablePrefix' => 'w_',
  19 + ],
13 20 'mailer' => [
14 21 'class' => 'yii\swiftmailer\Mailer',
15 22 'viewPath' => '@common/mail',
... ...
common/models/DetailsCurrency.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\models;
  4 +
  5 +use Yii;
  6 +
  7 +/**
  8 + * This is the model class for table "{{%details_currency}}".
  9 + *
  10 + * @property string $ID
  11 + * @property string $IMPORT_ID
  12 + * @property string $BRAND
  13 + * @property string $ARTICLE
  14 + * @property string $FULL_ARTICLE
  15 + * @property double $PRICE
  16 + * @property string $DESCR
  17 + * @property string $BOX
  18 + * @property string $ADD_BOX
  19 + * @property string $GROUP
  20 + * @property string $timestamp
  21 + * @property string $name
  22 + * @property double $rate
  23 + */
  24 +class DetailsCurrency extends \backend\components\base\BaseActiveRecord
  25 +{
  26 + /**
  27 + * @inheritdoc
  28 + */
  29 + public static function tableName()
  30 + {
  31 + return '{{%details_currency}}';
  32 + }
  33 +
  34 + /**
  35 + * @inheritdoc
  36 + */
  37 + public function rules()
  38 + {
  39 + return [
  40 + [['ID', 'IMPORT_ID', 'BOX', 'ADD_BOX'], 'integer'],
  41 + [['IMPORT_ID', 'BRAND', 'ARTICLE', 'FULL_ARTICLE', 'PRICE', 'DESCR', 'BOX', 'name', 'rate'], 'required'],
  42 + [['PRICE', 'rate'], 'number'],
  43 + [['timestamp'], 'safe'],
  44 + [['BRAND', 'ARTICLE'], 'string', 'max' => 100],
  45 + [['FULL_ARTICLE'], 'string', 'max' => 150],
  46 + [['DESCR', 'GROUP'], 'string', 'max' => 200],
  47 + [['name'], 'string', 'max' => 50]
  48 + ];
  49 + }
  50 +
  51 + /**
  52 + * @inheritdoc
  53 + */
  54 + public function attributeLabels()
  55 + {
  56 + return [
  57 + 'ID' => Yii::t('app', 'ID'),
  58 + 'IMPORT_ID' => Yii::t('app', 'Import ID'),
  59 + 'BRAND' => Yii::t('app', 'Бренд'),
  60 + 'ARTICLE' => Yii::t('app', 'Имя'),
  61 + 'FULL_ARTICLE' => Yii::t('app', 'Артикул'),
  62 + 'PRICE' => Yii::t('app', 'Цена'),
  63 + 'DESCR' => Yii::t('app', 'Описание'),
  64 + 'BOX' => Yii::t('app', 'Кол-во'),
  65 + 'ADD_BOX' => Yii::t('app', 'В пути'),
  66 + 'GROUP' => Yii::t('app', 'Группа RG'),
  67 + 'timestamp' => Yii::t('app', 'Дата обновления'),
  68 + 'name' => Yii::t('app', 'Валюта'),
  69 + 'rate' => Yii::t('app', 'Курс'),
  70 + ];
  71 + }
  72 +}
... ...
console/controllers/ParserController.php
... ... @@ -32,8 +32,7 @@ class ParserController extends Controller
32 32 'importer_id' => $importer_id,
33 33 'parser_config' => ['keys' => $keys,
34 34 'converter_conf' =>
35   - ['sign' => $sign,
36   - 'multiplier' => $multiplier],
  35 + [ 'sign' => $sign, 'multiplier' => $multiplier, 'importer_id' => $importer_id ],
37 36 'mode' => 'console']
38 37 ];
39 38 if ($this->parseFileConsole($file_path, $config)) {
... ...
console/migrations/m150925_111922_add_foreign_key_ImportFiles.php
... ... @@ -22,7 +22,7 @@ class m150925_111922_add_foreign_key_ImportFiles extends Migration
22 22 $this->addForeignKey('importer_fk', '{{%importers_files}}', 'importer_id', '{{%importers}}', 'id');
23 23 }
24 24  
25   - public function down()
  25 + public function safeDown()
26 26 {
27 27 $this->dropForeignKey('importer_fk', '{{%importers_files}}');
28 28 }
... ...
console/migrations/m151013_062829_deletePrefixFunction.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Schema;
  4 +use yii\db\Migration;
  5 +
  6 +/**
  7 + * Class m151013_062829_deletePrefixFunction
  8 + * добавляем две функции - одна ищет префикс по поставщику и бренду,
  9 + * другая удаляет найденный префикс из переданного артикула
  10 + */
  11 +class m151013_062829_deletePrefixFunction extends Migration
  12 +{
  13 +
  14 + public function safeUp()
  15 + {
  16 + $find_prefix = <<< MySQL
  17 + CREATE FUNCTION FindPrefix(p_importer_id int, p_brand VARCHAR(100)) RETURNS VARCHAR(50)
  18 + BEGIN
  19 + DECLARE _prefix varchar(10);
  20 +
  21 + select prefix into _prefix From w_importers_prefix where importer_id = p_importer_id and brand = p_brand COLLATE utf8_general_ci;
  22 +
  23 + RETURN (_prefix);
  24 + END
  25 +MySQL;
  26 +
  27 + $delete_prefix = <<< MySQL
  28 + CREATE FUNCTION DeletePrefix(p_articul VARCHAR(150), p_importer_id int, p_brand VARCHAR(100)) RETURNS VARCHAR(150)
  29 + BEGIN
  30 + DECLARE _articul varchar(10);
  31 +
  32 + select substring(p_articul, LENGTH( FindPrefix( p_importer_id, p_brand ) ) + 1 ) into _articul;
  33 + RETURN (_articul);
  34 + END
  35 +MySQL;
  36 +
  37 + $this->execute($find_prefix);
  38 + $this->execute($delete_prefix);
  39 +
  40 + }
  41 +
  42 + public function safedown()
  43 + {
  44 +
  45 + $find_prefix = <<< MySQL
  46 + drop FUNCTION FindPrefix;
  47 +MySQL;
  48 +
  49 + $delete_prefix = <<< MySQL
  50 + drop FUNCTION DeletePrefix;
  51 +MySQL;
  52 +
  53 + $this->execute($find_prefix);
  54 + $this->execute($delete_prefix);
  55 +
  56 +
  57 + }
  58 +
  59 +
  60 +}
... ...
console/migrations/m151016_080952_editDetailsCrossesTrigger.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +/**
  6 + * Class m151016_080952_editDetailsCrossesTrigger
  7 + * заменим существующий триггер на новый и переименуем его на более информативное имя
  8 + * с w_details_crosses на w_details_crosses_before_insert
  9 + * существующая функциональность сохраняется
  10 + * добавляется замена брендов и вставка новых брендов в таблицу w_brand
  11 + */
  12 +class m151016_080952_editDetailsCrossesTrigger extends Migration
  13 +{
  14 + public function init()
  15 + {
  16 + // используем специальное подключение с супер правами
  17 + $this->db = 'full_privileges_db';
  18 + parent::init();
  19 + }
  20 +
  21 + public function safeUp()
  22 + {
  23 + $drop_trigger = 'Drop trigger if exists w_details_crosses';
  24 +
  25 + $before_insert_trigger = <<< MySQL
  26 + CREATE DEFINER=`root`@`localhost` TRIGGER `w_details_crosses_before_insert` BEFORE INSERT ON `w_details_crosses`
  27 + FOR EACH ROW BEGIN
  28 + DECLARE vBrand varchar(150);
  29 + SET vBrand = '';
  30 +
  31 +
  32 + SELECT to_brand INTO vBrand from w_brands_replace where from_brand = NEW.BRAND;
  33 +
  34 + IF vBrand = '' or vBrand = NULL then
  35 + insert ignore into w_brands (BRAND) values(NEW.BRAND);
  36 + else
  37 + SET NEW.BRAND = vBrand;
  38 + end if;
  39 +
  40 + SET vBrand = '';
  41 +
  42 +
  43 + SELECT to_brand INTO vBrand from w_brands_replace where from_brand = NEW.CROSS_BRAND;
  44 +
  45 + IF vBrand = '' or vBrand = NULL then
  46 + insert ignore into w_brands (BRAND) values(NEW.CROSS_BRAND);
  47 + else
  48 + SET NEW.CROSS_BRAND = vBrand;
  49 + end if;
  50 +
  51 + insert ignore into `w_details_description`(`name`, `brand`)
  52 + values (NEW.`ARTICLE`,NEW.`BRAND`),(NEW.`CROSS_ARTICLE`,NEW.`CROSS_BRAND`);
  53 + END
  54 +MySQL;
  55 +
  56 + $this->execute($drop_trigger);
  57 + $this->execute($before_insert_trigger);
  58 +
  59 + }
  60 +
  61 + public function safedown()
  62 + {
  63 + // вернем все как было
  64 + $drop_trigger = 'Drop trigger if exists w_details_crosses_before_insert';
  65 +
  66 + $before_insert_trigger = <<< MySQL
  67 + CREATE DEFINER=`italautocomua`@`localhost` TRIGGER `w_details_crosses` BEFORE INSERT ON `w_details_crosses`
  68 + FOR EACH ROW BEGIN
  69 + insert ignore into `w_details_description`(`name`, `brand`)
  70 + values (NEW.`ARTICLE`,NEW.`BRAND`),(NEW.`CROSS_ARTICLE`,NEW.`CROSS_BRAND`);
  71 + END
  72 +MySQL;
  73 +
  74 + $this->execute($drop_trigger);
  75 + $this->execute($before_insert_trigger);
  76 +
  77 +
  78 + }
  79 +
  80 +}
... ...
console/migrations/m151016_090927_editDetailsTrigger.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +/**
  6 + * Class m151016_090927_editDetailsTrigger
  7 + * заменим существующий триггер на новый и переименуем его на более информативное имя
  8 + * с w_details на w_details_before_insert
  9 + * существующая функциональность сохраняется
  10 + * добавляется замена брендов и вставка новых брендов в таблицу w_brand,
  11 + * а также поиск и замена налогов товаров по таблице w_details_replace
  12 + */
  13 +class m151016_090927_editDetailsTrigger extends Migration
  14 +{
  15 + public function init()
  16 + {
  17 + // используем специальное подключение с супер правами
  18 + $this->db = 'full_privileges_db';
  19 + parent::init();
  20 + }
  21 +
  22 + public function safeUp()
  23 + {
  24 + $drop_trigger = 'Drop trigger if exists w_details';
  25 +
  26 + $before_insert_trigger = <<< MySQL
  27 + CREATE DEFINER=`root`@`localhost` TRIGGER `w_details_before_insert` BEFORE INSERT ON `w_details`
  28 + FOR EACH ROW BEGIN
  29 + DECLARE vBrand varchar(150);
  30 + DECLARE vArticle varchar(100);
  31 + SET vBrand = '';
  32 + SET vArticle = '';
  33 +
  34 + SELECT to_brand INTO vBrand from w_brands_replace where from_brand = NEW.BRAND;
  35 +
  36 + IF vBrand = '' or vBrand = NULL then
  37 + insert ignore into w_brands (BRAND) values(NEW.BRAND);
  38 + else
  39 + SET NEW.BRAND = vBrand;
  40 + end if;
  41 +
  42 + SET vBrand = '';
  43 +
  44 + SELECT to_name, to_brand INTO vArticle, vBrand from w_details_replace where from_name = NEW.ARTICLE AND from_brand = NEW.BRAND LIMIT 1;
  45 +
  46 + IF vArticle != '' then
  47 + SET NEW.BRAND = vBrand;
  48 + SET NEW.ARTICLE = vArticle;
  49 + end if;
  50 +
  51 + INSERT INTO `w_details_description`(`name`, `brand`, `supplier_description`, `article`)
  52 + values (NEW.`ARTICLE`,NEW.`BRAND`,NEW.`DESCR`,NEW.`FULL_ARTICLE`)
  53 + on duplicate key update `supplier_description` = if (`supplier_description` = '',values(`supplier_description`),`supplier_description`);
  54 + END
  55 +MySQL;
  56 +
  57 + $this->execute($drop_trigger);
  58 + $this->execute($before_insert_trigger);
  59 +
  60 + }
  61 +
  62 + public function safedown()
  63 + {
  64 + // вернем все как было
  65 + $drop_trigger = 'Drop trigger if exists w_details_before_insert';
  66 +
  67 + $before_insert_trigger = <<< MySQL
  68 + CREATE DEFINER=`italautocomua`@`localhost` TRIGGER `w_details` BEFORE INSERT ON `w_details`
  69 + FOR EACH ROW BEGIN
  70 + INSERT INTO `w_details_description`(`name`, `brand`, `supplier_description`, `article`)
  71 + values (NEW.`ARTICLE`,NEW.`BRAND`,NEW.`DESCR`,NEW.`FULL_ARTICLE`)
  72 + on duplicate key update `supplier_description` = if (`supplier_description` = '',values(`supplier_description`),`supplier_description`);
  73 + END
  74 +MySQL;
  75 +
  76 + $this->execute($drop_trigger);
  77 + $this->execute($before_insert_trigger);
  78 +
  79 + }
  80 +}
... ...
console/migrations/m151016_130143_add_fk_currency_to_Importers.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Schema;
  4 +use yii\db\Migration;
  5 +
  6 +class m151016_130143_add_fk_currency_to_Importers extends Migration
  7 +{
  8 + public function safeUp()
  9 + {
  10 + $this->addForeignKey('currency_fk', '{{%importers}}', 'currency_id', '{{%currency}}', 'id');
  11 + }
  12 +
  13 + public function safeDown()
  14 + {
  15 + $this->dropForeignKey('currency_fk', '{{%importers}}');
  16 + }
  17 +}
... ...
console/migrations/m151016_144435_addViewDetailsCurrency.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Schema;
  4 +use yii\db\Migration;
  5 +
  6 +class m151016_144435_addViewDetailsCurrency extends Migration
  7 +{
  8 + public function up()
  9 + {
  10 +
  11 + $view = <<< MySQL
  12 + create view w_details_currency as
  13 + select w_details.*, w_currency.name, w_currency.rate from w_details
  14 + inner join w_importers on w_importers.id = w_details.import_id
  15 + inner join w_currency on w_currency.id = w_importers.currency_id;
  16 +MySQL;
  17 +
  18 + $this->execute($view);
  19 +
  20 + }
  21 +
  22 + public function down()
  23 + {
  24 + // вернем все как было
  25 + $drop_view = 'drop view if exists w_details_currency';
  26 +
  27 + $this->execute($drop_view);
  28 +
  29 + }
  30 +}
... ...
test1.zip deleted
No preview for this file type
vendor/yiisoft/multiparser/Converter.php
... ... @@ -50,7 +50,7 @@ class Converter extends Behavior
50 50 return $value;
51 51 }
52 52  
53   - public static function convertToString($value)
  53 + public static function convertToEncode($value)
54 54 {
55 55 $res = $value;
56 56 if (is_array($value)) {
... ...
vendor/yiisoft/multiparser/CsvParser.php
... ... @@ -59,7 +59,6 @@ class CsvParser implements ParserInterface
59 59 */
60 60 public function setup()
61 61 {
62   -
63 62 $this->file->setCsvControl($this->delimiter);
64 63 $this->file->setFlags(\SplFileObject::READ_CSV);
65 64 $this->file->setFlags(\SplFileObject::SKIP_EMPTY);
... ... @@ -108,7 +107,6 @@ class CsvParser implements ParserInterface
108 107 }
109 108  
110 109 for ($i = 1; $i <= count($row); $i++) {
111   - // CustomVarDamp::dump($row[$i]);
112 110  
113 111 if ($row[$i - 1] <> '') {
114 112 $j++;
... ... @@ -179,11 +177,12 @@ class CsvParser implements ParserInterface
179 177 protected function readRow( )
180 178 {
181 179 $row = $this->file->fgetcsv();
182   - // уберем нулевые колонки
183   - $row = array_filter($row, function($val){
184   - return $val <> '';
185   - });
  180 +
186 181 if (is_array($row)) {
  182 + // уберем нулевые колонки
  183 + $row = array_filter($row, function($val){
  184 + return $val <> '';
  185 + });
187 186 // если есть заголовок, то перед конвертацией его нужно назначить
188 187 if ($this->hasHeaderRow && $this->keys !== NULL) {
189 188  
... ...
vendor/yiisoft/multiparser/DynamicFormHelper.php
... ... @@ -29,7 +29,7 @@ class DynamicFormHelper
29 29 * ключ - имя, значение - значение аттрибута
30 30 * если передано число, то создается переданное количество аттрибутов с именами - attr_0, attr_1...
31 31 */
32   - public static function CreateDynamicModel($source)
  32 + public static function CreateDynamicModel( $source )
33 33 {
34 34 $arr_keys = [];
35 35 if (is_array($source)) {
... ...