solidus_core 3.0.2 → 3.1.3

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.

Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +1 -1
  3. data/app/helpers/spree/products_helper.rb +1 -1
  4. data/app/models/concerns/spree/default_price.rb +63 -10
  5. data/app/models/spree/adjustment.rb +6 -5
  6. data/app/models/spree/customer_return.rb +3 -2
  7. data/app/models/spree/image/active_storage_attachment.rb +2 -7
  8. data/app/models/spree/image/paperclip_attachment.rb +2 -2
  9. data/app/models/spree/line_item.rb +2 -2
  10. data/app/models/spree/order.rb +11 -6
  11. data/app/models/spree/price.rb +1 -1
  12. data/app/models/spree/product/scopes.rb +5 -5
  13. data/app/models/spree/product.rb +12 -0
  14. data/app/models/spree/promotion/rules/item_total.rb +50 -6
  15. data/app/models/spree/promotion.rb +2 -2
  16. data/app/models/spree/promotion_code.rb +1 -1
  17. data/app/models/spree/shipping_rate_tax.rb +1 -1
  18. data/app/models/spree/stock/availability.rb +11 -3
  19. data/app/models/spree/stock/simple_coordinator.rb +0 -10
  20. data/app/models/spree/stock_location.rb +1 -1
  21. data/app/models/spree/store_credit.rb +6 -1
  22. data/app/models/spree/tax_calculator/shipping_rate.rb +1 -1
  23. data/app/models/spree/taxon/active_storage_attachment.rb +2 -2
  24. data/app/models/spree/taxon/paperclip_attachment.rb +3 -3
  25. data/app/models/spree/variant/price_selector.rb +16 -3
  26. data/app/models/spree/variant.rb +26 -16
  27. data/config/locales/en.yml +2 -0
  28. data/db/migrate/20210312061050_change_column_null_on_prices.rb +7 -0
  29. data/lib/generators/solidus/install/install_generator.rb +1 -1
  30. data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +3 -1
  31. data/lib/generators/solidus/update/templates/config/initializers/new_solidus_defaults.rb.tt +30 -0
  32. data/lib/generators/solidus/update/update_generator.rb +112 -0
  33. data/lib/generators/spree/dummy/templates/rails/application.rb.tt +0 -1
  34. data/lib/generators/spree/dummy/templates/rails/database.yml +78 -35
  35. data/lib/spree/app_configuration.rb +62 -0
  36. data/lib/spree/core/engine.rb +16 -9
  37. data/lib/spree/core/product_filters.rb +1 -1
  38. data/lib/spree/core/search/base.rb +1 -1
  39. data/lib/spree/core/state_machines/order.rb +1 -1
  40. data/lib/spree/core/version.rb +5 -1
  41. data/lib/spree/core/versioned_value.rb +75 -0
  42. data/lib/spree/core.rb +28 -0
  43. data/lib/spree/permitted_attributes.rb +1 -1
  44. data/lib/spree/preferences/configuration.rb +62 -0
  45. data/lib/spree/preferences/preferable.rb +8 -0
  46. data/lib/spree/preferences/preferable_class_methods.rb +37 -4
  47. data/lib/spree/preferences/preference_differentiator.rb +28 -0
  48. data/lib/spree/testing_support/dummy_app/database.yml +42 -22
  49. data/lib/spree/testing_support/dummy_app.rb +33 -18
  50. data/lib/tasks/solidus/delete_prices_with_nil_amount.rake +8 -0
  51. data/solidus_core.gemspec +6 -1
  52. metadata +17 -8
  53. data/app/models/spree/tax/shipping_rate_taxer.rb +0 -24
  54. data/lib/tasks/upgrade.rake +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca6d8d275b71868fa0cbcfd87ea5c540ed14c4db6908e90192012889adc936b9
4
- data.tar.gz: b9333bbde0b2634d590a9021d2b4c4a2cb398a25099254947b870f94ff0d5992
3
+ metadata.gz: 25d076da4eef33c845f1da39a5bb6e7b6164c98372bc59f1d9cd441fc182576a
4
+ data.tar.gz: f4b6369b678db721bd71e67323468e376e6ab59bfb67cb766cbc05927a42cc7c
5
5
  SHA512:
