solidus_frontend 2.7.4 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_frontend might be problematic. Click here for more details.

Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -5
  3. data/app/assets/images/favicon.ico +0 -0
  4. data/app/assets/javascripts/spree/frontend/checkout/coupon-code.js +1 -1
  5. data/app/assets/stylesheets/spree/frontend/screen.css.scss +3 -0
  6. data/app/controllers/spree/checkout_controller.rb +19 -0
  7. data/app/controllers/spree/coupon_codes_controller.rb +35 -0
  8. data/app/controllers/spree/locale_controller.rb +1 -1
  9. data/app/controllers/spree/orders_controller.rb +1 -0
  10. data/app/views/spree/checkout/_coupon_code.html.erb +1 -1
  11. data/app/views/spree/checkout/_delivery.html.erb +6 -2
  12. data/app/views/spree/coupon_codes/new.html.erb +6 -0
  13. data/app/views/spree/orders/_form.html.erb +1 -1
  14. data/app/views/spree/orders/_line_item.html.erb +3 -5
  15. data/app/views/spree/orders/edit.html.erb +5 -6
  16. data/app/views/spree/products/_image.html.erb +4 -1
  17. data/app/views/spree/products/_thumbnails.html.erb +10 -8
  18. data/app/views/spree/shared/_image.html.erb +4 -4
  19. data/app/views/spree/shared/_locale_selector.html.erb +1 -1
  20. data/app/views/spree/shared/_order_details.html.erb +3 -5
  21. data/app/views/spree/shared/_products.html.erb +1 -1
  22. data/config/routes.rb +1 -0
  23. data/lib/spree/frontend.rb +1 -1
  24. data/solidus_frontend.gemspec +1 -1
  25. data/spec/controllers/spree/checkout_controller_spec.rb +50 -6
  26. data/spec/controllers/spree/orders_controller_ability_spec.rb +0 -3
  27. data/spec/controllers/spree/orders_controller_spec.rb +4 -0
  28. data/spec/controllers/spree/products_controller_spec.rb +3 -3
  29. data/spec/controllers/spree/taxons_controller_spec.rb +1 -1
  30. data/spec/features/checkout_confirm_insufficient_stock_spec.rb +71 -0
  31. data/spec/features/checkout_spec.rb +1 -1
  32. data/spec/features/coupon_code_spec.rb +14 -14
  33. data/spec/features/promotion_code_invalidation_spec.rb +2 -2
  34. data/spec/features/quantity_promotions_spec.rb +9 -9
  35. data/spec/spec_helper.rb +1 -0
  36. data/spec/support/features/fill_in_with_force.rb +12 -0
  37. metadata +13 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00062dc677a13db89d2fb4be6fb5ed6ac401b2ac53a945e4b52b5f446978f229
4
- data.tar.gz: d93e7e1a27f66ca24eccb640752ce1e291c5592f0f382326782297793a61d3dc
3
+ metadata.gz: 0b78e6782c7aaf5de2799b93c100eb97e8431a5e9b865fcc202886e8c28cc008
4
+ data.tar.gz: 1e17148b86ae7d09454ecb6f8fe5b4589324d75b35cdc5aa410a33318df27db4
5
5
  SHA512:
6
- metadata.gz: 668601be08adae947f79f9235383de4522247fcc280e976bb0b357358d0ea4c23a8ae14502801d0aae7dbf4209a51a554712ed4b5c1d61574876b9701b2c1e7e
7
- data.tar.gz: d5dee3b13d029a6c6dc4a4df7614e10681ac8d55bc4c38b1063002691ee0f7c5342c11f4c812c4af3a0a8dca58db8018d7f8eb23c9474f42dcc3d13c9eb1671e
6
+ metadata.gz: 5267cc2ab0c37977c64c5aad4be7643a7bb45fc6368826632c012b3945fd3f1dfe4f47586c8a805c6e229b0317c505f663a44d685b788efae1df9f9784e768bf
7
+ data.tar.gz: 61d8f2a41bdacb457fd500965e9308996b5f005d049a2ee5a4b012d437b649510509d54ec87be3bbdb7f829e88d03ba5de6001d0614357bef01311c6c5cb1634
data/README.md CHANGED
@@ -11,19 +11,19 @@ Solidus provides a generator to help with copying the right view into your host
11
11
 
12
12
  Simply call the generator to copy all views into your host app.
13
13
 
14
- ```shell
14
+ ```bash
15
15
  $ bundle exec rails g solidus:views:override
16
16
  ```
17
17
 
18
18
  If you only want to copy certain views into your host app, you can provide the `--only` argument:
19
19
 
20
- ```shell
20
+ ```bash
21
21
  $ bundle exec rails g solidus:views:override --only products/show
22
22
  ```
23
23
 
24
24
  The argument to `--only` can also be a substring of the name of the view from the `app/views/spree` folder:
25
25
 
26
- ```shell
26
+ ```bash
27
27
  $ bundle exec rails g solidus:views:override --only product
