GSoC 2026: Patient Visit Summary Printing — Project Updates & Discussion

Hello everyone!

I’m Amrita, and I’ll be working on Patient Visit Summary Printing for OpenMRS O3 this summer as part of GSoC 2026. I’ll be using this thread to share weekly progress updates, ask questions, and have discussions throughout the project. Feel free to follow along, drop feedback, or just say hi :grinning_face_with_smiling_eyes:


What this project is about

Right now, if a clinician at an OpenMRS-powered facility wants a printed summary of a patient’s visit — for a referral, discharge, insurance, or just the patient’s own records — there’s no built-in way to generate one from O3.

This project adds that capability to the existing openmrs-module-patientdocuments module. The goal is a pluggable, configurable PDF pipeline that lets any deployment customize what shows up in their visit summaries without changing Java code.

How it works (high level)

The module uses an XML → XSLT → Apache FOP → PDF pipeline (same infrastructure the module already uses for patient ID stickers). Each section of the visit summary — vitals, diagnoses, allergies, medications, labs, visit notes — is a pluggable component that implements the VisitSummarySection SPI.

This means:

  • Deployers can toggle sections on/off via config

  • Deployers can customize which concepts appear (e.g. which vitals to include) without touching code

  • External modules (like a billing module) can plug in their own sections just by implementing the interface and registering a Spring bean

  • The XSLT stylesheet controls layout, so facilities can adjust page sizes (A4/A5/A6), add their logo, and customize formatting

Key goals

  • A working, production-ready visit summary PDF accessible from O3’s patient chart

  • Pluggable section architecture using Spring SPI (VisitSummarySectionTypedSection<T> → concrete sections)

  • Configurable via Initializer (concept references, section toggles, ordering)

  • Clinical safety: clear distinction between “no data recorded” and “data fetch failed” in the PDF output

  • Frontend print button integrated into O3’s visit detail view

Resources


Thank you to my mentors @wikumc and @nethmi, and to the community for all the support so far :yellow_heart:

Looking forward to a great summer of building and learning! :sunflower:

cc: @wikumc @nethmi @ibacher @dkayiwa @veronica @dennis @jayasanka @bawanthathilan @beryl

3 Likes

Community Bonding Period Update :books:

The community bonding period wraps up today and coding starts tomorrow, so here’s a quick look back at what these past few weeks looked like.

Dev environment setup

Got the module building and running locally on Windows + WSL2 + Docker with the O3 distro. Now I can build, deploy, and test PDF generation end-to-end!

About the very first PR of this project…

The architecture took shape through review. I raised my proof-of-concept as a draft PR early in the bonding period. It’s been through several rounds of review and the architecture evolved a lot through those discussions — the renderer went from hardcoding all section calls by name to a properly pluggable SPI where each section owns its own XML rendering. Along the way I also learned about using concept maps over hardcoded UUIDs, making clinical data lists extensible so different deployments can customize what shows up without touching code, and following existing module conventions for config keys. The PR is now out of draft and ready for review.

My biggest takeaway…?

Honestly, the most valuable learning came from the review discussions. One thing that really stuck with me was around error handling, I initially thought silently skipping a section when data fetching fails was graceful handling. But from a clinical perspective, there’s a huge difference between “this patient has no allergies” and “we couldn’t fetch the allergy data.” A clinician reading the PDF might assume it’s safe to prescribe something the patient is actually allergic to. That changed how I think about edge cases in healthcare software — every design decision carries real responsibility.

A note to my mentors​:yellow_heart:

A huge thank you to @wikumc and @nethmi for being incredibly patient and supportive throughout the bonding period. The reviews and discussions pushed me to think deeper, not just about making code work, but about why design decisions matter when the software is used in clinical settings. I’ve learned more in these few weeks than I expected, and I’m going to do my best to make this project something the community can genuinely use.

Now what’s next…?

Week 1 (May 25 – Jun 1): Addressing the remaining review feedback on the PR and working towards getting the first minimal working PDF merged — patient info + vitals with the full pipeline working end-to-end.

Excited to get building! :rocket:

2 Likes

@amrita21p Thank you for the updates. cc: @mmwanje @kmuiruri @fiona

1 Like

Week 1 Update — Addressing Review Feedback

The visit summary PDF pipeline PR went through code review this week. The main feedback was about making the module work across different OpenMRS deployments, not just the standard CIEL setup. Here’s what changed:

  • ConfigUtil over raw DB calls — switched to ConfigUtil.getProperty() for cached config lookups
  • Concept maps over UUIDs — replaced hardcoded UUIDs with concept map lookups (CIEL:5085 format via getConceptByMapping) so the module works at sites with non-standard concept dictionaries
  • Extensible vitals list — vitals shown on the PDF are now configurable via a single GP (report.visitSummary.vitals.concepts) instead of 7 hardcoded lines; added respiratory rate which was missing
  • Configurable section ordering — removed hardcoded @Order annotations; sections read their position from report.visitSummary.section.<key>.order
  • GP key naming — renamed keys to follow the module’s existing report.* convention
  • Units from ConceptNumeric — units come from the concept itself instead of being hardcoded

