usps-imis-api 1.0.0.pre.rc.4 → 1.0.0.pre.rc.7

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -3
  3. data/Gemfile.lock +61 -27
  4. data/Readme.md +168 -32
  5. data/lib/usps/imis/api.rb +27 -39
  6. data/lib/usps/imis/business_object.rb +93 -40
  7. data/lib/usps/imis/config.rb +27 -10
  8. data/lib/usps/imis/data.rb +72 -0
  9. data/lib/usps/imis/error.rb +51 -0
  10. data/lib/usps/imis/errors/api_error.rb +11 -0
  11. data/lib/usps/imis/errors/config_error.rb +11 -0
  12. data/lib/usps/imis/errors/locked_id_error.rb +15 -0
  13. data/lib/usps/imis/errors/mapper_error.rb +29 -0
  14. data/lib/usps/imis/errors/not_found_error.rb +11 -0
  15. data/lib/usps/imis/errors/panel_unimplemented_error.rb +34 -0
  16. data/lib/usps/imis/{error → errors}/response_error.rb +5 -8
  17. data/lib/usps/imis/errors/unexpected_property_type_error.rb +31 -0
  18. data/lib/usps/imis/mapper.rb +28 -20
  19. data/lib/usps/imis/mocks/business_object.rb +47 -0
  20. data/lib/usps/imis/mocks.rb +11 -0
  21. data/lib/usps/imis/panels/base_panel.rb +144 -0
  22. data/lib/usps/imis/panels/education.rb +33 -0
  23. data/lib/usps/imis/panels/vsc.rb +32 -0
  24. data/lib/usps/imis/panels.rb +25 -0
  25. data/lib/usps/imis/properties.rb +50 -0
  26. data/lib/usps/imis/query.rb +94 -0
  27. data/lib/usps/imis/requests.rb +29 -3
  28. data/lib/usps/imis/version.rb +1 -1
  29. data/lib/usps/imis.rb +16 -13
  30. data/spec/lib/usps/imis/api_spec.rb +26 -13
  31. data/spec/lib/usps/imis/business_object_spec.rb +47 -13
  32. data/spec/lib/usps/imis/config_spec.rb +30 -4
  33. data/spec/lib/usps/imis/data_spec.rb +66 -0
  34. data/spec/lib/usps/imis/{error/api_error_spec.rb → error_spec.rb} +1 -1
  35. data/spec/lib/usps/imis/{error → errors}/response_error_spec.rb +4 -4
  36. data/spec/lib/usps/imis/mapper_spec.rb +27 -3
  37. data/spec/lib/usps/imis/mocks/business_object_spec.rb +65 -0
  38. data/spec/lib/usps/imis/panels/base_panel_spec.rb +33 -0
  39. data/spec/lib/usps/imis/panels/education_spec.rb +70 -0
  40. data/spec/lib/usps/imis/{panel → panels}/vsc_spec.rb +6 -7
  41. data/spec/lib/usps/imis/properties_spec.rb +19 -0
  42. data/spec/spec_helper.rb +3 -0
  43. data/usps-imis-api.gemspec +3 -1
  44. metadata +43 -15
  45. data/lib/ext/hash.rb +0 -10
  46. data/lib/usps/imis/error/api_error.rb +0 -44
  47. data/lib/usps/imis/error/mapper_error.rb +0 -11
  48. data/lib/usps/imis/panel/base_panel.rb +0 -65
  49. data/lib/usps/imis/panel/education.rb +0 -113
  50. data/lib/usps/imis/panel/vsc.rb +0 -111
  51. data/spec/lib/usps/imis/panel/base_panel_spec.rb +0 -32
  52. data/spec/lib/usps/imis/panel/education_spec.rb +0 -55
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Mocks
6
+ # Mock data response for testing
7
+ #
8
+ class BusinessObject
9
+ attr_reader :fields
10
+
11
+ def initialize(**fields)
12
+ @fields = fields.transform_keys(&:to_s)
13
+ end
14
+
15
+ def get
16
+ Usps::Imis::Properties.build do |props|
17
+ fields.each { |name, value| props.add(name, value) }
18
+ end
19
+ end
20
+ alias read get
21
+
22
+ def get_field(name) = fields[name]
23
+ alias fetch get_field
24
+ alias [] get_field
25
+
26
+ def get_fields(*field_names) = field_names.map { fields[it] }
27
+ alias fetch_all get_fields
28
+
29
+ def put_fields(data)
30
+ Usps::Imis::Properties.build do |props|
31
+ fields.merge(data.transform_keys(&:to_s)).each { |name, value| props.add(name, value) }
32
+ end
33
+ end
34
+ alias patch put_fields
35
+
36
+ def put(data) = data
37
+ alias update put
38
+
39
+ def post(data) = data
40
+ alias create post
41
+
42
+ def delete = ''
43
+ alias destroy delete
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mocks/business_object'
4
+
5
+ module Usps
6
+ module Imis
7
+ # Namespace for all Mocks
8
+ #
9
+ module Mocks; end
10
+ end
11
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Panels
6
+ # Base class for configuring Panels
7
+ #
8
+ class BasePanel
9
+ # The parent +Api+ object
10
+ #
11
+ attr_reader :api
12
+
13
+ def initialize(api = nil, imis_id: nil)
14
+ @api = api || Api.new
15
+ @api.imis_id = imis_id if imis_id
16
+ end
17
+
18
+ # Get a specific object from the Panel
19
+ #
20
+ # If +fields+ is provided, will return only those field values
21
+ #
22
+ # @param fields [String] Field names to return
23
+ #
24
+ # @param ordinal [Integer] The ordinal identifier for the desired object
25
+ #
26
+ # @return [Usps::Imis::Data, Array<Usps::Imis::Data>] Response data from the API
27
+ #
28
+ def get(ordinal, *fields) = api.on(business_object, ordinal:).get(*fields)
29
+ alias read get
30
+
31
+ # Get a single named field from a Panel for the current member
32
+ #
33
+ # @param ordinal [Integer] The ordinal identifier for the desired object
34
+ # @param field [String] Field name to return
35
+ #
36
+ # @return Response data field value from the API
37
+ #
38
+ def get_field(ordinal, field) = api.on(business_object, ordinal:).get_field(field)
39
+ alias fetch get_field
40
+ alias [] get_field
41
+
42
+ # Get named fields from a Panel for the current member
43
+ #
44
+ # @param ordinal [Integer] The ordinal identifier for the desired object
45
+ # @param fields [Array<String>] Field names to return
46
+ #
47
+ # @return [Array] Response data from the API
48
+ #
49
+ def get_fields(ordinal, *fields) = api.on(business_object, ordinal:).get_fields(*fields)
50
+ alias fetch_all get_fields
51
+
52
+ # Update only specific fields on a Panel for the current member
53
+ #
54
+ # @param ordinal [Integer] The ordinal identifier for the desired object
55
+ # @param fields [Hash] Conforms to pattern +{ field_key => value }+
56
+ #
57
+ # @return [Usps::Imis::Data] Response data from the API
58
+ #
59
+ def put_fields(ordinal, fields) = api.on(business_object, ordinal:).put_fields(fields)
60
+ alias patch put_fields
61
+
62
+ # Update an existing object in the Panel
63
+ #
64
+ # @param data [Hash] The record data for the desired object -- including the required
65
+ # +ordinal+ identifier
66
+ #
67
+ # @return [Usps::Imis::Data] Response data from the API
68
+ #
69
+ def put(data) = api.on(business_object, ordinal: data[:ordinal]).put(payload(data))
70
+ alias update put
71
+
72
+ # Create a new object in the Panel
73
+ #
74
+ # @param data [Hash] The record data for the desired object
75
+ #
76
+ # @return [Usps::Imis::Data] Response data from the API
77
+ #
78
+ def post(data) = api.on(business_object).post(payload(data))
79
+ alias create post
80
+
81
+ # Remove a specific object from the Panel
82
+ #
83
+ # @param ordinal [Integer] The ordinal identifier for the desired object
84
+ #
85
+ # @return [true] Only on success response (i.e. blank string from the API)
86
+ #
87
+ def delete(ordinal) = api.on(business_object, ordinal:).delete
88
+ alias destroy delete
89
+
90
+ # Ruby 3.5 instance variable filter
91
+ #
92
+ def instance_variables_to_inspect = instance_variables - %i[@api]
93
+
94
+ private
95
+
96
+ def logger = Imis.logger('Panel')
97
+
98
+ def business_object
99
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'business_object')
100
+ end
101
+
102
+ def payload(_data)
103
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'payload(data)')
104
+ end
105
+
106
+ def payload_header(data)
107
+ {
108
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericEntityData, Asi.Contracts',
109
+ 'EntityTypeName' => business_object,
110
+ 'PrimaryParentEntityTypeName' => 'Party',
111
+ 'Identity' => identity(data[:ordinal]),
112
+ 'PrimaryParentIdentity' => primary_parent_identity
113
+ }
114
+ end
115
+
116
+ def identity(ordinal = nil)
117
+ {
118
+ '$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
119
+ 'EntityTypeName' => business_object,
120
+ 'IdentityElements' => {
121
+ '$type' => identity_type,
122
+ '$values' => [api.imis_id.to_s, ordinal&.to_s].compact
123
+ }
124
+ }
125
+ end
126
+
127
+ def primary_parent_identity
128
+ {
129
+ '$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
130
+ 'EntityTypeName' => 'Party',
131
+ 'IdentityElements' => {
132
+ '$type' => identity_type,
133
+ '$values' => [api.imis_id.to_s]
134
+ }
135
+ }
136
+ end
137
+
138
+ def identity_type = 'System.Collections.ObjectModel.Collection`1[[System.String, mscorlib]], mscorlib'
139
+
140
+ def build_payload(data, &) = payload_header(data).merge(Properties.build(&))
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Panels
6
+ # Panel for accessing the Educational completions business object
7
+ #
8
+ class Education < BasePanel
9
+ private
10
+
11
+ def business_object
12
+ 'ABC_ASC_Educ'
13
+ end
14
+
15
+ def payload(data)
16
+ build_payload(data) do |props|
17
+ props.add 'ID', api.imis_id.to_s
18
+ props.add 'Ordinal', data[:ordinal] if data[:ordinal]
19
+ props.add 'ABC_EDUC_THRU_DATE', data[:thru_date] || '0001-01-01T00:00:00'
20
+ props.add 'ABC_ECertificate', data[:certificate]
21
+ props.add 'ABC_Educ_Description', data[:description]
22
+ props.add 'ABC_Educ_Effective_Date', data[:effective_date]
23
+ props.add 'ABC_Educ_Source_System', data[:source]
24
+ props.add 'ABC_Educ_Transaction_Date', Time.now
25
+ props.add 'ABC_Other_Code', data[:code]
26
+ props.add 'ABC_Product_Code', data[:type_code]
27
+ props.add 'ABC_TYPE', data[:abc_type_code] || 'EDUC'
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Panels
6
+ # Panel for accessing the annual VSC completed counts business object
7
+ #
8
+ class Vsc < BasePanel
9
+ private
10
+
11
+ def business_object
12
+ 'ABC_ASC_Vessel_Safety_Checks'
13
+ end
14
+
15
+ def payload(data)
16
+ build_payload(data) do |props|
17
+ props.add 'ID', api.imis_id.to_s
18
+ props.add 'Ordinal', data[:ordinal] if data[:ordinal]
19
+ props.add 'Source_System', 'Manual ITCom Entry'
20
+ props.add 'ABC_ECertificate', data[:certificate]
21
+ props.add 'Activity_Type', 'VSC'
22
+ props.add 'Description', 'Vessel Safety Checks'
23
+ props.add 'Effective_Date', "#{data[:year]}-12-01T00:00:00"
24
+ props.add 'Quantity', data[:count]
25
+ props.add 'Thru_Date', "#{data[:year]}-12-31T00:00:00"
26
+ props.add 'Transaction_Date', Time.now
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'panels/base_panel'
4
+ require_relative 'panels/vsc'
5
+ require_relative 'panels/education'
6
+
7
+ module Usps
8
+ module Imis
9
+ # Namespace for all Panels
10
+ #
11
+ module Panels
12
+ # Convenience accessor for available Panel objects
13
+ #
14
+ # @param api [Api] Parent to use for making requests
15
+ #
16
+ def self.all(api = Api.new)
17
+ panels = constants.reject { it == :BasePanel }
18
+
19
+ Struct
20
+ .new(*panels.map { it.to_s.underscore.to_sym })
21
+ .new(*panels.map { const_get(it).new(api) })
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # Constructor for the Properties field
6
+ #
7
+ class Properties
8
+ # Build the data for a new Properties field
9
+ #
10
+ def self.build(&) = new.build(&)
11
+
12
+ # Build the data for the Properties field
13
+ #
14
+ def build
15
+ yield(self)
16
+
17
+ {
18
+ 'Properties' => {
19
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyDataCollection, Asi.Contracts',
20
+ '$values' => @properties
21
+ }
22
+ }
23
+ end
24
+
25
+ # Add an individual property to the field
26
+ #
27
+ def add(name, value)
28
+ @properties ||= []
29
+ @properties << {
30
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
31
+ 'Name' => name,
32
+ 'Value' => wrap(value)
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ def wrap(value)
39
+ case value
40
+ when String then value
41
+ when Time, DateTime then value.strftime('%Y-%m-%dT%H:%I:%S')
42
+ when Integer then { '$type' => 'System.Int32', '$value' => value }
43
+ when true, false then { '$type' => 'System.Boolean', '$value' => value }
44
+ else
45
+ raise Errors::UnexpectedPropertyTypeError.from(value)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # API wrapper for IQA Queries
6
+ #
7
+ class Query
8
+ include Enumerable
9
+ include Requests
10
+
11
+ # Endpoint for IQA query requests
12
+ #
13
+ QUERY_PATH = 'api/Query'
14
+
15
+ # The parent +Api+ object
16
+ #
17
+ attr_reader :api
18
+
19
+ # Name of the Query to run
20
+ #
21
+ attr_reader :query_name
22
+
23
+ # Parameters for the Query
24
+ #
25
+ attr_reader :query_params
26
+
27
+ # Current offset for paging through the Query
28
+ #
29
+ attr_reader :offset
30
+
31
+ # A new instance of +Query+
32
+ #
33
+ # @param api [Api] Parent to use for making requests
34
+ # @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
35
+ # @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
36
+ #
37
+ def initialize(api, query_name, query_params)
38
+ @api = api
39
+ @query_name = query_name
40
+ @query_params = query_params
41
+ end
42
+
43
+ # Iterate through all results from the query
44
+ #
45
+ def each(&)
46
+ logger.info 'Running IQA Query on iMIS'
47
+
48
+ items = []
49
+ find_each { items << it }
50
+ items.each(&)
51
+ end
52
+
53
+ # Iterate through all results from the query, fetching one page at a time
54
+ #
55
+ def find_each(&)
56
+ result = { 'HasNext' => true }
57
+ count = 0
58
+
59
+ while result['HasNext']
60
+ logger.info 'Fetching IQA Query page'
61
+
62
+ result = fetch
63
+
64
+ count += result['Count'] || 0
65
+ logger.info " -> #{count} / #{result['TotalCount']} #{'item'.pluralize(count)}"
66
+ logger.debug ' -> Query page data:'
67
+ JSON.pretty_generate(result).split("\n").each { logger.debug " -> #{it}" }
68
+
69
+ items = result['Items']['$values'].map { it.except('$type') }
70
+ @offset = result['NextOffset']
71
+
72
+ items.each(&)
73
+ end
74
+
75
+ nil
76
+ end
77
+
78
+ # Ruby 3.5 instance variable filter
79
+ #
80
+ def instance_variables_to_inspect = instance_variables - %i[@api]
81
+
82
+ private
83
+
84
+ def token = api.token
85
+ def token_expiration = api.token_expiration
86
+
87
+ def path = "#{QUERY_PATH}?#{query_params.merge(QueryName: query_name, Offset: offset).to_query}"
88
+ def uri = URI(File.join(Imis.configuration.hostname, path))
89
+ def fetch = JSON.parse(submit(uri, authorize(Net::HTTP::Get.new(uri))).body)
90
+
91
+ def logger = Imis.logger('Query')
92
+ end
93
+ end
94
+ end
@@ -2,9 +2,13 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
+ # @private
6
+ #
5
7
  module Requests
6
8
  private
7
9
 
10
+ def logger = Imis.logger
11
+
8
12
  def client(uri)
9
13
  Net::HTTP.new(uri.host, uri.port).tap do |http|
10
14
  http.use_ssl = true
@@ -17,15 +21,37 @@ module Usps
17
21
  # If the current token is missing/expired, request a new one
18
22
  #
19
23
  def authorize(request)
20
- authenticate if token_expiration < Time.now
21
- request.tap { |r| r.add_field('Authorization', "Bearer #{token}") }
24
+ if token_expiration < Time.now
25
+ logger.debug 'Token expired: re-authenticating with iMIS'
26
+ authenticate
27
+ end
28
+ request.tap { it.add_field('Authorization', "Bearer #{token}") }
22
29
  end
23
30
 
24
31
  def submit(uri, request)
32
+ logger.info 'Submitting request to iMIS'
33
+ logger.debug " -> #{request.class.name.demodulize.upcase} #{uri}"
34
+ sanitized_request_body(request).split("\n").each { logger.debug " -> #{it}" }
25
35
  client(uri).request(request).tap do |result|
26
- raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
36
+ raise Errors::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
37
+
38
+ logger.info 'Request succeeded'
27
39
  end
28
40
  end
41
+
42
+ def sanitized_request_body(request)
43
+ return '*** empty request body ***' if request.body.nil?
44
+
45
+ body = request.body.dup
46
+
47
+ Imis.config.filtered_parameters.each do |parameter|
48
+ body =
49
+ body.gsub(Imis.config.public_send(parameter), '[FILTERED]')
50
+ .gsub(CGI.escape(Imis.config.public_send(parameter)), '[FILTERED]')
51
+ end
52
+
53
+ body
54
+ end
29
55
  end
30
56
  end
31
57
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '1.0.0-rc.4'
5
+ VERSION = '1.0.0-rc.7'
6
6
  end
7
7
  end
data/lib/usps/imis.rb CHANGED
@@ -6,23 +6,21 @@ require 'json'
6
6
  require 'time'
7
7
  require 'cgi'
8
8
 
9
- # Extensions
10
- # :nocov:
11
- require 'ext/hash' unless defined?(Rails)
12
- # :nocov:
9
+ require 'active_support/core_ext/string/inflections'
10
+ require 'active_support/core_ext/object/to_query'
11
+ require 'active_support/core_ext/enumerable'
12
+ require 'active_support/string_inquirer'
13
+ require 'logger'
14
+ require 'active_support/isolated_execution_state' # Fix costant loading issue with TaggedLogging
15
+ require 'active_support/tagged_logging'
13
16
 
14
17
  # Internal requires
15
18
  require_relative 'imis/config'
16
- require_relative 'imis/error/api_error'
17
- require_relative 'imis/error/mapper_error'
18
- require_relative 'imis/error/response_error'
19
- require_relative 'imis/requests'
20
- require_relative 'imis/business_object'
19
+ require_relative 'imis/error'
21
20
  require_relative 'imis/api'
22
- require_relative 'imis/mapper'
23
- require_relative 'imis/panel/base_panel'
24
- require_relative 'imis/panel/vsc'
25
- require_relative 'imis/panel/education'
21
+ require_relative 'imis/properties'
22
+ require_relative 'imis/panels'
23
+ require_relative 'imis/mocks'
26
24
 
27
25
  module Usps
28
26
  # API wrapper for interacting with iMIS
@@ -36,6 +34,7 @@ module Usps
36
34
  def configuration
37
35
  @configuration ||= Config.new
38
36
  end
37
+ alias config configuration
39
38
 
40
39
  # Used to define a block of configuration settings
41
40
  #
@@ -45,6 +44,10 @@ module Usps
45
44
  yield(configuration) if block_given?
46
45
  configuration
47
46
  end
47
+
48
+ # Logger (with optional nested tags) to write to
49
+ #
50
+ def logger(*tags) = configuration.logger.tagged('iMIS', *tags)
48
51
  end
49
52
  end
50
53
  end
@@ -17,13 +17,13 @@ describe Usps::Imis::Api do
17
17
  it 'stores the initial imis_id' do
18
18
  api = described_class.new(imis_id: 42)
19
19
 
20
- expect(api.imis_id).to eq('42')
20
+ expect(api.imis_id).to eq(42)
21
21
  end
22
22
  end
23
23
 
24
24
  describe '#imis_id_for' do
25
25
  it 'gets the iMIS ID' do
26
- expect(api.imis_id_for('E231625')).to eq('31092')
26
+ expect(api.imis_id_for('E231625')).to eq(31092)
27
27
  end
28
28
 
29
29
  context 'with a query error' do
@@ -31,25 +31,38 @@ describe Usps::Imis::Api do
31
31
 
32
32
  it 'wraps errors' do
33
33
  expect { api.imis_id_for('E231625') }.to raise_error(
34
- Usps::Imis::Error::ApiError, 'Member not found'
34
+ Usps::Imis::Errors::NotFoundError, 'Member not found'
35
35
  )
36
36
  end
37
37
  end
38
38
  end
39
39
 
40
+ describe '#query' do
41
+ let(:query) { api.query('$/ABC/ExampleQueryAll', {}) }
42
+
43
+ before do
44
+ allow(query).to receive(:fetch).and_return(
45
+ { 'Items' => { '$values' => [{ 'key1' => 'value1' }] }, 'HasNext' => true, 'NextOffset' => 1 },
46
+ { 'Items' => { '$values' => [{ 'key1' => 'value2' }] }, 'HasNext' => false, 'NextOffset' => 0 }
47
+ )
48
+ end
49
+
50
+ it 'collects all query results' do
51
+ expect(query.to_a).to eq([{ 'key1' => 'value1' }, { 'key1' => 'value2' }])
52
+ end
53
+ end
54
+
40
55
  describe '#put' do
41
56
  before { api.imis_id = 31092 }
42
57
 
43
58
  it 'sends an update' do
44
- expect(api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to(
45
- be_a(Hash)
46
- )
59
+ expect(api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to be_a(Hash)
47
60
  end
48
61
 
49
62
  context 'when receiving a response error' do
50
63
  let(:warning_text) do
51
64
  <<~WARNING.chomp
52
- Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
65
+ Usps::Imis::Errors::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
53
66
  Something went wrong
54
67
  WARNING
55
68
  end
@@ -63,8 +76,8 @@ describe Usps::Imis::Api do
63
76
  end
64
77
 
65
78
  it 'wraps the error' do
66
- expect { api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }.to(
67
- raise_error(Usps::Imis::Error::ApiError, warning_text)
79
+ expect { api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }.to(
80
+ raise_error(Usps::Imis::Errors::ResponseError, warning_text)
68
81
  )
69
82
  end
70
83
  end
@@ -73,7 +86,7 @@ describe Usps::Imis::Api do
73
86
  describe '#with' do
74
87
  it 'sends an update from put' do
75
88
  expect(
76
- api.with(31092) { business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }
89
+ api.with(31092) { on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }
77
90
  ).to be_a(Hash)
78
91
  end
79
92
 
@@ -88,13 +101,13 @@ describe Usps::Imis::Api do
88
101
  it 'blocks calling imis_id=' do
89
102
  expect do
90
103
  api.with(31092) { self.imis_id = 31092 }
91
- end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
104
+ end.to raise_error(Usps::Imis::Errors::LockedIdError, 'Cannot change iMIS ID while locked')
92
105
  end
93
106
 
94
107
  it 'blocks calling imis_id_for' do
95
108
  expect do
96
109
  api.with(31092) { imis_id_for('E231625') }
97
- end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
110
+ end.to raise_error(Usps::Imis::Errors::LockedIdError, 'Cannot change iMIS ID while locked')
98
111
  end
99
112
  end
100
113
 
@@ -118,7 +131,7 @@ describe Usps::Imis::Api do
118
131
  end
119
132
 
120
133
  expect(result).to be_a(Hash)
121
- expect(api.imis_id).to eq('31092')
134
+ expect(api.imis_id).to eq(31092)
122
135
  end
123
136
 
124
137
  it 'nests on and with', :aggregate_failures do