Commit fd40a9e1a50870b86e374e87e579162b8d4d7097

Authored by Yarik
1 parent 2a050410

Products to order

assets/OrderAsset.php
@@ -25,4 +25,8 @@ @@ -25,4 +25,8 @@
25 public $js = [ 25 public $js = [
26 'js/order.js', 26 'js/order.js',
27 ]; 27 ];
  28 +
  29 + public $depends = [
  30 + 'yii\widgets\PjaxAsset',
  31 + ];
28 } 32 }
controllers/OrderController.php
1 <?php 1 <?php
2 2
3 namespace artbox\order\controllers; 3 namespace artbox\order\controllers;
4 - 4 +
  5 + use artbox\catalog\models\Product;
  6 + use artbox\catalog\models\Variant;
5 use artbox\order\models\Delivery; 7 use artbox\order\models\Delivery;
6 use artbox\order\models\Label; 8 use artbox\order\models\Label;
  9 + use artbox\order\models\OrderProduct;
7 use artbox\order\models\Payment; 10 use artbox\order\models\Payment;
8 use Yii; 11 use Yii;
9 use artbox\order\models\Order; 12 use artbox\order\models\Order;
10 use artbox\order\models\OrderSearch; 13 use artbox\order\models\OrderSearch;
  14 + use yii\base\InvalidParamException;
