diff --git a/Snomed_Substance_DDDs.tsv b/Snomed_Substance_DDDs.tsv
index 6cf144d..d343504 100644
--- a/Snomed_Substance_DDDs.tsv
+++ b/Snomed_Substance_DDDs.tsv
@@ -369,7 +369,7 @@ B02BA01 phytomenadione 66656000 Phytomenadione (substance) 20 mg O NA
B02BA01 phytomenadione 66656000 Phytomenadione (substance) 20 mg P NA
B02BA02 menadione 412244007 Menadione (substance) 10 mg O NA
B02BA02 menadione 412244007 Menadione (substance) 2 mg P NA
-B02BB01 fibrinogen, human 418326009 Human fibrinogen (substance) 5 g P NA
+B02BB01 "fibrinogen, human" 418326009 Human fibrinogen (substance) 5 g P NA
B02BX04 romiplostim 439122000 Romiplostim (substance) 30 mcg P NA
B02BX05 eltrombopag 432005001 Eltrombopag (substance) 50 mg O NA
B02BX06 emicizumab 763611007 Emicizumab (substance) 15 mg P NA
@@ -396,7 +396,6 @@ B03XA03 methoxy polyethylene glycol-epoetin beta 425913002 Methoxy polyethylene
B06AC02 icatibant 703834005 Icatibant (substance) 30 mg P NA
B06AC04 conestat alfa 713468002 Conestat alfa (substance) 3.5 TU P NA
B06AC05 lanadelumab 773956002 Lanadelumab (substance) 21.4 mg P NA
-B06AC05 lanadelumab 773956002 Lanadelumab (substance) NA NA NA NA
C01AA04 digitoxin 373534001 Digitoxin (substance) 0.1 mg O NA
C01AA04 digitoxin 373534001 Digitoxin (substance) 0.1 mg P NA
C01AA05 digoxin 387461009 Digoxin (substance) 0.25 mg O NA
@@ -719,7 +718,7 @@ G02AD03 gemeprost 395729005 Gemeprost (substance) 1 mg V Single dose treatment
G02AD04 carboprost 373455002 Carboprost (substance) 2.5 mg P Single dose treatment
G02AD05 sulprostone 713461008 Sulprostone (substance) 0.5 mg P NA
G02AD06 misoprostol 387242007 Misoprostol (substance) 0.2 mg O NA
-G02AD06 misoprostol 387242007 Misoprostol (substance) 0.2 mg V vaginal insert, refers to the content of one vaginal insert
+G02AD06 misoprostol 387242007 Misoprostol (substance) 0.2 mg V "vaginal insert, refers to the content of one vaginal insert"
G02CA01 ritodrine 372893009 Ritodrine (substance) 40 mg O NA
G02CA01 ritodrine 372893009 Ritodrine (substance) 40 mg P NA
G02CA02 buphenine 111140007 Nylidrin (substance) 30 mg P NA
@@ -749,11 +748,11 @@ G03CA03 estradiol 126172005 Estradiol (substance) 2 mg O NA
G03CA03 estradiol 126172005 Estradiol (substance) 1 mg P depot short duration
G03CA03 estradiol 126172005 Estradiol (substance) 0.3 mg P depot long duration
G03CA03 estradiol 126172005 Estradiol (substance) 5 mg R NA
-G03CA03 estradiol 126172005 Estradiol (substance) 50 mcg TD patch, refer to amount delivered per 24 hours
+G03CA03 estradiol 126172005 Estradiol (substance) 50 mcg TD "patch, refer to amount delivered per 24 hours"
G03CA03 estradiol 126172005 Estradiol (substance) 1 mg TD gel
G03CA03 estradiol 126172005 Estradiol (substance) 1.53 mg TD spray
G03CA03 estradiol 126172005 Estradiol (substance) 25 mcg V NA
-G03CA03 estradiol 126172005 Estradiol (substance) 7.5 mcg V vaginal ring, refers to amount delivered per 24 hours
+G03CA03 estradiol 126172005 Estradiol (substance) 7.5 mcg V "vaginal ring, refers to amount delivered per 24 hours"
G03CA04 estriol 73723004 Estriol (substance) 2 mg O NA
G03CA04 estriol 73723004 Estriol (substance) 2 mg P NA
G03CA04 estriol 73723004 Estriol (substance) 0.2 mg V NA
diff --git a/pom.xml b/pom.xml
index 8c01fdb..c0bdb9d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,6 +48,11 @@
poi-ooxml
5.2.3
+
+ net.steppschuh.markdowngenerator
+ markdowngenerator
+ 1.3.1.1
+
org.springframework.boot
diff --git a/src/main/java/org/snomed/cdsservice/model/AggregatedMedicationsBySubstance.java b/src/main/java/org/snomed/cdsservice/model/AggregatedMedicationsBySubstance.java
new file mode 100644
index 0000000..ce086d7
--- /dev/null
+++ b/src/main/java/org/snomed/cdsservice/model/AggregatedMedicationsBySubstance.java
@@ -0,0 +1,52 @@
+package org.snomed.cdsservice.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+public class AggregatedMedicationsBySubstance {
+ String substanceShortName;
+ List medicationsList;
+
+ Map dosageComparisonByRouteMap = new HashMap<>();
+ List referenceList;
+
+ public AggregatedMedicationsBySubstance(String substanceShortName, List medicationsList, List referenceList) {
+ this.substanceShortName = substanceShortName;
+ this.medicationsList = medicationsList;
+ this.referenceList = referenceList;
+ }
+
+ public String getSubstanceShortName() {
+ return substanceShortName;
+ }
+
+ public void setSubstanceShortName(String substanceShortName) {
+ this.substanceShortName = substanceShortName;
+ }
+
+ public List getMedicationsList() {
+ return medicationsList;
+ }
+
+ public void setMedicationsList(List medicationsList) {
+ this.medicationsList = medicationsList;
+ }
+
+ public List getReferenceList() {
+ return referenceList;
+ }
+
+ public void setReferenceList(List referenceList) {
+ this.referenceList = referenceList;
+ }
+
+ public Map getDosageComparisonByRouteMap() {
+ return dosageComparisonByRouteMap;
+ }
+
+ public void setDosageComparisonByRouteMap(Map dosageComparisonByRouteMap) {
+ this.dosageComparisonByRouteMap = dosageComparisonByRouteMap;
+ }
+}
diff --git a/src/main/java/org/snomed/cdsservice/model/DosageComparisonByRoute.java b/src/main/java/org/snomed/cdsservice/model/DosageComparisonByRoute.java
new file mode 100644
index 0000000..1edc348
--- /dev/null
+++ b/src/main/java/org/snomed/cdsservice/model/DosageComparisonByRoute.java
@@ -0,0 +1,39 @@
+package org.snomed.cdsservice.model;
+
+import org.snomed.cdsservice.service.model.SubstanceDefinedDailyDose;
+
+public class DosageComparisonByRoute {
+ PrescribedDailyDose totalPrescribedDailyDose;
+ SubstanceDefinedDailyDose substanceDefinedDailyDose;
+ String routeOfAdministration;
+
+ public DosageComparisonByRoute(PrescribedDailyDose totalPrescribedDailyDose, SubstanceDefinedDailyDose substanceDefinedDailyDose, String routeOfAdministration) {
+ this.totalPrescribedDailyDose = totalPrescribedDailyDose;
+ this.substanceDefinedDailyDose = substanceDefinedDailyDose;
+ this.routeOfAdministration = routeOfAdministration;
+ }
+
+ public PrescribedDailyDose getTotalPrescribedDailyDose() {
+ return totalPrescribedDailyDose;
+ }
+
+ public void setTotalPrescribedDailyDose(PrescribedDailyDose totalPrescribedDailyDose) {
+ this.totalPrescribedDailyDose = totalPrescribedDailyDose;
+ }
+
+ public SubstanceDefinedDailyDose getSubstanceDefinedDailyDose() {
+ return substanceDefinedDailyDose;
+ }
+
+ public void setSubstanceDefinedDailyDose(SubstanceDefinedDailyDose substanceDefinedDailyDose) {
+ this.substanceDefinedDailyDose = substanceDefinedDailyDose;
+ }
+
+ public String getRouteOfAdministration() {
+ return routeOfAdministration;
+ }
+
+ public void setRouteOfAdministration(String routeOfAdministration) {
+ this.routeOfAdministration = routeOfAdministration;
+ }
+}
diff --git a/src/main/java/org/snomed/cdsservice/model/PrescribedDailyDose.java b/src/main/java/org/snomed/cdsservice/model/PrescribedDailyDose.java
new file mode 100644
index 0000000..12d4a67
--- /dev/null
+++ b/src/main/java/org/snomed/cdsservice/model/PrescribedDailyDose.java
@@ -0,0 +1,32 @@
+package org.snomed.cdsservice.model;
+
+public class PrescribedDailyDose {
+ Double quantity;
+ String unit;
+
+ public PrescribedDailyDose(Double quantity, String unit) {
+ this.quantity = quantity;
+ this.unit = unit;
+ }
+
+ public Double getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Double quantity) {
+ this.quantity = quantity;
+ }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ public void addQuantity(Double newQuantity) {
+ this.quantity += newQuantity;
+ }
+
+}
diff --git a/src/main/java/org/snomed/cdsservice/service/MedicationDoseFormsLoaderService.java b/src/main/java/org/snomed/cdsservice/service/MedicationDoseFormsLoaderService.java
index b307773..e3ef06c 100644
--- a/src/main/java/org/snomed/cdsservice/service/MedicationDoseFormsLoaderService.java
+++ b/src/main/java/org/snomed/cdsservice/service/MedicationDoseFormsLoaderService.java
@@ -54,11 +54,12 @@ public List loadDoseFormMap() throws ServiceException {
String atcAdministrationCode = columns[0];
String snomedDoseFormQuery = columns[5];
int mapPriority = Integer.parseInt(columns[6]);
+ String routeOfAdministrationLabel = columns[1];
String valueSetURI = SnomedValueSetUtil.getSnomedECLValueSetURI(snomedDoseFormQuery);
try {
Set manufacturedDoseFormSnomedCodes = tsClient.expandValueSet(valueSetURI).stream().map(Coding::getCode).collect(Collectors.toSet());
logger.info("Mapping {} SNOMED CT Manufactured dose forms to ATC route of administration '{}'.", manufacturedDoseFormSnomedCodes.size(), atcAdministrationCode);
- mapEntries.add(new ManyToOneMapEntry(manufacturedDoseFormSnomedCodes, atcAdministrationCode, mapPriority));
+ mapEntries.add(new ManyToOneMapEntry(manufacturedDoseFormSnomedCodes, atcAdministrationCode, mapPriority, routeOfAdministrationLabel));
} catch (RestClientException e) {
throw new ServiceException(format("Failed to expand value set '%s'", valueSetURI), e);
}
diff --git a/src/main/java/org/snomed/cdsservice/service/SnomedMedicationDefinedDailyDoseService.java b/src/main/java/org/snomed/cdsservice/service/SnomedMedicationDefinedDailyDoseService.java
index 217eff8..dc66d8f 100644
--- a/src/main/java/org/snomed/cdsservice/service/SnomedMedicationDefinedDailyDoseService.java
+++ b/src/main/java/org/snomed/cdsservice/service/SnomedMedicationDefinedDailyDoseService.java
@@ -1,17 +1,21 @@
package org.snomed.cdsservice.service;
import jakarta.annotation.PostConstruct;
+import net.steppschuh.markdowngenerator.list.UnorderedList;
+import net.steppschuh.markdowngenerator.text.Text;
+import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.*;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.snomed.cdsservice.model.CDSCard;
+import org.snomed.cdsservice.model.*;
import org.snomed.cdsservice.service.model.ManyToOneMapEntry;
import org.snomed.cdsservice.service.model.SubstanceDefinedDailyDose;
import org.snomed.cdsservice.service.tsclient.ConceptParameters;
import org.snomed.cdsservice.service.tsclient.FHIRTerminologyServerClient;
import org.snomed.cdsservice.service.tsclient.SnomedConceptNormalForm;
-import org.snomed.cdsservice.service.units.TimeConversionUtil;
+import org.snomed.cdsservice.util.Frequency;
+import org.snomed.cdsservice.util.UnitConversion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -19,7 +23,10 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.MessageFormat;
import java.util.*;
+import java.util.stream.Collectors;
import static java.lang.String.format;
@@ -39,32 +46,43 @@ public class SnomedMedicationDefinedDailyDoseService {
public static final String ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_UNIT = "733725009";
public static final String ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_VALUE = "1142137007";
public static final String ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_UNIT = "733722007";
-
+ public static final String WARNING = "warning";
+ public static final String INFO = "info";
+ private static final String NEW_LINE = "\n";
+ private final Map> substanceDDD = new HashMap<>();
+ private final Logger logger = LoggerFactory.getLogger(getClass());
@Value("${rules.medication-substance-daily-doses.tsv}")
private String tsvPath;
-
@Autowired
private FHIRTerminologyServerClient tsClient;
-
@Autowired
private MedicationDoseFormsLoaderService doseFormsLoaderService;
-
private List doseFormsManySnomedToOneAtcCodeMap;
- private final Map> substanceDDD = new HashMap<>();
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
+ @Value("${acceptable-daily-dose-threshold-factor}")
+ private String acceptableDailyDoseThresholdFactor;
+ @Value("${maximum-daily-dose-threshold-factor}")
+ private String maximumDailyDoseThresholdFactor;
+ @Value("${card-summary-template-content}")
+ private String cardSummaryTemplate;
+ @Value("${who.atc.url-template}")
+ private String atcUrlTemplate;
public List checkMedications(List medicationRequests) {
List cards = new ArrayList<>();
-
+ Map aggregatedMedicationsBySubstanceMap = new HashMap<>();
for (MedicationRequest medicationRequest : medicationRequests) {
- BigDecimal medicationQuantityPerDay = getMedicationQuantityPerDay(medicationRequest);
- logger.debug("Medication quantity per day {}", medicationQuantityPerDay);
+ Dosage dosage = getDosagefromMedicationRequest(medicationRequest);
+ Quantity doseQuantity = getDoseQuantityFromDosage(dosage);
+ Frequency doseFrequency = getFrequencyFromDosage(dosage);
+ PrescribedDailyDose prescribedDailyDose = getMedicationQuantityPerDay(doseQuantity, doseFrequency);
+
+ logger.debug("Medication quantity per day {}", prescribedDailyDose);
- Optional snomedMedication = medicationRequest.getMedicationCodeableConcept().getCoding().stream()
- .filter(coding -> SNOMEDCT_SYSTEM.equals(coding.getSystem())).findFirst();
+ List codingList = medicationRequest.getMedicationCodeableConcept().getCoding();
+ Optional snomedMedication = codingList.stream().filter(coding -> SNOMEDCT_SYSTEM.equals(coding.getSystem())).findFirst();
if (snomedMedication.isPresent()) {
String snomedMedicationCode = snomedMedication.get().getCode();
+ String snomedMedicationLabel = snomedMedication.get().getDisplay();
ConceptParameters conceptParameters = tsClient.lookup(SNOMEDCT_SYSTEM, snomedMedicationCode);
if (conceptParameters == null) {
@@ -73,7 +91,7 @@ public List checkMedications(List medicationRequests
}
SnomedConceptNormalForm normalForm = conceptParameters.getNormalForm();
if (normalForm == null) {
- logger.info("No normal form found for snomed code {}, skipping.", snomedMedicationCode);
+ logger.info("No normal form found for SNOMED code {}, skipping.", snomedMedicationCode);
continue;
}
@@ -83,90 +101,214 @@ public List checkMedications(List medicationRequests
continue;
}
String atcRouteOfAdministrationCode = null;
+ String routeOfAdministrationLabel = null;
for (ManyToOneMapEntry manyToOneMapEntry : doseFormsManySnomedToOneAtcCodeMap) {
if (manyToOneMapEntry.getSourceCodes().contains(manufacturedDoseForm)) {
atcRouteOfAdministrationCode = manyToOneMapEntry.getTargetCode();
+ routeOfAdministrationLabel = manyToOneMapEntry.getLabel() != null ? manyToOneMapEntry.getLabel() : atcRouteOfAdministrationCode;
}
}
if (atcRouteOfAdministrationCode == null) {
logger.info("SNOMED dose form {} is not covered by the route of administration dynamic map, skipping", manufacturedDoseForm);
continue;
}
-
- // The substances within the clinical drug concepts are contained within attribute groups
- for (Map attributeGroup : normalForm.getAttributeGroups()) {
- String substance = attributeGroup.get(ATTRIBUTE_HAS_BASIS_OF_STRENGTH_SUBSTANCE);
- List substanceDefinedDailyDoses = substanceDDD.get(substance);
- if (substanceDefinedDailyDoses == null) {
- logger.debug("No DDDs found for substance {}", substance);
- continue;
- }
- SubstanceDefinedDailyDose substanceDefinedDailyDose = null;
- for (SubstanceDefinedDailyDose substanceDDD : substanceDefinedDailyDoses) {
- if (atcRouteOfAdministrationCode.equals(substanceDDD.getAtcRouteOfAdministration())) {
- substanceDefinedDailyDose = substanceDDD;
- }
- }
- if (substanceDefinedDailyDose == null) {
- logger.debug("No DDD found for substance {} and route of administration {}", substance, atcRouteOfAdministrationCode);
- continue;
- }
-
- // Substance is the chemical within the drug
- // Strength value and unit are saying how much chemical in each denominator value and unit.
- // Examples:
- // - 10mg of Azathioprine per 1 tablet (presentation type, always one thing to take)
- // - 3mg of ciprofloxacin per 1 milliliter (concentration type, need to measure out the thing to take)
- if (attributeGroup.containsKey(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_VALUE)) {
- String strengthValue = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_VALUE);
- String strengthUnit = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_UNIT);
- String denominatorValue = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_DENOMINATOR_VALUE);
- String denominatorUnit = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_DENOMINATOR_UNIT);
-
- // TODO: medicationQuantityPerDay * denominatorValue * strengthValue = how much of this chemical per day
- // TODO: Compare with substanceDefinedDailyDose
- float averageDailyDose = substanceDefinedDailyDose.getDose();
- String averageDailyDoseUnit = substanceDefinedDailyDose.getUnit();
- // TODO: If order is four times or more of average daily dose add card with warning.
- // TODO: Else if order is twice average daily dose add card with info?
-
- } else if (attributeGroup.containsKey(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_VALUE)) {
- String strengthValue = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_VALUE);
- String strengthUnit = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_UNIT);
- String denominatorValue = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_VALUE);
- String denominatorUnit = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_UNIT);
-
- // TODO: Same logic here - may need to convert units
- }
- }
+ aggregateMedicationsBySubstance(aggregatedMedicationsBySubstanceMap, prescribedDailyDose, codingList, snomedMedicationLabel, atcRouteOfAdministrationCode, routeOfAdministrationLabel, normalForm);
}
}
-
+ composeDosageAlerts(aggregatedMedicationsBySubstanceMap, cards);
return cards;
}
- @NotNull
- private static BigDecimal getMedicationQuantityPerDay(MedicationRequest medicationRequest) {
- List dosageInstruction = medicationRequest.getDosageInstruction();
- ArgumentAssertionUtil.expectCount(1, dosageInstruction.size(), "Medication Request dosageInstruction");
- Dosage dosage = dosageInstruction.get(0);
-
+ private Quantity getDoseQuantityFromDosage(Dosage dosage) {
List doseAndRate = dosage.getDoseAndRate();
ArgumentAssertionUtil.expectNotNull(doseAndRate, "Medication Request doseAndRate");
ArgumentAssertionUtil.expectCount(1, doseAndRate.size(), "Medication Request doseAndRate");
Dosage.DosageDoseAndRateComponent dosageDoseAndRateComponent = doseAndRate.get(0);
Quantity doseQuantity = dosageDoseAndRateComponent.getDoseQuantity();
+ return doseQuantity;
+ }
+ @NotNull
+ private PrescribedDailyDose getMedicationQuantityPerDay(Quantity doseQuantity, Frequency doseFrequency) {
BigDecimal doseQuantityValue = doseQuantity.getValue();
- // TODO: There are no units in the example I have. Do we need to do something extra here for liquids?
+ int frequencyCount = doseFrequency.getFrequencyCount();
+ int periodCount = doseFrequency.getPeriodCount();
+ String periodUnit = doseFrequency.getPeriodUnit();
+ Double dailyDoseQuantity = calculateTotalDosePerDay(doseQuantityValue, frequencyCount, periodCount, periodUnit);
+ return new PrescribedDailyDose(dailyDoseQuantity, doseQuantity.getUnit());
+ }
+ private Frequency getFrequencyFromDosage(Dosage dosage) {
Timing.TimingRepeatComponent repeat = dosage.getTiming().getRepeat();
- int frequency = repeat.getFrequency();
- BigDecimal period = repeat.getPeriod();
- Timing.UnitsOfTime periodUnit = repeat.getPeriodUnit();
- BigDecimal periodInDays = TimeConversionUtil.convertPeriodUnitToDay(period, periodUnit);
- BigDecimal timesPerDay = periodInDays.multiply(new BigDecimal(frequency));
- return doseQuantityValue.multiply(timesPerDay);
+ Frequency doseFrequency = new Frequency(repeat.getFrequency(), repeat.getPeriod().intValue(), repeat.getPeriodUnit().getDisplay());
+ return doseFrequency;
+ }
+
+ private Dosage getDosagefromMedicationRequest(MedicationRequest medicationRequest) {
+ List dosageInstruction = medicationRequest.getDosageInstruction();
+ ArgumentAssertionUtil.expectCount(1, dosageInstruction.size(), "Medication Request dosageInstruction");
+ Dosage dosage = dosageInstruction.get(0);
+ return dosage;
+ }
+
+ private Double calculateTotalDosePerDay(BigDecimal doseQuantityValue, int frequencyCount, int periodCount, String periodUnit) {
+ //calculate number of times per day
+ BigDecimal timesPerDay = new BigDecimal(0);
+ if (periodUnit.equals(Timing.UnitsOfTime.H.getDisplay())) {
+ timesPerDay = new BigDecimal(24).divide(new BigDecimal(periodCount)).multiply(new BigDecimal(frequencyCount));
+ } else if (periodUnit.equals(Timing.UnitsOfTime.D.getDisplay()) && periodCount == 1) {
+ timesPerDay = (new BigDecimal(periodCount)).multiply(new BigDecimal(frequencyCount));
+ } else {
+ timesPerDay = new BigDecimal(1);
+ }
+ //calculate total dose per day
+ BigDecimal totalDosePerDay = timesPerDay.multiply(doseQuantityValue);
+ return totalDosePerDay.doubleValue();
+ }
+
+ private void updateTotalPrescribedDailyDose(AggregatedMedicationsBySubstance aggregatedMedicationsBySubstance, PrescribedDailyDose prescribedDailyDoseInUnitOfDDD, String routeOfAdministrationCode, SubstanceDefinedDailyDose substanceDefinedDailyDose, String routeOfAdministration) {
+ Map dosageComparisonByRouteMap = aggregatedMedicationsBySubstance.getDosageComparisonByRouteMap();
+ DosageComparisonByRoute dosageComparisonByRoute = dosageComparisonByRouteMap.get(routeOfAdministrationCode);
+ if (dosageComparisonByRoute == null) {
+ dosageComparisonByRouteMap.put(routeOfAdministrationCode, new DosageComparisonByRoute(prescribedDailyDoseInUnitOfDDD, substanceDefinedDailyDose, StringUtils.capitalize(routeOfAdministration.trim())));
+ } else {
+ dosageComparisonByRoute.getTotalPrescribedDailyDose().addQuantity((prescribedDailyDoseInUnitOfDDD.getQuantity()));
+ dosageComparisonByRouteMap.put(routeOfAdministrationCode, dosageComparisonByRoute);
+ }
+ }
+
+ private void aggregateMedicationsBySubstance(Map aggregatedMedicationsBySubstanceMap, PrescribedDailyDose prescribedDailyDose, List codingList, String snomedMedicationLabel, String atcRouteOfAdministrationCode, String routeOfAdministrationLabel, SnomedConceptNormalForm normalForm) {
+ // The substances within the clinical drug concepts are contained within attribute groups
+ for (Map attributeGroup : normalForm.getAttributeGroups()) {
+ String substance = attributeGroup.get(ATTRIBUTE_HAS_BASIS_OF_STRENGTH_SUBSTANCE);
+ List substanceDefinedDailyDoses = substanceDDD.get(substance);
+ if (substanceDefinedDailyDoses == null) {
+ logger.debug("No DDDs found for substance {}", substance);
+ return;
+ }
+ SubstanceDefinedDailyDose substanceDefinedDailyDose = null;
+ for (SubstanceDefinedDailyDose substanceDDD : substanceDefinedDailyDoses) {
+ if (atcRouteOfAdministrationCode.equals(substanceDDD.getAtcRouteOfAdministration())) {
+ substanceDefinedDailyDose = substanceDDD;
+ }
+ }
+ if (substanceDefinedDailyDose == null) {
+ logger.debug("No DDD found for substance {} and route of administration {}", substance, atcRouteOfAdministrationCode);
+ return;
+ }
+
+ // Substance is the chemical within the drug
+ // Strength value and unit are saying how much chemical in each denominator value and unit.
+ // Examples:
+ // - 10mg of Azathioprine per 1 tablet (presentation type, always one thing to take)
+ // - 3mg of ciprofloxacin per 1 milliliter (concentration type, need to measure out the thing to take)
+
+ String strengthValue = null;
+ String strengthUnit = null;
+ String denominatorValue = null;
+ String denominatorUnit = null;
+
+ if (attributeGroup.containsKey(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_VALUE)) {
+ strengthValue = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_VALUE);
+ strengthUnit = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_NUMERATOR_UNIT);
+ denominatorValue = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_DENOMINATOR_VALUE);
+ denominatorUnit = attributeGroup.get(ATTRIBUTE_HAS_PRESENTATION_STRENGTH_DENOMINATOR_UNIT);
+
+ } else if (attributeGroup.containsKey(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_VALUE)) {
+ strengthValue = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_VALUE);
+ strengthUnit = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_NUMERATOR_UNIT);
+ denominatorValue = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_VALUE);
+ denominatorUnit = attributeGroup.get(ATTRIBUTE_HAS_CONCENTRATION_STRENGTH_DENOMINATOR_UNIT);
+ }
+
+
+ PrescribedDailyDose prescribedDailyDoseInUnitOfSubstanceStrength = getPrescribedDailyDoseInUnitOfSubstanceStrength(prescribedDailyDose, strengthValue, strengthUnit, denominatorValue, denominatorUnit);
+ PrescribedDailyDose prescribedDailyDoseInUnitOfDDD = getPrescribedDailyDoseInUnitOfDDD(prescribedDailyDoseInUnitOfSubstanceStrength.getQuantity(), prescribedDailyDoseInUnitOfSubstanceStrength.getUnit(), substanceDefinedDailyDose.getUnit());
+ AggregatedMedicationsBySubstance aggregatedMedicationsBySubstance = aggregatedMedicationsBySubstanceMap.get(substance);
+ if (aggregatedMedicationsBySubstance == null) {
+ String substanceShortName = getSnomedParameterValue(substance, "display");
+ aggregatedMedicationsBySubstance = new AggregatedMedicationsBySubstance(substanceShortName, new ArrayList<>(Collections.singletonList(snomedMedicationLabel)), new ArrayList<>(Collections.singletonList(new CDSReference(getCodings(codingList)))));
+ aggregatedMedicationsBySubstanceMap.put(substance, aggregatedMedicationsBySubstance);
+ aggregatedMedicationsBySubstance.getDosageComparisonByRouteMap().put(atcRouteOfAdministrationCode, new DosageComparisonByRoute(prescribedDailyDoseInUnitOfDDD, substanceDefinedDailyDose, StringUtils.capitalize(routeOfAdministrationLabel.trim())));
+ } else {
+ updateTotalPrescribedDailyDose(aggregatedMedicationsBySubstance, prescribedDailyDoseInUnitOfDDD, atcRouteOfAdministrationCode, substanceDefinedDailyDose, routeOfAdministrationLabel);
+ addMedications(aggregatedMedicationsBySubstance, snomedMedicationLabel, codingList);
+ }
+ }
+ }
+
+ void composeDosageAlerts(Map aggregatedMedicationsBySubstanceMap, List cards) {
+ for (var aggregatedMedicationsBySubstanceEntry : aggregatedMedicationsBySubstanceMap.entrySet()) {
+ String substanceName = aggregatedMedicationsBySubstanceEntry.getValue().getSubstanceShortName();
+ Double prescribedDosageFactor = getPrescribedDosageFactor(aggregatedMedicationsBySubstanceEntry.getValue().getDosageComparisonByRouteMap());
+ String alertLevelIndicator = getAlertIndicator(prescribedDosageFactor);
+ if (StringUtils.isNotBlank(alertLevelIndicator)) {
+ UUID randomUuid = UUID.fromString(UUID.nameUUIDFromBytes(substanceName.getBytes()).toString());
+ 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);
+ cards.add(cdsCard);
+ }
+ }
+ }
+
+ private String getAtcUrl(Map.Entry substanceEntry) {
+ Optional> dosageInfoEntry = substanceEntry.getValue().getDosageComparisonByRouteMap().entrySet().stream().findFirst();
+ if (dosageInfoEntry.isEmpty()) {
+ return null;
+ }
+ DosageComparisonByRoute dosageComparisonByRoute = dosageInfoEntry.get().getValue();
+ return MessageFormat.format(atcUrlTemplate, dosageComparisonByRoute.getSubstanceDefinedDailyDose().getAtcCode());
+ }
+
+ private String getAlertIndicator(double prescribedDosageFactor) {
+ String alertLevel = null;
+ if (prescribedDosageFactor >= Double.parseDouble(maximumDailyDoseThresholdFactor)) {
+ alertLevel = WARNING;
+ } else if (prescribedDosageFactor >= Double.parseDouble(acceptableDailyDoseThresholdFactor)) {
+ alertLevel = INFO;
+ }
+ return alertLevel;
+ }
+
+ private Double getPrescribedDosageFactor(Map dosageComparisonByRouteMap) {
+ Double prescribedDosageFactor = Double.valueOf(0);
+ for (var eachRoute : dosageComparisonByRouteMap.entrySet()) {
+ prescribedDosageFactor = prescribedDosageFactor + (eachRoute.getValue().getTotalPrescribedDailyDose().getQuantity() / eachRoute.getValue().getSubstanceDefinedDailyDose().getDose());
+ }
+ return prescribedDosageFactor;
+ }
+
+ private void addMedications(AggregatedMedicationsBySubstance aggregatedMedicationsBySubstance, String snomedMedicationLabel, List codingList) {
+ List medicationsList = aggregatedMedicationsBySubstance.getMedicationsList();
+ List cdsReferenceList = aggregatedMedicationsBySubstance.getReferenceList();
+ if (!medicationsList.contains(snomedMedicationLabel)) {
+ medicationsList.add(snomedMedicationLabel);
+ cdsReferenceList.add(new CDSReference(getCodings(codingList)));
+ aggregatedMedicationsBySubstance.setMedicationsList(medicationsList);
+ aggregatedMedicationsBySubstance.setReferenceList(cdsReferenceList);
+ }
+ }
+
+ private PrescribedDailyDose getPrescribedDailyDoseInUnitOfSubstanceStrength(PrescribedDailyDose prescribedDailyDose, String strengthValue, String strengthUnit, String denominatorValue, String denominatorUnit) {
+ Double prescribedDoseQuantity = prescribedDailyDose.getQuantity();
+ String prescribedDisplayUnit = prescribedDailyDose.getUnit();
+
+ String strengthDisplayUnit = getSnomedParameterValue(strengthUnit, "display");
+ String denominatorDisplayUnit = getSnomedParameterValue(denominatorUnit, "display");
+ double prescribedDoseQuantityInUnitOfSubstanceStrength = prescribedDoseQuantity * Double.parseDouble(strengthValue) / Double.parseDouble(denominatorValue) * UnitConversion.factorOfConversion(prescribedDisplayUnit, denominatorDisplayUnit);
+ return new PrescribedDailyDose(prescribedDoseQuantityInUnitOfSubstanceStrength, strengthDisplayUnit);
+ }
+
+ private String getSnomedParameterValue(String snomedCode, String parameterName) {
+ ConceptParameters conceptParameters = tsClient.lookup(SNOMEDCT_SYSTEM, snomedCode);
+ return conceptParameters.getParameter(parameterName).getValue().toString();
+ }
+
+ private PrescribedDailyDose getPrescribedDailyDoseInUnitOfDDD(Double inputStrengthValue, String inputStrengthUnit, String targetStrengthUnit) {
+ Double prescribedDailyDoseQuantity = inputStrengthValue * UnitConversion.factorOfConversion(inputStrengthUnit, targetStrengthUnit);
+ return new PrescribedDailyDose(prescribedDailyDoseQuantity, targetStrengthUnit);
}
@PostConstruct
@@ -178,8 +320,7 @@ public void init() throws ServiceException {
String expectedHeader = "atc_code\tatc_name\tsnomed_code\tsnomed_label\tddd\tuom\tadm_r\tnote";
String header = reader.readLine();
if (!expectedHeader.equals(header)) {
- throw new ServiceException(format("SNOMED Substance DDD file does not have the expected header. " +
- "Expected: '%s', Actual: '%s'", expectedHeader, header));
+ throw new ServiceException(format("SNOMED Substance DDD file does not have the expected header. " + "Expected: '%s', Actual: '%s'", expectedHeader, header));
}
String line;
@@ -195,16 +336,53 @@ public void init() throws ServiceException {
float dose = Float.parseFloat(values[4]);
String unit = values[5];
String atcRouteOfAdministrationCode = values[6];
- substanceDDD.computeIfAbsent(substanceSnomedCode, i -> new ArrayList<>())
- .add(new SubstanceDefinedDailyDose(atcRouteOfAdministrationCode, dose, unit));
+ String atcCode = values[0];
+ substanceDDD.computeIfAbsent(substanceSnomedCode, i -> new ArrayList<>()).add(new SubstanceDefinedDailyDose(atcRouteOfAdministrationCode, dose, unit, atcCode));
}
} catch (NumberFormatException e) {
- throw new ServiceException(format("Failed to read SNOMED Substance DDDs from tab separated file. " +
- "Number format error while reading row %s", row), e);
+ throw new ServiceException(format("Failed to read SNOMED Substance DDDs from tab separated file. " + "Number format error while reading row %s", row), e);
}
} catch (Exception e) {
throw new ServiceException("Failed to read SNOMED Substance DDDs from tab separated file", e);
}
logger.info("Doses loaded for {} substances.", substanceDDD.size());
}
+
+ private String getCardSummaryTemplate() {
+ return cardSummaryTemplate;
+ }
+
+ private String getCardDetailsInMarkDown(AggregatedMedicationsBySubstance aggregatedMedicationsBySubstance, Double dosageWeight) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(new Text("Substance : " + aggregatedMedicationsBySubstance.getSubstanceShortName())).append(NEW_LINE).append(NEW_LINE);
+ sb.append(new Text("Present in this patient’s medication :")).append(NEW_LINE);
+ sb.append(new UnorderedList<>(aggregatedMedicationsBySubstance.getMedicationsList())).append(NEW_LINE);
+ sb.append(NEW_LINE).append(new Text("Route of administration :")).append(NEW_LINE);
+ Map dosageMapByRoute = aggregatedMedicationsBySubstance.getDosageComparisonByRouteMap();
+ composeDosageByRoute(dosageMapByRoute, sb);
+ sb.append(new Text("Conclusion : Combined prescribed amount is " + getDecimalPlace(dosageWeight) + " times the average daily dose."));
+ return sb.toString();
+ }
+
+ private void composeDosageByRoute(Map dosageMapByRoute, StringBuilder sb) {
+ for (var dosageInfo : dosageMapByRoute.entrySet()) {
+ 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.getDose() + substanceDefinedDailyDose.getUnit(), "Prescribed amount is " + getDecimalPlace(aggregatedDailyDosage.getQuantity() / substanceDefinedDailyDose.getDose()) + " times over the average daily dose"))))).append(NEW_LINE).append(NEW_LINE);
+ }
+ }
+
+ private List getCodings(List codings) {
+ return codings.stream().map(coding -> new CDSCoding(coding.getSystem(), coding.getCode(), coding.getDisplay())).collect(Collectors.toList());
+ }
+
+ private String getDecimalPlace(Double value) {
+ return String.format("%.2f", value);
+ }
+
+ private String getDynamicDecimalPlace(Double value) {
+ DecimalFormat decimalFormat = new DecimalFormat("#.##");
+ return decimalFormat.format(value);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/snomed/cdsservice/service/model/ManyToOneMapEntry.java b/src/main/java/org/snomed/cdsservice/service/model/ManyToOneMapEntry.java
index ae9db07..9025c2d 100644
--- a/src/main/java/org/snomed/cdsservice/service/model/ManyToOneMapEntry.java
+++ b/src/main/java/org/snomed/cdsservice/service/model/ManyToOneMapEntry.java
@@ -7,13 +7,16 @@ public class ManyToOneMapEntry {
private final Set sourceCodes;
private final String targetCode;
private final int mapPriority;
+ private final String label;
- public ManyToOneMapEntry(Set sourceCodes, String targetCode, int mapPriority) {
+ public ManyToOneMapEntry(Set sourceCodes, String targetCode, int mapPriority, String label) {
this.sourceCodes = sourceCodes;
this.targetCode = targetCode;
this.mapPriority = mapPriority;
+ this.label = label;
}
+
public Set getSourceCodes() {
return sourceCodes;
}
@@ -25,4 +28,9 @@ public String getTargetCode() {
public int getMapPriority() {
return mapPriority;
}
+
+ public String getLabel() {
+ return label;
+ }
+
}
diff --git a/src/main/java/org/snomed/cdsservice/service/model/SubstanceDefinedDailyDose.java b/src/main/java/org/snomed/cdsservice/service/model/SubstanceDefinedDailyDose.java
index 521c4f2..261a535 100644
--- a/src/main/java/org/snomed/cdsservice/service/model/SubstanceDefinedDailyDose.java
+++ b/src/main/java/org/snomed/cdsservice/service/model/SubstanceDefinedDailyDose.java
@@ -5,11 +5,14 @@ public class SubstanceDefinedDailyDose {
private final String atcRouteOfAdministration;
private final float dose;
private final String unit;
+ private final String atcCode;
- public SubstanceDefinedDailyDose(String atcRouteOfAdministration, float dose, String unit) {
+
+ public SubstanceDefinedDailyDose(String atcRouteOfAdministration, float dose, String unit, String atcCode) {
this.dose = dose;
this.unit = unit;
this.atcRouteOfAdministration = atcRouteOfAdministration;
+ this.atcCode = atcCode;
}
public String getAtcRouteOfAdministration() {
@@ -23,4 +26,7 @@ public float getDose() {
public String getUnit() {
return unit;
}
+ public String getAtcCode() {
+ return atcCode;
+ }
}
diff --git a/src/main/java/org/snomed/cdsservice/service/tsclient/ConceptParameters.java b/src/main/java/org/snomed/cdsservice/service/tsclient/ConceptParameters.java
index 16a2682..39691da 100644
--- a/src/main/java/org/snomed/cdsservice/service/tsclient/ConceptParameters.java
+++ b/src/main/java/org/snomed/cdsservice/service/tsclient/ConceptParameters.java
@@ -31,7 +31,7 @@ public SnomedConceptNormalForm getNormalForm() {
Pattern attributePattern = Pattern.compile("(\\d+) ?= ?#?([\\d.]+)");
String ungroupedAttributes = null;
if (attributesAndGroups.contains("{")) {
- ungroupedAttributes = attributesAndGroups.substring(attributesAndGroups.indexOf("{"));
+ ungroupedAttributes = attributesAndGroups.substring(0,attributesAndGroups.indexOf("{")-2);
} else {
ungroupedAttributes = attributesAndGroups;
}
@@ -39,7 +39,7 @@ public SnomedConceptNormalForm getNormalForm() {
Map attributes = normalForm.getAttributes();
Matcher attributeMatcher = attributePattern.matcher(ungroupedAttributes);
while (attributeMatcher.find()) {
- attributes.put(attributeMatcher.group(0), attributeMatcher.group(1));
+ attributes.put(attributeMatcher.group(1), attributeMatcher.group(2));
}
Pattern groupPattern = Pattern.compile("\\{([^}]*)}");
@@ -49,7 +49,7 @@ public SnomedConceptNormalForm getNormalForm() {
Map groupAttributes = new HashMap<>();
Matcher groupedAttributeMatcher = attributePattern.matcher(group);
while (groupedAttributeMatcher.find()) {
- groupAttributes.put(groupedAttributeMatcher.group(0), groupedAttributeMatcher.group(1));
+ groupAttributes.put(groupedAttributeMatcher.group(1), groupedAttributeMatcher.group(2));
}
normalForm.getAttributeGroups().add(groupAttributes);
}
@@ -59,7 +59,7 @@ public SnomedConceptNormalForm getNormalForm() {
@Nullable
public String getPropertyValue(String propertyName) {
- List properties = getParameters("properties");
+ List properties = getParameters("property");
for (Parameters.ParametersParameterComponent property : properties) {
boolean correctPart = false;
for (Parameters.ParametersParameterComponent part : property.getPart()) {
diff --git a/src/main/java/org/snomed/cdsservice/service/tsclient/FHIRTerminologyServerClient.java b/src/main/java/org/snomed/cdsservice/service/tsclient/FHIRTerminologyServerClient.java
index 825f189..a90aaa6 100644
--- a/src/main/java/org/snomed/cdsservice/service/tsclient/FHIRTerminologyServerClient.java
+++ b/src/main/java/org/snomed/cdsservice/service/tsclient/FHIRTerminologyServerClient.java
@@ -1,5 +1,6 @@
package org.snomed.cdsservice.service.tsclient;
+import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Parameters;
import org.jetbrains.annotations.Nullable;
@@ -39,9 +40,12 @@ public ConceptParameters lookup(String codeSystem, String code) {
if (!lookupCache.containsKey(cacheKey)) {
logger.info("Lookup system {} code {}", codeSystem, code);
- ResponseEntity response = restTemplate.exchange(format("/CodeSystem/$lookup?_format=json&system=%s&code=%s", codeSystem, code),
- HttpMethod.GET, null, ConceptParameters.class);
- lookupCache.put(cacheKey, response.getBody());
+ ResponseEntity response = restTemplate.exchange(format("/CodeSystem/$lookup?_format=json&system=%s&code=%s&property=*", codeSystem, code),
+ HttpMethod.GET, null, String.class);
+ Parameters parameters = FhirContext.forR4().newJsonParser().parseResource(Parameters.class, response.getBody());
+ ConceptParameters conceptParameters = new ConceptParameters();
+ conceptParameters.setParameter(parameters.getParameter());
+ lookupCache.put(cacheKey, conceptParameters);
}
return lookupCache.get(cacheKey);
}
diff --git a/src/main/java/org/snomed/cdsservice/util/Frequency.java b/src/main/java/org/snomed/cdsservice/util/Frequency.java
new file mode 100644
index 0000000..640f434
--- /dev/null
+++ b/src/main/java/org/snomed/cdsservice/util/Frequency.java
@@ -0,0 +1,28 @@
+package org.snomed.cdsservice.util;
+
+;
+
+public class Frequency {
+ public final int frequencyCount;
+ public final int periodCount;
+ public final String periodUnit;
+
+
+ public Frequency( int frequencyCount, int periodCount, String periodUnit) {
+ this.frequencyCount = frequencyCount;
+ this.periodCount = periodCount;
+ this.periodUnit = periodUnit;
+ }
+
+ public int getFrequencyCount() {
+ return frequencyCount;
+ }
+
+ public int getPeriodCount() {
+ return periodCount;
+ }
+
+ public String getPeriodUnit() {
+ return periodUnit;
+ }
+}
diff --git a/src/main/java/org/snomed/cdsservice/util/UnitConversion.java b/src/main/java/org/snomed/cdsservice/util/UnitConversion.java
new file mode 100644
index 0000000..f35e0c6
--- /dev/null
+++ b/src/main/java/org/snomed/cdsservice/util/UnitConversion.java
@@ -0,0 +1,65 @@
+package org.snomed.cdsservice.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum UnitConversion {
+ MG_MG("mg", "mg", 1.0),
+ MG_G("mg", "g", 0.001),
+ MG_MCG("mg", "mcg", 1000.0),
+ G_MG("g", "mg", 1000.0),
+ G_G("g", "g", 1.0),
+ G_MCG("g", "mcg", 1000000.0),
+ MCG_MG("mcg", "mg", 0.001),
+ MCG_G("mcg", "g", 0.000001),
+ MCG_MCG("mcg", "mcg", 1.0),
+ L_L("L", "L", 1.0),
+ L_ML("L", "mL", 1000.0),
+ L_UL("L", "uL", 1000000.0),
+ ML_L("mL", "L", 0.001),
+ ML_ML("mL", "mL", 1.0),
+ ML_UL("mL", "uL", 1000.0),
+ UL_L("uL", "L", 0.000001),
+ UL_ML("uL", "mL", 0.001),
+ UL_UL("uL", "uL", 1.0),
+ TABLET_TABLET("Tablet", "Tablet", 1.0),
+ TABLET_CAPSULE("Tablet", "Capsule", 1.0),
+ CAPSULE_CAPSULE("Capsule", "Capsule", 1.0);
+
+
+ private static final Map BY_UNIT = new HashMap<>();
+
+ static {
+ for (UnitConversion e : values()) {
+ BY_UNIT.put(e.inputUnit + "-" + e.targetUnit, e.getFactor());
+ }
+ }
+
+ public final String inputUnit;
+ public final String targetUnit;
+ public final Double factor;
+
+ private UnitConversion(String inputUnit, String targetUnit, Double factor) {
+ this.inputUnit = inputUnit;
+ this.targetUnit = targetUnit;
+ this.factor = factor;
+ }
+
+ public static Double factorOfConversion(String sourceUnit, String targetUnit) {
+ return BY_UNIT.get(sourceUnit+"-"+targetUnit);
+ }
+
+ //getter
+ public String getInputUnit() {
+ return inputUnit;
+ }
+
+ public String getTargetUnit() {
+ return targetUnit;
+ }
+
+ public Double getFactor() {
+ return factor;
+ }
+}
+
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index e31cae2..eed5a4b 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -18,7 +18,19 @@ rules.medication-condition.spreadsheet=CDS_Medication-Condition_Cards.xlsx
rules.medication-medication.tsv=CDS_Medication-Medication_Cards.tsv
# Medication Dose rules csv
-rules.medication-substance-daily-doses.tsv=ATC_to_Snomed_Map_with_DDD.tsv
+rules.medication-substance-daily-doses.tsv=Snomed_Substance_DDDs.tsv
# Medication Dose Forms csv
rules.medication-dose-forms.tsv=ATC_Route_Of_Administration_Snomed_DoseForm_Map.tsv
+
+# Acceptable average daily dose
+acceptable-daily-dose-threshold-factor=2
+
+# Maximum average daily dose
+maximum-daily-dose-threshold-factor=4
+
+# card summary
+card-summary-template-content=The amount of %s prescribed is %s times the average daily dose.
+
+# who atc url template
+who.atc.url-template=https://www.whocc.no/atc_ddd_index/?code={0}
diff --git a/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectServiceTest.java b/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectServiceTest.java
index 0646a77..23d2453 100644
--- a/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectServiceTest.java
+++ b/src/test/java/org/snomed/cdsservice/service/MedicationOrderSelectServiceTest.java
@@ -25,6 +25,7 @@
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
class MedicationOrderSelectServiceTest {
@@ -42,7 +43,7 @@ class MedicationOrderSelectServiceTest {
void setMockOutput() {
CDSTrigger trigger = new MedicationConditionCDSTrigger(
"Atorvastatin",
- Collections.singleton(new Coding("http://snomed.info/sct", "108600003", null)),
+ Collections.singleton(new Coding("http://snomed.info/sct", "1145419005", null)),
"Disease of liver",
List.of(
new Coding("http://snomed.info/sct", "235856003", "Disease of liver"),
@@ -54,13 +55,13 @@ void setMockOutput() {
"The use of {{RuleMedication}} is contraindicated when the patient has {{RuleCondition}}.",
CDSIndicator.warning,
new CDSSource("Wikipedia"),
- Stream.of(new CDSReference(Collections.singletonList(new CDSCoding("http://snomed.info/sct", "108600003")))).collect(Collectors.toList()),
+ 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")))));
service.setMedicationOrderSelectTriggers(List.of(trigger));
}
@Test
- public void test() throws IOException {
+ public void shouldReturnAlert_WhenDrugAndConditionIsContraindicated() throws IOException {
CDSRequest cdsRequest = new CDSRequest();
cdsRequest.setPrefetchStrings(Map.of(
"patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
@@ -72,11 +73,242 @@ public void test() throws IOException {
assertEquals(1, cards.size());
CDSCard cdsCard = cards.get(0);
- assertEquals("Contraindication: \"Atorvastatin-containing product\" with patient condition \"Steatosis of liver\".", cdsCard.getSummary());
+ assertEquals("Contraindication: \"Atorvastatin (as atorvastatin calcium) 10 mg oral tablet\" with patient condition \"Steatosis of liver\".", cdsCard.getSummary());
assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
assertEquals("The use of Atorvastatin is contraindicated when the patient has Disease of liver.", cdsCard.getDetail());
- assertEquals("108600003", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode());
+ assertEquals("1145419005", cdsCard.getReferenceMedications().get(0).getCoding().get(0).getCode());
assertEquals("197321007", cdsCard.getReferenceCondition().getCoding().get(0).getCode());
}
+
+ @Test
+ public void shouldReturnOverDoseWarningAlert_WhenPrescribedDailyDoseExceedsMaximumThresholdFactor() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithWarningOverDose.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 6 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ 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"));
+ }
+
+ @Test
+ public void shouldReturnOverDoseInfoAlert_WhenPrescribedDailyDoseExceedsAcceptableThresholdFactor() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithInfoOverDose.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 2.5 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.info, cdsCard.getIndicator());
+ 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"));
+ }
+ @Test
+ public void shouldNotReturnOverDoseAlert_WhenPrescribedDailyDoseIsWithinAcceptableThresholdFactor() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithNoOverDose.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(1, cards.size());
+ }
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInDays() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInDays.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 12 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ 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"));
+ }
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInHours() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInHours.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 12 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ 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"));
+ }
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInWeeks() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInWeeks.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 5 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ 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"));
+ }
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForFrequencyPeriodUnitInMonths() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInMonths.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard = cards.get(1);
+ assertEquals("The amount of Atorvastatin prescribed is 5 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ 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"));
+ }
+
+
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForMultipleDrugs_WithDifferentDosageUnits() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithDosageAndUnits.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+ CDSCard cdsCard1 = cards.get(0);
+ assertEquals("The amount of Ramipril prescribed is 96 times the average daily dose.", cdsCard1.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard1.getIndicator());
+ 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"));
+
+ CDSCard cdsCard2 = cards.get(1);
+ assertEquals("The amount of Ranitidine prescribed is 40 times the average daily dose.", cdsCard2.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard2.getIndicator());
+ 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"));
+ }
+
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForMultipleDrugsHavingSameSubstance_WithDifferentRouteOfAdministration() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithDifferentManufacturedDosageFormAndDifferentRouteOfAdministration.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(1, cards.size());
+
+ CDSCard cdsCard = cards.get(0);
+ assertEquals("The amount of Ranitidine prescribed is 64 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 64.00 times the average daily dose."));
+ assertTrue( cdsCard.getDetail().contains("Parenteral"));
+ assertTrue( cdsCard.getDetail().contains("Oral"));
+ 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"));
+ }
+
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForMultipleDrugsHavingSameSubstance_WithDifferentManufacturedDoseForms() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithDifferentManufacturedDosageFormAndDifferentRouteOfAdministration.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(1, cards.size());
+
+ CDSCard cdsCard = cards.get(0);
+ assertEquals("The amount of Ranitidine prescribed is 64 times the average daily dose.", cdsCard.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard.getIndicator());
+ assertTrue( cdsCard.getDetail().contains("Conclusion : Combined prescribed amount is 64.00 times the average daily dose."));
+ assertTrue( cdsCard.getDetail().contains("Ranitidine (as ranitidine hydrochloride) 150 mg oral tablet"));
+ assertTrue( cdsCard.getDetail().contains("Ranitidine (as ranitidine hydrochloride) 25 mg/mL solution for injection"));
+ 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"));
+ }
+
+ @Test
+ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFactor_ForSingleDrugHavingMultipleSubstances() throws IOException {
+ CDSRequest cdsRequest = new CDSRequest();
+ cdsRequest.setPrefetchStrings(Map.of(
+ "patient", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/PatientResource.json"), StandardCharsets.UTF_8),
+ "conditions", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/ConditionBundle.json"), StandardCharsets.UTF_8),
+ "draftMedicationRequests", StreamUtils.copyToString(getClass().getResourceAsStream("/medication-order-select/MedicationRequestBundleWithCombinatorialDrug.json"), StandardCharsets.UTF_8)
+ ));
+
+ List cards = service.call(cdsRequest);
+ assertEquals(2, cards.size());
+
+ CDSCard cdsCard1 = cards.get(0);
+ assertEquals("The amount of Probenecid prescribed is 6 times the average daily dose.", cdsCard1.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard1.getIndicator());
+ assertTrue( cdsCard1.getDetail().contains("Conclusion : Combined prescribed amount is 6.00 times the average daily dose."));
+ 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"));
+
+ CDSCard cdsCard2 = cards.get(1);
+ assertEquals("The amount of Colchicine prescribed is 6 times the average daily dose.", cdsCard2.getSummary());
+ assertEquals(CDSIndicator.warning, cdsCard2.getIndicator());
+ assertTrue( cdsCard2.getDetail().contains("Conclusion : Combined prescribed amount is 6.00 times the average daily dose."));
+ 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"));
+
+ }
}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundle.json b/src/test/resources/medication-order-select/MedicationRequestBundle.json
index aef46ab..be9730b 100644
--- a/src/test/resources/medication-order-select/MedicationRequestBundle.json
+++ b/src/test/resources/medication-order-select/MedicationRequestBundle.json
@@ -13,16 +13,16 @@
"coding": [
{
"system": "http://snomed.info/sct",
- "code": "108600003",
- "display": "Atorvastatin-containing product"
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
},
{
"system": "http://bahmni.org/cds",
"code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
- "display": "Atorvastatin 20 mg"
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
}
],
- "text": "Atorvastatin 20 mg"
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
},
"subject": {
"reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
@@ -62,7 +62,8 @@
]
},
"doseQuantity": {
- "value": 1
+ "value": 1,
+ "unit": "Tablet"
}
}
]
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithCombinatorialDrug.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithCombinatorialDrug.json
new file mode 100644
index 0000000..c8707bb
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithCombinatorialDrug.json
@@ -0,0 +1,77 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "433216006",
+ "display": "Colchicine 500 microgram and probenecid 500 mg oral tablet"
+ }
+ ],
+ "text": "Colchicine 500 microgram and probenecid 500 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 1,
+ "period": 2,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithDifferentManufacturedDosageFormAndDifferentRouteOfAdministration.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithDifferentManufacturedDosageFormAndDifferentRouteOfAdministration.json
new file mode 100644
index 0000000..ff78d2d
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithDifferentManufacturedDosageFormAndDifferentRouteOfAdministration.json
@@ -0,0 +1,149 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "317249006",
+ "display": "Ranitidine (as ranitidine hydrochloride) 150 mg oral tablet"
+ }
+ ],
+ "text": "Ranitidine (as ranitidine hydrochloride) 150 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 2,
+ "period": 1,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ },
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "782087002",
+ "display": "Ranitidine (as ranitidine hydrochloride) 25 mg/mL solution for injection"
+ }
+ ],
+ "text": "Ranitidine (as ranitidine hydrochloride) 25 mg/mL solution for injection"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 2,
+ "period": 1,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 10,
+ "unit": "mL"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithDosageAndUnits.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithDosageAndUnits.json
new file mode 100644
index 0000000..90d13b5
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithDosageAndUnits.json
@@ -0,0 +1,149 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "408051007",
+ "display": "Ramipril 5 mg oral tablet"
+ }
+ ],
+ "text": "Ramipril 5 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 2,
+ "period": 1,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ },
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "782087002",
+ "display": "Ranitidine (as ranitidine hydrochloride) 25 mg/mL solution for injection"
+ }
+ ],
+ "text": "Ranitidine (as ranitidine hydrochloride) 25 mg/mL solution for injection"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 2,
+ "period": 1,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 10,
+ "unit": "mL"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInDays.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInDays.json
new file mode 100644
index 0000000..f2c0fa5
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInDays.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 24,
+ "period": 1,
+ "periodUnit": "d"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInHours.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInHours.json
new file mode 100644
index 0000000..5ccf755
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInHours.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 1,
+ "period": 1,
+ "periodUnit": "h"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInMonths.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInMonths.json
new file mode 100644
index 0000000..46173d9
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInMonths.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 3,
+ "period": 1,
+ "periodUnit": "mo"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 10,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInWeeks.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInWeeks.json
new file mode 100644
index 0000000..ead23a8
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithFrequencyPeriodUnitInWeeks.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 3,
+ "period": 1,
+ "periodUnit": "wk"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 10,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithInfoOverDose.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithInfoOverDose.json
new file mode 100644
index 0000000..e2b724a
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithInfoOverDose.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 10,
+ "period": 1,
+ "periodUnit": "d"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 0.5,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithNoOverDose.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithNoOverDose.json
new file mode 100644
index 0000000..be9730b
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithNoOverDose.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 1,
+ "period": 1,
+ "periodUnit": "d"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}
diff --git a/src/test/resources/medication-order-select/MedicationRequestBundleWithWarningOverDose.json b/src/test/resources/medication-order-select/MedicationRequestBundleWithWarningOverDose.json
new file mode 100644
index 0000000..7cfb132
--- /dev/null
+++ b/src/test/resources/medication-order-select/MedicationRequestBundleWithWarningOverDose.json
@@ -0,0 +1,82 @@
+{
+ "resourceType": "Bundle",
+ "id": "be826c54-b905-40fb-bd90-c147a63ae4e8",
+ "entry": [
+ {
+ "fullUrl": "https://r4.smarthealthit.org/MedicationRequest/5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "resource": {
+ "resourceType": "MedicationRequest",
+ "id": "5180e54d-0187-494a-9ca9-9dbfcab90ab6",
+ "status": "active",
+ "intent": "order",
+ "medicationCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://snomed.info/sct",
+ "code": "1145419005",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ {
+ "system": "http://bahmni.org/cds",
+ "code": "36939d4e-d325-4819-9c81-91e1a0434f9a",
+ "display": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ }
+ ],
+ "text": "Atorvastatin (as atorvastatin calcium) 10 mg oral tablet"
+ },
+ "subject": {
+ "reference": "Patient/618b2992-eec7-45c9-8544-12c9f586b78c"
+ },
+ "encounter": {
+ "reference": "Encounter/8f1950d4-13cc-4ea5-a9d0-855a4f4b9180"
+ },
+ "authoredOn": "2021-01-15T04:59:42+00:00",
+ "requester": {
+ "reference": "Practitioner/96333652-ed28-41d3-bb60-d435f478c8ed"
+ },
+ "reasonReference": [
+ {
+ "reference": "Condition/e21522b1-8006-4723-8b8d-bda8a575b87e"
+ }
+ ],
+ "dosageInstruction": [
+ {
+ "sequence": 1,
+ "timing": {
+ "repeat": {
+ "frequency": 12,
+ "period": 1,
+ "periodUnit": "d"
+ }
+ },
+ "asNeededBoolean": false,
+ "doseAndRate": [
+ {
+ "type": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
+ "code": "ordered",
+ "display": "Ordered"
+ }
+ ]
+ },
+ "doseQuantity": {
+ "value": 1,
+ "unit": "Tablet"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "search": {
+ "mode": "match"
+ },
+ "response": {
+ "status": "200 OK",
+ "etag": "W/\"4\""
+ }
+ }
+ ]
+}