solidus_core 4.7.1 → 4.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78c29ac128ed3b6ae1572035004a577b125403271d2d331f598a6fae3860003d
4
- data.tar.gz: aecc835e960dc5b51f163f41ea9abc07dba2ff27717f24c8623a563b14d5e9ad
3
+ metadata.gz: 6016be6a4a01809df118c168c5dd345f73ed968f3ad53262c45594680491d4cb
4
+ data.tar.gz: 64faf68ec42068af0ca862a72f5253fd1f72c99b12b0616178d10c11879e550a
5
5
  SHA512:
6
- metadata.gz: b9a161abf80858e4511684189d7f66f93e9a0774f091448702f174586ae10a1c13669d6c0efa6afd9f20470602dc95e55a06bad734913e482195915d053b56d6
7
- data.tar.gz: ea34f9b2b35829c6888d11ceea67b3b056c1857ab9567fc941827d84c7b23789853ae1f9f2f6aec4381074208fd574742fa571ddbb0d72edee33fb90ccd0c535
6
+ metadata.gz: c9b6182a1739ef955f53359f927874aee7bcbed451362e4d228b32ee9526ace50bddca9816fa9383662c41352824a03dcbe6a5d6064ab085271a56c0ae02d7bd
7
+ data.tar.gz: cc30e67a19c56e0f0948501a813e2bdf3810eb19e08ecf18482c771aeff678217d4eb4b1ff050a2f92688cd36bfbb1ca3c55e037fcda9bed71fa4edd04e385c0
@@ -49,7 +49,7 @@ module Spree
49
49
  if Spree::Config[:show_raw_product_description]
50
50
  raw(product.description)
51
51
  else
52
- raw(product.description.gsub(/(.*?)\r?\n\r?\n/m, '<p>\1</p>'))
52
+ sanitize(product.description.gsub(/(.*?)\r?\n\r?\n/m, '<p>\1</p>'))
53
53
  end
54
54
  end
55
55
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Spree
4
4
  # Base class for all Solidus background jobs
5
- class BaseJob < ActiveJob::Base # rubocop:disable Rails/ApplicationJob
5
+ class BaseJob < ActiveJob::Base
6
6
  # Automatically retry jobs that encountered a deadlock
7
7
  retry_on ActiveRecord::Deadlocked
8
8
 
@@ -130,14 +130,14 @@ module Spree
130
130
 
131
131
  # Updates the roles in keeping with the given ability's permissions
132
132
  #
133
- # Roles that are not accessible to the given ability will be ignored. It
134
- # also ensure not to remove non accessible roles when assigning new
135
- # accessible ones.
133
+ # Roles that the given ability cannot manage will be ignored. It also
134
+ # ensure not to remove non manageable roles when assigning new manageable
135
+ # ones.
136
136
  #
137
137
  # @param given_roles [Spree::Role]
138
138
  # @param ability [Spree::Ability]
139
139
  def update_spree_roles(given_roles, ability:)
140
- accessible_roles = Spree::Role.accessible_by(ability)
140
+ accessible_roles = Spree::Role.accessible_by(ability, :manage)
141
141
  non_accessible_roles = Spree::Role.all - accessible_roles
142
142
  new_accessible_roles = given_roles - non_accessible_roles
143
143
  self.spree_roles = spree_roles - accessible_roles + new_accessible_roles
@@ -321,8 +321,15 @@ module Spree
321
321
 
322
322
  # Associates the specified user with the order.
323
323
  def associate_user!(user, override_email = true)
324
+ user_changed = user_id != user.try(:id)
324
325
  self.user = user
325
326
  attrs_to_set = {user_id: user.try(:id)}
327
+
328
+ if user_changed
329
+ self.guest_token = nil
330
+ attrs_to_set[:guest_token] = create_token
331
+ end
332
+
326
333
  attrs_to_set[:email] = user.try(:email) if override_email
327
334
  attrs_to_set[:created_by_id] = user.try(:id) if created_by.blank?
328
335
 
@@ -113,7 +113,6 @@ module Spree
113
113
  end
114
114
 
115
115
  def gateway_options
116
- order.reload
117
116
  options = {
118
117
  email: order.email,
119
118
  customer: order.email,
@@ -8,6 +8,10 @@ module Spree
8
8
  # * :payment_method_id Id of payment method used for this payment
9
9
  # * :source_attributes Attributes used to build the source of this payment. Usually a {CreditCard}
10
10
  # * :wallet_payment_source_id (Integer): The id of a {WalletPaymentSource} to use
11
+ # * :gateway_customer_profile_id, :gateway_payment_profile_id (String): Gateway
12
+ # identifiers for a new {CreditCard}, e.g. a one-time token. Raises
13
+ # ActiveRecord::RecordNotFound if either already belongs to a {CreditCard}
14
+ # owned by a different user or order.
11
15
  # @param request_env [Hash] rack env of user creating the payment
12
16
  # @param payment [Payment] Internal use only. Instead of making a new payment, change the attributes for an existing one.
13
17
  def initialize(order, attributes, payment: nil, request_env: {})
@@ -44,6 +48,7 @@ module Spree
44
48
  def build_source
45
49
  payment_method = payment.payment_method
46
50
  if source_attributes.present? && payment_method.try(:payment_source_class)
51
+ ensure_gateway_profile_ownership!(payment_method.payment_source_class)
47
52
  payment.source = payment_method.payment_source_class.new(source_attributes)
48
53
  payment.source.payment_method_id = payment_method.id
49
54
  if order && payment.source.respond_to?(:user=)
@@ -52,6 +57,26 @@ module Spree
52
57
  end
53
58
  end
54
59
 
60
+ # Gateway profile IDs may only be submitted for a new source when they are
61
+ # unknown to the store (e.g. a one-time token) or already belong to the
62
+ # order's user. Raises if either id is stored on a {CreditCard} owned by a
63
+ # different user or no user, so customers cannot pay with another
64
+ # customer's stored gateway credential.
65
+ def ensure_gateway_profile_ownership!(source_class)
66
+ return unless source_class <= Spree::CreditCard
67
+
68
+ %i[gateway_customer_profile_id gateway_payment_profile_id].each do |attribute|
69
+ value = source_attributes[attribute]
70
+ next if value.blank?
71
+
72
+ foreign_cards = Spree::CreditCard.where(attribute => value)
73
+ if order&.user_id
74
+ foreign_cards = foreign_cards.where(user_id: nil).or(foreign_cards.where.not(user_id: order.user_id))
75
+ end
76
+ raise ActiveRecord::RecordNotFound if foreign_cards.exists?
77
+ end
78
+ end
79
+
55
80
  def build_from_wallet_payment_source
56
81
  wallet_payment_source_id = source_attributes.fetch(:wallet_payment_source_id)
57
82
  raise(ActiveRecord::RecordNotFound) if order.user.nil?
@@ -355,14 +355,17 @@ module Spree
355
355
  run_callbacks(:touch)
356
356
  end
357
357
 
358
- # Iterate through this product's taxons and taxonomies and touch their timestamps in a batch
358
+ # Iterate through this product's taxons and taxonomies and touch their timestamps
359
359
  def touch_taxons
360
- taxons_to_touch = taxons.flat_map(&:self_and_ancestors).uniq
361
- unless taxons_to_touch.empty?
362
- Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
360
+ taxons_to_touch = taxons.flat_map(&:self_and_ancestors).uniq.sort_by(&:id)
361
+ return if taxons_to_touch.empty?
363
362
 
364
- taxonomy_ids_to_touch = taxons_to_touch.flat_map(&:taxonomy_id).uniq
365
- Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
363
+ time = Time.current
364
+ taxons_to_touch.each { |taxon| taxon.update_column(:updated_at, time) }
365
+
366
+ taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).uniq
367
+ Spree::Taxonomy.where(id: taxonomy_ids_to_touch).order(:id).each do |taxonomy|
368
+ taxonomy.touch(time:)
366
369
  end
367
370
  end
368
371
 
@@ -41,6 +41,7 @@ module Spree
41
41
 
42
42
  validate :eligible_exchange_variant
43
43
  validate :belongs_to_same_customer_order
44
+ validate :belongs_to_return_authorization_order, if: -> { inventory_unit_id_changed? || return_authorization_id_changed? }
44
45
  validate :validate_acceptance_status_for_reimbursement
45
46
  validate :validate_no_other_completed_return_items
46
47
 
@@ -226,6 +227,14 @@ module Spree
226
227
  end
227
228
  end
228
229
 
230
+ def belongs_to_return_authorization_order
231
+ return unless return_authorization && inventory_unit
232
+
233
+ if return_authorization.order_id != inventory_unit.order_id
234
+ errors.add(:base, I18n.t("spree.return_items_cannot_be_associated_with_multiple_orders"))
235
+ end
236
+ end
237
+
229
238
  def eligible_exchange_variant
230
239
  return unless exchange_variant && exchange_variant_id_changed?
231
240
  unless eligible_exchange_variants.include?(exchange_variant)
@@ -25,7 +25,7 @@ module Spree
25
25
  self.allowed_ransackable_attributes = %w[name url code]
26
26
 
27
27
  before_save :ensure_default_exists_and_is_unique
28
- before_destroy :validate_not_default
28
+ before_destroy :validate_not_default, prepend: true
29
29
 
30
30
  enum :reverse_charge_status, {
31
31
  disabled: 0,
@@ -73,6 +73,7 @@ module Spree
73
73
  def validate_not_default
74
74
  if default
75
75
  errors.add(:base, :cannot_destroy_default_store)
76
+ throw :abort
76
77
  end
77
78
  end
78
79
  end
@@ -140,8 +140,11 @@ module Spree
140
140
  private
141
141
 
142
142
  def touch_ancestors_and_taxonomy
143
- # Touches all ancestors at once to avoid recursive taxonomy touch, and reduce queries.
144
- self.class.default_scoped.where(id: ancestors.pluck(:id)).update_all(updated_at: Time.current)
143
+ # Touches ancestors directly rather than through #touch to avoid a recursive taxonomy touch.
144
+ time = Time.current
145
+ self.class.default_scoped.where(id: ancestors.pluck(:id)).order(:id).each do |ancestor|
146
+ ancestor.update_column(:updated_at, time)
147
+ end
145
148
  # Have taxonomy touch happen in #touch_ancestors_and_taxonomy rather than association option in order for imports to override.
146
149
  taxonomy.try!(:touch)
147
150
  end
@@ -25,6 +25,7 @@ module Spree
25
25
  def run
26
26
  # Early return if there is no VAT rates in the current store.
27
27
  return if !variant.tax_category || variant_vat_rates.empty?
28
+ return if variant.default_price&.amount.nil?
28
29
 
29
30
  country_isos_requiring_price.each do |country_iso|
30
31
  # Don't re-create the default price
@@ -4,9 +4,7 @@ begin
4
4
  user_class.classify.constantize
5
5
  rescue NameError
6
6
  say_status :error, "Can't find an existing user class named #{user_class.classify}, plese set up one before using this authentication option.", :red
7
- # rubocop:disable Rails/Exit
8
7
  abort
9
- # rubocop:enable Rails/Exit
10
8
  end
11
9
 
12
10
  generate "spree:custom_user #{user_class.shellescape}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Spree
4
- VERSION = "4.7.1"
4
+ VERSION = "4.7.3"
5
5
 
6
6
  def self.solidus_version = VERSION
7
7
 
@@ -111,5 +111,9 @@ module Spree::Preferences
111
111
  def allowed_admin_form_preference_types
112
112
  DEFAULT_ADMIN_FORM_PREFERENCE_TYPES
113
113
  end
114
+
115
+ def permitted_preference_attributes
116
+ new.admin_form_preference_names.map { |name| :"preferred_#{name}" }
117
+ end
114
118
  end
115
119
  end
@@ -22,7 +22,8 @@ module Spree
22
22
 
23
23
  def preferences
24
24
  if respond_to?(:preference_source) && preference_source
25
- self.class.preference_sources[preference_source] || {}
25
+ source = self.class.preference_sources[preference_source]
26
+ source ? default_preferences.merge(source.to_hash) : {}
26
27
  else
27
28
  self[:preferences]
28
29
  end
@@ -2,7 +2,15 @@
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :return_item, class: "Spree::ReturnItem" do
5
- association(:inventory_unit, factory: :inventory_unit, state: :shipped)
5
+ inventory_unit do
6
+ # When a return authorization is given, the inventory unit must belong
7
+ # to the same order.
8
+ if __override_names__.include?(:return_authorization) && return_authorization&.order
9
+ association(:inventory_unit, state: :shipped, order: return_authorization.order)
10
+ else
11
+ association(:inventory_unit, state: :shipped)
12
+ end
13
+ end
6
14
  association(:return_reason, factory: :return_reason)
7
15
  return_authorization do |_return_item|
8
16
  build(:return_authorization, order: inventory_unit.order)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.1
4
+ version: 4.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team