Skip to content

HTML-886: Add new tag to record appointment service as obs#338

Merged
chibongho merged 5 commits into
masterfrom
HTML-886
Jun 17, 2026
Merged

HTML-886: Add new tag to record appointment service as obs#338
chibongho merged 5 commits into
masterfrom
HTML-886

Conversation

@chibongho

Copy link
Copy Markdown
Contributor

See: https://openmrs.atlassian.net/browse/HTML-886

Adds a <AppointmentServiceObs> tag to record appointment service as obs.

@chibongho
chibongho requested review from cioan, mogoodrich and mseaton and removed request for mseaton June 10, 2026 19:08

@mogoodrich mogoodrich left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tests, to demo how this works?

What was the considering with adding this as a new tag, versus a "obs" with
"style='appointmentService'" (like we have for location with "style='location')

(If this had all been discussed and decided while I was on vacay, that's fine, but if it hasn't been discussed, worth a discussion)

throw new IllegalArgumentException("Could not find concept: " + conceptId);
}

existingObs = context.removeExistingObs(concept, (Concept) null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test/document what happens if you multiple of these tags on a single form with the same concept id. At minimum, I don't think it will be able to reproduce them in the same order on reload. We should likely add support for mapping via form namespace and path via the control Id as the obs tag does, see: https://openmrs.atlassian.net/browse/HTML-788 (or if we don't make a new tag but use the obs tag we should get this out of the box).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will handle the rendering order correctly if we have multiple of these tags. That said, do we need to worry about that? An appointment can only be associated with one appointment service, and adding multiple of these tags for the same appointment should be a form design error.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you could be scheduling multiple appointments (for different services) on this form, correct? Would that work? This also ties into my previous question about why we decided to make this a new tag (instead of a obs tag with style='appointment')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to put this tag in HFE, we should aim to support as many of the best-practice nuances that there are already established. I'm fine putting this in the ObsSubmissionElement, but I'm 100% convinced this functionality belongs in the HFE module at all (versus in pihcore, etc)

@chibongho

Copy link
Copy Markdown
Contributor Author

Can you add some tests, to demo how this works?

What was the considering with adding this as a new tag, versus a "obs" with "style='appointmentService'" (like we have for location with "style='location')

(If this had all been discussed and decided while I was on vacay, that's fine, but if it hasn't been discussed, worth a discussion)

Yeah, I can add some tests.

Speaking with @mseaton, I think the biggest motivation of having a separate tag is that <obs> is a bit of a kitchen sink with too many things in it.

@mogoodrich

Copy link
Copy Markdown
Member

Speaking with @mseaton, I think the biggest motivation of having a separate tag is that <obs> is a bit of a kitchen sink with too many things in it.

Ah, okay, that makes sense then--we can keep as a separate tag. I do think we may want to add support for "controlId" attribute, but why don't you start by adding some tests so I can understand it better and then we can discuss. @chibongho

@mseaton mseaton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good but see comments

public AppointmentServiceObsElement(FormEntryContext context, Map<String, String> parameters) {
String conceptId = parameters.get("conceptId");
if (conceptId == null) {
throw new IllegalArgumentException("appointmentServiceObs requires a conceptId parameter");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these IllegalArgumentException should probably be BadFormDesignException

throw new IllegalArgumentException("Could not find concept: " + conceptId);
}

existingObs = context.removeExistingObs(concept, (Concept) null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to put this tag in HFE, we should aim to support as many of the best-practice nuances that there are already established. I'm fine putting this in the ObsSubmissionElement, but I'm 100% convinced this functionality belongs in the HFE module at all (versus in pihcore, etc)

}

existingObs = context.removeExistingObs(concept, (Concept) null);
String existingUuid = existingObs != null ? existingObs.getValueText() : null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in your other active PR, you used provider id, here you are using uuid. I agree uuid is best, but why the inconsistency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change it to the "<id> - <serviceName>" format similar to Location and Person.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be okay with keeping this as-is as this is a new domain we are capturing... I was more concerned about, say, capturing providers using "uuid" in some cases and "id" in others.

StringBuilder sb = new StringBuilder();
sb.append(serviceWidget.generateHtml(context));
if (context.getMode() != Mode.VIEW) {
sb.append("<span class='required'>*</span>");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what this does? Will this always mark this type of question as required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It really ought to be required, but I haven't gotten a way to make it be conditionally required only if the user choose to create an appointment. What I have now is making this input technically optional in the backend, but have the subform here enforce the conditional requirement check via JS. Adding the <span> here is technically incorrect; I'll remove.

@chibongho
chibongho requested review from mogoodrich and mseaton June 16, 2026 21:12

serviceWidget.addOption(new Option("", "", false));
for (AppointmentServiceDefinition svc : services) {
serviceWidget.addOption(new Option(svc.getName(), svc.getId() + " - " + svc.getName(), false));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the more I think about it, this should be uuid, regardless of what the other objects are doing... when reloading an existing obs is this doing a full match and so would fail on edit if the text name of a service as was changed?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this should definitely be uuid. Is there no uuid on appointmentservicedefinition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is. I'll use uuid.


serviceWidget.addOption(new Option("", "", false));
for (AppointmentServiceDefinition svc : services) {
serviceWidget.addOption(new Option(svc.getName(), svc.getId() + " - " + svc.getName(), false));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this should definitely be uuid. Is there no uuid on appointmentservicedefinition?

@chibongho
chibongho requested review from mogoodrich and mseaton June 17, 2026 18:37
@chibongho
chibongho merged commit 40945b0 into master Jun 17, 2026
5 checks passed
@chibongho
chibongho deleted the HTML-886 branch June 17, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants