Commit 6c8e3423c3e98a9c21fa11c1f719c227645e5784

Authored by Yarik
1 parent fb14ea2a

Fast buy

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   - &emsp;<button class="btn btn-template-main">
218   - <i class="fa fa-tags"></i> Купить в кредит
219   - </button>
  233 + &emsp;<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">&times;</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>');
... ...