yardi 4.0.8

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +29 -0
  3. data/.gitignore +5 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +20 -0
  6. data/CODEOWNERS +1 -0
  7. data/CODE_OF_CONDUCT.md +13 -0
  8. data/Gemfile +4 -0
  9. data/README.md +212 -0
  10. data/Rakefile +7 -0
  11. data/bin/console +15 -0
  12. data/config/multi_xml.rb +4 -0
  13. data/docs/contributing.md +24 -0
  14. data/docs/getting_started.md +14 -0
  15. data/lib/yardi.rb +54 -0
  16. data/lib/yardi/document_parser.rb +6 -0
  17. data/lib/yardi/document_parser/base.rb +85 -0
  18. data/lib/yardi/document_parser/guest_card_import_response_object.rb +72 -0
  19. data/lib/yardi/document_parser/prospects.rb +79 -0
  20. data/lib/yardi/document_parser/residents.rb +59 -0
  21. data/lib/yardi/error/base.rb +7 -0
  22. data/lib/yardi/error/connection_error.rb +12 -0
  23. data/lib/yardi/error/empty_response.rb +11 -0
  24. data/lib/yardi/error/error_response.rb +11 -0
  25. data/lib/yardi/error/fault_response.rb +14 -0
  26. data/lib/yardi/error/guests_not_found.rb +10 -0
  27. data/lib/yardi/error/invalid_configuration.rb +11 -0
  28. data/lib/yardi/error/missing_property.rb +10 -0
  29. data/lib/yardi/error/no_results.rb +10 -0
  30. data/lib/yardi/error/resource_not_found.rb +9 -0
  31. data/lib/yardi/error/service_unavailable.rb +11 -0
  32. data/lib/yardi/error/unparsable_response.rb +11 -0
  33. data/lib/yardi/model/event.rb +18 -0
  34. data/lib/yardi/model/guest_card_response.rb +12 -0
  35. data/lib/yardi/model/prospect.rb +49 -0
  36. data/lib/yardi/model/resident.rb +36 -0
  37. data/lib/yardi/parameter/agent.rb +13 -0
  38. data/lib/yardi/parameter/contact_info.rb +13 -0
  39. data/lib/yardi/parameter/credential.rb +16 -0
  40. data/lib/yardi/parameter/property.rb +35 -0
  41. data/lib/yardi/parameter/prospect.rb +25 -0
  42. data/lib/yardi/parameter/user.rb +64 -0
  43. data/lib/yardi/request/base.rb +99 -0
  44. data/lib/yardi/request/get_residents.rb +39 -0
  45. data/lib/yardi/request/get_yardi_guest_activity.rb +85 -0
  46. data/lib/yardi/request/import_yardi_guest.rb +73 -0
  47. data/lib/yardi/request_section.rb +24 -0
  48. data/lib/yardi/request_section/authentication.rb +24 -0
  49. data/lib/yardi/request_section/lead_management.rb +148 -0
  50. data/lib/yardi/request_section/prospect.rb +27 -0
  51. data/lib/yardi/request_section/residents.rb +18 -0
  52. data/lib/yardi/utils.rb +6 -0
  53. data/lib/yardi/utils/configuration_validator.rb +17 -0
  54. data/lib/yardi/utils/phone_parser.rb +23 -0
  55. data/lib/yardi/utils/request_fetcher.rb +47 -0
  56. data/lib/yardi/utils/request_generator.rb +88 -0
  57. data/lib/yardi/validator.rb +6 -0
  58. data/lib/yardi/validator/empty_response.rb +43 -0
  59. data/lib/yardi/validator/error_response.rb +87 -0
  60. data/lib/yardi/validator/fault_response.rb +40 -0
  61. data/lib/yardi/validator/missing_property.rb +60 -0
  62. data/lib/yardi/version.rb +5 -0
  63. data/yardi.gemspec +31 -0
  64. metadata +246 -0
