Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # frozen_string_literal: true
- require 'csv'
- module Reports
- class GenerateAggregateReport
- def perform(admin_id:, include_incomplete_assessment_data:, current_user_id:, start_date: nil, end_date: nil)
- @admin_id = admin_id
- @start_date = start_date
- @end_date = end_date
- @include_incomplete_assessment_data = include_incomplete_assessment_data
- @current_user_id = current_user_id
- generate_report
- media_file = create_media_file(current_user_id)
- send_email(media_file, AdminUser.find(current_user_id).dmail)
- delete_tmp_files
- end
- private
- def send_email(media_file, email)
- ServiceMailer.aggregate_report(media_file, email).deliver
- end
- def create_media_file(current_user_id)
- media_file = MediaFile.find_or_create_by(name: csv_file_name,
- admin_user_id: current_user_id)
- media_file.update!(
- asset: File.open(tmp_file_name),
- asset_file_name: csv_file_name,
- allow_others_to_copy: NO,
- public: false,
- category: :admin_report
- )
- media_file
- end
- def protocol_ids
- @protocol_ids ||= ::Health::Protocol.where(owner_id: clinic_admin_ids).ids
- end
- def test_ids
- @test_ids ||= tests.ids
- end
- def tests
- @tests ||= Test.format_html5.where.not(id: Test::Sar.id).order(:id)
- end
- def questionnaires
- return @questionnaires if @questionnaires
- @questionnaires = {}
- ::Health::Questionnaire.where(id: questionnaire_ids).each do |questionnaire|
- @questionnaires[questionnaire.id] = I18n.t(questionnaire.questionnaire_type)
- end
- @questionnaires
- end
- def questionnaire_ids
- @questionnaire_ids ||= BatchPage.joins(:questionnaire).where(admin_user_id: clinic_admin_ids)
- .pluck(:questionnaire_id).uniq.compact.sort
- end
- def clinic_admin_ids
- @clinic_admin_ids ||= ::Health::ClinicAdmin.find(@admin_id).related_clinic_admins.ids
- end
- def scope
- return @scope if @scope
- @scope = ::Health::ProtocolSession.where(protocol_id: protocol_ids)
- @scope = @scope.includes(user: :admin_user_detail, protocol: :assessments)
- .includes(:status_trackings)
- .includes(reports: :test_scores)
- .includes(reports: :user_answers)
- .includes(reports: :batch)
- @scope = @scope.where('health_protocol_sessions.created_at >= ?', @start_date) if @start_date
- @scope = @scope.where('health_protocol_sessions.created_at <= ?', @end_date) if @end_date
- unless @include_incomplete_assessment_data
- @scope = @scope.joins(:reports).where.not(sessions: { id: nil }).distinct
- end
- @scope
- end
- def comparative_group(patient, date)
- details = patient.details
- return nil if details&.age.nil? || details&.gender.nil?
- age = details.age(date)
- gender = details.gender.pluralize
- data = ::Experiment::Healthcare.demographic_options(age, gender)
- "#{data[:gender]}, #{data[:age]}"
- end
- def questionnaire_score(report, questionnaire)
- return if questionnaire.nil?
- answers = report.user_answers.map do |answer|
- { question_position: answer.question.position, answer: answer.question_type_casted_value }
- end
- calculation = Health::Questionnaire.calculation(
- questionnaire.questionnaire_type,
- { answers: answers, gender: report.admin_user.details.gender }
- ).to_h
- calculation[:score]
- end
- def session_row(protocol_session)
- patient = protocol_session.user
- protocol = protocol_session.protocol
- return [] if patient.nil? || protocol.nil?
- status_trackings = protocol_session.status_trackings
- started_at = status_trackings.find_by(status_update: :session_started)&.created_at
- completed_at = status_trackings.find_by(status_update: :session_completed)&.created_at
- row = [patient.client_id, patient.birthdate, comparative_group(patient, protocol_session.created_at)]
- row += [patient.owner&.dmail, protocol_session.created_by, protocol_session.created_at, started_at, completed_at]
- row += [protocol.name, "#{protocol_session.reports.count}/#{protocol.assessments.count}"]
- session_questionnaires = {}
- protocol_session.reports.each do |report|
- questionnaire = report.batch.main_questionnaire
- next unless questionnaire
- session_questionnaires[questionnaire.id] = questionnaire_score(report, questionnaire)
- end
- questionnaires.each do |questionnaire_id, _name|
- row << (session_questionnaires[questionnaire_id] if session_questionnaires.key?(questionnaire_id))
- end
- test_scores = protocol_session.reports.flat_map(&:test_scores)
- test_ids.each do |test_id|
- score = test_scores.find { |test_score| test_score.test_id == test_id }
- row += if score
- score_data = score.calc_score_data
- [score_data[:raw], score_data[:standard], score_data[:percentile],
- score_data[:adjusted_raw], score_data[:adjusted_standard],
- score_data[:adjusted_percentile], (score.test_duration / 1000).round]
- else
- [] * 7
- end
- end
- row
- end
- def generate_report
- CSV.open(tmp_file_name, 'w') do |csv|
- csv << csv_titles
- clinic_admin_ids.each do |clinic_admin_id|
- clinic_admin = ::Health::ClinicAdmin.find(clinic_admin_id)
- clinic_name = clinic_admin.clinic_name
- clinic_protocols = ::Health::Protocol.where(owner_id: clinic_admin_id)
- clinic_scope = scope.where(protocol_id: clinic_protocols.ids)
- clinic_scope.find_each.with_index do |protocol_session, index|
- csv << ([clinic_admin_id, clinic_name] + session_row(protocol_session))
- csv.flush
- sleep(0.5) if (index % 50 == 0)
- end
- end
- end
- end
- def tmp_file_name
- @tmp_file_name ||= "tmp/#{UUID.generate}_aggregate_report.csv"
- end
- def csv_file_name
- @csv_file_name ||= "aggregate_report_#{@admin_id}_#{Time.current.to_formatted_s(:number)}.csv"
- end
- def delete_tmp_files
- FileUtils.rm_f(tmp_file_name)
- end
- def csv_titles
- titles = ['Admin ID', 'Clinic Name', 'Patient ID', 'Date of Birth', 'Comparative Group', 'Provider/Practitioner',
- 'Administration Method', 'Time administered at', 'Session Start', 'Session Completed',
- 'Protocol Name', 'Assessments Completed']
- questionnaires.each do |_questionnaire_id, questionnaire_name|
- titles << "#{questionnaire_name} Score"
- end
- tests.each do |test|
- test_name = test.name
- titles += ["#{test_name} Raw", "#{test_name} standard", "#{test_name} percentile", "#{test_name} adjusted_raw",
- "#{test_name} adjusted_standard", "#{test_name} adjusted_percentile", "#{test_name} duration (time)"]
- end
- titles
- end
- end
- end
- module Health
- class ClinicAdmin < ::Health::User
- def related_clinic_admins
- ::Health::ClinicAdmin.joins(:admin_user_detail)
- .where(id: id)
- .or(::Health::ClinicAdmin.where(admin_user_details: { billing_admin_user_id: id }))
- end
- end
- end
- current_admin_user = AdminUser.find(1)
- admin_ids = [277673,255226,255222,255220,255221]
- admin_ids.each do |admin_id|
- ::Reports::GenerateAggregateReport.new.perform(admin_id: admin_id, start_date: nil, end_date: nil,
- current_user_id: current_admin_user,
- include_incomplete_assessment_data: true)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement