Completed
Push — master ( 05ce3e...f6d591 )
by Andrii
11:42
created

ServerGridView::getMonthlyFee()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 19
ccs 0
cts 18
cp 0
rs 8.8333
c 0
b 0
f 0
cc 7
nc 2
nop 1
crap 56
1
<?php
2
/**
3
 * Server module for HiPanel
4
 *
5
 * @link      https://github.com/hiqdev/hipanel-module-server
6
 * @package   hipanel-module-server
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\modules\server\grid;
12
13
use hipanel\base\Model;
14
use hipanel\grid\MainColumn;
15
use hipanel\grid\RefColumn;
16
use hipanel\grid\XEditableColumn;
17
use hipanel\helpers\StringHelper;
18
use hipanel\helpers\Url;
19
use hipanel\modules\hosting\controllers\AccountController;
0 ignored issues
show
Bug introduced by
The type hipanel\modules\hosting\...llers\AccountController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use hipanel\modules\hosting\controllers\IpController;
0 ignored issues
show
Bug introduced by
The type hipanel\modules\hosting\controllers\IpController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use hipanel\modules\server\menus\ServerActionsMenu;
22
use hipanel\modules\server\models\Consumption;
23
use hipanel\modules\server\widgets\DiscountFormatter;
24
use hipanel\modules\server\widgets\Expires;
25
use hipanel\modules\server\widgets\OSFormatter;
26
use hipanel\modules\server\widgets\ResourceConsumptionTable;
27
use hipanel\modules\server\widgets\State;
28
use hipanel\widgets\ArraySpoiler;
29
use hipanel\widgets\gridLegend\ColorizeGrid;
30
use hipanel\widgets\gridLegend\GridLegend;
31
use hipanel\widgets\Label;
32
use hiqdev\yii2\menus\grid\MenuColumn;
33
use Tuck\Sort\Sort;
34
use Yii;
35
use yii\data\ArrayDataProvider;
36
use yii\helpers\ArrayHelper;
37
use yii\helpers\Html;
38
39
class ServerGridView extends \hipanel\grid\BoxedGridView
40
{
41
    use ColorizeGrid;
0 ignored issues
show
introduced by
The trait hipanel\widgets\gridLegend\ColorizeGrid requires some properties which are not provided by hipanel\modules\server\grid\ServerGridView: $controller, $module
Loading history...
42
43
    public $controllerUrl = '@server';
44
45
    /**
46
     * @var array
47
     */
48
    public $osImages;
49
50
    protected function formatTariff($model)