PR is updated and waiting for re-review: PR

Detailed blog post: GSOC 2026 Week 1

Thanks!

Week 2 Update — Closing the Circuit

The PR went through another review cycle this week. The architecture from last week got approved, so the focus shifted to correctness and clinical safety details:

  • Diagnosis filtering fix — replaced date-based filtering (which leaked diagnoses from other visits) with getDiagnosesByVisit(), which filters at the database level through encounter → visit. Added DiagnosesSectionTest to prove visit-scoping works.

  • Section-error rendering — the TypedSection error handler was emitting <section-error> XML correctly, but the XSLT never invoked the matching template (xsl:call-template vs xsl:apply-templates mismatch). Wired it so errors render in-context, right where the failed section would have appeared.

  • Empty facility header handling — wrapped facilityName/address/phone in xsl:if guards so empty values don’t leave blank lines in the PDF.

Also started researching the O3 frontend architecture for the print button — went through the existing sticker print code, extension slot registration, modal API, and i18n patterns. Discussing with mentors where the frontend code should live.

PR is in its final review cycle​:grinning_face_with_smiling_eyes:

Detailed blog post: GSoC 2026 Week 2

Thanks!

ConditionsSection for Visit Summary PDF — What should clinicians see?

Hi everyone!

I’m starting work on the ConditionsSection (O3-5670) for the visit summary PDF pipeline in openmrs-module-patientdocuments.

Context: The visit summary PDF already has sections for vitals, diagnoses, and allergies (PR #16, in final review). Conditions is the next section to implement.

The design question: In OpenMRS, conditions are patient-level data — they belong to the patient, not to a specific visit (unlike vitals or diagnoses which are tied to encounters within a visit). This is the same as how we handle allergies. So the section will show the patient’s conditions as part of their clinical picture at the time the summary is printed.

I have two questions about what a clinician would expect to see:

1. Status filter Should the section show only Active conditions, or should it also include Inactive and History-of conditions?

My default assumption: only Active conditions, since the visit summary is a snapshot of the patient’s current clinical state. But I can see an argument for including History-of if clinicians find that useful for context (e.g., a resolved TB diagnosis that’s still clinically relevant).

2. Chronicity The original mockup labeled this section “Chronic Conditions.” Should we filter to only chronic conditions, or include all active conditions regardless of whether they’re acute or chronic?

My default assumption: show all active conditions. A clinician printing a visit summary likely wants the full picture — an acute condition like pneumonia is just as relevant as a chronic one like hypertension. The section heading could simply be “Conditions” rather than “Chronic Conditions.”

Would love to hear about what makes the most clinical sense.

Thanks!

cc: @veronica @ibacher @wikumc @nethmi

2 Likes

@amrita21p Good progress and great questions.

The Visit Summary is most useful when it gives a clinician a quick, accurate picture of what’s currently relevant to the patient’s care, which argues for Active conditions.

That said, it’s worth recognising that some History-of conditions still influence current decisions (e.g., “History of MI” matters when prescribing; “History of TB” matters when interpreting a chest X-ray). In my view, though, including inactive conditions adds noise.

For the MVP, I’d settle with Active only, and expand if implementers ask for something else.

Curious what others think.

cc: @fanderson @robaikisia @kmuiruri please chime to help us better understand what implementations need.

1 Like

Thanks, @veronica! Sticking to Active conditions for the MVP makes total sense to keep the summary noise-free. I’ll go ahead and build it that way for now…we can always expand it later if other implementers request it :smiley:

Week 3 Update — First Merge and Community-Driven Design

The first PR got merged this week! :tada: After a few final review fixes (config failure handling, dead code cleanup, AllergiesSectionTest), the core visit summary pipeline is now in main. We have a working PDF with patient info, vitals, diagnoses, and allergies.

With that done, I moved on to the ConditionsSection (O3-5670). Based on the discussion earlier in this thread and feedback from the O3 squad call:

  • Active conditions only for the MVP, since inactive conditions are really past medical history and would be a separate section entirely
  • Section heading: “Conditions” not “Chronic Conditions,” since conditions can be acute too (e.g., pneumonia)
  • Include by default, make togglable — it’s easier to include something and let deployers turn it off than to leave it out and wait for someone to ask

Currently implementing. PR will be up soon!

Detailed blog post: GSoC 2026 Week 3

Thanks!