Skip to content

Commit

Permalink
BS 288 | Mani| throw mismatched exceptions when dose unit doesn't mat…
Browse files Browse the repository at this point in the history
…ch (#9)

* BS 288 | Mani| throw mismatched exceptions when dose unit doesn't match

* BS-288 | Mani | Addressed feedback comments

* BS-288| Mani | added property to include  error message on the responses

* BS-288| Mani | updated the error message thrown

* BS-288 | Mani | Updated the error message based on desk check comments

* BS-288 | Mani | consolidated error messages together
  • Loading branch information
manimaarans committed Nov 9, 2023
1 parent 1a67068 commit d17459a
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,48 @@
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.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Dosage;
import org.hl7.fhir.r4.model.MedicationRequest;
import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.Timing;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snomed.cdsservice.model.*;
import org.snomed.cdsservice.model.AggregatedMedicationsBySubstance;
import org.snomed.cdsservice.model.CDSCard;
import org.snomed.cdsservice.model.CDSCoding;
import org.snomed.cdsservice.model.CDSIndicator;
import org.snomed.cdsservice.model.CDSReference;
import org.snomed.cdsservice.model.CDSSource;
import org.snomed.cdsservice.model.DosageComparisonByRoute;
import org.snomed.cdsservice.model.PrescribedDailyDose;
import org.snomed.cdsservice.service.ArgumentAssertionUtil;
import org.snomed.cdsservice.service.ServiceException;
import org.snomed.cdsservice.service.medication.dose.MedicationDoseFormsLoaderService;
import org.snomed.cdsservice.service.model.ManyToOneMapEntry;
import org.snomed.cdsservice.service.medication.dose.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.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.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

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.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import static java.lang.String.format;
Expand Down Expand Up @@ -266,10 +283,14 @@ private void aggregateMedicationsBySubstance(Map<String, AggregatedMedicationsBy
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.unit());
PrescribedDailyDose prescribedDailyDoseInUnitOfSubstanceStrength;
PrescribedDailyDose prescribedDailyDoseInUnitOfDDD;
try {
prescribedDailyDoseInUnitOfSubstanceStrength = getPrescribedDailyDoseInUnitOfSubstanceStrength(prescribedDailyDose, strengthValue, strengthUnit, denominatorValue, denominatorUnit);
prescribedDailyDoseInUnitOfDDD = getPrescribedDailyDoseInUnitOfDDD(prescribedDailyDoseInUnitOfSubstanceStrength.getQuantity(), prescribedDailyDoseInUnitOfSubstanceStrength.getUnit(), substanceDefinedDailyDose.unit());
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.PRECONDITION_FAILED, String.format("Prescribed dosage could not be validated for %s. Reason: Invalid dose unit.", snomedMedicationLabel), null);
}
AggregatedMedicationsBySubstance aggregatedMedicationsBySubstance = aggregatedMedicationsBySubstanceMap.get(substance);
if (aggregatedMedicationsBySubstance == null) {
String substanceShortName = getSnomedParameterValue(substance, "display");
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ card-summary-template-content=The amount of %s prescribed is %s times the averag

# who atc url template
who.atc.url-template=https://www.whocc.no/atc_ddd_index/?code={0}

# property to include error message as part of the response
server.error.include-message=always
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.util.StreamUtils;
import org.springframework.web.server.ResponseStatusException;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -38,6 +39,7 @@
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -363,6 +365,17 @@ public void shouldReturnOverDoseAlert_WhenPrescribedDailyDoseExceedsThresholdFac

}

@Test
public void shouldThrowException_WhenRequestBundleContainsMismatchedDoseUnits() 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/MedicationRequestBundleWithMismatchedDoseUnits"), StandardCharsets.UTF_8)
));
assertThrows(ResponseStatusException.class, () ->service.call(cdsRequest) );
}


private ConceptParameters getConceptParamsForDoseUnitMg() {
String response = "{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"code\",\"valueString\":\"258684004\"},{\"name\":\"display\",\"valueString\":\"mg\"},{\"name\":\"name\",\"valueString\":\"SNOMED CT release 2023-05-31\"},{\"name\":\"system\",\"valueString\":\"http://snomed.info/sct\"},{\"name\":\"version\",\"valueString\":\"http://snomed.info/sct/900000000000207008/version/20230531\"},{\"name\":\"inactive\",\"valueBoolean\":false},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"effectiveTime\"},{\"name\":\"valueString\",\"valueString\":\"20020131\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"moduleId\"},{\"name\":\"value\",\"valueCode\":\"900000000000207008\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"inactive\"},{\"name\":\"valueBoolean\",\"valueString\":\"false\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"sufficientlyDefined\"},{\"name\":\"valueBoolean\",\"valueString\":\"false\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"normalFormTerse\"},{\"name\":\"valueString\",\"valueString\":\"258681007\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"normalForm\"},{\"name\":\"valueString\",\"valueString\":\"258681007|International System of Units unit of mass (qualifier value)|\"}]},{\"extension\":[{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000509007\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000548007\",\"display\":\"PREFERRED\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000003001\",\"display\":\"Fully specified name\"}}]},{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000508004\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000548007\",\"display\":\"PREFERRED\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000003001\",\"display\":\"Fully specified name\"}}]}],\"name\":\"designation\",\"part\":[{\"name\":\"language\",\"valueCode\":\"en\"},{\"name\":\"use\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000003001\",\"display\":\"Fully specified name\"}},{\"name\":\"value\",\"valueString\":\"milligram (qualifier value)\"}]},{\"extension\":[{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000509007\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000548007\",\"display\":\"PREFERRED\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}}]},{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000508004\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000548007\",\"display\":\"PREFERRED\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}}]}],\"name\":\"designation\",\"part\":[{\"name\":\"language\",\"valueCode\":\"en\"},{\"name\":\"use\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}},{\"name\":\"value\",\"valueString\":\"mg\"}]},{\"extension\":[{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000509007\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000549004\",\"display\":\"ACCEPTABLE\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}}]},{\"url\":\"http://snomed.info/fhir/StructureDefinition/designation-use-context\",\"extension\":[{\"url\":\"context\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000508004\"}},{\"url\":\"role\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000549004\",\"display\":\"ACCEPTABLE\"}},{\"url\":\"type\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}}]}],\"name\":\"designation\",\"part\":[{\"name\":\"language\",\"valueCode\":\"en\"},{\"name\":\"use\",\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"900000000000013009\",\"display\":\"Synonym\"}},{\"name\":\"value\",\"valueString\":\"milligram\"}]},{\"name\":\"property\",\"part\":[{\"name\":\"code\",\"valueString\":\"parent\"},{\"name\":\"value\",\"valueCode\":\"258681007\"}]}]}";
Expand Down
Original file line number Diff line number Diff line change
@@ -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": "mL"
}
}
]
}
]
},
"search": {
"mode": "match"
},
"response": {
"status": "200 OK",
"etag": "W/\"4\""
}
}
]
}

0 comments on commit d17459a

Please sign in to comment.