Index: build.properties
===================================================================
--- build.properties (revision 14204)
+++ build.properties (working copy)
@@ -9,7 +9,7 @@
build.compiler=modern
openmrs.version.major=1
-openmrs.version.minor=8
+openmrs.version.minor=9
openmrs.version.maintenance=0
openmrs.version.suffix=dev
Index: metadata/api/hibernate/org/openmrs/api/db/hibernate/Encounter.hbm.xml
===================================================================
--- metadata/api/hibernate/org/openmrs/api/db/hibernate/Encounter.hbm.xml (revision 14204)
+++ metadata/api/hibernate/org/openmrs/api/db/hibernate/Encounter.hbm.xml (working copy)
@@ -69,13 +69,14 @@
-
-
-
-
+
+
+
+
Index: metadata/model/liquibase-update-to-latest.xml
===================================================================
--- metadata/model/liquibase-update-to-latest.xml (revision 14204)
+++ metadata/model/liquibase-update-to-latest.xml (working copy)
@@ -3247,35 +3247,35 @@
-
-
-
-
-
-
-
- Adding daemon user to users table
-
-
-
-
-
-
-
-
-
-
-
- Removing scheduler.username and scheduler.password global properties
-
- property = 'scheduler.username'
-
-
- property = 'scheduler.password'
-
-
+
+
+
+
+
+
+
+ Adding daemon user to users table
+
+
+
+
+
+
+
+
+
+
+
+ Removing scheduler.username and scheduler.password global properties
+
+ property = 'scheduler.username'
+
+
+ property = 'scheduler.password'
+
+
@@ -3297,237 +3297,237 @@
-
+
Switch boolean concepts/observations to be stored as coded
-
-
-
- Drop Not-Null constraint from location column in Encounter and Obs table
-
-
-
-
-
-
-
-
-
-
- Changing the default value to 2 for 'message_state' column in 'hl7_in_archive' table
-
-
-
-
-
-
-
-
- Converting 0 and 1 to 2 for 'message_state' column in 'hl7_in_archive' table
-
-
- message_state IN (0,1)
-
-
-
-
-
- Removing the duplicate privilege 'Add Concept Proposal' in favor of 'Add Concept Proposals'
-
-
- Add Concept Proposals
- privilege = 'Add Concept Proposal' and not exists (select * from (select role, privilege from role_privilege) rp2 where rp2.role = role and rp2.privilege = 'Add Concept Proposals')
-
- privilege='Add Concept Proposal'
- privilege='Add Concept Proposal'
-
-
-
-
- Removing the duplicate privilege 'Edit Concept Proposal' in favor of 'Edit Concept Proposals'
-
-
- Edit Concept Proposals
- privilege = 'Edit Concept Proposal' and not exists (select * from (select role, privilege from role_privilege) rp2 where rp2.role = role and rp2.privilege = 'Edit Concept Proposals')
-
- privilege='Edit Concept Proposal'
- privilege='Edit Concept Proposal'
-
-
-
-
-
-
-
-
-
- Create active list type table.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Create active list table
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Create allergen table
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Create problem table
-
-
-
-
-
-
-
-
-
-
-
-
- SELECT count(*) FROM active_list_type
-
-
- Inserting default active list types
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Drop Not-Null constraint from location column in Encounter and Obs table
+
+
+
+
+
+
+
+
+
+
+ Changing the default value to 2 for 'message_state' column in 'hl7_in_archive' table
+
+
+
+
+
+
+
+
+ Converting 0 and 1 to 2 for 'message_state' column in 'hl7_in_archive' table
+
+
+ message_state IN (0,1)
+
+
+
+ Removing the duplicate privilege 'Add Concept Proposal' in favor of 'Add Concept Proposals'
+
+
+ Add Concept Proposals
+ privilege = 'Add Concept Proposal' and not exists (select * from (select role, privilege from role_privilege) rp2 where rp2.role = role and rp2.privilege = 'Add Concept Proposals')
+
+ privilege='Add Concept Proposal'
+ privilege='Add Concept Proposal'
+
+
+
+
+ Removing the duplicate privilege 'Edit Concept Proposal' in favor of 'Edit Concept Proposals'
+
+
+ Edit Concept Proposals
+ privilege = 'Edit Concept Proposal' and not exists (select * from (select role, privilege from role_privilege) rp2 where rp2.role = role and rp2.privilege = 'Edit Concept Proposals')
+
+ privilege='Edit Concept Proposal'
+ privilege='Edit Concept Proposal'
+
+
+
+
+
+
+
+
+
+ Create active list type table.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create active list table
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create allergen table
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create problem table
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT count(*) FROM active_list_type
+
+
+ Inserting default active list types
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3663,5 +3663,39 @@
-
-
+
+
+
+
+
+
+
+
+
+ Allow multiple providers per encounter (see ticket #2369)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: src/api/org/openmrs/Encounter.java
===================================================================
--- src/api/org/openmrs/Encounter.java (revision 14204)
+++ src/api/org/openmrs/Encounter.java (working copy)
@@ -14,10 +14,12 @@
package org.openmrs;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.TreeSet;
/**
* An Encounter represents one visit or interaction of a patient with a healthcare worker. Every
@@ -48,16 +50,17 @@
private EncounterType encounterType;
- private Person provider;
-
private Set orders;
private Set obs;
+ private Set providers;
+
// Constructors
/** default constructor */
public Encounter() {
+ providers = createSortablePersons();
}
/**
@@ -65,6 +68,7 @@
* @should set encounter id
*/
public Encounter(Integer encounterId) {
+ this();
this.encounterId = encounterId;
}
@@ -80,7 +84,8 @@
* @should have equal encounter objects with no encounter ids
* @should not have equal encounter objects when one has null encounter id
*/
- public boolean equals(Object obj) {
+ @Override
+ public boolean equals(Object obj) {
if (obj instanceof Encounter) {
Encounter enc = (Encounter) obj;
if (this.getEncounterId() != null && enc.getEncounterId() != null)
@@ -101,7 +106,8 @@
* @should have different hash code when not equal
* @should get hash code with null attributes
*/
- public int hashCode() {
+ @Override
+ public int hashCode() {
if (this.getEncounterId() == null)
return super.hashCode();
return this.getEncounterId().hashCode();
@@ -403,27 +409,80 @@
/**
* @return Returns the provider.
* @since 1.6 (used to return User)
+ * @deprecated use{@link #getProviders()}
+ * @should return null if there is no providers
+ * @should return the first Person object from the Providers collection sorted by Person_Id
+ * Ascending
*/
+ @Deprecated
public Person getProvider() {
- return provider;
+ if (!providers.isEmpty()) {
+ return providers.iterator().next();
+ }
+ return null;
}
/**
* @param provider The provider to set.
- * @deprecated use {@link #setProvider(Person)}
+ * @deprecated use {@link #addProvider(Person)}
*/
+ @Deprecated
public void setProvider(User provider) {
setProvider(provider.getPerson());
}
/**
- * @param provider The provider to set.
- */
- public void setProvider(Person provider) {
- this.provider = provider;
- }
-
+ * @param provider The provider to set.
+ * @deprecated use {@link #addProvider(Person)}
+ */
+ @Deprecated
+ public void setProvider(Person provider) {
+ addProvider(provider);
+ }
+
/**
+ * @return Returns the providers
+ * @since 1.9
+ */
+ public Set getProviders() {
+ return providers;
+ }
+
+ /**
+ * @param provider a new provider
+ * @since 1.9
+ */
+ public void addProvider(Person provider) {
+ if (!providers.contains(provider)) {
+ providers.add(provider);
+ }
+ }
+
+ /**
+ * @param provider a provider is removed
+ * @since 1.9
+ */
+ public boolean removeProvider(Person provider) {
+ return providers.remove(provider);
+ }
+
+ /**
+ * @param providers The providers to set
+ * @since 1.9
+ */
+ public void setProviders(Set providers) {
+ Set sortedProviders = createSortablePersons();
+ if (providers != null) {
+ sortedProviders.addAll(providers);
+ }
+ this.providers = sortedProviders;
+ }
+
+ public void clearProviders() {
+ providers.clear();
+ }
+
+ /**
* @return Returns the form.
*/
public Form getForm() {
@@ -450,6 +509,7 @@
ret += this.getLocation() == null ? "(no Location) " : this.getLocation().getName() + " ";
ret += this.getPatient() == null ? "(no Patient) " : this.getPatient().getPatientId().toString() + " ";
ret += this.getForm() == null ? "(no Form) " : this.getForm().getName() + " ";
+ ret += this.getProviders().size() == 0 ? "(no Providers) " : "num Providers: " + this.getProviders().size() + " ";
ret += this.getObsAtTopLevel(false) == null ? "(no Obss) " : "num Obs: " + this.getObsAtTopLevel(false) + " ";
ret += this.getOrders() == null ? "(no Orders) " : "num Orders: " + this.getOrders().size() + " ";
return "Encounter: [" + ret + "]";
@@ -470,7 +530,31 @@
*/
public void setId(Integer id) {
setEncounterId(id);
-
}
+ /**
+ * Created empty TreeSet collection and sorted by Person_Id in ascending order *
+ *
+ * @return Set
+ * @since 1.9
+ */
+ public static final Set createSortablePersons() {
+ return new TreeSet(new Comparator() {
+
+ @Override
+ public int compare(Person person1, Person person2) {
+ if (person1 == null) {
+ return -1;
+ } else if (person2 == null) {
+ return 1;
+ }
+ if (person1.getPersonId() < person2.getPersonId()) {
+ return -1;
+ } else if (person1.getPersonId() > person2.getPersonId()) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+ }
}
Index: src/web/org/openmrs/web/controller/encounter/EncounterFormController.java
===================================================================
--- src/web/org/openmrs/web/controller/encounter/EncounterFormController.java (revision 14204)
+++ src/web/org/openmrs/web/controller/encounter/EncounterFormController.java (working copy)
@@ -15,8 +15,10 @@
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
@@ -34,6 +36,7 @@
import org.openmrs.FormField;
import org.openmrs.Location;
import org.openmrs.Obs;
+import org.openmrs.Person;
import org.openmrs.api.EncounterService;
import org.openmrs.api.FormService;
import org.openmrs.api.context.Context;
@@ -64,6 +67,25 @@
protected final Log log = LogFactory.getLog(getClass());
/**
+ * @see org.springframework.web.servlet.mvc.BaseCommandController#onBind(javax.servlet.http.HttpServletRequest,
+ * java.lang.Object)
+ */
+ @Override
+ protected void onBind(HttpServletRequest request, Object command) throws Exception {
+
+ Encounter encounter = (Encounter) command;
+
+ if (Context.isAuthenticated()) {
+ String[] providerIds = fetchProviderIds(request);
+ if (providerIds != null) {
+ updateProvidersOfEncounter(encounter, providerIds);
+ }
+ }
+
+ super.onBind(request, encounter);
+ }
+
+ /**
* Allows for Integers to be used as values in input tags. Normally, only strings and lists are
* expected
*
@@ -100,14 +122,14 @@
if (StringUtils.hasText(request.getParameter("patientId")))
encounter.setPatient(Context.getPatientService().getPatient(
Integer.valueOf(request.getParameter("patientId"))));
- if (StringUtils.hasText(request.getParameter("providerId")))
- encounter.setProvider(Context.getPersonService().getPerson(
- Integer.valueOf(request.getParameter("providerId"))));
+
if (encounter.isVoided())
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "voidReason", "error.null");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "patient", "error.null");
- ValidationUtils.rejectIfEmptyOrWhitespace(errors, "provider", "error.null");
+ if (fetchProviderIds(request) == null) {
+ errors.rejectValue("providers", "error.null", null, null);
+ }
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "encounterDatetime", "error.null");
}
@@ -129,7 +151,7 @@
* org.springframework.validation.BindException)
*/
@Override
- protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object obj,
+ protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object obj,
BindException errors) throws Exception {
HttpSession httpSession = request.getSession();
@@ -148,9 +170,6 @@
encounter.setPatient(Context.getPatientService().getPatient(
Integer.valueOf(request.getParameter("patientId"))));
- // set the provider if they changed it
- encounter.setProvider(Context.getPersonService().getPerson(Integer.valueOf(request.getParameter("providerId"))));
-
if (encounter.isVoided() && encounter.getVoidedBy() == null)
// if this is a "new" voiding, call voidEncounter to set appropriate attributes
Context.getEncounterService().voidEncounter(encounter, encounter.getVoidReason());
@@ -181,24 +200,61 @@
* @see org.springframework.web.servlet.mvc.AbstractFormController#formBackingObject(javax.servlet.http.HttpServletRequest)
*/
@Override
- protected Object formBackingObject(HttpServletRequest request) throws ServletException {
+ protected Object formBackingObject(HttpServletRequest request) throws ServletException {
Encounter encounter = null;
+ if (Context.isAuthenticated()) {
+ encounter = fetchEncounter(request);
+ }
+
+ return encounter;
+ }
+
+ private void updateProvidersOfEncounter(Encounter encounter, String[] newProviderIds) {
- if (Context.isAuthenticated()) {
- EncounterService es = Context.getEncounterService();
- String encounterId = request.getParameter("encounterId");
- if (encounterId != null) {
- encounter = es.getEncounter(Integer.valueOf(encounterId));
+ Set providers = encounter.getProviders();
+
+ Map mapExistingProviders = new HashMap();
+ for (Person person : providers) {
+ mapExistingProviders.put(person.getPersonId().toString(), person);
+ }
+ Set newProviders = new HashSet();
+ for (String providerId : newProviderIds) {
+ Person currentPerson = mapExistingProviders.get(providerId);
+ if (currentPerson == null) {
+ newProviders.add(Context.getPersonService().getPerson(Integer.valueOf(providerId)));
+ } else {
+ newProviders.add(currentPerson);
}
}
+ encounter.setProviders(newProviders);
- if (encounter == null)
- encounter = new Encounter();
+ }
+
+ private Encounter fetchEncounter(HttpServletRequest request) {
+ Encounter encounter = null;
+ EncounterService es = Context.getEncounterService();
+ String encounterId = request.getParameter("encounterId");
+ if (encounterId != null) {
+ encounter = es.getEncounter(Integer.valueOf(encounterId));
+ return encounter;
+ } else {
+ Encounter emptyEncounter = new Encounter();
+ emptyEncounter.setProviders(new HashSet());
+ return emptyEncounter;
+ }
- return encounter;
}
+ private String[] fetchProviderIds(HttpServletRequest request) {
+ String[] providerIds = null;
+ String strProviders = request.getParameter("encounterProviders");
+ if (StringUtils.hasText(strProviders)) {
+ providerIds = strProviders.split(" ");
+ }
+ return providerIds;
+ }
+
/**
* @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest,
* java.lang.Object, org.springframework.validation.Errors)
@@ -246,7 +302,7 @@
//get the obs that was not created with the original encounter
Encounter en = o.getEncounter();
- if(o.getDateCreated().compareTo(en.getDateCreated())!=0){
+ if (o.getDateCreated().compareTo(en.getDateCreated()) != 0) {
obsAfterEncounter.add(o.getId());
}
@@ -269,7 +325,7 @@
ff = new FormField();
// we only put the top-level obs in the obsMap. Those would
- // be the obs that don't have an obs grouper
+ // be the obs that don't have an obs grouper
if (o.getObsGroup() == null) {
// populate the obs map with this formfield and obs
List list = obsMapToReturn.get(ff);
@@ -294,7 +350,7 @@
map.put("locale", Context.getLocale());
map.put("editedObs", editedObs);
-
+
map.put("obsAfterEncounter", obsAfterEncounter);
return map;
Index: src/web/org/openmrs/web/dwr/EncounterListItem.java
===================================================================
--- src/web/org/openmrs/web/dwr/EncounterListItem.java (revision 14204)
+++ src/web/org/openmrs/web/dwr/EncounterListItem.java (working copy)
@@ -14,10 +14,13 @@
package org.openmrs.web.dwr;
import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Encounter;
+import org.openmrs.Person;
import org.openmrs.PersonName;
import org.openmrs.util.Format;
@@ -47,7 +50,6 @@
}
public EncounterListItem(Encounter encounter) {
-
if (encounter != null) {
encounterId = encounter.getEncounterId();
encounterDateTime = encounter.getEncounterDatetime();
@@ -62,8 +64,17 @@
if (pn.getFamilyName() != null)
PersonName += " " + pn.getFamilyName();
}
- if (encounter.getProvider() != null)
- providerName = encounter.getProvider().getPersonName().toString();
+ if (encounter.getProviders() != null && !encounter.getProviders().isEmpty()) {
+ Set persons = encounter.getProviders();
+ StringBuffer sb = new StringBuffer();
+ for (Iterator personIterator = persons.iterator(); personIterator.hasNext();) {
+ sb.append(personIterator.next().getPersonName());
+ if (personIterator.hasNext()) {
+ sb.append(",
");
+ }
+ }
+ providerName = sb.toString();
+ }
if (encounter.getLocation() != null)
location = encounter.getLocation().getName();
if (encounter.getEncounterType() != null)
Index: test/api/org/openmrs/api/EncounterServiceTest.java
===================================================================
--- test/api/org/openmrs/api/EncounterServiceTest.java (revision 14204)
+++ test/api/org/openmrs/api/EncounterServiceTest.java (working copy)
@@ -146,8 +146,12 @@
enc.setLocation(new Location(1));
enc.setEncounterType(new EncounterType(1));
enc.setEncounterDatetime(new Date());
- enc.setPatient(new Patient(3));
- enc.setProvider(new Person(1));
+ Patient patient = new Patient(3);
+ patient.setGender("M");
+ enc.setPatient(patient);
+ Person provider = new Person(1);
+ provider.setGender("M");
+ enc.setProvider(provider);
es.saveEncounter(enc);
// Now add an obs to it
Index: test/api/org/openmrs/EncounterTest.java
===================================================================
--- test/api/org/openmrs/EncounterTest.java (revision 14204)
+++ test/api/org/openmrs/EncounterTest.java (working copy)
@@ -16,6 +16,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Date;
@@ -901,4 +902,34 @@
encounter.removeOrder(new Order(123));
}
+ /**
+ * @see {@link Encounter#getProvider()}
+ */
+ @Test
+ @Verifies(value = "should return null if there is no providers", method = "getProvider()")
+ public void getProvider_shouldReturnNullIfThereIsNoProviders() throws Exception {
+ Encounter encounter = new Encounter();
+ assertNull(encounter.getProvider());
+ }
+
+ /**
+ * @see {@link Encounter#getProvider()}
+ */
+ @Test
+ @Verifies(value = "should return the first Person object from the Providers collection sorted by Person_Id Ascending", method = "getProvider()")
+ public void getProvider_shouldReturnTheFirstPersonObjectFromTheProvidersCollectionSortedByPerson_IdAscending()
+ throws Exception {
+ Encounter encounter = new Encounter();
+ Person provider = new Person(3);
+ encounter.addProvider(provider);
+
+ provider = new Person(1);
+ encounter.addProvider(provider);
+
+ provider = new Person(2);
+ encounter.addProvider(provider);
+
+ assertEquals(new Integer(1), encounter.getProvider().getPersonId());
+ }
+
}
Index: web/WEB-INF/messages.properties
===================================================================
--- web/WEB-INF/messages.properties (revision 14204)
+++ web/WEB-INF/messages.properties (working copy)
@@ -686,6 +686,7 @@
Encounter.type=Encounter Type
Encounter.location=Location
Encounter.provider=Provider
+Encounter.providers=Providers
Encounter.provider.find=Find Provider
Encounter.datetime=Encounter Date
Encounter.find=Find Encounter
Index: web/WEB-INF/openmrs_static_content-servlet.xml
===================================================================
--- web/WEB-INF/openmrs_static_content-servlet.xml (revision 14204)
+++ web/WEB-INF/openmrs_static_content-servlet.xml (working copy)
@@ -18,6 +18,7 @@
jstlContentController
jstlContentController
+ jstlContentController
jstlContentController
jstlContentController
jstlContentController
Index: web/WEB-INF/view/admin/encounters/encounterForm.jsp
===================================================================
--- web/WEB-INF/view/admin/encounters/encounterForm.jsp (revision 14204)
+++ web/WEB-INF/view/admin/encounters/encounterForm.jsp (working copy)
@@ -18,6 +18,37 @@
+