spree_core 4.0.7 → 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.rb +52 -3
- data/app/models/spree/image/configuration/active_storage.rb +9 -1
- data/app/models/spree/line_item.rb +1 -2
- data/app/models/spree/option_type.rb +4 -0
- data/app/models/spree/order.rb +12 -12
- data/app/models/spree/order/address_book.rb +20 -7
- 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 +2 -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.rb +0 -1
- 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/money.rb +8 -1
- data/lib/spree/permitted_attributes.rb +3 -2
- data/lib/spree/testing_support/capybara_ext.rb +0 -45
- 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 +8 -14
- metadata +45 -24
- 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
@@ -15,7 +15,15 @@ module Spree
|
|
15
15
|
mini: '48x48>',
|
16
16
|
small: '100x100>',
|
17
17
|
product: '240x240>',
|
18
|
-
|
18
|
+
pdp_thumbnail: '160x200>',
|
19
|
+
plp_and_carousel: '448x600>',
|
20
|
+
plp_and_carousel_xs: '254x340>',
|
21
|
+
plp_and_carousel_sm: '350x468>',
|
22
|
+
plp_and_carousel_md: '222x297>',
|
23
|
+
plp_and_carousel_lg: '278x371>',
|
24
|
+
large: '600x600>',
|
25
|
+
plp: '278x371>',
|
26
|
+
zoomed: '650x870>'
|
19
27
|
}
|
20
28
|
end
|
21
29
|
|
@@ -59,8 +59,7 @@ module Spree
|
|
59
59
|
|
60
60
|
extend DisplayMoney
|
61
61
|
money_methods :amount, :subtotal, :discounted_amount, :final_amount, :total, :price,
|
62
|
-
:adjustment_total, :additional_tax_total, :promo_total, :included_tax_total
|
63
|
-
:pre_tax_amount
|
62
|
+
:adjustment_total, :additional_tax_total, :promo_total, :included_tax_total
|
64
63
|
|
65
64
|
alias single_money display_price
|
66
65
|
alias single_display_amount display_price
|
data/app/models/spree/order.rb
CHANGED
@@ -21,8 +21,7 @@ module Spree
|
|
21
21
|
extend Spree::DisplayMoney
|
22
22
|
money_methods :outstanding_balance, :item_total, :adjustment_total,
|
23
23
|
:included_tax_total, :additional_tax_total, :tax_total,
|
24
|
-
:shipment_total, :promo_total, :total
|
25
|
-
:cart_promo_total, :pre_tax_item_amount, :pre_tax_total
|
24
|
+
:shipment_total, :promo_total, :total
|
26
25
|
|
27
26
|
alias display_ship_total display_shipment_total
|
28
27
|
alias_attribute :ship_total, :shipment_total
|
@@ -174,12 +173,7 @@ module Spree
|
|
174
173
|
|
175
174
|
# Sum of all line item amounts pre-tax
|
176
175
|
def pre_tax_item_amount
|
177
|
-
line_items.sum(
|
178
|
-
end
|
179
|
-
|
180
|
-
# Sum of all line item and shipment pre-tax
|
181
|
-
def pre_tax_total
|
182
|
-
pre_tax_item_amount + shipments.sum(:pre_tax_amount)
|
176
|
+
line_items.to_a.sum(&:pre_tax_amount)
|
183
177
|
end
|
184
178
|
|
185
179
|
def shipping_discount
|
@@ -375,8 +369,8 @@ module Spree
|
|
375
369
|
payment_state == 'paid' || payment_state == 'credit_owed'
|
376
370
|
end
|
377
371
|
|
378
|
-
def available_payment_methods
|
379
|
-
@available_payment_methods ||= collect_payment_methods
|
372
|
+
def available_payment_methods(store = nil)
|
373
|
+
@available_payment_methods ||= collect_payment_methods(store)
|
380
374
|
end
|
381
375
|
|
382
376
|
def insufficient_stock_lines
|
@@ -631,6 +625,12 @@ module Spree
|
|
631
625
|
all_adjustments.eligible.nonzero.promotion.map { |a| a.source.promotion_id }.uniq
|
632
626
|
end
|
633
627
|
|
628
|
+
def valid_coupon_promotions
|
629
|
+
promotions.
|
630
|
+
where(id: valid_promotion_ids).
|
631
|
+
coupons
|
632
|
+
end
|
633
|
+
|
634
634
|
private
|
635
635
|
|
636
636
|
def link_by_email
|
@@ -689,8 +689,8 @@ module Spree
|
|
689
689
|
self.token ||= generate_token
|
690
690
|
end
|
691
691
|
|
692
|
-
def collect_payment_methods
|
693
|
-
PaymentMethod.available_on_front_end.select { |pm| pm.available_for_order?(self) }
|
692
|
+
def collect_payment_methods(store = nil)
|
693
|
+
PaymentMethod.available_on_front_end.select { |pm| pm.available_for_order?(self) && pm.available_for_store?(store) }
|
694
694
|
end
|
695
695
|
|
696
696
|
def credit_card_nil_payment?(attributes)
|
@@ -55,18 +55,31 @@ module Spree
|
|
55
55
|
def update_or_create_address(attributes = {})
|
56
56
|
return if attributes.blank?
|
57
57
|
|
58
|
-
attributes.
|
58
|
+
attributes = attributes.select { |_k, v| v.present? }
|
59
59
|
|
60
|
-
|
61
|
-
|
60
|
+
if user
|
61
|
+
address = user.addresses.build(attributes.except(:id)).check
|
62
|
+
return address if address.id
|
63
|
+
end
|
64
|
+
|
65
|
+
if attributes[:id]
|
66
|
+
address = Spree::Address.find(attributes[:id])
|
67
|
+
attributes.delete(:id)
|
62
68
|
|
63
|
-
|
64
|
-
|
69
|
+
if address&.editable?
|
70
|
+
address.update(attributes)
|
71
|
+
return address
|
72
|
+
else
|
73
|
+
attributes.delete(:id)
|
74
|
+
end
|
75
|
+
end
|
65
76
|
|
66
|
-
|
77
|
+
unless attributes[:id]
|
78
|
+
address = Spree::Address.new(attributes)
|
79
|
+
address.save
|
67
80
|
end
|
68
81
|
|
69
|
-
|
82
|
+
address
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
@@ -12,6 +12,8 @@ module Spree
|
|
12
12
|
|
13
13
|
validates :name, presence: true
|
14
14
|
|
15
|
+
belongs_to :store
|
16
|
+
|
15
17
|
with_options dependent: :restrict_with_error do
|
16
18
|
has_many :payments, class_name: 'Spree::Payment', inverse_of: :payment_method
|
17
19
|
has_many :credit_cards, class_name: 'Spree::CreditCard'
|
@@ -75,5 +77,11 @@ module Spree
|
|
75
77
|
def available_for_order?(_order)
|
76
78
|
true
|
77
79
|
end
|
80
|
+
|
81
|
+
def available_for_store?(store)
|
82
|
+
return true if store.blank? || store_id.blank?
|
83
|
+
|
84
|
+
store_id == store.id
|
85
|
+
end
|
78
86
|
end
|
79
87
|
end
|
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
|