Index: src/api/org/openmrs/hl7/HL7Service.java =================================================================== --- src/api/org/openmrs/hl7/HL7Service.java (revision 13288) +++ src/api/org/openmrs/hl7/HL7Service.java (working copy) @@ -17,6 +17,7 @@ import java.util.List; import org.openmrs.Encounter; +import org.openmrs.Person; import org.openmrs.annotation.Authorized; import org.openmrs.api.APIException; import org.openmrs.api.OpenmrsService; @@ -25,8 +26,10 @@ import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.model.Message; +import ca.uhn.hl7v2.model.v25.datatype.CX; import ca.uhn.hl7v2.model.v25.datatype.PL; import ca.uhn.hl7v2.model.v25.datatype.XCN; +import ca.uhn.hl7v2.model.v25.segment.NK1; import ca.uhn.hl7v2.model.v25.segment.PID; /** @@ -360,13 +363,28 @@ /** * @param pid A PID segment of an hl7 message - * @return The internal id number of the Patient described by the PID segment, or null of the - * patient is not found, or if the PID segment is ambiguous + * @return The internal id number of the Patient described by the PID segment, or null if the + * patient is not found or if the PID segment is ambiguous * @throws HL7Exception */ public Integer resolvePatientId(PID pid) throws HL7Exception; /** + * determines a person (or patient) based on identifiers from a CX array, as found in a PID or + * NK1 segment; the first resolving identifier in the list wins + * + * @param identifiers CX identifier list from an identifier (either PID or NK1) + * @return The internal id number of a Person based on one of the given identifiers, or null if + * the Person is not found + * @throws HL7Exception + * @should find a person based on a patient identifier + * @should find a person based on a UUID + * @should find a person based on the internal person ID + * @should return null if no person is found + */ + public Person resolvePersonFromIdentifiers(CX[] identifiers) throws HL7Exception; + + /** * Clean up the current memory consumption */ public void garbageCollect(); @@ -422,4 +440,32 @@ */ public Message processHL7Message(Message hl7Message) throws HL7Exception; + /** + * finds a UUID from an array of identifiers + * + * @param identifiers + * @return the UUID or null + * @throws HL7Exception + * @should return null if no UUID found + * @should find a UUID in any position of the array + * @should not fail if multiple similar UUIDs exist in identifiers + * @should fail if multiple different UUIDs exist in identifiers + */ + public String getUuidFromIdentifiers(CX[] identifiers) throws HL7Exception; + + /** + * creates a Person from information held in an NK1 segment; if valid PatientIdentifiers + * exist, a Patient will be created and returned + * + * @param nk1 the NK1 segment with person information + * @return the newly formed (but not saved) person + * @throws HL7Exception + * @should return a saved new person + * @should return a Patient if valid patient identifiers exist + * @should fail if a person with the same UUID exists + * @should fail on an invalid gender + * @should fail if no gender specified + * @should fail if no birthdate specified + */ + public Person createPersonFromNK1(NK1 nk1) throws HL7Exception; } Index: src/api/org/openmrs/hl7/handler/ORUR01Handler.java =================================================================== --- src/api/org/openmrs/hl7/handler/ORUR01Handler.java (revision 13288) +++ src/api/org/openmrs/hl7/handler/ORUR01Handler.java (working copy) @@ -16,7 +16,10 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -33,6 +36,8 @@ import org.openmrs.Person; import org.openmrs.PersonAttribute; import org.openmrs.PersonAttributeType; +import org.openmrs.Relationship; +import org.openmrs.RelationshipType; import org.openmrs.User; import org.openmrs.api.context.Context; import org.openmrs.hl7.HL7InError; @@ -66,6 +71,7 @@ import ca.uhn.hl7v2.model.v25.group.ORU_R01_PATIENT_RESULT; import ca.uhn.hl7v2.model.v25.message.ORU_R01; import ca.uhn.hl7v2.model.v25.segment.MSH; +import ca.uhn.hl7v2.model.v25.segment.NK1; import ca.uhn.hl7v2.model.v25.segment.OBR; import ca.uhn.hl7v2.model.v25.segment.OBX; import ca.uhn.hl7v2.model.v25.segment.ORC; @@ -140,6 +146,7 @@ * @param oru the message to process * @return the processed message * @throws HL7Exception + * @should process multiple NK1 segments */ @SuppressWarnings("deprecation") private Message processORU_R01(ORU_R01 oru) throws HL7Exception { @@ -154,6 +161,7 @@ // extract segments for convenient use below MSH msh = getMSH(oru); PID pid = getPID(oru); + List nk1List = getNK1List(oru); PV1 pv1 = getPV1(oru); ORC orc = getORC(oru); // we're using the ORC assoc with first OBR to // hold data enterer and date entered for now @@ -180,6 +188,10 @@ log.error("Error while processing Discharge To Location (" + messageControlId + ")", e); } + // process NK1 (relationship) segments + for (NK1 nk1 : nk1List) + processNK1(patient, nk1); + // list of concepts proposed in the obs of this encounter. // these proposals need to be created after the encounter // has been created @@ -334,9 +346,87 @@ } - // private String getSendingApplication(ORU_R01 oru) { - // return oru.getMSH().getSendingApplication().getUniversalID().getValue(); - // } + /** + * process an NK1 segment and add relationships if needed + * + * @param patient + * @param nk1 + * @throws HL7Exception + * @should create a relationship from a NK1 segment + * @should not create a relationship if one exists + * @should create a person if the relative is not found + * @should fail if the coding system is not 99REL + * @should fail if the relationship identifier is formatted improperly + * @should fail if the relationship type is not found + */ + protected void processNK1(Patient patient, NK1 nk1) throws HL7Exception { + // guarantee we are working with our custom coding system + String relCodingSystem = nk1.getRelationship().getNameOfCodingSystem().getValue(); + if (!relCodingSystem.equals(FormConstants.HL7_LOCAL_RELATIONSHIP)) + throw new HL7Exception("Relationship coding system '" + relCodingSystem + "' unknown in NK1 segment."); + + // get the relationship type identifier + String relIdentifier = nk1.getRelationship().getIdentifier().getValue(); + + // validate the format of the relationship identifier + if (!Pattern.matches("[0-9]+[AB]", relIdentifier)) + throw new HL7Exception("Relationship type '" + relIdentifier + "' improperly formed in NK1 segment."); + + // get the type ID + Integer relTypeId = 0; + try { + relTypeId = Integer.parseInt(relIdentifier.substring(0, relIdentifier.length() - 1)); + } + catch (NumberFormatException e) { + throw new HL7Exception("Relationship type '" + relIdentifier + "' improperly formed in NK1 segment."); + } + + // find the relationship type + RelationshipType relType = Context.getPersonService().getRelationshipType(relTypeId); + if (relType == null) + throw new HL7Exception("Relationship type '" + relTypeId + "' in NK1 segment not found"); + + // find the relative + Person relative = getRelative(nk1); + + // determine if the patient is person A or B; the relIdentifier indicates + // the relative's side of the relationship, so the patient is the inverse + boolean patientIsPersonA = relIdentifier.endsWith("B"); + boolean patientCanBeEitherPerson = relType.getbIsToA().equals(relType.getaIsToB()); + + // look at existing relationships to determine if a new one is needed + Set rels = new HashSet(); + if (relative != null) { + if (patientCanBeEitherPerson || patientIsPersonA) + rels.addAll(Context.getPersonService().getRelationships(patient, relative, relType)); + if (patientCanBeEitherPerson || !patientIsPersonA) + rels.addAll(Context.getPersonService().getRelationships(relative, patient, relType)); + } + + // create a relationship if none is found + if (rels.isEmpty()) { + + // check the relative's existence + if (relative == null) { + // create one based on NK1 information + relative = Context.getHL7Service().createPersonFromNK1(nk1); + if (relative == null) + throw new HL7Exception("could not create a new relative from NK1 segment"); + } + + // create the relationship + Relationship relation = new Relationship(); + if (patientCanBeEitherPerson || patientIsPersonA) { + relation.setPersonA(patient); + relation.setPersonB(relative); + } else { + relation.setPersonA(relative); + relation.setPersonB(patient); + } + relation.setRelationshipType(relType); + Context.getPersonService().saveRelationship(relation); + } + } /** * Not used @@ -356,6 +446,24 @@ return oru.getPATIENT_RESULT().getPATIENT().getPID(); } + /** + * finds NK1 segments in an ORU_R01 message. all messages have at least one NK1 segment but if + * the message truly does not contain an NK1, the setID will be null on the generated NK1 + * + * @param oru ORU_R01 message to be parsed for NK1 segments + * @return list of not-null NK1 segments + * @throws HL7Exception + */ + public List getNK1List(ORU_R01 oru) throws HL7Exception { + List res = new ArrayList(); + // there will always be at least one NK1, even if the message does not contain one + for (int i = 0; i < oru.getPATIENT_RESULT().getPATIENT().getNK1Reps(); i++) + // if the setIDNK1 value is null, this NK1 is blank + if (oru.getPATIENT_RESULT().getPATIENT().getNK1(i).getSetIDNK1().getValue() != null) + res.add(oru.getPATIENT_RESULT().getPATIENT().getNK1(i)); + return res; + } + private PV1 getPV1(ORU_R01 oru) { return oru.getPATIENT_RESULT().getPATIENT().getVISIT().getPV1(); } @@ -790,6 +898,21 @@ return patient; } + /** + * gets a relative based on an NK1 segment + * + * @param nk1 an NK1 segment from the HL7 request + * @return a matching Person or null if not found + * @throws HL7Exception + */ + private Person getRelative(NK1 nk1) throws HL7Exception { + // if there are no associated party identifiers, the person will not exist + if (nk1.getNextOfKinAssociatedPartySIdentifiers().length < 1) + return null; + // find the related person via given IDs + return Context.getHL7Service().resolvePersonFromIdentifiers(nk1.getNextOfKinAssociatedPartySIdentifiers()); + } + private Location getLocation(PV1 pv1) throws HL7Exception { PL hl7Location = pv1.getAssignedPatientLocation(); Integer locationId = Context.getHL7Service().resolveLocationId(hl7Location); Index: src/api/org/openmrs/hl7/impl/HL7ServiceImpl.java =================================================================== --- src/api/org/openmrs/hl7/impl/HL7ServiceImpl.java (revision 13288) +++ src/api/org/openmrs/hl7/impl/HL7ServiceImpl.java (working copy) @@ -15,6 +15,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -25,11 +26,14 @@ import org.apache.commons.logging.LogFactory; import org.openmrs.Encounter; import org.openmrs.Location; +import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; import org.openmrs.Person; +import org.openmrs.PersonName; import org.openmrs.User; import org.openmrs.api.APIException; +import org.openmrs.api.PatientIdentifierException; import org.openmrs.api.context.Context; import org.openmrs.api.impl.BaseOpenmrsService; import org.openmrs.hl7.HL7Constants; @@ -38,9 +42,12 @@ import org.openmrs.hl7.HL7InQueue; import org.openmrs.hl7.HL7Service; import org.openmrs.hl7.HL7Source; +import org.openmrs.hl7.HL7Util; import org.openmrs.hl7.db.HL7DAO; +import org.openmrs.util.FormConstants; import org.openmrs.util.OpenmrsConstants; import org.openmrs.util.OpenmrsUtil; +import org.openmrs.validator.PatientIdentifierValidator; import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.app.Application; @@ -48,8 +55,12 @@ import ca.uhn.hl7v2.app.MessageTypeRouter; import ca.uhn.hl7v2.model.Message; import ca.uhn.hl7v2.model.v25.datatype.CX; +import ca.uhn.hl7v2.model.v25.datatype.ID; import ca.uhn.hl7v2.model.v25.datatype.PL; +import ca.uhn.hl7v2.model.v25.datatype.TS; import ca.uhn.hl7v2.model.v25.datatype.XCN; +import ca.uhn.hl7v2.model.v25.datatype.XPN; +import ca.uhn.hl7v2.model.v25.segment.NK1; import ca.uhn.hl7v2.model.v25.segment.PID; import ca.uhn.hl7v2.parser.EncodingNotSupportedException; import ca.uhn.hl7v2.parser.GenericParser; @@ -64,7 +75,7 @@ private Log log = LogFactory.getLog(this.getClass()); - private static HL7ServiceImpl instance; + private static HL7ServiceImpl instance; protected HL7DAO dao; @@ -74,6 +85,7 @@ /** * Private constructor to only support on singleton instance. + * * @see #getInstance() */ private HL7ServiceImpl() { @@ -90,7 +102,7 @@ } return instance; } - + /** * @see org.openmrs.hl7.HL7Service#setHL7DAO(org.openmrs.hl7.db.HL7DAO) */ @@ -456,7 +468,7 @@ } } } - + /** * @see org.openmrs.hl7.HL7Service#resolvePersonId(ca.uhn.hl7v2.model.v25.datatype.XCN) */ @@ -487,7 +499,7 @@ } } } - + /** * @param pl HL7 component of data type PL (person location) (see Ch 2.A.53) * @return internal identifier of the specified location, or null if it is not found or @@ -535,17 +547,25 @@ * @throws HL7Exception */ public Integer resolvePatientId(PID pid) throws HL7Exception { + Person p = resolvePersonFromIdentifiers(pid.getPatientIdentifierList()); + if (p != null && p.isPatient()) + return p.getPersonId(); + return null; + } + + /** + * @param identifiers CX identifier list from an identifier (either PID or NK1) + * @return The internal id number of the Patient based on one of the given identifiers, or null + * if the patient is not found + * @throws HL7Exception + */ + public Person resolvePersonFromIdentifiers(CX[] identifiers) throws HL7Exception { // TODO: Properly handle assigning authority. If specified it's // currently treated as PatientIdentifierType.name // TODO: Throw exceptions instead of returning null in some cases - // TODO: Don't hydrate Patient objects unnecessarily - // TODO: Determine how to handle assigning authority and openmrs - // patient_id numbers - Integer patientId = null; - - CX[] patientIdentifierList = pid.getPatientIdentifierList(); - if (patientIdentifierList.length < 1) + // give up if no identifiers exist + if (identifiers.length < 1) throw new HL7Exception("Missing patient identifier in PID segment"); // TODO other potential identifying characteristics in PID we could use @@ -555,10 +575,9 @@ // TS dateOfBirth = pid.getDateTimeOfBirth(); // Take the first uniquely matching identifier - for (CX identifier : patientIdentifierList) { - String hl7PatientId = identifier.getIDNumber().getValue(); - // TODO if 1st component is blank, check 2nd and 3rd of assigning - // authority + for (CX identifier : identifiers) { + String hl7PersonId = identifier.getIDNumber().getValue(); + // TODO if 1st component is blank, check 2nd and 3rd of assigning authority String assigningAuthority = identifier.getAssigningAuthority().getNamespaceID().getValue(); if (assigningAuthority != null && assigningAuthority.length() > 0) { @@ -567,41 +586,68 @@ PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierTypeByName( assigningAuthority); if (pit == null) { + // there is no matching PatientIdentifierType + if (assigningAuthority.equals(FormConstants.HL7_AUTHORITY_UUID)) { + // the identifier is a UUID + Person p = Context.getPersonService().getPersonByUuid(hl7PersonId); + if (p != null) + return p; + log.warn("Can't find person for UUID '" + hl7PersonId + "'"); + continue; // skip identifiers with unknown type + } else if (assigningAuthority.equals(FormConstants.HL7_AUTHORITY_LOCAL)) { + // the ID is internal (local) + String idType = identifier.getIdentifierTypeCode().getValue(); + try { + if (idType.equals(FormConstants.HL7_ID_PERSON)) { + Integer pid = Integer.parseInt(hl7PersonId); + // patient_id == person_id, so just look for the person + Person p = Context.getPersonService().getPerson(pid); + if (p != null) + return p; + } else if (idType.equals(FormConstants.HL7_ID_PATIENT)) { + Integer pid = Integer.parseInt(hl7PersonId); + // patient_id == person_id, so just look for the person + Patient p = Context.getPatientService().getPatient(pid); + if (p != null) + return p; + } + } + catch (NumberFormatException e) {} + log.warn("Can't find Local identifier of '" + hl7PersonId + "'"); + continue; // skip identifiers with unknown type + } log.warn("Can't find PatientIdentifierType named '" + assigningAuthority + "'"); continue; // skip identifiers with unknown type } - List matchingIds = Context.getPatientService().getPatientIdentifiers(hl7PatientId, + List matchingIds = Context.getPatientService().getPatientIdentifiers(hl7PersonId, Collections.singletonList(pit), null, null, null); if (matchingIds == null || matchingIds.size() < 1) { // no matches - log.warn("NO matches found for " + hl7PatientId); + log.warn("NO matches found for " + hl7PersonId); continue; // try next identifier } else if (matchingIds.size() == 1) { // unique match -- we're done - return matchingIds.get(0).getPatient().getPatientId(); + return matchingIds.get(0).getPatient(); } else { // ambiguous identifier log.debug("Ambiguous identifier in PID. " + matchingIds.size() + " matches for identifier '" - + hl7PatientId + "' of type '" + pit + "'"); + + hl7PersonId + "' of type '" + pit + "'"); continue; // try next identifier } } catch (Exception e) { - log.error("Error resolving patient identifier '" + hl7PatientId + "' for assigning authority '" + log.error("Error resolving patient identifier '" + hl7PersonId + "' for assigning authority '" + assigningAuthority + "'", e); continue; } } else { try { - log.debug("PID contains patient ID '" + hl7PatientId + log.debug("CX contains ID '" + hl7PersonId + "' without assigning authority -- assuming patient.patient_id"); - patientId = Integer.parseInt(hl7PatientId); - return patientId; + return Context.getPatientService().getPatient(Integer.parseInt(hl7PersonId)); } catch (NumberFormatException e) { - // throw new HL7Exception("Invalid patient ID '" + - // hl7PatientId + "'"); - log.warn("Invalid patient ID '" + hl7PatientId + "'"); + log.warn("Invalid patient ID '" + hl7PersonId + "'"); } } } @@ -701,11 +747,11 @@ hl7InError.setErrorDetails(""); else { StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw, true); - cause.printStackTrace(pw); - pw.flush(); - sw.flush(); - hl7InError.setErrorDetails(sw.toString()); + PrintWriter pw = new PrintWriter(sw, true); + cause.printStackTrace(pw); + pw.flush(); + sw.flush(); + hl7InError.setErrorDetails(sw.toString()); } Context.getHL7Service().saveHL7InError(hl7InError); Context.getHL7Service().purgeHL7InQueue(hl7InQueue); @@ -779,4 +825,139 @@ } } + /** + * @see org.openmrs.hl7.HL7Service#createPersonFromNK1(ca.uhn.hl7v2.model.v25.segment.NK1) + */ + public Person createPersonFromNK1(NK1 nk1) throws HL7Exception { + // NOTE: following block (with minor modifications) stolen from ADTA28Handler + // TODO: generalize this for use with both PID and NK1 segments + + Person person = new Person(); + + // UUID + CX[] identifiers = nk1.getNextOfKinAssociatedPartySIdentifiers(); + String uuid = getUuidFromIdentifiers(identifiers); + if (Context.getPersonService().getPersonByUuid(uuid) != null) + throw new HL7Exception("Non-unique UUID '" + uuid + "' for new person"); + person.setUuid(uuid); + + // Patient Identifiers + List goodIdentifiers = new ArrayList(); + for (CX id : identifiers) { + + String assigningAuthority = id.getAssigningAuthority().getNamespaceID().getValue(); + String hl7PatientId = id.getIDNumber().getValue(); + + log.debug("identifier has id=" + hl7PatientId + " assigningAuthority=" + assigningAuthority); + + if (assigningAuthority != null && assigningAuthority.length() > 0) { + + try { + PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierTypeByName( + assigningAuthority); + if (pit == null) { + if (!assigningAuthority.equals("UUID")) + log.warn("Can't find PatientIdentifierType named '" + assigningAuthority + "'"); + continue; // skip identifiers with unknown type + } + PatientIdentifier pi = new PatientIdentifier(); + pi.setIdentifierType(pit); + pi.setIdentifier(hl7PatientId); + + // Get default location + Location location = Context.getLocationService().getDefaultLocation(); + if (location == null) { + throw new HL7Exception("Cannot find default location"); + } + pi.setLocation(location); + + try { + PatientIdentifierValidator.validateIdentifier(pi); + goodIdentifiers.add(pi); + } + catch (PatientIdentifierException ex) { + log.warn("Patient identifier in NK1 is invalid: " + pi, ex); + } + + } + catch (Exception e) { + log.error("Uncaught error parsing/creating patient identifier '" + hl7PatientId + + "' for assigning authority '" + assigningAuthority + "'", e); + } + } + + else { + log.debug("NK1 contains identifier with no assigning authority"); + continue; + } + } + if (!goodIdentifiers.isEmpty()) { + // cast the person as a Patient and add identifiers + person = new Patient(person); + ((Patient) person).addIdentifiers(goodIdentifiers); + } + + // Person names + for (XPN patientNameX : nk1.getNKName()) { + PersonName name = new PersonName(); + name.setFamilyName(patientNameX.getFamilyName().getSurname().getValue()); + name.setGivenName(patientNameX.getGivenName().getValue()); + name.setMiddleName(patientNameX.getSecondAndFurtherGivenNamesOrInitialsThereof().getValue()); + person.addName(name); + } + + // Gender (checks for null, but not for 'M' or 'F') + String gender = nk1.getAdministrativeSex().getValue(); + if (gender == null) + throw new HL7Exception("Missing gender in an NK1 segment"); + gender = gender.toUpperCase(); + if (!OpenmrsConstants.GENDER().containsKey(gender)) + throw new HL7Exception("Unrecognized gender: " + gender); + person.setGender(gender); + + // Date of Birth + TS dateOfBirth = nk1.getDateTimeOfBirth(); + if (dateOfBirth == null || dateOfBirth.getTime() == null || dateOfBirth.getTime().getValue() == null) + throw new HL7Exception("Missing birth date in an NK1 segment"); + person.setBirthdate(HL7Util.parseHL7Timestamp(dateOfBirth.getTime().getValue())); + + // Estimated birthdate? + ID precisionTemp = dateOfBirth.getDegreeOfPrecision(); + if (precisionTemp != null && precisionTemp.getValue() != null) { + String precision = precisionTemp.getValue().toUpperCase(); + log.debug("The birthdate is estimated: " + precision); + + if (precision.equals("Y") || precision.equals("L")) + person.setBirthdateEstimated(true); + } + + // save the new person or patient + if (person instanceof Patient) + Context.getPatientService().savePatient((Patient) person); + else + Context.getPersonService().savePerson(person); + + return person; + } + + /** + * @see org.openmrs.hl7.HL7Service#getUuidFromIdentifiers(ca.uhn.hl7v2.model.v25.datatype.CX[]) + */ + public String getUuidFromIdentifiers(CX[] identifiers) throws HL7Exception { + Boolean found = false; + String uuid = null; + for (CX identifier : identifiers) { + // check for UUID as the assigning authority + if (identifier.getAssigningAuthority().getNamespaceID().getValue().equals("UUID")) { + // check for duplicates + if (found && !identifier.getIDNumber().getValue().equals(uuid)) + throw new HL7Exception("multiple UUID values found"); + uuid = identifier.getIDNumber().getValue(); + found = true; + } + } + // returns null if not found + return uuid; + } + } Index: src/api/org/openmrs/util/FormConstants.java =================================================================== --- src/api/org/openmrs/util/FormConstants.java (revision 13288) +++ src/api/org/openmrs/util/FormConstants.java (working copy) @@ -52,16 +52,26 @@ public static final String HL7_BOOLEAN = "BIT"; - public static final Integer CLASS_DRUG = 3; + public static final String HL7_AUTHORITY_UUID = "UUID"; - public static final String HL7_LOCAL_CONCEPT = "99DCT"; + public static final String HL7_AUTHORITY_LOCAL = "L"; + public static final Object HL7_ID_PERSON = "PN"; + + public static final Object HL7_ID_PATIENT = "PI"; + + public static final Integer CLASS_DRUG = 3; + /** * Used in hl7 sextuplets: 123^Primary name^99DCT^345^Chosen name^99NAM */ + public static final String HL7_LOCAL_CONCEPT = "99DCT"; + public static final String HL7_LOCAL_CONCEPT_NAME = "99NAM"; public static final String HL7_LOCAL_DRUG = "99RX"; + + public static final String HL7_LOCAL_RELATIONSHIP = "99REL"; // List of datatypes that do not require complex definitions public static final Hashtable simpleDatatypes = new Hashtable(); Index: test/api/org/openmrs/hl7/HL7ServiceTest.java =================================================================== --- test/api/org/openmrs/hl7/HL7ServiceTest.java (revision 13288) +++ test/api/org/openmrs/hl7/HL7ServiceTest.java (working copy) @@ -27,7 +27,9 @@ import org.openmrs.Concept; import org.openmrs.Obs; import org.openmrs.Patient; +import org.openmrs.Person; import org.openmrs.api.context.Context; +import org.openmrs.hl7.handler.ORUR01Handler; import org.openmrs.hl7.impl.HL7ServiceImpl; import org.openmrs.module.ModuleConstants; import org.openmrs.module.ModuleUtil; @@ -37,6 +39,9 @@ import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.app.Application; import ca.uhn.hl7v2.model.Message; +import ca.uhn.hl7v2.model.v25.datatype.CX; +import ca.uhn.hl7v2.model.v25.message.ORU_R01; +import ca.uhn.hl7v2.model.v25.segment.NK1; /** * Tests methods in the {@link HL7Service} @@ -121,7 +126,13 @@ executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); HL7Service hl7service = Context.getHL7Service(); Message message = hl7service - .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\rPID|||3^^^^||John3^Doe^||\rPV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\rORC|RE||||||||20080226102537|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\rOBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); Message result = hl7service.processHL7Message(message); Assert.assertNotNull(result); @@ -143,7 +154,13 @@ public void parseHL7String_shouldParseTheGivenStringIntoMessage() throws Exception { HL7Service hl7service = Context.getHL7Service(); Message message = hl7service - .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\rPID|||3^^^^||John3^Doe^||\rPV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\rORC|RE||||||||20080226102537|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\rOBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); Assert.assertNotNull(message); } @@ -171,7 +188,13 @@ HL7Service hl7service = Context.getHL7Service(); Message message = hl7service - .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ADR^A19|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\rPID|||3^^^^||John3^Doe^||\rPV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\rORC|RE||||||||20080226102537|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\rOBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ADR^A19|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); Assert.assertNotNull(message); try { @@ -227,4 +250,370 @@ ModuleUtil.shutdown(); } + + /** + * @see {@link HL7Service#resolvePersonFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should find a person based on a patient identifier", method = "resolvePersonFromIdentifiers(null)") + public void resolvePersonFromIdentifiers_shouldFindAPersonBasedOnAPatientIdentifier() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||1234^^^Test Identifier Type^PT||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Assert.assertEquals("too many NK1s parsed out", 1, nk1List.size()); + Person expected = new Person(2); + Person result = hl7service.resolvePersonFromIdentifiers(nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers()); + Assert.assertNotNull("should have found a person", result); + Assert.assertEquals("found the wrong person", expected, result); + } + + /** + * @see {@link HL7Service#resolvePersonFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should find a person based on a UUID", method = "resolvePersonFromIdentifiers(null)") + public void resolvePersonFromIdentifiers_shouldFindAPersonBasedOnAUUID() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Assert.assertEquals("too many NK1s parsed out", 1, nk1List.size()); + Person expected = new Person(2); + Person result = hl7service.resolvePersonFromIdentifiers(nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers()); + Assert.assertNotNull("should have found a person", result); + Assert.assertEquals("found the wrong person", expected, result); + } + + /** + * @see {@link HL7Service#resolvePersonFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should find a person based on the internal person ID", method = "resolvePersonFromIdentifiers(null)") + public void resolvePersonFromIdentifiers_shouldFindAPersonBasedOnTheInternalPersonID() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2^^^L^PN||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Assert.assertEquals("too many NK1s parsed out", 1, nk1List.size()); + Person expected = new Person(2); + Person result = hl7service.resolvePersonFromIdentifiers(nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers()); + Assert.assertNotNull("should have found a person", result); + Assert.assertEquals("found the wrong person", expected, result); + } + + /** + * @see {@link HL7Service#resolvePersonFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should return null if no person is found", method = "resolvePersonFromIdentifiers(null)") + public void resolvePersonFromIdentifiers_shouldReturnNullIfNoPersonIsFound() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||1000^^^L^PN||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Assert.assertEquals("too many NK1s parsed out", 1, nk1List.size()); + Person result = hl7service.resolvePersonFromIdentifiers(nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers()); + Assert.assertNull("should not have found a person", result); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if a person with the same UUID exists", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldFailIfAPersonWithTheSameUUIDExists() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.fail("should have thrown an exception"); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if no birthdate specified", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldFailIfNoBirthdateSpecified() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M||||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.fail("should have thrown an exception"); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if no gender specified", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldFailIfNoGenderSpecified() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL|||||||||||||19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.fail("should have thrown an exception"); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail on an invalid gender", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldFailOnAnInvalidGender() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||Q|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.fail("should have thrown an exception"); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test + @Verifies(value = "should return a saved new person", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldReturnASavedNewPerson() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Person result = hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.assertNotNull("should have returned a person", result); + Assert.assertNotNull("the person should exist", Context.getPersonService().getPersonByUuid(result.getUuid())); + } + + /** + * @see {@link HL7Service#createPersonFromNK1(NK1)} + */ + @Test + @Verifies(value = "should return a Patient if valid patient identifiers exist", method = "getPersonFromNK1(NK1)") + public void getPersonFromNK1_shouldReturnAPatientIfValidPatientIdentifiersExist() throws Exception { + executeDataSet("org/openmrs/hl7/include/ORUTest-initialData.xml"); + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220029^^^UUID^v4~9-1^^^Test Identifier Type^PT||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + Person result = hl7service.createPersonFromNK1(nk1List.get(0)); + Assert.assertNotNull("should have returned something", result); + Assert.assertTrue("should have returned a Patient", result instanceof Patient); + } + + /** + * @see {@link HL7Service#getUuidFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should find a UUID in any position of the array", method = "getUuidFromIdentifiers(null)") + public void getUuidFromIdentifiers_shouldFindAUUIDInAnyPositionOfTheArray() throws Exception { + // at the beginning of the list + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4~5^^^L^PN||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + CX[] identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + String result = hl7service.getUuidFromIdentifiers(identifiers); + Assert.assertEquals("2178037d-f86b-4f12-8d8b-be3ebc220022", result); + result = null; + + // at the end of the list + message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||5^^^L^PN~2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + oru = (ORU_R01) message; + nk1List = new ORUR01Handler().getNK1List(oru); + identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + result = hl7service.getUuidFromIdentifiers(identifiers); + Assert.assertEquals("2178037d-f86b-4f12-8d8b-be3ebc220022", result); + result = null; + + // middle of the list + message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||5^^^L^PN~2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4~101-3^^^MTRH^PT||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + oru = (ORU_R01) message; + nk1List = new ORUR01Handler().getNK1List(oru); + identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + result = hl7service.getUuidFromIdentifiers(identifiers); + Assert.assertEquals("2178037d-f86b-4f12-8d8b-be3ebc220022", result); + } + + /** + * @see {@link HL7Service#getUuidFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should return null if no UUID found", method = "getUuidFromIdentifiers(null)") + public void getUuidFromIdentifiers_shouldReturnNullIfNoUUIDFound() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501||||||||||||||||5^^^L^PN||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + CX[] identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + String result = hl7service.getUuidFromIdentifiers(identifiers); + Assert.assertNull("should have returned null", result); + } + + /** + * @see {@link HL7Service#getUuidFromIdentifiers(null)} + */ + @Test + @Verifies(value = "should not fail if multiple similar UUIDs exist in identifiers", method = "getUuidFromIdentifiers(null)") + public void getUuidFromIdentifiers_shouldNotFailIfMultipleSimilarUUIDsExistInIdentifiers() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4~2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + CX[] identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + String result = hl7service.getUuidFromIdentifiers(identifiers); + Assert.assertEquals("2178037d-f86b-4f12-8d8b-be3ebc220022", result); + } + + /** + * @see {@link HL7Service#getUuidFromIdentifiers(null)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if multiple different UUIDs exist in identifiers", method = "getUuidFromIdentifiers(null)") + public void getUuidFromIdentifiers_shouldFailIfMultipleDifferentUUIDsExistInIdentifiers() throws Exception { + HL7Service hl7service = Context.getHL7Service(); + Message message = hl7service + .parseHL7String("MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "NK1|1|Hornblower^Horatio^L|2B^Sibling^99REL||||||||||||M|19410501|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220022^^^UUID^v4~2178037d-f86b-4f12-8d8b-be3ebc220023^^^UUID^v4||||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"); + ORU_R01 oru = (ORU_R01) message; + List nk1List = new ORUR01Handler().getNK1List(oru); + CX[] identifiers = nk1List.get(0).getNextOfKinAssociatedPartySIdentifiers(); + hl7service.getUuidFromIdentifiers(identifiers); + Assert.fail("should have failed"); + } + } Index: test/api/org/openmrs/hl7/handler/ORUR01HandlerTest.java =================================================================== --- test/api/org/openmrs/hl7/handler/ORUR01HandlerTest.java (revision 13288) +++ test/api/org/openmrs/hl7/handler/ORUR01HandlerTest.java (working copy) @@ -32,15 +32,22 @@ import org.openmrs.Encounter; import org.openmrs.Obs; import org.openmrs.Patient; +import org.openmrs.Person; +import org.openmrs.Relationship; +import org.openmrs.RelationshipType; import org.openmrs.api.ConceptService; import org.openmrs.api.EncounterService; import org.openmrs.api.ObsService; +import org.openmrs.api.PersonService; import org.openmrs.api.context.Context; import org.openmrs.test.BaseContextSensitiveTest; import org.openmrs.test.Verifies; +import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.app.MessageTypeRouter; import ca.uhn.hl7v2.model.Message; +import ca.uhn.hl7v2.model.v25.message.ORU_R01; +import ca.uhn.hl7v2.model.v25.segment.NK1; import ca.uhn.hl7v2.parser.GenericParser; /** @@ -78,12 +85,23 @@ public void processMessage_shouldCreateEncounterAndObsFromHl7Message() throws Exception { ObsService obsService = Context.getObsService(); - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\rPID|||3^^^^||John3^Doe^||\rPV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\rORC|RE||||||||20080226102537|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\rOBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"; + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226102656||ORU^R01|JqnfhKKtouEz8kzTk6Zo|P|2.5|1||||||||16^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080226102537|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|5497^CD4, BY FACS^99DCT||450|||||||||20080206\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20080229|||||||||20080212"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); Patient patient = new Patient(3); + // check for an encounter + List encForPatient3 = Context.getEncounterService().getEncountersByPatient(patient); + assertNotNull(encForPatient3); + assertTrue("There should be an encounter created", encForPatient3.size() == 1); + // check for any obs List obsForPatient3 = obsService.getObservationsByPerson(patient); assertNotNull(obsForPatient3); @@ -115,7 +133,16 @@ public void processMessage_shouldCreateObsGroupForOBRs() throws Exception { ObsService obsService = Context.getObsService(); - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226103553||ORU^R01|OD9PWqcD9g0NKn81rvSD|P|2.5|1||||||||66^AMRS.ELD.FORMID\rPID|||3^^^^||John^Doe^||\rPV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080205|||||||V\rORC|RE||||||||20080226103428|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|DT|1592^MISSED RETURNED VISIT DATE^99DCT||20080201|||||||||20080205\rOBR|2|||1726^FOLLOW-UP ACTION^99DCT\rOBX|1|CWE|1558^PATIENT CONTACT METHOD^99DCT|1|1555^PHONE^99DCT|||||||||20080205\rOBX|2|NM|1553^NUMBER OF ATTEMPTS^99DCT|1|1|||||||||20080205\rOBX|3|NM|1554^SUCCESSFUL^99DCT|1|1|||||||||20080205"; + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080226103553||ORU^R01|OD9PWqcD9g0NKn81rvSD|P|2.5|1||||||||66^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||John^Doe^||\r" + + "PV1||O|1^Unknown Location||||1^Super User (1-8)|||||||||||||||||||||||||||||||||||||20080205|||||||V\r" + + "ORC|RE||||||||20080226103428|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|DT|1592^MISSED RETURNED VISIT DATE^99DCT||20080201|||||||||20080205\r" + + "OBR|2|||1726^FOLLOW-UP ACTION^99DCT\r" + + "OBX|1|CWE|1558^PATIENT CONTACT METHOD^99DCT|1|1555^PHONE^99DCT|||||||||20080205\r" + + "OBX|2|NM|1553^NUMBER OF ATTEMPTS^99DCT|1|1|||||||||20080205\r" + + "OBX|3|NM|1554^SUCCESSFUL^99DCT|1|1|||||||||20080205"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); @@ -194,7 +221,12 @@ // to append to assertNotNull(Context.getEncounterService().getEncounter(3)); - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080902151831||ORU^R01|yow3LEP6bycnLfoPyI31|P|2.5|1||||||||3^AMRS.ELD.FORMID\rPID|||7^^^^||Indakasi^Testarius^Ambote||\rPV1||O|1||||1^Super User (1-8)||||||||||||3|||||||||||||||||||||||||20080831|||||||V\rORC|RE||||||||20080902150000|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|NM|10^CD4 COUNT^99DCT||250|||||||||20080831"; + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080902151831||ORU^R01|yow3LEP6bycnLfoPyI31|P|2.5|1||||||||3^AMRS.ELD.FORMID\r" + + "PID|||7^^^^||Indakasi^Testarius^Ambote||\r" + + "PV1||O|1||||1^Super User (1-8)||||||||||||3|||||||||||||||||||||||||20080831|||||||V\r" + + "ORC|RE||||||||20080902150000|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|NM|10^CD4 COUNT^99DCT||250|||||||||20080831"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); @@ -222,7 +254,14 @@ List proposals = Context.getConceptService().getAllConceptProposals(false); Assert.assertEquals(0, proposals.size()); - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080924022306||ORU^R01|Z185fTD0YozQ5kvQZD7i|P|2.5|1||||||||3^AMRS.ELD.FORMID\rPID|||7^^^^||Joe^S^Mith||\rPV1||O|1^Unknown Module 2||||1^Joe (1-1)|||||||||||||||||||||||||||||||||||||20080212|||||||V\rORC|RE||||||||20080219085345|1^Joe\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|18|DT|5096^RETURN VISIT DATE^99DCT||20080506|||||||||20080212\rOBR|19|||5096^PROBLEM LIST^99DCT\rOBX|1|CWE|5096^PROBLEM ADDED^99DCT||PROPOSED^PELVIC MASS^99DCT|||||||||20080212"; + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080924022306||ORU^R01|Z185fTD0YozQ5kvQZD7i|P|2.5|1||||||||3^AMRS.ELD.FORMID\r" + + "PID|||7^^^^||Joe^S^Mith||\r" + + "PV1||O|1^Unknown Module 2||||1^Joe (1-1)|||||||||||||||||||||||||||||||||||||20080212|||||||V\r" + + "ORC|RE||||||||20080219085345|1^Joe\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|18|DT|5096^RETURN VISIT DATE^99DCT||20080506|||||||||20080212\r" + + "OBR|19|||5096^PROBLEM LIST^99DCT\r" + + "OBX|1|CWE|5096^PROBLEM ADDED^99DCT||PROPOSED^PELVIC MASS^99DCT|||||||||20080212"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); @@ -244,7 +283,16 @@ List proposals = Context.getConceptService().getAllConceptProposals(false); Assert.assertEquals(0, proposals.size()); - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20081006115934||ORU^R01|a1NZBpKqu54QyrWBEUKf|P|2.5|1||||||||3^AMRS.ELD.FORMID\rPID|||7^^^^~asdf^^^^||Joe^ ^Smith||\rPV1||O|1^Bishop Muge||||1^asdf asdf (5-9)|||||||||||||||||||||||||||||||||||||20081003|||||||V\rORC|RE||||||||20081006115645|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|1|CWE|5096^PAY CATEGORY^99DCT||5096^PILOT^99DCT|||||||||20081003\rOBX|2|DT|5096^RETURN VISIT DATE^99DCT||20081004|||||||||20081003\rOBR|3|||5096^PROBLEM LIST^99DCT\rOBX|1|CWE|5018^PROBLEM ADDED^99DCT||5096^HUMAN IMMUNODEFICIENCY VIRUS^99DCT|||||||||20081003\rOBX|2|CWE|5089^PROBLEM ADDED^99DCT||PROPOSED^ASDFASDFASDF^99DCT|||||||||20081003"; + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20081006115934||ORU^R01|a1NZBpKqu54QyrWBEUKf|P|2.5|1||||||||3^AMRS.ELD.FORMID\r" + + "PID|||7^^^^~asdf^^^^||Joe^ ^Smith||\r" + + "PV1||O|1^Bishop Muge||||1^asdf asdf (5-9)|||||||||||||||||||||||||||||||||||||20081003|||||||V\r" + + "ORC|RE||||||||20081006115645|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|1|CWE|5096^PAY CATEGORY^99DCT||5096^PILOT^99DCT|||||||||20081003\r" + + "OBX|2|DT|5096^RETURN VISIT DATE^99DCT||20081004|||||||||20081003\r" + + "OBR|3|||5096^PROBLEM LIST^99DCT\r" + + "OBX|1|CWE|5018^PROBLEM ADDED^99DCT||5096^HUMAN IMMUNODEFICIENCY VIRUS^99DCT|||||||||20081003\r" + + "OBX|2|CWE|5089^PROBLEM ADDED^99DCT||PROPOSED^ASDFASDFASDF^99DCT|||||||||20081003"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); @@ -266,7 +314,13 @@ ConceptService conceptService = Context.getConceptService(); EncounterService encService = Context.getEncounterService(); - String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080630094800||ORU^R01|kgWdFt0SVwwClOfJm3pe|P|2.5|1||||||||15^AMRS.ELD.FORMID\rPID|||3^^^^~d3811480^^^^||John3^Doe^||\rPV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20080208|||||||V\rORC|RE||||||||20080208000000|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBR|1|||1284^PROBLEM LIST^99DCT\rOBX|1|CWE|6042^PROBLEM ADDED^99DCT||PROPOSED^SEVERO DOLOR DE CABEZA^99DCT|||||||||20080208"; + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080630094800||ORU^R01|kgWdFt0SVwwClOfJm3pe|P|2.5|1||||||||15^AMRS.ELD.FORMID\r" + + "PID|||3^^^^~d3811480^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20080208|||||||V\r" + + "ORC|RE||||||||20080208000000|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBR|1|||1284^PROBLEM LIST^99DCT\r" + + "OBX|1|CWE|6042^PROBLEM ADDED^99DCT||PROPOSED^SEVERO DOLOR DE CABEZA^99DCT|||||||||20080208"; Message hl7message = parser.parse(hl7String); router.processMessage(hl7message); @@ -297,7 +351,14 @@ // sanity check to make sure this obs doesn't exist already Assert.assertEquals(0, obsService.getObservationsByPersonAndConcept(patient, concept).size()); - String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\rPID|||3^^^^||Beren^John^Bondo||\rPV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\rORC|RE||||||||20090728165937|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\rOBR|3|||23^FOOD CONSTRUCT^99DCT\rOBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; Message hl7message = parser.parse(hl7String); router.processMessage(hl7message); @@ -341,16 +402,256 @@ */ @Test @Verifies(value = "should send message to error queue for empty concept proposals", method = "processMessage(Message)") - public void processMessage__shouldSendMessageToErrorEueueForEmptyConceptProposals() - throws Exception { - String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080630094800||ORU^R01|kgWdFt0SVwwClOfJm3pe|P|2.5|1||||||||15^AMRS.ELD.FORMID\rPID|||3^^^^~d3811480^^^^||John3^Doe^||\rPV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20080208|||||||V\rORC|RE||||||||20080208000000|1^Super User\rOBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\rOBR|1|||1284^PROBLEM LIST^99DCT\rOBX|1|CWE|6042^PROBLEM ADDED^99DCT||PROPOSED^^99DCT|||||||||20080208"; + public void processMessage__shouldSendMessageToErrorEueueForEmptyConceptProposals() throws Exception { + String hl7string = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20080630094800||ORU^R01|kgWdFt0SVwwClOfJm3pe|P|2.5|1||||||||15^AMRS.ELD.FORMID\r" + + "PID|||3^^^^~d3811480^^^^||John3^Doe^||\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20080208|||||||V\r" + + "ORC|RE||||||||20080208000000|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBR|1|||1284^PROBLEM LIST^99DCT\r" + + "OBX|1|CWE|6042^PROBLEM ADDED^99DCT||PROPOSED^^99DCT|||||||||20080208"; int numberOfErrors = Context.getHL7Service().getAllHL7InErrors().size(); Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); Context.getHL7Service().getAllHL7InErrors(); //number or errors in queue should have incremented by 1 Assert.assertEquals(numberOfErrors + 1, Context.getHL7Service().getAllHL7InErrors().size()); + } + + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test + @Verifies(value = "should create a relationship from a NK1 segment", method = "processNK1(Patient,NK1)") + public void processNK1_shouldCreateARelationshipFromANK1Segment() throws Exception { + PersonService personService = Context.getPersonService(); + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + Patient relative = new Patient(2); // the patient that is related to patientA - } + // process a message with a single NK1 segment + // defines relative as patient's Parent + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3A^Parent^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + + // verify relationship was created + List rels = personService.getRelationships(relative, patient, new RelationshipType(3)); + Assert.assertTrue("new relationship was not created", !rels.isEmpty() && rels.size() == 1); + } + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if the coding system is not 99REL", method = "processNK1(Patient,NK1)") + public void processNK1_shouldFailIfTheCodingSystemIsNot99REL() throws Exception { + // process a message with an invalid coding system + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3A^Parent^ACKFOO||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + } + + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if the relationship identifier is formatted improperly", method = "processNK1(Patient,NK1)") + public void processNK1_shouldFailIfTheRelationshipIdentifierIsFormattedImproperly() throws Exception { + // process a message with an invalid relationship identifier format + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3C^Parent^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + } + + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test(expected = HL7Exception.class) + @Verifies(value = "should fail if the relationship type is not found", method = "processNK1(Patient,NK1)") + public void processNK1_shouldFailIfTheRelationshipTypeIsNotFound() throws Exception { + // process a message with a non-existent relationship type + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3952A^Fifth Cousin Twice Removed^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + } + + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test + @Verifies(value = "should not create a relationship if one exists", method = "processNK1(Patient,NK1)") + public void processNK1_shouldNotCreateARelationshipIfOneExists() throws Exception { + PersonService personService = Context.getPersonService(); + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + Patient relative = new Patient(2); // the patient that is related to patientA + + // create a relationship in the database + Relationship rel = new Relationship(); + rel.setRelationshipType(new RelationshipType(3)); + rel.setPersonA(relative); + rel.setPersonB(patient); + personService.saveRelationship(rel); + + // verify relationship exists + Assert.assertEquals(1, personService.getRelationships(relative, patient, new RelationshipType(3)).size()); + + // process a message with a single NK1 segment + // defines relative as patient's Parent + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3A^Parent^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + + // verify existing relationship + List rels = personService.getRelationships(relative, patient, new RelationshipType(3)); + Assert.assertTrue("existing relationship was not retained", !rels.isEmpty() && rels.size() == 1); + } + + /** + * @see {@link ORUR01Handler#processORU_R01(ORU_R01)} + */ + @Test + @Verifies(value = "should process multiple NK1 segments", method = "processORU_R01(ORU_R01)") + public void processORU_R01_shouldProcessMultipleNK1Segments() throws Exception { + PersonService personService = Context.getPersonService(); + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + Patient relative = new Patient(2); // the patient that is related to patientA + + // create a relationship in the database + Relationship newRel = new Relationship(); + newRel.setRelationshipType(new RelationshipType(3)); + newRel.setPersonA(relative); + newRel.setPersonB(patient); + personService.saveRelationship(newRel); + + // verify relationship exists + Assert.assertEquals(1, personService.getRelationships(relative, patient, new RelationshipType(3)).size()); + + // process a new message with multiple NK1 segments + // this one defines patientB as patientA's Sibling and Patient + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170333||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|2A^Sibling^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "NK1|2|Jones^Jane^Lee^^RN|1B^Patient^99REL||||||||||||F|19751016|||||||||||||||||2^^^L^PI\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + + Message hl7message = parser.parse(hl7String); + router.processMessage(hl7message); + + // verify existing relationship + List rels = personService.getRelationships(relative, patient, new RelationshipType(3)); + Assert.assertTrue("existing relationship was not retained", !rels.isEmpty() && rels.size() == 1); + + // verify first new relationship + rels = personService.getRelationships(patient, relative, new RelationshipType(2)); + Assert.assertTrue("first new relationship was not created", !rels.isEmpty() && rels.size() == 1); + + // verify second new relationship + rels = personService.getRelationships(patient, relative, new RelationshipType(1)); + Assert.assertTrue("second new relationship was not created", !rels.isEmpty() && rels.size() == 1); + } + + /** + * @see {@link ORUR01Handler#processNK1(Patient,NK1)} + */ + @Test + @Verifies(value = "should create a person if the relative is not found", method = "processNK1(Patient,NK1)") + public void processNK1_shouldCreateAPersonIfTheRelativeIsNotFound() throws Exception { + // process a message with an invalid relative identifier + PersonService personService = Context.getPersonService(); + Patient patient = new Patient(3); // the patient that is the focus of this hl7 message + + String hl7String = "MSH|^~\\&|FORMENTRY|AMRS.ELD|HL7LISTENER|AMRS.ELD|20090728170332||ORU^R01|gu99yBh4loLX2mh9cHaV|P|2.5|1||||||||4^AMRS.ELD.FORMID\r" + + "PID|||3^^^^||Beren^John^Bondo||\r" + + "NK1|1|Jones^Jane^Lee^^RN|3A^Parent^99REL||||||||||||F|19751016|||||||||||||||||2178037d-f86b-4f12-8d8b-be3ebc220029^^^UUID^v4\r" + + "PV1||O|1^Unknown||||1^Super User (admin)|||||||||||||||||||||||||||||||||||||20090714|||||||V\r" + + "ORC|RE||||||||20090728165937|1^Super User\r" + + "OBR|1|||1238^MEDICAL RECORD OBSERVATIONS^99DCT\r" + + "OBX|2|NM|5497^CD4 COUNT^99DCT||123|||||||||20090714\r" + + "OBR|3|||23^FOOD CONSTRUCT^99DCT\r" + + "OBX|1|CWE|21^FOOD ASSISTANCE FOR ENTIRE FAMILY^99DCT||22^UNKNOWN^99DCT^2471^UNKNOWN^99NAM|||||||||20090714"; + ORUR01Handler oruHandler = new ORUR01Handler(); + Message hl7message = parser.parse(hl7String); + ORU_R01 oru = (ORU_R01) hl7message; + List nk1List = oruHandler.getNK1List(oru); + for (NK1 nk1 : nk1List) + oruHandler.processNK1(patient, nk1); + + // find the relative in the database + Person relative = personService.getPersonByUuid("2178037d-f86b-4f12-8d8b-be3ebc220029"); + Assert.assertNotNull("a new person was not created", relative); + + // see if the relative made it into the relationship properly + List rels = personService.getRelationships(relative, patient, new RelationshipType(3)); + Assert.assertTrue("new relationship was not created", !rels.isEmpty() && rels.size() == 1); + } } Index: test/api/org/openmrs/hl7/include/ORUTest-initialData.xml =================================================================== --- test/api/org/openmrs/hl7/include/ORUTest-initialData.xml (revision 13288) +++ test/api/org/openmrs/hl7/include/ORUTest-initialData.xml (working copy) @@ -81,6 +81,8 @@ + +