Skip to content

Commit 1d78501

Browse files
authored
Merge pull request #5789 from simpledotorg/SIMPLEBACK-97
Controller (app/controllers/admin/deduplicate_patients_controller.rb):
2 parents 8b78ce2 + 3d5331c commit 1d78501

3 files changed

Lines changed: 204 additions & 4 deletions

File tree

app/controllers/admin/deduplicate_patients_controller.rb

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
class Admin::DeduplicatePatientsController < AdminController
22
skip_before_action :verify_authenticity_token
3+
before_action :set_filter_options, only: [:show], if: :filter_enabled?
34
DUPLICATE_LIMIT = 250
45

56
def show
67
facilities = current_admin.accessible_facilities(:manage)
78
authorize { facilities.any? }
89

10+
# Apply facility filter if selected and feature flag is enabled
11+
filtered_facilities = if filter_enabled? && @selected_facility.present?
12+
facilities.where(id: @selected_facility.id)
13+
elsif filter_enabled? && @selected_district.present?
14+
facilities.where(id: @selected_district.facilities)
15+
else
16+
facilities
17+
end
18+
919
# Scoping by facilities is costly for users who have a lot of facilities
10-
duplicate_patient_ids = if current_admin.accessible_organizations(:manage).any?
20+
use_all_organizations = current_admin.accessible_organizations(:manage).any? &&
21+
(!filter_enabled? || (!@selected_district.present? && !@selected_facility.present?))
22+
23+
duplicate_patient_ids = if use_all_organizations
1124
PatientDeduplication::Strategies.identifier_excluding_full_name_match(limit: DUPLICATE_LIMIT)
1225
else
1326
PatientDeduplication::Strategies.identifier_excluding_full_name_match_for_facilities(
1427
limit: DUPLICATE_LIMIT,
15-
facilities: facilities
28+
facilities: filtered_facilities
1629
)
1730
end
1831

@@ -44,4 +57,42 @@ def can_admin_deduplicate_patients?(patients)
4457
.where(id: patients.pluck(:assigned_facility_id))
4558
.any?
4659
end
60+
61+
private
62+
63+
def set_filter_options
64+
@accessible_facilities = current_admin.accessible_facilities(:manage)
65+
populate_districts
66+
set_selected_district
67+
populate_facilities
68+
set_selected_facility
69+
end
70+
71+
def populate_districts
72+
@districts = Region.district_regions
73+
.joins("INNER JOIN regions facility_region ON regions.path @> facility_region.path")
74+
.where("facility_region.source_id" => @accessible_facilities.map(&:id))
75+
.distinct(:slug)
76+
.order(:name)
77+
end
78+
79+
def set_selected_district
80+
@selected_district = if params[:district_slug].present?
81+
@districts.find_by(slug: params[:district_slug])
82+
elsif @districts.present?
83+
@districts.first
84+
end
85+
end
86+
87+
def populate_facilities
88+
@facilities = @accessible_facilities.where(id: @selected_district&.facilities).order(:name)
89+
end
90+
91+
def set_selected_facility
92+
@selected_facility = @facilities.find_by(id: params[:facility_id]) if params[:facility_id].present?
93+
end
94+
95+
def filter_enabled?
96+
Flipper.enabled?(:patient_deduplication_filter, current_admin)
97+
end
4798
end

app/views/admin/deduplicate_patients/show.html.erb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
11
<h1 class="page-title mb-3">Merge duplicate patients</h1>
2+
3+
<% if Flipper.enabled?(:patient_deduplication_filter, current_admin) %>
4+
<%= bootstrap_form_with(url: admin_deduplication_path, method: :get, layout: :horizontal, class: "mb-4") do |form| %>
5+
<% html_select_options = { onchange: "this.form.submit();" }
6+
searchable_select_options = html_select_options.merge(class: "selectpicker", data: {live_search: true}) %>
7+
<div class="form-row">
8+
<div id="district-selector" class="form-group col-md-4">
9+
<%= form.select :district_slug,
10+
@districts.order(:name).map { |district| [district.name, district.slug] },
11+
{
12+
hide_label: true,
13+
selected: @selected_district&.slug,
14+
wrapper: false
15+
},
16+
searchable_select_options
17+
%>
18+
</div>
19+
<div id="facility-selector" class="form-group col-md-4">
20+
<%= form.select :facility_id,
21+
@facilities.order(:name).map { |facility| [facility.label_with_district, facility.id] },
22+
{
23+
hide_label: true,
24+
include_blank: "All facilities",
25+
selected: @selected_facility&.id,
26+
wrapper: false
27+
},
28+
searchable_select_options
29+
%>
30+
</div>
31+
</div>
32+
<%= form.submit "Filter", style: "display: none" %>
33+
<% end %>
34+
<% end %>
35+
236
<div class="card">
337
<h3>
438
<% if @duplicate_count == Admin::DeduplicatePatientsController::DUPLICATE_LIMIT %>

spec/controllers/admin/deduplicate_patients_controller_spec.rb

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require "rails_helper"
22

