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)

Class Method Summary collapse

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

Class Method Details

.product_name_or_sku_cont(query) ⇒ Object



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

def self.product_name_or_sku_cont(query)
  joins(:product).where("#{Product.table_name}.name LIKE :query OR sku LIKE :query", query: "%#{query}%")
end

Instance Method Details

#amount_in(currency) ⇒ Object



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

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

#available?Boolean

Returns:

  • (Boolean)


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

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

#backordered?Boolean

Returns:

  • (Boolean)


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

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)


139
140
141
# File 'app/models/spree/variant.rb', line 139

def deleted?
  !!deleted_at
end

#descriptive_nameObject



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

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

#dimensionObject



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

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

#discontinue!Object



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

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

#discontinued?Boolean

Returns:

  • (Boolean)


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

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

#exchange_nameObject

Default to master name



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

def exchange_name
  is_master? ? name : options_text
end

#in_stock?Boolean

Returns:

  • (Boolean)


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

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

#name_and_skuObject



225
226
227
# File 'app/models/spree/variant.rb', line 225

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

#option_value(opt_name) ⇒ Object



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

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

#options=(options = {}) ⇒ Object



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

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

#options_textObject



123
124
125
# File 'app/models/spree/variant.rb', line 123

def options_text
  Spree::Variants::OptionsPresenter.new(self).to_sentence
end

#price_in(currency) ⇒ Object



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

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

#price_modifier_amount(options = {}) ⇒ Object



212
213
214
215
216
217
218
219
220
221
222
223
# File 'app/models/spree/variant.rb', line 212

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



199
200
201
202
203
204
205
206
207
208
209
210
# File 'app/models/spree/variant.rb', line 199

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.



146
147
148
# File 'app/models/spree/variant.rb', line 146

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

#purchasable?Boolean

Returns:

  • (Boolean)


243
244
245
# File 'app/models/spree/variant.rb', line 243

def purchasable?
  in_stock? || backorderable?
end

#set_option_value(opt_name, opt_value) ⇒ Object



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

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)


249
250
251
# File 'app/models/spree/variant.rb', line 249

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

#sku_and_options_textObject



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

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

#tax_categoryObject



115
116
117
118
119
120
121
# File 'app/models/spree/variant.rb', line 115

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

#track_inventoryObject



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

def track_inventory
  should_track_inventory?
end

#volumeObject



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

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