spree_core 2.2.14 → 2.3.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.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/{spree.js.coffee → spree.js.coffee.erb} +11 -2
  3. data/app/controllers/spree/base_controller.rb +1 -0
  4. data/app/helpers/spree/base_helper.rb +5 -6
  5. data/app/helpers/spree/orders_helper.rb +4 -0
  6. data/app/helpers/spree/products_helper.rb +8 -7
  7. data/app/mailers/spree/base_mailer.rb +2 -2
  8. data/app/mailers/spree/order_mailer.rb +2 -2
  9. data/app/mailers/spree/shipment_mailer.rb +1 -1
  10. data/app/mailers/spree/test_mailer.rb +1 -1
  11. data/app/models/spree/ability.rb +15 -16
  12. data/app/models/spree/address.rb +3 -6
  13. data/app/models/spree/adjustment.rb +2 -2
  14. data/app/models/spree/alert.rb +1 -1
  15. data/app/models/spree/app_configuration.rb +17 -20
  16. data/app/models/spree/asset.rb +2 -2
  17. data/app/models/spree/base.rb +9 -0
  18. data/app/models/spree/calculator.rb +1 -1
  19. data/app/models/spree/calculator/flat_rate.rb +1 -1
  20. data/app/models/spree/calculator/flexi_rate.rb +1 -1
  21. data/app/models/spree/calculator/price_sack.rb +1 -3
  22. data/app/models/spree/calculator/shipping/flat_rate.rb +1 -1
  23. data/app/models/spree/calculator/shipping/flexi_rate.rb +1 -1
  24. data/app/models/spree/calculator/shipping/per_item.rb +1 -1
  25. data/app/models/spree/calculator/shipping/price_sack.rb +1 -3
  26. data/app/models/spree/classification.rb +1 -1
  27. data/app/models/spree/configuration.rb +1 -1
  28. data/app/models/spree/country.rb +1 -1
  29. data/app/models/spree/credit_card.rb +8 -12
  30. data/app/models/spree/gateway.rb +0 -3
  31. data/app/models/spree/gateway/bogus.rb +2 -3
  32. data/app/models/spree/image.rb +3 -1
  33. data/app/models/spree/inventory_unit.rb +5 -6
  34. data/app/models/spree/item_adjustments.rb +3 -4
  35. data/app/models/spree/legacy_user.rb +1 -1
  36. data/app/models/spree/line_item.rb +6 -13
  37. data/app/models/spree/log_entry.rb +1 -1
  38. data/app/models/spree/option_type.rb +1 -1
  39. data/app/models/spree/option_value.rb +1 -3
  40. data/app/models/spree/order.rb +52 -70
  41. data/app/models/spree/order/checkout.rb +17 -10
  42. data/app/models/spree/order/currency_updater.rb +1 -1
  43. data/app/models/spree/order_contents.rb +7 -4
  44. data/app/models/spree/order_populator.rb +1 -1
  45. data/app/models/spree/order_updater.rb +8 -21
  46. data/app/models/spree/payment.rb +26 -12
  47. data/app/models/spree/payment/processing.rb +5 -16
  48. data/app/models/spree/payment_capture_event.rb +1 -1
  49. data/app/models/spree/payment_method.rb +2 -2
  50. data/app/models/spree/payment_method/check.rb +0 -2
  51. data/app/models/spree/preference.rb +1 -31
  52. data/app/models/spree/preferences/configuration.rb +2 -6
  53. data/app/models/spree/preferences/preferable.rb +46 -74
  54. data/app/models/spree/preferences/preferable_class_methods.rb +11 -46
  55. data/app/models/spree/preferences/scoped_store.rb +33 -0
  56. data/app/models/spree/preferences/store.rb +8 -7
  57. data/app/models/spree/price.rb +1 -3
  58. data/app/models/spree/product.rb +59 -87
  59. data/app/models/spree/product/scopes.rb +22 -13
  60. data/app/models/spree/product_option_type.rb +1 -1
  61. data/app/models/spree/product_property.rb +1 -3
  62. data/app/models/spree/product_scope/scopes.rb +1 -1
  63. data/app/models/spree/promotion.rb +4 -5
  64. data/app/models/spree/promotion/actions/create_adjustment.rb +11 -2
  65. data/app/models/spree/promotion/actions/create_item_adjustments.rb +19 -2
  66. data/app/models/spree/promotion/actions/create_line_items.rb +2 -12
  67. data/app/models/spree/promotion/rules/user.rb +5 -1
  68. data/app/models/spree/promotion_action.rb +1 -1
  69. data/app/models/spree/promotion_action_line_item.rb +1 -1
  70. data/app/models/spree/promotion_handler/cart.rb +2 -14
  71. data/app/models/spree/promotion_handler/coupon.rb +3 -13
  72. data/app/models/spree/promotion_rule.rb +1 -1
  73. data/app/models/spree/property.rb +1 -3
  74. data/app/models/spree/prototype.rb +1 -1
  75. data/app/models/spree/return_authorization.rb +4 -10
  76. data/app/models/spree/role.rb +1 -1
  77. data/app/models/spree/shipment.rb +1 -9
  78. data/app/models/spree/shipping_category.rb +3 -3
  79. data/app/models/spree/shipping_method.rb +1 -1
  80. data/app/models/spree/shipping_method_category.rb +2 -2
  81. data/app/models/spree/shipping_rate.rb +3 -3
  82. data/app/models/spree/state.rb +1 -1
  83. data/app/models/spree/state_change.rb +1 -1
  84. data/app/models/spree/stock/availability_validator.rb +7 -3
  85. data/app/models/spree/stock/package.rb +0 -23
  86. data/app/models/spree/stock/splitter/backordered.rb +1 -1
  87. data/app/models/spree/stock/splitter/shipping_category.rb +1 -1
  88. data/app/models/spree/stock/splitter/weight.rb +1 -1
  89. data/app/models/spree/stock_item.rb +7 -10
  90. data/app/models/spree/stock_location.rb +2 -6
  91. data/app/models/spree/stock_movement.rb +1 -3
  92. data/app/models/spree/stock_transfer.rb +1 -3
  93. data/app/models/spree/store.rb +33 -0
  94. data/app/models/spree/tax_category.rb +2 -2
  95. data/app/models/spree/tax_rate.rb +21 -52
  96. data/app/models/spree/taxon.rb +9 -8
  97. data/app/models/spree/taxonomy.rb +1 -1
  98. data/app/models/spree/tracker.rb +1 -1
  99. data/app/models/spree/variant.rb +13 -15
  100. data/app/models/spree/variant/scopes.rb +1 -1
  101. data/app/models/spree/zone.rb +22 -22
  102. data/app/models/spree/zone_member.rb +2 -2
  103. data/config/initializers/user_class_extensions.rb +0 -8
  104. data/config/locales/en.yml +7 -42
  105. data/db/default/spree/countries.rb +2 -3
  106. data/db/default/spree/stores.rb +9 -0
  107. data/db/migrate/20130611054351_rename_shipping_methods_zones_to_spree_shipping_methods_zones.rb +0 -5
  108. data/db/migrate/20130807024301_upgrade_adjustments.rb +4 -5
  109. data/db/migrate/20130807024302_rename_adjustment_fields.rb +5 -2
  110. data/db/migrate/20131118183431_add_line_item_id_to_spree_inventory_units.rb +1 -1
  111. data/db/migrate/20140106065820_remove_value_type_from_spree_preferences.rb +8 -0
  112. data/db/migrate/20140227112348_add_preference_store_to_everything.rb +8 -0
  113. data/db/migrate/20140309023735_migrate_old_preferences.rb +23 -0
  114. data/db/migrate/20140309024355_create_spree_stores.rb +25 -0
  115. data/db/migrate/20140309033438_create_store_from_preferences.rb +30 -0
  116. data/db/migrate/20140315053743_add_timestamps_to_spree_assets.rb +6 -0
  117. data/db/migrate/20140331100557_add_additional_store_fields.rb +8 -0
  118. data/db/migrate/20140410141842_add_many_missing_indexes.rb +18 -0
  119. data/db/migrate/20140410150358_correct_some_polymorphic_index_and_add_more_missing.rb +66 -0
  120. data/db/migrate/20140508151342_change_spree_price_amount_precision.rb +1 -1
  121. data/db/migrate/20140518174634_add_token_to_spree_orders.rb +5 -0
  122. data/db/migrate/20140530024945_move_order_token_from_tokenized_permission.rb +29 -0
  123. data/db/migrate/20140601011216_set_shipment_total_for_users_upgrading.rb +5 -3
  124. data/db/migrate/20140604135309_drop_credit_card_first_name_and_last_name.rb +6 -0
  125. data/lib/generators/spree/dummy/dummy_generator.rb +1 -0
  126. data/lib/generators/spree/dummy/templates/initializers/devise.rb +3 -0
  127. data/lib/generators/spree/dummy/templates/rails/routes.rb +0 -1
  128. data/lib/generators/spree/install/install_generator.rb +8 -17
  129. data/lib/generators/spree/install/templates/config/initializers/spree.rb +2 -2
  130. data/lib/spree/core.rb +13 -9
  131. data/lib/spree/core/calculated_adjustments.rb +1 -1
  132. data/lib/spree/core/controller_helpers/auth.rb +27 -18
  133. data/lib/spree/core/controller_helpers/common.rb +2 -2
  134. data/lib/spree/core/controller_helpers/order.rb +15 -24
  135. data/lib/spree/core/controller_helpers/store.rb +19 -0
  136. data/lib/spree/core/delegate_belongs_to.rb +2 -2
  137. data/lib/spree/core/engine.rb +0 -10
  138. data/lib/spree/core/importer.rb +1 -0
  139. data/lib/spree/core/importer/order.rb +16 -44
  140. data/lib/spree/core/importer/product.rb +62 -0
  141. data/lib/spree/core/product_filters.rb +0 -4
  142. data/lib/spree/core/routes.rb +4 -6
  143. data/lib/spree/core/validators/email.rb +23 -1
  144. data/lib/spree/core/version.rb +1 -1
  145. data/lib/spree/money.rb +1 -169
  146. data/lib/spree/permitted_attributes.rb +6 -4
  147. data/lib/spree/testing_support/authorization_helpers.rb +23 -21
  148. data/lib/spree/testing_support/capybara_ext.rb +11 -21
  149. data/lib/spree/testing_support/common_rake.rb +3 -1
  150. data/lib/spree/testing_support/controller_requests.rb +0 -2
  151. data/lib/spree/testing_support/factories/credit_card_factory.rb +1 -1
  152. data/lib/spree/testing_support/factories/line_item_factory.rb +4 -1
  153. data/lib/spree/testing_support/factories/order_factory.rb +5 -4
  154. data/lib/spree/testing_support/factories/product_factory.rb +0 -4
  155. data/lib/spree/testing_support/factories/promotion_factory.rb +5 -7
  156. data/lib/spree/testing_support/factories/shipment_factory.rb +0 -1
  157. data/lib/spree/testing_support/factories/stock_factory.rb +2 -2
  158. data/lib/spree/testing_support/factories/store_factory.rb +8 -0
  159. data/lib/spree/testing_support/preferences.rb +3 -3
  160. data/lib/tasks/core.rake +2 -2
  161. metadata +48 -39
  162. data/app/models/spree/stock/order_counter.rb +0 -55
  163. data/app/models/spree/tokenized_permission.rb +0 -6
  164. data/app/views/spree/shared/_routes.html.erb +0 -13
  165. data/db/migrate/20140804185157_add_default_to_shipment_cost.rb +0 -10
  166. data/db/migrate/20141021194502_add_state_lock_version_to_order.rb +0 -5
  167. data/lib/spree/core/adjustment_source.rb +0 -26
  168. data/lib/spree/core/mail_interceptor.rb +0 -22
  169. data/lib/spree/core/mail_method.rb +0 -27
  170. data/lib/spree/core/mail_settings.rb +0 -55
  171. data/lib/spree/core/ransackable_attributes.rb +0 -15
  172. data/lib/spree/core/token_resource.rb +0 -27
