diff --git a/Gemfile b/Gemfile index 0aed6a5fec..70d7174b6d 100644 --- a/Gemfile +++ b/Gemfile @@ -43,6 +43,7 @@ gem "kaminari" gem "lodash-rails" gem "lograge" gem "ougai" +gem "oj" gem "parallel", require: false gem "passenger" gem "pg", ">= 0.18", "< 2.0" diff --git a/Gemfile.lock b/Gemfile.lock index 569073c1bf..17c7a222a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -608,6 +608,7 @@ DEPENDENCIES memery memory_profiler mock_redis + oj ougai parallel parallel_tests diff --git a/app/controllers/api/v3/blood_sugars_controller.rb b/app/controllers/api/v3/blood_sugars_controller.rb index ba4ab65acc..c484e7c0ae 100644 --- a/app/controllers/api/v3/blood_sugars_controller.rb +++ b/app/controllers/api/v3/blood_sugars_controller.rb @@ -12,7 +12,7 @@ def sync_to_user private - def region_records + def model_sync_scope super.for_v3 end diff --git a/app/controllers/api/v3/facilities_controller.rb b/app/controllers/api/v3/facilities_controller.rb index 23f284ab8b..5925eba59d 100644 --- a/app/controllers/api/v3/facilities_controller.rb +++ b/app/controllers/api/v3/facilities_controller.rb @@ -16,7 +16,7 @@ def current_facility_records end def other_facility_records - Statsd.instance.time("other_facility_records.Facility") do + time(__method__) do Facility .with_discarded .updated_on_server_since(other_facilities_processed_since, limit) @@ -45,7 +45,7 @@ def force_resync? end def records_to_sync - Statsd.instance.time("records_to_sync.Facility") do + time(__method__) do other_facility_records .with_block_region_id .includes(:facility_group) diff --git a/app/controllers/api/v3/patients_controller.rb b/app/controllers/api/v3/patients_controller.rb index 323c31427f..e3678deaf0 100644 --- a/app/controllers/api/v3/patients_controller.rb +++ b/app/controllers/api/v3/patients_controller.rb @@ -13,25 +13,25 @@ def request_metadata {request_user_id: current_user.id, request_facility_id: current_facility.id} end - def region_records - super.includes(:address, :phone_numbers, :business_identifiers) - end - def current_facility_records - Statsd.instance.time("current_facility_records.Patient") do - region_records - .where(registration_facility: current_facility) - .updated_on_server_since(current_facility_processed_since, limit) + time(__method__) do + @current_facility_records ||= + current_facility + .prioritized_patients + .for_sync + .updated_on_server_since(current_facility_processed_since, limit) end end def other_facility_records - Statsd.instance.time("other_facility_records.Patient") do - other_facilities_limit = limit - current_facility_records.count - - region_records - .where.not(registration_facility: current_facility) - .updated_on_server_since(other_facilities_processed_since, other_facilities_limit) + time(__method__) do + other_facilities_limit = limit - current_facility_records.size + @other_facility_records ||= + current_sync_region + .syncable_patients + .where.not(registration_facility: current_facility) + .for_sync + .updated_on_server_since(other_facilities_processed_since, other_facilities_limit) end end diff --git a/app/controllers/api/v3/protocols_controller.rb b/app/controllers/api/v3/protocols_controller.rb index 327c1bed76..d89be32d30 100644 --- a/app/controllers/api/v3/protocols_controller.rb +++ b/app/controllers/api/v3/protocols_controller.rb @@ -16,7 +16,7 @@ def current_facility_records end def other_facility_records - Statsd.instance.time("other_facility_records.Protocol") do + time(__method__) do Protocol .with_discarded .updated_on_server_since(other_facilities_processed_since, limit) diff --git a/app/controllers/api/v3/sync_controller.rb b/app/controllers/api/v3/sync_controller.rb index d5f7ad05dd..7094d97914 100644 --- a/app/controllers/api/v3/sync_controller.rb +++ b/app/controllers/api/v3/sync_controller.rb @@ -15,12 +15,11 @@ def __sync_to_user__(response_key) AuditLog.create_logs_async(current_user, records, "fetch", Time.current) unless disable_audit_logs? log_block_level_sync_metrics(response_key) - render( - json: { + json: Oj.dump({ response_key => records.map { |record| transform_to_response(record) }, "process_token" => encode_process_token(response_process_token) - }, + }, mode: :compat), status: :ok ) end diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index ac605730c0..ac4760e1d7 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -68,16 +68,16 @@ def requested_sync_region_id end def validate_facility - return head :bad_request unless current_facility.present? + head :bad_request unless current_facility.present? end def validate_current_facility_belongs_to_users_facility_group - return head :unauthorized unless current_user.present? && + head :unauthorized unless current_user.present? && current_facility_group.facilities.where(id: current_facility.id).present? end def current_user_present? - return head :unauthorized unless current_user.present? + head :unauthorized unless current_user.present? end def validate_sync_approval_status_allowed diff --git a/app/controllers/concerns/api/v3/sync_to_user.rb b/app/controllers/concerns/api/v3/sync_to_user.rb index 0d3819b899..c9cbcb410b 100644 --- a/app/controllers/concerns/api/v3/sync_to_user.rb +++ b/app/controllers/concerns/api/v3/sync_to_user.rb @@ -2,46 +2,48 @@ module Api::V3::SyncToUser extend ActiveSupport::Concern included do - def region_records - model.syncable_to_region(current_sync_region) - end - def current_facility_records - Statsd.instance.time("current_facility_records.#{model.name}") do - region_records - .where(patient: prioritized_patients) - .updated_on_server_since(current_facility_processed_since, limit) + time(__method__) do + @current_facility_records ||= + model_sync_scope + .where(patient: current_facility.prioritized_patients.select(:id)) + .updated_on_server_since(current_facility_processed_since, limit) end end + # this is performance-critical code, be careful while refactoring it def other_facility_records - Statsd.instance.time("other_facility_records.#{model.name}") do - other_facilities_limit = limit - current_facility_records.count - - region_records - .where.not(patient: prioritized_patients) - .updated_on_server_since(other_facilities_processed_since, other_facilities_limit) + time(__method__) do + other_facilities_limit = limit - current_facility_records.size + @other_facility_records ||= + model_sync_scope + .where("patient_id = ANY (array(?))", + current_sync_region + .syncable_patients + .where.not(registration_facility: current_facility) + .select(:id)) + .updated_on_server_since(other_facilities_processed_since, other_facilities_limit) end end private + def model_sync_scope + model.for_sync + end + def model controller_name.classify.constantize end def records_to_sync - Statsd.instance.time("records_to_sync.#{model.name}") do + time(__method__) do current_facility_records + other_facility_records end end - def prioritized_patients - current_facility.registered_patients.with_discarded - end - def processed_until(records) - records.last.updated_at.strftime(APIController::TIME_WITHOUT_TIMEZONE_FORMAT) if records.present? + records.last.updated_at.strftime(APIController::TIME_WITHOUT_TIMEZONE_FORMAT) if records.any? end def response_process_token @@ -90,5 +92,13 @@ def sync_region_modified? return if process_token[:sync_region_id].blank? process_token[:sync_region_id] != requested_sync_region_id end + + def time(method_name, &block) + raise ArgumentError, "You must supply a block" unless block + + Statsd.instance.time("#{method_name}.#{model.name}") do + yield(block) + end + end end end diff --git a/app/models/appointment.rb b/app/models/appointment.rb index 509d69c0b1..7f280edb84 100644 --- a/app/models/appointment.rb +++ b/app/models/appointment.rb @@ -40,9 +40,7 @@ class Appointment < ApplicationRecord validates :device_created_at, presence: true validates :device_updated_at, presence: true - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } def self.all_overdue where(status: "scheduled") diff --git a/app/models/blood_pressure.rb b/app/models/blood_pressure.rb index 813ff47bd9..d21fb49c34 100644 --- a/app/models/blood_pressure.rb +++ b/app/models/blood_pressure.rb @@ -32,9 +32,7 @@ class BloodPressure < ApplicationRecord .where(arel_table[:diastolic].lt(THRESHOLDS[:hypertensive][:diastolic])) } - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } def critical? systolic >= THRESHOLDS[:critical][:systolic] || diastolic >= THRESHOLDS[:critical][:diastolic] diff --git a/app/models/blood_sugar.rb b/app/models/blood_sugar.rb index 1a524b75cf..a2cb03d6bc 100644 --- a/app/models/blood_sugar.rb +++ b/app/models/blood_sugar.rb @@ -30,10 +30,7 @@ class BloodSugar < ApplicationRecord V3_TYPES = %i[random post_prandial fasting].freeze scope :for_v3, -> { where(blood_sugar_type: V3_TYPES) } - - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } THRESHOLDS = { high: {random: 300, diff --git a/app/models/encounter.rb b/app/models/encounter.rb index be4b1af979..26a0ac2dd3 100644 --- a/app/models/encounter.rb +++ b/app/models/encounter.rb @@ -9,9 +9,7 @@ class Encounter < ApplicationRecord has_many :blood_pressures, through: :observations, source: :observable, source_type: "BloodPressure" has_many :blood_sugars, through: :observations, source: :observable, source_type: "BloodSugar" - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } def self.generate_id(facility_id, patient_id, encountered_on) UUIDTools::UUID diff --git a/app/models/facility.rb b/app/models/facility.rb index 17cb57c15a..49e26e2d60 100644 --- a/app/models/facility.rb +++ b/app/models/facility.rb @@ -215,6 +215,10 @@ def valid_block end end + def prioritized_patients + registered_patients.with_discarded + end + def self.localized_facility_size(facility_size) return unless facility_size I18n.t("activerecord.facility.facility_size.#{facility_size}", default: facility_size.capitalize) diff --git a/app/models/medical_history.rb b/app/models/medical_history.rb index 265b99f25a..4b8567d99c 100644 --- a/app/models/medical_history.rb +++ b/app/models/medical_history.rb @@ -29,9 +29,7 @@ class MedicalHistory < ApplicationRecord enum hypertension: MEDICAL_HISTORY_ANSWERS, _prefix: true enum diagnosed_with_hypertension: MEDICAL_HISTORY_ANSWERS, _prefix: true - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } def indicates_hypertension_risk? prior_heart_attack_boolean || prior_stroke_boolean diff --git a/app/models/patient.rb b/app/models/patient.rb index 4c171e9960..d54ac0da04 100644 --- a/app/models/patient.rb +++ b/app/models/patient.rb @@ -56,7 +56,8 @@ class Patient < ApplicationRecord attribute :call_result, :string - scope :syncable_to_region, ->(region) { region.syncable_patients } + scope :with_nested_sync_resources, -> { includes(:address, :phone_numbers, :business_identifiers) } + scope :for_sync, -> { with_discarded.with_nested_sync_resources } scope :search_by_address, ->(term) { joins(:address).merge(Address.search_by_street_or_village(term)) } scope :with_diabetes, -> { joins(:medical_history).merge(MedicalHistory.diabetes_yes).distinct } scope :with_hypertension, -> { joins(:medical_history).merge(MedicalHistory.hypertension_yes).distinct } diff --git a/app/models/prescription_drug.rb b/app/models/prescription_drug.rb index 6d970a93a3..05b047e8f1 100644 --- a/app/models/prescription_drug.rb +++ b/app/models/prescription_drug.rb @@ -21,9 +21,7 @@ class PrescriptionDrug < ApplicationRecord validates :is_protocol_drug, inclusion: {in: [true, false]} validates :is_deleted, inclusion: {in: [true, false]} - scope :syncable_to_region, ->(region) { - with_discarded.where(patient: Patient.syncable_to_region(region)) - } + scope :for_sync, -> { with_discarded } def self.prescribed_as_of(date) where("device_created_at <= ?", date.end_of_day) diff --git a/app/models/region.rb b/app/models/region.rb index d1f9d5ac96..070e58c0b1 100644 --- a/app/models/region.rb +++ b/app/models/region.rb @@ -100,10 +100,10 @@ def syncable_patients case region_type when "block" registered_patients.with_discarded - .union(assigned_patients.with_discarded) + .or(assigned_patients.with_discarded) .union(appointed_patients.with_discarded) else - registered_patients + registered_patients.with_discarded end end diff --git a/app/transformers/api/v3/facility_transformer.rb b/app/transformers/api/v3/facility_transformer.rb index 3bc9f67b74..860f549785 100644 --- a/app/transformers/api/v3/facility_transformer.rb +++ b/app/transformers/api/v3/facility_transformer.rb @@ -7,7 +7,9 @@ def to_response(facility) "enable_teleconsultation", "teleconsultation_phone_number", "teleconsultation_isd_code", - "teleconsultation_phone_numbers") + "teleconsultation_phone_numbers", + "organization_name", + "facility_group_name") .merge(config: {enable_diabetes_management: facility.enable_diabetes_management, enable_teleconsultation: facility.enable_teleconsultation}, protocol_id: facility.protocol.try(:id)) diff --git a/app/transformers/api/v3/patient_transformer.rb b/app/transformers/api/v3/patient_transformer.rb index e1a559d0ff..07e41b801a 100644 --- a/app/transformers/api/v3/patient_transformer.rb +++ b/app/transformers/api/v3/patient_transformer.rb @@ -59,10 +59,10 @@ def from_nested_request(payload_attributes) def to_nested_response(patient) Api::V3::Transformer.to_response(patient) - .except("address_id") - .except("registration_user_id") - .except("test_data") - .except("deleted_by_user_id") + .except("address_id", + "registration_user_id", + "test_data", + "deleted_by_user_id") .merge( "address" => Api::V3::Transformer.to_response(patient.address), "phone_numbers" => patient.phone_numbers.map do |phone_number| diff --git a/app/transformers/api/v3/transformer.rb b/app/transformers/api/v3/transformer.rb index 0e4c1db30c..256816fc80 100644 --- a/app/transformers/api/v3/transformer.rb +++ b/app/transformers/api/v3/transformer.rb @@ -1,31 +1,33 @@ class Api::V3::Transformer class << self - def from_request(attributes_of_payload) - rename_attributes(attributes_of_payload, key_mapping) + def from_request(payload_attributes) + rename_attributes(payload_attributes, from_request_key_mapping) end def to_response(model) - rename_attributes(model.attributes, inverted_key_mapping).as_json + rename_attributes(model.attributes, to_response_key_mapping).as_json end def rename_attributes(attributes, mapping) - mapping = mapping.with_indifferent_access - attributes - .to_hash - .except(*mapping.values) - .transform_keys! { |key| mapping[key] || key } - .with_indifferent_access + replace_keys(attributes.to_hash, mapping).with_indifferent_access end - def key_mapping + def replace_keys(hsh, mapping) + mapping.each do |k, v| + hsh[v] = hsh.delete(k) + end + hsh + end + + def from_request_key_mapping { "created_at" => "device_created_at", "updated_at" => "device_updated_at" } end - def inverted_key_mapping - key_mapping.invert + def to_response_key_mapping + from_request_key_mapping.invert end end end diff --git a/spec/controllers/api/v3/appointments_controller_spec.rb b/spec/controllers/api/v3/appointments_controller_spec.rb index e5104e77c7..e83879e6af 100644 --- a/spec/controllers/api/v3/appointments_controller_spec.rb +++ b/spec/controllers/api/v3/appointments_controller_spec.rb @@ -338,6 +338,8 @@ def create_record_list(n, options = {}) expect(response_1_records.count).to eq 4 expect(response_1_records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/blood_pressures_controller_spec.rb b/spec/controllers/api/v3/blood_pressures_controller_spec.rb index a7c09223de..6152fe312e 100644 --- a/spec/controllers/api/v3/blood_pressures_controller_spec.rb +++ b/spec/controllers/api/v3/blood_pressures_controller_spec.rb @@ -304,6 +304,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/blood_sugars_controller_spec.rb b/spec/controllers/api/v3/blood_sugars_controller_spec.rb index bf52b90e9f..9e7af97d29 100644 --- a/spec/controllers/api/v3/blood_sugars_controller_spec.rb +++ b/spec/controllers/api/v3/blood_sugars_controller_spec.rb @@ -283,6 +283,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/encounters_controller_spec.rb b/spec/controllers/api/v3/encounters_controller_spec.rb index b0c012d5ed..d48253981d 100644 --- a/spec/controllers/api/v3/encounters_controller_spec.rb +++ b/spec/controllers/api/v3/encounters_controller_spec.rb @@ -156,6 +156,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/medical_histories_controller_spec.rb b/spec/controllers/api/v3/medical_histories_controller_spec.rb index fa798941f3..263a4f3825 100644 --- a/spec/controllers/api/v3/medical_histories_controller_spec.rb +++ b/spec/controllers/api/v3/medical_histories_controller_spec.rb @@ -61,6 +61,8 @@ def create_record_list(n, options = {}) expect(response_1_records.count).to eq 4 expect(response_1_records.map(&:patient).to_set).to eq Set[patient_in_request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/patients_controller_spec.rb b/spec/controllers/api/v3/patients_controller_spec.rb index 3ce84d44c0..8b8f07a3e9 100644 --- a/spec/controllers/api/v3/patients_controller_spec.rb +++ b/spec/controllers/api/v3/patients_controller_spec.rb @@ -357,6 +357,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:registration_facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v3/prescription_drugs_controller_spec.rb b/spec/controllers/api/v3/prescription_drugs_controller_spec.rb index 91ff95622b..31dbfb8ea2 100644 --- a/spec/controllers/api/v3/prescription_drugs_controller_spec.rb +++ b/spec/controllers/api/v3/prescription_drugs_controller_spec.rb @@ -98,6 +98,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/api/v4/blood_sugars_controller_spec.rb b/spec/controllers/api/v4/blood_sugars_controller_spec.rb index d1cc0841ed..d0a1652ccf 100644 --- a/spec/controllers/api/v4/blood_sugars_controller_spec.rb +++ b/spec/controllers/api/v4/blood_sugars_controller_spec.rb @@ -270,6 +270,8 @@ def create_record_list(n, options = {}) expect(records.count).to eq 4 expect(records.map(&:facility).to_set).to eq Set[request_facility] + reset_controller + # GET request 2 get :sync_to_user, params: {limit: 4, process_token: response_1_body["process_token"]} response_2_body = JSON(response.body) diff --git a/spec/controllers/shared_examples/shared_spec_for_sync_controller.rb b/spec/controllers/shared_examples/shared_spec_for_sync_controller.rb index f68ef134fb..37e6c539bd 100644 --- a/spec/controllers/shared_examples/shared_spec_for_sync_controller.rb +++ b/spec/controllers/shared_examples/shared_spec_for_sync_controller.rb @@ -250,6 +250,8 @@ def discard_patient(record) response_1 = JSON(response.body) + reset_controller + get :sync_to_user, params: { process_token: response_1["process_token"], limit: 8 @@ -509,6 +511,8 @@ def discard_patient(record) request.env["HTTP_X_SYNC_REGION_ID"] = requested_sync_region_id process_token = make_process_token(response_process_token.merge(sync_region_id: process_token_sync_region_id)) + reset_controller + get :sync_to_user, params: {process_token: process_token} response_record_ids = JSON(response.body)[response_key].map { |r| r["id"] } diff --git a/spec/models/appointment_spec.rb b/spec/models/appointment_spec.rb index 5d53c235e5..683a3009a2 100644 --- a/spec/models/appointment_spec.rb +++ b/spec/models/appointment_spec.rb @@ -105,28 +105,11 @@ end end - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - facility = create(:facility, facility_group: facility_group) - patient = create(:patient) - other_patient = create(:patient) - - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - appointments = [ - create(:appointment, patient: patient, facility: facility), - create(:appointment, patient: patient, facility: facility).tap(&:discard), - create(:appointment, patient: patient) - ] - - _other_appointments = [ - create(:appointment, patient: other_patient, facility: facility), - create(:appointment, patient: other_patient, facility: facility).tap(&:discard), - create(:appointment, patient: other_patient) - ] - - expect(Appointment.syncable_to_region(facility_group)).to contain_exactly(*appointments) + describe ".for_sync" do + it "includes discarded appointments" do + discarded_appointment = create(:appointment, deleted_at: Time.now) + + expect(described_class.for_sync).to include(discarded_appointment) end end end diff --git a/spec/models/blood_pressure_spec.rb b/spec/models/blood_pressure_spec.rb index cad1851a8e..9677b40f51 100644 --- a/spec/models/blood_pressure_spec.rb +++ b/spec/models/blood_pressure_spec.rb @@ -40,28 +40,11 @@ end end - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - facility = create(:facility, facility_group: facility_group) - patient = create(:patient) - other_patient = create(:patient) - - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - blood_pressures = [ - create(:blood_pressure, patient: patient, facility: facility), - create(:blood_pressure, patient: patient, facility: facility).tap(&:discard), - create(:blood_pressure, patient: patient) - ] - - _other_blood_pressures = [ - create(:blood_pressure, patient: other_patient, facility: facility), - create(:blood_pressure, patient: other_patient, facility: facility).tap(&:discard), - create(:blood_pressure, patient: other_patient) - ] - - expect(BloodPressure.syncable_to_region(facility_group)).to contain_exactly(*blood_pressures) + describe ".for_sync" do + it "includes discarded blood pressures" do + discarded_bp = create(:blood_pressure, deleted_at: Time.now) + + expect(described_class.for_sync).to include(discarded_bp) end end end diff --git a/spec/models/blood_sugar_spec.rb b/spec/models/blood_sugar_spec.rb index 84cee1aa7e..439e45d09f 100644 --- a/spec/models/blood_sugar_spec.rb +++ b/spec/models/blood_sugar_spec.rb @@ -37,7 +37,7 @@ end end - describe "scopes" do + describe "Scopes" do let!(:fasting) { create(:blood_sugar, blood_sugar_type: :fasting) } let!(:random) { create(:blood_sugar, blood_sugar_type: :random) } let!(:post_prandial) { create(:blood_sugar, blood_sugar_type: :post_prandial) } @@ -50,28 +50,11 @@ end end - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - facility = create(:facility, facility_group: facility_group) - patient = create(:patient) - other_patient = create(:patient) + describe ".for_sync" do + it "includes discarded blood sugars" do + discarded_blood_sugar = create(:blood_sugar, deleted_at: Time.now) - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - blood_sugars = [ - create(:blood_sugar, patient: patient, facility: facility), - create(:blood_sugar, patient: patient, facility: facility).tap(&:discard), - create(:blood_sugar, patient: patient) - ] - - _other_blood_sugars = [ - create(:blood_sugar, patient: other_patient, facility: facility), - create(:blood_sugar, patient: other_patient, facility: facility).tap(&:discard), - create(:blood_sugar, patient: other_patient) - ] - - expect(BloodSugar.syncable_to_region(facility_group)).to contain_exactly(*blood_sugars) + expect(described_class.for_sync).to include(discarded_blood_sugar) end end end diff --git a/spec/models/encounter_spec.rb b/spec/models/encounter_spec.rb index ca4a9b0f62..1517b68d5f 100644 --- a/spec/models/encounter_spec.rb +++ b/spec/models/encounter_spec.rb @@ -34,28 +34,11 @@ end describe "Scopes" do - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - facility = create(:facility, facility_group: facility_group) - patient = create(:patient) - other_patient = create(:patient) - - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - encounters = [ - create(:encounter, patient: patient, facility: facility), - create(:encounter, patient: patient, facility: facility).tap(&:discard), - create(:encounter, patient: patient) - ] - - _other_encounters = [ - create(:encounter, patient: other_patient, facility: facility), - create(:encounter, patient: other_patient, facility: facility).tap(&:discard), - create(:encounter, patient: other_patient) - ] - - expect(Encounter.syncable_to_region(facility_group)).to contain_exactly(*encounters) + describe ".for_sync" do + it "includes discarded encounters" do + discarded_encounter = create(:encounter, deleted_at: Time.now) + + expect(described_class.for_sync).to include(discarded_encounter) end end end diff --git a/spec/models/medical_history_spec.rb b/spec/models/medical_history_spec.rb index d1b9cafe19..0c18937243 100644 --- a/spec/models/medical_history_spec.rb +++ b/spec/models/medical_history_spec.rb @@ -11,26 +11,11 @@ end describe "Scopes" do - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - patient = create(:patient) - other_patient = create(:patient) + describe ".for_sync" do + it "includes discarded medical histories" do + discarded_medical_history = create(:medical_history, deleted_at: Time.now) - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - MedicalHistory.destroy_all - medical_histories = [ - create(:medical_history, patient: patient), - create(:medical_history, patient: patient).tap(&:discard) - ] - - _other_medical_histories = [ - create(:medical_history, patient: other_patient), - create(:medical_history, patient: other_patient).tap(&:discard) - ] - - expect(MedicalHistory.syncable_to_region(facility_group)).to contain_exactly(*medical_histories) + expect(described_class.for_sync).to include(discarded_medical_history) end end end diff --git a/spec/models/patient_spec.rb b/spec/models/patient_spec.rb index 51ba76dadd..c42c6c6e9e 100644 --- a/spec/models/patient_spec.rb +++ b/spec/models/patient_spec.rb @@ -321,27 +321,19 @@ end end - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - other_facility_group = create(:facility_group) - - facility = create(:facility, facility_group: facility_group) - other_facility = create(:facility, facility_group: other_facility_group) - - patients = [ - create(:patient, registration_facility: facility), - create(:patient, registration_facility: facility).tap(&:discard), - create(:patient, registration_facility: facility, assigned_facility: other_facility) - ] + describe ".for_sync" do + it "includes discarded patients" do + discarded_patient = create(:patient, deleted_at: Time.now) - _other_patients = [ - create(:patient, registration_facility: other_facility), - create(:patient, registration_facility: other_facility).tap(&:discard), - create(:patient, registration_facility: other_facility, assigned_facility: facility) - ] + expect(described_class.for_sync).to include(discarded_patient) + end + + it "includes nested sync resources" do + _discarded_patient = create(:patient, deleted_at: Time.now) - expect(Patient.syncable_to_region(facility_group)).to contain_exactly(*patients) + expect(described_class.for_sync.first.association(:address).loaded?).to eq true + expect(described_class.for_sync.first.association(:phone_numbers).loaded?).to eq true + expect(described_class.for_sync.first.association(:business_identifiers).loaded?).to eq true end end end diff --git a/spec/models/prescription_drug_spec.rb b/spec/models/prescription_drug_spec.rb index cbfa37c568..4e8ec54a29 100644 --- a/spec/models/prescription_drug_spec.rb +++ b/spec/models/prescription_drug_spec.rb @@ -11,37 +11,20 @@ it { should belong_to(:teleconsultation).optional } end - describe "Behavior" do - it_behaves_like "a record that is deletable" - end - describe "Scopes" do - describe ".syncable_to_region" do - it "returns all patients registered in the region" do - facility_group = create(:facility_group) - facility = create(:facility, facility_group: facility_group) - patient = create(:patient) - other_patient = create(:patient) - - allow(Patient).to receive(:syncable_to_region).with(facility_group).and_return([patient]) - - prescription_drugs = [ - create(:prescription_drug, patient: patient, facility: facility), - create(:prescription_drug, patient: patient, facility: facility).tap(&:discard), - create(:prescription_drug, patient: patient) - ] - - _other_prescription_drugs = [ - create(:prescription_drug, patient: other_patient, facility: facility), - create(:prescription_drug, patient: other_patient, facility: facility).tap(&:discard), - create(:prescription_drug, patient: other_patient) - ] - - expect(PrescriptionDrug.syncable_to_region(facility_group)).to contain_exactly(*prescription_drugs) + describe ".for_sync" do + it "includes discarded prescription drugs" do + discarded_prescription_drug = create(:prescription_drug, deleted_at: Time.now) + + expect(described_class.for_sync).to include(discarded_prescription_drug) end end end + describe "Behavior" do + it_behaves_like "a record that is deletable" + end + describe ".prescribed_as_of" do def remove_drug(prescription_drug, time) prescription_drug.update(is_deleted: true, device_updated_at: time) diff --git a/spec/utils.rb b/spec/utils.rb index 30d484bf13..a53d486c02 100644 --- a/spec/utils.rb +++ b/spec/utils.rb @@ -20,7 +20,12 @@ def to_json_and_back def with_payload_keys Api::V3::Transformer.rename_attributes( - self, Api::V3::Transformer.inverted_key_mapping + self, Api::V3::Transformer.to_response_key_mapping ) end end + +def reset_controller + controller.instance_variable_set(:@current_facility_records, nil) + controller.instance_variable_set(:@other_facility_records, nil) +end