Test Failed
Push — master ( 5878a7...1a655d )
by Alexey
05:08
created

Cart::availablePayTypes()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 0
dl 0
loc 14
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cart
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
12
namespace Ecommerce;
13
/**
14
 * Class Cart
15
 *
16
 * @property int $id
17
 * @property int $user_id
18
 * @property int $cart_status_id
19
 * @property int $delivery_id
20
 * @property int $paytype_id
21
 * @property int $card_item_id
22
 * @property bool $warehouse_block
23
 * @property bool $payed
24
 * @property string $comment
25
 * @property bool $exported
26
 * @property string $complete_data
27
 * @property string $date_status
28
 * @property string $date_last_activ
29
 * @property string $date_create
30
 *
31
 * @property-read \Users\User $user
32
 * @property-read \Ecommerce\Cart\Item[] $cartItems
33
 * @property-read \Ecommerce\Cart\Event[] $events
34
 * @property-read \Ecommerce\Cart\Status $status
35
 * @property-read \Ecommerce\Delivery $delivery
36
 * @property-read \Ecommerce\PayType $payType
37
 * @property-read \Ecommerce\Cart\Info[] $infos
38
 * @property-read \Ecommerce\Cart\DeliveryInfo[] $deliveryInfos
39
 * @property-read \Ecommerce\Cart\Extra[] $extras
40
 * @property-read \Ecommerce\Card\Item $card
41
 * @property-read \Money\Pay[] $pays
42
 * @property-read \Ecommerce\Cart\Discount[] $discounts
43
 *
44
 * @method \Users\User user($options)($options)
45
 * @method \Ecommerce\Cart\Item[] cartItems($options)
46
 * @method \Ecommerce\Cart\Event[] events($options)
47
 * @method \Ecommerce\Cart\Status status($options)
48
 * @method \Ecommerce\Delivery delivery($options)
49
 * @method \Ecommerce\PayType payType($options)
50
 * @method \Ecommerce\Cart\Info[] infos($options)
51
 * @method \Ecommerce\Cart\DeliveryInfo[] deliveryInfos($options)
52
 * @method \Ecommerce\Cart\Extra[] extras($options)
53
 * @method \Ecommerce\Card\Item card($options)
54
 * @method \Money\Pay[] pays($options)
55
 * @method \Ecommerce\Cart\Discount[] discounts($options)
56
 */
