spree_core 4.3.0.rc1 → 4.3.1
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.
- checksums.yaml +4 -4
- data/app/finders/spree/products/find.rb +26 -2
- data/app/finders/spree/taxons/find.rb +22 -6
- data/app/helpers/spree/base_helper.rb +7 -5
- data/app/models/concerns/spree/display_money.rb +6 -2
- data/app/models/concerns/spree/image_methods.rb +24 -0
- data/app/models/concerns/spree/product_scopes.rb +12 -0
- data/app/models/concerns/spree/single_store_resource.rb +10 -0
- data/app/models/concerns/spree/user_methods.rb +9 -8
- data/app/models/concerns/spree/user_reporting.rb +35 -10
- data/app/models/concerns/spree/user_roles.rb +25 -0
- data/app/models/spree/app_dependencies.rb +3 -1
- data/app/models/spree/cms/sections/featured_article.rb +0 -7
- data/app/models/spree/cms/sections/hero_image.rb +0 -9
- data/app/models/spree/cms/sections/image_gallery.rb +2 -2
- data/app/models/spree/cms/sections/side_by_side_images.rb +2 -2
- data/app/models/spree/cms_section.rb +12 -0
- data/app/models/spree/gateway/bogus.rb +6 -4
- data/app/models/spree/image.rb +5 -24
- data/app/models/spree/payment_method.rb +12 -0
- data/app/models/spree/product.rb +10 -8
- data/app/models/spree/property.rb +1 -1
- data/app/models/spree/stock_location.rb +9 -0
- data/app/models/spree/store.rb +2 -2
- data/app/models/spree/taxon.rb +1 -0
- data/app/models/spree/taxon_image.rb +1 -0
- data/app/models/spree/variant.rb +9 -3
- data/app/presenters/spree/filters/options_presenter.rb +20 -0
- data/app/presenters/spree/filters/property_presenter.rb +20 -0
- data/app/services/spree/cart/associate.rb +16 -0
- data/app/services/spree/cart/change_currency.rb +27 -0
- data/app/sorters/spree/base_sorter.rb +23 -11
- data/app/sorters/spree/products/sort.rb +23 -7
- data/config/locales/en.yml +11 -1
- data/db/migrate/20210527094055_create_spree_products_stores.rb +15 -8
- data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
- data/lib/generators/spree/dummy/templates/rails/test.rb +2 -0
- data/lib/spree/core/controller_helpers/store.rb +14 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/permitted_attributes.rb +7 -0
- data/lib/spree/testing_support/factories/product_factory.rb +6 -0
- data/lib/spree/testing_support/locale_helpers.rb +1 -1
- data/lib/spree/testing_support/rspec_retry_config.rb +5 -0
- data/spree_core.gemspec +1 -1
- metadata +10 -7
- data/app/views/spree/shared/_purchased_items_table.text.erb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9362a52bbabd7b09ffc2bc0271bffc4a2d11bc311d7356b56db0271c79f0740
|
4
|
+
data.tar.gz: 41a19d295a5dad9f3b2dadfe07fe73210e5a57139cc82eeb170d9d2d6e143910
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b75ef727652e108dd4c34cf10bf2ab1d82abff4c9283ce2ee3c00078b328dbbcdcc38d729f7a1fa75d7a773470e48e5b3ce02d36d6cd33fbed5f8906dadfa944
|
7
|
+
data.tar.gz: eeaaf0d1aaa49aaaafd30b55ddc04e50ddcdc922ecd7779e9b98283ca5c8ac4e5fd899c73d770e8cbaa93474e25b3af40e0747612cb761e825afeb36988d2254
|
@@ -27,6 +27,9 @@ module Spree
|
|
27
27
|
@deleted = params.dig(:filter, :show_deleted)
|
28
28
|
@discontinued = params.dig(:filter, :show_discontinued)
|
29
29
|
@properties = params.dig(:filter, :properties)
|
30
|
+
@in_stock = params.dig(:filter, :in_stock)
|
31
|
+
@backorderable = params.dig(:filter, :backorderable)
|
32
|
+
@purchasable = params.dig(:filter, :purchasable)
|
30
33
|
end
|
31
34
|
|
32
35
|
def execute
|
@@ -42,6 +45,9 @@ module Spree
|
|
42
45
|
products = by_properties(products)
|
43
46
|
products = include_deleted(products)
|
44
47
|
products = include_discontinued(products)
|
48
|
+
products = show_only_stock(products)
|
49
|
+
products = show_only_backorderable(products)
|
50
|
+
products = show_only_purchasable(products)
|
45
51
|
products = ordered(products)
|
46
52
|
|
47
53
|
products.distinct
|
@@ -49,8 +55,8 @@ module Spree
|
|
49
55
|
|
50
56
|
private
|
51
57
|
|
52
|
-
attr_reader :ids, :skus, :price, :currency, :taxons, :concat_taxons, :name, :options,
|
53
|
-
:
|
58
|
+
attr_reader :ids, :skus, :price, :currency, :taxons, :concat_taxons, :name, :options, :option_value_ids, :scope,
|
59
|
+
:sort_by, :deleted, :discontinued, :properties, :store, :in_stock, :backorderable, :purchasable
|
54
60
|
|
55
61
|
def ids?
|
56
62
|
ids.present?
|
@@ -231,6 +237,24 @@ module Spree
|
|
231
237
|
discontinued ? products : products.active(currency)
|
232
238
|
end
|
233
239
|
|
240
|
+
def show_only_stock(products)
|
241
|
+
return products unless in_stock.to_s == 'true'
|
242
|
+
|
243
|
+
products.in_stock
|
244
|
+
end
|
245
|
+
|
246
|
+
def show_only_backorderable(products)
|
247
|
+
return products unless backorderable.to_s == 'true'
|
248
|
+
|
249
|
+
products.backorderable
|
250
|
+
end
|
251
|
+
|
252
|
+
def show_only_purchasable(products)
|
253
|
+
return products unless purchasable.to_s == 'true'
|
254
|
+
|
255
|
+
products.in_stock_or_backorderable
|
256
|
+
end
|
257
|
+
|
234
258
|
def map_prices(prices)
|
235
259
|
prices.map do |price|
|
236
260
|
price == 'Infinity' ? Float::INFINITY : price.to_f
|
@@ -3,16 +3,18 @@ module Spree
|
|
3
3
|
class Find
|
4
4
|
def initialize(scope:, params:)
|
5
5
|
@scope = scope
|
6
|
-
@ids
|
7
|
-
@parent
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
6
|
+
@ids = String(params.dig(:filter, :ids)).split(',')
|
7
|
+
@parent = params.dig(:filter, :parent_id)
|
8
|
+
@parent_permalink = params.dig(:filter, :parent_permalink)
|
9
|
+
@taxonomy = params.dig(:filter, :taxonomy_id)
|
10
|
+
@name = params.dig(:filter, :name)
|
11
|
+
@roots = params.dig(:filter, :roots)
|
11
12
|
end
|
12
13
|
|
13
14
|
def execute
|
14
15
|
taxons = by_ids(scope)
|
15
16
|
taxons = by_parent(taxons)
|
17
|
+
taxons = by_parent_permalink(taxons)
|
16
18
|
taxons = by_taxonomy(taxons)
|
17
19
|
taxons = by_roots(taxons)
|
18
20
|
taxons = by_name(taxons)
|
@@ -22,7 +24,7 @@ module Spree
|
|
22
24
|
|
23
25
|
private
|
24
26
|
|
25
|
-
attr_reader :ids, :parent, :taxonomy, :roots, :name, :scope
|
27
|
+
attr_reader :ids, :parent, :parent_permalink, :taxonomy, :roots, :name, :scope
|
26
28
|
|
27
29
|
def ids?
|
28
30
|
ids.present?
|
@@ -32,6 +34,10 @@ module Spree
|
|
32
34
|
parent.present?
|
33
35
|
end
|
34
36
|
|
37
|
+
def parent_permalink?
|
38
|
+
parent_permalink.present?
|
39
|
+
end
|
40
|
+
|
35
41
|
def taxonomy?
|
36
42
|
taxonomy.present?
|
37
43
|
end
|
@@ -60,6 +66,16 @@ module Spree
|
|
60
66
|
taxons.where(parent_id: parent)
|
61
67
|
end
|
62
68
|
|
69
|
+
def by_parent_permalink(taxons)
|
70
|
+
return taxons unless parent_permalink?
|
71
|
+
|
72
|
+
if Rails::VERSION::STRING >= '6.1'
|
73
|
+
taxons.joins(:parent).where(parent: { permalink: parent_permalink })
|
74
|
+
else
|
75
|
+
taxons.joins("INNER JOIN #{Spree::Taxon.table_name} AS parent_taxon ON parent_taxon.id = #{Spree::Taxon.table_name}.parent_id").where(["parent_taxon.permalink = ?", parent_permalink])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
63
79
|
def by_taxonomy(taxons)
|
64
80
|
return taxons unless taxonomy?
|
65
81
|
|
@@ -246,11 +246,13 @@ module Spree
|
|
246
246
|
options = options.first || {}
|
247
247
|
options[:alt] ||= product.name
|
248
248
|
image_path = default_image_for_product_or_variant(product)
|
249
|
-
if image_path.present?
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
249
|
+
img = if image_path.present?
|
250
|
+
create_product_image_tag image_path, product, options, style
|
251
|
+
else
|
252
|
+
inline_svg_tag "noimage/backend-missing-image.svg", class: "noimage", size: "60%*60%"
|
253
|
+
end
|
254
|
+
|
255
|
+
content_tag(:div, img, class: "admin-product-image-container #{style}-img")
|
254
256
|
end
|
255
257
|
end
|
256
258
|
|
@@ -17,13 +17,17 @@ module Spree
|
|
17
17
|
# Decorate a method, but with some additional options
|
18
18
|
# extend Spree::DisplayMoney
|
19
19
|
# money_methods tax_amount: { currency: "CAD", no_cents: true }, :price
|
20
|
+
# Use generated method with the same arguments as in wrapped method
|
21
|
+
# def tax_amount(order, country)
|
22
|
+
# display_tax_amount(order, country)
|
20
23
|
def money_methods(*args)
|
21
24
|
args.each do |money_method|
|
22
25
|
money_method = { money_method => {} } unless money_method.is_a? Hash
|
23
26
|
money_method.each do |method_name, opts|
|
24
|
-
define_method("display_#{method_name}") do
|
27
|
+
define_method("display_#{method_name}") do |**args_list|
|
25
28
|
default_opts = respond_to?(:currency) ? { currency: currency } : {}
|
26
|
-
|
29
|
+
|
30
|
+
Spree::Money.new(send(method_name, **args_list), default_opts.merge(opts).merge(args_list.slice(:currency)))
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Spree
|
2
|
+
module ImageMethods
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def generate_url(size:, gravity: 'center', quality: 80, background: 'show')
|
6
|
+
return if size.blank?
|
7
|
+
size = size.gsub(/\s+/, '')
|
8
|
+
|
9
|
+
return unless size.match(/(\d+)x(\d+)/)
|
10
|
+
|
11
|
+
polymorphic_path(attachment.variant(
|
12
|
+
gravity: gravity,
|
13
|
+
resize: size,
|
14
|
+
extent: size,
|
15
|
+
background: background,
|
16
|
+
quality: quality.to_i
|
17
|
+
), only_path: true)
|
18
|
+
end
|
19
|
+
|
20
|
+
def original_url
|
21
|
+
polymorphic_path(attachment, only_path: true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -62,6 +62,18 @@ module Spree
|
|
62
62
|
where("#{price_table_name}.amount >= ?", price)
|
63
63
|
end
|
64
64
|
|
65
|
+
add_search_scope :in_stock do
|
66
|
+
joins(:variants_including_master).merge(Spree::Variant.in_stock)
|
67
|
+
end
|
68
|
+
|
69
|
+
add_search_scope :backorderable do
|
70
|
+
joins(:variants_including_master).merge(Spree::Variant.backorderable)
|
71
|
+
end
|
72
|
+
|
73
|
+
add_search_scope :in_stock_or_backorderable do
|
74
|
+
joins(:variants_including_master).merge(Spree::Variant.in_stock_or_backorderable)
|
75
|
+
end
|
76
|
+
|
65
77
|
# This scope selects products in taxon AND all its descendants
|
66
78
|
# If you need products only within one taxon use
|
67
79
|
#
|
@@ -3,7 +3,17 @@ module Spree
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
+
validate :ensure_store_association_is_not_changed
|
7
|
+
|
6
8
|
scope :for_store, ->(store) { where(store_id: store.id) }
|
7
9
|
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def ensure_store_association_is_not_changed
|
14
|
+
if store_id_changed? && persisted?
|
15
|
+
errors.add(:store, Spree.t('errors.messages.store_association_can_not_be_changed'))
|
16
|
+
end
|
17
|
+
end
|
8
18
|
end
|
9
19
|
end
|
@@ -4,6 +4,7 @@ module Spree
|
|
4
4
|
|
5
5
|
include Spree::UserPaymentSource
|
6
6
|
include Spree::UserReporting
|
7
|
+
include Spree::UserRoles
|
7
8
|
include Spree::RansackableAttributes
|
8
9
|
|
9
10
|
included do
|
@@ -15,9 +16,6 @@ module Spree
|
|
15
16
|
|
16
17
|
attr_accessor :use_billing
|
17
18
|
|
18
|
-
has_many :role_users, class_name: 'Spree::RoleUser', foreign_key: :user_id, dependent: :destroy
|
19
|
-
has_many :spree_roles, through: :role_users, class_name: 'Spree::Role', source: :role
|
20
|
-
|
21
19
|
has_many :promotion_rule_users, class_name: 'Spree::PromotionRuleUser', foreign_key: :user_id, dependent: :destroy
|
22
20
|
has_many :promotion_rules, through: :promotion_rule_users, class_name: 'Spree::PromotionRule'
|
23
21
|
|
@@ -47,11 +45,6 @@ module Spree
|
|
47
45
|
end
|
48
46
|
end
|
49
47
|
|
50
|
-
# has_spree_role? simply needs to return true or false whether a user has a role or not.
|
51
|
-
def has_spree_role?(role_in_question)
|
52
|
-
spree_roles.any? { |role| role.name == role_in_question.to_s }
|
53
|
-
end
|
54
|
-
|
55
48
|
def last_incomplete_spree_order(store, options = {})
|
56
49
|
orders.where(store: store).incomplete.
|
57
50
|
includes(options[:includes]).
|
@@ -65,6 +58,14 @@ module Spree
|
|
65
58
|
store_credits.for_store(store).where(currency: currency).reload.to_a.sum(&:amount_remaining)
|
66
59
|
end
|
67
60
|
|
61
|
+
def available_store_credits(store)
|
62
|
+
store ||= Store.default
|
63
|
+
|
64
|
+
store_credits.for_store(store).pluck(:currency).uniq.each_with_object([]) do |currency, arr|
|
65
|
+
arr << Spree::Money.new(total_available_store_credit(currency, store), currency: currency)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
68
69
|
private
|
69
70
|
|
70
71
|
def check_completed_orders
|
@@ -3,20 +3,45 @@ module Spree
|
|
3
3
|
extend DisplayMoney
|
4
4
|
money_methods :lifetime_value, :average_order_value
|
5
5
|
|
6
|
-
def
|
7
|
-
|
6
|
+
def report_values_for(report_name, store)
|
7
|
+
store ||= Store.default
|
8
|
+
|
9
|
+
completed_orders(store).pluck(:currency).uniq.each_with_object([]) do |currency, arr|
|
10
|
+
arr << send("display_#{report_name}", store: store, currency: currency)
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
|
-
def
|
11
|
-
|
14
|
+
def lifetime_value(**args)
|
15
|
+
order_calculate(operation: :sum,
|
16
|
+
column: :total,
|
17
|
+
**args)
|
12
18
|
end
|
13
19
|
|
14
|
-
def average_order_value
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
def average_order_value(**args)
|
21
|
+
order_calculate(operation: :average,
|
22
|
+
column: :total,
|
23
|
+
**args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def order_count(store = nil)
|
27
|
+
store ||= Store.default
|
28
|
+
order_calculate(store: store,
|
29
|
+
currency: store.supported_currencies.split(','),
|
30
|
+
operation: :count,
|
31
|
+
column: :all)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def order_calculate(operation:, column:, store: nil, currency: nil)
|
37
|
+
store ||= Store.default
|
38
|
+
currency ||= store.default_currency
|
39
|
+
|
40
|
+
completed_orders(store).where(currency: currency).calculate(operation, column) || BigDecimal('0.00')
|
41
|
+
end
|
42
|
+
|
43
|
+
def completed_orders(store)
|
44
|
+
orders.for_store(store).complete
|
20
45
|
end
|
21
46
|
end
|
22
47
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spree
|
2
|
+
module UserRoles
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :role_users, class_name: 'Spree::RoleUser', foreign_key: :user_id, dependent: :destroy
|
7
|
+
has_many :spree_roles, through: :role_users, class_name: 'Spree::Role', source: :role
|
8
|
+
|
9
|
+
scope :admin, -> { joins(:spree_roles).where(Spree::Role.table_name => { name: 'admin' }) }
|
10
|
+
|
11
|
+
# has_spree_role? simply needs to return true or false whether a user has a role or not.
|
12
|
+
def has_spree_role?(role_name)
|
13
|
+
spree_roles.exists?(name: role_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.admin_created?
|
17
|
+
admin.exists?
|
18
|
+
end
|
19
|
+
|
20
|
+
def admin?
|
21
|
+
has_spree_role?('admin')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
:products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service,
|
14
14
|
:account_create_address_service, :account_update_address_service, :account_create_service, :account_update_service,
|
15
15
|
:address_finder, :collection_sorter, :error_handler, :current_store_finder, :cart_empty_service, :cart_destroy_service,
|
16
|
-
:classification_reposition_service, :credit_cards_destroy_service
|
16
|
+
:classification_reposition_service, :credit_cards_destroy_service, :cart_associate_service, :cart_change_currency_service
|
17
17
|
].freeze
|
18
18
|
|
19
19
|
attr_accessor *INJECTION_POINTS
|
@@ -43,6 +43,8 @@ module Spree
|
|
43
43
|
@cart_estimate_shipping_rates_service = 'Spree::Cart::EstimateShippingRates'
|
44
44
|
@cart_empty_service = 'Spree::Cart::Empty'
|
45
45
|
@cart_destroy_service = 'Spree::Cart::Destroy'
|
46
|
+
@cart_associate_service = 'Spree::Cart::Associate'
|
47
|
+
@cart_change_currency_service = 'Spree::Cart::ChangeCurrency'
|
46
48
|
|
47
49
|
# checkout
|
48
50
|
@checkout_next_service = 'Spree::Checkout::Next'
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Spree::Cms::Sections
|
2
2
|
class FeaturedArticle < Spree::CmsSection
|
3
|
-
before_save :reset_link_attributes
|
4
3
|
after_initialize :default_values
|
5
4
|
|
6
5
|
store :content, accessors: [:title, :subtitle, :button_text, :rte_content], coder: JSON
|
@@ -14,12 +13,6 @@ module Spree::Cms::Sections
|
|
14
13
|
|
15
14
|
private
|
16
15
|
|
17
|
-
def reset_link_attributes
|
18
|
-
if linked_resource_type_changed?
|
19
|
-
self.linked_resource_id = nil
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
16
|
def default_values
|
24
17
|
self.gutters ||= 'No Gutters'
|
25
18
|
self.fit ||= 'Screen'
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Spree::Cms::Sections
|
2
2
|
class HeroImage < Spree::CmsSection
|
3
|
-
before_save :reset_link_attributes
|
4
3
|
after_initialize :default_values
|
5
4
|
|
6
5
|
store :content, accessors: [:title, :button_text], coder: JSON
|
@@ -30,14 +29,6 @@ module Spree::Cms::Sections
|
|
30
29
|
|
31
30
|
private
|
32
31
|
|
33
|
-
def reset_link_attributes
|
34
|
-
if linked_resource_type_changed?
|
35
|
-
return if linked_resource_id_was.nil?
|
36
|
-
|
37
|
-
self.linked_resource_id = nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
32
|
def default_values
|
42
33
|
self.gutters ||= 'No Gutters'
|
43
34
|
self.fit ||= 'Screen'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spree::Cms::Sections
|
2
2
|
class ImageGallery < Spree::CmsSection
|
3
3
|
after_initialize :default_values
|
4
|
-
|
4
|
+
validate :reset_multiple_link_attributes
|
5
5
|
|
6
6
|
LINKED_RESOURCE_TYPE = if Rails::VERSION::STRING < '6.0'
|
7
7
|
['Spree::Taxon'].freeze
|
@@ -70,7 +70,7 @@ module Spree::Cms::Sections
|
|
70
70
|
|
71
71
|
private
|
72
72
|
|
73
|
-
def
|
73
|
+
def reset_multiple_link_attributes
|
74
74
|
return if Rails::VERSION::STRING < '6.0'
|
75
75
|
|
76
76
|
if link_type_one_changed?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spree::Cms::Sections
|
2
2
|
class SideBySideImages < Spree::CmsSection
|
3
3
|
after_initialize :default_values
|
4
|
-
|
4
|
+
validate :reset_multiple_link_attributes
|
5
5
|
|
6
6
|
LINKED_RESOURCE_TYPE = if Rails::VERSION::STRING < '6.0'
|
7
7
|
['Spree::Taxon'].freeze
|
@@ -48,7 +48,7 @@ module Spree::Cms::Sections
|
|
48
48
|
|
49
49
|
private
|
50
50
|
|
51
|
-
def
|
51
|
+
def reset_multiple_link_attributes
|
52
52
|
return if Rails::VERSION::STRING < '6.0'
|
53
53
|
|
54
54
|
if link_type_one_changed?
|
@@ -5,6 +5,8 @@ module Spree
|
|
5
5
|
acts_as_list scope: :cms_page
|
6
6
|
belongs_to :cms_page, touch: true
|
7
7
|
|
8
|
+
validate :reset_link_attributes
|
9
|
+
|
8
10
|
IMAGE_COUNT = ['one', 'two', 'three']
|
9
11
|
IMAGE_TYPES = ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'].freeze
|
10
12
|
IMAGE_SIZE = ['sm', 'md', 'lg', 'xl']
|
@@ -53,5 +55,15 @@ module Spree
|
|
53
55
|
def fullscreen?
|
54
56
|
fit == 'Screen'
|
55
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def reset_link_attributes
|
62
|
+
if linked_resource_type_changed?
|
63
|
+
return if linked_resource_id_was.nil?
|
64
|
+
|
65
|
+
self.linked_resource_id = nil
|
66
|
+
end
|
67
|
+
end
|
56
68
|
end
|
57
69
|
end
|
@@ -9,14 +9,12 @@ module Spree
|
|
9
9
|
|
10
10
|
attr_accessor :test
|
11
11
|
|
12
|
+
preference :dummy_key, :string, default: 'PUBLICKEY123'
|
13
|
+
|
12
14
|
def provider_class
|
13
15
|
self.class
|
14
16
|
end
|
15
17
|
|
16
|
-
def preferences
|
17
|
-
{}
|
18
|
-
end
|
19
|
-
|
20
18
|
def create_profile(payment)
|
21
19
|
return if payment.source.has_payment_profile?
|
22
20
|
|
@@ -88,5 +86,9 @@ module Spree
|
|
88
86
|
end
|
89
87
|
random
|
90
88
|
end
|
89
|
+
|
90
|
+
def public_preference_keys
|
91
|
+
[:dummy_key]
|
92
|
+
end
|
91
93
|
end
|
92
94
|
end
|
data/app/models/spree/image.rb
CHANGED
@@ -2,6 +2,7 @@ module Spree
|
|
2
2
|
class Image < Asset
|
3
3
|
include Configuration::ActiveStorage
|
4
4
|
include Rails.application.routes.url_helpers
|
5
|
+
include ::Spree::ImageMethods
|
5
6
|
|
6
7
|
# In Rails 5.x class constants are being undefined/redefined during the code reloading process
|
7
8
|
# in a rails development environment, after which the actual ruby objects stored in those class constants
|
@@ -15,13 +16,8 @@ module Spree
|
|
15
16
|
width, height = size.chop.split('x')
|
16
17
|
|
17
18
|
{
|
18
|
-
url:
|
19
|
-
|
20
|
-
resize: size,
|
21
|
-
extent: size,
|
22
|
-
background: 'snow2',
|
23
|
-
quality: 80
|
24
|
-
), only_path: true),
|
19
|
+
url: generate_url(size: size),
|
20
|
+
size: size,
|
25
21
|
width: width,
|
26
22
|
height: height
|
27
23
|
}
|
@@ -35,13 +31,7 @@ module Spree
|
|
35
31
|
width, height = size.chop.split('x')
|
36
32
|
|
37
33
|
{
|
38
|
-
url:
|
39
|
-
gravity: 'center',
|
40
|
-
resize: size,
|
41
|
-
extent: size,
|
42
|
-
background: 'snow2',
|
43
|
-
quality: 80
|
44
|
-
), only_path: true),
|
34
|
+
url: generate_url(size: size),
|
45
35
|
size: size,
|
46
36
|
width: width,
|
47
37
|
height: height
|
@@ -59,16 +49,7 @@ module Spree
|
|
59
49
|
end
|
60
50
|
|
61
51
|
def plp_url
|
62
|
-
size
|
63
|
-
variant = attachment.variant(
|
64
|
-
gravity: 'center',
|
65
|
-
resize: size,
|
66
|
-
extent: size,
|
67
|
-
background: 'snow2',
|
68
|
-
quality: 80
|
69
|
-
)
|
70
|
-
|
71
|
-
polymorphic_path(variant, only_path: true)
|
52
|
+
generate_url(size: self.class.styles[:plp_and_carousel])
|
72
53
|
end
|
73
54
|
end
|
74
55
|
end
|
@@ -87,5 +87,17 @@ module Spree
|
|
87
87
|
|
88
88
|
store_ids.include?(store.id)
|
89
89
|
end
|
90
|
+
|
91
|
+
def public_preferences
|
92
|
+
public_preference_keys.each_with_object({}) do |key, hash|
|
93
|
+
hash[key] = preferences[key]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def public_preference_keys
|
100
|
+
[]
|
101
|
+
end
|
90
102
|
end
|
91
103
|
end
|
data/app/models/spree/product.rb
CHANGED
@@ -142,17 +142,17 @@ module Spree
|
|
142
142
|
|
143
143
|
# Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
|
144
144
|
def purchasable?
|
145
|
-
|
145
|
+
default_variant.purchasable? || variants.any?(&:purchasable?)
|
146
146
|
end
|
147
147
|
|
148
148
|
# Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
|
149
149
|
def in_stock?
|
150
|
-
|
150
|
+
default_variant.in_stock? || variants.any?(&:in_stock?)
|
151
151
|
end
|
152
152
|
|
153
153
|
# Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
|
154
154
|
def backorderable?
|
155
|
-
|
155
|
+
default_variant.backorderable? || variants.any?(&:backorderable?)
|
156
156
|
end
|
157
157
|
|
158
158
|
def find_or_build_master
|
@@ -301,11 +301,13 @@ module Spree
|
|
301
301
|
end
|
302
302
|
|
303
303
|
def total_on_hand
|
304
|
-
@total_on_hand ||=
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
304
|
+
@total_on_hand ||= Rails.cache.fetch(['product-total-on-hand', cache_key_with_version]) do
|
305
|
+
if any_variants_not_track_inventory?
|
306
|
+
Float::INFINITY
|
307
|
+
else
|
308
|
+
stock_items.sum(:count_on_hand)
|
309
|
+
end
|
310
|
+
end
|
309
311
|
end
|
310
312
|
|
311
313
|
# Master variant may be deleted (i.e. when the product is deleted)
|
@@ -18,7 +18,7 @@ module Spree
|
|
18
18
|
after_touch :touch_all_products
|
19
19
|
after_save :ensure_product_properties_have_filter_params
|
20
20
|
|
21
|
-
self.whitelisted_ransackable_attributes = ['presentation']
|
21
|
+
self.whitelisted_ransackable_attributes = ['presentation', 'filterable']
|
22
22
|
|
23
23
|
def uniq_values(product_properties_scope: nil)
|
24
24
|
with_uniq_values_cache_key(product_properties_scope) do
|
@@ -2,6 +2,7 @@ module Spree
|
|
2
2
|
class StockLocation < Spree::Base
|
3
3
|
has_many :shipments
|
4
4
|
has_many :stock_items, dependent: :delete_all, inverse_of: :stock_location
|
5
|
+
has_many :variants, through: :stock_items
|
5
6
|
has_many :stock_movements, through: :stock_items
|
6
7
|
|
7
8
|
belongs_to :state, class_name: 'Spree::State', optional: true
|
@@ -14,6 +15,7 @@ module Spree
|
|
14
15
|
|
15
16
|
after_create :create_stock_items, if: :propagate_all_variants?
|
16
17
|
after_save :ensure_one_default
|
18
|
+
after_update :conditional_touch_records
|
17
19
|
|
18
20
|
def state_text
|
19
21
|
state.try(:abbr) || state.try(:name) || state_name
|
@@ -134,5 +136,12 @@ module Spree
|
|
134
136
|
StockLocation.where(default: true).where.not(id: id).update_all(default: false)
|
135
137
|
end
|
136
138
|
end
|
139
|
+
|
140
|
+
def conditional_touch_records
|
141
|
+
return unless active_changed?
|
142
|
+
|
143
|
+
stock_items.update_all(updated_at: Time.current)
|
144
|
+
variants.update_all(updated_at: Time.current)
|
145
|
+
end
|
137
146
|
end
|
138
147
|
end
|
data/app/models/spree/store.rb
CHANGED
@@ -76,8 +76,8 @@ module Spree
|
|
76
76
|
|
77
77
|
def self.current(url = nil)
|
78
78
|
ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
|
79
|
-
`Spree::Store.current` is deprecated and will be removed in Spree 5
|
80
|
-
Spree::Stores::FindCurrent.new(url: "
|
79
|
+
`Spree::Store.current` is deprecated and will be removed in Spree 5.0
|
80
|
+
Please use `Spree::Stores::FindCurrent.new(url: "https://example.com").execute` instead
|
81
81
|
DEPRECATION
|
82
82
|
Stores::FindCurrent.new(url: url).execute
|
83
83
|
end
|
data/app/models/spree/taxon.rb
CHANGED
@@ -44,6 +44,7 @@ module Spree
|
|
44
44
|
scope :for_store, ->(store) { joins(:taxonomy).where(spree_taxonomies: { store_id: store.id }) }
|
45
45
|
|
46
46
|
self.whitelisted_ransackable_associations = %w[taxonomy]
|
47
|
+
self.whitelisted_ransackable_attributes = %w[name permalink]
|
47
48
|
|
48
49
|
scope :for_stores, ->(stores) { joins(:taxonomy).where(spree_taxonomies: { store_id: stores.ids }) }
|
49
50
|
|
data/app/models/spree/variant.rb
CHANGED
@@ -60,7 +60,7 @@ module Spree
|
|
60
60
|
|
61
61
|
after_touch :clear_in_stock_cache
|
62
62
|
|
63
|
-
scope :in_stock, -> { joins(:stock_items).where(
|
63
|
+
scope :in_stock, -> { joins(:stock_items).where("#{Spree::StockItem.table_name}.count_on_hand > ? OR #{Spree::Variant.table_name}.track_inventory = ?", 0, false) }
|
64
64
|
scope :backorderable, -> { joins(:stock_items).where(spree_stock_items: { backorderable: true }) }
|
65
65
|
scope :in_stock_or_backorderable, -> { in_stock.or(backorderable) }
|
66
66
|
|
@@ -256,7 +256,13 @@ module Spree
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
|
-
|
259
|
+
def backorderable?
|
260
|
+
@backorderable ||= Rails.cache.fetch(['variant-backorderable', cache_key_with_version]) do
|
261
|
+
quantifier.backorderable?
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
delegate :total_on_hand, :can_supply?, to: :quantifier
|
260
266
|
|
261
267
|
alias is_backorderable? backorderable?
|
262
268
|
|
@@ -291,7 +297,7 @@ module Spree
|
|
291
297
|
end
|
292
298
|
|
293
299
|
def backordered?
|
294
|
-
@backordered ||=
|
300
|
+
@backordered ||= !in_stock? && stock_items.exists?(backorderable: true)
|
295
301
|
end
|
296
302
|
|
297
303
|
private
|
@@ -3,6 +3,26 @@ module Spree
|
|
3
3
|
class OptionsPresenter
|
4
4
|
FilterableOptionType = Struct.new(:option_type, :option_values, keyword_init: true) do
|
5
5
|
delegate_missing_to :option_type
|
6
|
+
|
7
|
+
def to_h
|
8
|
+
{
|
9
|
+
id: option_type.id,
|
10
|
+
name: option_type.name,
|
11
|
+
presentation: option_type.presentation,
|
12
|
+
option_values: option_values.map { |e| option_value_hash(e) }
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def option_value_hash(option_value)
|
19
|
+
{
|
20
|
+
id: option_value.id,
|
21
|
+
name: option_value.name,
|
22
|
+
presentation: option_value.presentation,
|
23
|
+
position: option_value.position
|
24
|
+
}
|
25
|
+
end
|
6
26
|
end
|
7
27
|
|
8
28
|
def initialize(option_values_scope:)
|
@@ -14,9 +14,29 @@ module Spree
|
|
14
14
|
property.uniq_values(product_properties_scope: product_properties)
|
15
15
|
end
|
16
16
|
|
17
|
+
def to_h
|
18
|
+
{
|
19
|
+
id: property.id,
|
20
|
+
name: property.name,
|
21
|
+
presentation: property.presentation,
|
22
|
+
values: values_hash
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
17
26
|
private
|
18
27
|
|
19
28
|
attr_reader :property
|
29
|
+
|
30
|
+
def values_hash
|
31
|
+
value_hashes = uniq_values.map do |filter_param, value|
|
32
|
+
{
|
33
|
+
value: value,
|
34
|
+
filter_param: filter_param
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
value_hashes.sort_by { |e| e[:value] }
|
39
|
+
end
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Spree
|
2
|
+
module Cart
|
3
|
+
class Associate
|
4
|
+
prepend Spree::ServiceModule::Base
|
5
|
+
|
6
|
+
def call(guest_order:, user:)
|
7
|
+
if guest_order.user.nil?
|
8
|
+
guest_order.associate_user!(user)
|
9
|
+
success(guest_order)
|
10
|
+
else
|
11
|
+
failure(guest_order, 'Already assigned to a user')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spree
|
2
|
+
module Cart
|
3
|
+
class ChangeCurrency
|
4
|
+
prepend Spree::ServiceModule::Base
|
5
|
+
|
6
|
+
def call(order:, new_currency:)
|
7
|
+
return failure('Currency not supported') unless supported_currency?(order, new_currency)
|
8
|
+
|
9
|
+
result = order.update!(currency: new_currency) rescue false
|
10
|
+
|
11
|
+
if result
|
12
|
+
success(order)
|
13
|
+
else
|
14
|
+
failure('Failed to update order')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def supported_currency?(order, currency)
|
21
|
+
store = order.store
|
22
|
+
supported_currencies = store.supported_currencies_list
|
23
|
+
supported_currencies.map(&:iso_code).include?(currency.upcase)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,34 +2,46 @@ module Spree
|
|
2
2
|
class BaseSorter
|
3
3
|
def initialize(scope, params = {}, allowed_sort_attributes = [])
|
4
4
|
@scope = scope
|
5
|
-
@sort = params[:sort]
|
6
5
|
@allowed_sort_attributes = allowed_sort_attributes
|
6
|
+
@sort = sort_fields(params[:sort])
|
7
7
|
end
|
8
8
|
|
9
9
|
def call
|
10
|
-
|
10
|
+
by_param_attributes(scope)
|
11
11
|
end
|
12
12
|
|
13
13
|
protected
|
14
14
|
|
15
15
|
attr_reader :scope, :collection, :sort, :allowed_sort_attributes
|
16
16
|
|
17
|
-
def
|
18
|
-
return scope if
|
17
|
+
def by_param_attributes(scope)
|
18
|
+
return scope if sort.empty?
|
19
19
|
|
20
|
-
|
20
|
+
sort.each do |value, order|
|
21
|
+
next if value.blank? || allowed_sort_attributes.exclude?(value.to_sym)
|
22
|
+
|
23
|
+
scope = scope.order("#{value}": order)
|
24
|
+
end
|
25
|
+
|
26
|
+
scope
|
27
|
+
end
|
28
|
+
|
29
|
+
def sort_fields(sort)
|
30
|
+
return [] if sort.nil?
|
31
|
+
|
32
|
+
sort.split(',').map { |field| [sort_field(field), order_direction(field)] }
|
21
33
|
end
|
22
34
|
|
23
|
-
def desc_order
|
24
|
-
|
35
|
+
def desc_order(field)
|
36
|
+
String(field)[0] == '-'
|
25
37
|
end
|
26
38
|
|
27
|
-
def sort_field
|
28
|
-
|
39
|
+
def sort_field(field)
|
40
|
+
desc_order(field) ? field[1..-1] : field
|
29
41
|
end
|
30
42
|
|
31
|
-
def order_direction
|
32
|
-
desc_order ? :desc : :asc
|
43
|
+
def order_direction(field)
|
44
|
+
desc_order(field) ? :desc : :asc
|
33
45
|
end
|
34
46
|
end
|
35
47
|
end
|
@@ -7,8 +7,9 @@ module Spree
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call
|
10
|
-
products =
|
10
|
+
products = by_param_attributes(scope)
|
11
11
|
products = by_price(products)
|
12
|
+
products = by_sku(products)
|
12
13
|
|
13
14
|
products.distinct
|
14
15
|
end
|
@@ -17,18 +18,33 @@ module Spree
|
|
17
18
|
|
18
19
|
attr_reader :sort, :scope, :currency, :allowed_sort_attributes
|
19
20
|
|
20
|
-
def price?
|
21
|
-
sort_field == 'price'
|
22
|
-
end
|
23
|
-
|
24
21
|
def by_price(scope)
|
25
|
-
return scope unless price
|
22
|
+
return scope unless (value = sort_by?('price'))
|
26
23
|
|
27
24
|
scope.joins(master: :prices).
|
28
25
|
select("#{Spree::Product.table_name}.*, #{Spree::Price.table_name}.amount").
|
29
26
|
distinct.
|
30
27
|
where(spree_prices: { currency: currency }).
|
31
|
-
order("#{Spree::Price.table_name}.amount #{
|
28
|
+
order("#{Spree::Price.table_name}.amount #{value[1]}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def by_sku(scope)
|
32
|
+
return scope unless (value = sort_by?('sku'))
|
33
|
+
|
34
|
+
select_product_attributes = if scope.to_sql.include?("#{Spree::Product.table_name}.*")
|
35
|
+
''
|
36
|
+
else
|
37
|
+
"#{Spree::Product.table_name}.*, "
|
38
|
+
end
|
39
|
+
|
40
|
+
scope.joins(:master).
|
41
|
+
select("#{select_product_attributes}#{Spree::Variant.table_name}.sku").
|
42
|
+
where(Spree::Variant.table_name.to_s => { is_master: true }).
|
43
|
+
order("#{Spree::Variant.table_name}.sku #{value[1]}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def sort_by?(field)
|
47
|
+
sort.detect { |s| s[0] == field }
|
32
48
|
end
|
33
49
|
end
|
34
50
|
end
|
data/config/locales/en.yml
CHANGED
@@ -184,6 +184,12 @@ en:
|
|
184
184
|
spree/address:
|
185
185
|
one: Address
|
186
186
|
other: Addresses
|
187
|
+
spree/cms_page:
|
188
|
+
one: Page
|
189
|
+
other: Pages
|
190
|
+
spree/cms_section:
|
191
|
+
one: Section
|
192
|
+
other: Sections
|
187
193
|
spree/country:
|
188
194
|
one: Country
|
189
195
|
other: Countries
|
@@ -558,6 +564,7 @@ en:
|
|
558
564
|
draft_mode: Draft Mode
|
559
565
|
full_width: Full width
|
560
566
|
link_to_taxon: Link to Taxon
|
567
|
+
link_to_product: Link to Product
|
561
568
|
title: Title
|
562
569
|
fit: Fit To
|
563
570
|
info_hero_image_body: "<p>The Hero Image section adds a large image with a button and tagline text to your page.</p>
|
@@ -964,6 +971,8 @@ en:
|
|
964
971
|
error: error
|
965
972
|
errors:
|
966
973
|
messages:
|
974
|
+
store_association_can_not_be_changed: The store association can not be changed
|
975
|
+
store_is_already_set: Store is already set
|
967
976
|
blank: can't be blank
|
968
977
|
could_not_create_taxon: Could not create taxon
|
969
978
|
no_shipping_methods_available: No shipping methods available for selected location, please change your address and try again.
|
@@ -1132,7 +1141,7 @@ en:
|
|
1132
1141
|
log_in_to_continue: Log in to continue
|
1133
1142
|
logs: "Logs"
|
1134
1143
|
logged_in_as: Logged in as
|
1135
|
-
|
1144
|
+
logged_in_successfully: Logged in successfully
|
1136
1145
|
logged_out: You have been logged out.
|
1137
1146
|
login: Login
|
1138
1147
|
login_as_existing: Login as Existing Customer
|
@@ -1341,6 +1350,7 @@ en:
|
|
1341
1350
|
backordered_confirm_info: Selected item is backordered so expect delays. Are you sure you want to order it?
|
1342
1351
|
overview: Overview
|
1343
1352
|
package_from: package from
|
1353
|
+
page: Page
|
1344
1354
|
page_not_found: Sorry! Page you are looking can’t be found.
|
1345
1355
|
pagination:
|
1346
1356
|
next_page: next page »
|
@@ -1,10 +1,17 @@
|
|
1
1
|
class CreateSpreeProductsStores < ActiveRecord::Migration[5.2]
|
2
2
|
def up
|
3
|
-
|
3
|
+
if table_exists?(:spree_products_stores)
|
4
|
+
unless index_exists?(:spree_products_stores, [:product_id, :store_id], unique: true)
|
5
|
+
add_index :spree_products_stores, [:product_id, :store_id], unique: true
|
6
|
+
end
|
7
|
+
unless column_exists?(:spree_products_stores, :created_at)
|
8
|
+
add_timestamps :spree_products_stores, default: Time.current
|
9
|
+
end
|
10
|
+
else
|
4
11
|
create_table :spree_products_stores do |t|
|
5
12
|
t.references :product, index: true
|
6
13
|
t.references :store, index: true
|
7
|
-
t.timestamps
|
14
|
+
t.timestamps default: Time.current
|
8
15
|
|
9
16
|
t.index [:product_id, :store_id], unique: true
|
10
17
|
end
|
@@ -12,13 +19,13 @@ class CreateSpreeProductsStores < ActiveRecord::Migration[5.2]
|
|
12
19
|
stores = Spree::Store.all
|
13
20
|
product_ids = Spree::Product.with_deleted.order(:id).ids
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
if product_ids.any? && Spree::StoreProduct.respond_to?(:insert_all)
|
23
|
+
stores.find_each do |store|
|
24
|
+
records = product_ids.map { |product_id| { product_id: product_id, store_id: store.id } }
|
18
25
|
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
# Rails 5 does not have insert_all
|
27
|
+
Spree::StoreProduct.insert_all(records)
|
28
|
+
end
|
22
29
|
end
|
23
30
|
end
|
24
31
|
end
|
@@ -22,6 +22,20 @@ module Spree
|
|
22
22
|
current_store.default_locale
|
23
23
|
end
|
24
24
|
|
25
|
+
def ensure_current_store(object)
|
26
|
+
return if object.nil?
|
27
|
+
|
28
|
+
if object.has_attribute?(:store_id)
|
29
|
+
if object.store.present? && object.store != current_store
|
30
|
+
raise Spree.t('errors.messages.store_is_already_set')
|
31
|
+
else
|
32
|
+
object.store = current_store
|
33
|
+
end
|
34
|
+
elsif object.class.method_defined?(:stores) && object.stores.exclude?(current_store)
|
35
|
+
object.stores << current_store
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
25
39
|
# Return a Hash of things that influence the prices displayed in your shop.
|
26
40
|
#
|
27
41
|
# By default, the only thing that influences prices that is the current order's +tax_zone+
|
data/lib/spree/core/version.rb
CHANGED
@@ -8,6 +8,8 @@ module Spree
|
|
8
8
|
:image_attributes,
|
9
9
|
:inventory_unit_attributes,
|
10
10
|
:line_item_attributes,
|
11
|
+
:menu_attributes,
|
12
|
+
:menu_item_attributes,
|
11
13
|
:option_type_attributes,
|
12
14
|
:option_value_attributes,
|
13
15
|
:payment_attributes,
|
@@ -62,6 +64,11 @@ module Spree
|
|
62
64
|
|
63
65
|
@@line_item_attributes = [:id, :variant_id, :quantity]
|
64
66
|
|
67
|
+
@@menu_attributes = [:name, :locale, :location]
|
68
|
+
|
69
|
+
@@menu_item_attributes = [:name, :subtite, :destination, :new_window, :item_type,
|
70
|
+
:linked_resource_type, :linked_resource_id, :code, :menu_id]
|
71
|
+
|
65
72
|
@@option_type_attributes = [:name, :presentation, :option_values_attributes]
|
66
73
|
|
67
74
|
@@option_value_attributes = [:name, :presentation]
|
@@ -36,6 +36,12 @@ FactoryBot.define do
|
|
36
36
|
after :create do |product|
|
37
37
|
product.master.stock_items.first.adjust_count_on_hand(10)
|
38
38
|
end
|
39
|
+
|
40
|
+
trait :without_backorder do
|
41
|
+
after :create do |product|
|
42
|
+
product.master.stock_items.update_all(backorderable: false)
|
43
|
+
end
|
44
|
+
end
|
39
45
|
end
|
40
46
|
|
41
47
|
factory :product_with_option_types do
|
@@ -48,7 +48,7 @@ module Spree
|
|
48
48
|
remember_me: 'Se souvenir de moi',
|
49
49
|
my_account: 'Mon compte',
|
50
50
|
my_orders: 'Mes commandes',
|
51
|
-
|
51
|
+
logged_in_successfully: 'Connexion réussie'
|
52
52
|
})
|
53
53
|
end
|
54
54
|
# rubocop:enable Layout/ArgumentAlignment
|
@@ -7,4 +7,9 @@ RSpec.configure do |config|
|
|
7
7
|
config.around :each, type: :feature do |ex|
|
8
8
|
ex.run_with_retry retry: ENV.fetch('RSPEC_RETRY_RETRY_COUNT', 3).to_i
|
9
9
|
end
|
10
|
+
|
11
|
+
# callback to be run between retries
|
12
|
+
config.retry_callback = proc do |ex|
|
13
|
+
Rails.cache.clear
|
14
|
+
end
|
10
15
|
end
|
data/spree_core.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.metadata = {
|
17
17
|
"bug_tracker_uri" => "https://github.com/spree/spree/issues",
|
18
18
|
"changelog_uri" => "https://github.com/spree/spree/releases/tag/v#{s.version}",
|
19
|
-
"documentation_uri" => "https://
|
19
|
+
"documentation_uri" => "https://dev-docs.spreecommerce.org/",
|
20
20
|
"source_code_uri" => "https://github.com/spree/spree/tree/v#{s.version}",
|
21
21
|
}
|
22
22
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.3.
|
4
|
+
version: 4.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Schofield
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-01-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|
@@ -472,6 +472,7 @@ files:
|
|
472
472
|
- app/models/concerns/spree/display_link.rb
|
473
473
|
- app/models/concerns/spree/display_money.rb
|
474
474
|
- app/models/concerns/spree/filter_param.rb
|
475
|
+
- app/models/concerns/spree/image_methods.rb
|
475
476
|
- app/models/concerns/spree/memoized_data.rb
|
476
477
|
- app/models/concerns/spree/multi_store_resource.rb
|
477
478
|
- app/models/concerns/spree/named_type.rb
|
@@ -483,6 +484,7 @@ files:
|
|
483
484
|
- app/models/concerns/spree/user_methods.rb
|
484
485
|
- app/models/concerns/spree/user_payment_source.rb
|
485
486
|
- app/models/concerns/spree/user_reporting.rb
|
487
|
+
- app/models/concerns/spree/user_roles.rb
|
486
488
|
- app/models/concerns/spree/vat_price_calculation.rb
|
487
489
|
- app/models/friendly_id/slug_decorator.rb
|
488
490
|
- app/models/spree/ability.rb
|
@@ -697,6 +699,8 @@ files:
|
|
697
699
|
- app/services/spree/account/update.rb
|
698
700
|
- app/services/spree/build_localized_redirect_url.rb
|
699
701
|
- app/services/spree/cart/add_item.rb
|
702
|
+
- app/services/spree/cart/associate.rb
|
703
|
+
- app/services/spree/cart/change_currency.rb
|
700
704
|
- app/services/spree/cart/create.rb
|
701
705
|
- app/services/spree/cart/destroy.rb
|
702
706
|
- app/services/spree/cart/empty.rb
|
@@ -722,7 +726,6 @@ files:
|
|
722
726
|
- app/sorters/spree/products/sort.rb
|
723
727
|
- app/validators/db_maximum_length_validator.rb
|
724
728
|
- app/validators/email_validator.rb
|
725
|
-
- app/views/spree/shared/_purchased_items_table.text.erb
|
726
729
|
- config/initializers/active_storage.rb
|
727
730
|
- config/initializers/friendly_id.rb
|
728
731
|
- config/initializers/inflections.rb
|
@@ -1192,9 +1195,9 @@ licenses:
|
|
1192
1195
|
- BSD-3-Clause
|
1193
1196
|
metadata:
|
1194
1197
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
1195
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v4.3.
|
1196
|
-
documentation_uri: https://
|
1197
|
-
source_code_uri: https://github.com/spree/spree/tree/v4.3.
|
1198
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v4.3.1
|
1199
|
+
documentation_uri: https://dev-docs.spreecommerce.org/
|
1200
|
+
source_code_uri: https://github.com/spree/spree/tree/v4.3.1
|
1198
1201
|
post_install_message:
|
1199
1202
|
rdoc_options: []
|
1200
1203
|
require_paths:
|
@@ -1210,7 +1213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1210
1213
|
- !ruby/object:Gem::Version
|
1211
1214
|
version: 1.8.23
|
1212
1215
|
requirements: []
|
1213
|
-
rubygems_version: 3.2.
|
1216
|
+
rubygems_version: 3.2.22
|
1214
1217
|
signing_key:
|
1215
1218
|
specification_version: 4
|
1216
1219
|
summary: The bare bones necessary for Spree
|
@@ -1,25 +0,0 @@
|
|
1
|
-
<% line_items.each do |item| %>
|
2
|
-
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %>
|
3
|
-
<% end %>
|
4
|
-
============================================================
|
5
|
-
<%= Spree.t('order_mailer.subtotal') %> <%= order.display_item_total %>
|
6
|
-
<% if order.line_item_adjustments.exists? %>
|
7
|
-
<% if order.all_adjustments.promotion.eligible.exists? %>
|
8
|
-
<% order.all_adjustments.promotion.eligible.group_by(&:label).each do |label, adjustments| %>
|
9
|
-
<%= Spree.t(:promotion) %>: <%= label %> <%= Spree::Money.new(adjustments.sum(&:amount), currency: order.currency) %>
|
10
|
-
<% end %>
|
11
|
-
<% end %>
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<% order.shipments.group_by { |s| s.selected_shipping_rate.try(:name) }.each do |name, shipments| %>
|
15
|
-
<%= Spree.t(:shipping) %>: <%= name %> <%= Spree::Money.new(shipments.sum(&:discounted_cost), currency: order.currency) %>
|
16
|
-
<% end %>
|
17
|
-
|
18
|
-
<% if order.additional_tax_total != 0 %>
|
19
|
-
<%= Spree.t(:tax) %>: <%= order.display_additional_tax_total.to_html %>
|
20
|
-
<% end %>
|
21
|
-
|
22
|
-
<% order.adjustments.eligible.each do |adjustment| %>
|
23
|
-
<% next if (adjustment.source_type == 'Spree::TaxRate') and (adjustment.amount == 0) %>
|
24
|
-
<%= adjustment.label %> <%= adjustment.display_amount %>
|
25
|
-
<% end %>
|