usps-imis-api 0.15.1 → 0.15.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0281a50954f7068fa9ab74ce19ed5c533d358d101a983cffb7b729bbca8e4139'
4
- data.tar.gz: fb411c0c9204eb97b240dc2ca92a2c7348fa1a0ce43ff09011336b3a18716537
3
+ metadata.gz: 6192c91d6014b89e3cb78b0afc8b05cb0cd8f44352bdbeb6fe55ac99d02bf9d4
4
+ data.tar.gz: f37891d8dabf058351c6dae8bc12f54b5c8752acdac352b52a1fc27add15b749
5
5
  SHA512:
6
- metadata.gz: 9e7e886d137639e08132b6cd7f8e7734d375c330d3f6d28712b10ea8ff5b7362fae0d1525b24b0060987833203fdfb96492629f8e62e6487be17fa5bbc0051e4
7
- data.tar.gz: 1bd999a801fc341d93243b27eaebbf0fc7701737c227723a91c77d1fd76c48d73320c8949d5da1fb48107481539a429f708475847bc46bb49fdfa5da6f6bcdc6
6
+ metadata.gz: 25d2d665ce5a3e323977de8c2308fad23284ef1fa3fb93b56b68f0e649978214d3cd296e4a4792f23eb09a9992fee3412344097055088191cecc64f8ffc13c58
7
+ data.tar.gz: e79ca2364a98b9394a21c2c213e35cfb956c75990a790baa99ae49f4441e652aa573bee3b4247aaa224f2b8684cec64a5f12b935ee72d41538cbfcef7430f9bd
data/lib/usps/imis/api.rb CHANGED
@@ -112,15 +112,19 @@ module Usps
112
112
  #
113
113
  # @return [Integer] Corresponding iMIS ID
114
114
  #
115
+ # @raise [Errors::AmbiguousCertificateError] If the certificate matches more than one person
116
+ #
115
117
  def imis_id_for(certificate)
116
118
  raise Errors::LockedIdError if lock_imis_id
117
119
 
118
120
  logger.debug "Fetching iMIS ID for #{certificate}"
119
121
 
120
- net_contact_data = query('NetContactData', MajorKey: certificate).one
121
- raise Errors::NotFoundError, 'Member not found' if net_contact_data.nil?
122
+ # Family records can share their member's MajorKey, so only people are candidates
123
+ people = query('NetContactData', MajorKey: certificate).page.reject { it['IsCompany'] }
124
+ raise Errors::NotFoundError, 'Member not found' if people.empty?
125
+ raise Errors::AmbiguousCertificateError, certificate if people.many?
122
126
 
123
- party = query('Party', UniformId: net_contact_data.id).one
127
+ party = query('Party', UniformId: people.first.id).one
124
128
  raise Errors::NotFoundError, 'Member not found' if party.nil?
125
129
 
126
130
  self.imis_id = party.imis_id
@@ -107,6 +107,14 @@ module Usps
107
107
  @global_logger = build_global_logger
108
108
  end
109
109
 
110
+ # Whether the global mirror debug logger writes anywhere. Disabled or unwritable, it is a null
111
+ # logger, and nothing needs to be mirrored to it.
112
+ #
113
+ def global_logging?
114
+ global_logger
115
+ @global_logging
116
+ end
117
+
110
118
  def silence!
111
119
  self.logger = Logger.new(nil)
112
120
  end
@@ -153,6 +161,7 @@ module Usps
153
161
  rescue StandardError
154
162
  false
155
163
  end
164
+ @global_logging = writable
156
165
  return ActiveSupport::TaggedLogging.new(::Logger.new(nil)) unless writable
157
166
 
