Skip to content

Commit

Permalink
Merge pull request #425 from LinuxForHealth/Issue411-Additional-patie…
Browse files Browse the repository at this point in the history
…nt.identifier-support-IN2.2,-6,-8

Addtl support to patient.idnt IN2.2,6,8
  • Loading branch information
cragun47 authored Jan 28, 2022
2 parents 933f598 + 070d1ec commit 58ad7c9
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2020, 2021
* (C) Copyright IBM Corp. 2020, 2022
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -69,6 +69,7 @@ public enum SimpleDataTypeMapper {
POLICYHOLDER_RELATIONSHIP(SimpleDataValueResolver.POLICYHOLDER_RELATIONSHIP),
SUBSCRIBER_RELATIONSHIP(SimpleDataValueResolver.SUBSCRIBER_RELATIONSHIP),
RELATED_PERSON_NEEDED(SimpleDataValueResolver.RELATED_PERSON_NEEDED),
SUBSCRIBER_IS_SELF(SimpleDataValueResolver.SUBSCRIBER_IS_SELF),
UNIT_SYSTEM(SimpleDataValueResolver.UNIT_SYSTEM),
ENCOUNTER_MODE_ARRIVAL_DISPLAY(SimpleDataValueResolver.ENCOUNTER_MODE_ARRIVAL_DISPLAY);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@ public class SimpleDataValueResolver {
return getFHIRCode(val, "RelatedPersonNeeded");
};

// Maps from IN1.17 or IN2.72 to a boolean string TRUE if the subscriber is equivalent to SELF
public static final ValueExtractor<Object, String> SUBSCRIBER_IS_SELF = (Object value) -> {
String val = Hl7DataHandlerUtil.getStringValue(value);
return getFHIRCode(val, "SubscriberIsSelf");
};

public static final ValueExtractor<Object, SimpleCode> MARITAL_STATUS = (Object value) -> {
String val = Hl7DataHandlerUtil.getStringValue(value);
String text = Hl7DataHandlerUtil.getOriginalDisplayText(value);
Expand Down
13 changes: 11 additions & 2 deletions src/main/resources/hl7/codesystem/v2ToFhirMapping.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# (C) Copyright IBM Corp. 2020
# (C) Copyright IBM Corp. 2020, 2022
#
# SPDX-License-Identifier: Apache-2.0
#
Expand Down Expand Up @@ -545,4 +545,13 @@ RelatedPersonNeeded:
# 16: Sponsored dependent : no relatedPerson
17: TRUE # Minor dependent of a minor dependant input (grandchild dependent) : Grandparent
18: TRUE # Parent : Child
19: TRUE # Grandparent : Grandchild
19: TRUE # Grandparent : Grandchild

# Indicates whether the input code maps to SELF by returning TRUE.
# FALSE and no match are equivalent.
# Only matching codes listed because all other codes fail.
SubscriberIsSelf:
# Codes from IN1.17 (values from table 0063)
SEL: TRUE
# Codes from IN2.72 (values from table 0344)
01: TRUE # Patient is insured : no relatedPerson
2 changes: 2 additions & 0 deletions src/main/resources/hl7/message/ADT_A01.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ resources:
additionalSegments:
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2

- resourceName: Encounter
segment: PV1
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/hl7/message/ADT_A03.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ resources:
additionalSegments:
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2


- resourceName: Encounter
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/hl7/message/ADT_A04.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ resources:
additionalSegments:
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2


- resourceName: Encounter
Expand Down
4 changes: 3 additions & 1 deletion src/main/resources/hl7/message/ADT_A08.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# (C) Copyright IBM Corp. 2021
# (C) Copyright IBM Corp. 2021, 2022
#
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -22,6 +22,8 @@ resources:
additionalSegments:
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2

- resourceName: Encounter
segment: PV1
Expand Down
6 changes: 4 additions & 2 deletions src/main/resources/hl7/message/ADT_A28.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ resources:
repeats: false
isReferenced: true
additionalSegments:
- PD1
- MSH
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2

- resourceName: Encounter
segment: PV1
Expand Down
6 changes: 4 additions & 2 deletions src/main/resources/hl7/message/ADT_A31.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ resources:
repeats: false
isReferenced: true
additionalSegments:
- PD1
- MSH
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2

- resourceName: Encounter
segment: PV1
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/hl7/message/DFT_P03.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ resources:
- PD1
- MSH
- INSURANCE.IN1
- INSURANCE.IN2

- resourceName: Encounter
segment: PV1
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/hl7/resource/Coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ subscriber_1:
# If the subscriber is SEL (self), do not create a relatedPerson, but reference the patient
# NOT_NULL check is not needed because we have positive values and condition will not fire without them
subscriber_2:
condition: $relatedRelationshipStr EQUALS SEL || $relatedRelationshipStr EQUALS 01
condition: $subscriberIsSelf EQUALS TRUE
valueOf: datatype/Reference
expressionType: resource
specs: $Patient
vars:
relatedRelationshipStr: String, IN1.17 | IN2.72
subscriberIsSelf: SUBSCRIBER_IS_SELF, IN1.17 | IN2.72 # subscriber relationship

subscriberId:
type: STRING
Expand Down
85 changes: 79 additions & 6 deletions src/main/resources/hl7/resource/Patient.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# (C) Copyright IBM Corp. 2020, 2021
# (C) Copyright IBM Corp. 2020, 2022
#
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -19,14 +19,46 @@ identifier_1:
vars:
assignerSystem: String, PID.3.4

# Gets the SSN from PID.19, formats and adds it as an ID
identifier_2:
condition: $valueIn NOT_NULL
# NOTE: indentifier_2a and indentifier_2b can be combined when complex boolean conditions supported
# When the Coverage.subscriber is not self use PID.19 for SSN identifier
identifier_2a:
condition: $valueIn NOT_NULL && $subscriberIsSelf NOT_EQUALS TRUE
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: String, PID.19
valueIn: String, PID.19 # subscriber SSN
subscriberIsSelf: SUBSCRIBER_IS_SELF, IN1.17 | IN2.72 # subscriber relationship
constants:
system: http://terminology.hl7.org/CodeSystem/v2-0203
code: SS
display: Social Security number
# There is no text for PID.19

# When the Coverage.subscriber is null use PID.19 for SSN identifier
identifier_2b:
condition: $valueIn NOT_NULL && $subscriberIsSelf NULL
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: String, PID.19 # subscriber SSN
subscriberIsSelf: SUBSCRIBER_IS_SELF, IN1.17 | IN2.72 # subscriber relationship
constants:
system: http://terminology.hl7.org/CodeSystem/v2-0203
code: SS
display: Social Security number
# There is no text for PID.19

# When the Coverage.subscriber is self use PID.19 / IN2.2 for SSN identifier
identifier_2c:
condition: $valueIn NOT_NULL && $subscriberIsSelf EQUALS TRUE
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: String, PID.19 | IN2.2 # subscriber SSN
subscriberIsSelf: SUBSCRIBER_IS_SELF, IN1.17 | IN2.72 # subscriber relationship
constants:
system: http://terminology.hl7.org/CodeSystem/v2-0203
code: SS
Expand Down Expand Up @@ -72,6 +104,47 @@ identifier_5:
constants:
system: http://terminology.hl7.org/CodeSystem/v2-0203

# only include when the subscriber is self
identifier_6:
condition: $valueIn NOT_NULL && $subscriberIsSelf EQUALS TRUE
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: IN2.61 | IN1.36
subscriberIsSelf: SUBSCRIBER_IS_SELF, IN1.17 | IN2.72 # subscriber relationship
# No systemCX set for this identifier
constants:
system: "http://terminology.hl7.org/CodeSystem/v2-0203"
code: "MB"
display: "Member Number"

identifier_7:
condition: $valueIn NOT_NULL
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: IN2.8
# No systemCX set for this identifier
constants:
system: "http://terminology.hl7.org/CodeSystem/v2-0203"
code: "MA"
display: "Patient Medicaid number"

identifier_8:
condition: $valueIn NOT_NULL
valueOf: datatype/Identifier_var
generateList: true
expressionType: resource
vars:
valueIn: IN2.6
# No systemCX set for this identifier
constants:
system: "http://terminology.hl7.org/CodeSystem/v2-0203"
code: "MC"
display: "Patient's Medicare number"

name:
valueOf: datatype/HumanName
generateList: true
Expand Down Expand Up @@ -187,7 +260,7 @@ generalPractitioner:
specs: PD1.4
vars:
practitionerVal: PD1.4

extension:
generateList: true
expressionType: nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ void testBasicInsuranceCoverageFields() throws IOException {
// IN1.36 also to subscriberId
// IN1.46 to third XV Coverage.identifier
// IN1.49 to PatientCoverage.identifier
+ "|MEMBER36||||||||||Value46|||PatientId49.1^^^System49.4^TypeCode49.5||||\n"
+ "|MEMBER36||||||||||Value46|||PatientId49.1^^^System49.4^XX||||\n"
// IN2.6 is purposely empty so will not create an MC Coverage.identifier
// IN2.8 is purposely empty so will not create an MA Coverage.identifier
// IN2.25 to new PayorId Organization
Expand Down Expand Up @@ -131,7 +131,7 @@ void testBasicInsuranceCoverageFields() throws IOException {
patientIdentifier = patient.getIdentifier().get(1);
assertThat(patientIdentifier.getValue()).isEqualTo("PatientId49.1"); // IN1.49.1
assertThat(patientIdentifier.getSystem()).isEqualTo("urn:id:System49.4"); // IN1.49.4
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "TypeCode49.5", null,
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "XX", null,
"http://terminology.hl7.org/CodeSystem/v2-0203", null); // IN1.49.5

List<Resource> organizations = ResourceUtils.getResourceList(e, ResourceType.Organization);
Expand Down Expand Up @@ -353,8 +353,8 @@ void testInsuranceCoverageByRelatedFields(String messageType) throws IOException
// IN1.50 through IN1.53 NOT REFERENCED
+ "|MEMBER36|||||||F|||Value46|||J494949^^^Large HMO^XX||||\n"
// IN2.2 to RelatedPerson.identifier (SSN)
// IN2.6 to Coverage.identifier MC Patient's Medicare number
// IN2.8 to Coverage.identifier MA Patient Medicaid number
// IN2.6 to Coverage.identifier MC Patient's Medicare number and Patient.identifier MC Medicare number
// IN2.8 to Coverage.identifier MA Patient Medicaid number and Patient.identifier MA Medicare number
// IN2.9 through IN2.60 not used
+ "IN2||777-88-9999||||MEDICARE06||MEDICAID08|| |||||||||| ||||||||||| |||||||||| |||||||||| ||||||||||"
// IN2.61 to Coverage.identifier MB; takes priority over IN1.36
Expand All @@ -379,6 +379,28 @@ void testInsuranceCoverageByRelatedFields(String messageType) throws IOException
assertThat(patients).hasSize(1); // From PID
Patient patient = (Patient) patients.get(0);
String patientId = patient.getId();
assertThat(patient.getIdentifier()).hasSize(4); // From PID.3, IN1.49, IN2.6, IN2.8
Identifier patientIdentifier = patient.getIdentifier().get(0);
assertThat(patientIdentifier.getValue()).isEqualTo("MR1"); // PID.3.1
assertThat(patientIdentifier.getSystem()).isEqualTo("urn:id:XYZ"); // PID.3.4
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "MR", "Medical record number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null); // PID.3.5
patientIdentifier = patient.getIdentifier().get(1);
assertThat(patientIdentifier.getValue()).isEqualTo("J494949"); // IN1.49.1
assertThat(patientIdentifier.getSystem()).isEqualTo("urn:id:Large_HMO"); // IN1.49.4
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "XX", null,
"http://terminology.hl7.org/CodeSystem/v2-0203", null); // IN1.49.5
patientIdentifier = patient.getIdentifier().get(2);
assertThat(patientIdentifier.getValue()).isEqualTo("MEDICAID08"); // IN2.8
assertThat(patientIdentifier.hasSystem()).isFalse(); // No system for IN2.8
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "MA", "Patient Medicaid number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null);
patientIdentifier = patient.getIdentifier().get(3);
assertThat(patientIdentifier.getValue()).isEqualTo("MEDICARE06"); // IN2.6
assertThat(patientIdentifier.hasSystem()).isFalse(); // No system for IN2.6
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "MC",
"Patient's Medicare number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null);

List<Resource> organizations = ResourceUtils.getResourceList(e, ResourceType.Organization);
assertThat(organizations).hasSize(1); // From Payor created by IN1
Expand Down Expand Up @@ -517,6 +539,7 @@ void testInsuranceCoverageOfSelfAndTenant() throws IOException {

String hl7message = "MSH|^~\\&|||||20151008111200||DFT^P03^DFT_P03|MSGID000001|T|2.6|||||||||\n"
+ "EVN||20210407191342||||||\n"
// PID.19 purposely empty so IN2.2 used as SSN PatientIdentifier
+ "PID|||MR1^^^XYZ^MR||DOE^JANE^|||F||||||||||||||||||||||\n"
+ "PV1||I||||||||||||||||||||||||||||||||||||||||||\n"
// FT1 added for completeness; required in specification, but not used (ignored) by templates
Expand All @@ -543,11 +566,13 @@ void testInsuranceCoverageOfSelfAndTenant() throws IOException {
// IN1.46 to third XV Coverage.identifier
// IN1.47 through IN1.53 NOT REFERENCED
+ "|MEMBER36||||||||||Value46|||||||\n"
// IN2.2 to SSN Patient.identifier because relationship = self and PID.19 is empty
// IN2.6 is purposely empty so will not create an MC Coverage.identifier
// IN2.8 is purposely empty so will not create an MA Coverage.identifier
// IN2.25 to new PayorId Organization
// IN2.61 is purposely empty (primary to IN1.36) so IN1.36 will be used as the MB Coverage.identifier
+ "IN2|||||||||||||||||||||||||IdValue25.1^^^IdSystem25.4^IdType25.5^^20201231145045^20211231145045|||||||||||||||||||||||||||||||||||||||||||"
// IN2.61 is purposely empty (primary to IN1.36) so IN1.36 will be used as the MB Coverage.identifier and MB Patient.Identifier
// Only used for MB Patient.Identifier because subscriber is SELF
+ "IN2||SSN123456|||||||||||||||||||||||IdValue25.1^^^IdSystem25.4^IdType25.5^^20201231145045^20211231145045|||||||||||||||||||||||||||||||||||||||||||"
// IN2.69 to new PolicyHolder Organization Name and ID
// IN2.72 is purposely empty (backup to IN1.17) so no RelatedPerson is created.
+ "|Name69.1^^^^^IdSystem69.6^XX^^^IdValue69.10||\n";
Expand All @@ -565,6 +590,23 @@ void testInsuranceCoverageOfSelfAndTenant() throws IOException {
assertThat(patients).hasSize(1); // From PID
Patient patient = (Patient) patients.get(0);
String patientId = patient.getId();
// Check Patient.identifiers
assertThat(patient.getIdentifier()).hasSize(3); // From PID.3, IN2.2 and IN1.36
Identifier patientIdentifier = patient.getIdentifier().get(0);
assertThat(patientIdentifier.getValue()).isEqualTo("MR1"); // PID.3.1
assertThat(patientIdentifier.getSystem()).isEqualTo("urn:id:XYZ"); // PID.3.4
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "MR", "Medical record number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null); // PID.3.5
patientIdentifier = patient.getIdentifier().get(1);
assertThat(patientIdentifier.getValue()).isEqualTo("MEMBER36"); // IN1.36 backup to IN2.61, active because subscriber is SELF
assertThat(patientIdentifier.hasSystem()).isFalse(); // No system for MB
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "MB", "Member Number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null);
patientIdentifier = patient.getIdentifier().get(2);
assertThat(patientIdentifier.getValue()).isEqualTo("SSN123456"); // IN2.2
assertThat(patientIdentifier.hasSystem()).isFalse(); // No system for SSN
DatatypeUtils.checkCommonCodeableConceptAssertions(patientIdentifier.getType(), "SS", "Social Security number",
"http://terminology.hl7.org/CodeSystem/v2-0203", null);

List<Resource> organizations = ResourceUtils.getResourceList(e, ResourceType.Organization);
assertThat(organizations).hasSize(3); // From Payor created by IN1, PayorId Organization (IN2.25), and PolcyHolder Organization Name (IN2.69)
Expand Down

0 comments on commit 58ad7c9

Please sign in to comment.