forked from spree/spree
/
variant.rb
104 lines (84 loc) · 3.43 KB
/
variant.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
class Variant < ActiveRecord::Base
belongs_to :product
delegate_belongs_to :product, :name, :description, :permalink, :available_on, :tax_category_id, :shipping_category_id, :meta_description, :meta_keywords
has_many :inventory_units
has_many :line_items
has_and_belongs_to_many :option_values
has_many :images, :as => :viewable, :order => :position, :dependent => :destroy
validate :check_price
validates :price, :presence => true
validates :cost_price, :numericality => true, :allow_nil => true if Variant.table_exists? && Variant.column_names.include?("cost_price")
before_save :touch_product
include ::Scopes::Variant
# default variant scope only lists non-deleted variants
scope :active, where("variants.deleted_at is null")
scope :deleted, where("not variants.deleted_at is null")
# default extra fields for shipping purposes
@fields = [ {:name => 'Weight', :only => [:variant], :format => "%.2f"},
{:name => 'Height', :only => [:variant], :format => "%.2f"},
{:name => 'Width', :only => [:variant], :format => "%.2f"},
{:name => 'Depth', :only => [:variant], :format => "%.2f"} ]
# Returns number of inventory units for this variant (new records haven't been saved to database, yet)
def on_hand
Spree::Config[:track_inventory_levels] ? self.count_on_hand : nil
end
# Adjusts the inventory units to match the given new level.
def on_hand=(new_level)
if Spree::Config[:track_inventory_levels]
new_level = new_level.to_i
# increase Inventory when
if new_level > on_hand
# fill backordered orders before creating new units
inventory_units.with_state("backordered").slice(0, new_level).each do |iu|
iu.fill_backorder
new_level -= 1
end
end
self.count_on_hand = new_level
else
raise "Cannot set on_hand value when Spree::Config[:track_inventory_levels] is false"
end
end
# returns number of units currently on backorder for this variant.
def on_backorder
inventory_units.with_state("backordered").size
end
# returns true if at least one inventory unit of this variant is "on_hand"
def in_stock?
Spree::Config[:track_inventory_levels] ? on_hand > 0 : true
end
alias in_stock in_stock?
def self.additional_fields
@fields
end
def self.additional_fields=(new_fields)
@fields = new_fields
end
# returns true if this variant is allowed to be placed on a new order
def available?
Spree::Config[:track_inventory_levels] ? (Spree::Config[:allow_backorders] || self.in_stock?) : true
end
def options_text
self.option_values.sort{|ov1, ov2| ov1.option_type.id <=> ov2.option_type.id}.map { |ov| "#{ov.option_type.presentation}: #{ov.presentation}" }.to_sentence({:words_connector => ", ", :two_words_connector => ", "})
end
def gross_profit
self.cost_price.nil? ? 0 : (self.price - self.cost_price)
end
# use deleted? rather than checking the attribute directly. this
# allows extensions to override deleted? if they want to provide
# their own definition.
def deleted?
deleted_at
end
private
# Ensures a new variant takes the product master price when price is not supplied
def check_price
if self.price.nil?
raise "Must supply price for variant or master.price for product." if self == product.master
self.price = product.master.price
end
end
def touch_product
product.touch unless is_master?
end
end