renalware-core 2.0.64 → 2.0.67

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/renalware/application.js.erb +2 -2
  3. data/app/controllers/renalware/admin/users_controller.rb +1 -1
  4. data/app/controllers/renalware/api/ukrdc/patients_controller.rb +14 -67
  5. data/app/controllers/renalware/drugs/drugs_controller.rb +1 -1
  6. data/app/controllers/renalware/hd/protocols_controller.rb +1 -1
  7. data/app/controllers/renalware/patients/bookmarks_controller.rb +16 -5
  8. data/app/controllers/renalware/snippets/snippets_controller.rb +1 -1
  9. data/app/controllers/renalware/system/user_feedback_controller.rb +1 -1
  10. data/app/documents/renalware/hd/session_document.rb +1 -0
  11. data/app/models/renalware/admissions/consult_query.rb +1 -1
  12. data/app/models/renalware/clinical/dry_weight.rb +4 -0
  13. data/app/models/renalware/clinical/patient.rb +5 -0
  14. data/app/models/renalware/clinical/patient_dry_weights_query.rb +1 -1
  15. data/app/models/renalware/directory/person_query.rb +1 -1
  16. data/app/models/renalware/hd/mdm_patients_query.rb +1 -1
  17. data/app/models/renalware/hd/patient.rb +6 -0
  18. data/app/models/renalware/hd/patient_listener.rb +8 -0
  19. data/app/models/renalware/hd/sessions/ongoing_query.rb +1 -1
  20. data/app/models/renalware/hd/sessions/patient_query.rb +1 -1
  21. data/app/models/renalware/letters/descriptions/search_query.rb +1 -1
  22. data/app/models/renalware/letters/letter_factory.rb +55 -2
  23. data/app/models/renalware/letters/letter_query.rb +1 -1
  24. data/app/models/renalware/letters/recipient.rb +11 -0
  25. data/app/models/renalware/letters/resolve_default_electronic_ccs.rb +47 -0
  26. data/app/models/renalware/low_clearance/mdm_patients_query.rb +1 -1
  27. data/app/models/renalware/medications/prescriptions_by_drug_type_query.rb +1 -1
  28. data/app/models/renalware/medications/prescriptions_query.rb +1 -1
  29. data/app/models/renalware/patients/bookmarks_query.rb +49 -0
  30. data/app/models/renalware/patients/patient_search.rb +1 -1
  31. data/app/models/renalware/pd/mdm_patients_query.rb +1 -1
  32. data/app/models/renalware/renal/prd_descriptions/search_query.rb +1 -1
  33. data/app/models/renalware/transplants/live_donors_query.rb +1 -1
  34. data/app/models/renalware/transplants/mdm_patients_query.rb +1 -1
  35. data/app/models/renalware/transplants/registrations/wait_list_query.rb +1 -1
  36. data/app/models/renalware/ukrdc/create_encrypted_patient_xml_files.rb +13 -11
  37. data/app/models/renalware/ukrdc/create_patient_xml_file.rb +33 -21
  38. data/app/models/renalware/ukrdc/transmission_log.rb +1 -1
  39. data/app/models/renalware/ukrdc/xml_renderer.rb +126 -0
  40. data/app/presenters/renalware/clinical/dry_weight_presenter.rb +4 -0
  41. data/app/presenters/renalware/clinical/dry_weights_presenter.rb +15 -9
  42. data/app/presenters/renalware/ukrdc/modality_presenter.rb +8 -0
  43. data/app/presenters/renalware/ukrdc/patient_presenter.rb +9 -6
  44. data/app/views/renalware/api/ukrdc/patients/_clinical_relationships.xml.builder +4 -4
  45. data/app/views/renalware/api/ukrdc/patients/_encounters.xml.builder +9 -9
  46. data/app/views/renalware/api/ukrdc/patients/_family_histories.xml.builder +4 -4
  47. data/app/views/renalware/api/ukrdc/patients/_patient.xml.builder +1 -20
  48. data/app/views/renalware/api/ukrdc/patients/_program_memberships.xml.builder +4 -4
  49. data/app/views/renalware/api/ukrdc/patients/_surveys.xml.builder +4 -4
  50. data/app/views/renalware/api/ukrdc/patients/encounters/_hd_session.xml.builder +31 -31
  51. data/app/views/renalware/api/ukrdc/patients/encounters/_treatment.xml.builder +34 -0
  52. data/app/views/renalware/api/ukrdc/patients/lab_orders/_lab_order.xml.builder +1 -1
  53. data/app/views/renalware/api/ukrdc/patients/show.xml.builder +1 -1
  54. data/app/views/renalware/hd/mdm/_summary.html.slim +12 -4
  55. data/app/views/renalware/hd/protocols/_recent_pathology.html.slim +4 -0
  56. data/app/views/renalware/hd/sessions/_form.html.slim +1 -0
  57. data/app/views/renalware/mdm/_prescription_buttons.html.slim +15 -0
  58. data/app/views/renalware/mdm/_prescriptions.html.slim +1 -8
  59. data/app/views/renalware/patients/bookmarks/_bookmark.html.slim +16 -0
  60. data/app/views/renalware/patients/bookmarks/_table.html.slim +20 -0
  61. data/app/views/renalware/patients/bookmarks/index.html.slim +3 -1
  62. data/app/views/renalware/transplants/mdm/_prescriptions.html.slim +1 -8
  63. data/config/initializers/core_extensions.rb +1 -1
  64. data/config/initializers/renalware.rb +3 -0
  65. data/config/locales/renalware/hd/session.en.yml +7 -0
  66. data/config/locales/renalware/patients/bookmarks.en.yml +12 -0
  67. data/config/locales/renalware/patients/side_menu.en.yml +1 -1
  68. data/db/migrate/20150119160039_create_versions.rb +3 -3
  69. data/db/migrate/20150120155952_create_problem_versions.rb +3 -3
  70. data/db/migrate/20150203161438_create_medication_prescription_versions.rb +3 -3
  71. data/db/migrate/20150515155052_users_have_and_belong_to_many_roles.rb +3 -1
  72. data/db/migrate/20160120203747_create_access_versions.rb +3 -3
  73. data/db/migrate/20160121175711_create_hd_versions.rb +3 -3
  74. data/db/migrate/20170217141529_create_clinic_versions.rb +3 -3
  75. data/db/migrate/20170217161409_create_patient_versions.rb +3 -3
  76. data/db/migrate/20170605102519_create_clinical_versions.rb +3 -3
  77. data/db/migrate/20171002175804_add_rr_columns_to_transplant_registration_status_descriptions.rb +9 -7
  78. data/db/migrate/20171003093347_create_hospital_wards.rb +14 -12
  79. data/db/migrate/20171003111228_create_aki_alert_actions.rb +6 -4
  80. data/db/migrate/20171003122425_create_renal_aki_alerts.rb +18 -16
  81. data/db/migrate/20171004092235_create_hd_dialysates.rb +9 -7
  82. data/db/migrate/20171004110909_add_dialysate_id_to_profile_and_session.rb +6 -4
  83. data/db/migrate/20171005081224_create_reporting_bone_audit.rb +3 -1
  84. data/db/migrate/20171005091202_reporting_audit_changes.rb +5 -3
  85. data/db/migrate/20171005130109_create_medication_current_prescriptions.rb +3 -1
  86. data/db/migrate/20171005144505_create_reporting_anaemia_audit.rb +3 -1
  87. data/db/migrate/20171009104106_add_legacy_patient_id_to_patients.rb +4 -2
  88. data/db/migrate/20171009181615_add_columns_to_drug_drugs.rb +6 -4
  89. data/db/migrate/20171012110133_create_research_studies.rb +19 -17
  90. data/db/migrate/20171012143050_create_research_study_participants.rb +27 -25
  91. data/db/migrate/20171013145849_set_patients_secure_id.rb +12 -10
  92. data/db/migrate/20171016152223_add_index_to_diary_slots.rb +14 -12
  93. data/db/migrate/20171017132738_add_unique_indexes_to_local_patient_ids.rb +11 -9
  94. data/db/migrate/20171017171625_update_hd_overall_audit_view.rb +7 -5
  95. data/db/migrate/20171101121130_create_function_to_render_audit_view_as_json.rb +6 -4
  96. data/db/migrate/20171101162244_create_consults.rb +21 -19
  97. data/db/migrate/20171106100216_create_pd_audit_view.rb +3 -1
  98. data/db/migrate/20171109084751_remove_local_patient_id_unique_idx.rb +11 -9
  99. data/db/migrate/20171113120217_add_uuid_to_hd_sessions.rb +4 -2
  100. data/db/migrate/20171114120904_add_pathology_snapshot_to_letters.rb +3 -1
  101. data/db/migrate/20171118160030_add_tags_to_patient_bookmarks.rb +3 -1
  102. data/db/migrate/20171123123712_add_id_to_roles_users.rb +3 -1
  103. data/db/migrate/20171123143534_add_pk_to_drug_types_drugs.rb +13 -12
  104. data/db/migrate/20171123154116_create_renal_versions.rb +11 -9
  105. data/db/migrate/20171127082158_add_region_to_addresses.rb +3 -1
  106. data/db/migrate/20171127092158_create_function_to_import_practices.rb +6 -2
  107. data/db/migrate/20171127092359_create_fn_to_insert_gps.rb +6 -2
  108. data/db/migrate/20171128163543_add_more_missing_indexes.rb +14 -12
  109. data/db/migrate/20171204112150_create_consult_sites.rb +13 -9
  110. data/db/migrate/20171206121652_add_loinc_code_to_observation_descriptions.rb +3 -1
  111. data/db/migrate/20171206140738_create_fn_to_load_practice_memberships_csv.rb +9 -5
  112. data/db/migrate/20171208211206_create_user_feedback.rb +7 -5
  113. data/db/migrate/20171211130716_remove_unused_patients_cols.rb +4 -2
  114. data/db/migrate/20171211131918_remove_email_from_primary_care_physicians.rb +5 -3
  115. data/db/migrate/20171211161400_create_pathology_current_table.rb +9 -7
  116. data/db/migrate/20171213111513_create_fn_to_refresh_current_obs.rb +6 -2
  117. data/db/migrate/20171214141335_create_trigger_to_update_current_observation_sets.rb +10 -6
  118. data/db/migrate/20171214190849_enforce_request_id_on_observations.rb +3 -1
  119. data/db/migrate/20171215122454_add_pathology_observation_set_to_letters.rb +8 -6
  120. data/db/migrate/20171219154529_create_admission_admissions.rb +25 -23
  121. data/db/migrate/20180102155055_update_patient_summaries_to_version_5.rb +3 -1
  122. data/db/migrate/20180105132358_add_emailed_at_to_letter_recipients.rb +4 -2
  123. data/db/migrate/20180108185400_remove_null_constraint_from_letters_pathology_snapshot.rb +3 -1
  124. data/db/migrate/20180112151706_create_low_clearance_profiles.rb +43 -41
  125. data/db/migrate/20180112151813_create_low_clearance_versions.rb +11 -9
  126. data/db/migrate/20180119121243_create_trigger_to_preprocess_hl7_msg.rb +10 -6
  127. data/db/migrate/20180121115246_add_include_pathology_in_letter_to_letters_letterheads.rb +3 -1
  128. data/db/migrate/20180122173922_create_virology_profiles.rb +5 -1
  129. data/db/migrate/20180125201356_make_obs_set_trigger_change_updated_at.rb +6 -2
  130. data/db/migrate/20180126142314_add_uuid_to_letters.rb +4 -2
  131. data/db/migrate/20180130165803_add_deleted_at_indexes.rb +14 -12
  132. data/db/migrate/20180201090444_add_created_at_to_delayed_jobs_in_hl7_trig_fn.rb +6 -2
  133. data/db/migrate/20180202184954_create_view_pathology_observation_digests.rb +3 -1
  134. data/db/migrate/20180206225525_update_fn_update_current_observation_set_from_trigger.rb +6 -2
  135. data/db/migrate/20180207082540_create_count_estimate_function.rb +6 -2
  136. data/db/migrate/20180208150629_add_authentication_token_to_users.rb +3 -1
  137. data/db/migrate/20180213124203_add_cancelled_to_pathology_observations.rb +7 -5
  138. data/db/migrate/20180213125734_update_fn_update_current_obs_set_trgger.rb +6 -2
  139. data/db/migrate/20180213171805_add_display_order_cols_to_observation_descriptions.rb +10 -8
  140. data/db/migrate/20180214124317_add_cols_to_aki_alerts.rb +7 -5
  141. data/db/migrate/20180216132741_disable_some_audits.rb +6 -4
  142. data/db/migrate/20180221210458_add_state_index_on_modalities.rb +3 -1
  143. data/db/migrate/20180222090501_add_partial_index_to_bookmarks.rb +4 -2
  144. data/db/migrate/20180223100420_add_sent_to_ukrdc_at_to_patients.rb +3 -1
  145. data/db/migrate/20180226124724_add_patient_id_to_virology_profile.rb +9 -5
  146. data/db/migrate/20180226132410_create_ukrdc_transmission_logs.rb +12 -10
  147. data/db/migrate/20180301095040_update_fn_to_upsert_gp_practive_memberships.rb +7 -3
  148. data/db/migrate/20180305134959_add_display_group_to_observation_desriptions.rb +23 -22
  149. data/db/migrate/20180306071308_remove_rogue_aki_alerts_column.rb +3 -1
  150. data/db/migrate/20180306080518_add_state_tracking_cols_to_letters.rb +17 -15
  151. data/db/migrate/20180307191650_add_dwell_time_to_pd_regime.rb +3 -1
  152. data/db/migrate/20180307223111_create_system_visits_and_events.rb +42 -39
  153. data/db/migrate/20180309140316_add_unique_constraint_to_obr_requestor.rb +3 -1
  154. data/db/migrate/20180311104609_remove_unique_obr_requestor_order_number_index.rb +4 -2
  155. data/db/migrate/20180313114927_remove_deleted_at_from_admission_consults.rb +3 -1
  156. data/db/migrate/20180313124819_remove_tx_operation_constraints.rb +7 -5
  157. data/db/migrate/20180319191942_create_function_to_sort_without_failing_on_nonnumerics.rb +6 -2
  158. data/db/migrate/20180323150241_update_path_obs_descs_for_letter_groupings.rb +25 -23
  159. data/db/migrate/20180326155400_add_admin_notes_to_system_user_feedback.rb +4 -2
  160. data/db/migrate/20180327100423_add_constraints_to_recipient_operations.rb +3 -1
  161. data/db/migrate/20180328210434_add_rrt_to_admission_consults.rb +3 -1
  162. data/db/migrate/20180419141524_add_cols_to_hd_patient_statistics.rb +8 -6
  163. data/db/migrate/20180422090043_update_hd_overall_audit_to_version_6.rb +85 -84
  164. data/db/migrate/20180427133558_add_code_to_hospitals_wards.rb +3 -1
  165. data/db/migrate/20180502093256_add_document_to_virology_profiles.rb +22 -21
  166. data/db/migrate/20180502110638_create_virology_versions.rb +7 -5
  167. data/db/migrate/20180510151959_update_hd_overall_audit_to_version_7.rb +8 -4
  168. data/db/migrate/20180511100345_add_notes_to_transplant_registration_statuses.rb +3 -1
  169. data/db/migrate/20180511140415_add_message_hash_messaging_messages.rb +4 -2
  170. data/db/migrate/20180511171835_create_unique_indexes_on_obr_obr_codes.rb +5 -3
  171. data/db/migrate/20180514151627_create_system_messages.rb +10 -8
  172. data/db/migrate/20180516111411_create_view_patient_current_modalities.rb +3 -1
  173. data/db/migrate/20180524072633_add_columns_to_dialysates.rb +10 -8
  174. data/db/migrate/20180524074320_add_columns_to_hd_dialysers.rb +8 -6
  175. data/db/migrate/20180605114332_create_pseudo_encrypt_function.rb +6 -2
  176. data/db/migrate/20180605141806_add_external_id_to_research_study_participants.rb +33 -31
  177. data/db/migrate/20180605175211_add_application_url_to_research_studies.rb +3 -1
  178. data/db/migrate/20180622130552_add_external_id_to_hd_sessions.rb +4 -2
  179. data/db/migrate/20180625124431_add_patient_identifier_to_feed_messages.rb +3 -1
  180. data/db/migrate/20180628132323_add_letter_date_indexes.rb +9 -7
  181. data/db/migrate/20180702091222_create_hd_providers.rb +5 -3
  182. data/db/migrate/20180702091237_create_hd_provider_units.rb +8 -6
  183. data/db/migrate/20180702091352_create_hd_transmission_log.rb +15 -13
  184. data/db/migrate/20180712143314_add_hidden_to_modality_descriptions.rb +3 -1
  185. data/db/migrate/20180718172750_update_audit_letters_authors_to_version_3.rb +13 -11
  186. data/db/migrate/20180725132557_add_days_text_to_hd_schedule_definitions.rb +21 -19
  187. data/db/migrate/20180725132808_create_hd_schedule_definition_filters_view.rb +3 -1
  188. data/db/migrate/20180730154454_add_external_session_id_to_hd_transmission_logs.rb +7 -5
  189. data/db/migrate/20180802103013_add_hd_mdm_missing_indexes.rb +6 -4
  190. data/db/migrate/20180802132417_add_missing_indexes_2.rb +16 -14
  191. data/db/migrate/20180802144507_add_missing_foreign_key_indexes.rb +14 -12
  192. data/db/migrate/20180803131157_add_uuid_to_hd_transmission_logs.rb +7 -1
  193. data/db/migrate/20180814103916_create_index_on_lower_patient_family_name.rb +5 -3
  194. data/db/migrate/20180815144429_update_hd_overall_audit_to_version_8.rb +8 -4
  195. data/db/migrate/20180831134926_create_daily_reports.rb +3 -6
  196. data/db/migrate/20180907100545_add_page_count_to_letters.rb +3 -1
  197. data/db/migrate/20181001162513_add_active_to_hospital_wards.rb +3 -1
  198. data/db/migrate/20181008144324_update_daily_letters_report_view_to_version_2.rb +0 -2
  199. data/db/migrate/20181008145159_create_reporting_daily_ukrdc_view.rb +0 -4
  200. data/db/migrate/20181013115138_update_reporting_daily_pathology_view_to_v2.rb +0 -2
  201. data/db/migrate/20181025170410_add_ukrdc_helper_column_to_patients.rb +0 -2
  202. data/db/migrate/20181026145459_create_ukrdc_batch_numbers.rb +5 -3
  203. data/db/migrate/20181106133500_update_hd_overall_audit_to_version_9.rb +0 -2
  204. data/db/migrate/20181109110616_create_hd_grouped_transmission_logs_view.rb +0 -2
  205. data/db/migrate/20181126090401_add_warnings_to_hd_transmission_logs.rb +7 -0
  206. data/db/migrate/20181126123745_refresh_hd_grouped_transmission_logs_view.rb +8 -0
  207. data/db/migrate/20181217124025_change_ukrdc_transmission_log_error_type.rb +15 -0
  208. data/db/seeds/default/practices/nhs_practices_sample.csv +2 -2
  209. data/db/seeds/default/practices/primary_care_physicians_sample.csv +2 -2
  210. data/lib/core_extensions/active_record/migration_helpers.rb +43 -1
  211. data/lib/renalware/engine.rb +2 -0
  212. data/lib/renalware/version.rb +1 -1
  213. metadata +55 -19
  214. data/lib/migration_helper.rb +0 -11
  215. data/vendor/assets/javascripts/renalware/moment.min.js +0 -1
  216. data/vendor/assets/javascripts/renalware/mousetrap.js +0 -1044
