Commit 6c8e3423c3e98a9c21fa11c1f719c227645e5784
1 parent
fb14ea2a
Fast buy
Showing
4 changed files
with
317 additions
and
163 deletions
Show diff stats
frontend/controllers/CheckoutController.php
... | ... | @@ -174,6 +174,33 @@ |
174 | 174 | ] |
175 | 175 | ); |
176 | 176 | } |
177 | + | |
178 | + public function actionFast() | |
179 | + { | |
180 | + $this->enableCsrfValidation = false; | |
181 | + $response = \Yii::$app->response; | |
182 | + $response->format = $response::FORMAT_JSON; | |
183 | + $model = new Order( | |
184 | + [ | |
185 | + 'scenario' => Order::SCENARIO_FAST, | |
186 | + ] | |
187 | + ); | |
188 | + if ($model->load(\Yii::$app->request->post())) { | |
189 | + $model->label_id = 1; | |
190 | + $model->delivery_id = 5; | |
191 | + $model->payment_id = 3; | |
192 | + if ($model->save()) { | |
193 | + return [ | |
194 | + 'success' => true, | |
195 | + 'msg' => \Yii::t( | |
196 | + 'app', | |
197 | + 'Заказ успешно оформлен. Вашему заказу присвоен номер ' . $model->id . '.' | |
198 | + ), | |
199 | + ]; | |
200 | + } | |
201 | + } | |
202 | + return $model->getErrors(); | |
203 | + } | |
177 | 204 | |
178 | 205 | public function beforeAction($action) |
179 | 206 | { |
... | ... | @@ -181,7 +208,7 @@ |
181 | 208 | * @var \artbox\order\models\Basket $basket |
182 | 209 | */ |
183 | 210 | $basket = \Yii::$app->get('basket'); |
184 | - if ($action->id !== 'index' && empty($basket->getData())) { | |
211 | + if ($action->id !== 'index' && $action->id !== 'fast' && empty($basket->getData())) { | |
185 | 212 | return $this->redirect([ 'site/index' ]); |
186 | 213 | } |
187 | 214 | return parent::beforeAction($action); | ... | ... |
frontend/models/Order.php
1 | 1 | <?php |
2 | 2 | |
3 | 3 | namespace frontend\models; |
4 | - | |
4 | + | |
5 | + use artbox\catalog\models\Variant; | |
5 | 6 | use artbox\order\models\Delivery; |
6 | 7 | use artbox\order\models\Payment; |
7 | - | |
8 | + | |
8 | 9 | class Order extends \artbox\order\models\Order |
9 | 10 | { |
11 | + public $variantId; | |
12 | + | |
10 | 13 | const SCENARIO_INFO = 'info'; |
11 | 14 | const SCENARIO_DELIVERY = 'delivery'; |
12 | 15 | const SCENARIO_PAYMENT = 'payment'; |
13 | 16 | const SCENARIO_CONFIRM = 'confirm'; |
14 | - | |
17 | + const SCENARIO_FAST = 'fast'; | |
18 | + | |
15 | 19 | /** |
16 | 20 | * @inheritdoc |
17 | 21 | */ |
... | ... | @@ -34,10 +38,15 @@ |
34 | 38 | self::SCENARIO_PAYMENT => [ |
35 | 39 | 'payment_id', |
36 | 40 | ], |
41 | + self::SCENARIO_FAST => [ | |
42 | + 'name', | |
43 | + 'phone', | |
44 | + 'variantId', | |
45 | + ], | |
37 | 46 | ] |
38 | 47 | ); |
39 | 48 | } |
40 | - | |
49 | + | |
41 | 50 | /** |
42 | 51 | * @inheritdoc |
43 | 52 | */ |
... | ... | @@ -51,6 +60,7 @@ |
51 | 60 | 'email', |
52 | 61 | 'delivery_id', |
53 | 62 | 'payment_id', |
63 | + 'variantId', | |
54 | 64 | ], |
55 | 65 | 'required', |
56 | 66 | ], |
... | ... | @@ -94,9 +104,37 @@ |
94 | 104 | 'targetClass' => Payment::className(), |
95 | 105 | 'targetAttribute' => 'id', |
96 | 106 | ], |
107 | + [ | |
108 | + [ | |
109 | + 'variant_id', | |
110 | + ], | |
111 | + 'exist', | |
112 | + 'targetClass' => Variant::className(), | |
113 | + 'targetAttribute' => 'id', | |
114 | + 'filter' => function ($query) { | |
115 | + /** | |
116 | + * @var \yii\db\Query $query | |
117 | + */ | |
118 | + $query->andWhere( | |
119 | + [ | |
120 | + '>', | |
121 | + 'price', | |
122 | + 0, | |
123 | + ] | |
124 | + ) | |
125 | + ->andWhere([ 'status' => true ]) | |
126 | + ->andWhere( | |
127 | + [ | |
128 | + '>', | |
129 | + 'stock', | |
130 | + 0, | |
131 | + ] | |
132 | + ); | |
133 | + }, | |
134 | + ], | |
97 | 135 | ]; |
98 | 136 | } |
99 | - | |
137 | + | |
100 | 138 | /** |
101 | 139 | * Save active attributes to session variable 'order' |
102 | 140 | */ |
... | ... | @@ -108,7 +146,7 @@ |
108 | 146 | } |
109 | 147 | \Yii::$app->session[ 'order' ] = $order; |
110 | 148 | } |
111 | - | |
149 | + | |
112 | 150 | /** |
113 | 151 | * Load active attributes from session variable 'order' |
114 | 152 | */ | ... | ... |
frontend/views/product/view.php
... | ... | @@ -4,6 +4,8 @@ |
4 | 4 | use artbox\catalog\models\Variant; |
5 | 5 | use artbox\core\components\SeoComponent; |
6 | 6 | use artbox\core\helpers\ImageHelper; |
7 | + use frontend\models\Order; | |
8 | + use yii\bootstrap\ActiveForm; | |
7 | 9 | use yii\bootstrap\Html; |
8 | 10 | use yii\helpers\ArrayHelper; |
9 | 11 | use yii\web\View; |
... | ... | @@ -209,14 +211,28 @@ |
209 | 211 | </p> |
210 | 212 | <hr> |
211 | 213 | <?php |
214 | + echo Html::a( | |
215 | + Html::icon( | |
216 | + 'phone', | |
217 | + [ | |
218 | + 'prefix' => 'fa fa-', | |
219 | + ] | |
220 | + ) . \Yii::t('app', 'Купить в один клик'), | |
221 | + '#', | |
222 | + [ | |
223 | + 'data' => [ | |
224 | + 'toggle' => 'modal', | |
225 | + 'target' => '#oneclick-modal', | |
226 | + ], | |
227 | + 'class' => 'btn btn-template-main', | |
228 | + ] | |
229 | + ) | |
230 | + ?> | |
231 | + <?php | |
212 | 232 | /* |
213 | - ?> | |
214 | - <button class="btn btn-template-main"> | |
215 | - <i class="fa fa-phone"></i> Купить в один клик | |
216 | - </button> | |
217 | -  <button class="btn btn-template-main"> | |
218 | - <i class="fa fa-tags"></i> Купить в кредит | |
219 | - </button> | |
233 | +  <button class="btn btn-template-main"> | |
234 | + <i class="fa fa-tags"></i> Купить в кредит | |
235 | + </button> | |
220 | 236 | */ |
221 | 237 | ?> |
222 | 238 | </div> |
... | ... | @@ -311,3 +327,65 @@ |
311 | 327 | <!-- /.container --> |
312 | 328 | </div> |
313 | 329 | <!-- /#content --> |
330 | +<div class="modal fade" id="oneclick-modal" tabindex="-1" role="dialog"> | |
331 | + <div class="modal-dialog modal-sm"> | |
332 | + | |
333 | + <div class="modal-content"> | |
334 | + <div class="modal-header"> | |
335 | + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | |
336 | + <h4 class="modal-title callback"><?php echo \Yii::t('app', 'Купить в один клик'); ?></h4> | |
337 | + </div> | |
338 | + <div class="modal-body"> | |
339 | + <?php | |
340 | + $order = new Order( | |
341 | + [ | |
342 | + 'scenario' => Order::SCENARIO_FAST, | |
343 | + 'variantId' => $variant->id, | |
344 | + ] | |
345 | + ); | |
346 | + $form = ActiveForm::begin( | |
347 | + [ | |
348 | + 'action' => [ 'checkout/fast' ], | |
349 | + 'id' => 'fast-buy-form', | |
350 | + ] | |
351 | + ); | |
352 | + echo $form->field($order, 'variantId') | |
353 | + ->label(false) | |
354 | + ->hiddenInput(); | |
355 | + echo $form->field($order, 'name') | |
356 | + ->label(false) | |
357 | + ->textInput( | |
358 | + [ | |
359 | + 'placeholder' => $order->getAttributeLabel('name'), | |
360 | + ] | |
361 | + ); | |
362 | + echo $form->field($order, 'phone') | |
363 | + ->label(false) | |
364 | + ->textInput( | |
365 | + [ | |
366 | + 'placeholder' => $order->getAttributeLabel('phone'), | |
367 | + ] | |
368 | + ); | |
369 | + echo Html::tag( | |
370 | + 'p', | |
371 | + Html::submitButton( | |
372 | + Html::icon( | |
373 | + 'shopping-cart', | |
374 | + [ | |
375 | + 'prefix' => 'fa fa-', | |
376 | + ] | |
377 | + ) . \Yii::t('app', ' Отправить'), | |
378 | + [ | |
379 | + 'class' => 'btn btn-template-main', | |
380 | + ] | |
381 | + ), | |
382 | + [ | |
383 | + 'class' => 'text-center', | |
384 | + ] | |
385 | + ); | |
386 | + $form::end(); | |
387 | + ?> | |
388 | + </div> | |
389 | + </div> | |
390 | + </div> | |
391 | +</div> | ... | ... |
frontend/web/js/script.js
1 | -$( | |
2 | - function() { | |
3 | - var basket = new ArtboxBasket({ | |
4 | - 'cartSelector': '#cart' | |
5 | - }); | |
6 | - /** | |
7 | - * Modal form submit code | |
8 | - */ | |
9 | - $(document) | |
10 | - .on( | |
11 | - 'beforeSubmit', '#feedback-form', function(e) { | |
12 | - var f = this; | |
13 | - var form = $(this); | |
14 | - var formData = form.serialize(); | |
15 | - $.ajax( | |
16 | - { | |
17 | - url: form.attr("action"), | |
18 | - type: form.attr("method"), | |
19 | - data: formData, | |
20 | - success: function(data) { | |
21 | - f.reset(); | |
22 | - $('#feedback-modal') | |
23 | - .modal('hide'); | |
24 | - $('#success-modal') | |
25 | - .modal('show'); | |
26 | - }, | |
27 | - error: function() { | |
28 | - $('#feedback-modal') | |
29 | - .modal('hide'); | |
30 | - } | |
31 | - } | |
32 | - ); | |
33 | - } | |
34 | - ) | |
35 | - .on( | |
36 | - 'submit', '#feedback-form', function(e) { | |
37 | - e.preventDefault(); | |
1 | +$(function() { | |
2 | + var basket = new ArtboxBasket({ | |
3 | + 'cartSelector': '#cart' | |
4 | + }); | |
5 | + /** | |
6 | + * Modal form submit code | |
7 | + */ | |
8 | + $(document) | |
9 | + .on('beforeSubmit', '#feedback-form', function(e) { | |
10 | + var f = this; | |
11 | + var form = $(this); | |
12 | + var formData = form.serialize(); | |
13 | + $.ajax({ | |
14 | + url: form.attr("action"), | |
15 | + type: form.attr("method"), | |
16 | + data: formData, | |
17 | + success: function(data) { | |
18 | + f.reset(); | |
19 | + $('#feedback-modal') | |
20 | + .modal('hide'); | |
21 | + $('#success-modal') | |
22 | + .modal('show'); | |
23 | + }, | |
24 | + error: function() { | |
25 | + $('#feedback-modal') | |
26 | + .modal('hide'); | |
38 | 27 | } |
39 | - ); | |
28 | + }); | |
29 | + }) | |
30 | + .on('submit', '#feedback-form', function(e) { | |
31 | + e.preventDefault(); | |
32 | + }); | |
40 | 33 | |
41 | - /** | |
42 | - * Contact form submitting | |
43 | - */ | |
44 | - $(document) | |
45 | - .on( | |
46 | - 'beforeSubmit', '#contact-form', function(e) { | |
47 | - var f = this; | |
48 | - var form = $(this); | |
49 | - var formData = form.serialize(); | |
50 | - $.ajax( | |
51 | - { | |
52 | - url: form.attr("action"), | |
53 | - type: form.attr("method"), | |
54 | - data: formData, | |
55 | - success: function(data) { | |
56 | - f.reset(); | |
57 | - form.replaceWith(data.alert); | |
58 | - }, | |
59 | - error: function() { | |
34 | + /** | |
35 | + * Contact form submitting | |
36 | + */ | |
37 | + $(document) | |
38 | + .on('beforeSubmit', '#contact-form', function(e) { | |
39 | + var f = this; | |
40 | + var form = $(this); | |
41 | + var formData = form.serialize(); | |
42 | + $.ajax({ | |
43 | + url: form.attr("action"), | |
44 | + type: form.attr("method"), | |
45 | + data: formData, | |
46 | + success: function(data) { | |
47 | + f.reset(); | |
48 | + form.replaceWith(data.alert); | |
49 | + }, | |
50 | + error: function() { | |
60 | 51 | |
61 | - } | |
62 | - } | |
63 | - ); | |
64 | 52 | } |
65 | - ) | |
66 | - .on( | |
67 | - 'submit', '#contact-form', function(e) { | |
68 | - e.preventDefault(); | |
69 | - } | |
70 | - ); | |
71 | - | |
72 | - /** | |
73 | - * Button UP code | |
74 | - */ | |
75 | - if ($('#back-to-top').length) { | |
76 | - var scrollTrigger = 100, // px | |
77 | - backToTop = function() { | |
78 | - var scrollTop = $(window) | |
79 | - .scrollTop(); | |
80 | - if (scrollTop > scrollTrigger) { | |
81 | - $('#back-to-top') | |
82 | - .addClass('show'); | |
83 | - } else { | |
84 | - $('#back-to-top') | |
85 | - .removeClass('show'); | |
86 | - } | |
87 | - }; | |
88 | - backToTop(); | |
89 | - $(window) | |
90 | - .on( | |
91 | - 'scroll', function() { | |
92 | - backToTop(); | |
93 | - } | |
94 | - ); | |
95 | - $('#back-to-top') | |
96 | - .on( | |
97 | - 'click', function(e) { | |
98 | - e.preventDefault(); | |
99 | - $('html,body') | |
100 | - .animate( | |
101 | - { | |
102 | - scrollTop: 0 | |
103 | - }, 700 | |
104 | - ); | |
105 | - } | |
106 | - ); | |
107 | - } | |
53 | + }); | |
54 | + }) | |
55 | + .on('submit', '#contact-form', function(e) { | |
56 | + e.preventDefault(); | |
57 | + }); | |
108 | 58 | |
109 | - $(document) | |
110 | - .on('click', '.add-to-basket', function(e) { | |
111 | - e.preventDefault(); | |
112 | - var id = $(this) | |
113 | - .data('id'); | |
114 | - basket.add(id, 1); | |
115 | - if ($('.alert-cart').length > 0) { | |
59 | + /** | |
60 | + * Button UP code | |
61 | + */ | |
62 | + if ($('#back-to-top').length) { | |
63 | + var scrollTrigger = 100, // px | |
64 | + backToTop = function() { | |
65 | + var scrollTop = $(window) | |
66 | + .scrollTop(); | |
67 | + if (scrollTop > scrollTrigger) { | |
68 | + $('#back-to-top') | |
69 | + .addClass('show'); | |
116 | 70 | } else { |
117 | - $('body').prepend($("<div class='alert-cart alert alert-success alert-dismissible'>Товар добавлен в корзину.</div>")); | |
118 | - setTimeout(function(){$(".alert-cart").addClass("active");},100); | |
119 | - setTimeout(function(){$(".alert-cart").removeClass("active");},3500); | |
120 | - setTimeout(function(){$(".alert-cart").remove();},3600); | |
71 | + $('#back-to-top') | |
72 | + .removeClass('show'); | |
121 | 73 | } |
74 | + }; | |
75 | + backToTop(); | |
76 | + $(window) | |
77 | + .on('scroll', function() { | |
78 | + backToTop(); | |
122 | 79 | }); |
123 | - | |
124 | - $(document) | |
125 | - .on('click', '.remove-product-cart', function(e) { | |
80 | + $('#back-to-top') | |
81 | + .on('click', function(e) { | |
126 | 82 | e.preventDefault(); |
127 | - var id = $(this) | |
128 | - .parents('.product-row-basket') | |
129 | - .data('id'); | |
130 | - showLoader('#basket'); | |
131 | - var xhr = basket.remove(id); | |
132 | - xhr.done(function() { | |
133 | - $.pjax.reload({ | |
134 | - container: '#basket', | |
135 | - fragment: '#basket', | |
136 | - timeout: 5000 | |
137 | - }); | |
138 | - }) | |
83 | + $('html,body') | |
84 | + .animate({ | |
85 | + scrollTop: 0 | |
86 | + }, 700); | |
139 | 87 | }); |
88 | + } | |
89 | + | |
90 | + $(document) | |
91 | + .on('click', '.add-to-basket', function(e) { | |
92 | + e.preventDefault(); | |
93 | + var id = $(this) | |
94 | + .data('id'); | |
95 | + basket.add(id, 1); | |
96 | + if ($('.alert-cart').length > 0) { | |
97 | + } else { | |
98 | + $('body') | |
99 | + .prepend($("<div class='alert-cart alert alert-success alert-dismissible'>Товар добавлен в корзину.</div>")); | |
100 | + setTimeout(function() { | |
101 | + $(".alert-cart") | |
102 | + .addClass("active"); | |
103 | + }, 100); | |
104 | + setTimeout(function() { | |
105 | + $(".alert-cart") | |
106 | + .removeClass("active"); | |
107 | + }, 3500); | |
108 | + setTimeout(function() { | |
109 | + $(".alert-cart") | |
110 | + .remove(); | |
111 | + }, 3600); | |
112 | + } | |
113 | + }); | |
140 | 114 | |
141 | - $(document) | |
142 | - .on('change', '.increase-product-basket', function(e) { | |
143 | - var id = $(this) | |
144 | - .parents('.product-row-basket') | |
145 | - .data('id'); | |
146 | - showLoader('#basket'); | |
147 | - var xhr = basket.set(id, $(this) | |
148 | - .val()); | |
149 | - xhr.done(function() { | |
150 | - $.pjax.reload({ | |
151 | - container: '#basket', | |
152 | - fragment: '#basket', | |
153 | - timeout: 5000 | |
154 | - }); | |
115 | + $(document) | |
116 | + .on('click', '.remove-product-cart', function(e) { | |
117 | + e.preventDefault(); | |
118 | + var id = $(this) | |
119 | + .parents('.product-row-basket') | |
120 | + .data('id'); | |
121 | + showLoader('#basket'); | |
122 | + var xhr = basket.remove(id); | |
123 | + xhr.done(function() { | |
124 | + $.pjax.reload({ | |
125 | + container: '#basket', | |
126 | + fragment: '#basket', | |
127 | + timeout: 5000 | |
155 | 128 | }); |
156 | - }); | |
129 | + }) | |
130 | + }); | |
157 | 131 | |
158 | - $(document) | |
159 | - .on('click', 'li.disabled a', function(e) { | |
160 | - e.preventDefault(); | |
132 | + $(document) | |
133 | + .on('change', '.increase-product-basket', function(e) { | |
134 | + var id = $(this) | |
135 | + .parents('.product-row-basket') | |
136 | + .data('id'); | |
137 | + showLoader('#basket'); | |
138 | + var xhr = basket.set(id, $(this) | |
139 | + .val()); | |
140 | + xhr.done(function() { | |
141 | + $.pjax.reload({ | |
142 | + container: '#basket', | |
143 | + fragment: '#basket', | |
144 | + timeout: 5000 | |
145 | + }); | |
161 | 146 | }); |
162 | - } | |
163 | -); | |
147 | + }); | |
148 | + | |
149 | + $(document) | |
150 | + .on('click', 'li.disabled a', function(e) { | |
151 | + e.preventDefault(); | |
152 | + }); | |
153 | + | |
154 | + $(document) | |
155 | + .on('submit', '#fast-buy-form', function(e) { | |
156 | + e.preventDefault(); | |
157 | + }); | |
158 | + | |
159 | + $(document) | |
160 | + .on('afterValidate', '#fast-buy-form', function(e, m, errors) { | |
161 | + if (!errors.length) { | |
162 | + var form = $(e.target); | |
163 | + var action = form.attr('action'); | |
164 | + $.post(action, form.serialize(), function(data) { | |
165 | + if (data.success) { | |
166 | + $('#oneclick-modal') | |
167 | + .find('.modal-body') | |
168 | + .text(data.msg); | |
169 | + } | |
170 | + }); | |
171 | + } | |
172 | + }.bind(this)); | |
173 | + | |
174 | +}); | |
164 | 175 | function showLoader(container) { |
165 | 176 | $(container) |
166 | 177 | .prepend('<div class="loader-wrapper"><div class="loader"></div></div>'); | ... | ... |