Completed
Push — master ( 00bad6...c7c8a3 )
by Dmitry
06:29
created

PlanController::actionUpdatePrices()   B

Complexity

Conditions 8
Paths 20

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 0
cts 33
cp 0
rs 8.0835
c 0
b 0
f 0
cc 8
nc 20
nop 2
crap 72
1
<?php
2
3
namespace hipanel\modules\finance\controllers;
4
5
use hipanel\actions\Action;
6
use hipanel\actions\IndexAction;
7
use hipanel\actions\SmartCreateAction;
8
use hipanel\actions\SmartDeleteAction;
9
use hipanel\actions\SmartPerformAction;
10
use hipanel\actions\SmartUpdateAction;
11
use hipanel\actions\ValidateFormAction;
12
use hipanel\actions\ViewAction;
13
use hipanel\base\CrudController;
14
use hipanel\helpers\ArrayHelper;
15
use hipanel\modules\finance\collections\PricesCollection;
16
use hipanel\modules\finance\helpers\PlanInternalsGrouper;
17
use hipanel\modules\finance\helpers\PriceChargesEstimator;
18
use hipanel\modules\finance\helpers\PriceSort;
19
use hipanel\modules\finance\models\factories\PriceModelFactory;
20
use hipanel\modules\finance\models\Plan;
21
use hipanel\filters\EasyAccessControl;
22
use hipanel\modules\finance\models\Price;
23
use hipanel\modules\finance\models\TargetObject;
24
use hiqdev\hiart\ResponseErrorException;
25
use Yii;
26
use yii\base\Event;
27
use yii\base\Module;
28
use yii\web\NotFoundHttpException;
29
use yii\web\Response;
30
use yii\web\UnprocessableEntityHttpException;
31
32
class PlanController extends CrudController
33
{
34
    /**
35
     * @var PriceModelFactory
36
     */
37
    public $priceModelFactory;
38
39
    /**
40
     * PlanController constructor.
41
     * @param string $id
42
     * @param Module $module
43
     * @param PriceModelFactory $priceModelFactory
44
     * @param array $config
45
     */
46
    public function __construct(string $id, Module $module, PriceModelFactory $priceModelFactory, array $config = [])
47
    {
48
        parent::__construct($id, $module, $config);
49
50
        $this->priceModelFactory = $priceModelFactory;
51
    }
52
53
    public function behaviors()
54
    {
55
        return array_merge(parent::behaviors(), [
56
            [
57
                'class' => EasyAccessControl::class,
58
                'actions' => [
59
                    'create' => 'plan.create',
60
                    'update' => 'plan.update',
61
                    'update-prices' => 'plan.update',
62
                    'templates' => 'plan.create',
63
                    'create-prices' => 'plan.create',
64
                    '*' => 'plan.read',
65
                ],
66
            ],
67
        ]);
68
    }
69
70
    public function actions()
71
    {
72
        return array_merge(parent::actions(), [
73
            'create' => [
74
                'class' => SmartCreateAction::class,
75
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully created'),
76
            ],
77
            'update' => [
78
                'class' => SmartUpdateAction::class,
79
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully updated'),
80
            ],
81
            'index' => [
82
                'class' => IndexAction::class,
83
            ],
84
            'view' => [
85
                'class' => ViewAction::class,
86
                'on beforePerform' => function (Event $event) {
87
                    $action = $event->sender;
88
                    $action->getDataProvider()->query
89
                        ->joinWith('sales')
90
                        ->andWhere(['state' => ['ok', 'deleted']])
91
                        ->withPrices();
92
                },
93
                'data' => function (Action $action, array $data) {
94
                    return array_merge($data, [
95
                        'grouper' => new PlanInternalsGrouper($data['model']),
96
                        'parentPrices' => $this->getParentPrices($data['model']['id'])
97
                    ]);
98
                },
99
            ],
100
            'set-note' => [
101
                'class' => SmartUpdateAction::class,
102
                'success' => Yii::t('hipanel', 'Note changed'),
103
            ],
104
            'validate-form' => [
105
                'class' => ValidateFormAction::class,
106
            ],
107
            'validate-single-form' => [
108
                'class' => ValidateFormAction::class,
109
                'validatedInputId' => false,
110
            ],
111
            'delete' => [
112
                'class' => SmartDeleteAction::class,
113
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully deleted'),
114
            ],
115
            'restore' => [
116
                'class' => SmartPerformAction::class,
117
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully restored'),
118
            ],
119
            'copy' => [
120
                'class' => SmartUpdateAction::class,
121
                'view' => 'modals/copy',
122
                'queryOptions' => ['batch' => false],
123
            ],
124
        ]);
125
    }
126
127
    public function actionCreatePrices(int $plan_id, int $template_plan_id)
128
    {
129
        $plan = Plan::findOne(['id' => $template_plan_id]);
130
131
        $suggestions = (new Price)->batchQuery('suggest', [
132
            'object_id' => $plan_id,
133
            'plan_id' => $plan_id,
134
            'template_plan_id' => $template_plan_id,
135
            'type' => $plan->type,
136
        ]);
137
138
        $this->populateWithPrices($plan, $suggestions);
0 ignored issues
show
Documentation introduced by
$plan is of type object<yii\db\ActiveRecordInterface>|array, but the function expects a object<hipanel\modules\finance\models\Plan>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
139
        $parentPrices = $this->getParentPrices($plan_id);
140
141
        $targetPlan = Plan::findOne(['id' => $plan_id]);
142
        $grouper = new PlanInternalsGrouper($plan);
0 ignored issues
show
Documentation introduced by
$plan is of type object<yii\db\ActiveRecordInterface>|array, but the function expects a object<hipanel\modules\finance\models\Plan>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
143
        [$plan->name, $plan->id] = [$targetPlan->name, $targetPlan->id];
144
        $action = ['@plan/update-prices', 'id' => $plan->id, 'scenario' => 'create'];
145
146
        return $this->render($plan->type . '/' . 'createPrices',
147
            compact('plan', 'grouper', 'parentPrices', 'action', 'plan_id'));
148
    }
149
150
    public function actionSuggestPricesModal($id)
151
    {
152
        $plan = Plan::findOne(['id' => $id]);
153
        if ($plan === null) {
154
            throw new NotFoundHttpException('Not found');
155
        }
156
        $this->layout = false;
157
158
        return $this->renderAjax('_suggestPricesModal', ['plan' => $plan]);
159
    }
160
161
    /**
162
     * @param string|null $object_id Object ID or `null`
163
     * when the desired templates are not related to a specific object
164
     * @param string $plan_id
165
     */
166
    public function actionTemplates($plan_id, $object_id = null)
167
    {
168
        $templates = (new Plan())->query('search-templates', [
169
            'id' => $plan_id,
170
            'object_id' => $object_id ?? $plan_id,
171
        ]);
172
173
        Yii::$app->response->format = Response::FORMAT_JSON;
174
175
        return $templates;
176
    }
177
178
    public function actionCalculateCharges()
179
    {
180
        Yii::$app->response->format = Response::FORMAT_JSON;
181
        $request = Yii::$app->request;
182
183
        /** @var PriceChargesEstimator $calculator */
184
        $calculator = Yii::$container->get(PriceChargesEstimator::class, [
185
            $request->post('actions'),
186
            $request->post('prices'),
187
        ]);
188
189
        try {
190
            return $calculator->calculateForPeriods([
191
                'now',
192
                'first day of +1 month',
193
                'first day of +1 year',
194
            ]);
195
        } catch (ResponseErrorException $exception) {
196
            Yii::$app->response->setStatusCode(412, $exception->getMessage());
197
            return [
198
                'formula' => $exception->getResponse()->getData()['_error_ops']['formula'] ?? null
199
            ];
200
        }
201
    }
202
203
    public function actionUpdatePrices(int $id, string $scenario = 'update')
204
    {
205
        $plan = Plan::find()
206
            ->byId($id)
207
            ->withPrices()
208
            ->one();
209
210
        $request = Yii::$app->request;
211
        if ($request->isPost) {
212
            try {
213
                $collection = new PricesCollection($this->priceModelFactory, ['scenario' => $scenario]);
214
                $collection->load();
215
                if ($collection->save() === false) {
216
                    if ($scenario === 'create') {
217
                        Yii::$app->session->addFlash('error', Yii::t('hipanel.finance.price', 'Error occurred during creation of prices'));
218
                    } elseif ($scenario === 'update') {
219
                        Yii::$app->session->addFlash('error', Yii::t('hipanel.finance.price', 'Error occurred during prices update'));
220
                    }
221
                } else {
222
                    if ($scenario === 'create') {
223
                        Yii::$app->session->addFlash('success', Yii::t('hipanel.finance.price', 'Prices were successfully created'));
224
                    } elseif ($scenario === 'update') {
225
                        Yii::$app->session->addFlash('success', Yii::t('hipanel.finance.price', 'Prices were successfully updated'));
226
                    }
227
                }
228
                return $this->redirect(['@plan/view', 'id' => $id]);
229
            } catch (\Exception $e) {
230
                throw new UnprocessableEntityHttpException($e->getMessage(), 0, $e);
231
            }
232
        }
233
234
        $grouper = new PlanInternalsGrouper($plan);
0 ignored issues
show
Documentation introduced by
$plan is of type object<hiqdev\hiart\ActiveRecord>|array|null, but the function expects a object<hipanel\modules\finance\models\Plan>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
235
        $parentPrices = $this->getParentPrices($id);
236
237
        return $this->render($plan->type . '/' . 'updatePrices',
238
            compact('plan', 'grouper', 'parentPrices'));
239
    }
240
241
    /**
242
     * @param int $plan_id
243
     * @return array | null
244
     */
245
    private function getParentPrices(int $plan_id)
246
    {
247
        $parent_id = (new Plan())->query('get-parent-id', [
248
            'id' => $plan_id,
249
        ]);
250
        $parent_id = $parent_id['parent_id'];
251
        if ($parent_id === null) {
252
            return null;
253
        }
254
255
        $parent = Plan::find()
256
            ->byId($parent_id)
257
            ->withPrices()
258
            ->one();
259
260
        return $parent ? (new PlanInternalsGrouper($parent))->group() : null;
0 ignored issues
show
Documentation introduced by
$parent is of type object<hiqdev\hiart\ActiveRecord>|array, but the function expects a object<hipanel\modules\finance\models\Plan>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
261
    }
262
263
    /**
264
     * @param Plan $plan
265
     * @param array $pricesData
266
     */
267
    private function populateWithPrices(Plan $plan, $pricesData): void
268
    {
269
        $prices = [];
270
        foreach ($pricesData as $priceData) {
271
            $object = ArrayHelper::remove($priceData, 'object');
272
            if (isset($priceData['plan_type']) &&
273
                $priceData['plan_type'] === 'certificate') {
274
                $priceData['class'] = 'CertificatePrice';
275
            }
276
277
            /** @var Price $price */
278
            $price = Price::instantiate($priceData);
279
            $price->setScenario('create');
280
            $price->setAttributes($priceData);
281
            $price->populateRelation('object', new TargetObject($object));
282
            $price->trigger(Price::EVENT_AFTER_FIND);
283
            $prices[] = $price;
284
        }
285
        $prices = PriceSort::anyPrices()->values($prices, true);
286
287
        $plan->populateRelation('prices', $prices);
288
    }
289
}
290