spree_core 4.0.8 → 4.1.0.rc1
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/assets/javascripts/spree.js +0 -1
- data/app/finders/spree/products/find.rb +19 -6
- data/app/finders/spree/variants/option_types_finder.rb +21 -0
- data/app/finders/spree/variants/visible_finder.rb +22 -0
- data/app/helpers/spree/base_helper.rb +48 -18
- data/app/helpers/spree/products_helper.rb +76 -8
- data/app/models/concerns/spree/user_methods.rb +2 -2
- data/app/models/spree/app_dependencies.rb +1 -7
- data/app/models/spree/credit_card.rb +4 -5
- data/app/models/spree/image/configuration/active_storage.rb +9 -1
- data/app/models/spree/image.rb +52 -3
- data/app/models/spree/line_item.rb +1 -2
- data/app/models/spree/option_type.rb +4 -0
- data/app/models/spree/order/address_book.rb +20 -7
- data/app/models/spree/order.rb +12 -12
- data/app/models/spree/payment_method.rb +8 -0
- data/app/models/spree/preferences/preferable.rb +1 -1
- data/app/models/spree/product.rb +7 -6
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +2 -1
- data/app/models/spree/return_item/eligibility_validator/base_validator.rb +1 -1
- data/app/models/spree/store.rb +2 -1
- data/app/models/spree/taxon.rb +2 -6
- data/app/models/spree/variant.rb +2 -14
- data/app/models/spree/zone.rb +6 -3
- data/app/presenters/spree/product_summary_presenter.rb +26 -0
- data/app/presenters/spree/variant_presenter.rb +69 -0
- data/app/presenters/spree/variants/option_types_presenter.rb +74 -0
- data/app/presenters/spree/variants/options_presenter.rb +49 -0
- data/app/services/spree/checkout/get_shipping_rates.rb +10 -7
- data/app/services/spree/checkout/update.rb +2 -13
- data/config/locales/en.yml +156 -14
- data/db/default/spree/stores.rb +8 -3
- data/db/migrate/20140309033438_create_store_from_preferences.rb +8 -4
- data/db/migrate/20191005121504_add_store_id_to_payment_methods.rb +7 -0
- data/db/migrate/20191016134113_add_deafult_value_for_store_default_currency.rb +5 -0
- data/db/migrate/20200102141311_add_social_to_spree_stores.rb +7 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +3 -1
- data/lib/generators/spree/dummy/templates/initializers/bullet.rb +5 -0
- data/lib/generators/spree/install/install_generator.rb +13 -5
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +0 -1
- data/lib/generators/spree/install/templates/config/initializers/spree_storefront.rb +1 -0
- data/lib/generators/spree/install/templates/config/spree_storefront.yml +67 -0
- data/lib/spree/core/controller_helpers/order.rb +12 -6
- data/lib/spree/core/controller_helpers/store.rb +2 -2
- data/lib/spree/core/search/base.rb +59 -22
- data/lib/spree/core/version.rb +1 -3
- data/lib/spree/core.rb +0 -1
- data/lib/spree/money.rb +8 -1
- data/lib/spree/permitted_attributes.rb +3 -2
- data/lib/spree/testing_support/capybara_ext.rb +0 -52
- data/lib/spree/testing_support/common_rake.rb +1 -1
- data/lib/spree/testing_support/factories/store_factory.rb +3 -0
- data/lib/spree/testing_support/order_walkthrough.rb +7 -3
- data/spree_core.gemspec +9 -15
- metadata +49 -34
- data/app/finders/spree/addresses/find.rb +0 -17
- data/app/services/spree/account/addresses/base.rb +0 -39
- data/app/services/spree/account/addresses/create.rb +0 -18
- data/app/services/spree/account/addresses/update.rb +0 -18
- data/lib/spree/database_type_utilities.rb +0 -12
data/app/models/spree/product.rb
CHANGED
@@ -110,7 +110,7 @@ module Spree
|
|
110
110
|
|
111
111
|
alias options product_option_types
|
112
112
|
|
113
|
-
self.whitelisted_ransackable_associations = %w[
|
113
|
+
self.whitelisted_ransackable_associations = %w[stores variants_including_master master variants]
|
114
114
|
self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on]
|
115
115
|
self.whitelisted_ransackable_scopes = %w[not_discontinued]
|
116
116
|
|
@@ -239,9 +239,7 @@ module Spree
|
|
239
239
|
# values should not be displayed to frontend users. Otherwise it breaks the
|
240
240
|
# idea of having variants
|
241
241
|
def variants_and_option_values(current_currency = nil)
|
242
|
-
variants.
|
243
|
-
variant.option_values.any?
|
244
|
-
end
|
242
|
+
variants.active(current_currency).joins(:option_value_variants)
|
245
243
|
end
|
246
244
|
|
247
245
|
def empty_option_values?
|
@@ -284,7 +282,10 @@ module Spree
|
|
284
282
|
end
|
285
283
|
|
286
284
|
def category
|
287
|
-
taxons.joins(:taxonomy).
|
285
|
+
taxons.joins(:taxonomy).
|
286
|
+
where(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) }).
|
287
|
+
order(depth: :desc).
|
288
|
+
first
|
288
289
|
end
|
289
290
|
|
290
291
|
private
|
@@ -321,7 +322,7 @@ module Spree
|
|
321
322
|
price: master.price
|
322
323
|
)
|
323
324
|
end
|
324
|
-
save
|
325
|
+
throw(:abort) unless save
|
325
326
|
end
|
326
327
|
|
327
328
|
def ensure_master
|
@@ -23,7 +23,7 @@ module Spree
|
|
23
23
|
order = line_item.order
|
24
24
|
|
25
25
|
# Prevent negative order totals
|
26
|
-
amounts << order.amount - order.adjustments.
|
26
|
+
amounts << order.amount - order.adjustments.sum(:amount).abs if order.adjustments.any?
|
27
27
|
|
28
28
|
amounts.min * -1
|
29
29
|
end
|
@@ -25,6 +25,7 @@ module Spree
|
|
25
25
|
|
26
26
|
def remove(coupon_code)
|
27
27
|
promotion = order.promotions.with_coupon_code(coupon_code)
|
28
|
+
|
28
29
|
if promotion.present?
|
29
30
|
# Order promotion has to be destroyed before line item removing
|
30
31
|
order.order_promotions.find_by!(promotion_id: promotion.id).destroy
|
@@ -75,7 +76,7 @@ module Spree
|
|
75
76
|
line_item = order.find_line_item_by_variant(item.variant)
|
76
77
|
next if line_item.blank?
|
77
78
|
|
78
|
-
Spree::Dependencies.cart_remove_item_service
|
79
|
+
Spree::Dependencies.cart_remove_item_service(order: order, item: item.variant, quantity: item.quantity)
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
data/app/models/spree/store.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Spree
|
2
2
|
class Store < Spree::Base
|
3
3
|
has_many :orders, class_name: 'Spree::Order'
|
4
|
+
has_many :payment_methods, class_name: 'Spree::PaymentMethod'
|
4
5
|
|
5
6
|
with_options presence: true do
|
6
|
-
validates :code, uniqueness: { case_sensitive: false, allow_blank: true }
|
7
7
|
validates :name, :url, :mail_from_address
|
8
|
+
validates :default_currency
|
8
9
|
end
|
9
10
|
|
10
11
|
before_save :ensure_default_exists_and_is_unique
|
data/app/models/spree/taxon.rb
CHANGED
@@ -48,13 +48,9 @@ module Spree
|
|
48
48
|
fs
|
49
49
|
end
|
50
50
|
|
51
|
-
# Return meta_title if set otherwise generates from
|
51
|
+
# Return meta_title if set otherwise generates from taxon name
|
52
52
|
def seo_title
|
53
|
-
|
54
|
-
root? ? name : "#{root.name} - #{name}"
|
55
|
-
else
|
56
|
-
meta_title
|
57
|
-
end
|
53
|
+
meta_title.blank? ? name : meta_title
|
58
54
|
end
|
59
55
|
|
60
56
|
# Creates permalink base for friendly_id
|
data/app/models/spree/variant.rb
CHANGED
@@ -116,15 +116,7 @@ module Spree
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def options_text
|
119
|
-
|
120
|
-
a.option_type.position <=> b.option_type.position
|
121
|
-
end
|
122
|
-
|
123
|
-
values.to_a.map! do |ov|
|
124
|
-
"#{ov.option_type.presentation}: #{ov.presentation}"
|
125
|
-
end
|
126
|
-
|
127
|
-
values.to_sentence(words_connector: ', ', two_words_connector: ', ')
|
119
|
+
Spree::Variants::OptionsPresenter.new(self).to_sentence
|
128
120
|
end
|
129
121
|
|
130
122
|
# Default to master name
|
@@ -234,11 +226,7 @@ module Spree
|
|
234
226
|
end
|
235
227
|
|
236
228
|
def in_stock?
|
237
|
-
|
238
|
-
# Check if model responds to cache version and fall back to updated_at for older rails versions
|
239
|
-
# This makes sure a version is supplied when recyclable cache keys are disabled.
|
240
|
-
version = respond_to?(:cache_version) ? cache_version : updated_at.to_i
|
241
|
-
Rails.cache.fetch(in_stock_cache_key, version: version) do
|
229
|
+
Rails.cache.fetch(in_stock_cache_key) do
|
242
230
|
total_on_hand > 0
|
243
231
|
end
|
244
232
|
end
|
data/app/models/spree/zone.rb
CHANGED
@@ -25,7 +25,9 @@ module Spree
|
|
25
25
|
self.whitelisted_ransackable_attributes = ['description']
|
26
26
|
|
27
27
|
def self.default_tax
|
28
|
-
|
28
|
+
Rails.cache.fetch('default_tax') do
|
29
|
+
find_by(default_tax: true)
|
30
|
+
end
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.potential_matching_zones(zone)
|
@@ -69,8 +71,8 @@ module Spree
|
|
69
71
|
end
|
70
72
|
|
71
73
|
def kind
|
72
|
-
if
|
73
|
-
|
74
|
+
if kind?
|
75
|
+
super
|
74
76
|
else
|
75
77
|
not_nil_scope = members.where.not(zoneable_type: nil)
|
76
78
|
zone_type = not_nil_scope.order('created_at ASC').pluck(:zoneable_type).last
|
@@ -173,6 +175,7 @@ module Spree
|
|
173
175
|
|
174
176
|
def remove_previous_default
|
175
177
|
Spree::Zone.with_default_tax.where.not(id: id).update_all(default_tax: false)
|
178
|
+
Rails.cache.delete('default_zone')
|
176
179
|
end
|
177
180
|
|
178
181
|
def set_zone_members(ids, type)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductSummaryPresenter
|
3
|
+
include Rails.application.routes.url_helpers
|
4
|
+
|
5
|
+
def initialize(product)
|
6
|
+
@product = product
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
{
|
11
|
+
name: @product.name,
|
12
|
+
images: images
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def images
|
19
|
+
@product.images.map do |image|
|
20
|
+
{
|
21
|
+
url_product: rails_representation_url(image.url(:product), only_path: true)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Spree
|
2
|
+
class VariantPresenter
|
3
|
+
include Rails.application.routes.url_helpers
|
4
|
+
include Spree::BaseHelper
|
5
|
+
|
6
|
+
attr_reader :current_currency, :current_price_options
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
@variants = opts[:variants]
|
10
|
+
@is_product_available_in_currency = opts[:is_product_available_in_currency]
|
11
|
+
@current_currency = opts[:current_currency]
|
12
|
+
@current_price_options = opts[:current_price_options]
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
@variants.map do |variant|
|
17
|
+
{
|
18
|
+
display_price: display_price(variant),
|
19
|
+
is_product_available_in_currency: @is_product_available_in_currency,
|
20
|
+
backorderable: backorderable?(variant),
|
21
|
+
images: images(variant),
|
22
|
+
option_values: option_values(variant),
|
23
|
+
}.merge(
|
24
|
+
variant_attributes(variant)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def images(variant)
|
30
|
+
variant.images.map do |image|
|
31
|
+
{
|
32
|
+
alt: image.alt,
|
33
|
+
url_product: rails_representation_url(image.url(:product), only_path: true)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def option_values(variant)
|
39
|
+
variant.option_values.map do |option_value|
|
40
|
+
{
|
41
|
+
id: option_value.id,
|
42
|
+
name: option_value.name,
|
43
|
+
presentation: option_value.presentation,
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def backorderable?(variant)
|
51
|
+
backorderable_variant_ids.include?(variant.id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def backorderable_variant_ids
|
55
|
+
@backorderable_variant_ids ||= Spree::Variant.joins(:stock_items).where(id: @variants.map(&:id)).
|
56
|
+
where(spree_stock_items: { backorderable: true }).merge(Spree::StockItem.with_active_stock_location).distinct.ids
|
57
|
+
end
|
58
|
+
|
59
|
+
def variant_attributes(variant)
|
60
|
+
{
|
61
|
+
id: variant.id,
|
62
|
+
sku: variant.sku,
|
63
|
+
price: variant.price,
|
64
|
+
in_stock: variant.in_stock?,
|
65
|
+
purchasable: variant.purchasable?
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Spree
|
2
|
+
module Variants
|
3
|
+
class OptionTypesPresenter
|
4
|
+
def initialize(option_types)
|
5
|
+
@option_types = option_types
|
6
|
+
end
|
7
|
+
|
8
|
+
def default_variant
|
9
|
+
default_variant_data[:variant]
|
10
|
+
end
|
11
|
+
|
12
|
+
def options
|
13
|
+
option_types.map do |option_type|
|
14
|
+
{
|
15
|
+
id: option_type.id,
|
16
|
+
name: option_type.name,
|
17
|
+
presentation: option_type.presentation,
|
18
|
+
position: option_type.position,
|
19
|
+
option_values: option_values_options(option_type.option_values)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :option_types
|
27
|
+
|
28
|
+
def default_variant_data
|
29
|
+
return {} if option_types.empty?
|
30
|
+
|
31
|
+
@default_variant_data ||= begin
|
32
|
+
find_in_stock_variant_data || find_backorderable_variant_data || find_first_variant_data
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_in_stock_variant_data
|
37
|
+
find_variant_data(&:in_stock?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_backorderable_variant_data
|
41
|
+
find_variant_data(&:backorderable?)
|
42
|
+
end
|
43
|
+
|
44
|
+
def find_variant_data(&block)
|
45
|
+
option_types.first.option_values.each do |option_value|
|
46
|
+
variant = option_value.variants.find(&block)
|
47
|
+
|
48
|
+
return { variant: variant, option_value: option_value } if variant
|
49
|
+
end
|
50
|
+
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def find_first_variant_data
|
55
|
+
option_value = option_types.first.option_values.first
|
56
|
+
variant = option_value.variants.first
|
57
|
+
|
58
|
+
{ variant: variant, option_value: option_value }
|
59
|
+
end
|
60
|
+
|
61
|
+
def option_values_options(option_values)
|
62
|
+
option_values.map do |option_value|
|
63
|
+
{
|
64
|
+
id: option_value.id,
|
65
|
+
position: option_value.position,
|
66
|
+
presentation: option_value.presentation,
|
67
|
+
variant_id: option_value.variants.first.id,
|
68
|
+
is_default: option_value == default_variant_data[:option_value]
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Spree
|
2
|
+
module Variants
|
3
|
+
class OptionsPresenter
|
4
|
+
WORDS_CONNECTOR = ', '.freeze
|
5
|
+
|
6
|
+
attr_reader :variant
|
7
|
+
|
8
|
+
delegate :option_values, to: :variant
|
9
|
+
|
10
|
+
def initialize(variant)
|
11
|
+
@variant = variant
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_sentence
|
15
|
+
options = option_values
|
16
|
+
options = sort_options(options)
|
17
|
+
options = present_options(options)
|
18
|
+
|
19
|
+
join_options(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def sort_options(options)
|
25
|
+
options.sort_by { |o| o.option_type.position }
|
26
|
+
end
|
27
|
+
|
28
|
+
def present_options(options)
|
29
|
+
options.map do |ov|
|
30
|
+
method = "present_#{ov.option_type.name}_option"
|
31
|
+
|
32
|
+
respond_to?(method, true) ? send(method, ov) : present_option(ov)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def present_color_option(option)
|
37
|
+
"#{option.option_type.presentation}: #{option.name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def present_option(option)
|
41
|
+
"#{option.option_type.presentation}: #{option.presentation}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def join_options(options)
|
45
|
+
options.to_sentence(words_connector: WORDS_CONNECTOR, two_words_connector: WORDS_CONNECTOR)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -7,7 +7,9 @@ module Spree
|
|
7
7
|
run :reload_order
|
8
8
|
run :ensure_shipping_address
|
9
9
|
run :ensure_line_items_present
|
10
|
-
run :
|
10
|
+
run :move_order_to_delivery_state
|
11
|
+
run :generate_shipping_rates
|
12
|
+
run :return_shipments
|
11
13
|
end
|
12
14
|
|
13
15
|
private
|
@@ -29,11 +31,6 @@ module Spree
|
|
29
31
|
success(order: order)
|
30
32
|
end
|
31
33
|
|
32
|
-
def generate_or_return_shipping_rates(order:)
|
33
|
-
generate_shipping_rates(order: order) if order.shipments.empty?
|
34
|
-
return_shipments(order: order)
|
35
|
-
end
|
36
|
-
|
37
34
|
def generate_shipping_rates(order:)
|
38
35
|
ApplicationRecord.transaction do
|
39
36
|
order.create_proposed_shipments
|
@@ -45,7 +42,13 @@ module Spree
|
|
45
42
|
end
|
46
43
|
|
47
44
|
def return_shipments(order:)
|
48
|
-
success(order.
|
45
|
+
success(order.shipments.includes([shipping_rates: :shipping_method]))
|
46
|
+
end
|
47
|
+
|
48
|
+
def move_order_to_delivery_state(order:)
|
49
|
+
Spree::Dependencies.checkout_next_service.constantize.call(order: order) until order.state == 'delivery'
|
50
|
+
|
51
|
+
success(order: order)
|
49
52
|
end
|
50
53
|
end
|
51
54
|
end
|
@@ -4,12 +4,8 @@ module Spree
|
|
4
4
|
prepend Spree::ServiceModule::Base
|
5
5
|
|
6
6
|
def call(order:, params:, permitted_attributes:, request_env:)
|
7
|
-
|
8
|
-
|
9
|
-
params = replace_country_iso_with_id(params, 'ship') if ship_changed
|
10
|
-
params = replace_country_iso_with_id(params, 'bill') if bill_changed
|
11
|
-
order.state = 'address' if (ship_changed || bill_changed) && order.has_checkout_step?('address')
|
12
|
-
order.state = 'delivery' if selected_shipping_rate_present?(params) && order.has_checkout_step?('delivery')
|
7
|
+
params = replace_country_iso_with_id(params, 'ship') if address_with_country_iso_present?(params, 'ship')
|
8
|
+
params = replace_country_iso_with_id(params, 'bill') if address_with_country_iso_present?(params, 'bill')
|
13
9
|
return success(order) if order.update_from_params(params, permitted_attributes, request_env)
|
14
10
|
|
15
11
|
failure(order)
|
@@ -24,13 +20,6 @@ module Spree
|
|
24
20
|
true
|
25
21
|
end
|
26
22
|
|
27
|
-
def selected_shipping_rate_present?(params)
|
28
|
-
shipments_attributes = params.dig(:order, :shipments_attributes)
|
29
|
-
return false unless shipments_attributes
|
30
|
-
|
31
|
-
shipments_attributes.any? { |s| s.dig(:selected_shipping_rate_id) }
|
32
|
-
end
|
33
|
-
|
34
23
|
def replace_country_iso_with_id(params, address_kind = 'ship')
|
35
24
|
country_id = Spree::Country.by_iso(params[:order]["#{address_kind}_address_attributes"].fetch(:country_iso))&.id
|
36
25
|
|