11 use yii\base\Model; 15 use yii\base\Model;
12 use yii\web\Controller; 16 use yii\web\Controller;
13 use yii\web\NotFoundHttpException; 17 use yii\web\NotFoundHttpException;
14 use yii\filters\VerbFilter; 18 use yii\filters\VerbFilter;
15 - 19 +
16 /** 20 /**
17 * OrderController implements the CRUD actions for Order model. 21 * OrderController implements the CRUD actions for Order model.
18 */ 22 */
@@ -32,7 +36,7 @@ @@ -32,7 +36,7 @@
32 ], 36 ],
33 ]; 37 ];
34 } 38 }
35 - 39 +
36 /** 40 /**
37 * Lists all Order models. 41 * Lists all Order models.
38 * 42 *
@@ -43,21 +47,21 @@ @@ -43,21 +47,21 @@
43 $searchModel = new OrderSearch(); 47 $searchModel = new OrderSearch();
44 $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 48 $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
45 $labels = Label::find() 49 $labels = Label::find()
46 - ->select(  
47 - [  
48 - 'title',  
49 - 'id',  
50 - ]  
51 - )  
52 - ->joinWith('lang')  
53 - ->andWhere(  
54 - [  
55 - 'status' => true,  
56 - ]  
57 - )  
58 - ->indexBy('id')  
59 - ->column();  
60 - 50 + ->select(
  51 + [
  52 + 'title',
  53 + 'id',
  54 + ]
  55 + )
  56 + ->joinWith('lang')
  57 + ->andWhere(
  58 + [
  59 + 'status' => true,
  60 + ]
  61 + )
  62 + ->indexBy('id')
  63 + ->column();
  64 +
61 return $this->render( 65 return $this->render(
62 '@artbox/order/views/order/index', 66 '@artbox/order/views/order/index',
63 [ 67 [
@@ -67,7 +71,7 @@ @@ -67,7 +71,7 @@
67 ] 71 ]
68 ); 72 );
69 } 73 }
70 - 74 +
71 /** 75 /**
72 * Displays a single Order model. 76 * Displays a single Order model.
73 * 77 *
@@ -84,7 +88,7 @@ @@ -84,7 +88,7 @@
84 ] 88 ]
85 ); 89 );
86 } 90 }
87 - 91 +
88 /** 92 /**
89 * Creates a new Order model. 93 * Creates a new Order model.
90 * If creation is successful, the browser will be redirected to the 'view' page. 94 * If creation is successful, the browser will be redirected to the 'view' page.
@@ -94,7 +98,7 @@ @@ -94,7 +98,7 @@
94 public function actionCreate() 98 public function actionCreate()
95 { 99 {
96 $model = new Order(); 100 $model = new Order();
97 - 101 +
98 if ($model->load(Yii::$app->request->post()) && $model->save()) { 102 if ($model->load(Yii::$app->request->post()) && $model->save()) {
99 return $this->redirect( 103 return $this->redirect(
100 [ 104 [
@@ -104,50 +108,50 @@ @@ -104,50 +108,50 @@
104 ); 108 );
105 } else { 109 } else {
106 $labels = Label::find() 110 $labels = Label::find()
107 - ->joinWith('lang')  
108 - ->select(  
109 - [  
110 - 'title',  
111 - 'id',  
112 - ]  
113 - )  
114 - ->where(  
115 - [  
116 - 'status' => true,  
117 - ]  
118 - )  
119 - ->indexBy('id')  
120 - ->column(); 111 + ->joinWith('lang')
  112 + ->select(
  113 + [
  114 + 'title',
  115 + 'id',
  116 + ]
  117 + )
  118 + ->where(
  119 + [
  120 + 'status' => true,
  121 + ]
  122 + )
  123 + ->indexBy('id')
  124 + ->column();
121 $deliveries = Delivery::find() 125 $deliveries = Delivery::find()
122 - ->joinWith('lang')  
123 - ->select(  
124 - [  
125 - 'title',  
126 - 'id',  
127 - ]  
128 - )  
129 - ->where(  
130 - [  
131 - 'status' => true,  
132 - ]  
133 - )  
134 - ->indexBy('id')  
135 - ->column(); 126 + ->joinWith('lang')
  127 + ->select(
  128 + [
  129 + 'title',
  130 + 'id',
  131 + ]
  132 + )
  133 + ->where(
  134 + [
  135 + 'status' => true,
  136 + ]
  137 + )
  138 + ->indexBy('id')
  139 + ->column();
136 $payments = Payment::find() 140 $payments = Payment::find()
137 - ->joinWith('lang')  
138 - ->select(  
139 - [  
140 - 'title',  
141 - 'id',  
142 - ]  
143 - )  
144 - ->where(  
145 - [  
146 - 'status' => true,  
147 - ]  
148 - )  
149 - ->indexBy('id')  
150 - ->column(); 141 + ->joinWith('lang')
  142 + ->select(
  143 + [
  144 + 'title',
  145 + 'id',
  146 + ]
  147 + )
  148 + ->where(
  149 + [
  150 + 'status' => true,
  151 + ]
  152 + )
  153 + ->indexBy('id')
  154 + ->column();
151 return $this->render( 155 return $this->render(
152 '@artbox/order/views/order/create', 156 '@artbox/order/views/order/create',
153 [ 157 [
@@ -159,7 +163,7 @@ @@ -159,7 +163,7 @@
159 ); 163 );
160 } 164 }
161 } 165 }
162 - 166 +
163 /** 167 /**
164 * Updates an existing Order model. 168 * Updates an existing Order model.
165 * If update is successful, the browser will be redirected to the 'view' page. 169 * If update is successful, the browser will be redirected to the 'view' page.
@@ -171,16 +175,9 @@ @@ -171,16 +175,9 @@
171 public function actionUpdate($id) 175 public function actionUpdate($id)
172 { 176 {
173 $model = $this->findModel($id); 177 $model = $this->findModel($id);
174 - 178 +
175 if ($model->load(Yii::$app->request->post()) && $model->save()) { 179 if ($model->load(Yii::$app->request->post()) && $model->save()) {
176 - if (Model::loadMultiple($model->orderProducts, \Yii::$app->request->post()) && Model::validateMultiple(  
177 - $model->orderProducts  
178 - )  
179 - ) {  
180 - foreach ($model->orderProducts as $orderProduct) {  
181 - $orderProduct->save(false);  
182 - }  
183 - } 180 + OrderProduct::saveItems(\Yii::$app->request->post('OrderProduct'), $id);
184 return $this->redirect( 181 return $this->redirect(
185 [ 182 [
186 'view', 183 'view',
@@ -204,35 +201,35 @@ @@ -204,35 +201,35 @@
204 ->indexBy('id') 201 ->indexBy('id')
205 ->column(); 202 ->column();
206 $deliveries = Delivery::find() 203 $deliveries = Delivery::find()
207 - ->joinWith('lang')  
208 - ->select(  
209 - [  
210 - 'title',  
211 - 'id',  
212 - ]  
213 - )  
214 - ->where(  
215 - [  
216 - 'status' => true,  
217 - ]  
218 - )  
219 - ->indexBy('id')  
220 - ->column(); 204 + ->joinWith('lang')
  205 + ->select(
  206 + [
  207 + 'title',
  208 + 'id',
  209 + ]
  210 + )
  211 + ->where(
  212 + [
  213 + 'status' => true,
  214 + ]
  215 + )
  216 + ->indexBy('id')
  217 + ->column();
221 $payments = Payment::find() 218 $payments = Payment::find()
222 - ->joinWith('lang')  
223 - ->select(  
224 - [  
225 - 'title',  
226 - 'id',  
227 - ]  
228 - )  
229 - ->where(  
230 - [  
231 - 'status' => true,  
232 - ]  
233 - )  
234 - ->indexBy('id')  
235 - ->column(); 219 + ->joinWith('lang')
  220 + ->select(
  221 + [
  222 + 'title',
  223 + 'id',
  224 + ]
  225 + )
  226 + ->where(
  227 + [
  228 + 'status' => true,
  229 + ]
  230 + )
  231 + ->indexBy('id')
  232 + ->column();
236 return $this->render( 233 return $this->render(
237 '@artbox/order/views/order/update', 234 '@artbox/order/views/order/update',
238 [ 235 [
@@ -244,7 +241,7 @@ @@ -244,7 +241,7 @@
244 ); 241 );
245 } 242 }
246 } 243 }
247 - 244 +
248 /** 245 /**
249 * Deletes an existing Order model. 246 * Deletes an existing Order model.
250 * If deletion is successful, the browser will be redirected to the 'index' page. 247 * If deletion is successful, the browser will be redirected to the 'index' page.
@@ -257,10 +254,116 @@ @@ -257,10 +254,116 @@
257 { 254 {
258 $this->findModel($id) 255 $this->findModel($id)
259 ->delete(); 256 ->delete();
260 - 257 +
261 return $this->redirect([ 'index' ]); 258 return $this->redirect([ 'index' ]);
262 } 259 }
263 - 260 +
  261 + public function actionProductList($q = null, $id = null)
  262 + {
  263 + $response = \Yii::$app->response;
  264 + $response->format = $response::FORMAT_JSON;
  265 + $out = [
  266 + 'results' => [
  267 + 'id' => '',
  268 + 'text' => '',
  269 + ],
  270 + ];
  271 + if (!is_null($q)) {
  272 + $out[ 'results' ] = [];
  273 + /**
  274 + * @var Variant[] $variants
  275 + */
  276 + $variants = Variant::find()
  277 + ->joinWith('lang', false)
  278 + ->joinWith('product.lang', false)
  279 + ->andWhere(
  280 + [
  281 + 'like',
  282 + 'product_lang.title',
  283 + $q,
  284 + ]
  285 + )
  286 + ->orWhere(
  287 + [
  288 + 'like',
  289 + 'variant_lang.title',
  290 + $q,
  291 + ]
  292 + )
  293 + ->orWhere([ 'variant.sku' => $q ])
  294 + ->all();
  295 + foreach ($variants as $variant) {
  296 + $out[ 'results' ][] = [
  297 + 'id' => $variant->id,
  298 + 'text' => $variant->product->lang->title,
  299 + ];
  300 + }
  301 + } elseif ($id > 0) {
  302 + /**
  303 + * @var Variant $variant
  304 + */
  305 + $variant = Variant::find()
  306 + ->with('lang', 'product.lang')
  307 + ->where([ 'id' => $id ])
  308 + ->one();
  309 + $out[ 'results' ] = [
  310 + 'id' => $id,
  311 + 'text' => $variant->product->lang->title,
  312 + ];
  313 + }
  314 + return $out;
  315 + }
  316 +
  317 + public function actionAddToOrder()
  318 + {
  319 + $id = \Yii::$app->request->post('id');
  320 + $count = \Yii::$app->request->post('count');
  321 + $orderId = \Yii::$app->request->post('order');
  322 + if (empty($id) || empty($count)) {
  323 + throw new InvalidParamException(\Yii::t('order', 'Set id and count'));
  324 + }
  325 + $order = Order::find()
  326 + ->where([ 'id' => $orderId ])
  327 + ->one();
  328 + if (empty($order)) {
  329 + throw new NotFoundHttpException(\Yii::t('order', 'Order not found'));
  330 + }
  331 + /**
  332 + * @var Variant $variant
  333 + */
  334 + $variant = Variant::find()
  335 + ->where([ 'id' => $id ])
  336 + ->one();
  337 + if (empty($variant)) {
  338 + throw new NotFoundHttpException(\Yii::t('order', 'Variant not found'));
  339 + }
  340 + /**
  341 + * @var OrderProduct $model
  342 + */
  343 + $model = OrderProduct::find()
  344 + ->where(
  345 + [
  346 + 'order_id' => $orderId,
  347 + 'variant_id' => $id,
  348 + ]
  349 + )
  350 + ->one();
  351 + if ($model) {
  352 + $model->count += $count;
  353 + } else {
  354 + $model = new OrderProduct(
  355 + [
  356 + 'order_id' => $orderId,
  357 + 'variant_id' => $id,
  358 + 'sku' => $variant->sku,
  359 + 'price' => $variant->price,
  360 + 'count' => $count,
  361 + ]
  362 + );
  363 + }
  364 + $model->save();
  365 + }
  366 +
