reps_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +2 -0
  4. data/Gemfile +4 -0
  5. data/README.md +62 -0
  6. data/Rakefile +14 -0
  7. data/lib/reps_client.rb +12 -0
  8. data/lib/reps_client/client.rb +95 -0
  9. data/lib/reps_client/community.rb +23 -0
  10. data/lib/reps_client/configuration.rb +83 -0
  11. data/lib/reps_client/errors.rb +36 -0
  12. data/lib/reps_client/lead.rb +291 -0
  13. data/lib/reps_client/pick_list.rb +62 -0
  14. data/lib/reps_client/version.rb +3 -0
  15. data/reps_client.gemspec +36 -0
  16. data/spec/fixtures/faults/client_fault.xml +28 -0
  17. data/spec/fixtures/faults/invalid_enterprise_key_fault.xml +25 -0
  18. data/spec/fixtures/faults/server_fault.xml +25 -0
  19. data/spec/fixtures/get_communities/multiple_communities.xml +59 -0
  20. data/spec/fixtures/get_communities/single_community.xml +54 -0
  21. data/spec/fixtures/get_pick_lists/full_pick_lists.xml +100 -0
  22. data/spec/fixtures/get_pick_lists/single_prefix.xml +70 -0
  23. data/spec/fixtures/get_pick_lists/single_relationship_type.xml +70 -0
  24. data/spec/fixtures/get_pick_lists/single_source.xml +71 -0
  25. data/spec/fixtures/get_pick_lists/single_suffix.xml +70 -0
  26. data/spec/reps_client/client_spec.rb +217 -0
  27. data/spec/reps_client/community_spec.rb +139 -0
  28. data/spec/reps_client/configuration_spec.rb +132 -0
  29. data/spec/reps_client/errors_spec.rb +56 -0
  30. data/spec/reps_client/lead_spec.rb +906 -0
  31. data/spec/reps_client/pick_list_spec.rb +320 -0
  32. data/spec/reps_client_spec.rb +11 -0
  33. data/spec/spec_helper.rb +21 -0
  34. data/spec/support/fault_handler_shared_examples.rb +51 -0
  35. data/spec/support/lead_shared_examples.rb +33 -0
  36. data/spec/support/pick_list_shared_examples.rb +16 -0
  37. metadata +259 -0
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *~
6
+ .DS_Store
7
+ doc/*
8
+ .yardoc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ branch_name=`git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'`
2
+ rvm --create use 1.8.7@reps_client-${branch_name}
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in reps_client.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # REPS Client #
2
+
3
+ This adapter provides a simple wrapper around a SOAP client for the [MDI Achieve][mdi] REPS Leads web service.
4
+
5
+ ## Installation ##
6
+
7
+ To use this library prior to the initial release, add this to your Gemfile:
8
+
9
+ gem 'reps_client', :git => 'git@github.com:g5search/reps_client.git', :branch => 'development'
10
+
11
+ ## Basics ##
12
+
13
+ For more details on any topic, see the [RDocs][rdocs].
14
+
15
+ ### Configuration ###
16
+
17
+ Most commonly, you will only need to supply the enterprise key in order to access the service.
18
+
19
+ Configuration options can be set at the module level to automatically apply it to all client instances:
20
+
21
+ RepsClient.configure do |config|
22
+ config.enterprise_key = 'mykey'
23
+ end
24
+
25
+ client = RepsClient::Client.new
26
+
27
+ Or you can set it on each individual client instance:
28
+
29
+ client = RepsClient::Client.new(:enterprise_key => 'mykey')
30
+
31
+ ### Examples ###
32
+
33
+ To retrieve a list of communities that belong to this enterprise:
34
+
35
+ communities = client.get_communities
36
+ # => [#<RepsClient::Community address1="123 Anywhere Ln" city="Somewhere" community_id="2" name="Pine View Terrace" state="AK" zip="12345">, #<RepsClient::Community community_id="8" name="The Hills at Dale Valley">]
37
+
38
+ To retrieve a list of enumerated data types (e.g. relationship type, ad source) that are available for a particular community:
39
+
40
+ pick_lists = client.get_pick_lists(2)
41
+ # => {:prefix => [#<RepsClient::Prefix prefix_id="1" value="Mr.">, #<RepsClient::Prefix prefix_id="2" value="Ms.">],
42
+ # :suffix => [#<RepsClient::Suffix suffix_id="200" value="Jr.">, #<RepsClient::Suffix suffix_id="99" value="M.D">],
43
+ # :relationship_type => [#<RepsClient::RelationshipType relationship_type_id="42" name="Self">],
44
+ # :source => [#<RepsClient::Source source_id="99" code="WEB" description="From the community website">]}
45
+
46
+ To save a lead, which include a contact and prospect. A very simple lead might look like this:
47
+
48
+ contact = RepsClient::Contact.new(:prefix => 'Mr.',
49
+ :first_name => 'Fred',
50
+ :last_name => 'Rogers',
51
+ :email => 'misterrogers@neighborhood.com',
52
+ :relationship_to_prospect_id => 2,
53
+ :source_id => 99)
54
+ prospect = RepsClient::Prospect.new(:prefix => 'Mr.',
55
+ :first_name => 'Fred',
56
+ :last_name => 'Rogers',
57
+ :email => 'misterrogers@neighborhood.com',
58
+ :notes => 'Request for Brochure')
59
+ client.save_lead(2, contact, prospect)
60
+
61
+ [mdi]: http://mdiachieve.com
62
+ [rdocs]: http://rubydoc.info/gems/reps_client
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ namespace :doc do
9
+ require 'yard'
10
+ YARD::Rake::YardocTask.new do |task|
11
+ task.files = ['README.md', 'lib/**/*.rb']
12
+ task.options = ['--markup', 'markdown']
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ require 'reps_client/version'
2
+ require 'reps_client/configuration'
3
+
4
+ module RepsClient
5
+ extend Configuration
6
+
7
+ require 'reps_client/client'
8
+
9
+ Modelish.configure do |config|
10
+ config.ignore_unknown_properties = true
11
+ end
12
+ end
@@ -0,0 +1,95 @@
1
+ require 'savon'
2
+
3
+ require 'reps_client/community'
4
+ require 'reps_client/errors'
5
+ require 'reps_client/pick_list'
6
+ require 'reps_client/lead'
7
+
8
+ module RepsClient
9
+ # TODO: document RepsClient::Client
10
+ class Client
11
+ include CommunityMethods
12
+ include PickListMethods
13
+ include LeadMethods
14
+
15
+ # Mutators for configuration options
16
+ attr_writer *RepsClient::VALID_CONFIG_OPTIONS
17
+
18
+ # Accessors for configuration options
19
+ RepsClient::VALID_CONFIG_OPTIONS.each do |opt|
20
+ define_method(opt) { get_value(opt) }
21
+ end
22
+
23
+ # Initializes the client.
24
+ #
25
+ # @param [Hash] options
26
+ # @option options [String] :username The username for authenticating to the web service
27
+ # @option options [String] :password The password for authenticating to the web service
28
+ # @option options [String] :enterprise_key The enterprise key for authentication to the web service
29
+ # @option options [String] :endpoint The address for connecting to the web service
30
+ # @option options [String] :namespace The XML namespace to use for requests
31
+ def initialize(options={})
32
+ options.each { |k,v| self.send("#{k}=", v) if self.respond_to?("#{k}=") }
33
+ end
34
+
35
+ # The raw SOAP client to directly execute requests against the REPS service.
36
+ # Preconfigures all service-wide endpoints, namespace URLs, credentials, etc.
37
+ # This method is provided as a convenience to developers; it should rarely be
38
+ # used directly.
39
+ #
40
+ # @return [Savon::Client] the SOAP client
41
+ def soap_client
42
+ Savon::Client.new do
43
+ wsdl.endpoint = self.endpoint.to_s
44
+ wsdl.namespace = self.namespace.to_s
45
+ wsse.credentials self.username, self.password, false
46
+
47
+ # We have to override the wsse timestamp method to force UTC
48
+ # (the reps service cacks on any other timezone)
49
+ class << wsse
50
+ define_method(:timestamp, lambda { @timestamp ||= Time.now.utc.xs_datetime })
51
+ end
52
+ end
53
+ end
54
+
55
+ # Sends a SOAP request to the remote service. This method takes care of
56
+ # constructing the SOAP envelope and headers as well as common parameters
57
+ # for REPS (e.g. the enterprise key)
58
+ #
59
+ # @param [Symbol] soap_action the name of the soap action to invoke (in snake-case, e.g. ":my_soap_action")
60
+ # @param [Hash] soap_parameters the input parameters for the soap action. All symbolic keys will
61
+ # converted to strings in lowerCamelCase (e.g. :my_soap_param becomes
62
+ # 'mySoapParam'); no conversion is performed on string keys.
63
+ # @return [Savon::SOAP::Response] the response from the service
64
+ def send_soap_request(soap_action,soap_parameters={})
65
+ begin
66
+ # The service requires that the soap action be in capitalized camelcase
67
+ # (e.g. 'GetCommunities') but the rest of the XML elements need to be in
68
+ # lower camelcase (e.g. 'enterpriseKey'). So we handle the soap_action
69
+ # format ourselves and retain Gyoku's default lower camelcase translation
70
+ # for everything else
71
+ camelcase_action = Gyoku::XMLKey.create(soap_action).gsub(/^[a-z]/) { |m| m.upcase }
72
+
73
+ response = soap_client.request :wsdl, camelcase_action do
74
+ soap.element_form_default = :qualified
75
+ soap.body = {:enterprise_key => self.enterprise_key}.merge(soap_parameters)
76
+ http.headers['SOAPAction'] = %{"#{URI.join(self.namespace, camelcase_action)}"}
77
+ end
78
+ rescue Savon::SOAP::Fault => f
79
+ raise RepsClient::ServiceError.translate_fault(f)
80
+ end
81
+ end
82
+
83
+
84
+ # Retrieves an attribute value. If the attribute has not been set
85
+ # on this object, it is retrieved from the global configuration.
86
+ #
87
+ # @see RepsClient.configure
88
+ #
89
+ # @param [Symbol] attribute the name of the attribute
90
+ # @return [String] the value of the attribute
91
+ def get_value(attribute)
92
+ instance_variable_get("@#{attribute}") || RepsClient.send(attribute)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,23 @@
1
+ require 'modelish'
2
+
3
+ module RepsClient
4
+ # A community (i.e. location) as configured in the MDI REPS service.
5
+ class Community < Modelish::Base
6
+ property :community_id, :from => :community_idy, :type => Integer
7
+ property :name, :type => String
8
+ property :address1, :from => :community_address1, :type => String
9
+ property :address2, :from => :community_address2, :type => String
10
+ property :city, :from => :community_city, :type => String
11
+ property :state, :from => :community_state, :type => String
12
+ property :zip, :from => :community_zip, :type => String
13
+ end
14
+
15
+ module CommunityMethods
16
+ def get_communities
17
+ response = send_soap_request(:get_communities)
18
+ communities = response.to_hash[:get_communities_response][:get_communities_result][:diffgram][:document_element][:community]
19
+ communities ||= []
20
+ [communities].flatten.collect { |c| Community.new(c) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,83 @@
1
+ require 'configlet'
2
+
3
+ module RepsClient
4
+ # All valid configurations options
5
+ VALID_CONFIG_OPTIONS = [:endpoint, :username, :password, :namespace, :enterprise_key]
6
+
7
+ DEFAULT_ENDPOINT = 'https://repssuite.mdiachieve.com/webservices/lead.asmx?wsdl'
8
+ DEFAULT_NAMESPACE = 'http://www.mdiachieve.com/'
9
+
10
+ module Configuration
11
+ include Configlet
12
+
13
+ def self.extended(base)
14
+ # Default configuration - happens whether or not .configure is called
15
+ base.config :reps_client do
16
+ default :endpoint => DEFAULT_ENDPOINT
17
+ default :namespace => DEFAULT_NAMESPACE
18
+ end
19
+ end
20
+
21
+ # Mutators and accessors for configuration options
22
+ VALID_CONFIG_OPTIONS.each do |config_opt|
23
+ define_method(config_opt) do
24
+ self[config_opt]
25
+ end
26
+
27
+ define_method("#{config_opt}=".to_sym) do |val|
28
+ self[config_opt] = val
29
+ end
30
+ end
31
+
32
+ # Configures this module through the given +block+.
33
+ # Default configuration options will be applied unless
34
+ # they are explicitly overridden in the +block+.
35
+ #
36
+ # @yield [_self] configures service connection options
37
+ # @yieldparam [YieldstarClient] _self the object on which the configure method was called
38
+ # @example Typical case utilizing defaults
39
+ # RepsClient.configure do |config|
40
+ # config.username = 'my_user'
41
+ # config.password = 'my_pass'
42
+ # config.enterprise_key = 'my_key'
43
+ # end
44
+ # @example Overriding defaults
45
+ # RepsClient.configure do |config|
46
+ # config.username = 'my_user'
47
+ # config.password = 'my_pass'
48
+ # config.endpoint = 'http://my.endpoint.com'
49
+ # config.namespace = 'http://my.namespace.com'
50
+ # config.enterprise_key = 'my_key'
51
+ # end
52
+ # @return [RepsClient] _self
53
+ # @see VALID_CONFIG_OPTIONS
54
+ def configure
55
+ config :reps_client do
56
+ yield self
57
+ end
58
+
59
+ self
60
+ end
61
+
62
+ # Create a hash of configuration options and their
63
+ # values.
64
+ #
65
+ # @return [Hash<Symbol,Object>] the options hash
66
+ def options
67
+ VALID_CONFIG_OPTIONS.inject({}) do |option, key|
68
+ option.merge!(key => send(key))
69
+ end
70
+ end
71
+
72
+ # Resets this module's configuration.
73
+ # Configuration options will be set to default values
74
+ # if they exist; otherwise, they will be set to nil.
75
+ #
76
+ # @see VALID_CONFIG_OPTIONS
77
+ # @see DEFAULT_ENDPOINT
78
+ # @see DEFAULT_NAMESPACE
79
+ def reset
80
+ VALID_CONFIG_OPTIONS.each { |opt| self.send("#{opt}=", nil) }
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,36 @@
1
+ module RepsClient
2
+ # Represents a server-side error returned by the REPS web service.
3
+ class ServiceError < StandardError
4
+ attr_reader :code
5
+
6
+ # Creates a new error object.
7
+ #
8
+ # @param [String] message the error message. If no message is supplied, the
9
+ # object's class name will be used as the message.
10
+ # @param [String] code the error code
11
+ def initialize(message=nil, code=nil)
12
+ super(message)
13
+ @code = code
14
+ end
15
+
16
+ # Translates a soap fault into the appropriate RepsClient error.
17
+ #
18
+ # @param [Savon::SOAP::Fault] soap_error the error object raised by the soap client
19
+ # @return [RepsClient::ServiceError] the corresponding RepsClient error
20
+ def self.translate_fault(soap_error)
21
+ fault = soap_error.to_hash[:fault]
22
+
23
+ # set up defaults
24
+ error_class = RepsClient::ServiceError
25
+
26
+ if fault[:faultcode] == 'InvalidEnterpriseKey'
27
+ error_class = RepsClient::InvalidEnterpriseKeyError
28
+ end
29
+
30
+ error_class.new(fault[:faultstring], fault[:faultcode])
31
+ end
32
+ end
33
+
34
+ # Represents an error in the enterprise key sent to the REPS service
35
+ class InvalidEnterpriseKeyError < ServiceError; end
36
+ end
@@ -0,0 +1,291 @@
1
+ require 'modelish'
2
+
3
+ module RepsClient
4
+ # The person who is the primary contact for a lead.
5
+ #
6
+ # Minimally, a Contact is required to have a first name,
7
+ # last name, and some means of contacting them (email, phone,
8
+ # or mailing address). All other attributes are optional.
9
+ #
10
+ # @example Creating a valid contact with an email address
11
+ # contact = RepsClient::Contact.new(:first_name => 'Alice',
12
+ # :last_name => 'Aardvark',
13
+ # :email => 'alice@aardvark.com')
14
+ #
15
+ # @example Creating a valid contact with a phone number
16
+ # contact = RepsClient::Contact.new(:first_name => 'Bob',
17
+ # :last_name => 'Builder',
18
+ # :phone => '5551234567')
19
+ #
20
+ # @example Creating a valid contact with a mailing address
21
+ # contact = RepsClient::Contact.new(:first_name => 'Charleston',
22
+ # :last_name => 'Chew',
23
+ # :address1 => '123 Gumdrop Ct',
24
+ # :city => 'Candyland',
25
+ # :state => 'CA',
26
+ # :zip_code => '12345')
27
+ class Contact < Modelish::Base
28
+ # @attribute [rw]
29
+ # @return [String] the contact's salutation (e.g. "Mr.", "Ms.", "Dr.", etc.)
30
+ # @see RepsClient::PickListMethods#get_pick_lists
31
+ property :prefix, :type => String, :max_length => 30
32
+
33
+ # @attribute [rw]
34
+ # @return [String] the contact's first name
35
+ # @note This attribute is required on initialization.
36
+ property :first_name, :type => String, :required => true, :max_length => 30
37
+
38
+ # @attribute [rw]
39
+ # @return [String] the contact's middle name or initial
40
+ property :middle_name, :type => String, :max_length => 30
41
+
42
+ # @attribute [rw]
43
+ # @return [String] the contact's last name
44
+ # @note This attribute is required on initialization.
45
+ property :last_name, :type => String, :required => true, :max_length => 30
46
+
47
+ # @attribute [rw]
48
+ # @return [String] the contact's name suffix (e.g. 'Jr.', 'M.D.', etc.)
49
+ # @see RepsClient::PickListMethods#get_pick_lists
50
+
51
+ property :suffix, :type => String, :max_length => 30
52
+
53
+ # @attribute [rw]
54
+ # @return [String] the first line of the contact's street address
55
+ # @note This attribute is only required when there is no phone or email.
56
+ property :address1, :type => String, :max_length => 100
57
+
58
+ # @attribute [rw]
59
+ # @return [String] the second line of the contact's street address
60
+ property :address2, :type => String, :max_length => 100
61
+
62
+ # @attribute [rw]
63
+ # @return [String] the city for the contact's mailing address
64
+ property :city, :type => String, :max_length => 50
65
+
66
+ # @attribute [rw]
67
+ # @return [String] the state code for the contact's mailing address
68
+ property :state, :type => String, :max_length => 2
69
+
70
+ # @attribute [rw]
71
+ # @return [String] the zip code for the contact's mailing address
72
+ property :zip_code, :type => String, :max_length => 10
73
+
74
+ # @attribute [rw]
75
+ # @return [String] the country from the contact's mailing address
76
+ property :country, :type => String
77
+
78
+ # @attribute [rw]
79
+ # @return [String] the contact's phone number
80
+ property :phone, :type => String, :max_length => 20
81
+
82
+ # @attribute [rw]
83
+ # @return [String] the contact's phone number extension
84
+ property :phone_extension, :type => String, :max_length => 5
85
+
86
+ # @attribute [rw]
87
+ # @return [String] the contact's email address
88
+ property :email, :type => String, :max_length => 100
89
+
90
+ # @attribute [rw]
91
+ # @return [int] the relationship type id describing the contact's relationship to the prospect
92
+ # @note The relationship type is determined based on the contact's answer to the question 'What
93
+ # is your relationship to the prospect?' For instance, if a contact was acting on behalf of their
94
+ # mother, the relationship type name might be 'Child'. Valid relationship types are available from
95
+ # the remote service.
96
+ # @see RepsClient::PickListMethods#get_pick_lists
97
+ property :relationship_to_prospect_id, :type => Integer
98
+
99
+ # @attribute [rw]
100
+ # @return [true,false] contact opted in to mailings (defaults to false)
101
+ property :include_in_mailings, :default => false, :type => lambda { |v| !!v }
102
+
103
+ # @attribute [rw]
104
+ # @return [true,false] contact opted in to mailings (defaults to false)
105
+ property :include_in_emailings, :default => false, :type => lambda { |v| !!v }
106
+
107
+ # @attribute [rw]
108
+ # @return [int]
109
+ # @see RepsClient::PickListMethods#get_pick_lists
110
+ # @note This attribute is required on initialization.
111
+ property :source_id, :type => Integer, :required => true, :validate_type => true
112
+
113
+ # Validates attributes (including contact method), returning errors.
114
+ # @see http://rubydoc.info/gems/modelish/Modelish/Validations#validate-instance_method
115
+ def validate
116
+ errors = super
117
+ [:phone, :email, :address1, :city, :state, :zip_code].each do |k|
118
+ errors[k] ||= []
119
+ errors[k] << contact_method_error
120
+ end unless has_contact_method?
121
+ errors
122
+ end
123
+
124
+ # Validates attributes (including contact method), raising errors.
125
+ # @see http://rubydoc.info/gems/modelish/Modelish/Validations#validate%21-instance_method
126
+ def validate!
127
+ super
128
+ raise contact_method_error unless has_contact_method?
129
+ end
130
+
131
+ # Checks that at least one contact method has been supplied.
132
+ # Possible contact methods include email, phone, and mailing address.
133
+ #
134
+ # @return [true,false] true if there is at least one contact method; false otherwise
135
+ def has_contact_method?
136
+ !(phone.blank? && email.blank? && (address1.blank? || city.blank? || state.blank? || zip_code.blank?))
137
+ end
138
+
139
+ # @private
140
+ # Wrangle the model into a format that the service will accept
141
+ def to_soap_hash
142
+ hash = {:order! => []}
143
+
144
+ [:prefix, :first_name, :middle_name, :last_name, :suffix,
145
+ :address1, :address2, :city, :state, :zip_code, :country,
146
+ :phone, :phone_extension, :email, :relationship_to_prospect_id,
147
+ :include_in_mailings, :include_in_emailings, :source_id].each do |prop|
148
+ val = self.send(prop)
149
+
150
+ unless val.nil?
151
+ key = prop == :source_id ? 'SourceIDY' : prop.to_s.camelcase
152
+ hash[key] = val
153
+ hash[:order!] << key
154
+ end
155
+ end
156
+
157
+ hash
158
+ end
159
+
160
+ private
161
+ def contact_method_error
162
+ ArgumentError.new('Must have one or more of the following: phone, email, or mailing address.')
163
+ end
164
+ end
165
+
166
+ # The person on whose behalf the lead was submitted; the prospective resident.
167
+ class Prospect < Modelish::Base
168
+ # @attribute [rw]
169
+ # @return [String] the prospect's salutation (e.g. 'Mr.', 'Ms.', 'Dr.', etc.)
170
+ # @see RepsClient::PickListMethods#get_pick_lists
171
+ property :prefix, :type => String, :max_length => 30
172
+
173
+ # @attribute [rw]
174
+ # @return [String] the prospect's first name
175
+ property :first_name, :type => String, :max_length => 30
176
+
177
+ # @attribute [rw]
178
+ # @return [String] the prospect's middle name
179
+ property :middle_name, :type => String, :max_length => 30
180
+
181
+ # @attribute [rw]
182
+ # @return [String] the prospect's last name
183
+ property :last_name, :type => String, :max_length => 30
184
+
185
+ # @attribute [rw]
186
+ # @return [String] the prospect's name suffix (e.g. 'Jr.', 'M.D.', etc.)
187
+ # @see RepsClient::PickListMethods#get_pick_lists
188
+ property :suffix, :type => String, :max_length => 30
189
+
190
+ # @attribute [rw]
191
+ # @return [String] the prospect's nickname
192
+ property :nickname, :type => String, :max_length => 30
193
+
194
+ # @attribute [rw]
195
+ # @return [String] the first line of the prospect's street address
196
+ property :address1, :type => String, :max_length => 100
197
+
198
+ # @attribute [rw]
199
+ # @return [String] the second line of the prospect's street address
200
+ property :address2, :type => String, :max_length => 100
201
+
202
+ # @attribute [rw]
203
+ # @return [String] the city for the prospect's mailing address
204
+ property :city, :type => String, :max_length => 50
205
+
206
+ # @attribute [rw]
207
+ # @return [String] the state code for the prospect's mailing address
208
+ property :state, :type => String, :max_length => 2
209
+
210
+ # @attribute [rw]
211
+ # @return [String] the zip code for the prospect's mailing address
212
+ property :zip_code, :type => String, :max_length => 10
213
+
214
+ # @attribute [rw]
215
+ # @return [String] the country for the prospect's mailing address
216
+ property :country, :type => String
217
+
218
+ # @attribute [rw]
219
+ # @return [String] the prospect's phone number
220
+ property :phone, :type => String, :max_length => 20
221
+
222
+ # @attribute [rw]
223
+ # @return [String] the prospect's phone extension
224
+ property :phone_extension, :type => String, :max_length => 5
225
+
226
+ # @attribute [rw]
227
+ # @return [String] the prospect's email address
228
+ property :email, :type => String, :max_length => 100
229
+
230
+ # @attribute [rw]
231
+ # @return [String] notes on the prospect (maximum 250 characters)
232
+ property :notes, :type => String
233
+
234
+ # @attribute [rw]
235
+ # @return [true,false] true if prospect opts in to mailings, false otherwise (defaults to false)
236
+ property :include_in_mailings, :default => false, :type => lambda { |v| !!v }
237
+
238
+ # @attribute [rw]
239
+ # @return [true,false] true if prospect opts in to emailings, false otherwise (defaults to false)
240
+ property :include_in_emailings, :default => false, :type => lambda { |v| !!v }
241
+
242
+ # @private
243
+ # Wrangle the model into a format that the service will accept
244
+ def to_soap_hash
245
+ hash = { :order! => [] }
246
+
247
+ [:prefix, :first_name, :middle_name, :last_name, :suffix, :nickname,
248
+ :address1, :address2, :city, :state, :zip_code, :country,
249
+ :phone, :phone_extension, :email, :notes, :include_in_mailings,
250
+ :include_in_emailings].each do |prop|
251
+ val = self.send(prop)
252
+ unless val.nil?
253
+ key = prop.to_s.camelcase
254
+ hash[key] = val
255
+ hash[:order!] << key
256
+ end
257
+ end
258
+
259
+ hash
260
+ end
261
+ end
262
+
263
+ module LeadMethods
264
+ include Modelish::Validations
265
+
266
+ # Submit a new lead to the remote REPS service.
267
+ # Each lead must have a contact and community_id.
268
+ #
269
+ # @param [Integer] community_id the REPS ID of the community
270
+ # @param [RepsClient::Contact] contact the contact person for the lead
271
+ # @param [RepsClient::Prospect] prospect the prospective resident (if different than contact)
272
+ #
273
+ def save_lead(community_id,contact,prospect=nil)
274
+ LeadMethods.validate_required!(:community_id => community_id,
275
+ :contact => contact)
276
+ LeadMethods.validate_type!(:community_id, community_id, Integer)
277
+
278
+ contact.validate!
279
+ soap_params = {:community_id => community_id,
280
+ :new_contact => contact.to_soap_hash,
281
+ :order! => [:enterprise_key, :community_id, :new_contact] }
282
+ if prospect
283
+ prospect.validate!
284
+ soap_params[:new_prospect] = prospect.to_soap_hash
285
+ soap_params[:order!] << :new_prospect
286
+ end
287
+
288
+ send_soap_request(:save_lead, soap_params)
289
+ end
290
+ end
291
+ end