spree_core 4.2.0.rc3 → 4.2.2

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spree.js +19 -0
  3. data/app/controllers/spree/base_controller.rb +2 -1
  4. data/app/controllers/spree/errors_controller.rb +11 -0
  5. data/app/finders/spree/orders/find_current.rb +1 -1
  6. data/app/finders/spree/products/find.rb +14 -3
  7. data/app/helpers/spree/base_helper.rb +2 -1
  8. data/app/helpers/spree/currency_helper.rb +34 -0
  9. data/app/helpers/spree/locale_helper.rb +31 -0
  10. data/app/helpers/spree/products_helper.rb +37 -12
  11. data/app/models/concerns/spree/product_scopes.rb +1 -1
  12. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  13. data/app/models/spree/ability.rb +45 -30
  14. data/app/models/spree/app_configuration.rb +2 -2
  15. data/app/models/spree/app_dependencies.rb +3 -1
  16. data/app/models/spree/credit_card.rb +4 -0
  17. data/app/models/spree/image.rb +14 -14
  18. data/app/models/spree/line_item.rb +6 -9
  19. data/app/models/spree/price.rb +1 -1
  20. data/app/models/spree/product.rb +29 -15
  21. data/app/models/spree/promotion/rules/option_value.rb +1 -1
  22. data/app/models/spree/store.rb +38 -9
  23. data/app/models/spree/variant.rb +8 -8
  24. data/app/paginators/spree/shared/paginate.rb +8 -1
  25. data/app/presenters/spree/variant_presenter.rb +2 -5
  26. data/app/services/spree/build_localized_redirect_url.rb +101 -0
  27. data/app/services/spree/cart/estimate_shipping_rates.rb +1 -1
  28. data/app/views/spree/errors/forbidden.html.erb +0 -0
  29. data/app/views/spree/errors/unauthorized.html.erb +0 -0
  30. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +13 -2
  31. data/app/views/spree/shared/_purchased_items_table.html.erb +15 -6
  32. data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +2 -2
  33. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +2 -2
  34. data/config/locales/en.yml +8 -54
  35. data/config/routes.rb +2 -1
  36. data/db/default/spree/stores.rb +1 -0
  37. data/db/default/spree/zones.rb +4 -1
  38. data/db/migrate/20191017121054_add_supported_currencies_to_store.rb +1 -0
  39. data/db/migrate/20201012091259_add_filterable_column_to_spree_option_types.rb +6 -2
  40. data/db/migrate/20210120142527_ensure_default_locale_in_spree_stores.rb +5 -0
  41. data/db/migrate/20210205211040_add_supported_locales_to_spree_stores.rb +11 -0
  42. data/db/migrate/20210215202602_migrate_spree_i18n_globalize_config.rb +22 -0
  43. data/lib/generators/spree/install/install_generator.rb +9 -6
  44. data/lib/spree/core.rb +2 -1
  45. data/lib/spree/core/controller_helpers/auth.rb +3 -1
  46. data/lib/spree/core/controller_helpers/common.rb +6 -8
  47. data/lib/spree/core/controller_helpers/currency.rb +54 -0
  48. data/lib/spree/core/controller_helpers/locale.rb +58 -0
  49. data/lib/spree/core/controller_helpers/search.rb +1 -1
  50. data/lib/spree/core/controller_helpers/store.rb +4 -16
  51. data/lib/spree/core/version.rb +3 -1
  52. data/lib/spree/i18n.rb +12 -0
  53. data/lib/spree/permitted_attributes.rb +1 -1
  54. data/lib/spree/service_module.rb +2 -2
  55. data/lib/spree/testing_support/common_rake.rb +1 -1
  56. data/lib/spree/testing_support/controller_requests.rb +10 -10
  57. data/lib/spree/testing_support/factories/stock_location_factory.rb +2 -2
  58. data/lib/spree/testing_support/factories/store_factory.rb +1 -0
  59. data/lib/spree/testing_support/flatpickr_capybara.rb +101 -0
  60. data/lib/spree/testing_support/locale_helpers.rb +78 -0
  61. data/lib/spree/testing_support/next_instance_of.rb +38 -0
  62. data/spree_core.gemspec +1 -1
  63. metadata +20 -9
  64. data/lib/generators/spree/install/templates/config/initializers/spree_storefront.rb +0 -1
  65. data/lib/generators/spree/install/templates/config/spree_storefront.yml +0 -67
  66. data/lib/spree/core/controller_helpers/currency_helpers.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e1c991fe1a4f4ffcb163ad34f7db0d399c802a14b09cabae9b6db567db1adbc
