From 1eae1b3000d2c2cf132afcca9c82bd69d1b09d66 Mon Sep 17 00:00:00 2001 From: rocho Date: Tue, 22 Sep 2015 17:04:43 +0200 Subject: [PATCH 1/3] add migrateion add_table_product --- .../m150922_133505_add__table__product.php | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 console/migrations/m150922_133505_add__table__product.php diff --git a/console/migrations/m150922_133505_add__table__product.php b/console/migrations/m150922_133505_add__table__product.php new file mode 100644 index 0000000..4e5bb00 --- /dev/null +++ b/console/migrations/m150922_133505_add__table__product.php @@ -0,0 +1,49 @@ +db->driverName === 'mysql') { + // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; + } + + $this->createTable('{{%product}}', [ + 'id_product' => $this->primaryKey(), + 'id_product_type' => $this->integer()->notNull(), + 'id_account' => $this->integer()->notNull(), + 'product_number' => $this->string(20), + 'barcode' => $this->string(20), + 'purchase_price' => $this->integer(), + 'sale_price' => $this->integer(), + 'profit_margins' => $this->integer(), + 'status' => $this->smallInteger()->notNull()->defaultValue(10), + 'description' => $this->string(255), + 'created_at' => $this->timestamp()->notNull(), + 'updated_at' => $this->timestamp()->notNull(), + ], $tableOptions); + } + + public function down() + { + echo "m150922_133505_add__table__product cannot be reverted.\n"; + + return false; + } + + /* + // Use safeUp/safeDown to run migration code within a transaction + public function safeUp() + { + } + + public function safeDown() + { + } + */ +} From fcc18d79f65400ee004d80df1374c287dc6e6621 Mon Sep 17 00:00:00 2001 From: rocho Date: Thu, 24 Sep 2015 10:06:10 +0200 Subject: [PATCH 2/3] add changes feature/33 --- Gruntfile.coffee | 62 +++++++++++ backend/components/AdminMenuStructure.php | 1 + backend/controllers/ProductController.php | 125 ++++++++++++++++++++++ backend/models/ProductSearch.php | 76 +++++++++++++ backend/views/product/_form.php | 42 ++++++++ backend/views/product/_search.php | 49 +++++++++ backend/views/product/create.php | 23 ++++ backend/views/product/index.php | 47 ++++++++ backend/views/product/update.php | 23 ++++ backend/views/product/view.php | 46 ++++++++ common/models/Account.php | 17 +++ common/models/Product.php | 107 ++++++++++++++++++ common/models/TicketType.php | 2 +- composer.json | 3 +- 14 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 Gruntfile.coffee create mode 100644 backend/controllers/ProductController.php create mode 100644 backend/models/ProductSearch.php create mode 100644 backend/views/product/_form.php create mode 100644 backend/views/product/_search.php create mode 100644 backend/views/product/create.php create mode 100644 backend/views/product/index.php create mode 100644 backend/views/product/update.php create mode 100644 backend/views/product/view.php create mode 100644 common/models/Product.php diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 0000000..c663c91 --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,62 @@ +module.exports = (grunt) -> + + # Project configuration. + grunt.initConfig + pkg: grunt.file.readJSON('package.json') + + config: + src: 'assets/coffee' + dest: 'assets/js' + + clean: + build: + src: [ 'frontend/web/stylesheet','backend/web/stylesheet' ] + + compass: + frontend: + options: + sassDir: 'frontend/web/scss' + cssDir: 'frontend/web/stylesheet' + backend: + options: + sassDir: 'backend/web/scss' + cssDir: 'backend/web/stylesheet' + + coffee: + frontend: + options: + sourceMap: true + bare: false + join: true + files: + 'frontend/web/js/frontend.js': ['frontend/web/coffee/**/*.coffee'] + backend: + options: + sourceMap: true + bare: false + join: true + files: + 'backend/web/js/backend.js': ['backend/web/coffee/**/*.coffee'] + + watch: + options: + spawn: false + interrupt: true + atBegin: true + interval: 500 + coffeewatch: + files: ['frontend/web/coffee/**/*.coffee','backend/web/coffee/**/*.coffee'] + tasks: ['any-newer:coffee'] + sasswatch: + files: ['frontend/web/scss/*.scss','backend/web/scss/*.scss'] + tasks: ['compass'] + + + #grunt.loadNpmTasks 'grunt-contrib-compass' + + require('matchdep').filterDev('grunt-*').forEach grunt.loadNpmTasks + + # Tasks + #grunt.registerTask 'default', ['concurrent:compile'] + grunt.registerTask 'default', ['compass','coffee'] + #grunt.registerTask 'production', ['clean', 'concurrent:compile', 'concurrent:optimize'] \ No newline at end of file diff --git a/backend/components/AdminMenuStructure.php b/backend/components/AdminMenuStructure.php index ae957ec..153b0ff 100644 --- a/backend/components/AdminMenuStructure.php +++ b/backend/components/AdminMenuStructure.php @@ -40,6 +40,7 @@ class AdminMenuStructure{ $items[] = ['label' => 'Kedvezmények', 'url' => ['/discount/index'] ]; $items[] = ['label' => 'Termék kategóriák', 'url' => ['/product-category/index'] ]; $items[] = ['label' => 'Bérlet típusok', 'url' => ['/ticket-type/index'] ]; + $items[] = ['label' => 'Termékek', 'url' => ['/product/index'] ]; if ( count($items) > 0 ){ $userMainMenu = ['label' => 'Beállítások', 'url' => null, diff --git a/backend/controllers/ProductController.php b/backend/controllers/ProductController.php new file mode 100644 index 0000000..3ce635f --- /dev/null +++ b/backend/controllers/ProductController.php @@ -0,0 +1,125 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['post'], + ], + ], + ]; + } + + /** + * Lists all Product models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new ProductSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Product model. + * @param integer $id + * @return mixed + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new Product model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new Product(); + $accounts = Account::readAccounts(null); + + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id_product]); + } else { + return $this->render('create', [ + 'model' => $model, + 'accounts' => $accounts, + ]); + } + } + + /** + * Updates an existing Product model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param integer $id + * @return mixed + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id_product]); + } else { + return $this->render('update', [ + 'model' => $model, + ]); + } + } + + /** + * Deletes an existing Product model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param integer $id + * @return mixed + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Product model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param integer $id + * @return Product the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Product::findOne($id)) !== null) { + return $model; + } else { + throw new NotFoundHttpException('The requested page does not exist.'); + } + } +} diff --git a/backend/models/ProductSearch.php b/backend/models/ProductSearch.php new file mode 100644 index 0000000..a528662 --- /dev/null +++ b/backend/models/ProductSearch.php @@ -0,0 +1,76 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + $query->andFilterWhere([ + 'id_product' => $this->id_product, + 'id_product_type' => $this->id_product_type, + 'id_account' => $this->id_account, + 'purchase_price' => $this->purchase_price, + 'sale_price' => $this->sale_price, + 'profit_margins' => $this->profit_margins, + 'status' => $this->status, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]); + + $query->andFilterWhere(['like', 'product_number', $this->product_number]) + ->andFilterWhere(['like', 'barcode', $this->barcode]) + ->andFilterWhere(['like', 'description', $this->description]); + + return $dataProvider; + } +} diff --git a/backend/views/product/_form.php b/backend/views/product/_form.php new file mode 100644 index 0000000..941c04d --- /dev/null +++ b/backend/views/product/_form.php @@ -0,0 +1,42 @@ + + +
+ + + + + field($model, 'id_account')->dropDownList($account_options) ?> + + field($model, 'product_number')->textInput(['maxlength' => true]) ?> + + field($model, 'barcode')->textInput(['maxlength' => true]) ?> + + field($model, 'purchase_price')->input('number') ?> + + field($model, 'sale_price')->input('number')?> + + field($model, 'profit_margins')->textInput() ?> + + field($model, 'status')->checkbox( ['value' => 10, 'label' => Yii::t('common/product', "Active") ]) ?> + + field($model, 'description')->textarea(['maxlength' => true])->hint( Yii::t( 'common/prodcut', "Max 255 character")) ?> + +
+ isNewRecord ? Yii::t('common/ticket_type', 'Create') : Yii::t('common/ticket_type', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> +
+ + + +
diff --git a/backend/views/product/_search.php b/backend/views/product/_search.php new file mode 100644 index 0000000..aba1bcc --- /dev/null +++ b/backend/views/product/_search.php @@ -0,0 +1,49 @@ + + + diff --git a/backend/views/product/create.php b/backend/views/product/create.php new file mode 100644 index 0000000..c9d4e28 --- /dev/null +++ b/backend/views/product/create.php @@ -0,0 +1,23 @@ +title = Yii::t('common/ticket_type', 'Create Product'); +$this->params['breadcrumbs'][] = ['label' => Yii::t('common/ticket_type', 'Products'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + 'accounts' => $accounts, + ]) ?> + +
diff --git a/backend/views/product/index.php b/backend/views/product/index.php new file mode 100644 index 0000000..41ee9c3 --- /dev/null +++ b/backend/views/product/index.php @@ -0,0 +1,47 @@ +title = Yii::t('common/ticket_type', 'Products'); +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ render('_search', ['model' => $searchModel]); ?> + +

+ 'btn btn-success']) ?> +