28
28
  ```
29
29
 
@@ -31,10 +31,12 @@ This will copy all views whose directory or filename contains the string "produc
31
31
 
32
32
  ### Handle upgrades
33
33
 
34
- After upgrading solidus to a new version run the generator again and follow on screen instructions.
34
+ After upgrading Solidus to a new version run the generator again and follow on screen instructions.
35
35
 
36
36
  ## Testing
37
37
 
38
38
  Run the tests
39
39
 
40
- bundle exec rspec
40
+ ```bash
41
+ bundle exec rspec
42
+ ```
@@ -14,7 +14,7 @@ Spree.onCouponCodeApply = function(e) {
14
14
  coupon_code: couponCode
15
15
  };
16
16
  var req = Spree.ajax({
17
- method: "PUT",
17
+ method: 'POST',
18
18
  url: Spree.routes.apply_coupon_code(Spree.current_order_id),
19
19
  data: JSON.stringify(data),
20
20
  contentType: "application/json"
@@ -1092,6 +1092,9 @@ div[data-hook="inside_cart_form"] {
1092
1092
  /*--------------------------------------*/
1093
1093
  #order_summary {
1094
1094
  margin-top: 0;
1095
+ h1 {
1096
+ padding-left: 10px;
1097
+ }
1095
1098
  }
1096
1099
  #order {
1097
1100
  p[data-hook="links"] {
@@ -24,6 +24,7 @@ module Spree
24
24
  helper 'spree/orders'
25
25
 
26
26
  rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
27
+ rescue_from Spree::Order::InsufficientStock, with: :insufficient_stock_error
27
28
 
28
29
  # Updates the order and advances to the next state (when possible.)
29
30
  def update
@@ -168,6 +169,7 @@ module Spree
168
169
 
169
170
  def apply_coupon_code
170
171
  if update_params[:coupon_code].present?
172
+ Spree::Deprecation.warn('This endpoint is deprecated. Please use `Spree::CouponCodesController#create` endpoint instead.')
171
173
  @order.coupon_code = update_params[:coupon_code]
172
174
 
173
175
  handler = PromotionHandler::Coupon.new(@order).apply
@@ -232,5 +234,22 @@ module Spree
232
234
  def check_authorization
233
235
  authorize!(:edit, current_order, cookies.signed[:guest_token])
234
236
  end
237
+
238
+ def insufficient_stock_error
239
+ packages = @order.shipments.map(&:to_package)
240
+ if packages.empty?
241
+ flash[:error] = I18n.t('spree.insufficient_stock_for_order')
242
+ redirect_to cart_path
243
+ else
244
+ availability_validator = Spree::Stock::AvailabilityValidator.new
245
+ unavailable_items = @order.line_items.reject { |line_item| availability_validator.validate(line_item) }
246
+ if unavailable_items.any?
247
+ item_names = unavailable_items.map(&:name).to_sentence
248
+ flash[:error] = t('spree.inventory_error_flash_for_insufficient_shipment_quantity', unavailable_items: item_names)
249
+ @order.restart_checkout_flow
250
+ redirect_to spree.checkout_state_path(@order.state)
251
+ end
252
+ end
253
+ end
235
254
  end
236
255
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class CouponCodesController < Spree::StoreController
5
+ before_action :load_order, only: :create
6
+ around_action :lock_order, only: :create
7
+
8
+ def create
9
+ authorize! :update, @order, cookies.signed[:guest_token]
10
+
11
+ if params[:coupon_code].present?
12
+ @order.coupon_code = params[:coupon_code]
13
+ handler = PromotionHandler::Coupon.new(@order).apply
14
+
15
+ respond_with(@order) do |format|
16
+ format.html do
17
+ if handler.successful?
18
+ flash[:success] = handler.success
19
+ redirect_to cart_path
20
+ else
21
+ flash.now[:error] = handler.error
22
+ render 'spree/coupon_codes/new'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def load_order
32
+ @order = current_order
33
+ end
34
+ end
35
+ end
@@ -7,7 +7,7 @@ module Spree
7
7
  requested_locale = params[:switch_to_locale] || params[:locale]
8
8
 
9
9
  if requested_locale && available_locales.map(&:to_s).include?(requested_locale)
10
- session[:locale] = requested_locale
10
+ session[set_user_language_locale_key] = requested_locale
11
11
  I18n.locale = requested_locale
12
12
  flash.notice = t('spree.locale_changed')
13
13
  else
@@ -122,6 +122,7 @@ module Spree
122
122
 
123
123
  def apply_coupon_code
124
124
  if order_params[:coupon_code].present?
125
+ Spree::Deprecation.warn('This endpoint is deprecated. Please use `Spree::CouponCodesController#create` endpoint instead.')
125
126
  @order.coupon_code = order_params[:coupon_code]
126
127
 
127
128
  handler = PromotionHandler::Coupon.new(@order).apply
@@ -1,7 +1,7 @@
1
1
  <div class="coupon-code" data-hook='coupon_code'>
2
2
  <%= form_for order, url: update_checkout_path(order.state) do |form| %>
3
3
  <%= form.label :coupon_code %>
4
- <%= form.text_field :coupon_code, placeholder: :coupon_code %>
4
+ <%= form.text_field :coupon_code, placeholder: true %>
5
5
 
6
6
  <button type="submit" class="button coupon-code-apply-button" id="coupon-code-apply-button">
7
7
  <%= t('spree.apply_code') %>
@@ -27,7 +27,9 @@
27
27
  <% ship_form.object.manifest.each do |item| %>
28
28
  <tr class="stock-item">
29
29
  <td class="item-image">
30
- <%= render 'spree/shared/image', image: item.variant.display_image, size: :mini %>
30
+ <%= render 'spree/shared/image',
31
+ image: (item.variant.gallery.images.first || item.variant.product.gallery.images.first),
32
+ size: :mini %>
31
33
  </td>
32
34
  <td class="item-name"><%= item.variant.name %></td>
33
35
  <td class="item-qty"><%= item.quantity %></td>
@@ -75,7 +77,9 @@
75
77
  <% @differentiator.missing.each do |variant, quantity| %>
76
78
  <tr class="stock-item">
77
79
  <td class="item-image">