4
- data.tar.gz: 6d27129f5c12ec9b48941c3001a341d8306e219fdb702b153944645bc1044b72
3
+ metadata.gz: 612f2690babce476b244e52eaf770e6993cabeef0ba9d7fa76a921cc1281a826
4
+ data.tar.gz: 1e71e1322e8d7af3b9595f33108c5b82ddb1ba0824570d6e9bb50e47160cc71e
5
5
  SHA512:
6
- metadata.gz: 4627be5137cf9b13ac72562df61b91a6ad0a95eb0119e9b9cf0c9a32b562874799ff35a0187ae8eadec622c88c0c5ee56f10cb21df79512b6524394b2f668fb1
7
- data.tar.gz: ecaf570ab3245130d1ea2b521e0201937617e2aa0d308051d56ec17e2757549ce202fc243bb0c9b7609e379dfb7179005773656a8c7cc69632341c9751a26967
6
+ metadata.gz: 3d8788642e21a9ae5f5e5ea2684cafb00e80a3ed300851c4b4bdb83e8bf83a927dfd6798ea99e8da04f94809e9163ada634e89452568b3307b0bffc3e567827c
7
+ data.tar.gz: db77fb1c959dbe53a50cc103977a1b3c83f3d45d846ce353b1ed739ebd89c8e9b0234b470ddc23a0b14b94137ee996c60165cf36350b997ea2eeb42d34ec7caf
@@ -17,9 +17,28 @@ Spree.adminPath = function () {
17
17
 
18
18
  Spree.pathFor = function (path) {
19
19
  var locationOrigin = (window.location.protocol + '//' + window.location.hostname) + (window.location.port ? ':' + window.location.port : '')
20
+
20
21
  return this.url('' + locationOrigin + (this.mountedAt()) + path, this.url_params).toString()
21
22
  }
22
23
 
24
+ Spree.localizedPathFor = function(path) {
25
+ if (typeof (SPREE_LOCALE) !== 'undefined' && typeof (SPREE_CURRENCY) !== 'undefined') {
26
+ var fullUrl = new URL(Spree.pathFor(path))
27
+ var params = fullUrl.searchParams
28
+ var pathName = fullUrl.pathname
29
+
30
+ params.set('currency', SPREE_CURRENCY)
31
+
32
+ if (pathName.match(/api\/v/)) {
33
+ params.set('locale', SPREE_LOCALE)
34
+ } else {
35
+ pathName = SPREE_LOCALE + '/' + path
36
+ }
37
+ return fullUrl.origin + (this.mountedAt()) + pathName + '?' + params.toString()
38
+ }
39
+ return Spree.pathFor(path)
40
+ }
41
+
23
42
  Spree.adminPathFor = function (path) {
24
43
  return this.pathFor('' + (this.adminPath()) + path)
25
44
  }
@@ -7,7 +7,8 @@ class Spree::BaseController < ApplicationController
7
7
  include Spree::Core::ControllerHelpers::Search
8
8
  include Spree::Core::ControllerHelpers::Store
9
9
  include Spree::Core::ControllerHelpers::StrongParameters
10
- include Spree::Core::ControllerHelpers::CurrencyHelpers
10
+ include Spree::Core::ControllerHelpers::Locale
11
+ include Spree::Core::ControllerHelpers::Currency
11
12
 
12
13
  respond_to :html
13
14
  end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ class ErrorsController < BaseController
3
+ def forbidden
4
+ render status: 403
5
+ end
6
+
7
+ def unauthorized
8
+ render status: 401
9
+ end
10
+ end
11
+ end
@@ -9,7 +9,7 @@ module Spree
9
9
  return order unless order.nil?
10
10
  return if user.nil?
11
11
 
12
- incomplete_orders.order(created_at: :desc).find_by(store: store, user: user)
12
+ incomplete_orders.order(created_at: :desc).find_by(store: store, user: user, currency: params[:currency])
13
13
  end
14
14
 
15
15
  private
@@ -7,7 +7,7 @@ module Spree
7
7
  @ids = String(params.dig(:filter, :ids)).split(',')
8
8
  @skus = String(params.dig(:filter, :skus)).split(',')
9
9
  @price = String(params.dig(:filter, :price)).split(',').map(&:to_f)
10
- @currency = params[:currency] || current_currency
10
+ @currency = current_currency
11
11
  @taxons = taxon_ids(params.dig(:filter, :taxons))
12
12
  @concat_taxons = taxon_ids(params.dig(:filter, :concat_taxons))
13
13
  @name = params.dig(:filter, :name)
@@ -22,6 +22,7 @@ module Spree
22
22
  products = by_ids(scope)
23
23
  products = by_skus(products)
24
24
  products = by_price(products)
25
+ products = by_currency(products)
25
26
  products = by_taxons(products)
26
27
  products = by_concat_taxons(products)
27
28
  products = by_name(products)
@@ -51,6 +52,10 @@ module Spree
51
52
  price.present?
52
53
  end
53
54
 
55
+ def currency?
56
+ currency.present?
57
+ end
58
+
54
59
  def taxons?
55
60
  taxons.present?
56
61
  end
@@ -94,15 +99,21 @@ module Spree
94
99
  def by_price(products)
95
100
  return products unless price?
96
101
 
97
- products.joins(master: :default_price).
102
+ products.joins(master: :prices).
98
103
  where(
99
104
  spree_prices: {
100
105
  amount: price.min..price.max,
101
- currency: currency
106
+ currency: currency&.upcase
102
107
  }
103
108
  )
104
109
  end
105
110
 
111
+ def by_currency(products)
112
+ return products unless currency?
113
+
114
+ products.joins(master: :prices).where(spree_prices: { currency: currency.upcase })
115
+ end
116
+
106
117
  def by_taxons(products)
107
118
  return products unless taxons?
108
119
 
@@ -134,7 +134,8 @@ module Spree
134
134
  [I18n.l(date.to_date, format: :long)].join(' ')
135
135
  end
136
136
 
137
- def seo_url(taxon, options = nil)
137
+ def seo_url(taxon, options = {})
138
+ options.merge(locale: locale_param)
138
139
  spree.nested_taxons_path(taxon.permalink, options)
139
140
  end
140
141
 
@@ -0,0 +1,34 @@
1
+ module Spree
2
+ module CurrencyHelper
3
+ def currency_options(selected_value = nil)
4
+ selected_value ||= Spree::Config[:currency]
5
+ currencies = ::Money::Currency.table.map do |_code, details|
6
+ iso = details[:iso_code]
7
+ [iso, "#{details[:name]} (#{iso})"]
8
+ end
9
+ options_from_collection_for_select(currencies, :first, :last, selected_value)
10
+ end
11
+
12
+ def supported_currency_options
13
+ return if current_store.nil?
14
+
15
+ current_store.supported_currencies_list.map(&:iso_code).map { |currency| currency_presentation(currency) }
16
+ end
17
+
18
+ def should_render_currency_dropdown?
19
+ return false if current_store.nil?
20
+
21
+ current_store.supported_currencies_list.size > 1
22
+ end
23
+
24
+ def currency_symbol(currency)
25
+ ::Money::Currency.find(currency).symbol
26
+ end
27
+
28
+ def currency_presentation(currency)
29
+ label = [currency_symbol(currency), currency].compact.join(' ')
30
+
31
+ [label, currency]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ module Spree
2
+ module LocaleHelper
3
+ def all_locales_options
4
+ supported_locales_for_all_stores.map { |locale| locale_presentation(locale) }
5
+ end
6
+
7
+ def available_locales_options
8
+ available_locales.map { |locale| locale_presentation(locale) }
9
+ end
10
+
11
+ def supported_locales_options
12
+ return if current_store.nil?
13
+
14
+ current_store.supported_locales_list.map { |locale| locale_presentation(locale) }
15
+ end
16
+
17
+ def locale_presentation(locale)
18
+ if I18n.exists?('spree.i18n.this_file_language', locale: locale)
19
+ [Spree.t('i18n.this_file_language', locale: locale), locale.to_s]
20
+ else
21
+ locale.to_s == 'en' ? ['English (US)', 'en'] : [locale, locale.to_s]
22
+ end
23
+ end
24
+
25
+ def should_render_locale_dropdown?
26
+ return false if current_store.nil?
27
+
28
+ current_store.supported_locales_list.size > 1
29
+ end
30
+ end
31
+ end
@@ -35,6 +35,11 @@ module Spree
35
35
  variants_option_types_presenter(variants, product).default_variant || product.default_variant
36
36
  end
37
37
 
38
+ def should_display_compare_at_price?(default_variant)
39
+ default_variant_price = default_variant.price_in(current_currency)
40
+ default_variant_price.compare_at_amount.present? && (default_variant_price.compare_at_amount > default_variant_price.amount)
41
+ end
42
+
38
43
  def used_variants_options(variants, product)
39
44
  variants_option_types_presenter(variants, product).options
40
45
  end
@@ -115,19 +120,39 @@ module Spree
115
120
  ).call.to_json
