diff --git a/.gitignore b/.gitignore index 427e890..430c527 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,12 @@ target .DS_Store # Log Files -*.log \ No newline at end of file +*.log + +# test files +api/null/* +null/* + +#vs Code +.vscode/* +api/id_file diff --git a/api/pom.xml b/api/pom.xml index c9ef90b..8f8a098 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -18,6 +18,7 @@ org.openmrs.module fhir2-api + ${fhirModuleVersion} org.openmrs.module @@ -67,10 +68,6 @@ javax.servlet javax.servlet-api - - javax.xml.ws - jaxws-api - org.springframework.ws spring-ws-core diff --git a/api/src/main/java/org/openmrs/module/xdssender/XdsSenderConstants.java b/api/src/main/java/org/openmrs/module/xdssender/XdsSenderConstants.java index 49e8b2d..e7209c0 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/XdsSenderConstants.java +++ b/api/src/main/java/org/openmrs/module/xdssender/XdsSenderConstants.java @@ -485,7 +485,17 @@ public final class XdsSenderConstants { public static final String SCT_TEMPLATE_HISTORY_OF_BLOOD_TRANSFUSIONS = "1.3.6.1.4.1.19376.1.5.3.1.1.9.12"; public static final String LOCATION_SITECODE_ATTRIBUTE_UUID = "6242bf19-207e-4076-9d28-9290525b8ed9"; - + + public static final String SYSTEM_IDENTIFIER_TYPE_NAME = "SYSTEM"; + + public static final String PROP_PID_LOCAL = "fhir2.uriPrefix"; + + public static final String IDENTIFIER_SYSTEM = "http://openclientregistry.org/fhir/sourceid"; + + public static final String SYSTEM_IDENTIFIER_TYPE_UUID = "99F5A4C3-CEEA-4F5F-ABE6-399CD4C9FE24"; + + public static final String ECID_IDENTIFIER_TYPE_NAME = "ECID"; + private XdsSenderConstants() { } } diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/cda/CdaDataUtil.java b/api/src/main/java/org/openmrs/module/xdssender/api/cda/CdaDataUtil.java index b27b4d2..1d150b3 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/cda/CdaDataUtil.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/cda/CdaDataUtil.java @@ -67,6 +67,7 @@ import org.openmrs.api.context.Context; import org.openmrs.module.xdssender.XdsSenderConfig; import org.openmrs.module.xdssender.XdsSenderConstants; +import org.openmrs.module.xdssender.api.xds.XdsUtil; import org.openmrs.util.OpenmrsConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -88,7 +89,7 @@ */ @Component("xdssender.CdaDataUtil") public class CdaDataUtil { - + // NOK codes private static final List nextOfKinRelations = Arrays.asList("MTH", "FTH", "GRMTH", "GRFTH", "SIB", "CHILD", "AUNT", "UNCLE", "PGRMTH", "MGRMTH", "PGRFTH", "MGRFTH", "SON", "DAU", "BRO", "SIS", "DOMPART", "FAMMEMB"); @@ -464,11 +465,29 @@ public RecordTarget createRecordTarget(Patient patient) { // Identifiers patientRole.setId(new SET()); for (PatientIdentifier pid : patient.getActiveIdentifiers()) { - II ii = new II(pid.getIdentifierType().getName(), pid.getIdentifier()); - if (!patientRole.getId().contains(ii)) - patientRole.getId().add(ii); + // To cater for old records assigned ECID by OpenEMPI, we will Skip adding the ECID identifier type + // if it already exists + if (!pid.getIdentifierType().getName().equals(XdsSenderConstants.ECID_IDENTIFIER_TYPE_NAME) ) { + II ii = new II(pid.getIdentifierType().getName(), pid.getIdentifier()); + if (!patientRole.getId().contains(ii)) + patientRole.getId().add(ii); + } } - + + // Add system identifier + II ii = null; + II iii = null; + try { + ii = new II(XdsSenderConstants.SYSTEM_IDENTIFIER_TYPE_NAME, XdsUtil.getPlaceholderSystemIdentifier(patient).getIdentifier()); + patientRole.getId().add(ii); + // Adding an ECID to allow for processing by xds-b-repository in the SHR + iii = new II(XdsSenderConstants.ECID_IDENTIFIER_TYPE_NAME, XdsUtil.getPlaceholderSystemIdentifier(patient).getIdentifier()); + patientRole.getId().add(iii); + } + catch (Exception e) { + e.printStackTrace(); + } + // Address? patientRole.setAddr(createAddressSet(patient)); @@ -476,10 +495,14 @@ public RecordTarget createRecordTarget(Patient patient) { patientRole.setTelecom(createTelecomSet(patient)); // Marital status? - PersonAttribute civilStatusCode = patient.getAttribute(XdsSenderConstants.ATTRIBUTE_NAME_CIVIL_STATUS); - if (civilStatusCode != null) - hl7Patient.setMaritalStatusCode(metadataUtil.getStandardizedCode((Concept) civilStatusCode.getHydratedObject(), - XdsSenderConstants.CODE_SYSTEM_MARITAL_STATUS, CE.class)); + try { + PersonAttribute civilStatusCode = patient.getAttribute(XdsSenderConstants.ATTRIBUTE_NAME_CIVIL_STATUS); + if (civilStatusCode != null) + hl7Patient.setMaritalStatusCode(metadataUtil.getStandardizedCode((Concept) civilStatusCode.getHydratedObject(), + XdsSenderConstants.CODE_SYSTEM_MARITAL_STATUS, CE.class)); + } catch (Exception e) { + e.printStackTrace(); + } // Names hl7Patient.setName(createNameSet(patient)); diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/cda/ClinicalDocumentBuilder.java b/api/src/main/java/org/openmrs/module/xdssender/api/cda/ClinicalDocumentBuilder.java index 1763db1..df763de 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/cda/ClinicalDocumentBuilder.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/cda/ClinicalDocumentBuilder.java @@ -68,11 +68,14 @@ public DocumentModel buildDocument(Patient patient, Encounter encounter) throws //relevantObs = Context.getObsService().getObservationsByPerson(builder.getRecordTarget()); for (Obs obs : relevantObs) { - //we want to have all obs groups at the end of the list - if (obs.hasGroupMembers()) { - medicationObs.add(obs); - } else { - medicationObs.add(0, obs); //this probably is some group member + // Ensure that only obs relating to Tests are eliminated from the list + if (!obs.getConcept().getConceptClass().getName().equals("Test")) { + //we want to have all obs groups at the end of the list + if (obs.hasGroupMembers()) { + medicationObs.add(obs); + } else { + medicationObs.add(0, obs); //this probably is some group member + } } } diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/cda/EncounterEventListener.java b/api/src/main/java/org/openmrs/module/xdssender/api/cda/EncounterEventListener.java index c1509b2..f6d564e 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/cda/EncounterEventListener.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/cda/EncounterEventListener.java @@ -103,8 +103,9 @@ private void exportEncounter(String encounterUuid) { LOGGER.warn("Skipped sending Encounter %s (formId is NULL " + "-> probably it's the creating encounter)"); } else { Patient patient = Context.getPatientService().getPatient(encounter.getPatient().getPatientId()); - - ecidUpdater.fetchEcidIfRequired(patient); + + // TODO: Replace this with a method that queries OpenCR and fetches/updates the patient data + // ecidUpdater.fetchEcidIfRequired(patient); XdsExportService service = Context.getService(XdsExportService.class); diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/fhir/FhirResourceDocumentBuilderImpl.java b/api/src/main/java/org/openmrs/module/xdssender/api/fhir/FhirResourceDocumentBuilderImpl.java index b106cd6..e9895ac 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/fhir/FhirResourceDocumentBuilderImpl.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/fhir/FhirResourceDocumentBuilderImpl.java @@ -4,6 +4,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Resource; import org.marc.everest.datatypes.NullFlavor; import org.marc.everest.datatypes.TS; @@ -14,10 +15,12 @@ import org.openmrs.api.impl.BaseOpenmrsService; import org.openmrs.module.fhir2.api.translators.PatientTranslator; import org.openmrs.module.fhir2.api.translators.impl.PatientTranslatorImpl; +import org.openmrs.module.xdssender.XdsSenderConfig; import org.openmrs.module.xdssender.XdsSenderConstants; import org.openmrs.module.xdssender.api.cda.CdaDataUtil; import org.openmrs.module.xdssender.api.cda.model.DocumentModel; import org.openmrs.module.xdssender.api.fhir.exceptions.ResourceGenerationException; +import org.openmrs.module.xdssender.api.xds.XdsUtil; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -82,13 +85,10 @@ public Resource generateFhirResource(Object openmrsEntity) throws ResourceGenera if (openmrsEntity instanceof Patient) { Patient patient = (Patient)openmrsEntity; resource = patientTranslator.toFhirResource(patient); - localPatientId = Context.getAdministrationService().getGlobalProperty(PROP_PID_LOCAL); - if (localPatientId == null) { - throw new ResourceGenerationException("Unable to retrieve the Local PID, ensure that the MPI client module is installed and the \"PID LOCAL\" global property has been set"); - } - org.hl7.fhir.r4.model.Patient patientResource = (org.hl7.fhir.r4.model.Patient) resource; - patientResource.addIdentifier().setSystem(IDENTIFIER_SYSTEM).setValue(localPatientId + patient.getUuid()); - resource = patientResource; + org.hl7.fhir.r4.model.Patient patientResource; + patientResource = checkAndSetSystemIdentifier(patient, (org.hl7.fhir.r4.model.Patient) resource); + + resource = patientResource; } else { log.error(String.format("Entity %s not yet implemented", openmrsEntity.getClass().getName())); throw new ResourceGenerationException("Entity not implemented"); @@ -97,7 +97,35 @@ public Resource generateFhirResource(Object openmrsEntity) throws ResourceGenera return resource; } - /** + private org.hl7.fhir.r4.model.Patient checkAndSetSystemIdentifier(Patient patient, org.hl7.fhir.r4.model.Patient patientResource) + throws ResourceGenerationException { + Boolean isSystemIdentifierDefined = false; + for (Identifier identifer: patientResource.getIdentifier()) { + if(identifer.getSystem() != null) { + if (identifer.getSystem().equals(XdsSenderConstants.IDENTIFIER_SYSTEM)) { + isSystemIdentifierDefined = true; + break; + } + } + } + + if (!isSystemIdentifierDefined) { + PatientIdentifier systemPatientIdentifier = null; + try { + systemPatientIdentifier = XdsUtil.getPlaceholderSystemIdentifier(patient); + } + catch (Exception e) { + throw new ResourceGenerationException("Unable to retrieve the Local PID, ensure that the \"PID LOCAL\" global property has been set"); + } + + patientResource.addIdentifier().setSystem(XdsSenderConfig.getInstance().getEcidRoot()).setValue(systemPatientIdentifier.getIdentifier()); + // qpatientResource.addIdentifier().setSystem(XdsSenderConstants.IDENTIFIER_SYSTEM).setValue(systemPatientIdentifier.getIdentifier()); + } + + return patientResource; + } + + /** * @should return valid document */ @Override diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/notificationspullpoint/impl/NotificationsPullPointClientImpl.java b/api/src/main/java/org/openmrs/module/xdssender/api/notificationspullpoint/impl/NotificationsPullPointClientImpl.java index a219b89..a9202db 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/notificationspullpoint/impl/NotificationsPullPointClientImpl.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/notificationspullpoint/impl/NotificationsPullPointClientImpl.java @@ -50,118 +50,130 @@ @Component("xdssender.NotificationsPullPointClientImpl") public class NotificationsPullPointClientImpl extends WebServiceGatewaySupport implements NotificationsPullPointClient { - + // TODO: Move this parameter to the Global Properties section and allow for multiple location tags private static final String LOCATION_TAG_NAME = "Login Location"; - + private static final Logger log = LoggerFactory.getLogger(NotificationsPullPointClientImpl.class); - + + public static final String FACILITY_QNAME = "facility"; private BigInteger MAX_MESSAGES_PER_REQUEST = BigInteger.valueOf(100); - + @Autowired private XdsSenderConfig config; - + @Override public List getNewMessages() { LocationTag loginLocationTag = Context.getLocationService().getLocationTagByName(LOCATION_TAG_NAME); List locations = Context.getLocationService().getLocationsByTag(loginLocationTag); List returnMessages = new ArrayList(); - + for (Location location : locations) { returnMessages.addAll(this.getNewMessages(location)); } - + if (returnMessages.size() > 0) { return returnMessages; } - + return null; } - + @Override public List getNewMessages(Location currentLocation) { GetMessages request = new GetMessages(); String siteCode = null; - + request.setMaximumNumber(MAX_MESSAGES_PER_REQUEST); - + for (LocationAttribute attribute : currentLocation.getAttributes()) { if (attribute.getAttributeType().getUuid().equals(XdsSenderConstants.LOCATION_SITECODE_ATTRIBUTE_UUID)) { siteCode = attribute.getValue().toString(); } } - + log.debug("Location SiteCode, Name: ID: SiteCode {}", currentLocation.getName() + ": " + currentLocation.getId() + ": " + siteCode); - request.getOtherAttributes().put(new QName("facility"), siteCode); - + request.getOtherAttributes().put(new QName(FACILITY_QNAME), siteCode); + + List result = new ArrayList<>(); GetMessagesResponse response; try { // response = (GetMessagesResponse) getResponse(request); response = (GetMessagesResponse) getResponseHttpClient(request); - List result = new ArrayList<>(); - HL7Service hl7Service = Context.getHL7Service(); for (NotificationMessageHolderType notification : response.getNotificationMessage()) { - // TODO: Ensure that this casting is working properly Element el = (Element) notification.getMessage().getAny(); - // Message e = new PipeParser().parse(el.getTextContent()); + String decodedMessage = new String(Base64.decodeBase64(el.getTextContent()), "UTF-8"); String parsedMessage = OruR01Util - .changeMessageVersionFrom251To25(el.getTextContent().replace("\n", Character.toString((char) 13)) // Replace new line character with it's ASCII equivalent + .changeMessageVersionFrom251To25(decodedMessage.replace("\n", Character.toString((char) 13)) // Replace new line character with it's ASCII equivalent .replaceAll("\\[[0-9]{4}\\]", "")); // Remove the time component from the birthdate to fix a HL7 parsing error - + log.debug(parsedMessage); Message message = hl7Service.parseHL7String(parsedMessage); result.add(message); } - - return result; - } catch (Exception e) { log.debug("Error getting response in NotificationsPullPointClientImpl: ", e); e.printStackTrace(); + } finally { + return result; } - - return null; - } - + private Object getResponse(Object requestPayload) throws Exception { - + WebServiceMessageCallback addAuthorizationHeader = new WebServiceMessageCallback() { - + @Override public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { addAuthorizationHeader(requestPayload); } }; - + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); - + marshaller.setContextPath("org.openmrs.module.xdssender.notificationspullpoint"); marshaller.afterPropertiesSet(); - + WebServiceTemplate webServiceTemplate = getWebServiceTemplate(); webServiceTemplate.setMarshaller(marshaller); return webServiceTemplate.marshalSendAndReceive(config.getNotificationsPullPointEndpoint(), requestPayload, addAuthorizationHeader); } - + private Object getResponseHttpClient(GetMessages requestPayload) throws Exception { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("org.openmrs.module.xdssender.notificationspullpoint"); marshaller.afterPropertiesSet(); StringResult result = new StringResult(); marshaller.marshal(requestPayload, result); - + OkHttpClient client = new OkHttpClient().newBuilder().build(); MediaType mediaType = MediaType.parse("text/xml; charset=utf-8"); + String facilitySiteCode = requestPayload.getOtherAttributes().get(new QName(FACILITY_QNAME)); + String getMessagesPayload = String.format("" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " 100\r\n" + + " \r\n" + + " \r\n" + + "", + facilitySiteCode); RequestBody body = RequestBody.create( - "\r\n \r\n \r\n \r\n 100\r\n \r\n \r\n", + getMessagesPayload, mediaType); - // RequestBody body = RequestBody.create(result.toString(), mediaType); Request request = new Request.Builder().url(config.getNotificationsPullPointEndpoint()).method("POST", body) .addHeader("Content-Type", "text/xml; charset=utf-8") .addHeader("Accept", "text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2") @@ -169,14 +181,14 @@ private Object getResponseHttpClient(GetMessages requestPayload) throws Exceptio config.getNotificationsPullPointPassword())) .build(); Response response = client.newCall(request).execute(); - + JAXBContext jaxbContext = JAXBContext.newInstance("org.openmrs.module.xdssender.notificationspullpoint"); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); String responseText = response.body().string(); Object res = unmarshaller.unmarshal(IOUtils.toInputStream(responseText)); - + return res; - + } private void addAuthorizationHeader() { @@ -185,7 +197,7 @@ private void addAuthorizationHeader() { connection.getConnection().addRequestProperty("Authorization", generateBasicAuthenticationHeader( config.getNotificationsPullPointUsername(), config.getNotificationsPullPointPassword())); } - + private void addAuthorizationHeader(Object requestPayload) { log.debug("Setting authorization headers"); TransportContext context = TransportContextHolder.getTransportContext(); @@ -199,10 +211,10 @@ private void addAuthorizationHeader(Object requestPayload) { log.debug(conn.getRequestProperty("Content-Length")); } } - + private static String generateBasicAuthenticationHeader(String userName, String userPassword) { byte[] bytesEncoded = Base64.encodeBase64((userName + ":" + userPassword).getBytes(Charset.forName("UTF-8"))); return "Basic " + new String(bytesEncoded, Charset.forName("UTF-8")); } - + } diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImpl.java b/api/src/main/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImpl.java index aa02897..a350331 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImpl.java @@ -2,25 +2,32 @@ import java.util.ArrayList; import java.util.List; +import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dcm4chee.xds2.infoset.ihe.ProvideAndRegisterDocumentSetRequestType; import org.dcm4chee.xds2.infoset.ihe.ProvideAndRegisterDocumentSetRequestType.Document; +import org.dcm4chee.xds2.infoset.rim.IdentifiableType; import org.dcm4chee.xds2.infoset.rim.RegistryResponseType; import org.openmrs.Encounter; import org.openmrs.Patient; +import org.openmrs.PatientIdentifier; +import org.openmrs.PatientIdentifierType; +import org.openmrs.api.context.Context; import org.openmrs.api.impl.BaseOpenmrsService; import org.openmrs.module.xdssender.XdsSenderConfig; import org.openmrs.module.xdssender.api.cda.ClinicalDocumentBuilder; import org.openmrs.module.xdssender.api.cda.model.DocumentModel; import org.openmrs.module.xdssender.api.fhir.FhirResourceDocumentBuilder; +import org.openmrs.module.xdssender.api.fhir.exceptions.ResourceGenerationException; import org.openmrs.module.xdssender.api.hl7.ORM_O01DocumentBuilder; import org.openmrs.module.xdssender.api.model.DocumentData; import org.openmrs.module.xdssender.api.model.DocumentInfo; import org.openmrs.module.xdssender.api.service.XdsExportService; import org.openmrs.module.xdssender.api.xds.MessageUtil; import org.openmrs.module.xdssender.api.xds.XdsSender; +import org.openmrs.module.xdssender.api.xds.XdsUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -50,6 +57,7 @@ public class XdsExportServiceImpl extends BaseOpenmrsService implements XdsExpor @Override public DocumentInfo exportProvideAndRegister(Encounter encounter, Patient patient) { try { + DocumentModel clinicalDocModel = clinicalDocBuilder.buildDocument(patient, encounter); DocumentInfo clinicalDocInfo = new DocumentInfo(encounter, patient, clinicalDocModel, "text/xsl", config.getProviderRoot()); @@ -66,21 +74,23 @@ public DocumentInfo exportProvideAndRegister(Encounter encounter, Patient patien additionalData.add(labOrderDoc); } + // Assign a placeholder System Identifier to be used for validating against the MPI + // patient.addIdentifier(XdsUtil.getPlaceholderSystemIdentifier(patient)); DocumentData patientFhirResourceDoc = null; DocumentModel patientFhirResourceDocModel = fhirResourceBuilder.buildDocument(patient, encounter); if (patientFhirResourceDocModel != null) { DocumentInfo patientFhirResourceDocInfo = new DocumentInfo(encounter, patient, patientFhirResourceDocModel, - "text/plain", config.getProviderRoot()); + "text/fhir", config.getProviderRoot()); patientFhirResourceDoc = new DocumentData(patientFhirResourceDocInfo, patientFhirResourceDocModel.getData()); additionalData.add(patientFhirResourceDoc); - } + } ProvideAndRegisterDocumentSetRequestType request = messageUtil.createProvideAndRegisterDocument(clinicalDoc, additionalData, encounter); logRequest(request); - + RegistryResponseType response = xdsSender.sendProvideAndRegister(request); if (!response.getStatus().contains("Success")) diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/xds/MessageUtil.java b/api/src/main/java/org/openmrs/module/xdssender/api/xds/MessageUtil.java index fd5d64e..9f605b8 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/xds/MessageUtil.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/xds/MessageUtil.java @@ -41,7 +41,7 @@ @Component("xdssender.MessageUtil") public class MessageUtil { - private static final String ECID_NAME = "ECID"; + private static final String ECID_NAME = "SYSTEM"; private static final String CODE_NATIONAL_NAME = "Code National"; @@ -64,6 +64,10 @@ public class MessageUtil { @Autowired private XdsSenderConfig config; + private String identifierAssigningAuthority; + + private String identifierAssigningAuthorityId; + public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterDocument(DocumentData clinicalData, DocumentData msgData, Encounter encounter) @@ -96,7 +100,7 @@ public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterDocument // createProvideAndRegisterClinicalDocument can be replaced by methods used to generate the ORM_O01 message ProvideAndRegisterDocumentSetRequestType result = createProvideAndRegisterClinicalDocument( clinicalData.getDocumentContent(), clinicalData.getDocumentInfo(), encounter); - + if (additionalData != null && additionalData.size() > 0) { Integer setid = 2; @@ -123,7 +127,15 @@ public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterClinical final DocumentInfo info, Encounter encounter) throws JAXBException { - String patientId = getPatientIdentifier(info).getIdentifier(); + String patientId = null; + try { + patientId = XdsUtil.getPlaceholderSystemIdentifier(info.getPatient()).getIdentifier(); + } + catch (Exception e) { + patientId = getPatientIdentifier(info).getIdentifier(); + e.printStackTrace(); + } + String location = getPatientLocation(info).getName(); ProvideAndRegisterDocumentSetRequestType retVal = new ProvideAndRegisterDocumentSetRequestType(); @@ -195,13 +207,17 @@ public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterClinical .toString()); InfosetUtil.addOrOverwriteSlot(oddRegistryObject, XDSConstants.SLOT_NAME_CREATION_TIME, new SimpleDateFormat( "yyyyMMddHHmmss").format(new Date())); - + + identifierAssigningAuthority = XdsSenderConstants.IDENTIFIER_SYSTEM; + + identifierAssigningAuthorityId = Context.getAdministrationService().getGlobalProperty(XdsSenderConstants.PROP_PID_LOCAL, "http://openmrs.org"); + // Unique identifier xdsUtil.addExtenalIdentifier(oddRegistryObject, XDSConstants.UUID_XDSDocumentEntry_uniqueId, String.format("2.25.%s", UUID.randomUUID().getLeastSignificantBits()).replaceAll("-", ""), "XDSDocumentEntry.uniqueId"); xdsUtil.addExtenalIdentifier(oddRegistryObject, XDSConstants.UUID_XDSDocumentEntry_patientId, - String.format("%s^^^%s&%s&NI", patientId, config.getEcidRoot(), config.getEcidRoot()), + String.format("%s^^^%s&%s&%s&NI", patientId, identifierAssigningAuthority, identifierAssigningAuthorityId, config.getEcidRoot()), "XDSDocumentEntry.patientId"); // Set classifications @@ -228,7 +244,11 @@ public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterClinical InfosetUtil.addOrOverwriteSlot(regPackage, XDSConstants.SLOT_NAME_SUBMISSION_TIME, now.getValue()); xdsUtil.addCodedValueClassification(regPackage, XDSConstants.UUID_XDSSubmissionSet_contentTypeCode, info.getClassCode(), "LOINC", "XDSSubmissionSet.contentTypeCode"); - + + identifierAssigningAuthority = XdsSenderConstants.IDENTIFIER_SYSTEM; + + identifierAssigningAuthorityId = Context.getAdministrationService().getGlobalProperty(XdsSenderConstants.PROP_PID_LOCAL, "http://openmrs.org"); + // Submission set external identifiers xdsUtil.addExtenalIdentifier(regPackage, XDSConstants.UUID_XDSSubmissionSet_uniqueId, String.format("2.25.%s", UUID.randomUUID().getLeastSignificantBits()).replaceAll("-", ""), @@ -237,7 +257,8 @@ public ProvideAndRegisterDocumentSetRequestType createProvideAndRegisterClinical String.format("2.25.%s", UUID.randomUUID().getLeastSignificantBits()).replaceAll("-", ""), "XDSSubmissionSet.sourceId"); xdsUtil.addExtenalIdentifier(regPackage, XDSConstants.UUID_XDSSubmissionSet_patientId, - String.format("%s^^^%s&%s&NI", patientId, config.getEcidRoot(), config.getEcidRoot()), + String.format("%s^^^%s&%s&%s&NI", patientId, identifierAssigningAuthority, identifierAssigningAuthorityId, config.getEcidRoot()), + // String.format("%s^^^%s&%s&NI", patientId, config.getEcidRoot(), config.getEcidRoot()), "XDSSubmissionSet.patientId"); // Add the eo to the submission @@ -333,7 +354,7 @@ public PatientIdentifier getPatientIdentifier(DocumentInfo info) { PatientIdentifier result = info.getPatient().getPatientIdentifier(); for (PatientIdentifier pid : info.getPatient().getIdentifiers()) { - if (pid.getIdentifierType().getName().equals(ECID_NAME)) { + if (pid.getIdentifierType().getName().equals(XdsSenderConstants.SYSTEM_IDENTIFIER_TYPE_NAME)) { result = pid; } } @@ -350,7 +371,7 @@ public PatientIdentifier getNationalPatientIdentifier(DocumentInfo info) { } return result; } - + public PatientIdentifier getSitePatientIdentifier(DocumentInfo info) { PatientIdentifier result = info.getPatient().getPatientIdentifier(); @@ -396,7 +417,14 @@ private SubmitObjectsRequest addAssociation(SubmitObjectsRequest registryRequest } private ExtrinsicObjectType createExtrinsicObjectType(DocumentInfo info, Encounter encounter) throws JAXBException { - String patientId = getPatientIdentifier(info).getIdentifier(); + String patientId = null; + try { + patientId = XdsUtil.getPlaceholderSystemIdentifier(info.getPatient()).getIdentifier(); + } + catch (Exception e) { + patientId = getPatientIdentifier(info).getIdentifier(); + e.printStackTrace(); + } String location = getPatientLocation(info).getName(); ExtrinsicObject extrinsicObject = new ExtrinsicObject(patientId, location); @@ -437,11 +465,17 @@ private ExtrinsicObjectType createExtrinsicObjectType(DocumentInfo info, Encount } private void addUniqueIdentifier(ExtrinsicObjectType extrinsicObject, String patientId) throws JAXBException { + identifierAssigningAuthority = XdsSenderConstants.IDENTIFIER_SYSTEM; + + identifierAssigningAuthorityId = Context.getAdministrationService().getGlobalProperty(XdsSenderConstants.PROP_PID_LOCAL, "http://openmrs.org"); + xdsUtil.addExtenalIdentifier(extrinsicObject, XDSConstants.UUID_XDSDocumentEntry_uniqueId, String.format("2.25.%s", UUID.randomUUID().getLeastSignificantBits()).replaceAll("-", ""), "XDSDocumentEntry.uniqueId"); xdsUtil.addExtenalIdentifier(extrinsicObject, XDSConstants.UUID_XDSDocumentEntry_patientId, - String.format("%s^^^%s&%s&NI", patientId, config.getEcidRoot(), config.getEcidRoot()), + String.format("%s^^^%s&%s&%s&NI", patientId, identifierAssigningAuthority, identifierAssigningAuthorityId, config.getEcidRoot()), + // String.format("%s^^^%s&%s&NI", patientId, config.getEcidRoot(), config.getEcidRoot()), + // String.format("%s", patientId), "XDSDocumentEntry.patientId"); } diff --git a/api/src/main/java/org/openmrs/module/xdssender/api/xds/XdsUtil.java b/api/src/main/java/org/openmrs/module/xdssender/api/xds/XdsUtil.java index 5873fd5..d9c0bfb 100644 --- a/api/src/main/java/org/openmrs/module/xdssender/api/xds/XdsUtil.java +++ b/api/src/main/java/org/openmrs/module/xdssender/api/xds/XdsUtil.java @@ -1,6 +1,7 @@ package org.openmrs.module.xdssender.api.xds; import groovy.text.GStringTemplateEngine; +import org.dcm4chee.xds2.common.XDSConstants; import org.dcm4chee.xds2.infoset.rim.ClassificationType; import org.dcm4chee.xds2.infoset.rim.ExternalIdentifierType; import org.dcm4chee.xds2.infoset.rim.InternationalStringType; @@ -11,7 +12,11 @@ import org.hl7.fhir.r4.model.*; import org.openmrs.Patient; import org.openmrs.PatientIdentifier; +import org.openmrs.PatientIdentifierType; +import org.openmrs.api.context.Context; import org.openmrs.module.xdssender.XdsSenderConfig; +import org.openmrs.module.xdssender.XdsSenderConstants; +import org.openmrs.module.xdssender.api.fhir.exceptions.ResourceGenerationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +39,23 @@ public final class XdsUtil { private static final Logger logger = LoggerFactory.getLogger(XdsUtil.class); + public static PatientIdentifier getPlaceholderSystemIdentifier(Patient patient) throws Exception { + PatientIdentifierType systemIdentifierType = new PatientIdentifierType(); + systemIdentifierType.setName(XdsSenderConstants.SYSTEM_IDENTIFIER_TYPE_NAME); + systemIdentifierType.setUuid(XdsSenderConstants.SYSTEM_IDENTIFIER_TYPE_UUID); + + PatientIdentifier systemIdentifier = new PatientIdentifier(); + systemIdentifier.setIdentifierType(systemIdentifierType); + String localPatientId = Context.getAdministrationService().getGlobalProperty(XdsSenderConstants.PROP_PID_LOCAL, "http://openmrs.org"); + if (localPatientId == null) { + throw new Exception("Unable to retrieve the Local PID, ensure that the MPI client module is installed and the \"PID LOCAL\" global property has been set"); + } + // systemIdentifier.setIdentifier(localPatientId + "/" + patient.getUuid()); + systemIdentifier.setIdentifier(patient.getUuid()); + + return systemIdentifier; + } + public String parseCcdToHtml(Bundle resource, File ccdTemplate) throws IOException, ClassNotFoundException { // TODO Find a better way to filter the obs of interest List codes = new ArrayList() {{ diff --git a/api/src/test/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImplTest.java b/api/src/test/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImplTest.java new file mode 100644 index 0000000..0fc002a --- /dev/null +++ b/api/src/test/java/org/openmrs/module/xdssender/api/service/impl/XdsExportServiceImplTest.java @@ -0,0 +1,40 @@ +package org.openmrs.module.xdssender.api.service.impl; + +import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; +import org.openmrs.Encounter; +import org.openmrs.Patient; +import org.openmrs.Visit; +import org.openmrs.api.context.Context; +import org.openmrs.module.xdssender.api.cda.model.DocumentModel; +import org.openmrs.module.xdssender.api.fhir.FhirResourceDocumentBuilder; +import org.openmrs.module.xdssender.api.model.DocumentInfo; +import org.openmrs.module.xdssender.api.service.XdsExportService; +import org.openmrs.test.BaseModuleContextSensitiveTest; +import org.springframework.test.context.ContextConfiguration; +import java.util.List; + +import static org.junit.Assert.assertNotNull; + +@ContextConfiguration(locations = { "classpath*:moduleApplicationContext.xml", "classpath*:applicationContext-service.xml" }, inheritLocations = false) +public class XdsExportServiceImplTest extends BaseModuleContextSensitiveTest { + + private static final String DATASET = "lab-dataset.xml"; + private static final String GLOBAL_CONFIGS = "global-configs.xml"; + + @Before + public void setUp() throws Exception { + executeDataSet(DATASET); + executeDataSet(GLOBAL_CONFIGS); + } + + @Test + public void testExportProvideAndRegister() { + Patient patient = Context.getPatientService().getPatient(10); + Encounter encounter = Context.getEncounterService().getEncounter(21); + XdsExportService xdsExportService = Context.getService(XdsExportService.class); + DocumentInfo di = xdsExportService.exportProvideAndRegister(encounter, patient); + assertNotNull(di); + } +} diff --git a/api/src/test/resources/global-configs.xml b/api/src/test/resources/global-configs.xml index d5327e2..bbc844b 100644 --- a/api/src/test/resources/global-configs.xml +++ b/api/src/test/resources/global-configs.xml @@ -1,8 +1,21 @@ + + + + + uuid="FAB088A2-7A9E-404A-A487-06258B65FF5C"/> diff --git a/api/src/test/resources/lab-dataset.xml b/api/src/test/resources/lab-dataset.xml index 0cd0d5f..294c0f8 100644 --- a/api/src/test/resources/lab-dataset.xml +++ b/api/src/test/resources/lab-dataset.xml @@ -47,6 +47,10 @@ + + + + @@ -62,6 +66,11 @@ + + + + + @@ -77,18 +86,11 @@ creator="1" date_created="2005-01-06 00:00:00"/> - - - - + + + + + - + + + + + - - + + - - + preferred="0" location_id="2"/> + + - - - + + +
+ + creator="1" date_created="2005-01-06 00:00:00" voided="0" form_id="1"/> + + + + - - - \ No newline at end of file + uuid="549c78dc-31da-11e8-acac-c3add5b19973" + form_id="1" + location_id="2" + visit_id="1"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/src/test/resources/xds-dataset.xml b/api/src/test/resources/xds-dataset.xml index 1b0ff32..3b1312f 100644 --- a/api/src/test/resources/xds-dataset.xml +++ b/api/src/test/resources/xds-dataset.xml @@ -3,7 +3,7 @@ - + f037e97b-471e-4898-a07c-b8e169e0ddc4 + + xdssender.ecidRoot + ECID Root + http://openclientregistry.org/fhir/sourceid + +