78
- <%= render 'spree/shared/image', image: variant.display_image, size: :mini %>
80
+ <%= render 'spree/shared/image',
81
+ image: (variant.gallery.images.first || variant.product.gallery.images.first),
82
+ size: :mini %>
79
83
  </td>
80
84
  <td class="item-name"><%= variant.name %></td>
81
85
  <td class="item-qty"><%= quantity %></td>
@@ -0,0 +1,6 @@
1
+ <div id="coupon_code" data-hook="coupon_code">
2
+ <%= form_tag order_coupon_codes_path(@order), method: :post do %>
3
+ <%= text_field_tag :coupon_code, nil, placeholder: t("spree.coupon_code"), size: 10 %>
4
+ <%= submit_tag t("spree.apply_code") %>
5
+ <% end %>
6
+ </div>
@@ -15,7 +15,7 @@
15
15
  </tbody>
16
16
  <% if order.adjustments.nonzero.exists? || order.line_item_adjustments.nonzero.exists? || order.shipment_adjustments.nonzero.exists? || order.shipments.any? %>
17
17
  <tr class="cart-subtotal">
18
- <td colspan="4" align='right'><h5><%= t('spree.cart_subtotal', count: order.line_items.sum(:quantity)) %></h5></th>
18
+ <td colspan="4" align='right'><h5><%= t('spree.cart_subtotal', count: order.line_items.sum(:quantity)) %></h5></td>
19
19
  <td colspan><h5><%= order.display_item_total %></h5></td>
20
20
  <td></td>
21
21
  </tr>
@@ -2,11 +2,9 @@
2
2
  <%= order_form.fields_for :line_items, line_item do |item_form| -%>
3
3
  <tr class="<%= cycle('', 'alt') %> line-item">
4
4
  <td class="cart-item-image" data-hook="cart_item_image">
5
- <% if variant.images.empty? %>
6
- <%= link_to(render('spree/shared/image', image: variant.product.display_image, size: :small), variant.product) %>
7
- <% else %>
8
- <%= link_to(render('spree/shared/image', image: variant.images.first, size: :small), variant.product) %>
9
- <% end %>
5
+ <%= link_to(render('spree/shared/image',
6
+ image: (variant.gallery.images.first || variant.product.gallery.images.first),
7
+ size: :small), variant.product) %>
10
8
  </td>
11
9
  <td class="cart-item-description" data-hook="cart_item_description">
12
10
  <h4><%= link_to line_item.name, product_path(variant.product) %></h4>
@@ -16,19 +16,16 @@
16
16
  <div data-hook="inside_cart_form">
17
17
 
18
18
  <div data-hook="cart_items">
19
- <%= render 'form', order_form: order_form %>
19
+ <%= render 'spree/orders/form', order_form: order_form %>
20
20
  </div>
21
21
 
22
22
  <div class="links columns sixteen alpha omega" data-hook="cart_buttons">
23
- <%= order_form.text_field :coupon_code, size: 10, placeholder: t('spree.coupon_code') %>
24
- <%= button_tag class: 'primary', id: 'update-button' do %>
25
- <%= t('spree.update') %>
26
- <% end %>
23
+ <%= button_tag t("spree.update"), class: "primary", id: "update-button" %>
24
+
27
25
  <%= button_tag class: 'button checkout primary', id: 'checkout-link', name: 'checkout' do %>
28
26
  <%= t('spree.checkout') %>
29
27
  <% end %>
30
28
  </div>
31
-
32
29
  </div>
33
30
  <% end %>
34
31
  </div>
@@ -41,6 +38,8 @@
41
38
  <%= link_to t('spree.continue_shopping'), products_path, class: 'continue button gray' %>
42
39
  </p>
43
40
  <% end %>
41
+
42
+ <%= render template: 'spree/coupon_codes/new' %>
44
43
  </div>
45
44
 
46
45
  <% end %>
@@ -1,5 +1,8 @@
1
1
  <% if defined?(image) && image %>
2
2
  <%= render 'spree/shared/image', image: image, size: :product, itemprop: "image" %>
3
3
  <% else %>
4
- <%= render 'spree/shared/image', image: @product.display_image, size: :product, itemprop: "image" %>
4
+ <%= render 'spree/shared/image',
5
+ image: @product.gallery.images.first,
6
+ size: :product,
7
+ itemprop: "image" %>
5
8
  <% end %>
@@ -1,17 +1,19 @@
1
1
  <%# no need for thumbnails unless there is more than one image %>
2
- <% if (@product.images + @product.variant_images).uniq.size > 1 %>
2
+ <% if @product.gallery.images.size > 1 %>
3
3
  <ul id="product-thumbnails" class="thumbnails inline" data-hook>
4
- <% @product.images.each do |i| %>
5
- <li class='tmb-all tmb-<%= i.viewable.id %>'>
6
- <%= link_to(image_tag(i.attachment.url(:mini)), i.attachment.url(:product)) %>
4
+
5
+ <% @product.gallery.images.each do |image| %>
6
+ <% next if image.viewable_id != @product.master.id %>
7
+ <li class='tmb-all tmb-<%= image.viewable_id %>'>
8
+ <%= link_to(image_tag(image.url(:mini)), image.url(:product)) %>
7
9
  </li>
8
10
  <% end %>
9
11
 
10
12
  <% if @product.has_variants? %>
11
- <% @product.variant_images.each do |i| %>
12
- <% next if @product.images.include?(i) %>
13
- <li class='vtmb tmb-<%= i.viewable.id %>'>
14
- <%= link_to(image_tag(i.attachment.url(:mini)), i.attachment.url(:product)) %>
13
+ <% @product.gallery.images.each do |image| %>
14
+ <% next if image.viewable_id == @product.master.id %>
15
+ <li class='vtmb tmb-<%= image.viewable_id %>'>
16
+ <%= link_to(image_tag(image.url(:mini)), image.url(:product)) %>
15
17
  </li>