6
- metadata.gz: c56f0af4fbd26a4d486aaeb170d6554d256a7265a33a0a515150822dc8aefa1369e7e4ce8b3e3b60ea2a32318b9f03d9f214d18c6014ff248649d3867cc83a0b
7
- data.tar.gz: acc8a07396946a959ebda8e0c7953eb7cb6ac656a7e91debd6e0159d0c7a6e896f0406d226fd3e28d6776999fc9797938010cdb952bea32ae819cdd64f435b4e
6
+ metadata.gz: 5eec6a669e66e4fb3c2a492844ff0e73c60e06b14b959f9ea868995e2f5e766f1a6493da85ef3494e726e0ddbbc483dc93b524d4a07be31305edde61fe917d24
7
+ data.tar.gz: aae29e7ece97dde8df64e368e2bddf5c9bd95cc5118a345d343d8625234355e15b9edf055f9aac7bca2d048235cff6b77de4cfcbd7ae81b544769924d7aa4c89
@@ -130,7 +130,7 @@ module Spree
130
130
  end
131
131
 
132
132
  def display_price(product_or_variant)
133
- product_or_variant.price_for(current_pricing_options).to_html
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.price_for(current_pricing_options).to_html
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.
@@ -5,23 +5,76 @@ module Spree
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- has_one :default_price,
9
- -> { with_discarded.currently_valid.with_default_attributes },
10
- class_name: 'Spree::Price',
11
- inverse_of: :variant,
12
- dependent: :destroy,
13
- autosave: true
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
- def find_or_build_default_price
17
- default_price || build_default_price(Spree::Config.default_pricing_options.desired_attributes)
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
- delegate :display_price, :display_amount, :price, to: :find_or_build_default_price
21
- delegate :price=, to: :find_or_build_default_price
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
@@ -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
- merge(Spree::Order.complete).
61
- where.not(spree_orders: { id: excluded_orders }).
62
- distinct
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
- return_items.first.inventory_unit.order
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.order_id == order_id }.any?
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
- mini: '48x48>',
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: { mini: '48x48>', small: '400x400>', product: '680x680>', large: '1200x1200>' },
11
- default_style: :product,
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.price_for(pricing_options)
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.price_for(pricing_options) if price.nil?
152
+ self.money_price = variant.price_for_options(pricing_options)&.money if price.nil?
153
153
  true
154
154
  end
155
155
 
@@ -51,7 +51,7 @@ module Spree
51
51
  end
52
52
 
53
53
  self.whitelisted_ransackable_associations = %w[shipments user order_promotions promotions bill_address ship_address line_items]
54
- self.whitelisted_ransackable_attributes = %w[bill_address_name completed_at created_at email number state payment_state shipment_state total store_id]
54
+ self.whitelisted_ransackable_attributes = %w[completed_at created_at email number state payment_state shipment_state total store_id]
55
55
 
56
56
  attr_reader :coupon_code
57
57
  attr_accessor :temporary_address
@@ -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: :require_email
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::OrderContents.new(self)
272
+ @contents ||= Spree::Config.order_contents_class.new(self)
273
273
  end
274
274
 
275
275
  def shipping
276
- @shipping ||= Spree::OrderShipping.new(self)
276
+ @shipping ||= Spree::Config.order_shipping_class.new(self)
277
277
  end
278
278
 
279
279
  def cancellations
280
- @cancellations ||= Spree::OrderCancellations.new(self)
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 require_email
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
@@ -13,7 +13,7 @@ module Spree
13
13
  delegate :tax_rates, to: :variant
14
14
 
15
15
  validate :check_price
16
- validates :amount, allow_nil: true, numericality: {
16
+ validates :amount, numericality: {
17
17
  greater_than_or_equal_to: 0,
18
18
  less_than_or_equal_to: MAXIMUM_AMOUNT
19
19
  }
@@ -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: :default_price).select('spree_products.* , spree_prices.amount')
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: :default_price).select('spree_products.* , spree_prices.amount')
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: :default_price).where(Price.table_name => { amount: low..high })
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: :default_price).where("#{price_table_name}.amount <= ?", price)
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: :default_price).where("#{price_table_name}.amount >= ?", price)
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
@@ -60,6 +60,17 @@ module Spree
60
60
  has_many :line_items, through: :variants_including_master
61
61
  has_many :orders, through: :line_items
62
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
+
63
74
  def find_or_build_master
64
75
  master || build_master
65
76
  end
@@ -84,6 +95,7 @@ module Spree
84
95
  :has_default_price?,
85
96
  :images,
86
97
  :price_for,
98
+ :price_for_options,
87
99
  :rebuild_vat_prices=,
88
100
  to: :find_or_build_master
89
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
- OPERATORS = ['gt', 'gte']
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
- item_total = order.item_total
22
- unless item_total.send(preferred_operator == 'gte' ? :>= : :>, BigDecimal(preferred_amount.to_s))
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
- if preferred_operator == 'gte'
77
+ case preferred_operator.to_s
78
+ when 'gte'
37
79
  eligibility_error_message(:item_total_less_than, amount: formatted_amount)
38
- else
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
@@ -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
 
@@ -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::Tax::ShippingRateTaxer
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
@@ -19,7 +19,7 @@ module Spree
19
19
  # Get the on_hand stock quantities
20
20
  # @return [Hash<Integer=>Spree::StockQuantities>] A map of stock_location_ids to the stock quantities available in that location
21
21
  def on_hand_by_stock_location_id
22
- counts_on_hand.to_a.group_by do |(_, stock_location_id), _|
22
+ quantities_by_location_id = counts_on_hand.to_a.group_by do |(_, stock_location_id), _|
23
23
  stock_location_id
24
24
  end.transform_values do |values|
25
25
  Spree::StockQuantities.new(
@@ -31,12 +31,13 @@ module Spree
31
31
  end.to_h
32
32
  )
33
33
  end
34
+ restore_location_order(quantities_by_location_id)
34
35
  end
35
36
 
36
- # Get the on_hand stock quantities
37
+ # Get the backorderable stock quantities
37
38
  # @return [Hash<Integer=>Spree::StockQuantities>] A map of stock_location_ids to the stock quantities available in that location
38
39
  def backorderable_by_stock_location_id
39
- backorderables.group_by(&:second).transform_values do |variant_ids|
40
+ quantities_by_location_id = backorderables.group_by(&:second).transform_values do |variant_ids|
40
41
  Spree::StockQuantities.new(
41
42
  variant_ids.map do |variant_id, _|
42
43
  variant = @variant_map[variant_id]
@@ -44,6 +45,7 @@ module Spree
44
45
  end.to_h
45
46
  )
46
47
  end
48
+ restore_location_order(quantities_by_location_id)
47
49
  end
48
50
 
49
51
  private
@@ -67,6 +69,12 @@ module Spree
67
69
  where(variant_id: @variants).
68
70
  where(stock_location_id: @stock_locations)
69
71
  end
72
+
73
+ def restore_location_order(quantities_by_location_id)
74
+ sorted_location_ids = @stock_locations.map(&:id)
75
+
76
+ quantities_by_location_id.sort_by { |key, _value| sorted_location_ids.index(key) }.to_h
77
+ end
70
78
  end
71
79
  end
72
80
  end
@@ -92,16 +92,6 @@ module Spree
92
92
  end
93
93
  end
94
94
 
95
- def sort_availability(availability)
96
- sorted_availability = availability.sort_by do |stock_location_id, _|
97
- @stock_locations.find_index do |stock_location|
98
- stock_location.id == stock_location_id
99
- end
100
- end
101
-
102
- Hash[sorted_availability]
103
- end
104
-
105
95
  def get_units(quantities)
106
96
  # Change our raw quantities back into inventory units
107
97
  quantities.flat_map do |variant, quantity|
