Skip to content

[ENG-702] refact :mapped all fields under the standalone context builder#3706

Open
nandkishorr wants to merge 1 commit into
developfrom
ENG-702-refactoring-template-report-datapoints
Open

[ENG-702] refact :mapped all fields under the standalone context builder#3706
nandkishorr wants to merge 1 commit into
developfrom
ENG-702-refactoring-template-report-datapoints

Conversation

@nandkishorr

@nandkishorr nandkishorr commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Proposed Changes

  • Removed the min spec and mapped all the fields under the standalone context builder for account,encounter and patient

Associated Issue

Merge Checklist

  • Tests added/fixed
  • Update docs in /docs
  • Linting Complete
  • Any other necessary step

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

  • New Features

    • Expanded report details to include fuller patient and encounter information.
    • Added facility-specific patient identifiers to encounter-related reports.
  • Bug Fixes

    • Improved consistency in report data across account, encounter, and patient sections.
    • Adjusted report output ordering and structure for more reliable display.

@nandkishorr nandkishorr self-assigned this Jul 7, 2026
@nandkishorr nandkishorr requested a review from a team as a code owner July 7, 2026 10:58
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Report context builders for patient, encounter, and account are refactored to remove minimum/base variants in favor of unified full context builders. PatientContextBuilder and EncounterReportContext now extend SingleObjectContextBuilder directly with their own metadata, and account/encounter fields are rewired to reference these consolidated classes. A PatientFacilityIdentifiersContextBuilder is added, and patient_facility_tags field position is adjusted within encounter context.

Changes

Report Context Builder Consolidation

Layer / File(s) Summary
PatientContextBuilder base class and registration
care/emr/reports/context_builder/data_points/patient.py
Adds PatientContextBuilder (subclassing SingleObjectContextBuilder) with report metadata and get_context(), replacing PatientContextBuilderBase, and updates registry registration accordingly.
EncounterReportContext restructuring and patient wiring
care/emr/reports/context_builder/data_points/encounter.py
Removes BaseEncounterReportContext/MinimumEncounterReportContext, defines EncounterReportContext directly with metadata, adds PatientFacilityIdentifiersContextBuilder, updates patient field to PatientContextBuilder, and repositions patient_facility_tags field.
AccountContextBuilder switched to full contexts
care/emr/reports/context_builder/data_points/account.py
Removes BaseAccountContextBuilder, has AccountContextBuilder extend SingleObjectContextBuilder directly with its own metadata and get_context, and updates primary_encounter/patient fields to reference EncounterReportContext/PatientContextBuilder.

Estimated code review effort: 2 (Simple) | ~12 minutes

Possibly related PRs

  • ohcnetwork/care#3662: Adds and wires the same PatientFacilityIdentifiersContextBuilder-related facility identifier fields into EncounterReportContext.

Well, someone finally decided the "minimum" context builders had outlived their minimalism — consolidating everything into full builders now, no gradual deprecation notice needed, apparently.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR's main change: mapping fields to the standalone context builder.
Description check ✅ Passed The description covers proposed changes, issue reference, and merge checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ENG-702-refactoring-template-report-datapoints

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR collapses three-level class hierarchies (Base + Minimum + Standalone) into a single class for each of the Patient, Encounter, and Account context builders, consolidating all fields under one class that serves both standalone report generation and embedded sub-context use.

  • PatientContextBuilder, EncounterReportContext, and AccountContextBuilder each now carry the get_context() from the former "Minimum" variant and the standalone_context = True metadata from the former standalone class; the slugs are unchanged so stored report templates continue to resolve correctly.
  • AccountContextBuilder.primary_encounter now points to the full EncounterReportContext (previously MinimumEncounterReportContext), meaning account-level templates can now access nested encounter clinical fields (diagnoses, symptoms, medication_prescriptions, etc.) that were previously unavailable.
  • PatientFacilityIdentifiersContextBuilder was correctly relocated before EncounterReportContext in encounter.py to maintain a valid definition order.

Confidence Score: 5/5

Safe to merge — the refactoring is purely structural with no logic changes outside consolidating the class hierarchy.

All three context builders preserve their original slugs, display names, and get_context() semantics. Standalone instantiation bypasses get_context() in both old and new code, so the merged method causes no regression. Embedded instantiation correctly calls getattr(parent_context, parent_attribute) as before. The schema-extraction utility's visited.copy() logic handles the newly deeper nesting without cycles. No model changes, no migrations, no API surface changes.

No files require special attention — all three changed files are self-contained context builder definitions with no downstream model or view impact.

Important Files Changed

Filename Overview
care/emr/reports/context_builder/data_points/patient.py Merges BasePatientContextBuilder + PatientMinimumContextBuilder + PatientContextBuilderBase into a single PatientContextBuilder with get_context() from the minimum variant; slug "patient_base" is preserved so existing templates are unaffected.
care/emr/reports/context_builder/data_points/encounter.py Merges BaseEncounterReportContext + MinimumEncounterReportContext + EncounterReportContext into a single class; PatientFacilityIdentifiersContextBuilder moved before EncounterReportContext to maintain valid forward-reference order; patient_facility_tags moved to bottom of the merged class.
care/emr/reports/context_builder/data_points/account.py Merges BaseAccountContextBuilder + AccountContextBuilder into one class; primary_encounter now references full EncounterReportContext (instead of MinimumEncounterReportContext), exposing nested patient/facility/clinical fields when building account-based reports.

Reviews (1): Last reviewed commit: "refact:mapped all fields under the stand..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
care/emr/reports/context_builder/data_points/account.py (1)

149-161: 🚀 Performance & Scalability | 🔵 Trivial

Full patient/facility context now gets built twice per account report.

With primary_encounter pointed at the full EncounterReportContext (which itself nests a full patient and facility) and account also directly nesting full patient/facility, an account report now computes patient demographics, identifiers, tags, and facility details twice (once via account.patient/account.facility, once via account.primary_encounter.patient/.facility). Previously the nested encounter used a lighter "minimum" variant, avoiding this. Worth confirming this duplicated payload/query cost is acceptable for the intended use case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@care/emr/reports/context_builder/data_points/account.py` around lines 149 -
161, The account report now builds full patient and facility context twice
because `primary_encounter` uses `EncounterReportContext`, which already nests
`patient` and `facility`, while `account` also includes direct `patient` and
`facility` fields. Update the `primary_encounter` field in `account.py` to point
to the lighter encounter context used previously, or otherwise reduce the nested
context so `PatientContextBuilder` and facility-building logic are not
duplicated in the account report; verify the intended context shape against
`primary_encounter`, `patient`, and `facility`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@care/emr/reports/context_builder/data_points/encounter.py`:
- Around line 229-233: `PatientFacilityIdentifiersContextBuilder.get_context`
assumes `patient.facility_identifiers` is always a dict, but it can be `None` or
otherwise falsy and will crash on `.get(...)`. Update this method to defensively
handle missing values the same way `Patient.build_facility_identifiers` does,
returning an empty list when `facility_identifiers` is unset, and only calling
`.get(...)` on a valid mapping.

---

Nitpick comments:
In `@care/emr/reports/context_builder/data_points/account.py`:
- Around line 149-161: The account report now builds full patient and facility
context twice because `primary_encounter` uses `EncounterReportContext`, which
already nests `patient` and `facility`, while `account` also includes direct
`patient` and `facility` fields. Update the `primary_encounter` field in
`account.py` to point to the lighter encounter context used previously, or
otherwise reduce the nested context so `PatientContextBuilder` and
facility-building logic are not duplicated in the account report; verify the
intended context shape against `primary_encounter`, `patient`, and `facility`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dcb3d8e4-5fc5-4ad9-b158-244a7b134618

📥 Commits

Reviewing files that changed from the base of the PR and between c6ca8ef and 509a419.

📒 Files selected for processing (3)
  • care/emr/reports/context_builder/data_points/account.py
  • care/emr/reports/context_builder/data_points/encounter.py
  • care/emr/reports/context_builder/data_points/patient.py

Comment on lines +229 to +233
class PatientFacilityIdentifiersContextBuilder(IdentifiersContextBuilder):
def get_context(self):
return self.parent_context.patient.facility_identifiers.get(
str(self.parent_context.facility.id), []
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard against facility_identifiers being None.

Patient.facility_identifiers is a JSONField(default=dict, null=True, blank=True), and the model's own build_facility_identifiers defensively checks if not self.facility_identifiers before use — meaning it can be falsy/None for some rows. Calling .get(...) directly here will raise AttributeError for any such patient, crashing the whole encounter report.

🛡️ Proposed fix
 class PatientFacilityIdentifiersContextBuilder(IdentifiersContextBuilder):
     def get_context(self):
-        return self.parent_context.patient.facility_identifiers.get(
+        return (self.parent_context.patient.facility_identifiers or {}).get(
             str(self.parent_context.facility.id), []
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class PatientFacilityIdentifiersContextBuilder(IdentifiersContextBuilder):
def get_context(self):
return self.parent_context.patient.facility_identifiers.get(
str(self.parent_context.facility.id), []
)
class PatientFacilityIdentifiersContextBuilder(IdentifiersContextBuilder):
def get_context(self):
return (self.parent_context.patient.facility_identifiers or {}).get(
str(self.parent_context.facility.id), []
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@care/emr/reports/context_builder/data_points/encounter.py` around lines 229 -
233, `PatientFacilityIdentifiersContextBuilder.get_context` assumes
`patient.facility_identifiers` is always a dict, but it can be `None` or
otherwise falsy and will crash on `.get(...)`. Update this method to defensively
handle missing values the same way `Patient.build_facility_identifiers` does,
returning an empty list when `facility_identifiers` is unset, and only calling
`.get(...)` on a valid mapping.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.65%. Comparing base (c6ca8ef) to head (509a419).

Files with missing lines Patch % Lines
...r/reports/context_builder/data_points/encounter.py 84.61% 2 Missing ⚠️
...emr/reports/context_builder/data_points/account.py 88.88% 1 Missing ⚠️
...emr/reports/context_builder/data_points/patient.py 90.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3706      +/-   ##
===========================================
- Coverage    79.66%   79.65%   -0.01%     
===========================================
  Files          479      479              
  Lines        23010    23007       -3     
  Branches      2379     2379              
===========================================
- Hits         18330    18326       -4     
- Misses        4080     4081       +1     
  Partials       600      600              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant