33import java .util .Collections ;
44import java .util .List ;
55import java .util .Optional ;
6+ import java .util .function .BiFunction ;
67
78import org .apache .commons .lang3 .StringUtils ;
89import org .hl7 .fhir .dstu3 .model .AllergyIntolerance ;
@@ -37,7 +38,6 @@ public class CodeableConceptCdMapper {
3738 private static final String FIXED_ACTUAL_PROBLEM_CODE = "55607006" ;
3839 private static final String PROBLEM_DISPLAY_NAME = "Problem" ;
3940 private static final String ACTIVE_CLINICAL_STATUS = "active" ;
40- private static final String RESOLVED_CLINICAL_STATUS = "resolved" ;
4141 private static final String PRESCRIBING_AGENCY_GP_PRACTICE_CODE = "prescribed-at-gp-practice" ;
4242 private static final String PRESCRIBING_AGENCY_PREVIOUS_PRACTICE_CODE = "prescribed-by-previous-practice" ;
4343 private static final String PRESCRIBING_AGENCY_ANOTHER_ORGANISATION_CODE = "prescribed-by-another-organisation" ;
@@ -51,10 +51,23 @@ public class CodeableConceptCdMapper {
5151 private static final String OTHER_CATEGORY_DESCRIPTION = "Other category" ;
5252
5353 public String mapCodeableConceptToCd (CodeableConcept codeableConcept ) {
54+ return mapCodeableConcept (codeableConcept , this ::getMainCode );
55+ }
56+
57+ public String mapCodeableConceptForMedication (CodeableConcept codeableConcept ) {
58+ return mapCodeableConcept (
59+ codeableConcept ,
60+ (descriptionExtensions , snomedCodeCoding ) -> Optional .ofNullable (snomedCodeCoding .getCode ()));
61+ }
62+
63+ private String mapCodeableConcept (
64+ CodeableConcept codeableConcept ,
65+ BiFunction <Optional <List <Extension >>, Coding , Optional <String >> getMainCodeFunction
66+ ) {
5467 Optional <Coding > snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
5568
5669 if (snomedCodeCoding .isEmpty ()) {
57- return buildNullFlavourCodeableConceptCd (codeableConcept , snomedCodeCoding );
70+ return mapToNullFlavorCodeableConcept (codeableConcept );
5871 }
5972
6073 var builder = CodeableConceptCdTemplateParameters .builder ();
@@ -64,87 +77,60 @@ public String mapCodeableConceptToCd(CodeableConcept codeableConcept) {
6477
6578 builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
6679
67- var mainCode = getMainCode (descriptionExtensions , snomedCodeCoding .get ());
68- mainCode .ifPresent (builder ::mainCode );
69-
7080 var mainDisplayName = getMainDisplayName (descriptionExtensions , snomedCodeCoding .get ());
7181 mainDisplayName .ifPresent (builder ::mainDisplayName );
7282
7383 builder .mainOriginalText (codeableConcept .getText ());
7484 builder .translations (getNonSnomedCodeCodings (codeableConcept ));
7585
86+ var mainCode = getMainCodeFunction .apply (descriptionExtensions , snomedCodeCoding .get ());
87+ mainCode .ifPresent (builder ::mainCode );
88+
7689 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
7790 }
7891
79- // Medications are currently using D&T Codes rather than snomed codes but are being passed through as SNOMED codes which is
80- // creating a degradation on the receiving side. Until the types are configured correctly and agreed to a specification
81- // we have agreed to use the Concept ID rather than Description Id for medications which will avoided the degradation.
82- public String mapCodeableConceptForMedication ( CodeableConcept codeableConcept ) {
92+ public String mapCodeableConceptToCdForAllergy (
93+ CodeableConcept codeableConcept ,
94+ AllergyIntolerance . AllergyIntoleranceClinicalStatus allergyIntoleranceClinicalStatus
95+ ) {
8396 var builder = CodeableConceptCdTemplateParameters .builder ();
84- var snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
97+ Optional < Coding > snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
8598
8699 if (snomedCodeCoding .isEmpty ()) {
87- return buildNullFlavourCodeableConceptCd (codeableConcept , snomedCodeCoding );
100+ builder .nullFlavor (true );
101+ return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
88102 }
89103
90- var extension = retrieveDescriptionExtension (snomedCodeCoding .get ())
91- .map (Extension ::getExtension )
92- .orElse (Collections .emptyList ());
93-
94- builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
95-
96- Optional <String > code = Optional .ofNullable (snomedCodeCoding .get ().getCode ());
97- code .ifPresent (builder ::mainCode );
104+ if (ACTIVE_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
105+ builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
106+ } else {
107+ builder .nullFlavor (true );
108+ }
98109
99- Optional <String > displayName = extension .stream ()
100- .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
101- .map (description -> description .getValue ().toString ())
102- .findFirst ()
103- .or (() -> Optional .ofNullable (snomedCodeCoding .get ().getDisplay ()));
104- displayName .ifPresent (builder ::mainDisplayName );
110+ getAllergyMainCode (snomedCodeCoding .get ()).ifPresent (builder ::mainCode );
111+ getCodingDisplayName (snomedCodeCoding .get ()).ifPresent (builder ::mainDisplayName );
105112
106- builder .mainOriginalText (codeableConcept .getText ());
113+ if (codeableConcept .hasText ()) {
114+ builder .mainOriginalText (codeableConcept .getText ());
115+ } else {
116+ var originalText = findOriginalTextForAllergy (codeableConcept , snomedCodeCoding , allergyIntoleranceClinicalStatus );
117+ originalText .ifPresent (builder ::mainOriginalText );
118+ }
107119
108- builder .translations (getNonSnomedCodeCodings (codeableConcept ));
109120 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
110121 }
111122
112- public String mapCodeableConceptToCdForAllergy (CodeableConcept codeableConcept , AllergyIntolerance .AllergyIntoleranceClinicalStatus
113- allergyIntoleranceClinicalStatus ) {
114- var builder = CodeableConceptCdTemplateParameters .builder ();
115- var mainCode = getSnomedCodeCoding (codeableConcept );
116-
117- builder .nullFlavor (mainCode .isEmpty ());
118-
119- if (mainCode .isPresent ()) {
120- var extension = retrieveDescriptionExtension (mainCode .get ())
121- .map (Extension ::getExtension )
122- .orElse (Collections .emptyList ());
123-
124- if (ACTIVE_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
125- builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
126- } else {
127- builder .nullFlavor (true );
128- }
123+ private static Optional <String > getCodingDisplayName (Coding snomedCodeCoding ) {
124+ return Optional .ofNullable (snomedCodeCoding .getDisplay ());
125+ }
129126
130- Optional <String > code = extension .stream ()
127+ private static Optional <String > getAllergyMainCode (Coding snomedCodeCoding ) {
128+ return retrieveDescriptionExtension (snomedCodeCoding )
129+ .flatMap (extension -> extension .getExtension ().stream ()
131130 .filter (descriptionExt -> DESCRIPTION_ID .equals (descriptionExt .getUrl ()))
132- .map (description -> description .getValue ().toString ())
133131 .findFirst ()
134- .or (() -> Optional .ofNullable (mainCode .get ().getCode ()));
135- code .ifPresent (builder ::mainCode );
136-
137- Optional <String > displayName = Optional .ofNullable (mainCode .get ().getDisplay ());
138- displayName .ifPresent (builder ::mainDisplayName );
139-
140- if (codeableConcept .hasText ()) {
141- builder .mainOriginalText (codeableConcept .getText ());
142- } else {
143- var originalText = findOriginalTextForAllergy (codeableConcept , mainCode , allergyIntoleranceClinicalStatus );
144- originalText .ifPresent (builder ::mainOriginalText );
145- }
146- }
147- return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
132+ .map (description -> description .getValue ().toString ()))
133+ .or (() -> Optional .ofNullable (snomedCodeCoding .getCode ()));
148134 }
149135
150136 public String mapCodeableConceptToCdForTransformedActualProblemHeader (CodeableConcept codeableConcept ) {
@@ -343,7 +329,7 @@ private Optional<String> findOriginalText(CodeableConcept codeableConcept, Optio
343329 return Optional .ofNullable (codeableConcept .getText ());
344330 } else {
345331 if (coding .get ().hasDisplay ()) {
346- return Optional . ofNullable (coding .get (). getDisplay ());
332+ return getCodingDisplayName (coding .get ());
347333 } else {
348334 var extension = retrieveDescriptionExtension (coding .get ());
349335 return extension .stream ()
@@ -362,52 +348,27 @@ private Optional<String> findOriginalTextForAllergy(
362348 Optional <Coding > coding ,
363349 AllergyIntolerance .AllergyIntoleranceClinicalStatus allergyIntoleranceClinicalStatus
364350 ) {
365- if (!allergyIntoleranceClinicalStatus .toCode ().isEmpty ()) {
366- if (RESOLVED_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
367- if (coding .isPresent ()) {
368- if (codeableConcept .hasText ()) {
369- return Optional .ofNullable (codeableConcept .getText ());
370- } else {
371- var extension = retrieveDescriptionExtension (coding .get ());
372- if (extension .isPresent ()) {
373- Optional <String > originalText = extension
374- .get ()
375- .getExtension ().stream ()
376- .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
377- .map (extension1 -> extension1 .getValue ().toString ())
378- .findFirst ();
379-
380- if (originalText .isPresent ()) {
381- return originalText ;
382- } else if (coding .get ().hasDisplay ()) {
383- return Optional .ofNullable (coding .get ().getDisplay ());
384- }
385- } else if (coding .get ().hasDisplay ()) {
386- return Optional .ofNullable (coding .get ().getDisplay ());
387- }
388- }
389- }
390- } else if (ACTIVE_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
391- Optional <Extension > extension = retrieveDescriptionExtension (coding .get ());
392- if (extension .isPresent ()) {
393- Optional <String > originalText = extension
394- .get ()
395- .getExtension ().stream ()
396- .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
397- .map (extension1 -> extension1 .getValue ().toString ())
398- .findFirst ();
399- if (originalText .isPresent () && StringUtils .isNotBlank (originalText .get ())) {
400- return originalText ;
401- }
402- }
351+ if (coding .isEmpty ()) {
352+ return Optional .empty ();
353+ }
403354
404- return Optional . empty ();
405- }
355+ if ( ACTIVE_CLINICAL_STATUS . equals ( allergyIntoleranceClinicalStatus . toCode ())) {
356+ return getOriginalTextForActiveAllergy ( coding . get ());
406357 }
407358
408359 return CodeableConceptMappingUtils .extractTextOrCoding (codeableConcept );
409360 }
410361
362+ private Optional <String > getOriginalTextForActiveAllergy (Coding coding ) {
363+ return retrieveDescriptionExtension (coding )
364+ .flatMap (value -> value
365+ .getExtension ().stream ()
366+ .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
367+ .map (extension1 -> extension1 .getValue ().toString ())
368+ .findFirst ()
369+ );
370+ }
371+
411372 private Optional <String > findDisplayText (Coding coding ) {
412373 return Optional .ofNullable (coding .getDisplay ());
413374 }
@@ -420,7 +381,7 @@ private boolean isPrescribingAgency(Coding coding) {
420381 return coding .hasSystem () && coding .getSystem ().equals (CARE_CONNECT_PRESCRIBING_AGENCY_SYSTEM );
421382 }
422383
423- private Optional <Extension > retrieveDescriptionExtension (Coding coding ) {
384+ private static Optional <Extension > retrieveDescriptionExtension (Coding coding ) {
424385 return coding
425386 .getExtension ()
426387 .stream ()
@@ -435,7 +396,6 @@ public String getDisplayFromCodeableConcept(CodeableConcept codeableConcept) {
435396 }
436397
437398 public String mapToNullFlavorCodeableConcept (CodeableConcept codeableConcept ) {
438-
439399 var builder = CodeableConceptCdTemplateParameters .builder ().nullFlavor (true );
440400 var mainCode = getSnomedCodeCoding (codeableConcept );
441401
@@ -456,15 +416,6 @@ public String mapToNullFlavorCodeableConceptForAllergy(
456416 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
457417 }
458418
459- private String buildNullFlavourCodeableConceptCd (CodeableConcept codeableConcept , Optional <Coding > snomedCode ) {
460- var builder = CodeableConceptCdTemplateParameters .builder ();
461- builder .nullFlavor (true );
462- var originalText = findOriginalText (codeableConcept , snomedCode );
463- originalText .ifPresent (builder ::mainOriginalText );
464-
465- return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
466- }
467-
468419 private Optional <String > getMainCode (Optional <List <Extension >> descriptionExtensions , Coding snomedCodeCoding ) {
469420 if (descriptionExtensions .isPresent ()) {
470421 var descriptionCode = descriptionExtensions .get ().stream ()
@@ -494,4 +445,4 @@ private Optional<String> getMainDisplayName(Optional<List<Extension>> descriptio
494445
495446 return Optional .ofNullable (snomedCodeCoding .getDisplay ());
496447 }
497- }
448+ }
0 commit comments