diff --git a/api/src/main/java/org/openmrs/module/queue/api/QueueEntryService.java b/api/src/main/java/org/openmrs/module/queue/api/QueueEntryService.java index 72499a2..427c92d 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/QueueEntryService.java +++ b/api/src/main/java/org/openmrs/module/queue/api/QueueEntryService.java @@ -14,11 +14,7 @@ import java.util.Collection; import java.util.Optional; -import org.openmrs.Location; -import org.openmrs.Visit; -import org.openmrs.VisitAttributeType; import org.openmrs.api.APIException; -import org.openmrs.module.queue.model.Queue; import org.openmrs.module.queue.model.QueueEntry; public interface QueueEntryService { @@ -63,6 +59,11 @@ public interface QueueEntryService { */ void purgeQueueEntry(@NotNull QueueEntry queueEntry) throws APIException; + /** + * Return all QueueEntries that are active (non-voided, not ended) + */ + Collection getActiveQueueEntries(); + /** * Search for queue entries by conceptStatus * @@ -80,14 +81,6 @@ public interface QueueEntryService { */ Long getQueueEntriesCountByStatus(@NotNull String status); - /** - * @param location - * @param queue - * @return VisitQueueNumber - used to identify patients in the queue instead of using patient name - */ - String generateVisitQueueNumber(@NotNull Location location, @NotNull Queue queue, @NotNull Visit visit, - @NotNull VisitAttributeType visitAttributeType); - /** * Closes all active queue entries */ diff --git a/api/src/main/java/org/openmrs/module/queue/api/VisitQueueEntryService.java b/api/src/main/java/org/openmrs/module/queue/api/VisitQueueEntryService.java index ee74ad0..ea78384 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/VisitQueueEntryService.java +++ b/api/src/main/java/org/openmrs/module/queue/api/VisitQueueEntryService.java @@ -16,6 +16,7 @@ import org.openmrs.api.APIException; import org.openmrs.module.queue.model.VisitQueueEntry; +import org.openmrs.module.queue.processor.VisitQueueEntryProcessor; public interface VisitQueueEntryService { @@ -106,9 +107,13 @@ Collection findVisitQueueEntries(String status, String service, * * @param service concept service name * @param status concept status name - * @param locaitonUuid location uuid + * @param locationUUid location uuid * @return {@link Long} count of visit queue entries */ Long getVisitQueueEntriesCountByLocationStatusAndService(@NotNull String status, String service, String locationUUid); + /** + * @param visitQueueEntryProcessor the visitQueueEntryProcessor to set + */ + void setVisitQueueEntryProcessor(VisitQueueEntryProcessor visitQueueEntryProcessor); } diff --git a/api/src/main/java/org/openmrs/module/queue/api/dao/QueueEntryDao.java b/api/src/main/java/org/openmrs/module/queue/api/dao/QueueEntryDao.java index 45b7b26..6b5879a 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/dao/QueueEntryDao.java +++ b/api/src/main/java/org/openmrs/module/queue/api/dao/QueueEntryDao.java @@ -15,10 +15,8 @@ import java.util.List; import org.openmrs.Auditable; -import org.openmrs.Location; import org.openmrs.OpenmrsObject; import org.openmrs.api.ConceptNameType; -import org.openmrs.module.queue.model.Queue; import org.openmrs.module.queue.model.QueueEntry; public interface QueueEntryDao extends BaseQueueDao { @@ -44,13 +42,6 @@ Collection SearchQueueEntriesByConceptStatus(@NotNull String concept Long getQueueEntriesCountByConceptStatus(@NotNull String conceptStatus, ConceptNameType conceptNameType, boolean localePreferred); - /** - * @param location - * @param queue - * @return VisitQueueNumber - used to identify patients in the queue instead of using patient name - */ - String generateVisitQueueNumber(@NotNull Location location, @NotNull Queue queue); - /** * Gets active queue entries * diff --git a/api/src/main/java/org/openmrs/module/queue/api/dao/impl/QueueEntryDaoImpl.java b/api/src/main/java/org/openmrs/module/queue/api/dao/impl/QueueEntryDaoImpl.java index 477edde..0e3040e 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/dao/impl/QueueEntryDaoImpl.java +++ b/api/src/main/java/org/openmrs/module/queue/api/dao/impl/QueueEntryDaoImpl.java @@ -9,29 +9,19 @@ */ package org.openmrs.module.queue.api.dao.impl; -import static org.hibernate.criterion.Restrictions.eq; - import javax.validation.constraints.NotNull; -import java.time.LocalDate; -import java.time.ZoneId; import java.util.Collection; -import java.util.Date; import java.util.List; -import org.apache.commons.lang3.StringUtils; import org.hibernate.Criteria; import org.hibernate.SessionFactory; -import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; import org.hibernate.criterion.Restrictions; -import org.openmrs.Location; import org.openmrs.api.ConceptNameType; import org.openmrs.module.queue.api.dao.QueueEntryDao; -import org.openmrs.module.queue.model.Queue; import org.openmrs.module.queue.model.QueueEntry; -import org.openmrs.module.queue.model.VisitQueueEntry; import org.springframework.beans.factory.annotation.Qualifier; @SuppressWarnings("unchecked") @@ -74,42 +64,6 @@ public Long getQueueEntriesCountByConceptStatus(@NotNull String conceptStatus, C return (Long) criteria.uniqueResult(); } - @Override - public String generateVisitQueueNumber(Location location, Queue queue) { - Criteria criteriaVisitQueueEntries = getCurrentSession().createCriteria(VisitQueueEntry.class, "_vqe"); - includeVoidedObjects(criteriaVisitQueueEntries, false); - Criteria criteriaQueueEntries = criteriaVisitQueueEntries.createCriteria("_vqe.queueEntry", "_qe"); - Criteria criteriaQueue = criteriaQueueEntries.createCriteria("_qe.queue", "_q"); - Criteria criteriaQueueLocation = criteriaQueue.createCriteria("_q.location", "_ql"); - criteriaQueueLocation.add(eq("_ql.uuid", location.getUuid())); - criteriaQueueLocation.add(eq("_q.uuid", queue.getUuid())); - - LocalDate minDate = LocalDate.now(); - LocalDate maxDate = LocalDate.now().plusDays(1); - - Date startOfDay = Date.from(minDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - Date endOfDay = Date.from(maxDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - - Conjunction queueEntryStartedAtCheck = Restrictions.conjunction(); - queueEntryStartedAtCheck.add(Restrictions.ge("startedAt", startOfDay)); - queueEntryStartedAtCheck.add(Restrictions.lt("startedAt", endOfDay)); - criteriaQueueEntries.add(queueEntryStartedAtCheck); - - List queueEntryList = criteriaQueueLocation.list(); - - int visitQueueNumber = 1; - - if (!queueEntryList.isEmpty()) { - visitQueueNumber = queueEntryList.size() + 1; - } - - String paddedString = StringUtils.leftPad(String.valueOf(visitQueueNumber), 3, "0"); - - String serviceName = queue.getName().toUpperCase(); - String prefix = serviceName.length() < 3 ? serviceName : serviceName.substring(0, 3); - return prefix + "-" + paddedString; - } - /** * @see QueueEntryDao#getActiveQueueEntries() */ diff --git a/api/src/main/java/org/openmrs/module/queue/api/impl/QueueEntryServiceImpl.java b/api/src/main/java/org/openmrs/module/queue/api/impl/QueueEntryServiceImpl.java index a57a5ed..c7ffbce 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/impl/QueueEntryServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/queue/api/impl/QueueEntryServiceImpl.java @@ -19,17 +19,12 @@ import lombok.AccessLevel; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.openmrs.Location; -import org.openmrs.Visit; -import org.openmrs.VisitAttribute; -import org.openmrs.VisitAttributeType; import org.openmrs.api.APIException; import org.openmrs.api.ConceptNameType; import org.openmrs.api.context.Context; import org.openmrs.api.impl.BaseOpenmrsService; import org.openmrs.module.queue.api.QueueEntryService; import org.openmrs.module.queue.api.dao.QueueEntryDao; -import org.openmrs.module.queue.model.Queue; import org.openmrs.module.queue.model.QueueEntry; import org.springframework.transaction.annotation.Transactional; @@ -91,6 +86,11 @@ public void purgeQueueEntry(QueueEntry queueEntry) throws APIException { this.dao.delete(queueEntry); } + @Override + public Collection getActiveQueueEntries() { + return dao.getActiveQueueEntries(); + } + /** * @see org.openmrs.module.queue.api.QueueEntryService#searchQueueEntriesByConceptStatus(String, * boolean) @@ -109,23 +109,6 @@ public Long getQueueEntriesCountByStatus(@NotNull String status) { return this.dao.getQueueEntriesCountByConceptStatus(status, ConceptNameType.FULLY_SPECIFIED, false); } - @Override - public String generateVisitQueueNumber(Location location, Queue queue, Visit visit, - VisitAttributeType visitAttributeType) { - if (location == null || queue == null || visit == null || visitAttributeType == null) { - throw new APIException("Sufficient parameters not supplied for generation of VisitQueueNumber"); - } - String queueNumber = dao.generateVisitQueueNumber(location, queue); - - // Create Visit Attribute using generated queue number - VisitAttribute visitQueueNumber = new VisitAttribute(); - visitQueueNumber.setAttributeType(visitAttributeType); - visitQueueNumber.setValue(queueNumber); - visit.setAttribute(visitQueueNumber); - Context.getVisitService().saveVisit(visit); - return queueNumber; - } - @Override public void closeActiveQueueEntries() { List queueEntries = dao.getActiveQueueEntries(); diff --git a/api/src/main/java/org/openmrs/module/queue/api/impl/VisitQueueEntryServiceImpl.java b/api/src/main/java/org/openmrs/module/queue/api/impl/VisitQueueEntryServiceImpl.java index e7fd498..fc7ac70 100644 --- a/api/src/main/java/org/openmrs/module/queue/api/impl/VisitQueueEntryServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/queue/api/impl/VisitQueueEntryServiceImpl.java @@ -30,13 +30,16 @@ import org.openmrs.module.queue.api.dao.VisitQueueEntryDao; import org.openmrs.module.queue.model.QueueEntry; import org.openmrs.module.queue.model.VisitQueueEntry; +import org.openmrs.module.queue.processor.VisitQueueEntryProcessor; import org.springframework.transaction.annotation.Transactional; @Slf4j @Transactional -@Setter(AccessLevel.MODULE) +@Setter(AccessLevel.PUBLIC) public class VisitQueueEntryServiceImpl extends BaseOpenmrsService implements VisitQueueEntryService { + private VisitQueueEntryProcessor visitQueueEntryProcessor; + private VisitQueueEntryDao dao; public void setDao(VisitQueueEntryDao dao) { @@ -49,23 +52,23 @@ public Optional getVisitQueueEntryByUuid(@NotNull String uuid) } @Override - public VisitQueueEntry createVisitQueueEntry(@NotNull VisitQueueEntry visitQueueEntry) { - //verify visit -patient & queue entry patient - //Todo more refactor - Visit visit = Context.getVisitService().getVisitByUuid(visitQueueEntry.getVisit().getUuid()); - Patient visitPatient = visit.getPatient(); - Patient queueEntryPatient = visitQueueEntry.getQueueEntry().getPatient(); - if (visitPatient != null & queueEntryPatient != null) { - boolean isPatientSame = visitPatient.getUuid().equals(queueEntryPatient.getUuid()); - if (!isPatientSame) { - throw new IllegalArgumentException("Patient mismatch - visit.patient does not match queueEntry.patient"); - } - QueueEntry newlyCreatedQueueEntry = Context.getService(QueueEntryService.class) - .createQueueEntry(visitQueueEntry.getQueueEntry()); - visitQueueEntry.setQueueEntry(newlyCreatedQueueEntry); - return this.dao.createOrUpdate(visitQueueEntry); + public synchronized VisitQueueEntry createVisitQueueEntry(@NotNull VisitQueueEntry visitQueueEntry) { + Visit visit = visitQueueEntry.getVisit(); + Patient visitPatient = Context.getVisitService().getVisitByUuid(visit.getUuid()).getPatient(); + QueueEntry queueEntry = visitQueueEntry.getQueueEntry(); + if (queueEntry.getPatient() == null) { + queueEntry.setPatient(visitPatient); + } else if (!queueEntry.getPatient().getUuid().equals(visitPatient.getUuid())) { + throw new IllegalArgumentException("Patient mismatch - visit.patient does not match queueEntry.patient"); + } + queueEntry = Context.getService(QueueEntryService.class).createQueueEntry(queueEntry); + visitQueueEntry.setQueueEntry(queueEntry); + visitQueueEntry = dao.createOrUpdate(visitQueueEntry); + + if (visitQueueEntryProcessor != null) { + visitQueueEntryProcessor.beforeSaveVisitQueueEntry(visitQueueEntry); } - return null; + return dao.createOrUpdate(visitQueueEntry); } /** diff --git a/api/src/main/java/org/openmrs/module/queue/model/QueueEntry.java b/api/src/main/java/org/openmrs/module/queue/model/QueueEntry.java index 074978d..6c8b5df 100644 --- a/api/src/main/java/org/openmrs/module/queue/model/QueueEntry.java +++ b/api/src/main/java/org/openmrs/module/queue/model/QueueEntry.java @@ -57,6 +57,9 @@ public class QueueEntry extends BaseChangeableOpenmrsData { @JoinColumn(name = "patient_id", nullable = false) private Patient patient; + @Column(name = "patient_queue_number") + private String patientQueueNumber; + @ManyToOne @JoinColumn(name = "priority", referencedColumnName = "concept_id", nullable = false) private Concept priority; diff --git a/api/src/main/java/org/openmrs/module/queue/processor/BasicPatientQueueNumberGenerator.java b/api/src/main/java/org/openmrs/module/queue/processor/BasicPatientQueueNumberGenerator.java new file mode 100644 index 0000000..3e6ec5e --- /dev/null +++ b/api/src/main/java/org/openmrs/module/queue/processor/BasicPatientQueueNumberGenerator.java @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.queue.processor; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.openmrs.module.queue.model.QueueEntry; +import org.openmrs.module.queue.model.VisitQueueEntry; +import org.springframework.stereotype.Component; + +/** + * Basic implementation of a VisitQueueEntryProcessor which simply returns the primary kye of the + * VisitQueueEntry as a string. + */ +@Slf4j +@Component +public class BasicPatientQueueNumberGenerator implements VisitQueueEntryProcessor { + + /** + * This populates the given VisitQueueEntry with an appropriate patient queue number + */ + public void beforeSaveVisitQueueEntry(VisitQueueEntry visitQueueEntry) { + QueueEntry queueEntry = visitQueueEntry.getQueueEntry(); + if (StringUtils.isBlank(queueEntry.getPatientQueueNumber())) { + queueEntry.setPatientQueueNumber(Integer.toString(visitQueueEntry.getId())); + } + } +} diff --git a/api/src/main/java/org/openmrs/module/queue/processor/VisitAttributeQueueNumberGenerator.java b/api/src/main/java/org/openmrs/module/queue/processor/VisitAttributeQueueNumberGenerator.java new file mode 100644 index 0000000..811705c --- /dev/null +++ b/api/src/main/java/org/openmrs/module/queue/processor/VisitAttributeQueueNumberGenerator.java @@ -0,0 +1,87 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.queue.processor; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Date; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.StringUtils; +import org.openmrs.VisitAttribute; +import org.openmrs.VisitAttributeType; +import org.openmrs.api.APIException; +import org.openmrs.api.AdministrationService; +import org.openmrs.api.VisitService; +import org.openmrs.module.queue.model.Queue; +import org.openmrs.module.queue.model.QueueEntry; +import org.openmrs.module.queue.model.VisitQueueEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Implementation of a VisitQueueEntryProcessor which aims to retain legacy functionality using + * visit attributes + */ +@Slf4j +@Component +public class VisitAttributeQueueNumberGenerator implements VisitQueueEntryProcessor { + + @Autowired + VisitService visitService; + + @Autowired + AdministrationService adminService; + + /** + * This populates the given VisitQueueEntry with an appropriate patient queue number + */ + public void beforeSaveVisitQueueEntry(VisitQueueEntry visitQueueEntry) { + QueueEntry queueEntry = visitQueueEntry.getQueueEntry(); + Queue queue = queueEntry.getQueue(); + VisitAttributeType visitAttributeType = getVisitAttributeType(); + + LocalDate minDate = LocalDate.now(); + LocalDate maxDate = LocalDate.now().plusDays(1); + Date startOfDay = Date.from(minDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endOfDay = Date.from(maxDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + int visitQueueNumber = 1; + for (QueueEntry qe : queue.getQueueEntries()) { + if (BooleanUtils.isNotTrue(qe.getVoided())) { + if (!qe.getStartedAt().before(startOfDay) && qe.getStartedAt().before(endOfDay)) { + visitQueueNumber++; + } + } + } + String paddedString = StringUtils.leftPad(String.valueOf(visitQueueNumber), 3, "0"); + String serviceName = queue.getName().toUpperCase(); + String prefix = serviceName.length() < 3 ? serviceName : serviceName.substring(0, 3); + String queueNumber = prefix + "-" + paddedString; + + // Associate this queue number directly + queueEntry.setPatientQueueNumber(queueNumber); + + // Create Visit Attribute using generated queue number + VisitAttribute visitAttribute = new VisitAttribute(); + visitAttribute.setAttributeType(visitAttributeType); + visitAttribute.setValueReferenceInternal(queueNumber); + visitQueueEntry.getVisit().addAttribute(visitAttribute); + } + + private VisitAttributeType getVisitAttributeType() { + String gpName = "queue.visitQueueNumberAttributeUuid"; + String attributeType = adminService.getGlobalPropertyValue(gpName, ""); + if (StringUtils.isNotEmpty(attributeType)) { + return visitService.getVisitAttributeTypeByUuid(attributeType); + } + throw new APIException("Visit Attribute Type is required. Please configure global property: " + gpName); + } +} diff --git a/api/src/main/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessor.java b/api/src/main/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessor.java new file mode 100644 index 0000000..07a5e00 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessor.java @@ -0,0 +1,25 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.queue.processor; + +import org.openmrs.module.queue.model.VisitQueueEntry; + +/** + * Implementations of this interface are able to add functionality into the VisitQueueEntry save + * process + */ +public interface VisitQueueEntryProcessor { + + /** + * This is called immediately prior saving a VisitQueueEntry to the database + */ + void beforeSaveVisitQueueEntry(VisitQueueEntry visitQueueEntry); + +} diff --git a/api/src/main/resources/liquibase.xml b/api/src/main/resources/liquibase.xml index 8acb6c6..e423f0c 100644 --- a/api/src/main/resources/liquibase.xml +++ b/api/src/main/resources/liquibase.xml @@ -385,4 +385,17 @@ schedulable_class = 'org.openmrs.module.queue.tasks.AutoCloseQueueEntryTask' + + + + + + + + Add column patient_queue_number to queue_entry table + + + + + diff --git a/api/src/test/java/org/openmrs/module/queue/api/dao/QueueEntryDaoTest.java b/api/src/test/java/org/openmrs/module/queue/api/dao/QueueEntryDaoTest.java index 557a071..b776964 100644 --- a/api/src/test/java/org/openmrs/module/queue/api/dao/QueueEntryDaoTest.java +++ b/api/src/test/java/org/openmrs/module/queue/api/dao/QueueEntryDaoTest.java @@ -10,7 +10,6 @@ package org.openmrs.module.queue.api.dao; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -25,12 +24,10 @@ import org.junit.Before; import org.junit.Test; import org.openmrs.Concept; -import org.openmrs.Location; import org.openmrs.Patient; import org.openmrs.api.ConceptNameType; import org.openmrs.api.context.Context; import org.openmrs.module.queue.SpringTestConfiguration; -import org.openmrs.module.queue.api.QueueEntryService; import org.openmrs.module.queue.model.Queue; import org.openmrs.module.queue.model.QueueEntry; import org.openmrs.test.BaseModuleContextSensitiveTest; @@ -244,16 +241,4 @@ public void shouldZeroCountQueueEntriesByBadStatus() { assertThat(queueEntriesCountByStatusCount, notNullValue()); assertThat(queueEntriesCountByStatusCount, is(0L)); } - - @Test - public void shouldGenerateVisitQueueNumber() { - QueueEntry queueEntry = Context.getService(QueueEntryService.class) - .getQueueEntryByUuid("7ub8fe43-2813-4kbc-80dc-2e5d30252cc5").get(); - Location location = Context.getLocationService().getLocationByUuid("d0938432-1691-11df-97a5-7038c098"); - - String queueNumber = dao.generateVisitQueueNumber(location, queueEntry.getQueue()); - - assertThat(queueNumber, notNullValue()); - assertThat(queueNumber, equalTo("CON-001")); - } } diff --git a/api/src/test/java/org/openmrs/module/queue/processor/TestPatientQueueNumberGenerator.java b/api/src/test/java/org/openmrs/module/queue/processor/TestPatientQueueNumberGenerator.java new file mode 100644 index 0000000..839c371 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/queue/processor/TestPatientQueueNumberGenerator.java @@ -0,0 +1,38 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.queue.processor; + +import lombok.extern.slf4j.Slf4j; +import org.openmrs.module.queue.model.VisitQueueEntry; +import org.springframework.stereotype.Component; + +/** + * Test class that allows delegating to a particular generator for a specific thread + */ +@Slf4j +@Component +public class TestPatientQueueNumberGenerator implements VisitQueueEntryProcessor { + + ThreadLocal processorToUse = new ThreadLocal<>(); + + /** + * This populates the given VisitQueueEntry with an appropriate patient queue number + */ + public void beforeSaveVisitQueueEntry(VisitQueueEntry visitQueueEntry) { + VisitQueueEntryProcessor processor = processorToUse.get(); + if (processor != null) { + processor.beforeSaveVisitQueueEntry(visitQueueEntry); + } + } + + public void setProcessorToUse(VisitQueueEntryProcessor visitQueueEntryProcessor) { + processorToUse.set(visitQueueEntryProcessor); + } +} diff --git a/api/src/test/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessorTest.java b/api/src/test/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessorTest.java new file mode 100644 index 0000000..baf3d60 --- /dev/null +++ b/api/src/test/java/org/openmrs/module/queue/processor/VisitQueueEntryProcessorTest.java @@ -0,0 +1,184 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.queue.processor; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.openmrs.Concept; +import org.openmrs.Patient; +import org.openmrs.Visit; +import org.openmrs.VisitAttributeType; +import org.openmrs.api.AdministrationService; +import org.openmrs.api.ConceptService; +import org.openmrs.api.PatientService; +import org.openmrs.api.VisitService; +import org.openmrs.customdatatype.datatype.FreeTextDatatype; +import org.openmrs.module.queue.SpringTestConfiguration; +import org.openmrs.module.queue.api.QueueEntryService; +import org.openmrs.module.queue.api.QueueService; +import org.openmrs.module.queue.api.VisitQueueEntryService; +import org.openmrs.module.queue.model.Queue; +import org.openmrs.module.queue.model.QueueEntry; +import org.openmrs.module.queue.model.VisitQueueEntry; +import org.openmrs.test.BaseModuleContextSensitiveTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration(classes = SpringTestConfiguration.class, inheritLocations = false) +public class VisitQueueEntryProcessorTest extends BaseModuleContextSensitiveTest { + + private static final List QUEUE_INITIAL_DATASET_XML = Arrays.asList( + "org/openmrs/module/queue/api/dao/QueueDaoTest_locationInitialDataset.xml", + "org/openmrs/module/queue/api/dao/QueueEntryDaoTest_conceptsInitialDataset.xml", + "org/openmrs/module/queue/api/dao/QueueDaoTest_initialDataset.xml", + "org/openmrs/module/queue/api/dao/QueueEntryDaoTest_patientInitialDataset.xml", + "org/openmrs/module/queue/api/dao/QueueEntryDaoTest_initialDataset.xml", + "org/openmrs/module/queue/api/dao/VisitQueueEntryDaoTest_visitInitialDataset.xml", + "org/openmrs/module/queue/api/dao/visitQueueEntryDaoTest_visitQueueNumberInitialDataset.xml", + "org/openmrs/module/queue/validators/QueueEntryValidatorTest_globalPropertyInitialDataset.xml"); + + @Autowired + AdministrationService adminService; + + @Autowired + PatientService patientService; + + @Autowired + VisitService visitService; + + @Autowired + @Qualifier("queue.QueueService") + QueueService queueService; + + @Autowired + @Qualifier("queue.QueueEntryService") + QueueEntryService queueEntryService; + + @Autowired + @Qualifier("queue.VisitQueueEntryService") + VisitQueueEntryService visitQueueEntryService; + + @Autowired + TestPatientQueueNumberGenerator testPatientQueueNumberGenerator; + + @Autowired + BasicPatientQueueNumberGenerator basicPatientQueueNumberGenerator; + + @Autowired + VisitAttributeQueueNumberGenerator visitAttributeQueueNumberGenerator; + + @Autowired + ConceptService conceptService; + + String visitQueueEntryUuid = "cd1d0825-71e6-11ee-af3b-0242ac120002"; + + Patient patient; + + Visit visit; + + Queue queue; + + Concept waitingStatus; + + Concept emergencyPriority; + + @Before + public void setup() { + QUEUE_INITIAL_DATASET_XML.forEach(this::executeDataSet); + patient = patientService.getPatient(100); + visit = visitService.getVisit(101); + queue = queueService.getQueueByUuid("3eb7fe43-2813-4kbc-80dc-2e5d30252bb5").get(); + waitingStatus = conceptService.getConcept(3001); + emergencyPriority = conceptService.getConcept(1001); + visitQueueEntryService.setVisitQueueEntryProcessor(testPatientQueueNumberGenerator); + + VisitAttributeType vat = new VisitAttributeType(); + vat.setName("Test"); + vat.setDatatypeClassname(FreeTextDatatype.class.getName()); + vat = visitService.saveVisitAttributeType(vat); + adminService.setGlobalProperty("queue.visitQueueNumberAttributeUuid", vat.getUuid()); + } + + private VisitQueueEntry newVisitQueueEntry() { + QueueEntry queueEntry = new QueueEntry(); + queueEntry.setUuid("5kb8fe43-2813-4kbc-80dc-2e5d30252cc87"); + queueEntry.setPatient(patient); + queueEntry.setQueue(queue); + queueEntry.setStartedAt(new Date()); + queueEntry.setStatus(waitingStatus); + queueEntry.setPriority(emergencyPriority); + VisitQueueEntry visitQueueEntry = new VisitQueueEntry(); + visitQueueEntry.setUuid(visitQueueEntryUuid); + visitQueueEntry.setQueueEntry(queueEntry); + visitQueueEntry.setVisit(visit); + return visitQueueEntry; + } + + @Test + public void shouldNotGenerateAVisitNumberIfNoProcessorsAreSpecified() { + testPatientQueueNumberGenerator.setProcessorToUse(null); + visitQueueEntryService.createVisitQueueEntry(newVisitQueueEntry()); + VisitQueueEntry visitQueueEntry = visitQueueEntryService.getVisitQueueEntryByUuid(visitQueueEntryUuid).get(); + assertThat(visitQueueEntry.getQueueEntry().getPatientQueueNumber(), nullValue()); + } + + @Test + public void shouldNotOverwriteAVisitNumberIfNoProcessorsAreSpecified() { + testPatientQueueNumberGenerator.setProcessorToUse(null); + VisitQueueEntry visitQueueEntry = newVisitQueueEntry(); + visitQueueEntry.getQueueEntry().setPatientQueueNumber("A1000"); + visitQueueEntryService.createVisitQueueEntry(visitQueueEntry); + visitQueueEntry = visitQueueEntryService.getVisitQueueEntryByUuid(visitQueueEntryUuid).get(); + assertThat(visitQueueEntry.getQueueEntry().getPatientQueueNumber(), equalTo("A1000")); + } + + @Test + public void shouldGenerateABasicVisitNumberIfProcessorIsSpecified() { + testPatientQueueNumberGenerator.setProcessorToUse(basicPatientQueueNumberGenerator); + visitQueueEntryService.createVisitQueueEntry(newVisitQueueEntry()); + VisitQueueEntry visitQueueEntry = visitQueueEntryService.getVisitQueueEntryByUuid(visitQueueEntryUuid).get(); + assertThat(visitQueueEntry.getQueueEntry().getPatientQueueNumber(), + equalTo(Integer.toString(visitQueueEntry.getId()))); + } + + @Test + public void shouldGenerateAVisitAttributeVisitNumberIfProcessorIsSpecified() { + testPatientQueueNumberGenerator.setProcessorToUse(visitAttributeQueueNumberGenerator); + visitQueueEntryService.createVisitQueueEntry(newVisitQueueEntry()); + VisitQueueEntry visitQueueEntry = visitQueueEntryService.getVisitQueueEntryByUuid(visitQueueEntryUuid).get(); + assertThat(visitQueueEntry.getQueueEntry().getPatientQueueNumber(), equalTo("TRI-002")); + assertThat(visitQueueEntry.getVisit().getAttributes().iterator().next().getValueReference(), equalTo("TRI-002")); + } + + @Test + public void shouldGenerateVisitAttributeVisitNumberForConsultation() { + QueueEntry queueEntry = queueEntryService.getQueueEntryByUuid("7ub8fe43-2813-4kbc-80dc-2e5d30252cc5").get(); + assertThat(queueEntry.getQueue().getLocation().getUuid(), equalTo("d0938432-1691-11df-97a5-7038c098")); + Visit visit = new Visit(); + visit.setPatient(queueEntry.getPatient()); + VisitQueueEntry visitQueueEntry = new VisitQueueEntry(); + visitQueueEntry.setQueueEntry(queueEntry); + visitQueueEntry.setVisit(visit); + visitAttributeQueueNumberGenerator.beforeSaveVisitQueueEntry(visitQueueEntry); + String queueNumber = visitQueueEntry.getVisit().getAttributes().iterator().next().getValueReference(); + assertThat(queueNumber, notNullValue()); + assertThat(queueNumber, equalTo("CON-001")); + } +} diff --git a/api/src/test/resources/org/openmrs/module/queue/api/dao/QueueEntryDaoTest_conceptsInitialDataset.xml b/api/src/test/resources/org/openmrs/module/queue/api/dao/QueueEntryDaoTest_conceptsInitialDataset.xml index fcdcad6..e74703b 100644 --- a/api/src/test/resources/org/openmrs/module/queue/api/dao/QueueEntryDaoTest_conceptsInitialDataset.xml +++ b/api/src/test/resources/org/openmrs/module/queue/api/dao/QueueEntryDaoTest_conceptsInitialDataset.xml @@ -13,8 +13,8 @@ - - + + diff --git a/omod/src/main/java/org/openmrs/module/queue/web/resources/QueueEntryNumberResource.java b/omod/src/main/java/org/openmrs/module/queue/web/resources/QueueEntryNumberResource.java deleted file mode 100644 index 9b967bf..0000000 --- a/omod/src/main/java/org/openmrs/module/queue/web/resources/QueueEntryNumberResource.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public License, - * v. 2.0. If a copy of the MPL was not distributed with this file, You can - * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under - * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. - * - * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS - * graphic logo is a trademark of OpenMRS Inc. - */ -package org.openmrs.module.queue.web.resources; - -import java.util.Arrays; -import java.util.Optional; - -import org.openmrs.Location; -import org.openmrs.Visit; -import org.openmrs.VisitAttributeType; -import org.openmrs.api.context.Context; -import org.openmrs.module.queue.api.QueueEntryService; -import org.openmrs.module.queue.api.QueueService; -import org.openmrs.module.queue.model.Queue; -import org.openmrs.module.queue.web.resources.custom.response.GenericSingleObjectResult; -import org.openmrs.module.queue.web.resources.custom.response.PropValue; -import org.openmrs.module.queue.web.resources.custom.response.QueueEntryNumber; -import org.openmrs.module.webservices.rest.SimpleObject; -import org.openmrs.module.webservices.rest.web.RequestContext; -import org.openmrs.module.webservices.rest.web.RestConstants; -import org.openmrs.module.webservices.rest.web.annotation.Resource; -import org.openmrs.module.webservices.rest.web.representation.Representation; -import org.openmrs.module.webservices.rest.web.resource.api.PageableResult; -import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource; -import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription; -import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException; -import org.openmrs.module.webservices.rest.web.response.ResponseException; - -@Resource(name = RestConstants.VERSION_1 - + "/queue-entry-number", supportedClass = QueueEntryNumber.class, supportedOpenmrsVersions = { "2.3 - 9.*" }) -public class QueueEntryNumberResource extends DelegatingCrudResource { - - @Override - public SimpleObject getByUniqueId(String uuid) { - throw new ResourceDoesNotSupportOperationException(); - } - - @Override - protected void delete(SimpleObject simpleObject, String s, RequestContext requestContext) throws ResponseException { - throw new ResourceDoesNotSupportOperationException(); - } - - @Override - public SimpleObject newDelegate() { - return new SimpleObject(); - } - - @Override - public SimpleObject save(SimpleObject simpleObject) { - throw new ResourceDoesNotSupportOperationException(); - } - - @Override - public void purge(SimpleObject simpleObject, RequestContext requestContext) throws ResponseException { - throw new ResourceDoesNotSupportOperationException(); - } - - @Override - public DelegatingResourceDescription getRepresentationDescription(Representation representation) { - return null; - } - - @Override - protected PageableResult doSearch(RequestContext requestContext) { - Location location = requestContext.getParameter("location") != null - ? Context.getLocationService().getLocationByUuid(requestContext.getParameter("location")) - : null; - Visit visit = requestContext.getParameter("visit") != null - ? Context.getVisitService().getVisitByUuid(requestContext.getParameter("visit")) - : null; - VisitAttributeType visitAttributeType = requestContext.getParameter("visitAttributeType") != null - ? Context.getVisitService().getVisitAttributeTypeByUuid(requestContext.getParameter("visitAttributeType")) - : null; - Optional queueOptional = Context.getService(QueueService.class) - .getQueueByUuid(requestContext.getParameter("queue")); - Queue queue = null; - if (queueOptional.isPresent()) { - queue = queueOptional.get(); - } - String visitQueueNumber = Context.getService(QueueEntryService.class).generateVisitQueueNumber(location, queue, - visit, visitAttributeType); - - return new GenericSingleObjectResult(Arrays.asList(new PropValue("serviceType", queue.getName()), - new PropValue("visitQueueNumber", visitQueueNumber))); - - } -}