diff --git a/src/main/java/org/snomed/cdsservice/model/CDSCard.java b/src/main/java/org/snomed/cdsservice/model/CDSCard.java index d16c699..ee9bc1d 100644 --- a/src/main/java/org/snomed/cdsservice/model/CDSCard.java +++ b/src/main/java/org/snomed/cdsservice/model/CDSCard.java @@ -19,7 +19,9 @@ public class CDSCard { private CDSReference referenceCondition; - public CDSCard(String uuid, String summary, String detail, CDSIndicator indicator, CDSSource source, List referenceMedications, CDSReference referenceCondition) { + private final String alertType; + + public CDSCard(String uuid, String summary, String detail, CDSIndicator indicator, CDSSource source, List referenceMedications, CDSReference referenceCondition, String alertType) { this.uuid = uuid; this.summary = summary; this.detail = detail; @@ -27,6 +29,7 @@ public CDSCard(String uuid, String summary, String detail, CDSIndicator indicato this.source = source; this.referenceMedications = referenceMedications; this.referenceCondition = referenceCondition; + this.alertType = alertType; } public String getUuid() { @@ -75,6 +78,10 @@ public void setReferenceCondition(CDSReference referenceCondition) { } public CDSCard cloneCard() { - return new CDSCard(uuid, summary, detail, indicator, source, referenceMedications, referenceCondition); + return new CDSCard(uuid, summary, detail, indicator, source, referenceMedications, referenceCondition, alertType); + } + + public String getAlertType() { + return alertType; } } diff --git a/src/main/java/org/snomed/cdsservice/service/hello/HelloCDSService.java b/src/main/java/org/snomed/cdsservice/service/hello/HelloCDSService.java index 9009c9b..9c56bd6 100644 --- a/src/main/java/org/snomed/cdsservice/service/hello/HelloCDSService.java +++ b/src/main/java/org/snomed/cdsservice/service/hello/HelloCDSService.java @@ -11,6 +11,8 @@ @Service public class HelloCDSService extends CDSService { + private static final String CONTRAINDICATION_ALERT_TYPE = "Contraindication"; + public HelloCDSService() { super("hello-test"); @@ -19,7 +21,7 @@ public HelloCDSService() { @Override public List call(CDSRequest cdsRequest) { CDSCard card = new CDSCard("22e982b7-4786-4afe-9f67-5af8266363f6", - "Hello! The CDS Service is working.", null, CDSIndicator.info, new CDSSource("http://example.com"), null, null); + "Hello! The CDS Service is working.", null, CDSIndicator.info, new CDSSource("http://example.com"), null, null, CONTRAINDICATION_ALERT_TYPE); card.setDetail("This is an example card from the 'hello-test' CDS Service."); return List.of(card); } diff --git a/src/main/java/org/snomed/cdsservice/service/medication/MedicationCombinationRuleLoaderService.java b/src/main/java/org/snomed/cdsservice/service/medication/MedicationCombinationRuleLoaderService.java index 13caaa2..287bcc8 100644 --- a/src/main/java/org/snomed/cdsservice/service/medication/MedicationCombinationRuleLoaderService.java +++ b/src/main/java/org/snomed/cdsservice/service/medication/MedicationCombinationRuleLoaderService.java @@ -26,6 +26,7 @@ public class MedicationCombinationRuleLoaderService { private final Logger logger = LoggerFactory.getLogger(getClass()); + private static final String CONTRAINDICATION_ALERT_TYPE = "Contraindication"; @Value("${rules.medication-medication.tsv}") private String tsvPath; @@ -80,7 +81,7 @@ public List loadTriggers() throws ServiceException { medication2SnomedCode = medication2SnomedCode.substring(medication2SnomedCode.indexOf("|")).trim(); } - CDSCard cdsCard = new CDSCard(uuid, cardSummary, cardDetail, CDSIndicator.valueOf(cardIndicator), new CDSSource(source, sourceLink), null, null); + CDSCard cdsCard = new CDSCard(uuid, cardSummary, cardDetail, CDSIndicator.valueOf(cardIndicator), new CDSSource(source, sourceLink), null, null, CONTRAINDICATION_ALERT_TYPE); Collection medication1Codings = tsClient.expandValueSet(SnomedValueSetUtil.getSNOMEDValueSetURI(medication1SnomedCode)); Collection medication2Codings = tsClient.expandValueSet(SnomedValueSetUtil.getSNOMEDValueSetURI(medication2SnomedCode)); logger.info("Created trigger {} / {}", medication1Label, medication2Label); diff --git a/src/main/java/org/snomed/cdsservice/service/medication/MedicationConditionRuleLoaderService.java b/src/main/java/org/snomed/cdsservice/service/medication/MedicationConditionRuleLoaderService.java index ddae703..f7a67a3 100644 --- a/src/main/java/org/snomed/cdsservice/service/medication/MedicationConditionRuleLoaderService.java +++ b/src/main/java/org/snomed/cdsservice/service/medication/MedicationConditionRuleLoaderService.java @@ -32,6 +32,8 @@ @Service public class MedicationConditionRuleLoaderService { + private static final String CONTRAINDICATION_ALERT_TYPE = "Contraindication"; + @Value("${rules.medication-condition.spreadsheet}") private String spreadsheetPath; @@ -150,7 +152,7 @@ public List loadTriggers() throws ServiceException { } } if (rowNumber > 1 && !Strings.isNullOrEmpty(source) && medicationSnomedCode != null && conditionSnomedCode != null) { - CDSCard cdsCard = new CDSCard(uuid, cardSummary, cardDetail, CDSIndicator.valueOf(cardIndicator), new CDSSource(source, sourceLink), null, null); + CDSCard cdsCard = new CDSCard(uuid, cardSummary, cardDetail, CDSIndicator.valueOf(cardIndicator), new CDSSource(source, sourceLink), null, null, CONTRAINDICATION_ALERT_TYPE); Collection medicationCodings = tsClient.expandValueSet(SnomedValueSetUtil.getSNOMEDValueSetURI(medicationSnomedCode)); Collection conditionCodings = tsClient.expandValueSet(SnomedValueSetUtil.getSNOMEDValueSetURI(conditionSnomedCode)); logger.info("Created trigger {} / {}", medicationLabel, conditionLabel); diff --git a/src/main/java/org/snomed/cdsservice/service/medication/dose/SnomedMedicationDefinedDailyDoseService.java b/src/main/java/org/snomed/cdsservice/service/medication/dose/SnomedMedicationDefinedDailyDoseService.java index f3f95c1..1acd2a9 100644 --- a/src/main/java/org/snomed/cdsservice/service/medication/dose/SnomedMedicationDefinedDailyDoseService.java +++ b/src/main/java/org/snomed/cdsservice/service/medication/dose/SnomedMedicationDefinedDailyDoseService.java @@ -53,6 +53,7 @@ public class SnomedMedicationDefinedDailyDoseService { public static final String WARNING = "warning"; public static final String INFO = "info"; private static final String NEW_LINE = "\n"; + private static final String HIGH_DOSAGE_ALERT_TYPE = "High Dosage"; @Autowired private FHIRTerminologyServerClient tsClient; @@ -292,7 +293,7 @@ void composeDosageAlerts(Map aggregate String cardSummaryMsg = String.format(getCardSummaryTemplate(), substanceName, getDynamicDecimalPlace(prescribedDosageFactor)); String cardDetailMsg = getCardDetailsInMarkDown(aggregatedMedicationsBySubstanceEntry.getValue(), prescribedDosageFactor); String atcUrl = getAtcUrl(aggregatedMedicationsBySubstanceEntry); - CDSCard cdsCard = new CDSCard(randomUuid.toString(), cardSummaryMsg, cardDetailMsg, CDSIndicator.valueOf(alertLevelIndicator), new CDSSource("WHO ATC DDD", atcUrl), aggregatedMedicationsBySubstanceEntry.getValue().getReferenceList(), null); + CDSCard cdsCard = new CDSCard(randomUuid.toString(), cardSummaryMsg, cardDetailMsg, CDSIndicator.valueOf(alertLevelIndicator), new CDSSource("WHO ATC DDD", atcUrl), aggregatedMedicationsBySubstanceEntry.getValue().getReferenceList(), null, HIGH_DOSAGE_ALERT_TYPE); cards.add(cdsCard); } } @@ -377,7 +378,7 @@ private void composeDosageByRoute(Map dosageMap DosageComparisonByRoute dosageComparisonByRouteValue = dosageInfo.getValue(); PrescribedDailyDose aggregatedDailyDosage = dosageComparisonByRouteValue.getTotalPrescribedDailyDose(); SubstanceDefinedDailyDose substanceDefinedDailyDose = dosageComparisonByRouteValue.getSubstanceDefinedDailyDose(); - sb.append(new UnorderedList<>(List.of(dosageComparisonByRouteValue.getRouteOfAdministration(), new UnorderedList<>(List.of("Prescribed daily dose : " + aggregatedDailyDosage.getQuantity() + aggregatedDailyDosage.getUnit(), "Recommended average daily dose : " + substanceDefinedDailyDose.dose() + substanceDefinedDailyDose.unit(), "Prescribed amount is " + getDecimalPlace(aggregatedDailyDosage.getQuantity() / substanceDefinedDailyDose.dose()) + " times over the average daily dose"))))).append(NEW_LINE).append(NEW_LINE); + sb.append(new UnorderedList<>(List.of(dosageComparisonByRouteValue.getRouteOfAdministration(), new UnorderedList<>(List.of("Prescribed daily dose : " + getDecimalPlace(aggregatedDailyDosage.getQuantity()) + aggregatedDailyDosage.getUnit(), "Recommended average daily dose : " + substanceDefinedDailyDose.dose() + substanceDefinedDailyDose.unit(), "Prescribed amount is " + getDecimalPlace(aggregatedDailyDosage.getQuantity() / substanceDefinedDailyDose.dose()) + " times over the average daily dose"))))).append(NEW_LINE).append(NEW_LINE); } } diff --git a/src/main/java/org/snomed/cdsservice/util/UnitConversion.java b/src/main/java/org/snomed/cdsservice/util/UnitConversion.java index f35e0c6..4b2ae15 100644 --- a/src/main/java/org/snomed/cdsservice/util/UnitConversion.java +++ b/src/main/java/org/snomed/cdsservice/util/UnitConversion.java @@ -24,7 +24,10 @@ public enum UnitConversion { UL_UL("uL", "uL", 1.0), TABLET_TABLET("Tablet", "Tablet", 1.0), TABLET_CAPSULE("Tablet", "Capsule", 1.0), - CAPSULE_CAPSULE("Capsule", "Capsule", 1.0); + CAPSULE_CAPSULE("Capsule", "Capsule", 1.0), + PUFF_ACTUATION("Actuation", "Actuation", 1.0), + SPOONFUL_SPOONFUL("Spoonful", "Spoonful", 1.0), + DROP_DROP("Drop", "Drop", 1.0); private static final Map BY_UNIT = new HashMap<>(); diff --git a/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectCDSServiceTest.java b/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectCDSServiceTest.java index 0ad6c83..57d1046 100644 --- a/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectCDSServiceTest.java +++ b/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectCDSServiceTest.java @@ -33,6 +33,9 @@ @SpringBootTest class MedicationOrderSelectCDSServiceTest { + private static final String CONTRAINDICATION_ALERT_TYPE = "Contraindication"; + private static final String HIGH_DOSAGE_ALERT_TYPE = "High Dosage"; + @MockBean private MedicationConditionRuleLoaderService ruleLoaderService; @@ -59,7 +62,7 @@ void setMockOutput() { CDSIndicator.warning, new CDSSource("Wikipedia"), Stream.of(new CDSReference(Collections.singletonList(new CDSCoding("http://snomed.info/sct", "1145419005")))).collect(Collectors.toList()), - new CDSReference(Collections.singletonList(new CDSCoding("http://snomed.info/sct", "197321007"))))); + new CDSReference(Collections.singletonList(new CDSCoding("http://snomed.info/sct", "197321007"))), CONTRAINDICATION_ALERT_TYPE)); service.setMedicationOrderSelectTriggers(List.of(trigger)); } @@ -81,6 +84,7 @@ public void shouldReturnAlert_WhenDrugAndConditionIsContraindicated() throws IOE assertEquals("The use of Atorvastatin is contraindicated when the patient has Disease of liver.", cdsCard.getDetail()); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertEquals("197321007", cdsCard.getReferenceCondition().getCoding().get(0).getCode()); + assertEquals(CONTRAINDICATION_ALERT_TYPE, cdsCard.getAlertType()); } @@ -102,6 +106,7 @@ public void shouldReturnOverDoseWarningAlert_WhenPrescribedDailyDoseExceedsMaxim assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 6.00 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test @@ -122,6 +127,7 @@ public void shouldReturnOverDoseInfoAlert_WhenPrescribedDailyDoseExceedsAcceptab assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 2.50 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test public void shouldNotReturnOverDoseAlert_WhenPrescribedDailyDoseIsWithinAcceptableThresholdFactor() throws IOException { @@ -153,6 +159,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 12.00 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInHours() throws IOException { @@ -172,6 +179,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 12.00 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInWeeks() throws IOException { @@ -191,6 +199,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 5.00 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInMonths() throws IOException { @@ -210,6 +219,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 5.00 times the average daily dose.")); assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C10AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @@ -230,6 +240,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard1.getDetail().contains("Conclusion : Combined prescribed amount is 96.00 times the average daily dose.")); assertEquals("408051007", cdsCard1.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard1.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=C09AA05")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard1.getAlertType()); CDSCard cdsCard2 = cards.get(1); assertEquals("The amount of Ranitidine prescribed is 40 times the average daily dose.", cdsCard2.getSummary()); @@ -237,6 +248,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertTrue( cdsCard2.getDetail().contains("Conclusion : Combined prescribed amount is 40.00 times the average daily dose.")); assertEquals("782087002", cdsCard2.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertTrue(cdsCard2.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=A02BA02")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard2.getAlertType()); } @Test @@ -260,6 +272,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertEquals("317249006", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertEquals("782087002", cdsCard.getReferenceMedications().get(1).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=A02BA02")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test @@ -283,6 +296,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertEquals("317249006", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertEquals("782087002", cdsCard.getReferenceMedications().get(1).getCoding().get(0).getCode()); assertTrue(cdsCard.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=A02BA02")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard.getAlertType()); } @Test @@ -304,6 +318,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertEquals("433216006", cdsCard1.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertEquals(1, cdsCard1.getReferenceMedications().size()); assertTrue(cdsCard1.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=M04AB01")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard1.getAlertType()); CDSCard cdsCard2 = cards.get(1); assertEquals("The amount of Colchicine prescribed is 6 times the average daily dose.", cdsCard2.getSummary()); @@ -312,6 +327,7 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac assertEquals("433216006", cdsCard2.getReferenceMedications().get(0).getCoding().get(0).getCode()); assertEquals(1, cdsCard2.getReferenceMedications().size()); assertTrue(cdsCard2.getSource().getUrl().contains("https://www.whocc.no/atc_ddd_index/?code=M04AC01")); + assertEquals(HIGH_DOSAGE_ALERT_TYPE, cdsCard2.getAlertType()); } }