solidus_frontend 2.7.4 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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.