116
121
  end
117
122
 
123
+ def product_relation_types
124
+ @product_relation_types ||= @product.respond_to?(:relation_types) ? @product.relation_types : []
125
+ end
126
+
127
+ def product_relations_by_type(relation_type)
128
+ return [] if product_relation_types.none? || !@product.respond_to?(:relations)
129
+
130
+ product_ids = @product.relations.where(relation_type: relation_type).pluck(:related_to_id).uniq
131
+
132
+ return [] if product_ids.empty?
133
+
134
+ Spree::Product.
135
+ available.not_discontinued.distinct.
136
+ where(id: product_ids).
137
+ includes(
138
+ :tax_category,
139
+ master: [
140
+ :prices,
141
+ { images: { attachment_attachment: :blob } },
142
+ ]
143
+ ).
144
+ limit(Spree::Config[:products_per_page])
145
+ end
146
+
118
147
  def related_products
119
- return [] unless @product.respond_to?(:has_related_products?) && @product.has_related_products?(:related_products)
120
-
121
- @related_products ||= @product.
122
- related_products.
123
- includes(
124
- :tax_category,
125
- master: [
126
- :prices,
127
- images: { attachment_attachment: :blob },
128
- ]
129
- ).
130
- limit(Spree::Config[:products_per_page])
148
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
149
+ ProductsHelper#related_products is deprecated and will be removed in Spree 5.0.
150
+ Please use ProductsHelper#relations from now on.
151
+ DEPRECATION
152
+
153
+ return [] unless @product.respond_to?(:has_related_products?)
154
+
155
+ @related_products ||= relations_by_type('related_products')
131
156
  end