16
18
  <% end %>
17
19
  <% end %>
@@ -1,11 +1,11 @@
1
1
  <% size ||= :mini %>
2
2
  <% itemprop ||= nil %>
3
3
 
4
- <% if image && image.attachment? %>
5
- <% if itemprop %>
6
- <%= image_tag image.attachment(size), itemprop: itemprop %>
4
+ <% if image_url = image.try(:url, size) %>
5
+ <% if image_alt = image.try(:alt) %>
6
+ <%= image_tag image_url, alt: image_alt, itemprop: itemprop %>
7
7
  <% else %>
8
- <%= image_tag image.attachment(size) %>
8
+ <%= image_tag image_url, itemprop: itemprop %>
9
9
  <% end %>
10
10
  <% else %>
11
11
  <span class="image-placeholder <%= size %>"></span>
@@ -4,7 +4,7 @@
4
4
  <%= form_tag spree.select_locale_path, class: 'navbar-form' do %>
5
5
  <div class="form-group">
6
6
  <label for="switch_to_locale" class="sr-only">
7
- <%= Spree.t(:'i18n.language') %>
7
+ <%= I18n.t('spree.i18n.language') %>
8
8
  </label>
9
9
  <%=
10
10
  select_tag(
@@ -62,11 +62,9 @@
62
62
  <% order.line_items.each do |item| %>
63
63
  <tr data-hook="order_details_line_item_row">
64
64
  <td data-hook="order_item_image">
65
- <% if item.variant.images.empty? %>
66
- <%= link_to(render('spree/shared/image', image: item.variant.product.display_image, size: :small), item.variant.product) %>
67
- <% else %>
68
- <%= link_to(render('spree/shared/image', image: item.variant.images.first, size: :small), item.variant.product) %>
69
- <% end %>
65
+ <%= link_to(render('spree/shared/image',
66
+ image: (item.variant.gallery.images.first || item.variant.product.gallery.images.first),
67
+ size: :small), item.variant.product) %>
70
68
  </td>
71
69
  <td data-hook="order_item_description">
72
70
  <h4><%= item.variant.product.name %></h4>
@@ -28,7 +28,7 @@
28
28
  <li id="product_<%= product.id %>" class="columns three <%= cycle("alpha", "secondary", "", "omega secondary", name: "classes") %>" data-hook="products_list_item" itemscope itemtype="http://schema.org/Product">
29
29
  <% cache(@taxon.present? ? [I18n.locale, current_pricing_options, @taxon, product] : [I18n.locale, current_pricing_options, product]) do %>
30
30
  <div class="product-image">
31
- <%= link_to(render('spree/shared/image', image: product.display_image, size: :small, itemprop: "image"), url, itemprop: 'url') %>
31
+ <%= link_to(render('spree/shared/image', image: product.gallery.images.first, size: :small, itemprop: "image"), url, itemprop: 'url') %>
32
32
  </div>
33
33
  <%= link_to truncate(product.name, length: 50), url, class: 'info', itemprop: "name", title: product.name %>
34
34
  <span itemprop="offers" itemscope itemtype="http://schema.org/Offer">
@@ -18,6 +18,7 @@ Spree::Core::Engine.routes.draw do
18
18
 
19
19
  resources :orders, except: [:index, :new, :create, :destroy] do
20
20
  post :populate, on: :collection
21
+ resources :coupon_codes, only: :create
21
22
  end
22
23
 
23
24
  get '/cart', to: 'orders#edit', as: :cart
@@ -3,7 +3,7 @@
3
3
  require 'rails/all'
4
4
  require 'jquery-rails'
5
5
  require 'canonical-rails'
6
- require 'sass-rails'
6
+ require 'sassc-rails'
7
7
  require 'font-awesome-rails'
8
8
  require 'responders'
9
9
  require 'kaminari'
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_dependency 'font-awesome-rails', '~> 4.0'
29
29
  s.add_dependency 'jquery-rails'
30
30
  s.add_dependency 'kaminari', '~> 1.1'
31
- s.add_dependency 'sass-rails'
31
+ s.add_dependency 'sassc-rails'
32
32
  s.add_dependency 'truncate_html', '~> 0.9', '>= 0.9.2'
33
33
 
34
34
  s.add_development_dependency 'capybara-accessible'
@@ -14,7 +14,6 @@ describe Spree::CheckoutController, type: :controller do
14
14
 
15
15
  before do
16
16
  allow(controller).to receive_messages try_spree_current_user: user
17
- allow(controller).to receive_messages spree_current_user: user
18
17
  allow(controller).to receive_messages current_order: order
19
18
  end
20
19
 
@@ -90,7 +89,7 @@ describe Spree::CheckoutController, type: :controller do
90
89
  order.line_items << FactoryBot.create(:line_item)
91
90
  end
92
91
 
93
- context "with the order in the cart state" do
92
+ context "with the order in the cart state", partial_double_verification: false do
94
93
  before do
95
94
  order.update_attributes! user: user
96
95
  order.update_column(:state, "cart")
@@ -139,7 +138,7 @@ describe Spree::CheckoutController, type: :controller do
139
138
  end
140
139
  end
141
140
 
142
- context "with the order in the address state" do
141
+ context "with the order in the address state", partial_double_verification: false do
143
142
  before do
144
143
  order.update_attributes! user: user
145
144
  order.update_columns(ship_address_id: create(:address).id, state: "address")
@@ -152,7 +151,7 @@ describe Spree::CheckoutController, type: :controller do
152
151
  end
153
152
  end
154
153
 
155
- context "with a billing and shipping address" do
154
+ context "with a billing and shipping address", partial_double_verification: false do
156
155
  subject do
157
156
  post :update, params: {
158
157
  state: "address",
@@ -184,7 +183,7 @@ describe Spree::CheckoutController, type: :controller do
184
183
  # the same thing here.
185
184
  # Perhaps we can just remove 'set_payment_parameters_amount' entirely at
186
185
  # some point?
187
- context "when there is a checkout step between payment and confirm" do
186
+ context "when there is a checkout step between payment and confirm", partial_double_verification: false do
188
187
  before do
189
188
  @old_checkout_flow = Spree::Order.checkout_flow
190
189
  Spree::Order.class_eval do
@@ -227,7 +226,7 @@ describe Spree::CheckoutController, type: :controller do
227
226
  end
228
227
  end
229
228
 
230
- context "when in the payment state" do
229
+ context "when in the payment state", partial_double_verification: false do
231
230
  let(:order) { create(:order_with_line_items) }
232
231
  let(:payment_method) { create(:credit_card_payment_method) }
233
232
 
@@ -420,6 +419,45 @@ describe Spree::CheckoutController, type: :controller do
420
419
  expect(flash[:error]).to eq(I18n.t('spree.payment_processing_failed'))
421
420
  end
422
421
  end
422
+
423
+ context "when InsufficientStock error is raised" do
424
+ before do
425
+ allow(controller).to receive_messages current_order: order
426
+ allow(controller).to receive_messages check_authorization: true
427
+ allow(controller).to receive_messages ensure_sufficient_stock_lines: true
428
+ end
429
+
430
+ context "when the order has no shipments" do
431
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:address) }
432
+
433
+ before do
434
+ allow(order).to receive_messages shipments: []
435
+ # Order#next is the tipical failure point here:
436
+ allow(order).to receive(:next).and_raise(Spree::Order::InsufficientStock)
437
+ end
438
+
439
+ it "redirects the customer to the cart page with an error message" do
440
+ put :update, params: { state: order.state, order: {} }
441
+ expect(flash[:error]).to eq(I18n.t('spree.insufficient_stock_for_order'))
442
+ expect(response).to redirect_to(spree.cart_path)
443
+ end
444
+ end
445
+
446
+ context "when the order has shipments" do
447
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
448
+
449
+ context "when items become somehow not available anymore" do
450
+ before { Spree::StockItem.update_all backorderable: false }
451
+
452
+ it "redirects the customer to the address checkout page with an error message" do
453
+ put :update, params: { state: order.state, order: {} }
454
+ error = I18n.t('spree.inventory_error_flash_for_insufficient_shipment_quantity', unavailable_items: order.products.first.name)
455
+ expect(flash[:error]).to eq(error)
456
+ expect(response).to redirect_to(spree.checkout_state_path(state: :address))
457
+ end
458
+ end
459
+ end
460
+ end
423
461
  end
