solidus_core 3.0.8 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of solidus_core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/helpers/spree/base_helper.rb +1 -1
- data/app/helpers/spree/products_helper.rb +1 -1
- data/app/models/concerns/spree/active_storage_adapter/attachment.rb +2 -4
- data/app/models/concerns/spree/default_price.rb +63 -10
- data/app/models/concerns/spree/user_methods.rb +1 -20
- data/app/models/spree/adjustment.rb +6 -5
- data/app/models/spree/customer_return.rb +3 -2
- data/app/models/spree/image/active_storage_attachment.rb +2 -7
- data/app/models/spree/image/paperclip_attachment.rb +2 -2
- data/app/models/spree/line_item.rb +2 -2
- data/app/models/spree/log_entry.rb +1 -74
- data/app/models/spree/order.rb +10 -5
- data/app/models/spree/order_shipping.rb +9 -6
- data/app/models/spree/price.rb +2 -2
- data/app/models/spree/product/scopes.rb +5 -5
- data/app/models/spree/product.rb +12 -1
- data/app/models/spree/promotion/rules/item_total.rb +50 -6
- data/app/models/spree/promotion.rb +2 -2
- data/app/models/spree/promotion_code.rb +3 -3
- data/app/models/spree/refund.rb +0 -8
- data/app/models/spree/shipping_rate_tax.rb +1 -1
- data/app/models/spree/stock/availability.rb +11 -3
- data/app/models/spree/stock/simple_coordinator.rb +0 -10
- data/app/models/spree/stock_location.rb +1 -1
- data/app/models/spree/store_credit.rb +6 -9
- data/app/models/spree/tax_calculator/shipping_rate.rb +1 -1
- data/app/models/spree/taxon/active_storage_attachment.rb +2 -2
- data/app/models/spree/taxon/paperclip_attachment.rb +3 -3
- data/app/models/spree/variant/price_selector.rb +16 -3
- data/app/models/spree/variant.rb +26 -16
- data/config/locales/en.yml +2 -249
- data/db/migrate/20210312061050_change_column_null_on_prices.rb +7 -0
- data/lib/generators/solidus/install/install_generator.rb +2 -3
- data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +3 -1
- data/lib/generators/solidus/update/templates/config/initializers/new_solidus_defaults.rb.tt +30 -0
- data/lib/generators/solidus/update/update_generator.rb +112 -0
- data/lib/generators/spree/dummy/templates/rails/application.rb.tt +0 -1
- data/lib/generators/spree/dummy/templates/rails/database.yml +78 -35
- data/lib/spree/app_configuration.rb +64 -19
- data/lib/spree/core/engine.rb +7 -22
- data/lib/spree/core/product_filters.rb +1 -1
- data/lib/spree/core/search/base.rb +1 -1
- data/lib/spree/core/state_machines/order.rb +1 -1
- data/lib/spree/core/validators/email.rb +1 -1
- data/lib/spree/core/version.rb +5 -1
- data/lib/spree/core/versioned_value.rb +75 -0
- data/lib/spree/core.rb +17 -0
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/preferences/configuration.rb +62 -0
- data/lib/spree/preferences/preferable.rb +8 -0
- data/lib/spree/preferences/preferable_class_methods.rb +5 -3
- data/lib/spree/preferences/preference_differentiator.rb +28 -0
- data/lib/spree/testing_support/blacklist_urls.rb +1 -1
- data/lib/spree/testing_support/dummy_app/database.yml +42 -22
- data/lib/spree/testing_support/dummy_app.rb +33 -19
- data/lib/spree/testing_support/factories/user_factory.rb +0 -6
- data/lib/tasks/solidus/delete_prices_with_nil_amount.rake +8 -0
- data/solidus_core.gemspec +0 -1
- metadata +9 -26
- data/app/models/spree/tax/shipping_rate_taxer.rb +0 -24
- data/lib/tasks/solidus/check_orders_with_invalid_email.rake +0 -18
- data/lib/tasks/upgrade.rake +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6d8a64c0ba51b637a6a5eb82952d5920f388413f74d271920c41b6c34b00b5f
|
4
|
+
data.tar.gz: a92bbdc37bd0a9f9a53fe943542ba0f4890af67290faf937de4a57583cdb1ffa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dd269d1a10a861a6d76cba306cf3b42b758773d4fe4e3265986e0abfe318e40ba2468d6431ec89d472b72591a23e19684a20afa37bb48f0be71371e79736e0f
|
7
|
+
data.tar.gz: c524310230c534ebc135368fbf5d1b75def4f3b3672f8b4818b85d6e40d2fd04f1bfb03e37d0218f37d5b5bb7167499c2deff8bbd2593a8571f9b1de211d665c
|
@@ -130,7 +130,7 @@ module Spree
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def display_price(product_or_variant)
|
133
|
-
product_or_variant.
|
133
|
+
product_or_variant.price_for_options(current_pricing_options)&.money&.to_html
|
134
134
|
end
|
135
135
|
|
136
136
|
def pretty_time(time, format = :long)
|
@@ -38,7 +38,7 @@ module Spree
|
|
38
38
|
.with_prices(current_pricing_options)
|
39
39
|
.all? { |variant_with_prices| variant_with_prices.price_same_as_master?(current_pricing_options) }
|
40
40
|
|
41
|
-
variant.
|
41
|
+
variant.price_for_options(current_pricing_options)&.money&.to_html
|
42
42
|
end
|
43
43
|
|
44
44
|
# Converts line breaks in product description into <p> tags.
|
@@ -30,9 +30,7 @@ module Spree
|
|
30
30
|
size = style_to_size(style)
|
31
31
|
@attachment.variant(
|
32
32
|
resize_to_limit: size,
|
33
|
-
|
34
|
-
strip: true
|
35
|
-
}
|
33
|
+
strip: true
|
36
34
|
).processed
|
37
35
|
end
|
38
36
|
|
@@ -60,7 +58,7 @@ module Spree
|
|
60
58
|
end
|
61
59
|
|
62
60
|
def normalize_styles(styles)
|
63
|
-
styles.transform_values { |v| v.split('x')
|
61
|
+
styles.transform_values { |v| v.split('x') }
|
64
62
|
end
|
65
63
|
|
66
64
|
def style_to_size(style)
|
@@ -5,23 +5,76 @@ module Spree
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
delegate :display_price, :display_amount, :price, to: :default_price, allow_nil: true
|
9
|
+
delegate :price=, to: :default_price_or_build
|
10
|
+
|
11
|
+
# @see Spree::Variant::PricingOptions.default_price_attributes
|
12
|
+
def self.default_price_attributes
|
13
|
+
Spree::Config.default_pricing_options.desired_attributes
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
# Returns `#prices` prioritized for being considered as default price
|
18
|
+
#
|
19
|
+
# @return [ActiveRecord::Relation<Spree::Price>]
|
20
|
+
def currently_valid_prices
|
21
|
+
prices.currently_valid
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
# Returns {#default_price} or builds it from {Spree::Variant.default_price_attributes}
|
25
|
+
#
|
26
|
+
# @return [Spree::Price, nil]
|
27
|
+
# @see Spree::Variant.default_price_attributes
|
28
|
+
def default_price_or_build
|
29
|
+
default_price ||
|
30
|
+
prices.build(self.class.default_price_attributes)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Select from {#prices} the one to be considered as the default
|
34
|
+
#
|
35
|
+
# This method works with the in-memory association, so non-persisted prices
|
36
|
+
# are taken into account. Discarded prices are also considered.
|
37
|
+
#
|
38
|
+
# A price is a candidate to be considered as the default when it meets
|
39
|
+
# {Spree::Variant.default_price_attributes} criteria. When more than one candidate is
|
40
|
+
# found, non-persisted records take preference. When more than one persisted
|
41
|
+
# candidate exists, the one most recently updated is taken or, in case of
|
42
|
+
# race condition, the one with higher id.
|
43
|
+
#
|
44
|
+
# @return [Spree::Price, nil]
|
45
|
+
# @see Spree::Variant.default_price_attributes
|
46
|
+
def default_price
|
47
|
+
prioritized_default(
|
48
|
+
prices_meeting_criteria_to_be_default(
|
49
|
+
(prices + prices.with_discarded).uniq
|
50
|
+
)
|
51
|
+
)
|
52
|
+
end
|
22
53
|
|
23
54
|
def has_default_price?
|
24
55
|
default_price.present? && !default_price.discarded?
|
25
56
|
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def prices_meeting_criteria_to_be_default(prices)
|
61
|
+
criteria = self.class.default_price_attributes.transform_keys(&:to_s)
|
62
|
+
prices.select do |price|
|
63
|
+
contender = price.attributes.slice(*criteria.keys)
|
64
|
+
criteria == contender
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def prioritized_default(prices)
|
69
|
+
prices.min do |prev, succ|
|
70
|
+
contender_one, contender_two = [succ, prev].map do |item|
|
71
|
+
[
|
72
|
+
item.updated_at || Time.zone.now,
|
73
|
+
item.id || Float::INFINITY
|
74
|
+
]
|
75
|
+
end
|
76
|
+
contender_one <=> contender_two
|
77
|
+
end
|
78
|
+
end
|
26
79
|
end
|
27
80
|
end
|
@@ -18,7 +18,7 @@ module Spree
|
|
18
18
|
has_many :stock_locations, through: :user_stock_locations
|
19
19
|
|
20
20
|
has_many :spree_orders, foreign_key: "user_id", class_name: "Spree::Order"
|
21
|
-
has_many :orders, foreign_key: "user_id", class_name: "Spree::Order"
|
21
|
+
has_many :orders, foreign_key: "user_id", class_name: "Spree::Order", dependent: :restrict_with_exception
|
22
22
|
|
23
23
|
has_many :store_credits, -> { includes(:credit_type) }, foreign_key: "user_id", class_name: "Spree::StoreCredit"
|
24
24
|
has_many :store_credit_events, through: :store_credits
|
@@ -27,7 +27,6 @@ module Spree
|
|
27
27
|
has_many :wallet_payment_sources, foreign_key: 'user_id', class_name: 'Spree::WalletPaymentSource', inverse_of: :user
|
28
28
|
|
29
29
|
after_create :auto_generate_spree_api_key
|
30
|
-
before_destroy :check_for_deletion
|
31
30
|
|
32
31
|
include Spree::RansackableAttributes unless included_modules.include?(Spree::RansackableAttributes)
|
33
32
|
|
@@ -77,23 +76,5 @@ module Spree
|
|
77
76
|
currency: currency,
|
78
77
|
)
|
79
78
|
end
|
80
|
-
|
81
|
-
# Restrict to delete users with existing orders
|
82
|
-
#
|
83
|
-
# Override this in your user model class to add another logic.
|
84
|
-
#
|
85
|
-
# Ie. to allow to delete users with incomplete orders add:
|
86
|
-
#
|
87
|
-
# orders.complete.none?
|
88
|
-
#
|
89
|
-
def can_be_deleted?
|
90
|
-
orders.none?
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def check_for_deletion
|
96
|
-
raise ActiveRecord::DeleteRestrictionError unless can_be_deleted?
|
97
|
-
end
|
98
79
|
end
|
99
80
|
end
|
@@ -55,11 +55,12 @@ module Spree
|
|
55
55
|
#
|
56
56
|
# @param excluded_orders [Array<Spree::Order>] Orders to exclude from query
|
57
57
|
# @return [ActiveRecord::Relation] Scoped Adjustments
|
58
|
-
def self.in_completed_orders(excluded_orders: [])
|
59
|
-
joins(:order)
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
def self.in_completed_orders(excluded_orders: [], exclude_canceled: false)
|
59
|
+
result = joins(:order)
|
60
|
+
.merge(Spree::Order.complete)
|
61
|
+
.where.not(spree_orders: { id: excluded_orders })
|
62
|
+
.distinct
|
63
|
+
exclude_canceled ? result.merge(Spree::Order.not_canceled) : result
|
63
64
|
end
|
64
65
|
|
65
66
|
def finalize!
|
@@ -40,7 +40,8 @@ module Spree
|
|
40
40
|
# Temporarily tie a customer_return to one order
|
41
41
|
def order
|
42
42
|
return nil if return_items.blank?
|
43
|
-
|
43
|
+
|
44
|
+
return_items.first.inventory_unit&.order
|
44
45
|
end
|
45
46
|
|
46
47
|
def fully_reimbursed?
|
@@ -65,7 +66,7 @@ module Spree
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def return_items_belong_to_same_order
|
68
|
-
if return_items.reject{ |return_item| return_item.inventory_unit
|
69
|
+
if return_items.reject{ |return_item| return_item.inventory_unit&.order_id == order_id }.any?
|
69
70
|
errors.add(:base, I18n.t('spree.return_items_cannot_be_associated_with_multiple_orders'))
|
70
71
|
end
|
71
72
|
end
|
@@ -12,13 +12,8 @@ module Spree::Image::ActiveStorageAttachment
|
|
12
12
|
validate :supported_content_type
|
13
13
|
|
14
14
|
has_attachment :attachment,
|
15
|
-
styles:
|
16
|
-
|
17
|
-
small: '400x400>',
|
18
|
-
product: '680x680>',
|
19
|
-
large: '1200x1200>'
|
20
|
-
},
|
21
|
-
default_style: :product
|
15
|
+
styles: Spree::Config.product_image_styles,
|
16
|
+
default_style: Spree::Config.product_image_style_default
|
22
17
|
|
23
18
|
def supported_content_type
|
24
19
|
unless attachment.content_type.in?(Spree::Config.allowed_image_mime_types)
|
@@ -7,8 +7,8 @@ module Spree::Image::PaperclipAttachment
|
|
7
7
|
validate :no_attachment_errors
|
8
8
|
|
9
9
|
has_attached_file :attachment,
|
10
|
-
styles:
|
11
|
-
default_style:
|
10
|
+
styles: Spree::Config.product_image_styles,
|
11
|
+
default_style: Spree::Config.product_image_style_default,
|
12
12
|
default_url: 'noimage/:style.png',
|
13
13
|
url: '/spree/products/:id/:style/:basename.:extension',
|
14
14
|
path: ':rails_root/public/spree/products/:id/:style/:basename.:extension',
|
@@ -123,7 +123,7 @@ module Spree
|
|
123
123
|
# a price for this line item, even if there is no existing price
|
124
124
|
# for the associated line item in the order currency.
|
125
125
|
unless options.key?(:price) || options.key?('price')
|
126
|
-
self.money_price = variant.
|
126
|
+
self.money_price = variant.price_for_options(pricing_options)&.money
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -149,7 +149,7 @@ module Spree
|
|
149
149
|
# Set price, cost_price and currency.
|
150
150
|
def set_pricing_attributes
|
151
151
|
self.cost_price ||= variant.cost_price
|
152
|
-
self.money_price = variant.
|
152
|
+
self.money_price = variant.price_for_options(pricing_options)&.money if price.nil?
|
153
153
|
true
|
154
154
|
end
|
155
155
|
|
@@ -2,83 +2,10 @@
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
class LogEntry < Spree::Base
|
5
|
-
# Classes used in core that can be present in serialized details
|
6
|
-
#
|
7
|
-
# Users can add their own classes in
|
8
|
-
# `Spree::Config#log_entry_permitted_classes`.
|
9
|
-
#
|
10
|
-
# @see Spree::AppConfiguration#log_entry_permitted_classes
|
11
|
-
CORE_PERMITTED_CLASSES = [
|
12
|
-
ActiveMerchant::Billing::Response,
|
13
|
-
ActiveSupport::TimeWithZone,
|
14
|
-
Time,
|
15
|
-
ActiveSupport::TimeZone
|
16
|
-
].freeze
|
17
|
-
|
18
|
-
# Raised when a disallowed class is tried to be loaded
|
19
|
-
class DisallowedClass < RuntimeError
|
20
|
-
attr_reader :psych_exception
|
21
|
-
|
22
|
-
def initialize(psych_exception:)
|
23
|
-
@psych_exception = psych_exception
|
24
|
-
super(default_message)
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def default_message
|
30
|
-
<<~MSG
|
31
|
-
#{psych_exception.message}
|
32
|
-
|
33
|
-
You can specify custom classes to be loaded in config/initializers/spree.rb. E.g:
|
34
|
-
|
35
|
-
Spree.config do |config|
|
36
|
-
config.log_entry_permitted_classes = ['MyClass']
|
37
|
-
end
|
38
|
-
MSG
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Raised when YAML contains aliases and they're not enabled
|
43
|
-
class BadAlias < RuntimeError
|
44
|
-
attr_reader :psych_exception
|
45
|
-
|
46
|
-
def initialize(psych_exception:)
|
47
|
-
@psych_exception = psych_exception
|
48
|
-
super(default_message)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def default_message
|
54
|
-
<<~MSG
|
55
|
-
#{psych_exception.message}
|
56
|
-
|
57
|
-
You can explicitly enable aliases in config/initializers/spree.rb. E.g:
|
58
|
-
|
59
|
-
Spree.config do |config|
|
60
|
-
config.log_entry_allow_aliases = true
|
61
|
-
end
|
62
|
-
MSG
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.permitted_classes
|
67
|
-
CORE_PERMITTED_CLASSES + Spree::Config.log_entry_permitted_classes.map(&:constantize)
|
68
|
-
end
|
69
|
-
|
70
5
|
belongs_to :source, polymorphic: true, optional: true
|
71
6
|
|
72
7
|
def parsed_details
|
73
|
-
@details ||= YAML.
|
74
|
-
details,
|
75
|
-
permitted_classes: self.class.permitted_classes,
|
76
|
-
aliases: Spree::Config.log_entry_allow_aliases
|
77
|
-
)
|
78
|
-
rescue Psych::DisallowedClass => e
|
79
|
-
raise DisallowedClass.new(psych_exception: e)
|
80
|
-
rescue Psych::BadAlias => e
|
81
|
-
raise BadAlias.new(psych_exception: e)
|
8
|
+
@details ||= YAML.load(details)
|
82
9
|
end
|
83
10
|
end
|
84
11
|
end
|
data/app/models/spree/order.rb
CHANGED
@@ -128,7 +128,7 @@ module Spree
|
|
128
128
|
before_create :create_token
|
129
129
|
before_create :link_by_email
|
130
130
|
|
131
|
-
validates :email, presence: true, if: :
|
131
|
+
validates :email, presence: true, if: :email_required?
|
132
132
|
validates :email, 'spree/email' => true, allow_blank: true
|
133
133
|
validates :guest_token, presence: { allow_nil: true }
|
134
134
|
validates :number, presence: true, uniqueness: { allow_blank: true, case_sensitive: true }
|
@@ -269,15 +269,15 @@ module Spree
|
|
269
269
|
end
|
270
270
|
|
271
271
|
def contents
|
272
|
-
@contents ||= Spree::
|
272
|
+
@contents ||= Spree::Config.order_contents_class.new(self)
|
273
273
|
end
|
274
274
|
|
275
275
|
def shipping
|
276
|
-
@shipping ||= Spree::
|
276
|
+
@shipping ||= Spree::Config.order_shipping_class.new(self)
|
277
277
|
end
|
278
278
|
|
279
279
|
def cancellations
|
280
|
-
@cancellations ||= Spree::
|
280
|
+
@cancellations ||= Spree::Config.order_cancellations_class.new(self)
|
281
281
|
end
|
282
282
|
|
283
283
|
# Associates the specified user with the order.
|
@@ -750,10 +750,15 @@ module Spree
|
|
750
750
|
end
|
751
751
|
|
752
752
|
# Determine if email is required (we don't want validation errors before we hit the checkout)
|
753
|
-
def
|
753
|
+
def email_required?
|
754
754
|
true unless new_record? || ['cart', 'address'].include?(state)
|
755
755
|
end
|
756
756
|
|
757
|
+
def require_email
|
758
|
+
Spree::Deprecation.warn "Use email_required? instead", caller(1)
|
759
|
+
email_required?
|
760
|
+
end
|
761
|
+
|
757
762
|
def ensure_inventory_units
|
758
763
|
if has_checkout_step?("delivery")
|
759
764
|
inventory_validator = Spree::Stock::InventoryValidator.new
|
@@ -62,15 +62,18 @@ class Spree::OrderShipping
|
|
62
62
|
end
|
63
63
|
|
64
64
|
inventory_units.map(&:shipment).uniq.each do |shipment|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
# Temporarily propagate the tracking number to the shipment as well
|
66
|
+
# TODO: Remove tracking numbers from shipments.
|
67
|
+
shipment.update!(tracking: tracking_number)
|
68
|
+
|
69
|
+
next unless shipment.inventory_units.reload.all? { |iu| iu.shipped? || iu.canceled? }
|
70
|
+
# TODO: make OrderShipping#ship_shipment call Shipment#ship! rather than
|
71
|
+
# having Shipment#ship! call OrderShipping#ship_shipment. We only really
|
72
|
+
# need this `update_columns` for the specs, until we make that change.
|
73
|
+
shipment.update_columns(state: 'shipped', shipped_at: Time.current)
|
70
74
|
end
|
71
75
|
|
72
76
|
send_shipment_emails(carton) if stock_location.fulfillable? && !suppress_mailer # e.g. digital gift cards that aren't actually shipped
|
73
|
-
@order.shipments.reload
|
74
77
|
@order.recalculate
|
75
78
|
|
76
79
|
carton
|
data/app/models/spree/price.rb
CHANGED
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
delegate :tax_rates, to: :variant
|
14
14
|
|
15
15
|
validate :check_price
|
16
|
-
validates :amount,
|
16
|
+
validates :amount, numericality: {
|
17
17
|
greater_than_or_equal_to: 0,
|
18
18
|
less_than_or_equal_to: MAXIMUM_AMOUNT
|
19
19
|
}
|
@@ -55,7 +55,7 @@ module Spree
|
|
55
55
|
|
56
56
|
def display_country
|
57
57
|
if country_iso
|
58
|
-
"#{country_iso} (#{
|
58
|
+
"#{country_iso} (#{country.name})"
|
59
59
|
else
|
60
60
|
I18n.t(:any_country, scope: [:spree, :admin, :prices])
|
61
61
|
end
|
@@ -29,25 +29,25 @@ module Spree
|
|
29
29
|
scope :descend_by_name, -> { order(name: :desc) }
|
30
30
|
|
31
31
|
add_search_scope :ascend_by_master_price do
|
32
|
-
joins(master: :
|
32
|
+
joins(master: :prices).select('spree_products.* , spree_prices.amount')
|
33
33
|
.order(Spree::Price.arel_table[:amount].asc)
|
34
34
|
end
|
35
35
|
|
36
36
|
add_search_scope :descend_by_master_price do
|
37
|
-
joins(master: :
|
37
|
+
joins(master: :prices).select('spree_products.* , spree_prices.amount')
|
38
38
|
.order(Spree::Price.arel_table[:amount].desc)
|
39
39
|
end
|
40
40
|
|
41
41
|
add_search_scope :price_between do |low, high|
|
42
|
-
joins(master: :
|
42
|
+
joins(master: :prices).where(Price.table_name => { amount: low..high })
|
43
43
|
end
|
44
44
|
|
45
45
|
add_search_scope :master_price_lte do |price|
|
46
|
-
joins(master: :
|
46
|
+
joins(master: :prices).where("#{price_table_name}.amount <= ?", price)
|
47
47
|
end
|
48
48
|
|
49
49
|
add_search_scope :master_price_gte do |price|
|
50
|
-
joins(master: :
|
50
|
+
joins(master: :prices).where("#{price_table_name}.amount >= ?", price)
|
51
51
|
end
|
52
52
|
|
53
53
|
# This scope selects products in taxon AND all its descendants
|
data/app/models/spree/product.rb
CHANGED
@@ -45,7 +45,6 @@ module Spree
|
|
45
45
|
|
46
46
|
has_many :variants,
|
47
47
|
-> { where(is_master: false).order(:position) },
|
48
|
-
inverse_of: :product,
|
49
48
|
class_name: 'Spree::Variant'
|
50
49
|
|
51
50
|
has_many :variants_including_master,
|
@@ -61,6 +60,17 @@ module Spree
|
|
61
60
|
has_many :line_items, through: :variants_including_master
|
62
61
|
has_many :orders, through: :line_items
|
63
62
|
|
63
|
+
scope :sort_by_master_default_price_amount_asc, -> {
|
64
|
+
with_default_price.order('spree_prices.amount ASC')
|
65
|
+
}
|
66
|
+
scope :sort_by_master_default_price_amount_desc, -> {
|
67
|
+
with_default_price.order('spree_prices.amount DESC')
|
68
|
+
}
|
69
|
+
scope :with_default_price, -> {
|
70
|
+
left_joins(master: :prices)
|
71
|
+
.where(master: { spree_prices: Spree::Config.default_pricing_options.desired_attributes })
|
72
|
+
}
|
73
|
+
|
64
74
|
def find_or_build_master
|
65
75
|
master || build_master
|
66
76
|
end
|
@@ -85,6 +95,7 @@ module Spree
|
|
85
95
|
:has_default_price?,
|
86
96
|
:images,
|
87
97
|
:price_for,
|
98
|
+
:price_for_options,
|
88
99
|
:rebuild_vat_prices=,
|
89
100
|
to: :find_or_build_master
|
90
101
|
|
@@ -5,12 +5,38 @@ module Spree
|
|
5
5
|
module Rules
|
6
6
|
# A rule to apply to an order greater than (or greater than or equal to)
|
7
7
|
# a specific amount
|
8
|
+
#
|
9
|
+
# To add extra operators please override `self.operators_map` or any other helper method.
|
10
|
+
# To customize the error message you can also override `ineligible_message`.
|
8
11
|
class ItemTotal < PromotionRule
|
12
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
13
|
+
|
9
14
|
preference :amount, :decimal, default: 100.00
|
10
15
|
preference :currency, :string, default: ->{ Spree::Config[:currency] }
|
11
|
-
preference :operator, :string, default: '
|
16
|
+
preference :operator, :string, default: 'gt'
|
17
|
+
|
18
|
+
# The list of allowed operators names mapped to their symbols.
|
19
|
+
def self.operators_map
|
20
|
+
{
|
21
|
+
gte: :>=,
|
22
|
+
gt: :>,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.operator_options
|
27
|
+
operators_map.map do |name, _method|
|
28
|
+
[I18n.t(name, scope: 'spree.item_total_rule.operators'), name]
|
29
|
+
end
|
30
|
+
end
|
12
31
|
|
13
|
-
|
32
|
+
# @deprecated
|
33
|
+
OPERATORS = operators_map.keys.map(&:to_s)
|
34
|
+
deprecate_constant(
|
35
|
+
:OPERATORS,
|
36
|
+
:operators_map,
|
37
|
+
message: "OPERATORS is deprecated! Use `operators_map.keys.map(&:to_s)` instead.",
|
38
|
+
deprecator: Spree::Deprecation,
|
39
|
+
)
|
14
40
|
|
15
41
|
def applicable?(promotable)
|
16
42
|
promotable.is_a?(Spree::Order)
|
@@ -18,8 +44,8 @@ module Spree
|
|
18
44
|
|
19
45
|
def eligible?(order, _options = {})
|
20
46
|
return false unless order.currency == preferred_currency
|
21
|
-
|
22
|
-
unless
|
47
|
+
|
48
|
+
unless total_for_order(order).send(operator, threshold)
|
23
49
|
eligibility_errors.add(:base, ineligible_message, error_code: ineligible_error_code)
|
24
50
|
end
|
25
51
|
|
@@ -28,15 +54,33 @@ module Spree
|
|
28
54
|
|
29
55
|
private
|
30
56
|
|
57
|
+
def operator
|
58
|
+
self.class.operators_map.fetch(
|
59
|
+
preferred_operator.to_sym,
|
60
|
+
preferred_operator_default,
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def total_for_order(order)
|
65
|
+
order.item_total
|
66
|
+
end
|
67
|
+
|
68
|
+
def threshold
|
69
|
+
BigDecimal(preferred_amount.to_s)
|
70
|
+
end
|
71
|
+
|
31
72
|
def formatted_amount
|
32
73
|
Spree::Money.new(preferred_amount, currency: preferred_currency).to_s
|
33
74
|
end
|
34
75
|
|
35
76
|
def ineligible_message
|
36
|
-
|
77
|
+
case preferred_operator.to_s
|
78
|
+
when 'gte'
|
37
79
|
eligibility_error_message(:item_total_less_than, amount: formatted_amount)
|
38
|
-
|
80
|
+
when 'gt'
|
39
81
|
eligibility_error_message(:item_total_less_than_or_equal, amount: formatted_amount)
|
82
|
+
else
|
83
|
+
eligibility_error_message(:item_total_doesnt_match_with_operator, amount: formatted_amount, operator: preferred_operator)
|
40
84
|
end
|
41
85
|
end
|
42
86
|
|
@@ -47,7 +47,7 @@ module Spree
|
|
47
47
|
where(table[:expires_at].eq(nil).or(table[:expires_at].gt(time)))
|
48
48
|
end
|
49
49
|
scope :has_actions, -> do
|
50
|
-
joins(:promotion_actions)
|
50
|
+
joins(:promotion_actions).distinct
|
51
51
|
end
|
52
52
|
scope :applied, -> { joins(:order_promotions).distinct }
|
53
53
|
|
@@ -192,7 +192,7 @@ module Spree
|
|
192
192
|
def usage_count(excluded_orders: [])
|
193
193
|
Spree::Adjustment.promotion.
|
194
194
|
eligible.
|
195
|
-
in_completed_orders(excluded_orders: excluded_orders).
|
195
|
+
in_completed_orders(excluded_orders: excluded_orders, exclude_canceled: true).
|
196
196
|
where(source_id: actions).
|
197
197
|
count(:order_id)
|
198
198
|
end
|
@@ -5,12 +5,12 @@ class Spree::PromotionCode < Spree::Base
|
|
5
5
|
belongs_to :promotion_code_batch, class_name: "Spree::PromotionCodeBatch", optional: true
|
6
6
|
has_many :adjustments
|
7
7
|
|
8
|
-
before_validation :normalize_code
|
9
|
-
|
10
8
|
validates :value, presence: true, uniqueness: { allow_blank: true, case_sensitive: true }
|
11
9
|
validates :promotion, presence: true
|
12
10
|
validate :promotion_not_apply_automatically, on: :create
|
13
11
|
|
12
|
+
before_save :normalize_code
|
13
|
+
|
14
14
|
self.whitelisted_ransackable_attributes = ['value']
|
15
15
|
|
16
16
|
# Whether the promotion code has exceeded its usage restrictions
|
@@ -30,7 +30,7 @@ class Spree::PromotionCode < Spree::Base
|
|
30
30
|
def usage_count(excluded_orders: [])
|
31
31
|
adjustments.
|
32
32
|
eligible.
|
33
|
-
in_completed_orders(excluded_orders: excluded_orders).
|
33
|
+
in_completed_orders(excluded_orders: excluded_orders, exclude_canceled: true).
|
34
34
|
count(:order_id)
|
35
35
|
end
|
36
36
|
|
data/app/models/spree/refund.rb
CHANGED
@@ -31,14 +31,6 @@ module Spree
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
# Sets this price's amount to a new value, parsing it if the new value is
|
35
|
-
# a string.
|
36
|
-
#
|
37
|
-
# @param price [String, #to_d] a new amount
|
38
|
-
def amount=(price)
|
39
|
-
self[:amount] = Spree::LocalizedNumber.parse(price)
|
40
|
-
end
|
41
|
-
|
42
34
|
def description
|
43
35
|
payment.payment_method.name
|
44
36
|
end
|
@@ -5,7 +5,7 @@ module Spree
|
|
5
5
|
# @attr [Spree::ShippingRate] shipping_rate The shipping rate to be taxed
|
6
6
|
# @attr [Spree::TaxRate] tax_rate The tax rate used to calculate the tax amount
|
7
7
|
# @since 1.3.0
|
8
|
-
# @see Spree::
|
8
|
+
# @see Spree::Stock::Estimator
|
9
9
|
class ShippingRateTax < Spree::Base
|
10
10
|
belongs_to :shipping_rate, class_name: "Spree::ShippingRate", optional: true
|
11
11
|
belongs_to :tax_rate, class_name: "Spree::TaxRate", optional: true
|