diff --git a/backend/components/AdminMenuStructure.php b/backend/components/AdminMenuStructure.php
index 20e37cc..fc27946 100644
--- a/backend/components/AdminMenuStructure.php
+++ b/backend/components/AdminMenuStructure.php
@@ -89,6 +89,7 @@ class AdminMenuStructure{
/////////////////////////////
$items = [];
$items[] = ['label' => 'Tranzakciók', 'url' => ['/transfer/index' , 'TransferSearch[start]' =>$today,'TransferSearch[end]' => $tomorrow ] ];
+ $items[] = ['label' => 'Bevétel', 'url' => ['/transfer/summary' , 'TransferSummarySearch[start]' =>$today,'TransferSummarySearch[end]' => $tomorrow ] ];
$items[] = ['label' => 'Kassza müveletek', 'url' => ['/account-state/index'] ];
$items[] = ['label' => 'Zárások', 'url' => ['/collection/index' , 'CollectionSearch[start]' =>$todayDatetime,'CollectionSearch[end]' => $tomorrowDatetime ] ];
$this->menuItems[] = ['label' => 'Pénzügy', 'url' => $this->emptyUrl,
diff --git a/backend/controllers/TransferController.php b/backend/controllers/TransferController.php
index 17327b5..b7f7217 100644
--- a/backend/controllers/TransferController.php
+++ b/backend/controllers/TransferController.php
@@ -9,6 +9,7 @@ use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use common\models\Account;
use common\models\User;
+use backend\models\TransferSummarySearch;
/**
* TransferController implements the CRUD actions for Transfer model.
@@ -23,7 +24,7 @@ class TransferController extends \backend\controllers\BackendController
'rules' => [
// allow authenticated users
[
- 'actions' => [ 'index','view' ],
+ 'actions' => [ 'index','view','summary' ],
'allow' => true,
'roles' => ['admin','employee','reception'],
],
@@ -57,6 +58,29 @@ class TransferController extends \backend\controllers\BackendController
]);
}
+
+
+ /**
+ * Lists all Transfer models.
+ * @return mixed
+ */
+ public function actionSummary()
+ {
+ $searchModel = new TransferSummarySearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ $accounts = Account::read();
+
+ $users = User::read();
+
+ return $this->render('summary', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ 'accounts' => $accounts,
+ 'users' => $users,
+ ]);
+ }
+
/**
* Displays a single Transfer model.
* @param integer $id
diff --git a/backend/models/TransferSearch.php b/backend/models/TransferSearch.php
index c76bc00..e2bd2a3 100644
--- a/backend/models/TransferSearch.php
+++ b/backend/models/TransferSearch.php
@@ -114,8 +114,9 @@ class TransferSearch extends Transfer
$accounts = Account::read();
$accountMap = ArrayHelper::map( $accounts ,'id_account','name' );
- $idUser = Yii::$app->user->id;
+ $idUser = $this->id_user;
+
$this->totals = Transfer::mkTotals($this->timestampStart, $this->timestampEnd, $idUser, $this->types, $this->id_account, $accounts, $accountMap);
diff --git a/backend/models/TransferSummarySearch.php b/backend/models/TransferSummarySearch.php
new file mode 100644
index 0000000..5570ea2
--- /dev/null
+++ b/backend/models/TransferSummarySearch.php
@@ -0,0 +1,180 @@
+ 'timestampStart' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ],
+ [[ 'end' , ], 'date' , 'timestampAttribute' => 'timestampEnd' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ],
+ ['types', 'each', 'rule' => ['integer']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function scenarios()
+ {
+ // bypass scenarios() implementation in the parent class
+ return Model::scenarios();
+ }
+
+ /**
+ * Creates data provider instance with search query applied
+ *
+ * @param array $params
+ *
+ * @return ActiveDataProvider
+ */
+ public function search($params)
+ {
+
+
+
+ $this->load($params);
+
+ if (!$this->validate()) {
+// $query->where('0=1');
+// return $dataProvider;
+ }
+
+
+ $this->readTicketMoney();
+ $this->readProductsByCategory();
+ $this->readMoneyMovements();
+ $this->calcTotal();
+ }
+
+ protected function calcTotal(){
+ $this->total = 0;
+ $this->total += $this->ticketMoney;
+ $this->total -= $this->moneyMovementMoneis['money_movement_money'];
+ foreach ($this->productMoneies as $pm ){
+ $this->total += $pm['product_money'];
+ }
+ }
+
+
+ protected function addQueryFilters($query){
+ if ( !RoleDefinition::isAdmin() ){
+ $query->innerJoin("user_account_assignment",'transfer.id_account = user_account_assignment.id_account' );
+ $query->andWhere(['user_account_assignment.id_user' => Yii::$app->user->id ]);
+ }
+
+ $query->andFilterWhere([
+ 'transfer.id_account' => $this->id_account,
+ 'transfer.type' => $this->type,
+ 'transfer.id_user' => $this->id_user,
+ ]);
+
+ $created_condition = ['and',[ '>=', 'transfer.created_at', $this->timestampStart ] ,[ '<', 'transfer.created_at', $this->timestampEnd ] ];
+ $paid_condition = ['and',[ '>=', 'transfer.paid_at', $this->timestampStart ] ,[ '<', 'transfer.paid_at', $this->timestampEnd ] ];
+
+
+ $query->andFilterWhere(['or' , $created_condition , $paid_condition]);
+
+ $query->andWhere(['transfer.status' => Transfer::STATUS_PAID]);
+
+ }
+
+
+ protected function readTicketMoney(){
+
+ $query = (new \yii\db\Query());
+ $query->select([' coalesce(sum(abs(transfer.money)),0) AS ticket_money']);
+ $query->from('transfer');
+ $query->andWhere(['transfer.type' => Transfer::TYPE_TICKET]);
+ $query->innerJoin("ticket", "ticket.id_ticket = transfer.id_object");
+ $this->addQueryFilters($query);
+
+// $query = Transfer::find();
+// $query->andWhere(['type' => Transfer::TYPE_TICKET]);
+// $this->addQueryFilters($query);
+ $this->ticketMoney = $query->scalar();
+ print_r($this->ticketMoney);
+ }
+
+ protected function readProductsByCategory(){
+
+
+ $query = (new \yii\db\Query());
+ $query->select(['coalesce(sum(transfer.money),0) AS product_money', 'product_category.name as category_name']);
+ $query->from('transfer');
+ $query->groupBy(['product_category.id_product_category','product_category.name']);
+ $query->andWhere(['transfer.type' => Transfer::TYPE_PRODUCT]);
+ $query->innerJoin("sale", "sale.id_sale = transfer.id_object");
+ $query->innerJoin("product", "sale.id_product = product.id_product");
+ $query->innerJoin("product_category", "product.id_product_category = product_category.id_product_category");
+ $this->addQueryFilters($query);
+
+ $this->productMoneies = $query->all();
+
+ }
+
+
+ protected function readMoneyMovements(){
+ $query = (new \yii\db\Query());
+ $query->select([' coalesce(sum(abs(transfer.money)),0) AS money_movement_money']);
+ $query->from('transfer');
+ $query->andWhere(['transfer.type' => Transfer::TYPE_MONEY_MOVEMENT_OUT]);
+ $query->innerJoin("money_movement", "money_movement.id_money_movement = transfer.id_object");
+ $this->addQueryFilters($query);
+
+ $this->moneyMovementMoneis = $query->one();
+ }
+
+
+
+}
diff --git a/backend/views/transfer/_search_summary.php b/backend/views/transfer/_search_summary.php
new file mode 100644
index 0000000..86b965a
--- /dev/null
+++ b/backend/views/transfer/_search_summary.php
@@ -0,0 +1,58 @@
+
+
+
+
+ ['summary'],
+ 'method' => 'get',
+ ]); ?>
+
+
+
+ = $form->field($model, 'id_account')->dropDownList( ['' => Yii::t('common/transfer', 'All')] +HtmlHelper::mkAccountOptions($accounts) ) ?>
+
+
+ = $form->field($model, 'id_user')->dropDownList( ['' => Yii::t('common/transfer', 'All')] +ArrayHelper::map($users,'id' , 'username') ) ?>
+
+
+
+
+
+ = $form->field($model, 'start')->widget(DatePicker::classname(), [
+ 'pluginOptions' => [
+ 'autoclose'=>true,
+ 'format' => 'yyyy.mm.dd'
+ ]
+ ]) ?>
+
+
+ = $form->field($model, 'end') ->widget(DatePicker::classname(), [
+ 'pluginOptions' => [
+ 'autoclose'=>true,
+ 'format' => 'yyyy.mm.dd'
+ ]
+ ]) ?>
+
+
+
+
+ = Html::submitButton(Yii::t('frontend/transfer', 'Search'), ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
diff --git a/backend/views/transfer/index.php b/backend/views/transfer/index.php
index 8ddc5f9..02ad157 100644
--- a/backend/views/transfer/index.php
+++ b/backend/views/transfer/index.php
@@ -43,6 +43,10 @@ $this->params['breadcrumbs'][] = $this->title;
'dataProvider' => $dataProvider,
'columns' => [
+ [
+ 'attribute' => 'id_transfer',
+ 'value' => 'id_transfer'
+ ],
[
'attribute' => 'type',
'value' => 'transferTypeName'
@@ -72,6 +76,7 @@ $this->params['breadcrumbs'][] = $this->title;
'value' => 'signedMoney'
],
'created_at:datetime',
+ 'paid_at:datetime',
['class' => 'yii\grid\ActionColumn',
'template' => '{view}'
diff --git a/backend/views/transfer/summary.php b/backend/views/transfer/summary.php
new file mode 100644
index 0000000..2f27a6e
--- /dev/null
+++ b/backend/views/transfer/summary.php
@@ -0,0 +1,73 @@
+title = Yii::t('frontend/transfer', 'Transfers Summary');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
+
+
= Html::encode($this->title) ?>
+ render('_search_summary', ['model' => $searchModel, 'accounts' => $accounts,'users' => $users,]); ?>
+
+
+
+
Bérletek összesen
+
+
+
+ | Bérletek |
+ ticketMoney?> FT |
+
+
+
+
Termékek összesen
+
+
+
+ | Termék kategória |
+ Összeg |
+
+
+
+
+ productMoneies as $pm ){
+ ?>
+ |
+ FT |
+
+
+
+
+
Pénzmozgások összesen
+
+
+
+ | Pénzmozgások |
+ moneyMovementMoneis['money_movement_money']?> FT |
+
+
+
+
Bevétel összesen
+
+
+
+ | Bérletek |
+ total?> FT |
+
+
+
+
diff --git a/backend/views/transfer/view.php b/backend/views/transfer/view.php
index 7e648a4..d2f58e3 100644
--- a/backend/views/transfer/view.php
+++ b/backend/views/transfer/view.php
@@ -41,6 +41,7 @@ $this->params['breadcrumbs'][] = $this->title;
'money',
'comment',
'created_at',
+ 'paid_at',
],
]) ?>
diff --git a/common/assets/TypeAheadAsset.php b/common/assets/TypeAheadAsset.php
new file mode 100644
index 0000000..7794e34
--- /dev/null
+++ b/common/assets/TypeAheadAsset.php
@@ -0,0 +1,27 @@
+
+ * @since 2.0
+ */
+class TypeAheadAsset extends AssetBundle
+{
+ public $sourcePath = '@vendor/bassjobsen/bootstrap-3-typeahead';
+ public $js = [
+ 'bootstrap3-typeahead.min.js',
+ ];
+ public $depends = [
+// 'yii\bootstrap\BootstrapAsset',
+// 'yii\bootstrap\BootstrapPluginAsset',
+ ];
+}
diff --git a/common/messages/hu/frontend/transfer.php b/common/messages/hu/frontend/transfer.php
index f8379da..816b973 100644
--- a/common/messages/hu/frontend/transfer.php
+++ b/common/messages/hu/frontend/transfer.php
@@ -28,4 +28,5 @@ return [
'Update' => 'Módosítás',
'Update {modelClass}: ' => '{modelClass} módosítás: ',
'pieces' => 'db',
+ 'Transfers Summary' => 'Bevétel'
];
diff --git a/common/models/Product.php b/common/models/Product.php
index 30544e8..94c04f7 100644
--- a/common/models/Product.php
+++ b/common/models/Product.php
@@ -168,6 +168,20 @@ class Product extends \common\models\BaseFitnessActiveRecord {
]);
}
+ public static function modelToMapIdName($product,$default = null){
+
+ if ( $product == null ){
+ return $default;
+ }
+
+ return ArrayHelper::toArray($product, [
+ 'common\models\Product' => [
+ 'id_product',
+ 'name',
+ ],
+ ]);
+ }
+
public static function sellProduct($product,$count){
$product->stock = $product->stock - $count;
}
diff --git a/composer.json b/composer.json
index 3f207c2..43d682f 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,8 @@
"yiisoft/yii2-jui": "^2.0",
"bower-asset/moment": "^2.10",
"bower-asset/accounting": "^0.3.2",
- "dmstr/yii2-adminlte-asset": "2.*"
+ "dmstr/yii2-adminlte-asset": "2.*",
+ "bassjobsen/bootstrap-3-typeahead": "^4.0"
},
"require-dev": {
"yiisoft/yii2-codeception": "*",
diff --git a/composer.lock b/composer.lock
index ef0da64..f0c982d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "48dcd434e58d6b2167477f208c700dc3",
- "content-hash": "2678695117e871d59f193589465751cf",
+ "hash": "acfc873fb659d08adc23d325138a56b2",
+ "content-hash": "28e2bce30da929c84bd2ac7cffd90f3f",
"packages": [
{
"name": "almasaeed2010/adminlte",
@@ -47,6 +47,42 @@
],
"time": "2015-10-23 14:50:49"
},
+ {
+ "name": "bassjobsen/bootstrap-3-typeahead",
+ "version": "v4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bassjobsen/Bootstrap-3-Typeahead.git",
+ "reference": "516d96962e1d7fc7c3972c9bbba3b0a133ae9aae"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bassjobsen/Bootstrap-3-Typeahead/zipball/516d96962e1d7fc7c3972c9bbba3b0a133ae9aae",
+ "reference": "516d96962e1d7fc7c3972c9bbba3b0a133ae9aae",
+ "shasum": ""
+ },
+ "type": "component",
+ "extra": {
+ "component": {
+ "files": [
+ "bootstrap3-typeahead.js",
+ "bootstrap3-typeahead.min.js"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Bass Jobsen",
+ "email": "bass@w3masters.nl"
+ }
+ ],
+ "description": "Bootstrap 3 Typeahead",
+ "time": "2015-11-14 22:02:27"
+ },
{
"name": "bower-asset/accounting",
"version": "v0.3.2",
diff --git a/frontend/assets/ProductSellAsset.php b/frontend/assets/ProductSellAsset.php
index 30bed56..e7a4430 100644
--- a/frontend/assets/ProductSellAsset.php
+++ b/frontend/assets/ProductSellAsset.php
@@ -26,5 +26,7 @@ class ProductSellAsset extends AssetBundle
public $depends = [
'frontend\assets\AppAsset',
'yii\jui\JuiAsset',
+ 'common\assets\TypeAheadAsset',
+
];
}
diff --git a/frontend/controllers/ProductController.php b/frontend/controllers/ProductController.php
index abb7a33..866a2dc 100644
--- a/frontend/controllers/ProductController.php
+++ b/frontend/controllers/ProductController.php
@@ -42,7 +42,7 @@ class ProductController extends Controller
],
'access' => [
'class' => \yii\filters\AccessControl::className(),
- 'only' => [ 'sale','payout-customer-cart','payout-user-cart', 'lookup'],
+ 'only' => [ 'sale','payout-customer-cart','payout-user-cart', 'lookup','find'],
'rules' => [
// allow authenticated users
[
@@ -82,6 +82,11 @@ class ProductController extends Controller
$model->customer = $this->customer;
$model->card = $this->card;
+ $products = Product::read();
+ $products = Product::modelToMapIdName($products);
+
+ $model->products = $products;
+
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
@@ -203,6 +208,23 @@ class ProductController extends Controller
+ return $result;
+ }
+
+ /**
+ */
+ public function actionFind($id=null)
+ {
+ $result = [];
+ $product = Product::findOne($id);
+ $product = Product::modelToArray($product);
+
+ $result['product'] = $product;
+
+ \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+
+
+
return $result;
}
diff --git a/frontend/models/ProductLookupForm.php b/frontend/models/ProductLookupForm.php
index 5486ec2..3da4082 100644
--- a/frontend/models/ProductLookupForm.php
+++ b/frontend/models/ProductLookupForm.php
@@ -14,6 +14,9 @@ class ProductLookupForm extends Model
{
public $filter_text;
+ public $product_search;
+
+
/**
@@ -33,6 +36,7 @@ class ProductLookupForm extends Model
{
return [
'filter_text' => Yii::t('frontend/product','Barcode or product code') ,
+ 'product_search' => Yii::t("frontend/product", "Name"),
];
}
diff --git a/frontend/models/ProductSaleForm.php b/frontend/models/ProductSaleForm.php
index 800f4e0..bc9f298 100644
--- a/frontend/models/ProductSaleForm.php
+++ b/frontend/models/ProductSaleForm.php
@@ -76,6 +76,8 @@ class ProductSaleForm extends Model
public $customerCart;
+ public $products;
+
/**
* @inheritdoc
*/
diff --git a/frontend/views/product/_sale_form.php b/frontend/views/product/_sale_form.php
index ad3bcf5..9dea5f8 100644
--- a/frontend/views/product/_sale_form.php
+++ b/frontend/views/product/_sale_form.php
@@ -47,6 +47,8 @@ $discountOptions = mkOptions( ArrayHelper::map($discounts, 'id_discount', 'name'
],
] )?>
+
+ field($lookupModel,'product_search')->textInput(['id'=>'product_search']); ?>
field($lookupModel,'filter_text')->textInput(['id'=>'filter_text']); ?>
diff --git a/frontend/views/product/sale.php b/frontend/views/product/sale.php
index d07db23..82ebfd8 100644
--- a/frontend/views/product/sale.php
+++ b/frontend/views/product/sale.php
@@ -16,8 +16,10 @@ ProductSellAsset::register($this);
$options = [];
$options['lookup_product_url'] = Url::toRoute(['product/lookup']);
+$options['find_product_url'] = Url::toRoute(['product/find']);
$options['url_pay_user_cart'] = Url::toRoute(['product/payout-user-cart']);
$options['user_cart'] = $userTransfers;
+$options['products'] = $model->products;
if ( isset($model->card) ){
$options['url_pay_customer_card'] = Url::toRoute(['product/payout-customer-cart','number' => $model->card->number]);
$options['customer_cart'] = $model->customerCart;
diff --git a/frontend/web/js/product.sell.js b/frontend/web/js/product.sell.js
index 0fb5a37..dcdff21 100644
--- a/frontend/web/js/product.sell.js
+++ b/frontend/web/js/product.sell.js
@@ -18,6 +18,7 @@ function ProductSell(o){
url_pay_user_cart: '',
/** ajax url for lookup service*/
lookup_product_url: '',
+ find_product_url: '',
/**the id of form*/
selector_form: '#product_form',
/**form contains error text*/
@@ -28,6 +29,7 @@ function ProductSell(o){
discounts: [],
customer_cart: [],
id_account: null,
+ products : [],
};
@@ -51,6 +53,8 @@ function ProductSell(o){
productChanged();
addDocumentKeypressedListener();
+
+ initAutocomplete();
}
/**
@@ -117,7 +121,7 @@ function ProductSell(o){
var word;
word = data.word;
if ( word.length > 0){
- if ( word.length >= 6 && word.length <= 8 ){
+ if ( word.length >= 6 && word.length <= 9 ){
//lookupuser
}else{
$("#filter_text").val(data.word);
@@ -175,11 +179,20 @@ function ProductSell(o){
$( app.defaults.selector_filter_text ).keypress(function( event ) {
if ( event.which == 13 ) {
event.preventDefault();
+ $('#product_search').val('');
+ $(this).val( fixBarcode($(this).val()));
lookupProduct();
}
});
}
+ function fixBarcode(s){
+ var result;
+ result = s;
+ result = result.replace(/ö/g, "0");
+ return result;
+ }
+
/**listen for enter key pressed on #productsaleform-count*/
function addBehaviorCountEnterPressedListener(){
$( '#productsaleform-count' ).keypress(function( event ) {
@@ -249,6 +262,22 @@ function ProductSell(o){
});
}
+ function _findProduct(id){
+ var data, url;
+
+ url = app.defaults.find_product_url;
+ data = {
+ 'id' : id,
+ };
+
+ $.ajax({
+ dataType: "json",
+ url: url,
+ data: data,
+ success: onLookupProductReady
+ });
+ }
+
/**succes event handler after lookup product event*/
function onLookupProductReady( data ){
app.product = data.product;
@@ -278,6 +307,7 @@ function ProductSell(o){
$('#productsaleform-id_product').val('');
$('#productsaleform-id_account').val( app.defaults.id_account ? app.defaults.id_account : '');
$("#productsaleform-count").val(1);
+//
}
function applyProduct(product){
@@ -374,6 +404,7 @@ function ProductSell(o){
clearForm();
refreshCalculatedValues();
$("#filter_text").val('');
+ $("#product_search").val('');
setFocus();
app.defaults.user_cart = response.transfers;
app.defaults.customer_cart = response.customer_cart;
@@ -486,7 +517,7 @@ function ProductSell(o){
function normalizePrice( price ){
var result;
- result = hufRound(price);
+// result = hufRound(price);
return result;
}
@@ -499,4 +530,44 @@ function ProductSell(o){
}
}
+
+ function initAutocomplete(){
+// var colors = ["red", "blue", "green", "yellow", "brown", "black"];
+// $('#product_search').typeahead( {source: colors } );
+
+ var $input = $('#product_search');
+ $input.typeahead({source: app.defaults.products,
+ autoSelect: true,
+ items: 12,
+ minLength: 3,
+// displayText: function (item){
+// return item.
+// }
+
+ });
+ $input.change(function() {
+ var current = $input.typeahead("getActive");
+ $("#filter_text").val('');
+ if (current) {
+ // Some item from your model is active!
+ if (current.name == $input.val()) {
+ // This means the exact match is found. Use toLowerCase() if you want case insensitive match.
+ console.info(current);
+ _findProduct(current.id_product);
+ } else {
+ // This means it is only a partial match, you can either add a new item
+ // or take the active if you don't want new items
+ console.info('partial');
+ app.product = null;
+ productChanged();
+ }
+ } else {
+ // Nothing is active so it is a new value (or maybe empty value)
+ console.info('incactive');
+ app.product = null;
+ productChanged();
+ }
+ });
+ }
+
}