Class: Spree::Product

Inherits:
ActiveRecord::Base
  • Object
show all
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

Instance Attribute Details

#option_values_hashObject

Returns the value of attribute option_values_hash.



72
73
74
# File 'app/models/spree/product.rb', line 72

def option_values_hash
  @option_values_hash
end

#prototype_idObject

Adding properties and option types on creation based on a chosen prototype



130
131
132
# File 'app/models/spree/product.rb', line 130

def prototype_id
  @prototype_id
end

Class Method Details

.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

.available(available_on = nil) ⇒ Object

Can’t use add_search_scope for this as it needs a default argument



191
192
193
# File 'app/models/spree/product/scopes.rb', line 191

def self.available(available_on = nil)
  where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
end

.like_any(fields, values) ⇒ Object



186
187
188
189
# File 'app/models/spree/product.rb', line 186

def self.like_any(fields, values)
  where_str = fields.map { |field| Array.new(values.size, "#{self.quoted_table_name}.#{field} #{LIKE} ?").join(' OR ') }.join(' OR ')
  self.where([where_str, values.map { |value| "%#{value}%" } * fields.size].flatten)
end

.simple_scopesObject



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

#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” -> […]



181
182
183
184
# File 'app/models/spree/product.rb', line 181

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.

Returns:

  • (Boolean)


175
176
177
# File 'app/models/spree/product.rb', line 175

def deleted?
  !!deleted_at
end

#duplicateObject

for adding products which are closely related to existing ones define “duplicate_extra” for site-specific actions, eg for additional fields



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'app/models/spree/product.rb', line 146

def duplicate
  p = self.dup
  p.name = 'COPY OF ' + name
  p.deleted_at = nil
  p.created_at = p.updated_at = nil
  p.taxons = taxons

  p.product_properties = product_properties.map { |q| r = q.dup; r.created_at = r.updated_at = nil; r }

  image_dup = lambda { |i| j = i.dup; j.attachment = i.attachment.clone; j }

  variant = master.dup
  variant.sku = 'COPY OF ' + master.sku
  variant.deleted_at = nil
  variant.images = master.images.map { |i| image_dup.call i }
  p.master = variant

  # don't dup the actual variants, just the characterising types
  p.option_types = option_types if has_variants?

  # allow site to do some customization
  p.send(:duplicate_extra, self) if p.respond_to?(:duplicate_extra)
  p.save!
  p
end

#empty_option_values?Boolean

Returns:

  • (Boolean)


191
192
193
194
195
# File 'app/models/spree/product.rb', line 191

def empty_option_values?
  options.empty? || options.any? do |opt|
    opt.option_type.option_values.empty?
  end
end

#ensure_masterObject



91
92
93
94
# File 'app/models/spree/product.rb', line 91

def ensure_master
  return unless new_record?
  self.master ||= Variant.new
end

#ensure_option_types_exist_for_values_hashObject

Ensures option_types and product_option_types exist for keys in option_values_hash



136
137
138
139
140
141
142
# File 'app/models/spree/product.rb', line 136

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}, :without_protection => true) unless product_option_types.map(&:option_type_id).include?(id)
  end
end

#has_stock?Boolean

Returns true if there are inventory units (any variant) with “on_hand” state for this product

Returns:

  • (Boolean)


117
118
119
# File 'app/models/spree/product.rb', line 117

def has_stock?
  master.in_stock? || variants.any?(&:in_stock?)
end

#has_variants?Boolean

returns true if the product has any variants (the master variant is not a member of the variants array)

Returns:

  • (Boolean)


101
102
103
# File 'app/models/spree/product.rb', line 101

def has_variants?
  variants.any?
end

#on_handObject

returns the number of inventory units “on_hand” for this product



106
107
108
# File 'app/models/spree/product.rb', line 106

def on_hand
  has_variants? ? variants.inject(0) { |sum, v| sum + v.on_hand } : master.on_hand
end

#on_hand=(new_level) ⇒ Object

adjusts the “on_hand” inventory level for the product up or down to match the given new_level



111
112
113
114
# File 'app/models/spree/product.rb', line 111

def on_hand=(new_level)
  raise 'cannot set on_hand of product with variants' if has_variants? && Spree::Config[:track_inventory_levels]
  master.on_hand = new_level
end

#property(property_name) ⇒ Object



197
198
199
200
# File 'app/models/spree/product.rb', line 197

def property(property_name)
  return nil unless prop = properties.find_by_name(property_name)
  product_properties.find_by_property_id(prop.id).try(:value)
end

#set_property(property_name, property_value) ⇒ Object



202
203
204
205
206
207
208
209
210
211
# File 'app/models/spree/product.rb', line 202

def set_property(property_name, property_value)
  prop = Spree::Property.find_or_initialize_by_name(property_name) do |p|
    p.presentation = property_name
    p.save!
  end

  prod_prop = Spree::ProductProperty.find_or_initialize_by_product_id_and_property_id(self.id, prop.id)
  prod_prop.value = property_value
  prod_prop.save!
end

#tax_categoryObject



121
122
123
124
125
126
127
# File 'app/models/spree/product.rb', line 121

def tax_category
  if self[:tax_category_id].nil?
    TaxCategory.where(:is_default => true).first
  else
    TaxCategory.find(self[:tax_category_id])
  end
end

#to_paramObject



96
97
98
# File 'app/models/spree/product.rb', line 96

def to_param
  permalink.present? ? permalink : (permalink_was || name.to_s.to_url)
end

#variant_imagesObject Also known as: images



61
62
63
64
65
66
# File 'app/models/spree/product.rb', line 61

def variant_images
  Image.joins("LEFT JOIN #{Variant.quoted_table_name} ON #{Variant.quoted_table_name}.id = #{Asset.quoted_table_name}.viewable_id").
  where("#{Variant.quoted_table_name}.product_id = #{self.id}").
  order("#{Asset.quoted_table_name}.position").
  extend(Spree::Core::RelationSerialization)
end