eligible 1.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.
@@ -0,0 +1,40 @@
1
+ module Eligible
2
+ class Demographic < APIResource
3
+ COMMON_ATTRIBUTES = [:timestamp, :eligible_id, :mapping_version]
4
+ ZIP_ATTRIBUTES = [:zip]
5
+ EMPLOYER_ATTRIBUTES = [:group_id, :group_name]
6
+ ADDRESS_ATTRIBUTES = [:address]
7
+ DOB_ATTRIBUTES = [:dob]
8
+
9
+ def self.get(params, api_key=nil)
10
+ response, api_key = Eligible.request(:get, url, api_key, params)
11
+ Util.convert_to_eligible_object(response, api_key)
12
+ end
13
+
14
+ def all
15
+ error ? nil : to_hash
16
+ end
17
+
18
+ def zip
19
+ keys = COMMON_ATTRIBUTES
20
+ h = to_hash.select { |k, v| keys.include?(k) }
21
+ h[:zip] = to_hash[:address][:zip]
22
+ error ? nil : h
23
+ end
24
+
25
+ def employer
26
+ keys = COMMON_ATTRIBUTES + EMPLOYER_ATTRIBUTES
27
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
28
+ end
29
+
30
+ def address
31
+ keys = COMMON_ATTRIBUTES + ADDRESS_ATTRIBUTES
32
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
33
+ end
34
+
35
+ def dob
36
+ keys = COMMON_ATTRIBUTES + DOB_ATTRIBUTES
37
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,121 @@
1
+ module Eligible
2
+
3
+ class EligibleObject
4
+ include Enumerable
5
+
6
+ attr_accessor :api_key
7
+ attr_accessor :eligible_id
8
+ @@permanent_attributes = Set.new([:api_key, :error, :balance, :address, :dob])
9
+
10
+ # The default :id method is deprecated and isn't useful to us
11
+ if method_defined?(:id)
12
+ undef :id
13
+ end
14
+
15
+ def initialize(id=nil, api_key=nil)
16
+ @api_key = api_key
17
+ @values = {}
18
+ # This really belongs in APIResource, but not putting it there allows us
19
+ # to have a unified inspect method
20
+ @unsaved_values = Set.new
21
+ @transient_values = Set.new
22
+ self.eligible_id = id if id
23
+ end
24
+
25
+ def self.construct_from(values, api_key=nil)
26
+ obj = self.new(values[:eligible_id], api_key)
27
+ obj.refresh_from(values, api_key)
28
+ obj
29
+ end
30
+
31
+ def refresh_from(values, api_key, partial=false)
32
+ @api_key = api_key
33
+
34
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
35
+ added = Set.new(values.keys - @values.keys)
36
+ # Wipe old state before setting new. This is useful for e.g. updating a
37
+ # customer, where there is no persistent card parameter. Mark those values
38
+ # which don't persist as transient
39
+
40
+ instance_eval do
41
+ remove_accessors(removed)
42
+ add_accessors(added)
43
+ end
44
+ removed.each do |k|
45
+ @values.delete(k)
46
+ @transient_values.add(k)
47
+ @unsaved_values.delete(k)
48
+ end
49
+ values.each do |k, v|
50
+ @values[k] = v#Util.convert_to_eligible_object(v, api_key)
51
+ @transient_values.delete(k)
52
+ @unsaved_values.delete(k)
53
+ end
54
+ end
55
+
56
+ def [](k)
57
+ k = k.to_sym if k.kind_of?(String)
58
+ @values[k]
59
+ end
60
+
61
+ def []=(k, v)
62
+ send(:"#{k}=", v)
63
+ end
64
+
65
+ def keys
66
+ @values.keys
67
+ end
68
+
69
+ def values
70
+ @values.values
71
+ end
72
+
73
+ def to_json(*a)
74
+ Eligible::JSON.dump(@values)
75
+ end
76
+
77
+ def to_hash
78
+ @values
79
+ end
80
+
81
+ def each(&blk)
82
+ @values.each(&blk)
83
+ end
84
+
85
+ def error
86
+ keys.include?(:error) ? @values[:error] : nil
87
+ end
88
+
89
+ protected
90
+
91
+ def metaclass
92
+ class << self; self; end
93
+ end
94
+
95
+ def remove_accessors(keys)
96
+ metaclass.instance_eval do
97
+ keys.each do |k|
98
+ next if @@permanent_attributes.include?(k)
99
+ k_eq = :"#{k}="
100
+ remove_method(k) if method_defined?(k)
101
+ remove_method(k_eq) if method_defined?(k_eq)
102
+ end
103
+ end
104
+ end
105
+
106
+ def add_accessors(keys)
107
+ metaclass.instance_eval do
108
+ keys.each do |k|
109
+ next if @@permanent_attributes.include?(k)
110
+ k_eq = :"#{k}="
111
+ define_method(k) { @values[k] }
112
+ define_method(k_eq) do |v|
113
+ @values[k] = v
114
+ @unsaved_values.add(k)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,4 @@
1
+ module Eligible
2
+ class APIConnectionError < EligibleError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eligible
2
+ class APIError < EligibleError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eligible
2
+ class AuthenticationError < EligibleError
3
+ end
4
+ end
@@ -0,0 +1,20 @@
1
+ module Eligible
2
+ class EligibleError < StandardError
3
+ attr_reader :message
4
+ attr_reader :http_status
5
+ attr_reader :http_body
6
+ attr_reader :json_body
7
+
8
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
+ @message = message
10
+ @http_status = http_status
11
+ @http_body = http_body
12
+ @json_body = json_body
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
17
+ "#{status_string}#{@message}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module Eligible
2
+ module JSON
3
+ if MultiJson.respond_to?(:dump)
4
+ def self.dump(*args)
5
+ MultiJson.dump(*args)
6
+ end
7
+
8
+ def self.load(*args)
9
+ MultiJson.load(*args)
10
+ end
11
+ else
12
+ def self.dump(*args)
13
+ MultiJson.encode(*args)
14
+ end
15
+
16
+ def self.load(*args)
17
+ MultiJson.decode(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ module Eligible
2
+ COMMON_ATTRIBUTES = [:timestamp, :eligible_id, :mapping_version, :primary_insurance, :additional_insurance]
3
+ STATUS_ATTRIBUTES = [:type, :coverage_status]
4
+ BALANCE_ATTRIBUTES = [:balance, :comments]
5
+ STOP_LOSS_ATTRIBUTES = [:stop_loss_in_network, :stop_loss_out_network]
6
+
7
+ class Plan < APIResource
8
+ def self.get(params, api_key=nil)
9
+ response, api_key = Eligible.request(:get, url, api_key, params)
10
+ Util.convert_to_eligible_object(response, api_key)
11
+ end
12
+
13
+ def all
14
+ error ? nil : to_hash
15
+ end
16
+
17
+ def status
18
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES
19
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
20
+ end
21
+
22
+ def deductible
23
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES + [:deductible_in_network, :deductible_out_network]
24
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
25
+ end
26
+
27
+ def dates
28
+ keys = COMMON_ATTRIBUTES
29
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
30
+ end
31
+
32
+ def balance
33
+ keys = COMMON_ATTRIBUTES + BALANCE_ATTRIBUTES
34
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
35
+ end
36
+
37
+ def stop_loss
38
+ keys = COMMON_ATTRIBUTES + STOP_LOSS_ATTRIBUTES
39
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ module Eligible
2
+ class Service < APIResource
3
+ COMMON_ATTRIBUTES = [:timestamp, :eligible_id, :mapping_version, :additional_insurance]
4
+ STATUS_ATTRIBUTES = [:type, :coverage_status]
5
+ VISITS_ATTRIBUTES = [:not_covered, :comments, :precertification_needed, :visits_in_network, :visits_out_network]
6
+ COPAYMENT_ATTRIBUTES = [:copayment_in_network, :copayment_out_network]
7
+ COINSURANCE_ATTRIBUTES = [:coinsurance_in_network, :coinsurance_out_network]
8
+ DEDUCTIBLE_ATTRIBUTES = [:deductible_in_network, :deductible_out_network]
9
+
10
+ def self.get(params, api_key=nil)
11
+ response, api_key = Eligible.request(:get, url, api_key, params)
12
+ Util.convert_to_eligible_object(response, api_key)
13
+ end
14
+
15
+ def all
16
+ error ? nil : to_hash
17
+ end
18
+
19
+ def visits
20
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES + VISITS_ATTRIBUTES
21
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
22
+ end
23
+
24
+ def copayment
25
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES + COPAYMENT_ATTRIBUTES
26
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
27
+ end
28
+
29
+ def coinsurance
30
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES + COINSURANCE_ATTRIBUTES
31
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
32
+ end
33
+
34
+ def deductible
35
+ keys = COMMON_ATTRIBUTES + STATUS_ATTRIBUTES + DEDUCTIBLE_ATTRIBUTES
36
+ error ? nil : to_hash.select { |k, v| keys.include?(k) }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,99 @@
1
+ module Eligible
2
+ module Util
3
+ def self.objects_to_ids(h)
4
+ case h
5
+ when APIResource
6
+ h.id
7
+ when Hash
8
+ res = {}
9
+ h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
10
+ res
11
+ when Array
12
+ h.map { |v| objects_to_ids(v) }
13
+ else
14
+ h
15
+ end
16
+ end
17
+
18
+ def self.convert_to_eligible_object(resp, api_key)
19
+ types = {
20
+ 'plan' => Plan,
21
+ 'service' => Service,
22
+ 'demographic' => Demographic,
23
+ 'claim' => Claim
24
+ }
25
+ case resp
26
+ when Array
27
+ resp.map { |i| convert_to_eligible_object(i, api_key) }
28
+ when Hash
29
+ # Try converting to a known object class. If none available, fall back to generic APIResource
30
+ if resp[:mapping_version] && klass_name = resp[:mapping_version].match(/^[^\/]*/)[0]
31
+ klass = types[klass_name]
32
+ end
33
+ klass ||= EligibleObject
34
+ klass.construct_from(resp, api_key)
35
+ else
36
+ resp
37
+ end
38
+ end
39
+
40
+ def self.file_readable(file)
41
+ begin
42
+ File.open(file) { |f| }
43
+ rescue
44
+ false
45
+ else
46
+ true
47
+ end
48
+ end
49
+
50
+ def self.symbolize_names(object)
51
+ case object
52
+ when Hash
53
+ new = {}
54
+ object.each do |key, value|
55
+ key = (key.to_sym rescue key) || key
56
+ new[key] = symbolize_names(value)
57
+ end
58
+ new
59
+ when Array
60
+ object.map { |value| symbolize_names(value) }
61
+ else
62
+ object
63
+ end
64
+ end
65
+
66
+ def self.url_encode(key)
67
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
68
+ end
69
+
70
+ def self.flatten_params(params, parent_key=nil)
71
+ result = []
72
+ params.each do |key, value|
73
+ calculated_key = parent_key ? "#{parent_key}[#{url_encode(key)}]" : url_encode(key)
74
+ if value.is_a?(Hash)
75
+ result += flatten_params(value, calculated_key)
76
+ elsif value.is_a?(Array)
77
+ result += flatten_params_array(value, calculated_key)
78
+ else
79
+ result << [calculated_key, value]
80
+ end
81
+ end
82
+ result
83
+ end
84
+
85
+ def self.flatten_params_array(value, calculated_key)
86
+ result = []
87
+ value.each do |elem|
88
+ if elem.is_a?(Hash)
89
+ result += flatten_params(elem, calculated_key)
90
+ elsif elem.is_a?(Array)
91
+ result += flatten_params_array(elem, calculated_key)
92
+ else
93
+ result << ["#{calculated_key}[]", elem]
94
+ end
95
+ end
96
+ result
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ module Eligible
2
+ VERSION = "1.0"
3
+ end
@@ -0,0 +1,279 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'rest-client'
6
+
7
+ class TestEligible < Test::Unit::TestCase
8
+ include Mocha
9
+
10
+ context "Version" do
11
+ should "have a version number" do
12
+ assert_not_nil Eligible::VERSION
13
+ end
14
+ end
15
+
16
+ context "General API" do
17
+ setup do
18
+ Eligible.api_key = "TEST"
19
+ @mock = mock
20
+ Eligible.mock_rest_client = @mock
21
+ end
22
+
23
+ teardown do
24
+ Eligible.mock_rest_client = nil
25
+ Eligible.api_key = nil
26
+ end
27
+
28
+ should "not specifying api credentials should raise an exception" do
29
+ Eligible.api_key = nil
30
+ assert_raises Eligible::AuthenticationError do
31
+ Eligible::Plan.get({})
32
+ end
33
+ end
34
+
35
+ should "specifying invalid api credentials should raise an exception" do
36
+ Eligible.api_key = "invalid"
37
+ response = test_response(test_invalid_api_key_error, 401)
38
+ assert_raises Eligible::AuthenticationError do
39
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
40
+ Eligible::Plan.get({})
41
+ end
42
+ end
43
+ end
44
+
45
+ context "Plan" do
46
+ setup do
47
+ Eligible.api_key = "TEST"
48
+ @mock = mock
49
+ Eligible.mock_rest_client = @mock
50
+ end
51
+
52
+ teardown do
53
+ Eligible.mock_rest_client = nil
54
+ Eligible.api_key = nil
55
+ end
56
+
57
+ should "return an error if no params are supplied" do
58
+ params = {}
59
+ response = test_response(test_plan_missing_params)
60
+ @mock.expects(:get).returns(response)
61
+ plan = Eligible::Plan.get(params)
62
+ assert_not_nil plan.error
63
+ end
64
+
65
+ should "return plan information if valid params are supplied" do
66
+ params = {
67
+ :payer_name => "Aetna",
68
+ :payer_id => "000001",
69
+ :service_provider_last_name => "Last",
70
+ :service_provider_first_name => "First",
71
+ :service_provider_NPI => "1928384219",
72
+ :subscriber_id => "W120923801",
73
+ :subscriber_last_name => "Austen",
74
+ :subscriber_first_name => "Jane",
75
+ :subscriber_dob => "1955-12-14"
76
+ }
77
+ response = test_response(test_plan)
78
+ @mock.expects(:get).returns(response)
79
+ plan = Eligible::Plan.get(params)
80
+ assert_nil plan.error
81
+ assert_not_nil plan.all
82
+ end
83
+
84
+ should "return the right subsets of the data when requested" do
85
+ params = {
86
+ :payer_name => "Aetna",
87
+ :payer_id => "000001",
88
+ :service_provider_last_name => "Last",
89
+ :service_provider_first_name => "First",
90
+ :service_provider_NPI => "1928384219",
91
+ :subscriber_id => "W120923801",
92
+ :subscriber_last_name => "Austen",
93
+ :subscriber_first_name => "Jane",
94
+ :subscriber_dob => "1955-12-14"
95
+ }
96
+ response = test_response(test_plan)
97
+ @mock.expects(:get).returns(response)
98
+ plan = Eligible::Plan.get(params)
99
+
100
+ assert_not_nil plan.all[:primary_insurance]
101
+ assert_not_nil plan.status[:coverage_status]
102
+ assert_nil plan.status[:deductible_in_network]
103
+ assert_not_nil plan.deductible[:deductible_in_network]
104
+ assert_nil plan.deductible[:balance]
105
+ assert_not_nil plan.dates[:primary_insurance][:plan_begins]
106
+ assert_nil plan.dates[:deductible_in_network]
107
+ assert_not_nil plan.balance[:balance]
108
+ assert_nil plan.balance[:deductible_in_network]
109
+ assert_not_nil plan.stop_loss[:stop_loss_in_network]
110
+ assert_nil plan.stop_loss[:deductible_in_network]
111
+ end
112
+ end
113
+
114
+ context "Service" do
115
+ setup do
116
+ Eligible.api_key = "TEST"
117
+ @mock = mock
118
+ Eligible.mock_rest_client = @mock
119
+ end
120
+
121
+ teardown do
122
+ Eligible.mock_rest_client = nil
123
+ Eligible.api_key = nil
124
+ end
125
+
126
+ should "return an error if no params are supplied" do
127
+ params = {}
128
+ response = test_response(test_service_missing_params)
129
+ @mock.expects(:get).returns(response)
130
+ service = Eligible::Service.get(params)
131
+ assert_not_nil service.error
132
+ end
133
+
134
+ should "return eligibility information if valid params are supplied" do
135
+ params = {
136
+ :payer_name => "Aetna",
137
+ :payer_id => "000001",
138
+ :service_provider_last_name => "Last",
139
+ :service_provider_first_name => "First",
140
+ :service_provider_NPI => "1928384219",
141
+ :subscriber_id => "W120923801",
142
+ :subscriber_last_name => "Austen",
143
+ :subscriber_first_name => "Jane",
144
+ :subscriber_dob => "1955-12-14"
145
+ }
146
+ response = test_response(test_service)
147
+ @mock.expects(:get).returns(response)
148
+ service = Eligible::Service.get(params)
149
+ assert_nil service.error
150
+ assert_not_nil service.all
151
+ end
152
+
153
+ should "return the right subsets of the data when requested" do
154
+ params = {
155
+ :payer_name => "Aetna",
156
+ :payer_id => "000001",
157
+ :service_provider_last_name => "Last",
158
+ :service_provider_first_name => "First",
159
+ :service_provider_NPI => "1928384219",
160
+ :subscriber_id => "W120923801",
161
+ :subscriber_last_name => "Austen",
162
+ :subscriber_first_name => "Jane",
163
+ :subscriber_dob => "1955-12-14"
164
+ }
165
+ response = test_response(test_service)
166
+ @mock.expects(:get).returns(response)
167
+ service = Eligible::Service.get(params)
168
+
169
+ assert_not_nil service.all[:service_begins]
170
+ assert_not_nil service.visits[:visits_in_network]
171
+ assert_nil service.visits[:copayment_in_network]
172
+ assert_not_nil service.copayment[:copayment_in_network]
173
+ assert_nil service.copayment[:visits_in_network]
174
+ assert_not_nil service.coinsurance[:coinsurance_in_network]
175
+ assert_nil service.coinsurance[:visits_in_network]
176
+ assert_not_nil service.deductible[:deductible_in_network]
177
+ assert_nil service.deductible[:visits_in_network]
178
+ end
179
+ end
180
+
181
+ context "Demographic" do
182
+ setup do
183
+ Eligible.api_key = "TEST"
184
+ @mock = mock
185
+ Eligible.mock_rest_client = @mock
186
+ end
187
+
188
+ teardown do
189
+ Eligible.mock_rest_client = nil
190
+ Eligible.api_key = nil
191
+ end
192
+
193
+ should "return an error if no params are supplied" do
194
+ params = {}
195
+ response = test_response(test_demographic_missing_params)
196
+ @mock.expects(:get).returns(response)
197
+ demographic = Eligible::Demographic.get(params)
198
+ assert_not_nil demographic.error
199
+ end
200
+
201
+ should "return demographic information if valid params are supplied" do
202
+ params = {
203
+ :payer_name => "Aetna",
204
+ :payer_id => "000001",
205
+ :service_provider_last_name => "Last",
206
+ :service_provider_first_name => "First",
207
+ :service_provider_NPI => "1928384219",
208
+ :subscriber_id => "W120923801",
209
+ :subscriber_last_name => "Austen",
210
+ :subscriber_first_name => "Jane",
211
+ :subscriber_dob => "1955-12-14"
212
+ }
213
+ response = test_response(test_demographic)
214
+ @mock.expects(:get).returns(response)
215
+ demographic = Eligible::Demographic.get(params)
216
+ assert_nil demographic.error
217
+ assert_not_nil demographic.all
218
+ end
219
+
220
+ should "return the right subsets of the data when requested" do
221
+ params = {
222
+ :payer_name => "Aetna",
223
+ :payer_id => "000001",
224
+ :service_provider_last_name => "Last",
225
+ :service_provider_first_name => "First",
226
+ :service_provider_NPI => "1928384219",
227
+ :subscriber_id => "W120923801",
228
+ :subscriber_last_name => "Austen",
229
+ :subscriber_first_name => "Jane",
230
+ :subscriber_dob => "1955-12-14"
231
+ }
232
+ response = test_response(test_demographic)
233
+ @mock.expects(:get).returns(response)
234
+ demographic = Eligible::Demographic.get(params)
235
+
236
+ assert_not_nil demographic.all[:timestamp]
237
+ assert_not_nil demographic.zip[:zip]
238
+ assert_nil demographic.zip[:group_id]
239
+ assert_not_nil demographic.employer[:group_id]
240
+ assert_nil demographic.employer[:zip]
241
+ assert_not_nil demographic.address[:address]
242
+ assert_nil demographic.address[:group_id]
243
+ assert_not_nil demographic.dob[:dob]
244
+ assert_nil demographic.dob[:address]
245
+ end
246
+ end
247
+
248
+ context "Claim" do
249
+ setup do
250
+ Eligible.api_key = "TEST"
251
+ @mock = mock
252
+ Eligible.mock_rest_client = @mock
253
+ end
254
+
255
+ teardown do
256
+ Eligible.mock_rest_client = nil
257
+ Eligible.api_key = nil
258
+ end
259
+
260
+ should "return an error if no params are supplied" do
261
+ params = {}
262
+ response = test_response(test_claim_missing_params)
263
+ @mock.expects(:get).returns(response)
264
+ claim = Eligible::Claim.get(params)
265
+ assert_not_nil claim.error
266
+ end
267
+
268
+ should "return claim information if valid params are supplied" do
269
+ params = {
270
+ :tbd => true
271
+ }
272
+ response = test_response(test_claim)
273
+ @mock.expects(:get).returns(response)
274
+ claim = Eligible::Claim.get(params)
275
+ assert_nil claim.error
276
+ assert_not_nil claim.status
277
+ end
278
+ end
279
+ end