158
167
  ActiveSupport::TaggedLogging.new(
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Raised when a certificate number matches more than one person, so there is no single
7
+ # iMIS ID to select for it
8
+ #
9
+ class AmbiguousCertificateError < Error
10
+ attr_reader :certificate
11
+
12
+ def initialize(certificate)
13
+ @certificate = certificate
14
+ super(message)
15
+ end
16
+
17
+ def message = "Multiple members found for certificate #{certificate}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -12,14 +12,29 @@ module Usps
12
12
  self.formatter = LoggerFormatter.new
13
13
  end
14
14
 
15
- # Also send logger methods to the global logger
15
+ # Also send logger methods to the global logger, while it is writing anywhere
16
16
  #
17
17
  %w[debug info warn error fatal unknown].each do |method|
18
18
  define_method(method) do |message|
19
19
  super(message)
20
- Usps::Imis.config.global_logger.tagged(formatter.current_tags).public_send(method, message)
20
+ mirror(method, message) if Usps::Imis.config.global_logging?
21
21
  end
22
22
  end
23
+
24
+ # Whether a message at this level is recorded anywhere: here, or by the global logger, which
25
+ # records everything while it is writing
26
+ #
27
+ def logs?(level) = super || Usps::Imis.config.global_logging?
28
+
29
+ private
30
+
31
+ # The block form tags this one message, rather than building a tagged copy of the global logger
32
+ # for every line logged
33
+ #
34
+ def mirror(method, message)
35
+ global_logger = Usps::Imis.config.global_logger
36
+ global_logger.tagged(formatter.current_tags) { global_logger.public_send(method, message) }
37
+ end
23
38
  end
24
39
  end
25
40
  end
@@ -5,11 +5,22 @@ module Usps
5
5
  # Formatted logger helpers
6
6
  #
7
7
  module LoggerHelpers
8
+ # Whether a message at this level is recorded at all
9
+ #
10
+ def logs?(level) = public_send(:"#{level}?")
11
+
12
+ # Each line is logged on its own, so nothing is formatted or split for a level that would only
13
+ # discard them -- a full query page is tens of thousands of lines
14
+ #
8
15
  def multiline(string, level: :debug)
16
+ return unless logs?(level)
17
+
9
18
  string.split("\n").each { public_send(level, it) }
10
19
  end
11
20
 
12
21
  def json(data, level: :debug)
22
+ return unless logs?(level)
23
+
13
24
  hash = data.is_a?(String) ? JSON.parse(data) : data
14
25
  tagged('JSON') { multiline(JSON.pretty_generate(hash), level:) }
15
26
  rescue StandardError
@@ -31,7 +31,7 @@ module Usps
31
31
  # Hash of all property names to values
32
32
  #
33
33
  def properties
34
- @properties ||= format_extracted(extract_hash(raw))
34
+ @properties ||= extract_hash(raw)
35
35
  end
36
36
 
37
37
  private
@@ -40,18 +40,12 @@ module Usps
40
40
  { entity:, imis_id: }.compact
41
41
  end
42
42
 
43
- def extract_hash(hash)
44
- hash.filter_map do |key, value|
45
- next if key == '$type'
46
-
47
- [key, extract_value(value)]
48
- end
49
- end
43
+ def extract_hash(hash) = hash.except('$type').transform_values { extract_value(it) }
50
44
 
51
45
  def extract_value(value)
52
46
  case value
53
47
  when String, Integer, true, false, nil then value
54
- when Array then value.map { extract_value(it) }
48
+ when Array then extract_array(value)
55
49
  when Hash then extract_hash_value(value)
56
50
  else
57
51
  raise Errors::ApiError, "Unrecognized value type: #{value.inspect}"
@@ -60,29 +54,23 @@ module Usps
60
54
 
61
55
  def extract_hash_value(value)
62
56
  return value['$value'] if value.key?('$value')
63
- return extract_value(value['$values']) if value.key?('$values')
64
- return [value['Name'], extract_value(value['Value'])] if value.key?('Name') && value.key?('Value')
57
+ return extract_array(value['$values']) if value.key?('$values')
65
58
 
66
59
  extract_hash(value)
67
60
  end
68
61
 
69
- def format_extracted(data)
70
- hash = data.to_h
71
-
72
- hash.each do |key, value|
73
- case value
74
- when String, Integer, true, false then next
75
- end
76
-
77
- if %w[Addresses AlternateIds CommunicationPreferences Emails Phones Salutations].include?(key)
78
- hash[key] = value.map { format_extracted(it.to_h) }
79
- elsif value.all?(String)
80
- # Do nothing
81
- else
82
- hash[key] = format_extracted(value.to_h)
83
- end
62
+ # A list of +Name+ / +Value+ objects (e.g. +AdditionalAttributes+) is a property bag, so
63
+ # collapse it into a hash; any other list stays a list
64
+ #
65
+ def extract_array(values)
66
+ if values.any? && values.all? { named_value?(it) }
67
+ values.to_h { [it['Name'], extract_value(it['Value'])] }
68
+ else
69
+ values.map { extract_value(it) }
84
70
  end
85
71
  end
72
+
73
+ def named_value?(value) = value.is_a?(Hash) && value.key?('Name') && value.key?('Value')
86
74
  end
87
75
  end
88
76
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '0.15.1'
5
+ VERSION = '0.15.3'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: usps-imis-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.15.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander
@@ -119,6 +119,7 @@ files:
119
119
  - lib/usps/imis/data.rb
120
120
  - lib/usps/imis/dependencies.rb
121
121
  - lib/usps/imis/error.rb
122
+ - lib/usps/imis/errors/ambiguous_certificate_error.rb
122
123
  - lib/usps/imis/errors/api_error.rb
123
124
  - lib/usps/imis/errors/command_line_error.rb
124
125
  - lib/usps/imis/errors/config_error.rb