Skip to content

Commit 496fa86

Browse files
NIAD-3304: Allow non-SNOMEDCT codes to be preserved when mapping CodeableConcepts (#1133)
* NIAD-3304: Add non-snomed code mapping to translations when mapping `CodeableConcept`s * Remove unnecessary non-snomed code systems from test files as the functionality has changed and are testing in a separate test * Update `CodeableConceptCdTemplateParameters` to include a property for translations. * Update `codeable_concept_cd_template.mustache` to handle translations. * Add test to ensure that non-snomed codes are populated as translations in the produced XML when a SNOMEDCT code is present. * Add functionality to `CodeableConceptCdMapper` to populate translations in the XML when non-SNOMEDCT codes have been provided alongside the SNOMEDCT Code. * * Update ObservationMapperTest XML files to reflect that Read V2 codes are now being preserved. * * Remove unnecessary null checks when populating builder parameters. * * SonarCube recommended fix: Remove useless assignment to local variable "nonSnomedCodeCodings"
1 parent 3c7d44e commit 496fa86

19 files changed

+123
-66
lines changed

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/CodeableConceptCdMapper.java

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import lombok.RequiredArgsConstructor;
1818
import lombok.extern.slf4j.Slf4j;
1919
import uk.nhs.adaptors.gp2gp.ehr.mapper.parameters.CodeableConceptCdTemplateParameters;
20+
import uk.nhs.adaptors.gp2gp.ehr.utils.CodeSystemsUtil;
2021
import uk.nhs.adaptors.gp2gp.ehr.utils.CodeableConceptMappingUtils;
2122
import uk.nhs.adaptors.gp2gp.ehr.utils.TemplateUtils;
2223

@@ -63,17 +64,14 @@ public String mapCodeableConceptToCd(CodeableConcept codeableConcept) {
6364

6465
builder.mainCodeSystem(SNOMED_SYSTEM_CODE);
6566

66-
if (descriptionExtensions.isPresent()) {
67-
var mainCode = getMainCode(descriptionExtensions.get(), snomedCodeCoding.get());
68-
mainCode.ifPresent(builder::mainCode);
67+
var mainCode = getMainCode(descriptionExtensions, snomedCodeCoding.get());
68+
mainCode.ifPresent(builder::mainCode);
6969

70-
var mainDisplayName = getMainDisplayName(descriptionExtensions.get(), snomedCodeCoding.get());
71-
mainDisplayName.ifPresent(builder::mainDisplayName);
70+
var mainDisplayName = getMainDisplayName(descriptionExtensions, snomedCodeCoding.get());
71+
mainDisplayName.ifPresent(builder::mainDisplayName);
7272

73-
if (codeableConcept.hasText()) {
74-
builder.mainOriginalText(codeableConcept.getText());
75-
}
76-
}
73+
builder.mainOriginalText(codeableConcept.getText());
74+
builder.translations(getNonSnomedCodeCodings(codeableConcept));
7775

7876
return TemplateUtils.fillTemplate(CODEABLE_CONCEPT_CD_TEMPLATE, builder.build());
7977
}
@@ -329,6 +327,20 @@ private Optional<Coding> getSnomedCodeCoding(CodeableConcept codeableConcept) {
329327
.findFirst();
330328
}
331329

330+
private List<Coding> getNonSnomedCodeCodings(CodeableConcept codeableConcept) {
331+
var nonSnomedCodeCodings = codeableConcept.getCoding()
332+
.stream()
333+
.filter(coding -> !isSnomed(coding))
334+
.toList();
335+
336+
for (Coding coding : nonSnomedCodeCodings) {
337+
var hl7CodeSystem = CodeSystemsUtil.getHl7code(coding.getSystem());
338+
coding.setSystem(hl7CodeSystem);
339+
}
340+
341+
return nonSnomedCodeCodings;
342+
}
343+
332344
private Optional<String> findOriginalText(CodeableConcept codeableConcept, Optional<Coding> coding) {
333345
if (coding.isPresent()) {
334346
if (codeableConcept.hasText()) {
@@ -457,30 +469,33 @@ private String buildNullFlavourCodeableConceptCd(CodeableConcept codeableConcept
457469
return TemplateUtils.fillTemplate(CODEABLE_CONCEPT_CD_TEMPLATE, builder.build());
458470
}
459471

460-
private Optional<String> getMainCode(List<Extension> descriptionExtensions, Coding snomedCodeCoding) {
461-
var descriptionCode = descriptionExtensions.stream()
462-
.filter(descriptionExt -> DESCRIPTION_ID.equals(descriptionExt.getUrl()))
463-
.map(description -> description.getValue().toString())
464-
.findFirst();
472+
private Optional<String> getMainCode(Optional<List<Extension>> descriptionExtensions, Coding snomedCodeCoding) {
473+
if (descriptionExtensions.isPresent()) {
474+
var descriptionCode = descriptionExtensions.get().stream()
475+
.filter(descriptionExt -> DESCRIPTION_ID.equals(descriptionExt.getUrl()))
476+
.map(description -> description.getValue().toString())
477+
.findFirst();
465478

466-
if (descriptionCode.isPresent()) {
467-
return descriptionCode;
479+
if (descriptionCode.isPresent()) {
480+
return descriptionCode;
481+
}
468482
}
469483

470484
return Optional.ofNullable(snomedCodeCoding.getCode());
471485
}
472486

473-
private Optional<String> getMainDisplayName(List<Extension> descriptionExtensions, Coding snomedCodeCoding) {
474-
var descriptionDisplayName = descriptionExtensions.stream()
475-
.filter(descriptionExt -> DESCRIPTION_DISPLAY.equals(descriptionExt.getUrl()))
476-
.map(description -> description.getValue().toString())
477-
.findFirst();
487+
private Optional<String> getMainDisplayName(Optional<List<Extension>> descriptionExtensions, Coding snomedCodeCoding) {
488+
if (descriptionExtensions.isPresent()) {
489+
var descriptionDisplayName = descriptionExtensions.get().stream()
490+
.filter(descriptionExt -> DESCRIPTION_DISPLAY.equals(descriptionExt.getUrl()))
491+
.map(description -> description.getValue().toString())
492+
.findFirst();
478493

479-
if (descriptionDisplayName.isPresent()) {
480-
return descriptionDisplayName;
494+
if (descriptionDisplayName.isPresent()) {
495+
return descriptionDisplayName;
496+
}
481497
}
482498

483499
return Optional.ofNullable(snomedCodeCoding.getDisplay());
484500
}
485-
486501
}

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/parameters/CodeableConceptCdTemplateParameters.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import lombok.Builder;
44
import lombok.Getter;
55
import lombok.Setter;
6+
import org.hl7.fhir.dstu3.model.Coding;
7+
8+
import java.util.List;
69

710
@Getter
811
@Setter
@@ -12,5 +15,6 @@ public class CodeableConceptCdTemplateParameters {
1215
private String mainCodeSystem;
1316
private String mainDisplayName;
1417
private String mainOriginalText;
18+
private List<Coding> translations;
1519
private boolean nullFlavor;
1620
}

service/src/main/resources/templates/codeable_concept_cd_template.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<code{{#nullFlavor}} nullFlavor="UNK"{{/nullFlavor}}{{^nullFlavor}} code="{{mainCode}}" codeSystem="{{mainCodeSystem}}" displayName="{{mainDisplayName}}"{{/nullFlavor}}>
2+
{{#translations}}
3+
<translation code="{{code}}" codeSystem="{{system}}" displayName="{{display}}" />
4+
{{/translations}}
25
{{#mainOriginalText}}
36
<originalText>{{mainOriginalText}}</originalText>
47
{{/mainOriginalText}}

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/CodeableConceptCdMapperTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,43 @@ public void When_MappingStubbedCodeableConcept_Expect_HL7CdObjectXml(String inpu
8585
.isEqualToIgnoringWhitespace(expectedOutput);
8686
}
8787

88+
@Test
89+
void When_MappingCodeableConceptWithNonSnomedCodeSystems_Expect_ManifestedXmlContainsTranslationsForThoseCodes() {
90+
var inputJson = """
91+
{
92+
"resourceType" : "Observation",
93+
"code": {
94+
"coding": [
95+
{
96+
"system": "http://snomed.info/sct",
97+
"code": "123456",
98+
"display": "Endometriosis of uterus"
99+
},
100+
{
101+
"system": "http://read.info/readv2",
102+
"code": "READ0",
103+
"display": "Read V2 Code Display"
104+
},
105+
{
106+
"system": "http://read.info/ctv3",
107+
"code": "READ1",
108+
"display": "Read CTV3 Code Display"
109+
}
110+
]
111+
}
112+
}""";
113+
var expectedOutputXml = """
114+
<code code="123456" codeSystem="2.16.840.1.113883.2.1.3.2.4.15" displayName="Endometriosis of uterus">
115+
<translation code="READ0" codeSystem="2.16.840.1.113883.2.1.6.2" displayName="Read V2 Code Display" />
116+
<translation code="READ1" codeSystem="2.16.840.1.113883.2.1.3.2.4.14" displayName="Read CTV3 Code Display" />
117+
</code>""";
118+
var codeableConcept = fhirParseService.parseResource(inputJson, Observation.class).getCode();
119+
120+
var outputMessageXml = codeableConceptCdMapper.mapCodeableConceptToCd(codeableConcept);
121+
122+
assertThat(outputMessageXml).isEqualToIgnoringWhitespace(expectedOutputXml);
123+
}
124+
88125
@ParameterizedTest
89126
@MethodSource("getTestArgumentsActualProblem")
90127
public void When_MappingStubbedCodeableConceptForActualProblemHeader_Expect_HL7CdObjectXml(String inputJson, String outputXml)

service/src/test/resources/ehr/mapper/codeableconcept/codeable_concept_snomed_with_description.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
"resourceType" : "Observation",
33
"code": {
44
"coding": [
5-
{
6-
"system": "http://blah.info/blahsomecodesystem",
7-
"code": "X%^^%",
8-
"display": "Display for invalid code/system",
9-
"userSelected": true
10-
},
115
{
126
"extension": [
137
{

service/src/test/resources/ehr/mapper/codeableconcept/codeable_concept_snomed_with_no_description.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
"resourceType" : "Observation",
33
"code": {
44
"coding": [
5-
{
6-
"system": "http://blah.info/blahsomecodesystem",
7-
"code": "X%^^%",
8-
"display": "Display for invalid code/system",
9-
"userSelected": true
10-
},
115
{
126
"extension": [
137
{

service/src/test/resources/ehr/mapper/codeableconcept/codeable_concept_with_text.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
"resourceType" : "Observation",
33
"code": {
44
"coding": [
5-
{
6-
"system": "http://blah.info/blahsomecodesystem",
7-
"code": "X%^^%",
8-
"display": "Display for invalid code/system",
9-
"userSelected": true
10-
},
115
{
126
"extension": [
137
{

service/src/test/resources/ehr/mapper/codeableconcept/codeable_concept_without_text.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22
"resourceType" : "Observation",
33
"code": {
44
"coding": [
5-
{
6-
"system": "http://blah.info/blahsomecodesystem",
7-
"code": "F%^^%",
8-
"display": "Happy puppet syndrome",
9-
"userSelected": true
10-
}, {
5+
{
116
"extension": [
127
{
138
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-coding-sctdescid",

service/src/test/resources/ehr/mapper/diagnosticreport/observation/observation_compound_statement_1.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<CompoundStatement classCode="CLUSTER" moodCode="EVN">
33
<id root="Mapped-From-Observation/B7F05EA7-A1A4-48C0-9C4C-CDB5768796B2"/>
44
<code code="2564081000000118" codeSystem="2.16.840.1.113883.2.1.3.2.4.15" displayName="Urine pregnancy test">
5-
</code>
5+
<translation code="465..00" codeSystem="2.16.840.1.113883.2.1.6.2" displayName="Urine pregnancy test" />
6+
</code>
67
<statusCode code="COMPLETE"/>
78
<effectiveTime>
89
<center value="20100223"/>
@@ -12,7 +13,8 @@
1213
<ObservationStatement classCode="OBS" moodCode="EVN">
1314
<id root="random-unmapped-id"/>
1415
<code code="2564081000000118" codeSystem="2.16.840.1.113883.2.1.3.2.4.15" displayName="Urine pregnancy test">
15-
</code>
16+
<translation code="465..00" codeSystem="2.16.840.1.113883.2.1.6.2" displayName="Urine pregnancy test" />
17+
</code>
1618
<statusCode code="COMPLETE"/>
1719
<effectiveTime>
1820
<center value="20100223"/>

service/src/test/resources/ehr/mapper/diagnosticreport/observation/observation_compound_statement_1_with_related_comment.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<CompoundStatement classCode="CLUSTER" moodCode="EVN">
33
<id root="Mapped-From-Observation/B7F05EA7-A1A4-48C0-9C4C-CDB5768796B2"/>
44
<code code="2564081000000118" codeSystem="2.16.840.1.113883.2.1.3.2.4.15" displayName="Urine pregnancy test">
5-
</code>
5+
<translation code="465..00" codeSystem="2.16.840.1.113883.2.1.6.2" displayName="Urine pregnancy test" />
6+
</code>
67
<statusCode code="COMPLETE"/>
78
<effectiveTime>
89
<center value="20100223"/>
@@ -12,7 +13,8 @@
1213
<ObservationStatement classCode="OBS" moodCode="EVN">
1314
<id root="random-unmapped-id"/>
1415
<code code="2564081000000118" codeSystem="2.16.840.1.113883.2.1.3.2.4.15" displayName="Urine pregnancy test">
15-
</code>
16+
<translation code="465..00" codeSystem="2.16.840.1.113883.2.1.6.2" displayName="Urine pregnancy test" />
17+
</code>
1618
<statusCode code="COMPLETE"/>
1719
<effectiveTime>
1820
<center value="20100223"/>

0 commit comments

Comments
 (0)