Class: Spree::Product

Inherits:
Base
  • Object
show all
Extended by:
FriendlyId
Includes:
Scopes, SoftDeletable
Defined in:
app/models/spree/product.rb,
app/models/spree/product/scopes.rb

Overview

Products represent an entity for sale in a store. Products can have variations, called variants. Product properties include description, permalink, availability, shipping category, etc. that do not change by variant.

Defined Under Namespace

Modules: Scopes

Constant Summary collapse

MASTER_ATTRIBUTES =
[
  :cost_currency,
  :cost_price,
  :depth,
  :height,
  :price,
  :sku,
  :track_inventory,
  :weight,
  :width,
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Scopes

prepended

Methods inherited from Base

display_includes

Methods included from Core::Permalinks

#generate_permalink, #save_permalink

Instance Attribute Details

#option_values_hashObject

Returns the value of attribute option_values_hash.



128
129
130
# File 'app/models/spree/product.rb', line 128

def option_values_hash
  @option_values_hash
end

Class Method Details

.like_any(fields, values) ⇒ ActiveRecord::Relation

Poor man’s full text search.

Filters products to those which have any of the strings in values in any of the fields in fields.



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

def self.like_any(fields, values)
  conditions = fields.product(values).map do |(field, value)|
    arel_table[field].matches("%#{value}%")
  end
  where conditions.inject(:or)
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



138
139
140
# File 'app/models/spree/product.rb', line 138

def self.ransackable_scopes(_auth_object = nil)
  i(with_discarded with_variant_sku_cont with_all_variant_sku_cont with_kept_variant_sku_cont)
end

Instance Method Details

#available?Boolean

Determines if product is available. A product is available if it has not been deleted, the available_on date is in the past and the discontinue_on date is nil or in the future.



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

def available?
  !deleted? && available_on&.past? && !discontinued?
end

#deleted?Boolean

Use for checking whether this product has been deleted. Provided for overriding the logic for determining if a product is deleted.



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

def deleted?
  !!deleted_at
end

#discontinued?Boolean

Determines if product is discontinued.

A product is discontinued if the discontinue_on date is not nil and in the past.



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

def discontinued?
  !!discontinue_on&.past?
end

#duplicateSpree::Product

Creates a new product with the same attributes, variants, etc.



165
166
167
168
# File 'app/models/spree/product.rb', line 165

def duplicate
  duplicator = ProductDuplicator.new(self)
  duplicator.duplicate
end

#empty_option_values?Boolean



240
241
242
# File 'app/models/spree/product.rb', line 240

def empty_option_values?
  options.empty? || !option_types.left_joins(:option_values).where('spree_option_values.id IS NULL').empty?
end

#ensure_option_types_exist_for_values_hashArray

Ensures option_types and product_option_types exist for keys in option_values_hash.



156
157
158
159
160
# File 'app/models/spree/product.rb', line 156

def ensure_option_types_exist_for_values_hash
  return if option_values_hash.nil?
  required_option_type_ids = option_values_hash.keys.map(&:to_i)
  self.option_type_ids |= required_option_type_ids
end

#find_or_build_masterObject



75
76
77
# File 'app/models/spree/product.rb', line 75

def find_or_build_master
  master || build_master
end

#find_variant_property_rule(option_value_ids) ⇒ Spree::VariantPropertyRule

Finds the variant property rule that matches the provided option value ids.



287
288
289
290
291
# File 'app/models/spree/product.rb', line 287

def find_variant_property_rule(option_value_ids)
  variant_property_rules.find do |rule|
    rule.matches_option_value_ids?(option_value_ids)
  end
end

The gallery for the product, which represents all the images associated with it, including those on its variants



297
298
299
# File 'app/models/spree/product.rb', line 297

def gallery
  @gallery ||= Spree::Config.product_gallery_class.new(self)
end

#has_variants?Boolean



143
144
145
# File 'app/models/spree/product.rb', line 143

def has_variants?
  variants.any?
end

#possible_promotionsArray



266
267
268
269
# File 'app/models/spree/product.rb', line 266

def possible_promotions
  promotion_ids = promotion_rules.map(&:promotion_id).uniq
  Spree::Promotion.advertised.where(id: promotion_ids).reject(&:inactive?)
end

#property(property_name) ⇒ String



246
247
248
249
# File 'app/models/spree/product.rb', line 246

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

Assigns the given value to the given property.



255
256
257
258
259
260
261
262
263
# File 'app/models/spree/product.rb', line 255

def set_property(property_name, property_value)
  ActiveRecord::Base.transaction do
    # Works around spree_i18n https://github.com/spree/spree/issues/301
    property = Spree::Property.create_with(presentation: property_name).find_or_create_by(name: property_name)
    product_property = Spree::ProductProperty.where(product: self, property: property).first_or_initialize
    product_property.value = property_value
    product_property.save!
  end
end

#tax_categorySpree::TaxCategory



148
149
150
# File 'app/models/spree/product.rb', line 148

def tax_category
  super || Spree::TaxCategory.find_by(is_default: true)
end

#total_on_handFixnum, Infinity

The number of on-hand stock items; Infinity if any variant does not track inventory.



275
276
277
278
279
280
281
# File 'app/models/spree/product.rb', line 275

def total_on_hand
  if any_variants_not_track_inventory?
    Float::INFINITY
  else
    stock_items.sum(:count_on_hand)
  end
end

#variant_option_values_by_option_type(variant_scope = nil) ⇒ Hash<Spree::OptionType, Array<Spree::OptionValue>>

Groups all of the option values that are associated to the product’s variants, grouped by option type.

used to determine the applied option_types associated with the products variants grouped by option type



228
229
230
231
232
233
234
235
236
237
# File 'app/models/spree/product.rb', line 228

def variant_option_values_by_option_type(variant_scope = nil)
  option_value_scope = Spree::OptionValuesVariant.joins(:variant)
    .where(spree_variants: { product_id: id })
  option_value_scope = option_value_scope.merge(variant_scope) if variant_scope
  option_value_ids = option_value_scope.distinct.pluck(:option_value_id)
  Spree::OptionValue.where(id: option_value_ids).
    includes(:option_type).
    order("#{Spree::OptionType.table_name}.position, #{Spree::OptionValue.table_name}.position").
    group_by(&:option_type)
end

#variants_and_option_values_for(pricing_options = Spree::Config.default_pricing_options) ⇒ Array<Spree::Variant>



215
216
217
218
219
# File 'app/models/spree/product.rb', line 215

def variants_and_option_values_for(pricing_options = Spree::Config.default_pricing_options)
  variants.includes(:option_values).with_prices(pricing_options).select do |variant|
    variant.option_values.any?
  end
end