@@ -36,7 +36,7 @@ module Renalware
36
36
  end
37
37
 
38
38
  def search
39
- @search ||= Letter.include(QueryableLetter).includes(:event).search(@q)
39
+ @search ||= Letter.include(QueryableLetter).includes(:event).ransack(@q)
40
40
  end
41
41
  end
42
42
  end
@@ -88,6 +88,8 @@ module Renalware
88
88
 
89
89
  def practice_address_for_patient
90
90
  address = letter.patient&.practice&.address
91
+ ensure_practice_name_is_present_in(address)
92
+
91
93
  if address.present? && letter.primary_care_physician.present?
92
94
  ensure_address_has_a_name_required_when_displaying_letters(
93
95
  address,
@@ -97,6 +99,15 @@ module Renalware
97
99
  address
98
100
  end
99
101
 
102
+ # There may not be an organisation name eg "Mill House Clinic" on the address record
103
+ # (in fact is unlikely) in which case copy it over from the practice so it will be displayed
104
+ # under the GP's name on the letter.
105
+ def ensure_practice_name_is_present_in(address)
106
+ return if address.blank?
107
+
108
+ address.organisation_name ||= letter.patient&.practice&.name
109
+ end
110
+
100
111
  def address_for_addressee_eg_contact
101
112
  addressee.address.tap do |address|
102
113
  ensure_address_has_a_name_required_when_displaying_letters(
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "attr_extras"
4
+
5
+ module Renalware
6
+ module Letters
7
+ # This class is responsible for collating the complete set of default electronic ccs for a new
8
+ # patient letter.
9
+ # An HD patient for instance might have a named nurse who should always be eCCed into any
10
+ # letters about them.
11
+ # Important to note here is that we are of course in the Letters module and have no knowledge
12
+ # of who should be eCCs and how to resolve those users; these are matters that relate for
13
+ # example to the user's current modality and the corresponding module (HD, PD, Transplant etc).
14
+ # So here all we can do is broadcast a (synchronous) event asking anyone listening (ie any
15
+ # class that is configured to listen in the broadcast_map) to add their eCC users to the
16
+ # passed in array_of_user_ids array. We will then dedupe and return that array,
17
+ # where it will be used to initialize the eCC component on the letters UI form with the correct
18
+ # initial default set up eCC users. This only applies to new letters, ie when displaying the
19
+ # the UI form for a new letter.
20
+ #
21
+ # Example usage:
22
+ #
23
+ # array_of_ecc_users = ResolveDefaultElectronicCCs
24
+ # .for(patient)
25
+ # .broadcasting_to_configured_subscribers
26
+ # .call
27
+ #
28
+ class ResolveDefaultElectronicCCs
29
+ include Broadcasting
30
+ pattr_initialize :patient
31
+
32
+ def self.for(patient)
33
+ new(patient)
34
+ end
35
+
36
+ def call
37
+ array_of_user_ids = []
38
+ broadcast(
39
+ :request_default_electronic_cc_recipients_for_use_in_letters,
40
+ patient: patient,
41
+ array_of_user_ids: array_of_user_ids
42
+ )
43
+ array_of_user_ids.compact.uniq
44
+ end
45
+ end
46
+ end
47
+ end
@@ -33,7 +33,7 @@ module Renalware
33
33
  .left_outer_joins(:current_observation_set)
34
34
  .with_current_modality_of_class(LowClearance::ModalityDescription)
35
35
  .public_send(named_filter.to_s)
36
- .search(query)
36
+ .ransack(query)
37
37
  end
38
38
  end
39
39
  # rubocop:enable Metrics/MethodLength
@@ -23,7 +23,7 @@ module Renalware
23
23
  .includes(patient: { current_modality: :description })
24
24
  .eager_load(drug: [:drug_types])
25
25
  .where("lower(drug_types.name) = lower(?)", drug_type_name)
26
- .search(search_params)
26
+ .ransack(search_params)
27
27
  end
28
28
  end
29
29
  end
@@ -16,7 +16,7 @@ module Renalware
16
16
  end
17
17
 
18
18
  def search
19
- @search ||= @relation.search(@search_params)
19
+ @search ||= @relation.ransack(@search_params)
20
20
  end
21
21
 
22
22
  private
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/admissions"
4
+
5
+ module Renalware
6
+ module Patients
7
+ class BookmarksQuery
8
+ attr_reader :default_relation, :query
9
+
10
+ def initialize(default_relation:, params: nil)
11
+ @default_relation = default_relation
12
+ @query = params || {}
13
+ @query[:s] ||= "created_at desc"
14
+ end
15
+
16
+ def call
17
+ search.result
18
+ end
19
+
20
+ # Note we *MUST* join onto patients for PatientsRansackHelper.identity_match to work.
21
+ # It might be better to refactor PatientsRansackHelper so we can include where required
22
+ # eg below using .extending(PatientsRansackHelper) rather than relying on it being in
23
+ # included in the model file.
24
+ # note that adding .includes(:created_by) here creates an ambigous column
25
+ # 'family_name' error
26
+ def search
27
+ @search ||= begin
28
+ (default_relation || Bookmark)
29
+ .extend(RansackScopes)
30
+ .joins(:patient)
31
+ .eager_load(patient: [current_modality: :description])
32
+ .order(created_at: :desc)
33
+ .ransack(query)
34
+ end
35
+ end
36
+
37
+ module RansackScopes
38
+ def self.extended(base)
39
+ # Using a custom ransacker here in order to sort by modality description name
40
+ # because using a predicate like :patient_current_modality_description_name
41
+ # results in an INNER JOIN onto modalities.
42
+ base.ransacker :modality_desc do
43
+ Arel.sql("modality_descriptions.name")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,7 +6,7 @@ module Renalware
6
6
  def self.call(params)
7
7
  Renalware::Patient
8
8
  .includes(current_modality: [:description])
9
- .search(params[:patient_search]).tap do |search|
9
+ .ransack(params[:patient_search]).tap do |search|
10
10
  search.sorts = %w(family_name_case_insensitive given_name)
11
11
  end
12
12
  end
@@ -29,7 +29,7 @@ module Renalware
29
29
  .with_current_pathology
30
30
  .with_registration_statuses
31
31
  .left_outer_joins(:current_observation_set)
32
- .search(q)
32
+ .ransack(q)
33
33
  end
34
34
  end
35
35
  end
@@ -21,7 +21,7 @@ module Renalware
21
21
  private
22
22
 
23
23
  def search
24
- @search ||= PRDDescription.search(term_or_code_cont: term).tap do |s|
24
+ @search ||= PRDDescription.ransack(term_or_code_cont: term).tap do |s|
25
25
  s.sorts = ["term"]
26
26
  end
27
27
  end
@@ -16,7 +16,7 @@ module Renalware
16
16
 
17
17
  def search
18
18
  @search ||= begin
19
- relation.search(q).tap do |search|
19
+ relation.ransack(q).tap do |search|
20
20
  search.sorts = DEFAULT_ORDER
21
21
  end
22
22
  end
@@ -35,7 +35,7 @@ module Renalware
35
35
  .with_current_pathology
36
36
  .left_outer_joins(:current_observation_set)
37
37
  .public_send(named_filter.to_s)
38
- .search(q)
38
+ .ransack(q)
39
39
  end
40
40
  end
41
41
 
@@ -26,7 +26,7 @@ module Renalware
26
26
  .eager_load(current_status: :description)
27
27
  .merge(HD::Patient.with_profile)
28
28
  .merge(Renal::Patient.with_profile)
29
- .search(query).tap do |s|
29
+ .ransack(query).tap do |s|
30
30
 
31
31
  s.sorts = ["patient_family_name, patient_given_name"]
32
32
  end
@@ -17,10 +17,9 @@ module Renalware
17
17
  :changed_since,
18
18
  :logger,
19
19
  :request_uuid,
20
- :paths,
21
20
  :timestamp,
22
- :summary,
23
- :batch_number
21
+ :batch_number,
22
+ :summary
24
23
  )
25
24
 
26
25
  def initialize(changed_since: nil, patient_ids: nil, logger: nil)
@@ -29,20 +28,13 @@ module Renalware
29
28
  @logger = logger || Rails.logger
30
29
  @request_uuid = SecureRandom.uuid # helps group logs together
31
30
  @timestamp = Time.zone.now.strftime("%Y%m%d%H%M%S%L")
32
-
31
+ @batch_number ||= BatchNumber.next.number
33
32
  @summary = ExportSummary.new
34
33
  end
35
34
 
36
35
  def call
37
36
  logger.tagged(request_uuid) do
38
- # Skipping transaction for now as worried about the quantity of rows and data invovled.
39
37
  ActiveRecord::Base.transaction do
40
- @batch_number = BatchNumber.next.number
41
- @paths = Paths.new(
42
- timestamp: timestamp,
43
- batch_number: batch_number,
44
- working_path: config.ukrdc_working_path
45
- )
46
38
  summary.milliseconds_taken = Benchmark.ms do
47
39
  create_patient_xml_files
48
40
  encrypt_patient_xml_files
@@ -62,6 +54,16 @@ module Renalware
62
54
 
63
55
  private
64
56
 
57
+ def paths
58
+ @paths ||= begin
59
+ Paths.new(
60
+ timestamp: timestamp,
61
+ batch_number: batch_number,
62
+ working_path: config.ukrdc_working_path
63
+ )
64
+ end
65
+ end
66
+
65
67
  def create_patient_xml_files
66
68
  patients = ukrdc_patients_who_have_changed_since_last_send
67
69
  summary.num_changed_patients = patients.count
@@ -10,24 +10,28 @@ module Renalware
10
10
  :patient!,
11
11
  :dir!,
12
12
  :request_uuid!,
13
- :renderer,
14
13
  :changes_since,
15
14
  :logger,
16
- :batch_number
15
+ :batch_number,
16
+ :renderer, # so we can pass a test renderer to bypass real rendering
17
+ :log
17
18
  ]