@@ -3,55 +3,33 @@ module Spree::Preferences
3
3
 
4
4
  def preference(name, type, *args)
5
5
  options = args.extract_options!
6
- options.assert_valid_keys(:default, :description)
6
+ options.assert_valid_keys(:default)
7
7
  default = options[:default]
8
- description = options[:description] || name
8
+ default = ->{ options[:default] } unless default.is_a?(Proc)
9
9
 
10
10
  # cache_key will be nil for new objects, then if we check if there
11
11
  # is a pending preference before going to default
12
12
  define_method preference_getter_method(name) do
13
-
14
- # perference_cache_key will only be nil/false for new records
15
- #
16
- if preference_cache_key(name)
17
- preference_store.get(preference_cache_key(name), default)
18
- else
19
- get_pending_preference(name) || default
13
+ preferences.fetch(name) do
14
+ default.call
20
15
  end
21
16
  end
22
- alias_method prefers_getter_method(name), preference_getter_method(name)
23
17
 
24
18
  define_method preference_setter_method(name) do |value|
25
19
  value = convert_preference_value(value, type)
26
- if preference_cache_key(name)
27
- preference_store.set preference_cache_key(name), value, type
28
- else
29
- add_pending_preference(name, value)
30
- end
31
- end
32
- alias_method prefers_setter_method(name), preference_setter_method(name)
20
+ preferences[name] = value
33
21
 
