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.
- checksums.yaml +7 -0
- data/.circleci/config.yml +29 -0
- data/.gitignore +5 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/CODEOWNERS +1 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/README.md +212 -0
- data/Rakefile +7 -0
- data/bin/console +15 -0
- data/config/multi_xml.rb +4 -0
- data/docs/contributing.md +24 -0
- data/docs/getting_started.md +14 -0
- data/lib/yardi.rb +54 -0
- data/lib/yardi/document_parser.rb +6 -0
- data/lib/yardi/document_parser/base.rb +85 -0
- data/lib/yardi/document_parser/guest_card_import_response_object.rb +72 -0
- data/lib/yardi/document_parser/prospects.rb +79 -0
- data/lib/yardi/document_parser/residents.rb +59 -0
- data/lib/yardi/error/base.rb +7 -0
- data/lib/yardi/error/connection_error.rb +12 -0
- data/lib/yardi/error/empty_response.rb +11 -0
- data/lib/yardi/error/error_response.rb +11 -0
- data/lib/yardi/error/fault_response.rb +14 -0
- data/lib/yardi/error/guests_not_found.rb +10 -0
- data/lib/yardi/error/invalid_configuration.rb +11 -0
- data/lib/yardi/error/missing_property.rb +10 -0
- data/lib/yardi/error/no_results.rb +10 -0
- data/lib/yardi/error/resource_not_found.rb +9 -0
- data/lib/yardi/error/service_unavailable.rb +11 -0
- data/lib/yardi/error/unparsable_response.rb +11 -0
- data/lib/yardi/model/event.rb +18 -0
- data/lib/yardi/model/guest_card_response.rb +12 -0
- data/lib/yardi/model/prospect.rb +49 -0
- data/lib/yardi/model/resident.rb +36 -0
- data/lib/yardi/parameter/agent.rb +13 -0
- data/lib/yardi/parameter/contact_info.rb +13 -0
- data/lib/yardi/parameter/credential.rb +16 -0
- data/lib/yardi/parameter/property.rb +35 -0
- data/lib/yardi/parameter/prospect.rb +25 -0
- data/lib/yardi/parameter/user.rb +64 -0
- data/lib/yardi/request/base.rb +99 -0
- data/lib/yardi/request/get_residents.rb +39 -0
- data/lib/yardi/request/get_yardi_guest_activity.rb +85 -0
- data/lib/yardi/request/import_yardi_guest.rb +73 -0
- data/lib/yardi/request_section.rb +24 -0
- data/lib/yardi/request_section/authentication.rb +24 -0
- data/lib/yardi/request_section/lead_management.rb +148 -0
- data/lib/yardi/request_section/prospect.rb +27 -0
- data/lib/yardi/request_section/residents.rb +18 -0
- data/lib/yardi/utils.rb +6 -0
- data/lib/yardi/utils/configuration_validator.rb +17 -0
- data/lib/yardi/utils/phone_parser.rb +23 -0
- data/lib/yardi/utils/request_fetcher.rb +47 -0
- data/lib/yardi/utils/request_generator.rb +88 -0
- data/lib/yardi/validator.rb +6 -0
- data/lib/yardi/validator/empty_response.rb +43 -0
- data/lib/yardi/validator/error_response.rb +87 -0
- data/lib/yardi/validator/fault_response.rb +40 -0
- data/lib/yardi/validator/missing_property.rb +60 -0
- data/lib/yardi/version.rb +5 -0
- data/yardi.gemspec +31 -0
- 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
|