Skip to content

Commit

Permalink
Block level reports via Regions (#1477)
Browse files Browse the repository at this point in the history
* Start spiking out Region backed reports

* Fix duplicate districts and blocks getting spun up

* Make region type creation idempotent

* Ensure the slugs stay consistent w/ source slug

Need to explicitly set them from the source, otherwise facility slugs
are getting set to different hings.  Which is oging to lead to problems
and confusion.

* find the correct region

* Arel deprecation error for some reason...

but the find is getting to the point where it should work

* Delegate assigned patients to a region's source

This works for now because the source is either a facility group or a
facility. This wont work once we have proper block level reports

* Check district region correctly

* Define singlular 'foo_region?' methods for Region instances; remove plural methods

this cleans up some confusion that is a result of the rails
auto-generated enum methods

* Get basic region reports working

duck typing where possible

* Get block level reports working

Need to figure out the virtual vs ActiveRecord source piece on Region

* Dont try to render blocks for FacilityDistrict

I'm not sure if that is a valid thing to even show .../cc harimohanraj89
do you know?

* linting

* Less type checks

* Avoid type checks

* Fix logging

* Add a test for block level control rates

* explain this magic number

* Simplify how we get assigned_patients for a Region

* remove Block, dont need it anymore

* Need to return a relation, not the single model

treat everything as a collection of facilities so that calling code
doesn't need to worry about it

* Add a better error message for FG factories w/ regions

Make it easier to track down dependancy issues here as we enable
regions_prep more broadly

* Add block spec; render views only CI

* typo

* back to debug in dev; info for test

* linting

* Update standard

To pull in standardrb/standard#228

* Remove this

not needed anymore, and I don't know if itw as even working

* remove dead code

* better local name

Co-authored-by: prabhanshuguptagit <[email protected]>
  • Loading branch information
rsanheim and prabhanshuguptagit authored Dec 8, 2020
1 parent 53a0a8c commit ebabedd
Show file tree
Hide file tree
Showing 16 changed files with 603 additions and 14 deletions.
2 changes: 0 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ Style/Documentation:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Lint/DuplicateBranch:
Enabled: false
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ GEM
sshkit-interactive (0.3.0)
sshkit (~> 1.12)
stackprof (0.2.15)
standard (0.10.1)
standard (0.10.2)
rubocop (= 1.4.2)
rubocop-performance (= 1.9.1)
strong_password (0.0.8)
Expand Down
33 changes: 29 additions & 4 deletions app/controllers/reports/regions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ def show
@new_registrations = @last_registration_value - (@data[:cumulative_registrations].values[-2] || 0)
@adjusted_registration_date = @data[:adjusted_registrations].keys[-4]

if @region.is_a?(FacilityGroup) || @region.is_a?(FacilityDistrict)
if @region.district_region?
@data_for_facility = @region.facilities.each_with_object({}) { |facility, hsh|
hsh[facility.name] = Reports::RegionService.new(region: facility,
period: @period).call
}
end
if current_admin.feature_enabled?(:region_reports) && @region.district_region? && @region.respond_to?(:block_regions)
@block_data = @region.block_regions.each_with_object({}) { |region, hsh|
hsh[region.name] = Reports::RegionService.new(region: region,
period: @period).call
}
end
end

def details
Expand All @@ -42,7 +48,7 @@ def details
prev_periods: 6,
include_current_period: true)

if @region.is_a?(Facility)
if @region.respond_to?(:recent_blood_pressures)
@recent_blood_pressures = paginate(@region.recent_blood_pressures)
end
end
Expand Down Expand Up @@ -132,6 +138,14 @@ def set_force_cache
end

def find_region
if current_admin.feature_enabled?("region_reports")
find_region_v2
else
find_region_v1
end
end

def find_region_v1
if report_params[:report_scope] == "facility_district"
@region = FacilityDistrict.new(name: report_params[:id], scope: current_admin.accessible_facilities(:view_reports))
else
Expand All @@ -141,14 +155,25 @@ def find_region
end
end

def find_region_v2
region_type = report_params[:report_scope]
@region = if region_type == "facility_district"
FacilityDistrict.new(name: report_params[:id], scope: current_admin.accessible_facilities(:view_reports))
else
Region.where(region_type: region_type).find_by!(slug: report_params[:id])
end
end

