spree_core 2.4.10 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/app/assets/images/logo/spree_50.png +0 -0
  4. data/app/controllers/spree/base_controller.rb +1 -2
  5. data/app/helpers/spree/base_helper.rb +41 -131
  6. data/app/helpers/spree/products_helper.rb +1 -1
  7. data/app/models/concerns/spree/adjustment_source.rb +51 -15
  8. data/app/models/concerns/spree/calculated_adjustments.rb +1 -0
  9. data/app/models/concerns/spree/display_money.rb +32 -0
  10. data/app/models/concerns/spree/named_type.rb +1 -1
  11. data/app/models/concerns/spree/number_generator.rb +39 -0
  12. data/app/models/concerns/spree/user_reporting.rb +3 -8
  13. data/app/models/spree/address.rb +0 -2
  14. data/app/models/spree/adjustable/adjustments_updater.rb +70 -0
  15. data/app/models/spree/adjustable/promotion_accumulator.rb +75 -0
  16. data/app/models/spree/adjustment.rb +17 -26
  17. data/app/models/spree/app_configuration.rb +4 -33
  18. data/app/models/spree/base.rb +0 -3
  19. data/app/models/spree/calculator.rb +0 -5
  20. data/app/models/spree/classification.rb +1 -1
  21. data/app/models/spree/country.rb +10 -4
  22. data/app/models/spree/credit_card.rb +14 -15
  23. data/app/models/spree/customer_return.rb +18 -25
  24. data/app/models/spree/gateway/bogus.rb +0 -4
  25. data/app/models/spree/line_item.rb +2 -5
  26. data/app/models/spree/option_type.rb +2 -4
  27. data/app/models/spree/option_value.rb +0 -2
  28. data/app/models/spree/order.rb +74 -134
  29. data/app/models/spree/order/checkout.rb +1 -1
  30. data/app/models/spree/order_contents.rb +9 -8
  31. data/app/models/spree/order_updater.rb +8 -1
  32. data/app/models/spree/payment.rb +13 -23
  33. data/app/models/spree/payment/gateway_options.rb +86 -0
  34. data/app/models/spree/payment/processing.rb +8 -39
  35. data/app/models/spree/payment_method.rb +3 -6
  36. data/app/models/spree/price.rb +2 -6
  37. data/app/models/spree/product.rb +27 -16
  38. data/app/models/spree/product_property.rb +1 -5
  39. data/app/models/spree/promotion.rb +7 -15
  40. data/app/models/spree/promotion/actions/create_adjustment.rb +4 -45
  41. data/app/models/spree/promotion/actions/create_item_adjustments.rb +8 -63
  42. data/app/models/spree/promotion/actions/create_line_items.rb +3 -12
  43. data/app/models/spree/promotion/actions/free_shipping.rb +4 -24
  44. data/app/models/spree/promotion/rules/option_value.rb +49 -0
  45. data/app/models/spree/promotion_action.rb +6 -0
  46. data/app/models/spree/promotion_handler/cart.rb +14 -18
  47. data/app/models/spree/promotion_handler/coupon.rb +1 -1
  48. data/app/models/spree/promotion_rule.rb +0 -1
  49. data/app/models/spree/property.rb +0 -2
  50. data/app/models/spree/refund.rb +0 -15
  51. data/app/models/spree/reimbursement.rb +4 -4
  52. data/app/models/spree/reimbursement_type/credit.rb +1 -1
  53. data/app/models/spree/reimbursement_type/original_payment.rb +1 -1
  54. data/app/models/spree/return_authorization.rb +4 -11
  55. data/app/models/spree/return_item.rb +16 -11
  56. data/app/models/spree/return_item/eligibility_validator/default.rb +2 -0
  57. data/app/models/spree/return_item/eligibility_validator/inventory_shipped.rb +16 -0
  58. data/app/models/spree/return_item/eligibility_validator/no_reimbursements.rb +16 -0
  59. data/app/models/spree/shipment.rb +20 -31
  60. data/app/models/spree/shipment_handler.rb +1 -1
  61. data/app/models/spree/shipping_method.rb +12 -13
  62. data/app/models/spree/state.rb +7 -0
  63. data/app/models/spree/state_change.rb +1 -6
  64. data/app/models/spree/stock/availability_validator.rb +9 -10
  65. data/app/models/spree/stock/coordinator.rb +1 -1
  66. data/app/models/spree/stock/estimator.rb +6 -6
  67. data/app/models/spree/stock/quantifier.rb +1 -1
  68. data/app/models/spree/stock_item.rb +1 -7
  69. data/app/models/spree/stock_location.rb +3 -1
  70. data/app/models/spree/stock_movement.rb +1 -8
  71. data/app/models/spree/stock_transfer.rb +11 -5
  72. data/app/models/spree/store.rb +2 -2
  73. data/app/models/spree/tax_rate.rb +30 -55
  74. data/app/models/spree/taxon.rb +8 -8
  75. data/app/models/spree/taxonomy.rb +8 -13
  76. data/app/models/spree/tracker.rb +1 -1
  77. data/app/models/spree/variant.rb +6 -15
  78. data/app/models/spree/zone.rb +43 -9
  79. data/config/initializers/user_class_extensions.rb +0 -12
  80. data/config/locales/en.yml +76 -85
  81. data/config/routes.rb +1 -1
  82. data/db/default/spree/countries.rb +23 -13
  83. data/db/default/spree/states.rb +24 -12
  84. data/db/default/spree/stores.rb +1 -1
  85. data/db/migrate/20120831092320_spree_one_two.rb +36 -36
  86. data/db/migrate/20120831092359_spree_promo_one_two.rb +1 -1
  87. data/db/migrate/20130211190146_create_spree_stock_items.rb +1 -1
  88. data/db/migrate/20130211191120_create_spree_stock_locations.rb +1 -1
  89. data/db/migrate/20130301162924_create_shipping_method_categories.rb +1 -1
  90. data/db/migrate/20130304162240_create_spree_shipping_rates.rb +1 -1
  91. data/db/migrate/20130305143310_create_stock_movements.rb +1 -1
  92. data/db/migrate/20130418125341_create_spree_stock_transfers.rb +1 -1
  93. data/db/migrate/20140205120320_create_spree_payment_capture_events.rb +1 -1
  94. data/db/migrate/20140309024355_create_spree_stores.rb +1 -1
  95. data/db/migrate/20140309033438_create_store_from_preferences.rb +0 -7
  96. data/db/migrate/20140625214618_create_spree_refunds.rb +1 -1
  97. data/db/migrate/20140702140656_create_spree_return_authorization_inventory_unit.rb +1 -1
  98. data/db/migrate/20140713140455_create_spree_return_authorization_reasons.rb +1 -1
  99. data/db/migrate/20140713140527_create_spree_refund_reasons.rb +1 -1
  100. data/db/migrate/20140715182625_create_spree_promotion_categories.rb +1 -1
  101. data/db/migrate/20140718133010_create_spree_customer_returns.rb +1 -1
  102. data/db/migrate/20140725131539_create_spree_reimbursements.rb +1 -1
  103. data/db/migrate/20140731150017_create_spree_reimbursement_types.rb +1 -1
  104. data/db/migrate/20140911173301_add_kind_to_zone.rb +11 -0
  105. data/db/migrate/20141215232040_remove_token_permissions_table.rb +6 -0
  106. data/db/migrate/20141215235502_remove_extra_products_slug_index.rb +5 -0
  107. data/db/migrate/20141217215630_update_product_slug_index.rb +6 -0
  108. data/db/migrate/20141218025915_rename_identifier_to_number_for_payment.rb +5 -0
  109. data/db/migrate/20150121022521_remove_environment_from_payment_method.rb +6 -0
  110. data/db/migrate/20150122145607_add_resellable_to_return_items.rb +5 -0
  111. data/db/migrate/20150122202432_add_code_to_spree_promotion_categories.rb +5 -0
  112. data/db/migrate/20150128032538_remove_environment_from_tracker.rb +6 -0
  113. data/db/migrate/20150128060325_remove_spree_configurations.rb +16 -0
  114. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  115. data/lib/generators/spree/install/templates/config/initializers/spree.rb +4 -0
  116. data/lib/spree/core.rb +2 -12
  117. data/lib/spree/core/controller_helpers/respond_with.rb +8 -18
  118. data/lib/spree/core/engine.rb +1 -7
  119. data/lib/spree/core/routes.rb +1 -1
  120. data/lib/spree/core/version.rb +1 -1
  121. data/lib/spree/money.rb +10 -10
  122. data/lib/spree/permitted_attributes.rb +4 -8
  123. data/lib/spree/testing_support/authorization_helpers.rb +3 -5
  124. data/lib/spree/testing_support/capybara_ext.rb +3 -3
  125. data/lib/spree/testing_support/common_rake.rb +2 -2
  126. data/lib/spree/testing_support/factories/order_factory.rb +3 -13
  127. data/lib/spree/testing_support/factories/payment_method_factory.rb +0 -3
  128. data/lib/spree/testing_support/factories/prototype_factory.rb +5 -0
  129. data/lib/spree/testing_support/factories/return_item_factory.rb +5 -1
  130. data/lib/spree/testing_support/factories/stock_location_factory.rb +3 -3
  131. data/lib/spree/testing_support/factories/tracker_factory.rb +0 -1
  132. data/lib/spree/testing_support/factories/user_factory.rb +1 -1
  133. data/lib/spree/testing_support/factories/zone_factory.rb +8 -0
  134. data/lib/tasks/core.rake +1 -1
  135. data/lib/tasks/email.rake +6 -3
  136. metadata +48 -35
  137. data/app/helpers/spree/checkout_helper.rb +0 -31
  138. data/app/helpers/spree/orders_helper.rb +0 -17
  139. data/app/helpers/spree/store_helper.rb +0 -16
  140. data/app/helpers/spree/taxons_helper.rb +0 -19
  141. data/app/models/concerns/spree/ransackable_attributes.rb +0 -19
  142. data/app/models/friendly_id/slug_decorator.rb +0 -3
  143. data/app/models/spree/billing_integration.rb +0 -21
  144. data/app/models/spree/configuration.rb +0 -5
  145. data/app/models/spree/item_adjustments.rb +0 -82
  146. data/app/models/spree/order_merger.rb +0 -65
  147. data/app/models/spree/order_populator.rb +0 -43
  148. data/app/models/spree/product_scope/scopes.rb +0 -47
  149. data/app/models/spree/variant/scopes.rb +0 -42
  150. data/db/migrate/20150515211137_fix_adjustment_order_id.rb +0 -70
  151. data/db/migrate/20150522181728_add_deleted_at_to_friendly_id_slugs.rb +0 -6
  152. data/db/migrate/20150707204155_enable_acts_as_paranoid_on_calculators.rb +0 -6
  153. data/lib/spree/core/controller_helpers/ssl.rb +0 -60
  154. data/lib/spree/core/permalinks.rb +0 -71
  155. data/lib/spree/testing_support/factories/configuration_factory.rb +0 -6