424
462
 
425
463
  context "When last inventory item has been purchased" do
@@ -501,6 +539,8 @@ describe Spree::CheckoutController, type: :controller do
501
539
  let(:promotion_handler) { instance_double('Spree::PromotionHandler::Coupon', error: nil, success: 'Coupon Applied!') }
502
540
 
503
541
  it "continues checkout flow normally" do
542
+ expect(Spree::Deprecation).to receive(:warn)
543
+
504
544
  expect(Spree::PromotionHandler::Coupon)
505
545
  .to receive_message_chain(:new, :apply)
506
546
  .and_return(promotion_handler)
@@ -515,6 +555,8 @@ describe Spree::CheckoutController, type: :controller do
515
555
  let(:promotion_handler) { instance_double('Spree::PromotionHandler::Coupon', error: 'Some error', success: false) }
516
556
 
517
557
  it "setups the current step correctly before rendering" do
558
+ expect(Spree::Deprecation).to receive(:warn)
559
+
518
560
  expect(Spree::PromotionHandler::Coupon)
519
561
  .to receive_message_chain(:new, :apply)
520
562
  .and_return(promotion_handler)
@@ -524,6 +566,8 @@ describe Spree::CheckoutController, type: :controller do
524
566
  end
525
567
 
526
568
  it "render cart with coupon error" do
569
+ expect(Spree::Deprecation).to receive(:warn)
570
+
527
571
  expect(Spree::PromotionHandler::Coupon)
528
572
  .to receive_message_chain(:new, :apply)
529
573
  .and_return(promotion_handler)
@@ -7,8 +7,6 @@ module Spree
7
7
  ORDER_TOKEN = 'ORDER_TOKEN'
8
8
 
9
9
  let!(:store) { create(:store) }
10
- let(:user) { create(:user) }
11
- let(:guest_user) { create(:user) }
12
10
  let(:order) { Spree::Order.create }
13
11
  let(:variant) { create(:variant) }
14
12
 
@@ -21,7 +19,6 @@ module Spree
21
19
 
22
20
  before do
23
21
  allow(controller).to receive_messages current_order: order
24
- allow(controller).to receive_messages spree_current_user: user
25
22
  end
26
23
 
27
24
  context '#populate' do
@@ -149,6 +149,8 @@ describe Spree::OrdersController, type: :controller do
149
149
  let(:promotion_handler) { instance_double('Spree::PromotionHandler::Coupon', error: nil, success: 'Coupon Applied!') }
150
150
 
151
151
  it "continues checkout flow normally" do
152
+ expect(Spree::Deprecation).to receive(:warn)
153
+
152
154
  expect(Spree::PromotionHandler::Coupon)
