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



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

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

#available?Boolean

Returns:

  • (Boolean)


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

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

#backordered?Boolean

Returns:

  • (Boolean)


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

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)


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

def deleted?
  !!deleted_at
end

#descriptive_nameObject



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

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

#dimensionObject



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

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

#discontinue!Object



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

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

#discontinued?Boolean

Returns:

  • (Boolean)


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

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

#exchange_nameObject

Default to master name



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

def exchange_name
  is_master? ? name : options_text
end

#in_stock?Boolean

Returns:

  • (Boolean)


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

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

#name_and_skuObject



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

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

#option_value(opt_name) ⇒ Object



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

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

#options=(options = {}) ⇒ Object



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

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

#options_textObject



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

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



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

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

#price_modifier_amount(options = {}) ⇒ Object



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

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



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

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.



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

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

#purchasable?Boolean

Returns:

  • (Boolean)


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

def purchasable?
  in_stock? || backorderable?
end

#set_option_value(opt_name, opt_value) ⇒ Object



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
189
# File 'app/models/spree/variant.rb', line 160

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)


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

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

#sku_and_options_textObject



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

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

#tax_categoryObject



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

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

#track_inventoryObject



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

def track_inventory
  should_track_inventory?
end

#volumeObject



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

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