@@ -22,10 +22,10 @@ module Spree
22
22
  # Update totals, then check if the order is eligible for any cart promotions.
23
23
  # If we do not update first, then the item total will be wrong and ItemTotal
24
24
  # promotion rules would not be triggered.
25
- persist_totals
25
+ reload_totals
26
26
  PromotionHandler::Cart.new(order).activate
27
27
  order.ensure_updated_shipments
28
- persist_totals
28
+ reload_totals
29
29
  true
30
30
  else
31
31
  false
@@ -34,12 +34,12 @@ module Spree
34
34
 
35
35
  private
36
36
  def after_add_or_remove(line_item, options = {})
37
- persist_totals
37
+ reload_totals
38
38
  shipment = options[:shipment]
39
39
  shipment.present? ? shipment.update_amounts : order.ensure_updated_shipments
40
40
  PromotionHandler::Cart.new(order, line_item).activate
41
- ItemAdjustments.new(line_item).update
42
- persist_totals
41
+ Adjustable::AdjustmentsUpdater.update(line_item)
42
+ reload_totals
43
43
  line_item
44
44
  end
45
45
 
@@ -61,9 +61,10 @@ module Spree
61
61
  @updater ||= OrderUpdater.new(order)
62
62
  end
63
63
 
64
- def persist_totals
64
+ def reload_totals
65
65
  order_updater.update_item_count