153
155
  .to receive_message_chain(:new, :apply)
154
156
  .and_return(promotion_handler)
@@ -163,6 +165,8 @@ describe Spree::OrdersController, type: :controller do
163
165
  let(:promotion_handler) { instance_double('Spree::PromotionHandler::Coupon', error: 'Some error', success: false) }
164
166
 
165
167
  it "render cart with coupon error" do
168
+ expect(Spree::Deprecation).to receive(:warn)
169
+
166
170
  expect(Spree::PromotionHandler::Coupon)
167
171
  .to receive_message_chain(:new, :apply)
168
172
  .and_return(promotion_handler)
@@ -7,7 +7,7 @@ describe Spree::ProductsController, type: :controller do
7
7
 
8
8
  # Regression test for https://github.com/spree/spree/issues/1390
9
9
  it "allows admins to view non-active products" do
10
- allow(controller).to receive_messages spree_current_user: mock_model(Spree.user_class, has_spree_role?: true, last_incomplete_spree_order: nil, spree_api_key: 'fake')
10
+ allow(controller).to receive_messages try_spree_current_user: mock_model(Spree.user_class, has_spree_role?: true, last_incomplete_spree_order: nil, spree_api_key: 'fake')
11
11
  get :show, params: { id: product.to_param }
12
12
  expect(response.status).to eq(200)
13
13
  end
@@ -20,7 +20,7 @@ describe Spree::ProductsController, type: :controller do
20
20
 
21
21
  it "should provide the current user to the searcher class" do
22
22
  user = mock_model(Spree.user_class, last_incomplete_spree_order: nil, spree_api_key: 'fake')
23
- allow(controller).to receive_messages spree_current_user: user
23
+ allow(controller).to receive_messages try_spree_current_user: user
24
24
  expect_any_instance_of(Spree::Config.searcher_class).to receive(:current_user=).with(user)
25
25
  get :index
26
26
  expect(response.status).to eq(200)
@@ -29,7 +29,7 @@ describe Spree::ProductsController, type: :controller do
29
29
  # Regression test for https://github.com/spree/spree/issues/2249
30
30
  it "doesn't error when given an invalid referer" do
31
31
  current_user = mock_model(Spree.user_class, has_spree_role?: true, last_incomplete_spree_order: nil, generate_spree_api_key!: nil)
32
- allow(controller).to receive_messages spree_current_user: current_user
32
+ allow(controller).to receive_messages try_spree_current_user: current_user
33
33
  request.env['HTTP_REFERER'] = "not|a$url"
34
34
 
35
35
  # Previously a URI::InvalidURIError exception was being thrown
@@ -6,7 +6,7 @@ describe Spree::TaxonsController, type: :controller do
6
6
  it "should provide the current user to the searcher class" do
7
7
  taxon = create(:taxon, permalink: "test")
8
8
  user = mock_model(Spree.user_class, last_incomplete_spree_order: nil, spree_api_key: 'fake')
9
- allow(controller).to receive_messages spree_current_user: user
9
+ allow(controller).to receive_messages try_spree_current_user: user
10
10
  expect_any_instance_of(Spree::Config.searcher_class).to receive(:current_user=).with(user)
11
11
  get :show, params: { id: taxon.permalink }
12
12
  expect(response.status).to eq(200)
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe "Checkout confirm page submission", type: :feature do
6
+ include_context 'checkout setup'
7
+
8
+ context "when the product from the order is not backorderable but has enough stock quantity" do
9
+ let(:user) { create(:user) }
10
+
11
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
12
+ let(:order_product) { order.products.first }
13
+ let(:order_stock_item) { order_product.stock_items.first }
14
+
15
+ before do
16
+ order_stock_item.update! backorderable: false
17
+ order_stock_item.set_count_on_hand(1)
18
+ allow_any_instance_of(Spree::CheckoutController).to receive_messages(current_order: order)
19
+ allow_any_instance_of(Spree::CheckoutController).to receive_messages(try_spree_current_user: user)
20
+ allow_any_instance_of(Spree::OrdersController).to receive_messages(try_spree_current_user: user)
21
+ end
22
+
23
+ context 'when there are not other backorderable stock locations' do
24
+ context 'when the customer is on the confirm page and the availabilty drops to zero' do
25
+ before do
26
+ visit spree.checkout_state_path(:confirm)
27
+ order_stock_item.set_count_on_hand(0)
28
+ end
29
+
30
+ it 'redirects to cart page and shows an unavailable product message' do
31
+ click_button "Place Order"
32
+ expect(page).to have_content "#{order_product.name} became unavailable"
33
+ expect(page).to have_current_path spree.cart_path
34
+ end
35
+ end
36
+ end
37
+
38
+ context 'when there is another backorderable stock location' do
39
+ before do
40
+ create :stock_location, backorderable_default: true, default: false
41
+ end
42
+
43
+ context 'when the customer is on the confirm page and the availabilty drops to zero' do
44
+ before do
45
+ visit spree.checkout_state_path(:confirm)
46
+ order_stock_item.set_count_on_hand(0)
47
+ end
48
+
49
+ it "redirects to the address checkout page and shows an availability changed message" do
50
+ click_button "Place Order"
51
+ error_message = "Quantity selected of #{order_product.name} is not available. Still, items may be available from another stock location, please try again."
52
+ expect(page).to have_content error_message
53
+ expect(page).to have_current_path spree.checkout_state_path(:address)
54
+ end
55
+
56
+ it "can still complete the order using the backorderable stock location by restarting the checkout" do
57
+ click_button "Place Order"
58
+ expect(page).to have_current_path spree.checkout_state_path(:address)
59
+ click_button "Save and Continue"
60
+ expect(page).to have_current_path spree.checkout_state_path(:delivery)
61
+ click_button "Save and Continue"
62
+ expect(page).to have_current_path spree.checkout_state_path(:payment)
63
+ click_button "Save and Continue"
64
+ expect(page).to have_current_path spree.checkout_state_path(:confirm)
65
+ click_button "Place Order"
66
+ expect(page).to have_content 'Your order has been processed successfully'
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -350,7 +350,7 @@ describe "Checkout", type: :feature, inaccessible: true do
350
350
  choose "use_existing_card_no"
