GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

BackendOrderController::actionAjaxContragent()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 32

Duplication

Lines 14
Ratio 43.75 %

Importance

Changes 0
Metric Value
dl 14
loc 32
rs 9.0968
c 0
b 0
f 0
cc 5
nc 4
nop 1
1
<?php
2
3
namespace app\modules\shop\controllers;
4
5
use app\backend\components\BackendController;
6
use app\backend\models\Notification;
7
use app\backend\models\OrderChat;
8
use app\components\Helper;
9
use app\components\SearchModel;
10
use app\modules\core\helpers\EventSubscribingHelper;
11
use app\modules\shop\events\OrderCalculateEvent;
12
use app\modules\shop\helpers\PriceHelper;
13
use app\modules\shop\models\Contragent;
14
use app\modules\shop\models\Customer;
15
use app\modules\shop\models\DeliveryInformation;
16
use app\modules\shop\models\Order;
17
use app\modules\shop\models\OrderDeliveryInformation;
18
use app\modules\shop\models\OrderItem;
19
use app\modules\shop\models\OrderStage;
20
use app\modules\shop\models\OrderTransaction;
21
use app\modules\shop\models\PaymentType;
22
use app\modules\shop\models\Product;
23
use app\modules\shop\models\ShippingOption;
24
use app\modules\shop\models\SpecialPriceList;
25
use app\modules\shop\ShopModule;
26
use app\modules\user\models\User;
27
use app\properties\HasProperties;
28
use kartik\helpers\Html;
29
use Yii;
30
use yii\caching\TagDependency;
31
use yii\data\ArrayDataProvider;
32
use yii\db\Query;
33
use yii\filters\AccessControl;
34
use yii\helpers\ArrayHelper;
35
use yii\helpers\Url;
36
use yii\web\BadRequestHttpException;
37
use yii\web\NotFoundHttpException;
38
use yii\web\Response;
39
40
/**
41
 * OrderController implements the CRUD actions for Order model.
42
 */
