forked from spree/spree
/
address.rb
133 lines (107 loc) · 3.81 KB
/
address.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
module Spree
class Address < ActiveRecord::Base
belongs_to :country
belongs_to :state
has_many :shipments
validates :firstname, :lastname, :address1, :city, :zipcode, :country, :phone, :presence => true
validate :state_validate
attr_accessible :firstname, :lastname, :address1, :address2,
:city, :zipcode, :country_id, :state_id,
:country, :state, :phone, :state_name,
:company, :alternative_phone
# Disconnected since there's no code to display error messages yet OR matching client-side validation
def phone_validate
return if phone.blank?
n_digits = phone.scan(/[0-9]/).size
valid_chars = (phone =~ /^[-+()\/\s\d]+$/)
errors.add :phone, :invalid unless (n_digits > 5 && valid_chars)
end
def self.default
country = Spree::Country.find(Spree::Config[:default_country_id]) rescue Spree::Country.first
new({:country => country}, :without_protection => true)
end
# Can modify an address if it's not been used in an order (but checkouts controller has finer control)
# def editable?
# new_record? || (shipments.empty? && checkouts.empty?)
# end
def full_name
"#{firstname} #{lastname}".strip
end
def state_text
state.nil? ? state_name : (state.abbr.blank? ? state.name : state.abbr)
end
def zone
(state && state.zone) || (country && country.zone)
end
def zones
Zone.match(self)
end
def same_as?(other)
return false if other.nil?
attributes.except('id', 'updated_at', 'created_at') == other.attributes.except('id', 'updated_at', 'created_at')
end
alias same_as same_as?
def to_s
"#{full_name}: #{address1}"
end
def clone
self.class.new(self.attributes.except('id', 'updated_at', 'created_at'))
end
def ==(other_address)
self_attrs = self.attributes
other_attrs = other_address.respond_to?(:attributes) ? other_address.attributes : {}
[self_attrs, other_attrs].each { |attrs| attrs.except!('id', 'created_at', 'updated_at', 'order_id') }
self_attrs == other_attrs
end
def empty?
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id').all? { |_, v| v.nil? }
end
# Generates an ActiveMerchant compatible address hash
def active_merchant_hash
{
:name => full_name,
:address1 => address1,
:address2 => address2,
:city => city,
:state => state_text,
:zip => zipcode,
:country => country.try(:iso),
:phone => phone
}
end
private
def state_validate
# Skip state validation without country (also required)
# or when disabled by preference
return if country.blank? || !Spree::Config[:address_requires_state]
# ensure associated state belongs to country
if state.present?
if state.country == country
self.state_name = nil #not required as we have a valid state and country combo
else
if state_name.present?
self.state = nil
else
errors.add(:state, :invalid)
end
end
end
# ensure state_name belongs to country without states, or that it matches a predefined state name/abbr
if state_name.present?
if country.states.present?
states = country.states.find_all_by_name_or_abbr(state_name)
if states.size == 1
self.state = states.first
self.state_name = nil
else
errors.add(:state, :invalid)
end
end
end
# ensure at least one state field is populated
if state.blank? && state_name.blank?
errors.add(:state, :blank)
end
end
end
end