132
157
 
133
158
  def product_available_in_currency?
@@ -206,7 +206,7 @@ module Spree
206
206
  search_scopes << :available
207
207
 
208
208
  def self.active(currency = nil)
209
- available(nil, currency)
209
+ available(nil, currency&.upcase)
210
210
  end
211
211
  search_scopes << :active
212
212
 
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def payment_sources
12
- credit_cards.with_payment_profile.not_expired
12
+ credit_cards.with_payment_profile.not_expired.where(payment_method: Spree::PaymentMethod.active)
13
13
  end
14
14
 
15
15
  def drop_payment_source(source)
@@ -23,55 +23,70 @@ module Spree
23
23
  end
24
24
 
25
25
  def initialize(user)
26
- # add cancancan aliasing
27
- alias_action :delete, to: :destroy
28
- alias_action :create, :update, :destroy, to: :modify
26
+ alias_cancan_delete_action
29
27
 
30
28
  user ||= Spree.user_class.new
31
29
 
32
30
  if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
33
- can :manage, :all
31
+ apply_admin_permissions(user)
34
32
  else
35
- can :read, Country
36
- can :read, OptionType
37
- can :read, OptionValue
38
- can :create, Order
39
- can :show, Order do |order, token|
40
- order.user == user || order.token && token == order.token
41
- end
42
- can :update, Order do |order, token|
43
- !order.completed? && (order.user == user || order.token && token == order.token)
44
- end
45
- can :manage, Address, user_id: user.id
46
- can :read, CreditCard, user_id: user.id
47
- can :read, Product
48
- can :read, ProductProperty
49
- can :read, Property
50
- can :create, Spree.user_class
51
- can [:show, :update, :destroy], Spree.user_class, id: user.id
52
- can :read, State
53
- can :read, Store
54
- can :read, Taxon
55
- can :read, Taxonomy
56
- can :read, Variant
57
- can :read, Zone
33
+ apply_user_permissions(user)
58
34
  end
59
35
 
60
36
  # Include any abilities registered by extensions, etc.
37
+ # this is legacy behaviour and should be removed in Spree 5.0
61
38
  Ability.abilities.merge(abilities_to_register).each do |clazz|
62
39
  merge clazz.new(user)
63
40
  end
64
41
 
65
- # Protect admin role
66
- cannot [:update, :destroy], Role, name: ['admin']
42
+ protect_admin_role
67
43
  end
68
44
 
69
- private
45
+ protected
70
46
 
71
47
  # you can override this method to register your abilities
72
48
  # this method has to return array of classes
73
49
  def abilities_to_register
74
50
  []
75
51
  end
