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 ;
@@ -51,10 +52,23 @@ public class CodeableConceptCdMapper {
5152 private static final String OTHER_CATEGORY_DESCRIPTION = "Other category" ;
5253
5354 public String mapCodeableConceptToCd (CodeableConcept codeableConcept ) {
55+ return mapCodeableConcept (codeableConcept , this ::getMainCode );
56+ }
57+
58+ public String mapCodeableConceptForMedication (CodeableConcept codeableConcept ) {
59+ return mapCodeableConcept (
60+ codeableConcept ,
61+ (descriptionExtensions , snomedCodeCoding ) -> Optional .ofNullable (snomedCodeCoding .getCode ()));
62+ }
63+
64+ private String mapCodeableConcept (
65+ CodeableConcept codeableConcept ,
66+ BiFunction <Optional <List <Extension >>, Coding , Optional <String >> getMainCodeFunction
67+ ) {
5468 Optional <Coding > snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
5569
5670 if (snomedCodeCoding .isEmpty ()) {
57- return buildNullFlavourCodeableConceptCd (codeableConcept , snomedCodeCoding );
71+ return mapToNullFlavorCodeableConcept (codeableConcept );
5872 }
5973
6074 var builder = CodeableConceptCdTemplateParameters .builder ();
@@ -64,87 +78,60 @@ public String mapCodeableConceptToCd(CodeableConcept codeableConcept) {
6478
6579 builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
6680
67- var mainCode = getMainCode (descriptionExtensions , snomedCodeCoding .get ());
68- mainCode .ifPresent (builder ::mainCode );
69-
7081 var mainDisplayName = getMainDisplayName (descriptionExtensions , snomedCodeCoding .get ());
7182 mainDisplayName .ifPresent (builder ::mainDisplayName );
7283
7384 builder .mainOriginalText (codeableConcept .getText ());
7485 builder .translations (getNonSnomedCodeCodings (codeableConcept ));
7586
87+ var mainCode = getMainCodeFunction .apply (descriptionExtensions , snomedCodeCoding .get ());
88+ mainCode .ifPresent (builder ::mainCode );
89+
7690 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
7791 }
7892
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 ) {
93+ public String mapCodeableConceptToCdForAllergy (
94+ CodeableConcept codeableConcept ,
95+ AllergyIntolerance . AllergyIntoleranceClinicalStatus allergyIntoleranceClinicalStatus
96+ ) {
8397 var builder = CodeableConceptCdTemplateParameters .builder ();
84- var snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
98+ Optional < Coding > snomedCodeCoding = getSnomedCodeCoding (codeableConcept );
8599
86100 if (snomedCodeCoding .isEmpty ()) {
87- return buildNullFlavourCodeableConceptCd (codeableConcept , snomedCodeCoding );
101+ builder .nullFlavor (true );
102+ return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
88103 }
89104
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 );
105+ if (ACTIVE_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
106+ builder .mainCodeSystem (SNOMED_SYSTEM_CODE );
107+ } else {
108+ builder .nullFlavor (true );
109+ }
98110
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 );
111+ getAllergyMainCode (snomedCodeCoding .get ()).ifPresent (builder ::mainCode );
112+ getCodingDisplayName (snomedCodeCoding .get ()).ifPresent (builder ::mainDisplayName );
105113
106- builder .mainOriginalText (codeableConcept .getText ());
114+ if (codeableConcept .hasText ()) {
115+ builder .mainOriginalText (codeableConcept .getText ());
116+ } else {
117+ var originalText = findOriginalTextForAllergy (codeableConcept , snomedCodeCoding , allergyIntoleranceClinicalStatus );
118+ originalText .ifPresent (builder ::mainOriginalText );
119+ }
107120
108- builder .translations (getNonSnomedCodeCodings (codeableConcept ));
109121 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
110122 }
111123
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- }
124+ private static Optional <String > getCodingDisplayName (Coding snomedCodeCoding ) {
125+ return Optional .ofNullable (snomedCodeCoding .getDisplay ());
126+ }
129127
130- Optional <String > code = extension .stream ()
128+ private static Optional <String > getAllergyMainCode (Coding snomedCodeCoding ) {
129+ return retrieveDescriptionExtension (snomedCodeCoding )
130+ .flatMap (extension -> extension .getExtension ().stream ()
131131 .filter (descriptionExt -> DESCRIPTION_ID .equals (descriptionExt .getUrl ()))
132- .map (description -> description .getValue ().toString ())
133132 .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 ());
133+ .map (description -> description .getValue ().toString ()))
134+ .or (() -> Optional .ofNullable (snomedCodeCoding .getCode ()));
148135 }
149136
150137 public String mapCodeableConceptToCdForTransformedActualProblemHeader (CodeableConcept codeableConcept ) {
@@ -343,7 +330,7 @@ private Optional<String> findOriginalText(CodeableConcept codeableConcept, Optio
343330 return Optional .ofNullable (codeableConcept .getText ());
344331 } else {
345332 if (coding .get ().hasDisplay ()) {
346- return Optional . ofNullable (coding .get (). getDisplay ());
333+ return getCodingDisplayName (coding .get ());
347334 } else {
348335 var extension = retrieveDescriptionExtension (coding .get ());
349336 return extension .stream ()
@@ -362,52 +349,69 @@ private Optional<String> findOriginalTextForAllergy(
362349 Optional <Coding > coding ,
363350 AllergyIntolerance .AllergyIntoleranceClinicalStatus allergyIntoleranceClinicalStatus
364351 ) {
352+ if (coding .isEmpty ()) {
353+ return Optional .empty ();
354+ }
355+
365356 if (!allergyIntoleranceClinicalStatus .toCode ().isEmpty ()) {
366357 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- }
403-
404- return Optional .empty ();
358+ return getOriginalTextForResolvedAllergy (codeableConcept , coding .get ());
359+ }
360+ if (ACTIVE_CLINICAL_STATUS .equals (allergyIntoleranceClinicalStatus .toCode ())) {
361+ return getOriginalTextForActiveAllergy (coding .get ());
405362 }
406363 }
407364
408365 return CodeableConceptMappingUtils .extractTextOrCoding (codeableConcept );
409366 }
410367
368+ private Optional <String > getOriginalTextForActiveAllergy (Coding coding ) {
369+ Optional <Extension > extension = retrieveDescriptionExtension (coding );
370+
371+ if (extension .isPresent ()) {
372+ Optional <String > originalText = extension
373+ .get ()
374+ .getExtension ().stream ()
375+ .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
376+ .map (extension1 -> extension1 .getValue ().toString ())
377+ .findFirst ();
378+ if (originalText .isPresent ()) {
379+ return originalText ;
380+ }
381+ }
382+
383+ return Optional .empty ();
384+ }
385+
386+ private Optional <String > getOriginalTextForResolvedAllergy (CodeableConcept codeableConcept , Coding coding ) {
387+
388+ if (codeableConcept .hasText ()) {
389+ return Optional .ofNullable (codeableConcept .getText ());
390+ }
391+
392+ var extension = retrieveDescriptionExtension (coding );
393+ if (extension .isEmpty ()) {
394+ return coding .hasDisplay ()
395+ ? Optional .ofNullable (coding .getDisplay ())
396+ : Optional .empty ();
397+ }
398+
399+ Optional <String > originalText = extension
400+ .get ()
401+ .getExtension ().stream ()
402+ .filter (displayExtension -> DESCRIPTION_DISPLAY .equals (displayExtension .getUrl ()))
403+ .map (extension1 -> extension1 .getValue ().toString ())
404+ .findFirst ();
405+
406+ if (originalText .isPresent ()) {
407+ return originalText ;
408+ } else if (coding .hasDisplay ()) {
409+ return Optional .ofNullable (coding .getDisplay ());
410+ }
411+
412+ return Optional .empty ();
413+ }
414+
411415 private Optional <String > findDisplayText (Coding coding ) {
412416 return Optional .ofNullable (coding .getDisplay ());
413417 }
@@ -420,7 +424,7 @@ private boolean isPrescribingAgency(Coding coding) {
420424 return coding .hasSystem () && coding .getSystem ().equals (CARE_CONNECT_PRESCRIBING_AGENCY_SYSTEM );
421425 }
422426
423- private Optional <Extension > retrieveDescriptionExtension (Coding coding ) {
427+ private static Optional <Extension > retrieveDescriptionExtension (Coding coding ) {
424428 return coding
425429 .getExtension ()
426430 .stream ()
@@ -435,7 +439,6 @@ public String getDisplayFromCodeableConcept(CodeableConcept codeableConcept) {
435439 }
436440
437441 public String mapToNullFlavorCodeableConcept (CodeableConcept codeableConcept ) {
438-
439442 var builder = CodeableConceptCdTemplateParameters .builder ().nullFlavor (true );
440443 var mainCode = getSnomedCodeCoding (codeableConcept );
441444
@@ -456,15 +459,6 @@ public String mapToNullFlavorCodeableConceptForAllergy(
456459 return TemplateUtils .fillTemplate (CODEABLE_CONCEPT_CD_TEMPLATE , builder .build ());
457460 }
458461
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-
468462 private Optional <String > getMainCode (Optional <List <Extension >> descriptionExtensions , Coding snomedCodeCoding ) {
469463 if (descriptionExtensions .isPresent ()) {
470464 var descriptionCode = descriptionExtensions .get ().stream ()
@@ -494,4 +488,4 @@ private Optional<String> getMainDisplayName(Optional<List<Extension>> descriptio
494488
495489 return Optional .ofNullable (snomedCodeCoding .getDisplay ());
496490 }
497- }
491+ }
0 commit comments