Class: Spree::Variant

Inherits:
Base
  • Object
show all
Includes:
DefaultPrice
Defined in:
app/models/spree/variant.rb

Constant Summary collapse

LOCALIZED_NUMBERS =
%w(cost_price weight depth width height)

Instance Method Summary collapse

Methods inherited from Base

belongs_to_required_by_default, page, spree_base_scopes

Methods included from Preferences::Preferable

#clear_preferences, #default_preferences, #defined_preferences, #get_preference, #has_preference!, #has_preference?, #preference_default, #preference_type, #set_preference

Instance Method Details

#amount_in(currency) ⇒ Object



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

def amount_in(currency)
  price_in(currency).try(:amount)
end

#available?Boolean

Returns:

  • (Boolean)


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

def available?
  !discontinued? && product.available?
end

#backordered?Boolean

Returns:

  • (Boolean)


276
277
278
# File 'app/models/spree/variant.rb', line 276

def backordered?
  total_on_hand <= 0 && stock_items.exists?(backorderable: true)
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)


142
143
144
# File 'app/models/spree/variant.rb', line 142

def deleted?
  !!deleted_at
end

#descriptive_nameObject



135
136
137
# File 'app/models/spree/variant.rb', line 135

def descriptive_name
  is_master? ? name + ' - Master' : name + ' - ' + options_text
end

#dimensionObject



264
265
266
# File 'app/models/spree/variant.rb', line 264

def dimension
  (width || 0) + (height || 0) + (depth || 0)
end

#discontinue!Object



268
269
270
# File 'app/models/spree/variant.rb', line 268

def discontinue!
  update_attribute(:discontinue_on, Time.current)
end

#discontinued?Boolean

Returns:

  • (Boolean)


272
273
274
# File 'app/models/spree/variant.rb', line 272

def discontinued?
  !!discontinue_on && discontinue_on <= Time.current
end

#exchange_nameObject

Default to master name



131
132
133
# File 'app/models/spree/variant.rb', line 131

def exchange_name
  is_master? ? name : options_text
end

#in_stock?Boolean

Returns:

  • (Boolean)


236
237
238
239
240
# File 'app/models/spree/variant.rb', line 236

def in_stock?
  Rails.cache.fetch(in_stock_cache_key) do
    total_on_hand > 0
  end
end

#name_and_skuObject



228
229
230
# File 'app/models/spree/variant.rb', line 228

def name_and_sku
  "#{name} - #{sku}"
end

#option_value(opt_name) ⇒ Object



190
191
192
# File 'app/models/spree/variant.rb', line 190

def option_value(opt_name)
  option_values.detect { |o| o.option_type.name == opt_name }.try(:presentation)
end

#options=(options = {}) ⇒ Object



153
154
155
156
157
# File 'app/models/spree/variant.rb', line 153

def options=(options = {})
  options.each do |option|
    set_option_value(option[:name], option[:value])
  end
end

#options_textObject



118
119
120
121
122
123
124
125
126
127
128
# File 'app/models/spree/variant.rb', line 118

def options_text
  values = option_values.sort do |a, b|
    a.option_type.position <=> b.option_type.position
  end

  values.to_a.map! do |ov|
    "#{ov.option_type.presentation}: #{ov.presentation}"
  end

  values.to_sentence(words_connector: ', ', two_words_connector: ', ')
end

#price_in(currency) ⇒ Object



194
195
196
# File 'app/models/spree/variant.rb', line 194

def price_in(currency)
  prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
end

#price_modifier_amount(options = {}) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
# File 'app/models/spree/variant.rb', line 215

def price_modifier_amount(options = {})
  return 0 unless options.present?

  options.keys.map do |key|
    m = "#{key}_price_modifier_amount".to_sym
    if respond_to? m
      send(m, options[key])
    else
      0
    end
  end.sum
end

#price_modifier_amount_in(currency, options = {}) ⇒ Object



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

def price_modifier_amount_in(currency, options = {})
  return 0 unless options.present?

  options.keys.map do |key|
    m = "#{key}_price_modifier_amount_in".to_sym
    if respond_to? m
      send(m, currency, options[key])
    else
      0
    end
  end.sum
end

#productObject

Product may be created with deleted_at already set, which would make AR’s default finder return nil. This is a stopgap for that little problem.



149
150
151
# File 'app/models/spree/variant.rb', line 149

def product
  Spree::Product.unscoped { super }
end

#purchasable?Boolean

Returns:

  • (Boolean)


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

def purchasable?
  in_stock? || backorderable?
end

#set_option_value(opt_name, opt_value) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'app/models/spree/variant.rb', line 159

def set_option_value(opt_name, opt_value)
  # no option values on master
  return if is_master

  option_type = Spree::OptionType.where(name: opt_name).first_or_initialize do |o|
    o.presentation = opt_name
    o.save!
  end

  current_value = option_values.detect { |o| o.option_type.name == opt_name }

  if current_value.nil?
    # then we have to check to make sure that the product has the option type
    unless product.option_types.include? option_type
      product.option_types << option_type
    end
  else
    return if current_value.name == opt_value

    option_values.delete(current_value)
  end

  option_value = Spree::OptionValue.where(option_type_id: option_type.id, name: opt_value).first_or_initialize do |o|
    o.presentation = opt_value
    o.save!
  end

  option_values << option_value
  save
end

#should_track_inventory?Boolean

Shortcut method to determine if inventory tracking is enabled for this variant This considers both variant tracking flag and site-wide inventory tracking settings

Returns:

  • (Boolean)


252
253
254
# File 'app/models/spree/variant.rb', line 252

def should_track_inventory?
  track_inventory? && Spree::Config.track_inventory_levels
end

#sku_and_options_textObject



232
233
234
# File 'app/models/spree/variant.rb', line 232

def sku_and_options_text
  "#{sku} #{options_text}".strip
end

#tax_categoryObject



110
111
112
113
114
115
116
# File 'app/models/spree/variant.rb', line 110

def tax_category
  if self[:tax_category_id].nil?
    product.tax_category
  else
    Spree::TaxCategory.find(self[:tax_category_id])
  end
end

#track_inventoryObject



256
257
258
# File 'app/models/spree/variant.rb', line 256

def track_inventory
  should_track_inventory?
end

#volumeObject



260
261
262
# File 'app/models/spree/variant.rb', line 260

def volume
  (width || 0) * (height || 0) * (depth || 0)
end