@@ -26,7 +26,7 @@ module Spree
26
26
  validates_uniqueness_of :code, allow_blank: true, case_sensitive: false
27
27
 
28
28
  scope :active, -> { where(active: true) }
29
- scope :order_default, -> { order(default: :desc, name: :asc) }
29
+ scope :order_default, -> { order(default: :desc, position: :asc) }
30
30
 
31
31
  after_create :create_stock_items, if: :propagate_all_variants?
32
32
  after_save :ensure_one_default
@@ -150,7 +150,12 @@ class Spree::StoreCredit < Spree::PaymentSource
150
150
  end
151
151
 
152
152
  def generate_authorization_code
153
- "#{id}-SC-#{Time.current.utc.strftime('%Y%m%d%H%M%S%6N')}"
153
+ [
154
+ id,
155
+ 'SC',
156
+ Time.current.utc.strftime('%Y%m%d%H%M%S%6N'),
157
+ SecureRandom.uuid
158
+ ].join('-')
154
159
  end
155
160
 
156
161
  def editable?
@@ -9,7 +9,7 @@ module Spree
9
9
  # looking to provide their own calculator should adhere to the API of this
10
10
  # class.
11
11
  #
12
- # @see Spree::Tax::ShippingRateTaxer
12
+ # @see Spree::Stock::Estimator
13
13
  class ShippingRate
14
14
  include Spree::Tax::TaxHelpers
15
15
 
@@ -6,8 +6,8 @@ module Spree::Taxon::ActiveStorageAttachment
6
6
 
7
7
  included do
8
8
  has_attachment :icon,
9
- styles: { mini: '32x32>', normal: '128x128>' },
10
- default_style: :mini
9
+ styles: Spree::Config.taxon_image_styles,
10
+ default_style: Spree::Config.taxon_image_style_default
11
11
  validate :icon_is_an_image
12
12
  end
13
13
  end
@@ -5,14 +5,14 @@ module Spree::Taxon::PaperclipAttachment
5
5
 
6
6
  included do
7
7
  has_attached_file :icon,
8
- styles: { mini: '32x32>', normal: '128x128>' },
9
- default_style: :mini,
8
+ styles: Spree::Config.taxon_image_styles,
9
+ default_style: Spree::Config.taxon_image_style_default,
10
10
  url: '/spree/taxons/:id/:style/:basename.:extension',
11
11
  path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
12
12
  default_url: '/assets/default_taxon.png'
13
13
 
14
14
  validates_attachment :icon,
15
- content_type: { content_type: %w[image/jpg image/jpeg image/png image/gif] }
15
+ content_type: { content_type: Spree::Config.allowed_image_mime_types }
16
16
  end
17
17
 
18
18
  def icon_present?
@@ -26,11 +26,24 @@ module Spree
26
26
  # @param [Spree::Variant::PricingOptions] price_options Pricing Options to abide by
27
27
  # @return [Spree::Money, nil] The most specific price for this set of pricing options.
28
28
  def price_for(price_options)
29
+ Spree::Deprecation.warn(
30
+ "price_for is deprecated and will be removed. The price_for method
31
+ should return a Spree::Price as described. Please use
32
+ #price_for_options and adjust your frontend code to explicitly call
33
+ &.money where required"
34
+ )
35
+ price_for_options(price_options)&.money
36
+ end
37
+
38
+ # The variant's Spree::Price record, given a set of pricing options
39
+ # @param [Spree::Variant::PricingOptions] price_options Pricing Options to abide by
40
+ # @return [Spree::Price, nil] The most specific price for this set of pricing options.
41
+ def price_for_options(price_options)
29
42
  variant.currently_valid_prices.detect do |price|
30
- ( price.country_iso == price_options.desired_attributes[:country_iso] ||
31
- price.country_iso.nil?
43
+ (price.country_iso == price_options.desired_attributes[:country_iso] ||
44
+ price.country_iso.nil?
32
45
  ) && price.currency == price_options.desired_attributes[:currency]
33
- end.try!(:money)
46
+ end
34
47
  end
35
48
  end
36
49
  end