Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FM2-312: Map the order number as an identifier for MedicationRequest and ServiceRequest #306

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public interface FhirMedicationRequestService extends FhirService<MedicationRequ
@Override
MedicationRequest get(@Nonnull String uuid);

IBundleProvider searchForMedicationRequests(ReferenceAndListParam patientReference,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we only have on search method per service. I would just extend the existing method to also support identifier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there not be some code already depending on the current method signature elsewhere? I was worried of the backwards compatibility by introducing another search.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. This is a very closed set so far and, in essence, no one outside of the FHIR2 module should be depending on this (at least yet).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh, ok. Thank you for clarifying this.

Copy link
Member Author

@Ruhanga Ruhanga Dec 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, there are very many tests that are so tightly coupled to the method signature scattered all over the project. I see a huge refactor if I refactored the method(for example), could I go ahead @ibacher? Thanks.

ReferenceAndListParam encounterReference, TokenAndListParam code, ReferenceAndListParam participantReference,
ReferenceAndListParam medicationReference, TokenAndListParam identifier, TokenAndListParam id,
DateRangeParam lastUpdated, HashSet<Include> includes);

IBundleProvider searchForMedicationRequests(ReferenceAndListParam patientReference,
ReferenceAndListParam encounterReference, TokenAndListParam code, ReferenceAndListParam participantReference,
ReferenceAndListParam medicationReference, TokenAndListParam id, DateRangeParam lastUpdated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public interface FhirServiceRequestService extends FhirService<ServiceRequest> {
IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, DateRangeParam lastUpdated, HashSet<Include> includes);

IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, TokenAndListParam identifier, DateRangeParam lastUpdated, HashSet<Include> includes);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
*/
package org.openmrs.module.fhir2.api.dao.impl;

import static org.hibernate.criterion.Restrictions.eq;

import java.util.Optional;

import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import lombok.AccessLevel;
import lombok.Setter;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.openmrs.DrugOrder;
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.api.dao.FhirMedicationRequestDao;
Expand Down Expand Up @@ -47,6 +52,10 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
entry.getValue().forEach(d -> handleMedicationReference("d", (ReferenceAndListParam) d.getParam())
.ifPresent(c -> criteria.createAlias("drug", "d").add(c)));
break;
case FhirConstants.IDENTIFIER:
ibacher marked this conversation as resolved.
Show resolved Hide resolved
entry.getValue().forEach(orderNumber -> handleOrderNumber((TokenAndListParam) orderNumber.getParam())
.ifPresent(criteria::add));
break;
case FhirConstants.COMMON_SEARCH_HANDLER:
handleCommonSearchParameters(entry.getValue()).ifPresent(criteria::add);
break;
Expand All @@ -64,4 +73,11 @@ private void handleCodedConcept(Criteria criteria, TokenAndListParam code) {
}
}

private Optional<Criterion> handleOrderNumber(TokenAndListParam orderNumber) {
if (orderNumber != null) {
return handleAndListParam(orderNumber, param -> Optional.of(eq("orderNumber", param.getValue())));
}
return Optional.empty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.openmrs.module.fhir2.api.dao.impl;

import static org.hibernate.criterion.Restrictions.and;
import static org.hibernate.criterion.Restrictions.eq;
import static org.hibernate.criterion.Restrictions.or;

import java.util.Optional;
Expand Down Expand Up @@ -55,6 +56,10 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
entry.getValue().forEach(dateRangeParam -> handleDateRange((DateRangeParam) dateRangeParam.getParam())
.ifPresent(criteria::add));
break;
case FhirConstants.IDENTIFIER:
ibacher marked this conversation as resolved.
Show resolved Hide resolved
entry.getValue().forEach(orderNumber -> handleOrderNumber((TokenAndListParam) orderNumber.getParam())
.ifPresent(criteria::add));
break;
case FhirConstants.COMMON_SEARCH_HANDLER:
handleCommonSearchParameters(entry.getValue()).ifPresent(criteria::add);
break;
Expand Down Expand Up @@ -84,4 +89,11 @@ private Optional<Criterion> handleDateRange(DateRangeParam dateRangeParam) {
handleDate("autoExpireDate", dateRangeParam.getUpperBound())))))))));
}

