trizetto-api 0.1.2 → 0.2.1
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/.travis.yml +2 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +3 -1
- data/README.md +55 -11
- data/lib/trizetto/api/eligibility/core2.rb +16 -15
- data/lib/trizetto/api/eligibility/web_service.rb +121 -59
- data/lib/trizetto/api/eligibility/web_service/benefit.rb +117 -0
- data/lib/trizetto/api/eligibility/web_service/benefit_entity.rb +54 -0
- data/lib/trizetto/api/eligibility/web_service/dependent.rb +72 -0
- data/lib/trizetto/api/eligibility/web_service/do_inquiry_response.rb +168 -0
- data/lib/trizetto/api/eligibility/web_service/extra_processing_info.rb +41 -0
- data/lib/trizetto/api/eligibility/web_service/info_reciever.rb +14 -0
- data/lib/trizetto/api/eligibility/web_service/info_source.rb +14 -0
- data/lib/trizetto/api/eligibility/web_service/node.rb +43 -0
- data/lib/trizetto/api/eligibility/web_service/patient.rb +36 -0
- data/lib/trizetto/api/eligibility/web_service/patient_name.rb +50 -0
- data/lib/trizetto/api/eligibility/web_service/rejectable.rb +62 -0
- data/lib/trizetto/api/eligibility/web_service/rejection.rb +31 -0
- data/lib/trizetto/api/eligibility/web_service/subscriber.rb +32 -0
- data/lib/trizetto/api/eligibility/web_service/validation_failure.rb +47 -0
- data/lib/trizetto/api/payer_list/web_service.rb +10 -8
- data/lib/trizetto/api/version.rb +1 -1
- data/trizetto-api.gemspec +4 -0
- metadata +32 -3
@@ -0,0 +1,54 @@
|
|
1
|
+
module Trizetto
|
2
|
+
module Api
|
3
|
+
module Eligibility
|
4
|
+
module WebService
|
5
|
+
|
6
|
+
# When a benefit is related to an entity, such as a primary care provider,
|
7
|
+
# the entity details are captured here
|
8
|
+
#
|
9
|
+
# <b>Example XML</b>
|
10
|
+
# <benefitentity>
|
11
|
+
# <entitycode>Primary Care Provider</entitycode>
|
12
|
+
# <name>JULIUS</name>
|
13
|
+
# <first>GROLLMAN</first>
|
14
|
+
# <identification_code_qualifier>Health Care Financing Administration National Provider Identifier</identification_code_qualifier>
|
15
|
+
# <benefit_related_entity_id>1609858695</benefit_related_entity_id>
|
16
|
+
# <benefit_related_entity_address_1>4101 TORRANCE BLVD</benefit_related_entity_address_1>
|
17
|
+
# <benefit_related_entity_city>TORRANCE</benefit_related_entity_city>
|
18
|
+
# <benefit_related_entity_state>CA</benefit_related_entity_state>
|
19
|
+
# <benefit_related_entity_zip>90503</benefit_related_entity_zip>
|
20
|
+
# <communicationnumberqualifier>Telephone</communicationnumberqualifier>
|
21
|
+
# <communicationnumber>3103035750</communicationnumber>
|
22
|
+
# </benefitentity>
|
23
|
+
#
|
24
|
+
# <b>Example</b>
|
25
|
+
# benefit.entity.entity_code # => "Primary Care Provider"
|
26
|
+
# benefit.entity.name # => "JULIUS"
|
27
|
+
# benefit.entity.first # => "GROLLMAN"
|
28
|
+
# benefit.entity.id # => "1609858695"
|
29
|
+
# benefit.entity.identification_code_qualifier # => "Health Care Financing Administration National Provider Identifier"
|
30
|
+
# benefit.entity.city # => "TORRANCE"
|
31
|
+
# benefit.entity.communication_number # => "3103035750"
|
32
|
+
#
|
33
|
+
class BenefitEntity < Node
|
34
|
+
KEY_CLEANUP =
|
35
|
+
{
|
36
|
+
entitycode: :entity_code,
|
37
|
+
communicationnumberqualifier: :communication_number_qualifier,
|
38
|
+
communicationnumber: :communication_number,
|
39
|
+
}
|
40
|
+
|
41
|
+
PREFIX_TRANSLATIONS =
|
42
|
+
[
|
43
|
+
:benefit_related_entity
|
44
|
+
]
|
45
|
+
|
46
|
+
def initialize(raw_hash = {})
|
47
|
+
super(raw_hash)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Trizetto
|
2
|
+
module Api
|
3
|
+
module Eligibility
|
4
|
+
module WebService
|
5
|
+
# A dependent in the eligibility XML.
|
6
|
+
#
|
7
|
+
# <b>NOTE: Not all fields have been transcribed to objects</b>
|
8
|
+
#
|
9
|
+
# <b>Example XML</b>
|
10
|
+
#
|
11
|
+
# <dependent>
|
12
|
+
# <trace_number>999999999</trace_number>
|
13
|
+
# <trace_id>99TRIZETTO</trace_id>
|
14
|
+
# <subscriberaddinfo>
|
15
|
+
# <subsupplementalid>99</subsupplementalid>
|
16
|
+
# <grouppolicynum>999</grouppolicynum>
|
17
|
+
# </subscriberaddinfo>
|
18
|
+
# <subscriberaddinfo>
|
19
|
+
# <subsupplementalid>6P</subsupplementalid>
|
20
|
+
# <grouppolicynum>999999999A6AG999</grouppolicynum>
|
21
|
+
# <plansponsorname>BERGE-GREENHOLT</plansponsorname>
|
22
|
+
# </subscriberaddinfo>
|
23
|
+
# <date>
|
24
|
+
# <datequalifier>Plan</datequalifier>
|
25
|
+
# <date-of-service>20160101-99991231</date-of-service>
|
26
|
+
# </date>
|
27
|
+
# <date>
|
28
|
+
# <datequalifier>Service</datequalifier>
|
29
|
+
# <date-of-service>20180116</date-of-service>
|
30
|
+
# </date>
|
31
|
+
# <patientname>
|
32
|
+
# <first>JUANA</first>
|
33
|
+
# <middle>M</middle>
|
34
|
+
# <last>ORN</last>
|
35
|
+
# </patientname>
|
36
|
+
# <sex>F</sex>
|
37
|
+
# <date-of-birth>19630717</date-of-birth>
|
38
|
+
# <relationship>
|
39
|
+
# <insuredindicator>No</insuredindicator>
|
40
|
+
# <relationshipcode>Spouse</relationshipcode>
|
41
|
+
# <relationshiptypecode>Change</relationshiptypecode>
|
42
|
+
# <relationshipreasoncode>Change in Identifying Data Elements</relationshipreasoncode>
|
43
|
+
# </relationship>
|
44
|
+
# <benefit>
|
45
|
+
# <info>Active Coverage</info>
|
46
|
+
# <coveragelevel>Employee and Spouse</coveragelevel>
|
47
|
+
# <servicetype>Health Benefit Plan Coverage</servicetype>
|
48
|
+
# <servicetypecode>30</servicetypecode>
|
49
|
+
# <insurancetype>Preferred Provider Organization (PPO)</insurancetype>
|
50
|
+
# <insurancetypecode>PR</insurancetypecode>
|
51
|
+
# <plancoveragedescription>CDHP</plancoveragedescription>
|
52
|
+
# </benefit>
|
53
|
+
# </dependent>
|
54
|
+
#
|
55
|
+
# <b>Example</b>
|
56
|
+
#
|
57
|
+
# dependent.trace_number # => "999999999"
|
58
|
+
# dependent.name.first # => "JUNNA"
|
59
|
+
# dependent.name.middle # => "M"
|
60
|
+
# dependent.name.last # => "ORN"
|
61
|
+
# dependent.name.sex # => "F"
|
62
|
+
# dependent.name.benefits # => [ Array of Benefits ]
|
63
|
+
class Dependent < Patient
|
64
|
+
def initialize(raw_hash = {})
|
65
|
+
super(raw_hash)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Trizetto
|
2
|
+
module Api
|
3
|
+
module Eligibility
|
4
|
+
module WebService
|
5
|
+
|
6
|
+
# The parsed response from an eligibility check
|
7
|
+
class DoInquiryResponse
|
8
|
+
|
9
|
+
# The SuccessCode in the XML response from the eligibility request.
|
10
|
+
#
|
11
|
+
# Takes on one of these values
|
12
|
+
# * <tt>Success</tt> - The request was well formed and not missing any fields
|
13
|
+
# * <tt>ValidationFailure</tt> - The request was not valid. Maybe a field was formatted incorrectly or omitted.
|
14
|
+
# * <tt>PayerTimeout</tt> - ?
|
15
|
+
# * <tt>PayerNotSupported</tt> - ?
|
16
|
+
# * <tt>SystemError</tt> - ?
|
17
|
+
# * <tt>PayerEnrollmentRequired</tt> - ?
|
18
|
+
# * <tt>ProviderEnrollmentRequired</tt> - ?
|
19
|
+
# * <tt>ProductRequired</tt> - ?
|
20
|
+
attr_accessor :success_code
|
21
|
+
|
22
|
+
# For a successful request that returned an eligibility response, the
|
23
|
+
# transaction identifier from Trizetto. Seems to be 30 random alpha
|
24
|
+
# numeric characters
|
25
|
+
attr_accessor :transaction_id
|
26
|
+
|
27
|
+
# For a successful request, the name of the payer (insurance company)
|
28
|
+
attr_accessor :payer_name
|
29
|
+
|
30
|
+
# For a successful request, the identifier of the payer (insurance company)
|
31
|
+
attr_accessor :payer_id
|
32
|
+
|
33
|
+
# Any validation error or messages provided in the response
|
34
|
+
#
|
35
|
+
# *Example*
|
36
|
+
# client.extra_processing_info.messages # => ["Invalid InsuredFirstName Length."]
|
37
|
+
# client.extra_processing_info.validation_failures.first.affected_fields # => ["InsuredFirstName"]
|
38
|
+
# client.extra_processing_info.validation_failures.first.message # => "Invalid InsuredFirstName Length."
|
39
|
+
#
|
40
|
+
# @see ExtraProcessingInfo
|
41
|
+
#
|
42
|
+
attr_accessor :extra_processing_info
|
43
|
+
|
44
|
+
# The eligibility response xml parsed into a hash.
|
45
|
+
attr_accessor :eligibility_response_as_hash
|
46
|
+
|
47
|
+
# The Subscriber in the eligibility XML.
|
48
|
+
#
|
49
|
+
# @see Subscriber
|
50
|
+
attr_accessor :subscriber
|
51
|
+
|
52
|
+
# The Dependent in the eligibility XML.
|
53
|
+
#
|
54
|
+
# @see Dependent
|
55
|
+
attr_accessor :dependent
|
56
|
+
|
57
|
+
# The infosource in the eligibilty XML
|
58
|
+
#
|
59
|
+
# @see InfoSource
|
60
|
+
attr_accessor :info_source
|
61
|
+
|
62
|
+
# The inforeceiver in the eligibilty XML
|
63
|
+
#
|
64
|
+
# @see InfoReceiver
|
65
|
+
attr_accessor :info_receiver
|
66
|
+
|
67
|
+
|
68
|
+
def initialize(response)
|
69
|
+
response = response.to_hash.dig(:do_inquiry_response, :do_inquiry_result) || {}
|
70
|
+
|
71
|
+
self.success_code = response[:success_code]
|
72
|
+
self.response_as_xml = response[:response_as_xml]
|
73
|
+
self.extra_processing_info = ExtraProcessingInfo.new(response[:extra_processing_info])
|
74
|
+
end
|
75
|
+
|
76
|
+
def response_as_xml=(eligibility_response_xml_as_string)
|
77
|
+
parser = Nori.new(convert_tags_to: lambda { |tag| tag.snakecase.to_sym })
|
78
|
+
self.eligibility_response_as_hash = parser.parse(eligibility_response_xml_as_string || '')[:eligibilityresponse] || {}
|
79
|
+
|
80
|
+
self.transaction_id = eligibility_response_as_hash.dig(:infosource, :transactionid)
|
81
|
+
self.payer_name = eligibility_response_as_hash.dig(:infosource, :payername)
|
82
|
+
self.payer_id = eligibility_response_as_hash.dig(:infosource, :payerid)
|
83
|
+
|
84
|
+
# TODO: I have not yet been able to find an example of multiple subscribers
|
85
|
+
# in a response from trizetto. But, I think if there were multiple
|
86
|
+
# subscribers matching a queruy, the would come back as <subscriber>...</subscriber><subscriber>...</subscriber>
|
87
|
+
# which Nori will turn into an array (subscriber: [...]).
|
88
|
+
|
89
|
+
if subscriber_xml = eligibility_response_as_hash[:subscriber]
|
90
|
+
raise MultipleSubscribersError if subscriber_xml.is_a?(Array)
|
91
|
+
self.subscriber = Subscriber.new(subscriber_xml)
|
92
|
+
end
|
93
|
+
|
94
|
+
if dependent_xml = eligibility_response_as_hash[:dependent]
|
95
|
+
raise MultipleDependentsError if dependent_xml.is_a?(Array)
|
96
|
+
self.dependent = Dependent.new(dependent_xml)
|
97
|
+
end
|
98
|
+
|
99
|
+
if info_source_xml = eligibility_response_as_hash[:infosource]
|
100
|
+
self.info_source = InfoSource.new(info_source_xml)
|
101
|
+
end
|
102
|
+
|
103
|
+
if info_receiver_xml = eligibility_response_as_hash[:inforeceiver]
|
104
|
+
self.info_receiver = InfoReceiver.new(info_receiver_xml)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
protected :response_as_xml=
|
108
|
+
|
109
|
+
# Did we successfully get back an eligibility response from the payer.
|
110
|
+
#
|
111
|
+
# This does not mean the patient has active coverage.
|
112
|
+
#
|
113
|
+
# @return Boolean
|
114
|
+
def success?
|
115
|
+
success_code == 'Success' && [transaction_id, payer_name, payer_id].none?(&:blank?)
|
116
|
+
end
|
117
|
+
|
118
|
+
# The dependent or the subscriber - the best guess at who is the patient
|
119
|
+
def patient
|
120
|
+
dependent || subscriber
|
121
|
+
end
|
122
|
+
|
123
|
+
# Was the eligibility check rejected. Eligibility checks may be rejected
|
124
|
+
# because they have expired, they don't exist, the payer service is unable
|
125
|
+
# to response, or there were errors with the request handled at the
|
126
|
+
# payer level instead of through Trizetto. There can be _multiple_ rejections
|
127
|
+
# on a single request
|
128
|
+
#
|
129
|
+
# @see #rejections
|
130
|
+
def rejected?
|
131
|
+
!rejections.empty?
|
132
|
+
end
|
133
|
+
|
134
|
+
# Rejections can appear in the subscriber, info source, info receiver,
|
135
|
+
# and possibly in the dependent. Additionaly, there can be _multiple_
|
136
|
+
# rejections in any one of those. This collects them all
|
137
|
+
def rejections
|
138
|
+
[subscriber, dependent, info_receiver, info_source].compact.map(&:rejections).flatten.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
# Validation errors handled at Trizetto's level
|
142
|
+
#
|
143
|
+
# @return ExtraProcessingInfo
|
144
|
+
def errors
|
145
|
+
self.extra_processing_info
|
146
|
+
end
|
147
|
+
|
148
|
+
# Does the patient we asked about have active insurance coverage for
|
149
|
+
# this service type code? Service type codes are strings and the
|
150
|
+
# most common is 30, general health benefits coverage.
|
151
|
+
#
|
152
|
+
# <b>Example</b>
|
153
|
+
#
|
154
|
+
# response.active_coverage_for?("30") #=> true
|
155
|
+
#
|
156
|
+
# <b>References</b>
|
157
|
+
#
|
158
|
+
# * {http://www.x12.org/codes/health-care-service-type-codes/ Service Type Code Reference<}
|
159
|
+
def active_coverage_for?(service_type_code)
|
160
|
+
!!(patient && patient.benefits.any? do |benefit|
|
161
|
+
benefit.active_coverage? && benefit.service_type_codes.include?(service_type_code.to_s)
|
162
|
+
end)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Trizetto
|
2
|
+
module Api
|
3
|
+
module Eligibility
|
4
|
+
module WebService
|
5
|
+
|
6
|
+
# Validation failures from the DoInquiryRequest.
|
7
|
+
#
|
8
|
+
# <b>WSDL Reference</b>
|
9
|
+
#
|
10
|
+
# <s:element minOccurs="0" maxOccurs="1" name="ExtraProcessingInfo" type="tns:ValidationFailureCollection" />
|
11
|
+
#
|
12
|
+
class ExtraProcessingInfo
|
13
|
+
|
14
|
+
# An array of strings, each a single validation failure
|
15
|
+
attr_accessor :messages
|
16
|
+
|
17
|
+
# An array of ValidationFailure, each indicating field that had errors
|
18
|
+
attr_accessor :validation_failures
|
19
|
+
|
20
|
+
def initialize(extra_processing_info)
|
21
|
+
self.messages = Array(extra_processing_info.dig(:all_messages, :string))
|
22
|
+
|
23
|
+
failures = extra_processing_info.dig(:failures,:validation_failure) || []
|
24
|
+
failures = [failures] if failures.is_a?(Hash)
|
25
|
+
|
26
|
+
self.validation_failures = failures.map do |failure|
|
27
|
+
ValidationFailure.new(failure)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_h
|
32
|
+
{
|
33
|
+
messages: messages,
|
34
|
+
validation_failures: validation_failures.map(&:to_h)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Trizetto
|
4
|
+
module Api
|
5
|
+
module Eligibility
|
6
|
+
module WebService
|
7
|
+
|
8
|
+
# Base class for parsed reponses in the eligibility response.
|
9
|
+
class Node < OpenStruct
|
10
|
+
def initialize(raw_hash = {})
|
11
|
+
required_keys = self.class.constants.include?(:REQUIRED_KEYS) ? self.class::REQUIRED_KEYS : {}
|
12
|
+
clean_hash = required_keys.merge(raw_hash)
|
13
|
+
|
14
|
+
cleanup_keys = self.class.constants.include?(:KEY_CLEANUP) ? self.class::KEY_CLEANUP : {}
|
15
|
+
cleanup_keys.each do |uglykey, friendly_key|
|
16
|
+
clean_hash[friendly_key] = clean_hash.delete(uglykey) if clean_hash.has_key?(uglykey)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Convert prefixed keys "benefit_related_entity_id" to simple keys "id"
|
20
|
+
prefix_translations = self.class.constants.include?(:PREFIX_TRANSLATIONS) ? self.class::PREFIX_TRANSLATIONS : {}
|
21
|
+
prefix_translations.each do |key_prefix|
|
22
|
+
clean_hash.keys.each do |key|
|
23
|
+
if key.to_s =~ /^#{key_prefix}_(.*)$/
|
24
|
+
clean_hash["#{$1}".to_sym] = clean_hash.delete(key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
super(clean_hash)
|
30
|
+
|
31
|
+
after_inititlize(clean_hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Callback after the prased eligibility response has been cleaned up
|
35
|
+
def after_inititlize(hash)
|
36
|
+
end
|
37
|
+
protected :after_inititlize
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Trizetto
|
2
|
+
module Api
|
3
|
+
module Eligibility
|
4
|
+
module WebService
|
5
|
+
|
6
|
+
# A Patient is either a Subscriber or Depedent. This is the common
|
7
|
+
# attributes between the two
|
8
|
+
class Patient < Node
|
9
|
+
|
10
|
+
# @see PatientName
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
# The benefits this patient has.
|
14
|
+
#
|
15
|
+
attr_accessor :benefits
|
16
|
+
|
17
|
+
KEY_CLEANUP = {
|
18
|
+
:patientid => :id
|
19
|
+
}
|
20
|
+
|
21
|
+
def initialize(raw_hash = {})
|
22
|
+
super(raw_hash)
|
23
|
+
self.name = PatientName.new(raw_hash[:patientname]) if raw_hash.has_key?(:patientname)
|
24
|
+
|
25
|
+
benefits_xml = raw_hash[:benefit] || []
|
26
|
+
benefits_xml = [benefits_xml] if benefits_xml.is_a?(Hash)
|
27
|
+
|
28
|
+
self.benefits = benefits_xml.map do |benefit_xml|
|
29
|
+
Benefit.new(benefit_xml)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|