Skip to content

Commit

Permalink
HTML-842: Add Appointments tag (#302)
Browse files Browse the repository at this point in the history
  • Loading branch information
mogoodrich authored May 24, 2024
1 parent 12d3f5a commit aa38901
Show file tree
Hide file tree
Showing 20 changed files with 689 additions and 12 deletions.
4 changes: 4 additions & 0 deletions api-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
<groupId>org.openmrs.module</groupId>
<artifactId>providermanagement-api</artifactId>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>appointments-api</artifactId>
</dependency>
<dependency>
<groupId>org.openmrs.test</groupId>
<artifactId>openmrs-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
package org.openmrs.module.htmlformentry;

import java.util.Date;
import java.util.Map;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openmrs.api.context.Context;
import org.openmrs.module.appointments.model.Appointment;
import org.openmrs.module.appointments.model.AppointmentStatus;
import org.openmrs.module.appointments.service.AppointmentsService;
import org.springframework.mock.web.MockHttpServletRequest;

public class AppointmentsTagTest extends BaseHtmlFormEntryTest {

@Before
public void loadTestData() throws Exception {
executeVersionedDataSet("org/openmrs/module/htmlformentry/data/RegressionTest-data-openmrs-2.3.xml");
executeVersionedDataSet("org/openmrs/module/htmlformentry/data/appointmentCheckInTest.xml");
}

@Test
public void testAppointmentCheckInTag_shouldDisplayCheckboxesForScheduledAppointmentsForPatient() throws Exception {
new RegressionTestHelper() {

@Override
public String getFormName() {
return "appointmentCheckInForm";
}

@Override
public String[] widgetLabels() {
return new String[] { "Date:", "Location:", "Provider:", "Appointments:" };
}

@Override
public void testBlankFormHtml(String html) {
TestUtil.assertFuzzyContains("value=\"05f2ad92-1cc8-4cec-bf54-9cac0200746d\"/>", html);
TestUtil.assertFuzzyContains("2024-08-16, 13:00:00 - of Cos, Hippocrates - Never Never Land", html);
TestUtil.assertFuzzyContains("value=\"75504r42-3ca8-11e3-bf2b-0800271c1111\"/>", html);
TestUtil.assertFuzzyContains("2024-08-15, 12:00:00 - of Cos, Hippocrates - Xanadu", html);
}
}.run();
}

@Test
public void testAppointmentCheckInTag_shouldCheckPatientInForSingleAppointment() throws Exception {
final Date date = new Date();
new RegressionTestHelper() {

@Override
public String getFormName() {
return "appointmentCheckInForm";
}

@Override
public String[] widgetLabels() {
return new String[] { "Date:", "Location:", "Provider:", "Appointments:" };
}

@Override
public void setupRequest(MockHttpServletRequest request, Map<String, String> widgets) {
request.setParameter(widgets.get("Date:"), dateAsString(date));
request.setParameter(widgets.get("Location:"), "2");
request.setParameter(widgets.get("Provider:"), "502");
request.setParameter(widgets.get("Appointments:"), "05f2ad92-1cc8-4cec-bf54-9cac0200746d");
}

@Override
public void testResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();
Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment1.getFulfillingEncounters().stream().findFirst().get());

// just confirm the other appointment has not been checked in or linked to the encounter
Appointment appointment2 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("75504r42-3ca8-11e3-bf2b-0800271c1111");
Assert.assertEquals(AppointmentStatus.Scheduled, appointment2.getStatus());
Assert.assertEquals(0, appointment2.getFulfillingEncounters().size());
}
}.run();
}

@Test
public void testAppointmentCheckInTag_shouldCheckPatientInForMultipleAppointments() throws Exception {
final Date date = new Date();
new RegressionTestHelper() {

@Override
public String getFormName() {
return "appointmentCheckInForm";
}

@Override
public String[] widgetLabels() {
return new String[] { "Date:", "Location:", "Provider:", "Appointments:" };
}

@Override
public void setupRequest(MockHttpServletRequest request, Map<String, String> widgets) {
request.setParameter(widgets.get("Date:"), dateAsString(date));
request.setParameter(widgets.get("Location:"), "2");
request.setParameter(widgets.get("Provider:"), "502");
request.setParameter(widgets.get("Appointments:"), "05f2ad92-1cc8-4cec-bf54-9cac0200746d");
request.setParameter(widgets.get("Appointments:").replace("_1", "_2"),
"75504r42-3ca8-11e3-bf2b-0800271c1111");
}

@Override
public void testResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();

Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment1.getFulfillingEncounters().stream().findFirst().get());

Appointment appointment2 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("75504r42-3ca8-11e3-bf2b-0800271c1111");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment2.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment2.getFulfillingEncounters().stream().findFirst().get());
}
}.run();
}