+ + $dataProvider, + 'columns' => [ + [ + 'attribute' => 'id_product_type', + 'value' => 'productCategoryName', + ], + [ + 'attribute' => 'id_account', + 'value' => 'accountName', + ], + 'product_number', + 'barcode', + 'purchase_price', + 'sale_price', + 'profit_margins', + 'status', + 'description', + 'created_at:datetime', + 'updated_at:datetime', + + ['class' => 'yii\grid\ActionColumn'], + ], + ]); ?> + +
diff --git a/backend/views/product/update.php b/backend/views/product/update.php new file mode 100644 index 0000000..2b6f0a3 --- /dev/null +++ b/backend/views/product/update.php @@ -0,0 +1,23 @@ +title = Yii::t('common/ticket_type', 'Update {modelClass}: ', [ + 'modelClass' => 'Product', +]) . ' ' . $model->id_product; +$this->params['breadcrumbs'][] = ['label' => Yii::t('common/ticket_type', 'Products'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->id_product, 'url' => ['view', 'id' => $model->id_product]]; +$this->params['breadcrumbs'][] = Yii::t('common/ticket_type', 'Update'); +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/backend/views/product/view.php b/backend/views/product/view.php new file mode 100644 index 0000000..214365d --- /dev/null +++ b/backend/views/product/view.php @@ -0,0 +1,46 @@ +title = $model->id_product; +$this->params['breadcrumbs'][] = ['label' => Yii::t('common/ticket_type', 'Products'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ +

+ $model->id_product], ['class' => 'btn btn-primary']) ?> + $model->id_product], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => Yii::t('common/ticket_type', 'Are you sure you want to delete this item?'), + 'method' => 'post', + ], + ]) ?> +

