solidus_core 3.0.8 → 3.1.0
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.
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
|