usps-imis-api 0.1.2 → 0.2.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 +4 -4
- data/Gemfile.lock +1 -1
- data/Readme.md +35 -5
- data/lib/imis/api.rb +41 -8
- data/lib/imis/mapper.rb +23 -8
- data/lib/imis/panel/vsc.rb +126 -0
- data/lib/usps-imis-api.rb +1 -0
- data/spec/lib/imis/api_spec.rb +9 -3
- data/spec/lib/imis/mapper_spec.rb +2 -2
- data/spec/lib/imis/panel/vsc_spec.rb +38 -0
- data/usps-imis-api.gemspec +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 596057339ef96ddfa1bc884107307bae2bedfa3ef28610f1293218362daa53ad
|
4
|
+
data.tar.gz: 304f7b47a0923b08646266b71365049074235d24983abaa78fac615f0b02e5cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec4ec8cedb9966992b4e6d86b34e2a219c3f6cc28d4c01622d460e1f1f7c44fdfa8c6aa76f3aad1fb97b2e44f75366eb7060f9685b83c1bca21937c8b778414f
|
7
|
+
data.tar.gz: 412e3f664b0384330956c11eee3ce11f0c6bb77a3154d24fb4c671e34d919628fb58f7780a92b5a164cb987de8f43893308a7de9f892580a3f6478515d861b3b
|
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# USPS iMIS API for Ruby
|
2
2
|
|
3
|
-

|
3
|
+
[](https://rubygems.org/gems/usps-imis-api)
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -112,7 +112,7 @@ Update only specific fields on a business object for the current member
|
|
112
112
|
`fields` is a hash of shape: `{ field_name => new_value }`
|
113
113
|
|
114
114
|
```ruby
|
115
|
-
api.
|
115
|
+
api.put_fields(business_object_name, fields)
|
116
116
|
```
|
117
117
|
|
118
118
|
Run an IQA Query
|
@@ -129,13 +129,39 @@ For fields that have already been mapped between the ITCom database and iMIS, yo
|
|
129
129
|
Mapper class to further simplify the update interface:
|
130
130
|
|
131
131
|
```ruby
|
132
|
-
api.mapper.update(:
|
132
|
+
api.mapper.update(mm: 15)
|
133
|
+
```
|
134
|
+
|
135
|
+
For simplicity, you can also call `update` on the `Api` class directly:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
api.update(mm: 15)
|
133
139
|
```
|
134
140
|
|
135
141
|
If there is no known mapping for the requested field, the Mapper will give up, but will provide
|
136
142
|
you with the standard API call syntax, and will suggest you inform ITCom leadership of the new
|
137
143
|
mapping you need.
|
138
144
|
|
145
|
+
### Panels
|
146
|
+
|
147
|
+
For supported panels (usually, business objects with composite identity keys), you can interact
|
148
|
+
with them in the same general way:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
vsc = Imis::Panel::Vsc.new
|
152
|
+
|
153
|
+
vsc.api.imis_id = 6374
|
154
|
+
|
155
|
+
vsc.get(1417)
|
156
|
+
|
157
|
+
created = vsc.create(certificate: 'E136924', year: 2024, count: 42)
|
158
|
+
ordinal = created['Properties']['$values'][1]['Value']['$value']
|
159
|
+
|
160
|
+
vsc.update(certificate: 'E136924', year: 2024, count: 43, ordinal: ordinal)
|
161
|
+
|
162
|
+
vsc.destroy(ordinal)
|
163
|
+
```
|
164
|
+
|
139
165
|
### DSL Mode
|
140
166
|
|
141
167
|
Instead of manually setting the current iMIS ID, then running individual queries, you can instead
|
@@ -144,9 +170,13 @@ previous value.
|
|
144
170
|
|
145
171
|
```ruby
|
146
172
|
api.with(31092) do
|
147
|
-
# These
|
173
|
+
# These three requests are identical:
|
174
|
+
|
148
175
|
put('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 })
|
149
|
-
|
176
|
+
|
177
|
+
mapper.update(mm: 15)
|
178
|
+
|
179
|
+
update(mm: 15)
|
150
180
|
end
|
151
181
|
```
|
152
182
|
|
data/lib/imis/api.rb
CHANGED
@@ -39,8 +39,8 @@ module Imis
|
|
39
39
|
|
40
40
|
# Get a business object for the current member
|
41
41
|
#
|
42
|
-
def get(business_object_name)
|
43
|
-
uri = uri_for(business_object_name)
|
42
|
+
def get(business_object_name, url_id: nil)
|
43
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
44
44
|
request = Net::HTTP::Get.new(uri)
|
45
45
|
result = submit(uri, authorize(request))
|
46
46
|
JSON.parse(result.body)
|
@@ -50,15 +50,42 @@ module Imis
|
|
50
50
|
#
|
51
51
|
# fields - hash of shape: { field_name => new_value }
|
52
52
|
#
|
53
|
-
def
|
54
|
-
uri = uri_for(business_object_name)
|
55
|
-
request = Net::HTTP::Put.new(uri)
|
53
|
+
def put_fields(business_object_name, fields, url_id: nil)
|
56
54
|
updated = filter_fields(business_object_name, fields)
|
57
|
-
|
55
|
+
put(business_object_name, updated, url_id: url_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Update a business object for the current member
|
59
|
+
#
|
60
|
+
def put(business_object_name, body, url_id: nil)
|
61
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
62
|
+
request = Net::HTTP::Put.new(uri)
|
63
|
+
request.body = JSON.dump(body)
|
58
64
|
result = submit(uri, authorize(request))
|
59
65
|
JSON.parse(result.body)
|
60
66
|
end
|
61
67
|
|
68
|
+
# Create a business object for the current member
|
69
|
+
#
|
70
|
+
def post(business_object_name, body, url_id: nil)
|
71
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
72
|
+
request = Net::HTTP::Post.new(uri)
|
73
|
+
request.body = JSON.dump(body)
|
74
|
+
result = submit(uri, authorize(request))
|
75
|
+
JSON.parse(result.body)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Remove a business object for the current member
|
79
|
+
#
|
80
|
+
# Returns empty string on success
|
81
|
+
#
|
82
|
+
def delete(business_object_name, url_id: nil)
|
83
|
+
uri = uri_for(business_object_name, url_id: url_id)
|
84
|
+
request = Net::HTTP::Delete.new(uri)
|
85
|
+
result = submit(uri, authorize(request))
|
86
|
+
result.body
|
87
|
+
end
|
88
|
+
|
62
89
|
# Run an IQA Query
|
63
90
|
#
|
64
91
|
# query_name - the full path of the query in IQA, e.g. `$/_ABC/Fiander/iMIS_ID`
|
@@ -77,6 +104,10 @@ module Imis
|
|
77
104
|
@mapper ||= Mapper.new(self)
|
78
105
|
end
|
79
106
|
|
107
|
+
def update(data)
|
108
|
+
mapper.update(data)
|
109
|
+
end
|
110
|
+
|
80
111
|
private
|
81
112
|
|
82
113
|
def client(uri)
|
@@ -101,8 +132,10 @@ module Imis
|
|
101
132
|
|
102
133
|
# Construct a business object API endpoint address
|
103
134
|
#
|
104
|
-
def uri_for(business_object_name)
|
105
|
-
|
135
|
+
def uri_for(business_object_name, url_id: nil)
|
136
|
+
url_id ||= imis_id
|
137
|
+
url_id = CGI.escape(url_id)
|
138
|
+
URI(File.join(imis_hostname, "#{API_PATH}/#{business_object_name}/#{url_id}"))
|
106
139
|
end
|
107
140
|
|
108
141
|
def submit(uri, request)
|
data/lib/imis/mapper.rb
CHANGED
@@ -10,31 +10,46 @@ module Imis
|
|
10
10
|
|
11
11
|
attr_reader :api
|
12
12
|
|
13
|
-
def initialize(api)
|
14
|
-
@api = api
|
13
|
+
def initialize(api = nil)
|
14
|
+
@api = api || Api.new
|
15
15
|
end
|
16
16
|
|
17
|
-
# Update a member's data by
|
17
|
+
# Update a member's data on multiple affected business objects by arbitrary field names
|
18
18
|
# Does not require knowing which business object / iMIS-specific field name to use
|
19
19
|
#
|
20
20
|
# Only available for previously-mapped fields
|
21
21
|
#
|
22
|
-
|
22
|
+
# `data` is a hash of shape { field_key => value }
|
23
|
+
#
|
24
|
+
def update(data)
|
25
|
+
updates = data.each_with_object({}) do |(field_key, value), hash|
|
26
|
+
map_update(field_key) do |business_object_name, field|
|
27
|
+
hash[business_object_name] ||= {}
|
28
|
+
hash[business_object_name][field] = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
updates.map do |business_object_name, field_updates|
|
33
|
+
api.put_fields(business_object_name, field_updates)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def map_update(field_name)
|
23
40
|
if FIELD_MAPPING.key?(field_name.to_sym)
|
24
41
|
business_object_name, field = FIELD_MAPPING[field_name.to_sym]
|
25
|
-
|
42
|
+
yield(business_object_name, field)
|
26
43
|
else
|
27
44
|
missing_mapping(field_name)
|
28
45
|
end
|
29
46
|
end
|
30
47
|
|
31
|
-
private
|
32
|
-
|
33
48
|
def missing_mapping(field_name)
|
34
49
|
unless ENV['TESTING']
|
35
50
|
warn(
|
36
51
|
"Mapper does not know how to handle field \"#{field_name}\".\n\n" \
|
37
|
-
'You can use api.
|
52
|
+
'You can use api.put_fields(business_object_name, { field_name => value }) ' \
|
38
53
|
"if you know the business object and iMIS-specific field name.\n\n"
|
39
54
|
)
|
40
55
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Imis
|
4
|
+
module Panel
|
5
|
+
class Vsc
|
6
|
+
BUSINESS_OBJECT = 'ABC_ASC_Vessel_Safety_Checks'
|
7
|
+
|
8
|
+
attr_reader :api
|
9
|
+
|
10
|
+
def initialize(api = nil)
|
11
|
+
@api = api || Api.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(ordinal)
|
15
|
+
api.get(BUSINESS_OBJECT, url_id: "~#{api.imis_id}|#{ordinal}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(data)
|
19
|
+
api.post(BUSINESS_OBJECT, payload(data), url_id: '')
|
20
|
+
end
|
21
|
+
|
22
|
+
def update(data)
|
23
|
+
api.put(BUSINESS_OBJECT, payload(data), url_id: "~#{api.imis_id}|#{data[:ordinal]}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy(ordinal)
|
27
|
+
api.delete(BUSINESS_OBJECT, url_id: "~#{api.imis_id}|#{ordinal}")
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# rubocop:disable Metrics/MethodLength
|
33
|
+
def payload(data)
|
34
|
+
{
|
35
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericEntityData, Asi.Contracts',
|
36
|
+
'EntityTypeName' => 'ABC_ASC_Vessel_Safety_Checks',
|
37
|
+
'PrimaryParentEntityTypeName' => 'Party',
|
38
|
+
'Identity' => {
|
39
|
+
'$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
|
40
|
+
'EntityTypeName' => 'ABC_ASC_Vessel_Safety_Checks',
|
41
|
+
'IdentityElements' => {
|
42
|
+
'$type' =>
|
43
|
+
'System.Collections.ObjectModel.Collection`1[[System.String, mscorlib]], mscorlib',
|
44
|
+
'$values' => [api.imis_id]
|
45
|
+
}
|
46
|
+
},
|
47
|
+
'PrimaryParentIdentity' => {
|
48
|
+
'$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
|
49
|
+
'EntityTypeName' => 'Party',
|
50
|
+
'IdentityElements' => {
|
51
|
+
'$type' =>
|
52
|
+
'System.Collections.ObjectModel.Collection`1[[System.String, mscorlib]], mscorlib',
|
53
|
+
'$values' => [api.imis_id]
|
54
|
+
}
|
55
|
+
},
|
56
|
+
'Properties' => {
|
57
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyDataCollection, Asi.Contracts',
|
58
|
+
'$values' => [
|
59
|
+
{
|
60
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
61
|
+
'Name' => 'ID',
|
62
|
+
'Value' => api.imis_id
|
63
|
+
},
|
64
|
+
(
|
65
|
+
if data[:ordinal]
|
66
|
+
{
|
67
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
68
|
+
'Name' => 'Ordinal',
|
69
|
+
'Value' => {
|
70
|
+
'$type' => 'System.Int32',
|
71
|
+
'$value' => data[:ordinal]
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
),
|
76
|
+
{
|
77
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
78
|
+
'Name' => 'Source_System',
|
79
|
+
'Value' => 'Manual ITCom Entry'
|
80
|
+
},
|
81
|
+
{
|
82
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
83
|
+
'Name' => 'ABC_ECertificate',
|
84
|
+
'Value' => data[:certificate]
|
85
|
+
},
|
86
|
+
{
|
87
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
88
|
+
'Name' => 'Activity_Type',
|
89
|
+
'Value' => 'VSC'
|
90
|
+
},
|
91
|
+
{
|
92
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
93
|
+
'Name' => 'Description',
|
94
|
+
'Value' => 'Vessel Safety Checks'
|
95
|
+
},
|
96
|
+
{
|
97
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
98
|
+
'Name' => 'Effective_Date',
|
99
|
+
'Value' => "#{data[:year]}-12-01T00:00:00"
|
100
|
+
},
|
101
|
+
{
|
102
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
103
|
+
'Name' => 'Quantity',
|
104
|
+
'Value' => {
|
105
|
+
'$type' => 'System.Int32',
|
106
|
+
'$value' => data[:count]
|
107
|
+
}
|
108
|
+
},
|
109
|
+
{
|
110
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
111
|
+
'Name' => 'Thru_Date',
|
112
|
+
'Value' => "#{data[:year]}-12-31T00:00:00"
|
113
|
+
},
|
114
|
+
{
|
115
|
+
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
116
|
+
'Name' => 'Transaction_Date',
|
117
|
+
'Value' => Time.now.strftime('%Y-%m-%dT%H:%M:%S')
|
118
|
+
}
|
119
|
+
].compact
|
120
|
+
}
|
121
|
+
}
|
122
|
+
end
|
123
|
+
# rubocop:enable Metrics/MethodLength
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/usps-imis-api.rb
CHANGED
data/spec/lib/imis/api_spec.rb
CHANGED
@@ -15,13 +15,19 @@ describe Imis::Api do
|
|
15
15
|
before { api.imis_id = 31092 }
|
16
16
|
|
17
17
|
it 'sends an update' do
|
18
|
-
expect(api.
|
18
|
+
expect(api.put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 })).to be_a(Hash)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
describe '#with' do
|
23
|
-
it 'sends an update' do
|
24
|
-
expect(
|
23
|
+
it 'sends an update from put' do
|
24
|
+
expect(
|
25
|
+
api.with(31092) { put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 }) }
|
26
|
+
).to be_a(Hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'sends an update from update' do
|
30
|
+
expect(api.with(31092) { update(mm: 15) }.first).to be_a(Hash)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -9,11 +9,11 @@ describe Imis::Mapper do
|
|
9
9
|
before { api.imis_id = 31092 }
|
10
10
|
|
11
11
|
it 'sends a mapped update' do
|
12
|
-
expect(api.mapper.update(:
|
12
|
+
expect(api.mapper.update(mm: 15).first).to be_a(Hash)
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'raises for unmapped updates' do
|
16
|
-
expect { api.mapper.update(:
|
16
|
+
expect { api.mapper.update(something: 'anything') }.to raise_error(
|
17
17
|
Imis::Error::Mapper,
|
18
18
|
'Unrecognized field: "something". ' \
|
19
19
|
'Please report what data you are attempting to work with to ITCom leadership.'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Imis::Panel::Vsc do
|
6
|
+
let(:vsc) { described_class.new }
|
7
|
+
|
8
|
+
let(:details) do
|
9
|
+
{
|
10
|
+
certificate: 'E136924',
|
11
|
+
year: 2024,
|
12
|
+
count: 42
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
before { vsc.api.imis_id = 6374 }
|
17
|
+
|
18
|
+
describe '#get' do
|
19
|
+
it 'loads a specific object' do
|
20
|
+
expect(vsc.get(1433)).to be_a(Hash)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# rubocop:disable RSpec/ExampleLength
|
25
|
+
it 'handles new records correctly', :aggregate_failures do
|
26
|
+
new_record = vsc.create(details)
|
27
|
+
expect(new_record).to be_a(Hash)
|
28
|
+
|
29
|
+
ordinal = new_record['Properties']['$values'][1]['Value']['$value']
|
30
|
+
|
31
|
+
update_result = vsc.update(details.merge(count: 43, ordinal: ordinal))
|
32
|
+
updated = update_result['Properties']['$values'].find { |v| v['Name'] == 'Quantity' }
|
33
|
+
expect(updated['Value']['$value']).to eq(43)
|
34
|
+
|
35
|
+
expect(vsc.destroy(ordinal)).to eq('')
|
36
|
+
end
|
37
|
+
# rubocop:enable RSpec/ExampleLength
|
38
|
+
end
|
data/usps-imis-api.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: usps-imis-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Fiander
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A wrapper for the iMIS API.
|
14
14
|
email: jsfiander@gmail.com
|
@@ -30,9 +30,11 @@ files:
|
|
30
30
|
- lib/imis/error/api.rb
|
31
31
|
- lib/imis/error/mapper.rb
|
32
32
|
- lib/imis/mapper.rb
|
33
|
+
- lib/imis/panel/vsc.rb
|
33
34
|
- lib/usps-imis-api.rb
|
34
35
|
- spec/lib/imis/api_spec.rb
|
35
36
|
- spec/lib/imis/mapper_spec.rb
|
37
|
+
- spec/lib/imis/panel/vsc_spec.rb
|
36
38
|
- spec/spec_helper.rb
|
37
39
|
- usps-imis-api.gemspec
|
38
40
|
homepage: http://rubygems.org/gems/usps-imis-api
|