66
66
  order_updater.update
67
+ order.reload
67
68
  end
68
69
 
69
70
  def add_to_line_item(variant, quantity, options = {})
@@ -89,8 +90,8 @@ module Spree
89
90
  line_item.quantity -= quantity
90
91
  line_item.target_shipment= options[:shipment]
91
92
 
92
- if line_item.quantity.zero?
93
- order.line_items.destroy(line_item)
93
+ if line_item.quantity == 0
94
+ line_item.destroy
94
95
  else
95
96
  line_item.save!
96
97
  end
@@ -30,7 +30,9 @@ module Spree
30
30
  end
31
31
 
32
32
  def recalculate_adjustments
33
- all_adjustments.includes(:adjustable).map(&:adjustable).uniq.each { |adjustable| Spree::ItemAdjustments.new(adjustable).update }
33
+ all_adjustments.includes(:adjustable).map(&:adjustable).uniq.each do |adjustable|
34
+ Adjustable::AdjustmentsUpdater.update(adjustable)
35
+ end
34
36
  end
35
37
 
36
38
  # Updates the following Order total values:
@@ -168,5 +170,10 @@ module Spree
168
170
  order.state_changed('payment') if last_state != order.payment_state
169
171
  order.payment_state
170
172
  end
173
+
174
+ private
175
+ def round_money(n)
176
+ (n * 100).round / 100.0
177
+ end
171
178
  end
