Completed
Push — master ( 9101e8...625686 )
by Dmitry
13:37
created

Price::getFormulaLines()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * Finance module for HiPanel
4
 *
5
 * @link      https://github.com/hiqdev/hipanel-module-finance
6
 * @package   hipanel-module-finance
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2019, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\modules\finance\models;
12
13
use hipanel\base\Model;
14
use hipanel\base\ModelTrait;
15
use hipanel\models\Ref;
16
use hipanel\modules\finance\models\factories\PriceModelFactory;
17
use hipanel\modules\finance\models\query\PriceQuery;
18
use Money\Money;
19
use Money\MoneyParser;
20
use Yii;
21
use yii\helpers\Inflector;
22
use yii\helpers\StringHelper;
23
24
/**
25
 * Class Price.
26
 *
27
 * @property int $id
28
 * @property int $plan_id
29
 * @property string|int $object_id
30
 * @property string|float $price
31
 * @property string $currency
32
 * @property string|int $main_object_id
33
 * @property string $main_object_name
34
 * @property string $unit
35
 * @property string $type
36
 * @property string $quantity
37
 * @property string $formula
38
 * @property int|null parent_id
39
 *
40
 * @property TargetObject $object
41
 * @property Plan $plan
42
 *
43
 * @author Dmytro Naumenko <[email protected]>
44
 */
