eligible 2.4.3 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|