43
class BackendOrderController extends BackendController
44
{
45
    /**
46
     * @property ShopModule $module
47
     */
48
49
    /**
50
     * Finds the Order model based on its primary key value.
51
     * If the model is not found, a 404 HTTP exception will be thrown.
52
     * @param string $id
53
     * @return Order the loaded model
54
     * @throws NotFoundHttpException if the model cannot be found
55
     */
56
    protected function findModel($id)
57
    {
58
        if (($model = Order::findOne($id)) !== null) {
0 ignored issues
show
Bug Compatibility introduced by
The expression \app\modules\shop\models\Order::findOne($id); of type yii\db\ActiveRecordInterface|array|null adds the type array to the return on line 59 which is incompatible with the return type documented by app\modules\shop\control...erController::findModel of type app\modules\shop\models\Order.
Loading history...
59
            return $model;
60
        } else {
61
            throw new NotFoundHttpException('The requested page does not exist.');
62
        }
63
    }
64
65
    public function actionDownloadFile($key, $orderId)
66
    {
67
        $order = Order::findOne($orderId);
68
        if ($order === null) {
69
            throw new NotFoundHttpException('Order not found');
70
        }
71
        $prop = $order->getPropertyValuesByKey($key);
0 ignored issues
show
Bug introduced by
The method getPropertyValuesByKey() does not seem to exist on object<yii\db\ActiveRecordInterface>.

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...
72
        if (empty($prop->values) === false) {
73
            $fileName = Yii::getAlias(Yii::$app->getModule('core')->visitorsFileUploadPath) . DIRECTORY_SEPARATOR . ArrayHelper::getValue($prop, 'values.0.value', '');
74
            if (file_exists($fileName)) {
75
                return Yii::$app->response->sendFile($fileName);
76
            }
77
        }
78
        throw new NotFoundHttpException(Yii::t('app', 'File not found'));
79
    }
80
81
82
    protected function getManagersList()
83
    {
84
        $managers = Yii::$app->cache->get('ManagersList');
85
        if ($managers === false) {
86
            $managers = User::find()
87
                ->join(
88
                    'INNER JOIN',
89
                    '{{%auth_assignment}}',
90
                    '{{%auth_assignment}}.user_id = ' . User::tableName() . '.id'
91
                )
92
                ->where(['{{%auth_assignment}}.item_name' => 'manager'])
93
                ->all();
94
            $managers = ArrayHelper::map($managers, 'id', 'username');
95
            Yii::$app->cache->set(
96
                'ManagersList',
97
                $managers,
98
                86400,
99
                new TagDependency(
100
                    [
101
                        'tags' => [
102
                            \devgroup\TagDependencyHelper\ActiveRecordHelper::getCommonTag(User::className())
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
103
                        ],
104
                    ]
105
                )
106
            );
107
        }
108
        return $managers;
109
    }
110
111
    /**
112
     * @inheritdoc
113
     */
114 View Code Duplication
    public function behaviors()
115
    {
116
        return [
117
            'access' => [
118
                'class' => AccessControl::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
119
                'rules' => [
120
                    [
121
                        'allow' => true,
122
                        'roles' => ['order manage'],
123
                    ],
124
                ],
125
            ],
126
        ];
127
    }
128
129
    public function beforeAction($action)
130
    {
131
        if (false === parent::beforeAction($action)) {
132
            return false;
133
        }
134
135
        EventSubscribingHelper::specialEventCallback(OrderCalculateEvent::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
136
            function (OrderCalculateEvent $event)
137
            {
138
                if (OrderCalculateEvent::AFTER_CALCULATE !== $event->state) {
139
                    return null;
140
                }
141
142
                /** @var OrderTransaction $transaction */
143
                $transaction = OrderTransaction::findLastByOrder(
144
                    $event->order,
145
                    null,
146
                    false,
147
                    false,
148
                    [OrderTransaction::TRANSACTION_START]
149
                );
150
151
                if (!empty($transaction)) {
152
                    $transaction->total_sum = $event->order->total_price;
153
                    $transaction->save();
154
                }
155
            }
156
        );
157
158
        return true;
159
    }
160
161
162
    /**
163
     * Lists all Order models.
164
     * @return mixed
165
     */
166
    public function actionIndex()
167
    {
168
        $searchModelConfig = [
169
            'defaultOrder' => ['id' => SORT_DESC],
170
            'model' => Order::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
171
            'relations' => ['user' => ['username']],
172
            'partialMatchAttributes' => ['start_date', 'end_date', 'user_username'],
173
            'additionalConditions' => [],
174
        ];
175
176
        if (intval($this->module->showDeletedOrders) === 0) {
177
            $searchModelConfig['additionalConditions'] = [['is_deleted' => 0]];
178
        }
179
180
        /** @var SearchModel $searchModel */
181
        $searchModel = new SearchModel($searchModelConfig);
182
        if (intval($this->module->defaultOrderStageFilterBackend) > 0) {
183
            $searchModel->order_stage_id = intval($this->module->defaultOrderStageFilterBackend);
0 ignored issues
show
Documentation introduced by
The property order_stage_id does not exist on object<app\components\SearchModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
184
        }
185
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
186
        return $this->render(
187
            'index',
188
            [
189
                'dataProvider' => $dataProvider,
190
                'managers' => $this->getManagersList(),
191
                'orderStages' => Helper::getModelMap(OrderStage::className(), 'id', 'name_short'),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
192
                'paymentTypes' => Helper::getModelMap(PaymentType::className(), 'id', 'name'),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
193
                'searchModel' => $searchModel,
194
                'shippingOptions' => Helper::getModelMap(ShippingOption::className(), 'id', 'name'),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
195
            ]
196
        );
197
    }
198
199
    /**
200
     * Displays a single Order model.
201
     * @param string $id
202
     * @return mixed
203
     */
204
    public function actionView($id)
205
    {
206
        $model = $this->findModel($id);
207
        $orderIsImmutable = $model->getImmutability(\app\modules\shop\models\Order::IMMUTABLE_MANAGER);
208
209
        $transactionsDataProvider = new ArrayDataProvider([
210
            'allModels' => $model->transactions,
211
        ]);
212
213
        if (Yii::$app->request->isPost && !$orderIsImmutable) {
214
            $model->setScenario('backend');
215
            if ($model->load(Yii::$app->request->post())) {
216
                /** @var OrderDeliveryInformation $orderDeliveryInformation */
217
                $orderDeliveryInformation = $model->orderDeliveryInformation;
218
                if ($orderDeliveryInformation->load(Yii::$app->request->post())) {
219
                    $orderDeliveryInformation->saveModelWithProperties(Yii::$app->request->post());
220
                }
221
222
                $model->save();
223
            }
224
        }
225
        $lastMessages = OrderChat::find()
226
            ->where(['order_id' => $id])
227
            ->orderBy(['id' => SORT_DESC])
228
            ->all();
229
        return $this->render(
230
            'view',
231
            [
232
                'lastMessages' => $lastMessages,
233
                'managers' => $this->getManagersList(),
234
                'model' => $model,
235
                'transactionsDataProvider' => $transactionsDataProvider,
236
                'orderIsImmutable' => $orderIsImmutable,
237
            ]
238
        );
239
    }
240
241
    /**
242
     * Update order status action.
243
     * @param integer|null $id
244
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
245
     * @throws \yii\web\BadRequestHttpException
246
     */
247
    public function actionUpdateStage($id = null)
248
    {
249
        Yii::$app->response->format = Response::FORMAT_JSON;
250
        $post = Yii::$app->request->post();
251
        if ($id === null) {
252
            if (!isset($post['editableIndex'], $post['editableKey'],
253
                $post['Order'][$post['editableIndex']]['order_stage_id'])) {
254
                throw new BadRequestHttpException;
255
            }
256
            $id = $post['editableKey'];
257
            $value = $post['Order'][$post['editableIndex']]['order_stage_id'];
258
        } else {
259
            if (!isset($post['Order']['order_stage_id'])) {
260
                throw new BadRequestHttpException;
261
            }
262
            $value = $post['Order']['order_stage_id'];
263
        }
264
        $order = $this->findModel($id);
265
        $order->order_stage_id = $value;
266
        /** @var OrderStage $orderStage */
267
        $orderStage = OrderStage::findOne($value);
268 View Code Duplication
        if ($orderStage === null || !$order->save(true, ['order_stage_id'])) {
269
            return [
270
                'message' => Yii::t('app', 'Cannot change order stage'),
271
            ];
272
        }
273
        return [
274
            'output' => Html::tag('span', $orderStage->name_short),
275
        ];
276
    }
277
278
    /**
279
     * @param $id
280
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
281
     * @throws BadRequestHttpException
282
     * @throws NotFoundHttpException
283
     */
284
    public function actionUpdateShippingOption($id)
285
    {
286
        Yii::$app->response->format = Response::FORMAT_JSON;
287
        $post = Yii::$app->request->post();
288
        if (!isset($post['OrderDeliveryInformation']['shipping_option_id'])) {
289
            throw new BadRequestHttpException;
290
        }
291
        /** @var OrderDeliveryInformation $orderDeliveryInformation */
292
        $orderDeliveryInformation = OrderDeliveryInformation::findOne($id);
293
        if (is_null($orderDeliveryInformation)) {
294
            throw new NotFoundHttpException;
295
        }
296
        $value = $post['OrderDeliveryInformation']['shipping_option_id'];
297
        $orderDeliveryInformation->shipping_option_id = $value;
298
        /** @var ShippingOption $shippingOption */
299
        $shippingOption = ShippingOption::findOne($value);
300
        // @todo Need to save shipping price
301
        if (is_null($shippingOption) || !$orderDeliveryInformation->save(true, ['shipping_option_id'])) {
302
            return [
303
                'message' => Yii::t('app', 'Cannot change shipping option'),
304
            ];
305
        }
306
        return [
307
            'output' => $shippingOption->name,
308
        ];
309
    }
310
311
    /**
312
     * @param integer $id
313
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
314
     * @throws \yii\web\BadRequestHttpException
315
     */
316
    public function actionChangeManager($id)
317
    {
318
        Yii::$app->response->format = Response::FORMAT_JSON;
319
        $order = $this->findModel($id);
320
        if (!isset($_POST['Order']['manager_id'])) {
321
            throw new BadRequestHttpException;
322
        }
323
        /** @var \app\modules\user\models\User|null $user */
324
        $user = User::findOne($_POST['Order']['manager_id']);
325
        if (is_null($user) || !Yii::$app->authManager->checkAccess($user->id, 'order manage')) {
326
            throw new BadRequestHttpException;
327
        }
328
        $order->scenario = 'changeManager';
329
        $oldManager = $order->manager;
330
        $order->load($_POST);
331
        if (!$order->save()) {
332
            return [
333
                'message' => Yii::t('app', 'Cannot change manager'),
334
            ];
335
        }
336
        if (is_null($oldManager) || $oldManager->id != $order->manager_id) {
337
            // send message
338
            try {
339
                $to = [$user->email];
340
                if (!is_null($oldManager)) {
341
                    $to[] = $oldManager->email;
342
                    $subject =  Yii::t(
343
                        'app',
344
                        'Manager has been changed from {oldManagerName} to {newManagerName}. Order #{orderId}',
345
                        [
346
                            'oldManagerName' => $oldManager->getDisplayName(),
347
                            'newManagerName' => $user->getDisplayName(),
348
                            'orderId' => $order->id,
349
                        ]
350
                    );
351
                    Notification::addNotification(
352
                        $oldManager->id,
353
                        Yii::t(
354
                            'app',
355
                            'You are not a manager of <a href="{orderUrl}" target="_blank">order #{orderId}</a> already',
356
                            [
357
                                'orderId' =>$order->id,
358
                                'orderUrl' => Url::toRoute(['/backend/order/view', 'id' => $order->id]),
359
                            ]
360
                        ),
361
                        'Order',
362
                        'info'
363
                    );
364
                } else {
365
                    $subject =  Yii::t(
366
                        'app',
367
                        'Manager has been changed to {newManagerName}. Order #{orderId}',
368
                        [
369
                            'newManagerName' => $user->getDisplayName(),
370
                            'orderId' => $order->id,
371
                        ]
372
                    );
373
                }
374
                Notification::addNotification(
375
                    $user->id,
376
                    Yii::t(
377
                        'app',
378
                        'You are a new manager of <a href="{orderUrl}" target="_blank">order #{orderId}</a>',
379
                        [
380
                            'orderId' =>$order->id,
381
                            'orderUrl' => Url::toRoute(['/backend/order/view', 'id' => $order->id]),
382
                        ]
383
                    ),
384
                    'Order',
385
                    'info'
386
                );
387
                Yii::$app->mail
388
                    ->compose(
389
                        '@app/backend/views/order/change-manager-email-template',
390
                        [
391
                            'manager' => $user,
392
                            'oldManager' => $oldManager,
393
                            'order' => $order,
394
                            'user' => Yii::$app->user->getIdentity(),
395
                        ]
396
                    )
397
                    ->setTo($to)
398
                    ->setFrom(Yii::$app->mail->transport->getUsername())
399
                    ->setSubject($subject)
400
                    ->send();
401
            } catch (\Exception $e) {
402
                // do nothing
403
            }
404
        }
405
        return [
406
            'output' => Html::encode($user->username),
407
        ];
408
    }
409
410 View Code Duplication
    public function actionDelete($id = null)
411
    {
412
        /** @var Order $model */
413
        if ((null === $id) || (null === $model = Order::findOne($id))) {
414
            throw new NotFoundHttpException;
415
        }
416
417
        if (!$model->delete()) {
418
            Yii::$app->session->setFlash('info', Yii::t('app', 'The object is placed in the cart'));
419
        } else {
420
            Yii::$app->session->setFlash('info', Yii::t('app', 'Object removed'));
421
        }
422
423
        return $this->redirect(
424
            Yii::$app->request->get(
425
                'returnUrl',
426
                Url::toRoute(['index'])
427
            )
428
        );
429
    }
430
431
    public function actionDeleteOrderItem($id)
432
    {
433
        /** @var OrderItem $orderItem */
434
        $orderItem = OrderItem::findOne($id);
435
        if (is_null($orderItem)) {
436
            throw new NotFoundHttpException();
437
        }
438
        $orderItem->delete();
439
        $orderItem->order->calculate(true);
440
        return $this->redirect(['view', 'id' => $orderItem->order->id]);
441
    }
442
443
    public function actionChangeOrderItemQuantity($id)
444
    {
445
        Yii::$app->response->format = Response::FORMAT_JSON;
446
        /** @var OrderItem $orderItem */
447
        $orderItem = OrderItem::findOne($id);
448
        $orderItem->load(Yii::$app->request->post());
449
        $orderItem->quantity = $orderItem->product->measure->ceilQuantity($orderItem->quantity);
450
        $orderItem->price_per_pcs = PriceHelper::getProductPrice(
451
            $orderItem->product,
0 ignored issues
show
Bug introduced by
It seems like $orderItem->product can also be of type object<app\properties\HasProperties>; however, app\modules\shop\helpers...lper::getProductPrice() does only seem to accept object<app\modules\shop\models\Product>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
452
            $orderItem->order,
453
            1,
454
            SpecialPriceList::TYPE_CORE
455
        );
456
        if (!$orderItem->save(true, ['quantity', 'total_price', 'discount_amount', 'total_price_without_discount'])
457
            || !$orderItem->order->calculate(true)
458
        ) {
459
            return [
460
                'message' => Yii::t('app', 'Cannot change quantity'),
461
                'error' => $orderItem->errors,
462
            ];
463
        }
464
        return [
465
            'output' => $orderItem->quantity,
466
        ];
467
    }
468
469
    public function actionAutoCompleteSearch($orderId, $term, $parentId = 0)
470
    {
471
        Yii::$app->response->format = Response::FORMAT_JSON;
472
        $product = Yii::$container->get(Product::class);
473
        $query = $product::find()->orderBy('sort_order');
474
        foreach (['name', 'content'] as $attribute) {
475
            $query->orWhere(['like', $attribute, $term]);
476
        }
477
        $products = $query->limit(20)->all();
478
        $result = [];
479
        /** @var Product $productModel */
480
        foreach ($products as $productModel) {
481
            $result[] = [
482
                'name' => $productModel->name,
483
                'url' => Url::toRoute([
484
                    'add-product',
485
                    'orderId' => $orderId,
486
                    'productId' => $productModel->id,
487
                    'parentId' => $parentId,
488
                ]),
489
            ];
490
        }
491
        return $result;
492
    }
493
494
    public function actionAddProduct($orderId, $productId, $parentId = 0)
495
    {
496
        $order = $this->findModel($orderId);
497
        /** @var OrderItem $orderItem */
498
        $orderItem = OrderItem::findOne(['product_id' => $productId, 'order_id' => $orderId]);
499
        $product = Yii::$container->get(Product::class);
500
        /** @var Product $productModel */
501
        $productModel = $product::findById($productId);
502
        if (is_null($orderItem)) {
503
            $orderItem = new OrderItem;
504
            $orderItem->attributes = [
505
                'parent_id' => $parentId,
506
                'order_id' => $order->id,
507
                'product_id' => $productModel->id,
508
                'quantity' => $productModel->measure->nominal,
509
                'price_per_pcs' =>  PriceHelper::getProductPrice(
510
                    $productModel,
511
                    $order,
512
                    1,
513
                    SpecialPriceList::TYPE_CORE
514
                ),
515
            ];
516
        } else {
517
            $orderItem->quantity++;
518
        }
519
        $orderItem->save();
520
        $order->calculate(true);
521
        return $this->redirect(['view', 'id' => $orderId]);
522
    }
523
524
    public function actionUpdateOrderProperties($id)
525
    {
526
        /** @var Order|HasProperties $model */
527
        $model = $this->findModel($id);
528
        $model->abstractModel->setAttributesValues(Yii::$app->request->post());
529
        if ($model->abstractModel->validate()) {
530
            $model->getPropertyGroups(true);
0 ignored issues
show
Bug introduced by
The method getPropertyGroups does only exist in app\properties\HasProperties, but not in app\modules\shop\models\Order.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
531
            $model->saveProperties(Yii::$app->request->post());
0 ignored issues
show
Bug introduced by
The method saveProperties does only exist in app\properties\HasProperties, but not in app\modules\shop\models\Order.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
532
        }
533
        return $this->redirect(['view', 'id' => $id]);
534
    }
535
536
    /**
537
     * @return string|Response
538
     * @throws \yii\base\Exception
539
     * @throws \yii\web\ServerErrorHttpException
540
     */
541
    public function actionCreate()
542
    {
543
        $model = Order::create(false, false, true);
544
        $model->setScenario('backend');
545
546
        if (Yii::$app->request->isPost) {
547
            $data = Yii::$app->request->post();
548
            if ($model->load($data) && $model->validate()) {
549
                if (User::USER_GUEST === intval($model->user_id)) {
550
                    $model->customer_id = 0;
551
                } elseif (null === Customer::findOne(['user_id' => intval($model->user_id), 'id' => intval($model->customer_id)])) {
552
                    $model->customer_id = 0;
553
                }
554
555
                if (0 === intval($model->customer_id)) {
556
                    $customer = Customer::createEmptyCustomer(intval($model->user_id));
557 View Code Duplication
                    if ($customer->load($data) && $customer->save()) {
558
                        if (!empty($customer->getPropertyGroup())) {
559
                            $customer->getPropertyGroup()->appendToObjectModel($customer);
560
                            $data[$customer->getAbstractModel()->formName()] = isset($data['CustomerNew']) ? $data['CustomerNew'] : [];
0 ignored issues
show
Documentation Bug introduced by
The method getAbstractModel does not exist on object<app\modules\shop\models\Customer>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
561
                        }
562
                        $customer->saveModelWithProperties($data);
563
                        $customer->refresh();
564
                        $model->customer_id = $customer->id;
565
                    }
566
                } else {
567
                    $customer = Customer::findOne(['id' => $model->customer_id]);
568
                }
569
570
                if (0 === $model->contragent_id || null === Contragent::findOne(['id' => $model->contragent_id, 'customer_id' => $model->customer_id])) {
571
                    $contragent = Contragent::createEmptyContragent($customer);
0 ignored issues
show
Documentation introduced by
$customer is of type null|object<yii\db\ActiveRecordInterface>|array, but the function expects a object<app\modules\shop\models\Customer>.

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...
572 View Code Duplication
                    if ($contragent->load($data) && $contragent->save()) {
0 ignored issues
show
Bug introduced by
The method load does only exist in app\modules\shop\models\Contragent, but not in app\properties\HasProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
Bug introduced by
The method save does only exist in app\modules\shop\models\Contragent, but not in app\properties\HasProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
573
                        if (!empty($contragent->getPropertyGroup())) {
574
                            $contragent->getPropertyGroup()->appendToObjectModel($contragent);
0 ignored issues
show
Bug introduced by
The method getPropertyGroup does only exist in app\modules\shop\models\Contragent, but not in app\properties\HasProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
575
                            $data[$contragent->getAbstractModel()->formName()] = isset($data['ContragentNew']) ? $data['ContragentNew'] : [];
0 ignored issues
show
Bug introduced by
The method getAbstractModel does only exist in app\properties\HasProperties, but not in app\modules\shop\models\Contragent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
576
                        }
577
                        $contragent->saveModelWithProperties($data);
0 ignored issues
show
Bug introduced by
The method saveModelWithProperties does only exist in app\modules\shop\models\Contragent, but not in app\properties\HasProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
578
                        $contragent->refresh();
0 ignored issues
show
Bug introduced by
The method refresh does only exist in app\modules\shop\models\Contragent, but not in app\properties\HasProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
579
                        $model->contragent_id = $contragent->id;
580
                    }
581
                } else {
582
                    $contragent = Contragent::findOne(['id' => $model->contragent_id]);
583
                }
584
585
                if ($model->save()) {
586
                    OrderDeliveryInformation::createNewOrderDeliveryInformation($model, false);
587
                    DeliveryInformation::createNewDeliveryInformation($contragent, false);
0 ignored issues
show
Documentation introduced by
$contragent is of type object<app\properties\Ha...eRecordInterface>|array, but the function expects a object<app\modules\shop\models\Contragent>.

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...
588
                    return $this->redirect(Url::toRoute([
589
                        'view', 'id' => $model->id
590
                    ]));
591
                }
592
            }
593
        }
594
595
        return $this->render('create', [
596
            'model' => $model,
597
        ]);
598
    }
599
600
    /**
601
     * @param $id
602
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
603
     * @throws BadRequestHttpException
604
     * @throws NotFoundHttpException
605
     */
606
    public function actionUpdatePaymentType($id)
607
    {
608
        Yii::$app->response->format = Response::FORMAT_JSON;
609
        $post = Yii::$app->request->post();
610
        if (!isset($post['Order']['payment_type_id'])) {
611
            throw new BadRequestHttpException;
612
        }
613
        $value = $post['Order']['payment_type_id'];
614
        $order = $this->findModel($id);
615
        $order->payment_type_id = $value;
616
        /** @var PaymentType $paymentType */
617
        $paymentType = PaymentType::findOne($value);
618 View Code Duplication
        if ($paymentType === null || !$order->save(true, ['payment_type_id'])) {
619
            return [
620
                'message' => Yii::t('app', 'Cannot change a payment type'),
621
            ];
622
        }
623
        return [
624
            'output' => Html::tag('span', $paymentType->name),
625
        ];
626
    }
627
628
    /**
629
     * Add new message to OrderChat
630
     * @param $orderId
631
     * @return int[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,integer>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
632
     * @throws BadRequestHttpException
633
     */
634
    public function actionSendToOrderChat($orderId)
635
    {
636
        Yii::$app->response->format = Response::FORMAT_JSON;
637
638
        /** @var Order $order */
639
        $order = Order::findOne($orderId);
640
        if (null === $order) {
641
            throw new BadRequestHttpException();
642
        }
643
644
        $message = new OrderChat();
645
        $message->loadDefaultValues();
646
        $message->message = Yii::$app->request->post('message');
647
        $message->order_id = $order->id;
648
        $message->user_id = Yii::$app->user->id;
649
        if ($message->save()) {
650
            if ($order->manager_id != Yii::$app->user->id) {
651
                Notification::addNotification(
652
                    $order->manager_id,
653
                    Yii::t(
654
                        'app',
655
                        'Added a new comment to <a href="{orderUrl}" target="_blank">order #{orderId}</a>',
656
                        [
657
                            'orderUrl' => Url::toRoute(['/backend/order/view', 'id' => $order->id]),
658
                            'orderId' => $order->id,
659
                        ]
660
                    ),
661
                    'Order',
662
                    'info'
663
                );
664
            }
665
            $message->refresh();
666
            $user = $message->user;
667
            return [
668
                'status' => 1,
669
                'message' => $message->message,
670
                'user' => null !== $user ? $user->username : Yii::t('app', 'Unknown'),
671
                'gravatar' => null !== $user ? $user->gravatar() : null,
672
                'date' => $message->date,
673
            ];
674
        }
675
676
        return ['status' => 0];
677
    }
678
679
    /**
680
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,false|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
681
     */
682
    public function actionAjaxUser()
683
    {
684
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
685
686
        $result = [
687
            'more' => false,
688
            'results' => []
689
        ];
690
        $search = \Yii::$app->request->get('search', []);
691
        if (!empty($search['term'])) {
692
            $query = User::find()
693
                ->select('id, username, first_name, last_name, email')
694
                ->where(['like', 'username', trim($search['term'])])
695
                ->orWhere(['like', 'email', trim($search['term'])])
696
                ->orWhere(['like', 'first_name', trim($search['term'])])
697
                ->orWhere(['like', 'last_name', trim($search['term'])])
698
                ->asArray();
699
700
            $result['results'] = array_values($query->all());
701
        }
702
703
        return $result;
704
    }
705
706
    /**
707
     * @return array
708
     */
709
    public function actionAjaxCustomer($template = null)
710
    {
711
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
712
713
        $result = [
714
            'more' => false,
715
            'results' => []
716
        ];
717
        $search = \Yii::$app->request->get('search', []);
718
        $user_id = isset($search['user']) && User::USER_GUEST !== intval($search['user']) ? intval($search['user']) : User::USER_GUEST;
719
        if (!empty($search['term'])) {
720
            $query = Customer::find()
721
                ->select('id, first_name, middle_name, last_name, email, phone')
722
                ->where(['user_id' => $user_id])
723
                ->andWhere('first_name LIKE :term1 OR middle_name LIKE :term2 OR last_name LIKE :term3 OR email LIKE :term4 OR phone LIKE :term5', [
724
                    ':term1' => '%'.trim($search['term']).'%',
725
                    ':term2' => '%'.trim($search['term']).'%',
726
                    ':term3' => '%'.trim($search['term']).'%',
727
                    ':term4' => '%'.trim($search['term']).'%',
728
                    ':term5' => '%'.trim($search['term']).'%',
729
                ])
730
                ->asArray();
731
732
            $result['results'] = array_values($query->all());
733
        }
734
735 View Code Duplication
        if (!empty($result['results']) && 'simple' === $template) {
736
            $result['cards'] = array_reduce($result['results'],
737
                function ($result, $item)
738
                {
739
                    /** @var array $item */
740
                    $result[$item['id']] = \app\modules\shop\widgets\Customer::widget([
741
                        'viewFile' => 'customer/backend_list',
742
                        'model' => Customer::findOne(['id' => $item['id']]),
743
                    ]);
744
                    return $result;
745
                }, []);
746
        }
747
748
        return $result;
749
    }
750
751
    /**
752
     * @return array
753
     */
754
    public function actionAjaxContragent($template = null)
755
    {
756
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
757
        $result = [
758
            'more' => false,
759
            'results' => [[0 => Yii::t('app', 'New contragent')]]
760
        ];
761
        $search = \Yii::$app->request->get('search', []);
762
        $customer_id = isset($search['customer']) ? intval($search['customer']) : 0;
763
        $query = Contragent::find()
764
            ->select('id, type')
765
            ->where(['customer_id' => $customer_id])
766
            ->asArray();
767
        $result['results'] = array_merge(array_values($query->all()), $result['results']);
768
769 View Code Duplication
        if (!empty($result['results']) && 'simple' === $template) {
770
            $result['cards'] = array_reduce($result['results'],
771
                function ($result, $item)
772
                {
773
                    /** @var array $item */
774
                    if (!empty($item['id'])) {
775
                        $result[$item['id']] = \app\modules\shop\widgets\Contragent::widget([
776
                            'viewFile' => 'contragent/backend_list',
777
                            'model' => Contragent::findOne(['id' => $item['id']]),
778
                        ]);
779
                    }
780
                    return $result;
781
                }, []);
782
        }
783
784
        return $result;
785
    }
786
}
787