Skip to content

Commit fc02c6f

Browse files
authored
HTML-885: Add a way to input provider obs with autocomplete search (#337)
* HTML-885: Add a way to input provider obs with autocomplete search * add comment * change to throwing BadFormDesignException
1 parent 3c0cce4 commit fc02c6f

6 files changed

Lines changed: 83 additions & 38 deletions

File tree

api-tests/src/test/java/org/openmrs/module/htmlformentry/HtmlFormEntryUtilTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,21 @@ public void stringToDocument_shouldNotAccessFilesystemResources() throws java.io
11141114

11151115
}
11161116

1117+
@Test
1118+
@Verifies(value = "shouldSetValueTextToProviderIdGivenAProvider", method = "createObs(Concept concept, Object value, Date datetime, String accessionNumber)")
1119+
public void createObs_shouldSetValueTextToProviderIdGivenAProvider() {
1120+
Provider provider = new Provider();
1121+
provider.setId(42);
1122+
1123+
Concept c = new Concept();
1124+
ConceptDatatype cd = new ConceptDatatype();
1125+
cd.setUuid("8d4a4ab4-c2cc-11de-8d13-0010c6dffd0f");
1126+
c.setDatatype(cd);
1127+
1128+
Obs o = HtmlFormEntryUtil.createObs(c, provider, null, null);
1129+
Assert.assertEquals("42", o.getValueText());
1130+
}
1131+
11171132
@Test
11181133
@Verifies(value = "shouldSetTheValueComplexOfObsIfConceptIsComplex", method = "createObs(Concept concept, Object value, Date datetime, String accessionNumber)")
11191134
public void createObs_shouldSetTheValueComplexOfObsIfConceptIsComplex() {

api-tests/src/test/java/org/openmrs/module/htmlformentry/element/ObsSubmissionElementTest.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.openmrs.ConceptNumeric;
3838
import org.openmrs.api.ConceptNameType;
3939
import org.openmrs.api.context.Context;
40+
import org.openmrs.module.htmlformentry.BadFormDesignException;
4041
import org.openmrs.module.htmlformentry.FormEntryContext;
4142
import org.openmrs.module.htmlformentry.HtmlFormEntryUtil;
4243
import org.openmrs.module.htmlformentry.TestUtil;
@@ -84,7 +85,7 @@ public void tearDown() {
8485
}
8586

8687
@Test
87-
public void testShowUnitsUsingTrue() {
88+
public void testShowUnitsUsingTrue() throws Exception {
8889
ConceptDatatype numeric = new ConceptDatatype();
8990
numeric.setUuid(ConceptDatatype.NUMERIC_UUID);
9091

@@ -106,7 +107,7 @@ public void testShowUnitsUsingTrue() {
106107

107108
@Test
108109
@Ignore
109-
public void testShowUnitsUsingCode() {
110+
public void testShowUnitsUsingCode() throws Exception {
110111
ConceptDatatype numeric = new ConceptDatatype();
111112
numeric.setUuid(ConceptDatatype.NUMERIC_UUID);
112113

@@ -211,31 +212,31 @@ public void testForcingLocaleOnRadioLabels() throws Exception {
211212
}
212213

213214
@Test(expected = RuntimeException.class)
214-
public void testNoConceptId_shouldThrowException() {
215+
public void testNoConceptId_shouldThrowException() throws Exception {
215216
new ObsSubmissionElement(context, params);
216217
}
217218

218219
@Test(expected = RuntimeException.class)
219-
public void testDuplicateConceptIds_shouldThrowException() {
220+
public void testDuplicateConceptIds_shouldThrowException() throws Exception {
220221
params.put("conceptId", "1");
221222
params.put("conceptIds", "2");
222223
new ObsSubmissionElement(context, params);
223224
}
224225

225226
@Test(expected = RuntimeException.class)
226-
public void testInvalidConceptIds_shouldThrowException() {
227+
public void testInvalidConceptIds_shouldThrowException() throws Exception{
227228
params.put("conceptIds", "adas,asda");
228229
new ObsSubmissionElement(context, params);
229230
}
230231

231232
@Test(expected = RuntimeException.class)
232-
public void testEmptyConceptIds_shouldThrowException() {
233+
public void testEmptyConceptIds_shouldThrowException() throws Exception {
233234
params.put("conceptIds", "");
234235
new ObsSubmissionElement(context, params);
235236
}
236237

237238
@Test(expected = RuntimeException.class)
238-
public void testInvalidAnswerConceptIds_shouldThrowException() {
239+
public void testInvalidAnswerConceptIds_shouldThrowException() throws Exception {
239240
params.put("answerConceptIds", "adas,asda");
240241
new ObsSubmissionElement(context, params);
241242
}

api/src/main/java/org/openmrs/module/htmlformentry/HtmlFormEntryUtil.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ public static Obs createObs(Concept concept, Object value, Date datetime, String
282282
} else if (value instanceof Person) {
283283
Person person = (Person) value;
284284
obs.setValueText(person.getId().toString() + " - " + person.getPersonName().toString());
285+
} else if (value instanceof Provider) {
286+
obs.setValueText(((Provider) value).getId().toString());
285287
} else {
286288
obs.setValueText(value.toString());
287289
}

api/src/main/java/org/openmrs/module/htmlformentry/element/ObsReferenceSubmissionElement.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.openmrs.Obs;
1313
import org.openmrs.Person;
1414
import org.openmrs.api.context.Context;
15+
import org.openmrs.module.htmlformentry.BadFormDesignException;
1516
import org.openmrs.module.htmlformentry.FormEntryContext;
1617
import org.openmrs.module.htmlformentry.HtmlFormEntryConstants;
1718
import org.openmrs.module.htmlformentry.HtmlFormEntryUtil;
@@ -37,7 +38,7 @@ public class ObsReferenceSubmissionElement extends ObsSubmissionElement<FormEntr
3738

3839
private String tooltipTemplate = "({{encounterType}} on {{encounterDate}})";
3940

40-
public ObsReferenceSubmissionElement(FormEntryContext context, Map<String, String> parameters) {
41+
public ObsReferenceSubmissionElement(FormEntryContext context, Map<String, String> parameters) throws BadFormDesignException {
4142

4243
super(context, parameters);
4344

api/src/main/java/org/openmrs/module/htmlformentry/element/ObsSubmissionElement.java

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.openmrs.Role;
1616
import org.openmrs.Visit;
1717
import org.openmrs.api.context.Context;
18+
import org.openmrs.module.htmlformentry.BadFormDesignException;
1819
import org.openmrs.module.htmlformentry.FormEntryContext;
1920
import org.openmrs.module.htmlformentry.FormEntryContext.Mode;
2021
import org.openmrs.module.htmlformentry.FormEntrySession;
@@ -30,8 +31,10 @@
3031
import org.openmrs.module.htmlformentry.widget.ConceptSearchAutocompleteWidget;
3132
import org.openmrs.module.htmlformentry.widget.DateTimeWidget;
3233
import org.openmrs.module.htmlformentry.widget.DateWidget;
34+
import org.openmrs.module.htmlformentry.util.MatchMode;
3335
import org.openmrs.module.htmlformentry.widget.DropdownWidget;
3436
import org.openmrs.module.htmlformentry.widget.DynamicAutocompleteWidget;
37+
import org.openmrs.module.htmlformentry.widget.ProviderAjaxAutoCompleteWidget;
3538
import org.openmrs.module.htmlformentry.widget.ErrorWidget;
3639
import org.openmrs.module.htmlformentry.widget.NumberFieldWidget;
3740
import org.openmrs.module.htmlformentry.widget.Option;
@@ -163,7 +166,7 @@ public class ObsSubmissionElement<T extends FormEntryContext> implements HtmlGen
163166

164167
private String tagControlId;
165168

166-
public ObsSubmissionElement(T context, Map<String, String> parameters) {
169+
public ObsSubmissionElement(T context, Map<String, String> parameters) throws BadFormDesignException {
167170
if (parameters.get("locale") != null) {
168171
this.locale = LocaleUtility.fromSpecification(parameters.get("locale"));
169172
}
@@ -241,7 +244,7 @@ else if (conceptId == null && conceptIds == null)
241244
isLocationObs = "location".equals(parameters.get("style")) || "location_radio".equals(parameters.get("style"))
242245
|| "location_dropdown".equals(parameters.get("style"));
243246
isProviderObs = "provider".equals(parameters.get("style")) || "provider_radio".equals(parameters.get("style"))
244-
|| "provider_dropdown".equals(parameters.get("style"));
247+
|| "provider_dropdown".equals(parameters.get("style")) || "provider_autocomplete".equals(parameters.get("style"));
245248
isRadioSet = "radio".equals(parameters.get("style")) || "location_radio".equals(parameters.get("style"))
246249
|| "provider_radio".equals(parameters.get("style"));
247250

@@ -273,7 +276,7 @@ private Widget buildDropdownWidget(Integer size) {
273276
return dropdownWidget;
274277
}
275278

276-
private void prepareWidgets(T context, Map<String, String> parameters) {
279+
private void prepareWidgets(T context, Map<String, String> parameters) throws BadFormDesignException {
277280
String userLocaleStr = locale.toString();
278281
try {
279282
if (answerConcept == null)
@@ -565,40 +568,55 @@ private void prepareWidgets(T context, Map<String, String> parameters) {
565568
}
566569
// configure the special obs type that allows selection of a provider (the provider_id PK is stored as the valueText)
567570
else if (isProviderObs) {
568-
if (isRadioSet) {
569-
valueWidget = new RadioButtonsWidget();
570-
if (answerSeparator != null) {
571-
((RadioButtonsWidget) valueWidget).setAnswerSeparator(answerSeparator);
572-
}
573-
} else { // dropdown
574-
valueWidget = new DropdownWidget();
575-
// if initialValueIsSet=false, no initial/default location, hence this shows the 'select input' field as first option
576-
boolean initialValueIsSet = !(initialValue == null);
577-
((SingleOptionWidget) valueWidget).addOption(
578-
new Option(Context.getMessageSourceService().getMessage("htmlformentry.chooseAProvider"), "",
579-
!initialValueIsSet));
580-
}
581571
List<String> roleIds = new ArrayList<>();
582572
String roleParam = parameters.get("providerRoles");
583573
if (StringUtils.isNotBlank(roleParam)) {
584574
for (String roleId : roleParam.split(",")) {
585575
roleIds.add(roleId.trim());
586576
}
587577
}
588-
List<Provider> providers = HtmlFormEntryUtil.getProviders(roleIds, true);
589-
590-
List<Option> providerOptions = new ArrayList<>();
591-
for (Provider provider : providers) {
592-
String providerId = provider.getId().toString();
593-
String label = HtmlFormEntryUtil.format(provider);
594-
Option option = new Option(label, providerId, providerId.equals(initialValue));
595-
providerOptions.add(option);
596-
}
597-
Collections.sort(providerOptions, new OptionComparator());
598-
599-
if (!providerOptions.isEmpty()) {
600-
for (Option option : providerOptions) {
601-
((SingleOptionWidget) valueWidget).addOption(option);
578+
if ("provider_autocomplete".equals(parameters.get("style"))) {
579+
MatchMode matchMode = MatchMode.ANYWHERE;
580+
if (StringUtils.isNotBlank(parameters.get("providerMatchMode"))) {
581+
try {
582+
matchMode = MatchMode.valueOf(parameters.get("providerMatchMode").toUpperCase());
583+
}
584+
catch (Exception e) {
585+
throw new BadFormDesignException(
586+
"Invalid providerMatchMode '" + parameters.get("providerMatchMode")
587+
+ "'. Valid values are: " + Arrays.toString(MatchMode.values()), e);
588+
}
589+
}
590+
valueWidget = new ProviderAjaxAutoCompleteWidget(matchMode, roleIds);
591+
} else {
592+
if (isRadioSet) {
593+
valueWidget = new RadioButtonsWidget();
594+
if (answerSeparator != null) {
595+
((RadioButtonsWidget) valueWidget).setAnswerSeparator(answerSeparator);
596+
}
597+
} else { // dropdown
598+
valueWidget = new DropdownWidget();
599+
// if initialValueIsSet=false, no initial/default location, hence this shows the 'select input' field as first option
600+
boolean initialValueIsSet = !(initialValue == null);
601+
((SingleOptionWidget) valueWidget).addOption(
602+
new Option(Context.getMessageSourceService().getMessage("htmlformentry.chooseAProvider"), "",
603+
!initialValueIsSet));
604+
}
605+
List<Provider> providers = HtmlFormEntryUtil.getProviders(roleIds, true);
606+
607+
List<Option> providerOptions = new ArrayList<>();
608+
for (Provider provider : providers) {
609+
String providerId = provider.getId().toString();
610+
String label = HtmlFormEntryUtil.format(provider);
611+
Option option = new Option(label, providerId, providerId.equals(initialValue));
612+
providerOptions.add(option);
613+
}
614+
Collections.sort(providerOptions, new OptionComparator());
615+
616+
if (!providerOptions.isEmpty()) {
617+
for (Option option : providerOptions) {
618+
((SingleOptionWidget) valueWidget).addOption(option);
619+
}
602620
}
603621
}
604622
} else if ("person".equals(parameters.get("style"))) {

omod/src/main/java/org/openmrs/module/htmlformentry/web/controller/ProviderSearchController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ public Object getProviders(@RequestParam(value = "searchParam", required = false
3333

3434
List<Provider> providerList = HtmlFormEntryUtil.getProviders(providerRoleIds, true);
3535

36+
/*
37+
* A frontend bug makes it possible for the matchMode to be null, when the element is considered rendered with <controls>;
38+
* see HTML-887. In that case, we default to MatchMode.ANYWHERE.
39+
*/
40+
if (matchMode == null) {
41+
matchMode = MatchMode.ANYWHERE;
42+
}
43+
3644
List<ProviderStub> stubs;
3745
if (searchParam == null) {
3846
stubs = HtmlFormEntryUtil.getProviderStubs(providerList);

0 commit comments

Comments
 (0)