spree_core 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/app/assets/javascripts/admin/admin.js.erb +18 -9
  2. data/app/assets/javascripts/admin/checkouts/edit.js +2 -2
  3. data/app/assets/stylesheets/admin/admin.css.erb +4 -2
  4. data/app/controllers/spree/admin/orders/customer_details_controller.rb +2 -2
  5. data/app/controllers/spree/admin/payments_controller.rb +1 -1
  6. data/app/models/spree/address.rb +6 -1
  7. data/app/models/spree/adjustment.rb +4 -2
  8. data/app/models/spree/calculator/default_tax.rb +2 -0
  9. data/app/models/spree/calculator/flat_percent_item_total.rb +4 -0
  10. data/app/models/spree/calculator/flat_rate.rb +4 -0
  11. data/app/models/spree/calculator/flexi_rate.rb +4 -0
  12. data/app/models/spree/calculator/per_item.rb +4 -0
  13. data/app/models/spree/calculator/price_sack.rb +6 -0
  14. data/app/models/spree/creditcard.rb +9 -6
  15. data/app/models/spree/gateway.rb +2 -0
  16. data/app/models/spree/image.rb +3 -0
  17. data/app/models/spree/mail_method.rb +7 -0
  18. data/app/models/spree/option_type.rb +2 -0
  19. data/app/models/spree/option_value.rb +2 -0
  20. data/app/models/spree/order.rb +1 -1
  21. data/app/models/spree/payment.rb +2 -0
  22. data/app/models/spree/payment_method.rb +2 -0
  23. data/app/models/spree/preference.rb +1 -0
  24. data/app/models/spree/product.rb +9 -1
  25. data/app/models/spree/product/scopes.rb +39 -34
  26. data/app/models/spree/product_property.rb +2 -0
  27. data/app/models/spree/property.rb +2 -0
  28. data/app/models/spree/prototype.rb +4 -0
  29. data/app/models/spree/return_authorization.rb +2 -0
  30. data/app/models/spree/role.rb +2 -0
  31. data/app/models/spree/shipment.rb +4 -0
  32. data/app/models/spree/shipping_category.rb +2 -0
  33. data/app/models/spree/shipping_method.rb +3 -0
  34. data/app/models/spree/state.rb +2 -0
  35. data/app/models/spree/tax_category.rb +2 -0
  36. data/app/models/spree/tax_rate.rb +2 -0
  37. data/app/models/spree/taxon.rb +2 -0
  38. data/app/models/spree/taxonomy.rb +2 -0
  39. data/app/models/spree/tracker.rb +2 -0
  40. data/app/models/spree/user.rb +1 -0
  41. data/app/models/spree/variant.rb +5 -0
  42. data/app/models/spree/zone.rb +2 -0
  43. data/app/models/spree/zone_member.rb +2 -0
  44. data/app/views/spree/admin/mail_methods/_form.html.erb +1 -1
  45. data/app/views/spree/admin/payment_methods/_form.html.erb +1 -1
  46. data/app/views/spree/admin/shared/_head.html.erb +3 -3
  47. data/app/views/spree/admin/tax_rates/index.html.erb +1 -1
  48. data/app/views/spree/admin/trackers/_form.html.erb +1 -1
  49. data/config/locales/en.yml +4 -0
  50. data/config/routes.rb +3 -3
  51. data/db/migrate/20120523061241_convert_sales_tax_to_default_tax.rb +9 -0
  52. data/lib/spree/core/calculated_adjustments.rb +6 -5
  53. data/lib/spree/core/ssl_requirement.rb +2 -2
  54. data/lib/spree/core/testing_support/fixtures.rb +4 -0
  55. data/lib/spree/core/version.rb +1 -1
  56. data/lib/spree/product_filters.rb +16 -7
  57. metadata +35 -36
@@ -1,3 +1,4 @@
1
+ <%# encoding: utf-8 %>
1
2
  //= require_self
2
3
 
3
4
  /**
@@ -59,8 +60,10 @@ format_product_autocomplete = function(item){
59
60
  }
60
61
 
61
62
  html += "<div><h4>" + product['name'] + "</h4>";
62
- html += "<span><strong>Sku: </strong>" + product['master']['sku'] + "</span>";
63
- html += "<span><strong>On Hand: </strong>" + product['count_on_hand'] + "</span></div>";
63
+ if (product['master']) {
64
+ html += "<span><strong><%= ::I18n.t(:sku) %>: </strong>" + product['master']['sku'] + "</span>";
65
+ }
66
+ html += "<span><strong><%= ::I18n.t(:on_hand) %>: </strong>" + product['count_on_hand'] + "</span></div>";
64
67
  }else{
65
68
  // variant
66
69
  var variant = item.data['variant'];
@@ -75,12 +78,12 @@ format_product_autocomplete = function(item){
75
78
  }
76
79
 
77
80
  name += " - " + $.map(variant['option_values'], function(option_value){
78
- return option_value["option_type"]["presentation"] + ": " + option_value['name'];
81
+ return option_value["option_type"]["presentation"] + ": " + option_value['presentation'];
79
82
  }).join(", ")
80
83
 
81
84
  html += "<div><h4>" + name + "</h4>";
82
- html += "<span><strong>Sku: </strong>" + variant['sku'] + "</span>";
83
- html += "<span><strong>On Hand: </strong>" + variant['count_on_hand'] + "</span></div>";
85
+ html += "<span><strong><%= ::I18n.t(:sku) %>: </strong>" + variant['sku'] + "</span>";
86
+ html += "<span><strong><%= ::I18n.t(:on_hand) %>: </strong>" + variant['count_on_hand'] + "</span></div>";
84
87
  }
85
88
 
86
89
  return html
@@ -97,7 +100,7 @@ prep_product_autocomplete_data = function(data){
97
100
 
98
101
  var name = product['name'];
99
102
  name += " - " + $.map(variant['option_values'], function(option_value){
100
- return option_value["option_type"]["presentation"] + ": " + option_value['name'];
103
+ return option_value["option_type"]["presentation"] + ": " + option_value['presentation'];
101
104
  }).join(", ");
102
105
 
103
106
  return {
@@ -120,7 +123,7 @@ $.fn.product_autocomplete = function(){
120
123
  return this.each(function() {
121
124
  $(this).autocomplete({
122
125
  source: function(request, response) {
123
- $.get("/admin/products.json?q=" + $('#add_product_name').val() + "&authenticity_token=" + encodeURIComponent($('meta[name=csrf-token]').attr("content")), function(data) {
126
+ $.get(ajax_urls.product_search_json + "?q=" + $('#add_product_name').val() + "&authenticity_token=" + encodeURIComponent($('meta[name=csrf-token]').attr("content")), function(data) {
124
127
  result = prep_product_autocomplete_data(data)
125
128
  response(result);
126
129
  });
@@ -171,8 +174,9 @@ $.fn.objectPicker = function(url){
171
174
  $.fn.productPicker = function(){
172
175
  $(this).objectPicker(ajax_urls.product_search_basic_json);
173
176
  }
177
+
174
178
  $.fn.userPicker = function(){
175
- $(this).objectPicker(ajax_urls.user_search_basic_json);
179
+ $(this).objectPicker(ajax_urls.user_search_json);
176
180
  }
177
181
 
178
182
  // Possible defunct
@@ -206,7 +210,12 @@ $(".observe_field").live('change', function() {
206
210
 
207
211
  handle_date_picker_fields = function(){
208
212
  $('.datepicker').datepicker({
209
- dateFormat: 'yy/mm/dd',
213
+ dateFormat: "<%= ::I18n.t(:format, :scope => 'spree.date_picker', :default => 'yy/mm/dd') %>",
214
+ dayNames: ["<%= ::I18n.t(:day_names, :scope => :date).join('","') %>"],
215
+ dayNamesMin: ["<%= ::I18n.t(:abbr_day_names, :scope => :date).join('","') %>"],
216
+ monthNames: ["<%= ::I18n.t(:month_names, :scope => :date).join('","') %>"],
217
+ prevText: '<%= ::I18n.t(:previous) %>',
218
+ nextText: '<%= ::I18n.t(:next) %>',
210
219
  showOn: "button",
211
220
  buttonImage: "<%= asset_path 'datepicker/cal.gif' %>",
212
221
  buttonImageOnly: true
@@ -46,7 +46,7 @@ $(document).ready(function(){
46
46
  minChars: 5,
47
47
  delay: 1500,
48
48
  source: function(request, response) {
49
- $.get("/admin/users.json?q=" + $("#customer_search").val() + "&authenticity_token=" + encodeURIComponent($('meta[name=csrf-token]').attr("content")), function(data) {
49
+ $.get(ajax_urls.user_search_json + "&q=" + $("#customer_search").val() + "&authenticity_token=" + encodeURIComponent($('meta[name=csrf-token]').attr("content")), function(data) {
50
50
  result = prep_user_autocomplete_data(data)
51
51
  response(result);
52
52
  });
@@ -78,6 +78,7 @@ $(document).ready(function(){
78
78
  $('#user_id').val(ui.item.data['id']);
79
79
  $('#guest_checkout_true').prop("checked", false);
80
80
  $('#guest_checkout_false').prop("checked", true);
81
+ $('#guest_checkout_false').prop("disabled", false);
81
82
  return true;
82
83
  }
83
84
  }).data("autocomplete")._renderItem = function(ul, item) {
@@ -107,7 +108,6 @@ $(document).ready(function(){
107
108
  $('#customer_search').val("");
108
109
  $('#user_id').val("");
109
110
  $('#checkout_email').val("");
110
- $('#guest_checkout_false').prop("disabled", true);
111
111
 
112
112
  $('#order_bill_address_attributes_firstname').val("");
113
113
  $('#order_bill_address_attributes_lastname').val("");
@@ -313,7 +313,7 @@ body {
313
313
  width: 24px; }
314
314
  button.small {
315
315
  font-size: 1em;
316
- padding: 0 10px 0 10px;
316
+ padding: 0 20px 0 0;
317
317
  }
318
318
  input.title,
319
319
  textarea {
@@ -597,7 +597,9 @@ span.handle{
597
597
  border: 1px solid #000;
598
598
  }
599
599
 
600
- .ac_results li h4 { width: 100% }
600
+ .ac_results li div { max-width: 90%; }
601
+
602
+ .ac_results li h4 { width: 100%; }
601
603
 
602
604
  .ac_results li:last-child { border: none; }
603
605
 
@@ -10,8 +10,8 @@ module Spree
10
10
  end
11
11
 
12
12
  def edit
13
- @order.build_bill_address(:country_id => Spree::Config[:default_country_id]) if @order.bill_address.nil?
14
- @order.build_ship_address(:country_id => Spree::Config[:default_country_id]) if @order.ship_address.nil?
13
+ @order.bill_address = Address.default if @order.bill_address.nil?
14
+ @order.ship_address = Address.default if @order.ship_address.nil?
15
15
  end
16
16
 
17
17
  def update
@@ -46,7 +46,7 @@ module Spree
46
46
 
47
47
  rescue Spree::Core::GatewayError => e
48
48
  flash[:error] = "#{e.message}"
49
- respond_with(@payment) { |format| format.html { redirect_to new_admin_payment_path(@order) } }
49
+ respond_with(@payment) { |format| format.html { redirect_to new_admin_order_payment_path(@order) } }
50
50
  end
51
51
  end
52
52
 
@@ -8,6 +8,11 @@ module Spree
8
8
  validates :firstname, :lastname, :address1, :city, :zipcode, :country, :phone, :presence => true
9
9
  validate :state_validate
10
10
 
11
+ attr_accessible :firstname, :lastname, :address1, :address2,
12
+ :city, :zipcode, :country_id, :state_id,
13
+ :country, :state, :phone, :state_name,
14
+ :company, :alternative_phone
15
+
11
16
  # disconnected since there's no code to display error messages yet OR matching client-side validation
12
17
  def phone_validate
13
18
  return if phone.blank?
@@ -60,7 +65,7 @@ module Spree
60
65
 
61
66
  def self.default
62
67
  country = Spree::Country.find_by_id(Spree::Config[:default_country_id])
63
- new :country_id => country.try(:id) || Country.first.id
68
+ new(:country => country || Country.first)
64
69
  end
65
70
 
66
71
  # can modify an address if it's not been used in an order (but checkouts controller has finer control)
@@ -22,6 +22,8 @@
22
22
  #
23
23
  module Spree
24
24
  class Adjustment < ActiveRecord::Base
25
+ attr_accessible :amount, :label
26
+
25
27
  belongs_to :adjustable, :polymorphic => true
26
28
  belongs_to :source, :polymorphic => true
27
29
  belongs_to :originator, :polymorphic => true
@@ -31,7 +33,7 @@ module Spree
31
33
 
32
34
  scope :tax, lambda { where(:originator_type => 'Spree::TaxRate', :adjustable_type => 'Spree::Order') }
33
35
  scope :price, lambda { where(:adjustable_type => 'Spree::LineItem') }
34
- scope :shipping, lambda { where(:label => I18n.t(:shipping)) }
36
+ scope :shipping, lambda { where(:originator_type => 'Spree::ShippingMethod') }
35
37
  scope :optional, where(:mandatory => false)
36
38
  scope :eligible, where(:eligible => true)
37
39
  scope :charge, where("amount >= 0")
@@ -74,7 +76,7 @@ module Spree
74
76
  private
75
77
 
76
78
  def update_adjustable
77
- adjustable.update! if adjustable.is_a? Order
79
+ adjustable.update! if adjustable.is_a? Spree::Order
78
80
  end
79
81
 
80
82
  end
@@ -1,3 +1,5 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::DefaultTax < Calculator
3
5
  def self.description
@@ -1,7 +1,11 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::FlatPercentItemTotal < Calculator
3
5
  preference :flat_percent, :decimal, :default => 0
4
6
 
7
+ attr_accessible :preferred_flat_percent
8
+
5
9
  def self.description
6
10
  I18n.t(:flat_percent)
7
11
  end
@@ -1,7 +1,11 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::FlatRate < Calculator
3
5
  preference :amount, :decimal, :default => 0
4
6
 
7
+ attr_accessible :preferred_amount
8
+
5
9
  def self.description
6
10
  I18n.t(:flat_rate_per_order)
7
11
  end
@@ -1,9 +1,13 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::FlexiRate < Calculator
3
5
  preference :first_item, :decimal, :default => 0.0
4
6
  preference :additional_item, :decimal, :default => 0.0
5
7
  preference :max_items, :integer, :default => 0
6
8
 
9
+ attr_accessible :preferred_first_item, :preferred_additional_item, :preferred_max_items
10
+
7
11
  def self.description
8
12
  I18n.t(:flexible_rate)
9
13
  end
@@ -1,7 +1,11 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::PerItem < Calculator
3
5
  preference :amount, :decimal, :default => 0
4
6
 
7
+ attr_accessible :preferred_amount
8
+
5
9
  def self.description
6
10
  I18n.t(:flat_rate_per_item)
7
11
  end
@@ -1,9 +1,15 @@
1
+ require_dependency 'spree/calculator'
2
+
1
3
  module Spree
2
4
  class Calculator::PriceSack < Calculator
3
5
  preference :minimal_amount, :decimal, :default => 0
4
6
  preference :normal_amount, :decimal, :default => 0
5
7
  preference :discount_amount, :decimal, :default => 0
6
8
 
9
+ attr_accessible :preferred_minimal_amount,
10
+ :preferred_normal_amount,
11
+ :preferred_discount_amount
12
+
7
13
  def self.description
8
14
  I18n.t(:price_sack)
9
15
  end
@@ -11,6 +11,9 @@ module Spree
11
11
  validates :number, :presence => true, :unless => :has_payment_profile?, :on => :create
12
12
  validates :verification_value, :presence => true, :unless => :has_payment_profile?, :on => :create
13
13
 
14
+ attr_accessible :first_name, :last_name, :number, :verification_value, :year,
15
+ :month, :gateway_customer_profile_id, :gateway_payment_profile_id
16
+
14
17
  def process!(payment)
15
18
  if Spree::Config[:auto_capture]
16
19
  purchase(payment.amount.to_f, payment)
@@ -171,12 +174,12 @@ module Spree
171
174
  record_log payment, response
172
175
 
173
176
  if response.success?
174
- Payment.create(:order => payment.order,
175
- :source => payment,
176
- :payment_method => payment.payment_method,
177
- :amount => amount.abs * -1,
178
- :response_code => response.authorization,
179
- :state => 'completed')
177
+ Payment.create({ :order => payment.order,
178
+ :source => payment,
179
+ :payment_method => payment.payment_method,
180
+ :amount => amount.abs * -1,
181
+ :response_code => response.authorization,
182
+ :state => 'completed'}, :without_protection => true)
180
183
  else
181
184
  gateway_error(response)
182
185
  end
@@ -7,6 +7,8 @@ module Spree
7
7
  preference :server, :string, :default => 'test'
8
8
  preference :test_mode, :boolean, :default => true
9
9
 
10
+ attr_accessible :preferred_server, :preferred_test_mode
11
+
10
12
  def payment_source_class
11
13
  Creditcard
12
14
  end
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class Image < Asset
3
3
  validate :no_attachment_errors
4
+
5
+ attr_accessible :alt, :attachment, :position, :viewable_type, :viewable_id
6
+
4
7
  has_attached_file :attachment,
5
8
  :styles => { :mini => '48x48>', :small => '100x100>', :product => '240x240>', :large => '600x600>' },
6
9
  :default_style => :product,
@@ -16,6 +16,13 @@ module Spree
16
16
  preference :mail_bcc, :string, :default => 'spree@example.com'
17
17
  preference :intercept_email, :string, :default => nil
18
18
 
19
+ attr_accessible :environment, :preferred_enable_mail_delivery,
20
+ :preferred_mails_from, :preferred_mail_bcc,
21
+ :preferred_intercept_email, :preferred_mail_domain,
22
+ :preferred_mail_host, :preferred_mail_port,
23
+ :preferred_secure_connection_type, :preferred_mail_auth_type,
24
+ :preferred_smtp_username, :preferred_smtp_password
25
+
19
26
  validates :environment, :presence => true
20
27
 
21
28
  def self.current
@@ -4,6 +4,8 @@ module Spree
4
4
  has_many :product_option_types, :dependent => :destroy
5
5
  has_and_belongs_to_many :prototypes, :join_table => 'spree_option_types_prototypes'
6
6
 
7
+ attr_accessible :name, :presentation, :option_values_attributes
8
+
7
9
  validates :name, :presentation, :presence => true
8
10
  default_scope :order => "#{self.table_name}.position"
9
11
 
@@ -3,5 +3,7 @@ module Spree
3
3
  belongs_to :option_type
4
4
  acts_as_list :scope => :option_type
5
5
  has_and_belongs_to_many :variants, :join_table => 'spree_option_values_variants'
6
+
7
+ attr_accessible :name, :presentation
6
8
  end
7
9
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class Order < ActiveRecord::Base
3
3
  attr_accessible :line_items, :bill_address_attributes, :ship_address_attributes, :payments_attributes,
4
- :ship_address, :bill_address, :line_items_attributes,
4
+ :ship_address, :bill_address, :line_items_attributes, :number,
5
5
  :shipping_method_id, :email, :use_billing, :special_instructions
6
6
 
7
7
  belongs_to :user
@@ -15,6 +15,8 @@ module Spree
15
15
  attr_accessor :source_attributes
16
16
  after_initialize :build_source
17
17
 
18
+ attr_accessible :amount, :payment_method_id, :source_attributes
19
+
18
20
  scope :from_creditcard, where(:source_type => 'Spree::Creditcard')
19
21
  scope :with_state, lambda { |s| where(:state => s) }
20
22
  scope :completed, with_state('completed')
@@ -5,6 +5,8 @@ module Spree
5
5
 
6
6
  scope :production, where(:environment => 'production')
7
7
 
8
+ attr_accessible :name, :description, :environment, :display_on, :active
9
+
8
10
  def self.providers
9
11
  Rails.application.config.spree.payment_methods
10
12
  end
@@ -1,4 +1,5 @@
1
1
  class Spree::Preference < ActiveRecord::Base
2
+ attr_accessible :name, :key, :value_type, :value
2
3
 
3
4
  validates :key, :presence => true
4
5
  validates :value_type, :presence => true
@@ -64,6 +64,14 @@ module Spree
64
64
 
65
65
  validates :name, :price, :permalink, :presence => true
66
66
 
67
+ attr_accessible :name, :description, :available_on, :permalink, :meta_description,
68
+ :meta_keywords, :price, :sku, :deleted_at, :prototype_id,
69
+ :option_values_hash, :on_hand, :weight, :height, :width, :depth,
70
+ :shipping_category_id, :tax_category_id, :product_properties_attributes,
71
+ :variants_attributes, :taxon_ids
72
+
73
+ attr_accessible :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
74
+
67
75
  accepts_nested_attributes_for :product_properties, :allow_destroy => true, :reject_if => lambda { |pp| pp[:property_name].blank? }
68
76
 
69
77
  make_permalink
@@ -119,7 +127,7 @@ module Spree
119
127
  def add_properties_and_option_types_from_prototype
120
128
  if prototype_id && prototype = Spree::Prototype.find_by_id(prototype_id)
121
129
  prototype.properties.each do |property|
122
- product_properties.create(:property => property)
130
+ product_properties.create({:property => property}, :without_protection => true)
123
131
  end
124
132
  self.option_types = prototype.option_types
125
133
  end
@@ -1,5 +1,14 @@
1
1
  module Spree
2
2
  class Product < ActiveRecord::Base
3
+ cattr_accessor :search_scopes do
4
+ []
5
+ end
6
+
7
+ def self.add_search_scope(name, &block)
8
+ self.singleton_class.send(:define_method, name.to_sym, &block)
9
+ search_scopes << name.to_sym
10
+ end
11
+
3
12
  def self.simple_scopes
4
13
  [
5
14
  :ascend_by_updated_at,
@@ -22,37 +31,34 @@ module Spree
22
31
  self.scope(name.to_s, relation.order(order_text))
23
32
  end
24
33
 
25
- def self.ascend_by_master_price
34
+ add_search_scope :ascend_by_master_price do
26
35
  joins(:variants_with_only_master).order("#{variant_table_name}.price ASC")
27
36
  end
28
37
 
29
- def self.descend_by_master_price
38
+ add_search_scope :descend_by_master_price do
30
39
  joins(:variants_with_only_master).order("#{variant_table_name}.price DESC")
31
40
  end
32
41
 
33
42
  # Ryan Bates - http://railscasts.com/episodes/112
34
43
  # general merging of conditions, names following the searchlogic pattern
35
- scope :conditions, lambda { |*args| { :conditions => args } }
44
+ add_search_scope :conditions do |*args|
45
+ where(args)
46
+ end
36
47
 
37
48
  # conditions_all is a more descriptively named enhancement of the above
38
- scope :conditions_all, lambda { |*args| { :conditions => [args].flatten } }
39
-
40
- # forming the disjunction of a list of conditions (as strings)
41
- scope :conditions_any, lambda { |*args|
42
- args = [args].flatten
43
- raise "non-strings in conditions_any" unless args.all? { |s| s.is_a? String }
44
- { :conditions => args.map { |c| "(#{c})"}.join(" OR ") }
45
- }
49
+ add_search_scope :conditions_all do |*args|
50
+ where([args].flatten)
51
+ end
46
52
 
47
- def self.price_between(low, high)
53
+ add_search_scope :price_between do |low, high|
48
54
  joins(:master).where(Variant.table_name => { :price => low..high })
49
55
  end
50
56
 
51
- def self.master_price_lte(price)
57
+ add_search_scope :master_price_lte do |price|
52
58
  joins(:master).where("#{variant_table_name}.price <= ?", price)
53
59
  end
54
60
 
55
- def self.master_price_gte(price)
61
+ add_search_scope :master_price_gte do |price|
56
62
  joins(:master).where("#{variant_table_name}.price >= ?", price)
57
63
  end
58
64
 
@@ -60,7 +66,7 @@ module Spree
60
66
  # If you need products only within one taxon use
61
67
  #
62
68
  # Spree::Product.taxons_id_eq(x)
63
- def self.in_taxon(taxon)
69
+ add_search_scope :in_taxon do |taxon|
64
70
  joins(:taxons).where(Taxon.table_name => { :id => taxon.self_and_descendants.map(&:id) })
65
71
  end
66
72
 
@@ -68,8 +74,7 @@ module Spree
68
74
  # If you need products only within one taxon use
69
75
  #
70
76
  # Spree::Product.taxons_id_eq([x,y])
71
- #
72
- def self.in_taxons(*taxons)
77
+ add_search_scope :in_taxons do |*taxons|
73
78
  taxons = get_taxons(taxons)
74
79
  taxons.first ? prepare_taxon_conditions(taxons) : scoped
75
80
  end
@@ -79,7 +84,7 @@ module Spree
79
84
  end
80
85
 
81
86
  # a scope that finds all products having property specified by name, object or id
82
- def self.with_property(property)
87
+ add_search_scope :with_property do |property|
83
88
  properties = Property.table_name
84
89
  conditions = case property
85
90
  when String then { "#{properties}.name" => property }
@@ -92,7 +97,7 @@ module Spree
92
97
 
93
98
  # a simple test for product with a certain property-value pairing
94
99
  # note that it can test for properties with NULL values, but not for absent values
95
- def self.with_property_value(property, value)
100
+ add_search_scope :with_property_value do |property, value|
96
101
  properties = Spree::Property.table_name
97
102
  conditions = case property
98
103
  when String then ["#{properties}.name = ?", property]
@@ -104,8 +109,7 @@ module Spree
104
109
  joins(:properties).where(conditions)
105
110
  end
106
111
 
107
- # a scope that finds all products having an option_type specified by name, object or id
108
- def self.with_option(option)
112
+ add_search_scope :with_option do |option|
109
113
  option_types = OptionType.table_name
110
114
  conditions = case option
111
115
  when String then { "#{option_types}.name" => option }
@@ -116,8 +120,7 @@ module Spree
116
120
  joins(:option_types).where(conditions)
117
121
  end
118
122
 
119
- # a scope that finds all products having an option value specified by name, object or id
120
- def self.with_option_value(option, value)
123
+ add_search_scope :with_option_value do |option, value|
121
124
  option_values = OptionValue.table_name
122
125
  option_type_id = case option
123
126
  when String then OptionType.find_by_name(option) || option.to_i
@@ -132,30 +135,30 @@ module Spree
132
135
  # Finds all products which have either:
133
136
  # 1) have an option value with the name matching the one given
134
137
  # 2) have a product property with a value matching the one given
135
- def self.with(value)
138
+ add_search_scope :with do |value|
136
139
  includes(:variants_including_master => :option_values).
137
140
  includes(:product_properties).
138
141
  where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
139
142
  end
140
143
 
141
144
  # Finds all products that have a name containing the given words.
142
- def self.in_name(words)
145
+ add_search_scope :in_name do |words|
143
146
  like_any([:name], prepare_words(words))
144
147
  end
145
148
 
146
149
  # Finds all products that have a name or meta_keywords containing the given words.
147
- def self.in_name_or_keywords(words)
150
+ add_search_scope :in_name_or_keywords do |words|
148
151
  like_any([:name, :meta_keywords], prepare_words(words))
149
152
  end
150
153
 
151
154
  # Finds all products that have a name, description, meta_description or meta_keywords containing the given keywords.
152
- def self.in_name_or_description(words)
155
+ add_search_scope :in_name_or_description do |words|
153
156
  like_any([:name, :description, :meta_description, :meta_keywords], prepare_words(words))
154
157
  end
155
158
 
156
159
  # Finds all products that have the ids matching the given collection of ids.
157
160
  # Alternatively, you could use find(collection_of_ids), but that would raise an exception if one product couldn't be found
158
- def self.with_ids(*ids)
161
+ add_search_scope :with_ids do |*ids|
159
162
  where(:id => ids)
160
163
  end
161
164
 
@@ -167,7 +170,7 @@ module Spree
167
170
  #
168
171
  # :joins => "LEFT OUTER JOIN (SELECT line_items.variant_id as vid, COUNT(*) as cnt FROM line_items GROUP BY line_items.variant_id) AS popularity_count ON variants.id = vid",
169
172
  # :order => 'COALESCE(cnt, 0) DESC'
170
- def self.descend_by_popularity
173
+ add_search_scope :descend_by_popularity do
171
174
  joins(:master).
172
175
  order(%Q{
173
176
  COALESCE((
@@ -185,25 +188,26 @@ module Spree
185
188
  })
186
189
  end
187
190
 
188
- def self.not_deleted
191
+ add_search_scope :not_deleted do
189
192
  where(:deleted_at => nil)
190
193
  end
191
194
 
195
+ # Can't use add_search_scope for this as it needs a default argument
192
196
  def self.available(available_on = nil)
193
197
  where('available_on <= ?', available_on || Time.now)
194
198
  end
199
+ search_scopes << :available
195
200
 
196
- #RAILS 3 TODO - this scope doesn't match the original 2.3.x version, needs attention (but it works)
197
- def self.active
201
+ add_search_scope :active do
198
202
  not_deleted.available
199
203
  end
200
204
 
201
- def self.on_hand
205
+ add_search_scope :on_hand do
202
206
  variants_table = Variant.table_name
203
207
  where("#{table_name}.id in (select product_id from #{variants_table} where product_id = #{table_name}.id group by product_id having sum(count_on_hand) > 0)")
204
208
  end
205
209
 
206
- def self.taxons_name_eq(name)
210
+ add_search_scope :taxons_name_eq do |name|
207
211
  joins(:taxons).where(Taxon.arel_table[:name].eq(name))
208
212
  end
209
213
 
@@ -215,6 +219,7 @@ module Spree
215
219
  scope :group_by_products_id, { :group => "#{self.quoted_table_name}.id" }
216
220
  end
217
221
  search_methods :group_by_products_id
222
+ search_scopes << :group_by_products_id
218
223
 
219
224
  private
220
225
  def self.variant_table_name