Skip to content

Commit

Permalink
Merge pull request openmrs#128 from wluyima/TRUNK-3231
Browse files Browse the repository at this point in the history
Encounter autocomplete should filter results by patient - TRUNK-3231
  • Loading branch information
dkayiwa committed Feb 12, 2013
2 parents 781d925 + c8d49d7 commit cd2bf80
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 34 deletions.
33 changes: 28 additions & 5 deletions api/src/main/java/org/openmrs/api/EncounterService.java
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,32 @@ public List<Encounter> getEncounters(Patient who, Location loc, Date fromDate, D
public List<Encounter> getEncounters(String query, Integer start, Integer length, boolean includeVoided)
throws APIException;

/**
* Searches for encounters by patient id, provider identifier, location, encounter type,
* provider, form or provider name. It returns a specific number of them from the specified
* starting position. If start and length are not specified, then all matches are returned
*
* @param query provider identifier, location, encounter type, provider, form or provider name
* @param patientId the patient id
* @param start beginning index for the batch
* @param length number of encounters to return in the batch
* @param includeVoided Specifies whether voided encounters should be included
* @return list of encounters for the given patient based on batch settings
* @throws APIException
* @since 1.10
* @should fetch encounters by patient id
* @should include voided encounters if includeVoided is set to true
* @should should match on provider identifier
* @should match on the provider name
* @should match on the location name
* @should match on the provider person name
* @should match on the encounter type name
* @should match on the form name
*/
@Authorized( { PrivilegeConstants.GET_ENCOUNTERS })
public List<Encounter> getEncounters(String query, Integer patientId, Integer start, Integer length,
boolean includeVoided) throws APIException;

/**
* Get all encounters for a cohort of patients
*
Expand Down Expand Up @@ -823,7 +849,6 @@ public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean inc
* @param user the user instance to filter "visible" encounters for
* @return list, that does not include encounters, which can not be shown to given user due to
* permissions check
*
* @should filter encounters if user is not allowed to see some encounters
* @should not filter all encounters when the encounter type's view privilege column is null
*/
Expand All @@ -832,19 +857,19 @@ public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean inc

/**
* Determines whether given user is granted to view all encounter types or not
*
* @param subject the user whose permission to view all encounter types will be checked
* @return true if user has access to view all types of encounters
*
* @should return true if user is granted to view all encounters
* @should return true when the encounter type's view privilege column is null
*/
public boolean canViewAllEncounterTypes(User subject);

/**
* Determines whether given user is granted to edit all encounter types or not
*
* @param subject the user whose permission to edit all encounter types will be checked
* @return true if user has access to edit all types of encounters
*
* @should return true if user is granted to edit all encounters
* @should return true when the encounter type's edit privilege column is null
*/
Expand All @@ -857,7 +882,6 @@ public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean inc
* @param encounter the encounter instance to be checked
* @param subject the user, who requests edit access
* @return true if user has privilege denoted by <em>editPrivilege</em> given on encounter type
*
* @should return true if user can edit encounter
* @should return false if user can not edit encounter
* @should fail if encounter is null
Expand All @@ -871,7 +895,6 @@ public Integer getEncountersByVisitsAndPatientCount(Patient patient, boolean inc
* @param encounter the encounter instance to be checked
* @param subject the user, who requests view access
* @return true if user has privilege denoted by <em>viewPrivilege</em> given on encounter type
*
* @should return true if user can view encounter
* @should return false if user can not view encounter
* @should fail if encounter is null
Expand Down
6 changes: 4 additions & 2 deletions api/src/main/java/org/openmrs/api/db/EncounterDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,14 @@ public List<Encounter> getEncounters(Patient patient, Location location, Date fr
* Get a list of {@link Encounter} by Patient name or identifier based on batch settings
*
* @param query patient name or identifier
* @param patientId the patient id
* @param start beginning index for the batch
* @param length number of encounters to return in the batch
* @param includeVoided Specifies whether voided encounters should be included
* @return list of {@link Encounter} based on batch settings
* @see EncounterService#getEncounters(String, Integer, Integer, boolean)
*/
List<Encounter> getEncounters(String query, Integer start, Integer length, boolean includeVoided);
List<Encounter> getEncounters(String query, Integer patientId, Integer start, Integer length, boolean includeVoided);

/**
* Gets the location of the encounter
Expand All @@ -183,11 +184,12 @@ public List<Encounter> getEncounters(Patient patient, Location location, Date fr
* Return the number of encounters matching a patient name or patient identifier
*
* @param query patient name or identifier
* @param patientId the patient id
* @param includeVoided Specifies whether voided encounters should be included
* @return the number of encounters matching the given search phrase
* @see {@link EncounterService#getCountOfEncounters(String, boolean)}
*/
public Long getCountOfEncounters(String query, boolean includeVoided);
public Long getCountOfEncounters(String query, Integer patientId, boolean includeVoided);

/**
* @see EncounterService#getEncountersByVisit(Visit, boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
Expand Down Expand Up @@ -244,15 +245,17 @@ public EncounterType getEncounterTypeByUuid(String uuid) {
}

/**
* @see org.openmrs.api.db.EncounterDAO#getEncounters(String, Integer, Integer, boolean)
* @see org.openmrs.api.db.EncounterDAO#getEncounters(String, Integer, Integer, Integer,
* boolean)
*/
@SuppressWarnings("unchecked")
public List<Encounter> getEncounters(String query, Integer start, Integer length, boolean includeVoided) {
if (StringUtils.isBlank(query)) {
public List<Encounter> getEncounters(String query, Integer patientId, Integer start, Integer length,
boolean includeVoided) {
if (StringUtils.isBlank(query) && patientId == null) {
return Collections.emptyList();
}

Criteria criteria = createEncounterByQueryCriteria(query, includeVoided, true);
Criteria criteria = createEncounterByQueryCriteria(query, patientId, includeVoided, true);

if (start != null)
criteria.setFirstResult(start);
Expand Down Expand Up @@ -321,11 +324,12 @@ private Criteria createEncounterCriteria(Cohort patients) {
}

/**
* @see org.openmrs.api.db.EncounterDAO#getCountOfEncounters(java.lang.String, boolean)
* @see org.openmrs.api.db.EncounterDAO#getCountOfEncounters(java.lang.String,
* java.lang.Integer, boolean)
*/
@Override
public Long getCountOfEncounters(String query, boolean includeVoided) {
Criteria criteria = createEncounterByQueryCriteria(query, includeVoided, false);
public Long getCountOfEncounters(String query, Integer patientId, boolean includeVoided) {
Criteria criteria = createEncounterByQueryCriteria(query, patientId, includeVoided, false);

criteria.setProjection(Projections.countDistinct("enc.encounterId"));
return (Long) criteria.uniqueResult();
Expand All @@ -336,26 +340,78 @@ public Long getCountOfEncounters(String query, boolean includeVoided) {
* specified search phrase
*
* @param query patient name or identifier
* @param patientId the patient id
* @param includeVoided Specifies whether voided encounters should be included
* @param orderByNames specifies whether the encounters should be ordered by person names
* @return Criteria
*/
private Criteria createEncounterByQueryCriteria(String query, boolean includeVoided, boolean orderByNames) {
private Criteria createEncounterByQueryCriteria(String query, Integer patientId, boolean includeVoided,
boolean orderByNames) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Encounter.class, "enc");
if (!includeVoided)
criteria.add(Restrictions.eq("voided", false));

criteria = criteria.createCriteria("patient", "pat");
String name = null;
String identifier = null;
if (query.matches(".*\\d+.*")) {
identifier = query;
criteria.add(Restrictions.eq("enc.voided", false));

if (patientId != null) {
criteria.add(Restrictions.eq("enc.patientId", patientId));
if (StringUtils.isNotBlank(query)) {
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
//match on location.name, encounterType.name, form.name
//provider.name, provider.identifier, provider.person.names
MatchMode mode = MatchMode.ANYWHERE;
criteria.createAlias("enc.location", "loc");
criteria.createAlias("enc.encounterType", "encType");
criteria.createAlias("enc.form", "form");
criteria.createAlias("enc.encounterProviders", "enc_prov");
criteria.createAlias("enc_prov.provider", "prov");
criteria.createAlias("prov.person", "person", Criteria.LEFT_JOIN);
criteria.createAlias("person.names", "personName", Criteria.LEFT_JOIN);

Disjunction or = Restrictions.disjunction();
or.add(Restrictions.ilike("loc.name", query, mode));
or.add(Restrictions.ilike("encType.name", query, mode));
or.add(Restrictions.ilike("form.name", query, mode));
or.add(Restrictions.ilike("prov.name", query, mode));
or.add(Restrictions.ilike("prov.identifier", query, mode));

String[] splitNames = query.split(" ");
Disjunction nameOr = Restrictions.disjunction();
for (String splitName : splitNames) {
nameOr.add(Restrictions.ilike("personName.givenName", splitName, mode));
nameOr.add(Restrictions.ilike("personName.middleName", splitName, mode));
nameOr.add(Restrictions.ilike("personName.familyName", splitName, mode));
nameOr.add(Restrictions.ilike("personName.familyName2", splitName, mode));
}
//OUTPUT for provider criteria:
//prov.name like '%query%' OR prov.identifier like '%query%'
//OR ( personName.voided = false
// AND ( personName.givenName like '%query%'
// OR personName.middleName like '%query%'
// OR personName.familyName like '%query%'
// OR personName.familyName2 like '%query%'
// )
// )
Conjunction personNameConjuction = Restrictions.conjunction();
personNameConjuction.add(Restrictions.eq("personName.voided", false));
personNameConjuction.add(nameOr);

or.add(personNameConjuction);

criteria.add(or);
}
} else {
// there is no number in the string, search on name
name = query;
criteria = criteria.createCriteria("patient", "pat");
String name = null;
String identifier = null;
if (query.matches(".*\\d+.*")) {
identifier = query;
} else {
// there is no number in the string, search on name
name = query;
}
criteria = new PatientSearchCriteria(sessionFactory, criteria).prepareCriteria(name, identifier,
new ArrayList<PatientIdentifierType>(), false, orderByNames);
}
criteria = new PatientSearchCriteria(sessionFactory, criteria).prepareCriteria(name, identifier,
new ArrayList<PatientIdentifierType>(), false, orderByNames);

return criteria;
}

Expand Down
17 changes: 14 additions & 3 deletions api/src/main/java/org/openmrs/api/impl/EncounterServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public List<Encounter> getEncountersByPatient(String query, boolean includeVoide
if (query == null)
throw new IllegalArgumentException("The 'query' parameter is required and cannot be null");

return filterEncountersByViewPermissions(dao.getEncounters(query, null, null, includeVoided), null);
return filterEncountersByViewPermissions(dao.getEncounters(query, null, null, null, includeVoided), null);
}

/**
Expand Down Expand Up @@ -701,7 +701,18 @@ public Map<Integer, List<Encounter>> getAllEncounters(Cohort patients) {
@Transactional(readOnly = true)
public List<Encounter> getEncounters(String query, Integer start, Integer length, boolean includeVoided)
throws APIException {
return filterEncountersByViewPermissions(dao.getEncounters(query, start, length, includeVoided), null);
return filterEncountersByViewPermissions(dao.getEncounters(query, null, start, length, includeVoided), null);
}

/**
* @see org.openmrs.api.EncounterService#getEncounters(java.lang.String, java.lang.Integer,
* java.lang.Integer, java.lang.Integer, boolean)
*/
@Override
@Transactional(readOnly = true)
public List<Encounter> getEncounters(String query, Integer patientId, Integer start, Integer length,
boolean includeVoided) throws APIException {
return filterEncountersByViewPermissions(dao.getEncounters(query, patientId, start, length, includeVoided), null);
}

/**
Expand All @@ -710,7 +721,7 @@ public List<Encounter> getEncounters(String query, Integer start, Integer length
@Override
@Transactional(readOnly = true)
public Integer getCountOfEncounters(String query, boolean includeVoided) {
return OpenmrsUtil.convertToInteger(dao.getCountOfEncounters(query, includeVoided));
return OpenmrsUtil.convertToInteger(dao.getCountOfEncounters(query, null, includeVoided));
}

/**
Expand Down
80 changes: 80 additions & 0 deletions api/src/test/java/org/openmrs/api/EncounterServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2430,4 +2430,84 @@ private Encounter getEncounterWithViewPrivilege() {
return encounter;
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*
*/
@Test
@Verifies(value = "should fetch encounters by patient id", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldFetchEncountersByPatientId() throws Exception {
Assert.assertEquals(2, Context.getEncounterService().getEncounters(null, 3, null, null, false).size());
Assert.assertEquals(4, Context.getEncounterService().getEncounters(null, 3, null, null, true).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*/
@Test
@Verifies(value = "should match on the location name", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldMatchOnTheLocationName() throws Exception {
Assert.assertEquals(2, Context.getEncounterService().getEncounters("Test Location", 3, null, null, false).size());
Assert.assertEquals(4, Context.getEncounterService().getEncounters("Test Location", 3, null, null, true).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*/
@Test
@Verifies(value = "should match on the provider name", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldMatchOnTheProviderName() throws Exception {
Assert.assertEquals(1, Context.getEncounterService().getEncounters("phys", 3, null, null, false).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*/
@Test
@Verifies(value = "should should match on provider identifier", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldShouldMatchOnProviderIdentifier() throws Exception {
Assert.assertEquals(1, Context.getEncounterService().getEncounters("2", 3, null, null, false).size());
Assert.assertEquals(2, Context.getEncounterService().getEncounters("2", 3, null, null, true).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*/
@Test
@Verifies(value = "should match on the provider person name", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldMatchOnTheProviderPersonName() throws Exception {
//Should match on Super User and John3 Doe
Assert.assertEquals(1, Context.getEncounterService().getEncounters("er jo", 3, null, null, false).size());
Assert.assertEquals(2, Context.getEncounterService().getEncounters("er jo", 3, null, null, true).size());
Assert.assertEquals(0, Context.getEncounterService().getEncounters("none", 3, null, null, true).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*/
@Test
@Verifies(value = "should include voided encounters if includeVoided is set to true", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldIncludeVoidedEncountersIfIncludeVoidedIsSetToTrue() throws Exception {
Assert.assertEquals(2, Context.getEncounterService().getEncounters("2", 3, null, null, true).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*
*/
@Test
@Verifies(value = "should match on the encounter type name", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldMatchOnTheEncounterTypeName() throws Exception {
Assert.assertEquals(2, Context.getEncounterService().getEncounters("Type B", 3, null, null, false).size());
}

/**
* @see {@link EncounterService#getEncounters(String,Integer,Integer,Integer,null)}
*
*/
@Test
@Verifies(value = "should match on the form name", method = "getEncounters(String,Integer,Integer,Integer,null)")
public void getEncounters_shouldMatchOnTheFormName() throws Exception {
Assert.assertEquals(2, Context.getEncounterService().getEncounters("Basic", 3, null, null, false).size());
}
}
Loading

0 comments on commit cd2bf80

Please sign in to comment.