34
- define_method preference_default_getter_method(name) do
35
- default
22
+ # If this is an activerecord object, we need to inform
23
+ # ActiveRecord::Dirty that this value has changed, since this is an
24
+ # in-place update to the preferences hash.
25
+ preferences_will_change! if respond_to?(:preferences_will_change!)
36
26
  end
37
27
 
28
+ define_method preference_default_getter_method(name), &default
29
+
38
30
  define_method preference_type_getter_method(name) do
39
31
  type
40
32
  end
41
-
42
- define_method preference_description_getter_method(name) do
43
- description
44
- end
45
- end
46
-
47
- def remove_preference(name)
48
- remove_method preference_getter_method(name) if method_defined? preference_getter_method(name)
49
- remove_method preference_setter_method(name) if method_defined? preference_setter_method(name)
50
- remove_method prefers_getter_method(name) if method_defined? prefers_getter_method(name)
51
- remove_method prefers_setter_method(name) if method_defined? prefers_setter_method(name)
52
- remove_method preference_default_getter_method(name) if method_defined? preference_default_getter_method(name)
53
- remove_method preference_type_getter_method(name) if method_defined? preference_type_getter_method(name)
54
- remove_method preference_description_getter_method(name) if method_defined? preference_description_getter_method(name)
55
33
  end