33
RSpec.describe Admin::DeduplicatePatientsController, type: :controller do
4-
context "#show" do
4+
describe "#show" do
55
it "shows patients accessible by the user" do
66
patient = create(:patient, full_name: "Patient one")
77
patient_passport_id = patient.business_identifiers.first.identifier
@@ -40,9 +40,124 @@
4040
expect(response.status).to eq(302)
4141
expect(flash[:alert]).to eq("You are not authorized to perform this action.")
4242
end
43+
44+
context "when patient_deduplication_filter feature flag is enabled" do
45+
let(:organization) { create(:organization) }
46+
let(:facility_group) { create(:facility_group, organization: organization) }
47+
let(:district) { facility_group.region }
48+
let(:facility1) { create(:facility, facility_group: facility_group) }
49+
let(:facility2) { create(:facility, facility_group: facility_group) }
50+
let(:admin) { create(:admin, :manager, :with_access, resource: organization) }
51+
52+
before do
53+
sign_in(admin.email_authentication)
54+
Flipper.enable(:patient_deduplication_filter, admin)
55+
end
56+
57+
it "sets filter options when feature flag is enabled" do
58+
facility1
59+
get :show
60+
61+
expect(assigns(:districts)).to be_present
62+
expect(assigns(:selected_district)).to be_present
63+
end
64+
65+
it "populates accessible districts" do
66+
facility1
67+
get :show
68+
69+
expect(assigns(:districts)).to include(district)
70+
end
71+
72+
it "filters patients by selected district" do
73+
patient1 = create(:patient, full_name: "Patient one", assigned_facility: facility1)
74+
patient1_passport_id = patient1.business_identifiers.first.identifier
75+
76+
patient1_dup = create(:patient, full_name: "Patient one dup", assigned_facility: facility1)
77+
patient1_dup.business_identifiers.first.update(identifier: patient1_passport_id)
78+
79+
other_facility_group = create(:facility_group, organization: organization)
80+
other_facility = create(:facility, facility_group: other_facility_group)
81+
82+
patient2 = create(:patient, full_name: "Patient two", assigned_facility: other_facility)
83+
patient2_passport_id = patient2.business_identifiers.first.identifier
84+
85+
patient2_dup = create(:patient, full_name: "Patient two dup", assigned_facility: other_facility)
86+
patient2_dup.business_identifiers.first.update(identifier: patient2_passport_id)
87+
88+
get :show, params: {district_slug: district.slug}
89+
90+
expect(assigns(:patients)).to include(patient1, patient1_dup)
91+
expect(assigns(:patients)).not_to include(patient2, patient2_dup)
92+
end
93+
94+
it "filters patients by selected facility" do
95+
patient1 = create(:patient, full_name: "Patient one", assigned_facility: facility1)
96+
patient1_passport_id = patient1.business_identifiers.first.identifier
97+
98+
patient1_dup = create(:patient, full_name: "Patient one dup", assigned_facility: facility1)
99+
patient1_dup.business_identifiers.first.update(identifier: patient1_passport_id)
100+
101+
patient2 = create(:patient, full_name: "Patient two", assigned_facility: facility2)
102+
patient2_passport_id = patient2.business_identifiers.first.identifier
103+
104+
patient2_dup = create(:patient, full_name: "Patient two dup", assigned_facility: facility2)
105+
patient2_dup.business_identifiers.first.update(identifier: patient2_passport_id)
106+
107+
get :show, params: {district_slug: district.slug, facility_id: facility1.id}
108+
109+
expect(assigns(:patients)).to include(patient1, patient1_dup)
110+
expect(assigns(:patients)).not_to include(patient2, patient2_dup)
111+
end
112+
113+
it "populates facilities for the selected district" do
114+
facility1
115+
facility2
116+
get :show, params: {district_slug: district.slug}
117+
118+
expect(assigns(:facilities)).to include(facility1, facility2)
119+
end
120+
121+
it "sets the selected facility when facility_id param is present" do
122+
facility1
123+
get :show, params: {district_slug: district.slug, facility_id: facility1.id}
124+
125+
expect(assigns(:selected_facility)).to eq(facility1)
126+
end
127+
end
128+
129+
context "when patient_deduplication_filter feature flag is disabled" do
130+
let(:admin) { create(:admin, :manager, :with_access, resource: create(:facility)) }
131+
132+
before do
133+
sign_in(admin.email_authentication)
134+
Flipper.disable(:patient_deduplication_filter)
135+
end
136+
137+
it "does not set filter options" do
138+
get :show
139+
140+
expect(assigns(:districts)).to be_nil
141+
expect(assigns(:selected_district)).to be_nil
142+
expect(assigns(:facilities)).to be_nil
143+
end
144+
145+
it "shows all accessible duplicate patients without filtering" do
146+
facility = admin.accessible_facilities(:manage).first
147+
patient = create(:patient, full_name: "Patient one", assigned_facility: facility)
148+
patient_passport_id = patient.business_identifiers.first.identifier
149+
150+
patient_dup = create(:patient, full_name: "Patient one dup", assigned_facility: facility)
151+
patient_dup.business_identifiers.first.update(identifier: patient_passport_id)
152+
153+
get :show
154+
155+
expect(assigns(:patients)).to contain_exactly(patient, patient_dup)
156+
end
157+
end
43158
end
44159

45-
context "#merge" do
160+
describe "#merge" do
46161
it "returns unauthorized when none of the patient IDs is accessible by the user" do
47162
patients = [create(:patient, full_name: "Patient one"), create(:patient, full_name: "Patient two")]
48163
admin = create(:admin, :manager, :with_access, resource: create(:facility))

0 commit comments

Comments
 (0)