diff --git a/backend/components/AdminMenuStructure.php b/backend/components/AdminMenuStructure.php index 4573b18..2fd0e27 100644 --- a/backend/components/AdminMenuStructure.php +++ b/backend/components/AdminMenuStructure.php @@ -76,7 +76,7 @@ class AdminMenuStructure{ $items = []; $items[] = ['label' => 'Vendégek', 'url' => ['/customer/index'] , 'target_url' => ['/customer/index' ,'/customer/view','/ticket/index-customer'] ]; $items[] = ['label' => 'Bérletkártyák', 'url' => ['/card/index'] ]; - $items[] = ['label' => 'Bérletek', 'url' => ['/ticket/index' , 'TicketSearch[start]' =>$today,'TicketSearch[end]' => $tomorrow ] ]; + $items[] = ['label' => 'Bérletek', 'url' => ['/ticket/index' , 'TicketSearch[start]' =>$todayDatetime,'TicketSearch[end]' => $tomorrowDatetime ] ]; $items[] = ['label' => 'Statisztika', 'url' => ['/ticket/statistics' , 'TicketSearchStatisitcs[start]' =>$today,'TicketSearchStatisitcs[end]' => $tomorrow ] ]; $items[] = ['label' => 'Kártya létrehozás', 'url' => ['/card-package/index' , ] ]; $items[] = ['label' => 'Kártya csomag RFId hozzárendelés', 'url' => ['/card-package/import' , ] ]; diff --git a/backend/controllers/TicketController.php b/backend/controllers/TicketController.php index 1d1505b..f03bd76 100644 --- a/backend/controllers/TicketController.php +++ b/backend/controllers/TicketController.php @@ -2,9 +2,11 @@ namespace backend\controllers; +use common\models\Transfer; use Yii; use common\models\Ticket; use backend\models\TicketSearch; +use yii\helpers\ArrayHelper; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; @@ -23,7 +25,6 @@ use common\components\DetStatTetelProcessor; use yii\helpers\VarDumper; use backend\models\TicketUpdate; use yii\helpers\Url; -use frontend\components\HtmlHelper; use common\components\Helper; /** @@ -68,17 +69,255 @@ class TicketController extends \backend\controllers\BackendController { public function actionIndex() { $searchModel = new TicketSearch (); $dataProvider = $searchModel->search ( Yii::$app->request->queryParams ); - $searchModel->searchTotals (); - - $searchModel->users = User::read (); - $searchModel->accounts = Account::read (); - $searchModel->ticketTypes = TicketType::read (); + if ( $searchModel->output != 'pdf' && $searchModel->output != 'xls' ){ + $searchModel->searchTotals (); + $searchModel->users = User::read (); + $searchModel->accounts = Account::read (); + $searchModel->ticketTypes = TicketType::read (); + } + + + + + if ( $searchModel->output == 'pdf' ){ + return $this->downloadIndexPdf($searchModel,$dataProvider); + }else if ( $searchModel->output == 'xls'){ + return $this->downloadIndexXls($searchModel,$dataProvider); + } return $this->render ( 'index', [ 'searchModel' => $searchModel, 'dataProvider' => $dataProvider ] ); } + + /** + * @param $searchModel \backend\models\TicketSearch + * @param $dataProvider \yii\data\ActiveDataProvider + */ + private function downloadIndexXls($searchModel, $dataProvider){ + $objPHPExcel = new \PHPExcel (); + $sheet = $objPHPExcel->setActiveSheetIndex ( 0 ); + $formatter = \Yii::$app->formatter; + + $admin = User::findOne(\Yii::$app->user->id); + + $row = 1; + + $sheet->setCellValue('A'.$row, 'Exportálta'); + $sheet->setCellValue('B'.$row, $admin->username); + $sheet->setCellValue('C'.$row, 'Exportálás ideje'); + $sheet->setCellValue('D'.$row, $formatter->asDatetime(new \DateTime())); + + $row++; + $user = User::findOne($searchModel->id_user); + $ticketType = TicketType::findOne($searchModel->id_ticket_type); + $account = Account::findOne($searchModel->id_account); + $cardNumber = !empty($searchModel->card_number) ? $searchModel->card_number : "Mind"; + $ticketStatus = !empty($searchModel->status) ? Ticket::toStatusName($searchModel->status) : "Mind"; + $customerIdCustomer = !empty($searchModel->id_customer) ? $searchModel->id_customer : "Mind"; + $customerName = !empty($searchModel->customer_name) ? $searchModel->customer_name : "Mind"; + $start = isset($searchModel->start) ? $formatter->asDateTime($searchModel->timestampStart) : ''; + $end = isset($searchModel->end) ? $formatter->asDateTime($searchModel->timestampEnd) : ''; + $ticketIdTicket = !empty($searchModel->id_ticket ) ? $searchModel->id_ticket : 'Mind'; + + $allDateConditionOn = $searchModel->isAllDateConditionOn(); + $ticketIntervalIsValid = ( $allDateConditionOn || "1" == $searchModel->valid_in_interval )? "Igen" : ""; + $ticketIntervalIsCreated =( $allDateConditionOn || "1" == $searchModel->created_in_interval) ? "Igen" : ""; + $ticketIntervalIsExpire = ( $allDateConditionOn || "1" == $searchModel->expire_in_interval) ? "Igen" : ""; + $ticketIntervalIsPaid = ( $allDateConditionOn || "1" == $searchModel->paid_in_interval) ? "Igen" : ""; + + $sheet->setCellValue('A'.$row, 'Felhasználó'); + $sheet->setCellValue('B'.$row, isset($user) ? $user->username : 'Mind'); + $sheet->setCellValue('C'.$row, 'Bérlet típus'); + $sheet->setCellValue('D'.$row, isset($ticketType) ? $ticketType->name : 'Mind'); + $sheet->setCellValue('E'.$row, 'Kassza'); + $sheet->setCellValue('F'.$row, isset($account) ? $account->name : 'Mind'); + + $row++; + $sheet->setCellValue('A'.$row, 'Bérlet státusz'); + $sheet->setCellValue('B'.$row, $ticketStatus); + + $sheet->setCellValue('C'.$row, 'Vendég azonosító'); + $sheet->setCellValue('D'.$row, $customerIdCustomer); + + $sheet->setCellValue('E'.$row, 'Vendég neve'); + $sheet->setCellValue('F'.$row, $customerName); + + $row++; + $sheet->setCellValue('A'.$row, 'Időszak kezdete'); + $sheet->setCellValue('B'.$row, $start); + $sheet->setCellValue('C'.$row, 'Időszak vége'); + $sheet->setCellValue('D'.$row, $end); + $sheet->setCellValue('E'.$row, 'Bérlet azonosító'); + $sheet->setCellValue('F'.$row, $ticketIdTicket); + $sheet->setCellValue('G'.$row, 'Kártya szám'); + $sheet->setCellValue('H'.$row, $cardNumber); + + $row++; + $sheet->setCellValue('A'.$row, 'Érvényes az időszakban'); + $sheet->setCellValue('B'.$row, $ticketIntervalIsValid); + $sheet->setCellValue('C'.$row, 'Kiadva az időszakban'); + $sheet->setCellValue('D'.$row, $ticketIntervalIsCreated); + $sheet->setCellValue('E'.$row, 'Lejár az időszakban'); + $sheet->setCellValue('F'.$row, $ticketIntervalIsExpire); + $sheet->setCellValue('G'.$row, 'Fizetve az időszakban'); + $sheet->setCellValue('H'.$row, $ticketIntervalIsPaid); + + $row++; + $sheet->setCellValue('A'.$row, 'B. Azonosító') + ->setCellValue('B'.$row, 'Vendég') + ->setCellValue('C'.$row, 'Kártya') + ->setCellValue('D'.$row, 'Érvényes -tól') + ->setCellValue('E'.$row, 'Érvényes -ig') + ->setCellValue('F'.$row, 'Létrehozva') + ->setCellValue('G'.$row, 'Bérlet típus') + ->setCellValue('H'.$row, 'Felhasználó') + ->setCellValue('I'.$row, 'Kassza') + ->setCellValue('J'.$row, 'Státusz') + ->setCellValue('K'.$row, 'Belépések száma') + ->setCellValue('L'.$row, 'Maximum belépések száma') + ->setCellValue('M'.$row, 'Nála fizették') + ->setCellValue('N'.$row, 'Fizetési mód') + ->setCellValue('O'.$row, 'Összeg') + ->setCellValue('P'.$row, 'Fizetés státusza') + ->setCellValue('Q'.$row, 'Vendég azonosító') + ; + + + foreach ( $dataProvider->getModels() as $model ) { + $row ++; + $sheet + ->setCellValue('A'.$row, $model['ticket_id_ticket']) + ->setCellValue('B'.$row, $model['customer_name']) + ->setCellValue('C'.$row, $model['card_number']) + ->setCellValue('D'.$row, $formatter->asDate($model['ticket_start'])) + ->setCellValue('E'.$row, $formatter->asDate($model['ticket_end'])) + ->setCellValue('F'.$row, $formatter->asDateTime($model['ticket_created_at'])) + ->setCellValue('G'.$row, $model['ticket_type_name']) + ->setCellValue('H'.$row, $model['user_username']) + ->setCellValue('I'.$row, $model['account_name']) + ->setCellValue('J'.$row, Ticket::toStatusName( $model['ticket_status'])) + ->setCellValue('K'.$row, $model['ticket_usage_count']) + ->setCellValue('L'.$row, $model['ticket_max_usage_count']) + ->setCellValue('M'.$row, $model['paid_by_username']) + ->setCellValue('N'.$row, Transfer::toPaymentMethodName( $model['transfer_payment_method'])) + ->setCellValue('O'.$row, $model['ticket_price_brutto']) + ->setCellValue('P'.$row, Transfer::toStatusName( $model['transfer_status'])) + ->setCellValue('Q'.$row, $model['customer_id_customer']) + ; + } + + $styleArray = array ( + 'font' => array ( + 'bold' => true + ) + ); + + foreach ( range ( 'A', 'Q' ) as $columnID ) { + $sheet->getColumnDimension ( $columnID )->setAutoSize ( true ); + $sheet->getStyle ( $columnID . '6' )->applyFromArray ( $styleArray ); + } + + foreach ( ['A','C','E' ,'G']as $columnID ) { + for ($i = 1 ; $i < 6; $i++){ + $sheet->getStyle ( $columnID . $i )->applyFromArray ( $styleArray ); + } + } + + $fileName = "berletek"; + $fileName .= "_" . date ( "Ymd_His" ); + $fileName .= ".xls"; + + // Redirect output to a client’s web browser (Excel5) + header ( 'Content-Type: application/vnd.ms-excel' ); + header ( 'Content-Disposition: attachment;filename="' . $fileName . '"' ); + 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 (); + } + + private function downloadIndexPdf($searchModel,$dataProvider){ + + $formatter = \Yii::$app->formatter; + $admin = User::findOne(\Yii::$app->user->id); + $exported_at = $formatter->asDatetime(new \DateTime()); + + $user = User::findOne($searchModel->id_user); + $ticketType = TicketType::findOne($searchModel->id_ticket_type); + $account = Account::findOne($searchModel->id_account); + $ticketStatus = !empty($searchModel->status) ? Ticket::toStatusName($searchModel->status) : "Mind"; + $customerIdCustomer = !empty($searchModel->id_customer) ? $searchModel->id_customer : "Mind"; + $customerName = !empty($searchModel->customer_name) ? $searchModel->customer_name : "Mind"; + $start = isset($searchModel->start) ? $formatter->asDateTime($searchModel->timestampStart) : ''; + $end = isset($searchModel->end) ? $formatter->asDateTime($searchModel->timestampEnd) : ''; + $ticketIdTicket = !empty($searchModel->id_ticket ) ? $searchModel->id_ticket : 'Mind'; + + $allDateConditionOn = $searchModel->isAllDateConditionOn(); + $ticketIntervalIsValid = ( $allDateConditionOn || "1" == $searchModel->valid_in_interval )? "Igen" : ""; + $ticketIntervalIsCreated =( $allDateConditionOn || "1" == $searchModel->created_in_interval) ? "Igen" : ""; + $ticketIntervalIsExpire = ( $allDateConditionOn || "1" == $searchModel->expire_in_interval) ? "Igen" : ""; + $ticketIntervalIsPaid = ( $allDateConditionOn || "1" == $searchModel->paid_in_interval) ? "Igen" : ""; + + $username = isset($user) ? $user->username : 'Mind'; + $ticketTypeName = isset($ticketType) ? $ticketType->name : 'Mind'; + $accountName = isset($account) ? $account->name : 'Mind'; + $cardNumber = !empty($searchModel->card_number) ? $searchModel->card_number : "Mind"; + + $filters = [ + 'admin' => $admin->username, + 'exported_at' => $exported_at, + 'ticketStatus' =>$ticketStatus, + 'customerIdCustomer' => $customerIdCustomer, + 'customerName' => $customerName, + 'start' => $start, + 'end' => $end, + 'ticketIdTicket' => $ticketIdTicket, + 'ticketIntervalIsValid' => $ticketIntervalIsValid, + 'ticketIntervalIsCreated' => $ticketIntervalIsCreated, + 'ticketIntervalIsExpire' => $ticketIntervalIsExpire, + 'ticketIntervalIsPaid' => $ticketIntervalIsPaid, + 'username' => $username, + 'ticketTypeName' => $ticketTypeName, + 'accountName' => $accountName, + 'cardNumber' => $cardNumber + ]; + + $fileName = "berletek"; + $fileName .= "_" . date ( "Ymd_His" ); + $fileName .= ".pdf"; + $mpdf = new \mPDF ( 'utf-8', 'A4' ); + + $mpdf->useSubstitutions = false; + $mpdf->simpleTables = true; + $mpdf->SetHeader( \Yii::$app->params[ "company_name" ] . " - Bérletek - Létrehozva: " .$admin->username . ", ".\Yii::$app->formatter->asDatetime(time()) ); + $mpdf->setFooter ( '{PAGENO} / {nb}' ); + + $stylesheet = file_get_contents( \Yii::getAlias('@backend/web/css/ticket-index-pdf.css')); // external css + $mpdf->WriteHTML($stylesheet,1); + + $mpdf->WriteHTML ( $this->renderPartial ( '_index_pdf.php', [ + 'model' => $searchModel, + 'dataProvider' => $dataProvider, + 'filters' => $filters + ] ) ); + $mpdf->Output ( $fileName, 'D' ); + exit (); +/* + return $this->render ( '_index_pdf', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider + ] ); +*/ + } /** * Lists all Ticket models. @@ -125,11 +364,13 @@ class TicketController extends \backend\controllers\BackendController { ] ); } } - + /** * Lists all Ticket models. - * + * + * @param $id * @return mixed + * @throws NotFoundHttpException */ public function actionIndexCustomer($id) { $customer = Customer::findOne ( $id ); diff --git a/backend/models/TicketSearch.php b/backend/models/TicketSearch.php index 3c2d59e..df61d06 100644 --- a/backend/models/TicketSearch.php +++ b/backend/models/TicketSearch.php @@ -2,12 +2,15 @@ namespace backend\models; +use common\models\Transfer; use Yii; use yii\base\Model; use yii\data\ActiveDataProvider; use common\models\Ticket; use common\components\Helper; use yii\db\ActiveRecord; +use yii\db\Expression; +use yii\db\Query; use yii\helpers\ArrayHelper; /** @@ -15,35 +18,44 @@ use yii\helpers\ArrayHelper; */ class TicketSearch extends Ticket { - - public $timestampStart; - public $timestampEnd; - - public $users; - public $accounts; - public $ticketTypes; - - public $valid_in_interval; - public $created_in_interval; - public $expire_in_interval; - - public $statistics; - public $statisticsTotal; - - public $customer; - - + + public $timestampStart; + public $timestampEnd; + + public $users; + public $accounts; + public $ticketTypes; + + public $valid_in_interval; + public $created_in_interval; + public $expire_in_interval; + public $paid_in_interval; + + public $statistics; + public $statisticsTotal; + + public $customer; + public $output; + + public $id_customer; + public $customer_name; + public $card_number; + + /** * @inheritdoc */ public function rules() { return [ - [[ 'id_ticket', 'id_user', 'id_ticket_type', 'id_account','status'], 'integer'], - [[ 'start', ], 'date' , 'timestampAttribute' => 'timestampStart' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], - [[ 'end' , ], 'date' , 'timestampAttribute' => 'timestampEnd' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], - [[ 'valid_in_interval','created_in_interval','expire_in_interval'],'boolean'] , - + [['id_ticket', 'id_user', 'id_ticket_type', 'id_account', 'status', 'id_customer'], 'integer'], +// [[ 'start', ], 'date' , 'timestampAttribute' => 'timestampStart' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], +// [[ 'end' , ], 'date' , 'timestampAttribute' => 'timestampEnd' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], + [['start',], 'date', 'format' => 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'], + [['valid_in_interval', 'created_in_interval', 'expire_in_interval', 'paid_in_interval'], 'boolean'], + [['output', 'customer_name','card_number'], 'safe'] + ]; } @@ -55,29 +67,32 @@ class TicketSearch extends Ticket // bypass scenarios() implementation in the parent class return Model::scenarios(); } - - public function attributeLabels(){ - return ArrayHelper::merge(parent::attributeLabels(), [ - 'start' => Yii::t('backend/ticket','Start of interval'), - 'end' => Yii::t('backend/ticket','End of interval'), - 'valid_in_interval' => Yii::t('backend/ticket','Valid in interval'), - 'created_in_interval' => Yii::t('backend/ticket','Created in interval'), - 'expire_in_interval' => Yii::t('backend/ticket','Expire in interval'), - ]); + + public function attributeLabels() + { + return ArrayHelper::merge(parent::attributeLabels(), [ + 'start' => Yii::t('backend/ticket', 'Start of interval'), + 'end' => Yii::t('backend/ticket', 'End of interval'), + 'valid_in_interval' => Yii::t('backend/ticket', 'Valid in interval'), + 'created_in_interval' => Yii::t('backend/ticket', 'Created in interval'), + 'expire_in_interval' => Yii::t('backend/ticket', 'Expire in interval'), + 'paid_in_interval' => "Fizetve az időszakban", + ]); } - public function afterValidate(){ - - if ( !isset($this->timestampStart)) { - $this->timestampStart ='1900-01-01'; + public function afterValidate() + { + + if (!isset($this->timestampStart)) { + $this->timestampStart = '1900-01-01'; } - - if ( !isset($this->timestampEnd)) { - $this->timestampEnd ='3000-01-01'; + + if (!isset($this->timestampEnd)) { + $this->timestampEnd = '3000-01-01'; } - + } - + /** * Creates data provider instance with search query applied * @@ -87,141 +102,209 @@ class TicketSearch extends Ticket */ public function search($params) { - $query = Ticket::find(); + + $query = new Query(); + $query->select([ + 'ticket.id_ticket as ticket_id_ticket', + 'customer.id_customer as customer_id_customer', + 'customer.name as customer_name', + 'card.number as card_number', + 'ticket.start as ticket_start', + 'ticket.end as ticket_end', + 'ticket.created_at as ticket_created_at', + 'user.username as user_username', + 'ticket_type.name as ticket_type_name', + 'account.name as account_name', + 'ticket.status as ticket_status', + 'ticket.max_usage_count as ticket_max_usage_count', + 'ticket.usage_count as ticket_usage_count', + 'paid_by.username as paid_by_username', + 'transfer.payment_method as transfer_payment_method', + 'transfer.status as transfer_status', + 'transfer.money as transfer_money', + 'ticket.price_brutto as ticket_price_brutto' + ]); + $query->from('ticket'); + $query->innerJoin("transfer", "ticket.id_ticket = transfer.id_object and transfer.type =" . Transfer::TYPE_TICKET); + $query->innerJoin("card", "ticket.id_card = card.id_card"); + $query->innerJoin("customer", "card.id_card = customer.id_customer_card"); + $query->innerJoin("user", "user.id = transfer.id_user"); + $query->leftJoin("user as paid_by", "paid_by.id = transfer.paid_by"); + $query->innerJoin("account", "account.id_account = transfer.id_account"); + $query->innerJoin("ticket_type", "ticket_type.id_ticket_type = ticket.id_ticket_type"); + + $query->andWhere(['transfer.type' => Transfer::TYPE_TICKET]); Helper::queryAccountConstraint($query, 'ticket.id_account'); - - $query->with('ticketType' ); - $query->with('user'); - $query->with('customer'); - - - - $dataProvider = new ActiveDataProvider([ - 'query' => $query, - 'sort' =>[ - 'defaultOrder' => ['end' => SORT_DESC], - 'attributes' => ['end'] - ] - ]); $this->load($params); - + if (!$this->validate()) { $query->where('0=1'); return $query; } - + + + $dataProviderSetup = [ + 'query' => $query, + ]; + + $dataProviderSetup['sort'] = [ + 'defaultOrder' => ['ticket_created_at' => SORT_DESC], + 'attributes' => Helper::mkYiiSortItems([ + ['ticket_id_ticket'], + ['customer_name'], + ['customer_id_customer'], + ['card_number'], + ['ticket_start'], + ['ticket_end'], + ['ticket_created_at'], + ['user_username'], + ['ticket_type_name'], + ['account_name'], + ['ticket_status'], + ['ticket_max_usage_count'], + ['ticket_usage_count'], + ['paid_by_username'], + ['paid_at'], + ['transfer_payment_method'], + ['transfer_status'], + ['transfer_money'], + ['ticket_price_brutto'], + ]) + ]; + + if ($this->output == 'pdf' || $this->output == 'xls') { + $dataProviderSetup['pagination'] = false; + } + + $dataProvider = new ActiveDataProvider($dataProviderSetup); $query->andFilterWhere([ - 'id_user' => $this->id_user, - 'id_ticket_type' => $this->id_ticket_type, - 'id_account' => $this->id_account, - 'id_card' => $this->id_card, - 'id_ticket' => $this->id_ticket, - 'status' => $this->status + 'user.id' => $this->id_user, + 'ticket_type.id_ticket_type' => $this->id_ticket_type, + 'account.id_account' => $this->id_account, + 'card.id_card' => $this->id_card, + 'ticket.id_ticket' => $this->id_ticket, + 'ticket.status' => $this->status, + 'customer.id_customer' => $this->id_customer, + 'card.number' => $this->card_number ]); - - - $all = (!($this->valid_in_interval) && !($this->expire_in_interval) && !($this->created_in_interval) ) - || - ($this->valid_in_interval == true && $this->expire_in_interval == true && $this->created_in_interval); - - $dateConditions = []; - $start = $this->timestampStart; - $end = $this->timestampEnd; - - if( $all || $this->created_in_interval ){ - $dateConditions[] = Helper::queryInIntervalRule('ticket.created_at', $start, $end); + $query->andFilterWhere(['like', new Expression('LOWER(customer.name)'), strtolower($this->customer_name)]); + + $all = (!($this->valid_in_interval) && !($this->expire_in_interval) && !($this->created_in_interval) && !($this->paid_in_interval)) + || + ($this->valid_in_interval == true && $this->expire_in_interval == true && $this->created_in_interval && $this->paid_in_interval); + + $dateConditions = []; + $start = $this->timestampStart; + $end = $this->timestampEnd; + + if ($all || $this->created_in_interval) { + $dateConditions[] = Helper::queryInIntervalRule('ticket.created_at', $start, $end); } - - if ( $all || $this->valid_in_interval ){ - $dateConditions[] = Helper::queryValidRule('ticket.start', 'ticket.end', $start, $end); + + if ($all || $this->valid_in_interval) { + $dateConditions[] = Helper::queryValidRule('ticket.start', 'ticket.end', $start, $end); } - - if ( $all || $this->expire_in_interval ){ - $dateConditions[] = Helper::queryExpireRule('ticket.start', 'ticket.end', $start, $end); + + if ($all || $this->expire_in_interval) { + $dateConditions[] = Helper::queryExpireRule('ticket.start', 'ticket.end', $start, $end); } - - if ( count($dateConditions) == 1 ){ - $query->andWhere($dateConditions[0]); - }else if ( count($dateConditions) > 1 ){ - $cond = ['or']; - foreach ($dateConditions as $c){ - $cond[] = $c; - } - $query->andWhere($cond); + + if ($all || $this->paid_in_interval) { + $dateConditions[] = ['and', ['>=', 'transfer.paid_at', $start], ['<', 'transfer.paid_at', $end]]; + } + + if (count($dateConditions) == 1) { + $query->andWhere($dateConditions[0]); + } else if (count($dateConditions) > 1) { + $cond = ['or']; + foreach ($dateConditions as $c) { + $cond[] = $c; + } + $query->andWhere($cond); } return $dataProvider; } - - - - public function searchTotals(){ - $query = Ticket::mkStatisticQuery($this->timestampStart, $this->timestampEnd,$this->id_card); - $this->statistics = $query->all(); - - $this->statisticsTotal =[ - 'valid' => 0, - 'created' => 0, - 'created_at_money' => 0, - 'expired' => 0, - ]; - - $this->statisticsTotal['valid'] = array_sum(array_column($this->statistics, 'valid')); - $this->statisticsTotal['created'] = array_sum(array_column($this->statistics, 'created')); - $this->statisticsTotal['created_money'] = array_sum(array_column($this->statistics, 'created_money')); - $this->statisticsTotal['expired'] = array_sum(array_column($this->statistics, 'expired')); + + + public function isAllDateConditionOn(){ + $all = (!($this->valid_in_interval) && !($this->expire_in_interval) && !($this->created_in_interval) && !($this->paid_in_interval)) + || + ($this->valid_in_interval == true && $this->expire_in_interval == true && $this->created_in_interval && $this->paid_in_interval); + + return $all; } - - - public static function mkSearchCondition( $timestampStart, $timestampEnd, $id_user,$id_ticket_tpye,$id_account,$valid_in_interval ,$expire_in_interval,$created_in_interval ){ - $query = Ticket::find(); - - Helper::queryAccountConstraint($query, 'ticket.id_account'); - - $query->with('ticketType' ); - $query->with('user'); - $query->with('customer'); - - $query->andFilterWhere([ - 'id_user' => $id_user, - 'id_ticket_type' => $id_ticket_type, - 'id_account' => $id_account, - ]); - - $all = (!($valid_in_interval) && !($expire_in_interval) && !($created_in_interval) ) - || - ($valid_in_interval == true && $expire_in_interval == true && $created_in_interval); - - $dateConditions = []; - $start = $timestampStart; - $end = $timestampEnd; - - if( $all || $created_in_interval ){ - $dateConditions[] = Helper::queryInIntervalRule('ticket.created_at', $start, $end); - } - - if ( $all || $valid_in_interval ){ - $dateConditions[] = Helper::queryValidRule('ticket.start', 'ticket.end', $start, $end); - } - - if ( $all || $expire_in_interval ){ - $dateConditions[] = Helper::queryExpireRule('ticket.start', 'ticket.end', $start, $end); - } - - if ( count($dateConditions) == 1 ){ - $query->andWhere($dateConditions[0]); - }else if ( count($dateConditions) > 1 ){ - $cond = ['or']; - foreach ($dateConditions as $c){ - $cond[] = $c; - } - $query->andWhere($cond); - } + + + public function searchTotals() + { + $query = Ticket::mkStatisticQuery($this->timestampStart, $this->timestampEnd, $this->id_card); + $this->statistics = $query->all(); + + $this->statisticsTotal = [ + 'valid' => 0, + 'created' => 0, + 'created_at_money' => 0, + 'expired' => 0, + ]; + + $this->statisticsTotal['valid'] = array_sum(array_column($this->statistics, 'valid')); + $this->statisticsTotal['created'] = array_sum(array_column($this->statistics, 'created')); + $this->statisticsTotal['created_money'] = array_sum(array_column($this->statistics, 'created_money')); + $this->statisticsTotal['expired'] = array_sum(array_column($this->statistics, 'expired')); } - + + + public static function mkSearchCondition($timestampStart, $timestampEnd, $id_user, $id_ticket_tpye, $id_account, $valid_in_interval, $expire_in_interval, $created_in_interval) + { + $query = Ticket::find(); + + Helper::queryAccountConstraint($query, 'ticket.id_account'); + + $query->with('ticketType'); + $query->with('user'); + $query->with('customer'); + + $query->andFilterWhere([ + 'id_user' => $id_user, + 'id_ticket_type' => $id_ticket_type, + 'id_account' => $id_account, + ]); + + $all = (!($valid_in_interval) && !($expire_in_interval) && !($created_in_interval)) + || + ($valid_in_interval == true && $expire_in_interval == true && $created_in_interval); + + $dateConditions = []; + $start = $timestampStart; + $end = $timestampEnd; + + if ($all || $created_in_interval) { + $dateConditions[] = Helper::queryInIntervalRule('ticket.created_at', $start, $end); + } + + if ($all || $valid_in_interval) { + $dateConditions[] = Helper::queryValidRule('ticket.start', 'ticket.end', $start, $end); + } + + if ($all || $expire_in_interval) { + $dateConditions[] = Helper::queryExpireRule('ticket.start', 'ticket.end', $start, $end); + } + + if (count($dateConditions) == 1) { + $query->andWhere($dateConditions[0]); + } else if (count($dateConditions) > 1) { + $cond = ['or']; + foreach ($dateConditions as $c) { + $cond[] = $c; + } + $query->andWhere($cond); + } + } + } diff --git a/backend/tests/fixtures/initdb.php b/backend/tests/fixtures/initdb.php new file mode 100644 index 0000000..2241c4d --- /dev/null +++ b/backend/tests/fixtures/initdb.php @@ -0,0 +1 @@ +INSERT INTO user (username,auth_key,password_hash,password_reset_token,email,status,created_at,updated_at) VALUES ('admin','TzZY5KoLbg4VTxwaxs5OoxhFwNt_VeIv','$2y$13$oWyHf7oSB7XktVe0pEhfROahmxr9NWbYo0o3z69aH6rnBf0oyhTSe',null,'admin@rocho-net.hu',10,1446658188,1461356211); diff --git a/backend/views/ticket/_index_pdf.php b/backend/views/ticket/_index_pdf.php new file mode 100644 index 0000000..7f2ee9e --- /dev/null +++ b/backend/views/ticket/_index_pdf.php @@ -0,0 +1,128 @@ + +
+

Bérletek

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExportáltaExportálás ideje
FelhasználóBérlet típus
KasszaStátusz
Vendég azonVendég neve
Időszak -tólIdőszak -ig
Bérlet azonKártya
Érvényes az időszakbanKiadva az időszakban
Lejár az időszakbanFizetve az időszakban
+
+ $dataProvider, + 'tableOptions' => ['class' => 'table table-bordered tbl-pdf'], + 'columns' => [ + [ + 'attribute' => 'ticket_id_ticket', + 'label' => 'B. Azon.', + 'enableSorting' => false + ], + [ + 'attribute' => 'customer_name', + 'label' => 'Vendég', + 'enableSorting' => false + ], + [ + 'attribute' => 'card_number', + 'label' => 'Kártya', + 'enableSorting' => false + ], + [ + 'attribute' => 'ticket_start', + 'label' => 'Érvényes -tól', + 'format' => 'date', + 'enableSorting' => false + ], + [ + 'attribute' => 'ticket_end', + 'label' => 'Érvényes -ig', + 'format' => 'date', + 'enableSorting' => false + ], + [ + 'attribute' => 'ticket_created_at', + 'label' => 'Létrehozva', + 'format' => 'datetime', + 'enableSorting' => false + ], + [ + 'attribute' => 'ticket_type_name', + 'label' => 'Bérlet típus', + 'enableSorting' => false + ],[ + 'attribute' => 'user_username', + 'label' => 'Felhasználó', + 'enableSorting' => false + ], + [ + 'attribute' => 'account_name', + 'label' => 'Kassza', + 'enableSorting' => false + ], + [ + 'attribute' => 'ticket_status', + 'label' => 'Státusz', + 'enableSorting' => false, + 'value' => function ($model, $key, $index, $column){ + return \common\models\Ticket::toStatusName($model['ticket_status']); + } + ], + ] + ]); ?> +
diff --git a/backend/views/ticket/_search.php b/backend/views/ticket/_search.php index 651cc72..53d218c 100644 --- a/backend/views/ticket/_search.php +++ b/backend/views/ticket/_search.php @@ -1,9 +1,9 @@ 'Mind'] + ArrayHelper::map($model->users, 'id', 'userna field($model, 'status')->dropDownList( ["" =>"Mind"]+ Ticket::statuses()) ?>
+ field($model, 'id_customer')->textInput()->label("Vendég azonosító") ?> +
+
+ field($model, 'customer_name')->textInput()->label("Vendég neve") ?> +
+ + +
+
+ field($model, 'id_ticket')->textInput() ?> +
+
+ field($model, 'card_number')->textInput()->label("Kártyaszám") ?>
- +
- field($model, 'start')->widget(DatePicker::classname(), [ - 'pluginOptions' => [ - 'autoclose'=>true, - 'format' => 'yyyy.mm.dd' - ] - ]) ?> + field($model, 'start')->widget(DateTimePicker::className(), [ + 'pluginOptions' => [ + 'autoclose'=>true, + 'format' => 'yyyy.mm.dd hh:ii' + ] + ]) ?>
- field($model, 'end') ->widget(DatePicker::classname(), [ - 'pluginOptions' => [ - 'autoclose'=>true, - 'format' => 'yyyy.mm.dd' - ] - ]) ?> + field($model, 'end') ->widget(DateTimePicker::className() , [ + 'pluginOptions' => [ + 'autoclose'=>true, + 'format' => 'yyyy.mm.dd hh:ii' + ] + ]) ?>
- field($model, 'id_ticket')->textInput() ?> +
-
+
field($model, 'valid_in_interval')->checkbox( ) ?>
-
+
field($model, 'created_in_interval')->checkbox( ) ?>
-
+
field($model, 'expire_in_interval')->checkbox( ) ?>
+
+ field($model, 'paid_in_interval')->checkbox( ) ?> +
diff --git a/backend/views/ticket/index.php b/backend/views/ticket/index.php index 6b9673c..d7bb03b 100644 --- a/backend/views/ticket/index.php +++ b/backend/views/ticket/index.php @@ -12,23 +12,36 @@ use yii\data\ArrayDataProvider; $this->title = Yii::t('common/ticket', 'Tickets'); $this->params['breadcrumbs'][] = $this->title; - - ?> -
-

title) ?>