172
179
  end
@@ -1,8 +1,18 @@
1
1
  module Spree
2
2
  class Payment < Spree::Base
3
+ extend FriendlyId
4
+ friendly_id :number, slug_column: :number, use: :slugged
5
+
3
6
  include Spree::Payment::Processing
7
+ include Spree::NumberGenerator
8
+
9
+ def generate_number(options = {})
10
+ options[:prefix] ||= 'P'
11
+ options[:letters] ||= true
12
+ options[:length] ||= 7
13
+ super(options)
14
+ end
4
15
 
5
- IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze
6
16
  NON_RISKY_AVS_CODES = ['B', 'D', 'H', 'J', 'M', 'Q', 'T', 'V', 'X', 'Y'].freeze
7
17
  RISKY_AVS_CODES = ['A', 'C', 'E', 'F', 'G', 'I', 'K', 'L', 'N', 'O', 'P', 'R', 'S', 'U', 'W', 'Z'].freeze
8
18
 
@@ -13,12 +23,10 @@ module Spree
13
23
  has_many :offsets, -> { offset_payment }, class_name: "Spree::Payment", foreign_key: :source_id
14
24
  has_many :log_entries, as: :source
15
25
  has_many :state_changes, as: :stateful
16
- has_many :capture_events, :class_name => 'Spree::PaymentCaptureEvent'
26
+ has_many :capture_events, class_name: 'Spree::PaymentCaptureEvent'
17
27
  has_many :refunds, inverse_of: :payment
18
28
 
19
- validates_presence_of :payment_method
20
29
  before_validation :validate_source
21
- before_create :set_unique_identifier
22
30
 
23
31
  after_save :create_payment_profile, if: :profiles_supported?
24
32
 
@@ -34,7 +42,7 @@ module Spree
34
42
 
35
43
  validates :amount, numericality: true
36
44
 
37
- default_scope -> { order("#{self.table_name}.created_at") }
45
+ default_scope { order("#{self.table_name}.created_at") }
38
46
 
39
47
  scope :from_credit_card, -> { where(source_type: 'Spree::CreditCard') }
40
48
  scope :with_state, ->(s) { where(state: s.to_s) }
@@ -165,10 +173,6 @@ module Spree
165
173
  amount - captured_amount
166
174
  end
167
175
 
168
- def editable?
169
- checkout? || pending?
170
- end
171
-
172
176
  private
173
177
 
174
178
  def validate_source
@@ -236,19 +240,5 @@ module Spree
236
240
  end
237
241
  end
238
242
 
239
- # Necessary because some payment gateways will refuse payments with
240
- # duplicate IDs. We *were* using the Order number, but that's set once and
241
- # is unchanging. What we need is a unique identifier on a per-payment basis,
242
- # and this is it. Related to #1998.
243
- # See https://github.com/spree/spree/issues/1998#issuecomment-12869105
244
- def set_unique_identifier
245
- begin
246
- self.identifier = generate_identifier
247
- end while self.class.exists?(identifier: self.identifier)
248
- end
249
-
250
- def generate_identifier
251
- Array.new(8){ IDENTIFIER_CHARS.sample }.join
252
- end
253
243
  end
254
244
  end