52
+
53
+ def alias_cancan_delete_action
54
+ alias_action :delete, to: :destroy
55
+ alias_action :create, :update, :destroy, to: :modify
56
+ end
57
+
58
+ def apply_admin_permissions(user)
59
+ can :manage, :all
60
+ end
61
+
62
+ def apply_user_permissions(user)
63
+ can :read, ::Spree::Country
64
+ can :read, ::Spree::OptionType
65
+ can :read, ::Spree::OptionValue
66
+ can :create, ::Spree::Order
67
+ can :show, ::Spree::Order do |order, token|
68
+ order.user == user || order.token && token == order.token
69
+ end
70
+ can :update, ::Spree::Order do |order, token|
71
+ !order.completed? && (order.user == user || order.token && token == order.token)
72
+ end
73
+ can :manage, ::Spree::Address, user_id: user.id
74
+ can :read, ::Spree::CreditCard, user_id: user.id
75
+ can :read, ::Spree::Product
76
+ can :read, ::Spree::ProductProperty
77
+ can :read, ::Spree::Property
78
+ can :create, ::Spree.user_class
79
+ can [:show, :update, :destroy], ::Spree.user_class, id: user.id
80
+ can :read, ::Spree::State
81
+ can :read, ::Spree::Store
82
+ can :read, ::Spree::Taxon
83
+ can :read, ::Spree::Taxonomy
84
+ can :read, ::Spree::Variant
85
+ can :read, ::Spree::Zone
86
+ end
87
+
88
+ def protect_admin_role
89
+ cannot [:update, :destroy], ::Spree::Role, name: ['admin']
90
+ end
76
91
  end
77
92
  end
@@ -68,8 +68,8 @@ module Spree
68
68
  preference :non_expiring_credit_types, :array, default: []
69
69
  preference :credit_to_new_allocation, :boolean, default: false
70
70
 
71
- # Multi currency configurations
72
- preference :show_store_currency_selector, :boolean, default: false
71
+ # Multi store configurations
72
+ preference :show_store_selector, :boolean, default: false
73
73
 
74
74
  # searcher_class allows spree extension writers to provide their own Search class
75
75
  def searcher_class
@@ -13,7 +13,7 @@ module Spree
13
13
  :completed_order_finder, :order_sorter, :cart_compare_line_items_service, :collection_paginator, :products_sorter,
14
14
  :products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service,
15
15
  :account_create_address_service, :account_update_address_service, :address_finder,
16
- :collection_sorter
16
+ :collection_sorter, :error_handler
17
17
  ].freeze
18
18
 
19
19
  attr_accessor *INJECTION_POINTS
@@ -66,6 +66,8 @@ module Spree
66
66
  # account
67
67
  @account_create_address_service = 'Spree::Account::Addresses::Create'
68
68
  @account_update_address_service = 'Spree::Account::Addresses::Update'
69
+
70
+ @error_handler = 'Spree::ErrorReporter'
69
71
  end
70
72
 
71
73
  def set_default_finders
@@ -127,6 +127,10 @@ module Spree
127
127
  "XXXX-XXXX-XXXX-#{last_digits}"
128
128
  end
129
129
 
130
+ def display_brand
131
+ brand.present? ? brand.upcase : Spree.t(:no_cc_type)
132
+ end
133
+
130
134
  def actions
131
135
  %w{capture void credit}
132
136
  end
@@ -15,13 +15,13 @@ module Spree
15
15
  width, height = size.chop.split('x')
16
16
 
17
17
  {
18
- url: polymorphic_path(attachment.variant(combine_options: {
19
- gravity: 'center',
20
- resize: size,
21
- extent: size,
22
- background: 'snow2',
23
- quality: 80
24
- }), only_path: true),
18
+ url: polymorphic_path(attachment.variant(
19
+ gravity: 'center',
20
+ resize: size,
21
+ extent: size,
22
+ background: 'snow2',
23
+ quality: 80
24
+ ), only_path: true),
25
25
  width: width,
26
26
  height: height
27
27
  }
@@ -35,13 +35,13 @@ module Spree
35
35
  width, height = size.chop.split('x')
36
36
 
37
37
  {
38
- url: polymorphic_path(attachment.variant(combine_options: {
39
- gravity: 'center',
40
- resize: size,
41
- extent: size,
42
- background: 'snow2',
43
- quality: 80
44
- }), only_path: true),
38
+ url: polymorphic_path(attachment.variant(
39
+ gravity: 'center',
40
+ resize: size,
41
+ extent: size,
42
+ background: 'snow2',
43
+ quality: 80
44
+ ), only_path: true),
45
45
  size: size,
46
46
  width: width,
47
47
  height: height