From ea904bf7ad791d4c842851623094c94860e6191f Mon Sep 17 00:00:00 2001 From: Joyce Quach Date: Thu, 18 Jan 2024 14:55:15 -0500 Subject: [PATCH 1/5] Fix typo --- .../java/org/hl7/davinci/ehrserver/authproxy/AuthProxy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/hl7/davinci/ehrserver/authproxy/AuthProxy.java b/src/main/java/org/hl7/davinci/ehrserver/authproxy/AuthProxy.java index 42ba3e8..3ad82d2 100644 --- a/src/main/java/org/hl7/davinci/ehrserver/authproxy/AuthProxy.java +++ b/src/main/java/org/hl7/davinci/ehrserver/authproxy/AuthProxy.java @@ -42,7 +42,7 @@ public class AuthProxy { * before redirecting back to the smart app. * @param reqParamValue - The parameters of the request * @param httpServletResponse - The response object to be sent back - * @param request - The request that has been recieved + * @param request - The request that has been received * @throws IOException - the uri components builder might throw an IO */ @GetMapping("/auth") @@ -120,7 +120,7 @@ public AuthResponse getLaunch(@RequestBody Payload payload) { * @param launch - the launch id is included in the path * @param reqParamValue - the parameters of the url should include only the code, state, and the original redirect url * @param httpServletResponse - the response object - * @param request - the request recieved + * @param request - the request received */ @GetMapping("/_auth/{launch}") public void authSync(@PathVariable String launch, @RequestParam Map reqParamValue, HttpServletResponse httpServletResponse, HttpServletRequest request) { From b9882548c2e5a7d95c96ae7eb7b997578c76e430 Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Fri, 2 Feb 2024 10:59:08 -0500 Subject: [PATCH 2/5] Receive RxFill message and return Status message. --- build.gradle | 4 + .../fhir/jpa/starter/FhirServerConfigR4.java | 1 + .../fhir/jpa/starter/FhirTesterConfig.java | 1 + .../codex/rems/script/DispensedStatus.java | 10 +++ .../org/hl7/codex/rems/script/FillStatus.java | 43 +++++++++ .../org/hl7/codex/rems/script/Header.java | 87 +++++++++++++++++++ .../org/hl7/codex/rems/script/Message.java | 30 +++++++ .../rems/script/NcpdpScriptController.java | 56 ++++++++++++ .../org/hl7/codex/rems/script/RxFill.java | 15 ++++ .../org/hl7/codex/rems/script/RxFillBody.java | 15 ++++ .../hl7/codex/rems/script/RxFillMessage.java | 26 ++++++ .../codex/rems/script/RxFillStatusBody.java | 23 +++++ .../rems/script/RxFillStatusMessage.java | 36 ++++++++ .../org/hl7/codex/rems/script/Status.java | 22 +++++ .../java/org/hl7/codex/rems/script/Tag.java | 22 +++++ 15 files changed, 391 insertions(+) create mode 100644 src/main/java/org/hl7/codex/rems/script/DispensedStatus.java create mode 100644 src/main/java/org/hl7/codex/rems/script/FillStatus.java create mode 100644 src/main/java/org/hl7/codex/rems/script/Header.java create mode 100644 src/main/java/org/hl7/codex/rems/script/Message.java create mode 100644 src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java create mode 100644 src/main/java/org/hl7/codex/rems/script/RxFill.java create mode 100644 src/main/java/org/hl7/codex/rems/script/RxFillBody.java create mode 100644 src/main/java/org/hl7/codex/rems/script/RxFillMessage.java create mode 100644 src/main/java/org/hl7/codex/rems/script/RxFillStatusBody.java create mode 100644 src/main/java/org/hl7/codex/rems/script/RxFillStatusMessage.java create mode 100644 src/main/java/org/hl7/codex/rems/script/Status.java create mode 100644 src/main/java/org/hl7/codex/rems/script/Tag.java diff --git a/build.gradle b/build.gradle index 2566c51..82c359e 100644 --- a/build.gradle +++ b/build.gradle @@ -99,6 +99,10 @@ dependencies { // providedImplementation 'javax.servlet:javax.servlet-api:3.1.0' // implementation group:'org.apache.tomcat', name:'tomcat-juli', version:property('tomcat.version') implementation 'javax.interceptor:javax.interceptor-api:1.2.2' + + implementation 'javax.xml.bind:jaxb-api:2.3.0' + implementation 'com.sun.xml.bind:jaxb-core:2.3.0' + implementation 'com.sun.xml.bind:jaxb-impl:2.3.0' } // To specify folder use -Dfhir_dir= diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java index 8298e08..679ed68 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigR4.java @@ -24,6 +24,7 @@ @Configuration @Conditional(OnR4Condition.class) @ComponentScan(basePackages = "org.hl7.davinci.ehrserver.authproxy") +@ComponentScan(basePackages = "org.hl7.codex.rems.script") @Import(StarterCqlR4Config.class) public class FhirServerConfigR4 extends BaseJavaConfigR4 { diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java index 426b0d4..3273df3 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirTesterConfig.java @@ -19,6 +19,7 @@ */ @Configuration @ComponentScan(basePackages = "org.hl7.davinci.ehrserver.authproxy") +@ComponentScan(basePackages = "org.hl7.codex.rems.script") @Import(FhirTesterMvcConfig.class) public class FhirTesterConfig { diff --git a/src/main/java/org/hl7/codex/rems/script/DispensedStatus.java b/src/main/java/org/hl7/codex/rems/script/DispensedStatus.java new file mode 100644 index 0000000..8422ec9 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/DispensedStatus.java @@ -0,0 +1,10 @@ +package org.hl7.codex.rems.script; + +/* + * The possible values include: Dispensed, PartiallyDispensed, NotDispensed, Transferred + */ +public class DispensedStatus { + public String ReferenceNumber; + public String Note; + public String ReasonCode; +} diff --git a/src/main/java/org/hl7/codex/rems/script/FillStatus.java b/src/main/java/org/hl7/codex/rems/script/FillStatus.java new file mode 100644 index 0000000..77524a7 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/FillStatus.java @@ -0,0 +1,43 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlElement; + +public class FillStatus { + private DispensedStatus dispensed; + private DispensedStatus partiallyDispensed; + private DispensedStatus notDispensed; + private DispensedStatus transferred; + + @XmlElement(name="Dispensed") + public DispensedStatus getDispensed() { + return dispensed; + } + public void setDispensed(DispensedStatus dispensed) { + this.dispensed = dispensed; + } + + @XmlElement(name="PartiallyDispensed") + public DispensedStatus getPartiallyDispensed() { + return partiallyDispensed; + } + public void setPartiallyDispensed(DispensedStatus partiallyDispensed) { + this.partiallyDispensed = partiallyDispensed; + } + + @XmlElement(name="NotDispensed") + public DispensedStatus getNotDispensed() { + return notDispensed; + } + public void setNotDispensed(DispensedStatus notDispensed) { + this.notDispensed = notDispensed; + } + + @XmlElement(name="Transferred") + public DispensedStatus getTransferred() { + return transferred; + } + public void setTransferred(DispensedStatus transferred) { + this.transferred = transferred; + } + +} diff --git a/src/main/java/org/hl7/codex/rems/script/Header.java b/src/main/java/org/hl7/codex/rems/script/Header.java new file mode 100644 index 0000000..41058e0 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/Header.java @@ -0,0 +1,87 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlElement; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Header { + private Tag to; + private Tag from; + private String sentTime; + private String messageId; + private String relatesToMessageId; + private String prescriberOrderNumber; + + public Header() { + this.to = null; + this.from = null; + this.sentTime = null; + this.messageId = null; + this.relatesToMessageId = null; + this.prescriberOrderNumber = null; + } + + public Header(String to, String from, String relatesToMessageId, + String prescriberOrderNumber) { + this.to = new Tag("P", to); + this.from = new Tag("C", from); + + LocalDateTime now = LocalDateTime.now(); + this.sentTime = now.toString(); + + DateTimeFormatter nowFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSSSSS"); + String nowFormatted = now.format(nowFormatter); + this.messageId = nowFormatted; + + this.relatesToMessageId = relatesToMessageId; + this.prescriberOrderNumber = prescriberOrderNumber; + } + + @XmlElement(name="To") + public Tag getTo() { + return to; + } + public void setTo(Tag to) { + this.to = to; + } + + @XmlElement(name="From") + public Tag getFrom() { + return from; + } + public void setFrom(Tag from) { + this.from = from; + } + + @XmlElement(name="SentTime") + public String getSentTime() { + return sentTime; + } + public void setSentTime(String sentTime) { + this.sentTime = sentTime; + } + + @XmlElement(name="MessageID") + public String getMessageId() { + return messageId; + } + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + @XmlElement(name="RelatesToMessageID") + public String getRelatesToMessageId() { + return relatesToMessageId; + } + public void setRelatesToMessageId(String relatesToMessageId) { + this.relatesToMessageId = relatesToMessageId; + } + + @XmlElement(name="PrescriberOrderNumber") + public String getPrescriberOrderNumber() { + return prescriberOrderNumber; + } + public void setPrescriberOrderNumber(String prescriberOrderNumber) { + this.prescriberOrderNumber = prescriberOrderNumber; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/Message.java b/src/main/java/org/hl7/codex/rems/script/Message.java new file mode 100644 index 0000000..786baa7 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/Message.java @@ -0,0 +1,30 @@ +package org.hl7.codex.rems.script; + +//import java.io.Serializable; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlElement; + +@XmlRootElement(name="Message") +//public class Message implements Serializable { +public class Message { + protected Header header; + //protected Body body; + + @XmlElement(name="Header") + public Header getHeader() { + return header; + } + public void setHeader(Header header) { + this.header = header; + } + + /* + @XmlElement(name="Body") + public Body getBody() { + return body; + } + public void setBody(Body body) { + this.body = body; + } + */ +} diff --git a/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java new file mode 100644 index 0000000..05392bc --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java @@ -0,0 +1,56 @@ +package org.hl7.codex.rems.script; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class NcpdpScriptController { + static final Logger logger = LoggerFactory.getLogger(NcpdpScriptController.class); + + private static final String APPLICATION_XML = "application/xml"; + + @Autowired + private org.springframework.core.env.Environment environment; + + /** + * A custom endpoint that handles NCPDP Script messages. + * @param payload - the object used to serialize the XML in the request body. + * @return - an object containing the NCPDP Script Status to return. + */ + @PostMapping(value = "/script/rxfill", produces = {APPLICATION_XML}, consumes = {APPLICATION_XML}) + @ResponseBody + public RxFillStatusMessage getScriptResponse(@RequestBody RxFillMessage payload) { + /* + * TODO: zzzz + * x create classes for xml NCPDP SCRIPT RxFill input + * x create classes for xml NCPDP SCRIPT Status output + * grab matching MedicationRequest + * create MedicationResponse + * store MedicationResponse + * x creat the output message and return + */ + logger.info("getScriptResponse /script/rxfill"); + + Header header = payload.getHeader(); + RxFillBody body = payload.getBody(); + + logger.info("zzzz: MessageID: " + header.getMessageId()); + logger.info("zzzz: To (" + header.getTo().qualifier + "): " + header.getTo().value); + logger.info("zzzz: From (" + header.getFrom().qualifier + "): " + header.getFrom().value); + logger.info("zzzz: PrescriberOrderNumber: " + header.getPrescriberOrderNumber()); + logger.info("zzzz: Dispensed Status: " + body.getRxFill().getFillStatus().getDispensed().Note); + + // build the status to return + Header statusHeader = new Header(header.getFrom().value, header.getTo().value, + header.getMessageId(), header.getPrescriberOrderNumber()); + Status status = new Status("000", null, null, null); + RxFillStatusBody statusBody = new RxFillStatusBody(status); + RxFillStatusMessage statusMessage = new RxFillStatusMessage(statusHeader, statusBody); + return statusMessage; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/RxFill.java b/src/main/java/org/hl7/codex/rems/script/RxFill.java new file mode 100644 index 0000000..96e8c7d --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/RxFill.java @@ -0,0 +1,15 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlElement; + +public class RxFill { + private FillStatus fillStatus; + + @XmlElement(name="FillStatus") + public FillStatus getFillStatus() { + return fillStatus; + } + public void setFillStatus(FillStatus fillStatus) { + this.fillStatus = fillStatus; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/RxFillBody.java b/src/main/java/org/hl7/codex/rems/script/RxFillBody.java new file mode 100644 index 0000000..09d9414 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/RxFillBody.java @@ -0,0 +1,15 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlElement; + +public class RxFillBody { + private RxFill rxFill; + + @XmlElement(name="RxFill") + public RxFill getRxFill() { + return rxFill; + } + public void setRxFill(RxFill rxFill) { + this.rxFill = rxFill; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/RxFillMessage.java b/src/main/java/org/hl7/codex/rems/script/RxFillMessage.java new file mode 100644 index 0000000..f8e8219 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/RxFillMessage.java @@ -0,0 +1,26 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlElement; + +@XmlRootElement(name="Message") +public class RxFillMessage { + protected Header header; + private RxFillBody body; + + @XmlElement(name="Header") + public Header getHeader() { + return header; + } + public void setHeader(Header header) { + this.header = header; + } + + @XmlElement(name="Body") + public RxFillBody getBody() { + return body; + } + public void setBody(RxFillBody body) { + this.body = body; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/RxFillStatusBody.java b/src/main/java/org/hl7/codex/rems/script/RxFillStatusBody.java new file mode 100644 index 0000000..51d946b --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/RxFillStatusBody.java @@ -0,0 +1,23 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlElement; + +public class RxFillStatusBody { + private Status status; + + @XmlElement(name="Status") + public Status getStatus() { + return status; + } + public void setStatus(Status status) { + this.status = status; + } + + public RxFillStatusBody() { + this.status = null; + } + + public RxFillStatusBody(Status status) { + this.status = status; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/RxFillStatusMessage.java b/src/main/java/org/hl7/codex/rems/script/RxFillStatusMessage.java new file mode 100644 index 0000000..2158897 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/RxFillStatusMessage.java @@ -0,0 +1,36 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlElement; + +@XmlRootElement(name="Message") +public class RxFillStatusMessage { + protected Header header; + private RxFillStatusBody body; + + public RxFillStatusMessage() { + this.header = null; + this.body = null; + } + + public RxFillStatusMessage(Header header, RxFillStatusBody body) { + this.header = header; + this.body = body; + } + + @XmlElement(name="Header") + public Header getHeader() { + return header; + } + public void setHeader(Header header) { + this.header = header; + } + + @XmlElement(name="Body") + public RxFillStatusBody getBody() { + return body; + } + public void setBody(RxFillStatusBody body) { + this.body = body; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/Status.java b/src/main/java/org/hl7/codex/rems/script/Status.java new file mode 100644 index 0000000..be4553e --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/Status.java @@ -0,0 +1,22 @@ +package org.hl7.codex.rems.script; + +public class Status { + public String Code; + public String DescriptionCode; + public String Description; + public String PrescriptionDeliveryMethod; + + public Status() { + this.Code = null; + this.DescriptionCode = null; + this.Description = null; + this.PrescriptionDeliveryMethod = null; + } + + public Status(String code, String descriptionCode, String description, String prescriptionDeliveryMethod) { + this.Code = code; + this.DescriptionCode = descriptionCode; + this.Description = description; + this.PrescriptionDeliveryMethod = prescriptionDeliveryMethod; + } +} diff --git a/src/main/java/org/hl7/codex/rems/script/Tag.java b/src/main/java/org/hl7/codex/rems/script/Tag.java new file mode 100644 index 0000000..88bcaf1 --- /dev/null +++ b/src/main/java/org/hl7/codex/rems/script/Tag.java @@ -0,0 +1,22 @@ +package org.hl7.codex.rems.script; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlValue; + +public class Tag { + @XmlAttribute(name="Qualifier") + public String qualifier; + + @XmlValue + public String value; + + public Tag() { + this.qualifier = null; + this.value = null; + } + + public Tag(String qualifier, String value) { + this.qualifier = qualifier; + this.value = value; + } +} From e28152f76e719b8f33478cf94556bf704d0dd09c Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Tue, 6 Feb 2024 23:47:16 -0500 Subject: [PATCH 3/5] Read MedicationRequest and create new MedicationDispense from it. --- .../jpa/starter/BaseJpaRestfulServer.java | 21 ++++- .../fhir/jpa/starter/JpaRestfulServer.java | 2 + .../org/hl7/codex/rems/script/FillStatus.java | 22 +++++ .../rems/script/NcpdpScriptController.java | 90 +++++++++++++++---- 4 files changed, 119 insertions(+), 16 deletions(-) diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java index d3d1256..2e59320 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; import ca.uhn.fhir.jpa.bulk.export.provider.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; @@ -66,7 +67,9 @@ import java.util.Optional; import java.util.stream.Collectors; - +import ca.uhn.fhir.rest.server.IResourceProvider; +import org.hl7.fhir.r4.model.DomainResource; +import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider; public class BaseJpaRestfulServer extends RestfulServer { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaRestfulServer.class); @@ -420,4 +423,20 @@ private ServerConformanceR4 createConformance(RestfulServer theRestfulServer, IF myApplicationContext.getAutowireCapableBeanFactory().autowireBean(con); return con; } + + /* + * Get the FHIR Resource DAO for the specified FHIR Resource. + */ + public IFhirResourceDao getDao(Class c) { + List resProvList = getResourceProviders(); + for (IResourceProvider prov : resProvList) { + + if (prov.getResourceType() == c) { + ourLog.info("BaseJpaRestfulServer::getDao: " + prov.getClass()); + BaseJpaResourceProvider sProv = (BaseJpaResourceProvider)prov; + return sProv.getDao(); + } + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java index 5348e9c..1d80762 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/JpaRestfulServer.java @@ -6,12 +6,14 @@ import org.springframework.context.annotation.Import; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +@Component("JpaRestfulServer") @Import(AppProperties.class) public class JpaRestfulServer extends BaseJpaRestfulServer { @Autowired diff --git a/src/main/java/org/hl7/codex/rems/script/FillStatus.java b/src/main/java/org/hl7/codex/rems/script/FillStatus.java index 77524a7..ba905f2 100644 --- a/src/main/java/org/hl7/codex/rems/script/FillStatus.java +++ b/src/main/java/org/hl7/codex/rems/script/FillStatus.java @@ -8,6 +8,14 @@ public class FillStatus { private DispensedStatus notDispensed; private DispensedStatus transferred; + enum DispensedStatusEnum { + DISPENSED, + PARTIALLY_DISPENSED, + NOT_DISPENSED, + TRANSFERRED, + UNKNOWN + } + @XmlElement(name="Dispensed") public DispensedStatus getDispensed() { return dispensed; @@ -39,5 +47,19 @@ public DispensedStatus getTransferred() { public void setTransferred(DispensedStatus transferred) { this.transferred = transferred; } + + public DispensedStatusEnum getStatus() { + if (getDispensed() != null) { + return DispensedStatusEnum.DISPENSED; + } else if (getPartiallyDispensed() != null) { + return DispensedStatusEnum.PARTIALLY_DISPENSED; + } else if (getNotDispensed() != null) { + return DispensedStatusEnum.NOT_DISPENSED; + } else if (getTransferred() != null) { + return DispensedStatusEnum.TRANSFERRED; + } else { + return DispensedStatusEnum.UNKNOWN; + } + } } diff --git a/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java index 05392bc..1c43a1f 100644 --- a/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java +++ b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java @@ -7,6 +7,18 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import org.hl7.fhir.r4.model.MedicationRequest; +import org.hl7.fhir.r4.model.MedicationDispense; +import org.hl7.fhir.r4.model.Reference; + +import ca.uhn.fhir.jpa.starter.JpaRestfulServer; + +import org.hl7.fhir.instance.model.api.IIdType; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.jpa.partition.SystemRequestDetails; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; + @RestController public class NcpdpScriptController { @@ -17,6 +29,9 @@ public class NcpdpScriptController { @Autowired private org.springframework.core.env.Environment environment; + @Autowired + private JpaRestfulServer jpaRestfulServer; + /** * A custom endpoint that handles NCPDP Script messages. * @param payload - the object used to serialize the XML in the request body. @@ -25,25 +40,70 @@ public class NcpdpScriptController { @PostMapping(value = "/script/rxfill", produces = {APPLICATION_XML}, consumes = {APPLICATION_XML}) @ResponseBody public RxFillStatusMessage getScriptResponse(@RequestBody RxFillMessage payload) { - /* - * TODO: zzzz - * x create classes for xml NCPDP SCRIPT RxFill input - * x create classes for xml NCPDP SCRIPT Status output - * grab matching MedicationRequest - * create MedicationResponse - * store MedicationResponse - * x creat the output message and return - */ - logger.info("getScriptResponse /script/rxfill"); + logger.info("NcpdpScriptController::getScriptResponse /script/rxfill"); Header header = payload.getHeader(); RxFillBody body = payload.getBody(); + FillStatus.DispensedStatusEnum dispensedStatus = body.getRxFill().getFillStatus().getStatus(); + + logger.info(" PrescriberOrderNumber: " + header.getPrescriberOrderNumber()); + logger.info(" Dispensed Status: " + dispensedStatus); + + IFhirResourceDao medicationRequestDao = + jpaRestfulServer.getDao(MedicationRequest.class); + IFhirResourceDao medicationDispenseDao = + jpaRestfulServer.getDao(MedicationDispense.class); + + IIdType id = new IdDt(header.getPrescriberOrderNumber()); + + RequestDetails requestDetails = new SystemRequestDetails(); + requestDetails.setRequestId(header.getPrescriberOrderNumber()); + + // retrieve the MedicationRequeest + MedicationRequest medicationRequest = null; + try { + medicationRequest = medicationRequestDao.read(id, requestDetails); + logger.info(" Retrieved MedicationRequest: " + medicationRequest.getId() + + " subject: " + medicationRequest.getSubject().getReference()); + + } catch (ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException e1) { + logger.warn(" ERROR: resource not found"); + } catch (ca.uhn.fhir.rest.server.exceptions.ResourceGoneException e2) { + logger.warn(" ERROR: resource has been deleted"); + } + + // create the MedicationDispense + MedicationDispense medicationDispense = new MedicationDispense(); + if (medicationRequest != null) { + String[] requestIdParts = medicationRequest.getId().split("/"); + String requestId = requestIdParts[0] + "/" + requestIdParts[1]; + String dispenseId = requestIdParts[1] + "-dispense"; + medicationDispense.setId(dispenseId); + switch(dispensedStatus) { + case DISPENSED: + medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.COMPLETED); + break; + case PARTIALLY_DISPENSED: + medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.INPROGRESS); + break; + case NOT_DISPENSED: + medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.PREPARATION); + break; + case TRANSFERRED: + case UNKNOWN: + default: + medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.UNKNOWN); + } + medicationDispense.setMedication(medicationRequest.getMedication()); + medicationDispense.setSubject(medicationRequest.getSubject()); + medicationDispense.addAuthorizingPrescription(new Reference(requestId)); - logger.info("zzzz: MessageID: " + header.getMessageId()); - logger.info("zzzz: To (" + header.getTo().qualifier + "): " + header.getTo().value); - logger.info("zzzz: From (" + header.getFrom().qualifier + "): " + header.getFrom().value); - logger.info("zzzz: PrescriberOrderNumber: " + header.getPrescriberOrderNumber()); - logger.info("zzzz: Dispensed Status: " + body.getRxFill().getFillStatus().getDispensed().Note); + // store the MedicationDispense + RequestDetails dispenseDetails = new SystemRequestDetails(); + dispenseDetails.setRequestId(dispenseId); + medicationDispenseDao.update(medicationDispense, dispenseDetails); + logger.info(" Created new MedicationDispense: " + dispenseId); + } // build the status to return Header statusHeader = new Header(header.getFrom().value, header.getTo().value, From 84c12e84525988289ca79a3f4b925b980bf4f1cb Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Tue, 6 Feb 2024 23:53:08 -0500 Subject: [PATCH 4/5] minor refactor --- .../rems/script/NcpdpScriptController.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java index 1c43a1f..635d02f 100644 --- a/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java +++ b/src/main/java/org/hl7/codex/rems/script/NcpdpScriptController.java @@ -79,21 +79,7 @@ public RxFillStatusMessage getScriptResponse(@RequestBody RxFillMessage payload) String requestId = requestIdParts[0] + "/" + requestIdParts[1]; String dispenseId = requestIdParts[1] + "-dispense"; medicationDispense.setId(dispenseId); - switch(dispensedStatus) { - case DISPENSED: - medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.COMPLETED); - break; - case PARTIALLY_DISPENSED: - medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.INPROGRESS); - break; - case NOT_DISPENSED: - medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.PREPARATION); - break; - case TRANSFERRED: - case UNKNOWN: - default: - medicationDispense.setStatus(MedicationDispense.MedicationDispenseStatus.UNKNOWN); - } + medicationDispense.setStatus(convertRxFillDispensedStatusToMedicationDispenseStatus(dispensedStatus)); medicationDispense.setMedication(medicationRequest.getMedication()); medicationDispense.setSubject(medicationRequest.getSubject()); medicationDispense.addAuthorizingPrescription(new Reference(requestId)); @@ -113,4 +99,19 @@ public RxFillStatusMessage getScriptResponse(@RequestBody RxFillMessage payload) RxFillStatusMessage statusMessage = new RxFillStatusMessage(statusHeader, statusBody); return statusMessage; } + + private MedicationDispense.MedicationDispenseStatus convertRxFillDispensedStatusToMedicationDispenseStatus(FillStatus.DispensedStatusEnum dispensedStatus) { + switch(dispensedStatus) { + case DISPENSED: + return MedicationDispense.MedicationDispenseStatus.COMPLETED; + case PARTIALLY_DISPENSED: + return MedicationDispense.MedicationDispenseStatus.INPROGRESS; + case NOT_DISPENSED: + return MedicationDispense.MedicationDispenseStatus.PREPARATION; + case TRANSFERRED: + case UNKNOWN: + default: + return MedicationDispense.MedicationDispenseStatus.UNKNOWN; + } + } } From 6868dc06c2c518399003d6615d362a746b222ef8 Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Wed, 7 Feb 2024 14:17:59 -0500 Subject: [PATCH 5/5] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f80a3c2..67a6b3b 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Finally, ensure that the [request generator](https://github.com/mcode/request-ge | -------------- | ------------------------------------------------------ | | `/test-ehr/` | Base server endpoint | | `/test-ehr/r4` | EHR FHIR Server endpoint (will not resolve in browser) | +| `/test-ehr/script/rxfill` | NCPDP SCRIPT endpoint that RxFill messages from the pharmacy can be sent to (will not resolve in browser) | ## Version