Advertisement
andrey_zavyalov

Untitled

Jan 29th, 2024
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.91 KB | None | 0 0
  1. # frozen_string_literal: true
  2.  
  3. require 'csv'
  4.  
  5. module Reports
  6. class GenerateAggregateReport
  7. def perform(admin_id:, include_incomplete_assessment_data:, current_user_id:, start_date: nil, end_date: nil)
  8. @admin_id = admin_id
  9. @start_date = start_date
  10. @end_date = end_date
  11. @include_incomplete_assessment_data = include_incomplete_assessment_data
  12. @current_user_id = current_user_id
  13.  
  14. generate_report
  15. media_file = create_media_file(current_user_id)
  16. send_email(media_file, AdminUser.find(current_user_id).dmail)
  17. delete_tmp_files
  18. end
  19.  
  20. private
  21.  
  22. def send_email(media_file, email)
  23. ServiceMailer.aggregate_report(media_file, email).deliver
  24. end
  25.  
  26. def create_media_file(current_user_id)
  27. media_file = MediaFile.find_or_create_by(name: csv_file_name,
  28. admin_user_id: current_user_id)
  29. media_file.update!(
  30. asset: File.open(tmp_file_name),
  31. asset_file_name: csv_file_name,
  32. allow_others_to_copy: NO,
  33. public: false,
  34. category: :admin_report
  35. )
  36. media_file
  37. end
  38.  
  39. def protocol_ids
  40. @protocol_ids ||= ::Health::Protocol.where(owner_id: clinic_admin_ids).ids
  41. end
  42.  
  43. def test_ids
  44. @test_ids ||= tests.ids
  45. end
  46.  
  47. def tests
  48. @tests ||= Test.format_html5.where.not(id: Test::Sar.id).order(:id)
  49. end
  50.  
  51. def questionnaires
  52. return @questionnaires if @questionnaires
  53.  
  54. @questionnaires = {}
  55. ::Health::Questionnaire.where(id: questionnaire_ids).each do |questionnaire|
  56. @questionnaires[questionnaire.id] = I18n.t(questionnaire.questionnaire_type)
  57. end
  58.  
  59. @questionnaires
  60. end
  61.  
  62. def questionnaire_ids
  63. @questionnaire_ids ||= BatchPage.joins(:questionnaire).where(admin_user_id: clinic_admin_ids)
  64. .pluck(:questionnaire_id).uniq.compact.sort
  65. end
  66.  
  67. def clinic_admin_ids
  68. @clinic_admin_ids ||= ::Health::ClinicAdmin.find(@admin_id).related_clinic_admins.ids
  69. end
  70.  
  71. def scope
  72. return @scope if @scope
  73.  
  74. @scope = ::Health::ProtocolSession.where(protocol_id: protocol_ids)
  75. @scope = @scope.includes(user: :admin_user_detail, protocol: :assessments)
  76. .includes(:status_trackings)
  77. .includes(reports: :test_scores)
  78. .includes(reports: :user_answers)
  79. .includes(reports: :batch)
  80.  
  81. @scope = @scope.where('health_protocol_sessions.created_at >= ?', @start_date) if @start_date
  82. @scope = @scope.where('health_protocol_sessions.created_at <= ?', @end_date) if @end_date
  83.  
  84. unless @include_incomplete_assessment_data
  85. @scope = @scope.joins(:reports).where.not(sessions: { id: nil }).distinct
  86. end
  87.  
  88. @scope
  89. end
  90.  
  91. def comparative_group(patient, date)
  92. details = patient.details
  93.  
  94. return nil if details&.age.nil? || details&.gender.nil?
  95.  
  96. age = details.age(date)
  97. gender = details.gender.pluralize
  98. data = ::Experiment::Healthcare.demographic_options(age, gender)
  99. "#{data[:gender]}, #{data[:age]}"
  100. end
  101.  
  102. def questionnaire_score(report, questionnaire)
  103. return if questionnaire.nil?
  104.  
  105. answers = report.user_answers.map do |answer|
  106. { question_position: answer.question.position, answer: answer.question_type_casted_value }
  107. end
  108.  
  109. calculation = Health::Questionnaire.calculation(
  110. questionnaire.questionnaire_type,
  111. { answers: answers, gender: report.admin_user.details.gender }
  112. ).to_h
  113.  
  114. calculation[:score]
  115. end
  116.  
  117. def session_row(protocol_session)
  118. patient = protocol_session.user
  119. protocol = protocol_session.protocol
  120.  
  121. return [] if patient.nil? || protocol.nil?
  122.  
  123. status_trackings = protocol_session.status_trackings
  124. started_at = status_trackings.find_by(status_update: :session_started)&.created_at
  125. completed_at = status_trackings.find_by(status_update: :session_completed)&.created_at
  126.  
  127. row = [patient.client_id, patient.birthdate, comparative_group(patient, protocol_session.created_at)]
  128. row += [patient.owner&.dmail, protocol_session.created_by, protocol_session.created_at, started_at, completed_at]
  129. row += [protocol.name, "#{protocol_session.reports.count}/#{protocol.assessments.count}"]
  130.  
  131. session_questionnaires = {}
  132. protocol_session.reports.each do |report|
  133. questionnaire = report.batch.main_questionnaire
  134. next unless questionnaire
  135.  
  136. session_questionnaires[questionnaire.id] = questionnaire_score(report, questionnaire)
  137. end
  138.  
  139. questionnaires.each do |questionnaire_id, _name|
  140. row << (session_questionnaires[questionnaire_id] if session_questionnaires.key?(questionnaire_id))
  141. end
  142.  
  143. test_scores = protocol_session.reports.flat_map(&:test_scores)
  144. test_ids.each do |test_id|
  145. score = test_scores.find { |test_score| test_score.test_id == test_id }
  146.  
  147. row += if score
  148. score_data = score.calc_score_data
  149. [score_data[:raw], score_data[:standard], score_data[:percentile],
  150. score_data[:adjusted_raw], score_data[:adjusted_standard],
  151. score_data[:adjusted_percentile], (score.test_duration / 1000).round]
  152. else
  153. [] * 7
  154. end
  155. end
  156.  
  157. row
  158. end
  159.  
  160. def generate_report
  161. CSV.open(tmp_file_name, 'w') do |csv|
  162. csv << csv_titles
  163.  
  164. clinic_admin_ids.each do |clinic_admin_id|
  165. clinic_admin = ::Health::ClinicAdmin.find(clinic_admin_id)
  166. clinic_name = clinic_admin.clinic_name
  167. clinic_protocols = ::Health::Protocol.where(owner_id: clinic_admin_id)
  168. clinic_scope = scope.where(protocol_id: clinic_protocols.ids)
  169.  
  170. clinic_scope.find_each.with_index do |protocol_session, index|
  171. csv << ([clinic_admin_id, clinic_name] + session_row(protocol_session))
  172. csv.flush
  173. sleep(0.5) if (index % 50 == 0)
  174. end
  175. end
  176. end
  177. end
  178.  
  179. def tmp_file_name
  180. @tmp_file_name ||= "tmp/#{UUID.generate}_aggregate_report.csv"
  181. end
  182.  
  183. def csv_file_name
  184. @csv_file_name ||= "aggregate_report_#{@admin_id}_#{Time.current.to_formatted_s(:number)}.csv"
  185. end
  186.  
  187. def delete_tmp_files
  188. FileUtils.rm_f(tmp_file_name)
  189. end
  190.  
  191. def csv_titles
  192. titles = ['Admin ID', 'Clinic Name', 'Patient ID', 'Date of Birth', 'Comparative Group', 'Provider/Practitioner',
  193. 'Administration Method', 'Time administered at', 'Session Start', 'Session Completed',
  194. 'Protocol Name', 'Assessments Completed']
  195.  
  196. questionnaires.each do |_questionnaire_id, questionnaire_name|
  197. titles << "#{questionnaire_name} Score"
  198. end
  199.  
  200. tests.each do |test|
  201. test_name = test.name
  202. titles += ["#{test_name} Raw", "#{test_name} standard", "#{test_name} percentile", "#{test_name} adjusted_raw",
  203. "#{test_name} adjusted_standard", "#{test_name} adjusted_percentile", "#{test_name} duration (time)"]
  204. end
  205.  
  206. titles
  207. end
  208. end
  209. end
  210.  
  211.  
  212. module Health
  213. class ClinicAdmin < ::Health::User
  214. def related_clinic_admins
  215. ::Health::ClinicAdmin.joins(:admin_user_detail)
  216. .where(id: id)
  217. .or(::Health::ClinicAdmin.where(admin_user_details: { billing_admin_user_id: id }))
  218. end
  219. end
  220. end
  221.  
  222.  
  223. current_admin_user = AdminUser.find(1)
  224.  
  225. admin_ids = [277673,255226,255222,255220,255221]
  226. admin_ids.each do |admin_id|
  227. ::Reports::GenerateAggregateReport.new.perform(admin_id: admin_id, start_date: nil, end_date: nil,
  228. current_user_id: current_admin_user,
  229. include_incomplete_assessment_data: true)
  230. end
  231.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement