Promote a Diagnosis to a Condition in OpenMRS
Status: REQUIREMENTS IN PROGRESS IN PROGRESS
Technical Complexity: EASY MEDIUM HARD / COMPLEX
Summary:
Clinicians recording a diagnosis in the
Visit Notecurrently have to re-enter the same information in theConditions modulewhen the diagnosis is a long-term condition, or navigate there separately to update the status of an existing condition. This feature removes both round trips.Below the diagnosis chips in the Visit Note, an Add to conditions list panel shows each diagnosis with the action appropriate to its current state on the patient's Conditions list:
Not on the list → Add as active condition
On the list as Active → Mark as inactive (in remission)
On the list as Inactive → Mark as active again
Each action is a single click. The Conditions widget refreshes immediately, a confirmation snackbar appears with an Undo affordance, and the row updates to reflect the new state.
Onset date is left blank on promotion. The standard OpenmrsDatePicker is shown as an optional input, alongside a note that the diagnosis date isn't necessarily when the condition began.
Promote Flow Summary
1. Problem
A clinician in a busy outpatient clinic sees twelve patients before noon. Three are newly diagnosed with a lifelong condition like Type 2 Diabetes or Hypertension. For each, she documents the diagnosis in the Visit Note, then navigates to the Conditions module and re-types the same diagnosis so it appears on the patient's ongoing Conditions list. That is six entries for information captured three times. Over a week, the re-entry adds up, and when she is rushed, she sometimes skips the Conditions module altogether, leaving the record incomplete.
The same double-entry happens in reverse: a patient's known active condition often needs to be named again as an encounter diagnosis for today's visit. The Visit Note and the Conditions list are separate modules, but for a chronic problem they record the same clinical fact — the clinician should only have to enter it once, in either direction.
2. User Stories
Story 1: Add a diagnosis to the condition list
As a clinician, when I record a diagnosis in the Visit Note that is a lifelong condition, I want to add it to the patient's Conditions list from the diagnosis itself, so that I don't re-enter it in the Conditions module.
Each diagnosis renders as a pill with a ⋮ (overflow) menu.
The menu offers "Add to condition list"; one tap creates an active condition from that concept, with no further data entry.
Onset is left blank (see §5).
The Conditions widget refreshes instantly, a snackbar confirms with Undo, and the pill gains a ✓ badge.
Story 2: See at a glance whether a diagnosis is already on the list
As a clinician, when I record a diagnosis that is already on the patient's Conditions list, I want a clear cue on that diagnosis pill, so that I can tell at a glance it's a pre-existing condition rather than a new problem.
As each diagnosis is entered, a green ✓ badge appears on its pill if that concept is already on the Conditions list.
Detection uses an exact concept match, recomputed as diagnoses change (not stored).
Story 3: Add an existing condition as an encounter diagnosis (reverse)
As a clinician, I want to pull an existing active condition into today's note as an encounter diagnosis, so that I don't retype a problem the patient is already known to have.
A "Select from condition list" affordance beside the diagnosis search presents active conditions not already in the encounter's diagnoses.
Selecting one adds it as a diagnosis in two taps, reusing the note's existing add-diagnosis and save path.
Story 4: On-list diagnosis is read-only in the visit form
As a clinician, when a diagnosis is already on the Conditions list, I want the pill to show its current status without letting me edit it here, and to point me to the Conditions module for any change, so that status management stays in one place.
The pill's menu is read-only: "On condition list · Active" (or the relevant status), plus a "Manage in Conditions →" link.
No status editing happens inside the visit form.
3. Market Analysis
1: Bahmni: Diagnoses and Conditions appear together on the same screen rather than in separate modules. Bahmni doesn't separate Visit-Note diagnosis from Conditions-list management; the two coexist in one combined view without an explicit promote step.
OpenMRS Talk discussion. Community input on the proposal can be found here.
4. Scope for V1
In scope for V1
Pill + ⋮ overflow menu on each diagnosis (low-footprint UI).
"Add to condition list" → create as active, onset blank, one tap.
Green ✓ at-a-glance on-list badge.
Read-only on-list state + "Manage in Conditions →".
Reverse: "Select from condition list" → add as encounter diagnosis.
Instant Conditions-widget refresh, snackbar, Undo.
Exact concept match throughout.
Out of scope for V1
In-form condition status management (mark inactive / reactivate) — handled in the Conditions module.
Chronic/acute eligibility classification — needs concept-level metadata the fhir2 module doesn't expose.
Related-concept matching (e.g. "Exacerbation of COPD" → "COPD"). V1 is exact match only. Post-V1 could use SNOMED / CIEL SAME-AS maps.
Auto-promotion on save — nothing reaches the list without an explicit action.
Frontend: V1 work breakdown
Add to conditions list panel. Render one row per diagnosis chip in the Visit Note. Per-row state is determined by a single query:
GET /ws/fhir2/R4/Condition?patient={uuid}&category=problem-list-item&code={conceptUUID}. Three branches:No result → Add as active condition button. On click:
POST /Conditionwithcategory=problem-list-item,clinicalStatus=active,code={concept},subject={patient}, onset left blank.Result with
clinicalStatus=active→ Mark as inactive (in remission) button. On click:PATCH /Condition/{uuid}settingclinicalStatus=inactive.Result with
clinicalStatus=inactive→ Mark as active again button. On click:PATCH /Condition/{uuid}settingclinicalStatus=active.
Typeahead annotation. For each concept search result, run the same exact concept-match check and surface an On conditions list marker on matches (regardless of Active/Inactive).
Conditions widget refresh. Re-fetch the patient's conditions after any of the three actions. No backend change needed.
Snackbar with Undo. On success, store the returned Condition UUID (create case) or the previous
clinicalStatus(status-flip cases). Undo issues the inverse action:DELETE /Condition/{uuid}for a newly created condition, or aPATCHback to the previous status.State sync. After any action, the row re-evaluates and the button updates to the next-state action.
Backend (FHIR2 Module): V1 work breakdown
No changes required. Read, create, search by concept+patient, status update, and delete are already implemented and working.
5. Technical Considerations & Dependencies
Single panel, state-driven actions. V1 deliberately avoids auto-classifying diagnoses. Each diagnosis row gets one action based on the current state of its concept on the patient's Conditions list. No chronic/acute auto-detection.
Explicit action only. Nothing on the Conditions list changes automatically. The Conditions list updates only when the clinician explicitly clicks one of the three actions. Saving the visit note alone changes nothing.
Curation by intent. The opt-in step keeps acute, one-off diagnoses (pharyngitis, a sprain) off the list. The list stays curated by clinician intent rather than by default, without the system having to classify anything.
Onset date. Onset is left blank on the create action, with the standard OpenmrsDatePicker available as an optional input. The picker is day-precision; month-only inputs are not modelled by the backend in V1.
Live updates. All three actions are real writes. The Conditions widget refreshes instantly with no reload, a snackbar confirms, and Undo reverts the action.
Dedupe and state coherence. The same exact concept-match query drives all three states, so a diagnosis cannot be promoted twice — a successful create flips the row to "Mark as inactive" mode, removing the option to create again.
FHIR semantics. The feature maps onto the FHIR
Condition.categorydistinction betweenencounter-diagnosisandproblem-list-item, and theclinicalStatusdistinction betweenactiveandinactive. Promotion is the move from an encounter diagnosis to a problem-list item; the remission and reactivation actions are status flips on the existing problem-list item.
Feasibility
The fhir2 module already treats org.openmrs.Diagnosis and org.openmrs.Condition as two separate data models mapped to the same FHIR resource type (Condition) via the category field. "Promotion" is reading a Diagnosis and writing a new Condition from it; "Mark as inactive" and "Mark as active again" are PATCH operations on clinicalStatus.
What already exists with no new code needed:
Category-based routing —
encounter-diagnosis→ Diagnosis DAO,problem-list-item→ Condition DAO.Condition creation via FHIR (
POST /ws/fhir2/R4/Condition).Condition status update via FHIR (
PATCH /ws/fhir2/R4/Condition/{uuid}) forclinicalStatus.Condition deletion via FHIR for Undo (
DELETE /ws/fhir2/R4/Condition/{uuid}).Search by concept+patient against the Conditions DAO.
FhirConditionServiceImpl and FhirUtils.getOpenmrsConditionType() already route reads, writes, and searches between the Diagnosis and Condition entities based on category. TwoSearchQueryBundleProvider already merges search results from both. No new API endpoint, no new service method, no new translator logic is needed.
Post-V1 considerations
Concept-level eligibility (chronic-conditions filter). Rather than offering the affordance on every diagnosis, an implementer could restrict it to concepts flagged problem-list-eligible — via a concept attribute, membership in a "Chronic conditions" concept set, or a Condition.category distinction. Diagnoses outside that set would still be recorded as diagnoses but show no action in the Add to conditions list panel. Requires concept-level metadata to be exposed in fhir2.
Related-concept matching. As Andrew Kanter raised, an encounter diagnosis is sometimes more specific than the condition it should promote to ("Exacerbation of COPD" on the visit, "COPD" on the conditions list). V1 only matches exact concept. Post-V1 work could leverage SNOMED maps from CIEL or a curated map of common terms; AI-assisted curation is another avenue worth exploring.
6. Sketches
All actionsAdded Diabetes Mellitus as an Active Condition
Marked Asthma Inactive
Marked Epilepsy Active