Class: Spree::Product
- Inherits:
-
Base
- Object
- ActiveRecord::Base
- Base
- Spree::Product
show all
- Extended by:
- FriendlyId
- Defined in:
- app/models/spree/product.rb,
app/models/spree/product/scopes.rb
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#clear_preferences, #default_preferences, #defined_preferences, #get_preference, #has_preference!, #has_preference?, #preference_default, #preference_type, #set_preference
Instance Attribute Details
#option_values_hash ⇒ Object
Returns the value of attribute option_values_hash.
88
89
90
|
# File 'app/models/spree/product.rb', line 88
def option_values_hash
@option_values_hash
end
|
#prototype_id ⇒ Object
Adding properties and option types on creation based on a chosen prototype
110
111
112
|
# File 'app/models/spree/product.rb', line 110
def prototype_id
@prototype_id
end
|
Class Method Details
.active(currency = nil) ⇒ Object
195
196
197
|
# File 'app/models/spree/product/scopes.rb', line 195
def self.active(currency = nil)
not_deleted.available(nil, currency)
end
|
.add_search_scope(name, &block) ⇒ Object
7
8
9
10
|
# File 'app/models/spree/product/scopes.rb', line 7
def self.add_search_scope(name, &block)
self.singleton_class.send(:define_method, name.to_sym, &block)
search_scopes << name.to_sym
end
|
.add_simple_scopes(scopes) ⇒ Object
21
22
23
24
25
26
27
28
|
# File 'app/models/spree/product/scopes.rb', line 21
def self.add_simple_scopes(scopes)
scopes.each do |name|
next if name.to_s.include?("master_price")
parts = name.to_s.match(/(.*)_by_(.*)/)
self.scope(name.to_s, -> { order("#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? "ASC" : "DESC"}") })
end
end
|
.available(available_on = nil, currency = nil) ⇒ Object
Can’t use add_search_scope for this as it needs a default argument
190
191
192
|
# File 'app/models/spree/product/scopes.rb', line 190
def self.available(available_on = nil, currency = nil)
joins(:master => :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
end
|
.distinct_by_product_ids(sort_order = nil) ⇒ Object
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
# File 'app/models/spree/product/scopes.rb', line 204
def self.distinct_by_product_ids(sort_order = nil)
sort_column = sort_order.split(" ").first
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
all
else
distinct
end
end
|
.like_any(fields, values) ⇒ Object
152
153
154
155
156
157
158
|
# File 'app/models/spree/product.rb', line 152
def self.like_any(fields, values)
where fields.map { |field|
values.map { |value|
arel_table[field].matches("%#{value}%")
}.inject(:or)
}.inject(:or)
end
|
.property_conditions(property) ⇒ Object
30
31
32
33
34
35
36
37
|
# File 'app/models/spree/product/scopes.rb', line 30
def self.property_conditions(property)
properties = Property.table_name
conditions = case property
when String then { "#{properties}.name" => property }
when Property then { "#{properties}.id" => property.id }
else { "#{properties}.id" => property.to_i }
end
end
|
.simple_scopes ⇒ Object
12
13
14
15
16
17
18
19
|
# File 'app/models/spree/product/scopes.rb', line 12
def self.simple_scopes
[
:ascend_by_updated_at,
:descend_by_updated_at,
:ascend_by_name,
:descend_by_name
]
end
|
Instance Method Details
#available? ⇒ Boolean
determine if product is available. deleted products and products with nil or future available_on date are not available
141
142
143
|
# File 'app/models/spree/product.rb', line 141
def available?
!(available_on.nil? || available_on.future?) && !deleted?
end
|
#categorise_variants_from_option(opt_type) ⇒ Object
split variants list into hash which shows mapping of opt value onto matching variants eg categorise_variants_from_option(color) => -> […], “blue” -> […]
147
148
149
150
|
# File 'app/models/spree/product.rb', line 147
def categorise_variants_from_option(opt_type)
return {} unless option_types.include?(opt_type)
variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type} }
end
|
#deleted? ⇒ Boolean
use deleted? rather than checking the attribute directly. this allows extensions to override deleted? if they want to provide their own definition.
134
135
136
|
# File 'app/models/spree/product.rb', line 134
def deleted?
!!deleted_at
end
|
#duplicate ⇒ Object
for adding products which are closely related to existing ones define “duplicate_extra” for site-specific actions, eg for additional fields
126
127
128
129
|
# File 'app/models/spree/product.rb', line 126
def duplicate
duplicator = ProductDuplicator.new(self)
duplicator.duplicate
end
|
#empty_option_values? ⇒ Boolean
171
172
173
174
175
|
# File 'app/models/spree/product.rb', line 171
def empty_option_values?
options.empty? || options.any? do |opt|
opt.option_type.option_values.empty?
end
end
|
#ensure_option_types_exist_for_values_hash ⇒ Object
Ensures option_types and product_option_types exist for keys in option_values_hash
116
117
118
119
120
121
122
|
# File 'app/models/spree/product.rb', line 116
def ensure_option_types_exist_for_values_hash
return if option_values_hash.nil?
option_values_hash.keys.map(&:to_i).each do |id|
self.option_type_ids << id unless option_type_ids.include?(id)
product_option_types.create(option_type_id: id) unless product_option_types.pluck(:option_type_id).include?(id)
end
end
|
#has_variants? ⇒ Boolean
the master variant is not a member of the variants array
97
98
99
|
# File 'app/models/spree/product.rb', line 97
def has_variants?
variants.any?
end
|
#master ⇒ Object
Master variant may be deleted (i.e. when the product is deleted) which would make AR’s default finder return nil. This is a stopgap for that little problem.
212
213
214
|
# File 'app/models/spree/product.rb', line 212
def master
super || variants_including_master.with_deleted.where(is_master: true).first
end
|
196
197
198
199
|
# File 'app/models/spree/product.rb', line 196
def possible_promotions
promotion_ids = promotion_rules.map(&:promotion_id).uniq
Spree::Promotion.advertised.where(id: promotion_ids).reject(&:expired?)
end
|
#property(property_name) ⇒ Object
177
178
179
180
|
# File 'app/models/spree/product.rb', line 177
def property(property_name)
return nil unless prop = properties.find_by(name: property_name)
product_properties.find_by(property: prop).try(:value)
end
|
#set_property(property_name, property_value) ⇒ Object
182
183
184
185
186
187
188
189
190
191
192
193
194
|
# File 'app/models/spree/product.rb', line 182
def set_property(property_name, property_value)
ActiveRecord::Base.transaction do
property = if Property.exists?(name: property_name)
Property.where(name: property_name).first
else
Property.create(name: property_name, presentation: property_name)
end
product_property = ProductProperty.where(product: self, property: property).first_or_initialize
product_property.value = property_value
product_property.save!
end
end
|
#tax_category ⇒ Object
101
102
103
104
105
106
107
|
# File 'app/models/spree/product.rb', line 101
def tax_category
if self[:tax_category_id].nil?
TaxCategory.where(is_default: true).first
else
TaxCategory.find(self[:tax_category_id])
end
end
|
#total_on_hand ⇒ Object
201
202
203
204
205
206
207
|
# File 'app/models/spree/product.rb', line 201
def total_on_hand
if self.variants_including_master.any? { |v| !v.should_track_inventory? }
Float::INFINITY
else
self.stock_items.to_a.sum(&:count_on_hand)
end
end
|
#variants_and_option_values(current_currency = nil) ⇒ Object
Suitable for displaying only variants that has at least one option value. There may be scenarios where an option type is removed and along with it all option values. At that point all variants associated with only those values should not be displayed to frontend users. Otherwise it breaks the idea of having variants
165
166
167
168
169
|
# File 'app/models/spree/product.rb', line 165
def variants_and_option_values(current_currency = nil)
variants.includes(:option_values).active(current_currency).select do |variant|
variant.option_values.any?
end
end
|