@Test
public void testAppointmentCheckInTag_editShouldDisassociateEncounterFromAppointmentAndAssociateNewEncounter()
throws Exception {
final Date date = new Date();
new RegressionTestHelper() {

@Override
public String getFormName() {
return "appointmentCheckInForm";
}

@Override
public String[] widgetLabels() {
return new String[] { "Date:", "Location:", "Provider:", "Appointments:" };
}

@Override
public void setupRequest(MockHttpServletRequest request, Map<String, String> widgets) {
request.setParameter(widgets.get("Date:"), dateAsString(date));
request.setParameter(widgets.get("Location:"), "2");
request.setParameter(widgets.get("Provider:"), "502");
request.setParameter(widgets.get("Appointments:"), "05f2ad92-1cc8-4cec-bf54-9cac0200746d");
}

@Override
public boolean doEditEncounter() {
return true;
}

@Override
public String[] widgetLabelsForEdit() {
return new String[] { "Appointments:" };
}

public void setupEditRequest(MockHttpServletRequest request, Map<String, String> widgets) {
request.setParameter(widgets.get("Appointments:"), "");
request.setParameter(widgets.get("Appointments:").replace("_1", "_2"),
"75504r42-3ca8-11e3-bf2b-0800271c1111");
}

@Override
public void testResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();

// sanity check
Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment1.getFulfillingEncounters().stream().findFirst().get());

Appointment appointment2 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("75504r42-3ca8-11e3-bf2b-0800271c1111");
Assert.assertEquals(AppointmentStatus.Scheduled, appointment2.getStatus());
Assert.assertEquals(0, appointment2.getFulfillingEncounters().size());
}

// confirm that the associated appointment is now checked by default
@Override
public void testEditFormHtml(String html) {
TestUtil.assertFuzzyContains("value=\"05f2ad92-1cc8-4cec-bf54-9cac0200746d\" checked=\"true\"/>", html);
}

@Override
public void testEditedResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();

Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus()); // Note that we are NOT changing the status back to Scheduled
Assert.assertEquals(0, appointment1.getFulfillingEncounters().size()); // but encounter should be removed

Appointment appointment2 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("75504r42-3ca8-11e3-bf2b-0800271c1111");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment2.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment2.getFulfillingEncounters().stream().findFirst().get());
}
}.run();
}

@Test
public void testAppointmentCheckInTag_editingFormWithoutChangingStatusShouldNotCauseError() throws Exception {
final Date date = new Date();
new RegressionTestHelper() {

@Override
public String getFormName() {
return "appointmentCheckInForm";
}

@Override
public String[] widgetLabels() {
return new String[] { "Date:", "Location:", "Provider:", "Appointments:" };
}

@Override
public void setupRequest(MockHttpServletRequest request, Map<String, String> widgets) {
request.setParameter(widgets.get("Date:"), dateAsString(date));
request.setParameter(widgets.get("Location:"), "2");
request.setParameter(widgets.get("Provider:"), "502");
request.setParameter(widgets.get("Appointments:"), "05f2ad92-1cc8-4cec-bf54-9cac0200746d");
}

@Override
public boolean doEditEncounter() {
return true;
}

@Override
public String[] widgetLabelsForEdit() {
return new String[] { "Appointments:" };
}

public void setupEditRequest(MockHttpServletRequest request, Map<String, String> widgets) {
// upon edit keep the same checked
request.setParameter(widgets.get("Appointments:"), "05f2ad92-1cc8-4cec-bf54-9cac0200746d");
}

@Override
public void testResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();

// sanity check
Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment1.getFulfillingEncounters().stream().findFirst().get());
}