render('_search', ['model' => $searchModel]); ?> - - - +
+
+
+ + Exportálás: + + 'pdf' ]), + ['class' => 'btn btn-primary pull-left','style'=> 'margin-left: 12px;'] + ); + ?> + 'xls' ]), + ['class' => 'btn btn-primary pull-left','style'=> 'margin-left: 12px;'] + ); + ?> +
+
+
Bérlet statisztika

Bérlet statisztika a kiválasztott időszakra

new ArrayDataProvider([ 'allModels' => $searchModel->statistics, @@ -71,51 +84,71 @@ $this->params['breadcrumbs'][] = $this->title; ?>
- - + $dataProvider, + 'columns' => [ + [ + 'attribute' => 'ticket_id_ticket', + 'label' => 'B. Azonosító' + ], + [ + 'attribute' => 'customer_name', + 'label' => 'Vendég' + ], + [ + 'attribute' => 'card_number', + 'label' => 'Kártya' + ], + [ + 'attribute' => 'ticket_start', + 'label' => 'Érvényes -tól', + 'format' => 'date' + ], + [ + 'attribute' => 'ticket_end', + 'label' => 'Érvényes -ig', + 'format' => 'date' + ], + [ + 'attribute' => 'ticket_type_name', + 'label' => 'Bérlet típus', + ], + [ + 'attribute' => 'ticket_created_at', + 'label' => 'Létrehozva', + 'format' => 'datetime' + ], + [ + 'attribute' => 'user_username', + 'label' => 'Felhasználó', + ], + [ + 'attribute' => 'account_name', + 'label' => 'Kassza', + ], + [ + 'attribute' => 'ticket_status', + 'label' => 'Státusz', + 'value' => function ($model, $key, $index, $column){ + return \common\models\Ticket::toStatusName($model['ticket_status']); + } + ], + [ + 'class' => 'yii\grid\ActionColumn', + 'template' => '{view}', + 'urlCreator' => function($action, $model, $key, $index){ + $result = ""; - $dataProvider, - 'columns' => [ - [ - 'attribute' => 'id_ticket', - 'value' => 'id_ticket', - 'label' => 'B. Azonosító' - ], - [ - 'attribute' => 'id_customer', - 'value' => 'customerName' - ], - [ - 'attribute' => 'id_card', - 'value' => 'cardNumber' - ], - 'start:date', - 'end:date', - 'created_at:date', - [ - 'attribute' => 'id_user', - 'value' => 'userName' + if ( $action == 'view'){ + $result = \yii\helpers\Url::toRoute(['ticket/view','id' => $model['ticket_id_ticket']]); + } + + return $result; + } ], - [ - 'attribute' => 'id_ticket_type', - 'value' => 'ticketTypeName' - ], - [ - 'attribute' => 'id_account', - 'value' => 'accountName' - ], - [ - 'attribute' => 'status', - 'value' => 'statusName' - ], -// 'max_usage_count', -// 'usage_count', + ] - ['class' => 'yii\grid\ActionColumn', - 'template' => '{view}' - ], - ], - ]); ?> - -
+ ]); + ?> +
\ No newline at end of file diff --git a/backend/views/ticket/view.php b/backend/views/ticket/view.php index 5a6e79e..97bf41c 100644 --- a/backend/views/ticket/view.php +++ b/backend/views/ticket/view.php @@ -11,47 +11,43 @@ $this->params['breadcrumbs'][] = ['label' => Yii::t('common/ticket', 'Tickets'), $this->params['breadcrumbs'][] = $this->title; ?>
-

title) ?>

- - $model, 'attributes' => [ 'id_ticket', - [ - 'attribute' => 'id_user', - 'value' => $model->user->username, - - ], - [ - 'attribute' => 'id_ticket_type', - 'value' => $model->ticketTypeName, - - ], - [ - 'attribute' => 'id_account', - 'value' => $model->accountName, - - ], - [ - 'attribute' => 'id_discount', - 'value' => $model->discountName, - - ], - 'start:datetime', - 'end:datetime', + [ + 'attribute' => 'id_user', + 'value' => $model->user->username, + + ], + [ + 'attribute' => 'id_ticket_type', + 'value' => $model->ticketTypeName, + + ], + [ + 'attribute' => 'id_account', + 'value' => $model->accountName, + + ], + [ + 'attribute' => 'id_discount', + 'value' => $model->discountName, + + ], + 'start:date', + 'end:date', 'max_usage_count', 'usage_count', - [ - 'attribute' => 'status', - 'value' => $model->statusName - ], + [ + 'attribute' => 'status', + 'value' => $model->statusName + ], 'price_brutto', 'comment:raw', - 'created_at', - 'updated_at', + 'created_at:datetime', + 'updated_at:datetime', ], ]) ?> -
diff --git a/backend/web/css/ticket-index-pdf.css b/backend/web/css/ticket-index-pdf.css new file mode 100644 index 0000000..c537995 --- /dev/null +++ b/backend/web/css/ticket-index-pdf.css @@ -0,0 +1,17 @@ +*{ + font-family: "Times New Roman"; +} + +table{ + border-collapse: collapse; +} + +th, td { + padding: 3px; + border: 1px solid #e2e2e2; +} + + +.filter-table th{ + text-align: left; +} \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 4eae589..cd5587a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +-0.0.76 + - add backend ticket changes + - add backend ticket export xls/pdf -0.0.75 - add unpaid tickets display -0.0.74 diff --git a/common/config/params.php b/common/config/params.php index a5b82df..9961e15 100644 --- a/common/config/params.php +++ b/common/config/params.php @@ -5,7 +5,7 @@ return [ 'supportEmail' => 'rocho02@gmail.com', 'infoEmail' => 'info@rocho-net.hu', 'user.passwordResetTokenExpire' => 3600, - 'version' => 'v0.0.75', + 'version' => 'v0.0.76', 'company' => 'movar',//gyor 'company_name' => "Freimann Kft.", 'product_visiblity' => 'account',// on reception which products to display. account or global diff --git a/common/models/Transfer.php b/common/models/Transfer.php index add47ae..18fef6a 100644 --- a/common/models/Transfer.php +++ b/common/models/Transfer.php @@ -478,6 +478,17 @@ class Transfer extends \common\models\BaseFitnessActiveRecord { return $result; } + + public static function toStatusName($id) { + $result = ""; + $arr = static::statuses(); + + if (array_key_exists ( $id, $arr )) { + $result = $arr [$id]; + } + + return $result; + } public static function readUserSoldTransfers($user) { $transfers = [ ]; diff --git a/tests/codeception/backend/acceptance.suite.yml b/tests/codeception/backend/acceptance.suite.yml index 1828a04..e0062e5 100644 --- a/tests/codeception/backend/acceptance.suite.yml +++ b/tests/codeception/backend/acceptance.suite.yml @@ -11,18 +11,18 @@ class_name: AcceptanceTester modules: enabled: - - PhpBrowser + # - PhpBrowser - tests\codeception\common\_support\FixtureHelper # you can use WebDriver instead of PhpBrowser to test javascript and ajax. # This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium # "restart" option is used by the WebDriver to start each time per test-file new session and cookies, # it is useful if you want to login in your app in each test. -# - WebDriver + - WebDriver config: - PhpBrowser: +# PhpBrowser: # PLEASE ADJUST IT TO THE ACTUAL ENTRY POINT WITHOUT PATH INFO - url: http://localhost:8080 -# WebDriver: -# url: http://localhost:8080 -# browser: firefox -# restart: true +# url: http://localhost/fitness-web + WebDriver: + url: http://localhost + browser: firefox + restart: true diff --git a/tests/codeception/backend/acceptance/LoginCept.php b/tests/codeception/backend/acceptance/LoginCept.php index 898b1c9..f01b172 100644 --- a/tests/codeception/backend/acceptance/LoginCept.php +++ b/tests/codeception/backend/acceptance/LoginCept.php @@ -10,11 +10,22 @@ $I->wantTo('ensure login page works'); $loginPage = LoginPage::openBy($I); +if (method_exists($I, 'wait')) { + $I->wait(10); // only for selenium +} + +$I->expectTo('see that login button'); +$I->see('Fitness'); + +/* $I->amGoingTo('submit login form with no data'); $loginPage->login('', ''); if (method_exists($I, 'wait')) { $I->wait(3); // only for selenium } +*/ + +/* $I->expectTo('see validations errors'); $I->see('Username cannot be blank.', '.help-block'); $I->see('Password cannot be blank.', '.help-block'); @@ -27,16 +38,16 @@ if (method_exists($I, 'wait')) { } $I->expectTo('see validations errors'); $I->see('Incorrect username or password.', '.help-block'); +*/ $I->amGoingTo('try to login with correct credentials'); -$loginPage->login('erau', 'password_0'); +$loginPage->login('admin', 'test'); if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium + $I->wait(10); // only for selenium } $I->expectTo('see that user is logged'); -$I->seeLink('Logout (erau)'); -$I->dontSeeLink('Login'); -$I->dontSeeLink('Signup'); +$I->see('Üdvözöljük adminisztrációs felületünkön'); +//$I->dontSeeLink('Signup'); /** Uncomment if using WebDriver * $I->click('Logout (erau)'); * $I->dontSeeLink('Logout (erau)'); diff --git a/tests/codeception/backend/acceptance/ObjectCept.php b/tests/codeception/backend/acceptance/ObjectCept.php new file mode 100644 index 0000000..af7b158 --- /dev/null +++ b/tests/codeception/backend/acceptance/ObjectCept.php @@ -0,0 +1,30 @@ +wantTo('entrar al sistema'); + $I->amOnPage('/'); + $I->seeInCurrentUrl('/admin/login'); + $I->fillField('user','perry'); + $I->fillField('pass','pass-perry'); + $I->click('Login'); + $I->see('You\'re logged!'); + $this->cookie = $I->grabCookie('your-session-cookie-name'); + } + */ +} \ No newline at end of file diff --git a/tests/codeception/backend/codeception.yml b/tests/codeception/backend/codeception.yml index 99f1bb2..fadb7f0 100644 --- a/tests/codeception/backend/codeception.yml +++ b/tests/codeception/backend/codeception.yml @@ -14,4 +14,4 @@ settings: config: # the entry script URL (with host info) for functional and acceptance tests # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL - test_entry_url: http://localhost:8080/backend/web/index-test.php + test_entry_url: http://localhost/fitness-web/backend/web/index-test.php diff --git a/tests/codeception/backend/functional/LoginCept.php b/tests/codeception/backend/functional/LoginCept.php index 7e7e26d..d9ff749 100644 --- a/tests/codeception/backend/functional/LoginCept.php +++ b/tests/codeception/backend/functional/LoginCept.php @@ -5,6 +5,7 @@ use tests\codeception\common\_pages\LoginPage; /* @var $scenario Codeception\Scenario */ +/* $I = new FunctionalTester($scenario); $I->wantTo('ensure login page works'); @@ -28,3 +29,4 @@ $I->expectTo('see that user is logged'); $I->seeLink('Logout (erau)'); $I->dontSeeLink('Login'); $I->dontSeeLink('Signup'); +*/ \ No newline at end of file diff --git a/tests/codeception/common/fixtures/data/init_login.php b/tests/codeception/common/fixtures/data/init_login.php index 841e279..ca6d9d1 100644 --- a/tests/codeception/common/fixtures/data/init_login.php +++ b/tests/codeception/common/fixtures/data/init_login.php @@ -11,4 +11,14 @@ return [ 'updated_at' => '1392559490', 'email' => 'sfriesen@jenkins.info', ], + [ + 'username' => 'admin', + 'auth_key' => 'TzZY5KoLbg4VTxwaxs5OoxhFwNt_VeIv', + 'password_hash' => '$2y$13$oWyHf7oSB7XktVe0pEhfROahmxr9NWbYo0o3z69aH6rnBf0oyhTSe', + 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', + 'email' => 'admin@rocho-net.hu', + 'status' => 10, + 'created_at' => '1446658188', + 'updated_at' => '1461356211', + ], ]; diff --git a/tests/codeception/config/backend/fixtures/initdb.php b/tests/codeception/config/backend/fixtures/initdb.php new file mode 100644 index 0000000..7ba9fef --- /dev/null +++ b/tests/codeception/config/backend/fixtures/initdb.php @@ -0,0 +1 @@ +INSERT INTO user (id,username,auth_key,password_hash,password_reset_token,email,status,created_at,updated_at) VALUES (1,'admin','TzZY5KoLbg4VTxwaxs5OoxhFwNt_VeIv','$2y$13$oWyHf7oSB7XktVe0pEhfROahmxr9NWbYo0o3z69aH6rnBf0oyhTSe',null,'admin@rocho-net.hu',10,1446658188,1461356211); diff --git a/tests/codeception/config/config.php b/tests/codeception/config/config.php index b478679..6f23d05 100644 --- a/tests/codeception/config/config.php +++ b/tests/codeception/config/config.php @@ -14,7 +14,10 @@ return [ ], 'components' => [ 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests', + 'dsn' => 'mysql:host=localhost;dbname=fitness_codecept', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', ], 'mailer' => [ 'useFileTransport' => true,