351
351
 
352
352
  fill_in "Name on card", with: 'Spree Commerce'
353
- fill_in "Card Number", with: '4111 1111 1111 1111'
353
+ fill_in_with_force "Card Number", with: '4111 1111 1111 1111'
354
354
  fill_in "card_expiry", with: '04 / 20'
355
355
  fill_in "Card Code", with: '123'
356
356
 
@@ -130,22 +130,22 @@ describe "Coupon code promotions", type: :feature, js: true do
130
130
  end
131
131
 
132
132
  it "can enter a coupon code and receives success notification" do
133
- fill_in "order_coupon_code", with: "onetwo"
134
- click_button "Update"
133
+ fill_in "coupon_code", with: "onetwo"
134
+ click_button "Apply Code"
135
135
  expect(page).to have_content(I18n.t('spree.coupon_code_applied'))
136
136
  end
137
137
 
138
138
  it "can enter a promotion code with both upper and lower case letters" do
139
- fill_in "order_coupon_code", with: "ONETwO"
140
- click_button "Update"
139
+ fill_in "coupon_code", with: "ONETwO"
140
+ click_button "Apply Code"
141
141
  expect(page).to have_content(I18n.t('spree.coupon_code_applied'))
142
142
  end
143
143
 
144
144
  it "informs the user about a coupon code which has exceeded its usage" do
145
145
  expect_any_instance_of(Spree::Promotion).to receive(:usage_limit_exceeded?).and_return(true)
146
146
 
147
- fill_in "order_coupon_code", with: "onetwo"
148
- click_button "Update"
147
+ fill_in "coupon_code", with: "onetwo"
148
+ click_button "Apply Code"
149
149
  expect(page).to have_content(I18n.t('spree.coupon_code_max_usage'))
150
150
  end
151
151
 
@@ -160,8 +160,8 @@ describe "Coupon code promotions", type: :feature, js: true do
160
160
  specify do
161
161
  visit spree.cart_path
162
162
 
163
- fill_in "order_coupon_code", with: "onetwo"
164
- click_button "Update"
163
+ fill_in "coupon_code", with: "onetwo"
164
+ click_button "Apply Code"
165
165
  expect(page).to have_content(I18n.t(:item_total_less_than_or_equal, scope: [:spree, :eligibility_errors, :messages], amount: "$100.00"))
166
166
  end
167
167
  end
@@ -170,8 +170,8 @@ describe "Coupon code promotions", type: :feature, js: true do
170
170
  promotion.expires_at = Date.today.beginning_of_week
171
171
  promotion.starts_at = Date.today.beginning_of_week.advance(day: 3)
172
172
  promotion.save!
173
- fill_in "order_coupon_code", with: "onetwo"
174
- click_button "Update"
173
+ fill_in "coupon_code", with: "onetwo"
174
+ click_button "Apply Code"
175
175
  expect(page).to have_content(I18n.t('spree.coupon_code_expired'))
176
176
  end
177
177
 
@@ -191,8 +191,8 @@ describe "Coupon code promotions", type: :feature, js: true do
191
191
  click_button "add-to-cart-button"
192
192
 
193
193
  visit spree.cart_path
194
- fill_in "order_coupon_code", with: "onetwo"
195
- click_button "Update"
194
+ fill_in "coupon_code", with: "onetwo"
195
+ click_button "Apply Code"
196
196
 
197
197
  fill_in "order_line_items_attributes_0_quantity", with: 2
198
198
  fill_in "order_line_items_attributes_1_quantity", with: 2
@@ -237,8 +237,8 @@ describe "Coupon code promotions", type: :feature, js: true do
237
237
  expect(page).to have_content("$30.00")
238
238
  end
239
239
 
240
- fill_in "order_coupon_code", with: "onetwo"
241
- click_button "Update"
240
+ fill_in "coupon_code", with: "onetwo"
241
+ click_button "Apply Code"
242
242
 
243
243
  within '#cart_adjustments' do
244
244
  expect(page).to have_content("Promotion (Onetwo) -$30.00")
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.feature "Promotion Code Invalidation" do
5
+ RSpec.feature "Promotion Code Invalidation", js: true do
6
6
  given!(:promotion) do