private Optional<Criterion> handleOrderNumber(TokenAndListParam orderNumber) {
if (orderNumber != null) {
return handleAndListParam(orderNumber, param -> Optional.of(eq("orderNumber", param.getValue())));
}
return Optional.empty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public class FhirMedicationRequestServiceImpl extends BaseFhirService<Medication
@Override
public IBundleProvider searchForMedicationRequests(ReferenceAndListParam patientReference,
ReferenceAndListParam encounterReference, TokenAndListParam code, ReferenceAndListParam participantReference,
ReferenceAndListParam medicationReference, TokenAndListParam id, DateRangeParam lastUpdated,
HashSet<Include> includes) {
ReferenceAndListParam medicationReference, TokenAndListParam identifier, TokenAndListParam id,
DateRangeParam lastUpdated, HashSet<Include> includes) {

SearchParameterMap theParams = new SearchParameterMap()
.addParameter(FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER, encounterReference)
Expand All @@ -61,10 +61,21 @@ public IBundleProvider searchForMedicationRequests(ReferenceAndListParam patient
.addParameter(FhirConstants.PARTICIPANT_REFERENCE_SEARCH_HANDLER, participantReference)
.addParameter(FhirConstants.MEDICATION_REFERENCE_SEARCH_HANDLER, medicationReference)
.addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.ID_PROPERTY, id)
.addParameter(FhirConstants.IDENTIFIER, identifier)
.addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.LAST_UPDATED_PROPERTY, lastUpdated)
.addParameter(FhirConstants.INCLUDE_SEARCH_HANDLER, includes);

return searchQuery.getQueryResults(theParams, dao, translator, searchQueryInclude);
}

@Override
public IBundleProvider searchForMedicationRequests(ReferenceAndListParam patientReference,
ReferenceAndListParam encounterReference, TokenAndListParam code, ReferenceAndListParam participantReference,
ReferenceAndListParam medicationReference, TokenAndListParam id, DateRangeParam lastUpdated,
HashSet<Include> includes) {

return searchForMedicationRequests(patientReference, encounterReference, code, participantReference,
medicationReference, null, id, lastUpdated, includes);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class FhirServiceRequestServiceImpl extends BaseFhirService<ServiceReques
@Override
public IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, DateRangeParam lastUpdated, HashSet<Include> includes) {
TokenAndListParam uuid, TokenAndListParam identifier, DateRangeParam lastUpdated, HashSet<Include> includes) {

SearchParameterMap theParams = new SearchParameterMap()
.addParameter(FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER, patientReference)
Expand All @@ -62,10 +62,20 @@ public IBundleProvider searchForServiceRequests(ReferenceAndListParam patientRef
.addParameter(FhirConstants.PARTICIPANT_REFERENCE_SEARCH_HANDLER, participantReference)
.addParameter(FhirConstants.DATE_RANGE_SEARCH_HANDLER, occurrence)
.addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.ID_PROPERTY, uuid)
.addParameter(FhirConstants.IDENTIFIER, identifier)
.addParameter(FhirConstants.COMMON_SEARCH_HANDLER, FhirConstants.LAST_UPDATED_PROPERTY, lastUpdated)
.addParameter(FhirConstants.INCLUDE_SEARCH_HANDLER, includes);

return searchQuery.getQueryResults(theParams, dao, translator, searchQueryInclude);
}

