spree_core 4.0.8 → 4.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|