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..24da95f
--- /dev/null
+++ b/backend/controllers/ProductController.php
@@ -0,0 +1,135 @@
+ [
+ '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();
+ $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]);
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ 'accounts' => $accounts,
+ 'categories' => $categories ,
+
+ ]);
+ }
+ }
+
+ /**
+ * 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);
+
+ $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 ,
+ ]);
+ }
+ }
+
+ /**
+ * 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..a74a216
--- /dev/null
+++ b/backend/models/ProductSearch.php
@@ -0,0 +1,69 @@
+ $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_category' => $this->id_product_category,
+ 'id_account' => $this->id_account,
+ 'status' => $this->status,
+ ]);
+
+ $query->andFilterWhere(['like', 'product_number', $this->product_number])
+ ->andFilterWhere(['like', 'barcode', $this->barcode]);
+
+ return $dataProvider;
+ }
+}
diff --git a/backend/views/product/_form.php b/backend/views/product/_form.php
new file mode 100644
index 0000000..182b4b5
--- /dev/null
+++ b/backend/views/product/_form.php
@@ -0,0 +1,47 @@
+
+
+
diff --git a/backend/views/product/_search.php b/backend/views/product/_search.php
new file mode 100644
index 0000000..0ce8aa3
--- /dev/null
+++ b/backend/views/product/_search.php
@@ -0,0 +1,63 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+
+
+ = $form->field($model, 'id_product_category')->dropDownList($productCategories) ?>
+
+
+ = $form->field($model, 'id_account')->dropDownList($accounts) ?>
+
+
+ field($model, 'status')->dropDownList($statusOptions) ?>
+
+
+ = $form->field($model, 'product_number') ?>
+
+
+ = $form->field($model, 'barcode') ?>
+
+
+
+
+
+
+
+ = Html::submitButton(Yii::t('common/product', 'Search'), ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
diff --git a/backend/views/product/create.php b/backend/views/product/create.php
new file mode 100644
index 0000000..dd4afce
--- /dev/null
+++ b/backend/views/product/create.php
@@ -0,0 +1,24 @@
+title = Yii::t('common/product', 'Create Product');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('common/product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'accounts' => $accounts,
+ 'categories' => $categories ,
+ ]) ?>
+
+
diff --git a/backend/views/product/index.php b/backend/views/product/index.php
new file mode 100644
index 0000000..87893bc
--- /dev/null
+++ b/backend/views/product/index.php
@@ -0,0 +1,51 @@
+title = Yii::t('common/product', 'Products');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('common/product', 'Create Product'), ['create'], ['class' => 'btn btn-success']) ?>
+
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => [
+ [
+ 'attribute' => 'name',
+ ],
+ [
+ 'attribute' => 'id_product_category',
+ 'value' => 'productCategoryName',
+ ],
+ [
+ 'attribute' => 'id_account',
+ 'value' => 'accountName',
+ ],
+ 'product_number',
+ 'barcode',
+ 'sale_price',
+ [
+ 'attribute' => 'status',
+ 'value' => 'statusHuman',
+
+ ],
+
+ ['class' => 'yii\grid\ActionColumn',
+ 'template' => '{view} {update}'
+ ],
+ ],
+ ]); ?>
+
+
diff --git a/backend/views/product/update.php b/backend/views/product/update.php
new file mode 100644
index 0000000..30cf1f0
--- /dev/null
+++ b/backend/views/product/update.php
@@ -0,0 +1,23 @@
+title = Yii::t('common/product', 'Update product:' ) . ' ' . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('common/product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id_product]];
+$this->params['breadcrumbs'][] = Yii::t('common/product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'accounts' => $accounts,
+ 'categories' => $categories ,
+ ]) ?>
+
+
diff --git a/backend/views/product/view.php b/backend/views/product/view.php
new file mode 100644
index 0000000..ac32061
--- /dev/null
+++ b/backend/views/product/view.php
@@ -0,0 +1,42 @@
+title = $model->name ;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('common/product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('common/product', 'Update'), ['update', 'id' => $model->id_product], ['class' => 'btn btn-primary']) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'productCategoryName',
+ 'accountName',
+ 'product_number',
+ 'barcode',
+ 'purchase_price',
+ 'sale_price',
+ 'profit_margins',
+ 'statusHuman',
+ [
+ 'attribute' => 'description',
+ 'value' => nl2br($model->description),
+ 'format' => 'raw'
+ ],
+ 'created_at:datetime',
+ 'updated_at:datetime',
+ ],
+ ]) ?>
+
+
diff --git a/common/messages/hu/common/product.php b/common/messages/hu/common/product.php
new file mode 100644
index 0000000..da3e15f
--- /dev/null
+++ b/common/messages/hu/common/product.php
@@ -0,0 +1,43 @@
+ 'Aktív',
+ 'All' => 'Mind',
+ 'Barcode' => 'Vonalkód',
+ 'Create' => 'Mentés',
+ 'Create Product' => 'Új termék',
+ 'Created At' => 'Létrehozás ideje',
+ 'Description' => 'Leírás',
+ 'Id Account' => 'Kassza',
+ 'Id Product' => 'Termék',
+ 'Id Product Category' => 'Termék kategória',
+ 'Inactive' => 'Inaktív',
+ 'Max 255 character' => 'Max 255 karakter',
+ 'Name' => 'Név',
+ 'Product Number' => 'Termék szám',
+ 'Products' => 'Termékek',
+ 'Profit Margins' => 'Haszonkulcs',
+ 'Purchase Price' => 'Beszerzési ár',
+ 'Sale Price' => 'Eladási ár',
+ 'Search' => 'Keresés',
+ 'Status' => 'Státusz',
+ 'Update' => 'Módosítás',
+ 'Update product:' => 'Termék módosítása:',
+ 'Updated At' => 'Módosítás ideje',
+];
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..6410e4f
--- /dev/null
+++ b/common/models/Product.php
@@ -0,0 +1,113 @@
+ 20],
+ [['name'], 'string', 'max' => 128],
+ [['description'], 'string', 'max' => 255],
+ [['product_number'], 'unique' ],
+ [['barcode'], 'unique' ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'id_product' => Yii::t('common/product', 'Id Product'),
+ 'id_product_category' => Yii::t('common/product', 'Id Product Category'),
+ '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'),
+ 'name' => Yii::t('common/product', 'Name'),
+ '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/ProductCategory.php b/common/models/ProductCategory.php
index 70b255a..cb5dd4d 100644
--- a/common/models/ProductCategory.php
+++ b/common/models/ProductCategory.php
@@ -69,4 +69,20 @@ class ProductCategory extends \common\models\BaseFitnessActiveRecord
return $result;
}
+
+ /**
+ * $param int $forceIncludeAccount id account, that should be included in list, even if it is inactive
+ * */
+ public static function read($forceIncludeObjectWithId = null){
+ $categories = null;
+
+ if ( $forceIncludeObjectWithId == null){
+ $categories = ProductCategory::find()->andWhere(['status' => ProductCategory::STATUS_ACTIVE])->all();
+ }else{
+ $categories = ProductCategory::find()->andWhere( ['or', ['status' => ProductCategory::STATUS_ACTIVE], ['id_product_category' => $forceIncludeObjectWithId ] ])->all();
+ }
+
+ return $categories;
+ }
+
}
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.lock b/composer.lock
index e7e2ee1..6a29fb3 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "5fe15fcdcc6c43b39968ffd29104ac62",
+ "hash": "8580bd82955b1fbb80d47024e184056e",
"packages": [
{
"name": "bower-asset/bootstrap",
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()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m150924_162425_alter__table__product_fix_columns.php b/console/migrations/m150924_162425_alter__table__product_fix_columns.php
new file mode 100644
index 0000000..475db33
--- /dev/null
+++ b/console/migrations/m150924_162425_alter__table__product_fix_columns.php
@@ -0,0 +1,32 @@
+renameColumn('product','id_product_type','id_product_category');
+ $this->addColumn('product','stock', 'int(11)' );
+ }
+
+ public function down()
+ {
+ echo "m150924_162425_alter__table__product_fix_columns cannot be reverted.\n";
+
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m150924_170806_alter__table__product__add__column__name.php b/console/migrations/m150924_170806_alter__table__product__add__column__name.php
new file mode 100644
index 0000000..8dac7a9
--- /dev/null
+++ b/console/migrations/m150924_170806_alter__table__product__add__column__name.php
@@ -0,0 +1,30 @@
+addColumn('product','name', 'varchar(128)' );
+ }
+
+ public function down()
+ {
+ echo "m150924_170806_alter__table__product__add__column__name cannot be reverted.\n";
+
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}