diff --git a/backend/assets/InventoryItemIndexAsset.php b/backend/assets/InventoryItemIndexAsset.php new file mode 100644 index 0000000..27f1ec7 --- /dev/null +++ b/backend/assets/InventoryItemIndexAsset.php @@ -0,0 +1,31 @@ + + * @since 2.0 + */ +class InventoryItemIndexAsset extends AssetBundle +{ + public $basePath = '@webroot'; + public $baseUrl = '@web'; + public $css = [ + ]; + public $js = [ + 'js/app.js', + 'js/inventory.item.index.js', + ]; + public $depends = [ + 'backend\assets\AppAsset', + 'yii\jui\JuiAsset', + 'common\assets\TypeAheadAsset', + ]; +} diff --git a/backend/components/AdminMenuStructure.php b/backend/components/AdminMenuStructure.php index b04dd80..b53c099 100644 --- a/backend/components/AdminMenuStructure.php +++ b/backend/components/AdminMenuStructure.php @@ -106,6 +106,7 @@ class AdminMenuStructure{ // $items[] = ['label' => 'Bevétel', 'url' => ['/transfer/summary' , 'TransferSummarySearch[start]' =>$today,'TransferSummarySearch[end]' => $tomorrow ] ]; $items[] = ['label' => 'Napi bevételek', 'url' => ['/transfer/list', 'TransferListSearch[start]' =>$todayDatetime,'TransferListSearch[end]' => $tomorrowDatetime ] ]; $items[] = ['label' => 'Kassza müveletek', 'url' => ['/account-state/index'] ]; + $items[] = ['label' => 'Későbbi utalások', 'url' => ['/transfer/payment-later','TransferLaterSearch[start]' =>$todayDatetime,'TransferLaterSearch[end]' => $tomorrowDatetime ] ]; //$items[] = ['label' => 'Zárások', 'url' => ['/collection/index' , 'CollectionSearch[start]' =>$todayDatetime,'CollectionSearch[end]' => $tomorrowDatetime ] ]; $this->menuItems[] = ['label' => 'Pénzügy', 'url' => $this->emptyUrl, 'items' => $items diff --git a/backend/controllers/AccountStateController.php b/backend/controllers/AccountStateController.php index 2d79718..e3304c5 100644 --- a/backend/controllers/AccountStateController.php +++ b/backend/controllers/AccountStateController.php @@ -69,7 +69,6 @@ class AccountStateController extends \backend\controllers\BackendController * @return mixed */ public function actionView($id) { - echo "view"; $accountState = $this->findModel ( $id ); $output = Yii::$app->getRequest ()->getQueryParam ( 'output' ); $details = null; diff --git a/backend/controllers/InventoryController.php b/backend/controllers/InventoryController.php index 432469c..308384f 100644 --- a/backend/controllers/InventoryController.php +++ b/backend/controllers/InventoryController.php @@ -8,13 +8,7 @@ use backend\models\InventorySearch; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; -use common\models\InventoryItem; -use yii\data\ActiveDataProvider; -use common\components\Helper; use common\models\User; -use common\models\Product; -use common\models\InventoryGroup; -use yii\db\Expression; use yii\db\Query; use backend\models\InventoryItemSearch; @@ -50,27 +44,7 @@ class InventoryController extends Controller ]); } - /** - * Displays a single Inventory model. - * @param integer $id - * @return mixed - */ - public function actionView($id) - { - $inventory = $this->findModel($id); - - $searchModel = new InventoryItemSearch(['inventory' => $inventory]); - $dataProvider = $searchModel->search(Yii::$app->request->queryParams); - - - $query = new Query(); - - return $this->render('view', [ - 'model' => $inventory, - 'dataProvider' => $dataProvider - ]); - } - + /** * Creates a new Inventory model. * If creation is successful, the browser will be redirected to the 'view' page. @@ -88,43 +62,13 @@ class InventoryController extends Controller if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id_inventory]); } else { + } return $this->render('create', [ 'model' => $model, ]); - } } - /** - * Updates an existing Inventory 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_inventory]); - } else { - return $this->render('update', [ - 'model' => $model, - ]); - } - } - - /** - * Deletes an existing Inventory 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 Inventory model based on its primary key value. diff --git a/backend/controllers/InventoryItemController.php b/backend/controllers/InventoryItemController.php index f5d1fb0..1091b42 100644 --- a/backend/controllers/InventoryItemController.php +++ b/backend/controllers/InventoryItemController.php @@ -10,6 +10,8 @@ use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; use backend\models\InventoryItemForm; use common\models\Inventory; +use yii\helpers\Url; +use common\models\Product; /** * InventoryItemController implements the CRUD actions for InventoryItem model. @@ -42,14 +44,95 @@ class InventoryItemController extends Controller $searchModel = new InventoryItemSearch(['inventory' => $inventory]); $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + $productOptions = Product::buildProductAndInventoryGroupList(); + + if ($searchModel->output == 'xls') { + $this->downloadIndexXls($dataProvider); + }else{ + Url::remember(Url::current(),"inventory-item-index"); + } + return $this->render('index', [ 'model' => $inventory, 'searchModel' => $searchModel, 'dataProvider' => $dataProvider, + 'productOptions' =>$productOptions ]); } + + protected function downloadIndexXls($dataProvider){ + + + $defs = [['item_created_at', 'Létrehozva'], + ['item_name', 'Termék/Termék csoport'], + ['user_username', 'Felhasználó'], + ['item_count_prev', 'Előző leltár (db)'], + ['item_count_sold', 'Eladott mennyiség (db)'], + ['item_count_in', 'Beszerzett mennyiség (db)'], + ['item_count', 'Leltározott mennyiség (db)'], + ['item_difference', 'Különbség (db)'], + ['item_count_system', 'Rendszer szerinti mennyiség (db)'], + ]; + $cols = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P']; + + $models = $dataProvider->getModels (); + $objPHPExcel = new \PHPExcel (); + + $sheet = $objPHPExcel->setActiveSheetIndex ( 0 ); + /** + * Termék azonosító Termék neve Termék szám Termék vonalkód Termék raktáron Termék eladva + */ + $row = 1; + $col = 0; + foreach ( $defs as $def ) { + $sheet->setCellValue ( $cols [$col] . $row, $def [1] ); + $col ++; + } + + foreach ( $models as $model ) { + $row ++; + $col = 0; + foreach ( $defs as $def ) { + $sheet->setCellValue ( $cols [$col] . $row, $model[$def [0]] ); + $col ++; + } + } + + $styleArray = array ( + 'font' => array ( + 'bold' => true + ) + ); + // 'color' => array('rgb' => 'FF0000'), + // 'size' => 15, + // 'name' => 'Verdana' + + + + foreach ( range ( 'A', 'I' ) as $columnID ) { + $sheet->getColumnDimension ( $columnID )->setAutoSize ( true ); + $sheet->getStyle ( $columnID . '1' )->applyFromArray ( $styleArray ); + } + + // Redirect output to a client’s web browser (Excel5) + header ( 'Content-Type: application/vnd.ms-excel' ); + header ( 'Content-Disposition: attachment;filename="leltar.xls"' ); + header ( 'Cache-Control: max-age=0' ); + // If you're serving to IE 9, then the following may be needed + header ( 'Cache-Control: max-age=1' ); + // If you're serving to IE over SSL, then the following may be needed + header ( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' ); // Date in the past + header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' ) . ' GMT' ); // always modified + header ( 'Cache-Control: cache, must-revalidate' ); // HTTP/1.1 + header ( 'Pragma: public' ); // HTTP/1.0 + $objWriter = \PHPExcel_IOFactory::createWriter ( $objPHPExcel, 'Excel5' ); + $objWriter->save ( 'php://output' ); + exit (); + } + /** * Displays a single InventoryItem model. * @param integer $id @@ -93,12 +176,21 @@ class InventoryItemController extends Controller public function actionUpdate($id) { $model = $this->findModel($id); + $inventory = Inventory::findOne($model->id_inventory); if ($model->load(Yii::$app->request->post()) && $model->save()) { - return $this->redirect(['view', 'id' => $model->id_inventory_item]); + + $prev = Url::previous("inventory-item-index"); + if ( isset($prev)){ + return $this->redirect($prev); + }else{ + return $this->redirect([ 'index', 'id' => $inventory->id_inventory ]); + } + } else { return $this->render('update', [ 'model' => $model, + 'inventory' => $inventory, ]); } } diff --git a/backend/controllers/TransferController.php b/backend/controllers/TransferController.php index 66b538b..1ae6b34 100644 --- a/backend/controllers/TransferController.php +++ b/backend/controllers/TransferController.php @@ -15,6 +15,8 @@ use backend\models\TransferSaleSearch; use common\models\ProductCategory; use common\models\Product; use backend\models\TransferListUserGroupedSearch; +use backend\models\TransferLaterSearch; +use yii\helpers\Url; /** * TransferController implements the CRUD actions for Transfer model. @@ -29,7 +31,14 @@ class TransferController extends \backend\controllers\BackendController 'rules' => [ // allow authenticated users [ - 'actions' => [ 'index','view','summary','list',"sale","sale-pdf" ,'list-user-grouped'], + 'actions' => [ 'index', + 'view', + 'summary', + 'list', + "sale", + "sale-pdf" , + 'list-user-grouped', + 'payment-later'], 'allow' => true, 'roles' => ['admin','employee','reception'], ], @@ -40,6 +49,34 @@ class TransferController extends \backend\controllers\BackendController } + public function actionPaymentLater(){ + $searchModel = new TransferLaterSearch(); + + + if ( \Yii::$app->request->isPost){ + $searchModel->load(Yii::$app->request->post()); + if ( $searchModel->doPayout()) { + return $this->redirect(['transfer/payment-later' ]); + } + } + + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + $accounts = Account::read(); + + + $users = User::read(); + + Url::remember("payment_later",Url::current()); + + return $this->render('payment_later', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + 'accounts' => $accounts, + 'users' => $users, + ]); + } + /** * Lists all Transfer models. * @return mixed diff --git a/backend/models/InventoryItemForm.php b/backend/models/InventoryItemForm.php index 8ef2ce4..6e53108 100644 --- a/backend/models/InventoryItemForm.php +++ b/backend/models/InventoryItemForm.php @@ -89,7 +89,6 @@ class InventoryItemForm extends Model{ } public function save(){ - if ( $this->validate()) { $this->loadLastInventory(); @@ -109,10 +108,14 @@ class InventoryItemForm extends Model{ if ( isset( $this->last_inventory_item ) ){ $item->id_inventory_item_prev = $this->last_inventory_item->id_inventory_item; $item->count_prev = $this->last_inventory_item->count; + if ( !isset($item->count_prev)){ + $item->count_prev = 0; + } }else{ $item->count_prev = 0; } + $item->id_user = \Yii::$app->user->id; if ( $this->type == 'product'){ @@ -122,19 +125,18 @@ class InventoryItemForm extends Model{ } $item->id_inventory = $this->inventory->id_inventory; - if ( !$item->save() ){ + if ( !$item->save(false) ){ throw new \Exception("Nem sikerült a leltár végrehajtása"); } $this->inventory_item = $item; return true; - } - return false; } + protected function loadProductIn(){ $query = new Query(); - $query->select(['sum(procurement.count) as total_in']); + $query->select(['coalesce(sum(procurement.count),0) as total_in']); $query->from(Procurement::tableName()); $query->innerJoin(Product::tableName(),"product.id_product = procurement.id_product"); @@ -155,7 +157,7 @@ class InventoryItemForm extends Model{ protected function loadProductSold(){ $query = new Query(); - $query->select(['sum(transfer.count) as total_sold']); + $query->select(['coalesce(sum(transfer.count),0) as total_sold']); $query->from(Transfer::tableName()); $query->innerJoin(Sale::tableName(),"sale.id_sale = transfer.id_object and transfer.type = " .Transfer::TYPE_PRODUCT); $query->innerJoin(Product::tableName(),"product.id_product = sale.id_product "); @@ -174,7 +176,7 @@ class InventoryItemForm extends Model{ protected function loadProductStock(){ $query = new Query(); - $query->select(['sum(product.stock) as total_stock']); + $query->select(['coalesce(sum(product.stock),0) as total_stock']); $query->from(Product::tableName()); if ( $this->type == 'product') { diff --git a/backend/models/InventoryItemSearch.php b/backend/models/InventoryItemSearch.php index ef2ea49..b49fb49 100644 --- a/backend/models/InventoryItemSearch.php +++ b/backend/models/InventoryItemSearch.php @@ -20,7 +20,10 @@ use common\models\Inventory; class InventoryItemSearch extends InventoryItem { public $inventory; - + public $output; + public $item_name; + public $item_type; + public $item_id; /** * @inheritdoc */ @@ -28,6 +31,10 @@ class InventoryItemSearch extends InventoryItem { return [ [['id_inventory_item', 'id_inventory', 'count_in', 'count_sold', 'count', 'type', 'id_product', 'id_inventory_group', 'id_user'], 'integer'], + ['output', 'string'], + ['item_name', 'string'], + ['item_type', 'string'], + ['item_id', 'integer'], ]; } @@ -50,6 +57,7 @@ class InventoryItemSearch extends InventoryItem public function search($params) { $query = new Query(); + $query->select([ 'inventory_item.id_inventory_item as item_id_inventory_item', 'inventory_item.created_at as item_created_at', @@ -63,8 +71,9 @@ class InventoryItemSearch extends InventoryItem 'inventory.created_at as inventory_created_at', 'inventory_prev.id_inventory as inventory_prev_id_inventory', 'inventory_prev.name as inventory_prev_name', - new Expression('(inventory_item.count - ( inventory_item.count_prev + inventory_item.count_in - inventory_item.count_sold )) as item_difference'), + new Expression('(coalesce(inventory_item.count,0) - ( coalesce(inventory_item.count_prev,0) + coalesce(inventory_item.count_in,0) - coalesce(inventory_item.count_sold,0) )) as item_difference'), ]); + $query->from(InventoryItem::tableName()); @@ -78,9 +87,19 @@ class InventoryItemSearch extends InventoryItem $query->andWhere( ['inventory_item.id_inventory' => $this->inventory->id_inventory] ); + $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; + } + $dataProvider = new ActiveDataProvider( ['query' => $query , + 'pagination' => ( empty($this->output) ? [] : false ), 'sort' => [ + 'defaultOrder' => ['item_name' => SORT_ASC], 'attributes' => Helper::mkYiiSortItems([ ['item_created_at', 'item_created_at'], ['item_name', 'item_name'], @@ -100,22 +119,16 @@ class InventoryItemSearch extends InventoryItem ] ] ); - $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([ - 'inventory_item.id_inventory_item' => $this->id_inventory_item, - 'inventory_item.type' => $this->type, - 'inventory_item.id_product' => $this->id_product, - 'inventory_item.id_inventory_group' => $this->id_inventory_group, - 'inventory_item.id_user' => $this->id_user, - 'inventory_item.created_at' => $this->created_at, - ]); + if ( !empty($this->item_type) && is_numeric($this->item_id) ){ + if ( $this->item_type == 'product'){ + $query->andFilterWhere(['product.id_product' => $this->item_id]); + }else if ( $this->item_type == 'group' ){ + $query->andFilterWhere(['inventory_group.id_inventory_group' => $this->item_id]); + } + } + return $dataProvider; } diff --git a/backend/models/InventorySearch.php b/backend/models/InventorySearch.php index 81ff763..baa9964 100644 --- a/backend/models/InventorySearch.php +++ b/backend/models/InventorySearch.php @@ -45,6 +45,9 @@ class InventorySearch extends Inventory $dataProvider = new ActiveDataProvider([ 'query' => $query, + 'sort' => [ + 'defaultOrder' => ['created_at' => SORT_DESC] + ] ]); $this->load($params); diff --git a/backend/models/TransferLaterSearch.php b/backend/models/TransferLaterSearch.php new file mode 100644 index 0000000..0ae56f2 --- /dev/null +++ b/backend/models/TransferLaterSearch.php @@ -0,0 +1,195 @@ +Yii::$app->formatter->datetimeFormat , 'timestampAttribute' => 'timestampStart' ,'timestampAttributeFormat' => 'yyyy-MM-dd HH:mm' ,'timeZone' => 'UTC' ], + [[ 'end' , ], 'date' ,'format' =>Yii::$app->formatter->datetimeFormat , 'timestampAttribute' => 'timestampEnd' ,'timestampAttributeFormat' => 'yyyy-MM-dd HH:mm' ,'timeZone' => 'UTC' ], + ['selected', '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) + { + $query = new Query(); + + $query->select([ + 'transfer.id_transfer as transfer_id_transfer', + 'transfer.created_at as transfer_created_at', + 'transfer.money as transfer_money', + 'transfer.status as transfer_status', + 'user.username as user_username', + 'customer.name as customer_name', + 'ticket_type.name as ticket_type_name', + 'product.name as product_name', + 'ticket.start as ticket_start', + 'ticket.end as ticket_end', + ]); + $query->from("transfer"); + $query->innerJoin('user', " user.id = transfer.id_user"); + $query->leftJoin('customer', " transfer.id_customer = customer.id_customer"); + $query->leftJoin('ticket', " transfer.type = ".Transfer::TYPE_TICKET." and transfer.id_object = ticket.id_ticket"); + $query->leftJoin('ticket_type', " ticket.id_ticket_type = ticket_type.id_ticket_type"); + $query->leftJoin('sale', " transfer.type = ".Transfer::TYPE_PRODUCT." and transfer.id_object = sale.id_sale"); + $query->leftJoin('product', " product.id_product = sale.id_product"); + + $query->andWhere(["transfer.payment_method" => Transfer::PAYMENT_METHOD_TRANSFER_LATER ]); + + $query->andWhere(['transfer.status' => Transfer::STATUS_NOT_PAID]); + + $dataProvider = new ActiveDataProvider([ + 'query' => $query, + 'sort' =>[ + 'defaultOrder' =>[ + 'transfer_created_at' => SORT_DESC + ], + 'attributes' => Helper::mkYiiSortItems([ + ['transfer_created_at'], + ['transfer_money'], + ['transfer_status'], + ['user_username'], + ['customer_name'], + ['ticket_type_name'], + ['product_name'], + ['ticket_start'], + ['ticket_end'], + ]) + + ] + ]); + + +// $query->addSelect( ['*' ]); + + $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([ + 'ticket_type.id_ticket_type' => $this->id_ticket_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]); + + $qtotal = Query::create($query); + $qtotal->select([ new Expression("coalesce(sum(transfer.money),0) as transfer_money" )]); + $this->total_money = $qtotal->scalar(); + + + return $dataProvider; + } + + + public function totalsTransfers( ){ + + + + + } + + + public function doPayout(){ + + if ( !isset($this->selected) || count($this->selected) == 0){ + Helper::flash("error", "Nincs kiválasztott tranzakció"); + return false; + } + + $transfers = Transfer::find() + ->andWhere(['status' => Transfer::STATUS_NOT_PAID ]) + ->andWhere(['payment_method' => Transfer::PAYMENT_METHOD_TRANSFER_LATER]) + ->andWhere(['in','transfer.id_transfer',$this->selected]) + ->all(); + + if ( count($transfers) != count($this->selected)){ + Helper::flash("warning", "A kiválasztott tranzakciókban időközben változás történt"); + return false; + } + + $db = \Yii::$app->db; + $tx = $db->beginTransaction(); + try{ + foreach ($transfers as $transfer){ + if ( !$transfer->payout($transfer->id_account) ){ + \Yii::error("Failed to payout transaction: " .$transfer->id_transfer); + throw new \Exception("Nem sikerült mententi a tranzakciókat"); + } + } + $tx->commit(); + Helper::flash("success", "Tranzakciók fizetettnek jelölve: " .count($transfers) . " db"); + }catch (\Exception $e){ + $tx->rollBack(); + Helper::flash("error", "Hiba történt a művelet közben"); + return false; + } + + + return true; + } + + + +} diff --git a/backend/models/TransferSearch.php b/backend/models/TransferSearch.php index b4e7bd7..16b1ace 100644 --- a/backend/models/TransferSearch.php +++ b/backend/models/TransferSearch.php @@ -143,7 +143,6 @@ class TransferSearch extends Transfer return $dataProvider; } - echo "start date:" .$this->timestampStart; $query->andFilterWhere([ 'transfer.id_account' => $this->id_account, diff --git a/backend/views/account-state/_item_view.php b/backend/views/account-state/_item_view.php index 7c58dce..3efd6fd 100644 --- a/backend/views/account-state/_item_view.php +++ b/backend/views/account-state/_item_view.php @@ -7,6 +7,7 @@ use yii\base\Widget; $model, + 'showDailyDownload' =>false ]); ?> diff --git a/backend/views/inventory-item/_form.php b/backend/views/inventory-item/_form.php index 0343c8d..e804144 100644 --- a/backend/views/inventory-item/_form.php +++ b/backend/views/inventory-item/_form.php @@ -12,8 +12,6 @@ use yii\widgets\ActiveForm; - field($model, 'name')->textInput(['autocomplete' => 'off']) ?> - field($model, 'id_product')->hiddenInput()->label(false) ?> field($model, 'type')->hiddenInput()->label(false) ?> field($model, 'count')->textInput() ?> diff --git a/backend/views/inventory-item/_search.php b/backend/views/inventory-item/_search.php index 1491d16..9214ca1 100644 --- a/backend/views/inventory-item/_search.php +++ b/backend/views/inventory-item/_search.php @@ -11,36 +11,22 @@ use yii\widgets\ActiveForm;