7
7
  FactoryBot.create(
8
8
  :promotion_with_item_adjustment,
@@ -28,7 +28,7 @@ RSpec.feature "Promotion Code Invalidation" do
28
28
 
29
29
  scenario "adding the promotion to a cart with two applicable items" do
30
30
  fill_in "Coupon code", with: "PROMO"
31
- click_button "Update"
31
+ click_button "Apply Code"
32
32
 
33
33
  expect(page).to have_content("The coupon code was successfully applied to your order")
34
34
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.feature "Quantity Promotions" do
5
+ RSpec.feature "Quantity Promotions", js: true do
6
6
  given(:action) do
7
7
  Spree::Promotion::Actions::CreateQuantityAdjustments.create(
8
8
  calculator: calculator,
@@ -26,8 +26,8 @@ RSpec.feature "Quantity Promotions" do
26
26
 
27
27
  scenario "adding and removing items from the cart" do
28
28
  # Attempt to use the code with too few items.
29
- fill_in "Coupon code", with: "PROMO"
30
- click_button "Update"
29
+ fill_in "coupon_code", with: "PROMO"
30
+ click_button "Apply Code"
31
31
  expect(page).to have_content("This coupon code could not be applied to the cart at this time")
32
32
 
33
33
  # Add another item to our cart.
@@ -36,8 +36,8 @@ RSpec.feature "Quantity Promotions" do
36
36
  click_button "Add To Cart"
37
37
 
38
38
  # Using the code should now succeed.
39
- fill_in "Coupon code", with: "PROMO"
40
- click_button "Update"
39
+ fill_in "coupon_code", with: "PROMO"
40
+ click_button "Apply Code"
41
41
  expect(page).to have_content("The coupon code was successfully applied to your order")
42
42
  within("#cart_adjustments") do
43
43
  expect(page).to have_content("-$10.00")
@@ -70,8 +70,8 @@ RSpec.feature "Quantity Promotions" do
70
70
  click_button "Update"
71
71
 
72
72
  # Apply the promo code and see a $10 discount (for 2 of the 3 items)
73
- fill_in "Coupon code", with: "PROMO"
74
- click_button "Update"
73
+ fill_in "coupon_code", with: "PROMO"
74
+ click_button "Apply Code"
75
75
  expect(page).to have_content("The coupon code was successfully applied to your order")
76
76
  within("#cart_adjustments") do
77
77
  expect(page).to have_content("-$10.00")
@@ -104,8 +104,8 @@ RSpec.feature "Quantity Promotions" do
104
104
  click_button "Update"
105
105
 
106
106
  # Apply the promo code and see a $15 discount
107
- fill_in "Coupon code", with: "PROMO"
108
- click_button "Update"
107
+ fill_in "coupon_code", with: "PROMO"
108
+ click_button "Apply Code"
109
109
  expect(page).to have_content("The coupon code was successfully applied to your order")
110
110
  within("#cart_adjustments") do
111
111
  expect(page).to have_content("-$15.00")
@@ -26,6 +26,7 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
26
26
 
27
27
  require 'database_cleaner'
28
28
 
29
+ require 'spree/testing_support/partial_double_verification'
29
30
  require 'spree/testing_support/authorization_helpers'
30
31
  require 'spree/testing_support/capybara_ext'
31
32
  require 'spree/testing_support/factories'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FillInWithForce
4
+ def fill_in_with_force(locator, with:)
5
+ field_id = find_field(locator)[:id]
6
+ page.execute_script "document.getElementById('#{field_id}').value = '#{with}';"
7
+ end
8
+ end
9
+
10
+ RSpec.configure do |config|
11
+ config.include FillInWithForce, type: :feature
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_frontend
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.4
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-23 00:00:00.000000000 Z
11
+ date: 2019-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus_api
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.7.4
19
+ version: 2.8.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.7.4
26
+ version: 2.8.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: solidus_core
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 2.7.4
33
+ version: 2.8.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 2.7.4
40
+ version: 2.8.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: canonical-rails
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.1'
97
97
  - !ruby/object:Gem::Dependency
98
- name: sass-rails
98
+ name: sassc-rails
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -195,6 +195,7 @@ files:
195
195
  - app/assets/stylesheets/spree/frontend/screen.css.scss
196
196
  - app/controllers/spree/checkout_controller.rb
197
197
  - app/controllers/spree/content_controller.rb
198
+ - app/controllers/spree/coupon_codes_controller.rb
198
199
  - app/controllers/spree/home_controller.rb
199
200
  - app/controllers/spree/locale_controller.rb
200
201
  - app/controllers/spree/orders_controller.rb
@@ -218,6 +219,7 @@ files:
218
219
  - app/views/spree/checkout/payment/_check.html.erb
219
220
  - app/views/spree/checkout/payment/_gateway.html.erb
220
221
  - app/views/spree/content/cvv.html.erb
222
+ - app/views/spree/coupon_codes/new.html.erb
221
223
  - app/views/spree/home/index.html.erb
222
224
  - app/views/spree/layouts/spree_application.html.erb
223
225
  - app/views/spree/orders/_adjustment_row.html.erb
@@ -286,6 +288,7 @@ files:
286
288
  - spec/features/caching/products_spec.rb
287
289
  - spec/features/caching/taxons_spec.rb
288
290
  - spec/features/cart_spec.rb
291
+ - spec/features/checkout_confirm_insufficient_stock_spec.rb
289
292
  - spec/features/checkout_spec.rb
290
293
  - spec/features/checkout_unshippable_spec.rb
291
294
  - spec/features/coupon_code_spec.rb
@@ -304,6 +307,7 @@ files:
304
307
  - spec/helpers/order_helper_spec.rb
305
308
  - spec/helpers/taxon_filters_helper_spec.rb
306
309
  - spec/spec_helper.rb
310
+ - spec/support/features/fill_in_with_force.rb
307
311
  - spec/support/shared_contexts/checkout_setup.rb
308
312
  - spec/support/shared_contexts/custom_products.rb
309
313
  - spec/support/shared_contexts/locales.rb
@@ -328,7 +332,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
328
332
  version: 1.8.23
329
333
  requirements:
330
334
  - none
331
- rubygems_version: 3.0.6
335
+ rubyforge_project:
336
+ rubygems_version: 2.7.3
332
337
  signing_key:
333
338
  specification_version: 4
334
339
  summary: Cart and storefront for the Solidus e-commerce project.