eligible 2.4.3 → 2.5.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/.gitignore +0 -1
- data/.rspec +2 -0
- data/.rubocop.yml +12 -0
- data/ChangeLog +51 -0
- data/LICENSE +1 -1
- data/README.md +71 -133
- data/Rakefile +12 -2
- data/eligible.gemspec +14 -15
- data/lib/eligible.rb +96 -68
- data/lib/eligible/api_resource.rb +4 -6
- data/lib/eligible/claim.rb +12 -18
- data/lib/eligible/coverage.rb +16 -17
- data/lib/eligible/demographic.rb +7 -10
- data/lib/eligible/eligible_object.rb +12 -14
- data/lib/eligible/enrollment.rb +12 -13
- data/lib/eligible/errors/eligible_error.rb +2 -2
- data/lib/eligible/medicare.rb +8 -14
- data/lib/eligible/payment.rb +4 -9
- data/lib/eligible/ticket.rb +23 -30
- data/lib/eligible/util.rb +31 -35
- data/lib/eligible/version.rb +1 -1
- data/lib/eligible/x12.rb +2 -4
- metadata +50 -52
- data/CONTRIBUTORS +0 -5
- data/test/test_eligible.rb +0 -178
- data/test/test_helper.rb +0 -97
data/eligible.gemspec
CHANGED
@@ -4,24 +4,23 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'eligible/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
|
-
gem.name =
|
7
|
+
gem.name = 'eligible'
|
8
8
|
gem.version = Eligible::VERSION
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
11
|
-
gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://
|
9
|
+
gem.authors = ['Katelyn Gleaon', 'Rodrigo Dominguez', 'Aaron Bedra']
|
10
|
+
gem.email = ['k@eligible.com', 'rod@eligible.com', 'abedra@eligible.com']
|
11
|
+
gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://eligible.com'
|
12
12
|
gem.summary = 'Ruby wrapper for the Eligible API'
|
13
|
-
gem.homepage =
|
14
|
-
gem.license =
|
13
|
+
gem.homepage = 'https://github.com/eligible/eligible-ruby'
|
14
|
+
gem.license = 'MIT'
|
15
15
|
|
16
|
-
gem.files = `git ls-files`.split(
|
17
|
-
gem.
|
18
|
-
gem.require_paths = ["lib"]
|
16
|
+
gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
gem.require_paths = ['lib']
|
19
18
|
|
20
|
-
gem.
|
21
|
-
gem.
|
22
|
-
gem.add_development_dependency('test-unit')
|
23
|
-
gem.add_development_dependency('rake')
|
19
|
+
gem.add_dependency('rest-client', '~> 1.8')
|
20
|
+
gem.add_dependency('multi_json', '~> 1.7')
|
24
21
|
|
25
|
-
gem.
|
26
|
-
gem.
|
22
|
+
gem.add_development_dependency('rake', '~> 10.5')
|
23
|
+
gem.add_development_dependency('rspec', '~> 3.4')
|
24
|
+
gem.add_development_dependency('rubocop', '= 0.35.0')
|
25
|
+
gem.add_development_dependency('simplecov', '~> 0.11')
|
27
26
|
end
|
data/lib/eligible.rb
CHANGED
@@ -28,13 +28,15 @@ require 'eligible/errors/authentication_error'
|
|
28
28
|
require 'eligible/errors/api_error'
|
29
29
|
require 'eligible/errors/invalid_request_error'
|
30
30
|
|
31
|
+
# rubocop:disable Metrics/ModuleLength, Style/ClassVars
|
31
32
|
module Eligible
|
32
33
|
@@api_key = nil
|
33
34
|
@@test = false
|
34
|
-
@@api_base = 'https://gds.eligibleapi.com/v1.1'
|
35
35
|
@@api_version = 1.1
|
36
|
+
@@api_base = "https://gds.eligibleapi.com/v#{@@api_version}"
|
37
|
+
@@fingerprints = %w(79d62e8a9d59ae687372f8e71345c76d92527fac 4b2c6888ede79d0ee47339dc6fab5a6d0dc3cb0e)
|
36
38
|
|
37
|
-
def self.api_url(url='')
|
39
|
+
def self.api_url(url = '')
|
38
40
|
@@api_base + url.to_s
|
39
41
|
end
|
40
42
|
|
@@ -70,87 +72,98 @@ module Eligible
|
|
70
72
|
@@api_version
|
71
73
|
end
|
72
74
|
|
73
|
-
def self.
|
75
|
+
def self.fingerprints
|
76
|
+
@@fingerprints
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.add_fingerprint(digest)
|
80
|
+
$stderr.puts 'The embedded certificate fingerprint was modified. This should only be done if instructed to by eligible support staff'
|
81
|
+
@@fingerprints << digest
|
82
|
+
end
|
83
|
+
|
84
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
85
|
+
def self.request(method, url, api_key, params = {}, headers = {})
|
74
86
|
api_key ||= @@api_key
|
75
87
|
test = self.test
|
76
|
-
api_key = params[:api_key] if params.
|
77
|
-
test = params[:test] if params.
|
88
|
+
api_key = params[:api_key] if params.key?(:api_key)
|
89
|
+
test = params[:test] if params.key?(:test)
|
78
90
|
|
79
|
-
|
91
|
+
fail AuthenticationError, 'No API key provided. (HINT: set your API key using "Eligible.api_key = <API-KEY>".' unless api_key
|
80
92
|
|
81
93
|
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
82
|
-
|
83
|
-
:
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
94
|
+
debug_info = {
|
95
|
+
bindings_version: Eligible::VERSION,
|
96
|
+
lang: 'ruby',
|
97
|
+
lang_version: lang_version,
|
98
|
+
platform: RUBY_PLATFORM,
|
99
|
+
publisher: 'eligible',
|
100
|
+
uname: uname
|
89
101
|
}
|
90
102
|
|
91
103
|
# GET requests, parameters on the query string
|
92
104
|
# POST requests, parameters as json in the body
|
93
|
-
url =
|
105
|
+
url = api_url(url)
|
94
106
|
case method.to_s.downcase.to_sym
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
107
|
+
when :get, :head
|
108
|
+
url += "?api_key=#{api_key}"
|
109
|
+
if params && params.count > 0
|
110
|
+
query_string = Util.flatten_params(params).collect { |key, value| "#{key}=#{Util.url_encode(value)}" }.join('&')
|
111
|
+
url += "&#{query_string}"
|
112
|
+
end
|
113
|
+
url += "&test=#{test}"
|
114
|
+
payload = nil
|
115
|
+
else
|
116
|
+
payload = Eligible::JSON.dump(params.merge!('api_key' => api_key, 'test' => test))
|
105
117
|
end
|
106
118
|
|
107
119
|
begin
|
108
|
-
headers = { :
|
120
|
+
headers = { x_eligible_debuginfo: Eligible::JSON.dump(debug_info) }.merge(headers)
|
109
121
|
rescue => e
|
110
122
|
headers = {
|
111
|
-
:
|
112
|
-
:
|
123
|
+
x_eligible_client_raw_user_agent: debug_info.inspect,
|
124
|
+
error: "#{e} (#{e.class})"
|
113
125
|
}.merge(headers)
|
114
126
|
end
|
115
127
|
|
116
128
|
headers = {
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
129
|
+
user_agent: "eligible-ruby/#{Eligible::VERSION}",
|
130
|
+
authorization: "Bearer #{api_key}",
|
131
|
+
content_type: 'application/x-www-form-urlencoded'
|
120
132
|
}.merge(headers)
|
121
133
|
|
122
|
-
headers[:eligible_version] =
|
134
|
+
headers[:eligible_version] = api_version if api_version
|
123
135
|
|
124
136
|
opts = {
|
125
|
-
:
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
129
|
-
:
|
130
|
-
:
|
137
|
+
method: method,
|
138
|
+
url: url,
|
139
|
+
headers: headers,
|
140
|
+
open_timeout: 30,
|
141
|
+
payload: payload,
|
142
|
+
timeout: 80,
|
143
|
+
ssl_verify_callback: verify_certificate
|
131
144
|
}
|
132
145
|
|
133
146
|
begin
|
134
147
|
response = execute_request(opts)
|
135
|
-
|
136
148
|
rescue SocketError => e
|
137
|
-
|
149
|
+
handle_restclient_error(e)
|
138
150
|
rescue NoMethodError => e
|
139
151
|
# Work around RestClient bug
|
140
152
|
if e.message =~ /\WRequestFailed\W/
|
141
153
|
e = APIConnectionError.new('Unexpected HTTP response code')
|
142
|
-
|
154
|
+
handle_restclient_error(e)
|
143
155
|
else
|
144
156
|
raise
|
145
157
|
end
|
158
|
+
# rubocop:disable Lint/AssignmentInCondition, Style/AndOr
|
146
159
|
rescue RestClient::ExceptionWithResponse => e
|
147
160
|
if rcode = e.http_code and rbody = e.http_body
|
148
|
-
|
161
|
+
handle_api_error(rcode, rbody)
|
149
162
|
else
|
150
|
-
|
163
|
+
handle_restclient_error(e)
|
151
164
|
end
|
152
165
|
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
153
|
-
|
166
|
+
handle_restclient_error(e)
|
154
167
|
end
|
155
168
|
|
156
169
|
rbody = response.body
|
@@ -171,6 +184,20 @@ module Eligible
|
|
171
184
|
[resp, api_key]
|
172
185
|
end
|
173
186
|
|
187
|
+
def self.verify_certificate
|
188
|
+
lambda do |preverify_ok, certificate_store|
|
189
|
+
return true if test == 'true'
|
190
|
+
return false unless preverify_ok
|
191
|
+
received = certificate_store.chain.first
|
192
|
+
return true unless received.to_der == certificate_store.current_cert.to_der
|
193
|
+
valid_fingerprint?(received)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.valid_fingerprint?(received)
|
198
|
+
fingerprints.include?(OpenSSL::Digest::SHA1.hexdigest(received.to_der))
|
199
|
+
end
|
200
|
+
|
174
201
|
private
|
175
202
|
|
176
203
|
def self.uname
|
@@ -181,51 +208,52 @@ module Eligible
|
|
181
208
|
RestClient::Request.execute(opts)
|
182
209
|
end
|
183
210
|
|
211
|
+
# rubocop:disable Style/SignalException
|
184
212
|
def self.handle_api_error(rcode, rbody)
|
185
213
|
begin
|
186
214
|
error_obj = Eligible::JSON.load(rbody)
|
187
215
|
error_obj = Util.symbolize_names(error_obj)
|
188
|
-
|
216
|
+
fail EligibleError unless error_obj.key?(:error)
|
217
|
+
error = error_obj[:error]
|
189
218
|
rescue MultiJson::DecodeError, EligibleError
|
190
219
|
raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
191
220
|
end
|
192
221
|
|
222
|
+
error_msg = error[:details] || error[:reject_reason_description]
|
223
|
+
|
193
224
|
case rcode
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
225
|
+
when 400, 404 then
|
226
|
+
raise invalid_request_error(error_msg, rcode, rbody, error_obj)
|
227
|
+
when 401
|
228
|
+
raise authentication_error(error_msg, rcode, rbody, error_obj)
|
229
|
+
else
|
230
|
+
raise api_error(error_msg, rcode, rbody, error_obj)
|
200
231
|
end
|
201
232
|
end
|
202
233
|
|
203
|
-
def self.invalid_request_error(
|
204
|
-
InvalidRequestError.new(
|
234
|
+
def self.invalid_request_error(error_msg, rcode, rbody, error_obj)
|
235
|
+
InvalidRequestError.new(error_msg, rcode, rbody, error_obj)
|
205
236
|
end
|
206
237
|
|
207
|
-
def self.authentication_error(
|
208
|
-
AuthenticationError.new(
|
238
|
+
def self.authentication_error(error_msg, rcode, rbody, error_obj)
|
239
|
+
AuthenticationError.new(error_msg, rcode, rbody, error_obj)
|
209
240
|
end
|
210
241
|
|
211
|
-
def self.api_error(
|
212
|
-
APIError.new(
|
242
|
+
def self.api_error(error_msg, rcode, rbody, error_obj)
|
243
|
+
APIError.new(error_msg, rcode, rbody, error_obj)
|
213
244
|
end
|
214
245
|
|
215
246
|
def self.handle_restclient_error(e)
|
216
247
|
case e
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
248
|
+
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
249
|
+
message = "Could not connect to Eligible (#{@@api_base}). Please check your internet connection and try again."
|
250
|
+
when RestClient::SSLCertificateNotVerified
|
251
|
+
message = "Could not verify Eligible's SSL certificate."
|
252
|
+
when SocketError
|
253
|
+
message = 'Unexpected error communicating when trying to connect to Eligible.'
|
254
|
+
else
|
255
|
+
message = 'Unexpected error communicating with Eligible. If this problem persists, let us know at support@eligible.com.'
|
225
256
|
end
|
226
|
-
|
227
|
-
raise APIConnectionError.new(message)
|
257
|
+
fail APIConnectionError, "#{message}\n\n(Network error: #{e.message})"
|
228
258
|
end
|
229
|
-
|
230
259
|
end
|
231
|
-
|
@@ -1,16 +1,14 @@
|
|
1
1
|
module Eligible
|
2
2
|
class APIResource < EligibleObject
|
3
|
-
|
4
3
|
def self.class_name
|
5
|
-
|
4
|
+
name.split('::').last
|
6
5
|
end
|
7
6
|
|
8
|
-
def self.url
|
7
|
+
def self.url
|
9
8
|
if self == APIResource
|
10
|
-
|
9
|
+
fail NotImplementedError, 'APIResource is an abstract class. You should perform actions on its subclasses (Plan, Service, etc.)'
|
11
10
|
end
|
12
11
|
"/#{CGI.escape(class_name.downcase)}/"
|
13
12
|
end
|
14
|
-
|
15
13
|
end
|
16
|
-
end
|
14
|
+
end
|
data/lib/eligible/claim.rb
CHANGED
@@ -1,28 +1,22 @@
|
|
1
1
|
module Eligible
|
2
2
|
class Claim < APIResource
|
3
|
+
def self.get(params, api_key = nil)
|
4
|
+
response, api_key = Eligible.request(:get, "/claims/acknowledgements/#{params[:reference_id]}.json", api_key, params)
|
5
|
+
Util.convert_to_eligible_object(response, api_key)
|
6
|
+
end
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
Util.convert_to_eligible_object(response, api_key)
|
9
|
-
end
|
10
|
-
|
11
|
-
def post(params, api_key = nil)
|
12
|
-
response, api_key = Eligible.request(:post, '/claims.json', api_key, params)
|
13
|
-
Util.convert_to_eligible_object(response, api_key)
|
14
|
-
end
|
15
|
-
|
16
|
-
def all(api_key = nil)
|
17
|
-
response, api_key = Eligible.request(:get, '/claims/acknowledgements.json', api_key)
|
18
|
-
Util.convert_to_eligible_object(response, api_key)
|
19
|
-
end
|
8
|
+
def self.post(params, api_key = nil)
|
9
|
+
response, api_key = Eligible.request(:post, '/claims.json', api_key, params)
|
10
|
+
Util.convert_to_eligible_object(response, api_key)
|
11
|
+
end
|
20
12
|
|
13
|
+
def self.all(api_key = nil)
|
14
|
+
response, api_key = Eligible.request(:get, '/claims/acknowledgements.json', api_key)
|
15
|
+
Util.convert_to_eligible_object(response, api_key)
|
21
16
|
end
|
22
17
|
|
23
18
|
def status
|
24
19
|
error ? nil : to_hash
|
25
20
|
end
|
26
|
-
|
27
21
|
end
|
28
|
-
end
|
22
|
+
end
|
data/lib/eligible/coverage.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
module Eligible
|
2
2
|
class Coverage < APIResource
|
3
|
+
def self.get(params, api_key = nil)
|
4
|
+
response, api_key = Eligible.request(:get, '/coverage/all.json', api_key, params)
|
5
|
+
Util.convert_to_eligible_object(response, api_key)
|
6
|
+
end
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
Util.convert_to_eligible_object(response, api_key)
|
9
|
-
end
|
10
|
-
|
11
|
-
def batch_post(params, api_key=nil)
|
12
|
-
response, api_key = Eligible.request(:post, '/coverage/all/batch.json', api_key, params)
|
13
|
-
Util.convert_to_eligible_object(response, api_key)
|
14
|
-
end
|
15
|
-
|
16
|
-
def batch_medicare_post(params, api_key=nil)
|
17
|
-
response, api_key = Eligible.request(:post, '/medicare/coverage/batch.json', api_key, params)
|
18
|
-
Util.convert_to_eligible_object(response, api_key)
|
19
|
-
end
|
8
|
+
def self.cost_estimate(params, api_key = nil)
|
9
|
+
response, api_key = Eligible.request(:get, '/coverage/cost_estimate.json', api_key, params)
|
10
|
+
Util.convert_to_eligible_object(response, api_key)
|
11
|
+
end
|
20
12
|
|
13
|
+
def self.batch_post(params, api_key = nil)
|
14
|
+
response, api_key = Eligible.request(:post, '/coverage/all/batch.json', api_key, params)
|
15
|
+
Util.convert_to_eligible_object(response, api_key)
|
21
16
|
end
|
22
17
|
|
18
|
+
def self.batch_medicare_post(params, api_key = nil)
|
19
|
+
response, api_key = Eligible.request(:post, '/medicare/coverage/batch.json', api_key, params)
|
20
|
+
Util.convert_to_eligible_object(response, api_key)
|
21
|
+
end
|
23
22
|
end
|
24
|
-
end
|
23
|
+
end
|
data/lib/eligible/demographic.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
module Eligible
|
2
2
|
class Demographic < APIResource
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
Util.convert_to_eligible_object(response, api_key)
|
8
|
-
end
|
3
|
+
def self.get(params, api_key = nil)
|
4
|
+
response, api_key = Eligible.request(:get, '/demographic/all.json', api_key, params)
|
5
|
+
Util.convert_to_eligible_object(response, api_key)
|
6
|
+
end
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
8
|
+
def self.batch_post(params, api_key = nil)
|
9
|
+
response, api_key = Eligible.request(:post, '/demographic/all/batch.json', api_key, params)
|
10
|
+
Util.convert_to_eligible_object(response, api_key)
|
14
11
|
end
|
15
12
|
end
|
16
13
|
end
|
@@ -1,18 +1,16 @@
|
|
1
1
|
module Eligible
|
2
|
-
|
3
2
|
class EligibleObject
|
4
3
|
include Enumerable
|
5
4
|
|
6
5
|
attr_accessor :api_key
|
7
6
|
attr_accessor :eligible_id
|
7
|
+
# rubocop:disable Style/ClassVars
|
8
8
|
@@permanent_attributes = Set.new([:api_key, :error, :balance, :address, :dob])
|
9
9
|
|
10
10
|
# The default :id method is deprecated and isn't useful to us
|
11
|
-
if method_defined?(:id)
|
12
|
-
undef :id
|
13
|
-
end
|
11
|
+
undef :id if method_defined?(:id)
|
14
12
|
|
15
|
-
def initialize(id=nil, api_key=nil)
|
13
|
+
def initialize(id = nil, api_key = nil)
|
16
14
|
@api_key = api_key
|
17
15
|
@values = {}
|
18
16
|
# This really belongs in APIResource, but not putting it there allows us
|
@@ -22,13 +20,14 @@ module Eligible
|
|
22
20
|
self.eligible_id = id if id
|
23
21
|
end
|
24
22
|
|
25
|
-
def self.construct_from(values, api_key=nil)
|
26
|
-
obj =
|
23
|
+
def self.construct_from(values, api_key = nil)
|
24
|
+
obj = new(values[:eligible_id], api_key)
|
27
25
|
obj.refresh_from(values, api_key)
|
28
26
|
obj
|
29
27
|
end
|
30
28
|
|
31
|
-
|
29
|
+
# rubocop:disable Metrics/AbcSize
|
30
|
+
def refresh_from(values, api_key, partial = false)
|
32
31
|
@api_key = api_key
|
33
32
|
|
34
33
|
removed = partial ? Set.new : Set.new(@values.keys - values.keys)
|
@@ -54,7 +53,7 @@ module Eligible
|
|
54
53
|
end
|
55
54
|
|
56
55
|
def [](k)
|
57
|
-
k = k.to_sym if k.
|
56
|
+
k = k.to_sym if k.is_a?(String)
|
58
57
|
@values[k]
|
59
58
|
end
|
60
59
|
|
@@ -70,7 +69,7 @@ module Eligible
|
|
70
69
|
@values.values
|
71
70
|
end
|
72
71
|
|
73
|
-
def to_json
|
72
|
+
def to_json
|
74
73
|
Eligible::JSON.dump(@values)
|
75
74
|
end
|
76
75
|
|
@@ -90,7 +89,7 @@ module Eligible
|
|
90
89
|
|
91
90
|
def metaclass
|
92
91
|
class << self; self; end
|
93
|
-
end
|
92
|
+
end
|
94
93
|
|
95
94
|
def remove_accessors(keys)
|
96
95
|
metaclass.instance_eval do
|
@@ -115,7 +114,6 @@ module Eligible
|
|
115
114
|
end
|
116
115
|
end
|
117
116
|
end
|
118
|
-
end
|
117
|
+
end
|
119
118
|
end
|
120
|
-
|
121
|
-
end
|
119
|
+
end
|