264 /** 367 /**
265 * Finds the Order model based on its primary key value. 368 * Finds the Order model based on its primary key value.
266 * If the model is not found, a 404 HTTP exception will be thrown. 369 * If the model is not found, a 404 HTTP exception will be thrown.
models/OrderProduct.php
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 4
5 use artbox\catalog\models\Variant; 5 use artbox\catalog\models\Variant;
6 use Yii; 6 use Yii;
  7 + use yii\helpers\ArrayHelper;
7 8
8 /** 9 /**
9 * This is the model class for table "order_product". 10 * This is the model class for table "order_product".
@@ -105,4 +106,74 @@ @@ -105,4 +106,74 @@
105 { 106 {
106 return $this->hasOne(Variant::className(), [ 'id' => 'variant_id' ]); 107 return $this->hasOne(Variant::className(), [ 'id' => 'variant_id' ]);
107 } 108 }
  109 +
  110 + /**
  111 + * @param array $items
  112 + * @param int $orderId
  113 + *
  114 + * @return \artbox\order\models\OrderProduct[]
  115 + */
  116 + public static function saveItems(array $items, int $orderId): array
  117 + {
  118 + $variantIds = ArrayHelper::getColumn($items, 'variant_id', false);
  119 + /**
  120 + * @var \artbox\order\models\OrderProduct[] $deletion
  121 + */
  122 + $deletion = self::find()
  123 + ->where(
  124 + [
  125 + 'not',
  126 + [ 'variant_id' => $variantIds ],
  127 + ]
  128 + )
  129 + ->andWhere([ 'order_id' => $orderId ])
  130 + ->all();
  131 + foreach ($deletion as $record) {
  132 + $record->delete();
  133 + }
  134 + /**
  135 + * @var \artbox\order\models\OrderProduct[] $orderProducts
  136 + */
  137 + $orderProducts = self::find()
  138 + ->where(
  139 + [
  140 + 'variant_id' => $variantIds,
  141 + 'order_id' => $orderId,
  142 + ]
  143 + )
  144 + ->all();
  145 + $newItems = [];
  146 + foreach ($items as $item) {
  147 + $id = $item[ 'variant_id' ];
  148 + $count = $item[ 'count' ];
  149 + foreach ($orderProducts as $orderProduct) {
  150 + if ($orderProduct->variant_id == $id) {
  151 + $orderProduct->count = $count;
  152 + break 2;
  153 + }
  154 + }
  155 + /**
  156 + * @var Variant $variant
  157 + */
  158 + $variant = Variant::find()
  159 + ->where([ 'id' => $id ])
  160 + ->one();
  161 + if ($variant) {
  162 + $newItems[] = new OrderProduct(
  163 + [
  164 + 'order_id' => $orderId,
  165 + 'variant_id' => $id,
  166 + 'sku' => $variant->sku,
  167 + 'price' => $variant->price,
  168 + 'count' => $count,
  169 + ]
  170 + );
  171 + }
  172 + }
  173 + $orderProducts = array_merge($orderProducts, $newItems);
  174 + foreach ($orderProducts as $orderProduct) {
  175 + $orderProduct->save();
  176 + }
  177 + return $orderProducts;
  178 + }
