Class: Spree::Product
- Extended by:
- FriendlyId
- Includes:
- Scopes, SoftDeletable
- Defined in:
- app/models/spree/product.rb,
app/models/spree/product/scopes.rb
Overview
this model uses paranoia. #destroy will only soft-destroy records and the default scope hides soft-destroyed records using WHERE deleted_at IS NULL.
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, :weight, :width, ]
Instance Attribute Summary collapse
-
#option_values_hash ⇒ Object
Returns the value of attribute option_values_hash.
Class Method Summary collapse
-
.like_any(fields, values) ⇒ ActiveRecord::Relation
Poor man’s full text search.
- .ransackable_scopes(_auth_object = nil) ⇒ Object
Instance Method Summary collapse
-
#available? ⇒ Boolean
Determines if product is available.
-
#categorise_variants_from_option(opt_type, pricing_options = Spree::Config.default_pricing_options) ⇒ Hash
deprecated
Deprecated.
This method is not called in the Solidus codebase
-
#deleted? ⇒ Boolean
Use for checking whether this product has been deleted.
-
#discontinued? ⇒ Boolean
Determines if product is discontinued.
-
#display_image ⇒ Spree::Image
Image that can be used for the product.
-
#duplicate ⇒ Spree::Product
Creates a new product with the same attributes, variants, etc.
-
#empty_option_values? ⇒ Boolean
True if there are no option values.
-
#ensure_option_types_exist_for_values_hash ⇒ Array
Ensures option_types and product_option_types exist for keys in option_values_hash.
- #find_or_build_master ⇒ Object
-
#find_variant_property_rule(option_value_ids) ⇒ Spree::VariantPropertyRule
Finds the variant property rule that matches the provided option value ids.
-
#gallery ⇒ Spree::Gallery
The gallery for the product, which represents all the images associated with it, including those on its variants.
-
#has_variants? ⇒ Boolean
True if there are any variants.
-
#possible_promotions ⇒ Array
All advertised and not-rejected promotions.
-
#property(property_name) ⇒ String
The value of the given property.
-
#set_property(property_name, property_value) ⇒ Object
Assigns the given value to the given property.
-
#tax_category ⇒ Spree::TaxCategory
Tax category for this product, or the default tax category.
-
#total_on_hand ⇒ Fixnum, Infinity
The number of on-hand stock items; Infinity if any variant does not track inventory.
-
#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.
-
#variants_and_option_values(current_currency = nil) ⇒ Array<Spree::Variant>
deprecated
Deprecated.
This method can only handle prices for currencies
-
#variants_and_option_values_for(pricing_options = Spree::Config.default_pricing_options) ⇒ Array<Spree::Variant>
All variants with at least one option value.
Methods included from Scopes
Methods inherited from Base
display_includes, page, preference, #preferences
Methods included from Core::Permalinks
#generate_permalink, #save_permalink
Instance Attribute Details
#option_values_hash ⇒ Object
Returns the value of attribute option_values_hash.
120 121 122 |
# File 'app/models/spree/product.rb', line 120 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.
210 211 212 213 214 215 |
# File 'app/models/spree/product.rb', line 210 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
130 131 132 |
# File 'app/models/spree/product.rb', line 130 def self.ransackable_scopes(_auth_object = nil) i(with_discarded with_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.
175 176 177 |
# File 'app/models/spree/product.rb', line 175 def available? !deleted? && available_on&.past? && !discontinued? end |
#categorise_variants_from_option(opt_type, pricing_options = Spree::Config.default_pricing_options) ⇒ Hash
This method is not called in the Solidus codebase
Groups variants by the specified option type.
196 197 198 199 |
# File 'app/models/spree/product.rb', line 196 def categorise_variants_from_option(opt_type, = Spree::Config.) return {} unless option_types.include?(opt_type) variants.with_prices().group_by { |variant| variant.option_values.detect { |option| option.option_type == opt_type } } end |
#deleted? ⇒ Boolean
Use for checking whether this product has been deleted. Provided for overriding the logic for determining if a product is deleted.
166 167 168 |
# File 'app/models/spree/product.rb', line 166 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.
185 186 187 |
# File 'app/models/spree/product.rb', line 185 def discontinued? !!discontinue_on&.past? end |
#display_image ⇒ Spree::Image
Image that can be used for the product.
Will first search for images on the product, then those belonging to the variants. If all else fails, will return a new image object.
304 305 306 307 |
# File 'app/models/spree/product.rb', line 304 def display_image Spree::Deprecation.warn('Spree::Product#display_image is DEPRECATED. Choose an image from Spree::Product#gallery instead.') images.first || variant_images.first || Spree::Image.new end |
#duplicate ⇒ Spree::Product
Creates a new product with the same attributes, variants, etc.
157 158 159 160 |
# File 'app/models/spree/product.rb', line 157 def duplicate duplicator = ProductDuplicator.new(self) duplicator.duplicate end |
#empty_option_values? ⇒ Boolean
Returns true if there are no option values.
256 257 258 |
# File 'app/models/spree/product.rb', line 256 def empty_option_values? .empty? || !option_types.left_joins(:option_values).where('spree_option_values.id IS NULL').empty? end |
#ensure_option_types_exist_for_values_hash ⇒ Array
Ensures option_types and product_option_types exist for keys in option_values_hash.
148 149 150 151 152 |
# File 'app/models/spree/product.rb', line 148 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_master ⇒ Object
68 69 70 |
# File 'app/models/spree/product.rb', line 68 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.
313 314 315 316 317 |
# File 'app/models/spree/product.rb', line 313 def find_variant_property_rule(option_value_ids) variant_property_rules.find do |rule| rule.matches_option_value_ids?(option_value_ids) end end |
#gallery ⇒ Spree::Gallery
The gallery for the product, which represents all the images associated with it, including those on its variants
323 324 325 |
# File 'app/models/spree/product.rb', line 323 def gallery @gallery ||= Spree::Config.product_gallery_class.new(self) end |
#has_variants? ⇒ Boolean
Returns true if there are any variants.
135 136 137 |
# File 'app/models/spree/product.rb', line 135 def has_variants? variants.any? end |
#possible_promotions ⇒ Array
Returns all advertised and not-rejected promotions.
282 283 284 285 |
# File 'app/models/spree/product.rb', line 282 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
Returns the value of the given property. nil if property is undefined on this product.
262 263 264 265 |
# File 'app/models/spree/product.rb', line 262 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.
271 272 273 274 275 276 277 278 279 |
# File 'app/models/spree/product.rb', line 271 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_category ⇒ Spree::TaxCategory
Returns tax category for this product, or the default tax category.
140 141 142 |
# File 'app/models/spree/product.rb', line 140 def tax_category super || Spree::TaxCategory.find_by(is_default: true) end |
#total_on_hand ⇒ Fixnum, Infinity
The number of on-hand stock items; Infinity if any variant does not track inventory.
291 292 293 294 295 296 297 |
# File 'app/models/spree/product.rb', line 291 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
244 245 246 247 248 249 250 251 252 253 |
# File 'app/models/spree/product.rb', line 244 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(current_currency = nil) ⇒ Array<Spree::Variant>
This method can only handle prices for currencies
Returns all variants with at least one option value.
220 221 222 223 224 |
# File 'app/models/spree/product.rb', line 220 def variants_and_option_values(current_currency = nil) variants.includes(:option_values).active(current_currency).select do |variant| variant.option_values.any? end end |
#variants_and_option_values_for(pricing_options = Spree::Config.default_pricing_options) ⇒ Array<Spree::Variant>
Returns all variants with at least one option value.
231 232 233 234 235 |
# File 'app/models/spree/product.rb', line 231 def variants_and_option_values_for( = Spree::Config.) variants.includes(:option_values).with_prices().select do |variant| variant.option_values.any? end end |