def region_class
@region_class ||= case report_params[:report_scope]
when "facility_district"
"facility_district"
when "district"
"facility_group"
when "facility"
"facility"
when "facility_district"
"facility_district"
when "block"
"block"
else
raise ActiveRecord::RecordNotFound, "unknown report scope #{report_params[:report_scope]}"
end
Expand Down
10 changes: 10 additions & 0 deletions app/models/facility.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ def discardable?
registered_patients.none? && blood_pressures.none? && blood_sugars.none? && appointments.none?
end

# For regions compatibility
def facility_region?
true
end

# For regions compatibility
def district_region?
false
end

def valid_block
unless facility_group.region.block_regions.pluck(:name).include?(block)
errors.add(:zone, "not present in the facility group")
Expand Down
10 changes: 10 additions & 0 deletions app/models/facility_district.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,14 @@ def model_name
def updated_at
facilities.maximum(:updated_at) || Time.current.beginning_of_day
end

# For regions compatibility
def facility_region?
false
end

# For regions compatibility
def district_region?
true
end
end
10 changes: 10 additions & 0 deletions app/models/facility_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ def cohort_analytics(period:, prev_periods:)
query.call
end

# For regions compatibility
def facility_region?
false
end

# For regions compatibility
def district_region?
true
end

private

def set_diabetes_management(value)
Expand Down
29 changes: 26 additions & 3 deletions app/models/region.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ class Region < ApplicationRecord
REGION_TYPES = %w[root organization state district block facility].freeze
enum region_type: REGION_TYPES.zip(REGION_TYPES).to_h, _suffix: "regions"

REGION_TYPES.each do |type|
# Our enum adds a pluralized suffix, which is nice for scopes, but weird for the question methods
# with individual objects. So we define our own question methods here for a nicer API.
define_method("#{type}_region?") do
region_type == type
end
# Don't leave around the old, auto generated methods to avoid confusion
undef_method "#{type}_regions?"
end

def self.root
Region.find_by(region_type: :root)
end
Expand All @@ -38,6 +48,19 @@ def short_uuid
SecureRandom.uuid[0..7]
end

def assigned_patients
Patient.where(assigned_facility: facilities)
end

def facilities
if facility_region?
Facility.where(id: source_id)
else
source_ids = facility_regions.pluck(:source_id)
Facility.where(id: source_ids)
end
end

# A label is a sequence of alphanumeric characters and underscores.
# (In C locale the characters A-Za-z0-9_ are allowed).
# Labels must be less than 256 bytes long.
Expand All @@ -62,18 +85,18 @@ def log_payload
if self_and_descendant_types(region_type).include?(self.region_type)
self_and_ancestors.find_by(region_type: region_type)
else
raise NoMethodError, "undefined method #{region_type} for #{self} of type #{self.region_type}"
raise NoMethodError, "undefined method #{region_type} for region '#{name}' of type #{self.region_type}"
end
end

# Generates has_many type of methods to fetch a region's descendants
# e.g. organization.facilities
# e.g. organization.facility_regions
descendant_method = "#{region_type}_regions"
define_method(descendant_method) do
if ancestor_types(region_type).include?(self.region_type)
descendants.where(region_type: region_type)
else
raise NoMethodError, "undefined method #{region_type.pluralize} for #{self} of type #{self.region_type}"
raise NoMethodError, "undefined method #{region_type.pluralize} for region '#{name}' of type #{self.region_type}"
end
end
end
Expand Down
7 changes: 4 additions & 3 deletions app/services/control_rate_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def initialize(region, periods:)
end
@quarterly_report = @report_range.begin.quarter?
@results = Reports::Result.new(region: @region, period_type: @report_range.begin.type)
logger.info class: self.class, msg: "created", region: region.id, region_name: region.name,
report_range: report_range.inspect, facilities: facilities.map(&:id)
logger.info class: self.class.name, msg: "created", region: region.id, region_name: region.name,
report_range: report_range.inspect, facilities: facilities.map(&:id), cache_key: cache_key
end

delegate :logger, to: Rails
Expand Down Expand Up @@ -63,7 +63,8 @@ def fetch_all_data
def registration_counts
return @registration_counts if defined? @registration_counts
formatter = lambda { |v| quarterly_report? ? Period.quarter(v) : Period.month(v) }
@registration_counts = region.assigned_patients.with_hypertension.group_by_period(report_range.begin.type, :recorded_at, {format: formatter}).count
@registration_counts = region.assigned_patients.with_hypertension.group_by_period(report_range.begin.type,
:recorded_at, {format: formatter}).count
end

def controlled_patients(period)
Expand Down
Loading

0 comments on commit ebabedd

Please sign in to comment.