Completed
Push — master ( b864d9...3fa98b )
by Dmitry
07:42 queued 03:17
created

PlanController::populateWithPrices()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 14
cp 0
rs 9.568
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 20
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\helpers\PlanInternalsGrouper;
16
use hipanel\modules\finance\helpers\PriceChargesEstimator;
17
use hipanel\modules\finance\helpers\PriceSort;
18
use hipanel\modules\finance\models\Plan;
19
use hipanel\filters\EasyAccessControl;
20
use hipanel\modules\finance\models\Price;
21
use hipanel\modules\finance\models\TargetObject;
22
use hiqdev\hiart\Collection;
23
use hiqdev\hiart\ResponseErrorException;
24
use Yii;
25
use yii\base\Event;
26
use yii\web\NotFoundHttpException;
27
use yii\web\Response;
28
use yii\web\UnprocessableEntityHttpException;
29
30
class PlanController extends CrudController
31
{
32
    public function behaviors()
33
    {
34
        return array_merge(parent::behaviors(), [
35
            [
36
                'class' => EasyAccessControl::class,
37
                'actions' => [
38
                    'create' => 'plan.create',
39
                    'update' => 'plan.update',
40
                    'update-prices' => 'plan.update',
41
                    'templates' => 'plan.create',
42
                    'create-prices' => 'plan.create',
43
                    '*' => 'plan.read',
44
                ],
45
            ],
46
        ]);
47
    }
48
49
    public function actions()
50
    {
51
        return array_merge(parent::actions(), [
52
            'create' => [
53
                'class' => SmartCreateAction::class,
54
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully created'),
55
            ],
56
            'update' => [
57
                'class' => SmartUpdateAction::class,
58
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully updated'),
59
            ],
60
            'index' => [
61
                'class' => IndexAction::class,
62
            ],
63
            'view' => [
64
                'class' => ViewAction::class,
65
                'on beforePerform' => function (Event $event) {
66
                    $action = $event->sender;
67
                    $action->getDataProvider()->query
68
                        ->joinWith('sales')
69
                        ->andWhere(['state' => ['ok', 'deleted']])
70
                        ->withPrices();
71
                },
72
                'data' => function (Action $action, array $data) {
73
                    return array_merge($data, [
74
                        'grouper' => new PlanInternalsGrouper($data['model']),
75
                        'parentPrices' => $this->getParentPrices($data['model']['id'])
76
                    ]);
77
                },
78
            ],
79
            'set-note' => [
80
                'class' => SmartUpdateAction::class,
81
                'success' => Yii::t('hipanel', 'Note changed'),
82
            ],
83
            'validate-form' => [
84
                'class' => ValidateFormAction::class,
85
            ],
86
            'validate-single-form' => [
87
                'class' => ValidateFormAction::class,
88
                'validatedInputId' => false,
89
            ],
90
            'delete' => [
91
                'class' => SmartDeleteAction::class,
92
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully deleted'),
93
            ],
94
            'restore' => [
95
                'class' => SmartPerformAction::class,
96
                'success' => Yii::t('hipanel.finance.plan', 'Plan was successfully restored'),
97
            ],
98
            'copy' => [
99
                'class' => SmartUpdateAction::class,
100
                'view' => 'modals/copy',
101
                'queryOptions' => ['batch' => false],
102
            ],
103
        ]);
104
    }
105
106
    public function actionCreatePrices(int $plan_id, int $template_plan_id)
107
    {
108
        $plan = Plan::findOne(['id' => $template_plan_id]);
109
110
        $suggestions = (new Price)->batchQuery('suggest', [
111
            'object_id' => $plan_id,
112
            'plan_id' => $plan_id,
113
            'template_plan_id' => $template_plan_id,
114
            'type' => $plan->type,
115
        ]);
116
117
        $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...
118
        $parentPrices = $this->getParentPrices($plan_id);
119
120
        $targetPlan = Plan::findOne(['id' => $plan_id]);
121
        [$name, $id] = [$targetPlan->name, $targetPlan->id];
0 ignored issues
show
Bug introduced by
The variable $name 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...
Bug introduced by
The variable $id 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...
122
        $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...
123
        $action = ['@plan/update-prices', 'id' => $id, 'scenario' => 'create'];
124
125
        return $this->render($plan->type . '/' . 'createPrices',
126
            compact('plan', 'grouper', 'parentPrices', 'action', 'plan_id', 'name', 'id'));
127
    }
128
129
    public function actionSuggestPricesModal($id)
130
    {
131
        $plan = Plan::findOne(['id' => $id]);
132
        if ($plan === null) {
133
            throw new NotFoundHttpException('Not found');
134
        }
135
        $this->layout = false;
136
137
        return $this->renderAjax('_suggestPricesModal', ['plan' => $plan]);
138
    }
139
140
    /**
141
     * @param string|null $object_id Object ID or `null`
142
     * when the desired templates are not related to a specific object
143
     * @param string $plan_id
144
     */
145
    public function actionTemplates($plan_id, $object_id = null)
146
    {
147
        $templates = (new Plan())->query('search-templates', [
148
            'id' => $plan_id,
149
            'object_id' => $object_id ?? $plan_id,
150
        ]);
151
152
        Yii::$app->response->format = Response::FORMAT_JSON;
153
154
        return $templates;
155
    }
156
157
    public function actionCalculateCharges()
158
    {
159
        Yii::$app->response->format = Response::FORMAT_JSON;
160
        $request = Yii::$app->request;
161
162
        /** @var PriceChargesEstimator $calculator */
163
        $calculator = Yii::$container->get(PriceChargesEstimator::class, [
164
            $request->post('actions'),
165
            $request->post('prices'),
166
        ]);
167
168
        try {
169
            return $calculator->calculateForPeriods([
170
                'now',
171
                'first day of +1 month',
172
                'first day of +1 year',
173
            ]);
174
        } catch (ResponseErrorException $exception) {
175
            Yii::$app->response->setStatusCode(412, $exception->getMessage());
176
            return [
177
                'formula' => $exception->getResponse()->getData()['_error_ops']['formula'] ?? null
178
            ];
179
        }
180
    }
181
182
    public function actionUpdatePrices(int $id, string $scenario = 'update')
183
    {
184
        $plan = Plan::find()
185
            ->byId($id)
186
            ->withPrices()
187
            ->one();
188
189
        $request = Yii::$app->request;
190
        if ($request->isPost) {
191
            try {
192
                $priceClass = $plan->getDesiredPriceClass();
193
                /** @var Price $price */
194
                $price = new $priceClass(['scenario' => $scenario]);
195
                $prices = $request->post($price->formName());
196
                $collection = new Collection([
197
                    'model' => $price,
198
                    'scenario' => $scenario,
199
                ]);
200
                $collection->load($prices);
201
                if ($collection->save() === false) {
202
                    if ($scenario === 'create') {
203
                        Yii::$app->session->addFlash('error', Yii::t('hipanel.finance.price', 'Error occurred during creation of prices'));
204
                    } elseif ($scenario === 'update') {
205
                        Yii::$app->session->addFlash('error', Yii::t('hipanel.finance.price', 'Error occurred during prices update'));
206
                    }
207
                } else {
208
                    if ($scenario === 'create') {
209
                        Yii::$app->session->addFlash('success', Yii::t('hipanel.finance.price', 'Prices were successfully created'));
210
                    } elseif ($scenario === 'update') {
211
                        Yii::$app->session->addFlash('success', Yii::t('hipanel.finance.price', 'Prices were successfully updated'));
212
                    }
213
                }
214
                return $this->redirect(['@plan/view', 'id' => $id]);
215
            } catch (\Exception $e) {
216
                throw new UnprocessableEntityHttpException($e->getMessage(), 0, $e);
217
            }
218
        }
219
220
        $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...
221
        $parentPrices = $this->getParentPrices($id);
222
223
        return $this->render($plan->type . '/' . 'updatePrices',
224
            compact('plan', 'grouper', 'parentPrices'));
225
    }
226
227
    /**
228
     * @param int $plan_id
229
     * @return array | null
230
     */
231
    private function getParentPrices(int $plan_id)
232
    {
233
        $parent_id = (new Plan())->query('get-parent-id', [
234
            'id' => $plan_id,
235
        ]);
236
        $parent_id = $parent_id['parent_id'];
237
        if ($parent_id === null) {
238
            return null;
239
        }
240
241
        $parent = Plan::find()
242
            ->byId($parent_id)
243
            ->withPrices()
244
            ->one();
245
246
        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...
247
    }
248
249
    /**
250
     * @param Plan $plan
251
     * @param array $pricesData
252
     */
253
    private function populateWithPrices(Plan $plan, $pricesData): void
254
    {
255
        $prices = [];
256
        foreach ($pricesData as $priceData) {
257
            $object = ArrayHelper::remove($priceData, 'object');
258
            if (isset($priceData['plan_type']) &&
259
                $priceData['plan_type'] === 'certificate') {
260
                $priceData['class'] = 'CertificatePrice';
261
            }
262
263
            /** @var Price $price */
264
            $price = Price::instantiate($priceData);
265
            $price->setScenario('create');
266
            $price->setAttributes($priceData);
267
            $price->populateRelation('object', new TargetObject($object));
268
            $price->trigger(Price::EVENT_AFTER_FIND);
269
            $prices[] = $price;
270
        }
271
        $prices = PriceSort::anyPrices()->values($prices, true);
272
273
        $plan->populateRelation('prices', $prices);
274
    }
275
}
276