56
34
 
57
35
  def preference_getter_method(name)
@@ -62,14 +40,6 @@ module Spree::Preferences
62
40
  "preferred_#{name}=".to_sym
63
41
  end
64
42
 
65
- def prefers_getter_method(name)
66
- "prefers_#{name}?".to_sym
67
- end
68
-
69
- def prefers_setter_method(name)
70
- "prefers_#{name}=".to_sym
71
- end
72
-
73
43
  def preference_default_getter_method(name)
74
44
  "preferred_#{name}_default".to_sym
75
45
  end
@@ -77,10 +47,5 @@ module Spree::Preferences
77
47
  def preference_type_getter_method(name)
78
48
  "preferred_#{name}_type".to_sym
79
49
  end
80
-
81
- def preference_description_getter_method(name)
82
- "preferred_#{name}_description".to_sym
83
- end
84
-
85
50
  end
86
51
  end
@@ -0,0 +1,33 @@
1
+ module Spree::Preferences
2
+ class ScopedStore
3
+ def initialize prefix, suffix=nil
4
+ @prefix = prefix
5
+ @suffix = suffix
6
+ end
7
+
8
+ def store
9
+ Spree::Preferences::Store.instance
10
+ end
11
+
12
+ def fetch key, &block
13
+ store.fetch(key_for(key), &block)
14
+ end
15
+
16
+ def []= key, value
17
+ store[key_for(key)] = value
18
+ end
19
+
20
+ def delete key
21
+ store.delete(key_for(key))
22
+ end
23
+
24
+ private
25
+ def key_for key
26
+ [rails_cache_id, @prefix, key, @suffix].compact.join('/')
27
+ end
28
+
29
+ def rails_cache_id
30
+ ENV['RAILS_CACHE_ID']
31
+ end
32
+ end
33
+ end
@@ -16,17 +16,18 @@ module Spree::Preferences
16
16
  @persistence = true
