Completed
Push — master ( f3d60a...4c3e60 )
by Dmitry
04:23
created

BillForm::currencyValidate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 13
cp 0
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 12
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\forms;
12
13
use hipanel\helpers\ArrayHelper;
14
use hipanel\modules\finance\behaviors\BillQuantity;
15
use hipanel\modules\finance\logic\bill\QuantityTrait;
16
use hipanel\modules\finance\models\Bill;
17
use hipanel\modules\finance\models\Charge;
18
use hipanel\modules\finance\models\Purse;
19
use hipanel\modules\finance\validation\BillChargesSumValidator;
20
use Yii;
21
use yii\base\Model;
22
23
class BillForm extends Model
24
{
25
    use QuantityTrait;
26
27
    const SCENARIO_CREATE = 'create';
28
    const SCENARIO_UPDATE = 'update';
29
    const SCENARIO_COPY   = 'copy';
30
31
    const EVENT_SHOW_FORM = 'showForm';
32
33
    /**
34
     * @var integer
35
     */
36
    public $id;
37
38
    /**
39
     * @var integer
40
     */
41
    public $client_id;
42
43
    /**
44
     * @var string
45
     */
46
    public $currency;
47
48
    /**
49
     * @var float
50
     */
51
    public $sum;
52
53
    /**
54
     * @var string
55
     */
56
    public $time;
57
58
    /**
59
     * @var string
60
     */
61
    public $type;
62
63
    /**
64
     * @var string
65
     */
66
    public $gtype;
67
68
    /**
69
     * @var float
70
     */
71
    public $quantity;
72
73
    /**
74
     * @var float
75
     */
76
    public $unit;
77
78
    /**
79
     * @var float
80
     */
81
    public $userQuantity;
82
83
    /**
84
     * @var string
85
     */
86
    public $label;
87
88
    /**
89
     * @var integer
90
     */
91
    public $object_id;
92
93
    /**
94
     * @var string
95
     */
96
    public $object;
97
98
    /**
99
     * @var string
100
     */
101
    public $class;
102
103
    /**
104
     * @var Charge[]
105
     */
106
    public $charges = [];
107
108
    public function behaviors()
109
    {
110
        return [
111
            [
112
                'class' => BillQuantity::class,
113
            ],
114
        ];
115
    }
116
117
    /**
118
     * Creates [[BillForm]] from [[Bill]].
119
     *
120
     * @param Bill $bill
121
     * @param string $scenario
122
     * @return BillForm
123
     */
124
    public static function createFromBill($bill, $scenario)
125
    {
126
        $attributes = $bill->getAttributes([
127
            'id', 'object_id', 'client_id', 'currency', 'type',
128
            'gtype', 'sum', 'time', 'quantity', 'unit', 'label', 'object', 'class',
129
        ]);
130
131
        $form = new self(['scenario' => $scenario]);
132
        $form->setAttributes($attributes, false);
133
134
        $form->charges = array_map(function ($model) use ($scenario) {
135
            $model->scenario = $scenario;
136
137
            return $model;
138
        }, $bill->charges);
139
140
        return $form;
141
    }
142
143
    /**
144
     * @param Bill[] $bills
145
     * @param string $scenario
146
     * @return BillForm[]
147
     */
148
    public static function createMultipleFromBills($bills, $scenario)
149
    {
150
        $result = [];
151
        foreach ($bills as $bill) {
152
            $result[] = self::createFromBill($bill, $scenario);
153
        }
154
155
        return $result;
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function load($data, $formName = null)
162
    {
163
        $this->setAttributes($data);
164
        $this->loadCharges($data['charges']);
165
166
        return true;
167
    }
168
169
    /**
170
     * @return Charge[]
171
     */
172
    public function getCharges()
173
    {
174
        if (!empty($this->charges)) {
175
            return $this->charges;
176
        }
177
178
        return [$this->newCharge()];
179
    }
180
181
    /**
182
     * Creates new charge.
183
     *
184
     * @return Charge
185
     */
186
    public function newCharge()
187
    {
188
        return new Charge(['scenario' => Charge::SCENARIO_CREATE]);
189
    }
190
191
    /**
192
     * @return array
193
     */
194
    public function rules()
195
    {
196
        return [
197
            [['id', 'object_id'], 'integer', 'on' => [self::SCENARIO_UPDATE]],
198
            [['sum', 'quantity'], 'number', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]],
199
            [['time'], 'date', 'format' => 'php:Y-m-d H:i:s'],
200
            [['label', 'currency', 'unit', 'type', 'object', 'class'], 'safe', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]],
201
            [['sum'], BillChargesSumValidator::class],
202
            [['unit'], 'default', 'value' => 'items', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]], // TODO: should be probably replaced with input on client side
203
            [['object_id'], 'integer', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]],
204
            [['currency'], 'currencyValidate', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]],
205
            [['id'], 'required', 'on' => [self::SCENARIO_UPDATE]],