@@ -0,0 +1,86 @@
1
+ module Spree
2
+ class Payment
3
+ class GatewayOptions
4
+ def initialize(payment)
5
+ @payment = payment
6
+ end
7
+
8
+ def email
9
+ order.email
10
+ end
11
+
12
+ def customer
13
+ order.email
14
+ end
15
+
16
+ def customer_id
17
+ order.user_id
18
+ end
19
+
20
+ def ip
21
+ order.last_ip_address
22
+ end
23
+
24
+ def order_id
25
+ "#{order.number}-#{@payment.number}"
26
+ end
27
+
28
+ def shipping
29
+ order.ship_total * 100
30
+ end
31
+
32
+ def tax
33
+ order.additional_tax_total * 100
34
+ end
35
+
36
+ def subtotal
37
+ order.item_total * 100
38
+ end
39
+
40
+ def discount
41
+ order.promo_total * 100
42
+ end
43
+
44
+ def currency
45
+ @payment.currency
46
+ end
47
+
48
+ def billing_address
49
+ order.bill_address.try(:active_merchant_hash)
50
+ end
51
+
52
+ def shipping_address
53
+ order.ship_address.try(:active_merchant_hash)
54
+ end
55
+
56
+ def hash_methods
57
+ [
58
+ :email,
59
+ :customer,
60
+ :customer_id,
61
+ :ip,
62
+ :order_id,
63
+ :shipping,
64
+ :tax,
65
+ :subtotal,
66
+ :discount,
67
+ :currency,
68
+ :billing_address,
69
+ :shipping_address
70
+ ]
71
+ end
72
+
73
+ def to_hash
74
+ Hash[hash_methods.map do |method|
75
+ [method, send(method)]
76
+ end]
77
+ end
78
+
79
+ private
80
+
81
+ def order
82
+ @payment.order
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,6 +1,12 @@
1
1
  module Spree
2
2
  class Payment < Spree::Base
3
3
  module Processing
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ class_attribute :gateway_options_class
7
+ self.gateway_options_class = Spree::Payment::GatewayOptions
8
+ end
9
+
4
10
  def process!
5
11
  if payment_method && payment_method.auto_capture?
6
12
  purchase!
@@ -26,7 +32,6 @@ module Spree
26
32
  amount ||= money.money.cents
27
33
  started_processing!
28
34
  protect_from_connection_error do
29
- check_environment
30
35
  # Standard ActiveMerchant capture usage
