Commit a0be9a4da2410e806174335c09e86122777e7496

Authored by Karnovsky A
1 parent 9d539ac3

30062016

backend/views/layouts/main-sidebar.php
... ... @@ -34,6 +34,11 @@ use yii\widgets\Menu;
34 34 'options' => ['class'=>\Yii::$app->user->can('product') ? '' :'hide']
35 35 ],
36 36 [
  37 + 'label' => 'Модификации',
  38 + 'url' => ['/product/variant'],
  39 + 'options' => ['class'=>\Yii::$app->user->can('product') ? '' :'hide']
  40 + ],
  41 + [
37 42 'label' => 'Категории',
38 43 'url' => ['/category'],
39 44 'options' => ['class'=>\Yii::$app->user->can('category') ? '' :'hide'],
... ...
common/config/main.php
... ... @@ -207,6 +207,27 @@ return [
207 207 'model' => 'common\modules\product\models\ProductOption',
208 208 ]
209 209 ],
  210 + 'product_variant_option' => [
  211 + 'name' => Yii::t('product', 'Properties'),
  212 + 'field' => 'options',
  213 + 'entity1' => [
  214 + 'model' => '\common\modules\product\models\ProductVariant',
  215 + 'label' => 'Variant',
  216 + 'listField' => 'fullname',
  217 + 'key' => 'product_variant_id',
  218 + 'linked_key' => 'product_variant_id',
  219 + ],
  220 + 'entity2' => [
  221 + 'model' => '\common\modules\rubrication\models\TaxOption',
  222 + 'label' => 'Option',
  223 + 'listField' => 'ValueRenderFlash',
  224 + 'key' => 'tax_option_id',
  225 + 'linked_key' => 'option_id',
  226 + ],
  227 + 'via' => [
  228 + 'model' => 'common\modules\product\models\ProductVariantOption',
  229 + ]
  230 + ],