@@ -0,0 +1,13 @@
1
+ module Yardi
2
+ module Parameter
3
+ # Wrapper for a Yardi agent. An agent is required for guest card insertions.
4
+ class Agent
5
+ attr_reader :first_name, :last_name
6
+
7
+ def initialize(first_name:, last_name:)
8
+ @first_name = first_name
9
+ @last_name = last_name
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Yardi
2
+ module Parameter
3
+ class ContactInfo
4
+ attr_reader :email, :cell_phone, :home_phone
5
+
6
+ def initialize(email:, cell_phone: nil, home_phone: nil)
7
+ @email = email
8
+ @cell_phone= cell_phone
9
+ @home_phone = home_phone
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module Yardi
2
+ module Parameter
3
+ # Contains PMC-specific data for interfacing with Yardi's API.
4
+ class Credential
5
+ attr_reader :database, :password, :server, :username, :web_service_url
6
+
7
+ def initialize(database:, password:, server:, username:, web_service_url:)
8
+ @database = database
9
+ @password = password
10
+ @server = server
11
+ @username = username
12
+ @web_service_url = web_service_url
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module Yardi
2
+ module Parameter
3
+ class Property
4
+ attr_reader :first_contact_time,
5
+ :remote_id,
6
+ :tour_notes,
7
+ :tour_remote_id,
8
+ :tour_time
9
+
10
+ # @param first_contact_time [Time] The time of the renter's first contact
11
+ # with the property, in the property's time zone
12
+ # @param remote_id [String] The ID associated with the property in Yardi's
13
+ # system. From Apartment List, property.remote_property_id
14
+ # @param tour_notes [String] The notes to be inserted to the Comments
15
+ # node in the Appointment event.
16
+ # @param tour_remote_id [String] The ID in Yardi's system of the renter's
17
+ # tour, or nil if there is no tour for the renter at the property.
18
+ # @param tour_time [Time] The time of the renter's tour, or nil if there
19
+ # is no tour for the renter at the property.
20
+ def initialize(
21
+ remote_id:,
22
+ first_contact_time:,
23
+ tour_notes: nil,
24
+ tour_remote_id: nil,
25
+ tour_time: nil
26
+ )
27
+ @first_contact_time = first_contact_time
28
+ @remote_id = remote_id
29
+ @tour_notes = tour_notes
30
+ @tour_remote_id = tour_remote_id
31
+ @tour_time = tour_time
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # This is the parameter used for prospect search in GetYardiGuestActivity. It
2
+ # should not be confused with the Parameter::User that is used for guestcard
3
+ # insertion in ImportYardiGuest.
4
+
5
+ module Yardi
6
+ module Parameter
7
+ class Prospect
8
+ attr_reader :first_name, :last_name, :email, :phone, :yardi_prospect_id
9
+
10
+ def initialize(
11
+ first_name: nil,
12
+ last_name: nil,
13
+ email: nil,
14
+ phone: nil,
15
+ yardi_prospect_id: nil
16
+ )
17
+ @first_name = first_name
18
+ @last_name = last_name
19
+ @email = email
20
+ @phone = phone
21
+ @yardi_prospect_id = yardi_prospect_id
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ module Yardi
2
+ module Parameter
3
+ # Wraps the user-related data that we pass to Yardi.
4
+ class User
5
+ attr_reader :beds,
6
+ :contact_info,
7
+ :first_name,
8
+ :id,
9
+ :last_name,
10
+ :message,
11
+ :move_in_date,
12
+ :preference_notes,
13
+ :preferred_floorplan_id,
14
+ :preferred_unit_id,
15
+ :price
16
+
17
+ # @param beds [Integer] Number of beds the renter is interested in
18
+ # @param contact_info [Parameter::ContactInfo] Renter contact information
19
+ # @param first_name [String] Renter first name
20
+ # @param id [Integer] ID of the renter in Apartment List database, user.id
21
+ # @param last_name [String] Renter last name
22
+ # @param message [String] Message from the renter to the property
23
+ # @param move_in_date [Date] Renter move in date
24
+ # @param preference_notes [String] Notes to be inserted into Comments node
25
+ # of CustomerPreferences section of guest card
26
+ # @param preferred_floorplan_id [String] ID of Yardi floorplan the renter
27
+ # is interested in. MUST be a real floorplan on the property in Yardi's
28
+ # system. The list of floorplans can be seen with a
29
+ # UnitAvailability_Login request.
30
+ # @param preferred_unit_id [String] ID of Yardi unit the renter is
31
+ # interested in. If specified, it MUST be a real unit on the property in
32
+ # Yardi's system. The list of units can be seen with a
33
+ # UnitAvailability_Login request. This param is only required when
34
+ # inserting a tour.
35
+ # @param price [Integer] Renter budget
36
+ def initialize(
37
+ beds:,
38
+ contact_info:,
39
+ first_name:,
40
+ id:,
41
+ last_name:,
42
+ message:,
43
+ move_in_date:,
44
+ preference_notes:,
45
+ preferred_floorplan_id:,
46
+ preferred_unit_id: nil,
47
+ price:
48
+ )
49
+
50
+ @beds = beds.nil? || beds == '' ? nil : beds.to_i
51
+ @contact_info = contact_info
52
+ @first_name = first_name
53
+ @id = id
54
+ @last_name = last_name
55
+ @message = message
56
+ @move_in_date = move_in_date
57
+ @preference_notes = preference_notes
58
+ @preferred_floorplan_id = preferred_floorplan_id
59
+ @preferred_unit_id = preferred_unit_id
60
+ @price = price.to_i > 0 ? price.to_i : nil
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,99 @@
1
+ require 'yardi/request_section/authentication'
2
+ require 'yardi/utils/request_fetcher'
3
+ require 'yardi/utils/request_generator'
4
+
5
+ module Yardi
6
+ module Request
7
+ # Base class for actions that fetch and parse specific Yardi SOAP actions.
8
+ #
9
+ # When subclassing this base class, you may override the following methods
10
+ # to extend functionality:
11
+ #
12
+ # * after_initialize(params) - a hook into the initializer to give
13
+ # subclasses access to the parameters passed in. If the subclass uses
14
+ # any parameters that the base class is agnostic to, this is the place
15
+ # the set these values to instance variables
16
+ # * sections (returns Array<RequestSection>) - add additional request
17
+ # sections to the request XML document. The necessary authentication
18
+ # data will always be inserted into the XML document by this class,
19
+ # so there is no need to add it to the response of this method.
20
+ #
21
+ # Additionally, this base class provides the #soap_action method, which
22
+ # returns the CamelCased name of the SOAP action being requested. This
23
+ # method assumes that the subclass will be named the same as the action.
24
+ class Base
25
+ attr_reader :connection, :credential, :response
26
+ # @param credential [Parameter::Credential] contains the PMC-specific
27
+ # configuration information needed to make a request. We want to fail
28
+ # noisily if it's missing, so it is separate from the main params hash.
29
+ # @param params [Hash<Symbol, Object>] the parameters needed to build the
30
+ # XML request.
31
+ def initialize(credential:, params:)
32
+ @credential = credential
33
+ @connection = params[:connection] || Faraday.new
34
+ after_initialize(params)
35
+ end
36
+
37
+ # @return [Yardi::Model|Array<Yardi::Model>] the parsed response
38
+ # from Yardi
39
+ # @raise [Yardi::Error] if an error was encountered when validating
40
+ # the response
41
+ def perform
42
+ @response = xml
43
+ parser.parse(@response)
44
+ end
45
+
46
+ # @return [String] the XMl response from Yardi
47
+ def xml
48
+ Utils::RequestFetcher.new(
49
+ connection: connection,
50
+ endpoint: credential.web_service_url,
51
+ generator: generator
52
+ ).fetch
53
+ end
54
+
55
+ # This makes it easy for us to see what XML we're about to send when
56
+ # debugging requests
57
+ def generator
58
+ Utils::RequestGenerator.new(soap_action, sections, interface)
59
+ end
60
+
61
+ private
62
+
63
+ # A hook into the initializer to give subclasses access to the parameters
64
+ # passed in. If the subclass uses any parameters that the base class is
65
+ # agnostic to, this is the place the set these values to instance
66
+ # variables
67
+ def after_initialize(_params)
68
+ # No-op, this method is a call back for subclasses
69
+ end
70
+
71
+ # A hook to add additional request sections to the request XML document.
72
+ # The 'auth' section will always be inserted into the XML document by this
73
+ # class, so there is no need to add it to the response of this method.
74
+ def sections
75
+ { soap_body: soap_body_sections, xml_doc: xml_doc_sections }
76
+ end
77
+
78
+ def soap_body_sections
79
+ []
80
+ end
81
+
82
+ def xml_doc_sections
83
+ []
84
+ end
85
+
86
+ # Each request must specify its associated SOAP action.
87
+ def soap_action
88
+ raise NotImplementedError
89
+ end
90
+
91
+ # Each request must specify its associated interface.
92
+ def interface
93
+ raise NotImplementedError
94
+ end
95
+ end
96
+
97
+ private_constant :Base
98
+ end
99
+ end
@@ -0,0 +1,39 @@
1
+ require 'yardi/document_parser/residents'
2
+ require 'yardi/request_section/residents'
3
+
4
+ require_relative 'base'
5
+
6
+ module Yardi
7
+ module Request
8
+ # Get all residents for a given property ID.
9
+ class GetResidents < Base
10
+ private
11
+
12
+ attr_reader :property_id
13
+
14
+ def after_initialize(params)
15
+ @property_id = params[:property_id]
16
+ raise ArgumentError, ':property_id is required' unless property_id
17
+ end
18
+
19
+ def parser
20
+ DocumentParser::Residents.new(property_id)
21
+ end
22
+
23
+ def soap_body_sections
24
+ [
25
+ RequestSection::Authentication.new(credential),
26
+ RequestSection::Residents.new(property_id: property_id)
27
+ ]
28
+ end
29
+
30
+ def soap_action
31
+ 'GetResidents'
32
+ end
33
+
34
+ def interface
35
+ 'ItfResidentData'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,85 @@
1
+ require 'yardi/document_parser/prospects'
2
+ require 'yardi/request_section/prospect'
3
+
4
+ require_relative 'base'
5
+
6
+ module Yardi
7
+ module Request
8
+ ##
9
+ # Search Yardi for Prospects
10
+ #
11
+ # prospect = Yardi::Parameter::Prospect.new(...)
12
+ #
13
+ # request = Yardi::Request::GetYardiGuestActivity.new(
14
+ # credential: credential,
15
+ # params: { property_id: 'p263656', prospect: prospect }
16
+ # )
17
+ #
18
+ # request.perform
19
+ # # => [#<Yardi::Model::Prospect>, #<Yardi::Model::Prospect>]
20
+ #
21
+ class GetYardiGuestActivity < Base
22
+ ##
23
+ # :method: initialize
24
+ #
25
+ # Create a new instance of GetYardiGuestActivity
26
+ #
27
+ # Required parameters:
28
+ # * +property_id+ String
29
+ # * +prospect+ Yardi::Parameter::Prospect
30
+ #
31
+ # request = Yardi::Request::GetYardiGuestActivity.new(
32
+ # credential: credential,
33
+ # params: { property_id: 'p263656', prospect: prospect }
34
+ # )
35
+
36
+ ##
37
+ # :method: perform
38
+ #
39
+ # Use #perform to send the actual HTTP request
40
+ #
41
+ # request.perform
42
+ # # => [#<Yardi::Model::Prospect>, #<Yardi::Model::Prospect>]
43
+ #
44
+ # Returns an Array of Yardi::Model::Prospect records
45
+ #
46
+
47
+ ##
48
+ # Private methods
49
+ private
50
+
51
+ attr_reader :property_id, :prospect
52
+
53
+ def after_initialize(params)
54
+ @property_id = params[:property_id]
55
+ @prospect = params[:prospect]
56
+
57
+ unless property_id && prospect
58
+ raise ArgumentError, ':property_id and :prospect are required'
59
+ end
60
+ end
61
+
62
+ def parser
63
+ DocumentParser::Prospects.new
64
+ end
65
+
66
+ def soap_body_sections
67
+ [
68
+ RequestSection::Authentication.new(credential),
69
+ RequestSection::Prospect.new(
70
+ property_id: property_id,
71
+ prospect: prospect
72
+ )
73
+ ]
74
+ end
75
+
76
+ def soap_action
77
+ 'GetYardiGuestActivity_Search'
78
+ end
79
+
80
+ def interface
81
+ 'ItfILSGuestCard'
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,73 @@
1
+ require 'yardi/document_parser/guest_card_import_response_object'
2
+ require 'yardi/request_section/lead_management'
3
+
4
+ require_relative 'base'
5
+
6
+ module Yardi
7
+ module Request
8
+ # Post a GuestCard to Yardi's system
9
+ #
10
+ # Required initializer parameters:
11
+ #
12
+ # @param agent [Parameter::Agent] The agent to associate with the guestcard.
13
+ # @param credential [Parameter::Credential] PMC-specific information needed
14
+ # to post to Yardi
15
+ # @param lead_source [String] The originating source of the lead
16
+ # @param property [Parameter::Property] The property that the renter is
17
+ # expressing interest in
18
+ # @param reason [String] The reason the renter contacted the property, e.g.
19
+ # 'tour', 'price inquiry', etc.
20
+ # @param user [Parameter::User] The renter
21
+ class ImportYardiGuest < Base
22
+ private
23
+
24
+ attr_reader :agent, :lead_source, :property, :reason, :user
25
+
26
+ def after_initialize(params)
27
+ @agent = params[:agent]
28
+ @lead_source = params[:lead_source]
29
+ @property = params[:property]
30
+ @reason = params[:reason]
31
+ @user = params[:user]
32
+
33
+ check_required_params
34
+ end
35
+
36
+ def check_required_params
37
+ unless agent && lead_source && property && reason && user
38
+ message =
39
+ ':agent, :lead_source, :property, :reason, :user are all required'
40
+ raise ArgumentError, message
41
+ end
42
+ end
43
+
44
+ def parser
45
+ DocumentParser::GuestCardImportResponseObject.new
46
+ end
47
+
48
+ def soap_body_sections
49
+ [RequestSection::Authentication.new(credential)]
50
+ end
51
+
52
+ def xml_doc_sections
53
+ [
54
+ RequestSection::LeadManagement.new(
55
+ agent: agent,
56
+ lead_source: lead_source,
57
+ property: property,
58
+ reason: reason,
59
+ user: user
60
+ )
61
+ ]
62
+ end
63
+
64
+ def soap_action
65
+ 'ImportYardiGuest_Login'
66
+ end
67
+
68
+ def interface
69
+ 'ItfILSGuestCard'
70
+ end
71
+ end
72
+ end
73
+ end