yardi 4.0.8

Sign up to get free protection for your applications and to get access to all the features.
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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23da65dd97a13b80552415335b257aad1f1ae7f8
4
+ data.tar.gz: 75a31101f34ac6e8d129cc97aeb82b0f05710c86
5
+ SHA512:
6
+ metadata.gz: a8ee7e3f3e4edeb6a33dea96055ae771e197870df3df603e9ca90145faa10afa7497725b8fb4884d5e39b2bf61bcb79575ef3162f677990e58209e23db59aae8
7
+ data.tar.gz: b1f9f8ebde63520dcf5242153dcc37f939e63e2faa3d7b4950ac7147a70e195f54873804ed190291d427212599dc3499567dd7f5d9e0540ea64344854c693529
@@ -0,0 +1,29 @@
1
+ version: 2.1
2
+
3
+ jobs:
4
+ test:
5
+ docker:
6
+ - image: circleci/ruby:2.4.5
7
+ environment:
8
+ PG_USER: circleci
9
+
10
+ working_directory: ~/yardi
11
+
12
+ steps:
13
+ - checkout
14
+ - restore_cache:
15
+ key: dependency-cache-{{ checksum "Gemfile" }}
16
+ - run:
17
+ command: bundle install
18
+ - run:
19
+ command: bundle exec rake
20
+ - save_cache:
21
+ key: dependency-cache-{{ checksum "Gemfile" }}
22
+ paths:
23
+ - /usr/local/bundle/cache
24
+
25
+ workflows:
26
+ version: 2.1
27
+ testing:
28
+ jobs:
29
+ - test
@@ -0,0 +1,5 @@
1
+ /doc
2
+ Gemfile.lock
3
+ yardi-*.gem
4
+ # Ignore bundler config
5
+ /.bundle
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require 'spec_helper'
@@ -0,0 +1,20 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Style/MultilineMethodCallIndentation:
5
+ EnforcedStyle: indented
6
+
7
+ Style/NumericLiterals:
8
+ Enabled: false
9
+
10
+ Style/FrozenStringLiteralComment:
11
+ Enabled: false
12
+
13
+ # We prefer [] over () for % delimited Arrays such as %w and %i.
14
+ PercentLiteralDelimiters:
15
+ PreferredDelimiters:
16
+ '%i': '[]'
17
+ '%w': '[]'
18
+
19
+ Performance/Casecmp:
20
+ Enabled: false
@@ -0,0 +1 @@
1
+ * @heidi
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yardi.gemspec
4
+ gemspec
@@ -0,0 +1,212 @@
1
+ [![CircleCI](https://circleci.com/gh/apartmentlist/yardi.svg?style=svg&circle-token=f257321b5c0e4a15a49eda74aa869a09d6db2f19)](https://circleci.com/gh/apartmentlist/yardi)
2
+
3
+ # yardi
4
+ A Ruby client for v4 of Yardi's Guestcard (and soon ILS) API
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'yardi'
12
+ ```
13
+
14
+ And then re-install your application's bundle:
15
+
16
+ $ bundle install
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install yardi
21
+
22
+ ## Usage
23
+
24
+ ### Configuration
25
+
26
+ Configure the gem with your Yardi license, entity and platform:
27
+
28
+ ```ruby
29
+ Yardi.configure do |config|
30
+ # Use your web service URL below
31
+ config.license_key = ENV['LICENSE_KEY']
32
+ config.entity = 'Apartment List'
33
+ config.platform = 'SQL Server'
34
+ end
35
+ ```
36
+
37
+ ### Useful classes
38
+
39
+ #### Yardi::Credential
40
+
41
+ Yardi SOAP actions require authentication so the SOAP action classes
42
+ (see below) require a `:credential` parameter in the initializer.
43
+
44
+ ```ruby
45
+ credential = Yardi::Credential.new(
46
+ username: 'my-username',
47
+ password: 'my-password',
48
+ database: 'test_db_live',
49
+ server: '0SQL_DBtest'
50
+ )
51
+
52
+ params = {
53
+ agent: Agent.new(first_name: 'Test', last_name: 'Agent'),
54
+ credential: credential,
55
+ ... # any other required params
56
+ }
57
+ response = Yardi::Request::SomeSoapAction.new(params).perform
58
+ ```
59
+
60
+ ### SOAP Actions
61
+
62
+ To request an action, instantiate the appropriate class (see below) and invoke
63
+ `#perform` on it. The API response will be parsed and returned as a ruby object.
64
+
65
+ #### Yardi::Action::ImportYardiGuest_Login
66
+ Insert a guest card into Yardi's system.
67
+
68
+ ##### Initialization parameters
69
+
70
+ * `agent [Yardi::Parameter::Agent]`
71
+ * `credential [Yardi::Parameter::Credential]`
72
+ information needed to authenticate with Yardi
73
+ * `lead_source [String]` what Yardi calls TransactionSource
74
+ * `reason [String]` what Yardi calls Event Reasons. This is the reason for
75
+ the event, e.g. price inquiry, tour, etc.
76
+ * `property [Yardi::Parameter::Property]` the property to associate the guest
77
+ card with
78
+ * `user [Yardi::Parameter::User]` the user to associate the guest card with
79
+
80
+ #### Yardi::Request::GetResidents
81
+ Get all the residents for a given property ID.
82
+
83
+ ##### Initialization parameters
84
+
85
+ * `credential [Yardi::Parameter::Credential]` information needed to authenticate with Yardi
86
+ * `property_id [String]` the remote `YardiPropertyId`
87
+
88
+ ##### Response
89
+ An array of `Yardi::Model::Resident`s
90
+
91
+ ###### Example
92
+ ```ruby
93
+ Yardi::Request::GetResidents.new(
94
+ credential: credential, params: { property_id: 'p263656'}
95
+ ).perform
96
+
97
+ =>
98
+
99
+ [
100
+ #<Yardi::Model::Resident:0x007fe922f01d98
101
+ @email="jb007@mi6.uk",
102
+ @first_name="James",
103
+ @last_name="Bond",
104
+ @lease_id="sprng007",
105
+ @lease_lead_id="p0012007",
106
+ @move_in_date="12/23/2014",
107
+ @phones=[
108
+ {
109
+ "PhoneType" => "home",
110
+ "PhoneDescription" => "Home",
111
+ "PhoneNumber" => "(123) 456-7890"
112
+ }
113
+ ],
114
+ @status="Current",
115
+ @unit_name="A2"
116
+ >,
117
+ #<Yardi::Model::Resident:0x007fe922f01d48
118
+ @email="itsjasonbourne@cia.gov",
119
+ @first_name="Jason",
120
+ @last_name="Bourne",
121
+ @lease_id="sprng456",
122
+ @lease_lead_id="p0041571",
123
+ @move_in_date="10/13/2016",
124
+ @phones=[
125
+ {
126
+ "PhoneType" => "cell",
127
+ "PhoneDescription" => "Mobile",
128
+ "PhoneNumber" => "8507742326"
129
+ }
130
+ ],
131
+ @status="Current",
132
+ @unit_name="A3"
133
+ >
134
+ ]
135
+ ```
136
+
137
+ #### Yardi::Request::GetYardiGuestActivity
138
+
139
+ Get a list of `Yardi::Model::Prospect`s for a given Prospect at the specified property ID.
140
+
141
+ ##### Initialization parameters
142
+
143
+ * `credential [Yardi::Parameter::Credential]` information needed to authenticate with Yardi
144
+ * `params [Hash]`
145
+ * `property_id [String]`
146
+ * `prospect [Yardi::Parameter::Prospect]`
147
+
148
+ ##### Response
149
+
150
+ An array of `Yardi::Model::Prospect`s
151
+
152
+ ###### Example
153
+ ```ruby
154
+ Yardi::Request::GetYardiGuestActivity.new(
155
+ credential: credential,
156
+ params: { property_id: 'p263656', prospect: prospect }
157
+ ).perform
158
+ # => [#<Yardi::Model::Prospect>, #<Yardi::Model::Prospect>]
159
+ ```
160
+
161
+ #### Yardi::Model::Prospect
162
+
163
+ ##### Attributes
164
+
165
+ * `first_name` The `Prospect`'s first name according to Yardi's database
166
+ * `last_name` The `Prospect`'s last name according to Yardi's database
167
+ * `email` The `Prospect`'s email address according to Yardi's database
168
+ * `phones` An Array of the `Prospect`'s phone numbers, or `nil` if there are none
169
+ * `events` An Array of `Yardi::Model::Event` objects
170
+ * `prospect_id` The `Prospect` id from Yardi's database e.g. `"p00003693"`
171
+ * `tenant_id` The tenant id from Yardi's database e.g. `"t000456"`
172
+
173
+ ## Development
174
+
175
+ To install this gem onto your local machine, run `bundle exec rake install`.
176
+ To release a new version, update the version number in `version.rb`, and then
177
+ run `bundle exec rake release` to create a git tag for the version, push git
178
+ commits and tags, and push the `.gem` file to
179
+ [rubygems.org](https://rubygems.org).
180
+
181
+ ## Contributing
182
+
183
+ If you are interested in contributing to this project, please review the
184
+ [contribution guidelines](docs/contributing.md).
185
+
186
+ ## Versions
187
+ - 4.0.0 Add handling for 404 errors and move ConnectionError to be a subclass of
188
+ Yardi::Error::Base
189
+ - 3.1.2 Fix Prospect parsing to properly handle missing `Event` nodes
190
+ - 3.1.1 Fix roommate parsing to properly extract roommate data from GetResidents response
191
+ - 3.1.0 Add roommates to Resident Model and Parser
192
+ - 3.0.6 Handle Yardi connection errors
193
+ - 3.0.5 Handle missing event ids
194
+ - 3.0.4 Add GuestsNotFound Error
195
+ - 3.0.3 Handle roommates in prospect search results
196
+ - 3.0.2 Raise an error when GetResidents call returns no Residents
197
+ - 3.0.1 Handle parsing resident response when there is only one result
198
+ - 3.0.0 GetYardiGuestActivity returns an Array of Prospects
199
+ - 2.0.0 GetYardiGuestActivity uses a Prospect parameter
200
+ - 1.0.3 Fix when GetResidents call returns nil dates
201
+ - 1.0.2 Fix when GetResidents call returns a single phone number
202
+ - 1.0.1 Fix when GetResidents call returns nil phone numbers
203
+ - 1.0.0 Change response for GetYardiGuestActivity to be an array of Events instead of Tours. Also add lease dates GetResidents response.
204
+ - 0.3.0 Add GetResidents request
205
+ - 0.2.1 Handle when Yardi's response is completely empty
206
+ - 0.2.0 Insert FirstContact events as Email instead of Other
207
+ - 0.1.5 Handle missing bed/price preferences
208
+ - 0.1.4 Fix Prospect search, which requires a property ID
209
+ - 0.1.3 Fetch existing tours from Yardi
210
+ - 0.1.2 Support custom connections for use with a proxy
211
+ - 0.1.1 Handle multiple errors in the response
212
+ - 0.1.0 Initial release with guestcard insertion and response handling
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'pry'
5
+ require 'yardi'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start
@@ -0,0 +1,4 @@
1
+ require 'multi_xml'
2
+ require 'ox'
3
+
4
+ MultiXml.parser = :ox
@@ -0,0 +1,24 @@
1
+ ## Contributing
2
+
3
+ We happily accept issues and pull requests on GitHub.
4
+
5
+ Please review the design goals of this project and run the test suite before
6
+ submitting a pull request.
7
+
8
+ ### Design goals
9
+
10
+ * Only test and document the public interfaces of this gem.
11
+ * When in doubt, please adhere to RuboCop's community style guide.
12
+
13
+ ### Running tests
14
+
15
+ $ bundle exec rake
16
+
17
+ ### Submitting a pull request
18
+
19
+ 1. Fork it ( https://github.com/[my-github-username]/yardi/fork )
20
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
21
+ 3. Run the test suite
22
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
23
+ 5. Push to the branch (`git push origin my-new-feature`)
24
+ 6. Create a new Pull Request
@@ -0,0 +1,14 @@
1
+ ## Getting started
2
+
3
+ For developers interested in working on this gem please follow the
4
+ development setup instructions and the read over the
5
+ [contribution guidelines](contributing.md).
6
+
7
+ ### Development setup
8
+
9
+ * Clone the repo
10
+ * Run `bundle install`
11
+
12
+ ### Contributing
13
+
14
+ Please continue on to [the contributing documentation](contributing.md).
@@ -0,0 +1,54 @@
1
+ require_relative '../config/multi_xml.rb'
2
+
3
+ require 'yardi/error/base'
4
+ require 'yardi/error/connection_error'
5
+ require 'yardi/error/empty_response'
6
+ require 'yardi/error/error_response'
7
+ require 'yardi/error/fault_response'
8
+ require 'yardi/error/guests_not_found'
9
+ require 'yardi/error/invalid_configuration'
10
+ require 'yardi/error/missing_property'
11
+ require 'yardi/error/no_results'
12
+ require 'yardi/error/resource_not_found'
13
+ require 'yardi/error/service_unavailable'
14
+ require 'yardi/error/unparsable_response'
15
+
16
+ require 'yardi/model/event'
17
+ require 'yardi/model/guest_card_response'
18
+ require 'yardi/model/resident'
19
+
20
+ require 'yardi/parameter/agent'
21
+ require 'yardi/parameter/contact_info'
22
+ require 'yardi/parameter/credential'
23
+ require 'yardi/parameter/property'
24
+ require 'yardi/parameter/prospect'
25
+ require 'yardi/parameter/user'
26
+
27
+ require 'yardi/request/import_yardi_guest'
28
+ require 'yardi/request/get_yardi_guest_activity'
29
+ require 'yardi/request/get_residents'
30
+
31
+ require 'yardi/version'
32
+ # The toplevel Yardi module. This includes configuration information that
33
+ # we'll need to build requests. This information is the same for all of our
34
+ # clients. Client-specific configuration is specified in credential.rb.
35
+ module Yardi
36
+ CONFIG_KEYS = %i[
37
+ entity
38
+ license_key
39
+ platform
40
+ ].freeze
41
+
42
+ Config = Struct.new(*CONFIG_KEYS)
43
+ private_constant :Config
44
+
45
+ class << self
46
+ def configure(&block)
47
+ yield config
48
+ end
49
+
50
+ def config
51
+ @config ||= Config.new
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ module Yardi
2
+ module DocumentParser
3
+ end
4
+
5
+ private_constant :DocumentParser
6
+ end
@@ -0,0 +1,85 @@
1
+ require 'multi_xml'
2
+
3
+ require 'yardi/validator/error_response'
4
+ require 'yardi/validator/empty_response'
5
+ require 'yardi/validator/missing_property'
6
+ require 'yardi/validator/fault_response'
7
+
8
+ require 'yardi/document_parser'
9
+
10
+ module Yardi
11
+ module DocumentParser
12
+ # Base class for parsing Yardi responses. Subclasses must implement
13
+ # #parse_body and can optionally override #validator_classes to add more
14
+ # validation than just the default
15
+ class Base
16
+ # Order matters here. The parsing logic for an ErrorResponse relies on the
17
+ # fact that the response is not empty. The MissingProperty error looks
18
+ # similar to the unknown error response, so we want to check that first
19
+ # in order to raise a configuration error if we can.
20
+ DEFAULT_VALIDATOR_CLASSES = [
21
+ Validator::EmptyResponse,
22
+ Validator::MissingProperty,
23
+ Validator::ErrorResponse,
24
+ Validator::FaultResponse
25
+ ].freeze
26
+ private_constant :DEFAULT_VALIDATOR_CLASSES
27
+
28
+ # @param xml [String] the XML response from the request
29
+ # @return [Object] the parsed object(s) from the rsesponse
30
+ # @raise [Yardi::Error::Base] if the response is invalid
31
+ def parse(xml)
32
+ begin
33
+ parsed = MultiXml.parse(xml)
34
+ rescue MultiXml::ParseError => e
35
+ raise unparsable_xml_error(xml)
36
+ end
37
+
38
+ # This is a temporary code to be able to see what Yardi response
39
+ # looks like when envelope is empty.
40
+ if !parsed.empty? && parsed['soap:Envelope'].nil?
41
+ raise Yardi::Error::UnparsableResponse.new(xml)
42
+ end
43
+
44
+ [*DEFAULT_VALIDATOR_CLASSES, *validator_classes].each do |klass|
45
+ klass.new(action: action, parsed_response: parsed).validate!
46
+ end
47
+
48
+ parse_body(parsed['soap:Envelope']['soap:Body'])
49
+ end
50
+
51
+ private
52
+
53
+ def result_node
54
+ body["#{action}Response"]["#{action}Result"]
55
+ end
56
+
57
+ # @param body [Hash<String, Object>] the body of the XML response parsed
58
+ # into a Hash
59
+ # @return [Object] the parsed object(s) from the rsesponse
60
+ # @raise [Yardi::Error::Base] if the response is invalid
61
+ def parse_body(body)
62
+ raise NotImplementedError,
63
+ "#{self.class.name} must implement #{__method__}"
64
+ end
65
+
66
+ def action
67
+ self.class::SOAP_ACTION
68
+ end
69
+
70
+ def validator_classes
71
+ []
72
+ end
73
+
74
+ def unparsable_xml_error(response)
75
+ if !response.nil? && response =~ /Service Unavailable/
76
+ Yardi::Error::ServiceUnavailable.new(response)
77
+ elsif !response.nil? && response =~ /!DOCTYPE html/
78
+ Yardi::Error::ErrorResponse.new(response)
79
+ else
80
+ Yardi::Error::UnparsableResponse.new(response)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end