210 231 'tax_group_to_category' => [
211 232 'name' => Yii::t('product', 'Характеристики по категориям'),
212 233 'field' => 'group_to_category',
... ...
common/modules/product/controllers/ManageController.php
... ... @@ -117,16 +117,6 @@ class ManageController extends Controller
117 117 $model = $this->findModel($id);
118 118 if ($model->load(Yii::$app->request->post())) {
119 119 $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
120   - $model->variantImagesUpload = UploadedFile::getInstances($model, 'variants');
121   - /*if (!empty($variantImagesUpload)) {
122   - var_dump($variantImagesUpload);exit;
123   - }*/
124   - /*$model->variantImagesUpload = [];
125   - foreach ($_POST['Product']['variants'] as $i => $variant) {
126   - if (!empty($variant['product_variant_id'])) {
127   - $model->variantImagesUpload[$variant['product_variant_id']] = $variantImagesUpload[$i];
128   - }
129   - }*/
130 120 if ($model->save()) {
131 121 // foreach ($model->images as $image) {
132 122 // $image->delete();
... ... @@ -140,19 +130,6 @@ class ManageController extends Controller
140 130 }
141 131 }
142 132  
143   - if ( ($images = $model->variantImagesUpload()) !== FALSE) {
144   - foreach ($images as $i => $image) {
145   - if (empty($model->_variants[$i])) {
146   - continue;
147   - }
148   - $imageModel = new ProductImage();
149   - $imageModel->product_id = $model->product_id;
150   - $imageModel->product_variant_id = intval($model->_variants[$i]['product_variant_id']);
151   - $imageModel->image = $image;
152   - $imageModel->save();
153   - }
154   - }
155   -
156 133 return $this->redirect(['view', 'id' => $model->product_id]);
157 134 }
158 135 } else {
... ...
common/modules/product/controllers/VariantController.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\controllers;
  4 +
  5 +use common\modules\product\models\Product;
  6 +use common\modules\product\models\ProductVariant;
  7 +use common\modules\product\models\ProductVariantSearch;
  8 +use Yii;
  9 +use yii\web\Controller;
  10 +use yii\web\NotFoundHttpException;
  11 +use yii\filters\VerbFilter;
  12 +use yii\web\UploadedFile;
  13 +
  14 +/**
  15 + * ManageController implements the CRUD actions for ProductVariant model.
  16 + */
  17 +class VariantController extends Controller
  18 +{
  19 + /**
  20 + * @inheritdoc
  21 + */
  22 + public function behaviors()
  23 + {
  24 + return [
  25 + 'verbs' => [
  26 + 'class' => VerbFilter::className(),
  27 + 'actions' => [
  28 + 'delete' => ['POST'],
  29 + ],
  30 + ],
  31 + ];
  32 + }
  33 +
  34 + /**
  35 + * Lists all ProductVariant models.
  36 + * @return mixed
  37 + */
  38 + public function actionIndex()
  39 + {
  40 + $searchModel = new ProductVariantSearch();
  41 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  42 +
  43 + if ( ($product = Yii::$app->request->get('product_id')) !== null) {
  44 + $product = Product::findOne($product);
  45 + }
  46 +
  47 + return $this->render('index', [
  48 + 'searchModel' => $searchModel,
  49 + 'dataProvider' => $dataProvider,
  50 + 'product' => $product,
  51 + ]);
  52 + }
  53 +
  54 + /**
  55 + * Displays a single ProductVariant model.
  56 + * @param integer $id
  57 + * @return mixed
  58 + */
  59 + public function actionView($id)
  60 + {
  61 + return $this->render('view', [
  62 + 'model' => $this->findModel($id),
  63 + ]);
  64 + }
  65 +
  66 + /**
  67 + * Creates a new ProductVariant model.
  68 + * If creation is successful, the browser will be redirected to the 'view' page.
  69 + * @return mixed
  70 + */
  71 + public function actionCreate()
  72 + {
  73 + $model = new ProductVariant();
  74 +
  75 + if ($model->load(Yii::$app->request->post())) {
  76 + $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
  77 +
  78 + if ($model->save() && $model->imagesUpload) {
  79 + if ( ($images = $model->imagesUpload()) !== FALSE) {
  80 + foreach ($images as $image) {
  81 + $imageModel = new ProductImage();
  82 + $imageModel->product_id = $model->product_id;
  83 + $imageModel->product_variant_id = $model->product_variant_id;
  84 + $imageModel->image = $image;
  85 + $imageModel->save();
  86 + }
  87 + }
  88 +
  89 + return $this->redirect(['view', 'id' => $model->product_variant_id]);
  90 + }
  91 + } else {
  92 + return $this->render('create', [
  93 + 'model' => $model,
  94 + ]);
  95 + }
  96 + }
  97 +
  98 + /**
  99 + * Updates an existing ProductVariant model.
  100 + * If update is successful, the browser will be redirected to the 'view' page.
  101 + * @param integer $id
  102 + * @return mixed
  103 + */
  104 + public function actionUpdate($id)
  105 + {
  106 + $model = $this->findModel($id);
  107 + if ($model->load(Yii::$app->request->post())) {
  108 + $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
  109 + if ($model->save()) {
  110 + if ( ($images = $model->imagesUpload()) !== FALSE) {
  111 + foreach ($images as $image) {
  112 + $imageModel = new ProductImage();
  113 + $imageModel->product_id = $model->product_id;
  114 + $imageModel->product_variant_id = $model->product_variant_id;
  115 + $imageModel->image = $image;
  116 + $imageModel->save();
  117 + }
  118 + }
  119 +
  120 + return $this->redirect(['view', 'id' => $model->product_variant_id]);
  121 + }
  122 + } else {
  123 + $groups = $model->category->getTaxGroups();
  124 +
  125 + return $this->render('update', [
  126 + 'model' => $model,
  127 + 'groups' => $groups,
  128 + ]);
  129 + }
  130 + }
  131 +
  132 + /**
  133 + * Deletes an existing ProductVariant model.
  134 + * If deletion is successful, the browser will be redirected to the 'index' page.
  135 + * @param integer $id
  136 + * @return mixed
  137 + */
  138 + public function actionDelete($id)
  139 + {
  140 + $this->findModel($id)->delete();
  141 +
  142 + return $this->redirect(['index']);
  143 + }
  144 +
  145 + public function actionDelimg($id)
  146 + {
  147 + $image = ProductImage::findOne($id);
  148 +
  149 + if ($image) {
  150 + $image->delete();
  151 + }
  152 +
  153 + print '1';
  154 + exit;
  155 + }
  156 +
  157 + /**
  158 + * Finds the ProductVariant model based on its primary key value.
  159 + * If the model is not found, a 404 HTTP exception will be thrown.
  160 + * @param integer $id
  161 + * @return ProductVariant the loaded model
  162 + * @throws NotFoundHttpException if the model cannot be found
  163 + */
  164 + protected function findModel($id)
  165 + {
  166 + if (($model = ProductVariant::findOne($id)) !== null) {
  167 + return $model;
  168 + } else {
  169 + throw new NotFoundHttpException('The requested page does not exist.');
  170 + }
  171 + }
  172 +}
... ...
common/modules/product/helpers/ProductHelper.php
... ... @@ -140,4 +140,63 @@ class ProductHelper extends Object {
140 140 }
141 141 return $products;
142 142 }
  143 +
  144 + public static function _setQueryParams(&$query, $params, $setPriceLimits = true) {
  145 + if (!empty($params['keywords'])) {
  146 + if (!is_array($params['keywords'])) {
  147 + $params['keywords'] = [$params['keywords']];
  148 + }
  149 + foreach ($params['keywords'] as $keyword) {
  150 + $query->orFilterWhere(['ilike', Product::tableName() .'.name', $keyword]);
  151 + $query->orFilterWhere(['ilike', BrandName::tableName() .'.value', $keyword]);
  152 + $query->orFilterWhere(['ilike', CategoryName::tableName() .'.value', $keyword]);
  153 + }
  154 + }
  155 + if (!empty($params['special'])) {
  156 + foreach($params['special'] as $key => $value) {
  157 + $query->orFilterWhere([Product::tableName() .'.'. $key => $value]);
  158 + }
  159 + }
  160 + if (!empty($params['brands'])) {
  161 + $query->andFilterWhere([Product::tableName() .'.brand_id' => $params['brands']]);
  162 + }
  163 + if (!empty($params['options'])) {
  164 + foreach ($params['options'] as $group => $options) {
  165 + foreach ($options as &$option) {
  166 + $option = "'$option'";
  167 + }
  168 + $query->andWhere(
  169 + Product::tableName() . '.product_id IN (SELECT product_id AS products FROM product_option INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id WHERE tax_group.alias LIKE \''. $group .'\' AND tax_option.alias IN (' . implode(',', $options) . '))'
  170 + );
  171 + }
  172 + }
  173 +
  174 + if ($setPriceLimits && !empty($params['prices'])) {
  175 + if ($params['prices']['min'] > 0) {
  176 + $query->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
  177 + }
  178 + if ($params['prices']['max'] > 0) {
  179 + $query->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
  180 + }
  181 + }
  182 + }
  183 +
  184 + public static function productCountQuery($category = null, $params, $excludeKeys = []) {
  185 + $p = [];
  186 + foreach ($params as $key => $param) {
  187 + if (in_array($key, $excludeKeys)) {
  188 + $p[$key] = $param;
  189 + }
  190 + }
  191 + /** @var ActiveQuery $query */
  192 + if (!empty($category)) {
  193 + $query = $category->getProducts();
  194 + } else {
  195 + $query = Product::find();
  196 + }
  197 + ProductHelper::_setQueryParams($query, $params);
  198 + $query->select(['COUNT(product.product_id)']);
  199 +
  200 + return $query;
  201 + }
