reps_client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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