108 } 179 }
views/order/_form.php
1 <?php 1 <?php
2 2
  3 + use kartik\select2\Select2;
3 use yii\bootstrap\Html; 4 use yii\bootstrap\Html;
  5 + use yii\helpers\Url;
  6 + use yii\web\JsExpression;
4 use yii\widgets\ActiveForm; 7 use yii\widgets\ActiveForm;
5 8
6 /** 9 /**
@@ -54,72 +57,129 @@ @@ -54,72 +57,129 @@
54 if (!$model->isNewRecord) { 57 if (!$model->isNewRecord) {
55 ?> 58 ?>
56 <div class="order-product-container"> 59 <div class="order-product-container">
57 - <div class="row strong">  
58 - <div class="col-md-4"> 60 + <div id="order-product-pjax" style="position: relative;">
  61 + <div class="row strong">
  62 + <div class="col-md-4">
  63 + <?php
  64 + echo Html::tag('strong', \Yii::t('order', 'Product'));
  65 + ?>
  66 + </div>
  67 + <div class="col-md-4">
  68 + <?php
  69 + echo Html::tag('strong', \Yii::t('order', 'Price'));
  70 + ?>
  71 + </div>
  72 + <div class="col-md-4">
  73 + <?php
  74 + echo Html::tag('strong', \Yii::t('order', 'Count'));
  75 + ?>
  76 + </div>
  77 + </div>
  78 +
  79 + <?php
  80 + foreach ($model->orderProducts as $index => $orderProduct) {
  81 + ?>
  82 + <div class="row row-order-product">
  83 + <div class="col-md-4">
  84 + <?php
  85 + echo $form->field($orderProduct, "[$index]variant_id")
  86 + ->hiddenInput()
  87 + ->label(false);
  88 + echo $orderProduct->variant->product->lang->title . '(' . $orderProduct->variant->sku . ')';
  89 + ?>
  90 + </div>
  91 + <div class="col-md-4">
  92 + <?php echo $orderProduct->price; ?>
  93 + </div>
  94 + <div class="col-md-3">
  95 + <?php
  96 + echo $form->field($orderProduct, "[$index]count")
  97 + ->textInput()
  98 + ->label(false);
  99 + ?>
  100 + </div>
  101 + <div class="col-md-1">
  102 + <?php
  103 + echo Html::a(
  104 + Html::icon(
  105 + 'trash-o',
  106 + [
  107 + 'prefix' => 'fa fa-',
  108 + ]
  109 + ),
  110 + '#',
  111 + [
  112 + 'class' => 'remove-order-product',
  113 + ]
  114 + )
  115 + ?>
  116 + </div>
  117 + </div>
  118 + <?php
  119 + }
  120 + ?>
  121 + </div>
  122 + <div class="row">
  123 + <div class="col-md-8">
59 <?php 124 <?php
60 - echo Html::tag('strong', \Yii::t('order', 'Product')); 125 + echo Select2::widget(
  126 + [
  127 + 'name' => 'add-to-order',
  128 + 'options' => [
  129 + 'placeholder' => \Yii::t('order', 'Select product'),
  130 + ],
  131 + 'pluginOptions' => [
  132 + 'allowClear' => true,
  133 + 'minimumInputLength' => 3,
  134 + 'language' => [
  135 + 'errorLoading' => new JsExpression(
  136 + "function() {return '" . \Yii::t('order', 'Waiting for results') . "'; }"
  137 + ),
  138 + ],
  139 + 'ajax' => [
  140 + 'url' => Url::to([ 'product-list' ]),
  141 + 'dataType' => 'json',
  142 + 'data' => new JsExpression('function(params) { return {q:params.term}; }'),
  143 + ],
  144 + 'escapeMarkup' => new JsExpression('function (markup) { return markup; }'),
  145 + 'templateResult' => new JsExpression('function(city) { return city.text; }'),
  146 + 'templateSelection' => new JsExpression('function (city) { return city.text; }'),
  147 + ],
  148 + 'id' => 'add-to-order',
  149 + ]
  150 + );
61 ?> 151 ?>
62 </div> 152 </div>
63 - <div class="col-md-4"> 153 + <div class="col-md-3">
64 <?php 154 <?php
65 - echo Html::tag('strong', \Yii::t('order', 'Price')); 155 + echo Html::textInput(
  156 + 'count-to-order',
  157 + null,
  158 + [
  159 + 'class' => 'form-control',
  160 + 'id' => 'count-to-order',
  161 + ]
  162 + );
66 ?> 163 ?>
67 </div> 164 </div>
68 - <div class="col-md-4"> 165 + <div class="col-md-1">
69 <?php 166 <?php
70 - echo Html::tag('strong', \Yii::t('order', 'Count')); 167 + echo Html::a(
  168 + Html::icon(
  169 + 'plus-circle',
  170 + [
  171 + 'prefix' => 'fa fa-',
  172 + ]
  173 + ),
  174 + '#',
  175 + [
  176 + 'class' => 'variant-to-order',
  177 + 'data-id' => $model->id,
  178 + ]
  179 + );
71 ?> 180 ?>
72 </div> 181 </div>
73 </div> 182 </div>
74 -  
75 - <?php  
76 - foreach ($model->orderProducts as $index => $orderProduct) {  
77 - ?>  
78 - <div class="row row-order-product">  
79 - <div class="col-md-4">  
80 - <?php  
81 - echo $form->field($orderProduct, "[$index]variant_id")  
82 - ->hiddenInput()  
83 - ->label(false);  
84 - echo $orderProduct->variant->product->lang->title . '(' . $orderProduct->variant->sku . ')';  
85 - ?>  
86 - </div>  
87 - <div class="col-md-4">  
88 - <?php echo $orderProduct->price; ?>  
89 - </div>  
90 - <div class="col-md-3">  
91 - <?php  
92 - echo $form->field($orderProduct, "[$index]count")  
93 - ->textInput()  
94 - ->label(false);  
95 - ?>  
96 - </div>  
97 - <div class="col-md-1">  
98 - <?php  
99 - echo Html::a(  
100 - Html::icon(  
101 - 'trash-o',  
102 - [  
103 - 'prefix' => 'fa fa-',  
104 - ]  
105 - ),  
106 - '#',  
107 - [  
108 - 'class' => 'remove-order-product',  
109 - ]  
110 - )  
111 - ?>  
112 - </div>  
113 - </div>  
114 - <?php  
115 - }  
116 - ?>  
117 - <div class="row">  
118 - <div class="col-md-8">  
119 - </div>  
120 - <div class="col-md-4">  
121 - </div>  
122 - </div>  
123 </div> 183 </div>
124 <?php 184 <?php
125 } 185 }
@@ -6,4 +6,34 @@ $(function() { @@ -6,4 +6,34 @@ $(function() {
6 .parents('.row-order-product') 6 .parents('.row-order-product')
7 .remove(); 7 .remove();
8 }); 8 });
9 -});  
10 \ No newline at end of file 9 \ No newline at end of file
  10 + $(document)
  11 + .on('click', '.variant-to-order', function(e) {
  12 + e.preventDefault();
  13 + var id = $('#add-to-order');
  14 + var count = $('#count-to-order');
  15 + var order = $(this)
  16 + .data('id');
  17 + if (id.val() && count.val()) {
  18 + var selector = '#order-product-pjax';
  19 + showLoader(selector);
  20 + $.post('/admin/order/add-to-order', {
  21 + id: id.val(),
  22 + count: count.val(),
  23 + order: order
  24 + }, function() {
  25 + $.pjax.reload(selector, {
  26 + timeout: 5000,
  27 + fragment: selector
  28 + });
  29 + });
  30 + id.val(null)
  31 + .trigger('change');
  32 + count.val(null)
  33 + .trigger('change');
  34 + }
  35 + });
  36 +});
  37 +function showLoader(container) {
  38 + $(container)
  39 + .prepend('<div class="loader-wrapper"></div>');
  40 +}
11 \ No newline at end of file 41 \ No newline at end of file