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\"" + } + } + ] +}