Skip to content

fix:Fix camp analytics counters to return actual counts

Suma Pullaiahgari requested to merge fix/camp-analyics into develop

Merge Request

Overview

Fix camp analytics counters to return actual database counts for each stage instead of forcing them into an artificially decreasing funnel. Previously, downstream stages were capped by upstream stages (e.g., consultation count capped at waiting count), which hid real bottlenecks from camp coordinators.

What does this MR do and why?

Problem: The analytics funnel was artificially smoothing stage counts. If 9 patients had consultations but only 2 were marked as waiting, the consultation counter was capped at 2 — making it impossible to identify where patients were actually getting stuck.

Fix: Removed the capping logic and corrected the database queries to accurately count patients at each stage independently.

Changes Made

  • app/services/analytics_service.py

    • Removed print() debug logging statements
    • Removed or_ import and capping logic that enforced artificial funnel ordering
    • Changed KYP counting: now queries Patient records directly and checks life_style/work_profile fields for completeness (using existing _is_missing, _has_missing_value, _has_invalid_kyp_format helpers), instead of relying on ConsultationQueue status
    • Changed waiting count: now joins via ConsultationQueue.camp_visit_id -> CampVisit instead of ConsultationQueue.book_no -> Patient -> User -> CampVisit
    • Changed consultation count: now counts PatientVisitDetails with an existing PatientConsultation record instead of querying ConsultationQueue with medicine_prescribing status
  • tests/test_services/test_analytics_service.py

    • Added test_get_current_camp_analytics_returns_uncapped_stage_counts to verify that stage counts are returned as-is without capping

Technical Details

  • Root cause: The funnel capping logic (if patients_consultation > patients_waiting: cap) was masking real data. A stage like "consultation done" can legitimately exceed "waiting" when patients move through quickly or when queue statuses are updated asynchronously.
  • KYP rework: KYP completeness is now based on actual patient data (life_style + work_profile fields) rather than a queue status flag, which aligns with the domain meaning of "Know Your Patient."
  • Query simplification: Join paths were simplified to use direct FK relationships (ConsultationQueue.camp_visit_id) instead of multi-hop joins through Patient and User tables.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Related Issues / References

Screenshots or Screen Recordings

How to Validate Locally

  1. Start the app and seed data with at least one camp having patients at various stages
  2. Hit GET /api/v1/analytics?camp_id={id} and verify:
    • Each counter reflects the actual DB count for that stage
    • consultation_done is not artificially capped by waiting_for_doctor
    • kyp_done accurately reflects patients with completed life_style + work_profile fields

Testing Done

  • Unit tests added/updated
  • API endpoint tests passing

Test Cases Covered:

Scenario Expected Result Status
Uncapped stage counts are returned as-is when downstream > upstream Each counter matches its query result
KYP counts only patients with complete life_style + work_profile Patients with partial KYP data are excluded

Test Commands Run:

pytest tests/test_services/test_analytics_service.py -v -k "uncapped"

Code Quality Checklist

Code Standards

  • Code follows project conventions (naming, structure, formatting)
  • No debug statements or commented-out code left
  • No unused imports, variables, or functions
  • No duplicate code (DRY principle followed)
  • Type hints are properly defined

Python & FastAPI Best Practices

  • Functions follow single-responsibility principle
  • Error handling is comprehensive

Database & Migrations

  • No raw SQL queries (using SQLAlchemy ORM)

Known Limitations / Technical Debt

  • The _get_or_validate_camp function is still patched in tests rather than testing with real DB data (noted as existing tech debt)
  • Some older test cases in the same file are marked with @pytest.mark.skip due to complex mock requirements

Additional Notes

This is a targeted fix; no schema changes or migrations were required.


MR Acceptance Checklist

Quality & Correctness

  • Code works as intended and solves the stated problem
  • No bugs introduced (existing functionality not broken)
  • Edge cases handled appropriately (empty camps, no patients at a given stage)

Maintainability

  • Code is readable and well-organized
  • Code is testable and well-tested
  • Follows project patterns and conventions

Acceptance Review

  • Reviewed by at least 1 teammate

Merge request reports

Loading