18
19
 
19
20
  # rubocop:disable Metrics/AbcSize
20
21
  def call
21
22
  update_patient_to_indicated_we_checked_them_for_any_relevant_changes
22
23
  UKRDC::TransmissionLog.with_logging(patient, request_uuid) do |log|
24
+ @log = log
23
25
  logger.info " Patient #{patient.ukrdc_external_id}"
24
26
  xml_payload = build_payload(log)
25
- if xml_payload_same_as_last_sent_payload?(xml_payload)
26
- logger.info " skipping as no change in XML file"
27
- log.unsent_no_change_since_last_send!
28
- else
29
- create_xml_file(xml_payload, log)
30
- update_patient_to_indicate_we_have_sent_their_data_to_ukrdc
27
+ if xml_payload.present?
28
+ if xml_payload_same_as_last_sent_payload?(xml_payload)
29
+ logger.info " skipping as no change in XML file"
30
+ log.unsent_no_change_since_last_send!
31
+ else
32
+ create_xml_file(xml_payload, log)
33
+ update_patient_to_indicate_we_have_sent_their_data_to_ukrdc
34
+ end
31
35
  end
32
36
  logger.info " Status: #{log.status}"
33
37
  end
@@ -72,17 +76,30 @@ module Renalware
72
76
  end
