diff --git a/api-tests/pom.xml b/api-tests/pom.xml
index 7e231352a..786767c64 100644
--- a/api-tests/pom.xml
+++ b/api-tests/pom.xml
@@ -61,6 +61,10 @@
org.openmrs.module
providermanagement-api
+
+ org.bahmni.module
+ appointments-api
+
org.openmrs.test
openmrs-test
diff --git a/api-tests/src/test/java/org/openmrs/module/htmlformentry/AppointmentsTagTest.java b/api-tests/src/test/java/org/openmrs/module/htmlformentry/AppointmentsTagTest.java
new file mode 100644
index 000000000..8f6f99c16
--- /dev/null
+++ b/api-tests/src/test/java/org/openmrs/module/htmlformentry/AppointmentsTagTest.java
@@ -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 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 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 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 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 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 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();
+ }
+}
diff --git a/api-tests/src/test/resources/test-hibernate.cfg.xml b/api-tests/src/test/resources/test-hibernate.cfg.xml
index a237592da..e99851903 100644
--- a/api-tests/src/test/resources/test-hibernate.cfg.xml
+++ b/api-tests/src/test/resources/test-hibernate.cfg.xml
@@ -5,6 +5,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/api/pom.xml b/api/pom.xml
index bb0f99977..b79f82cbd 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -45,6 +45,11 @@
org.openmrs.module
providermanagement-api
+
+ org.bahmni.module
+ appointments-api
+
+
diff --git a/api/src/main/java/org/openmrs/module/htmlformentry/FormEntryContext.java b/api/src/main/java/org/openmrs/module/htmlformentry/FormEntryContext.java
index 4690f8885..1ad95633a 100644
--- a/api/src/main/java/org/openmrs/module/htmlformentry/FormEntryContext.java
+++ b/api/src/main/java/org/openmrs/module/htmlformentry/FormEntryContext.java
@@ -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
*
diff --git a/api/src/main/java/org/openmrs/module/htmlformentry/FormEntrySession.java b/api/src/main/java/org/openmrs/module/htmlformentry/FormEntrySession.java
index baadf0542..374eb96a2 100644
--- a/api/src/main/java/org/openmrs/module/htmlformentry/FormEntrySession.java
+++ b/api/src/main/java/org/openmrs/module/htmlformentry/FormEntrySession.java
@@ -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;
@@ -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()) {
diff --git a/api/src/main/java/org/openmrs/module/htmlformentry/FormSubmissionActions.java b/api/src/main/java/org/openmrs/module/htmlformentry/FormSubmissionActions.java
index d74cdcf2c..c42b96a59 100644
--- a/api/src/main/java/org/openmrs/module/htmlformentry/FormSubmissionActions.java
+++ b/api/src/main/java/org/openmrs/module/htmlformentry/FormSubmissionActions.java
@@ -79,6 +79,10 @@ public class FormSubmissionActions {
private List identifiersToVoid = new Vector();
+ private List
+
+ org.bahmni.module
+ appointments-api
+ 2.0.0-SNAPSHOT
+ provided
+
org.codehaus.jackson
jackson-mapper-asl