@Override
public IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, DateRangeParam lastUpdated, HashSet<Include> includes) {

return searchForServiceRequests(patientReference, code, encounterReference, participantReference, occurrence, uuid,
null, lastUpdated, includes);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/

package org.openmrs.module.fhir2.api.translators;

import org.hl7.fhir.r4.model.Identifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ public MedicationRequest toFhirResource(@Nonnull DrugOrder drugOrder) {
medicationRequest.setId(drugOrder.getUuid());
medicationRequest.setStatus(statusTranslator.toFhirResource(drugOrder));

if (drugOrder.getOrderNumber() != null) {
medicationRequest.addIdentifier(orderIdentifierTranslator.toFhirResource(drugOrder));
}

medicationRequest.setMedication(medicationReferenceTranslator.toFhirResource(drugOrder.getDrug()));
medicationRequest.setPriority(medicationRequestPriorityTranslator.toFhirResource(drugOrder.getUrgency()));
medicationRequest.setRequester(practitionerReferenceTranslator.toFhirResource(drugOrder.getOrderer()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public ServiceRequest toFhirResource(@Nonnull TestOrder order) {

serviceRequest.setId(order.getUuid());

if (order.getOrderNumber() != null) {
serviceRequest.addIdentifier(orderIdentifierTranslator.toFhirResource(order));
}

serviceRequest.setStatus(determineServiceRequestStatus(order));

serviceRequest.setCode(conceptTranslator.toFhirResource(order.getConcept()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Practitioner;
import org.hl7.fhir.r4.model.ServiceRequest;
import org.openmrs.module.fhir2.api.FhirMedicationRequestService;
import org.openmrs.module.fhir2.providers.util.FhirProviderUtils;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -109,6 +110,7 @@ public IBundleProvider searchForMedicationRequests(
@OptionalParam(name = MedicationRequest.SP_ENCOUNTER, chainWhitelist = {
"" }, targetTypes = Encounter.class) ReferenceAndListParam encounterReference,
@OptionalParam(name = MedicationRequest.SP_CODE) TokenAndListParam code,
@OptionalParam(name = ServiceRequest.SP_IDENTIFIER) TokenAndListParam orderNumber,
@OptionalParam(name = MedicationRequest.SP_REQUESTER, chainWhitelist = { "", Practitioner.SP_IDENTIFIER,
Practitioner.SP_GIVEN, Practitioner.SP_FAMILY,
Practitioner.SP_NAME }, targetTypes = Practitioner.class) ReferenceAndListParam participantReference,
Expand All @@ -129,6 +131,6 @@ public IBundleProvider searchForMedicationRequests(
}

return fhirMedicationRequestService.searchForMedicationRequests(patientReference, encounterReference, code,
participantReference, medicationReference, id, lastUpdated, includes);
participantReference, medicationReference, orderNumber, id, lastUpdated, includes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public IBundleProvider searchForServiceRequests(
Practitioner.SP_NAME }, targetTypes = Practitioner.class) ReferenceAndListParam participantReference,
@OptionalParam(name = ServiceRequest.SP_OCCURRENCE) DateRangeParam occurrence,
@OptionalParam(name = ServiceRequest.SP_RES_ID) TokenAndListParam uuid,
@OptionalParam(name = ServiceRequest.SP_IDENTIFIER) TokenAndListParam orderNumber,
@OptionalParam(name = "_lastUpdated") DateRangeParam lastUpdated,
@IncludeParam(allow = { "ServiceRequest:" + ServiceRequest.SP_PATIENT,
"ServiceRequest:" + ServiceRequest.SP_REQUESTER,
Expand All @@ -122,6 +123,6 @@ public IBundleProvider searchForServiceRequests(
}

return serviceRequestService.searchForServiceRequests(patientReference, code, encounterReference,
participantReference, occurrence, uuid, lastUpdated, includes);
participantReference, occurrence, uuid, orderNumber, lastUpdated, includes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class FhirMedicationRequestDaoImplTest extends BaseModuleContextSensitive

private static final String DRUG_ORDER_UUID = "6d0ae116-707a-4629-9850-f15206e63ab0";

private static final String DRUG_ORDER_NUMBER = "ORD-22";

private static final String BAD_DRUG_ORDER_UUID = "uie3b9a2-4de5-4b12-ac40-jk90sdh";

private static final String MEDICATION_REQUEST_INITIAL_DATA_XML = "org/openmrs/module/fhir2/api/dao/impl/FhirMedicationRequestDaoImpl_initial_data.xml";
Expand Down Expand Up @@ -85,4 +87,23 @@ public void search_shouldReturnSearchQuery() {
assertThat(drugOrder, notNullValue());
}

@Test
public void search_shouldReturnResultsBasedOnOrderNumber() {
// Settup
TokenAndListParam ordrNumber = new TokenAndListParam();
TokenParam token = new TokenParam();
token.setValue(DRUG_ORDER_NUMBER);
ordrNumber.addAnd(token);

SearchParameterMap theParams = new SearchParameterMap();
theParams.addParameter(FhirConstants.IDENTIFIER, ordrNumber);

// Replay
List<String> matchingResourceUuids = medicationRequestDao.getSearchResultUuids(theParams);
List<DrugOrder> drugOrders = medicationRequestDao.getSearchResults(theParams, matchingResourceUuids);

// Verify
assertThat(drugOrders, notNullValue());
assertThat(drugOrders.get(0).getOrderNumber(), equalTo(DRUG_ORDER_NUMBER));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@
*/
package org.openmrs.module.fhir2.api.dao.impl;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;

import java.util.List;

import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import org.hibernate.SessionFactory;
import org.junit.Before;
import org.junit.Test;
import org.openmrs.OrderType;
import org.openmrs.TestOrder;
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.TestFhirSpringConfiguration;
import org.openmrs.module.fhir2.api.search.param.SearchParameterMap;
import org.openmrs.test.BaseModuleContextSensitiveTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -31,6 +37,8 @@ public class FhirServiceRequestDaoImplTest extends BaseModuleContextSensitiveTes

private static final String TEST_ORDER_UUID = "7d96f25c-4949-4f72-9931-d808fbc226de";

private static final String TEST_ORDER_NUMBER = "ORD-6";

private static final String OTHER_ORDER_UUID = "02b9d1e4-7619-453e-bd6b-c32286f861df";

private static final String WRONG_UUID = "7d96f25c-4949-4f72-9931-d808fbc226dd";
Expand Down Expand Up @@ -72,4 +80,24 @@ public void shouldReturnNullIfUuidIsNotValidTestOrder() {
TestOrder result = dao.get(OTHER_ORDER_UUID);
assertThat(result, nullValue());
}

@Test
public void search_shouldReturnResultsBasedOnOrderNumber() {
// Settup
TokenAndListParam ordrNumber = new TokenAndListParam();
TokenParam token = new TokenParam();
token.setValue(TEST_ORDER_NUMBER);
ordrNumber.addAnd(token);

SearchParameterMap theParams = new SearchParameterMap();
theParams.addParameter(FhirConstants.IDENTIFIER, ordrNumber);

// Replay
List<String> matchingResourceUuids = dao.getSearchResultUuids(theParams);
List<TestOrder> drugOrders = dao.getSearchResults(theParams, matchingResourceUuids);

// Verify
assertThat(drugOrders, notNullValue());
assertThat(drugOrders.get(0).getOrderNumber(), equalTo(TEST_ORDER_NUMBER));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ public class MedicationRequestTranslatorImplTest {

private static final String DOSING_INSTRUCTIONS = "Dosing instructions";

private static final String IDENTIFIER_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0203";

private static final String IDENTIFIER_CODE = "PLAC";

private static final String IDENTIFIER_DISPLAY = "Placer Identifier";

@Mock
private PractitionerReferenceTranslator<Provider> providerPractitionerReferenceTranslator;

Expand Down Expand Up @@ -160,6 +166,11 @@ public void toFhirResource_shouldTranslateToFhirResource() {
assertThat(result, notNullValue());
assertThat(result.getId(), notNullValue());
assertThat(result.getId(), equalTo(DRUG_ORDER_UUID));
assertThat(result.getIdentifier().get(0).getValue(), equalTo(DRUG_ORDER_NUMBER));
assertThat(result.getIdentifier().get(0).getType().getCoding().get(0).getSystem(), equalTo(IDENTIFIER_SYSTEM));
assertThat(result.getIdentifier().get(0).getType().getCoding().get(0).getCode(), equalTo(IDENTIFIER_CODE));
assertThat(result.getIdentifier().get(0).getType().getCoding().get(0).getDisplay(), equalTo(IDENTIFIER_DISPLAY));
assertThat(result.getIdentifier().get(0).getUse().getDisplay(), equalTo("Usual"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.exparity.hamcrest.date.DateMatchers;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Period;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.ServiceRequest;
Expand Down Expand Up @@ -85,6 +86,12 @@ public class ServiceRequestTranslatorImplTest {

private static final int COUNT = 1;

private static final String IDENTIFIER_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0203";

private static final String IDENTIFIER_CODE = "PLAC";

private static final String IDENTIFIER_DISPLAY = "Placer Identifier";

private ServiceRequestTranslatorImpl translator;

@Mock
Expand Down Expand Up @@ -550,6 +557,34 @@ public void toFhirResource_shouldTranslateRequester() {
assertThat(result.getReference(), containsString(PRACTITIONER_UUID));
}

@Test
public void toFhirResource_shouldTranslateOrderNumber() {

TestOrder order = new TestOrder();
Provider requester = new Provider();
Reference requesterReference = new Reference();

requester.setUuid(PRACTITIONER_UUID);
order.setUuid(SERVICE_REQUEST_UUID);
order.setOrderer(requester);
setOrderNumberByReflection(order, TEST_ORDER_NUMBER);
requesterReference.setType(FhirConstants.PRACTITIONER)
.setReference(FhirConstants.PRACTITIONER + "/" + PRACTITIONER_UUID);

when(taskService.searchForTasks(any(), any(), any(), any(), any(), any()))
.thenReturn(new MockIBundleProvider<>(Collections.emptyList(), PREFERRED_PAGE_SIZE, COUNT));
when(practitionerReferenceTranslator.toFhirResource(requester)).thenReturn(requesterReference);

Identifier result = translator.toFhirResource(order).getIdentifier().get(0);

assertThat(result, notNullValue());
assertThat(result.getValue(), containsString(TEST_ORDER_NUMBER));
assertThat(result.getType().getCoding().get(0).getSystem(), equalTo(IDENTIFIER_SYSTEM));
assertThat(result.getType().getCoding().get(0).getCode(), equalTo(IDENTIFIER_CODE));
assertThat(result.getType().getCoding().get(0).getDisplay(), equalTo(IDENTIFIER_DISPLAY));
assertThat(result.getUse().getDisplay(), equalTo("Usual"));
}

private List<Task> setUpBasedOnScenario(Task.TaskStatus status) {
Reference basedOnRef = new Reference();
Task task = new Task();
Expand Down