Class: MPI::Responses::ProfileParser
Overview
Parses a MVI response and returns a MviProfile
Constant Summary
collapse
- BODY_XPATH =
'env:Envelope/env:Body/idm:PRPA_IN201306UV02'
- CODE_XPATH =
'acknowledgement/typeCode/@code'
- QUERY_XPATH =
'controlActProcess/queryByParameter'
- SSN_ROOT_ID =
'2.16.840.1.113883.4.1'
- SUBJECT_XPATH =
'controlActProcess/subject'
- PATIENT_XPATH =
'registrationEvent/subject1/patient'
- STATUS_XPATH =
'statusCode/@code'
- CONFIDENTIALITY_CODE_XPATH =
'confidentialityCode/@code'
- ID_THEFT_INDICATOR =
'ID_THEFT^TRUE'
- PATIENT_PERSON_PREFIX =
'patientPerson/'
- RELATIONSHIP_PREFIX =
'relationshipHolder1/'
- GENDER_XPATH =
'administrativeGenderCode/@code'
- DOB_XPATH =
'birthTime/@value'
- SSN_XPATH =
'asOtherIDs'
- NAME_XPATH =
'name'
- NAME_LEGAL_INDICATOR =
'L'
- NAME_PREFERRED_INDICATOR =
'ASGN'
- ADDRESS_XPATH =
'addr'
- DECEASED_XPATH =
'deceasedTime/@value'
- PHONE =
'telecom'
- PERSON_TYPE =
'PERSON_TYPE'
- RELATIONSHIP_PERSON_TYPE =
'RoleCode'
- PERSON_TYPE_SEPARATOR =
'~'
- PERSON_TYPE_VALUE_XPATH =
'value/@code'
- PERSON_TYPE_CODE_XPATH =
'code/@code'
- RELATIONSHIP_PERSON_TYPE_VALUE_XPATH =
'code/@code'
- RELATIONSHIP_PERSON_TYPE_CODE_XPATH =
'code/@codeSystemName'
- ADMIN_OBSERVATION_XPATH =
'*/administrativeObservation'
- ACKNOWLEDGEMENT_DETAIL_XPATH =
'acknowledgement/acknowledgementDetail/text'
- ACKNOWLEDGEMENT_TARGET_MESSAGE_ID_EXTENSION_XPATH =
'acknowledgement/targetMessage/id/@extension'
- MULTIPLE_MATCHES_FOUND =
'Multiple Matches Found'
- PATIENT_RELATIONSHIP_XPATH =
'patientPerson/personalRelationship'
Identity::Parsers::GCIdsConstants::ACTIVE_MHV_IDS_REGEX, Identity::Parsers::GCIdsConstants::BIRLS_IDS_REGEX, Identity::Parsers::GCIdsConstants::CERNER_FACILITY_IDS_REGEX, Identity::Parsers::GCIdsConstants::CERNER_ID_REGEX, Identity::Parsers::GCIdsConstants::DOD_ROOT_OID, Identity::Parsers::GCIdsConstants::EDIPI_REGEX, Identity::Parsers::GCIdsConstants::ICN_ASSIGNING_AUTHORITY_ID, Identity::Parsers::GCIdsConstants::ICN_REGEX, Identity::Parsers::GCIdsConstants::IDENTIFIERS_SPLIT_TOKEN, Identity::Parsers::GCIdsConstants::IDME_ID_REGEX, Identity::Parsers::GCIdsConstants::IDS_SPLIT_TOKEN, Identity::Parsers::GCIdsConstants::ID_MAPPINGS, Identity::Parsers::GCIdsConstants::LOGINGOV_ID_REGEX, Identity::Parsers::GCIdsConstants::MHV_IDS_REGEX, Identity::Parsers::GCIdsConstants::MHV_IEN_REGEX, Identity::Parsers::GCIdsConstants::PERMANENT_ICN_REGEX, Identity::Parsers::GCIdsConstants::SEC_ID_REGEX, Identity::Parsers::GCIdsConstants::VA_ROOT_OID, Identity::Parsers::GCIdsConstants::VBA_CORP_ID_REGEX, Identity::Parsers::GCIdsConstants::VET360_ID_REGEX, Identity::Parsers::GCIdsConstants::VHA_FACILITY_IDS_REGEX
Constants inherited
from ParserBase
MPI::Responses::ParserBase::EXTERNAL_RESPONSE_CODES
Instance Method Summary
collapse
#build_hash, #parse_string_gcids, #parse_xml_gcids, #select, #select_extension, #select_icn_with_aaid, #select_token_position
#sanitize_edipi, #sanitize_id, #sanitize_id_array
#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata
Methods inherited from ParserBase
#failed_or_invalid?, #failed_request?, #invalid_request?, #locate_element, #locate_elements, #unknown_error?
Constructor Details
Returns a new instance of ProfileParser.
54
55
56
57
58
|
# File 'lib/mpi/responses/profile_parser.rb', line 54
def initialize(response)
@transaction_id = response.['x-global-transaction-id']
@original_body = locate_element(response.body, BODY_XPATH)
@code = locate_element(@original_body, CODE_XPATH)
end
|
Instance Method Details
#build_mpi_profile(patient) ⇒ Object
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# File 'lib/mpi/responses/profile_parser.rb', line 102
def build_mpi_profile(patient)
profile_identity_hash = create_mpi_profile_identity(patient)
profile_ids_hash = create_mpi_profile_ids(patient)
misc_hash = {
search_token: locate_element(@original_body, 'id').attributes[:extension],
relationships: parse_relationships(patient.locate(PATIENT_RELATIONSHIP_XPATH)),
id_theft_flag: parse_id_theft_flag(patient),
transaction_id: @transaction_id
}
mpi_attribute_validations(profile_identity_hash, profile_ids_hash)
log_mpi_relationships(misc_hash[:relationships]) if misc_hash[:relationships].present?
MPI::Models::MviProfile.new(profile_identity_hash.merge(profile_ids_hash).merge(misc_hash))
end
|
#build_relationship_mpi_profile(relationship) ⇒ Object
121
122
123
124
125
|
# File 'lib/mpi/responses/profile_parser.rb', line 121
def build_relationship_mpi_profile(relationship)
relationship_identity_hash = create_mpi_profile_relationship_identity(relationship)
relationship_ids_hash = create_mpi_profile_ids(locate_element(relationship, RELATIONSHIP_PREFIX))
MPI::Models::MviProfileRelationship.new(relationship_identity_hash.merge(relationship_ids_hash))
end
|
#create_ids_obj(full_mvi_ids, parsed_mvi_ids) ⇒ Object
169
170
171
172
173
|
# File 'lib/mpi/responses/profile_parser.rb', line 169
def create_ids_obj(full_mvi_ids, parsed_mvi_ids)
{
full_mvi_ids:
}.merge(parse_single_ids(parsed_mvi_ids).merge(parse_multiple_ids(parsed_mvi_ids)))
end
|
#create_mpi_profile_identity(person) ⇒ Object
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/mpi/responses/profile_parser.rb', line 143
def create_mpi_profile_identity(person)
person_component = locate_element(person, PATIENT_PERSON_PREFIX)
person_types = parse_person_type(person)
name = parse_name(locate_elements(person_component, NAME_XPATH))
preferred_names = parse_name(locate_elements(person_component, NAME_XPATH), indicator: NAME_PREFERRED_INDICATOR)
{
given_names: name[:given],
family_name: name[:family],
suffix: name[:suffix],
preferred_names: preferred_names[:given],
gender: locate_element(person_component, GENDER_XPATH),
birth_date: locate_element(person_component, DOB_XPATH),
deceased_date: locate_element(person_component, DECEASED_XPATH),
ssn: parse_ssn(locate_element(person_component, SSN_XPATH)),
address: parse_address(person_component),
home_phone: parse_phone(person, PATIENT_PERSON_PREFIX),
person_types:
}
end
|
#create_mpi_profile_ids(patient) ⇒ Object
163
164
165
166
167
|
# File 'lib/mpi/responses/profile_parser.rb', line 163
def create_mpi_profile_ids(patient)
full_mvi_ids = get_extensions(patient.locate('id'))
parsed_mvi_ids = parse_xml_gcids(patient.locate('id'))
create_ids_obj(full_mvi_ids, parsed_mvi_ids)
end
|
#create_mpi_profile_relationship_identity(relationship) ⇒ Object
132
133
134
135
136
137
138
139
140
141
|
# File 'lib/mpi/responses/profile_parser.rb', line 132
def create_mpi_profile_relationship_identity(relationship)
person_component = locate_element(relationship, RELATIONSHIP_PREFIX)
person_types = parse_relationship_person_type(relationship)
name = parse_relationship_name(locate_elements(person_component, NAME_XPATH))
{
given_names: name[:given],
family_name: name[:family],
person_types:
}
end
|
#error_details ⇒ Object
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/mpi/responses/profile_parser.rb', line 81
def error_details
error_details = {
ack_detail_code: @code,
id_extension: locate_element(@original_body, ACKNOWLEDGEMENT_TARGET_MESSAGE_ID_EXTENSION_XPATH),
transaction_id: @transaction_id,
error_texts: []
}
error_text_nodes = locate_elements(@original_body, ACKNOWLEDGEMENT_DETAIL_XPATH)
if error_text_nodes.nil?
error_details[:error_texts] = error_text_nodes
else
error_text_nodes.each do |node|
error_text = node.text || node&.nodes&.first&.value
error_details[:error_texts].append(error_text) unless error_details[:error_texts].include?(error_text)
end
end
{ error_details: }
end
|
#get_extensions(id_array) ⇒ Object
204
205
206
207
208
|
# File 'lib/mpi/responses/profile_parser.rb', line 204
def get_extensions(id_array)
id_array.map do |id_object|
id_object.attributes[:extension]
end
end
|
#log_inactive_mhv_ids(mhv_ids, active_mhv_ids) ⇒ Object
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
# File 'lib/mpi/responses/profile_parser.rb', line 220
def log_inactive_mhv_ids(mhv_ids, active_mhv_ids)
return if mhv_ids.blank?
if (mhv_ids - active_mhv_ids).present?
log_message_to_sentry('Inactive MHV correlation IDs present', :info,
ids: mhv_ids)
end
unless active_mhv_ids.include?(mhv_ids.first)
log_message_to_sentry('Returning inactive MHV correlation ID as first identifier', :warn,
ids: mhv_ids)
end
if active_mhv_ids.uniq.size > 1
log_message_to_sentry('Multiple active MHV correlation IDs present', :info,
ids: active_mhv_ids)
end
end
|
#log_mpi_relationships(relationships) ⇒ Object
215
216
217
218
|
# File 'lib/mpi/responses/profile_parser.rb', line 215
def log_mpi_relationships(relationships)
Rails.logger.info('[MPI][Responses][ProfileParser] Relationships detected',
{ person_types: relationships.map(&:person_types) })
end
|
#mpi_attribute_validations(identity_hash, ids_hash) ⇒ Object
210
211
212
213
|
# File 'lib/mpi/responses/profile_parser.rb', line 210
def mpi_attribute_validations(identity_hash, ids_hash)
log_inactive_mhv_ids(ids_hash[:mhv_ids].to_a, ids_hash[:active_mhv_ids].to_a)
validate_dob(identity_hash[:birth_date], ids_hash[:icn])
end
|
#multiple_match? ⇒ Boolean
60
61
62
63
64
65
|
# File 'lib/mpi/responses/profile_parser.rb', line 60
def multiple_match?
acknowledgement_detail = locate_element(@original_body, ACKNOWLEDGEMENT_DETAIL_XPATH)
return false unless acknowledgement_detail
acknowledgement_detail.nodes.first == MULTIPLE_MATCHES_FOUND
end
|
#no_match? ⇒ Boolean
67
68
69
|
# File 'lib/mpi/responses/profile_parser.rb', line 67
def no_match?
locate_element(@original_body, SUBJECT_XPATH).blank?
end
|
#parse ⇒ Object
71
72
73
74
75
76
77
78
79
|
# File 'lib/mpi/responses/profile_parser.rb', line 71
def parse
subject = locate_element(@original_body, SUBJECT_XPATH)
return MPI::Models::MviProfile.new({ transaction_id: @transaction_id }) unless subject
patient = locate_element(subject, PATIENT_XPATH)
return MPI::Models::MviProfile.new({ transaction_id: @transaction_id }) unless patient
build_mpi_profile(patient)
end
|
#parse_address(person) ⇒ Object
281
282
283
284
285
286
287
288
|
# File 'lib/mpi/responses/profile_parser.rb', line 281
def parse_address(person)
el = locate_element(person, ADDRESS_XPATH)
return nil unless el
address_hash = el.nodes.map { |n| { n.value.snakecase.to_sym => n.nodes.first } }.reduce({}, :merge)
address_hash[:street] = address_hash.delete :street_address_line
MPI::Models::MviProfileAddress.new(address_hash)
end
|
#parse_id_theft_flag(patient) ⇒ Object
#parse_multiple_ids(parsed_mvi_ids) ⇒ Object
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
# File 'lib/mpi/responses/profile_parser.rb', line 189
def parse_multiple_ids(parsed_mvi_ids)
{
mhv_ids: parsed_mvi_ids[:mhv_ids],
active_mhv_ids: parsed_mvi_ids[:active_mhv_ids],
edipis: sanitize_id_array(parsed_mvi_ids[:edipis]),
participant_ids: sanitize_id_array(parsed_mvi_ids[:vba_corp_ids]),
mhv_iens: sanitize_id_array(parsed_mvi_ids[:mhv_iens]),
sec_ids: parsed_mvi_ids[:sec_ids],
vha_facility_ids: parsed_mvi_ids[:vha_facility_ids],
vha_facility_hash: parsed_mvi_ids[:vha_facility_hash],
birls_ids: sanitize_id_array(parsed_mvi_ids[:birls_ids]),
cerner_facility_ids: parsed_mvi_ids[:cerner_facility_ids]
}
end
|
#parse_name(name, indicator: NAME_LEGAL_INDICATOR) ⇒ Object
253
254
255
256
257
258
259
260
261
262
263
|
# File 'lib/mpi/responses/profile_parser.rb', line 253
def parse_name(name, indicator: NAME_LEGAL_INDICATOR)
name_element = parse_name_node(name, indicator:)
given = [*name_element.locate('given')].map { |el| el.nodes.first.capitalize }
family = name_element.locate('family')&.first&.nodes&.first&.capitalize
suffix = name_element.locate('suffix')&.first&.nodes&.first&.capitalize
{ given:, family:, suffix: }
rescue
Rails.logger.warn 'MPI::Response.parse_name failed' if indicator == NAME_LEGAL_INDICATOR
{ given: nil, family: nil }
end
|
#parse_name_node(name_array, indicator: NAME_LEGAL_INDICATOR) ⇒ Object
265
266
267
|
# File 'lib/mpi/responses/profile_parser.rb', line 265
def parse_name_node(name_array, indicator: NAME_LEGAL_INDICATOR)
name_array.find { |name_element| name_element if name_element.attributes[:use] == indicator }
end
|
#parse_person_type(person) ⇒ Object
#parse_phone(person, person_prefix) ⇒ Object
290
291
292
293
294
295
|
# File 'lib/mpi/responses/profile_parser.rb', line 290
def parse_phone(person, person_prefix)
el = locate_element(person, PHONE) || locate_element(person, person_prefix + PHONE)
return nil unless el
el.attributes[:value]
end
|
#parse_relationship_name(name) ⇒ Object
243
244
245
246
247
248
249
250
251
|
# File 'lib/mpi/responses/profile_parser.rb', line 243
def parse_relationship_name(name)
name_element = parse_name_node(name, indicator: NAME_PREFERRED_INDICATOR) ||
parse_name_node(name, indicator: NAME_LEGAL_INDICATOR)
return { given: nil, family: nil } if name_element.blank?
given = [*name_element.locate('given')].map { |el| el.nodes.first.capitalize }
family = name_element.locate('family').first.nodes.first.capitalize
{ given:, family: }
end
|
#parse_relationship_person_type(element) ⇒ Object
#parse_relationships(relationships_array) ⇒ Object
117
118
119
|
# File 'lib/mpi/responses/profile_parser.rb', line 117
def parse_relationships(relationships_array)
relationships_array.map { |relationship| build_relationship_mpi_profile(relationship) }
end
|
#parse_single_ids(parsed_mvi_ids) ⇒ Object
175
176
177
178
179
180
181
182
183
184
185
186
187
|
# File 'lib/mpi/responses/profile_parser.rb', line 175
def parse_single_ids(parsed_mvi_ids)
{
icn: parsed_mvi_ids[:icn],
edipi: sanitize_edipi(parsed_mvi_ids[:edipi]),
participant_id: sanitize_id(parsed_mvi_ids[:vba_corp_id]),
mhv_ien: sanitize_id(parsed_mvi_ids[:mhv_ien]),
sec_id: parsed_mvi_ids[:sec_id],
birls_id: sanitize_id(parsed_mvi_ids[:birls_id]),
vet360_id: parsed_mvi_ids[:vet360_id],
icn_with_aaid: parsed_mvi_ids[:icn_with_aaid],
cerner_id: parsed_mvi_ids[:cerner_id]
}
end
|
#parse_ssn(other_ids) ⇒ Object
other_ids can be hash or array of hashes
270
271
272
273
274
275
276
277
278
279
|
# File 'lib/mpi/responses/profile_parser.rb', line 270
def parse_ssn(other_ids)
other_ids = [other_ids] unless other_ids.is_a? Array
ssn_element = select_ssn_element(other_ids)
return nil unless ssn_element
ssn_element.attributes[:extension]
rescue
Rails.logger.warn 'MPI::Response.parse_ssn failed'
nil
end
|
#select_ssn_element(other_ids) ⇒ Object
297
298
299
300
301
302
|
# File 'lib/mpi/responses/profile_parser.rb', line 297
def select_ssn_element(other_ids)
other_ids.each do |oi|
node = oi.nodes.select { |n| n.attributes[:root] == SSN_ROOT_ID }
return node.first unless node.empty?
end
end
|
#validate_dob(dob, icn) ⇒ Object
237
238
239
240
241
|
# File 'lib/mpi/responses/profile_parser.rb', line 237
def validate_dob(dob, icn)
Date.iso8601(dob)
rescue Date::Error
Rails.logger.warn 'MPI::Response.parse_dob failed', { dob:, icn: }
end
|