17
17
  end
18
18
 
19
- def set(key, value, type)
19
+ def set(key, value)
20
20
  @cache.write(key, value)
21
- persist(key, value, type)
21
+ persist(key, value)
22
22
  end
23
+ alias_method :[]=, :set
23
24
 
24
25
  def exist?(key)
25
26
  @cache.exist?(key) ||
26
27
  should_persist? && Spree::Preference.where(:key => key).exists?
27
28
  end
28
29
 
29
- def get(key,fallback=nil)
30
+ def get(key)
30
31
  # return the retrieved value, if it's in the cache
31
32
  # use unless nil? incase the value is actually boolean false
32
33
  #
@@ -44,7 +45,7 @@ module Spree::Preferences
44
45
  val = preference.value
45
46
  else
46
47
  # use the fallback value
47
- val = fallback
48
+ val = yield
48
49
  end
49
50
 
50
51
  # Cache either the value from the db or the fallback value.
@@ -53,9 +54,10 @@ module Spree::Preferences
53
54
 
54
55
  return val
55
56
  else
56
- return fallback
57
+ yield
57
58
  end
58
59
  end
60
+ alias_method :fetch, :get
59
61
 
60
62
  def delete(key)
61
63
  @cache.delete(key)
@@ -68,12 +70,11 @@ module Spree::Preferences
68
70
 
69
71
  private
70
72
 
71
- def persist(cache_key, value, type)
73
+ def persist(cache_key, value)
72
74
  return unless should_persist?
73
75
 
74
76
  preference = Spree::Preference.where(:key => cache_key).first_or_initialize
75
77
  preference.value = value
76
- preference.value_type = type
77
78
  preference.save
78
79
  end
79
80
 
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Price < ActiveRecord::Base
2
+ class Price < Spree::Base
3
3
  acts_as_paranoid
4
4
  belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
5
5
 
@@ -11,8 +11,6 @@ module Spree
11
11
  end
12
12
  alias :display_price :display_amount
13
13
 
14
- self.whitelisted_ransackable_attributes = ['amount']
15
-
16
14
  def money
17
15
  Spree::Money.new(amount || 0, { currency: currency })
18
16
  end
@@ -19,11 +19,12 @@
19
19
  #
20
20
 
21
21
  module Spree
22
- class Product < ActiveRecord::Base
22
+ class Product < Spree::Base
23
23
  extend FriendlyId
24
24
  friendly_id :slug_candidates, use: :slugged
25
25
 
26
26
  acts_as_paranoid
27
+
27
28
  has_many :product_option_types, dependent: :destroy, inverse_of: :product
28
29
  has_many :option_types, through: :product_option_types
29
30
  has_many :product_properties, dependent: :destroy, inverse_of: :product
@@ -39,7 +40,8 @@ module Spree
39
40
  has_one :master,
40
41
  -> { where is_master: true },
