Commit 2f25da0966476d00ec3396e22f80b5236505ea9c

Authored by Yarik
0 parents

first commit

Showing 133 changed files with 16624 additions and 0 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 133 files are displayed.

artbox-blog @ 6813d2d0b71
  1 +++ a/artbox-blog
  1 +Subproject commit 6813d2d0b71aba72d5c8e6dfdcb7f13aa3791772
... ...
artbox-comment @ a2cde075db9
  1 +++ a/artbox-comment
  1 +Subproject commit a2cde075db985ec267c8d896e5abb034a750930e
... ...
artbox-ecommerce/Module.php 0 → 100755
  1 +++ a/artbox-ecommerce/Module.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce;
  4 +
  5 + /**
  6 + * product module definition class
  7 + */
  8 + class Module extends \yii\base\Module
  9 + {
  10 +
  11 + public $types = [];
  12 +
  13 + /**
  14 + * @inheritdoc
  15 + */
  16 + public function init()
  17 + {
  18 + parent::init();
  19 +
  20 + \Yii::configure($this, require( __DIR__ . '/config.php' ));
  21 + }
  22 + }
... ...
artbox-ecommerce/behaviors/FilterBehavior.php 0 → 100755
  1 +++ a/artbox-ecommerce/behaviors/FilterBehavior.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\behaviors;
  4 +
  5 + use artweb\artbox\ecommerce\models\ProductOption;
  6 + use artweb\artbox\ecommerce\models\TaxOption;
  7 + use yii\base\Behavior;
  8 + use yii\db\ActiveRecord;
  9 +
  10 + class FilterBehavior extends Behavior
  11 + {
  12 +
  13 + public function getFilters()
  14 + {
  15 +
  16 + /**
  17 + * @var ActiveRecord $owner
  18 + */
  19 + $owner = $this->owner;
  20 + return $owner->hasMany(TaxOption::className(), [ 'tax_option_id' => 'option_id' ])
  21 + ->viaTable(ProductOption::tableName(), [ 'product_id' => $owner->getTableSchema()->primaryKey[ 0 ] ])
  22 + ->joinWith('taxGroup')
  23 + ->all();
  24 + }
  25 +
  26 + }
0 27 \ No newline at end of file
... ...
artbox-ecommerce/composer.json 0 → 100644
  1 +++ a/artbox-ecommerce/composer.json
  1 +{
  2 + "name": "artweb/artbox-ecommerce",
  3 + "description": "Yii2 light-weight CMS",
  4 + "license": "BSD-3-Clause",
  5 + "require": {
  6 + "php": ">=7.0",
  7 + "yiisoft/yii2": "*",
  8 + "developeruz/yii2-db-rbac": "*"
  9 + },
  10 + "autoload": {
  11 + "psr-4": {
  12 + "artweb\\artbox\\ecommerce\\": ""
  13 + }
  14 + }
  15 +}
0 16 \ No newline at end of file
... ...
artbox-ecommerce/config.php 0 → 100755
  1 +++ a/artbox-ecommerce/config.php
  1 +<?php
  2 +
  3 + return [
  4 + 'params' => [
  5 + 'category_group' => 1,
  6 + 'brand_group' => 2,
  7 + ],
  8 + ];
0 9 \ No newline at end of file
... ...
artbox-ecommerce/controllers/ManageController.php 0 → 100755
  1 +++ a/artbox-ecommerce/controllers/ManageController.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\controllers;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use artweb\artbox\ecommerce\models\Export;
  7 + use artweb\artbox\ecommerce\models\Import;
  8 + use artweb\artbox\ecommerce\models\ProductImage;
  9 + use Yii;
  10 + use artweb\artbox\ecommerce\models\Product;
  11 + use artweb\artbox\ecommerce\models\ProductSearch;
  12 + use yii\db\ActiveQuery;
  13 + use yii\web\Controller;
  14 + use yii\web\NotFoundHttpException;
  15 + use yii\filters\VerbFilter;
  16 + use yii\web\Response;
  17 + use yii\web\UploadedFile;
  18 +
  19 + /**
  20 + * ManageController implements the CRUD actions for Product model.
  21 + */
  22 + class ManageController extends Controller
  23 + {
  24 +
  25 + /**
  26 + * @inheritdoc
  27 + */
  28 + public function behaviors()
  29 + {
  30 + return [
  31 + 'verbs' => [
  32 + 'class' => VerbFilter::className(),
  33 + 'actions' => [
  34 + 'delete' => [ 'POST' ],
  35 + ],
  36 + ],
  37 + ];
  38 + }
  39 +
  40 + /**
  41 + * Lists all Product models.
  42 + *
  43 + * @return mixed
  44 + */
  45 + public function actionIndex()
  46 + {
  47 + $searchModel = new ProductSearch();
  48 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  49 +
  50 + return $this->render(
  51 + 'index',
  52 + [
  53 + 'searchModel' => $searchModel,
  54 + 'dataProvider' => $dataProvider,
  55 + ]
  56 + );
  57 + }
  58 +
  59 + /**
  60 + * Displays a single Product model.
  61 + *
  62 + * @param integer $id
  63 + *
  64 + * @return mixed
  65 + */
  66 + public function actionView($id)
  67 + {
  68 + $model = $this->findModel($id);
  69 + $categories = $model->getCategories()
  70 + ->with('lang')
  71 + ->all();
  72 + $variants = $model->getVariants()
  73 + ->with('lang')
  74 + ->all();
  75 + $properties = $model->getProperties();
  76 + return $this->render(
  77 + 'view',
  78 + [
  79 + 'model' => $this->findModel($id),
  80 + 'categories' => $categories,
  81 + 'variants' => $variants,
  82 + 'properties' => $properties,
  83 + ]
  84 + );
  85 + }
  86 +
  87 + /**
  88 + * Creates a new Product model.
  89 + * If creation is successful, the browser will be redirected to the 'view' page.
  90 + *
  91 + * @return mixed
  92 + */
  93 + public function actionCreate()
  94 + {
  95 + $model = new Product();
  96 + $model->generateLangs();
  97 + if ($model->load(Yii::$app->request->post())) {
  98 + $model->loadLangs(\Yii::$app->request);
  99 + if ($model->save() && $model->transactionStatus) {
  100 + return $this->redirect(
  101 + [
  102 + 'view',
  103 + 'id' => $model->id,
  104 + ]
  105 + );
  106 + }
  107 + }
  108 + return $this->render(
  109 + 'create',
  110 + [
  111 + 'model' => $model,
  112 + 'modelLangs' => $model->modelLangs,
  113 + ]
  114 + );
  115 + }
  116 +
  117 + /**
  118 + * Updates an existing Product model.
  119 + * If update is successful, the browser will be redirected to the 'view' page.
  120 + *
  121 + * @param integer $id
  122 + *
  123 + * @return mixed
  124 + */
  125 + public function actionUpdate($id)
  126 + {
  127 + $model = $this->findModel($id);
  128 + $model->generateLangs();
  129 + if ($model->load(Yii::$app->request->post())) {
  130 + $model->loadLangs(\Yii::$app->request);
  131 + if ($model->save() && $model->transactionStatus) {
  132 + return $this->redirect(
  133 + [
  134 + 'view',
  135 + 'id' => $model->id,
  136 + ]
  137 + );
  138 + }
  139 + }
  140 + /**
  141 + * @var ActiveQuery $groups
  142 + */
  143 + $groups = $model->getTaxGroupsByLevel(0);
  144 + return $this->render(
  145 + 'update',
  146 + [
  147 + 'model' => $model,
  148 + 'modelLangs' => $model->modelLangs,
  149 + 'groups' => $groups,
  150 + ]
  151 + );
  152 + }
  153 +
  154 + /**
  155 + * Deletes an existing Product model.
  156 + * If deletion is successful, the browser will be redirected to the 'index' page.
  157 + *
  158 + * @param integer $id
  159 + *
  160 + * @return mixed
  161 + */
  162 + public function actionDelete($id)
  163 + {
  164 + $this->findModel($id)
  165 + ->delete();
  166 + return $this->redirect([ 'index' ]);
  167 + }
  168 +
  169 + /**
  170 + * Deletes an existing ProductImage model.
  171 + *
  172 + * @param int $id
  173 + */
  174 + public function actionDeleteImage($id)
  175 + {
  176 + $image = ProductImage::findOne($id);
  177 +
  178 + if ($image) {
  179 + $image->delete();
  180 + }
  181 +
  182 + print '1';
  183 + exit;
  184 + }
  185 +
  186 + /**
  187 + * Toggle product top status
  188 + *
  189 + * @param int $id Product ID
  190 + *
  191 + * @return \yii\web\Response
  192 + */
  193 + public function actionIsTop($id)
  194 + {
  195 + $model = $this->findModel($id);
  196 +
  197 + $model->is_top = intval(empty( $model->is_top ));
  198 +
  199 + $model->save(false, [ 'is_top' ]);
  200 +
  201 + return $this->redirect([ 'index' ]);
  202 + }
  203 +
  204 + /**
  205 + * Toggle product new status
  206 + *
  207 + * @param int $id Product ID
  208 + *
  209 + * @return \yii\web\Response
  210 + */
  211 + public function actionIsNew($id)
  212 + {
  213 + $model = $this->findModel($id);
  214 +
  215 + $model->is_new = intval(empty( $model->is_new ));
  216 +
  217 + $model->save(false, [ 'is_new' ]);
  218 +
  219 + return $this->redirect([ 'index' ]);
  220 + }
  221 +
  222 + /**
  223 + * Toggle product discount status
  224 + *
  225 + * @param int $id Product ID
  226 + *
  227 + * @return \yii\web\Response
  228 + */
  229 + public function actionIsDiscount($id)
  230 + {
  231 + $model = $this->findModel($id);
  232 +
  233 + $model->is_discount = intval(empty( $model->is_discount ));
  234 +
  235 + $model->save(false, [ 'is_discount' ]);
  236 +
  237 + return $this->redirect([ 'index' ]);
  238 + }
  239 +
  240 + /**
  241 + * Perform product import
  242 + *
  243 + * @return string
  244 + */
  245 + public function actionImport()
  246 + {
  247 + $model = new Import();
  248 +
  249 + $languages = Language::find()
  250 + ->select(
  251 + [
  252 + 'name',
  253 + 'id',
  254 + ]
  255 + )
  256 + ->where([ 'status' => 1 ])
  257 + ->orderBy([ 'default' => SORT_DESC ])
  258 + ->asArray()
  259 + ->indexBy('id')
  260 + ->column();
  261 +
  262 + if ($model->load(Yii::$app->request->post())) {
  263 + \Yii::$app->session->set('export_lang', $model->lang);
  264 + $file = UploadedFile::getInstances($model, 'file');
  265 + $method = 'go' . ucfirst($model->type);
  266 + $target = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFile' . ucfirst($model->type));
  267 + if (empty( $file )) {
  268 + $model->errors[] = 'File not upload';
  269 + } elseif ($method == 'goPrices' && $file[ 0 ]->name != 'file_1.csv') {
  270 + $model->errors[] = 'File need "file_1.csv"';
  271 + } elseif ($method == 'goProducts' && $file[ 0 ]->name == 'file_1.csv') {
  272 + $model->errors[] = 'File can not "file_1.csv"';
  273 + } elseif ($model->validate() && $file[ 0 ]->saveAs($target)) {
  274 + // PROCESS PAGE
  275 + return $this->render(
  276 + 'import-process',
  277 + [
  278 + 'model' => $model,
  279 + 'method' => $model->type,
  280 + 'target' => $target,
  281 + ]
  282 + );
  283 + } else {
  284 + $model->errors[] = 'File can not be upload or other error';
  285 + }
  286 + }
  287 +
  288 + return $this->render(
  289 + 'import',
  290 + [
  291 + 'model' => $model,
  292 + 'languages' => $languages,
  293 + ]
  294 + );
  295 + }
  296 +
  297 + /**
  298 + * Import products via AJAX
  299 + *
  300 + * @return array
  301 + * @throws \HttpRequestException
  302 + */
  303 + public function actionProducts()
  304 + {
  305 + $from = Yii::$app->request->get('from', 0);
  306 +
  307 + $model = new Import();
  308 +
  309 + if (Yii::$app->request->isAjax) {
  310 + Yii::$app->response->format = Response::FORMAT_JSON;
  311 + return $model->goProducts($from, 1);
  312 + } else {
  313 + throw new \HttpRequestException('Must be AJAX');
  314 + }
  315 + }
  316 +
  317 + /**
  318 + * Import prices via AJAX
  319 + *
  320 + * @return array
  321 + * @throws \HttpRequestException
  322 + */
  323 + public function actionPrices()
  324 + {
  325 + $from = Yii::$app->request->get('from', 0);
  326 +
  327 + $model = new Import();
  328 +
  329 + if (Yii::$app->request->isAjax) {
  330 + Yii::$app->response->format = Response::FORMAT_JSON;
  331 + return $model->goPrices($from, 10);
  332 + } else {
  333 + throw new \HttpRequestException('Must be AJAX');
  334 + }
  335 + }
  336 +
  337 + /**
  338 + * Export proccess via AJAX
  339 + *
  340 + * @param int $from
  341 + * @param string $filename
  342 + *
  343 + * @return array
  344 + * @throws \HttpRequestException
  345 + */
  346 + public function actionExportProcess($from, $filename)
  347 + {
  348 +
  349 + $model = new Export();
  350 + if (Yii::$app->request->isAjax) {
  351 + Yii::$app->response->format = Response::FORMAT_JSON;
  352 + return $model->process($filename, $from);
  353 + } else {
  354 + throw new \HttpRequestException('Must be AJAX');
  355 + }
  356 + }
  357 +
  358 + /**
  359 + * Perform export
  360 + *
  361 + * @return string
  362 + */
  363 + public function actionExport()
  364 + {
  365 + $model = new Export();
  366 +
  367 + if ($model->load(Yii::$app->request->post())) {
  368 + \Yii::$app->session->set('export_lang', $model->lang);
  369 + return $this->render(
  370 + 'export-process',
  371 + [
  372 + 'model' => $model,
  373 + 'method' => 'export',
  374 + ]
  375 + );
  376 + }
  377 +
  378 + return $this->render(
  379 + 'export',
  380 + [
  381 + 'model' => $model,
  382 + ]
  383 + );
  384 + }
  385 +
  386 + /**
  387 + * Finds the Product model based on its primary key value.
  388 + * If the model is not found, a 404 HTTP exception will be thrown.
  389 + *
  390 + * @param integer $id
  391 + *
  392 + * @return Product the loaded model
  393 + * @throws NotFoundHttpException if the model cannot be found
  394 + */
  395 + protected function findModel($id)
  396 + {
  397 + if (( $model = Product::find()
  398 + ->where([ 'id' => $id ])
  399 + ->with('lang')
  400 + ->one() ) !== null
  401 + ) {
  402 + return $model;
  403 + } else {
  404 + throw new NotFoundHttpException('The requested page does not exist.');
  405 + }
  406 + }
  407 + }
... ...
artbox-ecommerce/controllers/ProductUnitController.php 0 → 100755
  1 +++ a/artbox-ecommerce/controllers/ProductUnitController.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\controllers;
  4 +
  5 + use Yii;
  6 + use artweb\artbox\ecommerce\models\ProductUnit;
  7 + use artweb\artbox\ecommerce\models\ProductUnitSearch;
  8 + use yii\web\Controller;
  9 + use yii\web\NotFoundHttpException;
  10 + use yii\filters\VerbFilter;
  11 +
  12 + /**
  13 + * ProductUnitController implements the CRUD actions for ProductUnit model.
  14 + */
  15 + class ProductUnitController extends Controller
  16 + {
  17 +
  18 + /**
  19 + * @inheritdoc
  20 + */
  21 + public function behaviors()
  22 + {
  23 + return [
  24 + 'verbs' => [
  25 + 'class' => VerbFilter::className(),
  26 + 'actions' => [
  27 + 'delete' => [ 'POST' ],
  28 + ],
  29 + ],
  30 + ];
  31 + }
  32 +
  33 + /**
  34 + * Lists all ProductUnit models.
  35 + *
  36 + * @return mixed
  37 + */
  38 + public function actionIndex()
  39 + {
  40 + $searchModel = new ProductUnitSearch();
  41 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  42 +
  43 + return $this->render(
  44 + 'index',
  45 + [
  46 + 'searchModel' => $searchModel,
  47 + 'dataProvider' => $dataProvider,
  48 + ]
  49 + );
  50 + }
  51 +
  52 + /**
  53 + * Displays a single ProductUnit model.
  54 + *
  55 + * @param integer $id
  56 + *
  57 + * @return mixed
  58 + */
  59 + public function actionView($id)
  60 + {
  61 + return $this->render(
  62 + 'view',
  63 + [
  64 + 'model' => $this->findModel($id),
  65 + ]
  66 + );
  67 + }
  68 +
  69 + /**
  70 + * Creates a new ProductUnit model.
  71 + * If creation is successful, the browser will be redirected to the 'view' page.
  72 + *
  73 + * @return mixed
  74 + */
  75 + public function actionCreate()
  76 + {
  77 + $model = new ProductUnit();
  78 + $model->generateLangs();
  79 + if ($model->load(Yii::$app->request->post())) {
  80 + $model->loadLangs(\Yii::$app->request);
  81 + if ($model->save() && $model->transactionStatus) {
  82 + return $this->redirect(
  83 + [
  84 + 'view',
  85 + 'id' => $model->id,
  86 + ]
  87 + );
  88 + }
  89 + }
  90 + return $this->render(
  91 + 'create',
  92 + [
  93 + 'model' => $model,
  94 + 'modelLangs' => $model->modelLangs,
  95 + ]
  96 + );
  97 + }
  98 +
  99 + /**
  100 + * Updates an existing ProductUnit model.
  101 + * If update is successful, the browser will be redirected to the 'view' page.
  102 + *
  103 + * @param integer $id
  104 + *
  105 + * @return mixed
  106 + */
  107 + public function actionUpdate($id)
  108 + {
  109 + $model = $this->findModel($id);
  110 + $model->generateLangs();
  111 + if ($model->load(Yii::$app->request->post())) {
  112 + $model->loadLangs(\Yii::$app->request);
  113 + if ($model->save() && $model->transactionStatus) {
  114 + return $this->redirect(
  115 + [
  116 + 'view',
  117 + 'id' => $model->id,
  118 + ]
  119 + );
  120 + }
  121 + }
  122 + return $this->render(
  123 + 'update',
  124 + [
  125 + 'model' => $model,
  126 + 'modelLangs' => $model->modelLangs,
  127 + ]
  128 + );
  129 + }
  130 +
  131 + /**
  132 + * Deletes an existing ProductUnit model.
  133 + * If deletion is successful, the browser will be redirected to the 'index' page.
  134 + *
  135 + * @param integer $id
  136 + *
  137 + * @return mixed
  138 + */
  139 + public function actionDelete($id)
  140 + {
  141 + $this->findModel($id)
  142 + ->delete();
  143 +
  144 + return $this->redirect([ 'index' ]);
  145 + }
  146 +
  147 + /**
  148 + * Finds the ProductUnit model based on its primary key value.
  149 + * If the model is not found, a 404 HTTP exception will be thrown.
  150 + *
  151 + * @param integer $id
  152 + *
  153 + * @return ProductUnit the loaded model
  154 + * @throws NotFoundHttpException if the model cannot be found
  155 + */
  156 + protected function findModel($id)
  157 + {
  158 + if (( $model = ProductUnit::find()
  159 + ->where([ 'id' => $id ])
  160 + ->with('lang')
  161 + ->one() ) !== null
  162 + ) {
  163 + return $model;
  164 + } else {
  165 + throw new NotFoundHttpException('The requested page does not exist.');
  166 + }
  167 + }
  168 + }
... ...
artbox-ecommerce/controllers/TaxGroupController.php 0 → 100755
  1 +++ a/artbox-ecommerce/controllers/TaxGroupController.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\controllers;
  4 +
  5 + use artweb\artbox\ecommerce\models\TaxGroupSearch;
  6 + use Yii;
  7 + use artweb\artbox\ecommerce\models\TaxGroup;
  8 + use yii\data\ActiveDataProvider;
  9 + use yii\db\ActiveQuery;
  10 + use yii\web\Controller;
  11 + use yii\web\NotFoundHttpException;
  12 + use yii\filters\VerbFilter;
  13 +
  14 + /**
  15 + * TaxGroupController implements the CRUD actions for TaxGroup model.
  16 + */
  17 + class TaxGroupController extends Controller
  18 + {
  19 +
  20 + /**
  21 + * @inheritdoc
  22 + */
  23 + public function behaviors()
  24 + {
  25 + return [
  26 + 'verbs' => [
  27 + 'class' => VerbFilter::className(),
  28 + 'actions' => [
  29 + 'delete' => [ 'POST' ],
  30 + ],
  31 + ],
  32 + ];
  33 + }
  34 +
  35 + /**
  36 + * Lists all TaxGroup models.
  37 + *
  38 + * @param $level integer
  39 + *
  40 + * @return mixed
  41 + */
  42 + public function actionIndex($level)
  43 + {
  44 + $searchModel = new TaxGroupSearch();
  45 + $dataProvider = $searchModel->search(\Yii::$app->request->queryParams, $level);
  46 + /**
  47 + * @var ActiveQuery $query
  48 + */
  49 + $query = $dataProvider->query;
  50 + $query->with('options')
  51 + ->with('categories');
  52 +
  53 + return $this->render(
  54 + 'index',
  55 + [
  56 + 'dataProvider' => $dataProvider,
  57 + 'searchModel' => $searchModel,
  58 + 'level' => $level,
  59 + ]
  60 + );
  61 + }
  62 +
  63 + /**
  64 + * Creates a new TaxGroup model.
  65 + * If creation is successful, the browser will be redirected to the 'view' page.
  66 + *
  67 + * @param $level integer
  68 + *
  69 + * @return mixed
  70 + */
  71 + public function actionCreate($level)
  72 + {
  73 + $model = new TaxGroup();
  74 + $model->generateLangs();
  75 + if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  76 + $model->loadLangs(\Yii::$app->request);
  77 + $model->level = $level;
  78 + if ($model->save() && $model->transactionStatus) {
  79 + return $this->redirect(
  80 + [
  81 + 'index',
  82 + 'level' => $level,
  83 + ]
  84 + );
  85 + }
  86 + }
  87 + return $this->render(
  88 + 'create',
  89 + [
  90 + 'model' => $model,
  91 + 'modelLangs' => $model->modelLangs,
  92 + ]
  93 + );
  94 + }
  95 +
  96 + /**
  97 + * Updates an existing TaxGroup model.
  98 + * If update is successful, the browser will be redirected to the 'view' page.
  99 + *
  100 + * @param $level integer
  101 + * @param integer $id
  102 + *
  103 + * @return mixed
  104 + */
  105 + public function actionUpdate($level, $id)
  106 + {
  107 + $model = $this->findModel($id);
  108 + $model->generateLangs();
  109 + if ($model->load(Yii::$app->request->post())) {
  110 + $model->loadLangs(\Yii::$app->request);
  111 + if ($model->save() && $model->transactionStatus) {
  112 + return $this->redirect(
  113 + [
  114 + 'index',
  115 + 'level' => $level,
  116 + ]
  117 + );
  118 + }
  119 + }
  120 + return $this->render(
  121 + 'update',
  122 + [
  123 + 'model' => $model,
  124 + 'modelLangs' => $model->modelLangs,
  125 + 'level' => $level,
  126 + ]
  127 + );
  128 + }
  129 +
  130 + /**
  131 + * Deletes an existing TaxGroup model.
  132 + * If deletion is successful, the browser will be redirected to the 'index' page.
  133 + *
  134 + * @param $level integer
  135 + * @param integer $id
  136 + *
  137 + * @return mixed
  138 + */
  139 + public function actionDelete($level, $id)
  140 + {
  141 + $this->findModel($id)
  142 + ->delete();
  143 + return $this->redirect(
  144 + [
  145 + 'index',
  146 + 'level' => $level,
  147 + ]
  148 + );
  149 + }
  150 +
  151 + /**
  152 + * Finds the TaxGroup model based on its primary key value.
  153 + * If the model is not found, a 404 HTTP exception will be thrown.
  154 + *
  155 + * @param integer $id
  156 + *
  157 + * @return TaxGroup the loaded model
  158 + * @throws NotFoundHttpException if the model cannot be found
  159 + */
  160 + protected function findModel($id)
  161 + {
  162 + if (( $model = TaxGroup::find()
  163 + ->with('lang')
  164 + ->where([ 'id' => $id ])
  165 + ->one() ) !== null
  166 + ) {
  167 + return $model;
  168 + } else {
  169 + throw new NotFoundHttpException('The requested page does not exist.');
  170 + }
  171 + }
  172 + }
... ...
artbox-ecommerce/controllers/TaxOptionController.php 0 → 100755
  1 +++ a/artbox-ecommerce/controllers/TaxOptionController.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\controllers;
  4 +
  5 + use artweb\artbox\ecommerce\models\TaxGroup;
  6 + use Yii;
  7 + use artweb\artbox\ecommerce\models\TaxOption;
  8 + use artweb\artbox\ecommerce\models\TaxOptionSearch;
  9 + use yii\db\ActiveQuery;
  10 + use yii\web\Controller;
  11 + use yii\web\NotFoundHttpException;
  12 + use yii\filters\VerbFilter;
  13 +
  14 + /**
  15 + * TaxOptionController implements the CRUD actions for TaxOption model.
  16 + */
  17 + class TaxOptionController extends Controller
  18 + {
  19 +
  20 + /**
  21 + * @inheritdoc
  22 + */
  23 + public function behaviors()
  24 + {
  25 + return [
  26 + 'verbs' => [
  27 + 'class' => VerbFilter::className(),
  28 + 'actions' => [
  29 + 'delete' => [ 'POST' ],
  30 + ],
  31 + ],
  32 + ];
  33 + }
  34 +
  35 + /**
  36 + * Lists all TaxOption models.
  37 + *
  38 + * @return mixed
  39 + */
  40 + public function actionIndex()
  41 + {
  42 + $group = $this->findGroup(Yii::$app->request->queryParams[ 'group' ]);
  43 + $searchModel = new TaxOptionSearch();
  44 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  45 + /**
  46 + * @var ActiveQuery $query
  47 + */
  48 + $query = $dataProvider->query;
  49 + $query->andWhere([ 'tax_group_id' => $group->id ]);
  50 + if ($group->level) {
  51 + $query->with('productVariants');
  52 + } else {
  53 + $query->with('products');
  54 + }
  55 + return $this->render(
  56 + 'index',
  57 + [
  58 + 'searchModel' => $searchModel,
  59 + 'dataProvider' => $dataProvider,
  60 + 'group' => $group,
  61 + ]
  62 + );
  63 + }
  64 +
  65 + /**
  66 + * Creates a new TaxOption model.
  67 + * If creation is successful, the browser will be redirected to the 'view' page.
  68 + *
  69 + * @return mixed
  70 + */
  71 + public function actionCreate()
  72 + {
  73 + $group = $this->findGroup(Yii::$app->request->queryParams[ 'group' ]);
  74 + $model = new TaxOption(
  75 + [
  76 + 'tax_group_id' => $group->id,
  77 + ]
  78 + );
  79 + $model->generateLangs();
  80 + if ($model->load(Yii::$app->request->post())) {
  81 + $model->loadLangs(\Yii::$app->request);
  82 + if ($model->save() && $model->transactionStatus) {
  83 + return is_null(Yii::$app->request->post('create_and_new')) ? $this->redirect(
  84 + [
  85 + 'index',
  86 + 'group' => $group->id,
  87 + ]
  88 + ) : $this->redirect(array_merge([ 'create' ], Yii::$app->request->queryParams));
  89 + }
  90 + }
  91 + return $this->render(
  92 + 'create',
  93 + [
  94 + 'model' => $model,
  95 + 'modelLangs' => $model->modelLangs,
  96 + 'group' => $group,
  97 + ]
  98 + );
  99 + }
  100 +
  101 + /**
  102 + * Updates an existing TaxOption model.
  103 + * If update is successful, the browser will be redirected to the 'view' page.
  104 + *
  105 + * @param string $id
  106 + *
  107 + * @return mixed
  108 + */
  109 + public function actionUpdate($id)
  110 + {
  111 + $model = $this->findModel($id);
  112 + $group = $this->findGroup($model->tax_group_id);
  113 + $model->generateLangs();
  114 + if ($model->load(Yii::$app->request->post())) {
  115 + $model->loadLangs(\Yii::$app->request);
  116 + if ($model->save() && $model->transactionStatus) {
  117 + return $this->redirect(
  118 + [
  119 + 'index',
  120 + 'group' => $group->id,
  121 + ]
  122 + );
  123 + }
  124 + }
  125 + return $this->render(
  126 + 'update',
  127 + [
  128 + 'model' => $model,
  129 + 'modelLangs' => $model->modelLangs,
  130 + 'group' => $group,
  131 + ]
  132 + );
  133 + }
  134 +
  135 + /**
  136 + * Deletes an existing TaxOption model.
  137 + * If deletion is successful, the browser will be redirected to the 'index' page.
  138 + *
  139 + * @param string $id
  140 + *
  141 + * @return mixed
  142 + */
  143 + public function actionDelete($id)
  144 + {
  145 + $model = $this->findModel($id);
  146 + $group_id = $model->tax_group_id;
  147 +
  148 + $model->delete();
  149 +
  150 + return $this->redirect(
  151 + [
  152 + 'index',
  153 + 'group' => $group_id,
  154 + ]
  155 + );
  156 + }
  157 +
  158 + /**
  159 + * Finds the TaxOption model based on its primary key value.
  160 + * If the model is not found, a 404 HTTP exception will be thrown.
  161 + *
  162 + * @param string $id
  163 + *
  164 + * @return TaxOption the loaded model
  165 + * @throws NotFoundHttpException if the model cannot be found
  166 + */
  167 + protected function findModel($id)
  168 + {
  169 + if (( $model = TaxOption::find()
  170 + ->with('lang')
  171 + ->where([ 'id' => $id ])
  172 + ->one() ) !== null
  173 + ) {
  174 + return $model;
  175 + } else {
  176 + throw new NotFoundHttpException('The requested page does not exist.');
  177 + }
  178 + }
  179 +
  180 + /**
  181 + * @param int $id
  182 + *
  183 + * @return null|TaxGroup
  184 + * @throws NotFoundHttpException
  185 + */
  186 + protected function findGroup($id)
  187 + {
  188 + if (( $model = TaxGroup::find()
  189 + ->with('lang')
  190 + ->where([ 'id' => $id ])
  191 + ->one() ) !== null
  192 + ) {
  193 + return $model;
  194 + } else {
  195 + throw new NotFoundHttpException('The requested page does not exist.');
  196 + }
  197 + }
  198 + }
... ...
artbox-ecommerce/controllers/VariantController.php 0 → 100755
  1 +++ a/artbox-ecommerce/controllers/VariantController.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\controllers;
  4 +
  5 + use artweb\artbox\ecommerce\models\Product;
  6 + use artweb\artbox\ecommerce\models\ProductImage;
  7 + use artweb\artbox\ecommerce\models\ProductStock;
  8 + use artweb\artbox\ecommerce\models\ProductVariant;
  9 + use artweb\artbox\ecommerce\models\ProductVariantSearch;
  10 + use artweb\artbox\ecommerce\models\Stock;
  11 + use Yii;
  12 + use yii\db\ActiveQuery;
  13 + use yii\web\Controller;
  14 + use yii\web\NotFoundHttpException;
  15 + use yii\filters\VerbFilter;
  16 +
  17 + /**
  18 + * VartiantController implements the CRUD actions for ProductVariant model.
  19 + */
  20 + class VariantController extends Controller
  21 + {
  22 +
  23 + /**
  24 + * @inheritdoc
  25 + */
  26 + public function behaviors()
  27 + {
  28 + return [
  29 + 'verbs' => [
  30 + 'class' => VerbFilter::className(),
  31 + 'actions' => [
  32 + 'delete' => [ 'POST' ],
  33 + ],
  34 + ],
  35 + ];
  36 + }
  37 +
  38 + /**
  39 + * Lists all ProductVariant models.
  40 + *
  41 + * @param int $product_id
  42 + *
  43 + * @return mixed
  44 + */
  45 + public function actionIndex($product_id)
  46 + {
  47 + $product = $this->findProduct($product_id);
  48 + $searchModel = new ProductVariantSearch();
  49 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  50 + /**
  51 + * @var ActiveQuery $query
  52 + */
  53 + $query = $dataProvider->query;
  54 + $query->with('image')
  55 + ->andWhere([ 'product_id' => $product->id ]);
  56 +
  57 + return $this->render(
  58 + 'index',
  59 + [
  60 + 'searchModel' => $searchModel,
  61 + 'dataProvider' => $dataProvider,
  62 + 'product' => $product,
  63 + ]
  64 + );
  65 + }
  66 +
  67 + /**
  68 + * Displays a single ProductVariant model.
  69 + *
  70 + * @param integer $id
  71 + *
  72 + * @return mixed
  73 + */
  74 + public function actionView($id)
  75 + {
  76 + $model = $this->findModel($id);
  77 + $properties = $model->getProperties();
  78 + return $this->render(
  79 + 'view',
  80 + [
  81 + 'model' => $model,
  82 + 'properties' => $properties,
  83 + ]
  84 + );
  85 + }
  86 +
  87 + /**
  88 + * Creates a new ProductVariant model.
  89 + * If creation is successful, the browser will be redirected to the 'view' page.
  90 + *
  91 + * @param int $product_id
  92 + *
  93 + * @return mixed
  94 + */
  95 + public function actionCreate($product_id)
  96 + {
  97 + $product = $this->findProduct($product_id);
  98 + $model = new ProductVariant();
  99 + $model->product_id = $product->id;
  100 + $model->generateLangs();
  101 + if ($model->load(Yii::$app->request->post())) {
  102 + $model->loadLangs(\Yii::$app->request);
  103 + if ($model->save() && $model->transactionStatus) {
  104 + $model->stock = $this->saveStocks($model, Yii::$app->request->post('ProductStock', []));
  105 + if ($model->save(true, [ 'stock' ]) && $model->transactionStatus) {
  106 + return $this->redirect(
  107 + [
  108 + 'index',
  109 + 'product_id' => $product->id,
  110 + ]
  111 + );
  112 + }
  113 + }
  114 + }
  115 + $groups = $model->getTaxGroupsByLevel(1);
  116 + return $this->render(
  117 + 'create',
  118 + [
  119 + 'model' => $model,
  120 + 'modelLangs' => $model->modelLangs,
  121 + 'groups' => $groups,
  122 + 'stocks' => [ new ProductStock() ],
  123 + 'product' => $product,
  124 + ]
  125 + );
  126 + }
  127 +
  128 + /**
  129 + * Updates an existing ProductVariant model.
  130 + * If update is successful, the browser will be redirected to the 'view' page.
  131 + *
  132 + * @param integer $product_id
  133 + * @param integer $id
  134 + *
  135 + * @return mixed
  136 + */
  137 + public function actionUpdate($product_id, $id)
  138 + {
  139 + $product = $this->findProduct($product_id);
  140 + $model = $this->findModel($id);
  141 + $model->generateLangs();
  142 + if ($model->load(Yii::$app->request->post())) {
  143 + $model->loadLangs(\Yii::$app->request);
  144 + if ($model->save() && $model->transactionStatus) {
  145 + $model->stock = $this->saveStocks($model, Yii::$app->request->post('ProductStock', []));
  146 + if ($model->save(true, [ 'stock' ]) && $model->transactionStatus) {
  147 + return $this->redirect(
  148 + [
  149 + 'index',
  150 + 'product_id' => $product_id,
  151 + ]
  152 + );
  153 + }
  154 + }
  155 + }
  156 + $groups = $model->getTaxGroupsByLevel(1);
  157 + return $this->render(
  158 + 'update',
  159 + [
  160 + 'model' => $model,
  161 + 'modelLangs' => $model->modelLangs,
  162 + 'groups' => $groups,
  163 + 'stocks' => ( !empty( $model->variantStocks ) ) ? $model->variantStocks : [ new ProductStock ],
  164 + 'product' => $product,
  165 + ]
  166 + );
  167 + }
  168 +
  169 + /**
  170 + * Deletes an existing ProductVariant model.
  171 + * If deletion is successful, the browser will be redirected to the 'index' page.
  172 + *
  173 + * @param integer $product_id
  174 + * @param integer $id
  175 + *
  176 + * @return mixed
  177 + */
  178 + public function actionDelete($product_id, $id)
  179 + {
  180 +
  181 + $this->findModel($id)
  182 + ->delete();
  183 +
  184 + return $this->redirect(
  185 + [
  186 + 'index',
  187 + 'product_id' => $product_id,
  188 + ]
  189 + );
  190 + }
  191 +
  192 + /**
  193 + * Deletes an existing ProductImage model.
  194 + *
  195 + * @param $id
  196 + */
  197 + public function actionDeleteImage($id)
  198 + {
  199 + $image = ProductImage::findOne($id);
  200 +
  201 + if ($image) {
  202 + $image->delete();
  203 + }
  204 +
  205 + print '1';
  206 + exit;
  207 + }
  208 +
  209 + /**
  210 + * Save ProductStocks for ProductVariant and return total count of products.
  211 + *
  212 + * @param \artweb\artbox\ecommerce\models\ProductVariant $productVariant
  213 + * @param array|null $productStocks
  214 + *
  215 + * @return int
  216 + */
  217 + protected function saveStocks(ProductVariant $productVariant, array $productStocks = null)
  218 + {
  219 + $total_quantity = 0;
  220 + if (!empty( $productStocks )) {
  221 + $productVariant->unlinkAll('stocks', true);
  222 + $sorted_array = [];
  223 + foreach ($productStocks as $productStock) {
  224 + if (!empty( $productStock[ 'title' ] ) && !empty( $productStock[ 'quantity' ] )) {
  225 + if (!empty( $sorted_array[ $productStock[ 'title' ] ] )) {
  226 + $sorted_array[ $productStock[ 'title' ] ] += $productStock[ 'quantity' ];
  227 + } else {
  228 + $sorted_array[ $productStock[ 'title' ] ] = $productStock[ 'quantity' ];
  229 + }
  230 + }
  231 + }
  232 + $productStocks = $sorted_array;
  233 + $stock_names = array_keys($productStocks);
  234 + $stocks = Stock::find()
  235 + ->joinWith('lang')
  236 + ->where([ 'stock_lang.title' => $stock_names ])
  237 + ->indexBy(function($row) {
  238 + /**
  239 + * @var Stock $row
  240 + */
  241 + return $row->lang->title;
  242 + })
  243 + ->all();
  244 + foreach ($productStocks as $stockName => $quantity) {
  245 + $quantity = (int) $quantity;
  246 + if (!array_key_exists($stockName, $stocks)) {
  247 + $stock = new Stock();
  248 + $stock->generateLangs();
  249 + foreach ($stock->modelLangs as $modelLang) {
  250 + $modelLang->title = $stockName;
  251 + }
  252 + if (!$stock->save() || !$stock->transactionStatus) {
  253 + continue;
  254 + }
  255 + } else {
  256 + $stock = $stocks[ $stockName ];
  257 + }
  258 + $psModel = new ProductStock(
  259 + [
  260 + 'product_variant_id' => $productVariant->id,
  261 + 'stock_id' => $stock->id,
  262 + 'quantity' => $quantity,
  263 + ]
  264 + );
  265 + if ($psModel->save()) {
  266 + $total_quantity += $quantity;
  267 + }
  268 + }
  269 + } else {
  270 + $productVariant->unlinkAll('stocks', true);
  271 + }
  272 + return $total_quantity;
  273 + }
  274 +
  275 + /**
  276 + * Finds the ProductVariant model based on its primary key value.
  277 + * If the model is not found, a 404 HTTP exception will be thrown.
  278 + *
  279 + * @param integer $id
  280 + *
  281 + * @return ProductVariant the loaded model
  282 + * @throws NotFoundHttpException if the model cannot be found
  283 + */
  284 + protected function findModel($id)
  285 + {
  286 + if (( $model = ProductVariant::find()
  287 + ->where([ 'id' => $id ])
  288 + ->with('lang')
  289 + ->one() ) !== null
  290 + ) {
  291 + return $model;
  292 + } else {
  293 + throw new NotFoundHttpException('The requested page does not exist.');
  294 + }
  295 + }
  296 +
  297 + /**
  298 + * @param int $product_id
  299 + *
  300 + * @return Product
  301 + * @throws NotFoundHttpException
  302 + */
  303 + protected function findProduct($product_id)
  304 + {
  305 + if (( $model = Product::find()
  306 + ->with('lang')
  307 + ->where([ 'id' => $product_id ])
  308 + ->one() ) !== null
  309 + ) {
  310 + return $model;
  311 + } else {
  312 + throw new NotFoundHttpException('The requested page does not exist.');
  313 + }
  314 + }
  315 + }
... ...
artbox-ecommerce/helpers/FilterHelper.php 0 → 100755
  1 +++ a/artbox-ecommerce/helpers/FilterHelper.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\helpers;
  4 +
  5 + use artweb\artbox\ecommerce\models\BrandLang;
  6 + use artweb\artbox\ecommerce\models\CategoryLang;
  7 + use artweb\artbox\ecommerce\models\Product;
  8 + use artweb\artbox\ecommerce\models\ProductLang;
  9 + use artweb\artbox\ecommerce\models\ProductVariant;
  10 + use artweb\artbox\ecommerce\models\ProductVariantLang;
  11 + use artweb\artbox\ecommerce\models\TaxGroup;
  12 + use yii\base\Object;
  13 + use yii\db\ActiveQuery;
  14 + use yii\db\Query;
  15 + use yii\helpers\ArrayHelper;
  16 +
  17 + class FilterHelper extends Object
  18 + {
  19 +
  20 + public static $optionsList = [];
  21 +
  22 + /**
  23 + * Get TaxGroups
  24 + *
  25 + * @return array
  26 + */
  27 + public static function optionsTemplate()
  28 + {
  29 + if (empty( static::$optionsList )) {
  30 + return static::$optionsList = ArrayHelper::getColumn(
  31 + TaxGroup::find()
  32 + ->joinWith('lang')
  33 + ->where([ 'is_filter' => 'TRUE' ])
  34 + ->all(),
  35 + 'lang.alias'
  36 + );
  37 + } else {
  38 + return static::$optionsList;
  39 + }
  40 +
  41 + }
  42 +
  43 + /**
  44 + * Return custom filter-option link
  45 + *
  46 + * @param array $filter
  47 + * @param string $key
  48 + * @param mixed $value
  49 + * @param bool $remove
  50 + *
  51 + * @return array
  52 + */
  53 + public static function getFilterForOption(array $filter, string $key, $value, bool $remove = false)
  54 + {
  55 +
  56 + $optionsTemplate = self::optionsTemplate();
  57 + array_unshift($optionsTemplate, "special", "brands");
  58 +
  59 + $result = $filter;
  60 +
  61 + if (is_array($value)) {
  62 + foreach ($value as $value_key => $value_items) {
  63 + if (!is_array($value_items)) {
  64 + $value_items = [ $value_items ];
  65 + }
  66 + foreach ($value_items as $value_item) {
  67 + if ($remove && isset( $result[ $key ] ) && ( $i = array_search(
  68 + $value_item,
  69 + $result[ $key ][ $value_key ]
  70 + ) ) !== false
  71 + ) {
  72 + unset( $result[ $key ][ $value_key ][ $i ] );
  73 + if (empty( $result[ $key ][ $value_key ] )) {
  74 + unset( $result[ $key ][ $value_key ] );
  75 + }
  76 + } else {
  77 + if (!isset( $result[ $key ][ $value_key ] ) || array_search(
  78 + $value_item,
  79 + $result[ $key ][ $value_key ]
  80 + ) === false
  81 + ) {
  82 + $result[ $key ][ $value_key ][] = $value_item;
  83 + }
  84 + }
  85 + }
  86 + }
  87 + } else {
  88 + if ($remove && isset( $result[ $key ] ) && ( $i = array_search($value, $result[ $key ]) ) !== false) {
  89 + unset( $result[ $key ][ $i ] );
  90 + if (empty( $result[ $key ] )) {
  91 + unset( $result[ $key ] );
  92 + }
  93 + } else {
  94 + if (!isset( $result[ $key ] ) || array_search($value, $result[ $key ]) === false) {
  95 + $result[ $key ][] = $value;
  96 + }
  97 + }
  98 + }
  99 +
  100 + $filterView = [];
  101 +
  102 + foreach ($optionsTemplate as $optionKey) {
  103 + if (isset( $result[ $optionKey ] )) {
  104 + $filterView[ $optionKey ] = $result[ $optionKey ];
  105 + }
  106 +
  107 + }
  108 +
  109 + return $filterView;
  110 + }
  111 +
  112 + /**
  113 + * Fill query with filter conditions
  114 + *
  115 + * @param ActiveQuery $query
  116 + * @param array $params
  117 + */
  118 + public static function setQueryParams(ActiveQuery $query, array $params)
  119 + {
  120 + $last_query = null;
  121 + foreach ($params as $key => $param) {
  122 + switch ($key) {
  123 + case 'special':
  124 + self::filterSpecial($param, $query);
  125 + break;
  126 + case 'brands':
  127 + self::filterBrands($param, $query);
  128 + break;
  129 + case 'keywords':
  130 + self::filterKeywords($param, $query);
  131 + break;
  132 + case 'prices':
  133 + self::filterPrices($param, $query);
  134 + break;
  135 + default:
  136 + $last_query = self::filterOptions($param, $last_query);
  137 + break;
  138 + }
  139 + }
  140 + // If tax option filters were provided filter query with them
  141 + if (!empty( $last_query )) {
  142 + $query->andWhere([ 'product.id' => $last_query ]);
  143 + }
  144 + }
  145 +
  146 + /**
  147 + * Tax Option filter
  148 + *
  149 + * @param string[] $params
  150 + * @param \yii\db\Query|null $last_query
  151 + *
  152 + * @return Query
  153 + */
  154 + private static function filterOptions(array $params, Query $last_query = null): Query
  155 + {
  156 + $variant_query = ( new Query() )->distinct()
  157 + ->select('product_variant.product_id as products')
  158 + ->from('product_variant_option')
  159 + ->innerJoin(
  160 + 'product_variant',
  161 + 'product_variant_option.product_variant_id = product_variant.id'
  162 + )
  163 + ->innerJoin(
  164 + 'tax_option',
  165 + 'tax_option.id = product_variant_option.option_id'
  166 + )
  167 + ->innerJoin(
  168 + 'tax_option_lang',
  169 + 'tax_option_lang.tax_option_id = tax_option.id'
  170 + )
  171 + ->where([ 'tax_option_lang.alias' => $params ]);
  172 + $product_query = ( new Query() )->distinct()
  173 + ->select('product_option.product_id as products')
  174 + ->from('product_option')
  175 + ->innerJoin('tax_option', 'product_option.option_id = tax_option.id')
  176 + ->innerJoin(
  177 + 'tax_option_lang',
  178 + 'tax_option_lang.tax_option_id = tax_option.id'
  179 + )
  180 + ->where(
  181 + [ 'tax_option_lang.alias' => $params ]
  182 + )
  183 + ->union($variant_query);
  184 + $query = ( new Query() )->select('products')
  185 + ->from([ 'result_table' => $product_query ]);
  186 + if (!empty( $last_query )) {
  187 + $query->andWhere([ 'product.id' => $last_query ]);
  188 + }
  189 + return $query;
  190 + }
  191 +
  192 + /**
  193 + * Fill $query with special filters (used in Product)
  194 + *
  195 + * @param array $params
  196 + * @param \yii\db\ActiveQuery $query
  197 + */
  198 + private static function filterSpecial(array $params, ActiveQuery $query)
  199 + {
  200 + $conditions = [];
  201 + /**
  202 + * @var string $key
  203 + */
  204 + foreach ($params as $key => $param) {
  205 + $conditions[] = [
  206 + '=',
  207 + Product::tableName() . '.' . $key,
  208 + $param,
  209 + ];
  210 + }
  211 + /* If 2 or more special conditions get all that satisfy at least one of them. */
  212 + if (count($conditions) > 1) {
  213 + array_unshift($conditions, 'or');
  214 + } else {
  215 + $conditions = $conditions[ 0 ];
  216 + }
  217 + $query->andFilterWhere($conditions);
  218 + }
  219 +
  220 + /**
  221 + * Fill query with brands filter
  222 + *
  223 + * @param int[] $param
  224 + * @param \yii\db\ActiveQuery $query
  225 + */
  226 + private static function filterBrands(array $param, ActiveQuery $query)
  227 + {
  228 + $query->andFilterWhere([ Product::tableName() . '.brand_id' => $param ]);
  229 + }
  230 +
  231 + /**
  232 + * Fill query with keywords filter
  233 + *
  234 + * @param array $params
  235 + * @param \yii\db\ActiveQuery $query
  236 + */
  237 + private static function filterKeywords(array $params, ActiveQuery $query)
  238 + {
  239 + $conditions = [];
  240 + if (!empty( $params )) {
  241 + if (!is_array($params)) {
  242 + $params = [ $params ];
  243 + }
  244 + /**
  245 + * @var string $param Inputed keyword
  246 + */
  247 + foreach ($params as $param) {
  248 + $conditions[] = [
  249 + 'or',
  250 + [
  251 + 'ilike',
  252 + ProductLang::tableName() . '.title',
  253 + $param,
  254 + ],
  255 + [
  256 + 'ilike',
  257 + BrandLang::tableName() . '.title',
  258 + $param,
  259 + ],
  260 + [
  261 + 'ilike',
  262 + CategoryLang::tableName() . '.title',
  263 + $param,
  264 + ],
  265 + [
  266 + 'ilike',
  267 + ProductVariantLang::tableName() . '.title',
  268 + $param,
  269 + ],
  270 + ];
  271 + }
  272 + }
  273 + if (count($conditions) > 1) {
  274 + array_unshift($conditions, 'or');
  275 + } else {
  276 + $conditions = $conditions[ 0 ];
  277 + }
  278 + $query->andFilterWhere($conditions);
  279 + }
  280 +
  281 + /**
  282 + * Fill query with price limits filter
  283 + *
  284 + * @param array $params
  285 + * @param \yii\db\ActiveQuery $query
  286 + */
  287 + private static function filterPrices(array $params, ActiveQuery $query)
  288 + {
  289 + $conditions = [];
  290 + if (!empty( $params[ 'min' ] ) && $params[ 'min' ] > 0) {
  291 + $conditions[] = [
  292 + '>=',
  293 + ProductVariant::tableName() . '.price',
  294 + $params[ 'min' ],
  295 + ];
  296 + }
  297 + if (!empty( $params[ 'max' ] ) && $params[ 'max' ] > 0) {
  298 + $conditions[] = [
  299 + '<=',
  300 + ProductVariant::tableName() . '.price',
  301 + $params[ 'max' ],
  302 + ];
  303 + }
  304 + if (count($conditions) > 1) {
  305 + array_unshift($conditions, 'and');
  306 + } else {
  307 + $conditions = $conditions[ 0 ];
  308 + }
  309 + $query->andFilterWhere($conditions);
  310 + }
  311 +
  312 + }
  313 +
0 314 \ No newline at end of file
... ...
artbox-ecommerce/helpers/ProductHelper.php 0 → 100755
  1 +++ a/artbox-ecommerce/helpers/ProductHelper.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\helpers;
  4 +
  5 + use artweb\artbox\ecommerce\models\Category;
  6 + use artweb\artbox\ecommerce\models\Product;
  7 + use yii\base\Object;
  8 + use Yii;
  9 + use yii\db\ActiveQuery;
  10 + use yii\helpers\ArrayHelper;
  11 +
  12 + class ProductHelper extends Object
  13 + {
  14 +
  15 + /**
  16 + * @todo ArtboxTree
  17 + * @return array
  18 + */
  19 + public static function getCategories()
  20 + {
  21 + return Category::find()
  22 + ->getTree(null, 'lang');
  23 + }
  24 +
  25 + /**
  26 + * Add $product_id to last products in session. Limit 16 products.
  27 + *
  28 + * @param int $product_id
  29 + */
  30 + public static function addLastProducts(int $product_id)
  31 + {
  32 + $last_products = self::getLastProducts();
  33 + if (!in_array($product_id, $last_products)) {
  34 + $last_products[] = intval($product_id);
  35 + if (count($last_products) > 16) {
  36 + array_shift($last_products);
  37 + }
  38 + Yii::$app->session->set('last_products', $last_products);
  39 + }
  40 + }
  41 +
  42 + /**
  43 + * Get last products ids from session or last Product models with ProductVariant, which are in stock if
  44 + * $as_object is true
  45 + *
  46 + * @param bool $as_object
  47 + *
  48 + * @return array
  49 + */
  50 + public static function getLastProducts(bool $as_object = false)
  51 + {
  52 + $last_products = Yii::$app->session->get('last_products', []);
  53 + if ($as_object) {
  54 + $last_products = Product::find()
  55 + ->joinWith([ 'variant' ])
  56 + ->where([ 'product.id' => $last_products ])
  57 + ->andWhere(
  58 + [
  59 + '!=',
  60 + 'product_variant.stock',
  61 + 0,
  62 + ]
  63 + )
  64 + ->indexBy('id')
  65 + ->all();
  66 + }
  67 + return array_reverse($last_products);
  68 + }
  69 +
  70 + /**
  71 + * Get special Products array with ProductVariants, which are in stock
  72 + * Available types:
  73 + * * top
  74 + * * new
  75 + * * promo
  76 + *
  77 + * @param string $type
  78 + * @param int $count
  79 + *
  80 + * @return Product[]
  81 + */
  82 + public static function getSpecialProducts(string $type, int $count)
  83 + {
  84 + switch ($type) {
  85 + case 'top':
  86 + $data = [ 'is_top' => true ];
  87 + break;
  88 + case 'new':
  89 + $data = [ 'is_new' => true ];
  90 + break;
  91 + case 'promo':
  92 + $data = [ 'is_discount' => true ];
  93 + break;
  94 + default:
  95 + return [];
  96 + break;
  97 + }
  98 + return Product::find()
  99 + ->with('lang')
  100 + ->joinWith('variants.lang')
  101 + ->where($data)
  102 + ->andWhere(
  103 + [
  104 + '!=',
  105 + 'productVariant.stock',
  106 + 0,
  107 + ]
  108 + )
  109 + ->limit($count)
  110 + ->all();
  111 + }
  112 +
  113 + /**
  114 + * Get ActiveQuery to get similar products to $product
  115 + *
  116 + * @param Product $product
  117 + * @param int $count
  118 + *
  119 + * @return ActiveQuery
  120 + */
  121 + public static function getSimilarProducts(Product $product, $count = 10): ActiveQuery
  122 + {
  123 + $query = Product::find();
  124 + if (empty( $product->properties )) {
  125 + $query->where('0 = 1');
  126 + return $query;
  127 + }
  128 + $query->innerJoinWith('variants')
  129 + ->joinWith('categories')
  130 + ->where(
  131 + [
  132 + '!=',
  133 + 'product_variant.stock',
  134 + 0,
  135 + ]
  136 + )
  137 + ->andWhere(
  138 + [ 'product_category.category_id' => ArrayHelper::getColumn($product->categories, 'id') ]
  139 + );
  140 + $options = [];
  141 + foreach ($product->properties as $group) {
  142 + foreach ($group->options as $option) {
  143 + $options[] = $option->id;
  144 + }
  145 + }
  146 + if (!empty( $options )) {
  147 + $query->innerJoinWith('options')
  148 + ->andWhere([ 'product_option.option_id' => $options ]);
  149 + } else {
  150 + $query->where('0 = 1');
  151 + return $query;
  152 + }
  153 + $query->andWhere(
  154 + [
  155 + '!=',
  156 + 'product.id',
  157 + $product->id,
  158 + ]
  159 + );
  160 + $query->groupBy('product.id');
  161 + $query->limit($count);
  162 + return $query;
  163 + }
  164 +
  165 + /**
  166 + * Add last category id to session
  167 + *
  168 + * @param int $category_id
  169 + */
  170 + public static function addLastCategory(int $category_id)
  171 + {
  172 + \Yii::$app->session->set('last_category_id', $category_id);
  173 + }
  174 +
  175 + /**
  176 + * Get last category id from session
  177 + *
  178 + * @return int
  179 + */
  180 + public static function getLastCategory(): int
  181 + {
  182 + return \Yii::$app->session->get('last_category_id');
  183 + }
  184 + }
0 185 \ No newline at end of file
... ...
artbox-ecommerce/models/Brand.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Brand.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\SaveImgBehavior;
  6 + use common\modules\language\behaviors\LanguageBehavior;
  7 + use Yii;
  8 + use yii\db\ActiveQuery;
  9 + use yii\db\ActiveRecord;
  10 + use yii\web\Request;
  11 +
  12 + /**
  13 + * This is the model class for table "brand".
  14 + *
  15 + * @property integer $id
  16 + * @property string $image
  17 + * @property bool $in_menu
  18 + * @property Product[] $products
  19 + * @property string $remote_id
  20 + * * From language behavior *
  21 + * @property BrandLang $lang
  22 + * @property BrandLang[] $langs
  23 + * @property BrandLang $objectLang
  24 + * @property string $ownerKey
  25 + * @property string $langKey
  26 + * @property BrandLang[] $modelLangs
  27 + * @property bool $transactionStatus
  28 + * @method string getOwnerKey()
  29 + * @method void setOwnerKey( string $value )
  30 + * @method string getLangKey()
  31 + * @method void setLangKey( string $value )
  32 + * @method ActiveQuery getLangs()
  33 + * @method ActiveQuery getLang( integer $language_id )
  34 + * @method BrandLang[] generateLangs()
  35 + * @method void loadLangs( Request $request )
  36 + * @method bool linkLangs()
  37 + * @method bool saveLangs()
  38 + * @method bool getTransactionStatus()
  39 + * * End language behavior *
  40 + * * From SaveImgBehavior
  41 + * @property string|null $imageFile
  42 + * @property string|null $imageUrl
  43 + * @method string|null getImageFile( int $field )
  44 + * @method string|null getImageUrl( int $field )
  45 + * * End SaveImgBehavior
  46 + */
  47 + class Brand extends ActiveRecord
  48 + {
  49 + /**
  50 + * @inheritdoc
  51 + */
  52 + public static function tableName()
  53 + {
  54 + return 'brand';
  55 + }
  56 +
  57 + public function behaviors()
  58 + {
  59 + return [
  60 + [
  61 + 'class' => SaveImgBehavior::className(),
  62 + 'fields' => [
  63 + [
  64 + 'name' => 'image',
  65 + 'directory' => 'brand',
  66 + ],
  67 + ],
  68 + ],
  69 + 'language' => [
  70 + 'class' => LanguageBehavior::className(),
  71 + ],
  72 + ];
  73 + }
  74 +
  75 + /**
  76 + * @inheritdoc
  77 + */
  78 + public function rules()
  79 + {
  80 + return [
  81 + [
  82 + [ 'in_menu' ],
  83 + 'boolean',
  84 + ],
  85 + ];
  86 + }
  87 +
  88 + /**
  89 + * @inheritdoc
  90 + */
  91 + public function attributeLabels()
  92 + {
  93 + return [
  94 + 'id' => Yii::t('product', 'Brand ID'),
  95 + 'image' => Yii::t('product', 'Image'),
  96 + ];
  97 + }
  98 +
  99 + /**
  100 + * Get all products with current brand
  101 + *
  102 + * @return \yii\db\ActiveQuery
  103 + */
  104 + public function getProducts()
  105 + {
  106 + return $this->hasMany(Product::className(), [ 'brand_id' => 'id' ]);
  107 + }
  108 + }
... ...
artbox-ecommerce/models/BrandLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/BrandLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "brand_lang".
  11 + *
  12 + * @property integer $brand_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property string $meta_title
  16 + * @property string $meta_robots
  17 + * @property string $meta_description
  18 + * @property string $seo_text
  19 + * @property string $alias
  20 + * @property Brand $brand
  21 + * @property Language $language
  22 + */
  23 + class BrandLang extends ActiveRecord
  24 + {
  25 +
  26 + public static function primaryKey()
  27 + {
  28 + return [
  29 + 'brand_id',
  30 + 'language_id',
  31 + ];
  32 + }
  33 +
  34 + /**
  35 + * @inheritdoc
  36 + */
  37 + public static function tableName()
  38 + {
  39 + return 'brand_lang';
  40 + }
  41 +
  42 + public function behaviors()
  43 + {
  44 + return [
  45 + 'slug' => [
  46 + 'class' => 'common\behaviors\Slug',
  47 + ],
  48 + ];
  49 + }
  50 +
  51 + /**
  52 + * @inheritdoc
  53 + */
  54 + public function rules()
  55 + {
  56 + return [
  57 + [
  58 + [ 'title' ],
  59 + 'required',
  60 + ],
  61 + [
  62 + [ 'seo_text' ],
  63 + 'string',
  64 + ],
  65 + [
  66 + [
  67 + 'title',
  68 + 'meta_title',
  69 + 'meta_robots',
  70 + 'meta_description',
  71 + 'alias',
  72 + ],
  73 + 'string',
  74 + 'max' => 255,
  75 + ],
  76 + [
  77 + [
  78 + 'brand_id',
  79 + 'language_id',
  80 + ],
  81 + 'unique',
  82 + 'targetAttribute' => [
  83 + 'brand_id',
  84 + 'language_id',
  85 + ],
  86 + 'message' => 'The combination of Brand ID and Language ID has already been taken.',
  87 + ],
  88 + [
  89 + [ 'brand_id' ],
  90 + 'exist',
  91 + 'skipOnError' => true,
  92 + 'targetClass' => Brand::className(),
  93 + 'targetAttribute' => [ 'brand_id' => 'id' ],
  94 + ],
  95 + [
  96 + [ 'language_id' ],
  97 + 'exist',
  98 + 'skipOnError' => true,
  99 + 'targetClass' => Language::className(),
  100 + 'targetAttribute' => [ 'language_id' => 'id' ],
  101 + ],
  102 + ];
  103 + }
  104 +
  105 + /**
  106 + * @inheritdoc
  107 + */
  108 + public function attributeLabels()
  109 + {
  110 + return [
  111 + 'brand_id' => Yii::t('app', 'Brand ID'),
  112 + 'language_id' => Yii::t('app', 'Language ID'),
  113 + 'title' => Yii::t('app', 'Name'),
  114 + 'meta_title' => Yii::t('app', 'Meta Title'),
  115 + 'meta_robots' => Yii::t('app', 'Meta Robots'),
  116 + 'meta_description' => Yii::t('app', 'Meta Desc'),
  117 + 'seo_text' => Yii::t('app', 'Seo Text'),
  118 + 'alias' => Yii::t('app', 'Alias'),
  119 + ];
  120 + }
  121 +
  122 + /**
  123 + * @return \yii\db\ActiveQuery
  124 + */
  125 + public function getBrand()
  126 + {
  127 + return $this->hasOne(Brand::className(), [ 'id' => 'brand_id' ]);
  128 + }
  129 +
  130 + /**
  131 + * @return \yii\db\ActiveQuery
  132 + */
  133 + public function getLanguage()
  134 + {
  135 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  136 + }
  137 + }
... ...
artbox-ecommerce/models/BrandSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/BrandSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * BrandSearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\Brand`.
  11 + */
  12 + class BrandSearch extends Brand
  13 + {
  14 +
  15 + public $brandName;
  16 +
  17 + /**
  18 + * @inheritdoc
  19 + */
  20 + public function rules()
  21 + {
  22 + return [
  23 + [
  24 + [ 'brandName' ],
  25 + 'safe',
  26 + ],
  27 + [
  28 + [ 'id' ],
  29 + 'integer',
  30 + ],
  31 + ];
  32 + }
  33 +
  34 + public function behaviors()
  35 + {
  36 + return [];
  37 + }
  38 +
  39 + /**
  40 + * @inheritdoc
  41 + */
  42 + public function scenarios()
  43 + {
  44 + // bypass scenarios() implementation in the parent class
  45 + return Model::scenarios();
  46 + }
  47 +
  48 + /**
  49 + * Creates data provider instance with search query applied
  50 + *
  51 + * @param array $params
  52 + *
  53 + * @return ActiveDataProvider
  54 + */
  55 + public function search($params)
  56 + {
  57 + $query = Brand::find()
  58 + ->joinWith('lang');
  59 +
  60 + // add conditions that should always apply here
  61 +
  62 + $dataProvider = new ActiveDataProvider(
  63 + [
  64 + 'query' => $query,
  65 + ]
  66 + );
  67 +
  68 + $this->load($params);
  69 +
  70 + /*if (!$this->validate()) {
  71 + // uncomment the following line if you do not want to return any records when validation fails
  72 + // $query->where('0=1');
  73 + return $dataProvider;
  74 + }*/
  75 +
  76 + $dataProvider->setSort(
  77 + [
  78 + 'attributes' => [
  79 + 'id',
  80 + 'brandName' => [
  81 + 'asc' => [ 'brand_lang.title' => SORT_ASC ],
  82 + 'desc' => [ 'brand_lang.title' => SORT_DESC ],
  83 + ],
  84 + ],
  85 + ]
  86 + );
  87 +
  88 + // grid filtering conditions
  89 + $query->andFilterWhere(
  90 + [
  91 + 'brand.id' => $this->id,
  92 + ]
  93 + )
  94 + ->andFilterWhere(
  95 + [
  96 + 'ilike',
  97 + 'brand_lang.title',
  98 + $this->brandName,
  99 + ]
  100 + );
  101 +
  102 + return $dataProvider;
  103 + }
  104 + }
... ...
artbox-ecommerce/models/Category.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Category.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\SaveImgBehavior;
  6 + use common\components\artboxtree\ArtboxTreeBehavior;
  7 + use common\modules\language\behaviors\LanguageBehavior;
  8 + use common\modules\language\models\Language;
  9 + use artweb\artbox\ecommerce\models\TaxGroup;
  10 + use Yii;
  11 + use yii\base\InvalidParamException;
  12 + use yii\db\ActiveQuery;
  13 + use yii\db\ActiveRecord;
  14 + use yii\db\Query;
  15 + use yii\web\Request;
  16 +
  17 + /**
  18 + * This is the model class for table "category".
  19 + *
  20 + * @todo Write doc for ArtboxTreeBehavior
  21 + * @property integer $id
  22 + * @property integer $remote_id
  23 + * @property integer $parent_id
  24 + * @property string $path
  25 + * @property integer $depth
  26 + * @property string $image
  27 + * @property integer $product_unit_id
  28 + * @property Product[] $products
  29 + * @property ProductUnit $productUnit
  30 + * @property ProductCategory[] $productCategories
  31 + * @property Brand[] $brands
  32 + * @property TaxGroup[] $taxGroups
  33 + * * From language behavior *
  34 + * @property CategoryLang $lang
  35 + * @property CategoryLang[] $langs
  36 + * @property CategoryLang $objectLang
  37 + * @property string $ownerKey
  38 + * @property string $langKey
  39 + * @property CategoryLang[] $modelLangs
  40 + * @property bool $transactionStatus
  41 + * @method string getOwnerKey()
  42 + * @method void setOwnerKey( string $value )
  43 + * @method string getLangKey()
  44 + * @method void setLangKey( string $value )
  45 + * @method ActiveQuery getLangs()
  46 + * @method ActiveQuery getLang( integer $language_id )
  47 + * @method CategoryLang[] generateLangs()
  48 + * @method void loadLangs( Request $request )
  49 + * @method bool linkLangs()
  50 + * @method bool saveLangs()
  51 + * @method bool getTransactionStatus()
  52 + * * End language behavior *
  53 + * * From SaveImgBehavior
  54 + * @property string|null $imageFile
  55 + * @property string|null $imageUrl
  56 + * @method string|null getImageFile( int $field )
  57 + * @method string|null getImageUrl( int $field )
  58 + * * End SaveImgBehavior
  59 + */
  60 + class Category extends ActiveRecord
  61 + {
  62 +
  63 + public function behaviors()
  64 + {
  65 + return [
  66 + 'artboxtree' => [
  67 + 'class' => ArtboxTreeBehavior::className(),
  68 + 'keyNameGroup' => null,
  69 + 'keyNamePath' => 'path',
  70 + ],
  71 + 'language' => [
  72 + 'class' => LanguageBehavior::className(),
  73 + ],
  74 + [
  75 + 'class' => SaveImgBehavior::className(),
  76 + 'fields' => [
  77 + [
  78 + 'name' => 'image',
  79 + 'directory' => 'categories',
  80 + ],
  81 + ],
  82 + ],
  83 + ];
  84 + }
  85 +
  86 + /**
  87 + * @inheritdoc
  88 + */
  89 + public static function tableName()
  90 + {
  91 + return 'category';
  92 + }
  93 +
  94 + /**
  95 + * @inheritdoc
  96 + */
  97 + public function rules()
  98 + {
  99 + return [
  100 + [
  101 + [
  102 + 'parent_id',
  103 + 'depth',
  104 + 'product_unit_id',
  105 + ],
  106 + 'integer',
  107 + ],
  108 + [
  109 + [
  110 + 'path',
  111 + ],
  112 + 'string',
  113 + ],
  114 + ];
  115 + }
  116 +
  117 + /**
  118 + * @inheritdoc
  119 + */
  120 + public function attributeLabels()
  121 + {
  122 + return [
  123 + 'id' => Yii::t('product', 'Category ID'),
  124 + 'parent_id' => Yii::t('product', 'Parent ID'),
  125 + 'path' => Yii::t('product', 'Path'),
  126 + 'depth' => Yii::t('product', 'Depth'),
  127 + 'image' => Yii::t('product', 'Image'),
  128 + 'imageUrl' => Yii::t('product', 'Image'),
  129 + 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
  130 + 'remote_id' => Yii::t('product', 'Remote ID'),
  131 + ];
  132 + }
  133 +
  134 + public static function find()
  135 + {
  136 + return new CategoryQuery(get_called_class());
  137 + }
  138 +
  139 + /**
  140 + * @return \yii\db\ActiveQuery
  141 + */
  142 + public function getProductUnit()
  143 + {
  144 + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]);
  145 + }
  146 +
  147 + /**
  148 + * @return ActiveQuery
  149 + */
  150 + public function getProducts()
  151 + {
  152 + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ])
  153 + ->viaTable('product_category', [ 'category_id' => 'id' ]);
  154 + }
  155 +
  156 + /**
  157 + * @return \yii\db\ActiveQuery
  158 + */
  159 + public function getProductCategories()
  160 + {
  161 + return $this->hasMany(ProductCategory::className(), [ 'category_id' => 'id' ]);
  162 + }
  163 +
  164 + /**
  165 + * Get all brands for Category query
  166 + *
  167 + * @return ActiveQuery
  168 + */
  169 + public function getBrands()
  170 + {
  171 + return $this->hasMany(Brand::className(), [ 'id' => 'brand_id' ])
  172 + ->via('products');
  173 + }
  174 +
  175 + /**
  176 + * Get Tax Groups by level
  177 + * * 0 for Product
  178 + * * 1 for ProductVariant
  179 + *
  180 + * @param int $level
  181 + *
  182 + * @return ActiveQuery
  183 + */
  184 + public function getTaxGroupsByLevel(int $level)
  185 + {
  186 + if ($level !== 0 || $level !== 1) {
  187 + throw new InvalidParamException('Level supports only 0 and 1 values');
  188 + }
  189 + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ])
  190 + ->viaTable('tax_group_to_category', [ 'category_id' => 'id' ])
  191 + ->andWhere([ 'level' => $level ]);
  192 + }
  193 +
  194 + /**
  195 + * Леша найди путь как убрать это, мб в базу записать просто по умолчанию значение и notnull
  196 + *
  197 + * @param bool $insert
  198 + *
  199 + * @return bool
  200 + */
  201 + public function beforeSave($insert)
  202 + {
  203 + if (parent::beforeSave($insert)) {
  204 +
  205 + if (empty( $this->parent_id )) {
  206 + $this->parent_id = 0;
  207 + }
  208 +
  209 + return true;
  210 + }
  211 + return false;
  212 + }
  213 +
  214 + /**
  215 + * Get query for activefilter for current category
  216 + *
  217 + * @return Query
  218 + */
  219 + public function getActiveFilters()
  220 + {
  221 + $language_id = Language::getCurrent()->id;
  222 + $query1 = ( new Query() )->distinct()
  223 + ->select(
  224 + [
  225 + 'option_id',
  226 + ]
  227 + )
  228 + ->from('tax_option')
  229 + ->innerJoin(
  230 + 'product_variant_option',
  231 + 'tax_option.id = product_variant_option.option_id'
  232 + )
  233 + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id')
  234 + ->innerJoin(
  235 + 'product_variant',
  236 + 'product_variant.id = product_variant_option.product_variant_id'
  237 + )
  238 + ->innerJoin('product', 'product.id = product_variant.product_id')
  239 + ->innerJoin('product_category', 'product_category.product_id = product.id')
  240 + ->where(
  241 + [
  242 + 'product_category.category_id' => $this->id,
  243 + 'tax_group.is_filter' => true,
  244 + ]
  245 + )
  246 + ->andWhere(
  247 + [
  248 + '!=',
  249 + 'product_variant.stock',
  250 + 0,
  251 + ]
  252 + );
  253 +
  254 + $query2 = ( new Query() )->distinct()
  255 + ->select(
  256 + [
  257 + 'option_id',
  258 + ]
  259 + )
  260 + ->from('tax_option')
  261 + ->innerJoin(
  262 + 'product_option',
  263 + 'tax_option.id = product_option.option_id'
  264 + )
  265 + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id')
  266 + ->innerJoin('product', 'product.id = product_option.product_id')
  267 + ->innerJoin('product_category', 'product_category.product_id = product.id')
  268 + ->innerJoin('product_variant', 'product_variant.product_id = product.id')
  269 + ->where(
  270 + [
  271 + 'product_category.category_id' => $this->id,
  272 + 'tax_group.is_filter' => true,
  273 + ]
  274 + )
  275 + ->andWhere(
  276 + [
  277 + '!=',
  278 + 'product_variant.stock',
  279 + 0,
  280 + ]
  281 + );
  282 + $query3 = ( new Query() )->select(
  283 + [
  284 + 'tax_option.*',
  285 + 'tax_option_lang.alias as option_alias',
  286 + 'tax_group_lang.alias as group_alias',
  287 + 'tax_option_lang.value as value',
  288 + 'tax_option.sort AS tax_option_sort',
  289 + 'tax_group.sort AS tax_group_sort',
  290 + ]
  291 + )
  292 + ->from([ 'tax_option' ])
  293 + ->where([ 'tax_option.id' => $query1->union($query2) ])
  294 + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id')
  295 + ->innerJoin('tax_option_lang', 'tax_option.id = tax_option_lang.tax_option_id')
  296 + ->innerJoin('tax_group_lang', 'tax_group.id = tax_group_lang.tax_group_id')
  297 + ->andWhere([ 'tax_option_lang.language_id' => $language_id ])
  298 + ->andWhere([ 'tax_group_lang.language_id' => $language_id ])
  299 + ->orderBy('tax_option.sort, tax_group.sort');
  300 + return $query3;
  301 + }
  302 +
  303 + /**
  304 + * Get query to get all TaxGroup for current Category
  305 + *
  306 + * @return ActiveQuery
  307 + */
  308 + public function getTaxGroups()
  309 + {
  310 + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ])
  311 + ->viaTable('tax_group_to_category', [ 'category_id' => 'id' ]);
  312 + }
  313 + }
... ...
artbox-ecommerce/models/CategoryLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/CategoryLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "category_lang".
  11 + * @property integer $category_id
  12 + * @property integer $language_id
  13 + * @property string $title
  14 + * @property string $meta_title
  15 + * @property string $meta_robots
  16 + * @property string $meta_description
  17 + * @property string $seo_text
  18 + * @property string $h1
  19 + * @property Category $category
  20 + * @property Language $language
  21 + */
  22 + class CategoryLang extends ActiveRecord
  23 + {
  24 +
  25 + public static function primaryKey()
  26 + {
  27 + return [
  28 + 'category_id',
  29 + 'language_id',
  30 + ];
  31 + }
  32 +
  33 + /**
  34 + * @inheritdoc
  35 + */
  36 + public static function tableName()
  37 + {
  38 + return 'category_lang';
  39 + }
  40 +
  41 + public function behaviors()
  42 + {
  43 + return [
  44 + 'slug' => [
  45 + 'class' => 'common\behaviors\Slug',
  46 + ],
  47 + ];
  48 + }
  49 +
  50 + /**
  51 + * @inheritdoc
  52 + */
  53 + public function rules()
  54 + {
  55 + return [
  56 + [
  57 + [ 'title' ],
  58 + 'required',
  59 + ],
  60 + [
  61 + [
  62 + 'seo_text',
  63 + 'alias',
  64 + ],
  65 + 'string',
  66 + ],
  67 + [
  68 + [
  69 + 'title',
  70 + 'meta_title',
  71 + 'meta_robots',
  72 + 'meta_description',
  73 + 'h1',
  74 + ],
  75 + 'string',
  76 + 'max' => 255,
  77 + ],
  78 + [
  79 + [
  80 + 'category_id',
  81 + 'language_id',
  82 + ],
  83 + 'unique',
  84 + 'targetAttribute' => [
  85 + 'category_id',
  86 + 'language_id',
  87 + ],
  88 + 'message' => 'The combination of Category ID and Language ID has already been taken.',
  89 + ],
  90 + [
  91 + [ 'category_id' ],
  92 + 'exist',
  93 + 'skipOnError' => true,
  94 + 'targetClass' => Category::className(),
  95 + 'targetAttribute' => [ 'category_id' => 'id' ],
  96 + ],
  97 + [
  98 + [ 'language_id' ],
  99 + 'exist',
  100 + 'skipOnError' => true,
  101 + 'targetClass' => Language::className(),
  102 + 'targetAttribute' => [ 'language_id' => 'id' ],
  103 + ],
  104 + ];
  105 + }
  106 +
  107 + /**
  108 + * @inheritdoc
  109 + */
  110 + public function attributeLabels()
  111 + {
  112 + return [
  113 + 'category_id' => Yii::t('app', 'Category ID'),
  114 + 'language_id' => Yii::t('app', 'Language ID'),
  115 + 'title' => Yii::t('app', 'Name'),
  116 + 'meta_title' => Yii::t('app', 'Meta Title'),
  117 + 'meta_robots' => Yii::t('app', 'Meta Robots'),
  118 + 'meta_description' => Yii::t('app', 'Meta Desc'),
  119 + 'seo_text' => Yii::t('app', 'Seo Text'),
  120 + 'h1' => Yii::t('app', 'H1'),
  121 + ];
  122 + }
  123 +
  124 + /**
  125 + * @return \yii\db\ActiveQuery
  126 + */
  127 + public function getCategory()
  128 + {
  129 + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]);
  130 + }
  131 +
  132 + /**
  133 + * @return \yii\db\ActiveQuery
  134 + */
  135 + public function getLanguage()
  136 + {
  137 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  138 + }
  139 + }
... ...
artbox-ecommerce/models/CategoryQuery.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/CategoryQuery.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\components\artboxtree\ArtboxTreeQueryTrait;
  6 + use yii\db\ActiveQuery;
  7 +
  8 + /**
  9 + * This is the ActiveQuery class for [[Category]].
  10 + *
  11 + * @see Category
  12 + */
  13 + class CategoryQuery extends ActiveQuery
  14 + {
  15 + use ArtboxTreeQueryTrait;
  16 +
  17 + /**
  18 + * @inheritdoc
  19 + * @return Category[]|array
  20 + */
  21 + public function all($db = null)
  22 + {
  23 + return parent::all($db);
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + * @return Category|array|null
  29 + */
  30 + public function one($db = null)
  31 + {
  32 + return parent::one($db);
  33 + }
  34 + }
... ...
artbox-ecommerce/models/CategorySearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/CategorySearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * CategorySearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\Category`.
  11 + */
  12 + class CategorySearch extends Category
  13 + {
  14 +
  15 + public $categoryName;
  16 +
  17 + public function behaviors()
  18 + {
  19 + return [];
  20 + }
  21 +
  22 + /**
  23 + * @inheritdoc
  24 + */
  25 + public function rules()
  26 + {
  27 + return [
  28 + [
  29 + [ 'categoryName' ],
  30 + 'safe',
  31 + ],
  32 + [
  33 + [ 'id' ],
  34 + 'integer',
  35 + ],
  36 + ];
  37 + }
  38 +
  39 + /**
  40 + * @inheritdoc
  41 + */
  42 + public function scenarios()
  43 + {
  44 + // bypass scenarios() implementation in the parent class
  45 + return Model::scenarios();
  46 + }
  47 +
  48 + /**
  49 + * Creates data provider instance with search query applied
  50 + *
  51 + * @param array $params
  52 + *
  53 + * @return ActiveDataProvider
  54 + */
  55 + public function search($params)
  56 + {
  57 + $query = Category::find()
  58 + ->joinWith('lang');
  59 +
  60 + $dataProvider = new ActiveDataProvider(
  61 + [
  62 + 'query' => $query,
  63 + 'sort' => false,
  64 + ]
  65 + );
  66 +
  67 + $this->load($params);
  68 +
  69 + /*if (!$this->validate()) {
  70 + // uncomment the following line if you do not want to return any records when validation fails
  71 + // $query->where('0=1');
  72 + return $dataProvider;
  73 + }*/
  74 +
  75 + // grid filtering conditions
  76 + $query->andFilterWhere(
  77 + [
  78 + 'category.id' => $this->id,
  79 + ]
  80 + )
  81 + ->andFilterWhere(
  82 + [
  83 + 'ilike',
  84 + 'category_lang.title',
  85 + $this->categoryName,
  86 + ]
  87 + );
  88 +
  89 + $query->orderBy(
  90 + [
  91 + 'category.path' => SORT_ASC,
  92 + 'category.depth' => SORT_ASC,
  93 + 'category.id' => SORT_ASC,
  94 + ]
  95 + );
  96 +
  97 + return $dataProvider;
  98 + }
  99 + }
... ...
artbox-ecommerce/models/Export.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Export.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use artweb\artbox\ecommerce\models\TaxOption;
  7 + use yii\base\Model;
  8 +
  9 + class Export extends Model
  10 + {
  11 + /**
  12 + * Language ID to export language tables
  13 + *
  14 + * @var int $lang
  15 + */
  16 + public $lang;
  17 +
  18 + public $file;
  19 +
  20 + public $errors = [];
  21 +
  22 + public $output = [];
  23 +
  24 + /**
  25 + * @inheritdoc
  26 + */
  27 + public function rules()
  28 + {
  29 + return [
  30 + [
  31 + 'lang',
  32 + 'integer',
  33 + ],
  34 + [
  35 + 'lang',
  36 + 'default',
  37 + 'value' => Language::getCurrent()->id,
  38 + ],
  39 + ];
  40 + }
  41 +
  42 + /**
  43 + * Perform product export
  44 + *
  45 + * @param null|string $filename Export csv file name
  46 + * @param int $from Product start
  47 + *
  48 + * @return array
  49 + */
  50 + public function process($filename = null, $from = 0)
  51 + {
  52 + $limit = 100;
  53 +
  54 + if (empty( $filename )) {
  55 + $filename = 'products_' . date('d_m_Y_H_i') . '.csv';
  56 + $handle = fopen(\Yii::getAlias('@storage/sync/') . $filename, "w");
  57 + } else {
  58 + $handle = fopen(\Yii::getAlias('@storage/sync/') . $filename, "a");
  59 + }
  60 +
  61 + $language = Language::findOne(\Yii::$app->session->get('export_lang', Language::getDefaultLanguage()->id));
  62 + Language::setCurrent($language->url);
  63 +
  64 + /**
  65 + * @var Product[] $products
  66 + */
  67 + $products = Product::find()
  68 + ->with('variantsWithFilters', 'brand.lang', 'categories.lang', 'filters', 'images')
  69 + ->joinWith('lang', true, 'INNER JOIN')
  70 + ->limit($limit)
  71 + ->offset($from)
  72 + ->all();
  73 + $filesize = Product::find()
  74 + ->joinWith('lang', true, 'INNER JOIN')
  75 + ->count();
  76 + foreach ($products as $product) {
  77 + $mods = [];
  78 + $filterString = $this->convertFilterToString($product->filters);
  79 +
  80 + foreach ($product->variantsWithFilters as $variant) {
  81 + /**
  82 + * @var ProductVariant $variant
  83 + */
  84 + $color = $variant->lang->title;
  85 + $mods[] = $variant->sku . $this->generateID(
  86 + $variant->remote_id
  87 + ) . '=' . $this->convertFilterToString(
  88 + $variant->filters
  89 + ) . '=' . $color . '=' . ( ( !empty( $variant->image ) ) ? $variant->image->image : '' ) . '=' . $variant->stock;
  90 + }
  91 +
  92 + $fotos = [];
  93 + foreach ($product->images as $image) {
  94 + $fotos[] = $image->image;
  95 + }
  96 +
  97 + $categories = [];
  98 + foreach ($product->categories as $value) {
  99 + $categories[] = $value->lang->title . $this->generateID($value->remote_id);
  100 + }
  101 +
  102 + $categories = implode(',', $categories);
  103 +
  104 + $list = [
  105 + $categories,
  106 + //A - категории через запятую Название(remote_id)
  107 + ( ( !empty( $product->brand ) ) ? $product->brand->lang->title . $this->generateID(
  108 + $product->brand->remote_id
  109 + ) : '' ),
  110 + //B - бренд Название(remote_id)
  111 + $product->lang->title . $this->generateID($product->remote_id),
  112 + //C - название товара Название(remote_id)
  113 + ( ( !empty( $product->lang->description ) ) ? $product->lang->description : '' ),
  114 + //D - описание товара Описание(remote_id)
  115 + $filterString,
  116 + //E - характеристики товара. Структура: [Группа1(remote_id):Характеристика11(remote_id),Характеристика12(remote_id)]*[Группа2(remote_id):Характеристика21(remote_id),Характеристика22(remote_id)]
  117 + ( !empty( $product->variant ) ) ? $product->variant->price_old : '',
  118 + //F - страрая цена
  119 + ( !empty( $product->variant ) ) ? $product->variant->price : '',
  120 + //G - новая цена
  121 + intval($product->is_discount),
  122 + //H - товар акционный (1/0)
  123 + '',
  124 + //I - пустой
  125 + intval($product->is_new),
  126 + //J - товар новинка
  127 + intval($product->is_top),
  128 + //K - товар в топе
  129 + $product->video,
  130 + //L - ссылка на видео (iframe)
  131 + implode(',', $fotos),
  132 + //M - название файлов через запятую, картинки должны хранится в /storage/sync/product_images
  133 + // Все последующие модификации: SKU(remote_id)=[Группа1(remote_id):Характеристика11(remote_id),Характеристика12(remote_id)]*[Группа2(remote_id):Характеристика21(remote_id),Характеристика22(remote_id)]=Название=Изображение=Остаток
  134 + ];
  135 + $to_write = array_merge($list, $mods);
  136 + fputcsv($handle, $to_write, ';');
  137 + unset( $product );
  138 + }
  139 +
  140 + fclose($handle);
  141 +
  142 + $from += $limit;
  143 + $end = false;
  144 + if ($from > $filesize) {
  145 + $end = true;
  146 + }
  147 +
  148 + $result = [
  149 + 'end' => $end,
  150 + 'from' => $from,
  151 + 'totalsize' => $filesize,
  152 + 'filename' => $filename,
  153 + ];
  154 +
  155 + if ($end) {
  156 + $result = array_merge(
  157 + $result,
  158 + [
  159 + 'link' => '/storage/sync/' . $filename,
  160 + ]
  161 + );
  162 + }
  163 +
  164 + return $result;
  165 + }
  166 +
  167 + /**
  168 + * Stringify filters for export
  169 + * * Result: [filterName1:filterValue11,filterValue12]*[filterName2:filterValue21,filterValue22]
  170 + *
  171 + * @param $filters
  172 + *
  173 + * @return string
  174 + */
  175 + public function convertFilterToString($filters)
  176 + {
  177 + $filtersArray = [];
  178 + /**
  179 + * @var TaxOption[] $filters
  180 + */
  181 + foreach ($filters as $filter) {
  182 + $filtersArray[ $filter->taxGroup->lang->title . $this->generateID(
  183 + $filter->taxGroup->remote_id
  184 + ) ][] = $filter->lang->value . $this->generateID($filter->remote_id);
  185 + }
  186 + $filterString = [];
  187 +
  188 + foreach ($filtersArray as $filterName => $filterRows) {
  189 + $row = implode(',', $filterRows);
  190 + $filterString[] = "[{$filterName}:{$row}]";
  191 + }
  192 + return implode('*', $filterString);
  193 + }
  194 +
  195 + /**
  196 + * Generate remote ID string
  197 + *
  198 + * @param string $id Remote ID
  199 + *
  200 + * @return string Formatted remote ID
  201 + */
  202 + private function generateID(string $id):string
  203 + {
  204 + return sprintf('(#%s#)', $id);
  205 + }
  206 + }
  207 +
0 208 \ No newline at end of file
... ...
artbox-ecommerce/models/Import.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Import.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use artweb\artbox\ecommerce\models\TaxGroup;
  7 + use artweb\artbox\ecommerce\models\TaxOption;
  8 + use Yii;
  9 + use yii\base\Model;
  10 + use yii\helpers\ArrayHelper;
  11 +
  12 + /**
  13 + * Class Import
  14 + *
  15 + * @package artweb\artbox\ecommerce\models
  16 + */
  17 + class Import extends Model
  18 + {
  19 + /**
  20 + * Import csv file
  21 + *
  22 + * @var string $file
  23 + */
  24 + public $file;
  25 +
  26 + /**
  27 + * Import type
  28 + * * product
  29 + * * price
  30 + *
  31 + * @var string $type
  32 + */
  33 + public $type;
  34 +
  35 + /**
  36 + * Import language ID
  37 + *
  38 + * @var int $lang
  39 + */
  40 + public $lang;
  41 +
  42 + public $errors = [];
  43 +
  44 + public $output = [];
  45 +
  46 + /**
  47 + * @inheritdoc
  48 + */
  49 + public function rules()
  50 + {
  51 + return [
  52 + [
  53 + [
  54 + 'type',
  55 + 'lang',
  56 + ],
  57 + 'required',
  58 + ],
  59 + [
  60 + [ 'lang' ],
  61 + 'integer',
  62 + ],
  63 + [
  64 + [ 'type' ],
  65 + 'string',
  66 + ],
  67 + [
  68 + [ 'file' ],
  69 + 'file',
  70 + 'extensions' => 'csv',
  71 + ],
  72 + ];
  73 + }
  74 +
  75 + /**
  76 + * @inheritdoc
  77 + */
  78 + public function attributeLabels()
  79 + {
  80 + return [
  81 + 'file' => Yii::t('product', 'File'),
  82 + ];
  83 + }
  84 +
  85 + /**
  86 + * Get import type
  87 + *
  88 + * @see Import::type
  89 + * @return string
  90 + */
  91 + public function getType()
  92 + {
  93 + if (!$this->type) {
  94 + $this->type = 'products';
  95 + }
  96 + return $this->type;
  97 + }
  98 +
  99 + /**
  100 + * Import prices
  101 + *
  102 + * @param int $from Start row
  103 + * @param null $limit Row limit
  104 + *
  105 + * @return array|bool Array if OK, false otherwise
  106 + */
  107 + public function goPrices($from = 0, $limit = null)
  108 + {
  109 + set_time_limit(0);
  110 +
  111 + if (!( $handle = $this->getProductsFile('uploadFilePrices') )) {
  112 + $this->errors[] = 'File not found';
  113 + return false;
  114 + }
  115 +
  116 + $filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'));
  117 + if ($from) {
  118 + fseek($handle, $from);
  119 + }
  120 +
  121 + $j = 0;
  122 +
  123 + $is_utf = ( preg_match(
  124 + '//u',
  125 + file_get_contents(
  126 + Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'),
  127 + null,
  128 + null,
  129 + null,
  130 + 1000000
  131 + )
  132 + ) );
  133 +
  134 + while (( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) {
  135 + foreach ($data as &$value) {
  136 + if (!$is_utf) {
  137 + $value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
  138 + }
  139 + $value = trim($value);
  140 + }
  141 +
  142 + // данные строк
  143 + $modification_code = @$data[ 0 ];
  144 + $price = floatval(@$data[ 1 ]);
  145 + $price_promo = floatval(@$data[ 2 ]);
  146 + $count = intval(@$data[ 3 ]);
  147 + $city_name = @$data[ 4 ];
  148 + $product_title = @$data[ 5 ];
  149 +
  150 + if (empty ( $modification_code )) {
  151 + continue;
  152 + }
  153 + // товары в пути
  154 + if (empty ( $city_name )) {
  155 + $this->output[] = 'Товар ' . $product_title . ' в пути';
  156 + continue;
  157 + }
  158 + /**
  159 + * @var ProductVariant $productVariant
  160 + */
  161 + if (( $productVariant = ProductVariant::find()
  162 + ->filterWhere([ 'sku' => $modification_code ])
  163 + ->one() ) === null
  164 + ) {
  165 + $this->output[] = 'Для товара ' . $product_title . ' не найдено соотвествие';
  166 + continue;
  167 + }
  168 + // ===== Set stock ====
  169 + if ($city_name) {
  170 + if (( $stock = Stock::find()
  171 + ->filterWhere([ 'title' => trim($city_name) ])
  172 + ->one() ) === null
  173 + ) {
  174 + // Create stock
  175 + $stock = new Stock();
  176 + $stock->title = trim($city_name);
  177 + $stock->save(false);
  178 + }
  179 +
  180 + $productStock = ProductStock::find()
  181 + ->where(
  182 + [
  183 + 'product_variant_id' => $productVariant->id,
  184 + 'stock_id' => $stock->id,
  185 + ]
  186 + )
  187 + ->one();
  188 + if (!$productStock instanceof ProductStock) {
  189 + $productStock = new ProductStock();
  190 + $productStock->product_variant_id = $productVariant->id;
  191 + $productStock->stock_id = $stock->id;
  192 + }
  193 + $productStock->quantity = $count;
  194 +
  195 + $productStock->save(false);
  196 + $productStocks = ProductStock::find()
  197 + ->where(
  198 + [ 'product_variant_id' => $productVariant->id ]
  199 + )
  200 + ->andWhere(
  201 + [
  202 + '<>',
  203 + 'stock_id',
  204 + $stock->id,
  205 + ]
  206 + )
  207 + ->all();
  208 +
  209 + $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
  210 + } else {
  211 +
  212 + $productStocks = ProductStock::find()
  213 + ->where(
  214 + [ 'product_variant_id' => $productVariant->id ]
  215 + )
  216 + ->all();
  217 +
  218 + if ($productStocks instanceof ProductStock) {
  219 + $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
  220 + } else {
  221 + $quantity = 0;
  222 + }
  223 +
  224 + }
  225 +
  226 + if ($price_promo) {
  227 + $productVariant->price_old = $price;
  228 + $productVariant->price = $price_promo;
  229 + } else {
  230 + $productVariant->price = $price;
  231 + $productVariant->price_old = $price_promo;
  232 + }
  233 +
  234 + $productVariant->stock = $quantity;
  235 +
  236 + $productVariant->save(false);
  237 +
  238 + $this->output[] = '<span style="color:blue">Товар ' . $product_title . ' успешно сохранен</span>';
  239 + }
  240 +
  241 + $result = [
  242 + 'end' => feof($handle),
  243 + 'from' => ftell($handle),
  244 + 'totalsize' => $filesize,
  245 + 'items' => $this->output,
  246 +
  247 + ];
  248 +
  249 + fclose($handle);
  250 +
  251 + if ($result[ 'end' ]) {
  252 + unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'));
  253 + }
  254 +
  255 + return $result;
  256 + }
  257 +
  258 + /**
  259 + * Pull name and remote_id from formatted string
  260 + *
  261 + * @param string $name
  262 + *
  263 + * @return array
  264 + */
  265 + private function parseName(string $name):array
  266 + {
  267 + $pattern = '/^(?P<name>.*)(?:\(#(?P<remote_id>\w+)#\))?$/U';
  268 + $name = trim($name);
  269 + $matches = [];
  270 + if (preg_match($pattern, $name, $matches)) {
  271 + if (!isset( $matches[ 'remote_id' ] )) {
  272 + $matches[ 'remote_id' ] = '';
  273 + }
  274 + return $matches;
  275 + }
  276 + return [
  277 + 'name' => $name,
  278 + 'remote_id' => '',
  279 + ];
  280 + }
  281 +
  282 + /**
  283 + * Save categories
  284 + *
  285 + * @param array $catalog_names
  286 + *
  287 + * @return int[] Category IDs
  288 + * @throws \Exception
  289 + */
  290 + private function saveCatalog(array $catalog_names):array
  291 + {
  292 + $category_id = [];
  293 +
  294 + foreach ($catalog_names as $catalog_name) {
  295 + // ==== Set category ====
  296 + $parsed_name = $this->parseName($catalog_name);
  297 + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $category = Category::find()
  298 + ->joinWith('lang')
  299 + ->andFilterWhere(
  300 + [ 'remote_id' => $parsed_name[ 'remote_id' ] ]
  301 + )
  302 + ->one() ) !== null
  303 + ) {
  304 + if (!empty( $category->lang )) {
  305 + $category->lang->title = $parsed_name[ 'name' ];
  306 + $category->lang->save(false);
  307 + } else {
  308 + throw new \Exception(
  309 + 'Category with ID ' . $category->id . ' and lang ' . Language::getCurrent(
  310 + )->id . ' doesn\'t exist'
  311 + );
  312 + }
  313 +
  314 + } else {
  315 + // Create category
  316 + $category = new Category();
  317 + $category->generateLangs();
  318 + $category_langs = $category->modelLangs;
  319 + foreach ($category_langs as $category_lang) {
  320 + $category_lang->title = $parsed_name[ 'name' ];
  321 + }
  322 + $category->remote_id = $parsed_name[ 'remote_id' ];
  323 + $category->save(false);
  324 + }
  325 + $category_id[] = $category->id;
  326 + }
  327 + return $category_id;
  328 + }
  329 +
  330 + /**
  331 + * Save brand
  332 + *
  333 + * @param string|null $brand_name
  334 + *
  335 + * @return int|null New Brand ID if inserted or exist or null if skipped
  336 + * @throws \Exception
  337 + */
  338 + private function saveBrand(string $brand_name = null):int
  339 + {
  340 +
  341 + $parsed_name = $this->parseName($brand_name);
  342 + if (!empty( $brand_name )) {
  343 + /**
  344 + * @var Brand $brand
  345 + */
  346 + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $brand = Brand::find()
  347 + ->joinWith('lang')
  348 + ->andFilterWhere(
  349 + [ 'remote_id' => $parsed_name[ 'remote_id' ] ]
  350 + )
  351 + ->one() ) !== null
  352 + ) {
  353 + if (!empty( $brand->lang )) {
  354 + $brand->lang->title = $parsed_name[ 'name' ];
  355 + $brand->lang->save(false);
  356 + } else {
  357 + throw new \Exception(
  358 + 'Brand with ID ' . $brand->id . ' and lang ' . Language::getCurrent(
  359 + )->id . ' doesn\'t exist'
  360 + );
  361 + }
  362 + return $brand->id;
  363 + } else {
  364 + // Create brand
  365 + $brand = new Brand();
  366 + $brand->generateLangs();
  367 + $brand_langs = $brand->modelLangs;
  368 + foreach ($brand_langs as $brand_lang) {
  369 + $brand_lang->title = $parsed_name[ 'name' ];
  370 + }
  371 + $brand->remote_id = $parsed_name[ 'remote_id' ];
  372 + $brand->save(false);
  373 + return $brand->id;
  374 + }
  375 + }
  376 + return null;
  377 + }
  378 +
  379 + /**
  380 + * Save Product or ProductVariant photoes
  381 + *
  382 + * @param string[] $fotos Photoes names
  383 + * @param int $product_id
  384 + * @param int|null $product_variant_id Null if photo for Product
  385 + */
  386 + private function saveFotos(array $fotos, int $product_id, int $product_variant_id = null)
  387 + {
  388 + if (!empty( $fotos )) {
  389 + foreach ($fotos as $foto) {
  390 + if (empty( $foto )) {
  391 + continue;
  392 + }
  393 + $source_image = Yii::getAlias('@uploadDir') . '/product_images/' . urlencode($foto);
  394 + if (file_exists($source_image)) {
  395 + if (( $productImage = ProductImage::find()
  396 + ->andWhere([ 'image' => $foto ])
  397 + ->andWhere([ 'product_id' => $product_id ])
  398 + ->andFilterWhere(
  399 + [ 'product_variant_id' => $product_variant_id ]
  400 + )
  401 + ->one() ) === null
  402 + ) {
  403 + copy($source_image, Yii::getAlias('@productsDir') . "/" . $foto);
  404 + $productImage = new ProductImage();
  405 + $productImage->product_id = $product_id;
  406 + $productImage->product_variant_id = $product_variant_id;
  407 + $productImage->image = $foto;
  408 + $productImage->save(false);
  409 + }
  410 + }
  411 + }
  412 + }
  413 + }
  414 +
  415 + /**
  416 + * Save ProductVariants
  417 + *
  418 + * @param array $data ProductVariats data
  419 + * @param float $product_cost_old Old price
  420 + * @param int $product_id Product ID
  421 + * @param array $category_id Ca
  422 + * @param float|null $product_cost
  423 + *
  424 + * @return int[] Array of ProductVariants IDs
  425 + * @throws \Exception
  426 + */
  427 + private function saveVariants(
  428 + array $data,
  429 + float $product_cost_old,
  430 + int $product_id,
  431 + array $category_id,
  432 + float $product_cost = null
  433 + ):array
  434 + {
  435 + $MOD_ARRAY = [];
  436 + for ($i = 13; $i < count($data); $i++) {
  437 + if (!empty ( $data[ $i ] )) {
  438 + $mod_arr = explode('=', $data[ $i ]);
  439 + $mod_art = $mod_arr[ 0 ];
  440 + $mod_art_parsed = $this->parseName($mod_art);
  441 + $variant_filters = explode('*', $mod_arr[ 1 ]);
  442 + $mod_name = $mod_arr[ 2 ];
  443 + if (empty( $mod_name )) {
  444 + $mod_name = $mod_art_parsed[ 'name' ];
  445 + }
  446 + $mod_image = $mod_arr[ 3 ];
  447 + $mod_stock = isset( $mod_arr[ 4 ] ) ? $mod_arr[ 4 ] : 1;
  448 + $mod_cost = isset( $product_cost ) ? floatval($product_cost) : 0;
  449 + $mod_old_cost = floatval($product_cost_old);
  450 + // Check product variant
  451 + /**
  452 + * @var ProductVariant $_productVariant
  453 + */
  454 + if (( $_productVariant = ProductVariant::find()
  455 + ->joinWith('lang')
  456 + ->andFilterWhere(
  457 + [ 'remote_id' => $mod_art_parsed[ 'remote_id' ] ]
  458 + )
  459 + ->andFilterWhere(
  460 + [ 'product_variant.product_id' => $product_id ]
  461 + )
  462 + ->one() ) === null
  463 + ) {
  464 + $_productVariant = new ProductVariant();
  465 + $_productVariant->product_id = $product_id;
  466 + if (!empty( $mod_art_parsed[ 'remote_id' ] )) {
  467 + $_productVariant->remote_id = $mod_art_parsed[ 'remote_id' ];
  468 + }
  469 + $_productVariant->generateLangs();
  470 + $product_variant_langs = $_productVariant->modelLangs;
  471 + foreach ($product_variant_langs as $product_variant_lang) {
  472 + $product_variant_lang->title = $mod_name;
  473 + }
  474 + } else {
  475 + if (!empty( $_productVariant->lang )) {
  476 + $_productVariant->lang->title = $mod_name;
  477 + $_productVariant->lang->save(false);
  478 + } else {
  479 + throw new \Exception(
  480 + 'Product variant with ID ' . $_productVariant->id . ' and lang ' . Language::getCurrent(
  481 + )->id . ' doesn\'t exist'
  482 + );
  483 + }
  484 + }
  485 + $_productVariant->product_unit_id = 1;
  486 + $_productVariant->sku = $mod_art_parsed[ 'name' ];
  487 + $_productVariant->price = $mod_cost;
  488 + $_productVariant->price_old = $mod_old_cost;
  489 + $_productVariant->stock = $mod_stock;
  490 +
  491 + if (!empty ( $variant_filters )) {
  492 + $variants_options = $this->saveFilters($variant_filters, 1, $category_id);
  493 + }
  494 +
  495 + if (isset( $variants_options ) && !empty( $variants_options )) {
  496 + $_productVariant->options = $variants_options;
  497 + }
  498 +
  499 + /**
  500 + * @todo set to false
  501 + */
  502 + $_productVariant->save(false);
  503 +
  504 + $MOD_ARRAY[] = $_productVariant->id;
  505 + $this->saveFotos([ $mod_image ], $product_id, $_productVariant->id);
  506 + }
  507 + }
  508 + return $MOD_ARRAY;
  509 + }
  510 +
  511 + /**
  512 + * Perform product import
  513 + *
  514 + * @param int $from Begin row
  515 + * @param null $limit Row limit
  516 + *
  517 + * @return array|bool Array if OK, false if error
  518 + */
  519 + public function goProducts($from = 0, $limit = null)
  520 + {
  521 + set_time_limit(0);
  522 +
  523 + if (!( $handle = $this->getProductsFile('uploadFileProducts') )) {
  524 + $this->errors[] = 'File not found';
  525 + return false;
  526 + }
  527 +
  528 + $filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'));
  529 +
  530 + if ($from) {
  531 + fseek($handle, $from);
  532 + }
  533 +
  534 + $j = 0;
  535 +
  536 + $is_utf = ( preg_match(
  537 + '//u',
  538 + file_get_contents(
  539 + Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'),
  540 + null,
  541 + null,
  542 + null,
  543 + 1000000
  544 + )
  545 + ) );
  546 +
  547 + $result_items = [];
  548 +
  549 + while (( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) {
  550 + try {
  551 +
  552 + foreach ($data as &$value) {
  553 + if (!$is_utf) {
  554 + $value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
  555 + }
  556 + $value = trim($value);
  557 + }
  558 + // будет всегда 19 элементов
  559 + for ($i = 0; $i <= 18; $i++) {
  560 + if (!isset ( $data[ $i ] )) {
  561 + $data[ $i ] = null;
  562 + }
  563 + }
  564 + // 1 Группа (категория)
  565 + $catalog_names = explode(',', $data[ 0 ]);
  566 + if (empty ( $catalog_names )) {
  567 + $result_items[] = "Не указана категория (строка $j)";
  568 + continue;
  569 + }
  570 +
  571 + // 2 Бренд
  572 + $brand_name = $data[ 1 ];
  573 + // if(empty ( $brand_name )) {
  574 + // $result_items[] = "Не указан бренд (строка $j)";
  575 + // continue;
  576 + // }
  577 +
  578 + // 3 Название товара
  579 + $product_name = $data[ 2 ];
  580 + if (empty ( $product_name )) {
  581 + $result_items[] = "Не указано наименование товара (строка $j)";
  582 + continue;
  583 + }
  584 +
  585 + // 5 Описание товара
  586 + $product_body = $data[ 3 ];
  587 +
  588 + // 6 Фильтр
  589 + $filters = explode('*', $data[ 4 ]);
  590 +
  591 + // 11 Цена акция
  592 + $product_cost_old = floatval($data[ 6 ]);
  593 +
  594 + $product_cost = null;
  595 + // 10 Цена
  596 + if ($product_cost_old) {
  597 + $product_cost_old = floatval($data[ 5 ]);
  598 + $product_cost = floatval($data[ 6 ]);
  599 + }
  600 +
  601 + // 12 Акция
  602 + $product_discount = (bool) $data[ 7 ];
  603 +
  604 + // 13 Сопуд. Тов.
  605 + $similar = explode(',', $data[ 8 ]);
  606 +
  607 + // 14 Новинки
  608 + $product_new = (bool) $data[ 9 ];
  609 +
  610 + // 15 Топ продаж
  611 + $product_top = (bool) $data[ 10 ];
  612 +
  613 + // 17 ВИДЕО КОД
  614 + $product_video = $data[ 11 ];
  615 +
  616 + // 18 Галлерея фото
  617 + $fotos = [];
  618 + if (trim($data[ 12 ])) {
  619 + $fotos = explode(',', trim($data[ 12 ]));
  620 + }
  621 +
  622 + // $lang = \Yii::$app->session->get('export_lang', Language::getDefaultLanguage()->id);
  623 + // /**
  624 + // * @var Language $language
  625 + // */
  626 + // $language = Language::find()
  627 + // ->where([ 'id' => $lang ])
  628 + // ->one();
  629 + // Language::setCurrent($language->url);
  630 + $categories = $this->saveCatalog($catalog_names);
  631 +
  632 + $brand_id = $this->saveBrand($brand_name);
  633 +
  634 + $options = [];
  635 + if (!empty ( $filters )) {
  636 + $options = $this->saveFilters($filters, 0, $categories);
  637 + }
  638 + $parsed_name = $this->parseName($product_name);
  639 + /**
  640 + * @var Product $_product
  641 + */
  642 + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $_product = Product::find()
  643 + ->joinWith('lang')
  644 + ->andFilterWhere(
  645 + [ 'remote_id' => $parsed_name[ 'remote_id' ] ]
  646 + )
  647 + ->one() ) !== null
  648 + ) {
  649 + if (!empty( $_product->lang )) {
  650 + $_product->lang->title = $parsed_name[ 'name' ];
  651 + $_product->lang->description = $product_body;
  652 + $_product->lang->save(false);
  653 + } else {
  654 + throw new \Exception(
  655 + 'Product with ID ' . $_product->id . ' and lang ' . Language::getCurrent(
  656 + )->id . ' doesn\'t exist'
  657 + );
  658 + }
  659 + } else {
  660 + $_product = new Product();
  661 + $_product->generateLangs();
  662 + $product_langs = $_product->modelLangs;
  663 + foreach ($product_langs as $product_lang) {
  664 + $product_lang->title = $parsed_name[ 'name' ];
  665 + $product_lang->description = $product_body;
  666 + }
  667 + }
  668 +
  669 + $is_new_product = empty( $_product->id );
  670 +
  671 + $_product->categories = $categories;
  672 +
  673 + $_product->brand_id = $brand_id;
  674 +
  675 + $_product->video = $product_video;
  676 + $_product->is_top = $product_top;
  677 + $_product->is_discount = $product_discount;
  678 + $_product->is_new = $product_new;
  679 + if (!empty( $options )) {
  680 + $_product->options = $options;
  681 + }
  682 +
  683 + if (!empty( $_product->lang )) {
  684 + $product_name_inserted = $_product->lang->title;
  685 + } else {
  686 + $product_name_inserted = $_product->modelLangs[ Language::$current->id ]->title;
  687 + }
  688 +
  689 + if (( $_product->save(false) === false ) || !$_product->transactionStatus) {
  690 + $result_items[] = 'Product #' . $product_name_inserted . ' not saved' . " (line $j)";
  691 + continue;
  692 + }
  693 +
  694 + $this->saveFotos($fotos, $_product->id);
  695 + // нужно для проставления характеристик относящихся к модификациям
  696 +
  697 + $this->saveVariants($data, $product_cost_old, $_product->id, $_product->categories, $product_cost);
  698 +
  699 + // $_product->save(false);
  700 +
  701 + $result_items[] = "Product {$product_name_inserted} #{$_product->id} saved (" . ( $is_new_product ? 'new product' : 'exists product' ) . ")" . " (line $j)";
  702 +
  703 + } catch (\Exception $e) {
  704 + $result_items[] = $e->getMessage() . '(line ' . $j . ')';
  705 + }
  706 +
  707 + }
  708 +
  709 + $result = [
  710 + 'end' => feof($handle),
  711 + 'from' => ftell($handle),
  712 + 'totalsize' => $filesize,
  713 + 'items' => $result_items,
  714 + ];
  715 +
  716 + fclose($handle);
  717 +
  718 + if ($result[ 'end' ]) {
  719 + // unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'));
  720 + }
  721 +
  722 + return $result;
  723 + }
  724 +
  725 + /**
  726 + * Get import file
  727 + *
  728 + * @param string $file_type
  729 + *
  730 + * @return bool|resource false if File not found and file resource if OK
  731 + */
  732 + private function getProductsFile($file_type)
  733 + {
  734 + $filename = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@' . $file_type);
  735 + if (!is_file($filename)) {
  736 + $this->errors[] = "File $filename not found";
  737 + return false;
  738 + }
  739 + return fopen($filename, 'r');
  740 + }
  741 +
  742 + /**
  743 + * Save filters
  744 + *
  745 + * @param array $filters array of filters like [['pol'='мужской'],['god' =
  746 + * '2013'],['volume'='25 л']*['size'='49 x 30 x
  747 + * 20см'],['composition'='600D полиэстер']]
  748 + * @param int $level 0 for products and 1 for product variant
  749 + * @param int[] $catalog_names array catalogs id
  750 + *
  751 + * @return array
  752 + * @throws \Exception
  753 + */
  754 + private function saveFilters(array $filters, int $level, array $catalog_names):array
  755 + {
  756 + $options = [];
  757 + foreach ($filters as $filter) {
  758 +
  759 + preg_match_all('/\[(.*):(.*)\]/', $filter, $filter);
  760 +
  761 + if (empty( $filter[ 1 ][ 0 ] )) {
  762 + continue;
  763 + }
  764 + $filter_name = trim($filter[ 1 ][ 0 ]);
  765 + $parsed_group_name = $this->parseName($filter_name);
  766 +
  767 + /**
  768 + * @var TaxGroup $taxGroup
  769 + */
  770 + if (!empty( $parsed_group_name[ 'remote_id' ] ) && ( $taxGroup = TaxGroup::find()
  771 + ->joinWith('lang')
  772 + ->andFilterWhere(
  773 + [ 'remote_id' => $parsed_group_name[ 'remote_id' ] ]
  774 + )
  775 + ->one() ) !== null
  776 + ) {
  777 + if (!empty( $taxGroup->lang )) {
  778 + $taxGroup->lang->title = $parsed_group_name[ 'name' ];
  779 + $taxGroup->lang->save(false);
  780 + } else {
  781 + throw new \Exception(
  782 + 'Tax group with ID ' . $taxGroup->id . ' and lang ' . Language::getCurrent(
  783 + )->id . ' doesn\'t exist'
  784 + );
  785 + }
  786 + } else {
  787 + $taxGroup = new TaxGroup();
  788 + $taxGroup->generateLangs();
  789 + $tax_group_langs = $taxGroup->modelLangs;
  790 + foreach ($tax_group_langs as $tax_group_lang) {
  791 + $tax_group_lang->title = $parsed_group_name[ 'name' ];
  792 + }
  793 + $taxGroup->level = $level;
  794 + $taxGroup->categories = $catalog_names;
  795 + $taxGroup->is_filter = false;
  796 + $taxGroup->save(false);
  797 + }
  798 + $filters_options = explode(',', $filter[ 2 ][ 0 ]);
  799 + foreach ($filters_options as $filter_options) {
  800 + $parsed_option_name = $this->parseName($filter_options);
  801 + /**
  802 + * @var TaxOption $option
  803 + */
  804 +
  805 + if (!empty( $parsed_option_name[ 'remote_id' ] ) && ( $option = TaxOption::find()
  806 + ->joinWith('lang')
  807 + ->andFilterWhere(
  808 + [ 'remote_id' => $parsed_option_name[ 'remote_id' ] ]
  809 + )
  810 + ->andFilterWhere(
  811 + [ 'tax_group_id' => $taxGroup->id ]
  812 + )
  813 + ->one() ) !== null
  814 + ) {
  815 + if (!empty( $option->lang )) {
  816 + $option->lang->value = $parsed_option_name[ 'name' ];
  817 + $option->lang->save(false);
  818 + } else {
  819 + throw new \Exception(
  820 + 'Tax option with ID ' . $option->id . ' and lang ' . Language::getCurrent(
  821 + )->id . ' doesn\'t exist'
  822 + );
  823 + }
  824 + } else {
  825 + // Create option
  826 + $option = new TaxOption();
  827 + $option->generateLangs();
  828 + $option_langs = $option->modelLangs;
  829 + foreach ($option_langs as $option_lang) {
  830 + $option_lang->value = $parsed_option_name[ 'name' ];
  831 + }
  832 + $option->id = $taxGroup->id;
  833 + $option->save(false);
  834 + }
  835 + $options[] = $option->id;
  836 + }
  837 + }
  838 + return $options;
  839 + }
  840 + }
  841 +
0 842 \ No newline at end of file
... ...
artbox-ecommerce/models/Product.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Product.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\DefaultVariantBehavior;
  6 + use common\behaviors\MultipleImgBehavior;
  7 + use common\behaviors\SaveMultipleFileBehavior;
  8 + use common\models\ProductToRating;
  9 + use common\modules\comment\models\CommentModel;
  10 + use common\modules\language\behaviors\LanguageBehavior;
  11 + use artweb\artbox\ecommerce\models\TaxGroup;
  12 + use artweb\artbox\ecommerce\models\TaxGroupToCategory;
  13 + use artweb\artbox\ecommerce\models\TaxOption;
  14 + use Yii;
  15 + use yii\base\InvalidParamException;
  16 + use yii\db\ActiveQuery;
  17 + use yii\db\ActiveRecord;
  18 + use yii\helpers\ArrayHelper;
  19 + use yii\web\NotFoundHttpException;
  20 + use yii\web\Request;
  21 +
  22 + /**
  23 + * This is the model class for table "{{%product}}".
  24 + *
  25 + * @property integer $brand_id
  26 + * @property integer $id
  27 + * @property Category $category
  28 + * @property Category[] $categories
  29 + * @property ProductVariant $variant
  30 + * @property ProductVariant[] $variants
  31 + * @property ProductVariant $productVariant
  32 + * @property ProductVariant[] $productVariants
  33 + * @property boolean $is_top
  34 + * @property boolean $is_new
  35 + * @property boolean $is_discount
  36 + * @property ProductToRating $averageRating
  37 + * @property TaxGroup[] $properties
  38 + * @property ProductVariant $enabledVariant
  39 + * @property ProductVariant[] $enabledVariants
  40 + * @property string $video
  41 + * @property TaxOption[] $options
  42 + * @property Brand $brand
  43 + * @property TaxOption[] $filters
  44 + * @property ProductVariant[] $variantsWithFilters
  45 + * @property string $remote_id
  46 + * @property string $fullname
  47 + * @property float $variantPrice
  48 + * @property float $enabledVariantPrice
  49 + * @property array $categoryNames
  50 + * @property Stock[] $stocks
  51 + * @property ProductStock[] $productStocks
  52 + * @property int $quantity
  53 + * @property TaxGroupToCategory[] $categoriesToGroups
  54 + * @property TaxGroup[] $taxGroupsByLevel
  55 + * * From language behavior *
  56 + * @property ProductLang $lang
  57 + * @property ProductLang[] $langs
  58 + * @property ProductLang $objectLang
  59 + * @property string $ownerKey
  60 + * @property string $langKey
  61 + * @property ProductLang[] $modelLangs
  62 + * @property bool $transactionStatus
  63 + * @method string getOwnerKey()
  64 + * @method void setOwnerKey( string $value )
  65 + * @method string getLangKey()
  66 + * @method void setLangKey( string $value )
  67 + * @method ActiveQuery getLangs()
  68 + * @method ActiveQuery getLang( integer $language_id )
  69 + * @method ProductLang[] generateLangs()
  70 + * @method void loadLangs( Request $request )
  71 + * @method bool linkLangs()
  72 + * @method bool saveLangs()
  73 + * @method bool getTransactionStatus()
  74 + * * End language behavior *
  75 + * * From multipleImage behavior
  76 + * @property ProductImage $image
  77 + * @property ProductImage[] $images
  78 + * @property array imagesConfig
  79 + * @method ActiveQuery getImage()
  80 + * @method ActiveQuery getImages()
  81 + * @method array getImagesConfig()
  82 + * @method array getImagesHTML( string $preset )
  83 + * * End multipleImage behavior
  84 + */
  85 + class Product extends ActiveRecord
  86 + {
  87 +
  88 + public $imagesUpload = [];
  89 +
  90 + /**
  91 + * @inheritdoc
  92 + */
  93 + public function behaviors()
  94 + {
  95 + return [
  96 + 'images' => [
  97 + 'class' => SaveMultipleFileBehavior::className(),
  98 + 'name' => 'imagesUpload',
  99 + 'directory' => 'products',
  100 + 'column' => 'image',
  101 + 'links' => [
  102 + 'id' => 'product_id',
  103 + ],
  104 + 'model' => ProductImage::className(),
  105 + ],
  106 + 'multipleImage' => [
  107 + 'class' => MultipleImgBehavior::className(),
  108 + 'links' => [
  109 + 'product_id' => 'id',
  110 + ],
  111 + 'conditions' => [
  112 + 'product_variant_id' => null,
  113 + ],
  114 + 'model' => ProductImage::className(),
  115 + 'config' => [
  116 + 'caption' => 'image',
  117 + 'delete_action' => '/product/manage/delete-image',
  118 + 'id' => 'id',
  119 + ],
  120 + ],
  121 + 'language' => [
  122 + 'class' => LanguageBehavior::className(),
  123 + ],
  124 + 'defaultVariant' => DefaultVariantBehavior::className(),
  125 + ];
  126 + }
  127 +
  128 + /**
  129 + * @inheritdoc
  130 + */
  131 + public static function tableName()
  132 + {
  133 + return 'product';
  134 + }
  135 +
  136 + /**
  137 + * @inheritdoc
  138 + */
  139 + public function rules()
  140 + {
  141 + return [
  142 + [
  143 + [ 'brand_id' ],
  144 + 'integer',
  145 + ],
  146 + [
  147 + [
  148 + 'categories',
  149 + 'variants',
  150 + 'options',
  151 + 'imagesUpload',
  152 + ],
  153 + 'safe',
  154 + ],
  155 + [
  156 + [
  157 + 'video',
  158 + ],
  159 + 'safe',
  160 + ],
  161 + [
  162 + [
  163 + 'is_top',
  164 + 'is_new',
  165 + 'is_discount',
  166 + ],
  167 + 'boolean',
  168 + ],
  169 + ];
  170 + }
  171 +
  172 + /**
  173 + * @inheritdoc
  174 + */
  175 + public function attributeLabels()
  176 + {
  177 + return [
  178 + 'id' => Yii::t('product', 'ID'),
  179 + 'brand_id' => Yii::t('product', 'Brand'),
  180 + 'categories' => Yii::t('product', 'Categories'),
  181 + 'category' => Yii::t('product', 'Category'),
  182 + 'image' => Yii::t('product', 'Image'),
  183 + 'images' => Yii::t('product', 'Images'),
  184 + 'video' => Yii::t('product', 'Video embeded'),
  185 + 'variants' => Yii::t('product', 'Variants'),
  186 + 'is_top' => Yii::t('product', 'Is top'),
  187 + 'is_new' => Yii::t('product', 'Is new'),
  188 + 'is_discount' => Yii::t('product', 'Is promo'),
  189 + ];
  190 + }
  191 +
  192 + /**
  193 + * Get Brand query to current Product
  194 + *
  195 + * @return \yii\db\ActiveQuery
  196 + */
  197 + public function getBrand()
  198 + {
  199 + return $this->hasOne(Brand::className(), [ 'id' => 'brand_id' ]);
  200 + }
  201 +
  202 + /**
  203 + * Get ProductVariant query to current Product
  204 + *
  205 + * @return \yii\db\ActiveQuery
  206 + */
  207 + public function getVariant()
  208 + {
  209 + return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ]);
  210 + }
  211 +
  212 + /**
  213 + * Synonim of getVariant()
  214 + *
  215 + * @see Product::getVariant()
  216 + * @return \yii\db\ActiveQuery
  217 + */
  218 + public function getProductVariant()
  219 + {
  220 + return $this->getVariant();
  221 + }
  222 +
  223 + /**
  224 + * Get ProductVariants query to current Product
  225 + *
  226 + * @return \yii\db\ActiveQuery
  227 + */
  228 + public function getVariants()
  229 + {
  230 + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]);
  231 + }
  232 +
  233 + /**
  234 + * Synonim of getVariants()
  235 + *
  236 + * @see Product::getVariants()
  237 + * @return \yii\db\ActiveQuery
  238 + */
  239 + public function getProductVariants()
  240 + {
  241 + return $this->getVariant();
  242 + }
  243 +
  244 + /**
  245 + * Get ProductVariant query fetching only available in stock to current Product
  246 + *
  247 + * @see Product::getVariant()
  248 + * @return \yii\db\ActiveQuery
  249 + */
  250 + public function getEnabledVariant()
  251 + {
  252 + return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ])
  253 + ->andWhere(
  254 + [
  255 + '!=',
  256 + ProductVariant::tableName() . '.stock',
  257 + 0,
  258 + ]
  259 + );
  260 + }
  261 +
  262 + /**
  263 + * Get ProductVariants query fetching only available in stock to current Product
  264 + *
  265 + * @see Product::getVariants()
  266 + * @return \yii\db\ActiveQuery
  267 + */
  268 + public function getEnabledVariants()
  269 + {
  270 + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ])
  271 + ->andWhere(
  272 + [
  273 + '!=',
  274 + ProductVariant::tableName() . '.stock',
  275 + 0,
  276 + ]
  277 + );
  278 + }
  279 +
  280 + /**
  281 + * Get random ProductVariant price or 0 if not exist
  282 + *
  283 + * @param bool $exception Whether to throw exception if variant not exist
  284 + *
  285 + * @return float
  286 + * @throws \yii\web\NotFoundHttpException
  287 + */
  288 + public function getVariantPrice(bool $exception = false): float
  289 + {
  290 + if (!empty( $this->variant )) {
  291 + return $this->variant->price;
  292 + } elseif ($exception) {
  293 + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got variants');
  294 + } else {
  295 + return 0;
  296 + }
  297 + }
  298 +
  299 + /**
  300 + * Get random ProductVariant that in stock price or 0 or exception if not exist
  301 + *
  302 + * @param bool $exception Whether to throw exception if variant not exist
  303 + *
  304 + * @return float
  305 + * @throws \yii\web\NotFoundHttpException
  306 + */
  307 + public function getEnabledVariantPrice(bool $exception = false): float
  308 + {
  309 + if (!empty( $this->enabledVariant )) {
  310 + return $this->enabledVariant->price;
  311 + } elseif ($exception) {
  312 + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got enabled variants');
  313 + } else {
  314 + return 0;
  315 + }
  316 + }
  317 +
  318 + /**
  319 + * Get Product name concatenated with Brand name
  320 + *
  321 + * @return string
  322 + */
  323 + public function getFullname():string
  324 + {
  325 + return empty( $this->brand ) ? $this->lang->title : $this->brand->lang->title . ' ' . $this->lang->title;
  326 + }
  327 +
  328 + /**
  329 + * Get Category query for current Product
  330 + *
  331 + * @return ActiveQuery
  332 + */
  333 + public function getCategory()
  334 + {
  335 + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ])
  336 + ->viaTable('product_category', [ 'product_id' => 'id' ]);
  337 + }
  338 +
  339 + /**
  340 + * Get Categories query for current Product
  341 + *
  342 + * @return ActiveQuery
  343 + */
  344 + public function getCategories()
  345 + {
  346 + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ])
  347 + ->viaTable('product_category', [ 'product_id' => 'id' ]);
  348 + }
  349 +
  350 + /**
  351 + * @param bool $index
  352 + *
  353 + * @return array
  354 + */
  355 + public function getCategoryNames(bool $index = false): array
  356 + {
  357 + if ($index) {
  358 + $result = ArrayHelper::map($this->categories, 'id', 'lang.title');
  359 + } else {
  360 + $result = ArrayHelper::getColumn($this->categories, 'lang.title');
  361 + }
  362 + return $result;
  363 + }
  364 +
  365 + /**
  366 + * Get ProductVariants query with lang, filters and image for current Product
  367 + *
  368 + * @return ActiveQuery
  369 + */
  370 + public function getVariantsWithFilters()
  371 + {
  372 + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ])
  373 + ->joinWith('lang')
  374 + ->with(
  375 + [
  376 + 'filters',
  377 + 'image',
  378 + ]
  379 + );
  380 + }
  381 +
  382 + /**
  383 + * Get TaxOptions query for current Product
  384 + *
  385 + * @return ActiveQuery
  386 + */
  387 + public function getOptions()
  388 + {
  389 + return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ])
  390 + ->viaTable('product_option', [ 'product_id' => 'id' ]);
  391 + }
  392 +
  393 + /**
  394 + * Get TaxOptions query for current Product joined with TaxGroups
  395 + *
  396 + * @see Product::getOptions()
  397 + * @return ActiveQuery
  398 + */
  399 + public function getFilters()
  400 + {
  401 + return $this->getOptions()
  402 + ->joinWith('taxGroup.lang')
  403 + ->joinWith('lang');
  404 + }
  405 +
  406 + /**
  407 + * Get all TaxGroups for current Product filled with $customOptions that satisfy current Product
  408 + *
  409 + * @return TaxGroup[]
  410 + */
  411 + public function getProperties(): array
  412 + {
  413 + $groups = $options = [];
  414 + foreach ($this->getOptions()
  415 + ->with('lang')
  416 + ->all() as $option) {
  417 + /**
  418 + * @var TaxOption $option
  419 + */
  420 + $options[ $option[ 'tax_group_id' ] ][] = $option;
  421 + }
  422 + foreach (TaxGroup::find()
  423 + ->where([ 'id' => array_keys($options) ])
  424 + ->with('lang')
  425 + ->all() as $group) {
  426 + /**
  427 + * @var TaxGroup $group
  428 + */
  429 + if (!empty( $options[ $group->id ] )) {
  430 + $group->customOptions = $options[ $group->id ];
  431 + $groups[] = $group;
  432 + }
  433 + }
  434 + return $groups;
  435 + }
  436 +
  437 + /**
  438 + * Get Stock query where current Product is in stock
  439 + *
  440 + * @return ActiveQuery
  441 + */
  442 + public function getStocks()
  443 + {
  444 + return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ])
  445 + ->via('productStocks');
  446 + }
  447 +
  448 + /**
  449 + * Get ProductStocks query for current Product
  450 + *
  451 + * @return ActiveQuery
  452 + */
  453 + public function getProductStocks()
  454 + {
  455 + return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ])
  456 + ->via('variants');
  457 + }
  458 +
  459 + /**
  460 + * Get quantity of all ProductVariants for current Product
  461 + *
  462 + * @see Product::getProductStocks()
  463 + * @return int
  464 + */
  465 + public function getQuantity():int
  466 + {
  467 + return $this->getProductStocks()
  468 + ->sum('quantity');
  469 + }
  470 +
  471 + /**
  472 + * Override Categories and TaxOptions
  473 + *
  474 + * @inheritdoc
  475 + */
  476 + public function afterSave($insert, $changedAttributes)
  477 + {
  478 + parent::afterSave($insert, $changedAttributes);
  479 +
  480 + if (!empty( $this->categories )) {
  481 + $categories = Category::findAll($this->categories);
  482 + $this->unlinkAll('categories', true);
  483 + foreach ($categories as $category) {
  484 + $this->link('categories', $category);
  485 + }
  486 + }
  487 +
  488 + if (!empty( $this->options )) {
  489 + $options = TaxOption::findAll($this->options);
  490 + $this->unlinkAll('options', true);
  491 + foreach ($options as $option) {
  492 + $this->link('options', $option);
  493 + }
  494 + }
  495 + }
  496 +
  497 + /**
  498 + * Recalculate rating for artboxcomment module
  499 + *
  500 + * @todo Rewrite with behavior
  501 + * @return bool
  502 + */
  503 + public function recalculateRating():bool
  504 + {
  505 + /**
  506 + * @var ProductToRating $averageRating
  507 + */
  508 + $average = $this->getComments()
  509 + ->joinWith('rating')
  510 + ->select([ 'average' => 'avg(artbox_comment_rating.value)::float' ])
  511 + ->scalar();
  512 + if (!$average) {
  513 + $average = 0;
  514 + }
  515 + $averageRating = $this->averageRating;
  516 + if (!empty( $averageRating )) {
  517 + $averageRating->value = $average;
  518 + } else {
  519 + $averageRating = new ProductToRating(
  520 + [
  521 + 'product_id' => $this->id,
  522 + 'value' => $average,
  523 + ]
  524 + );
  525 + }
  526 + if ($averageRating->save()) {
  527 + return true;
  528 + } else {
  529 + return false;
  530 + }
  531 + }
  532 +
  533 + /**
  534 + * Get CommmentModel query for artboxcomment module
  535 + *
  536 + * @todo Rewrite with behavior
  537 + * @return ActiveQuery
  538 + */
  539 + public function getComments()
  540 + {
  541 + return $this->hasMany(CommentModel::className(), [ 'entity_id' => 'id' ])
  542 + ->where(
  543 + [
  544 + 'artbox_comment.entity' => self::className(),
  545 + 'artbox_comment.status' => CommentModel::STATUS_ACTIVE,
  546 + 'artbox_comment.artbox_comment_pid' => null,
  547 + ]
  548 + );
  549 + }
  550 +
  551 + /**
  552 + * Get ProductToRating query in order to get average rating for current Product
  553 + *
  554 + * @return \yii\db\ActiveQuery
  555 + */
  556 + public function getAverageRating()
  557 + {
  558 + return $this->hasOne(ProductToRating::className(), [ 'product_id' => 'id' ]);
  559 + }
  560 +
  561 + /**
  562 + * Get TaxGroupToCategories query via product_category table
  563 + *
  564 + * @return ActiveQuery
  565 + */
  566 + public function getCategoriesToGroups()
  567 + {
  568 + return $this->hasMany(TaxGroupToCategory::className(), [ 'category_id' => 'category_id' ])
  569 + ->viaTable('product_category', [ 'product_id' => 'id' ]);
  570 + }
  571 +
  572 + /**
  573 + * Get TaxGroups query for current Product according to level
  574 + * * 0 - Product Tax Groups
  575 + * * 1 - ProductVariant Tax Groups
  576 + *
  577 + * @param int $level
  578 + *
  579 + * @return ActiveQuery
  580 + * @throws InvalidParamException
  581 + */
  582 + public function getTaxGroupsByLevel(int $level = 0)
  583 + {
  584 + if ($level !== 0 && $level !== 1) {
  585 + throw new InvalidParamException(
  586 + 'Level must be 0 for Product Tax Groups or 1 for Product Variant Tax Groups'
  587 + );
  588 + }
  589 + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ])
  590 + ->via('categoriesToGroups')
  591 + ->where([ 'level' => $level ])
  592 + ->distinct();
  593 + }
  594 +
  595 + /**
  596 + * Setter for Categories
  597 + *
  598 + * @param array $values
  599 + */
  600 + public function setCategories($values)
  601 + {
  602 + $this->categories = $values;
  603 + }
  604 +
  605 + /**
  606 + * Setter for Options
  607 + *
  608 + * @param array $values
  609 + */
  610 + public function setOptions($values)
  611 + {
  612 + $this->options = $values;
  613 + }
  614 + }
... ...
artbox-ecommerce/models/ProductCategory.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductCategory.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use Yii;
  6 + use yii\db\ActiveRecord;
  7 +
  8 + /**
  9 + * This is the model class for table "{{%product_category}}".
  10 + *
  11 + * @property integer $product_id
  12 + * @property integer $category_id
  13 + */
  14 + class ProductCategory extends ActiveRecord
  15 + {
  16 + /**
  17 + * @inheritdoc
  18 + */
  19 + public static function tableName()
  20 + {
  21 + return 'product_category';
  22 + }
  23 +
  24 + /**
  25 + * @inheritdoc
  26 + */
  27 + public function rules()
  28 + {
  29 + return [
  30 + [
  31 + [
  32 + 'product_id',
  33 + 'category_id',
  34 + ],
  35 + 'integer',
  36 + ],
  37 + [
  38 + [ 'category_id' ],
  39 + 'exist',
  40 + 'skipOnError' => true,
  41 + 'targetClass' => Category::className(),
  42 + 'targetAttribute' => [ 'category_id' => 'id' ],
  43 + ],
  44 + [
  45 + [ 'product_id' ],
  46 + 'exist',
  47 + 'skipOnError' => true,
  48 + 'targetClass' => Product::className(),
  49 + 'targetAttribute' => [ 'product_id' => 'id' ],
  50 + ],
  51 + ];
  52 + }
  53 +
  54 + /**
  55 + * @inheritdoc
  56 + */
  57 + public function attributeLabels()
  58 + {
  59 + return [
  60 + 'product_id' => Yii::t('product', 'Product'),
  61 + 'category_id' => Yii::t('product', 'Category'),
  62 + ];
  63 + }
  64 +
  65 + public function getCategory()
  66 + {
  67 + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]);
  68 + }
  69 +
  70 + public function getProduct()
  71 + {
  72 + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
  73 + }
  74 + }
... ...
artbox-ecommerce/models/ProductImage.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductImage.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\ImageBehavior;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "product_image".
  11 + *
  12 + * @property integer $id
  13 + * @property integer $product_id
  14 + * @property integer $product_variant_id
  15 + * @property string $image
  16 + * @property string $alt
  17 + * @property string $title
  18 + * @property Product $product
  19 + * @property ProductVariant $productVariant
  20 + */
  21 + class ProductImage extends ActiveRecord
  22 + {
  23 +
  24 + /**
  25 + * @inheritdoc
  26 + */
  27 + public static function tableName()
  28 + {
  29 + return 'product_image';
  30 + }
  31 +
  32 + public function behaviors()
  33 + {
  34 + return [
  35 + [
  36 + 'class' => ImageBehavior::className(),
  37 + 'link' => 'image',
  38 + 'directory' => 'products',
  39 + ],
  40 + ];
  41 + }
  42 +
  43 + /**
  44 + * @inheritdoc
  45 + */
  46 + public function rules()
  47 + {
  48 + return [
  49 + [
  50 + [ 'product_id' ],
  51 + 'required',
  52 + ],
  53 + [
  54 + [
  55 + 'id',
  56 + 'product_id',
  57 + 'product_variant_id',
  58 + ],
  59 + 'integer',
  60 + ],
  61 + [
  62 + [
  63 + 'alt',
  64 + 'title',
  65 + 'image',
  66 + ],
  67 + 'string',
  68 + 'max' => 255,
  69 + ],
  70 + [
  71 + [ 'product_id' ],
  72 + 'exist',
  73 + 'skipOnError' => true,
  74 + 'targetClass' => Product::className(),
  75 + 'targetAttribute' => [ 'product_id' => 'id' ],
  76 + ],
  77 + [
  78 + [ 'product_variant_id' ],
  79 + 'exist',
  80 + 'skipOnError' => true,
  81 + 'targetClass' => ProductVariant::className(),
  82 + 'targetAttribute' => [ 'product_variant_id' => 'id' ],
  83 + ],
  84 + ];
  85 + }
  86 +
  87 + /**
  88 + * @inheritdoc
  89 + */
  90 + public function attributeLabels()
  91 + {
  92 + return [
  93 + 'id' => Yii::t('product', 'Product Image ID'),
  94 + 'product_id' => Yii::t('product', 'Product ID'),
  95 + 'product_variant_id' => Yii::t('product', 'Product Variant ID'),
  96 + 'product' => Yii::t('product', 'Product'),
  97 + 'product_variant' => Yii::t('product', 'Product Variant'),
  98 + 'image' => Yii::t('product', 'Image'),
  99 + 'alt' => Yii::t('product', 'Alt'),
  100 + 'title' => Yii::t('product', 'Title'),
  101 + ];
  102 + }
  103 +
  104 + /**
  105 + * @return \yii\db\ActiveQuery
  106 + */
  107 + public function getProduct()
  108 + {
  109 + $return = $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
  110 + return $return;
  111 + }
  112 +
  113 + /**
  114 + * @return \yii\db\ActiveQuery
  115 + */
  116 + public function getProductVariant()
  117 + {
  118 + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]);
  119 + }
  120 + }
... ...
artbox-ecommerce/models/ProductLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "product_lang".
  11 + * @property integer $product_id
  12 + * @property integer $language_id
  13 + * @property string $title
  14 + * @property string $description
  15 + * @property string $alias
  16 + * @property Language $language
  17 + * @property Product $product
  18 + */
  19 + class ProductLang extends ActiveRecord
  20 + {
  21 +
  22 + public static function primaryKey()
  23 + {
  24 + return [
  25 + 'product_id',
  26 + 'language_id',
  27 + ];
  28 + }
  29 +
  30 + /**
  31 + * @inheritdoc
  32 + */
  33 + public static function tableName()
  34 + {
  35 + return 'product_lang';
  36 + }
  37 +
  38 + public function behaviors()
  39 + {
  40 + return [
  41 + 'slug' => [
  42 + 'class' => 'common\behaviors\Slug',
  43 + ],
  44 + ];
  45 + }
  46 +
  47 + /**
  48 + * @inheritdoc
  49 + */
  50 + public function rules()
  51 + {
  52 + return [
  53 + [
  54 + [ 'title' ],
  55 + 'required',
  56 + ],
  57 + [
  58 + [ 'description' ],
  59 + 'string',
  60 + ],
  61 + [
  62 + [
  63 + 'title',
  64 + 'alias',
  65 + ],
  66 + 'string',
  67 + 'max' => 255,
  68 + ],
  69 + [
  70 + [
  71 + 'product_id',
  72 + 'language_id',
  73 + ],
  74 + 'unique',
  75 + 'targetAttribute' => [
  76 + 'product_id',
  77 + 'language_id',
  78 + ],
  79 + 'message' => 'The combination of Product ID and Language ID has already been taken.',
  80 + ],
  81 + [
  82 + [ 'language_id' ],
  83 + 'exist',
  84 + 'skipOnError' => true,
  85 + 'targetClass' => Language::className(),
  86 + 'targetAttribute' => [ 'language_id' => 'id' ],
  87 + ],
  88 + [
  89 + [ 'product_id' ],
  90 + 'exist',
  91 + 'skipOnError' => true,
  92 + 'targetClass' => Product::className(),
  93 + 'targetAttribute' => [ 'product_id' => 'id' ],
  94 + ],
  95 + ];
  96 + }
  97 +
  98 + /**
  99 + * @inheritdoc
  100 + */
  101 + public function attributeLabels()
  102 + {
  103 + return [
  104 + 'product_id' => Yii::t('app', 'Product ID'),
  105 + 'language_id' => Yii::t('app', 'Language ID'),
  106 + 'title' => Yii::t('app', 'Name'),
  107 + 'description' => Yii::t('app', 'Description'),
  108 + 'alias' => Yii::t('app', 'Alias'),
  109 + ];
  110 + }
  111 +
  112 + /**
  113 + * @return \yii\db\ActiveQuery
  114 + */
  115 + public function getLanguage()
  116 + {
  117 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  118 + }
  119 +
  120 + /**
  121 + * @return \yii\db\ActiveQuery
  122 + */
  123 + public function getProduct()
  124 + {
  125 + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
  126 + }
  127 + }
... ...
artbox-ecommerce/models/ProductOption.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductOption.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use artweb\artbox\ecommerce\models\TaxOption;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "product_option".
  11 + * @property integer $product_id
  12 + * @property integer $option_id
  13 + * @property Product $product
  14 + * @property TaxOption $option
  15 + */
  16 + class ProductOption extends ActiveRecord
  17 + {
  18 +
  19 + /**
  20 + * @inheritdoc
  21 + */
  22 + public static function tableName()
  23 + {
  24 + return 'product_option';
  25 + }
  26 +
  27 + /**
  28 + * @inheritdoc
  29 + */
  30 + public function rules()
  31 + {
  32 + return [
  33 + [
  34 + [
  35 + 'product_id',
  36 + 'option_id',
  37 + ],
  38 + 'required',
  39 + ],
  40 + [
  41 + [
  42 + 'product_id',
  43 + 'option_id',
  44 + ],
  45 + 'integer',
  46 + ],
  47 + [
  48 + [ 'product_id' ],
  49 + 'exist',
  50 + 'skipOnError' => true,
  51 + 'targetClass' => Product::className(),
  52 + 'targetAttribute' => [ 'product_id' => 'id' ],
  53 + ],
  54 + [
  55 + [ 'option_id' ],
  56 + 'exist',
  57 + 'skipOnError' => true,
  58 + 'targetClass' => TaxOption::className(),
  59 + 'targetAttribute' => [ 'option_id' => 'id' ],
  60 + ],
  61 + ];
  62 + }
  63 +
  64 + /**
  65 + * @inheritdoc
  66 + */
  67 + public function attributeLabels()
  68 + {
  69 + return [
  70 + 'product_id' => Yii::t('product', 'Product ID'),
  71 + 'option_id' => Yii::t('product', 'Option ID'),
  72 + ];
  73 + }
  74 +
  75 + /**
  76 + * @return \yii\db\ActiveQuery
  77 + */
  78 + public function getProduct()
  79 + {
  80 + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
  81 + }
  82 +
  83 + /**
  84 + * @return \yii\db\ActiveQuery
  85 + */
  86 + public function getOption()
  87 + {
  88 + return $this->hasOne(TaxOption::className(), [ 'id' => 'option_id' ]);
  89 + }
  90 + }
... ...
artbox-ecommerce/models/ProductSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 + use yii\db\ActiveQuery;
  8 +
  9 + /**
  10 + * ProductSearch represents the model behind the search form about
  11 + * `artweb\artbox\ecommerce\models\Product`.
  12 + */
  13 + class ProductSearch extends Product
  14 + {
  15 +
  16 + public $categoryId;
  17 +
  18 + public $productName;
  19 +
  20 + public $variantCount;
  21 +
  22 + public function behaviors()
  23 + {
  24 + $behaviors = parent::behaviors();
  25 + if (isset( $behaviors[ 'language' ] )) {
  26 + unset( $behaviors[ 'language' ] );
  27 + }
  28 + return $behaviors;
  29 + }
  30 +
  31 + /**
  32 + * @inheritdoc
  33 + */
  34 + public function rules()
  35 + {
  36 + return [
  37 + [
  38 + [
  39 + 'productName',
  40 + ],
  41 + 'safe',
  42 + ],
  43 + [
  44 + [
  45 + 'brand_id',
  46 + 'id',
  47 + 'categoryId',
  48 + ],
  49 + 'integer',
  50 + ],
  51 + [
  52 + [
  53 + 'is_top',
  54 + 'is_new',
  55 + 'is_discount',
  56 + ],
  57 + 'boolean',
  58 + ],
  59 + ];
  60 + }
  61 +
  62 + public function attributeLabels()
  63 + {
  64 + $labels = parent::attributeLabels();
  65 + $new_labels = [
  66 + 'categoryId' => 'Category ID',
  67 + 'brand_id' => 'Brand ID',
  68 + 'productName' => 'Product name',
  69 + 'variantCount' => 'Variant count',
  70 + ];
  71 + return array_merge($labels, $new_labels);
  72 + }
  73 +
  74 + /**
  75 + * @inheritdoc
  76 + */
  77 + public function scenarios()
  78 + {
  79 + // bypass scenarios() implementation in the parent class
  80 + return Model::scenarios();
  81 + }
  82 +
  83 + /**
  84 + * Creates data provider instance with search query applied
  85 + *
  86 + * @param array $params
  87 + *
  88 + * @return ActiveDataProvider
  89 + */
  90 + public function search($params)
  91 + {
  92 + $query = Product::find();
  93 + $query->select(
  94 + [
  95 + 'product.*',
  96 + ]
  97 + );
  98 +
  99 + $query->joinWith(
  100 + [
  101 + 'categories',
  102 + 'lang',
  103 + ]
  104 + )
  105 + ->joinWith(
  106 + [
  107 + 'brand' => function ($query) {
  108 + /**
  109 + * @var ActiveQuery $query
  110 + */
  111 + $query->joinWith('lang');
  112 + },
  113 + ]
  114 + )
  115 + ->joinWith('variants');
  116 +
  117 + $query->groupBy(
  118 + [
  119 + 'product.id',
  120 + 'product_variant.id',
  121 + ]
  122 + );
  123 +
  124 + $dataProvider = new ActiveDataProvider(
  125 + [
  126 + 'query' => $query,
  127 + ]
  128 + );
  129 +
  130 + $dataProvider->setSort(
  131 + [
  132 + 'attributes' => [
  133 + 'id',
  134 + 'productName' => [
  135 + 'asc' => [ 'product_lang.title' => SORT_ASC ],
  136 + 'desc' => [ 'product_lang.title' => SORT_DESC ],
  137 + ],
  138 + 'brand_id' => [
  139 + 'asc' => [ 'brand_lang.title' => SORT_ASC ],
  140 + 'desc' => [ 'brand_lang.title' => SORT_DESC ],
  141 + ],
  142 + ],
  143 + ]
  144 + );
  145 +
  146 + $this->load($params);
  147 +
  148 + if (!$this->validate()) {
  149 + // uncomment the following line if you do not want to return any records when validation fails
  150 + // $query->where('0=1');
  151 + return $dataProvider;
  152 + }
  153 +
  154 + if (isset( $this->is_top )) {
  155 + $query->andWhere(
  156 + [
  157 + 'is_top' => (bool) $this->is_top,
  158 + ]
  159 + );
  160 + }
  161 + if (isset( $this->is_new )) {
  162 + $query->andWhere(
  163 + [
  164 + 'is_new' => (bool) $this->is_new,
  165 + ]
  166 + );
  167 + }
  168 + if (isset( $this->is_discount )) {
  169 + $query->andWhere(
  170 + [
  171 + 'is_discount' => (bool) $this->is_discount,
  172 + ]
  173 + );
  174 + }
  175 + $query->andFilterWhere(
  176 + [
  177 + 'product.brand_id' => $this->brand_id,
  178 + 'product.id' => $this->id,
  179 + 'product_category.category_id' => $this->categoryId,
  180 + ]
  181 + );
  182 + $query->andFilterWhere(
  183 + [
  184 + 'like',
  185 + 'product_lang.title',
  186 + $this->productName,
  187 + ]
  188 + );
  189 +
  190 + return $dataProvider;
  191 + }
  192 + }
... ...
artbox-ecommerce/models/ProductStock.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductStock.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\db\ActiveRecord;
  6 +
  7 + /**
  8 + * This is the model class for table "product_stock".
  9 + *
  10 + * @property integer $stock_id
  11 + * @property integer $quantity
  12 + * @property integer $product_variant_id
  13 + * @property Product $product
  14 + * @property ProductVariant $productVariant
  15 + * @property Stock $stock
  16 + * @property string $title
  17 + */
  18 + class ProductStock extends ActiveRecord
  19 + {
  20 + protected $title;
  21 + /**
  22 + * @inheritdoc
  23 + */
  24 + public static function tableName()
  25 + {
  26 + return 'product_stock';
  27 + }
  28 +
  29 + /**
  30 + * @inheritdoc
  31 + */
  32 + public function rules()
  33 + {
  34 + return [
  35 + [
  36 + [
  37 + 'stock_id',
  38 + 'quantity',
  39 + 'product_variant_id',
  40 + ],
  41 + 'integer',
  42 + ],
  43 + [
  44 + [ 'title' ],
  45 + 'required',
  46 + ],
  47 + [
  48 + [ 'product_variant_id' ],
  49 + 'exist',
  50 + 'skipOnError' => true,
  51 + 'targetClass' => ProductVariant::className(),
  52 + 'targetAttribute' => [ 'product_variant_id' => 'id' ],
  53 + ],
  54 + [
  55 + [ 'stock_id' ],
  56 + 'exist',
  57 + 'skipOnError' => true,
  58 + 'targetClass' => Stock::className(),
  59 + 'targetAttribute' => [ 'stock_id' => 'id' ],
  60 + ],
  61 + ];
  62 + }
  63 +
  64 + /**
  65 + * @inheritdoc
  66 + */
  67 + public function attributeLabels()
  68 + {
  69 + return [
  70 + 'stock_id' => 'Stock ID',
  71 + 'quantity' => 'Количество',
  72 + 'product_variant_id' => 'Product Variant ID',
  73 + 'title' => "Название",
  74 + ];
  75 + }
  76 +
  77 + /**
  78 + * @return \yii\db\ActiveQuery
  79 + */
  80 + public function getProduct()
  81 + {
  82 + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ])
  83 + ->via('variants');
  84 + }
  85 +
  86 + /**
  87 + * @return \yii\db\ActiveQuery
  88 + */
  89 + public function getProductVariant()
  90 + {
  91 + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]);
  92 + }
  93 +
  94 + /**
  95 + * Get Stock title, tries to get from Stock lang
  96 + *
  97 + * @return string
  98 + */
  99 + public function getTitle(): string
  100 + {
  101 + if (!empty( $this->title )) {
  102 + return $this->title;
  103 + } elseif (!empty( $this->stock )) {
  104 + return $this->stock->lang->title;
  105 + } else {
  106 + return '';
  107 + }
  108 + }
  109 +
  110 + /**
  111 + * Set Stock title, will be saved to Stock table
  112 + *
  113 + * @param mixed $value
  114 + */
  115 + public function setTitle(string $value)
  116 + {
  117 + $this->title = $value;
  118 + }
  119 +
  120 + /**
  121 + * @return \yii\db\ActiveQuery
  122 + */
  123 + public function getStock()
  124 + {
  125 + return $this->hasOne(Stock::className(), [ 'id' => 'stock_id' ]);
  126 + }
  127 +
  128 + /**
  129 + * @inheritdoc
  130 + */
  131 + public static function primaryKey()
  132 + {
  133 + return [
  134 + "stock_id",
  135 + "product_variant_id",
  136 + ];
  137 + }
  138 + }
... ...
artbox-ecommerce/models/ProductUnit.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductUnit.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\behaviors\LanguageBehavior;
  6 + use Yii;
  7 + use yii\db\ActiveQuery;
  8 + use yii\db\ActiveRecord;
  9 + use yii\web\Request;
  10 +
  11 + /**
  12 + * This is the model class for table "product_unit".
  13 + *
  14 + * @property integer $id
  15 + * @property boolean $is_default
  16 + * @property Category[] $categories
  17 + * @property ProductVariant[] $productVariants
  18 + * * From language behavior *
  19 + * @property ProductUnitLang $lang
  20 + * @property ProductUnitLang[] $langs
  21 + * @property ProductUnitLang $objectLang
  22 + * @property string $ownerKey
  23 + * @property string $langKey
  24 + * @property ProductUnitLang[] $modelLangs
  25 + * @property bool $transactionStatus
  26 + * @method string getOwnerKey()
  27 + * @method void setOwnerKey( string $value )
  28 + * @method string getLangKey()
  29 + * @method void setLangKey( string $value )
  30 + * @method ActiveQuery getLangs()
  31 + * @method ActiveQuery getLang( integer $language_id )
  32 + * @method ProductUnitLang[] generateLangs()
  33 + * @method void loadLangs( Request $request )
  34 + * @method bool linkLangs()
  35 + * @method bool saveLangs()
  36 + * @method bool getTransactionStatus()
  37 + * * End language behavior *
  38 + */
  39 + class ProductUnit extends ActiveRecord
  40 + {
  41 +
  42 + /**
  43 + * @inheritdoc
  44 + */
  45 + public static function tableName()
  46 + {
  47 + return 'product_unit';
  48 + }
  49 +
  50 + public function behaviors()
  51 + {
  52 + return [
  53 + 'language' => [
  54 + 'class' => LanguageBehavior::className(),
  55 + ],
  56 + ];
  57 + }
  58 +
  59 + /**
  60 + * @inheritdoc
  61 + */
  62 + public function rules()
  63 + {
  64 + return [
  65 + [
  66 + [ 'is_default' ],
  67 + 'boolean',
  68 + ],
  69 + ];
  70 + }
  71 +
  72 + /**
  73 + * @inheritdoc
  74 + */
  75 + public function attributeLabels()
  76 + {
  77 + return [
  78 + 'id' => Yii::t('product', 'Product Unit ID'),
  79 + 'is_default' => Yii::t('product', 'Is Default'),
  80 + ];
  81 + }
  82 +
  83 + /**
  84 + * @return \yii\db\ActiveQuery
  85 + */
  86 + public function getCategories()
  87 + {
  88 + return $this->hasMany(Category::className(), [ 'product_unit_id' => 'id' ]);
  89 + }
  90 +
  91 + /**
  92 + * @return \yii\db\ActiveQuery
  93 + */
  94 + public function getProductVariants()
  95 + {
  96 + return $this->hasMany(ProductVariant::className(), [ 'product_unit_id' => 'id' ]);
  97 + }
  98 + }
... ...
artbox-ecommerce/models/ProductUnitLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductUnitLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "product_unit_lang".
  11 + *
  12 + * @property integer $product_unit_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property string $short
  16 + * @property Language $language
  17 + * @property ProductUnit $productUnit
  18 + */
  19 + class ProductUnitLang extends ActiveRecord
  20 + {
  21 +
  22 + public static function primaryKey()
  23 + {
  24 + return [
  25 + 'product_unit_id',
  26 + 'language_id',
  27 + ];
  28 + }
  29 +
  30 + /**
  31 + * @inheritdoc
  32 + */
  33 + public static function tableName()
  34 + {
  35 + return 'product_unit_lang';
  36 + }
  37 +
  38 + /**
  39 + * @inheritdoc
  40 + */
  41 + public function rules()
  42 + {
  43 + return [
  44 + [
  45 + [ 'title' ],
  46 + 'required',
  47 + ],
  48 + [
  49 + [
  50 + 'title',
  51 + 'short',
  52 + ],
  53 + 'string',
  54 + 'max' => 255,
  55 + ],
  56 + [
  57 + [
  58 + 'product_unit_id',
  59 + 'language_id',
  60 + ],
  61 + 'unique',
  62 + 'targetAttribute' => [
  63 + 'product_unit_id',
  64 + 'language_id',
  65 + ],
  66 + 'message' => 'The combination of Product Unit ID and Language ID has already been taken.',
  67 + ],
  68 + [
  69 + [ 'language_id' ],
  70 + 'exist',
  71 + 'skipOnError' => true,
  72 + 'targetClass' => Language::className(),
  73 + 'targetAttribute' => [ 'language_id' => 'id' ],
  74 + ],
  75 + [
  76 + [ 'product_unit_id' ],
  77 + 'exist',
  78 + 'skipOnError' => true,
  79 + 'targetClass' => ProductUnit::className(),
  80 + 'targetAttribute' => [ 'product_unit_id' => 'id' ],
  81 + ],
  82 + ];
  83 + }
  84 +
  85 + /**
  86 + * @inheritdoc
  87 + */
  88 + public function attributeLabels()
  89 + {
  90 + return [
  91 + 'product_unit_id' => Yii::t('app', 'Product Unit ID'),
  92 + 'language_id' => Yii::t('app', 'Language ID'),
  93 + 'title' => Yii::t('app', 'Name'),
  94 + 'short' => Yii::t('app', 'Short'),
  95 + ];
  96 + }
  97 +
  98 + /**
  99 + * @return \yii\db\ActiveQuery
  100 + */
  101 + public function getLanguage()
  102 + {
  103 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  104 + }
  105 +
  106 + /**
  107 + * @return \yii\db\ActiveQuery
  108 + */
  109 + public function getProductUnit()
  110 + {
  111 + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]);
  112 + }
  113 + }
... ...
artbox-ecommerce/models/ProductUnitSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductUnitSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * ProductUnitSearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\ProductUnit`.
  11 + */
  12 + class ProductUnitSearch extends ProductUnit
  13 + {
  14 +
  15 + public $title;
  16 +
  17 + public function behaviors()
  18 + {
  19 + return [];
  20 + }
  21 +
  22 + public function attributeLabels()
  23 + {
  24 + $labels = parent::attributeLabels();
  25 + $new_labels = [
  26 + 'title' => \Yii::t('product', 'Product Unit Name'),
  27 + ];
  28 + return array_merge($labels, $new_labels);
  29 + }
  30 +
  31 + /**
  32 + * @inheritdoc
  33 + */
  34 + public function rules()
  35 + {
  36 + return [
  37 + [
  38 + [ 'title' ],
  39 + 'safe',
  40 + ],
  41 + [
  42 + [ 'id' ],
  43 + 'integer',
  44 + ],
  45 + [
  46 + [ 'is_default' ],
  47 + 'boolean',
  48 + ],
  49 + ];
  50 + }
  51 +
  52 + /**
  53 + * @inheritdoc
  54 + */
  55 + public function scenarios()
  56 + {
  57 + // bypass scenarios() implementation in the parent class
  58 + return Model::scenarios();
  59 + }
  60 +
  61 + /**
  62 + * Creates data provider instance with search query applied
  63 + *
  64 + * @param array $params
  65 + *
  66 + * @return ActiveDataProvider
  67 + */
  68 + public function search($params)
  69 + {
  70 + $query = ProductUnit::find()
  71 + ->joinWith('lang');
  72 +
  73 + // add conditions that should always apply here
  74 +
  75 + $dataProvider = new ActiveDataProvider(
  76 + [
  77 + 'query' => $query,
  78 + 'sort' => [
  79 + 'attributes' => [
  80 + 'id',
  81 + 'is_defaut',
  82 + 'title' => [
  83 + 'asc' => [ 'product_unit_lang.title' => SORT_ASC ],
  84 + 'desc' => [ 'product_unit_lang.title' => SORT_DESC ],
  85 + ],
  86 + ],
  87 + ],
  88 + ]
  89 + );
  90 +
  91 + $this->load($params);
  92 +
  93 + if (!$this->validate()) {
  94 + // uncomment the following line if you do not want to return any records when validation fails
  95 + // $query->where('0=1');
  96 + return $dataProvider;
  97 + }
  98 +
  99 + // grid filtering conditions
  100 + $query->andFilterWhere(
  101 + [
  102 + 'id' => $this->id,
  103 + 'is_default' => $this->is_default,
  104 + ]
  105 + )
  106 + ->andFilterWhere(
  107 + [
  108 + 'ilike',
  109 + 'product_unit_lang.title',
  110 + $this->title,
  111 + ]
  112 + );
  113 +
  114 + return $dataProvider;
  115 + }
  116 + }
... ...
artbox-ecommerce/models/ProductVariant.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductVariant.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\MultipleImgBehavior;
  6 + use common\behaviors\SaveMultipleFileBehavior;
  7 + use common\modules\language\behaviors\LanguageBehavior;
  8 + use artweb\artbox\ecommerce\models\TaxGroup;
  9 + use artweb\artbox\ecommerce\models\TaxOption;
  10 + use Yii;
  11 + use yii\base\InvalidParamException;
  12 + use yii\db\ActiveQuery;
  13 + use yii\db\ActiveRecord;
  14 + use yii\web\Request;
  15 +
  16 + /**
  17 + * This is the model class for table "product_variant".
  18 + *
  19 + * @property integer $id
  20 + * @property integer $product_id
  21 + * @property integer $remote_id
  22 + * @property string $sku
  23 + * @property double $price
  24 + * @property double $price_old
  25 + * @property double $stock
  26 + * @property integer $product_unit_id
  27 + * @property string $fullname
  28 + * @property TaxOption[] $options
  29 + * @property ProductUnit $productUnit
  30 + * @property Product $product
  31 + * @property Category[] $categories
  32 + * @property Category $category
  33 + * @property TaxOption[] $filters
  34 + * @property ProductStock[] $productStocks
  35 + * @property int $quantity
  36 + * @property ProductStock[] $variantStocks
  37 + * @property Stock[] $stocks
  38 + * @property TaxGroup[] $properties
  39 + * @property TaxGroup[] $taxGroupsByLevel
  40 + * * From language behavior *
  41 + * @property ProductVariantLang $lang
  42 + * @property ProductVariantLang[] $langs
  43 + * @property ProductVariantLang $objectLang
  44 + * @property string $ownerKey
  45 + * @property string $langKey
  46 + * @property ProductVariantLang[] $modelLangs
  47 + * @property bool $transactionStatus
  48 + * @method string getOwnerKey()
  49 + * @method void setOwnerKey( string $value )
  50 + * @method string getLangKey()
  51 + * @method void setLangKey( string $value )
  52 + * @method ActiveQuery getLangs()
  53 + * @method ActiveQuery getLang( integer $language_id )
  54 + * @method ProductVariantLang[] generateLangs()
  55 + * @method void loadLangs( Request $request )
  56 + * @method bool linkLangs()
  57 + * @method bool saveLangs()
  58 + * @method bool getTransactionStatus()
  59 + * * End language behavior *
  60 + * * From multipleImage behavior
  61 + * @property ProductImage $image
  62 + * @property ProductImage[] $images
  63 + * @property array $imagesConfig
  64 + * @method ActiveQuery getImage()
  65 + * @method ActiveQuery getImages()
  66 + * @method array getImagesConfig()
  67 + * @method array getImagesHTML( string $preset )
  68 + * * End multipleImage behavior
  69 + */
  70 + class ProductVariant extends ActiveRecord
  71 + {
  72 + /**
  73 + * @var int[] $options
  74 + */
  75 + private $options;
  76 +
  77 + /** @var array $_images */
  78 + public $imagesUpload = [];
  79 +
  80 + /**
  81 + * @var array $stocks
  82 + */
  83 + protected $stocks = [];
  84 +
  85 + /**
  86 + * @inheritdoc
  87 + */
  88 + public static function tableName()
  89 + {
  90 + return 'product_variant';
  91 + }
  92 +
  93 + public function behaviors()
  94 + {
  95 + return [
  96 + 'language' => [
  97 + 'class' => LanguageBehavior::className(),
  98 + ],
  99 + 'images' => [
  100 + 'class' => SaveMultipleFileBehavior::className(),
  101 + 'name' => 'imagesUpload',
  102 + 'directory' => 'products',
  103 + 'column' => 'image',
  104 + 'links' => [
  105 + 'product_id' => 'product_id',
  106 + 'id' => 'product_variant_id',
  107 + ],
  108 + 'model' => ProductImage::className(),
  109 + ],
  110 + 'multipleImage' => [
  111 + 'class' => MultipleImgBehavior::className(),
  112 + 'links' => [
  113 + 'product_variant_id' => 'id',
  114 + ],
  115 + 'model' => ProductImage::className(),
  116 + 'config' => [
  117 + 'caption' => 'image',
  118 + 'delete_action' => '/product/variant/delete-image',
  119 + 'id' => 'id',
  120 + ],
  121 + ],
  122 + ];
  123 + }
  124 +
  125 + /**
  126 + * @inheritdoc
  127 + */
  128 + public function rules()
  129 + {
  130 + return [
  131 + [
  132 + [
  133 + 'product_id',
  134 + 'product_unit_id',
  135 + ],
  136 + 'required',
  137 + ],
  138 + [
  139 + [
  140 + 'product_id',
  141 + 'product_unit_id',
  142 + ],
  143 + 'integer',
  144 + ],
  145 + [
  146 + [
  147 + 'price',
  148 + 'price_old',
  149 + 'stock',
  150 + ],
  151 + 'number',
  152 + ],
  153 + [
  154 + [
  155 + 'sku',
  156 + ],
  157 + 'string',
  158 + 'max' => 255,
  159 + ],
  160 + [
  161 + [
  162 + 'options',
  163 + ],
  164 + 'safe',
  165 + ],
  166 + [
  167 + [ 'product_unit_id' ],
  168 + 'exist',
  169 + 'skipOnError' => true,
  170 + 'targetClass' => ProductUnit::className(),
  171 + 'targetAttribute' => [ 'product_unit_id' => 'id' ],
  172 + ],
  173 + [
  174 + [ 'product_id' ],
  175 + 'exist',
  176 + 'skipOnError' => true,
  177 + 'targetClass' => Product::className(),
  178 + 'targetAttribute' => [ 'product_id' => 'id' ],
  179 + ],
  180 + ];
  181 + }
  182 +
  183 + /**
  184 + * @inheritdoc
  185 + */
  186 + public function attributeLabels()
  187 + {
  188 + return [
  189 + 'id' => Yii::t('product', 'Product Variant ID'),
  190 + 'product_id' => Yii::t('product', 'Product ID'),
  191 + 'sku' => Yii::t('product', 'Sku'),
  192 + 'price' => Yii::t('product', 'Price'),
  193 + 'price_old' => Yii::t('product', 'Price Old'),
  194 + 'stock' => Yii::t('product', 'Stock'),
  195 + 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
  196 + 'stock_caption' => Yii::t('product', 'Stock'),
  197 + 'image' => Yii::t('product', 'Image'),
  198 + 'images' => Yii::t('product', 'Images'),
  199 + ];
  200 + }
  201 +
  202 + /**
  203 + * @return \yii\db\ActiveQuery
  204 + */
  205 + public function getProductUnit()
  206 + {
  207 + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]);
  208 + }
  209 +
  210 + /**
  211 + * @return \yii\db\ActiveQuery
  212 + */
  213 + public function getProduct()
  214 + {
  215 + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
  216 + }
  217 +
  218 + /**
  219 + * @return \yii\db\ActiveQuery
  220 + */
  221 + public function getProductStocks()
  222 + {
  223 + return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]);
  224 + }
  225 +
  226 + /**
  227 + * Get qunatity for current ProductVariant
  228 + * If $recalculate set to true will recalculate stock via product_stock table
  229 + *
  230 + * @param bool $recalculate
  231 + *
  232 + * @return int
  233 + */
  234 + public function getQuantity(bool $recalculate = false): int
  235 + {
  236 + if (!$recalculate) {
  237 + return $this->stock;
  238 + } else {
  239 + $quantity = $this->getProductStocks()
  240 + ->sum('quantity');
  241 + if (empty( $quantity )) {
  242 + $this->stock = 0;
  243 + } else {
  244 + $this->stock = (int) $quantity;
  245 + }
  246 + $this->save(false, [ 'stock' ]);
  247 + return $this->stock;
  248 + }
  249 + }
  250 +
  251 + /**
  252 + * Get ProductStocks query woth preloaded Stocks for current ProductVariant
  253 + * **Used in dynamic fields in product variant form**
  254 + *
  255 + * @return ActiveQuery
  256 + */
  257 + public function getVariantStocks()
  258 + {
  259 + return $this->getProductStocks()
  260 + ->joinWith('stock');
  261 + }
  262 +
  263 + /**
  264 + * @return ActiveQuery
  265 + */
  266 + public function getStocks()
  267 + {
  268 + return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ])
  269 + ->via('productStocks');
  270 + }
  271 +
  272 + /**
  273 + * @return ActiveQuery
  274 + */
  275 + public function getOptions()
  276 + {
  277 + return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ])
  278 + ->viaTable('product_variant_option', [ 'product_variant_id' => 'id' ]);
  279 + }
  280 +
  281 + /**
  282 + * Get TaxOptions with preloaded TaxGroups for current ProductVariant
  283 + *
  284 + * @return ActiveQuery
  285 + */
  286 + public function getFilters()
  287 + {
  288 + return $this->getOptions()
  289 + ->joinWith('taxGroup.lang')
  290 + ->joinWith('lang');
  291 + }
  292 +
  293 + /**
  294 + * Get Product title concanated with current ProductVariant title
  295 + *
  296 + * @return string
  297 + */
  298 + public function getFullname(): string
  299 + {
  300 + return $this->product->lang->title . ' ' . $this->lang->title;
  301 + }
  302 +
  303 + /**
  304 + * Set Options to override previous
  305 + *
  306 + * @param int[] $values
  307 + */
  308 + public function setOptions($values)
  309 + {
  310 + $this->options = $values;
  311 + }
  312 +
  313 + /**
  314 + * Get all TaxGroups for current ProductVariant filled with $customOptions that satisfy current ProductVariant
  315 + *
  316 + * @return TaxGroup[]
  317 + */
  318 + public function getProperties()
  319 + {
  320 + $groups = $options = [];
  321 + foreach ($this->getOptions()
  322 + ->with('lang')
  323 + ->all() as $option) {
  324 + /**
  325 + * @var TaxOption $option
  326 + */
  327 + $options[ $option->tax_group_id ][] = $option;
  328 + }
  329 + foreach (TaxGroup::find()
  330 + ->where([ 'tax_group.id' => array_keys($options) ])
  331 + ->orderBy([ 'sort' => SORT_ASC ])
  332 + ->with('lang')
  333 + ->all() as $group) {
  334 + /**
  335 + * @var TaxGroup $group
  336 + */
  337 + if (!empty( $options[ $group->id ] )) {
  338 + $group->customOptions = $options[ $group->id ];
  339 + $groups[] = $group;
  340 + }
  341 + }
  342 + return $groups;
  343 + }
  344 +
  345 + /**
  346 + * Set stocks to override existing in product_stock table
  347 + *
  348 + * @param mixed $stocks
  349 + */
  350 + public function setStocks($stocks)
  351 + {
  352 + $this->stocks = (array) $stocks;
  353 + }
  354 +
  355 + /**
  356 + * @return ActiveQuery
  357 + */
  358 + public function getCategory()
  359 + {
  360 + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ])
  361 + ->viaTable('product_category', [ 'product_id' => 'product_id' ]);
  362 + }
  363 +
  364 + /**
  365 + * @return ActiveQuery
  366 + */
  367 + public function getCategories()
  368 + {
  369 + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ])
  370 + ->viaTable('product_category', [ 'product_id' => 'product_id' ]);
  371 + }
  372 +
  373 + /**
  374 + * Get TaxGroups query for current ProductVariant according to level
  375 + * * 0 - Product Tax Groups
  376 + * * 1 - ProductVariant Tax Groups
  377 + *
  378 + * @param int $level
  379 + *
  380 + * @return ActiveQuery
  381 + * @throws InvalidParamException
  382 + */
  383 + public function getTaxGroupsByLevel(int $level = 0)
  384 + {
  385 + return $this->product->getTaxGroupsByLevel($level);
  386 + }
  387 +
  388 + public function afterSave($insert, $changedAttributes)
  389 + {
  390 + parent::afterSave($insert, $changedAttributes);
  391 + if (!empty( $this->options )) {
  392 + $options = TaxOption::findAll($this->options);
  393 + $this->unlinkAll('options', true);
  394 + foreach ($options as $option) {
  395 + $this->link('options', $option);
  396 + }
  397 + }
  398 +
  399 + if (!empty( $this->stocks )) {
  400 + ProductStock::deleteAll([ 'product_variant_id' => $this->id ]);
  401 + foreach ($this->stocks as $id => $quantity) {
  402 + /**
  403 + * @var ProductStock $productStock
  404 + */
  405 + $productStock = ProductStock::find()
  406 + ->where(
  407 + [
  408 + 'product_variant_id' => $this->id,
  409 + 'stock_id' => $id,
  410 + ]
  411 + )
  412 + ->one();
  413 + $productStock->quantity = $quantity;
  414 + $productStock->save();
  415 + }
  416 + }
  417 + }
  418 + }
... ...
artbox-ecommerce/models/ProductVariantLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductVariantLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "product_variant_lang".
  11 + *
  12 + * @property integer $product_variant_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property Language $language
  16 + * @property ProductVariant $productVariant
  17 + */
  18 + class ProductVariantLang extends ActiveRecord
  19 + {
  20 +
  21 + public static function primaryKey()
  22 + {
  23 + return [
  24 + 'product_variant_id',
  25 + 'language_id',
  26 + ];
  27 + }
  28 +
  29 + /**
  30 + * @inheritdoc
  31 + */
  32 + public static function tableName()
  33 + {
  34 + return 'product_variant_lang';
  35 + }
  36 +
  37 + /**
  38 + * @inheritdoc
  39 + */
  40 + public function rules()
  41 + {
  42 + return [
  43 + [
  44 + [ 'title' ],
  45 + 'required',
  46 + ],
  47 + [
  48 + [ 'title' ],
  49 + 'string',
  50 + 'max' => 255,
  51 + ],
  52 + [
  53 + [
  54 + 'product_variant_id',
  55 + 'language_id',
  56 + ],
  57 + 'unique',
  58 + 'targetAttribute' => [
  59 + 'product_variant_id',
  60 + 'language_id',
  61 + ],
  62 + 'message' => 'The combination of Product Variant ID and Language ID has already been taken.',
  63 + ],
  64 + [
  65 + [ 'language_id' ],
  66 + 'exist',
  67 + 'skipOnError' => true,
  68 + 'targetClass' => Language::className(),
  69 + 'targetAttribute' => [ 'language_id' => 'id' ],
  70 + ],
  71 + [
  72 + [ 'product_variant_id' ],
  73 + 'exist',
  74 + 'skipOnError' => true,
  75 + 'targetClass' => ProductVariant::className(),
  76 + 'targetAttribute' => [ 'product_variant_id' => 'id' ],
  77 + ],
  78 + ];
  79 + }
  80 +
  81 + /**
  82 + * @inheritdoc
  83 + */
  84 + public function attributeLabels()
  85 + {
  86 + return [
  87 + 'product_variant_id' => Yii::t('app', 'Product Variant ID'),
  88 + 'language_id' => Yii::t('app', 'Language ID'),
  89 + 'title' => Yii::t('app', 'Name'),
  90 + ];
  91 + }
  92 +
  93 + /**
  94 + * @return \yii\db\ActiveQuery
  95 + */
  96 + public function getLanguage()
  97 + {
  98 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  99 + }
  100 +
  101 + /**
  102 + * @return \yii\db\ActiveQuery
  103 + */
  104 + public function getProductVariant()
  105 + {
  106 + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]);
  107 + }
  108 + }
... ...
artbox-ecommerce/models/ProductVariantOption.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductVariantOption.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use artweb\artbox\ecommerce\models\TaxOption;
  6 + use yii\db\ActiveRecord;
  7 +
  8 + /**
  9 + * This is the model class for table "product_variant_option".
  10 + *
  11 + * @property integer $product_variant_id
  12 + * @property integer $option_id
  13 + * @property ProductVariant $productVariant
  14 + * @property TaxOption $option
  15 + */
  16 + class ProductVariantOption extends ActiveRecord
  17 + {
  18 +
  19 + /**
  20 + * @inheritdoc
  21 + */
  22 + public static function tableName()
  23 + {
  24 + return 'product_variant_option';
  25 + }
  26 +
  27 + /**
  28 + * @inheritdoc
  29 + */
  30 + public function rules()
  31 + {
  32 + return [
  33 + [
  34 + [
  35 + 'product_variant_id',
  36 + 'option_id',
  37 + ],
  38 + 'required',
  39 + ],
  40 + [
  41 + [
  42 + 'product_variant_id',
  43 + 'option_id',
  44 + ],
  45 + 'integer',
  46 + ],
  47 + [
  48 + [ 'product_variant_id' ],
  49 + 'exist',
  50 + 'skipOnError' => true,
  51 + 'targetClass' => ProductVariant::className(),
  52 + 'targetAttribute' => [ 'product_variant_id' => 'id' ],
  53 + ],
  54 + [
  55 + [ 'option_id' ],
  56 + 'exist',
  57 + 'skipOnError' => true,
  58 + 'targetClass' => TaxOption::className(),
  59 + 'targetAttribute' => [ 'option_id' => 'id' ],
  60 + ],
  61 + ];
  62 + }
  63 +
  64 + /**
  65 + * @inheritdoc
  66 + */
  67 + public function attributeLabels()
  68 + {
  69 + return [
  70 + 'product_variant_id' => 'Product Variant ID',
  71 + 'option_id' => 'Option ID',
  72 + ];
  73 + }
  74 +
  75 + /**
  76 + * @return \yii\db\ActiveQuery
  77 + */
  78 + public function getProductVariant()
  79 + {
  80 + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]);
  81 + }
  82 +
  83 + /**
  84 + * @return \yii\db\ActiveQuery
  85 + */
  86 + public function getOption()
  87 + {
  88 + return $this->hasOne(TaxOption::className(), [ 'id' => 'option_id' ]);
  89 + }
  90 + }
... ...
artbox-ecommerce/models/ProductVariantSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/ProductVariantSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * ProductVariantSearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\ProductVariant`.
  11 + */
  12 + class ProductVariantSearch extends ProductVariant
  13 + {
  14 +
  15 + public $variantName;
  16 +
  17 + public function behaviors()
  18 + {
  19 + return [];
  20 + }
  21 +
  22 + /**
  23 + * @inheritdoc
  24 + */
  25 + public function rules()
  26 + {
  27 + return [
  28 + [
  29 + [
  30 + 'variantName',
  31 + 'sku',
  32 + ],
  33 + 'safe',
  34 + ],
  35 + [
  36 + [
  37 + 'id',
  38 + 'stock',
  39 + ],
  40 + 'integer',
  41 + ],
  42 + [
  43 + [
  44 + 'price',
  45 + 'price_old',
  46 + ],
  47 + 'number',
  48 + ],
  49 + ];
  50 + }
  51 +
  52 + /**
  53 + * @inheritdoc
  54 + */
  55 + public function scenarios()
  56 + {
  57 + // bypass scenarios() implementation in the parent class
  58 + return Model::scenarios();
  59 + }
  60 +
  61 + /**
  62 + * Creates data provider instance with search query applied
  63 + *
  64 + * @param array $params
  65 + *
  66 + * @return ActiveDataProvider
  67 + */
  68 + public function search($params)
  69 + {
  70 + $query = ProductVariant::find()
  71 + ->joinWith('lang');
  72 +
  73 + // add conditions that should always apply here
  74 +
  75 + $dataProvider = new ActiveDataProvider(
  76 + [
  77 + 'query' => $query,
  78 + ]
  79 + );
  80 +
  81 + $this->load($params);
  82 +
  83 + if (!$this->validate()) {
  84 + // uncomment the following line if you do not want to return any records when validation fails
  85 + // $query->where('0=1');
  86 + return $dataProvider;
  87 + }
  88 +
  89 + $dataProvider->setSort(
  90 + [
  91 + 'attributes' => [
  92 + 'id',
  93 + 'sku',
  94 + 'variantName' => [
  95 + 'asc' => [ 'product_variant_lang.title' => SORT_ASC ],
  96 + 'desc' => [ 'product_variant_lang.title' => SORT_DESC ],
  97 + ],
  98 + 'price',
  99 + 'price_old',
  100 + 'stock',
  101 + ],
  102 + ]
  103 + );
  104 +
  105 + $query->andFilterWhere(
  106 + [
  107 + 'price' => $this->price,
  108 + 'price_old' => $this->price_old,
  109 + 'stock' => $this->stock,
  110 + ]
  111 + );
  112 +
  113 + $query->andFilterWhere(
  114 + [
  115 + 'ilike',
  116 + 'product_variant_lang.title',
  117 + $this->variantName,
  118 + ]
  119 + )
  120 + ->andFilterWhere(
  121 + [
  122 + 'ilike',
  123 + 'sku',
  124 + $this->sku,
  125 + ]
  126 + );
  127 +
  128 + $query->groupBy(
  129 + [
  130 + 'product_variant.id',
  131 + 'product_variant_lang.title',
  132 + ]
  133 + );
  134 +
  135 + return $dataProvider;
  136 + }
  137 + }
... ...
artbox-ecommerce/models/Stock.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/Stock.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\behaviors\LanguageBehavior;
  6 + use Yii;
  7 + use yii\db\ActiveQuery;
  8 + use yii\db\ActiveRecord;
  9 + use yii\web\Request;
  10 +
  11 + /**
  12 + * This is the model class for table "stock".
  13 + *
  14 + * @property integer $id
  15 + * @property ProductStock[] $productStocks
  16 + * @property ProductVariant[] $productVariants
  17 + * @property Product[] $products
  18 + * * From language behavior *
  19 + * @property StockLang $lang
  20 + * @property StockLang[] $langs
  21 + * @property StockLang $objectLang
  22 + * @property string $ownerKey
  23 + * @property string $langKey
  24 + * @property StockLang[] $modelLangs
  25 + * @property bool $transactionStatus
  26 + * @method string getOwnerKey()
  27 + * @method void setOwnerKey( string $value )
  28 + * @method string getLangKey()
  29 + * @method void setLangKey( string $value )
  30 + * @method ActiveQuery getLangs()
  31 + * @method ActiveQuery getLang( integer $language_id )
  32 + * @method StockLang[] generateLangs()
  33 + * @method void loadLangs( Request $request )
  34 + * @method bool linkLangs()
  35 + * @method bool saveLangs()
  36 + * @method bool getTransactionStatus()
  37 + * * End language behavior *
  38 + */
  39 + class Stock extends ActiveRecord
  40 + {
  41 + /**
  42 + * @inheritdoc
  43 + */
  44 + public static function tableName()
  45 + {
  46 + return 'stock';
  47 + }
  48 +
  49 + public function behaviors()
  50 + {
  51 + return [
  52 + 'language' => [
  53 + 'class' => LanguageBehavior::className(),
  54 + ],
  55 + ];
  56 + }
  57 +
  58 + /**
  59 + * @inheritdoc
  60 + */
  61 + public function attributeLabels()
  62 + {
  63 + return [
  64 + 'id' => Yii::t('product', 'Stock ID'),
  65 + ];
  66 + }
  67 +
  68 + /**
  69 + * @return \yii\db\ActiveQuery
  70 + */
  71 + public function getProductStocks()
  72 + {
  73 + return $this->hasMany(ProductStock::className(), [ 'stock_id' => 'id' ]);
  74 + }
  75 +
  76 + /**
  77 + * @return ActiveQuery
  78 + */
  79 + public function getProductVariants()
  80 + {
  81 + return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ])
  82 + ->via('productStocks');
  83 + }
  84 +
  85 + /**
  86 + * @return ActiveQuery
  87 + */
  88 + public function getProducts()
  89 + {
  90 + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ])
  91 + ->via('productVariants');
  92 + }
  93 + }
... ...
artbox-ecommerce/models/StockLang.php 0 → 100644
  1 +++ a/artbox-ecommerce/models/StockLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "brand_lang".
  11 + *
  12 + * @property integer $stock_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property Stock $stock
  16 + * @property Language $language
  17 + */
  18 + class StockLang extends ActiveRecord
  19 + {
  20 +
  21 + public static function primaryKey()
  22 + {
  23 + return [
  24 + 'stock_id',
  25 + 'language_id',
  26 + ];
  27 + }
  28 +
  29 + /**
  30 + * @inheritdoc
  31 + */
  32 + public static function tableName()
  33 + {
  34 + return 'stock_lang';
  35 + }
  36 +
  37 + /**
  38 + * @inheritdoc
  39 + */
  40 + public function rules()
  41 + {
  42 + return [
  43 + [
  44 + [ 'title' ],
  45 + 'required',
  46 + ],
  47 + [
  48 + [
  49 + 'title',
  50 + ],
  51 + 'string',
  52 + 'max' => 255,
  53 + ],
  54 + [
  55 + [
  56 + 'stock_id',
  57 + 'language_id',
  58 + ],
  59 + 'unique',
  60 + 'targetAttribute' => [
  61 + 'stock_id',
  62 + 'language_id',
  63 + ],
  64 + 'message' => 'The combination of Stock ID and Language ID has already been taken.',
  65 + ],
  66 + [
  67 + [ 'stock_id' ],
  68 + 'exist',
  69 + 'skipOnError' => true,
  70 + 'targetClass' => Stock::className(),
  71 + 'targetAttribute' => [ 'stock_id' => 'id' ],
  72 + ],
  73 + [
  74 + [ 'language_id' ],
  75 + 'exist',
  76 + 'skipOnError' => true,
  77 + 'targetClass' => Language::className(),
  78 + 'targetAttribute' => [ 'language_id' => 'id' ],
  79 + ],
  80 + ];
  81 + }
  82 +
  83 + /**
  84 + * @inheritdoc
  85 + */
  86 + public function attributeLabels()
  87 + {
  88 + return [
  89 + 'stock_id' => Yii::t('app', 'Stock ID'),
  90 + 'language_id' => Yii::t('app', 'Language ID'),
  91 + 'title' => Yii::t('app', 'Name'),
  92 + ];
  93 + }
  94 +
  95 + /**
  96 + * @return \yii\db\ActiveQuery
  97 + */
  98 + public function getStock()
  99 + {
  100 + return $this->hasOne(Stock::className(), [ 'id' => 'stock_id' ]);
  101 + }
  102 +
  103 + /**
  104 + * @return \yii\db\ActiveQuery
  105 + */
  106 + public function getLanguage()
  107 + {
  108 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  109 + }
  110 + }
... ...
artbox-ecommerce/models/TaxGroup.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxGroup.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\behaviors\LanguageBehavior;
  6 + use common\modules\language\models\Language;
  7 + use artweb\artbox\ecommerce\models\Category;
  8 + use yii\base\InvalidValueException;
  9 + use yii\db\ActiveQuery;
  10 + use yii\db\ActiveRecord;
  11 + use yii\web\Request;
  12 +
  13 + /**
  14 + * This is the model class for table "{{%tax_group}}".
  15 + *
  16 + * @property integer $id
  17 + * @property boolean $is_filter
  18 + * @property integer $level
  19 + * @property integer $sort
  20 + * @property boolean $display
  21 + * @property boolean $is_menu
  22 + * @property string $remote_id
  23 + * @property TaxOption[] $taxOptions
  24 + * @property Category[] $categories
  25 + * @property TaxOption[] $options
  26 + * @property TaxOption[] $customOptions
  27 + * @property string $alias
  28 + * * From language behavior *
  29 + * @property TaxGroupLang $lang
  30 + * @property TaxGroupLang[] $langs
  31 + * @property TaxGroupLang $objectLang
  32 + * @property string $ownerKey
  33 + * @property string $langKey
  34 + * @property TaxGroupLang[] $modelLangs
  35 + * @property bool $transactionStatus
  36 + * @method string getOwnerKey()
  37 + * @method void setOwnerKey( string $value )
  38 + * @method string getLangKey()
  39 + * @method void setLangKey( string $value )
  40 + * @method ActiveQuery getLangs()
  41 + * @method ActiveQuery getLang( integer $language_id )
  42 + * @method TaxGroupLang[] generateLangs()
  43 + * @method void loadLangs( Request $request )
  44 + * @method bool linkLangs()
  45 + * @method bool saveLangs()
  46 + * @method bool getTransactionStatus()
  47 + * * End language behavior *
  48 + */
  49 + class TaxGroup extends ActiveRecord
  50 + {
  51 +
  52 + const GROUP_PRODUCT = 0;
  53 + const GROUP_VARIANT = 1;
  54 +
  55 + /**
  56 + * @var TaxOption[] $options
  57 + */
  58 + protected $customOptions = [];
  59 +
  60 + /**
  61 + * @inheritdoc
  62 + */
  63 + public function behaviors()
  64 + {
  65 + return [
  66 + 'language' => [
  67 + 'class' => LanguageBehavior::className(),
  68 + ],
  69 + ];
  70 + }
  71 +
  72 + /**
  73 + * @inheritdoc
  74 + */
  75 + public static function tableName()
  76 + {
  77 + return 'tax_group';
  78 + }
  79 +
  80 + /**
  81 + * @inheritdoc
  82 + */
  83 + public function rules()
  84 + {
  85 + return [
  86 + [
  87 + [
  88 + 'is_filter',
  89 + 'display',
  90 + 'is_menu',
  91 + ],
  92 + 'boolean',
  93 + ],
  94 + [
  95 + [
  96 + 'level',
  97 + 'sort',
  98 + ],
  99 + 'integer',
  100 + ],
  101 + [
  102 + [ 'categories' ],
  103 + 'safe',
  104 + ],
  105 + ];
  106 + }
  107 +
  108 + /**
  109 + * @inheritdoc
  110 + */
  111 + public function attributeLabels()
  112 + {
  113 + return [
  114 + 'id' => 'Tax Group ID',
  115 + 'is_filter' => 'Use in filter',
  116 + 'sort' => 'Sort',
  117 + 'display' => 'Display',
  118 + 'is_menu' => 'Отображать в меню',
  119 + ];
  120 + }
  121 +
  122 + /**
  123 + * @return ActiveQuery
  124 + */
  125 + public function getCategories()
  126 + {
  127 + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ])
  128 + ->viaTable('tax_group_to_category', [ 'tax_group_id' => 'id' ]);
  129 + }
  130 +
  131 + /**
  132 + * Set categories to override tax_group_to_category table data
  133 + *
  134 + * @param int[] $values
  135 + */
  136 + public function setCategories(array $values)
  137 + {
  138 + $this->categories = $values;
  139 + }
  140 +
  141 + /**
  142 + * @inheritdoc
  143 + */
  144 + public function afterSave($insert, $changedAttributes)
  145 + {
  146 + parent::afterSave($insert, $changedAttributes);
  147 + $this->unlinkAll('categories', true);
  148 + $categories = [];
  149 + if (!empty( $this->categories )) {
  150 + $categories = Category::findAll($this->categories);
  151 + }
  152 + foreach ($categories as $category) {
  153 + $this->link('categories', $category);
  154 + }
  155 + }
  156 +
  157 + /**
  158 + * @return ActiveQuery
  159 + */
  160 + public function getTaxOptions()
  161 + {
  162 + return $this->hasMany(TaxOption::className(), [ 'tax_group_id' => 'id' ])
  163 + ->inverseOf('taxGroup');
  164 + }
  165 +
  166 + /**
  167 + * Synonim for getTaxOptions()
  168 + *
  169 + * @see TaxGroup::getTaxOptions()
  170 + * @return \yii\db\ActiveQuery
  171 + */
  172 + public function getOptions()
  173 + {
  174 + return $this->getTaxOptions();
  175 + }
  176 +
  177 + /**
  178 + * Get customOptins that were filled dynamically.
  179 + * If $fillDefault is true then fill $customOptions with TaxOptions for current TaxGroup
  180 + *
  181 + * @param bool $fillDefault
  182 + *
  183 + * @return TaxOption[]
  184 + */
  185 + public function getCustomOptions(bool $fillDefault = false): array
  186 + {
  187 + if ($fillDefault && empty( $this->custom_options )) {
  188 + $this->customOptions = $this->getTaxOptions()
  189 + ->with('lang')
  190 + ->all();
  191 + }
  192 + return $this->customOptions;
  193 + }
  194 +
  195 + /**
  196 + * Set customOptions
  197 + *
  198 + * @param TaxOption[] $value
  199 + */
  200 + public function setCustomOptions(array $value)
  201 + {
  202 + foreach ($value as $item) {
  203 + if (!( $item instanceof TaxOption )) {
  204 + throw new InvalidValueException('All elements must be instances of ' . TaxOption::className());
  205 + }
  206 + }
  207 + $this->customOptions = $value;
  208 + }
  209 +
  210 + /**
  211 + * Get default lang alias
  212 + *
  213 + * @return string
  214 + */
  215 + public function getAlias()
  216 + {
  217 + $default_lang = Language::getDefaultLanguage();
  218 + /**
  219 + * @var TaxGroupLang $lang
  220 + */
  221 + $lang = $this->getLang($default_lang->id)
  222 + ->one();
  223 + return $lang->alias;
  224 + }
  225 + }
... ...
artbox-ecommerce/models/TaxGroupLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxGroupLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "tax_group_lang".
  11 + *
  12 + * @property integer $tax_group_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property string $alias
  16 + * @property string $description
  17 + * @property Language $language
  18 + * @property TaxGroup $taxGroup
  19 + */
  20 + class TaxGroupLang extends ActiveRecord
  21 + {
  22 +
  23 + public static function primaryKey()
  24 + {
  25 + return [
  26 + 'tax_group_id',
  27 + 'language_id',
  28 + ];
  29 + }
  30 +
  31 + /**
  32 + * @inheritdoc
  33 + */
  34 + public static function tableName()
  35 + {
  36 + return 'tax_group_lang';
  37 + }
  38 +
  39 + public function behaviors()
  40 + {
  41 + return [
  42 + 'slug' => [
  43 + 'class' => 'common\behaviors\Slug',
  44 + ],
  45 + ];
  46 + }
  47 +
  48 + /**
  49 + * @inheritdoc
  50 + */
  51 + public function rules()
  52 + {
  53 + return [
  54 + [
  55 + [ 'title' ],
  56 + 'required',
  57 + ],
  58 + [
  59 + [ 'description' ],
  60 + 'string',
  61 + ],
  62 + [
  63 + [
  64 + 'title',
  65 + 'alias',
  66 + ],
  67 + 'string',
  68 + 'max' => 255,
  69 + ],
  70 + [
  71 + [
  72 + 'tax_group_id',
  73 + 'language_id',
  74 + ],
  75 + 'unique',
  76 + 'targetAttribute' => [
  77 + 'tax_group_id',
  78 + 'language_id',
  79 + ],
  80 + 'message' => 'The combination of Tax Group ID and Language ID has already been taken.',
  81 + ],
  82 + [
  83 + [ 'language_id' ],
  84 + 'exist',
  85 + 'skipOnError' => true,
  86 + 'targetClass' => Language::className(),
  87 + 'targetAttribute' => [ 'language_id' => 'id' ],
  88 + ],
  89 + [
  90 + [ 'tax_group_id' ],
  91 + 'exist',
  92 + 'skipOnError' => true,
  93 + 'targetClass' => TaxGroup::className(),
  94 + 'targetAttribute' => [ 'tax_group_id' => 'id' ],
  95 + ],
  96 + ];
  97 + }
  98 +
  99 + /**
  100 + * @inheritdoc
  101 + */
  102 + public function attributeLabels()
  103 + {
  104 + return [
  105 + 'tax_group_id' => Yii::t('app', 'Tax Group ID'),
  106 + 'language_id' => Yii::t('app', 'Language ID'),
  107 + 'title' => Yii::t('app', 'Name'),
  108 + 'description' => Yii::t('app', 'Description'),
  109 + 'alias' => Yii::t('app', 'Alias'),
  110 + ];
  111 + }
  112 +
  113 + /**
  114 + * @return \yii\db\ActiveQuery
  115 + */
  116 + public function getLanguage()
  117 + {
  118 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  119 + }
  120 +
  121 + /**
  122 + * @return \yii\db\ActiveQuery
  123 + */
  124 + public function getTaxGroup()
  125 + {
  126 + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]);
  127 + }
  128 + }
... ...
artbox-ecommerce/models/TaxGroupSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxGroupSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * TaxGroupSearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\TaxGroup`.
  11 + */
  12 + class TaxGroupSearch extends TaxGroup
  13 + {
  14 +
  15 + public $groupName;
  16 +
  17 + public function behaviors()
  18 + {
  19 + $behaviors = parent::behaviors();
  20 + if (isset( $behaviors[ 'language' ] )) {
  21 + unset( $behaviors[ 'language' ] );
  22 + }
  23 + return $behaviors;
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + */
  29 + public function rules()
  30 + {
  31 + return [
  32 + [
  33 + [
  34 + 'id',
  35 + 'level',
  36 + ],
  37 + 'integer',
  38 + ],
  39 + [
  40 + [
  41 + 'is_filter',
  42 + ],
  43 + 'boolean',
  44 + ],
  45 + [
  46 + [
  47 + 'groupName',
  48 + ],
  49 + 'safe',
  50 + ],
  51 + ];
  52 + }
  53 +
  54 + /**
  55 + * @inheritdoc
  56 + */
  57 + public function scenarios()
  58 + {
  59 + // bypass scenarios() implementation in the parent class
  60 + return Model::scenarios();
  61 + }
  62 +
  63 + /**
  64 + * Creates data provider instance with search query applied
  65 + *
  66 + * @param array $params
  67 + *
  68 + * @return ActiveDataProvider
  69 + */
  70 + public function search($params, int $level = null)
  71 + {
  72 + $query = TaxGroup::find()
  73 + ->joinWith('lang');
  74 +
  75 + $dataProvider = new ActiveDataProvider(
  76 + [
  77 + 'query' => $query,
  78 + 'sort' => [
  79 + 'attributes' => [
  80 + 'id',
  81 + 'is_filter',
  82 + 'groupName' => [
  83 + 'asc' => [ 'tax_group_lang.title' => SORT_ASC ],
  84 + 'desc' => [ 'tax_group_lang.title' => SORT_DESC ],
  85 + ],
  86 + ],
  87 + ],
  88 + ]
  89 + );
  90 +
  91 + $this->load($params);
  92 +
  93 + if (!is_null($level)) {
  94 + $this->level = $level;
  95 + }
  96 +
  97 + if (!$this->validate()) {
  98 + // uncomment the following line if you do not want to return any records when validation fails
  99 + // $query->where('0=1');
  100 + return $dataProvider;
  101 + }
  102 +
  103 + $query->andFilterWhere(
  104 + [
  105 + 'id' => $this->id,
  106 + 'is_filter' => $this->is_filter,
  107 + 'level' => $this->level,
  108 + ]
  109 + )
  110 + ->andFilterWhere(
  111 + [
  112 + 'ilike',
  113 + 'tax_group_lang.title',
  114 + $this->groupName,
  115 + ]
  116 + );
  117 +
  118 + return $dataProvider;
  119 + }
  120 + }
... ...
artbox-ecommerce/models/TaxGroupToCategory.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxGroupToCategory.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use artweb\artbox\ecommerce\models\Category;
  6 + use yii\db\ActiveRecord;
  7 +
  8 + /**
  9 + * This is the model class for table "tax_group_to_category".
  10 + *
  11 + * @property integer $tax_group_to_category_id
  12 + * @property integer $tax_group_id
  13 + * @property integer $category_id
  14 + * @property Category $category
  15 + * @property TaxGroup $taxGroup
  16 + */
  17 + class TaxGroupToCategory extends ActiveRecord
  18 + {
  19 +
  20 + /**
  21 + * @inheritdoc
  22 + */
  23 + public static function tableName()
  24 + {
  25 + return 'tax_group_to_category';
  26 + }
  27 +
  28 + /**
  29 + * @inheritdoc
  30 + */
  31 + public function rules()
  32 + {
  33 + return [
  34 + [
  35 + [
  36 + 'tax_group_id',
  37 + 'category_id',
  38 + ],
  39 + 'required',
  40 + ],
  41 + [
  42 + [
  43 + 'tax_group_id',
  44 + 'category_id',
  45 + ],
  46 + 'integer',
  47 + ],
  48 + [
  49 + [ 'category_id' ],
  50 + 'exist',
  51 + 'skipOnError' => true,
  52 + 'targetClass' => Category::className(),
  53 + 'targetAttribute' => [ 'category_id' => 'id' ],
  54 + ],
  55 + [
  56 + [ 'tax_group_id' ],
  57 + 'exist',
  58 + 'skipOnError' => true,
  59 + 'targetClass' => TaxGroup::className(),
  60 + 'targetAttribute' => [ 'tax_group_id' => 'id' ],
  61 + ],
  62 + ];
  63 + }
  64 +
  65 + /**
  66 + * @inheritdoc
  67 + */
  68 + public function attributeLabels()
  69 + {
  70 + return [
  71 + 'tax_group_to_category_id' => 'Tax Group To Category ID',
  72 + 'tax_group_id' => 'Tax Group ID',
  73 + 'category_id' => 'Category ID',
  74 + ];
  75 + }
  76 +
  77 + /**
  78 + * @return \yii\db\ActiveQuery
  79 + */
  80 + public function getCategory()
  81 + {
  82 + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]);
  83 + }
  84 +
  85 + /**
  86 + * @return \yii\db\ActiveQuery
  87 + */
  88 + public function getTaxGroup()
  89 + {
  90 + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]);
  91 + }
  92 + }
... ...
artbox-ecommerce/models/TaxOption.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxOption.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\behaviors\SaveImgBehavior;
  6 + use common\modules\language\behaviors\LanguageBehavior;
  7 + use artweb\artbox\ecommerce\models\Product;
  8 + use artweb\artbox\ecommerce\models\ProductVariant;
  9 + use Yii;
  10 + use yii\db\ActiveQuery;
  11 + use yii\db\ActiveRecord;
  12 + use yii\web\Request;
  13 +
  14 + /**
  15 + * This is the model class for table "{{%tax_option}}".
  16 + *
  17 + * @property string $id
  18 + * @property integer $tax_group_id
  19 + * @property integer $tree
  20 + * @property integer $sort
  21 + * @property string $image
  22 + * @property TaxGroup $taxGroup
  23 + * @property TaxGroup $group
  24 + * @property Product[] $products
  25 + * @property ProductVariant[] $productVariants
  26 + * * From language behavior *
  27 + * @property TaxOptionLang $lang
  28 + * @property TaxOptionLang[] $langs
  29 + * @property TaxOptionLang $objectLang
  30 + * @property string $ownerKey
  31 + * @property string $langKey
  32 + * @property TaxOptionLang[] $modelLangs
  33 + * @property bool $transactionStatus
  34 + * @method string getOwnerKey()
  35 + * @method void setOwnerKey( string $value )
  36 + * @method string getLangKey()
  37 + * @method void setLangKey( string $value )
  38 + * @method ActiveQuery getLangs()
  39 + * @method ActiveQuery getLang( integer $language_id )
  40 + * @method TaxOptionLang[] generateLangs()
  41 + * @method void loadLangs( Request $request )
  42 + * @method bool linkLangs()
  43 + * @method bool saveLangs()
  44 + * @method bool getTransactionStatus()
  45 + * * End language behavior *
  46 + * * From SaveImgBehavior
  47 + * @property string|null $imageFile
  48 + * @property string|null $imageUrl
  49 + * @method string|null getImageFile( int $field )
  50 + * @method string|null getImageUrl( int $field )
  51 + * * End SaveImgBehavior
  52 + */
  53 + class TaxOption extends ActiveRecord
  54 + {
  55 +
  56 + /**
  57 + * @inheritdoc
  58 + */
  59 + public function behaviors()
  60 + {
  61 + return [
  62 + [
  63 + 'class' => SaveImgBehavior::className(),
  64 + 'fields' => [
  65 + [
  66 + 'name' => 'image',
  67 + 'directory' => 'tax_option',
  68 + ],
  69 + ],
  70 + ],
  71 + 'language' => [
  72 + 'class' => LanguageBehavior::className(),
  73 + ],
  74 + ];
  75 + }
  76 +
  77 + /**
  78 + * @inheritdoc
  79 + */
  80 + public static function tableName()
  81 + {
  82 + return '{{%tax_option}}';
  83 + }
  84 +
  85 + /**
  86 + * @inheritdoc
  87 + */
  88 + public function rules()
  89 + {
  90 + return [
  91 + [
  92 + [
  93 + 'tax_group_id',
  94 + 'sort',
  95 + ],
  96 + 'integer',
  97 + ],
  98 + [
  99 + [ 'tax_group_id' ],
  100 + 'exist',
  101 + 'skipOnError' => true,
  102 + 'targetClass' => TaxGroup::className(),
  103 + 'targetAttribute' => [ 'tax_group_id' => 'id' ],
  104 + ],
  105 + ];
  106 + }
  107 +
  108 + /**
  109 + * @inheritdoc
  110 + */
  111 + public function attributeLabels()
  112 + {
  113 + return [
  114 + 'id' => Yii::t('app', 'Tax Option ID'),
  115 + 'tax_group_id' => Yii::t('app', 'Tax Group ID'),
  116 + 'sort' => Yii::t('app', 'Sort'),
  117 + 'image' => Yii::t('product', 'Image'),
  118 + ];
  119 + }
  120 +
  121 + /**
  122 + * @return \yii\db\ActiveQuery
  123 + */
  124 + public function getTaxGroup()
  125 + {
  126 + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ])
  127 + ->inverseOf('taxOptions');
  128 + }
  129 +
  130 + /**
  131 + * Synonim for TaxOption::getTaxGroup()
  132 + *
  133 + * @see TaxOption::getTaxGroup()
  134 + * @return \yii\db\ActiveQuery
  135 + */
  136 + public function getGroup()
  137 + {
  138 + return $this->getTaxGroup();
  139 + }
  140 +
  141 + /**
  142 + * @return ActiveQuery
  143 + */
  144 + public function getProducts()
  145 + {
  146 + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ])
  147 + ->viaTable('product_option', [ 'option_id' => 'id' ]);
  148 + }
  149 +
  150 + /**
  151 + * @return ActiveQuery
  152 + */
  153 + public function getProductVariants()
  154 + {
  155 + return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ])
  156 + ->viaTable('product_variant_option', [ 'option_id' => 'id' ]);
  157 + }
  158 + }
... ...
artbox-ecommerce/models/TaxOptionLang.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxOptionLang.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use common\modules\language\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "tax_option_lang".
  11 + *
  12 + * @property integer $tax_option_id
  13 + * @property integer $language_id
  14 + * @property string $value
  15 + * @property string $alias
  16 + * @property Language $language
  17 + * @property TaxOption $taxOption
  18 + */
  19 + class TaxOptionLang extends ActiveRecord
  20 + {
  21 +
  22 + public static function primaryKey()
  23 + {
  24 + return [
  25 + 'tax_option_id',
  26 + 'language_id',
  27 + ];
  28 + }
  29 +
  30 + /**
  31 + * @inheritdoc
  32 + */
  33 + public static function tableName()
  34 + {
  35 + return 'tax_option_lang';
  36 + }
  37 +
  38 + public function behaviors()
  39 + {
  40 + return [
  41 + 'slug' => [
  42 + 'class' => 'common\behaviors\Slug',
  43 + 'inAttribute' => 'value',
  44 + ],
  45 + ];
  46 + }
  47 +
  48 + /**
  49 + * @inheritdoc
  50 + */
  51 + public function rules()
  52 + {
  53 + return [
  54 + [
  55 + [ 'value' ],
  56 + 'required',
  57 + ],
  58 + [
  59 + [
  60 + 'value',
  61 + 'alias',
  62 + ],
  63 + 'string',
  64 + 'max' => 255,
  65 + ],
  66 + [
  67 + [
  68 + 'tax_option_id',
  69 + 'language_id',
  70 + ],
  71 + 'unique',
  72 + 'targetAttribute' => [
  73 + 'tax_option_id',
  74 + 'language_id',
  75 + ],
  76 + 'message' => 'The combination of Tax Option ID and Language ID has already been taken.',
  77 + ],
  78 + [
  79 + [ 'language_id' ],
  80 + 'exist',
  81 + 'skipOnError' => true,
  82 + 'targetClass' => Language::className(),
  83 + 'targetAttribute' => [ 'language_id' => 'id' ],
  84 + ],
  85 + [
  86 + [ 'tax_option_id' ],
  87 + 'exist',
  88 + 'skipOnError' => true,
  89 + 'targetClass' => TaxOption::className(),
  90 + 'targetAttribute' => [ 'tax_option_id' => 'id' ],
  91 + ],
  92 + ];
  93 + }
  94 +
  95 + /**
  96 + * @inheritdoc
  97 + */
  98 + public function attributeLabels()
  99 + {
  100 + return [
  101 + 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
  102 + 'language_id' => Yii::t('app', 'Language ID'),
  103 + 'value' => Yii::t('app', 'Value'),
  104 + 'alias' => Yii::t('app', 'Alias'),
  105 + ];
  106 + }
  107 +
  108 + /**
  109 + * @return \yii\db\ActiveQuery
  110 + */
  111 + public function getLanguage()
  112 + {
  113 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  114 + }
  115 +
  116 + /**
  117 + * @return \yii\db\ActiveQuery
  118 + */
  119 + public function getTaxOption()
  120 + {
  121 + return $this->hasOne(TaxOption::className(), [ 'id' => 'tax_option_id' ]);
  122 + }
  123 + }
... ...
artbox-ecommerce/models/TaxOptionSearch.php 0 → 100755
  1 +++ a/artbox-ecommerce/models/TaxOptionSearch.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\models;
  4 +
  5 + use yii\base\Model;
  6 + use yii\data\ActiveDataProvider;
  7 +
  8 + /**
  9 + * TaxOptionSearch represents the model behind the search form about
  10 + * `artweb\artbox\ecommerce\models\TaxOption`.
  11 + */
  12 + class TaxOptionSearch extends TaxOption
  13 + {
  14 +
  15 + public $value;
  16 +
  17 + public function behaviors()
  18 + {
  19 + $behaviors = parent::behaviors();
  20 + if (isset( $behaviors[ 'language' ] )) {
  21 + unset( $behaviors[ 'language' ] );
  22 + }
  23 + return $behaviors;
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + */
  29 + public function rules()
  30 + {
  31 + return [
  32 + [
  33 + [ 'value' ],
  34 + 'safe',
  35 + ],
  36 + [
  37 + [ 'id' ],
  38 + 'integer',
  39 + ],
  40 + ];
  41 + }
  42 +
  43 + /**
  44 + * @inheritdoc
  45 + */
  46 + public function scenarios()
  47 + {
  48 + // bypass scenarios() implementation in the parent class
  49 + return Model::scenarios();
  50 + }
  51 +
  52 + /**
  53 + * Creates data provider instance with search query applied
  54 + *
  55 + * @param array $params
  56 + *
  57 + * @return ActiveDataProvider
  58 + */
  59 + public function search($params)
  60 + {
  61 + $query = TaxOption::find()
  62 + ->joinWith('lang');
  63 +
  64 + $dataProvider = new ActiveDataProvider(
  65 + [
  66 + 'query' => $query,
  67 + 'sort' => [
  68 + 'attributes' => [
  69 + 'id',
  70 + 'value' => [
  71 + 'asc' => [ 'tax_option_lang.value' => SORT_ASC ],
  72 + 'desc' => [ 'tax_option_lang.value' => SORT_DESC ],
  73 + ],
  74 + ],
  75 + ],
  76 + ]
  77 + );
  78 +
  79 + $this->load($params);
  80 +
  81 + // if (!$this->validate()) {
  82 + // return $dataProvider;
  83 + // }
  84 +
  85 + // grid filtering conditions
  86 + $query->andFilterWhere(
  87 + [
  88 + 'id' => $this->id,
  89 + ]
  90 + )
  91 + ->andFilterWhere(
  92 + [
  93 + 'like',
  94 + 'tax_option_lang.value',
  95 + $this->value,
  96 + ]
  97 + );
  98 +
  99 + return $dataProvider;
  100 + }
  101 + }
... ...
artbox-ecommerce/views/manage/_form.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/_form.php
  1 +<?php
  2 +
  3 + use common\modules\language\widgets\LanguageForm;
  4 + use artweb\artbox\ecommerce\models\Brand;
  5 + use artweb\artbox\ecommerce\models\ProductLang;
  6 + use artweb\artbox\ecommerce\models\TaxGroup;
  7 + use yii\db\ActiveQuery;
  8 + use yii\helpers\Html;
  9 + use yii\widgets\ActiveForm;
  10 + use yii\helpers\ArrayHelper;
  11 + use common\components\artboxtree\ArtboxTreeHelper;
  12 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  13 + use kartik\select2\Select2;
  14 +
  15 + /**
  16 + * @var yii\web\View $this
  17 + * @var artweb\artbox\ecommerce\models\Product $model
  18 + * @var ProductLang[] $modelLangs
  19 + * @var yii\widgets\ActiveForm $form
  20 + * @var ActiveQuery $groups
  21 + */
  22 +?>
  23 +
  24 +<div class="product-form">
  25 +
  26 + <?php $form = ActiveForm::begin(
  27 + [
  28 + 'options' => [ 'enctype' => 'multipart/form-data' ],
  29 + ]
  30 + ); ?>
  31 +
  32 + <?= $form->field($model, 'is_top')
  33 + ->checkbox([ 'label' => 'ТОП' ]) ?>
  34 + <?= $form->field($model, 'is_new')
  35 + ->checkbox([ 'label' => 'Новинка' ]) ?>
  36 + <?= $form->field($model, 'is_discount')
  37 + ->checkbox([ 'label' => 'Акционный' ]) ?>
  38 +
  39 + <?= $form->field($model, 'video')
  40 + ->textarea(); ?>
  41 +
  42 + <?= $form->field($model, 'brand_id')
  43 + ->dropDownList(
  44 + ArrayHelper::map(
  45 + Brand::find()
  46 + ->with('lang')
  47 + ->all(),
  48 + 'id',
  49 + 'lang.title'
  50 + ),
  51 + [
  52 + 'prompt' => Yii::t('product', 'Select brand'),
  53 + ]
  54 + ) ?>
  55 +
  56 + <?= $form->field($model, 'categories')
  57 + ->widget(
  58 + Select2::className(),
  59 + [
  60 + 'data' => ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'id', 'lang.title'),
  61 + 'language' => 'ru',
  62 + 'options' => [
  63 + 'placeholder' => Yii::t('product', 'Select categories'),
  64 + 'multiple' => true,
  65 + ],
  66 + 'pluginOptions' => [
  67 + 'allowClear' => true,
  68 + ],
  69 + ]
  70 + ) ?>
  71 +
  72 + <?= $form->field($model, 'imagesUpload[]')
  73 + ->widget(
  74 + \kartik\file\FileInput::className(),
  75 + [
  76 + 'language' => 'ru',
  77 + 'options' => [
  78 + 'accept' => 'image/*',
  79 + 'multiple' => true,
  80 + ],
  81 + 'pluginOptions' => [
  82 + 'allowedFileExtensions' => [
  83 + 'jpg',
  84 + 'gif',
  85 + 'png',
  86 + ],
  87 + 'initialPreview' => !empty( $model->imagesHTML ) ? $model->imagesHTML : [],
  88 + 'initialPreviewConfig' => $model->imagesConfig,
  89 + 'overwriteInitial' => false,
  90 + 'showRemove' => false,
  91 + 'showUpload' => false,
  92 + 'uploadAsync' => !empty( $model->id ),
  93 + 'previewFileType' => 'image',
  94 + ],
  95 + ]
  96 + ); ?>
  97 +
  98 + <?php if (!empty( $groups )) {
  99 + foreach ($groups->with('lang')
  100 + ->all() as $group) {
  101 + /**
  102 + * @var TaxGroup $group
  103 + */
  104 + echo $form->field($model, 'options')
  105 + ->checkboxList(
  106 + ArrayHelper::map(
  107 + $group->getOptions()
  108 + ->with('lang')
  109 + ->all(),
  110 + 'id',
  111 + 'lang.value'
  112 + ),
  113 + [
  114 + 'multiple' => true,
  115 + 'unselect' => NULL,
  116 + ]
  117 + )
  118 + ->label($group->lang->title);
  119 + }
  120 + }
  121 + ?>
  122 +
  123 + <hr>
  124 +
  125 + <?= LanguageForm::widget(
  126 + [
  127 + 'modelLangs' => $modelLangs,
  128 + 'formView' => '@common/modules/product/views/manage/_form_language',
  129 + 'form' => $form,
  130 + ]
  131 + ) ?>
  132 +
  133 + <div class="form-group">
  134 + <?= Html::submitButton(
  135 + $model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'),
  136 + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]
  137 + ) ?>
  138 + </div>
  139 +
  140 + <?php ActiveForm::end(); ?>
  141 +
  142 +</div>
... ...
artbox-ecommerce/views/manage/_form_language.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/_form_language.php
  1 +<?php
  2 + use common\modules\language\models\Language;
  3 + use artweb\artbox\ecommerce\models\ProductLang;
  4 + use mihaildev\ckeditor\CKEditor;
  5 + use mihaildev\elfinder\ElFinder;
  6 + use yii\web\View;
  7 + use yii\widgets\ActiveForm;
  8 +
  9 + /**
  10 + * @var ProductLang $model_lang
  11 + * @var Language $language
  12 + * @var ActiveForm $form
  13 + * @var View $this
  14 + */
  15 +?>
  16 +<?= $form->field($model_lang, '[' . $language->id . ']title')
  17 + ->textInput([ 'maxlength' => true ]); ?>
  18 +<?= $form->field($model_lang, '[' . $language->id . ']alias')
  19 + ->textInput([ 'maxlength' => true ]); ?>
  20 +<?= $form->field($model_lang, '[' . $language->id . ']description')
  21 + ->widget(CKEditor::className(), [
  22 + 'editorOptions' => ElFinder::ckeditorOptions('elfinder', [
  23 + 'preset' => 'full',
  24 + 'inline' => false,
  25 + 'filebrowserUploadUrl' => Yii::$app->getUrlManager()
  26 + ->createUrl('file/uploader/images-upload'),
  27 + ]),
  28 + ]) ?>
0 29 \ No newline at end of file
... ...
artbox-ecommerce/views/manage/create.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/create.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Product;
  4 + use artweb\artbox\ecommerce\models\ProductLang;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var Product $model
  11 + * @var ProductLang[] $modelLangs
  12 + */
  13 +
  14 + $this->title = Yii::t('product', 'Create Product');
  15 + $this->params[ 'breadcrumbs' ][] = [
  16 + 'label' => Yii::t('product', 'Products'),
  17 + 'url' => [ 'index' ],
  18 + ];
  19 + $this->params[ 'breadcrumbs' ][] = $this->title;
  20 +?>
  21 +<div class="product-create">
  22 +
  23 + <h1><?= Html::encode($this->title) ?></h1>
  24 +
  25 + <?= $this->render('_form', [
  26 + 'model' => $model,
  27 + 'modelLangs' => $modelLangs,
  28 + ]) ?>
  29 +
  30 +</div>
... ...
artbox-ecommerce/views/manage/export-process.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/export-process.php
  1 +<?php
  2 + /**
  3 + * @var View $this
  4 + */
  5 +
  6 + use yii\web\View;
  7 +
  8 +?>
  9 +<?php
  10 + $this->registerJs("var in_process=true;
  11 + var count=1;
  12 + var filename = null;
  13 +
  14 + doExport(0,filename);
  15 +
  16 + function doExport(from,filename) {
  17 + from = typeof(from) != 'undefined' ? from : 0;
  18 +
  19 + $.ajax({
  20 + method: 'get',
  21 + url: '" . Yii::$app->request->baseUrl . '/product/manage/export-process' . "',
  22 + data: {
  23 + from:from,
  24 + filename: filename
  25 + },
  26 + dataType: 'json',
  27 + success: function(data){
  28 +
  29 + var per = Math.round(100*data.from/data.totalsize)+'%';
  30 + $('#progressbar div').css({width: per});
  31 +
  32 + if(data != false && !data.end)
  33 + {
  34 + doExport(data.from,data.filename);
  35 + }
  36 + else
  37 + {
  38 + console.log(data.link);
  39 + $(progressbar).hide('fast');
  40 + $('#result_link').attr('href', data.link).removeClass('hidden');
  41 + in_process = false;
  42 + }
  43 + },
  44 + error: function(xhr, status, errorThrown) {
  45 + }
  46 + });
  47 + }");
  48 +?>
  49 +
  50 +<!--<script>-->
  51 +<!-- var in_process=true;-->
  52 +<!-- var count=1;-->
  53 +<!-- var filename = null;-->
  54 +<!-- -->
  55 +<!-- doExport(0,filename);-->
  56 +<!-- -->
  57 +<!-- function doExport(from,filename) {-->
  58 +<!-- from = typeof(from) != 'undefined' ? from : 0;-->
  59 +<!-- -->
  60 +<!-- $.ajax({-->
  61 +<!-- method: 'get',-->
  62 +<!-- url: '".Yii::$app->request->baseUrl .'/product/manage/export-process'."',-->
  63 +<!-- data: {-->
  64 +<!-- from:from,-->
  65 +<!-- filename: filename-->
  66 +<!-- },-->
  67 +<!-- dataType: 'json',-->
  68 +<!-- success: function(data){-->
  69 +<!-- -->
  70 +<!-- var per = Math.round(100*data.from/data.totalsize)+'%';-->
  71 +<!-- $('#progressbar div').css({width: per});-->
  72 +<!-- -->
  73 +<!-- if(data != false && !data.end)-->
  74 +<!-- {-->
  75 +<!-- doExport(data.from,data.filename);-->
  76 +<!-- }-->
  77 +<!-- else-->
  78 +<!-- {-->
  79 +<!-- console.log(data.link);-->
  80 +<!-- progressbar.hide('fast');-->
  81 +<!-- in_process = false;-->
  82 +<!-- }-->
  83 +<!-- },-->
  84 +<!-- error: function(xhr, status, errorThrown) {-->
  85 +<!-- }-->
  86 +<!-- });-->
  87 +<!-- }-->
  88 +<!--</script>-->
  89 +
  90 +<div class="product-import-process-form">
  91 + <h1>Экспорт данных товаров</h1>
  92 +
  93 + <?= \yii\jui\ProgressBar::widget([
  94 + 'clientOptions' => [
  95 + 'value' => 100,
  96 + 'label' => '',
  97 + ],
  98 + 'options' => [
  99 + 'id' => 'progressbar',
  100 + ],
  101 + ]); ?>
  102 + <ul id="process-result"></ul>
  103 + <a id="result_link" href="" class="hidden"><?php echo \Yii::t('app', 'Get File'); ?></a>
  104 +</div>
... ...
artbox-ecommerce/views/manage/export.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/export.php
  1 +<?php
  2 +
  3 + use common\modules\language\models\Language;
  4 + use artweb\artbox\ecommerce\models\Export;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 + use yii\widgets\ActiveForm;
  8 +
  9 + /**
  10 + * @var View $this
  11 + * @var Export $model
  12 + */
  13 +?>
  14 +
  15 +<div class="product-import-form">
  16 + <?php $form = ActiveForm::begin([
  17 + 'enableClientValidation' => false,
  18 + 'options' => [ 'enctype' => 'multipart/form-data' ],
  19 + ]); ?>
  20 +
  21 + <?php if($model->errors) : ?>
  22 + <div class="error">
  23 + <?= implode("<br>\n", $model->errors); ?>
  24 + </div>
  25 + <?php endif ?>
  26 +
  27 + <?php if($model->output) : ?>
  28 + <h2>Лог операции</h2>
  29 + <div class="success" style="height: 10em;overflow: auto;border: 1px solid #000">
  30 + <?= implode("<br>\n", $model->output); ?>
  31 + </div>
  32 + <?php endif ?>
  33 +
  34 + <?= $form->field($model, 'lang')
  35 + ->dropDownList(Language::find()
  36 + ->select([
  37 + 'name',
  38 + 'id',
  39 + ])
  40 + ->where([ 'status' => 1 ])
  41 + ->orderBy([ 'default' => SORT_DESC ])
  42 + ->asArray()
  43 + ->indexBy('id')
  44 + ->column()) ?>
  45 +
  46 + <div class="form-group">
  47 + <?= Html::submitButton(Yii::t('product', 'Export'), [ 'class' => 'btn btn-success' ]) ?>
  48 + </div>
  49 +
  50 + <?php ActiveForm::end(); ?>
  51 +</div>
0 52 \ No newline at end of file
... ...
artbox-ecommerce/views/manage/import-process.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/import-process.php
  1 +<?php
  2 + /**
  3 + * @var View $this
  4 + * @var string $method
  5 + */
  6 + use yii\web\View;
  7 +
  8 + $this->registerJs("
  9 +var in_process=false;
  10 + var count=1;
  11 +
  12 + in_process=true;
  13 +
  14 + doImport();
  15 +
  16 + function doImport(from) {
  17 + from = typeof(from) != 'undefined' ? from : 0;
  18 + console.log('go', from);
  19 + $.ajax({
  20 + url: '" . \Yii::$app->request->baseUrl . '/product/manage/' . $method . "',
  21 + data: {from:from},
  22 + dataType: 'json',
  23 + success: function(data){
  24 + for(var key in data.items)
  25 + {
  26 + $('ul#process-result').prepend('<li>'+ data.items[key] +'</li>');
  27 + count++;
  28 + }
  29 +
  30 + var per = Math.round(100*data.from/data.totalsize)+'%';
  31 + $('#progressbar div').css({width: per});
  32 +
  33 + if(data != false && !data.end)
  34 + {
  35 + doImport(data.from);
  36 + }
  37 + else
  38 + {
  39 + $('ul#process-result').prepend('<li>Импорт цен успешно завершен!</li>');
  40 + progressbar.hide('fast');
  41 + in_process = false;
  42 + }
  43 + },
  44 + error: function(xhr, status, errorThrown) {
  45 + }
  46 + });
  47 + }
  48 +");
  49 + //?>
  50 +
  51 +<div class="product-import-process-form">
  52 + <h1>Импорт <?= $method == 'prices' ? 'цен' : 'данных' ?> товаров</h1>
  53 +
  54 + <?= \yii\jui\ProgressBar::widget([
  55 + 'clientOptions' => [
  56 + 'value' => 100,
  57 + 'label' => '',
  58 + ],
  59 + 'options' => [
  60 + 'id' => 'progressbar',
  61 + ],
  62 + ]); ?>
  63 + <ul id="process-result"></ul>
  64 +</div>
... ...
artbox-ecommerce/views/manage/import.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/import.php
  1 +<?php
  2 +
  3 + /**
  4 + * @var Import $model
  5 + * @var array $languages
  6 + */
  7 +
  8 + use artweb\artbox\ecommerce\models\Import;
  9 + use yii\helpers\Html;
  10 + use yii\widgets\ActiveForm;
  11 +
  12 +?>
  13 +
  14 +<div class="product-import-form">
  15 + <?php $form = ActiveForm::begin([
  16 + 'enableClientValidation' => false,
  17 + 'options' => [ 'enctype' => 'multipart/form-data' ],
  18 + ]); ?>
  19 +
  20 + <?php if($model->errors) : ?>
  21 + <div class="error">
  22 + <?= implode("<br>\n", $model->errors); ?>
  23 + </div>
  24 + <?php endif ?>
  25 +
  26 + <?php if($model->output) : ?>
  27 + <h2>Лог операции</h2>
  28 + <div class="success" style="height: 10em;overflow: auto;border: 1px solid #000">
  29 + <?= implode("<br>\n", $model->output); ?>
  30 + </div>
  31 + <?php endif ?>
  32 +
  33 + <?= $form->field($model, 'type')
  34 + ->radioList([
  35 + 'products' => Yii::t('product', 'Load products'),
  36 + 'prices' => Yii::t('product', 'Load prices'),
  37 + ]); ?>
  38 +
  39 + <?= $form->field($model, 'lang')
  40 + ->dropDownList($languages); ?>
  41 +
  42 + <?= $form->field($model, 'file')
  43 + ->fileInput([ 'multiple' => false, ]) ?>
  44 +
  45 + <?php /*= $form->field($model, 'file')->widget(\kartik\file\FileInput::classname(), [
  46 + 'language' => 'ru',
  47 + 'options' => [
  48 + 'multiple' => false,
  49 + ],
  50 + 'pluginOptions' => [
  51 + 'allowedFileExtensions' => ['csv'],
  52 + 'overwriteInitial' => true,
  53 + 'showRemove' => false,
  54 + 'showUpload' => false,
  55 + ],
  56 + ])*/ ?>
  57 +
  58 + <div class="form-group">
  59 + <?= Html::submitButton(Yii::t('product', 'Import'), [ 'class' => 'btn btn-primary' ]) ?>
  60 + </div>
  61 +
  62 + <?php ActiveForm::end(); ?>
  63 +</div>
... ...
artbox-ecommerce/views/manage/index.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/index.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Brand;
  4 + use artweb\artbox\ecommerce\models\Category;
  5 + use artweb\artbox\ecommerce\models\Product;
  6 + use artweb\artbox\ecommerce\models\ProductSearch;
  7 + use yii\data\ActiveDataProvider;
  8 + use yii\helpers\Html;
  9 + use yii\grid\GridView;
  10 + use kartik\select2\Select2;
  11 + use common\components\artboxtree\ArtboxTreeHelper;
  12 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  13 + use yii\web\View;
  14 +
  15 + /**
  16 + * @var View $this
  17 + * @var ProductSearch $searchModel
  18 + * @var ActiveDataProvider $dataProvider
  19 + */
  20 + $this->title = Yii::t('product', 'Products');
  21 + $this->params[ 'breadcrumbs' ][] = $this->title;
  22 +?>
  23 +<div class="product-index">
  24 +
  25 + <h1><?= Html::encode($this->title) ?></h1>
  26 +
  27 + <p>
  28 + <?= Html::a(Yii::t('product', 'Create Product'), [ 'create' ], [ 'class' => 'btn btn-success' ]) ?>
  29 + </p>
  30 + <?= GridView::widget(
  31 + [
  32 + 'dataProvider' => $dataProvider,
  33 + 'filterModel' => $searchModel,
  34 + 'columns' => [
  35 + 'id',
  36 + [
  37 + 'attribute' => 'productName',
  38 + 'value' => 'lang.title',
  39 + ],
  40 + [
  41 + 'label' => Yii::t('product', 'Brand'),
  42 + 'attribute' => 'brand_id',
  43 + 'value' => 'brand.lang.title',
  44 + 'filter' => Select2::widget(
  45 + [
  46 + 'model' => $searchModel,
  47 + 'attribute' => 'brand_id',
  48 + 'data' => Brand::find()
  49 + ->joinWith('lang')
  50 + ->select(
  51 + [
  52 + 'brand_lang.title',
  53 + 'brand.id',
  54 + ]
  55 + )
  56 + ->asArray()
  57 + ->indexBy('id')
  58 + ->column(),
  59 + 'language' => 'ru',
  60 + 'options' => [
  61 + 'placeholder' => Yii::t('product', 'Select brand'),
  62 + 'multiple' => false,
  63 + ],
  64 + 'pluginOptions' => [
  65 + 'allowClear' => true,
  66 + ],
  67 + ]
  68 + ),
  69 + ],
  70 + [
  71 + 'label' => Yii::t('product', 'Category'),
  72 + 'attribute' => 'categoryId',
  73 + 'value' => function ($model) {
  74 + /**
  75 + * @var Product $model
  76 + */
  77 + $categories = [];
  78 + foreach ($model->getCategories()
  79 + ->with('lang')
  80 + ->all() as $category) {
  81 + /**
  82 + * @var Category $category
  83 + */
  84 + $categories[] = $category->lang->title;
  85 + }
  86 + return implode(", ", $categories);
  87 + },
  88 + 'filter' => Select2::widget(
  89 + [
  90 + 'model' => $searchModel,
  91 + 'attribute' => 'categoryId',
  92 + 'data' => ArtboxTreeHelper::treeMap(
  93 + ProductHelper::getCategories(),
  94 + 'id',
  95 + 'lang.title'
  96 + ),
  97 + 'language' => 'ru',
  98 + 'options' => [
  99 + 'placeholder' => Yii::t('product', 'Select category'),
  100 + 'multiple' => false,
  101 + ],
  102 + 'pluginOptions' => [
  103 + 'allowClear' => true,
  104 + ],
  105 + ]
  106 + ),
  107 + ],
  108 + [
  109 + 'attribute' => 'variantCount',
  110 + 'value' => function ($model) {
  111 + /**
  112 + * @var Product $model
  113 + */
  114 + return count($model->variants);
  115 + },
  116 + ],
  117 + [
  118 + 'class' => 'yii\grid\ActionColumn',
  119 + 'template' => '{items} {view} |{is_top} {is_new} {is_discount} | {update} {delete}',
  120 + 'buttons' => [
  121 + 'is_top' => function ($url, $model) {
  122 + return Html::a(
  123 + '<span class="glyphicon glyphicon-star' . ( $model->is_top ? '' : '-empty' ) . '"></span>',
  124 + $url,
  125 + [
  126 + 'title' => Yii::t('product', ( $model->is_top ? 'Set not is top' : 'Set is top' )),
  127 + ]
  128 + );
  129 + },
  130 + 'is_new' => function ($url, $model) {
  131 + return Html::a(
  132 + '<span class="glyphicon glyphicon-heart' . ( $model->is_new ? '' : '-empty' ) . '"></span>',
  133 + $url,
  134 + [
  135 + 'title' => Yii::t('product', ( $model->is_new ? 'Set not is new' : 'Set is new' )),
  136 + ]
  137 + );
  138 + },
  139 + 'is_discount' => function ($url, $model) {
  140 + return Html::a(
  141 + '<span class="glyphicon glyphicon-tag' . ( $model->is_discount ? 's' : '' ) . '"></span>',
  142 + $url,
  143 + [
  144 + 'title' => Yii::t(
  145 + 'product',
  146 + ( $model->is_discount ? 'Set not is promotion' : 'Set is promotion' )
  147 + ),
  148 + ]
  149 + );
  150 + },
  151 + 'items' => function ($url, $model) {
  152 + return Html::a(
  153 + '<span class="glyphicon glyphicon-th-list"></span>',
  154 + $url,
  155 + [
  156 + 'title' => Yii::t('product', 'Variants'),
  157 + ]
  158 + );
  159 + },
  160 +
  161 + ],
  162 + 'urlCreator' => function ($action, $model, $key, $index) {
  163 + /**
  164 + * @var Product $model
  165 + */
  166 + switch ($action) {
  167 + case 'items':
  168 + return \yii\helpers\Url::to(
  169 + [
  170 + '/product/variant',
  171 + 'product_id' => $model->id,
  172 + ]
  173 + );
  174 + break;
  175 + case 'is_top':
  176 + return \yii\helpers\Url::to(
  177 + [
  178 + 'manage/is_top',
  179 + 'id' => $model->id,
  180 + ]
  181 + );
  182 + break;
  183 + case 'is_new':
  184 + return \yii\helpers\Url::to(
  185 + [
  186 + 'manage/is_new',
  187 + 'id' => $model->id,
  188 + ]
  189 + );
  190 + break;
  191 + case 'is_discount':
  192 + return \yii\helpers\Url::to(
  193 + [
  194 + 'manage/is-discount',
  195 + 'id' => $model->id,
  196 + ]
  197 + );
  198 + break;
  199 + case 'view':
  200 + return \yii\helpers\Url::to(
  201 + [
  202 + 'manage/view',
  203 + 'id' => $model->id,
  204 + ]
  205 + );
  206 + break;
  207 + case 'update':
  208 + return \yii\helpers\Url::to(
  209 + [
  210 + 'manage/update',
  211 + 'id' => $model->id,
  212 + ]
  213 + );
  214 + break;
  215 + case 'delete':
  216 + return \yii\helpers\Url::to(
  217 + [
  218 + 'manage/delete',
  219 + 'id' => $model->id,
  220 + ]
  221 + );
  222 + break;
  223 + default:
  224 + return '';
  225 + break;
  226 + }
  227 + },
  228 + ],
  229 + ],
  230 + ]
  231 + ); ?>
  232 +</div>
... ...
artbox-ecommerce/views/manage/update.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/update.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Product;
  4 + use artweb\artbox\ecommerce\models\ProductLang;
  5 + use yii\db\ActiveQuery;
  6 + use yii\helpers\Html;
  7 + use yii\web\View;
  8 +
  9 + /**
  10 + * @var View $this
  11 + * @var Product $model
  12 + * @var ProductLang[] $modelLangs
  13 + * @var ActiveQuery $groups
  14 + */
  15 +
  16 + $this->title = Yii::t('product', 'Update {modelClass}: ', [
  17 + 'modelClass' => 'Product',
  18 + ]) . ' ' . $model->lang->title;
  19 + $this->params[ 'breadcrumbs' ][] = [
  20 + 'label' => Yii::t('product', 'Products'),
  21 + 'url' => [ 'index' ],
  22 + ];
  23 + $this->params[ 'breadcrumbs' ][] = [
  24 + 'label' => $model->lang->title,
  25 + 'url' => [
  26 + 'view',
  27 + 'id' => $model->id,
  28 + ],
  29 + ];
  30 + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update');
  31 +?>
  32 +<div class="product-update">
  33 +
  34 + <h1><?= Html::encode($this->title) ?></h1>
  35 +
  36 + <?= $this->render('_form', [
  37 + 'model' => $model,
  38 + 'modelLangs' => $modelLangs,
  39 + 'groups' => $groups,
  40 + ]) ?>
  41 +
  42 +</div>
... ...
artbox-ecommerce/views/manage/view.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/manage/view.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Category;
  4 + use artweb\artbox\ecommerce\models\Product;
  5 + use artweb\artbox\ecommerce\models\ProductVariant;
  6 + use artweb\artbox\ecommerce\models\TaxGroup;
  7 + use yii\helpers\ArrayHelper;
  8 + use yii\helpers\Html;
  9 + use yii\web\View;
  10 + use yii\widgets\DetailView;
  11 +
  12 + /**
  13 + * @var View $this
  14 + * @var Product $model
  15 + * @var Category[] $categories
  16 + * @var TaxGroup[] $properties
  17 + * @var ProductVariant[] $variants
  18 + */
  19 +
  20 + $this->title = $model->lang->title;
  21 + $this->params[ 'breadcrumbs' ][] = [
  22 + 'label' => Yii::t('product', 'Products'),
  23 + 'url' => [ 'index' ],
  24 + ];
  25 + $this->params[ 'breadcrumbs' ][] = $this->title;
  26 + $properties_string = '';
  27 + foreach ($properties as $property) {
  28 + $property_list = '';
  29 + foreach ($property->options as $option) {
  30 + $property_list .= Html::tag('li', $option->lang->value);
  31 + }
  32 + $properties_string .= Html::tag('p', $property->lang->title) . Html::tag('ul', $property_list);
  33 + }
  34 + $variants_string = '';
  35 + foreach ($variants as $variant) {
  36 + $variants_string .= Html::a(
  37 + $variant->lang->title,
  38 + [
  39 + '/product/variant/view',
  40 + 'id' => $variant->id,
  41 + ]
  42 + ) . '<br>';
  43 + }
  44 +?>
  45 +<div class="product-view">
  46 +
  47 + <h1><?= Html::encode($this->title) ?></h1>
  48 +
  49 + <p>
  50 + <?= Html::a(
  51 + Yii::t('product', 'Update'),
  52 + [
  53 + 'update',
  54 + 'id' => $model->id,
  55 + ],
  56 + [ 'class' => 'btn btn-primary' ]
  57 + ) ?>
  58 + <?= Html::a(
  59 + Yii::t('product', 'Delete'),
  60 + [
  61 + 'delete',
  62 + 'id' => $model->id,
  63 + ],
  64 + [
  65 + 'class' => 'btn btn-danger',
  66 + 'data' => [
  67 + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
  68 + 'method' => 'post',
  69 + ],
  70 + ]
  71 + ) ?>
  72 + <?= Html::a(
  73 + Yii::t('product', 'Variants'),
  74 + [
  75 + '/product/variant/index',
  76 + 'product_id' => $model->id,
  77 + ],
  78 + [ 'class' => 'btn btn-info' ]
  79 + ) ?>
  80 + </p>
  81 +
  82 + <?= DetailView::widget(
  83 + [
  84 + 'model' => $model,
  85 + 'attributes' => [
  86 + 'id',
  87 + 'brand.lang.title',
  88 + [
  89 + 'label' => \Yii::t('app', 'Categories'),
  90 + 'value' => implode('<br>', ArrayHelper::getColumn($categories, 'lang.title')),
  91 + 'format' => 'html',
  92 + ],
  93 + [
  94 + 'attribute' => 'is_top',
  95 + 'value' => $model->is_top ? Html::tag(
  96 + 'span',
  97 + '',
  98 + [ 'class' => 'glyphicon glyphicon-ok' ]
  99 + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]),
  100 + 'format' => 'html',
  101 + ],
  102 + [
  103 + 'attribute' => 'is_new',
  104 + 'value' => $model->is_new ? Html::tag(
  105 + 'span',
  106 + '',
  107 + [ 'class' => 'glyphicon glyphicon-ok' ]
  108 + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]),
  109 + 'format' => 'html',
  110 + ],
  111 + [
  112 + 'attribute' => 'is_discount',
  113 + 'value' => $model->is_discount ? Html::tag(
  114 + 'span',
  115 + '',
  116 + [ 'class' => 'glyphicon glyphicon-ok' ]
  117 + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]),
  118 + 'format' => 'html',
  119 + ],
  120 + [
  121 + 'attribute' => 'video',
  122 + 'format' => 'html',
  123 + ],
  124 + [
  125 + 'label' => \Yii::t('app', 'Properties'),
  126 + 'value' => $properties_string,
  127 + 'format' => 'html',
  128 + ],
  129 + [
  130 + 'label' => \Yii::t('app', 'Variants'),
  131 + 'value' => $variants_string,
  132 + 'format' => 'html',
  133 + ],
  134 + 'lang.description:html',
  135 + 'image.imageUrl:image',
  136 + ],
  137 + ]
  138 + ) ?>
  139 +
  140 +</div>
... ...
artbox-ecommerce/views/product-unit/_form.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/_form.php
  1 +<?php
  2 +
  3 + use common\modules\language\widgets\LanguageForm;
  4 + use artweb\artbox\ecommerce\models\ProductUnit;
  5 + use artweb\artbox\ecommerce\models\ProductUnitLang;
  6 + use yii\helpers\Html;
  7 + use yii\web\View;
  8 + use yii\widgets\ActiveForm;
  9 +
  10 + /**
  11 + * @var View $this
  12 + * @var ProductUnit $model
  13 + * @var ProductUnitLang[] $modelLangs
  14 + * @var ActiveForm $form
  15 + */
  16 +?>
  17 +
  18 +<div class="product-unit-form">
  19 +
  20 + <?php $form = ActiveForm::begin(); ?>
  21 +
  22 + <?= $form->field($model, 'is_default')
  23 + ->checkbox() ?>
  24 +
  25 + <?= LanguageForm::widget([
  26 + 'modelLangs' => $modelLangs,
  27 + 'form' => $form,
  28 + 'formView' => '@common/modules/product/views/product-unit/_form_language',
  29 + ]) ?>
  30 +
  31 + <div class="form-group">
  32 + <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]) ?>
  33 + </div>
  34 +
  35 + <?php ActiveForm::end(); ?>
  36 +
  37 +</div>
... ...
artbox-ecommerce/views/product-unit/_form_language.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/_form_language.php
  1 +<?php
  2 + use common\modules\language\models\Language;
  3 + use artweb\artbox\ecommerce\models\ProductUnitLang;
  4 + use yii\web\View;
  5 + use yii\widgets\ActiveForm;
  6 +
  7 + /**
  8 + * @var ProductUnitLang $model_lang
  9 + * @var Language $language
  10 + * @var ActiveForm $form
  11 + * @var View $this
  12 + */
  13 +?>
  14 +<?= $form->field($model_lang, '[' . $language->id . ']title')
  15 + ->textInput([ 'maxlength' => true ]); ?>
  16 +<?= $form->field($model_lang, '[' . $language->id . ']short')
  17 + ->textInput([ 'maxlength' => true ]); ?>
0 18 \ No newline at end of file
... ...
artbox-ecommerce/views/product-unit/create.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/create.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\ProductUnit;
  4 + use artweb\artbox\ecommerce\models\ProductUnitLang;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var ProductUnit $model
  11 + * @var ProductUnitLang[] $modelLangs
  12 + */
  13 +
  14 + $this->title = Yii::t('product', 'Create Product Unit');
  15 + $this->params[ 'breadcrumbs' ][] = [
  16 + 'label' => Yii::t('product', 'Product Units'),
  17 + 'url' => [ 'index' ],
  18 + ];
  19 + $this->params[ 'breadcrumbs' ][] = $this->title;
  20 +?>
  21 +<div class="product-unit-create">
  22 +
  23 + <h1><?= Html::encode($this->title) ?></h1>
  24 +
  25 + <?= $this->render('_form', [
  26 + 'model' => $model,
  27 + 'modelLangs' => $modelLangs,
  28 + ]) ?>
  29 +
  30 +</div>
... ...
artbox-ecommerce/views/product-unit/index.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/index.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\ProductUnitSearch;
  4 + use yii\data\ActiveDataProvider;
  5 + use yii\helpers\Html;
  6 + use yii\grid\GridView;
  7 + use yii\web\View;
  8 +
  9 + /**
  10 + * @var View $this
  11 + * @var ProductUnitSearch $searchModel
  12 + * @var ActiveDataProvider $dataProvider
  13 + */
  14 +
  15 + $this->title = Yii::t('product', 'Product Units');
  16 + $this->params[ 'breadcrumbs' ][] = $this->title;
  17 +?>
  18 +<div class="product-unit-index">
  19 +
  20 + <h1><?= Html::encode($this->title) ?></h1>
  21 +
  22 + <p>
  23 + <?= Html::a(Yii::t('product', 'Create Product Unit'), [ 'create' ], [ 'class' => 'btn btn-success' ]) ?>
  24 + </p>
  25 + <?= GridView::widget(
  26 + [
  27 + 'dataProvider' => $dataProvider,
  28 + 'filterModel' => $searchModel,
  29 + 'columns' => [
  30 + 'id',
  31 + [
  32 + 'attribute' => 'is_default',
  33 + 'format' => 'boolean',
  34 + 'filter' => [
  35 + \Yii::$app->formatter->asBoolean(false),
  36 + \Yii::$app->formatter->asBoolean(true),
  37 + ],
  38 + ],
  39 + [
  40 + 'attribute' => 'title',
  41 + 'value' => 'lang.title',
  42 + ],
  43 + 'lang.short',
  44 + [ 'class' => 'yii\grid\ActionColumn' ],
  45 + ],
  46 + ]
  47 + ); ?>
  48 +</div>
... ...
artbox-ecommerce/views/product-unit/update.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/update.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\ProductUnit;
  4 + use artweb\artbox\ecommerce\models\ProductUnitLang;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var ProductUnit $model
  11 + * @var ProductUnitLang[] $modelLangs
  12 + */
  13 +
  14 + $this->title = Yii::t('product', 'Update {modelClass}: ', [
  15 + 'modelClass' => 'Product Unit',
  16 + ]) . $model->lang->title;
  17 + $this->params[ 'breadcrumbs' ][] = [
  18 + 'label' => Yii::t('product', 'Product Units'),
  19 + 'url' => [ 'index' ],
  20 + ];
  21 + $this->params[ 'breadcrumbs' ][] = [
  22 + 'label' => $model->lang->title,
  23 + 'url' => [
  24 + 'view',
  25 + 'id' => $model->id,
  26 + ],
  27 + ];
  28 + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update');
  29 +?>
  30 +<div class="product-unit-update">
  31 +
  32 + <h1><?= Html::encode($this->title) ?></h1>
  33 +
  34 + <?= $this->render('_form', [
  35 + 'model' => $model,
  36 + 'modelLangs' => $modelLangs,
  37 + ]) ?>
  38 +
  39 +</div>
... ...
artbox-ecommerce/views/product-unit/view.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/product-unit/view.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\ProductUnit;
  4 + use yii\helpers\Html;
  5 + use yii\web\View;
  6 + use yii\widgets\DetailView;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var ProductUnit $model
  11 + */
  12 +
  13 + $this->title = $model->lang->title;
  14 + $this->params[ 'breadcrumbs' ][] = [
  15 + 'label' => Yii::t('product', 'Product Units'),
  16 + 'url' => [ 'index' ],
  17 + ];
  18 + $this->params[ 'breadcrumbs' ][] = $this->title;
  19 +?>
  20 +<div class="product-unit-view">
  21 +
  22 + <h1><?= Html::encode($this->title) ?></h1>
  23 +
  24 + <p>
  25 + <?= Html::a(
  26 + Yii::t('product', 'Update'),
  27 + [
  28 + 'update',
  29 + 'id' => $model->id,
  30 + ],
  31 + [ 'class' => 'btn btn-primary' ]
  32 + ) ?>
  33 + <?= Html::a(
  34 + Yii::t('product', 'Delete'),
  35 + [
  36 + 'delete',
  37 + 'id' => $model->id,
  38 + ],
  39 + [
  40 + 'class' => 'btn btn-danger',
  41 + 'data' => [
  42 + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
  43 + 'method' => 'post',
  44 + ],
  45 + ]
  46 + ) ?>
  47 + </p>
  48 +
  49 + <?= DetailView::widget(
  50 + [
  51 + 'model' => $model,
  52 + 'attributes' => [
  53 + 'id',
  54 + 'is_default:boolean',
  55 + 'lang.title',
  56 + 'lang.short',
  57 + ],
  58 + ]
  59 + ) ?>
  60 +
  61 +</div>
... ...
artbox-ecommerce/views/tax-group/_form.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/_form.php
  1 +<?php
  2 +
  3 + use common\modules\language\widgets\LanguageForm;
  4 + use artweb\artbox\ecommerce\models\TaxGroup;
  5 + use artweb\artbox\ecommerce\models\TaxGroupLang;
  6 + use yii\helpers\Html;
  7 + use yii\web\View;
  8 + use yii\widgets\ActiveForm;
  9 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  10 + use common\components\artboxtree\ArtboxTreeHelper;
  11 +
  12 + /**
  13 + * @var View $this
  14 + * @var TaxGroup $model
  15 + * @var TaxGroupLang[] $modelLangs
  16 + * @var ActiveForm $form
  17 + */
  18 +?>
  19 +
  20 +<div class="tax-group-form">
  21 +
  22 + <?php $form = ActiveForm::begin([ 'options' => [ 'enctype' => 'multipart/form-data' ] ]); ?>
  23 +
  24 + <?= $form->field($model, 'categories')
  25 + ->dropDownList(ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'id', 'lang.title'), [
  26 + 'multiple' => true,
  27 + ])
  28 + ->label('Use in the following categories') ?>
  29 +
  30 + <?= $form->field($model, 'is_filter')
  31 + ->checkbox() ?>
  32 +
  33 + <?= $form->field($model, 'display')
  34 + ->checkbox() ?>
  35 +
  36 + <?= $form->field($model, 'is_menu')
  37 + ->checkbox() ?>
  38 +
  39 + <?= $form->field($model, 'sort')
  40 + ->textInput() ?>
  41 +
  42 + <?php
  43 + echo LanguageForm::widget([
  44 + 'modelLangs' => $modelLangs,
  45 + 'formView' => '@common/modules/rubrication/views/tax-group/_form_language',
  46 + 'form' => $form,
  47 + ]);
  48 + ?>
  49 +
  50 + <div class="form-group">
  51 + <?= Html::submitButton($model->isNewRecord ? Yii::t('rubrication', 'Create') : Yii::t('rubrication', 'Update'), [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]) ?>
  52 + </div>
  53 +
  54 + <?php ActiveForm::end(); ?>
  55 +
  56 +</div>
... ...
artbox-ecommerce/views/tax-group/_form_language.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/_form_language.php
  1 +<?php
  2 + use common\modules\language\models\Language;
  3 + use artweb\artbox\ecommerce\models\TaxGroupLang;
  4 + use yii\web\View;
  5 + use yii\widgets\ActiveForm;
  6 +
  7 + /**
  8 + * @var TaxGroupLang $model_lang
  9 + * @var Language $language
  10 + * @var ActiveForm $form
  11 + * @var View $this
  12 + */
  13 +?>
  14 +<?= $form->field($model_lang, '[' . $language->id . ']title')
  15 + ->textInput([ 'maxlength' => true ]); ?>
  16 +<?= $form->field($model_lang, '[' . $language->id . ']alias')
  17 + ->textInput([ 'maxlength' => true ]); ?>
  18 +<?= $form->field($model_lang, '[' . $language->id . ']description')
  19 + ->textarea([ 'rows' => 6 ]) ?>
0 20 \ No newline at end of file
... ...
artbox-ecommerce/views/tax-group/create.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/create.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxGroupLang;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var TaxGroup $model
  11 + * @var TaxGroupLang[] $modelLangs
  12 + */
  13 + $this->title = Yii::t('rubrication', 'Create Tax Group');
  14 + $this->params[ 'breadcrumbs' ][] = [
  15 + 'label' => Yii::t('rubrication', 'Tax Groups'),
  16 + 'url' => [ 'index' ],
  17 + ];
  18 + $this->params[ 'breadcrumbs' ][] = $this->title;
  19 +?>
  20 +<div class="tax-group-create">
  21 +
  22 + <h1><?= Html::encode($this->title) ?></h1>
  23 +
  24 + <?= $this->render('_form', [
  25 + 'model' => $model,
  26 + 'modelLangs' => $modelLangs,
  27 + ]) ?>
  28 +
  29 +</div>
... ...
artbox-ecommerce/views/tax-group/index.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/index.php
  1 +<?php
  2 + use artweb\artbox\ecommerce\models\TaxGroup;
  3 + use artweb\artbox\ecommerce\models\TaxGroupSearch;
  4 + use yii\data\ActiveDataProvider;
  5 + use yii\helpers\Html;
  6 + use yii\grid\GridView;
  7 + use yii\helpers\Url;
  8 + use yii\web\View;
  9 +
  10 + /**
  11 + * @var View $this
  12 + * @var integer $level
  13 + * @var ActiveDataProvider $dataProvider
  14 + * @var TaxGroupSearch $searchModel
  15 + * @var TaxGroup $model
  16 + */
  17 +
  18 + $this->title = $level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups');
  19 + $this->params[ 'breadcrumbs' ][] = $this->title;
  20 +?>
  21 +
  22 +<div class="tax-group-index">
  23 +
  24 + <h1><?= Html::encode($this->title) ?></h1>
  25 + <p>
  26 + <?= Html::a(
  27 + Yii::t('rubrication', 'Create Group'),
  28 + Url::to(
  29 + [
  30 + '/rubrication/tax-group/create',
  31 + 'level' => $level,
  32 + ]
  33 + ),
  34 + [ 'class' => 'btn btn-success' ]
  35 + ) ?>
  36 + </p>
  37 +
  38 + <?= GridView::widget(
  39 + [
  40 + 'dataProvider' => $dataProvider,
  41 + 'filterModel' => $searchModel,
  42 + 'columns' => [
  43 + [ 'class' => 'yii\grid\SerialColumn' ],
  44 + 'id',
  45 + [
  46 + 'attribute' => 'is_filter',
  47 + 'format' => 'boolean',
  48 + 'filter' => \Yii::$app->formatter->booleanFormat,
  49 + ],
  50 + [
  51 + 'attribute' => 'groupName',
  52 + 'value' => 'lang.title',
  53 + ],
  54 + [
  55 + 'label' => \Yii::t('rubrication', 'Options count'),
  56 + 'value' => function ($model) {
  57 + /**
  58 + * @var TaxGroup $model
  59 + */
  60 + return count($model->options);
  61 + },
  62 + ],
  63 + [
  64 + 'label' => \Yii::t('rubrication', 'Categories count'),
  65 + 'value' => function ($model) {
  66 + /**
  67 + * @var TaxGroup $model
  68 + */
  69 + return count($model->categories);
  70 + },
  71 + ],
  72 + [
  73 + 'class' => 'yii\grid\ActionColumn',
  74 + 'template' => '{update} {options} {delete}',
  75 + 'buttons' => [
  76 + 'options' => function ($url, $model) {
  77 + return Html::a(
  78 + '<span class="glyphicon glyphicon-th-list"></span>',
  79 + $url,
  80 + [
  81 + 'title' => Yii::t('rubrication', 'Options'),
  82 + ]
  83 + );
  84 + },
  85 + ],
  86 + 'urlCreator' => function ($action, $model, $key, $index) use ($level) {
  87 + if ($action === 'options') {
  88 + $url = '/admin/rubrication/tax-option?group=' . $model->id;
  89 + return $url;
  90 + } elseif ($action === 'update') {
  91 + $url = Url::to(
  92 + [
  93 + '/rubrication/tax-group/update',
  94 + 'level' => $level,
  95 + 'id' => $model->id,
  96 + ]
  97 + );
  98 + return $url;
  99 + } elseif ($action === 'delete') {
  100 + $url = Url::to(
  101 + [
  102 + '/rubrication/tax-group/delete',
  103 + 'level' => $level,
  104 + 'id' => $model->id,
  105 + ]
  106 + );
  107 + return $url;
  108 + }
  109 + return '';
  110 + },
  111 + ],
  112 + ],
  113 + ]
  114 + ); ?>
  115 +</div>
  116 +
... ...
artbox-ecommerce/views/tax-group/update.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/update.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxGroupLang;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 +
  8 + /**
  9 + * @var View $this
  10 + * @var TaxGroup $model
  11 + * @var TaxGroupLang[] $modelLangs
  12 + * @var int $level
  13 + */
  14 +
  15 + $this->title = Yii::t('rubrication', 'Update {modelClass}: ', [
  16 + 'modelClass' => 'Tax Group',
  17 + ]) . ' ' . $model->lang->title;
  18 + $this->params[ 'breadcrumbs' ][] = [
  19 + 'label' => $level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'),
  20 + 'url' => [
  21 + 'index',
  22 + 'level' => $level,
  23 + ],
  24 + ];
  25 + $this->params[ 'breadcrumbs' ][] = Yii::t('rubrication', 'Update');
  26 +?>
  27 +<div class="tax-group-update">
  28 +
  29 + <h1><?= Html::encode($this->title) ?></h1>
  30 +
  31 + <?= $this->render('_form', [
  32 + 'model' => $model,
  33 + 'modelLangs' => $modelLangs,
  34 + ]) ?>
  35 +
  36 +</div>
... ...
artbox-ecommerce/views/tax-group/view.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-group/view.php
  1 +<?php
  2 +
  3 + use yii\helpers\Html;
  4 + use yii\widgets\DetailView;
  5 +
  6 + /* @var $this yii\web\View */
  7 + /* @var $model artweb\artbox\ecommerce\models\TaxGroup */
  8 +
  9 + $this->title = $model->id;
  10 + $this->params[ 'breadcrumbs' ][] = [
  11 + 'label' => Yii::t('rubrication', 'Tax Groups'),
  12 + 'url' => [ 'index' ],
  13 + ];
  14 + $this->params[ 'breadcrumbs' ][] = $this->title;
  15 +?>
  16 +<div class="tax-group-view">
  17 +
  18 + <h1><?= Html::encode($this->title) ?></h1>
  19 +
  20 + <p>
  21 + <?= Html::a(
  22 + Yii::t('rubrication', 'Update'),
  23 + [
  24 + 'update',
  25 + 'id' => $model->id,
  26 + ],
  27 + [ 'class' => 'btn btn-primary' ]
  28 + ) ?>
  29 + <?= Html::a(
  30 + Yii::t('rubrication', 'Delete'),
  31 + [
  32 + 'delete',
  33 + 'id' => $model->id,
  34 + ],
  35 + [
  36 + 'class' => 'btn btn-danger',
  37 + 'data' => [
  38 + 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'),
  39 + 'method' => 'post',
  40 + ],
  41 + ]
  42 + ) ?>
  43 + <?= Html::a(
  44 + Yii::t('rubrication', 'Create Option'),
  45 + [ 'tax-option/create?group=' . $model->id ],
  46 + [ 'class' => 'btn btn-success' ]
  47 + ) ?>
  48 + </p>
  49 +
  50 + <?= DetailView::widget(
  51 + [
  52 + 'model' => $model,
  53 + 'attributes' => [
  54 + 'id',
  55 + 'is_filter:boolean',
  56 + ],
  57 + ]
  58 + ) ?>
  59 +
  60 +</div>
... ...
artbox-ecommerce/views/tax-option/_form.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/_form.php
  1 +<?php
  2 +
  3 + use common\modules\language\widgets\LanguageForm;
  4 + use artweb\artbox\ecommerce\models\TaxGroup;
  5 + use artweb\artbox\ecommerce\models\TaxOptionLang;
  6 + use yii\helpers\ArrayHelper;
  7 + use yii\helpers\Html;
  8 + use yii\widgets\ActiveForm;
  9 + use artweb\artbox\ecommerce\models\TaxOption;
  10 +
  11 + /**
  12 + * @var yii\web\View $this
  13 + * @var artweb\artbox\ecommerce\models\TaxOption $model
  14 + * @var yii\widgets\ActiveForm $form
  15 + * @var TaxGroup $group
  16 + * @var TaxOptionLang[] $modelLangs
  17 + */
  18 +?>
  19 +
  20 +<div class="tax-option-form">
  21 +
  22 + <?php $form = ActiveForm::begin([ 'options' => [ 'enctype' => 'multipart/form-data' ] ]); ?>
  23 + <?php if (empty( $group->id )) : ?>
  24 + <?= $form->field($model, 'tax_group_id')
  25 + ->dropDownList(
  26 + ArrayHelper::map(
  27 + TaxOption::find()
  28 + ->all(),
  29 + 'tax_group_id',
  30 + 'tax_group_id'
  31 + ),
  32 + [
  33 + 'prompt' => Yii::t('rubrication', 'Select group'),
  34 + ]
  35 + ) ?>
  36 + <?php else : ?>
  37 + <?= $form->field($model, 'tax_group_id')
  38 + ->hiddenInput()
  39 + ->label('') ?>
  40 + <?php endif ?>
  41 +
  42 + <?= $form->field($model, 'image')
  43 + ->widget(
  44 + \kartik\file\FileInput::className(),
  45 + [
  46 + 'language' => 'ru',
  47 + 'options' => [
  48 + 'accept' => 'image/*',
  49 + 'multiple' => false,
  50 + ],
  51 + 'pluginOptions' => [
  52 + 'allowedFileExtensions' => [
  53 + 'jpg',
  54 + 'gif',
  55 + 'png',
  56 + ],
  57 + 'initialPreview' => !empty( $model->imageUrl ) ? \common\components\artboximage\ArtboxImageHelper::getImage(
  58 + $model->imageUrl,
  59 + 'list'
  60 + ) : '',
  61 + 'overwriteInitial' => true,
  62 + 'showRemove' => false,
  63 + 'showUpload' => false,
  64 + 'previewFileType' => 'image',
  65 + ],
  66 + ]
  67 + )
  68 + ->hint(
  69 + ( ( $model->tax_group_id == 5 ) ? 'Для корректного отображения на сайте, размер изображения должен быть 262x144 либо соблюдать соотношение сторон примерно 2:1' : '' )
  70 + ); ?>
  71 + <?= $form->field($model, 'sort')
  72 + ->textInput() ?>
  73 +
  74 + <?php
  75 + echo LanguageForm::widget(
  76 + [
  77 + 'modelLangs' => $modelLangs,
  78 + 'formView' => '@common/modules/rubrication/views/tax-option/_form_language',
  79 + 'form' => $form,
  80 + ]
  81 + );
  82 + ?>
  83 +
  84 + <div class="form-group">
  85 + <?= Html::submitButton(
  86 + $model->isNewRecord ? Yii::t('rubrication', 'Create') : Yii::t('rubrication', 'Update'),
  87 + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]
  88 + ) ?>
  89 + <?php if ($model->isNewRecord) : ?>
  90 + <?= Html::submitButton(
  91 + Yii::t('rubrication', 'Create and continue'),
  92 + [
  93 + 'name' => 'create_and_new',
  94 + 'class' => 'btn btn-primary',
  95 + ]
  96 + ) ?>
  97 + <?php endif ?>
  98 + </div>
  99 +
  100 + <?php ActiveForm::end(); ?>
  101 +
  102 +</div>
... ...
artbox-ecommerce/views/tax-option/_form_language.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/_form_language.php
  1 +<?php
  2 + use common\modules\language\models\Language;
  3 + use artweb\artbox\ecommerce\models\TaxOptionLang;
  4 + use yii\web\View;
  5 + use yii\widgets\ActiveForm;
  6 +
  7 + /**
  8 + * @var TaxOptionLang $model_lang
  9 + * @var Language $language
  10 + * @var ActiveForm $form
  11 + * @var View $this
  12 + */
  13 +?>
  14 +<?= $form->field($model_lang, '[' . $language->id . ']value')
  15 + ->textInput([ 'maxlength' => true ]); ?>
  16 +<?= $form->field($model_lang, '[' . $language->id . ']alias')
  17 + ->textInput([ 'maxlength' => true ]); ?>
... ...
artbox-ecommerce/views/tax-option/create.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/create.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxOptionLang;
  5 + use yii\helpers\Html;
  6 +
  7 + /**
  8 + * @var yii\web\View $this
  9 + * @var artweb\artbox\ecommerce\models\TaxOption $model
  10 + * @var TaxGroup $group
  11 + * @var TaxOptionLang[] $modelLangs
  12 + */
  13 + $this->title = Yii::t('rubrication', 'Create Tax Option');
  14 + $this->params[ 'breadcrumbs' ][] = [
  15 + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'),
  16 + 'url' => [
  17 + 'tax-group/index',
  18 + 'level' => $group->level,
  19 + ],
  20 + ];
  21 + $this->params[ 'breadcrumbs' ][] = [
  22 + 'label' => $group->lang->title,
  23 + 'url' => [
  24 + 'tax-group/update',
  25 + 'id' => $group->id,
  26 + 'level' => $group->level,
  27 + ],
  28 + ];
  29 + $this->params[ 'breadcrumbs' ][] = [
  30 + 'label' => Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]),
  31 + 'url' => [
  32 + 'index',
  33 + 'group' => $group->id,
  34 + 'level' => $group->level,
  35 + ],
  36 + ];
  37 + $this->params[ 'breadcrumbs' ][] = $this->title;
  38 +?>
  39 +<div class="tax-option-create">
  40 +
  41 + <h1><?= Html::encode($this->title) ?></h1>
  42 +
  43 + <?= $this->render('_form', [
  44 + 'model' => $model,
  45 + 'modelLangs' => $modelLangs,
  46 + 'group' => $group,
  47 + ]) ?>
  48 +
  49 +</div>
... ...
artbox-ecommerce/views/tax-option/index.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/index.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxOption;
  5 + use yii\helpers\Html;
  6 + use yii\grid\GridView;
  7 +
  8 + /**
  9 + * @var yii\web\View $this
  10 + * @var artweb\artbox\ecommerce\models\TaxOptionSearch $searchModel
  11 + * @var yii\data\ActiveDataProvider $dataProvider
  12 + * @var TaxGroup $group
  13 + */
  14 +
  15 + $this->title = Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]);
  16 + $this->params[ 'breadcrumbs' ][] = [
  17 + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t(
  18 + 'rubrication',
  19 + 'Product Groups'
  20 + ),
  21 + 'url' => [
  22 + 'tax-group/index',
  23 + 'level' => $group->level,
  24 + ],
  25 + ];
  26 + $this->params[ 'breadcrumbs' ][] = [
  27 + 'label' => $group->lang->title,
  28 + 'url' => [
  29 + 'tax-group/update',
  30 + 'id' => $group->id,
  31 + 'level' => $group->level,
  32 + ],
  33 + ];
  34 + $this->params[ 'breadcrumbs' ][] = $this->title;
  35 +?>
  36 +<div class="tax-option-index">
  37 +
  38 + <h1><?= Html::encode($this->title) ?></h1>
  39 +
  40 + <p>
  41 + <?= Html::a(
  42 + Yii::t('rubrication', 'Create Option'),
  43 + [ 'create?group=' . $group->id ],
  44 + [ 'class' => 'btn btn-success' ]
  45 + ) ?>
  46 + </p>
  47 +
  48 + <?php echo GridView::widget(
  49 + [
  50 + 'dataProvider' => $dataProvider,
  51 + 'filterModel' => $searchModel,
  52 + 'columns' => [
  53 + [ 'class' => 'yii\grid\SerialColumn' ],
  54 + 'id',
  55 + [
  56 + 'attribute' => 'value',
  57 + 'value' => 'lang.value',
  58 + ],
  59 + 'imageUrl:image',
  60 + [
  61 + 'label' => $group->level ? \Yii::t('rubrication', 'Variants count') : \Yii::t(
  62 + 'rubrication',
  63 + 'Products count'
  64 + ),
  65 + 'value' => function ($model) use ($group) {
  66 + /**
  67 + * @var TaxOption $model
  68 + */
  69 + return count($group->level ? $model->productVariants : $model->products);
  70 + },
  71 + ],
  72 + [
  73 + 'class' => 'yii\grid\ActionColumn',
  74 + 'template' => '{update} {delete}',
  75 + ],
  76 + ],
  77 + ]
  78 + ); ?>
  79 +</div>
... ...
artbox-ecommerce/views/tax-option/update.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/update.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxOptionLang;
  5 + use yii\helpers\Html;
  6 +
  7 + /**
  8 + * @var yii\web\View $this
  9 + * @var artweb\artbox\ecommerce\models\TaxOption $model
  10 + * @var TaxGroup $group
  11 + * @var TaxOptionLang[] $modelLangs
  12 + */
  13 + $this->title = Yii::t('rubrication', 'Update {modelClass}: ', [
  14 + 'modelClass' => 'Tax Option',
  15 + ]) . ' ' . $model->lang->value;
  16 + $this->params[ 'breadcrumbs' ][] = [
  17 + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'),
  18 + 'url' => [
  19 + 'tax-group/index',
  20 + 'level' => $group->level,
  21 + ],
  22 + ];
  23 + $this->params[ 'breadcrumbs' ][] = [
  24 + 'label' => $group->lang->title,
  25 + 'url' => [
  26 + 'tax-group/update',
  27 + 'id' => $group->id,
  28 + 'level' => $group->level,
  29 + ],
  30 + ];
  31 + $this->params[ 'breadcrumbs' ][] = [
  32 + 'label' => Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]),
  33 + 'url' => [
  34 + 'index',
  35 + 'group' => $group->id,
  36 + 'level' => $group->level,
  37 + ],
  38 + ];
  39 + $this->params[ 'breadcrumbs' ][] = $this->title;
  40 +?>
  41 +<div class="tax-option-update">
  42 +
  43 + <h1><?= Html::encode($this->title) ?></h1>
  44 +
  45 + <?= $this->render('_form', [
  46 + 'model' => $model,
  47 + 'modelLangs' => $modelLangs,
  48 + 'group' => $group,
  49 + ]) ?>
  50 +
  51 +</div>
... ...
artbox-ecommerce/views/tax-option/view.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/tax-option/view.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\TaxGroup;
  4 + use artweb\artbox\ecommerce\models\TaxOption;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 + use yii\widgets\DetailView;
  8 +
  9 + /**
  10 + * @var View $this
  11 + * @var TaxOption $model
  12 + * @var TaxGroup $group
  13 + */
  14 +
  15 + $this->title = $model->id;
  16 + $this->params[ 'breadcrumbs' ][] = [
  17 + 'label' => Yii::t('rubrication', 'Groups'),
  18 + 'url' => [ 'tax-group/index' ],
  19 + ];
  20 + $this->params[ 'breadcrumbs' ][] = [
  21 + 'label' => Yii::t('rubrication', $group->id),
  22 + 'url' => [
  23 + 'index',
  24 + 'group' => $group->id,
  25 + ],
  26 + ];
  27 + $this->params[ 'breadcrumbs' ][] = [
  28 + 'label' => Yii::t('rubrication', Yii::t('rubrication', 'Options of {title}', [ 'title' => $group->id ])),
  29 + 'url' => [
  30 + 'index',
  31 + 'group' => $group->id,
  32 + ],
  33 + ];
  34 + $this->params[ 'breadcrumbs' ][] = $this->title;
  35 +?>
  36 +<div class="tax-option-view">
  37 +
  38 + <h1><?= Html::encode($this->title) ?></h1>
  39 +
  40 + <p>
  41 + <?= Html::a(
  42 + Yii::t('rubrication', 'Update'),
  43 + [
  44 + 'update',
  45 + 'id' => $model->id,
  46 + ],
  47 + [ 'class' => 'btn btn-primary' ]
  48 + ) ?>
  49 + <?= Html::a(
  50 + Yii::t('rubrication', 'Delete'),
  51 + [
  52 + 'delete',
  53 + 'id' => $model->id,
  54 + ],
  55 + [
  56 + 'class' => 'btn btn-danger',
  57 + 'data' => [
  58 + 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'),
  59 + 'method' => 'post',
  60 + ],
  61 + ]
  62 + ) ?>
  63 + <?= Html::a(
  64 + Yii::t('rubrication', 'Create Option'),
  65 + [ 'tax-option/create?group=' . $model->id ],
  66 + [ 'class' => 'btn btn-success' ]
  67 + ) ?>
  68 + </p>
  69 +
  70 + <?= DetailView::widget(
  71 + [
  72 + 'model' => $model,
  73 + 'attributes' => [
  74 + 'id',
  75 + 'group.id',
  76 + 'sort',
  77 + ],
  78 + ]
  79 + ) ?>
  80 +
  81 +</div>
... ...
artbox-ecommerce/views/variant/_form.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/_form.php
  1 +<?php
  2 +
  3 + use common\modules\language\widgets\LanguageForm;
  4 + use artweb\artbox\ecommerce\models\Product;
  5 + use artweb\artbox\ecommerce\models\ProductStock;
  6 + use artweb\artbox\ecommerce\models\ProductUnit;
  7 + use artweb\artbox\ecommerce\models\ProductVariant;
  8 + use artweb\artbox\ecommerce\models\ProductVariantLang;
  9 + use artweb\artbox\ecommerce\models\TaxGroup;
  10 + use yii\db\ActiveQuery;
  11 + use yii\helpers\Html;
  12 + use yii\web\View;
  13 + use yii\widgets\ActiveForm;
  14 + use yii\helpers\ArrayHelper;
  15 + use wbraganca\dynamicform\DynamicFormWidget;
  16 +
  17 + /**
  18 + * @var View $this
  19 + * @var ProductVariant $model
  20 + * @var ProductVariantLang[] $modelLangs
  21 + * @var ActiveQuery $groups
  22 + * @var ProductStock[] $stocks
  23 + * @var ActiveForm $form
  24 + * @var Product $product
  25 + */
  26 +
  27 + $js = '
  28 +$(".dynamicform_wrapper").on("beforeDelete", function(e, item) {
  29 + if (! confirm("Are you sure you want to delete this item?")) {
  30 + return false;
  31 + }
  32 + return true;
  33 +});
  34 +
  35 +$(".dynamicform_wrapper").on("limitReached", function(e, item) {
  36 + alert("Limit reached");
  37 +});
  38 +';
  39 +
  40 + $this->registerJs($js, View::POS_END);
  41 +?>
  42 +<div class="product-form">
  43 +
  44 + <?php $form = ActiveForm::begin(
  45 + [
  46 + 'id' => 'dynamic-form',
  47 + 'options' => [ 'enctype' => 'multipart/form-data' ],
  48 + ]
  49 + ); ?>
  50 +
  51 + <?= $form->field($model, 'product_id')
  52 + ->hiddenInput()
  53 + ->label(false); ?>
  54 +
  55 + <?= $form->field($model, 'sku')
  56 + ->textarea(); ?>
  57 + <?= $form->field($model, 'price')
  58 + ->textarea(); ?>
  59 + <?= $form->field($model, 'price_old')
  60 + ->textarea(); ?>
  61 + <?= $form->field($model, 'imagesUpload[]')
  62 + ->widget(
  63 + \kartik\file\FileInput::className(),
  64 + [
  65 + 'language' => 'ru',
  66 + 'options' => [
  67 + 'accept' => 'image/*',
  68 + 'multiple' => true,
  69 + ],
  70 + 'pluginOptions' => [
  71 + 'allowedFileExtensions' => [
  72 + 'jpg',
  73 + 'gif',
  74 + 'png',
  75 + ],
  76 + 'initialPreview' => !empty( $model->imagesHTML ) ? $model->imagesHTML : [],
  77 + 'initialPreviewConfig' => $model->imagesConfig,
  78 + 'overwriteInitial' => false,
  79 + 'showRemove' => false,
  80 + 'showUpload' => false,
  81 + 'uploadAsync' => !empty( $model->id ),
  82 + 'previewFileType' => 'image',
  83 + ],
  84 + ]
  85 + ); ?>
  86 +
  87 + <?= LanguageForm::widget(
  88 + [
  89 + 'modelLangs' => $modelLangs,
  90 + 'formView' => '@common/modules/product/views/variant/_form_language',
  91 + 'form' => $form,
  92 + ]
  93 + ) ?>
  94 +
  95 + <?php DynamicFormWidget::begin(
  96 + [
  97 + 'widgetContainer' => 'dynamicform_wrapper',
  98 + // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
  99 + 'widgetBody' => '.container-items',
  100 + // required: css class selector
  101 + 'widgetItem' => '.item',
  102 + // required: css class
  103 + 'limit' => 10,
  104 + // the maximum times, an element can be added (default 999)
  105 + 'min' => 0,
  106 + // 0 or 1 (default 1)
  107 + 'insertButton' => '.add-item',
  108 + // css class
  109 + 'deleteButton' => '.remove-item',
  110 + // css class
  111 + 'model' => $stocks[ 0 ],
  112 + 'formId' => 'dynamic-form',
  113 + 'formFields' => [
  114 + 'quantity',
  115 + 'title',
  116 + ],
  117 + ]
  118 + ); ?>
  119 +
  120 + <div class="panel panel-default">
  121 + <div class="panel-heading">
  122 + <h4>
  123 + <i class="glyphicon glyphicon-envelope"></i> Склады
  124 + <button type="button" class="add-item btn btn-success btn-sm pull-right">
  125 + <i class="glyphicon glyphicon-plus"></i> Add
  126 + </button>
  127 + </h4>
  128 + </div>
  129 + <div class="panel-body">
  130 + <div class="container-items"><!-- widgetBody -->
  131 + <?php foreach ($stocks as $i => $stock): ?>
  132 + <div class="item panel panel-default"><!-- widgetItem -->
  133 + <div class="panel-body">
  134 + <?php
  135 + // necessary for update action.
  136 + if (!$stock->isNewRecord) {
  137 + echo Html::activeHiddenInput($stock, "[{$i}]stock_id");
  138 + }
  139 + ?>
  140 + <div class="row">
  141 + <div class="col-sm-5">
  142 + <?= $form->field($stock, "[{$i}]quantity")
  143 + ->textInput([ 'maxlength' => true ]) ?>
  144 + </div>
  145 + <div class="col-sm-5">
  146 + <?= $form->field($stock, "[{$i}]title")
  147 + ->textInput([ 'maxlength' => true ]) ?>
  148 + </div>
  149 + <div class="col-sm-2" style="margin-top: 30px">
  150 + <button type="button" class="remove-item btn btn-danger btn-xs">
  151 + <i class="glyphicon glyphicon-minus"></i></button>
  152 + </div>
  153 + </div><!-- .row -->
  154 + </div>
  155 + </div>
  156 + <?php endforeach; ?>
  157 + </div>
  158 + </div>
  159 + </div><!-- .panel -->
  160 + <?php DynamicFormWidget::end(); ?>
  161 +
  162 + <?= $form->field($model, 'product_unit_id')
  163 + ->dropDownList(
  164 + ArrayHelper::map(
  165 + ProductUnit::find()
  166 + ->with('lang')
  167 + ->all(),
  168 + 'id',
  169 + 'lang.title'
  170 + )
  171 + )
  172 + ->label(Yii::t('product', 'Unit')) ?>
  173 +
  174 + <?php if (!empty( $groups )) {
  175 + foreach ($groups->with('lang')
  176 + ->all() as $group) {
  177 + /**
  178 + * @var TaxGroup $group
  179 + */
  180 + echo $form->field($model, 'options')
  181 + ->checkboxList(
  182 + ArrayHelper::map(
  183 + $group->getOptions()
  184 + ->with('lang')
  185 + ->all(),
  186 + 'id',
  187 + 'lang.value'
  188 + ),
  189 + [
  190 + 'multiple' => true,
  191 + 'unselect' => null,
  192 + ]
  193 + )
  194 + ->label($group->lang->title);
  195 + }
  196 + } ?>
  197 +
  198 + <div class="form-group">
  199 + <?= Html::submitButton(
  200 + $model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'),
  201 + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]
  202 + ) ?>
  203 + </div>
  204 +
  205 + <?php ActiveForm::end(); ?>
  206 +
  207 +</div>
... ...
artbox-ecommerce/views/variant/_form_language.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/_form_language.php
  1 +<?php
  2 + use common\modules\language\models\Language;
  3 + use artweb\artbox\ecommerce\models\ProductVariantLang;
  4 + use yii\web\View;
  5 + use yii\widgets\ActiveForm;
  6 +
  7 + /**
  8 + * @var ProductVariantLang $model_lang
  9 + * @var Language $language
  10 + * @var ActiveForm $form
  11 + * @var View $this
  12 + */
  13 +?>
  14 +<?= $form->field($model_lang, '[' . $language->id . ']title')
  15 + ->textInput([ 'maxlength' => true ]); ?>
0 16 \ No newline at end of file
... ...
artbox-ecommerce/views/variant/create.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/create.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Product;
  4 + use artweb\artbox\ecommerce\models\ProductStock;
  5 + use artweb\artbox\ecommerce\models\ProductVariant;
  6 + use artweb\artbox\ecommerce\models\ProductVariantLang;
  7 + use yii\db\ActiveQuery;
  8 + use yii\helpers\Html;
  9 + use yii\web\View;
  10 +
  11 + /**
  12 + * @var View $this
  13 + * @var ProductVariant $model
  14 + * @var ProductVariantLang[] $modelLangs
  15 + * @var ActiveQuery $groups
  16 + * @var ProductStock[] $stocks
  17 + * @var Product $product
  18 + */
  19 + $this->title = Yii::t('product', 'Create Variant');
  20 + $this->params[ 'breadcrumbs' ][] = [
  21 + 'label' => Yii::t('product', 'Products'),
  22 + 'url' => [ '/product/manage/index' ],
  23 + ];
  24 + $this->params[ 'breadcrumbs' ][] = [
  25 + 'label' => $product->lang->title,
  26 + 'url' => [
  27 + '/product/manage/view',
  28 + 'id' => $product->id,
  29 + ],
  30 + ];
  31 + $this->params[ 'breadcrumbs' ][] = [
  32 + 'label' => Yii::t('product', 'Variants'),
  33 + 'url' => [
  34 + 'index',
  35 + 'product_id' => $product->id,
  36 + ],
  37 + ];
  38 + $this->params[ 'breadcrumbs' ][] = $this->title;
  39 +?>
  40 +<div class="product-create">
  41 +
  42 + <h1><?= Html::encode($this->title) ?></h1>
  43 +
  44 + <?= $this->render(
  45 + '_form',
  46 + [
  47 + 'model' => $model,
  48 + 'modelLangs' => $modelLangs,
  49 + 'groups' => $groups,
  50 + 'stocks' => $stocks,
  51 + 'product' => $product,
  52 + ]
  53 + ) ?>
  54 +
  55 +</div>
... ...
artbox-ecommerce/views/variant/index.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/index.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Product;
  4 + use artweb\artbox\ecommerce\models\ProductVariantSearch;
  5 + use yii\data\ActiveDataProvider;
  6 + use yii\helpers\Html;
  7 + use yii\grid\GridView;
  8 + use yii\helpers\Url;
  9 + use yii\web\View;
  10 +
  11 + /**
  12 + * @var View $this
  13 + * @var ProductVariantSearch $searchModel
  14 + * @var ActiveDataProvider $dataProvider
  15 + * @var Product $product
  16 + */
  17 +
  18 + $this->title = Yii::t('product', 'Variants for ') . $product->lang->title;
  19 + $this->params[ 'breadcrumbs' ][] = [
  20 + 'label' => Yii::t('product', 'Products'),
  21 + 'url' => [ '/product/manage/index' ],
  22 + ];
  23 + $this->params[ 'breadcrumbs' ][] = [
  24 + 'label' => $product->lang->title,
  25 + 'url' => [
  26 + '/product/manage/view',
  27 + 'id' => $product->id,
  28 + ],
  29 + ];
  30 + $this->params[ 'breadcrumbs' ][] = \Yii::t('product', 'Variants');
  31 +?>
  32 +<div class="product-index">
  33 +
  34 + <h1><?= Html::encode($this->title) ?></h1>
  35 +
  36 + <p>
  37 + <?= Html::a(
  38 + Yii::t('product', 'Create Variant'),
  39 + Url::toRoute(
  40 + [
  41 + 'create',
  42 + 'product_id' => $product->id,
  43 + ]
  44 + ),
  45 + [ 'class' => 'btn btn-success' ]
  46 + ) ?>
  47 + </p>
  48 + <?= GridView::widget(
  49 + [
  50 + 'dataProvider' => $dataProvider,
  51 + 'filterModel' => $searchModel,
  52 + 'columns' => [
  53 + 'id',
  54 + [
  55 + 'attribute' => 'variantName',
  56 + 'value' => 'lang.title',
  57 + ],
  58 + 'sku',
  59 + 'price',
  60 + 'price_old',
  61 + 'stock',
  62 + 'image.imageUrl:image',
  63 + [
  64 + 'class' => 'yii\grid\ActionColumn',
  65 + 'buttons' => [
  66 + 'view' => function ($url, $model) {
  67 + return Html::a(
  68 + '<span class="glyphicon glyphicon-eye-open"></span>',
  69 + Url::to(
  70 + [
  71 + 'view',
  72 + 'product_id' => $model->product_id,
  73 + 'id' => $model->id,
  74 + ]
  75 + ),
  76 + [
  77 + 'title' => \Yii::t('app', "Просмотр"),
  78 + ]
  79 + );
  80 + },
  81 + 'update' => function ($url, $model) {
  82 + return Html::a(
  83 + '<span class="glyphicon glyphicon-pencil"></span>',
  84 + Url::to(
  85 + [
  86 + 'update',
  87 + 'product_id' => $model->product_id,
  88 + 'id' => $model->id,
  89 + ]
  90 + ),
  91 + [
  92 + 'title' => \Yii::t('app', "Редактировать"),
  93 + ]
  94 + );
  95 + },
  96 + 'delete' => function ($url, $model) {
  97 +
  98 + return Html::a(
  99 + '<span class="glyphicon glyphicon-trash"></span>',
  100 + Url::to(
  101 + [
  102 + 'delete',
  103 + 'product_id' => $model->product_id,
  104 + 'id' => $model->id,
  105 + ]
  106 + ),
  107 + [
  108 + 'title' => Yii::t('yii', 'Delete'),
  109 + 'data-confirm' => Yii::t('yii', 'Are you sure to delete this item?'),
  110 + 'data-method' => 'post',
  111 + ]
  112 + );
  113 +
  114 + },
  115 + ],
  116 + ],
  117 + ],
  118 + ]
  119 + ); ?>
  120 +</div>
... ...
artbox-ecommerce/views/variant/update.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/update.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\Product;
  4 + use artweb\artbox\ecommerce\models\ProductStock;
  5 + use artweb\artbox\ecommerce\models\ProductVariant;
  6 + use artweb\artbox\ecommerce\models\ProductVariantLang;
  7 + use yii\db\ActiveQuery;
  8 + use yii\helpers\Html;
  9 + use yii\helpers\Url;
  10 + use yii\web\View;
  11 +
  12 + /**
  13 + * @var View $this
  14 + * @var ProductVariant $model
  15 + * @var ProductVariantLang[] $modelLangs
  16 + * @var ActiveQuery $groups
  17 + * @var ProductStock[] $stocks
  18 + * @var Product $product
  19 + */
  20 + $this->title = Yii::t(
  21 + 'product',
  22 + 'Update {modelClass}: ',
  23 + [
  24 + 'modelClass' => 'Product',
  25 + ]
  26 + ) . ' ' . $model->lang->title;
  27 + $this->params[ 'breadcrumbs' ][] = [
  28 + 'label' => Yii::t('product', 'Products'),
  29 + 'url' => [ '/product/manage/index' ],
  30 + ];
  31 + $this->params[ 'breadcrumbs' ][] = [
  32 + 'label' => $model->product->lang->title,
  33 + 'url' => [
  34 + '/product/manage/view',
  35 + 'id' => $model->product->id,
  36 + ],
  37 + ];
  38 + $this->params[ 'breadcrumbs' ][] = [
  39 + 'label' => Yii::t('product', 'Variants'),
  40 + 'url' => Url::to(
  41 + [
  42 + 'index',
  43 + 'product_id' => $model->product->id,
  44 + ]
  45 + ),
  46 + ];
  47 + $this->params[ 'breadcrumbs' ][] = [
  48 + 'label' => Yii::t('product', $model->lang->title),
  49 + 'url' => Url::to(
  50 + [
  51 + 'view',
  52 + 'id' => $model->id,
  53 + ]
  54 + ),
  55 + ];
  56 + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update');
  57 +?>
  58 +<div class="product-update">
  59 +
  60 + <h1><?= Html::encode($this->title) ?></h1>
  61 +
  62 + <?= $this->render(
  63 + '_form',
  64 + [
  65 + 'model' => $model,
  66 + 'modelLangs' => $modelLangs,
  67 + 'groups' => $groups,
  68 + 'stocks' => $stocks,
  69 + 'product' => $product,
  70 + ]
  71 + ) ?>
  72 +
  73 +</div>
... ...
artbox-ecommerce/views/variant/view.php 0 → 100755
  1 +++ a/artbox-ecommerce/views/variant/view.php
  1 +<?php
  2 +
  3 + use artweb\artbox\ecommerce\models\ProductVariant;
  4 + use artweb\artbox\ecommerce\models\TaxGroup;
  5 + use yii\helpers\Html;
  6 + use yii\web\View;
  7 + use yii\widgets\DetailView;
  8 +
  9 + /**
  10 + * @var View $this
  11 + * @var ProductVariant $model
  12 + * @var TaxGroup[] $properties
  13 + */
  14 +
  15 + $this->title = $model->lang->title;
  16 + $this->params[ 'breadcrumbs' ][] = [
  17 + 'label' => Yii::t('product', 'Products'),
  18 + 'url' => [ 'index' ],
  19 + ];
  20 + $this->params[ 'breadcrumbs' ][] = [
  21 + 'label' => $model->product->lang->title,
  22 + 'url' => [
  23 + 'view',
  24 + 'id' => $model->product->id,
  25 + ],
  26 + ];
  27 + $this->params[ 'breadcrumbs' ][] = [
  28 + 'label' => Yii::t('product', 'Variants'),
  29 + 'url' => [ '/product/variant?product_id=' . $model->product->id ],
  30 + ];
  31 + $this->params[ 'breadcrumbs' ][] = $this->title;
  32 + $properties_string = '';
  33 + foreach ($properties as $property) {
  34 + $options_string = '';
  35 + foreach ($property->options as $option) {
  36 + $options_string .= Html::tag('li', $option->lang->value);
  37 + }
  38 + $properties_string .= Html::tag('p', $property->lang->title) . Html::tag('ul', $options_string);
  39 + }
  40 +?>
  41 +<div class="product-view">
  42 +
  43 + <h1><?= Html::encode($this->title) ?></h1>
  44 +
  45 + <p>
  46 + <?= Html::a(
  47 + Yii::t('product', 'Update'),
  48 + [
  49 + 'update',
  50 + 'id' => $model->id,
  51 + ],
  52 + [ 'class' => 'btn btn-primary' ]
  53 + ) ?>
  54 + <?= Html::a(
  55 + Yii::t('product', 'Delete'),
  56 + [
  57 + 'delete',
  58 + 'id' => $model->id,
  59 + ],
  60 + [
  61 + 'class' => 'btn btn-danger',
  62 + 'data' => [
  63 + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
  64 + 'method' => 'post',
  65 + ],
  66 + ]
  67 + ) ?>
  68 + </p>
  69 +
  70 + <?= DetailView::widget(
  71 + [
  72 + 'model' => $model,
  73 + 'attributes' => [
  74 + 'id',
  75 + 'lang.title',
  76 + 'sku',
  77 + 'price',
  78 + 'price_old',
  79 + 'stock',
  80 + 'productUnit.lang.title',
  81 + [
  82 + 'attribute' => 'product_id',
  83 + 'value' => Html::a(
  84 + $model->product->fullname,
  85 + [
  86 + '/product/manage/view',
  87 + 'id' => $model->id,
  88 + ]
  89 + ),
  90 + 'format' => 'html',
  91 + ],
  92 + 'image.imageUrl:image',
  93 + [
  94 + 'label' => \Yii::t('app', 'Properties'),
  95 + 'value' => $properties_string,
  96 + 'format' => 'html',
  97 + ],
  98 + ],
  99 + ]
  100 + ) ?>
  101 +
  102 +</div>
... ...
artbox-ecommerce/widgets/brandsCarouselWidget.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/brandsCarouselWidget.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\widgets;
  4 +
  5 + use artweb\artbox\ecommerce\models\Brand;
  6 + use yii\base\Widget;
  7 +
  8 + class brandsCarouselWidget extends Widget
  9 + {
  10 +
  11 + public function init()
  12 + {
  13 + parent::init();
  14 + }
  15 +
  16 + public function run()
  17 + {
  18 + $brands = Brand::find()
  19 + ->with('lang')
  20 + ->all();
  21 + return $this->render(
  22 + 'brandsCarousel',
  23 + [
  24 + 'brands' => $brands,
  25 + ]
  26 + );
  27 + }
  28 + }
  29 +
0 30 \ No newline at end of file
... ...
artbox-ecommerce/widgets/lastProducts.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/lastProducts.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\widgets;
  4 +
  5 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  6 + use yii\base\Widget;
  7 +
  8 + class lastProducts extends Widget
  9 + {
  10 +
  11 + public function init()
  12 + {
  13 + parent::init();
  14 + }
  15 +
  16 + public function run()
  17 + {
  18 + return $this->render(
  19 + 'products_block',
  20 + [
  21 + 'title' => \Yii::t('product', 'Вы недавно просматривали'),
  22 + 'class' => 'last-products',
  23 + 'products' => ProductHelper::getLastProducts(true),
  24 + ]
  25 + );
  26 + }
  27 + }
  28 +
0 29 \ No newline at end of file
... ...
artbox-ecommerce/widgets/similarProducts.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/similarProducts.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\widgets;
  4 +
  5 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  6 + use yii\base\Widget;
  7 + use Yii;
  8 +
  9 + class similarProducts extends Widget
  10 + {
  11 +
  12 + public $count = 10;
  13 +
  14 + public $title;
  15 +
  16 + public $product;
  17 +
  18 + public function init()
  19 + {
  20 + parent::init();
  21 + }
  22 +
  23 + public function run()
  24 + {
  25 + $products = ProductHelper::getSimilarProducts($this->product, $this->count);
  26 +
  27 + if (!$this->title) {
  28 + $this->title = Yii::t('product', 'Similar products');
  29 + }
  30 +
  31 + return $this->render(
  32 + 'products_block',
  33 + [
  34 + 'title' => $this->title,
  35 + 'class' => 'similar-products',
  36 + 'products' => $products,
  37 + ]
  38 + );
  39 + }
  40 + }
  41 +
0 42 \ No newline at end of file
... ...
artbox-ecommerce/widgets/specialProducts.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/specialProducts.php
  1 +<?php
  2 +
  3 + namespace artweb\artbox\ecommerce\widgets;
  4 +
  5 + use artweb\artbox\ecommerce\helpers\ProductHelper;
  6 + use yii\base\Widget;
  7 + use Yii;
  8 +
  9 + class specialProducts extends Widget
  10 + {
  11 +
  12 + public $type = 'top';
  13 +
  14 + public $count = 8;
  15 +
  16 + public $title;
  17 +
  18 + public function init()
  19 + {
  20 + parent::init();
  21 + }
  22 +
  23 + public function run()
  24 + {
  25 + $products = ProductHelper::getSpecialProducts($this->type, $this->count);
  26 +
  27 + if (!$this->title) {
  28 + switch ($this->type) {
  29 + case 'top':
  30 + $this->title = Yii::t('product', 'Top products');
  31 + break;
  32 + case 'promo':
  33 + $this->title = Yii::t('product', 'Promo products');
  34 + break;
  35 + case 'new':
  36 + $this->title = Yii::t('product', 'New products');
  37 + break;
  38 + }
  39 + }
  40 +
  41 + return $this->render(
  42 + 'products_block',
  43 + [
  44 + 'title' => $this->title,
  45 + 'class' => $this->type,
  46 + 'products' => $products,
  47 + ]
  48 + );
  49 + }
  50 + }
  51 +
0 52 \ No newline at end of file
... ...
artbox-ecommerce/widgets/views/brandsCarousel.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/views/brandsCarousel.php
  1 +<?php
  2 + /**
  3 + * @var Brand[] $brands
  4 + */
  5 + use common\components\artboximage\ArtboxImageHelper;
  6 + use artweb\artbox\ecommerce\models\Brand;
  7 +
  8 +?>
  9 +<div class="slider_prod">
  10 + <div class="pc_prev"></div>
  11 + <div class="prods_carousel">
  12 + <ul>
  13 + <?php foreach($brands as $brand) { ?>
  14 + <li>
  15 + <span><a href="<?= \yii\helpers\Url::to('/brands/' . $brand->lang->alias) ?>" title="<?= $brand->lang->title ?>"><?= $brand->image ? ArtboxImageHelper::getImage($brand->imageFile, 'brandlist') : '' ?></a></span>
  16 + </li>
  17 + <?php } ?>
  18 + </ul>
  19 + </div>
  20 + <div class="pc_next"></div>
  21 +</div>
0 22 \ No newline at end of file
... ...
artbox-ecommerce/widgets/views/product_smart.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/views/product_smart.php
  1 +<?php
  2 + /**
  3 + * @var $product artweb\artbox\ecommerce\models\Product
  4 + */
  5 + use yii\helpers\Html;
  6 + use yii\helpers\Url;
  7 +
  8 +?>
  9 +<div class="catalog_item">
  10 + <div class="wrapper">
  11 + <div class="item_container">
  12 + <input class="prodInfo" type="hidden" value="[]">
  13 + <div class="title">
  14 + <?= Html::a(
  15 + $product->lang->title,
  16 + Url::to(
  17 + [
  18 + 'catalog/product',
  19 + 'product' => $product->lang->alias,
  20 + ]
  21 + ),
  22 + [ 'class' => 'btn-product-details' ]
  23 + ) ?>
  24 + </div>
  25 + <div class="img">
  26 + <a class="btn-product-details" href="<?= Url::to(
  27 + [
  28 + 'catalog/product',
  29 + 'product' => $product->lang->alias,
  30 + ]
  31 + ) ?>">
  32 + <?= \common\components\artboximage\ArtboxImageHelper::getImage(
  33 + $product->enabledVariants[ 0 ]->imageUrl,
  34 + 'list',
  35 + [
  36 + 'alt' => $product->category->lang->title . ' ' . $product->fullname,
  37 + 'title' => $product->category->lang->title . ' ' . $product->fullname,
  38 + 'class' => 'selected',
  39 + ]
  40 + ) ?>
  41 + </a>
  42 + <div class="info_icons">
  43 + <a href="#" class="btn buy_button" data-toggle="modal" data-target="#buyForm" data-id="<?= $product->variant->id; ?>" lang="145">Купить</a>
  44 + <ul class="ul wishlike_block hidden">
  45 + <li class="compare hidden">
  46 + <a onclick="add2compare(); return false;" class="compare compare_text_link_3631483" href="#">К сравнению</a>
  47 + <span class="icon"></span>
  48 + </li>
  49 + <li class="like hidden">
  50 + <a class="like like_text_link_3631483" href="#">В избранное</a><span class="icon"></span>
  51 + </li>
  52 + </ul>
  53 + </div>
  54 + </div>
  55 + <div class="price">
  56 + <div class="dlexfduinxipi">
  57 + Цена:
  58 + <span class="main">
  59 + <?= $product->variant->price ?>
  60 + <span class="currency">грн</span>
  61 + </span>
  62 + </div>
  63 + </div>
  64 + <div class="additional_info params">
  65 + <div class="block_title">Особенности</div>
  66 + <div class="descr">
  67 + <div class="info">
  68 + <ul class="sv">
  69 +
  70 + <li><span>Бренд:</span> <?= $product->brand->lang->title ?></li>
  71 +
  72 + <?php foreach ($product->getProperties() as $group): ?>
  73 + <li>
  74 + <span><?= $group->lang->title ?> <?php foreach ( $group->customOptions as $option ) : ?>&nbsp;</span><?= $option->lang->value ?><?php endforeach ?>
  75 + </li>
  76 + <?php endforeach; ?>
  77 +
  78 +
  79 + </ul>
  80 + </div>
  81 + <div class="clearfix"></div>
  82 + </div>
  83 + <div class="price" style="display: none;">
  84 + <div class="dlexfduinxipi">
  85 + Цена:
  86 + <span class="main">
  87 + <?php
  88 +
  89 + echo '<div class="cost-block" itemprop="offers" itemscope itemtype="http://schema.org/Offer">';
  90 +
  91 + // есть скидка
  92 + echo '<p class="cost">';
  93 + if ($product->enabledVariants[ 0 ]->price_old != 0 && $product->enabledVariants[ 0 ]->price_old != $product->enabledVariants[ 0 ]->price) {
  94 + echo '<strike><span id=\'old_cost\' itemprop="price">' . $product->enabledVariants[ 0 ]->price_old . '</span> грн.</strike>&nbsp;';
  95 + echo $product->enabledVariants[ 0 ]->price . ' <span>грн.</span></p>';
  96 + } else {
  97 + echo '<span itemprop="price">' . $product->enabledVariants[ 0 ]->price . ' </span><span>грн.</span></p>';
  98 + }
  99 + echo '<meta itemprop="priceCurrency" content = "UAH">';
  100 + echo '</div>';
  101 +
  102 + ?>
  103 + </span>
  104 + </div>
  105 + </div>
  106 + </div>
  107 + <div class="opacity_bg"></div>
  108 + </div>
  109 + </div>
  110 +</div>
0 111 \ No newline at end of file
... ...
artbox-ecommerce/widgets/views/products_block.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/views/products_block.php
  1 +<?php
  2 + use artweb\artbox\ecommerce\models\Product;
  3 + use yii\web\View;
  4 +
  5 + /**
  6 + * @var Product[] $products
  7 + */
  8 +?>
  9 +<?php if(!empty( $products )) { ?>
  10 + <div class="_prd_spec-wr">
  11 + <div class="special-products products<?= ( !empty( $class ) ? ' ' . $class : '' ) ?>">
  12 + <span style="text-align: center;
  13 + text-transform: uppercase;
  14 + font-size: 20px; display: block;
  15 + -webkit-margin-before: 1em;
  16 + -webkit-margin-after: 1em;
  17 + -webkit-margin-start: 0;
  18 + -webkit-margin-end: 0;
  19 + font-weight: bold;"><?= $title ?></span>
  20 + <div id="<?= $class ?>">
  21 + <?php foreach($products as $product) : ?>
  22 + <?= $this->render('product_smart', [ 'product' => $product ]); ?>
  23 + <?php endforeach ?>
  24 + </div>
  25 + <div class="both"></div>
  26 + </div>
  27 + </div>
  28 + <?php $js = "$('#$class').owlCarousel({
  29 +navigation:true,
  30 +navigationText: []
  31 +})
  32 +";
  33 + $this->registerJs($js, View::POS_READY);
  34 + ?>
  35 +<?php } ?>
0 36 \ No newline at end of file
... ...
artbox-ecommerce/widgets/views/submenu.php 0 → 100755
  1 +++ a/artbox-ecommerce/widgets/views/submenu.php
  1 +<?php
  2 + /**
  3 + * @var Category $rootCategory
  4 + * @var string $rootClass
  5 + */
  6 + use artweb\artbox\ecommerce\models\Category;
  7 +
  8 +?>
  9 +<div class="menu_item">
  10 + <?= \yii\helpers\Html::a($rootCategory->lang->title, [
  11 + 'catalog/category',
  12 + 'category' => $rootCategory,
  13 + ], [ 'class' => 'submenu_button ' . $rootClass ]) ?>
  14 + <div class="submenu">
  15 + <ul class="categories">
  16 + <?php foreach($items as $item) : ?>
  17 + <li class="sub_cat">
  18 + <span><?= $item[ 'item' ]->title ?></span>
  19 + <?php if(!empty( $item[ 'children' ] )) : ?>
  20 + <div class="sub_cat_content">
  21 + <div class="content_items">
  22 + <?php foreach($item[ 'children' ] as $_item) : ?>
  23 + <div class="content_item"><a href="<?= \yii\helpers\Url::to([
  24 + 'catalog/category',
  25 + 'category' => $_item[ 'item' ],
  26 + ]) ?>">
  27 + <div class="picture">
  28 + <?php if(empty( $_item[ 'item' ]->image )) : ?>
  29 + <img src="/images/no_photo.png">
  30 + <?php else : ?>
  31 + <?= $_item[ 'item' ]->imageUrl ? \common\components\artboximage\ArtboxImageHelper::getImage($_item[ 'item' ]->imageUrl, 'mainmenu') : '' ?>
  32 + <?php endif ?>
  33 + </div>
  34 + <div class="title"><?= $_item[ 'item' ]->title ?></div>
  35 + </a></div>
  36 + <?php endforeach ?>
  37 + </div>
  38 + </div>
  39 + <?php endif ?>
  40 + </li>
  41 + <?php endforeach ?>
  42 + </ul>
  43 + </div>
  44 +</div>
... ...
artbox-file/FileUploadAsset.php 0 → 100755
  1 +++ a/artbox-file/FileUploadAsset.php
  1 +<?php
  2 +/**
  3 + * @link http://www.yiiframework.com/
  4 + * @copyright Copyright (c) 2008 Yii Software LLC
  5 + * @license http://www.yiiframework.com/license/
  6 + */
  7 +
  8 +
  9 +namespace artweb\artbox\file;
  10 +
  11 +use yii\helpers\Url;
  12 +use yii\web\AssetBundle;
  13 +
  14 +/**
  15 + * Asset bundle for the Twitter bootstrap javascript files.
  16 + *
  17 + * @author Qiang Xue <qiang.xue@gmail.com>
  18 + * @since 2.0
  19 + */
  20 +class FileUploadAsset extends AssetBundle
  21 +{
  22 +
  23 +
  24 + /**
  25 + * @inheritdoc
  26 + */
  27 + public function init()
  28 + {
  29 + parent::init();
  30 + $this->sourcePath = __DIR__.'/assets';
  31 + }
  32 +
  33 + public $css = [
  34 + 'css/jquery.fileupload.css',
  35 + 'css/fileupload/style.css'
  36 + ];
  37 +
  38 + public $js = [
  39 + 'js/vendor/jquery.ui.widget.js',
  40 + 'js/jquery.iframe-transport.js',
  41 + 'js/jquery.fileupload.js'
  42 + ];
  43 +}
... ...
artbox-file/Module.php 0 → 100755
  1 +++ a/artbox-file/Module.php
  1 +<?php
  2 +namespace artweb\artbox\file;
  3 +
  4 +use yii\base\BootstrapInterface;
  5 +
  6 +class Module extends \yii\base\Module
  7 +{
  8 + public function init()
  9 + {
  10 + parent::init();
  11 +
  12 + \Yii::configure($this, require(__DIR__.'/config.php'));
  13 + }
  14 +
  15 +}
... ...
artbox-file/assets/css/fileupload/style.css 0 → 100755
  1 +++ a/artbox-file/assets/css/fileupload/style.css
  1 +.remover_image {
  2 + position: absolute !important;
  3 + font-size: 20px;
  4 + right: 30px;
  5 + top:30px;
  6 + cursor:pointer;
  7 +}
... ...
artbox-file/assets/css/jquery.fileupload-noscript.css 0 → 100755
  1 +++ a/artbox-file/assets/css/jquery.fileupload-noscript.css
  1 +@charset "UTF-8";
  2 +/*
  3 + * jQuery File Upload Plugin NoScript CSS
  4 + * https://github.com/blueimp/jQuery-File-Upload
  5 + *
  6 + * Copyright 2013, Sebastian Tschan
  7 + * https://blueimp.net
  8 + *
  9 + * Licensed under the MIT license:
  10 + * http://www.opensource.org/licenses/MIT
  11 + */
  12 +
  13 +.fileinput-button input {
  14 + position: static;
  15 + opacity: 1;
  16 + filter: none;
  17 + font-size: inherit;
  18 + direction: inherit;
  19 +}
  20 +.fileinput-button span {
  21 + display: none;
  22 +}
... ...
artbox-file/assets/css/jquery.fileupload-ui-noscript.css 0 → 100755
  1 +++ a/artbox-file/assets/css/jquery.fileupload-ui-noscript.css
  1 +@charset "UTF-8";
  2 +/*
  3 + * jQuery File Upload UI Plugin NoScript CSS
  4 + * https://github.com/blueimp/jQuery-File-Upload
  5 + *
  6 + * Copyright 2012, Sebastian Tschan
  7 + * https://blueimp.net
  8 + *
  9 + * Licensed under the MIT license:
  10 + * http://www.opensource.org/licenses/MIT
  11 + */
  12 +
  13 +.fileinput-button i,
  14 +.fileupload-buttonbar .delete,
  15 +.fileupload-buttonbar .toggle {
  16 + display: none;
  17 +}
... ...
artbox-file/assets/css/jquery.fileupload-ui.css 0 → 100755
  1 +++ a/artbox-file/assets/css/jquery.fileupload-ui.css
  1 +@charset "UTF-8";
  2 +/*
  3 + * jQuery File Upload UI Plugin CSS
  4 + * https://github.com/blueimp/jQuery-File-Upload
  5 + *
  6 + * Copyright 2010, Sebastian Tschan
  7 + * https://blueimp.net
  8 + *
  9 + * Licensed under the MIT license:
  10 + * http://www.opensource.org/licenses/MIT
  11 + */
  12 +
  13 +.fileupload-buttonbar .btn,
  14 +.fileupload-buttonbar .toggle {
  15 + margin-bottom: 5px;
  16 +}
  17 +.progress-animated .progress-bar,
  18 +.progress-animated .bar {
  19 + background: url("../img/progressbar.gif") !important;
  20 + filter: none;
  21 +}
  22 +.fileupload-process {
  23 + float: right;
  24 + display: none;
  25 +}
  26 +.fileupload-processing .fileupload-process,
  27 +.files .processing .preview {
  28 + display: block;
  29 + width: 32px;
  30 + height: 32px;
  31 + background: url("../img/loading.gif") center no-repeat;
  32 + background-size: contain;
  33 +}
  34 +.files audio,
  35 +.files video {
  36 + max-width: 300px;
  37 +}
  38 +
  39 +@media (max-width: 767px) {
  40 + .fileupload-buttonbar .toggle,
  41 + .files .toggle,
  42 + .files .btn span {
  43 + display: none;
  44 + }
  45 + .files .name {
  46 + width: 80px;
  47 + word-wrap: break-word;
  48 + }
  49 + .files audio,
  50 + .files video {
  51 + max-width: 80px;
  52 + }
  53 + .files img,
  54 + .files canvas {
  55 + max-width: 100%;
  56 + }
  57 +}
... ...
artbox-file/assets/css/jquery.fileupload.css 0 → 100755
  1 +++ a/artbox-file/assets/css/jquery.fileupload.css
  1 +@charset "UTF-8";
  2 +/*
  3 + * jQuery File Upload Plugin CSS
  4 + * https://github.com/blueimp/jQuery-File-Upload
  5 + *
  6 + * Copyright 2013, Sebastian Tschan
  7 + * https://blueimp.net
  8 + *
  9 + * Licensed under the MIT license:
  10 + * http://www.opensource.org/licenses/MIT
  11 + */
  12 +
  13 +.fileinput-button {
  14 + position: relative;
  15 + overflow: hidden;
  16 + display: inline-block;
  17 +}
  18 +.fileinput-button input {
  19 + position: absolute;
  20 + top: 0;
  21 + right: 0;
  22 + margin: 0;
  23 + opacity: 0;
  24 + -ms-filter: 'alpha(opacity=0)';
  25 + font-size: 200px;
  26 + direction: ltr;
  27 + cursor: pointer;
  28 +}
  29 +
  30 +/* Fixes for IE < 8 */
  31 +@media screen\9 {
  32 + .fileinput-button input {
  33 + filter: alpha(opacity=0);
  34 + font-size: 100%;
  35 + height: 100%;
  36 + }
  37 +}
... ...
artbox-file/assets/img/loading.gif 0 → 100755

3.81 KB

artbox-file/assets/img/progressbar.gif 0 → 100755

3.25 KB

artbox-file/assets/js/cors/jquery.postmessage-transport.js 0 → 100755
  1 +++ a/artbox-file/assets/js/cors/jquery.postmessage-transport.js
  1 +/*
  2 + * jQuery postMessage Transport Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2011, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + */
  11 +
  12 +/* global define, require, window, document */
  13 +
  14 +(function (factory) {
  15 + 'use strict';
  16 + if (typeof define === 'function' && define.amd) {
  17 + // Register as an anonymous AMD module:
  18 + define(['jquery'], factory);
  19 + } else if (typeof exports === 'object') {
  20 + // Node/CommonJS:
  21 + factory(require('jquery'));
  22 + } else {
  23 + // Browser globals:
  24 + factory(window.jQuery);
  25 + }
  26 +}(function ($) {
  27 + 'use strict';
  28 +
  29 + var counter = 0,
  30 + names = [
  31 + 'accepts',
  32 + 'cache',
  33 + 'contents',
  34 + 'contentType',
  35 + 'crossDomain',
  36 + 'data',
  37 + 'dataType',
  38 + 'headers',
  39 + 'ifModified',
  40 + 'mimeType',
  41 + 'password',
  42 + 'processData',
  43 + 'timeout',
  44 + 'traditional',
  45 + 'type',
  46 + 'url',
  47 + 'username'
  48 + ],
  49 + convert = function (p) {
  50 + return p;
  51 + };
  52 +
  53 + $.ajaxSetup({
  54 + converters: {
  55 + 'postmessage text': convert,
  56 + 'postmessage json': convert,
  57 + 'postmessage html': convert
  58 + }
  59 + });
  60 +
  61 + $.ajaxTransport('postmessage', function (options) {
  62 + if (options.postMessage && window.postMessage) {
  63 + var iframe,
  64 + loc = $('<a>').prop('href', options.postMessage)[0],
  65 + target = loc.protocol + '//' + loc.host,
  66 + xhrUpload = options.xhr().upload;
  67 + return {
  68 + send: function (_, completeCallback) {
  69 + counter += 1;
  70 + var message = {
  71 + id: 'postmessage-transport-' + counter
  72 + },
  73 + eventName = 'message.' + message.id;
  74 + iframe = $(
  75 + '<iframe style="display:none;" src="' +
  76 + options.postMessage + '" name="' +
  77 + message.id + '"></iframe>'
  78 + ).bind('load', function () {
  79 + $.each(names, function (i, name) {
  80 + message[name] = options[name];
  81 + });
  82 + message.dataType = message.dataType.replace('postmessage ', '');
  83 + $(window).bind(eventName, function (e) {
  84 + e = e.originalEvent;
  85 + var data = e.data,
  86 + ev;
  87 + if (e.origin === target && data.id === message.id) {
  88 + if (data.type === 'progress') {
  89 + ev = document.createEvent('Event');
  90 + ev.initEvent(data.type, false, true);
  91 + $.extend(ev, data);
  92 + xhrUpload.dispatchEvent(ev);
  93 + } else {
  94 + completeCallback(
  95 + data.status,
  96 + data.statusText,
  97 + {postmessage: data.result},
  98 + data.headers
  99 + );
  100 + iframe.remove();
  101 + $(window).unbind(eventName);
  102 + }
  103 + }
  104 + });
  105 + iframe[0].contentWindow.postMessage(
  106 + message,
  107 + target
  108 + );
  109 + }).appendTo(document.body);
  110 + },
  111 + abort: function () {
  112 + if (iframe) {
  113 + iframe.remove();
  114 + }
  115 + }
  116 + };
  117 + }
  118 + });
  119 +
  120 +}));
... ...
artbox-file/assets/js/cors/jquery.xdr-transport.js 0 → 100755
  1 +++ a/artbox-file/assets/js/cors/jquery.xdr-transport.js
  1 +/*
  2 + * jQuery XDomainRequest Transport Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2011, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + *
  11 + * Based on Julian Aubourg's ajaxHooks xdr.js:
  12 + * https://github.com/jaubourg/ajaxHooks/
  13 + */
  14 +
  15 +/* global define, require, window, XDomainRequest */
  16 +
  17 +(function (factory) {
  18 + 'use strict';
  19 + if (typeof define === 'function' && define.amd) {
  20 + // Register as an anonymous AMD module:
  21 + define(['jquery'], factory);
  22 + } else if (typeof exports === 'object') {
  23 + // Node/CommonJS:
  24 + factory(require('jquery'));
  25 + } else {
  26 + // Browser globals:
  27 + factory(window.jQuery);
  28 + }
  29 +}(function ($) {
  30 + 'use strict';
  31 + if (window.XDomainRequest && !$.support.cors) {
  32 + $.ajaxTransport(function (s) {
  33 + if (s.crossDomain && s.async) {
  34 + if (s.timeout) {
  35 + s.xdrTimeout = s.timeout;
  36 + delete s.timeout;
  37 + }
  38 + var xdr;
  39 + return {
  40 + send: function (headers, completeCallback) {
  41 + var addParamChar = /\?/.test(s.url) ? '&' : '?';
  42 + function callback(status, statusText, responses, responseHeaders) {
  43 + xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
  44 + xdr = null;
  45 + completeCallback(status, statusText, responses, responseHeaders);
  46 + }
  47 + xdr = new XDomainRequest();
  48 + // XDomainRequest only supports GET and POST:
  49 + if (s.type === 'DELETE') {
  50 + s.url = s.url + addParamChar + '_method=DELETE';
  51 + s.type = 'POST';
  52 + } else if (s.type === 'PUT') {
  53 + s.url = s.url + addParamChar + '_method=PUT';
  54 + s.type = 'POST';
  55 + } else if (s.type === 'PATCH') {
  56 + s.url = s.url + addParamChar + '_method=PATCH';
  57 + s.type = 'POST';
  58 + }
  59 + xdr.open(s.type, s.url);
  60 + xdr.onload = function () {
  61 + callback(
  62 + 200,
  63 + 'OK',
  64 + {text: xdr.responseText},
  65 + 'Content-Type: ' + xdr.contentType
  66 + );
  67 + };
  68 + xdr.onerror = function () {
  69 + callback(404, 'Not Found');
  70 + };
  71 + if (s.xdrTimeout) {
  72 + xdr.ontimeout = function () {
  73 + callback(0, 'timeout');
  74 + };
  75 + xdr.timeout = s.xdrTimeout;
  76 + }
  77 + xdr.send((s.hasContent && s.data) || null);
  78 + },
  79 + abort: function () {
  80 + if (xdr) {
  81 + xdr.onerror = $.noop();
  82 + xdr.abort();
  83 + }
  84 + }
  85 + };
  86 + }
  87 + });
  88 + }
  89 +}));
... ...
artbox-file/assets/js/jquery.fileupload-angular.js 0 → 100755
  1 +++ a/artbox-file/assets/js/jquery.fileupload-angular.js
  1 +/*
  2 + * jQuery File Upload AngularJS Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2013, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + */
  11 +
  12 +/* jshint nomen:false */
  13 +/* global define, angular */
  14 +
  15 +(function (factory) {
  16 + 'use strict';
  17 + if (typeof define === 'function' && define.amd) {
  18 + // Register as an anonymous AMD module:
  19 + define([
  20 + 'jquery',
  21 + 'angular',
  22 + './jquery.fileupload-image',
  23 + './jquery.fileupload-audio',
  24 + './jquery.fileupload-video',
  25 + './jquery.fileupload-validate'
  26 + ], factory);
  27 + } else {
  28 + factory();
  29 + }
  30 +}(function () {
  31 + 'use strict';
  32 +
  33 + angular.module('blueimp.fileupload', [])
  34 +
  35 + // The fileUpload service provides configuration options
  36 + // for the fileUpload directive and default handlers for
  37 + // File Upload events:
  38 + .provider('fileUpload', function () {
  39 + var scopeEvalAsync = function (expression) {
  40 + var scope = angular.element(this)
  41 + .fileupload('option', 'scope');
  42 + // Schedule a new $digest cycle if not already inside of one
  43 + // and evaluate the given expression:
  44 + scope.$evalAsync(expression);
  45 + },
  46 + addFileMethods = function (scope, data) {
  47 + var files = data.files,
  48 + file = files[0];
  49 + angular.forEach(files, function (file, index) {
  50 + file._index = index;
  51 + file.$state = function () {
  52 + return data.state();
  53 + };
  54 + file.$processing = function () {
  55 + return data.processing();
  56 + };
  57 + file.$progress = function () {
  58 + return data.progress();
  59 + };
  60 + file.$response = function () {
  61 + return data.response();
  62 + };
  63 + });
  64 + file.$submit = function () {
  65 + if (!file.error) {
  66 + return data.submit();
  67 + }
  68 + };
  69 + file.$cancel = function () {
  70 + return data.abort();
  71 + };
  72 + },
  73 + $config;
  74 + $config = this.defaults = {
  75 + handleResponse: function (e, data) {
  76 + var files = data.result && data.result.files;
  77 + if (files) {
  78 + data.scope.replace(data.files, files);
  79 + } else if (data.errorThrown ||
  80 + data.textStatus === 'error') {
  81 + data.files[0].error = data.errorThrown ||
  82 + data.textStatus;
  83 + }
  84 + },
  85 + add: function (e, data) {
  86 + if (e.isDefaultPrevented()) {
  87 + return false;
  88 + }
  89 + var scope = data.scope,
  90 + filesCopy = [];
  91 + angular.forEach(data.files, function (file) {
  92 + filesCopy.push(file);
  93 + });
  94 + scope.$parent.$applyAsync(function () {
  95 + addFileMethods(scope, data);
  96 + var method = scope.option('prependFiles') ?
  97 + 'unshift' : 'push';
  98 + Array.prototype[method].apply(scope.queue, data.files);
  99 + });
  100 + data.process(function () {
  101 + return scope.process(data);
  102 + }).always(function () {
  103 + scope.$parent.$applyAsync(function () {
  104 + addFileMethods(scope, data);
  105 + scope.replace(filesCopy, data.files);
  106 + });
  107 + }).then(function () {
  108 + if ((scope.option('autoUpload') ||
  109 + data.autoUpload) &&
  110 + data.autoUpload !== false) {
  111 + data.submit();
  112 + }
  113 + });
  114 + },
  115 + done: function (e, data) {
  116 + if (e.isDefaultPrevented()) {
  117 + return false;
  118 + }
  119 + var that = this;
  120 + data.scope.$apply(function () {
  121 + data.handleResponse.call(that, e, data);
  122 + });
  123 + },
  124 + fail: function (e, data) {
  125 + if (e.isDefaultPrevented()) {
  126 + return false;
  127 + }
  128 + var that = this,
  129 + scope = data.scope;
  130 + if (data.errorThrown === 'abort') {
  131 + scope.clear(data.files);
  132 + return;
  133 + }
  134 + scope.$apply(function () {
  135 + data.handleResponse.call(that, e, data);
  136 + });
  137 + },
  138 + stop: scopeEvalAsync,
  139 + processstart: scopeEvalAsync,
  140 + processstop: scopeEvalAsync,
  141 + getNumberOfFiles: function () {
  142 + var scope = this.scope;
  143 + return scope.queue.length - scope.processing();
  144 + },
  145 + dataType: 'json',
  146 + autoUpload: false
  147 + };
  148 + this.$get = [
  149 + function () {
  150 + return {
  151 + defaults: $config
  152 + };
  153 + }
  154 + ];
  155 + })
  156 +
  157 + // Format byte numbers to readable presentations:
  158 + .provider('formatFileSizeFilter', function () {
  159 + var $config = {
  160 + // Byte units following the IEC format
  161 + // http://en.wikipedia.org/wiki/Kilobyte
  162 + units: [
  163 + {size: 1000000000, suffix: ' GB'},
  164 + {size: 1000000, suffix: ' MB'},
  165 + {size: 1000, suffix: ' KB'}
  166 + ]
  167 + };
  168 + this.defaults = $config;
  169 + this.$get = function () {
  170 + return function (bytes) {
  171 + if (!angular.isNumber(bytes)) {
  172 + return '';
  173 + }
  174 + var unit = true,
  175 + i = 0,
  176 + prefix,
  177 + suffix;
  178 + while (unit) {
  179 + unit = $config.units[i];
  180 + prefix = unit.prefix || '';
  181 + suffix = unit.suffix || '';
  182 + if (i === $config.units.length - 1 || bytes >= unit.size) {
  183 + return prefix + (bytes / unit.size).toFixed(2) + suffix;
  184 + }
  185 + i += 1;
  186 + }
  187 + };
  188 + };
  189 + })
  190 +
  191 + // The FileUploadController initializes the fileupload widget and
  192 + // provides scope methods to control the File Upload functionality:
  193 + .controller('FileUploadController', [
  194 + '$scope', '$element', '$attrs', '$window', 'fileUpload',
  195 + function ($scope, $element, $attrs, $window, fileUpload) {
  196 + var uploadMethods = {
  197 + progress: function () {
  198 + return $element.fileupload('progress');
  199 + },
  200 + active: function () {
  201 + return $element.fileupload('active');
  202 + },
  203 + option: function (option, data) {
  204 + if (arguments.length === 1) {
  205 + return $element.fileupload('option', option);
  206 + }
  207 + $element.fileupload('option', option, data);
  208 + },
  209 + add: function (data) {
  210 + return $element.fileupload('add', data);
  211 + },
  212 + send: function (data) {
  213 + return $element.fileupload('send', data);
  214 + },
  215 + process: function (data) {
  216 + return $element.fileupload('process', data);
  217 + },
  218 + processing: function (data) {
  219 + return $element.fileupload('processing', data);
  220 + }
  221 + };
  222 + $scope.disabled = !$window.jQuery.support.fileInput;
  223 + $scope.queue = $scope.queue || [];
  224 + $scope.clear = function (files) {
  225 + var queue = this.queue,
  226 + i = queue.length,
  227 + file = files,
  228 + length = 1;
  229 + if (angular.isArray(files)) {
  230 + file = files[0];
  231 + length = files.length;
  232 + }
  233 + while (i) {
  234 + i -= 1;
  235 + if (queue[i] === file) {
  236 + return queue.splice(i, length);
  237 + }
  238 + }
  239 + };
  240 + $scope.replace = function (oldFiles, newFiles) {
  241 + var queue = this.queue,
  242 + file = oldFiles[0],
  243 + i,
  244 + j;
  245 + for (i = 0; i < queue.length; i += 1) {
  246 + if (queue[i] === file) {
  247 + for (j = 0; j < newFiles.length; j += 1) {
  248 + queue[i + j] = newFiles[j];
  249 + }
  250 + return;
  251 + }
  252 + }
  253 + };
  254 + $scope.applyOnQueue = function (method) {
  255 + var list = this.queue.slice(0),
  256 + i,
  257 + file;
  258 + for (i = 0; i < list.length; i += 1) {
  259 + file = list[i];
  260 + if (file[method]) {
  261 + file[method]();
  262 + }
  263 + }
  264 + };
  265 + $scope.submit = function () {
  266 + this.applyOnQueue('$submit');
  267 + };
  268 + $scope.cancel = function () {
  269 + this.applyOnQueue('$cancel');
  270 + };
  271 + // Add upload methods to the scope:
  272 + angular.extend($scope, uploadMethods);
  273 + // The fileupload widget will initialize with
  274 + // the options provided via "data-"-parameters,
  275 + // as well as those given via options object:
  276 + $element.fileupload(angular.extend(
  277 + {scope: $scope},
  278 + fileUpload.defaults
  279 + )).on('fileuploadadd', function (e, data) {
  280 + data.scope = $scope;
  281 + }).on('fileuploadfail', function (e, data) {
  282 + if (data.errorThrown === 'abort') {
  283 + return;
  284 + }
  285 + if (data.dataType &&
  286 + data.dataType.indexOf('json') === data.dataType.length - 4) {
  287 + try {
  288 + data.result = angular.fromJson(data.jqXHR.responseText);
  289 + } catch (ignore) {}
  290 + }
  291 + }).on([
  292 + 'fileuploadadd',
  293 + 'fileuploadsubmit',
  294 + 'fileuploadsend',
  295 + 'fileuploaddone',
  296 + 'fileuploadfail',
  297 + 'fileuploadalways',
  298 + 'fileuploadprogress',
  299 + 'fileuploadprogressall',
  300 + 'fileuploadstart',
  301 + 'fileuploadstop',
  302 + 'fileuploadchange',
  303 + 'fileuploadpaste',
  304 + 'fileuploaddrop',
  305 + 'fileuploaddragover',
  306 + 'fileuploadchunksend',
  307 + 'fileuploadchunkdone',
  308 + 'fileuploadchunkfail',
  309 + 'fileuploadchunkalways',
  310 + 'fileuploadprocessstart',
  311 + 'fileuploadprocess',
  312 + 'fileuploadprocessdone',
  313 + 'fileuploadprocessfail',
  314 + 'fileuploadprocessalways',
  315 + 'fileuploadprocessstop'
  316 + ].join(' '), function (e, data) {
  317 + $scope.$parent.$applyAsync(function () {
  318 + if ($scope.$emit(e.type, data).defaultPrevented) {
  319 + e.preventDefault();
  320 + }
  321 + });
  322 + }).on('remove', function () {
  323 + // Remove upload methods from the scope,
  324 + // when the widget is removed:
  325 + var method;
  326 + for (method in uploadMethods) {
  327 + if (uploadMethods.hasOwnProperty(method)) {
  328 + delete $scope[method];
  329 + }
  330 + }
  331 + });
  332 + // Observe option changes:
  333 + $scope.$watch(
  334 + $attrs.fileUpload,
  335 + function (newOptions) {
  336 + if (newOptions) {
  337 + $element.fileupload('option', newOptions);
  338 + }
  339 + }
  340 + );
  341 + }
  342 + ])
  343 +
  344 + // Provide File Upload progress feedback:
  345 + .controller('FileUploadProgressController', [
  346 + '$scope', '$attrs', '$parse',
  347 + function ($scope, $attrs, $parse) {
  348 + var fn = $parse($attrs.fileUploadProgress),
  349 + update = function () {
  350 + var progress = fn($scope);
  351 + if (!progress || !progress.total) {
  352 + return;
  353 + }
  354 + $scope.num = Math.floor(
  355 + progress.loaded / progress.total * 100
  356 + );
  357 + };
  358 + update();
  359 + $scope.$watch(
  360 + $attrs.fileUploadProgress + '.loaded',
  361 + function (newValue, oldValue) {
  362 + if (newValue !== oldValue) {
  363 + update();
  364 + }
  365 + }
  366 + );
  367 + }
  368 + ])
  369 +
  370 + // Display File Upload previews:
  371 + .controller('FileUploadPreviewController', [
  372 + '$scope', '$element', '$attrs',
  373 + function ($scope, $element, $attrs) {
  374 + $scope.$watch(
  375 + $attrs.fileUploadPreview + '.preview',
  376 + function (preview) {
  377 + $element.empty();
  378 + if (preview) {
  379 + $element.append(preview);
  380 + }
  381 + }
  382 + );
  383 + }
  384 + ])
  385 +
  386 + .directive('fileUpload', function () {
  387 + return {
  388 + controller: 'FileUploadController',
  389 + scope: true
  390 + };
  391 + })
  392 +
  393 + .directive('fileUploadProgress', function () {
  394 + return {
  395 + controller: 'FileUploadProgressController',
  396 + scope: true
  397 + };
  398 + })
  399 +
  400 + .directive('fileUploadPreview', function () {
  401 + return {
  402 + controller: 'FileUploadPreviewController'
  403 + };
  404 + })
  405 +
  406 + // Enhance the HTML5 download attribute to
  407 + // allow drag&drop of files to the desktop:
  408 + .directive('download', function () {
  409 + return function (scope, elm) {
  410 + elm.on('dragstart', function (e) {
  411 + try {
  412 + e.originalEvent.dataTransfer.setData(
  413 + 'DownloadURL',
  414 + [
  415 + 'application/octet-stream',
  416 + elm.prop('download'),
  417 + elm.prop('href')
  418 + ].join(':')
  419 + );
  420 + } catch (ignore) {}
  421 + });
  422 + };
  423 + });
  424 +
  425 +}));
... ...
artbox-file/assets/js/jquery.fileupload-audio.js 0 → 100755
  1 +++ a/artbox-file/assets/js/jquery.fileupload-audio.js
  1 +/*
  2 + * jQuery File Upload Audio Preview Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2013, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + */
  11 +
  12 +/* jshint nomen:false */
  13 +/* global define, require, window, document */
  14 +
  15 +(function (factory) {
  16 + 'use strict';
  17 + if (typeof define === 'function' && define.amd) {
  18 + // Register as an anonymous AMD module:
  19 + define([
  20 + 'jquery',
  21 + 'load-image',
  22 + './jquery.fileupload-process'
  23 + ], factory);
  24 + } else if (typeof exports === 'object') {
  25 + // Node/CommonJS:
  26 + factory(
  27 + require('jquery'),
  28 + require('load-image')
  29 + );
  30 + } else {
  31 + // Browser globals:
  32 + factory(
  33 + window.jQuery,
  34 + window.loadImage
  35 + );
  36 + }
  37 +}(function ($, loadImage) {
  38 + 'use strict';
  39 +
  40 + // Prepend to the default processQueue:
  41 + $.blueimp.fileupload.prototype.options.processQueue.unshift(
  42 + {
  43 + action: 'loadAudio',
  44 + // Use the action as prefix for the "@" options:
  45 + prefix: true,
  46 + fileTypes: '@',
  47 + maxFileSize: '@',
  48 + disabled: '@disableAudioPreview'
  49 + },
  50 + {
  51 + action: 'setAudio',
  52 + name: '@audioPreviewName',
  53 + disabled: '@disableAudioPreview'
  54 + }
  55 + );
  56 +
  57 + // The File Upload Audio Preview plugin extends the fileupload widget
  58 + // with audio preview functionality:
  59 + $.widget('blueimp.fileupload', $.blueimp.fileupload, {
  60 +
  61 + options: {
  62 + // The regular expression for the types of audio files to load,
  63 + // matched against the file type:
  64 + loadAudioFileTypes: /^audio\/.*$/
  65 + },
  66 +
  67 + _audioElement: document.createElement('audio'),
  68 +
  69 + processActions: {
  70 +
  71 + // Loads the audio file given via data.files and data.index
  72 + // as audio element if the browser supports playing it.
  73 + // Accepts the options fileTypes (regular expression)
  74 + // and maxFileSize (integer) to limit the files to load:
  75 + loadAudio: function (data, options) {
  76 + if (options.disabled) {
  77 + return data;
  78 + }
  79 + var file = data.files[data.index],
  80 + url,
  81 + audio;
  82 + if (this._audioElement.canPlayType &&
  83 + this._audioElement.canPlayType(file.type) &&
  84 + ($.type(options.maxFileSize) !== 'number' ||
  85 + file.size <= options.maxFileSize) &&
  86 + (!options.fileTypes ||
  87 + options.fileTypes.test(file.type))) {
  88 + url = loadImage.createObjectURL(file);
  89 + if (url) {
  90 + audio = this._audioElement.cloneNode(false);
  91 + audio.src = url;
  92 + audio.controls = true;
  93 + data.audio = audio;
  94 + return data;
  95 + }
  96 + }
  97 + return data;
  98 + },
  99 +
  100 + // Sets the audio element as a property of the file object:
  101 + setAudio: function (data, options) {
  102 + if (data.audio && !options.disabled) {
  103 + data.files[data.index][options.name || 'preview'] = data.audio;
  104 + }
  105 + return data;
  106 + }
  107 +
  108 + }
  109 +
  110 + });
  111 +
  112 +}));
... ...