45
class Price extends Model
46
{
47
    use ModelTrait;
48
49
    const SCENARIO_CREATE = 'create';
50
    const SCENARIO_UPDATE = 'update';
51
    const SCENARIO_DELETE = 'delete';
52
53
    public function rules()
54
    {
55
        return array_merge(parent::rules(), [
56
            [['id', 'parent_id', 'plan_id', 'object_id', 'type_id', 'unit_id', 'currency_id', 'main_object_id'], 'integer'],
57
            [['type', 'type_label', 'plan_name', 'unit', 'currency', 'note', 'data', 'main_object_name'], 'string'],
58
            [['quantity', 'price'], 'number'],
59
            [['formula_lines'], 'safe'],
60
            [['class'], 'string'], // todo: probably, refactor is needed
61
62
            [['plan_id', 'type', 'price', 'currency'], 'required', 'on' => ['create', 'update']],
63
            [['id'], 'required', 'on' => ['update', 'set-note', 'delete']],
64
            [['class'], 'default', 'value' => function ($model) {
0 ignored issues
show
Unused Code introduced by
The parameter $model is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
65
                return (new \ReflectionClass($this))->getShortName();
66
            }],
67
            [['class'], 'string'],
68
            [['formula'], 'string', 'on' => ['create', 'update']], // TODO syn check
69
        ]);
70
    }
71
72
    public function attributeLabels()
73
    {
74
        return [
75
            'plan_id' => Yii::t('hipanel:finance', 'Tariff plan'),
76
            'plan' => Yii::t('hipanel:finance', 'Tariff plan'),
77
            'quantity' => Yii::t('hipanel:finance', 'Prepaid'),
78
            'unit' => Yii::t('hipanel:finance', 'Unit'),
79
            'price' => Yii::t('hipanel:finance', 'Price'),
80
            'formula' => Yii::t('hipanel.finance.price', 'Formula'),
81
            'note' => Yii::t('hipanel', 'Note'),
82
            'type' => Yii::t('hipanel', 'Type'),
83
        ];
84
    }
85
86
    public function getTypeOptions()
87
    {
88
        return Ref::getList('type,bill', null, [
89
            'select' => 'name',
90
            'pnames' => 'monthly,overuse',
91
            'with_recursive' => 1,
92
        ]);
93
    }
94
95
    /**
96
     * Returns array of unit option, that are available for this price
97
     * depending on price type.
98
     *
99
     * @return array
100
     */
101
    public function getUnitOptions()
102
    {
103
        $unitGroup = [
104
            'hour'  => ['hour'],
105
            'items' => ['items'],
106
            'speed' => ['bps', 'kbps', 'mbps', 'gbps', 'tbps'],
107
            'size'  => ['mb', 'mb10', 'mb100', 'gb', 'tb'],
108
        ];
109
110
        $type2group = [
111
            'overuse,ip_num'            => 'items',
112
            'overuse,support_time'      => 'hour',
113
            'overuse,backup_du'         => 'size',
114
            'overuse,server_traf_max'   => 'size',
115
            'overuse,server_traf95_max' => 'speed',
116
            'overuse,cdn_traf_max'      => 'size',
117
            'overuse,cdn_traf95_max'    => 'speed',
118
            'overuse,cdn_cache'         => 'size',
119
            'overuse,storage_du'        => 'size',
120
            'overuse,server_du'         => 'size',
121
            'overuse,server_ssd'        => 'size',
122
            'overuse,server_sata'       => 'size',
123
            'overuse,backup_traf'       => 'size',
124
            'overuse,domain_traf'       => 'size',
125
            'overuse,domain_num'        => 'items',
126
            'overuse,ip_traf_max'       => 'size',
127
            'overuse,account_traf'      => 'size',
128
            'overuse,account_du'        => 'size',
129
            'overuse,mail_num'          => 'items',
130
            'overuse,mail_du'           => 'size',
131
            'overuse,db_num'            => 'items',
132
        ];
133
134
        foreach ($type2group as $type => $group) {
135
            $availableUnitsByPriceType[$type] = $unitGroup[$group];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$availableUnitsByPriceType was never initialized. Although not strictly required by PHP, it is generally a good practice to add $availableUnitsByPriceType = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
136
        }
137
138
        $units = Ref::getList('type,unit', 'hipanel.finance.units', [
139
            'with_recursive' => 1,
140
            'select' => 'oname_label',
141
            'mapOptions' => ['from' => 'oname'],
142
        ]);
143
144
        $possibleTypes = $availableUnitsByPriceType[$this->type] ?? [];
145
146
        return array_intersect_key($units, array_combine($possibleTypes, $possibleTypes));
147
    }
148
149
    /**
150
     * Method checks, whether current price quantity is predefined and is not a result
151
     * of sophisticated calculation on server side.
152
     * @return bool
153
     */
154
    public function isQuantityPredefined(): bool
155
    {
156
        if (!$this->isOveruse()
157
            && ($this->isShared() || $this->getSubtype() === 'rack_unit')
158
        ) {
159
            return false;
160
        }
161
162
        return true;
163
    }
164
165
    /**
166
     * @return bool Whether this price is shared
167
     */
168
    public function isShared(): bool
169
    {
170
        return $this->object_id === null;
171
    }
172
173
    public function getUnitLabel()
174
    {
175
        return $this->getUnitOptions()[$this->unit] ?? null;
176
    }
177
178
    public function getCurrencyOptions()
179
    {
180
        return Ref::getList('type,currency');
181
    }
182
183
    public function getObject()
184
    {
185
        return $this->hasOne(TargetObject::class, ['id' => 'id']);
186
    }
187
188
    public function getPlan()
189
    {
190
        return $this->hasOne(Plan::class, ['id' => 'plan_id']);
191
    }
192
193
    public static function tableName()
194
    {
195
        return Inflector::camel2id(StringHelper::basename(__CLASS__), '-');
196
    }
197
198
    public function isOveruse()
199
    {
200
        return strpos($this->type, 'overuse,') === 0;
201
    }
202
203
    public function isServer95Traf()
204
    {
205
        return false;
206
    }
207
208
    public function getSubtype()
209
    {
210
        [, $subtype] = explode(',', $this->type);
0 ignored issues
show
Bug introduced by
The variable $subtype does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
211
212
        return $subtype;
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218
    public static function instantiate($row)
219
    {
220
        /** @var PriceModelFactory $factory */
221
        $factory = Yii::$container->get(PriceModelFactory::class);
222
223
        return $factory->build($row['class'] ?? 'SinglePrice', $row['type']);
224
    }
225
226
    public function formulaLines(): array
227
    {
228
        if (strlen($this->formula) === 0) {
229
            return [];
230
        }
231
232
        return explode("\n", $this->formula);
233
    }
234
235
    public function getMoney(): Money
236
    {
237
        // TODO: decide how to get MoneyParser correctly
238
        return Yii::$container->get(MoneyParser::class)
239
            ->parse((string)$this->price, strtoupper($this->currency));
240
    }
241
242
    public function getFormulaLines(): array
243
    {
244
        return $this->formula_lines;
0 ignored issues
show
Bug introduced by
The property formula_lines does not seem to exist. Did you mean formula?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
245
    }
246
247
    public static function find(array $options = []): PriceQuery
248
    {
249
        return new PriceQuery(get_called_class(), [
250
            'options' => $options,
251
        ]);
252
    }
253
}
254