73
77
 
74
78
  def build_payload(log)
75
- Payload.new(render_xml_for(patient)).tap do |payload|
76
- log.payload = payload.to_s
77
- log.payload_hash = payload.to_md5_hash
79
+ result = attempt_to_generate_patient_ukrdc_xml
80
+ if result.failure?
81
+ handle_invalid_xml(result)
82
+ nil
83
+ else
84
+ Payload.new(result.xml).tap do |payload|
85
+ log.payload = payload.to_s
86
+ log.payload_hash = payload.to_md5_hash
87
+ end
78
88
  end
79
89
  end
80
90
 
81
- def render_xml_for(patient)
82
- renderer.render(
83
- "renalware/api/ukrdc/patients/show",
84
- locals: { patient: presenter_for(patient) }
85
- )
91
+ def attempt_to_generate_patient_ukrdc_xml
92
+ (renderer || default_renderer).call
93
+ end
94
+
95
+ def handle_invalid_xml(result)
96
+ log.error = result.validation_errors
97
+ log.status = :error
98
+ nil
99
+ end
100
+
101
+ def default_renderer
102
+ Renalware::UKRDC::XmlRenderer.new(locals: { patient: presenter_for(patient) })
86
103
  end
87
104
 
88
105
  def presenter_for(patient)
