-
Notifications
You must be signed in to change notification settings - Fork 9
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
HSC-379: Add support for imaging, procedure and medical supply orders #68
Merged
Merged
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
37ecd8d
[WIP] Add Procedure router
VaishSiddharth 6398896
[WIP] Add MedicalSupply orders support
VaishSiddharth 550280c
Fix
VaishSiddharth 07d0480
Add MedicalSupply support
VaishSiddharth 3ea0a72
Remove table from FhirResource listen tables for MedicalSupply
VaishSiddharth 8927840
Refactor
VaishSiddharth f3a2aac
Add lombok and remove hardcoings
VaishSiddharth 6d0b7b2
Unit tests added for SupplyRequest and Procedure order router
VaishSiddharth 4d11a07
Fix
VaishSiddharth 47eecec
Fix+
VaishSiddharth 6899925
Add tests
VaishSiddharth f477007
Disabled unit tests for Supply and Procedure orders
VaishSiddharth f5d43cd
Address comments
VaishSiddharth cad1e09
Address comments+
VaishSiddharth fc82bb8
Address comments+
VaishSiddharth 3789978
Add support for OAuth
VaishSiddharth f89334f
Add http headers
VaishSiddharth d8646c4
Fix test
VaishSiddharth e8167ba
Address comments
VaishSiddharth 8d2ed1a
Fix tests
VaishSiddharth 102a3d1
Refactor
VaishSiddharth 3516ce6
Add support for discontinue and modify order
VaishSiddharth f23991e
Fix * imports
VaishSiddharth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
camel-openmrs-fhir/src/main/java/org/openmrs/eip/fhir/routes/resources/ProcedureRouter.java
VaishSiddharth marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package org.openmrs.eip.fhir.routes.resources; | ||
|
||
import static org.openmrs.eip.fhir.Constants.HEADER_FHIR_EVENT_TYPE; | ||
import static org.openmrs.eip.fhir.Constants.PROCEDURE_ORDER_TYPE_UUID; | ||
import static org.openmrs.eip.fhir.Constants.PROP_EVENT_OPERATION; | ||
|
||
import java.util.Date; | ||
|
||
import org.apache.camel.LoggingLevel; | ||
import org.apache.camel.component.http.HttpComponent; | ||
import org.apache.camel.model.dataformat.JsonLibrary; | ||
import org.hl7.fhir.r4.model.CodeableConcept; | ||
import org.hl7.fhir.r4.model.Coding; | ||
import org.hl7.fhir.r4.model.Reference; | ||
import org.hl7.fhir.r4.model.ServiceRequest; | ||
import org.openmrs.eip.fhir.FhirResource; | ||
import org.openmrs.eip.fhir.routes.resources.dto.Order; | ||
import org.openmrs.eip.fhir.spring.OpenmrsRestConfiguration; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import lombok.Setter; | ||
|
||
@Setter | ||
@Component | ||
public class ProcedureRouter extends BaseFhirResourceRouter { | ||
|
||
@Value("${openmrs.baseUrl}") | ||
private String openmrsBaseUrl; | ||
|
||
@Autowired | ||
private OpenmrsRestConfiguration openmrsRestConfiguration; | ||
|
||
ProcedureRouter() { | ||
super(FhirResource.PROCEDURE); | ||
} | ||
|
||
@Override | ||
public void configure() throws Exception { | ||
getCamelContext().getComponent("http", HttpComponent.class) | ||
.setHttpClientConfigurer(openmrsRestConfiguration.createHttpClientConfigurer()); | ||
|
||
from(FhirResource.PROCEDURE.incomingUrl()).routeId("fhir-procedure-router").filter(isSupportedTable()).toD( | ||
"sql:SELECT ot.uuid as uuid from order_type ot join orders o on o.order_type_id = ot.order_type_id where o.uuid ='${exchangeProperty.event.identifier}'?dataSource=#openmrsDataSource") | ||
.filter(simple("${body[0]['uuid']} == '" + PROCEDURE_ORDER_TYPE_UUID + "'")) | ||
.log(LoggingLevel.INFO, "Processing ProcedureRouter ${exchangeProperty.event.tableName}") | ||
.toD( | ||
"sql:SELECT voided, order_action, previous_order_id FROM orders WHERE uuid = '${exchangeProperty.event.identifier}'?dataSource=#openmrsDataSource") | ||
.choice().when(simple("${exchangeProperty.event.operation} == 'd' || ${body[0]['voided']} == 1")) | ||
.setHeader(HEADER_FHIR_EVENT_TYPE, constant("d")).setBody(simple("${exchangeProperty.event.identifier}")) | ||
.to(FhirResource.PROCEDURE.outgoingUrl()).when(simple("${body[0]['order_action']} == 'DISCONTINUE'")) | ||
.toD( | ||
"sql:SELECT uuid FROM orders WHERE order_id = ${body[0]['previous_order_id']}?dataSource=#openmrsDataSource") | ||
.setHeader("CamelHttpMethod", constant("GET")).toD(openmrsBaseUrl + "/ws/rest/v1/order/${body[0]['uuid']}") | ||
.unmarshal().json(JsonLibrary.Jackson, Order.class).process(exchange -> { | ||
Order order = exchange.getIn().getBody(Order.class); | ||
exchange.getMessage().setBody(mapOrderToServiceRequest(order)); | ||
}).setHeader(HEADER_FHIR_EVENT_TYPE, constant("d")).to(FhirResource.PROCEDURE.outgoingUrl()).otherwise() | ||
.setHeader("CamelHttpMethod", constant("GET")) | ||
.toD(openmrsBaseUrl + "/ws/rest/v1/order/${exchangeProperty.event.identifier}").unmarshal() | ||
.json(JsonLibrary.Jackson, Order.class).process(exchange -> { | ||
Order order = exchange.getIn().getBody(Order.class); | ||
exchange.getMessage().setBody(mapOrderToServiceRequest(order)); | ||
}).setHeader(HEADER_FHIR_EVENT_TYPE, simple("${exchangeProperty." + PROP_EVENT_OPERATION + "}")) | ||
.to(FhirResource.PROCEDURE.outgoingUrl()).endChoice().end(); | ||
} | ||
|
||
private ServiceRequest mapOrderToServiceRequest(Order order) { | ||
ServiceRequest serviceRequest = new ServiceRequest(); | ||
serviceRequest.setStatus(determineServiceRequestStatus(order)); | ||
serviceRequest.setIntent(ServiceRequest.ServiceRequestIntent.ORDER); | ||
serviceRequest.setCode(new CodeableConcept( | ||
new Coding().setCode(order.getConcept().getUuid()).setDisplay(order.getConcept().getDisplay())) | ||
.setText(order.getConcept().getDisplay())); | ||
serviceRequest.setSubject(new Reference().setReference("Patient/" + order.getPatient().getUuid()).setType("Patient") | ||
.setDisplay(order.getPatient().getDisplay())); | ||
serviceRequest.setEncounter( | ||
new Reference().setReference("Encounter/" + order.getEncounter().getUuid()).setType("Encounter")); | ||
serviceRequest.setRequester(new Reference().setReference("Practitioner/" + order.getOrderer().getUuid()) | ||
.setType("Practitioner").setDisplay(order.getOrderer().getDisplay())); | ||
|
||
return serviceRequest; | ||
} | ||
|
||
private ServiceRequest.ServiceRequestStatus determineServiceRequestStatus(Order order) { | ||
Date currentDate = new Date(); | ||
boolean isCompeted = order.isActivated() | ||
&& ((order.getDateStopped() != null && currentDate.after(order.getDateStopped())) | ||
|| (order.getAutoExpireDate() != null && currentDate.after(order.getAutoExpireDate()))); | ||
boolean isDiscontinued = order.isActivated() && order.getAction().equals("DISCONTINUE"); | ||
|
||
if ((isCompeted && isDiscontinued)) { | ||
return ServiceRequest.ServiceRequestStatus.UNKNOWN; | ||
} else if (isDiscontinued) { | ||
return ServiceRequest.ServiceRequestStatus.REVOKED; | ||
} else if (isCompeted) { | ||
return ServiceRequest.ServiceRequestStatus.COMPLETED; | ||
} else { | ||
return ServiceRequest.ServiceRequestStatus.ACTIVE; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
...openmrs-fhir/src/main/java/org/openmrs/eip/fhir/routes/resources/SupplyRequestRouter.java
VaishSiddharth marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package org.openmrs.eip.fhir.routes.resources; | ||
|
||
import static org.openmrs.eip.fhir.Constants.HEADER_FHIR_EVENT_TYPE; | ||
import static org.openmrs.eip.fhir.Constants.PROP_EVENT_OPERATION; | ||
import static org.openmrs.eip.fhir.Constants.SUPPLY_REQUEST_ORDER_TYPE_UUID; | ||
|
||
import java.util.Collections; | ||
import java.util.Date; | ||
|
||
import org.apache.camel.LoggingLevel; | ||
import org.apache.camel.component.http.HttpComponent; | ||
import org.apache.camel.model.dataformat.JsonLibrary; | ||
import org.hl7.fhir.r4.model.Quantity; | ||
import org.hl7.fhir.r4.model.Reference; | ||
import org.hl7.fhir.r4.model.ServiceRequest; | ||
import org.hl7.fhir.r4.model.SupplyRequest; | ||
import org.openmrs.eip.fhir.FhirResource; | ||
import org.openmrs.eip.fhir.routes.resources.dto.Order; | ||
import org.openmrs.eip.fhir.spring.OpenmrsRestConfiguration; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import lombok.Setter; | ||
|
||
@Setter | ||
@Component | ||
public class SupplyRequestRouter extends BaseFhirResourceRouter { | ||
|
||
@Value("${openmrs.baseUrl}") | ||
private String openmrsBaseUrl; | ||
|
||
@Autowired | ||
private OpenmrsRestConfiguration openmrsRestConfiguration; | ||
|
||
SupplyRequestRouter() { | ||
super(FhirResource.SUPPLYREQUEST); | ||
} | ||
|
||
@Override | ||
public void configure() throws Exception { | ||
getCamelContext().getComponent("http", HttpComponent.class) | ||
.setHttpClientConfigurer(openmrsRestConfiguration.createHttpClientConfigurer()); | ||
|
||
from(FhirResource.SUPPLYREQUEST.incomingUrl()).routeId("fhir-supplyrequest-router").filter(isSupportedTable()).toD( | ||
"sql:SELECT ot.uuid as uuid from order_type ot join orders o on o.order_type_id = ot.order_type_id where o.uuid ='${exchangeProperty.event.identifier}'?dataSource=#openmrsDataSource") | ||
.filter(simple("${body[0]['uuid']} == '" + SUPPLY_REQUEST_ORDER_TYPE_UUID + "'")) | ||
.log(LoggingLevel.INFO, "Processing SupplyRequestRouter ${exchangeProperty.event.tableName}") | ||
.toD( | ||
"sql:SELECT voided, order_action, previous_order_id FROM orders WHERE uuid = '${exchangeProperty.event.identifier}'?dataSource=#openmrsDataSource") | ||
.choice().when(simple("${exchangeProperty.event.operation} == 'd' || ${body[0]['voided']} == 1")) | ||
.setHeader(HEADER_FHIR_EVENT_TYPE, constant("d")).setBody(simple("${exchangeProperty.event.identifier}")) | ||
.to(FhirResource.SUPPLYREQUEST.outgoingUrl()).when(simple("${body[0]['order_action']} == 'DISCONTINUE'")) | ||
.toD( | ||
"sql:SELECT uuid FROM orders WHERE order_id = ${body[0]['previous_order_id']}?dataSource=#openmrsDataSource") | ||
.setHeader("CamelHttpMethod", constant("GET")).toD(openmrsBaseUrl + "/ws/rest/v1/order/${body[0]['uuid']}") | ||
.unmarshal().json(JsonLibrary.Jackson, Order.class).process(exchange -> { | ||
Order order = exchange.getIn().getBody(Order.class); | ||
exchange.getMessage().setBody(mapOrderToSupplyRequest(order)); | ||
}).setHeader(HEADER_FHIR_EVENT_TYPE, constant("d")).to(FhirResource.SUPPLYREQUEST.outgoingUrl()).otherwise() | ||
.setHeader("CamelHttpMethod", constant("GET")) | ||
.toD(openmrsBaseUrl + "/ws/rest/v1/order/${exchangeProperty.event.identifier}").unmarshal() | ||
.json(JsonLibrary.Jackson, Order.class).process(exchange -> { | ||
Order order = exchange.getIn().getBody(Order.class); | ||
exchange.getMessage().setBody(mapOrderToSupplyRequest(order)); | ||
}).setHeader(HEADER_FHIR_EVENT_TYPE, simple("${exchangeProperty." + PROP_EVENT_OPERATION + "}")) | ||
.to(FhirResource.SUPPLYREQUEST.outgoingUrl()).endChoice().end(); | ||
} | ||
|
||
private SupplyRequest mapOrderToSupplyRequest(Order order) { | ||
SupplyRequest supplyRequest = new SupplyRequest(); | ||
supplyRequest.setId(order.getUuid()); | ||
supplyRequest.setItem(new Reference().setReference("MedicalSupply/" + order.getConcept().getUuid()) | ||
.setDisplay(order.getConcept().getDisplay())); | ||
supplyRequest.setReasonReference(Collections.singletonList( | ||
new Reference().setType("Encounter").setReference("Encounter/" + order.getEncounter().getUuid()))); | ||
supplyRequest.setQuantity(new Quantity().setValue(order.getQuantity()).setCode(order.getQuantityUnits().getUuid())); | ||
supplyRequest.setRequester( | ||
new Reference().setReference(order.getOrderer().getUuid()).setDisplay(order.getOrderer().getDisplay())); | ||
supplyRequest.setDeliverTo(new Reference().setReference("Patient/" + order.getPatient().getUuid()) | ||
.setDisplay(order.getPatient().getDisplay())); | ||
supplyRequest.setStatus(determineSupplyRequestStatus(order)); | ||
|
||
return supplyRequest; | ||
} | ||
|
||
private SupplyRequest.SupplyRequestStatus determineSupplyRequestStatus(Order order) { | ||
Date currentDate = new Date(); | ||
boolean isCompeted = order.isActivated() | ||
&& ((order.getDateStopped() != null && currentDate.after(order.getDateStopped())) | ||
|| (order.getAutoExpireDate() != null && currentDate.after(order.getAutoExpireDate()))); | ||
boolean isDiscontinued = order.isActivated() && order.getAction().equals("DISCONTINUE"); | ||
|
||
if ((isCompeted && isDiscontinued)) { | ||
return SupplyRequest.SupplyRequestStatus.UNKNOWN; | ||
} else if (isDiscontinued) { | ||
return SupplyRequest.SupplyRequestStatus.CANCELLED; | ||
} else if (isCompeted) { | ||
return SupplyRequest.SupplyRequestStatus.COMPLETED; | ||
} else { | ||
return SupplyRequest.SupplyRequestStatus.ACTIVE; | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
camel-openmrs-fhir/src/main/java/org/openmrs/eip/fhir/routes/resources/dto/Concept.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.openmrs.eip.fhir.routes.resources.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class Concept { | ||
|
||
public String uuid; | ||
|
||
public String display; | ||
} |
19 changes: 19 additions & 0 deletions
19
camel-openmrs-fhir/src/main/java/org/openmrs/eip/fhir/routes/resources/dto/Encounter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.openmrs.eip.fhir.routes.resources.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class Encounter { | ||
|
||
public String uuid; | ||
|
||
public String display; | ||
|
||
} |
95 changes: 95 additions & 0 deletions
95
camel-openmrs-fhir/src/main/java/org/openmrs/eip/fhir/routes/resources/dto/Order.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package org.openmrs.eip.fhir.routes.resources.dto; | ||
|
||
import java.sql.Timestamp; | ||
import java.util.Date; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class Order { | ||
|
||
public String uuid; | ||
|
||
public String orderNumber; | ||
|
||
public String accessionNumber; | ||
|
||
public Patient patient; | ||
|
||
public Concept concept; | ||
|
||
public String action; | ||
|
||
public Object previousOrder; | ||
|
||
public Date dateActivated; | ||
|
||
public Object scheduledDate; | ||
|
||
public Date dateStopped; | ||
|
||
public Date autoExpireDate; | ||
|
||
public Encounter encounter; | ||
|
||
public Orderer orderer; | ||
|
||
public Object orderReason; | ||
|
||
public Object orderReasonNonCoded; | ||
|
||
public String urgency; | ||
|
||
public Object instructions; | ||
|
||
public Object commentToFulfiller; | ||
|
||
public String display; | ||
|
||
public String type; | ||
|
||
public String resourceVersion; | ||
|
||
public float quantity; | ||
|
||
public QuantityUnits quantityUnits; | ||
|
||
public boolean isActivated() { | ||
return this.isActivated(new Date()); | ||
} | ||
|
||
public boolean isActivated(Date checkDate) { | ||
if (this.dateActivated == null) { | ||
return false; | ||
} else { | ||
if (checkDate == null) { | ||
checkDate = new Date(); | ||
} | ||
|
||
return compare(this.dateActivated, checkDate) <= 0; | ||
} | ||
} | ||
|
||
public static int compare(Date d1, Date d2) { | ||
if (d1 instanceof Timestamp && d2 instanceof Timestamp) { | ||
return d1.compareTo(d2); | ||
} else { | ||
if (d1 instanceof Timestamp) { | ||
d1 = new Date(d1.getTime()); | ||
} | ||
|
||
if (d2 instanceof Timestamp) { | ||
d2 = new Date(d2.getTime()); | ||
} | ||
|
||
return d1.compareTo(d2); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, hardcoding UUIDs is not ideal, as different implementations may require different sets of UUIDs. I would prefer making these configurable with default values, rather than embedding them directly into the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you are right. But let's take this up separately as this is an existing practice for this repo.
Have created a ticket here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this issue is becoming more prominent as it is going to be consumed by existing distributions with pre-existing data. The sooner this is addressed, the better. I believe this can be resolved in the current PR, as it already includes the majority of the referenced UUIDs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ruhanga I would not want to include the changes you suggested in this PR. I have created a new PR for the above ticket. Will need to fix test cases to make it work.
I would request @rbuisson to please merge this PR as this is blocking HSC deployment.