31
36
  response = payment_method.capture(
32
37
  amount,
@@ -43,7 +48,6 @@ module Spree
43
48
  def void_transaction!
44
49
  return true if void?
45
50
  protect_from_connection_error do
46
- check_environment
47
51
 
48
52
  if payment_method.payment_profiles_supported?
49
53
  # Gateways supporting payment profiles will need access to credit card object because this stores the payment profile information
@@ -65,32 +69,12 @@ module Spree
65
69
  end
66
70
 
67
71
  def cancel!
68
- response = payment_method.cancel(response_code)
69
- handle_response(response, :void, :failure)
72
+ payment_method.cancel(response_code)
70
73
  end
71
74
 
72
75
  def gateway_options
73
76
  order.reload
74
- options = { :email => order.email,
75
- :customer => order.email,
76
- :customer_id => order.user_id,
77
- :ip => order.last_ip_address,
78
- # Need to pass in a unique identifier here to make some
79
- # payment gateways happy.
80
- #
81
- # For more information, please see Spree::Payment#set_unique_identifier
82
- :order_id => gateway_order_id }
83
-
84
- options.merge!({ :shipping => order.ship_total * 100,
85
- :tax => order.additional_tax_total * 100,
86
- :subtotal => order.item_total * 100,
87
- :discount => order.promo_total * 100,
88
- :currency => currency })
89
-
90
- options.merge!({ :billing_address => order.bill_address.try(:active_merchant_hash),
91
- :shipping_address => order.ship_address.try(:active_merchant_hash) })
92
-
93
- options
77
+ gateway_options_class.new(self).to_hash
94
78
  end
95
79
 
96
80
  private
@@ -130,8 +114,6 @@ module Spree
130
114
 
131
115
  def gateway_action(source, action, success_state)
132
116
  protect_from_connection_error do
133
- check_environment
134
-
135
117
  response = payment_method.send(action, money.money.cents,
136
118
  source,
137
119
  gateway_options)
@@ -184,19 +166,6 @@ module Spree
184
166
  raise Core::GatewayError.new(text)
185
167
  end
186
168
 
187
- # Saftey check to make sure we're not accidentally performing operations on a live gateway.
188
- # Ex. When testing in staging environment with a copy of production data.
189
- def check_environment
190
- return if payment_method.environment == Rails.env
191
- message = Spree.t(:gateway_config_unavailable) + " - #{Rails.env}"
192
- raise Core::GatewayError.new(message)
193
- end
194
-
195
- # The unique identifier to be passed in to the payment gateway
196
- def gateway_order_id
197
- "#{order.number}-#{self.identifier}"
198
- end
199
-
200
169
  def token_based?
201
170
  source.gateway_customer_profile_id.present? || source.gateway_payment_profile_id.present?
202
171
  end
@@ -2,9 +2,7 @@ module Spree
2
2
  class PaymentMethod < Spree::Base
3
3
  acts_as_paranoid
4
4
  DISPLAY = [:both, :front_end, :back_end]
5
- default_scope -> { where(deleted_at: nil) }
6
-
7
- scope :production, -> { where(environment: 'production') }
5
+ default_scope { where(deleted_at: nil) }
8
6
 
9
7
  validates :name, presence: true
10
8
 
@@ -29,13 +27,12 @@ module Spree
29
27
  def self.available(display_on = 'both')
30
28
  all.select do |p|
31
29
  p.active &&
32
- (p.display_on == display_on.to_s || p.display_on.blank?) &&
33
- (p.environment == Rails.env || p.environment.blank?)
30
+ (p.display_on == display_on.to_s || p.display_on.blank?)
34
31
  end
35
32
  end
36
33
 
37
34
  def self.active?
38
- where(type: self.to_s, environment: Rails.env, active: true).count > 0
35
+ where(type: self.to_s, active: true).count > 0
39
36
  end
40
37
 
41
38
  def method_type
@@ -7,12 +7,8 @@ module Spree
7
7
  validates :amount, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
8
8
  validate :validate_amount_maximum
9
9
 
10
- def display_amount
11
- money
12
- end
13
- alias :display_price :display_amount
14
-
15
- self.whitelisted_ransackable_attributes = ['amount']
10
+ extend DisplayMoney
11
+ money_methods :amount, :price
16
12
 
17
13
  def money
18
14
  Spree::Money.new(amount || 0, { currency: currency })
@@ -74,7 +74,6 @@ module Spree
74
74
  after_create :build_variants_from_option_values_hash, if: :option_values_hash
75
75
 
76
76
  after_destroy :punch_slug
77
- after_restore :update_slug_history
78
77
 
79
78
  after_initialize :ensure_master
80
79
 
@@ -99,9 +98,6 @@ module Spree
99
98
 
100
99
  alias :options :product_option_types
101
100
 
102
- self.whitelisted_ransackable_associations = %w[stores variants_including_master master variants]
103
- self.whitelisted_ransackable_attributes = %w[slug]
104
-
105
101
  # the master variant is not a member of the variants array
106
102
  def has_variants?
107
103
  variants.any?
@@ -267,12 +263,7 @@ module Spree
267
263
  end
268
264
 
269
265
  def punch_slug
270
- # punch slug with date prefix to allow reuse of original
271
- update_column :slug, "#{Time.now.to_i}_#{slug}"[0..254] unless frozen?
272
- end
273
-
274
- def update_slug_history
275
- self.save!
266
+ update_column :slug, "#{Time.now.to_i}_#{slug}" # punch slug with date prefix to allow reuse of original
276
267
  end
277
268
 
278
269
  def anything_changed?
@@ -283,11 +274,25 @@ module Spree
283
274
  @nested_changes = false
284
275
  end
285
276
 
277
+ def master_updated?
278
+ master && (
279
+ master.new_record? ||
280
+ master.changed? ||
281
+ (
282
+ master.default_price &&
283
+ (
284
+ master.default_price.new_record? ||
285
+ master.default_price.changed?
286
+ )
287
+ )
288
+ )
289
+ end
290
+
286
291
  # there's a weird quirk with the delegate stuff that does not automatically save the delegate object
287
292
  # when saving so we force a save using a hook
288
293
  # Fix for issue #5306
289
294
  def save_master
290
- if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed? || master.default_price.new_record?)))
295
+ if master_updated?
291
296
  master.save!
292
297
  @nested_changes = true
293
298
  end
@@ -322,13 +327,19 @@ module Spree
322
327
  run_callbacks(:touch)
323
328
  end
324
329
 
330
+ def taxon_and_ancestors
331
+ taxons.map(&:self_and_ancestors).flatten.uniq
332
+ end
333
+
334
+ # Get the taxonomy ids of all taxons assigned to this product and their ancestors.
335
+ def taxonomy_ids
336
+ taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
337
+ end
338
+
325
339
  # Iterate through this products taxons and taxonomies and touch their timestamps in a batch
326
340
  def touch_taxons
327
- taxons_to_touch = taxons.map(&:self_and_ancestors).flatten.uniq
328
- Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
329
-
330
- taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
331
- Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
341
+ Spree::Taxon.where(id: taxon_and_ancestors.map(&:id)).update_all(updated_at: Time.current)
342
+ Spree::Taxonomy.where(id: taxonomy_ids).update_all(updated_at: Time.current)
332
343
  end
333
344
 
334
345
  end