51
    {
52
        if (Yii::$app->user->can('plan.read')) {
0 ignored issues
show
Bug introduced by
The method can() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        if (Yii::$app->user->/** @scrutinizer ignore-call */ can('plan.read')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
53
            if ($model->parent_tariff) {
54
                $title = Html::tag('abbr', $model->parent_tariff, [
55
                    'title' => $model->tariff, 'data-toggle' => 'tooltip',
56
                ]);
57
            } else {
58
                $title = $model->tariff;
59
            }
60
61
            return Html::a($title, ['@plan/view', 'id' => $model->tariff_id]);
62
        }
63
64
        return !empty($model->parent_tariff) ? $model->parent_tariff : $model->tariff;
65
    }
66
67
    public function columns()
68
    {
69
        $canAdmin = Yii::$app->user->can('admin');
0 ignored issues
show
Unused Code introduced by
The assignment to $canAdmin is dead and can be removed.
Loading history...
70
        $canSupport = Yii::$app->user->can('support');
71
72
        return array_merge(parent::columns(), [
73
            'server' => [
74
                'class' => MainColumn::class,
75
                'attribute' => 'name',
76
                'filterAttribute' => 'name_like',
77
                'note' => Yii::$app->user->can('server.set-label') ? 'label' : 'note',
78
                'noteOptions' => [
79
                    'url' => Yii::$app->user->can('server.set-label') ? Url::to('set-label') : (Yii::$app->user->can('server.set-note') ? Url::to('set-note') : ''),
80
                ],
81
                'badges' => function ($model) use ($canSupport) {
82
                    $badges = '';
83
                    if ($canSupport) {
84
                        if ($model->wizzarded) {
85
                            $badges .= Label::widget(['label' => 'W', 'tag' => 'sup', 'color' => 'success']);
86
                        }
87
                    }
88
89
                    return $badges;
90
                },
91
            ],
92
            'dc' => [
93
                'attribute' => 'dc',
94
                'filter' => false,
95
            ],
96
            'state' => [
97
                'class' => RefColumn::class,
98
                'filterOptions' => ['class' => 'narrow-filter'],
99
                'i18nDictionary' => 'hipanel:server',
100
                'format' => 'raw',
101
                'gtype' => 'state,device',
102
                'value' => function ($model) {
103
                    $html = State::widget(compact('model'));
104
                    if ($model->status_time) {
105
                        $html .= ' ' . Html::tag('nobr', Yii::t('hipanel:server', 'since {date}', ['date' => Yii::$app->formatter->asDate($model->status_time)]));
106
                    }
107
108
                    return $html;
109
                },
110
            ],
111
            'panel' => [
112
                'attribute' => 'panel',
113
                'format' => 'html',
114
                'contentOptions' => ['class' => 'text-uppercase'],
115
                'value' => function ($model) use ($canSupport) {
116
                    $value = $model->getPanel() ? Yii::t('hipanel:server:panel', $model->getPanel()) : Yii::t('hipanel:server:panel', 'No control panel');
117
                    if ($canSupport) {
118
                        $value .= $model->wizzarded ? Label::widget([
119
                            'label' => 'W', 'tag' => 'sup', 'color' => 'success',
120
                        ]) : '';
121
                    }
122
123
                    return $value;
124
                },
125
            ],
126
            'os' => [
127
                'attribute' => 'os',
128
                'format' => 'raw',
129
                'value' => function ($model) {
130
                    return OSFormatter::widget([
131
                        'osimages' => $this->osImages,
132
                        'imageName' => $model->osimage,
133
                    ]);
134
                },
135
            ],
136
            'os_and_panel' => [
137
                'attribute' => 'os',
138
                'format' => 'raw',
139
                'value' => function ($model) {
140
                    $html = OSFormatter::widget([
141
                        'osimages' => $this->osImages,
142
                        'imageName' => $model->osimage,
143
                    ]);
144
                    $html .= ' ' . ($model->panel ?: '');
145
146
                    return $html;
147
                },
148
            ],
149
            'discount' => [
150
                'attribute' => 'discount',
151
                'label' => Yii::t('hipanel:server', 'Discount'),
152
                'format' => 'raw',
153
                'headerOptions' => ['style' => 'width: 1em'],
154
                'value' => function ($model) {
155
                    return DiscountFormatter::widget([
156
                        'current' => $model->discounts['fee']['current'],
157
                        'next' => $model->discounts['fee']['next'],
158
                    ]);
159
                },
160
            ],
161
            'expires' => [
162
                'filter' => false,
163
                'format' => 'raw',
164
                'headerOptions' => ['style' => 'width: 1em'],
165
                'value' => function ($model) {
166
                    return Expires::widget(compact('model'));
167
                },
168
            ],
169
            'tariff' => [
170
                'format' => 'raw',
171
                'filterAttribute' => 'tariff_like',
172
                'value' => function ($model) {
173
                    return $this->formatTariff($model);
174
                },
175
            ],
176
            'tariff_and_discount' => [
177
                'attribute' => 'tariff',
178
                'filterAttribute' => 'tariff_like',
179
                'format' => 'raw',
180
                'value' => function ($model) {
181
                    return $this->formatTariff($model) . ' ' . DiscountFormatter::widget([
182
                            'current' => $model->discounts['fee']['current'],
183
                            'next' => $model->discounts['fee']['next'],
184
                        ]);
185
                },
186
            ],
187
            'ip' => [
188
                'filter' => false,
189
            ],
190
            'mac' => [
191
                'filter' => false,
192
            ],
193
            'ips' => [
194
                'format' => 'raw',
195
                'attribute' => 'ips',
196
                'filter' => false,
197
                'contentOptions' => [
198
                    'class' => 'text-center',
199
                    'style' => 'width:1%; white-space:nowrap;',
200
                ],
201
                'value' => function ($model) {
202
                    return ArraySpoiler::widget([
203
                        'data' => ArrayHelper::getColumn($model->ips, 'ip'),
204
                        'delimiter' => '<br />',
205
                        'visibleCount' => 1,
206
                        'formatter' => function ($ip, $idx) use ($model) {
207
                            if ($idx === 0) {
208
                                return Html::a($ip, IpController::getSearchUrl(['server_in' => $model->name]), [
209
                                    'class' => 'text-bold',
210
                                    'target' => '_blank',
211
                                ]);
212
                            }
213
214
                            return $ip;
215
                        },
216
                        'button' => [
217
                            'label' => Yii::t('hipanel:server', '') . ' +' . (count($model->ips) - 1),
218
                            'tag' => 'button',
219
                            'type' => 'button',
220
                            'class' => 'btn btn-xs btn-flat',
221
                            'style' => 'font-size: 10px',
222
                            'popoverOptions' => [
223
                                'html' => true,
224
                                'placement' => 'bottom',
225
                                'title' => Yii::t('hipanel:server', 'IPs'),
226
                                'template' => '
227
                                    <div class="popover" role="tooltip">
228
                                        <div class="arrow"></div>
229
                                        <h3 class="popover-title"></h3>
230
                                        <div class="popover-content" style="min-width: 15rem; height: 15rem; overflow-x: scroll;"></div>
231
                                    </div>
232
                                ',
233
                            ],
234
                        ]
235
                    ]);
236
                },
237
            ],
238
            'sale_time' => [
239
                'attribute' => 'sale_time',
240
                'format' => 'datetime',
241
            ],
242
            'note' => [
243
                'class' => XEditableColumn::class,
244
                'pluginOptions' => [
245
                    'url' => Url::to('set-note'),
246
                ],
247
                'widgetOptions' => [
248
                    'linkOptions' => [
249
                        'data-type' => 'textarea',
250
                    ],
251
                ],
252
                'visible' => Yii::$app->user->can('server.set-note'),
253
            ],
254
            'label' => [
255
                'class' => XEditableColumn::class,
256
                'pluginOptions' => [
257
                    'url' => Url::to('set-label'),
258
                ],
259
                'widgetOptions' => [
260
                    'linkOptions' => [
261
                        'data-type' => 'textarea',
262
                    ],
263
                ],
264
                'visible' => Yii::$app->user->can('server.set-label'),
265
            ],
266
            'type' => [
267
                'format' => 'html',
268
                'filter' => false,
269
                'value' => function ($model) {
270
                    return Html::tag('span', $model->type_label, ['class' => 'label label-default']);
271
                },
272
            ],
273
            'detailed_type' => [
274
                'label' => Yii::t('hipanel', 'Type'),
275
                'format' => 'html',
276
                'filter' => false,
277
                'value' => function ($model) {
278
                    return Html::tag('span', $model->type_label, ['class' => 'label label-default']);
279
                },
280
                'contentOptions' => function ($model) {
281
                    return GridLegend::create($this->findOrFailGridLegend($model))->gridColumnOptions('actions');
282
                },
283
            ],
284
            'rack' => [
285
                'class' => BindingColumn::class,
286
            ],
287
            'net' => [
288
                'class' => BindingColumn::class,
289
            ],
290
            'kvm' => [
291
                'class' => BindingColumn::class,
292
            ],
293
            'pdu' => [
294
                'class' => BindingColumn::class,
295
            ],
296
            'ipmi' => [
297
                'class' => BindingColumn::class,
298
            ],
299
            'nums' => [
300
                'label' => '',
301
                'format' => 'raw',
302
                'value' => function ($model) {
303
                    $ips_num = $model->ips_num;
304
                    $ips = $ips_num ? Html::a("$ips_num ips", IpController::getSearchUrl(['server' => $model->name])) : 'no ips';
305
                    $act_acs_num = $model->acs_num - $model->del_acs_num;
306
                    $del_acs_num = $model->del_acs_num;
307
                    $acs_num = $act_acs_num . ($del_acs_num ? "+$del_acs_num" : '');
308
                    $acs = $acs_num ? Html::a("$acs_num acc", AccountController::getSearchUrl(['server' => $model->name])) : 'no acc';
309
310
                    return Html::tag('nobr', $ips) . ' ' . Html::tag('nobr', $acs);
311
                },
312
            ],
313
            'monthly_fee' => [
314
                'label' => Yii::t('hipanel:finance', 'Monthly fee'),
315
                'format' => 'html',
316
                'filter' => false,
317
                'value' => function ($model) {
318
                    return $this->getMonthlyFee($model);
319
                },
320
                'visible' => Yii::$app->user->can('consumption.read'),
321
            ],
322
            'traffic' => [
323
                'label' => Yii::t('hipanel:server', 'Traffic'),
324
                'format' => 'html',
325
                'filter' => false,
326
                'value' => function ($model) {
327
                    return isset($model->consumptions['overuse,server_traf_max']) ? $this->getFormattedConsumptionFor($model->consumptions['overuse,server_traf_max']) : null;
328
                },
329
                'visible' => Yii::$app->user->can('consumption.read'),
330
            ],
331
            'additional_services' => [
332
                'label' => Yii::t('hipanel:server', 'Additional services'),
333
                'format' => 'raw',
334
                'filter' => false,
335
                'contentOptions' => ['class' => 'no-padding'],
336
                'value' => function ($model) {
337
                    return $this->getAdditionalServices($model);
338
                },
339
                'visible' => Yii::$app->user->can('consumption.read'),
340
            ],
341
            'type_of_sale' => [
342
                'label' => Yii::t('hipanel:server', 'Type of sale'),
343
                'format' => 'raw',
344
                'filter' => false,
345
                'value' => function ($model) {
346
                    return $this->getTypeOfSale($model);
347
                },
348
                'visible' => Yii::$app->user->can('consumption.read'),
349
            ],
350
            'actions' => [
351
                'class' => MenuColumn::class,
352
                'menuClass' => ServerActionsMenu::class,
353
                'contentOptions' => [
354
                    'class' => 'text-center',
355
                    'style' => 'width:1%; white-space:nowrap;',
356
                ],
357
            ],
358
        ]);
359
    }
360
361
    private function getFormattedConsumptionFor(Consumption $consumption): string
362
    {
363
        $result = '';
364
        $widget = Yii::createObject(['class' => ResourceConsumptionTable::class, 'model' => $consumption]);
365
366
        if ($limit = $widget->getFormatted($consumption, $consumption->limit)) {
0 ignored issues
show
Bug Best Practice introduced by
The property limit does not exist on hipanel\modules\server\models\Consumption. Since you implemented __get, consider adding a @property annotation.
Loading history...
367
            $result .= sprintf('%s: %s<br />',
368
                Html::tag('b', Yii::t('hipanel:server', 'included')),
369
                $limit
370
            );
371
        }
372
        if ($price = $consumption->getFormattedPrice()) {
373
            $result .= sprintf('%s: %s',
374
                Html::tag('b', Yii::t('hipanel:server', 'price')),
375
                $price
376
            );
377
        }
378
379
        return $result;
380
    }
381
382
    private function getMonthlyFee($model): string
383
    {
384
        $unionConsumption = new Consumption();
385
        $prices = [];
386
        if ($model->consumptions) {
387
            array_walk($model->consumptions, function (Consumption $consumption) use (&$prices) {
388
                if ($consumption->type && $consumption->hasFormattedAttributes() && StringHelper::startsWith($consumption->type, 'monthly,')) {
389
                    if ($consumption->price) {
0 ignored issues
show
Bug Best Practice introduced by
The property price does not exist on hipanel\modules\server\models\Consumption. Since you implemented __get, consider adding a @property annotation.
Loading history...
390
                        $consumption->setAttribute('prices', [$consumption->currency => $consumption->price]);
0 ignored issues
show
Bug Best Practice introduced by
The property currency does not exist on hipanel\modules\server\models\Consumption. Since you implemented __get, consider adding a @property annotation.
Loading history...
391
                    }
392
                    foreach ($consumption->prices as $currency => $price) {
0 ignored issues
show
Bug Best Practice introduced by
The property prices does not exist on hipanel\modules\server\models\Consumption. Since you implemented __get, consider adding a @property annotation.
Loading history...
393
                        $prices[$currency] += $price;
394
                    }
395
                }
396
            });
397
        }
398
        $unionConsumption->setAttribute('prices', $prices);
399
400
        return $unionConsumption->getFormattedPrice();
401
    }
402
403
    private function getAdditionalServices($model): string
404
    {
405
        $additional = new class() extends Model
406
        {
407
            /**
408
             * @var string
409
             */
410
            public $typeLabel;
411
412
            /**
413
             * @var string
414
             */
415
            public $value;
416
        };
417
        $models = [];
418
        foreach (['overuse,support_time', 'overuse,backup_du', 'monthly,win_license'] as $type) {
419
            if (isset($model->consumptions[$type]) && $model->consumptions[$type]->hasFormattedAttributes()) {
420
                $consumption = $model->consumptions[$type];
421
                $models[] = new $additional([
422
                    'typeLabel' => Yii::t('hipanel.server.consumption.type', $consumption->typeLabel),
423
                    'value' => $this->getFormattedConsumptionFor($consumption),
424
                ]);
425
            }
426
        }
427
428
        return \yii\grid\GridView::widget([
429
            'layout' => '{items}',
430
            'showOnEmpty' => false,
431
            'emptyText' => '',
432
            'tableOptions' => ['class' => 'table table-striped table-condensed'],
433
            'headerRowOptions' => [
434
                'style' => 'display: none;',
435
            ],
436
            'dataProvider' => new ArrayDataProvider(['allModels' => $models, 'pagination' => false]),
437
            'columns' => [
438
                [
439
                    'attribute' => 'typeLabel',
440
                ],
441
                [
442
                    'attribute' => 'value',
443
                    'format' => 'html',
444
                ],
445
            ],
446
        ]);
447
    }
448
449
    private function getTypeOfSale($model): string
450
    {
451
        $html = '';
452
        $badgeColors = [
453
            'leasing' => 'bg-orange',
454
            'rent' => 'bg-purple',
455
            'sold' => 'bg-olive',
456
        ];
457
        if ($model->prices) {
458
            foreach ($model->prices as $saleType => $prices) {
459
                $html .= ArraySpoiler::widget([
460
                    'data' => Sort::by($prices, function ($price) {
461
                        $order = ['CHASSIS', 'MOTHERBOARD', 'CPU', 'RAM', 'HDD', 'SSD'];
462
                        $type = substr($price['part'], 0, strpos($price['part'], ':'));
463
                        $key = array_search($type, $order, true);
464
                        if ($key !== false) {
465
                            return $key;
466
                        }
467
468
                        return INF;
469
                    }),
470
                    'delimiter' => '<br/>',
471
                    'visibleCount' => 0,
472
                    'button' => [
473
                        'label' => Yii::t('hipanel:server', $saleType) . ' ' . (count($prices)),
474
                        'tag' => 'button',
475
                        'type' => 'button',
476
                        'class' => "btn btn-xs {$badgeColors[$saleType]}",
477
                        'popoverOptions' => [
478
                            'html' => true,
479
                            'placement' => 'bottom',
480
                            'title' => Yii::t('hipanel:stock', 'Parts'),
481
                            'template' => '
482
                                <div class="popover" role="tooltip">
483
                                    <div class="arrow"></div>
484
                                    <h3 class="popover-title"></h3>
485
                                    <div class="popover-content" style="height: 25rem; overflow-x: scroll;"></div>
486
                                </div>
487
                            ',
488
489
                        ],
490
                    ],
491
                    'formatter' => function ($item) {
492
                        $title = $item['part'];
493
                        if ($item['serialno']) {
494
                            $title .= ': ' .$item['serialno'];
495
                        }
496
497
                        return Html::a(
498
                            $title,
499
                            ['@part/view', 'id' => $item['part_id']],
500
                            ['class' => 'text-nowrap', 'target' => '_blank']
501
                        );
502
                    },
503
                ]);
504
            }
505
        }
506
507
        return $html;
508
    }
509
}
510