143 202 }
144 203 \ No newline at end of file
... ...
common/modules/product/models/BrandSearch.php
... ... @@ -2,6 +2,8 @@
2 2  
3 3 namespace common\modules\product\models;
4 4  
  5 +use common\modules\product\helpers\ProductHelper;
  6 +use common\modules\rubrication\models\TaxOption;
5 7 use Yii;
6 8 use yii\base\Model;
7 9 use yii\data\ActiveDataProvider;
... ... @@ -89,14 +91,47 @@ class BrandSearch extends Brand
89 91 }
90 92  
91 93 public function getBrands($category = null, $params = []) {
  94 +// $queryCount = ProductHelper::productCountQuery($category, $params, ['brands']);
  95 +
  96 + /*if (!empty($params['prices'])) {
  97 + if ($params['prices']['min'] > 0) {
  98 + $queryCount->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
  99 + }
  100 + if ($params['prices']['max'] > 0) {
  101 + $queryCount->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
  102 + }
  103 + }*/
  104 +// if (!empty($params['options'])) {
  105 +// $queryCount->innerJoin(TaxOption::tableName(), TaxOption::tableName())
  106 +// }
  107 +
92 108 $query = Brand::find()
93 109 ->select([
94   - Brand::tableName() .'.*',
95   - 'COUNT('. ProductCategory::tableName() .'.product_id) AS _items_count'
  110 + Brand::tableName() .'.*'
96 111 ])
97 112 ->innerJoin(Product::tableName(), Product::tableName() .'.brand_id='. Brand::tableName() .'.brand_id')
98 113 ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. Product::tableName() .'.product_id')
99 114 ->with(['brandName']);
  115 +
  116 + if (!empty($params['options'])) {
  117 + $queryCount = ProductOption::find()
  118 + ->select(['COUNT(pr.product_id)'])
  119 + ->innerJoin('tax_option', 'tax_option.tax_option_id = product_option.option_id')
  120 + ->innerJoin('tax_group', 'tax_group.tax_group_id = tax_option.tax_group_id')
  121 + ->innerJoin('product AS pr', 'pr.product_id = product_option.product_id')
  122 + ->where('pr.brand_id = brand.brand_id');
  123 +// ->groupBy(['product.product_id']);
  124 + foreach ($params['options'] as $group => $options) {
  125 + $queryCount->andWhere([
  126 + 'tax_group.alias' => $group,
  127 + 'tax_option.alias' => $options
  128 + ]);
  129 + }
  130 + $query->addSelect(['_items_count' => $queryCount]);
  131 +// $query->addSelect("(SELECT COUNT(product_option.product_id) AS products FROM product_option INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id WHERE tax_group.alias LIKE '$group' AND tax_option.alias IN (" . implode(',', $options) . ")) AS _items_count");
  132 + }
  133 +
  134 +
100 135 $query->innerJoin('product_variant', 'product_variant.product_id = '. Product::tableName() .'.product_id');
101 136 $query->where(['!=', 'product_variant.stock', 0]);
102 137 $query->groupBy(Product::tableName() .'.product_id');
... ... @@ -106,20 +141,6 @@ class BrandSearch extends Brand
106 141 ]);
107 142 }
108 143 $query->groupBy(Brand::tableName() .'.brand_id');
109   - if (isset($params['options'])) {
110   - unset($params['options']);
111   - }
112   - if (!empty($params['prices'])) {
113   - if ($params['prices']['min'] > 0 || $params['prices']['max'] > 0) {
114   - $query->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id='. Product::tableName() .'.product_id');
115   - }
116   - if ($params['prices']['min'] > 0) {
117   - $query->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
118   - }
119   - if ($params['prices']['max'] > 0) {
120   - $query->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
121   - }
122   - }
123 144  
124 145 return $query;
125 146 }
... ...
common/modules/product/models/Product.php
... ... @@ -38,7 +38,7 @@ class Product extends \yii\db\ActiveRecord
38 38  
39 39 /** @var array $_images */
40 40 public $imagesUpload = [];
41   - public $variantImagesUpload = [];
  41 +