41
42
  inverse_of: :product,
42
- class_name: 'Spree::Variant'
43
+ class_name: 'Spree::Variant',
44
+ dependent: :destroy
43
45
 
44
46
  has_many :variants,
45
47
  -> { where(is_master: false).order("#{::Spree::Variant.quoted_table_name}.position ASC") },
@@ -63,9 +65,9 @@ module Spree
63
65
  after_create :set_master_variant_defaults
64
66
  after_create :add_properties_and_option_types_from_prototype
65
67
  after_create :build_variants_from_option_values_hash, if: :option_values_hash
68
+
66
69
  after_save :save_master
67
- after_save :run_touch_callbacks, if: :anything_changed?
68
- after_save :reset_nested_changes
70
+ after_save :touch
69
71
  after_touch :touch_taxons
70
72
 
71
73
  delegate :images, to: :master, prefix: true
@@ -91,13 +93,6 @@ module Spree
91
93
 
92
94
  after_initialize :ensure_master
93
95
 
94
- self.whitelisted_ransackable_associations = %w[stores variants_including_master master variants]
95
- self.whitelisted_ransackable_attributes = %w[slug]
96
-
97
- def to_param
98
- slug
99
- end
100
-
101
96
  # the master variant is not a member of the variants array
102
97
  def has_variants?
103
98
  variants.any?
@@ -204,10 +199,10 @@ module Spree
204
199
  end
205
200
 
206
201
  def total_on_hand
207
- if any_variants_not_track_inventory?
202
+ if self.variants_including_master.any? { |v| !v.should_track_inventory? }
208
203
  Float::INFINITY
209
204
  else
210
- stock_items.sum(:count_on_hand)
205
+ self.stock_items.to_a.sum(&:count_on_hand)
211
206
  end
212
207
  end
213
208
 
@@ -220,93 +215,70 @@ module Spree
220
215
 
221
216
  private
222
217
 
223
- def add_properties_and_option_types_from_prototype
224
- if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
225
- prototype.properties.each do |property|
226
- product_properties.create(property: property)
227
- end
228
- self.option_types = prototype.option_types
218
+ def normalize_slug
219
+ self.slug = normalize_friendly_id(slug)
229
220
  end
230
- end
231
221
 
232
- def any_variants_not_track_inventory?
233
- if variants_including_master.loaded?
234
- variants_including_master.any? { |v| !v.should_track_inventory? }
235
- else
236
- !Spree::Config.track_inventory_levels || variants_including_master.where(track_inventory: false).any?
222
+ # Builds variants from a hash of option types & values
223
+ def build_variants_from_option_values_hash
224
+ ensure_option_types_exist_for_values_hash
225
+ values = option_values_hash.values
226
+ values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
227
+
228
+ values.each do |ids|
229
+ variant = variants.create(
230
+ option_value_ids: ids,
231
+ price: master.price
232
+ )
233
+ end
234
+ save
237
235
  end
238
- end
239
236
 
240
- # Builds variants from a hash of option types & values
241
- def build_variants_from_option_values_hash
242
- ensure_option_types_exist_for_values_hash
243
- values = option_values_hash.values
244
- values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
245
-
246
- values.each do |ids|
247
- variant = variants.create(
248
- option_value_ids: ids,
249
- price: master.price
250
- )
237
+ def add_properties_and_option_types_from_prototype
238
+ if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
239
+ prototype.properties.each do |property|
240
+ product_properties.create(property: property)
241
+ end
242
+ self.option_types = prototype.option_types
243
+ end
251
244
  end
252
- save
253
- end
254
-
255
- def ensure_master
256
- return unless new_record?
257
- self.master ||= Variant.new
258
- end
259
245
 