@Override
public void testEditedResults(SubmissionResults results) {
results.assertNoErrors();
results.assertEncounterCreated();

Appointment appointment1 = Context.getService(AppointmentsService.class)
.getAppointmentByUuid("05f2ad92-1cc8-4cec-bf54-9cac0200746d");
Assert.assertEquals(AppointmentStatus.CheckedIn, appointment1.getStatus());
Assert.assertEquals(results.getEncounterCreated(),
appointment1.getFulfillingEncounters().stream().findFirst().get());
}
}.run();
}
}
9 changes: 9 additions & 0 deletions api-tests/src/test/resources/test-hibernate.cfg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

<hibernate-configuration>
<session-factory>
<mapping resource="AppointmentServiceDefinition.hbm.xml"/>
<mapping resource="Speciality.hbm.xml"/>
<mapping resource="ServiceWeeklyAvailability.hbm.xml"/>
<mapping resource="Appointment.hbm.xml"/>
<mapping resource="AppointmentServiceType.hbm.xml"/>
<mapping resource="AppointmentAudit.hbm.xml"/>
<mapping resource="AppointmentProvider.hbm.xml"/>
<mapping resource="AppointmentRecurringPattern.hbm.xml"/>

<mapping resource="HtmlFormEntryHtmlForm.hbm.xml" />
<mapping resource="MetadataSource.hbm.xml"/>
<mapping resource="MetadataTermMapping.hbm.xml"/>
Expand Down
5 changes: 5 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
<groupId>org.openmrs.module</groupId>
<artifactId>providermanagement-api</artifactId>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>appointments-api</artifactId>
</dependency>


<!-- jars required only to run test scripts (scope=test) -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,26 +146,40 @@ public Mode getMode() {
private Integer sequenceNextVal = 1;

/**
* Registers a widget within the Context
* Registers a widget within the Context If a field id is passed in, register with that field id,
* otherwise generate a unique field id using a sequence number and appending 'w' to the front
* (Generally you do not want to pass in a field id, but rather defer to this method to generate one
* for you)
*
* @param widget the widget to register
* @return the field id used to identify this widget in the HTML Form
*/
public String registerWidget(Widget widget) {
public String registerWidget(Widget widget, String fieldName) {
if (fieldNames.containsKey(widget))
throw new IllegalArgumentException("This widget is already registered");
int thisVal = 0;
synchronized (sequenceNextVal) {
thisVal = sequenceNextVal;
sequenceNextVal = sequenceNextVal + 1;

if (StringUtils.isBlank(fieldName)) {
int thisVal = 0;
synchronized (sequenceNextVal) {
thisVal = sequenceNextVal;
sequenceNextVal = sequenceNextVal + 1;
}
fieldName = "w" + thisVal;
}
String fieldName = "w" + thisVal;

fieldNames.put(widget, fieldName);
if (log.isTraceEnabled())
log.trace("Registered widget " + widget.getClass() + " as " + fieldName);
return fieldName;
}

/**
* Registers a widget within the Context, generating a unique field id
*/
public String registerWidget(Widget widget) {
return registerWidget(widget, null);
}

/**
* Registers an error widget within the Context
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.openmrs.api.ObsService;
import org.openmrs.api.context.Context;
import org.openmrs.module.htmlformentry.FormEntryContext.Mode;
import org.openmrs.module.htmlformentry.appointment.AppointmentsAbstractor;
import org.openmrs.module.htmlformentry.property.ExitFromCareProperty;
import org.openmrs.module.htmlformentry.velocity.VelocityContextContentProvider;
import org.openmrs.module.htmlformentry.widget.AutocompleteWidget;
Expand Down Expand Up @@ -636,6 +637,17 @@ public void applyActions() throws BadFormDesignException {
}
}

// handle appointments (needs to happen after encounter is saved?)
if (submissionActions.getAppointmentsToMarkCheckedInAndAssociateWithEncounter() != null) {
new AppointmentsAbstractor().markAppointmentsAsCheckedInAndAssociateWithEncounter(
submissionActions.getAppointmentsToMarkCheckedInAndAssociateWithEncounter(), encounter);
}

if (submissionActions.getAppointmentsToDisassociateFromEncounter() != null) {
new AppointmentsAbstractor().disassociateAppointmentsFromEncounter(
submissionActions.getAppointmentsToDisassociateFromEncounter(), encounter);
}

//deal with relationships
if (submissionActions.getRelationshipsToCreate() != null) {
for (Relationship r : submissionActions.getRelationshipsToCreate()) {
Expand Down
Loading

0 comments on commit aa38901

Please sign in to comment.