+ + $model, + 'attributes' => [ + 'id_product', + 'id_product_type', + 'id_account', + 'product_number', + 'barcode', + 'purchase_price', + 'sale_price', + 'profit_margins', + 'status', + 'description', + 'created_at', + 'updated_at', + ], + ]) ?> + +
diff --git a/common/models/Account.php b/common/models/Account.php index 125a73c..b50733f 100644 --- a/common/models/Account.php +++ b/common/models/Account.php @@ -108,4 +108,21 @@ class Account extends \yii\db\ActiveRecord return $this->status == self::STATUS_DELETED; } + /** + * $param int $forceIncludeAccount id account, that should be included in list, even if it is inactive + * */ + public static function readAccounts($forceIncludeAccount = null){ + $accounts = null; + + if ( $forceIncludeAccount == null){ + $accounts = Account::find()->andWhere(['status' => Account::STATUS_ACTIVE])->all(); + }else{ + $accounts = Account::find()->andWhere( ['or', ['status' => Account::STATUS_ACTIVE], ['id_account' => $forceIncludeAccount ] ])->all(); + } + + return $accounts; + } + + + } diff --git a/common/models/Product.php b/common/models/Product.php new file mode 100644 index 0000000..41600ab --- /dev/null +++ b/common/models/Product.php @@ -0,0 +1,107 @@ + 20], + [['description'], 'string', 'max' => 255] + ]; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'id_product' => Yii::t('common/product', 'Id Product'), + 'id_product_type' => Yii::t('common/product', 'Id Product Type'), + 'id_account' => Yii::t('common/product', 'Id Account'), + 'product_number' => Yii::t('common/product', 'Product Number'), + 'barcode' => Yii::t('common/product', 'Barcode'), + 'purchase_price' => Yii::t('common/product', 'Purchase Price'), + 'sale_price' => Yii::t('common/product', 'Sale Price'), + 'profit_margins' => Yii::t('common/product', 'Profit Margins'), + 'status' => Yii::t('common/product', 'Status'), + 'description' => Yii::t('common/product', 'Description'), + 'created_at' => Yii::t('common/product', 'Created At'), + 'updated_at' => Yii::t('common/product', 'Updated At'), + ]; + } + + + public function getAccount() { + return $this->hasOne ( Account::className (), [ + 'id_account' => 'id_account' + ] ); + } + public function getAccountName() { + return $this->account->name; + } + + public function getProductCategory() { + return $this->hasOne ( ProductCategory::className (), [ + 'id_product_category' => 'id_product_category' + ] ); + } + public function getProductCategoryName() { + return $this->productCategory->name; + } + + /** + * @formatter:on + */ + static function statuses() { + return [ + self::STATUS_ACTIVE => Yii::t ( 'common/product', 'Active' ), + self::STATUS_DELETED => Yii::t ( 'common/product', 'Inactive' ) + ]; + } + public function getStatusHuman() { + $result = null; + $s = self::statuses ( ); + if (array_key_exists ( $this->status, $s )) { + $result = $s [$this->status]; + } + return $result; + } + +} diff --git a/common/models/TicketType.php b/common/models/TicketType.php index 11a86d4..ed620c9 100644 --- a/common/models/TicketType.php +++ b/common/models/TicketType.php @@ -123,7 +123,7 @@ class TicketType extends \common\models\BaseFitnessActiveRecord { } public function getStatusHuman() { $result = null; - $s = self::statuses ( $this->status ); + $s = self::statuses ( ); if (array_key_exists ( $this->status, $s )) { $result = $s [$this->status]; } diff --git a/composer.json b/composer.json index 22993b0..4ef624f 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ "php": ">=5.4.0", "yiisoft/yii2": ">=2.0.6", "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" + "yiisoft/yii2-swiftmailer": "*", + "npm-asset/grunt": "^0.4.5" }, "require-dev": { "yiisoft/yii2-codeception": "*", From a2b835225a9c27d7f711322bd052a36ff74909af Mon Sep 17 00:00:00 2001 From: rocho Date: Thu, 24 Sep 2015 22:14:09 +0200 Subject: [PATCH 3/3] add product --- backend/controllers/ProductController.php | 12 +++- backend/models/ProductSearch.php | 15 ++--- backend/views/product/_form.php | 9 ++- backend/views/product/_search.php | 58 ++++++++++++------- backend/views/product/create.php | 5 +- backend/views/product/index.php | 26 +++++---- backend/views/product/update.php | 12 ++-- backend/views/product/view.php | 30 +++++----- common/messages/hu/common/product.php | 43 ++++++++++++++ common/models/Product.php | 16 +++-- common/models/ProductCategory.php | 16 +++++ composer.json | 3 +- composer.lock | 2 +- ...2425_alter__table__product_fix_columns.php | 32 ++++++++++ ...ter__table__product__add__column__name.php | 30 ++++++++++ 15 files changed, 229 insertions(+), 80 deletions(-) create mode 100644 common/messages/hu/common/product.php create mode 100644 console/migrations/m150924_162425_alter__table__product_fix_columns.php create mode 100644 console/migrations/m150924_170806_alter__table__product__add__column__name.php diff --git a/backend/controllers/ProductController.php b/backend/controllers/ProductController.php index 3ce635f..24da95f 100644 --- a/backend/controllers/ProductController.php +++ b/backend/controllers/ProductController.php @@ -9,6 +9,7 @@ use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; use common\models\Account; +use common\models\ProductCategory; /** * ProductController implements the CRUD actions for Product model. @@ -62,8 +63,10 @@ class ProductController extends Controller public function actionCreate() { $model = new Product(); + $model->stock = 0; + $model->status = Product::STATUS_ACTIVE; $accounts = Account::readAccounts(null); - + $categories = ProductCategory::read(null); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id_product]); @@ -71,6 +74,8 @@ class ProductController extends Controller return $this->render('create', [ 'model' => $model, 'accounts' => $accounts, + 'categories' => $categories , + ]); } } @@ -85,11 +90,16 @@ class ProductController extends Controller { $model = $this->findModel($id); + $accounts = Account::readAccounts($model->id_account); + $categories = ProductCategory::read($model->id_product_category); + if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id_product]); } else { return $this->render('update', [ 'model' => $model, + 'accounts' => $accounts, + 'categories' => $categories , ]); } } diff --git a/backend/models/ProductSearch.php b/backend/models/ProductSearch.php index a528662..a74a216 100644 --- a/backend/models/ProductSearch.php +++ b/backend/models/ProductSearch.php @@ -18,8 +18,8 @@ class ProductSearch extends Product public function rules() { return [ - [['id_product', 'id_product_type', 'id_account', 'purchase_price', 'sale_price', 'profit_margins', 'status'], 'integer'], - [['product_number', 'barcode', 'description', 'created_at', 'updated_at'], 'safe'], + [[ 'id_product_category', 'id_account', 'status'], 'integer'], + [['product_number', 'barcode' ], 'safe'], ]; } @@ -56,20 +56,13 @@ class ProductSearch extends Product } $query->andFilterWhere([ - 'id_product' => $this->id_product, - 'id_product_type' => $this->id_product_type, + 'id_product_category' => $this->id_product_category, 'id_account' => $this->id_account, - 'purchase_price' => $this->purchase_price, - 'sale_price' => $this->sale_price, - 'profit_margins' => $this->profit_margins, 'status' => $this->status, - 'created_at' => $this->created_at, - 'updated_at' => $this->updated_at, ]); $query->andFilterWhere(['like', 'product_number', $this->product_number]) - ->andFilterWhere(['like', 'barcode', $this->barcode]) - ->andFilterWhere(['like', 'description', $this->description]); + ->andFilterWhere(['like', 'barcode', $this->barcode]); return $dataProvider; } diff --git a/backend/views/product/_form.php b/backend/views/product/_form.php index 941c04d..182b4b5 100644 --- a/backend/views/product/_form.php +++ b/backend/views/product/_form.php @@ -11,13 +11,18 @@ use yii\helpers\ArrayHelper; ?>
+ field($model, 'name')->textInput(['maxlength' => true]) ?> field($model, 'id_account')->dropDownList($account_options) ?> + + field($model, 'id_product_category')->dropDownList($product_category_options) ?> field($model, 'product_number')->textInput(['maxlength' => true]) ?> @@ -31,10 +36,10 @@ $account_options = ArrayHelper::map($accounts, 'id_account', 'name'); field($model, 'status')->checkbox( ['value' => 10, 'label' => Yii::t('common/product', "Active") ]) ?> - field($model, 'description')->textarea(['maxlength' => true])->hint( Yii::t( 'common/prodcut', "Max 255 character")) ?> + field($model, 'description')->textarea(['maxlength' => true])->hint( Yii::t( 'common/product', "Max 255 character")) ?>
- isNewRecord ? Yii::t('common/ticket_type', 'Create') : Yii::t('common/ticket_type', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> + isNewRecord ? Yii::t('common/product', 'Create') : Yii::t('common/product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
diff --git a/backend/views/product/_search.php b/backend/views/product/_search.php index aba1bcc..0ce8aa3 100644 --- a/backend/views/product/_search.php +++ b/backend/views/product/_search.php @@ -2,12 +2,30 @@ use yii\helpers\Html; use yii\widgets\ActiveForm; +use common\models\Product; +use common\models\ProductCategory; +use yii\helpers\ArrayHelper; +use common\models\Account; /* @var $this yii\web\View */ /* @var $model backend\models\ProductSearch */ /* @var $form yii\widgets\ActiveForm */ ?> +