260
- def normalize_slug
261
- self.slug = normalize_friendly_id(slug)
262
- end
263
-
264
- def punch_slug
265
- update_column :slug, "#{Time.now.to_i}_#{slug}" # punch slug with date prefix to allow reuse of original
266
- end
267
-
268
- def anything_changed?
269
- changed? || @nested_changes
270
- end
271
-
272
- def reset_nested_changes
273
- @nested_changes = false
274
- end
246
+ # ensures the master variant is flagged as such
247
+ def set_master_variant_defaults
248
+ master.is_master = true
249
+ end
275
250
 
276
- # there's a weird quirk with the delegate stuff that does not automatically save the delegate object
277
- # when saving so we force a save using a hook.
278
- def save_master
279
- if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed? || master.default_price.new_record?)))
280
- master.save
281
- @nested_changes = true
251
+ # there's a weird quirk with the delegate stuff that does not automatically save the delegate object
252
+ # when saving so we force a save using a hook.
253
+ def save_master
254
+ master.save if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed? || master.default_price.new_record?)))
282
255
  end
283
- end
284
256
 
285
- # ensures the master variant is flagged as such
286
- def set_master_variant_defaults
287
- master.is_master = true
288
- end
257
+ def ensure_master
258
+ return unless new_record?
259
+ self.master ||= Variant.new
260
+ end
289
261
 
290
- # Try building a slug based on the following fields in increasing order of specificity.
291
- def slug_candidates
292
- [
293
- :name,
294
- [:name, :sku]
295
- ]
296
- end
262
+ # Iterate through this products taxons and taxonomies and touch their timestamps in a batch
263
+ def touch_taxons
264
+ taxons_to_touch = taxons.map(&:self_and_ancestors).flatten.uniq
265
+ Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
297
266
 
298
- def run_touch_callbacks
299
- run_callbacks(:touch)
300
- end
267
+ taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
268
+ Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
269
+ end
301
270
 
302
- # Iterate through this products taxons and taxonomies and touch their timestamps in a batch
303
- def touch_taxons
304
- taxons_to_touch = taxons.map(&:self_and_ancestors).flatten.uniq
305
- Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
271
+ # Try building a slug based on the following fields in increasing order of specificity.
272
+ def slug_candidates
273
+ [
274
+ :name,
275
+ [:name, :sku]
276
+ ]
277
+ end
306
278
 
307
- taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
308
- Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
309
- end
279
+ def punch_slug
280
+ update(slug: "#{Time.now.to_i}_#{slug}") # punch slug with date prefix to allow reuse of original
281
+ end
310
282
 
311
283
  end
312
284
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Product < ActiveRecord::Base
2
+ class Product < Spree::Base
3
3
  cattr_accessor :search_scopes do
4
4
  []
5
5
  end
@@ -201,19 +201,28 @@ module Spree
201
201
  group("spree_products.id").joins(:taxons).where(Taxon.arel_table[:name].eq(name))
202
202
  end
203
203
 
204
- def self.distinct_by_product_ids(sort_order=nil)
205
- if (ActiveRecord::Base.connection.adapter_name == 'PostgreSQL')
206
- sort_column = sort_order.split(" ").first
207
- # Don't allow sort_column, a variable coming from params,
208
- # to be anything but a column in the database
209
- if column_names.include?(sort_column)
210
- distinct_fields = ["id", sort_column].compact.join(",")
211
- select("DISTINCT ON(#{distinct_fields}) spree_products.*")
212
- else
213
- all
214
- end
204
+ def self.distinct_by_product_ids(sort_order = nil)
205
+ sort_column = sort_order.split(" ").first
206
+
207
+ # Postgres will complain when using ordering by expressions not present in
208
+ # SELECT DISTINCT. e.g.
209
+ #
210
+ # PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
211
+ # expressions must appear in select list. e.g.
212
+ #
213
+ # SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
214
+ # "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
215
+ # AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
216
+ # "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
217
+ # AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
218
+ # ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
219
+ #
220
+ # Don't allow sort_column, a variable coming from params,
221
+ # to be anything but a column in the database
222
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
223
+ all
215
224
  else
216
- select("DISTINCT spree_products.*")
225
+ distinct
217
226
  end
218
227
  end
219
228