amsi 1.0.0
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/.ci +125 -0
- data/.gitignore +2 -0
- data/.rspec +3 -0
- data/CHANGELOG.txt +20 -0
- data/CODEOWNERS +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +319 -0
- data/Rakefile +6 -0
- data/amsi.gemspec +32 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/config/multi_xml.rb +4 -0
- data/lib/amsi/attribute_parser/base.rb +23 -0
- data/lib/amsi/attribute_parser/boolean.rb +25 -0
- data/lib/amsi/attribute_parser/date.rb +28 -0
- data/lib/amsi/attribute_parser/date_time.rb +24 -0
- data/lib/amsi/attribute_parser/decimal.rb +15 -0
- data/lib/amsi/attribute_parser/integer.rb +15 -0
- data/lib/amsi/attribute_parser/string.rb +13 -0
- data/lib/amsi/attribute_parser.rb +45 -0
- data/lib/amsi/document_parser/base.rb +52 -0
- data/lib/amsi/document_parser/get_moveins.rb +66 -0
- data/lib/amsi/document_parser/guest_card_result.rb +31 -0
- data/lib/amsi/document_parser/leases.rb +46 -0
- data/lib/amsi/document_parser/properties.rb +103 -0
- data/lib/amsi/error/bad_request.rb +18 -0
- data/lib/amsi/error/base.rb +9 -0
- data/lib/amsi/error/invalid_response.rb +9 -0
- data/lib/amsi/error/request_fault.rb +18 -0
- data/lib/amsi/error/request_timeout.rb +9 -0
- data/lib/amsi/error/unparsable_response.rb +11 -0
- data/lib/amsi/model/address.rb +18 -0
- data/lib/amsi/model/base/attribute.rb +63 -0
- data/lib/amsi/model/base/attribute_store.rb +37 -0
- data/lib/amsi/model/base.rb +64 -0
- data/lib/amsi/model/guest_card.rb +18 -0
- data/lib/amsi/model/guest_card_result.rb +26 -0
- data/lib/amsi/model/lease.rb +63 -0
- data/lib/amsi/model/leasing_agent.rb +21 -0
- data/lib/amsi/model/manager.rb +16 -0
- data/lib/amsi/model/marketing_source.rb +21 -0
- data/lib/amsi/model/occupant.rb +32 -0
- data/lib/amsi/model/property.rb +35 -0
- data/lib/amsi/model/unit_type.rb +38 -0
- data/lib/amsi/parameter/contact_type.rb +10 -0
- data/lib/amsi/parameter/prospect.rb +19 -0
- data/lib/amsi/request/add_guest_card.rb +93 -0
- data/lib/amsi/request/base.rb +106 -0
- data/lib/amsi/request/get_moveins_by_first_marketing_source.rb +57 -0
- data/lib/amsi/request/get_property_list.rb +49 -0
- data/lib/amsi/request/get_property_residents.rb +45 -0
- data/lib/amsi/request_section/add_guest_card.rb +105 -0
- data/lib/amsi/request_section/auth.rb +22 -0
- data/lib/amsi/request_section/moveins_filter.rb +42 -0
- data/lib/amsi/request_section/property_list_filter.rb +45 -0
- data/lib/amsi/request_section/property_resident_filter.rb +32 -0
- data/lib/amsi/utils/request_fetcher.rb +37 -0
- data/lib/amsi/utils/request_generator.rb +54 -0
- data/lib/amsi/utils/snowflake_event_tracker.rb +113 -0
- data/lib/amsi/validator/base.rb +95 -0
- data/lib/amsi/validator/prospect_event_validator.rb +20 -0
- data/lib/amsi/validator/request_errors.rb +61 -0
- data/lib/amsi/validator/request_fault.rb +57 -0
- data/lib/amsi/validator/resident_event_validator.rb +20 -0
- data/lib/amsi/validator.rb +7 -0
- data/lib/amsi/version.rb +3 -0
- data/lib/amsi.rb +31 -0
- metadata +265 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ba53ba480c086ec1e01d65348931bf4708372e953204b10185ac6026705a8883
|
4
|
+
data.tar.gz: '0875be24b6bc5bcf8b7d0931cf78b1746a0e042348dd8c71b112d603cff851ba'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 328e40dde433775dc50915974d5ad85de748ffe7e5814951acf8be84a24c68776f0d6c94d9f057e0f4a4b6d004a00fbf4f577e6a509d056944fd1221047230df
|
7
|
+
data.tar.gz: 6a3dde90f9b980bf9b3277c37f7cb4ae58a0b40bf1c1e01e074252f4b64e016ac5fe1d0f74925b8c85a1b2e062ec2b7036c2506484a548211db9273a13422b20
|
data/.ci
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/usr/bin/env groovy
|
2
|
+
|
3
|
+
// https://github.com/apartmentlist/ci-shared-library
|
4
|
+
@Library('ci-shared-library')_
|
5
|
+
|
6
|
+
// Log Rotation
|
7
|
+
properties([
|
8
|
+
buildDiscarder(
|
9
|
+
logRotator(
|
10
|
+
artifactDaysToKeepStr: '',
|
11
|
+
artifactNumToKeepStr: '',
|
12
|
+
daysToKeepStr: '30',
|
13
|
+
numToKeepStr: '100'
|
14
|
+
)
|
15
|
+
)
|
16
|
+
]) //properties
|
17
|
+
|
18
|
+
// Generate unique worker labels
|
19
|
+
def k8s_label = "${UUID.randomUUID().toString()}"
|
20
|
+
|
21
|
+
pipeline {
|
22
|
+
|
23
|
+
environment {
|
24
|
+
APP_NAME = 'amsi'
|
25
|
+
APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE = "true"
|
26
|
+
CI = 'true'
|
27
|
+
CLOUDSDK_CORE_DISABLE_PROMPTS = '1'
|
28
|
+
GIT_COMMIT_SHORT = sh(script: "git rev-parse --short ${GIT_COMMIT}", returnStdout: true).trim()
|
29
|
+
GIT_MESSAGE = sh(script: "git log --format=%B -n 1 ${GIT_COMMIT}", returnStdout: true).trim()
|
30
|
+
GIT_USER = sh(script: "git log -1 --pretty=format:'%ae'", returnStdout: true).trim()
|
31
|
+
GITHUB_URL = "https://github.com"
|
32
|
+
LANG = "en_US.UTF-8"
|
33
|
+
LANGUAGE = "en_US:en"
|
34
|
+
LC_ALL = "en_US.UTF-8"
|
35
|
+
SLACK_SUCCESS_CHANNEL = "#staging-releases"
|
36
|
+
SLACK_FAILURE_CHANNEL = "#supply_log_info"
|
37
|
+
SLACK_FAILURE_MAIN = "#supply_log_error"
|
38
|
+
} // environment
|
39
|
+
|
40
|
+
agent {
|
41
|
+
kubernetes {
|
42
|
+
label k8s_label
|
43
|
+
defaultContainer 'jnlp'
|
44
|
+
yaml """
|
45
|
+
apiVersion: v1
|
46
|
+
kind: Pod
|
47
|
+
spec:
|
48
|
+
containers:
|
49
|
+
- name: ruby
|
50
|
+
image: gcr.io/alist-development/ruby:2.6.3
|
51
|
+
imagePullPolicy: Always
|
52
|
+
resources:
|
53
|
+
requests:
|
54
|
+
memory: "2048Mi"
|
55
|
+
cpu: "2"
|
56
|
+
limits:
|
57
|
+
memory: "2048Mi"
|
58
|
+
cpu: "2"
|
59
|
+
command:
|
60
|
+
- "tail"
|
61
|
+
- "-f"
|
62
|
+
- "/dev/null"
|
63
|
+
"""
|
64
|
+
} // kubernetes
|
65
|
+
} // agent
|
66
|
+
|
67
|
+
options {
|
68
|
+
timestamps()
|
69
|
+
timeout(time: 30, unit: 'MINUTES')
|
70
|
+
ansiColor('xterm')
|
71
|
+
} // options
|
72
|
+
|
73
|
+
stages {
|
74
|
+
|
75
|
+
stage('Preparation') {
|
76
|
+
parallel {
|
77
|
+
stage('Slack') {
|
78
|
+
steps {
|
79
|
+
slackPreparation()
|
80
|
+
} // steps
|
81
|
+
} // stage - Slack
|
82
|
+
stage('Build Description') {
|
83
|
+
steps {
|
84
|
+
buildDescription()
|
85
|
+
} // steps
|
86
|
+
} // stage
|
87
|
+
stage('Bundle') {
|
88
|
+
steps {
|
89
|
+
container('ruby') {
|
90
|
+
sh 'gem install bundler:2.2.29'
|
91
|
+
sh 'bundle install -j 12'
|
92
|
+
} //container
|
93
|
+
} //steps
|
94
|
+
} //stage - Bundle
|
95
|
+
} //parallel
|
96
|
+
} //stage - Preparation
|
97
|
+
|
98
|
+
stage('Tests') {
|
99
|
+
parallel {
|
100
|
+
stage('Rake & Audit') {
|
101
|
+
steps {
|
102
|
+
container('ruby') {
|
103
|
+
withEnv([
|
104
|
+
"RAILS_ENV=test",
|
105
|
+
"RACK_ENV=test"
|
106
|
+
]) {
|
107
|
+
sh 'bundle exec rspec spec'
|
108
|
+
} //withEnv
|
109
|
+
} //container
|
110
|
+
} //steps
|
111
|
+
} //stage
|
112
|
+
} //parallel
|
113
|
+
} //stage
|
114
|
+
} // stages
|
115
|
+
|
116
|
+
post {
|
117
|
+
success {
|
118
|
+
slackSuccess()
|
119
|
+
} // success
|
120
|
+
failure {
|
121
|
+
slackFailure()
|
122
|
+
} // failure
|
123
|
+
} // post
|
124
|
+
|
125
|
+
} // pipeline
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/CHANGELOG.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
* 1.0.0 Add eventing gem and track import_pms_resident and import_pms_prospect events for each occupant on GetPropertyResidents
|
2
|
+
* 0.12.0 Add lead_source_code, lead_date and lead_id to Model::Lease
|
3
|
+
* 0.11.5 Raise Amsi::Error::UnparsableResponse error when xml response can't be parsed
|
4
|
+
* 0.11.4 Fix ambiguous time zone bug
|
5
|
+
* 0.11.3 Add `<requirements>` node to guest card insertion request
|
6
|
+
* 0.11.2 Correctly handle gateway time outs
|
7
|
+
* 0.11.1 Parse faultstring more reliably during error
|
8
|
+
* 0.11.0 Add property_id to Model::GuestCard
|
9
|
+
* 0.10.0 Add initial_source_id to Model::GuestCard, rename guest_card_id to id
|
10
|
+
* 0.9.0 Made date interval params in GetMoveinsByFirstMarketingSource Dates
|
11
|
+
* 0.8.0 Added Model::GuestCard to response from GetMoveinsByFirstMarketingSource
|
12
|
+
* 0.7.0 Added GetMoveinsByFirstMarketingSource request
|
13
|
+
* 0.6.0 Removed SOCKS5 proxy request building; that is now up to clients
|
14
|
+
* 0.5.0 Added support for SOCKS5 proxy requests
|
15
|
+
* 0.4.0 Added GetPropertyList request
|
16
|
+
* 0.3.0 Added AddGuestCard request
|
17
|
+
* 0.2.5 Added bad request validator
|
18
|
+
* 0.2.4 Fixed Model::Occupant#occupant_status_code and added model specs
|
19
|
+
* 0.2.3 Tested by Tom locally against production data with 74 AMSI properties
|
20
|
+
* 0.1.0 Initial release with mocked GetPropertyResidents request
|
data/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @tcollier @heidi
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Apartment List, Inc
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,319 @@
|
|
1
|
+
# Amsi
|
2
|
+
|
3
|
+
Ruby client of AMSI Evolution Suite API
|
4
|
+
|
5
|
+
## Versions
|
6
|
+
|
7
|
+
See the [changelog](CHANGELOG.txt)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'amsi'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install amsi
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### SOAP Actions
|
28
|
+
|
29
|
+
To request an action, instantiate the appropriate request class (see below) and invoke #perform
|
30
|
+
on it. The API response will be parsed and returned as a ruby object.
|
31
|
+
|
32
|
+
#### Amsi::Request::AddGuestCard
|
33
|
+
Add a new guest card for the prospect
|
34
|
+
|
35
|
+
##### Initialization parameters
|
36
|
+
|
37
|
+
Required initializer parameters:
|
38
|
+
* `contact_type` [String] See [Amsi::Parameter::ContactType](#amsiparametercontacttype)
|
39
|
+
* `password` [String] Amsi account password
|
40
|
+
* `portfolio_name` [String] the unique identifier for the property in AMSI
|
41
|
+
* `property_id` [String] AMSI property id
|
42
|
+
* `prospect` [Amsi::Parameter::Prospect](#amsiparameterprospect)
|
43
|
+
* `user_id` [String] Amsi account username
|
44
|
+
* `web_service_url` [String] Amsi Url to the leasing.asmx resource
|
45
|
+
|
46
|
+
Optional initializer parameters:
|
47
|
+
* `appointment_date` [Date] date the prospect is going to visit the property
|
48
|
+
* `comments` [String]
|
49
|
+
* `contact_datetime` [DateTime]
|
50
|
+
* `date_needed` [Date]
|
51
|
+
* `initial_source_id` [String]
|
52
|
+
* `lease_term_desired` [Integer]
|
53
|
+
* `leasing_agent_id` [String]
|
54
|
+
* `qualified` [Boolean]
|
55
|
+
* `unit_subtype` [String]
|
56
|
+
* `unit_type` [String]
|
57
|
+
|
58
|
+
##### Response
|
59
|
+
|
60
|
+
[Amsi::Model::GuestCardResult](#amsimodelguestcardresult)
|
61
|
+
|
62
|
+
#### Amsi::Request::GetMoveinsByFirstMarketingSource
|
63
|
+
Get all leases matching the specified marketing source and within the specified
|
64
|
+
time window.
|
65
|
+
|
66
|
+
##### Initialization parameters
|
67
|
+
|
68
|
+
Required initializer parameters:
|
69
|
+
* `from_date` [Date] Beginning of date interval within which to search
|
70
|
+
* `marketing_source_code` [String] Code corresponding to the marketing source
|
71
|
+
for which to fetch move ins. Max of 3 characters according to their docs.
|
72
|
+
* `password` [String] Amsi account password
|
73
|
+
* `portfolio_name` [String] the unique identifier for the property in AMSI
|
74
|
+
* `property_id` [String] AMSI property id
|
75
|
+
* `through_date` [Date] End of date interval within which to search
|
76
|
+
* `user_id` [String] Amsi account username
|
77
|
+
* `web_service_url` [String] Amsi Url to the leasing.asmx resource
|
78
|
+
|
79
|
+
##### Response
|
80
|
+
|
81
|
+
Array<[Amsi::Model::Lease](#amsimodellease)>
|
82
|
+
|
83
|
+
#### Amsi::Request::GetPropertyList
|
84
|
+
Retrieve a list of properties and detailed information about each.
|
85
|
+
|
86
|
+
##### Initialization parameters
|
87
|
+
|
88
|
+
Required initializer parameters:
|
89
|
+
* `user_id` [String] Amsi account username
|
90
|
+
* `password` [String] Amsi account password
|
91
|
+
* `portfolio_name` [String] the unique identifier for the property in AMSI
|
92
|
+
* `web_service_url` [String] Amsi Url to the leasing.asmx resource
|
93
|
+
|
94
|
+
Optional initializer parameters and default values:
|
95
|
+
* `property_id` [String] Amsi property id (if this field is left blank, the response will
|
96
|
+
include all properties in the portfolio)
|
97
|
+
* `include_leasing_agents` [Boolean] if true, response will include leasing agents for each property returned.
|
98
|
+
* `include_marketing_sources` [Boolean] if true, response will include marketing sources for each property returned.
|
99
|
+
* `include_unit_types` [Boolean] if true, response will include unit types for each property returned.
|
100
|
+
|
101
|
+
|
102
|
+
##### Response
|
103
|
+
|
104
|
+
Array<[Amsi::Model::Property](#amsimodelproperty)>
|
105
|
+
|
106
|
+
|
107
|
+
#### Amsi::Request::GetPropertyResidents
|
108
|
+
Retrieve resident leases for a given property. Returns current leases only by default.
|
109
|
+
|
110
|
+
##### Initialization parameters
|
111
|
+
|
112
|
+
Required initializer parameters:
|
113
|
+
* `user_id` [String] Amsi account username
|
114
|
+
* `password` [String] Amsi account password
|
115
|
+
* `portfolio_name` [String] the unique identifier for the property in Amsi
|
116
|
+
* `property_id` [String] Amsi property id
|
117
|
+
* `web_service_url` [String] Amsi Url to the leasing.asmx resource
|
118
|
+
* `params` [Hash] extra configuration fields: `:start_date` [String], `:end_date` [String], `:remote_id` [String], `:billing_config` [BillingConfiguration], `:import_id` [String] and `:pmc_id` [String]
|
119
|
+
|
120
|
+
Optional initializer parameters and default values:
|
121
|
+
* `lease_status` [String] Lease status filter; defaults to current leases ("C"). Valid values: (A)pplicant, (C)urrent, (I)ntent to Transfer, (L)eased, (N)otice, (P)revious, (T)ransfer, (V)approved, (X)cancelled
|
122
|
+
* `include_marketing_source` [Boolean] if true, response will include marketing sources on each lease returned.
|
123
|
+
|
124
|
+
##### Response
|
125
|
+
|
126
|
+
Array<[Amsi::Model::Lease](#amsimodelfloorplan)>
|
127
|
+
|
128
|
+
|
129
|
+
### Parameters
|
130
|
+
|
131
|
+
#### Amsi::Parameter::ContactType
|
132
|
+
|
133
|
+
Constants for the different channels prospects can use for contacting. Available constants are:
|
134
|
+
|
135
|
+
* `INTERNET`
|
136
|
+
* `PHONE`
|
137
|
+
* `RETURN_VISIT`
|
138
|
+
* `VISIT`
|
139
|
+
|
140
|
+
#### Amsi::Parameter::Prospect
|
141
|
+
|
142
|
+
A container for prospect details.
|
143
|
+
|
144
|
+
Required initializer parameters:
|
145
|
+
* `last_name` [String]
|
146
|
+
|
147
|
+
Optional initializer parameters:
|
148
|
+
* `daytime_phone` [String]
|
149
|
+
* `email` [String]
|
150
|
+
* `first_name` [String]
|
151
|
+
|
152
|
+
|
153
|
+
### Models
|
154
|
+
|
155
|
+
#### Amsi::Model::Address
|
156
|
+
|
157
|
+
A [Amsi::Model::Property](#amsimodelproperty) has an address and a remit_to_address
|
158
|
+
|
159
|
+
* `line_1` [String] 1st line in the street address
|
160
|
+
* `line_2` [String] 2nd line in the street address
|
161
|
+
* `line_3` [String] 3rd line in the street address
|
162
|
+
* `line_4` [String] 4th line in the street address
|
163
|
+
* `city` [String] the city
|
164
|
+
* `state` [String] the state
|
165
|
+
* `zip_code` [String] the zip code
|
166
|
+
* `country` [String] the country
|
167
|
+
|
168
|
+
#### Amsi::Model::GuestCardResult
|
169
|
+
|
170
|
+
The response from [AddGuestCard](#amsirequestaddguestcard), will have the following attributes:
|
171
|
+
|
172
|
+
* `contact_sequence_number` [Integer] (alias `contact_seq_no`)
|
173
|
+
* `guest_card_id` [String] the unique identifier for the newly created guest card
|
174
|
+
* `property_id` [String]
|
175
|
+
* `status` [String] either "SUCCESS" or "FAILURE" (also has convenience method `success?`)
|
176
|
+
|
177
|
+
#### Amsi::Model::GuestCard
|
178
|
+
|
179
|
+
The response from [GetMoveinsByFirstMarketingSource](#amsirequestsgetmoveinsbyfirstmarketingsource)
|
180
|
+
is an array of `Amsi::Model::Lease` instances. Leases have `guest_card` and
|
181
|
+
`matched_guest_cards`. `guest_card` is either an Amsi::Model::GuestCard or nil
|
182
|
+
and `matched_guest_cards` is an array of Amsi::Model::GuestCards
|
183
|
+
(can be empty). Amsi::Model::GuestCards have the following attributes:
|
184
|
+
|
185
|
+
* `email` [String]
|
186
|
+
* `create_date` [DateTime] The time the guest card was created according to AMSI
|
187
|
+
* `first_name` [String] The renter's first name
|
188
|
+
* `id` [String] The ID of the guest card in AMSI
|
189
|
+
* `initial_source_id` [String] the short code for the marketing source attributed to the lease
|
190
|
+
* `last_name` [String] The renter's last name
|
191
|
+
* `property_id` [String] The unique identifier of the property that the guest card belongs to
|
192
|
+
|
193
|
+
#### Amsi::Model::Lease
|
194
|
+
|
195
|
+
The response from [GetPropertyResidents](#amsirequestgetpropertyresidents) is an array of `Amsi::Model::Lease`
|
196
|
+
instances. Each instance will have the following attributes:
|
197
|
+
|
198
|
+
* `property_id` [String]
|
199
|
+
* `building_id` [String] Building ID
|
200
|
+
* `unit_id` [String] Unit name
|
201
|
+
* `resident_id` [String] Resident ID
|
202
|
+
* `external_reference_id` [String]
|
203
|
+
* `guest_card` [[Amsi::Model::GuestCard](#amsimodelguestcard)] or nil
|
204
|
+
* `matched_guest_cards` [Array<[Amsi::Model::GuestCard](#amsimodelguestcard)>], can be []
|
205
|
+
* `occupant_status_code` [String in Amsi::Model::Lease::Status]
|
206
|
+
* `occupant_status_code_description` [String]
|
207
|
+
* `begin_date` [Date]
|
208
|
+
* `end_date` [Date]
|
209
|
+
* `application_date` [Date]
|
210
|
+
* `sign_date` [Date]
|
211
|
+
* `move_in_date` [Date]
|
212
|
+
* `rent_amount` [Integer]
|
213
|
+
* `occupants` [Array<[Amsi::Model::Occupant](#amsimodeloccupant)>]
|
214
|
+
* `lead_id` [String] Guest Card No.
|
215
|
+
* `lead_date` [DateTime] Guest first contact date
|
216
|
+
* `lead_source_code` [String] Marketing source code
|
217
|
+
|
218
|
+
#### Amsi::Model::LeasingAgent
|
219
|
+
|
220
|
+
A [Amsi::Model::Property](#amsimodelproperty) has 0 or more leasing agents
|
221
|
+
|
222
|
+
* `agent_active_flag` [String] "Y" if the agent is active, otherwise "N" (also has convenience method `active?`)
|
223
|
+
* `code` [String] the unique identifier for the agent within the property (alias of `agent_code`)
|
224
|
+
* `agent_name` [String] the leasing agent's full name (alias of `agent_name`)
|
225
|
+
* `property_id` [String] the unique ID of the property the leasing agent works at
|
226
|
+
|
227
|
+
#### Amsi::Model::Manager
|
228
|
+
|
229
|
+
A [Amsi::Model::Property](#amsimodelproperty) has a manager
|
230
|
+
|
231
|
+
* `fax` [String] the property manager's fax number
|
232
|
+
* `first_name` [String] the property manager's first name
|
233
|
+
* `last_name` [String] the property manager's last name
|
234
|
+
* `middle_name` [String] the property manager's middle name
|
235
|
+
* `phone` [String] the property manager's phone number
|
236
|
+
* `salutation` [String] the property manager's salutation, e.g. "Mrs"
|
237
|
+
|
238
|
+
#### Amsi::Model::MarketingSource
|
239
|
+
|
240
|
+
A [Amsi::Model::Property](#amsimodelproperty) has 0 or more marketing sources
|
241
|
+
|
242
|
+
* `code` [String] unique identifier within the property (alias of `source_code`)
|
243
|
+
* `description` [String] a description of the marketing source (alias of `source_desc`)
|
244
|
+
* `source_active_flag` [String] "Y" if the marketing source is active, otherwise "N" (also has convenience method `active?`)
|
245
|
+
* `property_id` [String] the unique ID of the property the marketing source belongs to
|
246
|
+
|
247
|
+
#### Amsi::Model::Occupant
|
248
|
+
|
249
|
+
One occupant of a lease. Each instance will have the following attributes:
|
250
|
+
|
251
|
+
* `property_id` [String]
|
252
|
+
* `building_id` [String] Building ID
|
253
|
+
* `unit_id` [String] Unit name
|
254
|
+
* `resident_id` [String] Resident ID
|
255
|
+
* `sequence_number` [String] Sequence number
|
256
|
+
* `first_name` [String]
|
257
|
+
* `last_name` [String]
|
258
|
+
* `phone_1` [String]
|
259
|
+
* `phone_2` [String]
|
260
|
+
* `responsible_flag` [String in ["Responsible" | "Non-Responsible"]]
|
261
|
+
* `email` [String]
|
262
|
+
|
263
|
+
#### Amsi::Model::Property
|
264
|
+
|
265
|
+
The response from [GetPropertyList](#amsirequestgetpropertylist) is an array of `Amsi::Model::Property`
|
266
|
+
instances. Each instance will have the following attributes:
|
267
|
+
|
268
|
+
* `address` [[Amsi::Model::Address](#amsimodeladdress)] the property's physical address
|
269
|
+
* `email` [String] the email address of the property (alias of `property_addr_email`)
|
270
|
+
* `id` [String] the property's unique identifier
|
271
|
+
* `leasing_agents` [Array<[Amsi::Model::LeasingAgent](#amsimodelleasingagent)>] the list of leasing agents for the property
|
272
|
+
* `live_date` [Date] the date the property went live
|
273
|
+
* `live_flag` [String] "Y" if the property is live, otherwise "N" (also has convenience method `live?`)
|
274
|
+
* `manager` [[Amsi::Model::Manager](#amsimodelmanager)] the property manager's contact info
|
275
|
+
* `marketing_sources` [Array<[Amsi::Model::MarketingSource](#amsimodelmarketingsource)>] the list of marketing sources for the property
|
276
|
+
* `name` [String] the name of the property (alias of `property_name_1`)
|
277
|
+
* `name_2` [String] an optional alternate name of the property (alias of `property_name_2`)
|
278
|
+
* `remit_to_address` [[Amsi::Model::Address](#amsimodeladdress)] the property's mailing address
|
279
|
+
* `unit_types` [Array<[Amsi::Model::UnitType](#amsimodelunittype)>] the list of unit types for the property
|
280
|
+
|
281
|
+
#### Amsi::Model::UnitType
|
282
|
+
|
283
|
+
A [Amsi::Model::Property](#amsimodelproperty) has 0 or more unit types
|
284
|
+
|
285
|
+
* `baths` [Decimal] the number of bathrooms in the unit
|
286
|
+
* `bedrooms` [Integer] the number of bedrooms in the unit
|
287
|
+
* `count` [Integer] Number of units in the property that are of this type
|
288
|
+
* `description` [String] a description of the unit type (alias of `unit_type_desc`)
|
289
|
+
* `market_rent` [Decimal] the rental price of the unit
|
290
|
+
* `minimum_security_deposit` [Decimal] the minimum security deposit needed for the unit (alias of `sec_min`)
|
291
|
+
* `month_to_month_renew` [Decimal] the month-to-month renewal amount (alias of `mtm_renew`)
|
292
|
+
* `other_renew` [Decimal] other renewal amount
|
293
|
+
* `property_id` [String] the unique ID of the property the unit is in
|
294
|
+
* `rooms` [Integer] the total number of rooms in the unit
|
295
|
+
* `sqft` [Integer] the total area of the unit (alias of `sqftg`)
|
296
|
+
* `standard_renew` [Decimal] the standard renewal amount
|
297
|
+
* `type` [String] the unique identifier within the property for this unit type (alias of `unit_type`)
|
298
|
+
|
299
|
+
|
300
|
+
## Compatibility
|
301
|
+
|
302
|
+
This gem sets global configurations on other dependent libraries, which makes it inherently *not*
|
303
|
+
thread-safe. Notably, it sets the following
|
304
|
+
|
305
|
+
* `MultiXml.parser = :ox`
|
306
|
+
|
307
|
+
If your client depends on any of these global settings, it is recommended that you do not run in
|
308
|
+
a multi-threaded environment.
|
309
|
+
|
310
|
+
|
311
|
+
## Development
|
312
|
+
|
313
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
314
|
+
|
315
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
316
|
+
|
317
|
+
## Contributing
|
318
|
+
|
319
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/apartmentlist/amsi.
|
data/Rakefile
ADDED
data/amsi.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'amsi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'amsi'
|
8
|
+
spec.version = Amsi::VERSION
|
9
|
+
spec.authors = ['Justin Richard']
|
10
|
+
spec.email = ['justin@apartmentlist.com']
|
11
|
+
|
12
|
+
spec.summary = 'Ruby client of AMSI Evolution Suite API'
|
13
|
+
spec.homepage = 'https://github.com/apartmentlist/amsi'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_runtime_dependency 'faraday', '~> 0.9'
|
21
|
+
spec.add_runtime_dependency 'multi_xml', '~> 0.5'
|
22
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.6'
|
23
|
+
spec.add_runtime_dependency 'ox', '~> 2.3'
|
24
|
+
spec.add_runtime_dependency 'tzinfo', '~> 1.2'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '>= 2'
|
27
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.3'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
30
|
+
spec.add_development_dependency 'timecop', '~> 0.8'
|
31
|
+
spec.add_development_dependency 'webmock', '~> 1.21'
|
32
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'pry'
|
5
|
+
require 'amsi'
|
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
|
data/bin/setup
ADDED
data/config/multi_xml.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'amsi/error/invalid_response'
|
2
|
+
|
3
|
+
module Amsi
|
4
|
+
class AttributeParser
|
5
|
+
# Base class for attribute parsers.
|
6
|
+
class Base
|
7
|
+
# @param value [String] the response value from AMSI
|
8
|
+
def initialize(value)
|
9
|
+
@value = value
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Object] the parsed attribute value
|
13
|
+
def parse
|
14
|
+
raise NotImplementedError,
|
15
|
+
"#{self.class.name} must implement #{__method__}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Amsi
|
4
|
+
class AttributeParser
|
5
|
+
# Parse the response value of a boolean attribute
|
6
|
+
class Boolean < Base
|
7
|
+
# Values that AMSI responds with for true
|
8
|
+
TRUE_VALUES = %w[1 true].freeze
|
9
|
+
private_constant :TRUE_VALUES
|
10
|
+
|
11
|
+
# Values that AMSI responds with for true
|
12
|
+
FALSE_VALUES = %w[0 false].freeze
|
13
|
+
private_constant :FALSE_VALUES
|
14
|
+
|
15
|
+
# @return [true|false] the parsed attribute value
|
16
|
+
# @raise [Amsi::Error::InvalidResponse] if the value doesn't parse
|
17
|
+
# into true or false
|
18
|
+
def parse
|
19
|
+
return true if TRUE_VALUES.include?(value)
|
20
|
+
return false if FALSE_VALUES.include?(value)
|
21
|
+
raise Error::InvalidResponse, "Invalid boolean response value: #{value}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Amsi
|
4
|
+
class AttributeParser
|
5
|
+
# Parse the response value of a date attribute
|
6
|
+
class Date < Base
|
7
|
+
# AMSI responds with multiple date formats. This is one format that
|
8
|
+
# Date.parse will not parse correctly, so we need special handling
|
9
|
+
FORMAT = '%m/%d/%Y'.freeze
|
10
|
+
private_constant :FORMAT
|
11
|
+
|
12
|
+
# @return [Date] the parsed attribute value
|
13
|
+
def parse
|
14
|
+
return if value == ''
|
15
|
+
if value =~ %r[/]
|
16
|
+
::Date.strptime(value, FORMAT)
|
17
|
+
else
|
18
|
+
# AMSI sometimes returns 0001-01-01 for dates, which appears to be
|
19
|
+
# their representation of a NULL value.
|
20
|
+
date = ::Date.parse(value)
|
21
|
+
date.year == 1 ? nil : date
|
22
|
+
end
|
23
|
+
rescue ArgumentError
|
24
|
+
raise Error::InvalidResponse, "Invalid date response value: #{value}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|