57
class Cart extends \Model {
58
59
    public static $objectName = 'Корзины';
60
61
    public static function indexes() {
62
        return [
63
            'ecommerce_cartStatusBlock' => [
64
                'type' => 'INDEX',
65
                'cols' => [
66
                    'cart_cart_status_id',
67
                    'cart_warehouse_block'
68
                ]
69
            ],
70
            'ecommerce_cartStats' => [
71
                'type' => 'INDEX',
72
                'cols' => [
73
                    'cart_cart_status_id',
74
                ]
75
            ],
76
            'ecommerce_cartBlock' => [
77
                'type' => 'INDEX',
78
                'cols' => [
79
                    'cart_warehouse_block'
80
                ]
81
            ],
82
        ];
83
    }
84
85
    public static function relations() {
86
        return [
87
            'user' => [
88
                'model' => 'Users\User',
89
                'col' => 'user_id'
90
            ],
91
            'cartItems' => [
92
                'type' => 'many',
93
                'model' => 'Ecommerce\Cart\Item',
94
                'col' => 'cart_id',
95
            ],
96
            'events' => [
97
                'type' => 'many',
98
                'model' => 'Ecommerce\Cart\Event',
99
                'col' => 'cart_id',
100
            ],
101
            'status' => [
102
                'model' => 'Ecommerce\Cart\Status',
103
                'col' => 'cart_status_id'
104
            ],
105
            'delivery' => [
106
                'model' => 'Ecommerce\Delivery',
107
                'col' => 'delivery_id'
108
            ],
109
            'payType' => [
110
                'model' => 'Ecommerce\PayType',
111
                'col' => 'paytype_id'
112
            ],
113
            'infos' => [
114
                'type' => 'many',
115
                'model' => 'Ecommerce\Cart\Info',
116
                'col' => 'cart_id',
117
                'resultKey' => 'useradds_field_id'
118
            ],
119
            'deliveryInfos' => [
120
                'type' => 'many',
121
                'model' => 'Ecommerce\Cart\DeliveryInfo',
122
                'col' => 'cart_id',
123
                'resultKey' => 'delivery_field_id'
124
            ],
125
            'extras' => [
126
                'type' => 'many',
127
                'model' => 'Ecommerce\Cart\Extra',
128
                'col' => 'cart_id'
129
            ],
130
            'card' => [
131
                'model' => 'Ecommerce\Card\Item',
132
                'col' => 'card_item_id'
133
            ],
134
            'pays' => [
135
                'type' => 'many',
136
                'model' => 'Money\Pay',
137
                'col' => 'data'
138
            ],
139
            'discounts' => [
140
                'type' => 'relModel',
141
                'relModel' => 'Ecommerce\Cart\Discount',
142
                'model' => 'Ecommerce\Discount',
143
            ]
144
        ];
145
    }
146
147
    public function beforeDelete() {
148
        foreach ($this->cartItems as $cartItem) {
149
            $cartItem->delete();
150
        }
151
        foreach ($this->infos as $info) {
152
            $info->delete();
153
        }
154
        foreach ($this->extras as $extra) {
155
            $extra->delete();
156
        }
157
        foreach ($this->events as $event) {
158
            $event->delete();
159
        }
160
    }
161
162
    public static $labels = [
163
        'user_id' => 'Пользователь',
164
        'cart_status_id' => 'Статус',
165
        'delivery_id' => 'Доставка',
166
        'comment' => 'Комментарий',
167
        'bonus_used' => 'Выгодные рубли',
168
        'complete_data' => 'Время заказа',
169
        'info' => 'Информация',
170
        'items' => 'Товары',
171
        'paytype_id' => 'Способ оплаты',
172
        'payed' => 'Оплачен',
173
        'exported' => 'Выгружено',
174
        'warehouse_block' => 'Блокировка товаров',
175
        'extra' => 'Доп.',
176
        'card_item_id' => 'Дисконтная карта',
177
        'info' => 'Информация',
178
        'contacts' => 'Информация',
179
        'pay' => 'Счета',
180
        'sums' => 'Суммы',
181
        'deliveryInfo' => 'Для доставки',
182
        'discount' => 'Скидки',
183
    ];
184
    public static $cols = [
185
        //Основные параметры
186
        'user_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'user'],
187
        'cart_status_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'status'],
188
        'delivery_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'delivery'],
189
        'paytype_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'payType'],
190
        'card_item_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'card'],
191
        'warehouse_block' => ['type' => 'bool'],
192
        'payed' => ['type' => 'bool'],
193
        'comment' => ['type' => 'textarea'],
194
        //Системные
195
        'exported' => ['type' => 'bool'],
196
        'complete_data' => ['type' => 'dateTime', 'null' => true, 'emptyValue' => null],
197
        'date_status' => ['type' => 'dateTime', 'null' => true, 'emptyValue' => null],
198
        'date_last_activ' => ['type' => 'dateTime', 'null' => true, 'emptyValue' => null],
199
        'date_create' => ['type' => 'dateTime'],
200
        //Виджеты
201
        'sums' => [
202
            'type' => 'void',
203
            'view' => [
204
                'type' => 'widget',
205
                'widget' => 'Ecommerce\adminSums',
206
            ],
207
        ],
208
        'contacts' => [
209
            'type' => 'void',
210
            'view' => [
211
                'type' => 'widget',
212
                'widget' => 'Ecommerce\admin/contacts',
213
            ],
214
        ],
215
        //Менеджеры
216
        'extra' => ['type' => 'dataManager', 'relation' => 'extras'],
217
        'pay' => ['type' => 'dataManager', 'relation' => 'pays'],
218
        'items' => ['type' => 'dataManager', 'relation' => 'cartItems'],
219
        'info' => ['type' => 'dataManager', 'relation' => 'infos'],
220
        'deliveryInfo' => ['type' => 'dataManager', 'relation' => 'deliveryInfos'],
221
        'discount' => ['type' => 'dataManager', 'relation' => 'discounts'],
222
    ];
223
    public static $dataManagers = [
224
        'manager' => [
225
            'cols' => [
226
                'contacts',
227
                'items',
228
                'extra',
229
                'discount',
230
                'sums',
231
                'cart_status_id',
232
                'delivery_id',
233
                'deliveryInfo',
234
                'payed',
235
                'pay',
236
                'complete_data',
237
            ],
238
            'sortable' => [
239
                'cart_status_id',
240
                'delivery_id',
241
                'payed',
242
                'complete_data',
243
            ],
244
            'filters' => [
245
                'cart_status_id',
246
                'delivery_id',
247
                'payed',
248
                'complete_data',
249
            ],
250
            'preSort' => [
251
                'complete_data' => 'desc'
252
            ],
253
            'actions' => [
254
                'Ecommerce\CloseCartBtn', 'Open', 'Edit', 'Delete'
255
            ]
256
        ]
257
    ];
258
259
    public static function itemName($item) {
260
        return $item->pk() . '. ' . $item->name();
261
    }
262
263
    public static $forms = [
264
        'manager' => [
265
            'inputs' => [
266
                'userSearch' => [
267
                    'type' => 'search',
268
                    'source' => 'relation',
269
                    'relation' => 'user',
270
                    'label' => 'Покупатель',
271
                    'cols' => [
272
                        'info:first_name',
273
                        'info:last_name',
274
                        'info:middle_name',
275
                        'mail'
276
                    ],
277
                    'col' => 'user_id',
278
                    'required' => true,
279
                    'showCol' => [
280
                        'type' => 'staticMethod',
281
                        'class' => 'Ecommerce\Cart',
282
                        'method' => 'itemName',
283
                    ],
284
                ],
285
                'cardSearch' => [
286
                    'type' => 'search',
287
                    'source' => 'relation',
288
                    'relation' => 'card',
289
                    'label' => 'Дисконтная карта',
290
                    'cols' => [
291
                        'code',
292
                        'user:info:first_name',
293
                        'user:info:last_name',
294
                        'user:info:middle_name',
295
                        'user:mail'
296
                    ],
297
                    'col' => 'card_item_id',
298
                ],
299
            ],
300
            'map' => [
301
                ['userSearch', 'cart_status_id'],
302
                ['paytype_id', 'delivery_id'],
303
                ['cardSearch', 'comment'],
304
                ['warehouse_block', 'complete_data'],
305
                ['payed'],
306
                ['items'],
307
                ['extra'],
308
                ['pay'],
309
                ['info'],
310
                ['deliveryInfo']
311
            ]
312
        ],
313
    ];
314
315
    public function checkStage() {
316
        $sum = $this->itemsSum();
317
        $stages = Cart\Stage::getList(['order' => ['sum', 'asc']]);
318
        $groups = [];
319
        foreach ($stages as $stage) {
320
            if ($sum->greater(new \Money\Sums([$stage->currency_id => $stage->sum])) || $sum->equal(new \Money\Sums([$stage->currency_id => $stage->sum]))) {
321
                $groups[$stage->group] = $stage;
322
            }
323
        }
324
        $discounts = Cart\Discount::getList(['where' => ['cart_id', $this->id]]);
325
        foreach ($discounts as $discount) {
326
            if (!isset($groups[$discount->group]) && $discount->auto) {
327
                $discount->delete();
328
            }
329
            if (isset($groups[$discount->group]) && $groups[$discount->group]->type == 'discount') {
330
                $discount->discount_id = $groups[$discount->group]->value;
331
                $discount->save();
332
                unset($groups[$discount->group]);
333
            }
334
        }
335
        foreach ($groups as $group) {
336
            if ($group && $group->type == 'discount') {
337
                $rel = $this->addRelation('discounts', $group->value);
338
                $rel->auto = true;
339
                $rel->group = 'discount';
340
                $rel->save();
341
            }
342
        }
343
    }
344
345
    public function needDelivery() {
346
        foreach ($this->cartItems as $cartItem) {
347
            if ((!$cartItem->item->type && !empty(\App::$cur->ecommerce->config['defaultNeedDelivery'])) || ($cartItem->item->type && $cartItem->item->type->delivery)) {
348
                return true;
349
            }
350
        }
351
        return false;
352
    }
353
354
    public function deliverySum() {
355
        $sum = new \Money\Sums([0 => 0]);
356
        if ($this->delivery && $this->needDelivery()) {
357
            $sums = $this->itemsSum();
358
            $deliveryPrice = new \Money\Sums([$this->delivery->currency_id => $this->delivery->max_cart_price]);
359
            if ($this->delivery->max_cart_price && $sums->greater($deliveryPrice) || $sums->equal($deliveryPrice)) {
360
                $sum->sums = [$this->delivery->currency_id => 0];
361
            } else if ($this->delivery->prices) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->delivery->prices of type Ecommerce\Delivery\Price[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
362
                foreach ($this->delivery->prices(['order' => ['cart_price', 'asc']]) as $delPrice) {
363
                    $deliveryPrice = new \Money\Sums([$delPrice->currency_id => $delPrice->cart_price]);
364
                    if ($sums->greater($deliveryPrice) || $sums->equal($deliveryPrice)) {
365
                        $sum->sums = [$delPrice->currency_id => $delPrice->price];
366
                    }
367
                }
368
                if (!$sum->sums) {
369
                    $sum->sums = [$this->delivery->currency_id => $this->delivery->price];
370
                }
371
            } else {
372
                if (!$this->delivery->provider) {
0 ignored issues
show
Bug introduced by
The property provider does not seem to exist. Did you mean delivery_provider_id?

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...
373
                    $sum->sums = [$this->delivery->currency_id => $this->delivery->price];
374
                } else {
375
                    $className = 'Ecommerce\DeliveryProvider\\' . $this->delivery->provider->object;
0 ignored issues
show
Bug introduced by
The property provider does not seem to exist. Did you mean delivery_provider_id?

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...
376
                    $sum = $className::calcPrice($this);
377
                }
378
            }
379
        }
380
        return $sum;
381
    }
382
383
    public function hasDiscount() {
384
        return (bool) $this->card || $this->discounts;
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->discounts of type Ecommerce\Cart\Discount[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
385
    }
386
387
    public function discountSum() {
388
        $sums = [];
389
        foreach ($this->cartItems as $cartItem) {
390
            $sums[$cartItem->price->currency_id] = isset($sums[$cartItem->price->currency_id]) ? $sums[$cartItem->price->currency_id] + $cartItem->discount() * $cartItem->count : $cartItem->discount() * $cartItem->count;
391
        }
392
        return new \Money\Sums($sums);
393
    }
394
395
    public function finalSum() {
396
        $sums = $this->itemsSum();
397
        $sums = $sums->minus($this->discountSum());
398
        $sums = $sums->plus($this->deliverySum());
399
        return $sums;
400
    }
401
402
    public function itemsSum() {
403
        $cart = Cart::get($this->id);
404
        $sums = [];
405
        foreach ($cart->cartItems as $cartItem) {
406
            if (!$cartItem->price) {
407
                continue;
408
            }
409
            $sums[$cartItem->price->currency_id] = isset($sums[$cartItem->price->currency_id]) ? $sums[$cartItem->price->currency_id] + $cartItem->price->price * $cartItem->count : $cartItem->price->price * $cartItem->count;
410
        }
411
        return new \Money\Sums($sums);
412
    }
413
414
    public function checkPrices() {
415
        $change = false;
416
        foreach ($this->cartItems as $cartItem) {
417
            if ($cartItem->price && !$cartItem->price->checkUserAccess()) {
418
                $newPrice = $cartItem->price->offer->getPrice();
419
                $cartItem->item_offer_price_id = $newPrice->id;
420
                $cartItem->save();
421
                $cartItem->loadRelation('price');
422
                $change = true;
423
            }
424
        }
425
        return $change;
426
    }
427
428
    public function addItem($offer_price_id, $count = 1, $final_price = 0) {
429
        $price = Item\Offer\Price::get((int) $offer_price_id);
430
431
        if (!$price) {
432
            return false;
433
        }
434
435
        if ($count <= 0) {
436
            $count = 1;
437
        }
438
439
        $cartItem = new Cart\Item();
440
        $cartItem->cart_id = $this->id;
441
        $cartItem->item_id = $price->offer->item->id;
442
        $cartItem->count = $count;
443
        $cartItem->item_offer_price_id = $price->id;
444
        $cartItem->final_price = $final_price ? $final_price : $price->price;
445
        $cartItem->save();
446
        return true;
447
    }
448
449
    public function calc($save = true) {
450
        if ($save) {
451
            $this->save();
452
        }
453
    }
454
455
    public function availablePayTypes() {
456
        if (!$this->delivery) {
457
            return \Ecommerce\PayType::getList(['order' => ['weight', 'ASC']]);
458
        }
459
        $providerHelper = $this->delivery->providerHelper();
460
        if (!$providerHelper) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $providerHelper of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
461
            return \Ecommerce\PayType::getList(['order' => ['weight', 'ASC']]);
462
        }
463
        $payTypeGroups = $providerHelper::availablePayTypeGroups($this);
464
        if (!$payTypeGroups || $payTypeGroups[0] === '*') {
465
            return \Ecommerce\PayType::getList(['order' => ['weight', 'ASC']]);
466
        }
467
        return \Ecommerce\PayType::getList(['where' => ['group', $payTypeGroups, 'IN'], 'order' => ['weight', 'ASC']]);
468
    }
469
}
470