usps-imis-api 0.2.1 → 0.3.1.pre.1
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 +4 -4
- data/.rubocop.yml +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/Rakefile +12 -0
- data/Readme.md +51 -21
- data/bin/console +21 -0
- data/bin/setup +8 -0
- data/lib/usps/imis/api.rb +201 -0
- data/lib/usps/imis/config.rb +27 -0
- data/lib/usps/imis/error/api.rb +62 -0
- data/lib/usps/imis/error/mapper.rb +9 -0
- data/lib/usps/imis/mapper.rb +69 -0
- data/lib/usps/imis/panel/vsc.rb +129 -0
- data/lib/usps/imis/version.rb +7 -0
- data/lib/usps/imis.rb +41 -0
- data/spec/lib/{imis → usps/imis}/api_spec.rb +1 -1
- data/spec/lib/{imis → usps/imis}/mapper_spec.rb +3 -3
- data/spec/lib/{imis → usps/imis}/panel/vsc_spec.rb +1 -1
- data/spec/spec_helper.rb +14 -2
- data/usps-imis-api.gemspec +3 -1
- metadata +17 -16
- data/lib/imis/api.rb +0 -199
- data/lib/imis/config.rb +0 -25
- data/lib/imis/error/api.rb +0 -60
- data/lib/imis/error/mapper.rb +0 -7
- data/lib/imis/mapper.rb +0 -64
- data/lib/imis/panel/vsc.rb +0 -126
- data/lib/usps-imis-api.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13821ed6722f9e24d653b29cb2af661a6bfa47b6b38434fd862d9c01f6434056
|
4
|
+
data.tar.gz: d5265804414bde5404c920575baadd957323bb6d700a335a9c637a6cdb9855d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff6ad6b82f7bf14f6784f31c3d459080d246750a72363a78f4c6cb8aff392ef15123fe0df1cea7623d1c09c574f4e9ee39f75e34813d59c4a20852692214fd56
|
7
|
+
data.tar.gz: f73aeb715681573896f992390f8fcc5dcdeb7eaf9db21d69fc8a324b0d4fc0dcbe76a9b683c2e6b08ad76f20b3ce45b2a46793eb2311d56acc8837fe30c5a0a7
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
usps-imis-api (0.
|
4
|
+
usps-imis-api (0.3.1.pre.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -18,6 +18,7 @@ GEM
|
|
18
18
|
racc
|
19
19
|
racc (1.8.1)
|
20
20
|
rainbow (3.1.1)
|
21
|
+
rake (13.2.1)
|
21
22
|
regexp_parser (2.9.2)
|
22
23
|
rspec (3.13.0)
|
23
24
|
rspec-core (~> 3.13.0)
|
@@ -61,6 +62,7 @@ PLATFORMS
|
|
61
62
|
|
62
63
|
DEPENDENCIES
|
63
64
|
dotenv (>= 3.1.4)
|
65
|
+
rake (>= 13.2.1)
|
64
66
|
rspec (>= 3.13.0)
|
65
67
|
rubocop (>= 1.66.1)
|
66
68
|
rubocop-rspec (>= 3.1.0)
|
data/Rakefile
ADDED
data/Readme.md
CHANGED
@@ -13,7 +13,7 @@ gem install usps-imis-api
|
|
13
13
|
or add this line to your Gemfile:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'usps-imis-api', '>= 0.
|
16
|
+
gem 'usps-imis-api', '>= 0.3.0'
|
17
17
|
```
|
18
18
|
|
19
19
|
## Setup
|
@@ -22,9 +22,9 @@ Include the library, and set the configuration:
|
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
require 'dotenv/load' # Optionally load environment variables from `.env` file
|
25
|
-
require 'usps
|
25
|
+
require 'usps/imis'
|
26
26
|
|
27
|
-
Imis.configure do |config|
|
27
|
+
Usps::Imis.configure do |config|
|
28
28
|
config.environment = :development # Rails.env
|
29
29
|
config.imis_id_query_name = ENV['IMIS_ID_QUERY_NAME']
|
30
30
|
|
@@ -33,10 +33,12 @@ Imis.configure do |config|
|
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
+
When using `bin/console`, this configuration will be run by default.
|
37
|
+
|
36
38
|
Instantiate the API object:
|
37
39
|
|
38
40
|
```ruby
|
39
|
-
api = Imis::Api.new
|
41
|
+
api = Usps::Imis::Api.new
|
40
42
|
```
|
41
43
|
|
42
44
|
### Authentication
|
@@ -61,9 +63,13 @@ api.get_imis_id(certificate)
|
|
61
63
|
This will both return the ID, and store it for use with other requests. If you need to change which
|
62
64
|
member you are working with, just run this method again with the new certificate number.
|
63
65
|
|
64
|
-
|
66
|
+
You can also manually set the current ID, if you already have it for a given member
|
65
67
|
|
66
|
-
|
68
|
+
```ruby
|
69
|
+
api.imis_id = imis_id
|
70
|
+
```
|
71
|
+
|
72
|
+
### GET
|
67
73
|
|
68
74
|
To fetch member data, run e.g.:
|
69
75
|
|
@@ -73,7 +79,7 @@ api.imis_id = 31092
|
|
73
79
|
data = api.get('ABC_ASC_Individual_Demog')
|
74
80
|
```
|
75
81
|
|
76
|
-
|
82
|
+
### PUT Fields
|
77
83
|
|
78
84
|
To update member data, run e.g.:
|
79
85
|
|
@@ -81,40 +87,48 @@ To update member data, run e.g.:
|
|
81
87
|
api.imis_id = 31092
|
82
88
|
|
83
89
|
data = { 'MMS_Updated' => Time.now.strftime('%Y-%m-%dT%H:%M:%S'), 'TotMMS' => new_total }
|
84
|
-
update = api.
|
90
|
+
update = api.put_fields('ABC_ASC_Individual_Demog', data)
|
85
91
|
```
|
86
92
|
|
87
93
|
This method fetches the current data structure, and filters it down to just what you want to
|
88
94
|
update, to reduce the likelihood of update collisions or type validation failures.
|
89
95
|
|
90
|
-
###
|
96
|
+
### PUT
|
91
97
|
|
92
|
-
|
98
|
+
To update member data, run e.g.:
|
93
99
|
|
94
100
|
```ruby
|
95
|
-
api.
|
101
|
+
api.imis_id = 31092
|
102
|
+
|
103
|
+
update = api.put('ABC_ASC_Individual_Demog', complete_imis_object)
|
96
104
|
```
|
97
105
|
|
98
|
-
|
106
|
+
This method requires a complete iMIS data structure.
|
99
107
|
|
100
|
-
|
101
|
-
api.imis_id = imis_id
|
102
|
-
```
|
108
|
+
### POST
|
103
109
|
|
104
|
-
|
110
|
+
To create new member data, run e.g.:
|
105
111
|
|
106
112
|
```ruby
|
107
|
-
api.
|
113
|
+
created = api.post('ABC_ASC_Individual_Demog', complete_imis_object)
|
108
114
|
```
|
109
115
|
|
110
|
-
|
116
|
+
This method requires a complete iMIS data structure.
|
117
|
+
|
118
|
+
### DELETE
|
111
119
|
|
112
|
-
|
120
|
+
To remove member data, run e.g.:
|
113
121
|
|
114
122
|
```ruby
|
115
|
-
api.
|
123
|
+
api.imis_id = 31092
|
124
|
+
|
125
|
+
api.delete('ABC_ASC_Individual_Demog')
|
116
126
|
```
|
117
127
|
|
128
|
+
This returns a blank string on success.
|
129
|
+
|
130
|
+
### QUERY
|
131
|
+
|
118
132
|
Run an IQA Query
|
119
133
|
|
120
134
|
`query_params` is a hash of shape: `{ param_name => param_value }`
|
@@ -148,7 +162,7 @@ For supported panels (usually, business objects with composite identity keys), y
|
|
148
162
|
with them in the same general way:
|
149
163
|
|
150
164
|
```ruby
|
151
|
-
vsc = Imis::Panel::Vsc.new
|
165
|
+
vsc = Usps::Imis::Panel::Vsc.new
|
152
166
|
|
153
167
|
vsc.api.imis_id = 6374
|
154
168
|
|
@@ -162,6 +176,12 @@ vsc.update(certificate: 'E136924', year: 2024, count: 43, ordinal: ordinal)
|
|
162
176
|
vsc.destroy(ordinal)
|
163
177
|
```
|
164
178
|
|
179
|
+
Panels are also accessible directly from the API object:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
api.panels.vsc.get(1417)
|
183
|
+
```
|
184
|
+
|
165
185
|
### DSL Mode
|
166
186
|
|
167
187
|
Instead of manually setting the current iMIS ID, then running individual queries, you can instead
|
@@ -177,7 +197,11 @@ api.with(31092) do
|
|
177
197
|
mapper.update(mm: 15)
|
178
198
|
|
179
199
|
update(mm: 15)
|
200
|
+
end
|
201
|
+
```
|
180
202
|
|
203
|
+
```ruby
|
204
|
+
api.with(6374) do
|
181
205
|
panels.vsc.get(1417)
|
182
206
|
end
|
183
207
|
```
|
@@ -204,6 +228,12 @@ bundle exec rubocop
|
|
204
228
|
|
205
229
|
Testing and linting are automatically run on every push.
|
206
230
|
|
231
|
+
## Development
|
232
|
+
|
233
|
+
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.
|
234
|
+
|
235
|
+
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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
236
|
+
|
207
237
|
## PHP
|
208
238
|
|
209
239
|
This same API is
|
data/bin/console
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'usps/imis'
|
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
|
+
# Configure from the environment automatically
|
11
|
+
require 'dotenv/load'
|
12
|
+
Usps::Imis.configure do |config|
|
13
|
+
config.environment = :development
|
14
|
+
config.imis_id_query_name = ENV['IMIS_ID_QUERY_NAME']
|
15
|
+
|
16
|
+
config.username = ENV['IMIS_USERNAME']
|
17
|
+
config.password = ENV['IMIS_PASSWORD']
|
18
|
+
end
|
19
|
+
|
20
|
+
require "irb"
|
21
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Usps
|
4
|
+
module Imis
|
5
|
+
class Api
|
6
|
+
AUTHENTICATION_PATH = 'Token'
|
7
|
+
API_PATH = 'api'
|
8
|
+
QUERY_PATH = 'api/Query'
|
9
|
+
PANELS = Struct.new(:vsc)
|
10
|
+
|
11
|
+
attr_reader :token, :token_expiration, :imis_id
|
12
|
+
|
13
|
+
def initialize(skip_authentication: false)
|
14
|
+
authenticate unless skip_authentication
|
15
|
+
end
|
16
|
+
|
17
|
+
# Manually set the current ID, if you already have it for a given member
|
18
|
+
#
|
19
|
+
def imis_id=(id)
|
20
|
+
@imis_id = id.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
# Convert a member's certificate number into an iMIS ID number
|
24
|
+
#
|
25
|
+
def imis_id_for(certificate)
|
26
|
+
result = query(Imis.configuration.imis_id_query_name, { certificate: certificate })
|
27
|
+
@imis_id = result['Items']['$values'][0]['ID']
|
28
|
+
end
|
29
|
+
|
30
|
+
# Run requests as DSL, with specific iMIS ID only maintained for this scope
|
31
|
+
#
|
32
|
+
# This should be used with methods that do not change the value of `imis_id`
|
33
|
+
#
|
34
|
+
def with(id, &block)
|
35
|
+
old_id = imis_id
|
36
|
+
self.imis_id = id
|
37
|
+
instance_eval(&block)
|
38
|
+
ensure
|
39
|
+
self.imis_id = old_id
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get a business object for the current member
|
43
|
+
#
|
44
|
+
def get(business_object_name, url_id: nil)
|
45
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
46
|
+
request = Net::HTTP::Get.new(uri)
|
47
|
+
result = submit(uri, authorize(request))
|
48
|
+
JSON.parse(result.body)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Update only specific fields on a business object for the current member
|
52
|
+
#
|
53
|
+
# fields - hash of shape: { field_name => new_value }
|
54
|
+
#
|
55
|
+
def put_fields(business_object_name, fields, url_id: nil)
|
56
|
+
updated = filter_fields(business_object_name, fields)
|
57
|
+
put(business_object_name, updated, url_id: url_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Update a business object for the current member
|
61
|
+
#
|
62
|
+
def put(business_object_name, body, url_id: nil)
|
63
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
64
|
+
request = Net::HTTP::Put.new(uri)
|
65
|
+
request.body = JSON.dump(body)
|
66
|
+
result = submit(uri, authorize(request))
|
67
|
+
JSON.parse(result.body)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Create a business object for the current member
|
71
|
+
#
|
72
|
+
def post(business_object_name, body, url_id: nil)
|
73
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
74
|
+
request = Net::HTTP::Post.new(uri)
|
75
|
+
request.body = JSON.dump(body)
|
76
|
+
result = submit(uri, authorize(request))
|
77
|
+
JSON.parse(result.body)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Remove a business object for the current member
|
81
|
+
#
|
82
|
+
# Returns empty string on success
|
83
|
+
#
|
84
|
+
def delete(business_object_name, url_id: nil)
|
85
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
86
|
+
request = Net::HTTP::Delete.new(uri)
|
87
|
+
result = submit(uri, authorize(request))
|
88
|
+
result.body
|
89
|
+
end
|
90
|
+
|
91
|
+
# Run an IQA Query
|
92
|
+
#
|
93
|
+
# query_name - the full path of the query in IQA, e.g. `$/_ABC/Fiander/iMIS_ID`
|
94
|
+
# query_params - hash of shape: { param_name => param_value }
|
95
|
+
#
|
96
|
+
def query(query_name, query_params = {})
|
97
|
+
query_params[:QueryName] = query_name
|
98
|
+
path = "#{QUERY_PATH}?#{query_params.to_query}"
|
99
|
+
uri = URI(File.join(imis_hostname, path))
|
100
|
+
request = Net::HTTP::Get.new(uri)
|
101
|
+
result = submit(uri, authorize(request))
|
102
|
+
JSON.parse(result.body)
|
103
|
+
end
|
104
|
+
|
105
|
+
def mapper
|
106
|
+
@mapper ||= Mapper.new(self)
|
107
|
+
end
|
108
|
+
|
109
|
+
def panels
|
110
|
+
@panels ||= PANELS.new(
|
111
|
+
Panel::Vsc.new(self)
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
def update(data)
|
116
|
+
mapper.update(data)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def client(uri)
|
122
|
+
Net::HTTP.new(uri.host, uri.port).tap do |http|
|
123
|
+
http.use_ssl = true
|
124
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def imis_hostname
|
129
|
+
Imis.configuration.hostname
|
130
|
+
end
|
131
|
+
|
132
|
+
# Authorize a request prior to submitting
|
133
|
+
#
|
134
|
+
# If the current token is missing/expired, request a new one
|
135
|
+
#
|
136
|
+
def authorize(request)
|
137
|
+
authenticate if token_expiration < Time.now
|
138
|
+
request.tap { |r| r.add_field('Authorization', "Bearer #{token}") }
|
139
|
+
end
|
140
|
+
|
141
|
+
# Construct a business object API endpoint address
|
142
|
+
#
|
143
|
+
def uri_for(business_object_name, url_id: nil)
|
144
|
+
url_id ||= imis_id
|
145
|
+
url_id = CGI.escape(url_id)
|
146
|
+
URI(File.join(imis_hostname, "#{API_PATH}/#{business_object_name}/#{url_id}"))
|
147
|
+
end
|
148
|
+
|
149
|
+
def submit(uri, request)
|
150
|
+
client(uri).request(request).tap do |result|
|
151
|
+
raise Error::Api.from(result) unless result.is_a?(Net::HTTPSuccess)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Authenticate to the iMIS API, and store the access token and expiration time
|
156
|
+
#
|
157
|
+
def authenticate
|
158
|
+
uri = URI(File.join(imis_hostname, AUTHENTICATION_PATH))
|
159
|
+
req = Net::HTTP::Post.new(uri)
|
160
|
+
authentication_data = {
|
161
|
+
grant_type: 'password',
|
162
|
+
username: Imis.configuration.username,
|
163
|
+
password: Imis.configuration.password
|
164
|
+
}
|
165
|
+
req.body = URI.encode_www_form(authentication_data)
|
166
|
+
result = submit(uri, req)
|
167
|
+
json = JSON.parse(result.body)
|
168
|
+
|
169
|
+
@token = json['access_token']
|
170
|
+
@token_expiration = Time.parse(json['.expires'])
|
171
|
+
end
|
172
|
+
|
173
|
+
# Manually assemble the matching data structure, with fields in the correct order
|
174
|
+
#
|
175
|
+
def filter_fields(business_object_name, fields)
|
176
|
+
existing = get(business_object_name)
|
177
|
+
|
178
|
+
JSON.parse(JSON.dump(existing)).tap do |updated|
|
179
|
+
# The first property is always the iMIS ID again
|
180
|
+
updated['Properties']['$values'] = [existing['Properties']['$values'][0]]
|
181
|
+
|
182
|
+
# Iterate through all existing fields
|
183
|
+
existing['Properties']['$values'].each do |value|
|
184
|
+
next unless fields.keys.include?(value['Name'])
|
185
|
+
|
186
|
+
# Strings are not wrapped in the type definition structure
|
187
|
+
new_value = fields[value['Name']]
|
188
|
+
if new_value.is_a?(String)
|
189
|
+
value['Value'] = new_value
|
190
|
+
else
|
191
|
+
value['Value']['$value'] = new_value
|
192
|
+
end
|
193
|
+
|
194
|
+
# Add the completed field with the updated value
|
195
|
+
updated['Properties']['$values'] << value
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Usps
|
4
|
+
module Imis
|
5
|
+
class Config
|
6
|
+
IMIS_ROOT_URL_PROD = 'https://portal.americasboatingclub.org'
|
7
|
+
IMIS_ROOT_URL_DEV = 'https://abcdev.imiscloud.com'
|
8
|
+
|
9
|
+
attr_accessor :environment, :imis_id_query_name, :username, :password
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
yield self if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def hostname
|
16
|
+
case environment.to_sym
|
17
|
+
when :production
|
18
|
+
IMIS_ROOT_URL_PROD
|
19
|
+
when :development
|
20
|
+
IMIS_ROOT_URL_DEV
|
21
|
+
else
|
22
|
+
raise "Unexpected API environment: #{environment}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Usps
|
4
|
+
module Imis
|
5
|
+
module Error
|
6
|
+
class Api < StandardError
|
7
|
+
attr_reader :response
|
8
|
+
attr_accessor :metadata
|
9
|
+
|
10
|
+
def self.from(response)
|
11
|
+
new('The iMIS API returned an error.', response)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(message, response, metadata = {})
|
15
|
+
super(message)
|
16
|
+
@metadata = metadata
|
17
|
+
@response = response
|
18
|
+
end
|
19
|
+
|
20
|
+
def bugsnag_meta_data
|
21
|
+
{ api: { status: status, body: body }.merge!(metadata) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def status
|
27
|
+
@status ||=
|
28
|
+
case response.code
|
29
|
+
when '400'
|
30
|
+
:bad_request
|
31
|
+
when '401'
|
32
|
+
:unauthorized # RequestVerificationToken invalid
|
33
|
+
when '404'
|
34
|
+
:not_found
|
35
|
+
when '422'
|
36
|
+
:unprocessable_entity # validation error
|
37
|
+
when /^50\d$/
|
38
|
+
:internal_server_error # error within iMIS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def response_body
|
43
|
+
@response_body ||= JSON.parse(response.body)
|
44
|
+
rescue StandardError
|
45
|
+
@response_body ||= response.body
|
46
|
+
end
|
47
|
+
|
48
|
+
def body
|
49
|
+
return response_body unless response_body.is_a?(Hash)
|
50
|
+
|
51
|
+
case response_body['error']
|
52
|
+
when 'invalid_grant'
|
53
|
+
response_body['error_description']
|
54
|
+
else
|
55
|
+
# Unknown error type: just use the raw response
|
56
|
+
response.body
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Usps
|
4
|
+
module Imis
|
5
|
+
class Mapper
|
6
|
+
FIELD_MAPPING = {
|
7
|
+
grade: %w[ABC_ASC_Individual_Demog Grade],
|
8
|
+
edpro: %w[ABC_ASC_Individual_Demog Educ_Proficiency],
|
9
|
+
edach: %w[ABC_ASC_Individual_Demog Educ_Achievement],
|
10
|
+
vessel_examiner: %w[ABC_ASC_Individual_Demog Vol_Vessel_Examiner],
|
11
|
+
mm: %w[ABC_ASC_Individual_Demog TotMMS],
|
12
|
+
mm_updated: %w[ABC_ASC_Individual_Demog MMS_Updated]
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader :api
|
16
|
+
|
17
|
+
def initialize(api = nil)
|
18
|
+
@api = api || Api.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# Update a member's data on multiple affected business objects by arbitrary field names
|
22
|
+
# Does not require knowing which business object / iMIS-specific field name to use
|
23
|
+
#
|
24
|
+
# Only available for previously-mapped fields
|
25
|
+
#
|
26
|
+
# `data` is a hash of shape { field_key => value }
|
27
|
+
#
|
28
|
+
def update(data)
|
29
|
+
updates = data.each_with_object({}) do |(field_key, value), hash|
|
30
|
+
map_update(field_key) do |business_object_name, field|
|
31
|
+
hash[business_object_name] ||= {}
|
32
|
+
hash[business_object_name][field] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
updates.map do |business_object_name, field_updates|
|
37
|
+
api.put_fields(business_object_name, field_updates)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def map_update(field_name)
|
44
|
+
if FIELD_MAPPING.key?(field_name.to_sym)
|
45
|
+
business_object_name, field = FIELD_MAPPING[field_name.to_sym]
|
46
|
+
yield(business_object_name, field)
|
47
|
+
else
|
48
|
+
missing_mapping(field_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def missing_mapping(field_name)
|
53
|
+
unless ENV['TESTING']
|
54
|
+
warn(
|
55
|
+
"Mapper does not know how to handle field \"#{field_name}\".\n\n" \
|
56
|
+
'You can use api.put_fields(business_object_name, { field_name => value }) ' \
|
57
|
+
"if you know the business object and iMIS-specific field name.\n\n"
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
raise(
|
62
|
+
Imis::Error::Mapper,
|
63
|
+
"Unrecognized field: \"#{field_name}\". " \
|
64
|
+
'Please report what data you are attempting to work with to ITCom leadership.'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|