@@ -92,11 +109,6 @@ module Renalware
92
109
  )
93
110
  end
94
111
 
95
- # Note a test might have passed in a mock renderer
96
- def renderer
97
- @renderer ||= Renalware::API::UKRDC::PatientsController.renderer
98
- end
99
-
100
112
  def xml_filepath
101
113
  xml_filename = Filename.new(patient: patient, batch_number: batch_number).to_s
102
114
  File.join(dir, xml_filename)
@@ -16,7 +16,7 @@ module Renalware
16
16
  yield log if block_given?
17
17
  log.save!
18
18
  rescue StandardError => error
19
- log.error = formatted_exception(error)
19
+ log.error << formatted_exception(error)
20
20
  log.status = :error
21
21
  log.save!
22
22
  raise error
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/ukrdc"
4
+
5
+ module Renalware
6
+ module UKRDC
7
+ class XmlRenderer
8
+ DEFAULT_TEMPLATE = "/renalware/api/ukrdc/patients/show"
9
+ attr_reader :template, :xsd_path, :locals, :errors
10
+
11
+ class Success < Renalware::Success
12
+ alias_method :xml, :object
13
+ end
14
+
15
+ class Failure < Renalware::Failure
16
+ alias_method :validation_errors, :object
17
+ end
18
+
19
+ def initialize(template: nil, xsd_path: nil, locals: {})
20
+ @template = template || DEFAULT_TEMPLATE
21
+ @xsd_path = xsd_path || default_xsd_path
22
+ @locals = locals
23
+ end
24
+
25
+ # If we successfully generate the UKRDC XML for a patient, return a Success object where
26
+ # success#xml is the valid XML
27
+ # If there are XSD validation messages, we return a Failure object where
28
+ # failure#validation_messages is an array of XSD validation messages.
29
+ def call
30
+ return XmlRenderer::Failure.new(validation_errors) if validation_errors.any?
31
+
32
+ XmlRenderer::Success.new(xml)
33
+ end
34
+
35
+ def xml
36
+ @xml ||= begin
37
+ API::UKRDC::PatientsController.new.render_to_string(
38
+ template: template,
39
+ format: :xml,
40
+ locals: locals,
41
+ encoding: "UTF-8"
42
+ )
43
+ end
44
+ end
45
+
46
+ # Returns an array of SchemaValidation errors
47
+ def validation_errors
48
+ @validation_errors ||= begin
49
+ document = Nokogiri::XML(xml)
50
+ xsddoc = Nokogiri::XML(File.read(xsd_path), xsd_path)
51
+ schema = Nokogiri::XML::Schema.from_document(xsddoc)
52
+ schema.validate(document)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def default_xsd_path
59
+ File.join(Renalware::Engine.root, "vendor/xsd/ukrdc/Schema/UKRDC.xsd")
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ #
66
+ # An alternative xml rendering implementation - we moved to a template based approach
67
+ # for now as its provides more clarity
68
+ #
69
+
70
+ # class Base
71
+ # include ActiveModel::Serializers::Xml
72
+ # include Virtus::Model
73
+ # end
74
+
75
+ # class PatientNumber < Base
76
+ # attribute :number, String
77
+ # attribute :organisation, String
78
+
79
+ # def self.build_nhs_number(number)
80
+ # new(number: number, organisation: "NHS")
81
+ # end
82
+ # end
83
+
84
+ # class Name < Base
85
+ # attribute :prefix, String
86
+ # attribute :family, String
87
+ # attribute :given, String
88
+ # attribute :suffix, String
89
+ # attribute :use, String
90
+ # end
91
+
92
+ # class Patient < Base
93
+ # attribute :gender, String # 0=Not Known 1=Male 2=Female 9=Not Specified.
94
+ # attribute :birth_time, DateTime
95
+ # attribute :death_time, DateTime
96
+ # attribute :patient_numbers, Array(PatientNumber)
97
+ # attribute :name, Name
98
+ # attribute :country_of_birth, String # ISO 3166-1 3-char alphabetic code
99
+ # end
100
+
101
+ # rdc_patient = UKRDC::Patient.new(
102
+ # gender: patient.sex&.code,
103
+ # birth_time: patient.born_on,
104
+ # death_time: patient.died_on,
105
+ # country_of_birth: "???"
106
+ # )
107
+
108
+ # rdc_patient.name = Name.new(
109
+ # prefix: patient.title,
110
+ # family: patient.family_name,
111
+ # given: patient.given_name,
112
+ # suffix: patient.suffix
113
+ # )
114
+
115
+ # rdc_patient.patient_numbers << UKRDC::PatientNumber.build_nhs_number(patient.nhs_number)
116
+ # Renalware.config.patient_hospital_identifiers.each do |_key, field|
117
+ # number = patient.public_send(field)
118
+ # unless number.blank?
119
+ # patient_number = UKRDC::PatientNumber.new(number: number, organisation: "LOCALHOSP")
120
+ # rdc_patient.patient_numbers << patient_number
121
+ # end
122
+ # end
123
+
124
+ # # Render XML
125
+ # respond_with rdc_patient, camelize: true
126
+ #