42 42 /**
43 43 * @inheritdoc
44 44 */
... ... @@ -318,27 +318,6 @@ class Product extends \yii\db\ActiveRecord
318 318 ProductVariant::deleteAll(['product_id' => $this->product_id]);
319 319 }
320 320  
321   - public function variantImagesUpload()
322   - {
323   - if ($this->validate()) {
324   - $images = [];
325   - foreach ($this->variantImagesUpload as $product_variant_id => $image) {
326   - $imageName = $image->baseName .'.'. $image->extension;
327   - $i = 0;
328   - while(file_exists(Yii::getAlias('@imagesDir/products/' . $imageName))) {
329   - $i++;
330   - $imageName = $image->baseName .'_'. $i .'.'. $image->extension;
331   - }
332   -
333   - $image->saveAs(Yii::getAlias('@imagesDir/products/' .$imageName));
334   - $images[$product_variant_id] = $imageName;
335   - }
336   - return $images;
337   - } else {
338   - return false;
339   - }
340   - }
341   -
342 321 public function imagesUpload()
343 322 {
344 323 if ($this->validate()) {
... ...
common/modules/product/models/ProductVariant.php
... ... @@ -2,6 +2,8 @@
2 2  
3 3 namespace common\modules\product\models;
4 4  
  5 +use common\modules\relation\relationBehavior;
  6 +use common\modules\rubrication\models\TaxOption;
5 7 use Yii;
6 8 use yii\helpers\ArrayHelper;
7 9  
... ... @@ -37,7 +39,23 @@ class ProductVariant extends \yii\db\ActiveRecord
37 39 public $stocks;
38 40  
39 41 /** @var array $_images */
40   -// public $imagesUpload = [];
  42 + public $imagesUpload = [];
  43 +
  44 + /**
  45 + * @inheritdoc
  46 + */
  47 + public function behaviors()
  48 + {
  49 + return [
  50 + [
  51 + 'class' => relationBehavior::className(),
  52 + 'relations' => [
  53 + 'product_variant_option' => 'entity1' // Product variant options
  54 + ]
  55 + ]
  56 + ];
  57 + }
  58 +
41 59 /**
42 60 * @inheritdoc
43 61 */
... ... @@ -57,6 +75,7 @@ class ProductVariant extends \yii\db\ActiveRecord
57 75 [['price', 'price_old', 'stock'], 'number'],
58 76 [['name', 'sku'], 'string', 'max' => 255],
59 77 [['remote_id'], 'string', 'max' => 20],
  78 + [['options', 'imagesUpload'], 'safe'],
60 79 // [['imagesUpload'], 'safe'],
61 80 // [['imagesUpload'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif', 'maxFiles' => 50],
62 81 [['product_unit_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductUnit::className(), 'targetAttribute' => ['product_unit_id' => 'product_unit_id']],
... ... @@ -144,6 +163,34 @@ class ProductVariant extends \yii\db\ActiveRecord
144 163 return empty($this->product) ? null : ($this->product->name . (empty($this->name) ? '' : ' '. $this->name));
145 164 }
146 165  
  166 + public function getImagesHTML() {
  167 + $op = [];
  168 + if ($this->images) {
  169 + foreach ($this->images as $image) {
  170 + $op[] = \common\components\artboximage\ArtboxImageHelper::getImage($image->imageUrl, 'admin_thumb');
  171 + }
  172 + }
  173 + return $op;
  174 + }
  175 +
  176 + public function getImagesConfig() {
  177 + $op = [];
  178 + if ($this->images) {
  179 + foreach ($this->images as $image) {
  180 + $op[] = [
  181 + 'caption' => $image->image,
  182 + 'width' => '120px',
  183 + 'url' => \yii\helpers\Url::to(['/product/manage/delimg', 'id' => $image->product_image_id]),
  184 + 'key' => $image->product_image_id,
  185 + 'extra' => [
  186 + 'id' => $image->product_image_id,
  187 + ],
  188 + ];
  189 + }
  190 + }
  191 + return $op;
  192 + }
  193 +
147 194 /**
148 195 * @return \yii\db\ActiveQuery
149 196 */
... ... @@ -152,6 +199,24 @@ class ProductVariant extends \yii\db\ActiveRecord
152 199 return $this->hasMany(ProductImage::className(), ['product_variant_id' => 'product_variant_id']);
153 200 }
154 201  
  202 + public function getOptions() {
  203 + return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])->viaTable('product_variant_option', ['product_variant_id' => 'product_variant_id']);
  204 + }
  205 +
  206 + public function getProperties() {
  207 + $groups = $options = [];
  208 + foreach ($this->options as $option) {
  209 + $options[$option->tax_group_id][] = $option;
  210 + }
  211 + foreach (TaxGroup::find()->where(['tax_group_id' => array_keys($options)])->all() as $group) {
  212 + if (!empty($options[$group->tax_group_id])) {
  213 + $group->_options = $options[$group->tax_group_id];
  214 + $groups[] = $group;
  215 + }
  216 + }
  217 + return $groups;
  218 + }
  219 +
155 220 /**
156 221 * @inheritdoc
157 222 * @return ProductVariantQuery the active query used by this AR class.
... ... @@ -169,6 +234,10 @@ class ProductVariant extends \yii\db\ActiveRecord
169 234 $this->stocks = (array) $stocks;
170 235 }
171 236  
  237 + public function getCategory() {
  238 + return $this->hasOne(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
  239 + }
  240 +
172 241 public function afterSave($insert, $changedAttributes)
173 242 {
174 243 if (!is_null($this->stocks)) {
... ... @@ -187,4 +256,25 @@ class ProductVariant extends \yii\db\ActiveRecord
187 256 ProductImage::deleteAll(['product_variant_id' => $this->product_variant_id]);
188 257 ProductStock::deleteAll(['product_variant_id' => $this->product_variant_id]);
189 258 }
  259 +
  260 + public function imagesUpload()
  261 + {
  262 + if ($this->validate()) {
  263 + $images = [];
  264 + foreach ($this->imagesUpload as $image) {
  265 + $imageName = $image->baseName .'.'. $image->extension;
  266 + $i = 0;
  267 + while(file_exists(Yii::getAlias('@imagesDir/products/' . $imageName))) {
  268 + $i++;
  269 + $imageName = $image->baseName .'_'. $i .'.'. $image->extension;
  270 + }
  271 +
  272 + $image->saveAs(Yii::getAlias('@imagesDir/products/' .$imageName));
  273 + $images[] = $imageName;
  274 + }
  275 + return $images;
  276 + } else {
  277 + return false;
  278 + }
  279 + }
190 280 }
... ...
common/modules/product/models/ProductVariantOption.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\models;
  4 +
  5 +use Yii;
  6 +
  7 +/**
  8 + * This is the model class for table "product_variant_option".
  9 + *
  10 + * @property integer $product_variant_id
  11 + * @property integer $option_id
  12 + *
  13 + * @property ProductVariant $productVariant
  14 + * @property TaxOption $option
  15 + */
  16 +class ProductVariantOption extends \yii\db\ActiveRecord
  17 +{
  18 + /**
  19 + * @inheritdoc
  20 + */
  21 + public static function tableName()
  22 + {
  23 + return 'product_variant_option';
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + */
  29 + public function rules()
  30 + {
  31 + return [
  32 + [['product_variant_id', 'option_id'], 'required'],
  33 + [['product_variant_id', 'option_id'], 'integer'],
  34 + [['product_variant_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductVariant::className(), 'targetAttribute' => ['product_variant_id' => 'product_variant_id']],
  35 + [['option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['option_id' => 'tax_option_id']],
  36 + ];
  37 + }
  38 +
  39 + /**
  40 + * @inheritdoc
  41 + */
  42 + public function attributeLabels()
  43 + {
  44 + return [
  45 + 'product_variant_id' => 'Product Variant ID',
  46 + 'option_id' => 'Option ID',
  47 + ];
  48 + }
  49 +
  50 + /**
  51 + * @return \yii\db\ActiveQuery
  52 + */
  53 + public function getProductVariant()
  54 + {
  55 + return $this->hasOne(ProductVariant::className(), ['product_variant_id' => 'product_variant_id']);
  56 + }
  57 +
  58 + /**
  59 + * @return \yii\db\ActiveQuery
  60 + */
  61 + public function getOption()
  62 + {
  63 + return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'option_id']);
  64 + }
  65 +}
... ...
common/modules/product/models/ProductVariantSearch.php
... ... @@ -24,7 +24,7 @@ class ProductVariantSearch extends ProductVariant
24 24 public function rules()
25 25 {
26 26 return [
27   - [['name', 'fullname', 'sku', 'price', 'price_old', 'stock', 'fullname', 'brand_name', 'category_name'], 'safe'],
  27 + [['name', 'fullname', 'sku', 'price', 'price_old', 'stock', 'brand_name', 'category_name'], 'safe'],
28 28 [['product_variant_id', 'product_id'], 'integer'],
29 29 [['is_top', 'is_new', 'akciya'], 'boolean'],
30 30 ];
... ... @@ -48,7 +48,7 @@ class ProductVariantSearch extends ProductVariant
48 48 */
49 49 public function search($params)
50 50 {
51   - $query = Product::find();
  51 + $query = ProductVariant::find();
52 52  
53 53 // add conditions that should always apply here
54 54  
... ... @@ -58,6 +58,10 @@ class ProductVariantSearch extends ProductVariant
58 58  
59 59 $this->load($params);
60 60  
  61 + if (!empty($params['product_id'])) {
  62 + $this->product_id = $params['product_id'];
  63 + }
  64 +
61 65 if (!$this->validate()) {
62 66 // uncomment the following line if you do not want to return any records when validation fails
63 67 // $query->where('0=1');
... ... @@ -66,7 +70,12 @@ class ProductVariantSearch extends ProductVariant
66 70  
67 71 $dataProvider->setSort([
68 72 'attributes' => [
69   - 'name',
  73 + 'name' => [
  74 + 'asc' => ['product_variant.name' => SORT_ASC],
  75 + 'desc' => ['product_variant.value' => SORT_DESC],
  76 + 'default' => SORT_DESC,
  77 + 'label' => 'Variant name',
  78 + ],
70 79 'brand_name' => [
71 80 'asc' => ['brand_name.value' => SORT_ASC],
72 81 'desc' => ['brand_name.value' => SORT_DESC],
... ... @@ -98,12 +107,12 @@ class ProductVariantSearch extends ProductVariant
98 107  
99 108 // grid filtering conditions
100 109 $query->andFilterWhere([
101   - 'product.product_id' => $this->product_id,
  110 + 'product_variant.product_id' => $this->product_id,
102 111 'product_variant_id' => $this->product_variant_id,
103 112 ]);
104 113  
105 114 if (!empty($this->fullname)) {
106   - $query->orFilterWhere(['like', 'name', $this->fullname]);
  115 + $query->orFilterWhere(['like', 'product_variant.name', $this->fullname]);
107 116 $query->orFilterWhere(['ilike', 'product.name', $this->fullname]);
108 117 }
109 118 $query->andFilterWhere(['ilike', 'product.brand_name.value', $this->brand_name]);
... ... @@ -111,7 +120,7 @@ class ProductVariantSearch extends ProductVariant
111 120 $query->andFilterWhere(['ilike', 'sku', $this->sku]);
112 121  
113 122 $query->groupBy(['product_variant_id']);
114   - $query->orderBy('product.product_id', 'DESC');
  123 + $query->orderBy('product_variant.product_id', 'ASC');
115 124  
116 125 return $dataProvider;
117 126 }
... ...
common/modules/product/views/manage/_form.php
... ... @@ -69,7 +69,7 @@ use kartik\select2\Select2;
69 69 ],
70 70 ]); ?>
71 71  
72   - <?= $form->field($model, 'variants')->widget(MultipleInput::className(), [
  72 + <?php /*= $form->field($model, 'variants')->widget(MultipleInput::className(), [
73 73 'columns' => [
74 74 [
75 75 'name' => 'product_variant_id',
... ... @@ -119,7 +119,7 @@ use kartik\select2\Select2;
119 119 ],
120 120 ],
121 121 ]);
122   - ?>
  122 + */ ?>
123 123  
124 124 <?php if(isset($groups)) :?>
125 125 <?php foreach($groups->all() as $group) :?>
... ...
common/modules/product/views/manage/index.php
... ... @@ -27,7 +27,6 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
27 27 'filterModel' => $searchModel,
28 28 'columns' => [
29 29 ['class' => 'yii\grid\SerialColumn'],
30   -// 'product_id',
31 30 'name',
32 31 [
33 32 'label' => Yii::t('product', 'Brand'),
... ... @@ -87,7 +86,7 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
87 86 ],
88 87 [
89 88 'class' => 'yii\grid\ActionColumn',
90   - 'template' => '{view} |{is_top} {is_new} {akciya} | {update} {delete}',
  89 + 'template' => '{items} {view} |{is_top} {is_new} {akciya} | {update} {delete}',
91 90 'buttons' => [
92 91 'is_top' => function ($url, $model) {
93 92 return Html::a('<span class="glyphicon glyphicon-star' . ($model->is_top ? '' : '-empty') . '"></span>', $url, [
... ... @@ -104,9 +103,18 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
104 103 'title' => Yii::t('product', ($model->akciya ? 'Set not is promotion' : 'Set is promotion')),
105 104 ]);
106 105 },
  106 + 'items' => function ($url, $model) {
  107 + return Html::a('<span class="glyphicon glyphicon-th-list"></span>', $url, [
  108 + 'title' => Yii::t('product', 'Variants'),
  109 + ]);
  110 + },
  111 +
107 112 ],
108 113 'urlCreator' => function ($action, $model, $key, $index) {
109 114 switch ($action) {
  115 + case 'items':
  116 + return \yii\helpers\Url::to(['/product/variant', 'product_id' => $model->product_id]);
  117 + break;
110 118 case 'is_top':
111 119 return \yii\helpers\Url::to(['manage/is_top', 'id' => $model->product_id]);
112 120 break;
... ...
common/modules/product/views/variant/_form.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +use yii\widgets\ActiveForm;
  5 +use yii\helpers\ArrayHelper;
  6 +use common\components\artboxtree\ArtboxTreeHelper;
  7 +use common\modules\product\helpers\ProductHelper;
  8 +use kartik\file\FileInput;
  9 +use unclead\widgets\MultipleInput;
  10 +use unclead\widgets\MultipleInputColumn;
  11 +use kartik\select2\Select2;
  12 +
  13 +/* @var $this yii\web\View */
  14 +/* @var $model common\modules\product\models\Product */
  15 +/* @var $form yii\widgets\ActiveForm */
  16 +?>
  17 +
  18 +<div class="product-form">
  19 +
  20 + <?php $form = ActiveForm::begin([
  21 + 'options' => ['enctype' => 'multipart/form-data']
  22 + ]); ?>
  23 +
  24 + <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
  25 +
  26 + <?= $form->field($model, 'product_id')->hiddenInput()->label(''); ?>
  27 +
  28 + <?= $form->field($model, 'sku')->textarea(); ?>
  29 + <?= $form->field($model, 'price')->textarea(); ?>
  30 + <?= $form->field($model, 'price_old')->textarea(); ?>
  31 +
  32 + <?= $form->field($model, 'imagesUpload[]')->widget(\kartik\file\FileInput::classname(), [
  33 + 'language' => 'ru',
  34 + 'options' => [
  35 + 'accept' => 'image/*',
  36 + 'multiple' => true,
  37 + ],
  38 + 'pluginOptions' => [
  39 + 'allowedFileExtensions' => ['jpg', 'gif', 'png'],
  40 + 'initialPreview' => !empty($model->imagesHTML) ? $model->imagesHTML : [],
  41 + 'initialPreviewConfig' => $model->imagesConfig,
  42 + 'overwriteInitial' => false,
  43 + 'showRemove' => false,
  44 + 'showUpload' => false,
  45 +// 'uploadUrl' => empty($model->product_id) ? null : \yii\helpers\Url::to(['/product/manage/uploadImage']),
  46 + 'uploadAsync' => !empty($model->product_id),
  47 + 'previewFileType' => 'image',
  48 + ],
  49 + ]); ?>
  50 +
  51 + <?php /*= $form->field($model, 'variants')->widget(MultipleInput::className(), [
  52 + 'columns' => [
  53 + [
  54 + 'name' => 'product_variant_id',
  55 + 'type' => MultipleInputColumn::TYPE_HIDDEN_INPUT,
  56 + ],
  57 + [
  58 + 'name' => 'name',
  59 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  60 + 'title' => Yii::t('product', 'Name'),
  61 + ],
  62 + [
  63 + 'name' => 'sku',
  64 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  65 + 'title' => Yii::t('product', 'SKU'),
  66 + ],
  67 + [
  68 + 'name' => 'price',
  69 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  70 + 'title' => Yii::t('product', 'Price'),
  71 + ],
  72 + [
  73 + 'name' => 'price_old',
  74 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  75 + 'title' => Yii::t('product', 'Old Price'),
  76 + ],
  77 + [
  78 + 'name' => 'product_unit_id',
  79 + 'type' => MultipleInputColumn::TYPE_DROPDOWN,
  80 + 'title' => Yii::t('product', 'Unit'),
  81 + 'items' => ArrayHelper::map(\common\modules\product\models\ProductUnit::find()->all(), 'product_unit_id', 'name'),
  82 + ],
  83 + [
  84 + 'name' => 'stock',
  85 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  86 + 'title' => Yii::t('product', 'Stock'),
  87 + 'options' => [
  88 + 'placeholder' => '∞'
  89 + ],
  90 + ],
  91 + [
  92 + 'name' => 'image',
  93 + 'type' => 'fileInput',
  94 + 'title' => Yii::t('product', 'Image'),
  95 + 'options' => [
  96 + 'multiple' => false
  97 + ],
  98 + ],
  99 + ],
  100 + ]);
  101 + */ ?>
  102 +
  103 + <?php if(isset($groups)) :?>
  104 + <?php foreach($groups->all() as $group) :?>
  105 + <?= $form->field($model, 'options')->checkboxList(
  106 + ArrayHelper::map($group->options, 'tax_option_id', 'ValueRenderFlash'),
  107 + [
  108 + 'multiple' => true,
  109 + 'unselect' => null,
  110 + ]
  111 + )->label($group->name);?>
  112 + <?php endforeach?>
  113 + <?php endif?>
  114 +
  115 + <div class="form-group">
  116 + <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
  117 + </div>
  118 +
  119 + <?php ActiveForm::end(); ?>
  120 +
  121 +</div>
... ...
common/modules/product/views/variant/_search.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +use yii\widgets\ActiveForm;
  5 +
  6 +/* @var $this yii\web\View */
  7 +/* @var $model common\modules\product\models\ProductSearch */
  8 +/* @var $form yii\widgets\ActiveForm */
  9 +?>
  10 +
  11 +<div class="product-search">
  12 +
  13 + <?php $form = ActiveForm::begin([
  14 + 'action' => ['index'],
  15 + 'method' => 'get',
  16 + ]); ?>
  17 +
  18 + <?= $form->field($model, 'name') ?>
  19 +
  20 + <?= $form->field($model, 'brand_id') ?>
  21 +
  22 + <?= $form->field($model, 'product_id') ?>
  23 +
  24 + <div class="form-group">
  25 + <?= Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
  26 + <?= Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
  27 + </div>
  28 +
  29 + <?php ActiveForm::end(); ?>
  30 +
  31 +</div>
... ...
common/modules/product/views/variant/create.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +
  5 +
  6 +/* @var $this yii\web\View */
  7 +/* @var $model common\modules\product\models\Product */
  8 +
  9 +$this->title = Yii::t('product', 'Create Product');
  10 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
  11 +$this->params['breadcrumbs'][] = $this->title;
  12 +?>
  13 +<div class="product-create">
  14 +
  15 + <h1><?= Html::encode($this->title) ?></h1>
  16 +
  17 + <?= $this->render('_form', [
  18 + 'model' => $model,
  19 + ]) ?>
  20 +
  21 +</div>
... ...
common/modules/product/views/variant/index.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +use yii\grid\GridView;
  5 +
  6 +/* @var $this yii\web\View */
  7 +/* @var $searchModel common\modules\product\models\ProductVariantSearch */
  8 +/* @var $dataProvider yii\data\ActiveDataProvider */
  9 +
  10 +$this->title = Yii::t('product', 'Variants');
  11 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['/product/manage']];
  12 +if (!empty($product)) {
  13 + $this->params['breadcrumbs'] = [
  14 + ['label' => Yii::t('product', 'Variants'), 'url' => ['/product/variant']],
  15 + $product->fullname
  16 + ];
  17 +} else {
  18 + $this->params['breadcrumbs'][] = $this->title;
  19 +}
  20 +?>
  21 +<div class="product-index">
  22 +
  23 + <h1><?= Html::encode($this->title) ?></h1>
  24 + <?php // echo $this->render('_search', ['model' => $searchModel]); ?>
  25 +
  26 + <p>
  27 + <?= Html::a(Yii::t('product', 'Create Variant'), ['create'], ['class' => 'btn btn-success']) ?>
  28 + </p>
  29 + <?= GridView::widget([
  30 + 'dataProvider' => $dataProvider,
  31 + 'filterModel' => $searchModel,
  32 + 'columns' => [
  33 + ['class' => 'yii\grid\SerialColumn'],
  34 +
  35 + [
  36 + 'attribute' => 'product_id',
  37 + 'value' => 'fullname',
  38 + 'label' => Yii::t('product', 'Name'),
  39 + 'filter' => \kartik\select2\Select2::widget([
  40 + 'model' => $searchModel,
  41 + 'attribute' => 'product_id',
  42 + 'data' => \yii\helpers\ArrayHelper::map(\common\modules\product\models\Product::find()->orderBy(['name' => 'ASC'])->all(), 'product_id', 'name'),
  43 + 'language' => 'ru',
  44 + 'options' => [
  45 + 'placeholder' => Yii::t('product', 'Select product'),
  46 + 'multiple' => false,
  47 + ],
  48 + 'pluginOptions' => [
  49 + 'allowClear' => true
  50 + ],
  51 + ]),
  52 + ],
  53 + 'sku',
  54 + 'price',
  55 + 'price_old',
  56 + 'stock',
  57 +
  58 + ['class' => 'yii\grid\ActionColumn'],
  59 + ],
  60 + ]); ?>
  61 +</div>
... ...
common/modules/product/views/variant/update.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +
  5 +/* @var $this yii\web\View */
  6 +/* @var $model common\modules\product\models\Product */
  7 +
  8 +$this->title = Yii::t('product', 'Update {modelClass}: ', [
  9 + 'modelClass' => 'Product',
  10 +]) . ' ' . $model->name;
  11 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
  12 +$this->params['breadcrumbs'][] = ['label' => $model->product->name, 'url' => ['view', 'id' => $model->product->product_id]];
  13 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Variants'), 'url' => ['/product/variant?product_id='. $model->product->product_id]];
  14 +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->product_variant_id]];
  15 +$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
  16 +?>
  17 +<div class="product-update">
  18 +
  19 + <h1><?= Html::encode($this->title) ?></h1>
  20 +
  21 + <?= $this->render('_form', [
  22 + 'model' => $model,
  23 + 'groups' => $groups,
  24 + ]) ?>
  25 +
  26 +</div>
... ...
common/modules/product/views/variant/view.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +use yii\widgets\DetailView;
  5 +
  6 +/* @var $this yii\web\View */
  7 +/* @var $model common\modules\product\models\Product */
  8 +
  9 +$this->title = $model->name;
  10 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
  11 +$this->params['breadcrumbs'][] = ['label' => $model->product->name, 'url' => ['view', 'id' => $model->product->product_id]];
  12 +$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Variants'), 'url' => ['/product/variant?product_id='. $model->product->product_id]];
  13 +$this->params['breadcrumbs'][] = $this->title;
  14 +?>
  15 +<div class="product-view">
  16 +
  17 + <h1><?= Html::encode($this->title) ?></h1>
  18 +
  19 + <p>
  20 + <?= Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->product_variant_id], ['class' => 'btn btn-primary']) ?>
  21 + <?= Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->product_variant_id], [
  22 + 'class' => 'btn btn-danger',
  23 + 'data' => [
  24 + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
  25 + 'method' => 'post',
  26 + ],
  27 + ]) ?>
  28 + </p>
  29 +
  30 + <?= DetailView::widget([
  31 + 'model' => $model,
  32 + 'attributes' => [
  33 + 'product_id',
  34 + 'name',
  35 + 'fullname',
  36 + 'brand.name',
  37 + 'category.name',
  38 + 'image.imageUrl:image'
  39 + ],
  40 + ]) ?>
  41 +
  42 +</div>
... ...
common/translation/ru/product.php
... ... @@ -24,6 +24,8 @@ return [
24 24 'Price Old' => 'Старая Цена',
25 25 'Products' => 'Товары',
26 26 'Product' => 'Товар',
  27 + 'Variants' => 'Модифицкации',
  28 + 'Variant' => 'Модифицкация',
27 29 'Create Product' => 'Создать Товар',
28 30 'Enable' => 'Доступно',
29 31 'Disable' => 'Отсутсвует',
... ...
frontend/models/ProductFrontendSearch.php
... ... @@ -2,6 +2,7 @@
2 2  
3 3 namespace frontend\models;
4 4  
  5 +use common\modules\product\helpers\ProductHelper;
5 6 use common\modules\product\models\Brand;
6 7 use common\modules\product\models\BrandName;
7 8 use common\modules\product\models\CategoryName;
... ... @@ -86,7 +87,7 @@ class ProductFrontendSearch extends Product {
86 87 return $dataProvider;
87 88 }
88 89  
89   - $this->_setParams($query, $params);
  90 + ProductHelper::_setQueryParams($query, $params);
90 91  
91 92 $query->andWhere(['!=', ProductVariant::tableName() .'.stock', 0]);
92 93  
... ... @@ -144,7 +145,7 @@ class ProductFrontendSearch extends Product {
144 145 }
145 146 $query->joinWith('variant');
146 147  
147   - $this->_setParams($query, $params, false);
  148 + ProductHelper::_setQueryParams($query, $params, false);
148 149  
149 150 // $query->select([
150 151 // 'MIN('. ProductVariant::tableName() .'.price) AS priceMIN',
... ... @@ -156,46 +157,4 @@ class ProductFrontendSearch extends Product {
156 157 'max' => $query->max(ProductVariant::tableName() .'.price'),
157 158 ];
158 159 }
159   -
160   - protected function _setParams(&$query, $params, $setPriceLimits = true) {
161   - if (!empty($params['keywords'])) {
162   - if (!is_array($params['keywords'])) {
163   - $params['keywords'] = [$params['keywords']];
164   - }
165   - foreach ($params['keywords'] as $keyword) {
166   - $query->orFilterWhere(['ilike', Product::tableName() .'.name', $keyword]);
167   - $query->orFilterWhere(['ilike', BrandName::tableName() .'.value', $keyword]);
168   - $query->orFilterWhere(['ilike', CategoryName::tableName() .'.value', $keyword]);
169   - }
170   - }
171   - if (!empty($params['special'])) {
172   - foreach($params['special'] as $key => $value) {
173   - $query->orFilterWhere([Product::tableName() .'.'. $key => $value]);
174   - }
175   - }
176   - if (!empty($params['brands'])) {
177   - $query->andFilterWhere([Product::tableName() .'.brand_id' => $params['brands']]);
178   - }
179   - if (!empty($params['options'])) {
180   - foreach ($params['options'] as $group => $options) {
181   - foreach ($options as &$option) {
182   - $option = "'$option'";
183   - }
184   - $query->andWhere(
185   - Product::tableName() . '.product_id IN (SELECT product_id AS products FROM product_option INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id WHERE tax_group.alias LIKE \''. $group .'\' AND tax_option.alias IN (' . implode(',', $options) . '))'
186   - );
187   - }
188   - }
189   -
190   -
191   -
192   - if ($setPriceLimits && !empty($params['prices'])) {
193   - if ($params['prices']['min'] > 0) {
194   - $query->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
195   - }
196   - if ($params['prices']['max'] > 0) {
197   - $query->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
198   - }
199   - }
200   - }
201 160 }
202 161 \ No newline at end of file
... ...