1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace app\modules\shop\controllers; |
4
|
|
|
|
5
|
|
|
use app\modules\core\behaviors\DisableRobotIndexBehavior; |
6
|
|
|
use app\modules\core\helpers\EventTriggeringHelper; |
7
|
|
|
use app\modules\core\models\Events; |
8
|
|
|
use app\modules\shop\helpers\PriceHelper; |
9
|
|
|
use app\modules\shop\events\OrderStageEvent; |
10
|
|
|
use app\modules\shop\events\OrderStageLeafEvent; |
11
|
|
|
use app\modules\shop\models\Currency; |
12
|
|
|
use app\modules\shop\models\Order; |
13
|
|
|
use app\modules\shop\models\OrderCode; |
14
|
|
|
use app\modules\shop\models\OrderItem; |
15
|
|
|
use app\modules\shop\models\OrderStage; |
16
|
|
|
use app\modules\shop\models\OrderStageLeaf; |
17
|
|
|
use app\modules\shop\models\Product; |
18
|
|
|
use app\modules\shop\models\SpecialPriceList; |
19
|
|
|
use app\modules\shop\ShopModule; |
20
|
|
|
use yii\helpers\Url; |
21
|
|
|
use Yii; |
22
|
|
|
use yii\helpers\ArrayHelper; |
23
|
|
|
use yii\web\BadRequestHttpException; |
24
|
|
|
use yii\web\Controller; |
25
|
|
|
use yii\web\NotFoundHttpException; |
26
|
|
|
use yii\web\Response; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Class CartController |
30
|
|
|
* @package app\modules\shop\controllers |
31
|
|
|
* @property ShopModule $module |
32
|
|
|
*/ |
33
|
|
|
class CartController extends Controller |
34
|
|
|
{ |
35
|
|
|
public function behaviors() |
36
|
|
|
{ |
37
|
|
|
return [ |
38
|
|
|
[ |
39
|
|
|
'class' => DisableRobotIndexBehavior::className(), |
40
|
|
|
] |
41
|
|
|
]; |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Get Order. |
46
|
|
|
* @param bool $create Create order if it does not exist |
47
|
|
|
* @param bool $throwException Throw exception if it does not exist |
48
|
|
|
* @return null|Order |
49
|
|
|
* @throws NotFoundHttpException |
50
|
|
|
*/ |
51
|
|
|
protected function loadOrder($create = false, $throwException = true) |
52
|
|
|
{ |
53
|
|
|
$model = Order::getOrder($create); |
54
|
|
|
if (is_null($model) && $throwException) { |
55
|
|
|
throw new NotFoundHttpException; |
56
|
|
|
} |
57
|
|
|
return $model; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Get OrderItem. |
62
|
|
|
* @param int $id |
63
|
|
|
* @param bool $checkOrderAttachment |
64
|
|
|
* @return OrderItem |
|
|
|
|
65
|
|
|
* @throws NotFoundHttpException |
66
|
|
|
*/ |
67
|
|
|
protected function loadOrderItem($id, $checkOrderAttachment = true) |
68
|
|
|
{ |
69
|
|
|
/** @var OrderItem $orderItemModel */ |
70
|
|
|
$orderModel = $checkOrderAttachment ? $this->loadOrder() : null; |
71
|
|
|
$orderItemModel = OrderItem::findOne($id); |
72
|
|
|
if (is_null($orderItemModel) |
73
|
|
|
|| ($checkOrderAttachment && (is_null($orderModel) || $orderItemModel->order_id != $orderModel->id)) |
74
|
|
|
) { |
75
|
|
|
throw new NotFoundHttpException; |
76
|
|
|
} |
77
|
|
|
return $orderItemModel; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
protected function addProductsToOrder($products, $parentId = 0) |
81
|
|
|
{ |
82
|
|
|
if (!is_array($products)) { |
83
|
|
|
throw new BadRequestHttpException; |
84
|
|
|
} |
85
|
|
|
$order = $this->loadOrder(true); |
86
|
|
|
$result = [ |
87
|
|
|
'errors' => [], |
88
|
|
|
'itemModalPreview' => '', |
89
|
|
|
]; |
90
|
|
|
foreach ($products as $product) { |
91
|
|
|
if (!isset($product['id']) || is_null($productModel = Product::findById($product['id']))) { |
92
|
|
|
$result['errors'][] = Yii::t('app', 'Product not found.'); |
93
|
|
|
continue; |
94
|
|
|
} |
95
|
|
|
/** @var Product $productModel */ |
96
|
|
|
$quantity = isset($product['quantity']) && (double) $product['quantity'] > 0 |
97
|
|
|
? (double) $product['quantity'] |
98
|
|
|
: 1; |
99
|
|
|
$quantity = $productModel->measure->ceilQuantity($quantity); |
100
|
|
|
if ($this->module->allowToAddSameProduct |
101
|
|
|
|| is_null($orderItem = OrderItem::findOne(['order_id' => $order->id, 'product_id' => $productModel->id, 'parent_id' => 0])) |
|
|
|
|
102
|
|
|
) { |
103
|
|
|
$orderItem = new OrderItem; |
104
|
|
|
$orderItem->attributes = [ |
105
|
|
|
'parent_id' => $parentId, |
106
|
|
|
'order_id' => $order->id, |
107
|
|
|
'product_id' => $productModel->id, |
108
|
|
|
'quantity' => $quantity, |
109
|
|
|
'price_per_pcs' => PriceHelper::getProductPrice( |
110
|
|
|
$productModel, |
111
|
|
|
$order, |
112
|
|
|
1, |
113
|
|
|
SpecialPriceList::TYPE_CORE |
114
|
|
|
), |
115
|
|
|
]; |
116
|
|
|
} else { |
117
|
|
|
/** @var OrderItem $orderItem */ |
118
|
|
|
$orderItem->quantity += $quantity; |
119
|
|
|
} |
120
|
|
|
if (!$orderItem->save()) { |
121
|
|
|
$result['errors'][] = Yii::t('app', 'Cannot save order item.'); |
122
|
|
|
} else { |
123
|
|
|
// refresh order |
124
|
|
|
Order::clearStaticOrder(); |
125
|
|
|
$order = $this->loadOrder(false); |
126
|
|
|
} |
127
|
|
|
if (isset($product['children'])) { |
128
|
|
|
$result = ArrayHelper::merge( |
129
|
|
|
$result, |
130
|
|
|
$this->addProductsToOrder($product['children'], $orderItem->id) |
131
|
|
|
); |
132
|
|
|
} |
133
|
|
|
if ($parentId === 0) { |
134
|
|
|
$result['itemModalPreview'] .= $this->renderPartial( |
135
|
|
|
'item-modal-preview', |
136
|
|
|
[ |
137
|
|
|
'order' => $order, |
138
|
|
|
'orderItem' => $orderItem, |
139
|
|
|
'product' => $product, |
140
|
|
|
] |
141
|
|
|
); |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
if ($parentId === 0) { |
145
|
|
|
$order->calculate(true); |
146
|
|
|
} |
147
|
|
|
$mainCurrency = Currency::getMainCurrency(); |
148
|
|
|
return ArrayHelper::merge( |
149
|
|
|
$result, |
150
|
|
|
[ |
151
|
|
|
'itemsCount' => $order->items_count, |
152
|
|
|
'success' => true, // @todo Return true success value |
|
|
|
|
153
|
|
|
'totalPrice' => $mainCurrency->format($order->total_price), |
154
|
|
|
] |
155
|
|
|
); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
public function actionAdd() |
159
|
|
|
{ |
160
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
161
|
|
|
if (!is_array(Yii::$app->request->post('products', null))) { |
162
|
|
|
throw new BadRequestHttpException; |
163
|
|
|
} |
164
|
|
|
$order = $this->loadOrder(true); |
165
|
|
|
if (is_null($order->stage) || $order->stage->immutable_by_user == 1) { |
166
|
|
|
throw new BadRequestHttpException; |
167
|
|
|
} |
168
|
|
|
return $this->addProductsToOrder(Yii::$app->request->post('products')); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
public function actionChangeQuantity() |
172
|
|
|
{ |
173
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
174
|
|
|
$id = Yii::$app->request->post('id'); |
175
|
|
|
$quantity = Yii::$app->request->post('quantity'); |
176
|
|
|
if (is_null($id) || is_null($quantity) || (double) $quantity <= 0) { |
177
|
|
|
throw new BadRequestHttpException; |
178
|
|
|
} |
179
|
|
|
$orderItem = $this->loadOrderItem($id); |
180
|
|
|
$order = $this->loadOrder(); |
181
|
|
|
if (is_null($order->stage) || $order->stage->immutable_by_user == 1) { |
182
|
|
|
throw new BadRequestHttpException; |
183
|
|
|
} |
184
|
|
|
$orderItem->quantity = $orderItem->product->measure->ceilQuantity($quantity); |
185
|
|
|
// @todo Consider lock_product_price ? |
|
|
|
|
186
|
|
|
if ($orderItem->lock_product_price == 0) { |
187
|
|
|
$orderItem->price_per_pcs = PriceHelper::getProductPrice( |
188
|
|
|
$orderItem->product, |
189
|
|
|
$order, |
190
|
|
|
1, |
191
|
|
|
SpecialPriceList::TYPE_CORE |
192
|
|
|
); |
193
|
|
|
} |
194
|
|
|
$orderItem->save(); |
|
|
|
|
195
|
|
|
$mainCurrency = Currency::getMainCurrency(); |
196
|
|
|
if ($order->calculate(true)) { |
197
|
|
|
return [ |
198
|
|
|
'success' => true, |
199
|
|
|
'itemsCount' => $order->items_count, |
200
|
|
|
'itemPrice' => $mainCurrency->format($orderItem->total_price), |
201
|
|
|
'totalPrice' => $mainCurrency->format($order->total_price), |
202
|
|
|
'calculatedQuantity' => $orderItem->quantity, |
203
|
|
|
]; |
204
|
|
|
} else { |
205
|
|
|
return [ |
206
|
|
|
'success' => false, |
207
|
|
|
'message' => Yii::t('app', 'Cannot change quantity'), |
208
|
|
|
]; |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Delete OrderItem action. |
214
|
|
|
* @param int $id |
215
|
|
|
* @throws NotFoundHttpException |
216
|
|
|
* @throws \Exception |
217
|
|
|
* @return array |
218
|
|
|
*/ |
219
|
|
|
public function actionDelete($id) |
220
|
|
|
{ |
221
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
222
|
|
|
$order = $this->loadOrder(); |
223
|
|
|
if (is_null($order->stage) || $order->stage->immutable_by_user == 1) { |
224
|
|
|
throw new BadRequestHttpException; |
225
|
|
|
} |
226
|
|
|
if ($this->loadOrderItem($id)->delete() && $order->calculate(true)) { |
|
|
|
|
227
|
|
|
$mainCurrency = Currency::getMainCurrency(); |
228
|
|
|
return [ |
229
|
|
|
'success' => true, |
230
|
|
|
'itemsCount' => $order->items_count, |
231
|
|
|
'totalPrice' => $mainCurrency->format($order->total_price), |
232
|
|
|
'itemModalPreview' => $this->renderPartial("item-modal-preview", |
233
|
|
|
[ |
234
|
|
|
"order" => $order, |
235
|
|
|
"orderItem" => null, |
236
|
|
|
"product" => null |
237
|
|
|
] |
238
|
|
|
) |
239
|
|
|
]; |
240
|
|
|
} else { |
241
|
|
|
return [ |
242
|
|
|
'success' => false, |
243
|
|
|
'message' => Yii::t('app', 'Cannot change additional params'), |
244
|
|
|
]; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
public function actionClear() |
249
|
|
|
{ |
250
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
251
|
|
|
$order = $this->loadOrder(); |
252
|
|
|
foreach ($order->items as $item) { |
253
|
|
|
$item->delete(); |
254
|
|
|
} |
255
|
|
|
$order->calculate(true); |
256
|
|
|
return ['success' => true,]; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
public function actionIndex() |
260
|
|
|
{ |
261
|
|
|
$model = $this->loadOrder(false, false); |
262
|
|
|
$orderCode = null; |
263
|
|
|
if (!is_null($model)) { |
264
|
|
|
$orderCode = OrderCode::find() |
265
|
|
|
->where( |
266
|
|
|
[ |
267
|
|
|
'order_id' => $model->id, |
268
|
|
|
'status' => 1 |
269
|
|
|
] |
270
|
|
|
) |
271
|
|
|
->one(); |
272
|
|
|
|
273
|
|
|
if ($orderCode === null) { |
274
|
|
|
$orderCode = new OrderCode(); |
275
|
|
|
|
276
|
|
|
if (Yii::$app->request->isPost) { |
277
|
|
|
$orderCode->load(Yii::$app->request->post()); |
278
|
|
|
$orderCode->order_id = $model->id; |
279
|
|
|
if ($orderCode->save()) { |
280
|
|
|
$this->refresh(); |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
$model->calculate(); |
285
|
|
|
} |
286
|
|
|
return $this->render('index', ['model' => $model, 'orderCode' => $orderCode]); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @return string|Response |
291
|
|
|
* @throws NotFoundHttpException |
292
|
|
|
*/ |
293
|
|
|
public function actionStage() |
294
|
|
|
{ |
295
|
|
|
$order = $this->loadOrder(false, false); |
296
|
|
|
if (empty($order) || $order->getImmutability(Order::IMMUTABLE_USER)) { |
297
|
|
|
return $this->redirect(Url::to(['index'])); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** @var OrderStage $orderStage */ |
301
|
|
|
$orderStage = $order->stage; |
302
|
|
|
$eventData = ['order' => $order]; |
303
|
|
|
|
304
|
|
|
if (0 === intval($orderStage->is_in_cart)) { |
305
|
|
|
Yii::$app->session->remove('orderId'); |
306
|
|
|
$order->in_cart = 0; |
307
|
|
|
$order->save(); |
308
|
|
|
Order::clearStaticOrder(); |
309
|
|
|
} |
310
|
|
|
if (1 === intval($orderStage->become_non_temporary)) { |
311
|
|
|
$order->temporary = 0; |
312
|
|
|
$order->save(); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
// if (null !== Yii::$app->session->get('OrderStageReach')) { |
|
|
|
|
316
|
|
|
/** @var Events $eventClass */ |
317
|
|
|
$eventClass = Events::findByName($orderStage->event_name); |
318
|
|
|
if (!empty($eventClass) && is_subclass_of($eventClass->event_class_name, OrderStageEvent::className())) { |
|
|
|
|
319
|
|
|
/** @var OrderStageEvent $event */ |
320
|
|
|
$event = new $eventClass->event_class_name; |
321
|
|
|
$event->setEventData($eventData); |
322
|
|
|
EventTriggeringHelper::triggerSpecialEvent($event); |
323
|
|
|
$eventData = $event->eventData(); |
324
|
|
|
|
325
|
|
|
if (!empty($eventData['__redirect'])) { |
326
|
|
|
return $this->redirect($eventData['__redirect']); |
327
|
|
|
} |
328
|
|
|
} |
329
|
|
|
Yii::$app->session->remove('OrderStageReach'); |
330
|
|
|
// } |
331
|
|
|
|
332
|
|
|
return $this->render( |
333
|
|
|
'stage', |
334
|
|
|
[ |
335
|
|
|
'order' => $order, |
336
|
|
|
'stage' => $orderStage, |
337
|
|
|
'eventData' => $eventData, |
338
|
|
|
] |
339
|
|
|
); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* @param null $id |
344
|
|
|
* @return Response |
345
|
|
|
* @throws NotFoundHttpException |
346
|
|
|
* @throws \yii\base\Exception |
347
|
|
|
*/ |
348
|
|
|
public function actionStageLeaf($id = null) |
349
|
|
|
{ |
350
|
|
|
if (empty($id)) { |
351
|
|
|
return $this->redirect(Url::to(['stage'])); |
352
|
|
|
} |
353
|
|
|
/** @var OrderStageLeaf $orderStageLeaf */ |
354
|
|
|
$orderStageLeaf = OrderStageLeaf::findOne(['id' => $id]); |
355
|
|
|
if (empty($orderStageLeaf)) { |
356
|
|
|
return $this->redirect(Url::to(['stage'])); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
$order = $this->loadOrder(false, false); |
360
|
|
|
if (empty($order)) { |
361
|
|
|
return $this->redirect(Url::to(['index'])); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
$orderStage = $order->stage; |
365
|
|
|
if ($orderStage->id !== $orderStageLeaf->stage_from_id && $orderStage->id !== $orderStageLeaf->stage_to_id) { |
366
|
|
|
return $this->redirect(Url::to(['stage'])); |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
if (null !== Yii::$app->request->get('previous') && 1 !== intval($orderStageLeaf->stageFrom->immutable_by_user)) { |
|
|
|
|
370
|
|
|
$order->order_stage_id = $orderStageLeaf->stageFrom->id; |
371
|
|
|
$order->save(); |
372
|
|
|
} else { |
373
|
|
|
/** @var Events $eventClassName */ |
374
|
|
|
$eventClassName = Events::findByName($orderStageLeaf->event_name); |
375
|
|
|
if (!empty($eventClassName) && is_subclass_of($eventClassName->event_class_name, OrderStageLeafEvent::className())) { |
|
|
|
|
376
|
|
|
/** @var OrderStageLeafEvent $event */ |
377
|
|
|
$event = new $eventClassName->event_class_name; |
378
|
|
|
EventTriggeringHelper::triggerSpecialEvent($event); |
379
|
|
|
if ($event->getStatus()) { |
380
|
|
|
$order->order_stage_id = $order->order_stage_id == $orderStageLeaf->stage_to_id |
381
|
|
|
? $orderStageLeaf->stage_from_id |
382
|
|
|
: $orderStageLeaf->stage_to_id; |
383
|
|
|
$order->save(); |
384
|
|
|
|
385
|
|
|
Yii::$app->session->set('OrderStageReach', true); |
386
|
|
|
} |
387
|
|
|
} |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
return $this->redirect(Url::to(['stage'])); |
391
|
|
|
} |
392
|
|
|
} |
393
|
|
|
|
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.If the return type contains the type array, this check recommends the use of a more specific type like
String[]
orarray<String>
.