amsi 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|