206
            [
207
                ['client_id', 'sum', 'quantity', 'unit', 'time', 'currency', 'type'],
208
                'required',
209
                'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY],
210
            ],
211
            [['!charges'], 'safe', 'on' => [self::SCENARIO_CREATE, self::SCENARIO_UPDATE, self::SCENARIO_COPY]],
212
213
            [['time', 'object_id', 'type'], function ($attribute) {
214
                try {
215
                    Bill::perform('check-unique', $this->attributes);
216
                } catch (\Exception $e) {
217
                    $this->addError($attribute, Yii::t('hipanel:finance', 'The bill is not unique'));
218
                }
219
            }, 'on' => self::SCENARIO_COPY],
220
        ];
221
    }
222
223
    public function currencyValidate($attribute, $params, $validator)
0 ignored issues
show
Unused Code introduced by
The parameter $params 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...
Unused Code introduced by
The parameter $validator 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...
224
    {
225
        if (empty($this->client_id)) {
226
            return;
227
        }
228
        $clientCurrencies = Yii::$app->cache->getOrSet('clientCurrencies' . $this->client_id, function (): array {
229
            $purses = Purse::find()
230
                        ->where(['id' => $this->client_id])
231
                        ->all();
232
            return ArrayHelper::getColumn($purses, 'currency');
233
        }, 3600);
234
        if (!in_array($this->currency, $clientCurrencies)) {
235
            $this->addError($attribute, Yii::t('hipanel:finance', 'Client hasn\'t purse with this currency'));
236
        }
237
    }
238
239 View Code Duplication
    public function attributeLabels()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
    {
241
        return [
242
            'client_id' => Yii::t('hipanel', 'Client'),
243
            'time' => Yii::t('hipanel', 'Time'),
244
            'currency' => Yii::t('hipanel', 'Currency'),
245
            'sum' => Yii::t('hipanel:finance', 'Sum'),
246
            'label' => Yii::t('hipanel', 'Description'),
247
            'type' => Yii::t('hipanel', 'Type'),
248
            'quantity' => Yii::t('hipanel', 'Quantity'),
249
            'object_id' => Yii::t('hipanel', 'Object'),
250
        ];
251
    }
252
253
    public function getIsNewRecord()
254
    {
255
        return $this->id === null;
256
    }
257
258
    public function forceNewRecord(): void
259
    {
260
        $this->id = null;
261
        $this->time = new \DateTime();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \DateTime() of type object<DateTime> is incompatible with the declared type string of property $time.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
262
    }
263
264
    private function getChargesAsArray()
265
    {
266
        return array_filter(array_map(function ($model) {
267
            /** @var Charge $model */
268
            if ($model->validate()) {
269
                return $model->toArray();
270
            }
271
272
            return null;
273
        }, $this->charges));
274
    }
275
276
    public function fields()
277
    {
278
        return [
279
            'id',
280
            'client_id',
281
            'object_id',
282
            'currency',
283
            'sum',
284
            'time',
285
            'type',
286
            'quantity',
287
            'label',
288
            'object',
289
            'class',
290
            'charges' => function () {
291
                return $this->getChargesAsArray();
292
            },
293
        ];
294
    }
295
296
    public function loadCharges($data)
297
    {
298
        $charges = [];
299
300
        foreach ((array) $data as $datum) {
301
            $charge = $this->newCharge();
302
            if ($charge->load($datum, '')) {
303
                $charge->markAsNotNew();
304
                $charges[] = $charge;
305
            }
306
        }
307
308
        $this->charges = $charges;
309
310
        return true;
311
    }
312
313
    public function getPrimaryKey()
314
    {
315
        return $this->id;
316
    }
317
318
    public static function primaryKey()
319
    {
320
        return ['id'];
321
    }
322
323
    /**
324
     * For compatibility with [[hiqdev\hiart\Collection]].
325
     *
326
     * @param $defaultScenario
327
     * @param array $data
328
     * @param array $options
329
     * @return mixed
330
     */
331
    public function batchQuery($defaultScenario, $data = [], array $options = [])
332
    {
333
        $map = [
334
            'create' => 'create',
335
            'update' => 'update',
336
        ];
337
        $scenario = isset($map[$defaultScenario]) ? $map[$defaultScenario] : $defaultScenario;
338
339
        return (new Bill())->batchQuery($scenario, $data, $options);
340
    }
341
342
    public function getOldAttribute($attribute)
343
    {
344
        return $this->$attribute;
345
    }
346
347
    public function setOldAttribute($attribute, $value)
0 ignored issues
show
Unused Code introduced by
The parameter $attribute 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...
Unused Code introduced by
The parameter $value 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...
348
    {
349
        return true;
350
    }
351
352
    public function setOldAttributes($values)
0 ignored issues
show
Unused Code introduced by
The parameter $values 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...
353
    {
354
        return true;
355
    }
356
357
    public function afterSave()
358
    {
359
        return true;
360
    }
361
}
362