renalware-core 2.0.0.pre.rc3 → 2.0.0.pre.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (281) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +1 -0
  4. data/app/assets/images/renalware/chosen-sprite.png +0 -0
  5. data/app/assets/images/renalware/chosen-sprite@2x.png +0 -0
  6. data/app/assets/images/renalware/nhs_a4_letter_logo_black.png +0 -0
  7. data/app/assets/images/renalware/nhs_a4_letter_logo_blue.png +0 -0
  8. data/app/assets/javascripts/renalware/session_timeout_redirect.js.erb +3 -1
  9. data/app/assets/stylesheets/renalware/base/_variables.scss +2 -0
  10. data/app/assets/stylesheets/renalware/modules/_admissions.scss +21 -25
  11. data/app/assets/stylesheets/renalware/modules/_feeds.scss +27 -0
  12. data/app/assets/stylesheets/renalware/modules/_letters.scss +4 -0
  13. data/app/assets/stylesheets/renalware/modules/_patients.scss +18 -17
  14. data/app/assets/stylesheets/renalware/modules/_pd.scss +8 -0
  15. data/app/assets/stylesheets/renalware/partials/_lists.scss +3 -0
  16. data/app/assets/stylesheets/renalware/partials/_modal_window.scss +7 -1
  17. data/app/assets/stylesheets/renalware/partials/_navigation.scss +2 -2
  18. data/app/assets/stylesheets/renalware/partials/_tables.scss +20 -0
  19. data/app/assets/stylesheets/renalware/partials/_typography.scss +4 -0
  20. data/app/controllers/renalware/admin/feeds/files_controller.rb +49 -0
  21. data/app/controllers/renalware/admissions/admissions_controller.rb +101 -0
  22. data/app/controllers/renalware/admissions/patient_admissions_controller.rb +20 -0
  23. data/app/controllers/renalware/devise/sessions_controller.rb +29 -0
  24. data/app/controllers/renalware/letters/approved_letters_controller.rb +9 -1
  25. data/app/controllers/renalware/letters/contacts_controller.rb +29 -0
  26. data/app/controllers/renalware/low_clearance/base_controller.rb +13 -0
  27. data/app/controllers/renalware/low_clearance/dashboards_controller.rb +21 -0
  28. data/app/controllers/renalware/low_clearance/mdm_controller.rb +13 -0
  29. data/app/controllers/renalware/low_clearance/mdm_patients_controller.rb +27 -0
  30. data/app/controllers/renalware/low_clearance/profiles_controller.rb +45 -0
  31. data/app/controllers/renalware/patients/primary_care_physicians_controller.rb +4 -3
  32. data/app/controllers/renalware/pd/exit_site_infections_controller.rb +2 -1
  33. data/app/controllers/renalware/transplants/donor_workups_controller.rb +5 -2
  34. data/app/documents/renalware/low_clearance/profile_document.rb +26 -0
  35. data/app/documents/renalware/renal/profile_document.rb +0 -21
  36. data/app/helpers/renalware/application_helper.rb +5 -0
  37. data/app/helpers/renalware/attribute_name_helper.rb +0 -24
  38. data/app/helpers/renalware/infection_organisms_helper.rb +0 -20
  39. data/app/helpers/renalware/mdm_helper.rb +1 -1
  40. data/app/helpers/renalware/pd_regimes_helper.rb +1 -5
  41. data/app/mailers/renalware/admin/user_mailer.rb +1 -3
  42. data/app/mailers/renalware/letters/delivery/errors.rb +9 -0
  43. data/app/mailers/renalware/letters/delivery/practice_mailer.rb +55 -0
  44. data/app/mailers/{previews → renalware/previews}/user_mailer_preview.rb +0 -0
  45. data/app/models/concerns/renalware/feeds/job.rb +30 -0
  46. data/app/models/concerns/renalware/letters/letter_pathology.rb +31 -8
  47. data/app/models/concerns/renalware/patients_ransack_helper.rb +9 -9
  48. data/app/models/concerns/renalware/personable.rb +8 -3
  49. data/app/models/concerns/renalware/string_logging.rb +11 -0
  50. data/app/models/renalware/admissions/admission.rb +42 -0
  51. data/app/models/renalware/admissions/admission_query.rb +38 -0
  52. data/app/models/renalware/admissions/admission_search_form.rb +51 -0
  53. data/app/models/renalware/clinics/clinic_visit.rb +1 -0
  54. data/app/models/renalware/feeds/file.rb +31 -0
  55. data/app/models/renalware/feeds/file_type.rb +13 -0
  56. data/app/models/renalware/feeds/files/create_feed_file.rb +51 -0
  57. data/app/models/renalware/feeds/files/enqueue_file_for_background_processing.rb +18 -0
  58. data/app/models/renalware/feeds/files/exceptions.rb +12 -0
  59. data/app/models/renalware/feeds/files/file_upload_form.rb +24 -0
  60. data/app/models/renalware/feeds/files/import_job_factory.rb +15 -0
  61. data/app/models/renalware/feeds/files/practice_memberships/import_csv.rb +30 -0
  62. data/app/models/renalware/feeds/files/practice_memberships/import_job.rb +49 -0
  63. data/app/models/renalware/feeds/files/practices/convert_xml_to_csv.rb +145 -0
  64. data/app/models/renalware/feeds/files/practices/country_map.rb +33 -0
  65. data/app/models/renalware/feeds/files/practices/csv_file.rb +23 -0
  66. data/app/models/renalware/feeds/files/practices/csv_organisation.rb +35 -0
  67. data/app/models/renalware/feeds/files/practices/import_csv.rb +30 -0
  68. data/app/models/renalware/feeds/files/practices/import_job.rb +58 -0
  69. data/app/models/renalware/feeds/files/primary_care_physicians/import_csv.rb +28 -0
  70. data/app/models/renalware/feeds/files/primary_care_physicians/import_job.rb +44 -0
  71. data/app/models/renalware/feeds/files/tissue_typing/import.rb +12 -0
  72. data/app/models/renalware/feeds/hl7_message.rb +15 -0
  73. data/app/models/renalware/hd/sessions/auditable_session.rb +1 -1
  74. data/app/models/renalware/hospitals/unit.rb +2 -1
  75. data/app/models/renalware/hospitals/ward.rb +1 -1
  76. data/app/models/renalware/letters/approve_letter.rb +15 -9
  77. data/app/models/renalware/letters/delivery/deliver_letter.rb.dead +41 -0
  78. data/app/models/renalware/letters/delivery/delivery_policy.rb +28 -0
  79. data/app/models/renalware/letters/delivery/email_letter_to_practice.rb +46 -0
  80. data/app/models/renalware/letters/delivery/practice_email.rb +28 -0
  81. data/app/models/renalware/letters/draft_letter.rb +1 -1
  82. data/app/models/renalware/letters/part/recent_pathology_results.rb +43 -4
  83. data/app/models/renalware/letters/pdf_letter_cache.rb +2 -3
  84. data/app/models/renalware/letters/recipient_params_processor.rb +1 -1
  85. data/app/models/renalware/letters/relevant_observation_description.rb +2 -3
  86. data/app/models/renalware/letters/revise_letter.rb +3 -1
  87. data/app/models/renalware/letters.rb +3 -0
  88. data/app/models/renalware/low_clearance/mdm_patients_query.rb +62 -0
  89. data/app/models/renalware/low_clearance/modality_description.rb +11 -0
  90. data/app/models/renalware/low_clearance/patient.rb +14 -0
  91. data/app/models/renalware/low_clearance/profile.rb +15 -0
  92. data/app/models/renalware/low_clearance/version.rb +9 -0
  93. data/app/models/renalware/low_clearance.rb +15 -0
  94. data/app/models/renalware/patient.rb +3 -0
  95. data/app/models/renalware/patients/patient_hospital_identifiers.rb +8 -0
  96. data/app/models/renalware/patients/practice.rb +4 -1
  97. data/app/models/renalware/patients/practice_membership.rb +12 -0
  98. data/app/models/renalware/patients/primary_care_physician.rb +24 -5
  99. data/app/models/renalware/pd/exit_site_infection.rb +6 -0
  100. data/app/models/renalware/pd/regime_bag.rb +1 -1
  101. data/app/models/renalware/problems/note.rb +1 -1
  102. data/app/models/renalware/renal/registry/preflight_checks/deaths_query.rb +1 -1
  103. data/app/models/renalware/renal.rb +0 -4
  104. data/app/models/renalware/system/update_user.rb +1 -1
  105. data/app/models/renalware/transplants/recipient_operation.rb +3 -8
  106. data/app/models/renalware/user.rb +3 -3
  107. data/app/models/renalware/zip_archive.rb +48 -0
  108. data/app/policies/renalware/admissions/admission_policy.rb +8 -0
  109. data/app/policies/renalware/feeds/file_policy.rb +25 -0
  110. data/app/policies/renalware/letters/letter_policy.rb +2 -0
  111. data/app/policies/renalware/low_clearance/profile_policy.rb +13 -0
  112. data/app/presenters/renalware/admissions/admission_presenter.rb +49 -0
  113. data/app/presenters/renalware/dashboard/dashboard_presenter.rb +1 -1
  114. data/app/presenters/renalware/hd/session_access_presenter.rb +1 -1
  115. data/app/presenters/renalware/letters/letter_form_presenter.rb +1 -1
  116. data/app/presenters/renalware/letters/letter_presenter.rb +6 -1
  117. data/app/presenters/renalware/letters/practice_email_meta_data.rb +85 -0
  118. data/app/presenters/renalware/low_clearance/dashboard_presenter.rb +19 -0
  119. data/app/presenters/renalware/low_clearance/mdm_presenter.rb +12 -0
  120. data/app/presenters/renalware/pathology/observation_set_presenter.rb +1 -1
  121. data/app/presenters/renalware/pathology/observations_diff.rb +1 -1
  122. data/app/presenters/renalware/renal/clinical_summary_presenter.rb +17 -1
  123. data/app/validators/renalware/patients/height_validator.rb +17 -0
  124. data/app/views/renalware/admin/feeds/files/index.html.slim +61 -0
  125. data/app/views/renalware/admissions/admissions/_filters.html.slim +24 -0
  126. data/app/views/renalware/admissions/admissions/_form.html.slim +56 -0
  127. data/app/views/renalware/admissions/admissions/_table.html.slim +65 -0
  128. data/app/views/renalware/admissions/admissions/edit.html.slim +6 -0
  129. data/app/views/renalware/admissions/admissions/index.html.slim +12 -0
  130. data/app/views/renalware/admissions/admissions/new.html.slim +6 -0
  131. data/app/views/renalware/admissions/consults/_form.html.slim +2 -3
  132. data/app/views/renalware/admissions/consults/_table.html.slim +1 -3
  133. data/app/views/renalware/admissions/patient_admissions/index.html.slim +10 -0
  134. data/app/views/renalware/clinics/clinic_visits/_table.html.slim +2 -1
  135. data/app/views/renalware/clinics/clinic_visits/_table_row.html.slim +1 -0
  136. data/app/views/renalware/drugs/drugs/index.html.slim +3 -2
  137. data/app/views/renalware/hd/current_profile/_summary.html.slim +8 -8
  138. data/app/views/renalware/hd/diary_slots/_form.html.slim +4 -4
  139. data/app/views/renalware/hd/mdm_patients/_patient.html.slim +0 -1
  140. data/app/views/renalware/hd/protocols/_profile.html.slim +4 -4
  141. data/app/views/renalware/letters/contacts/_contact.html.slim +5 -1
  142. data/app/views/renalware/letters/contacts/_edit.html.slim +30 -0
  143. data/app/views/renalware/letters/contacts/_form.html.slim +1 -1
  144. data/app/views/renalware/letters/contacts/_table.html.slim +6 -5
  145. data/app/views/renalware/letters/contacts/edit.html.slim +8 -0
  146. data/app/views/renalware/letters/contacts/edit.js.erb +9 -0
  147. data/app/views/renalware/letters/contacts/index.html.slim +9 -3
  148. data/app/views/renalware/letters/contacts/index.js.erb +1 -1
  149. data/app/views/renalware/letters/contacts/update.js.erb +10 -0
  150. data/app/views/renalware/letters/delivery/practice_mailer/patient_letter.text.erb +3 -0
  151. data/app/views/renalware/letters/electronic_receipts/_table.html.slim +3 -1
  152. data/app/views/renalware/letters/electronic_receipts/sent.html.slim +6 -9
  153. data/app/views/renalware/letters/formatted_letters/_letter.html.slim +26 -13
  154. data/app/views/renalware/letters/letters/_cc_recipient_form.html.slim +1 -1
  155. data/app/views/renalware/letters/letters/_form.html.slim +0 -1
  156. data/app/views/renalware/letters/letters/_pathology.html.slim +1 -2
  157. data/app/views/renalware/letters/letters/_preview.html.slim +14 -5
  158. data/app/views/renalware/letters/parts/_clinical_observations.html.slim +2 -2
  159. data/app/views/renalware/letters/parts/_recent_pathology_results.html.slim +1 -7
  160. data/app/views/renalware/low_clearance/dashboards/_page_actions.html.slim +19 -0
  161. data/app/views/renalware/low_clearance/dashboards/show.html.slim +7 -0
  162. data/app/views/renalware/{renal/low_clearance → low_clearance}/mdm/_bottom.html.slim +0 -0
  163. data/app/views/renalware/{renal/low_clearance → low_clearance}/mdm/_low_clearance_profile.html.slim +0 -0
  164. data/app/views/renalware/{renal/low_clearance → low_clearance}/mdm/_top.html.slim +0 -0
  165. data/app/views/renalware/low_clearance/mdm_patients/_filters.html.slim +9 -0
  166. data/app/views/renalware/low_clearance/profiles/_summary.html.slim +125 -0
  167. data/app/views/renalware/low_clearance/profiles/edit.html.slim +39 -0
  168. data/app/views/renalware/medications/prescriptions/_table.html.slim +1 -1
  169. data/app/views/renalware/messaging/internal/receipts/_receipt.html.slim +2 -1
  170. data/app/views/renalware/messaging/internal/receipts/_sent_receipt.html.slim +3 -2
  171. data/app/views/renalware/messaging/internal/receipts/_sent_table.html.slim +2 -1
  172. data/app/views/renalware/messaging/internal/receipts/_table.html.slim +1 -0
  173. data/app/views/renalware/navigation/_mdms.html.slim +1 -1
  174. data/app/views/renalware/navigation/_patients_admin.html.slim +1 -0
  175. data/app/views/renalware/navigation/_renalware_admin.html.slim +12 -22
  176. data/app/views/renalware/patients/_side_menu.html.slim +0 -1
  177. data/app/views/renalware/patients/clinical_summaries/_admissions.html.slim +11 -0
  178. data/app/views/renalware/patients/clinical_summaries/show.html.slim +7 -0
  179. data/app/views/renalware/patients/primary_care_physicians/_form.html.slim +1 -3
  180. data/app/views/renalware/patients/primary_care_physicians/_primary_care_physician.html.slim +1 -3
  181. data/app/views/renalware/patients/primary_care_physicians/index.html.slim +0 -1
  182. data/app/views/renalware/patients/side_menu/_actions.html.slim +1 -1
  183. data/app/views/renalware/patients/side_menu/_general.html.slim +3 -0
  184. data/app/views/renalware/patients/side_menu/_modalities.html.slim +4 -0
  185. data/app/views/renalware/pd/_pet_adequacies.html.slim +1 -1
  186. data/app/views/renalware/pd/dashboards/show/_page_actions.html.slim +3 -1
  187. data/app/views/renalware/pd/exit_site_infections/_details.html.slim +6 -1
  188. data/app/views/renalware/pd/exit_site_infections/_fields.html.slim +7 -0
  189. data/app/views/renalware/pd/exit_site_infections/_form.html.slim +6 -7
  190. data/app/views/renalware/pd/regime_bags/_regime_bag.html.slim +1 -1
  191. data/app/views/renalware/pd/regime_bags/_regime_bags.html.slim +1 -1
  192. data/app/views/renalware/pd/regimes/_current_regime.html.slim +6 -1
  193. data/app/views/renalware/pd/regimes/_glucose.html.slim +1 -3
  194. data/app/views/renalware/renal/profiles/_form.html.slim +0 -21
  195. data/app/views/renalware/renal/profiles/show.html.slim +0 -5
  196. data/app/views/renalware/research/study_participants/_form.html.slim +2 -2
  197. data/app/views/renalware/shared/_attributes_list.html.slim +4 -4
  198. data/app/views/renalware/snippets/snippets/_table.html.slim +10 -5
  199. data/app/views/renalware/transplants/donations/_form.html.slim +6 -6
  200. data/app/views/renalware/transplants/live_donors/_filters.html.slim +5 -5
  201. data/app/views/renalware/transplants/recipient_dashboards/_page_actions.html.slim +5 -1
  202. data/config/cucumber.yml +2 -2
  203. data/config/initializers/client_side_validations.rb +8 -10
  204. data/config/initializers/devise_security_extension.rb +1 -1
  205. data/config/initializers/inflections.rb +6 -1
  206. data/config/initializers/renalware.rb +6 -6
  207. data/config/locales/renalware/admissions/admissions.yml +37 -0
  208. data/config/locales/renalware/clinics/visit.yml +3 -0
  209. data/config/locales/renalware/feeds/file.en.yml +17 -0
  210. data/config/locales/renalware/low_clearance/dashboard.en.yml +11 -0
  211. data/config/locales/renalware/low_clearance/low_clearance.en.yml +14 -0
  212. data/config/locales/renalware/low_clearance/profile.en.yml +71 -0
  213. data/config/locales/renalware/messaging/internal/messages.en.yml +3 -2
  214. data/config/locales/renalware/patients/side_menu.en.yml +2 -0
  215. data/config/locales/renalware/pd/dashboard.en.yml +1 -0
  216. data/config/locales/renalware/pd/exit_site_infection.en.yml +10 -0
  217. data/config/locales/renalware/renal/profile.en.yml +0 -46
  218. data/config/locales/renalware/transplants/recipient_dashboards.en.yml +1 -0
  219. data/config/routes.rb +19 -9
  220. data/db/migrate/20170523125610_add_esi_fields.rb +9 -0
  221. data/db/migrate/20170615130714_add_deleted_at_to_practices.rb +7 -0
  222. data/db/migrate/20170615144802_add_name_to_patient_primary_care_physicians.rb +9 -0
  223. data/db/migrate/20170620121255_create_patient_practice_memberships.rb +24 -0
  224. data/db/migrate/20170621102157_add_unique_index_on_practice_code.rb +6 -0
  225. data/db/migrate/20170627110058_create_feed_file_types.rb +15 -0
  226. data/db/migrate/20170627110619_create_feed_files.rb +20 -0
  227. data/db/migrate/20171009181615_add_columns_to_drug_drugs.rb +8 -0
  228. data/db/migrate/20171127082158_add_region_to_addresses.rb +5 -0
  229. data/db/migrate/20171127092158_create_function_to_import_practices.rb +123 -0
  230. data/db/migrate/20171127092359_create_fn_to_insert_gps.rb +145 -0
  231. data/db/migrate/20171206140738_create_fn_to_load_practice_memberships_csv.rb +62 -0
  232. data/db/migrate/20171211131918_remove_email_from_primary_care_physicians.rb +7 -0
  233. data/db/migrate/20171219154529_create_admission_admissions.rb +28 -0
  234. data/db/migrate/20171222153815_add_unique_constraint_to_patient_practice_memberships.rb +8 -0
  235. data/db/migrate/20180102155055_update_patient_summaries_to_version_5.rb +5 -0
  236. data/db/migrate/20180105132358_add_emailed_at_to_letter_recipients.rb +6 -0
  237. data/db/migrate/20180108185400_remove_null_constraint_from_letters_pathology_snapshot.rb +5 -0
  238. data/db/migrate/20180112151706_create_low_clearance_profiles.rb +49 -0
  239. data/db/migrate/20180112151813_create_low_clearance_versions.rb +14 -0
  240. data/db/seeds/default/feeds/import_file_types.rb +35 -0
  241. data/db/seeds/default/feeds/seeds.rb +1 -0
  242. data/db/seeds/default/modalities/descriptions.rb +1 -2
  243. data/db/seeds/default/practices/nhs_practices_sample.csv +26 -26
  244. data/db/seeds/default/practices/practices.rb +1 -2
  245. data/db/seeds/default/practices/primary_care_physicians.rb +3 -4
  246. data/db/seeds/default/practices/primary_care_physicians_sample.csv +193 -193
  247. data/db/seeds/default/seeds.rb +1 -0
  248. data/db/views/patient_summaries_v05.sql +17 -0
  249. data/lib/dropdown_button_item.rb +1 -1
  250. data/lib/renalware/configuration.rb +19 -1
  251. data/lib/renalware/engine.rb +6 -2
  252. data/lib/renalware/version.rb +1 -1
  253. data/lib/tasks/feeds/files.rake +34 -0
  254. data/lib/xml_parser.rb +84 -0
  255. data/spec/factories/admissions/admissions.rb +11 -0
  256. data/spec/factories/clinics/clinic_visits.rb +2 -2
  257. data/spec/factories/feeds/file.rb +14 -0
  258. data/spec/factories/feeds/file_types.rb +17 -0
  259. data/spec/factories/low_clearance/modality_descriptions.rb +8 -0
  260. data/spec/factories/low_clearance/patients.rb +3 -0
  261. data/spec/factories/low_clearance/profiles.rb +3 -0
  262. data/spec/factories/modalities/modality_descriptions.rb +1 -1
  263. data/spec/factories/patients/practice_memberships.rb +7 -0
  264. data/spec/factories/patients/primary_care_physicians.rb +2 -4
  265. data/spec/factories/system/users.rb +1 -1
  266. data/spec/support/factory_bot.rb +1 -1
  267. data/spec/support/shared_examples/paranoia_examples.rb +14 -0
  268. metadata +172 -40
  269. data/app/controllers/renalware/renal/low_clearance/mdm_controller.rb +0 -15
  270. data/app/controllers/renalware/renal/low_clearance/mdm_patients_controller.rb +0 -29
  271. data/app/helpers/renalware/section_helper.rb +0 -10
  272. data/app/models/renalware/renal/low_clearance/mdm_patients_query.rb +0 -64
  273. data/app/models/renalware/renal/low_clearance/modality_description.rb +0 -13
  274. data/app/presenters/renalware/renal/low_clearance/mdm_presenter.rb +0 -14
  275. data/app/views/renalware/renal/low_clearance/mdm_patients/_filters.html.slim +0 -9
  276. data/app/views/renalware/transplants/registrations/_sections_nav.html.slim +0 -15
  277. data/config/initializers/application_controller_renderer.rb +0 -13
  278. data/config/initializers/assets.rb +0 -10
  279. data/config/initializers/renalware_core.rb +0 -15
  280. data/config/locales/renalware/renal/low_clearance.en.yml +0 -15
  281. data/spec/factories/renal/lcc_modality_description.rb +0 -9
@@ -0,0 +1,45 @@
1
+ require_dependency "renalware/low_clearance"
2
+
3
+ module Renalware
4
+ module LowClearance
5
+ class ProfilesController < BaseController
6
+ def edit
7
+ render_edit(find_and_authorize_profile)
8
+ end
9
+
10
+ def update
11
+ profile = find_and_authorize_profile
12
+ if profile.update_by(current_user, profile_params)
13
+ redirect_to patient_low_clearance_dashboard_path,
14
+ notice: t(".success", model_name: "profile")
15
+ else
16
+ flash.now[:error] = failed_msg_for("profile")
17
+ render_edit(profile)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def find_and_authorize_profile
24
+ (patient.profile || patient.build_profile).tap do |profile|
25
+ authorize profile
26
+ end
27
+ end
28
+
29
+ def render_edit(profile)
30
+ render :edit, locals: { patient: patient, profile: profile }
31
+ end
32
+
33
+ def profile_params
34
+ params
35
+ .require(:low_clearance_profile)
36
+ .permit(document: [])
37
+ .merge(document: document_attributes)
38
+ end
39
+
40
+ def document_attributes
41
+ params.require(:low_clearance_profile)[:document]&.permit!
42
+ end
43
+ end
44
+ end
45
+ end
@@ -10,7 +10,8 @@ module Renalware
10
10
  before_action :find_primary_care_physician, only: [:edit, :update]
11
11
 
12
12
  def index
13
- primary_care_physicians = PrimaryCarePhysician.order(:family_name)
13
+ primary_care_physicians = PrimaryCarePhysician.order(:name)
14
+ .includes(:address)
14
15
  .eager_load(practices: :address)
15
16
  .page(page)
16
17
  .per(per_page)
@@ -86,11 +87,11 @@ module Renalware
86
87
 
87
88
  def primary_care_physician_params
88
89
  params.require(:patients_primary_care_physician).permit(
89
- :given_name, :family_name, :email, :practitioner_type, :code, :telephone,
90
+ :name, :practitioner_type, :code, :telephone,
90
91
  practice_ids: [],
91
92
  address_attributes: [
92
93
  :id, :name, :organisation_name, :street_1, :street_2, :street_3, :town, :county,
93
- :postcode, :country_id, :telephone, :email
94
+ :postcode, :country_id, :telephone
94
95
  ]
95
96
  )
96
97
  end
@@ -94,7 +94,8 @@ module Renalware
94
94
  def exit_site_infection_params
95
95
  params
96
96
  .require(:pd_exit_site_infection)
97
- .permit(:diagnosis_date, :treatment, :outcome, :notes)
97
+ .permit(:diagnosis_date, :treatment, :outcome, :notes, :recurrent, :cleared,
98
+ :catheter_removed, clinical_presentation: [])
98
99
  end
99
100
 
100
101
  def load_exit_site_infection
@@ -7,8 +7,11 @@ module Renalware
7
7
 
8
8
  def show
9
9
  workup = DonorWorkup.for_patient(patient).first_or_initialize
10
- redirect_to edit_patient_transplants_donor_workup_path(patient) if workup.new_record?
11
- render locals: { patient: patient, workup: workup }
10
+ if workup.new_record?
11
+ redirect_to edit_patient_transplants_donor_workup_path(patient)
12
+ else
13
+ render locals: { patient: patient, workup: workup }
14
+ end
12
15
  end
13
16
 
14
17
  def edit
@@ -0,0 +1,26 @@
1
+ require "document/embedded"
2
+ require "document/enum"
3
+
4
+ module Renalware
5
+ module LowClearance
6
+ class ProfileDocument < Document::Embedded
7
+ attribute :first_seen_on, Date
8
+ attribute :dialysis_plan, Document::Enum
9
+ attribute :dialysis_planned_on, Date
10
+ attribute :predicted_esrf_date, Date
11
+ attribute :referral_creatinine, Integer
12
+ attribute :referred_by, String
13
+ attribute :education_status, Document::Enum
14
+ attribute :referral_egfr, Decimal
15
+ attribute :education_type, Document::Enum
16
+ attribute :attended_on, Date
17
+ attribute :dvd1_provided, Document::Enum, enums: %i(yes no)
18
+ attribute :dvd2_provided, Document::Enum, enums: %i(yes no)
19
+ attribute :transplant_referral, Document::Enum, enums: %i(yes no)
20
+ attribute :transplant_referred_on, Date
21
+ attribute :home_hd_possible, Document::Enum, enums: %i(yes no)
22
+ attribute :self_care_possible, Document::Enum, enums: %i(yes no)
23
+ attribute :access_notes, String
24
+ end
25
+ end
26
+ end
@@ -23,27 +23,6 @@ module Renalware
23
23
  attribute :smoking, SmokingStatus
24
24
  end
25
25
  attribute :comorbidities, Comorbidities
26
-
27
- class LowClearance < Document::Embedded
28
- attribute :first_seen_on, Date
29
- attribute :dialysis_plan, Document::Enum
30
- attribute :dialysis_planned_on, Date
31
- attribute :predicted_esrf_date, Date
32
- attribute :referral_creatinine, Integer
33
- attribute :referred_by, String
34
- attribute :education_status, Document::Enum
35
- attribute :referral_egfr, Decimal
36
- attribute :education_type, Document::Enum
37
- attribute :attended_on, Date
38
- attribute :dvd1_provided, Document::Enum, enums: %i(yes no)
39
- attribute :dvd2_provided, Document::Enum, enums: %i(yes no)
40
- attribute :transplant_referral, Document::Enum, enums: %i(yes no)
41
- attribute :transplant_referred_on, Date
42
- attribute :home_hd_possible, Document::Enum, enums: %i(yes no)
43
- attribute :self_care_possible, Document::Enum, enums: %i(yes no)
44
- attribute :access_notes, String
45
- end
46
- attribute :low_clearance, LowClearance
47
26
  end
48
27
  end
49
28
  end
@@ -60,6 +60,11 @@ module Renalware
60
60
  bool ? "Yes" : "No"
61
61
  end
62
62
 
63
+ def yes_no_if_set(bool)
64
+ return if bool.nil?
65
+ yes_no(bool)
66
+ end
67
+
63
68
  def default_for_associated(assoc, method, msg)
64
69
  assoc.present? ? assoc.public_send(method) : msg
65
70
  end
@@ -6,28 +6,4 @@ module Renalware
6
6
  klass.human_attribute_name(attr) + String(suffix)
7
7
  end
8
8
  end
9
-
10
- # A WIP experiment to create a better way of generating attribute names from I18n
11
- # using the underlying human_attribute_name.
12
- # Not convinced yet this is worth added complexity but the idea to access labels eg for
13
- # table headers like so:
14
- # PatientLabels.name
15
- # PatientLabels.nhs_number
16
- #
17
- # class PatientLabels
18
- # class << self
19
- # # disables :reek:BooleanParameter
20
- # def method_missing(method, *_args, &block)
21
- # Renalware::Patient.human_attribute_name(method.to_sym) || super
22
- # end
23
-
24
- # def respond_to_missing?(_method_name, _include_private = false)
25
- # true
26
- # end
27
-
28
- # def name
29
- # method_missing(:name)
30
- # end
31
- # end
32
- # end
33
9
  end
@@ -7,25 +7,5 @@ module Renalware
7
7
  def new_pd_infection_organism_path(infectable)
8
8
  super(infectable_type: infectable.class.to_s, infectable_id: infectable.id)
9
9
  end
10
-
11
- def organisms_and_sensitivities(infection_organisms)
12
- if infection_organisms.blank?
13
- "Unknown"
14
- else
15
- safe_join(
16
- infection_organisms.map do |io|
17
- "<li>#{io.organism_code.name} - #{io.sensitivity}</li>".html_safe
18
- end
19
- )
20
- end
21
- end
22
-
23
- def organisms(infection_organisms)
24
- if infection_organisms.blank?
25
- "Unknown"
26
- else
27
- safe_join(infection_organisms.map { |io| "<li>#{io.organism_code.name}</li>".html_safe })
28
- end
29
- end
30
10
  end
31
11
  end
@@ -22,7 +22,7 @@ module Renalware
22
22
  when :pd then patient_pd_mdm_path(patient)
23
23
  when :hd then patient_hd_mdm_path(patient)
24
24
  when :transplant then patient_transplants_mdm_path(patient)
25
- when :low_clearance then patient_renal_low_clearance_mdm_path(patient)
25
+ when :low_clearance then patient_low_clearance_mdm_path(patient)
26
26
  end
27
27
  end
28
28
  end
@@ -15,11 +15,7 @@ module Renalware
15
15
  end
16
16
 
17
17
  def default_daily_glucose_average(glucose)
18
- if glucose.blank?
19
- 0
20
- else
21
- glucose
22
- end
18
+ glucose.presence || 0
23
19
  end
24
20
 
25
21
  # The list of treatment options, stored in I18n
@@ -1,7 +1,5 @@
1
1
  module Renalware
2
- class Admin::UserMailer < ActionMailer::Base
3
- default from: "renalware-admin@renalware.herokuapp.com"
4
-
2
+ class Admin::UserMailer < ApplicationMailer
5
3
  def approval(user)
6
4
  @user = user
7
5
  mail(to: @user.email, subject: "Renalware account approved")
@@ -0,0 +1,9 @@
1
+ require_dependency "renalware/letters"
2
+
3
+ module Renalware
4
+ module Letters
5
+ module Delivery
6
+ class PatientHasNoPracticeError < StandardError; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ require_dependency "renalware/letters"
2
+ require "attr_extras"
3
+ require_relative "./errors"
4
+
5
+ module Renalware
6
+ module Letters
7
+ module Delivery
8
+ class PracticeMailer < ApplicationMailer
9
+ def patient_letter(letter:, to:)
10
+ validate_letter(letter)
11
+ letter_presenter = LetterPresenterFactory.new(letter)
12
+ attachments["letter.pdf"] = Letters::PdfRenderer.call(letter_presenter)
13
+
14
+ # Note here we render the content in a block so that we can use the locals: {..} syntax
15
+ # which is cleaner than using @vars.
16
+ mail(
17
+ to: to,
18
+ subject: build_subject_for(letter),
19
+ from: Renalware.config.default_from_email_address,
20
+ locals: locals_for(letter)
21
+ ) { |format| format.text { render(locals: locals_for(letter)) } }
22
+ end
23
+
24
+ private
25
+
26
+ # "$lettdescr from King's Renal Unit (KCH No $hospno1)";
27
+ def build_subject_for(letter)
28
+ renal_unit = Renalware.config.renal_unit_on_letters
29
+ "#{letter.description} from #{renal_unit} #{letter.patient.hospital_identifier}"
30
+ end
31
+
32
+ def locals_for(letter)
33
+ {
34
+ help_phone_number: Renalware.config.phone_number_on_letters,
35
+ help_email_address: Renalware.config.default_from_email_address,
36
+ ident_metadata: ident_meta_data_for_insertion_into_body(letter)
37
+ }
38
+ end
39
+
40
+ def ident_meta_data_for_insertion_into_body(letter)
41
+ patient = letter.patient
42
+ PracticeEmailMetaData.new(
43
+ letter: letter,
44
+ primary_care_physician: patient.primary_care_physician,
45
+ practice: patient.practice
46
+ )
47
+ end
48
+
49
+ def validate_letter(letter)
50
+ raise Delivery::PatientHasNoPracticeError if letter.patient&.practice.blank?
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ require_dependency "renalware/feeds"
2
+
3
+ module Renalware
4
+ module Feeds
5
+ module Job
6
+ extend ActiveSupport::Concern
7
+
8
+ def formatted_exception(error)
9
+ [
10
+ "#{error.backtrace.first}: #{error.message} (#{error.class})",
11
+ error.backtrace.drop(1).map{ |s| "\t#{s}" }
12
+ ].join("\n")
13
+ end
14
+
15
+ def log(msg)
16
+ Rails.logger.info(msg)
17
+ end
18
+
19
+ def find_file_in(files, pattern)
20
+ file = files.select{ |f| f.basename.to_s.match(pattern) }.first
21
+ if file.nil?
22
+ msg = "Zip file does not contain a file with name matching #{pattern}!"
23
+ log(msg)
24
+ fail(msg)
25
+ end
26
+ file
27
+ end
28
+ end
29
+ end
30
+ end
@@ -5,15 +5,38 @@ module Renalware
5
5
  module LetterPathology
6
6
  extend ActiveSupport::Concern
7
7
 
8
- # Update a letter's pathology snapshot to the current point in time
9
- def build_pathology_snapshot(patient, letter)
10
- return if patient.current_observation_set.nil?
11
- possible_letter_codes = Renalware::Letters::RelevantObservationDescription.all.map(&:code)
12
- letter.pathology_snapshot = begin
13
- patient.current_observation_set.values.select do |code, _|
14
- possible_letter_codes.include?(code.to_s)
15
- end
8
+ # Filters a set of observations using a specific set of OBX codes
9
+ class FilteredObservationSet
10
+ EMPTY_SNAPSHOT = {}.freeze
11
+
12
+ def initialize(observation_set:, codes: nil)
13
+ @codes = codes || RelevantObservationDescription.all.map(&:code)
14
+ @observation_set = observation_set
16
15
  end
16
+
17
+ # Returns a hash of the filtered observations e.g.
18
+ # {
19
+ # "NA"=>{"result"=>"139", "observed_at"=>"2016-03-15T03:28:00"},
20
+ # "ALB"=>{"result"=>"49", "observed_at"=>"2016-03-15T03:28:00"},
21
+ # ...
22
+ # }
23
+ def to_h
24
+ return if observation_set.blank?
25
+ hash = observation_set.values.select { |code, _| codes.include?(code.to_s) }
26
+ hash.empty? ? nil : hash
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :observation_set, :codes
32
+ end
33
+
34
+ # Update a letter's pathology snapshot to the current point in time
35
+ def build_pathology_snapshot(patient)
36
+ FilteredObservationSet.new(
37
+ observation_set: patient.current_observation_set,
38
+ codes: Renalware::Letters::RelevantObservationDescription.all.map(&:code)
39
+ ).to_h
17
40
  end
18
41
  end
19
42
  end
@@ -52,16 +52,16 @@ module Renalware
52
52
 
53
53
  def identity_sql(query)
54
54
  sql = <<-SQL.squish
55
- local_patient_id = :ucase_term OR
56
- local_patient_id_2 = :ucase_term OR
57
- local_patient_id_3 = :ucase_term OR
58
- local_patient_id_4 = :ucase_term OR
59
- local_patient_id_5 = :ucase_term OR
60
- external_patient_id = :exact_term OR
61
- nhs_number = :exact_term OR
62
- family_name ILIKE :fuzzy_term
55
+ patients.local_patient_id = :ucase_term OR
56
+ patients.local_patient_id_2 = :ucase_term OR
57
+ patients.local_patient_id_3 = :ucase_term OR
58
+ patients.local_patient_id_4 = :ucase_term OR
59
+ patients.local_patient_id_5 = :ucase_term OR
60
+ patients.external_patient_id = :exact_term OR
61
+ patients.nhs_number = :exact_term OR
62
+ patients.family_name ILIKE :fuzzy_term
63
63
  SQL
64
- sql += " OR ukrdc_external_id = :exact_term" if query_is_a_uuid?(query)
64
+ sql += " OR patients.ukrdc_external_id = :exact_term" if query_is_a_uuid?(query)
65
65
  sql
66
66
  end
67
67
  # rubocop:enable Metrics/MethodLength
@@ -4,18 +4,23 @@ module Renalware
4
4
 
5
5
  included do
6
6
  class_eval do
7
- validates :given_name, presence: true
8
7
  validates :family_name, presence: true
8
+ validates :given_name,
9
+ presence: {
10
+ unless: -> {
11
+ defined?(skip_given_name_validation?) && skip_given_name_validation?
12
+ }
13
+ }
9
14
  end
10
15
 
11
16
  def full_name
12
- "#{given_name} #{family_name}"
17
+ [given_name, family_name].compact.join(" ")
13
18
  end
14
19
 
15
20
  def to_s(format = :default)
16
21
  case format
17
22
  when :default
18
- "#{family_name}, #{given_name}"
23
+ [family_name, given_name].compact.join(", ")
19
24
  when :long
20
25
  "#{family_name}, #{given_name} (#{nhs_number})"
21
26
  end
@@ -0,0 +1,11 @@
1
+ module Renalware
2
+ module StringLogging
3
+ extend ActiveSupport::Concern
4
+
5
+ def logging_to_stringio(string_io)
6
+ logger = ActiveSupport::Logger.new(string_io)
7
+ logger.formatter = Rails.configuration.log_formatter
8
+ Rails.logger = ActiveSupport::TaggedLogging.new(logger)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ require_dependency "renalware/admissions"
2
+
3
+ module Renalware
4
+ module Admissions
5
+ class Admission < ApplicationRecord
6
+ include Accountable
7
+ # PatientsRansackHelper adds the :identity_match scope for querying by patient name,
8
+ # local hospital id or NHS number. We use this scope from the filters on the admissions list
9
+ # to enable searching for a patient. *Note* you must join onto the patients table first
10
+ # if calling this scope or using it with ransack, e.g.
11
+ # Admission.joins(:patient).identity_match("rab rog")
12
+
13
+ include PatientsRansackHelper
14
+ extend Enumerize
15
+
16
+ acts_as_paranoid
17
+
18
+ validates :patient_id, presence: true
19
+ validates :hospital_ward_id, presence: true
20
+ validates :admitted_on, presence: true
21
+ validates :reason_for_admission, presence: true
22
+ validates :admission_type, presence: true
23
+
24
+ belongs_to :patient
25
+ belongs_to :hospital_ward, class_name: "Hospitals::Ward"
26
+ belongs_to :summarised_by, class_name: "User"
27
+ belongs_to :modality_at_admission, class_name: "Modalities::Modality"
28
+
29
+ enumerize :admission_type, in: %i(unknown routine elective emergency consult transfer)
30
+ enumerize :discharge_destination, in: %i(home other_ward other_hosp itu death other)
31
+
32
+ scope :currently_admitted, lambda {
33
+ where(discharged_on: nil)
34
+ }
35
+
36
+ scope :discharged_but_missing_a_summary, lambda {
37
+ where("discharge_summary is null or discharge_summary = ?", "")
38
+ .where.not(discharged_on: nil)
39
+ }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require_dependency "renalware/admissions"
2
+ require "attr_extras"
3
+
4
+ module Renalware
5
+ module Admissions
6
+ class AdmissionQuery
7
+ pattr_initialize :query
8
+
9
+ def self.call(query)
10
+ new(query).call
11
+ end
12
+
13
+ def call
14
+ search.result
15
+ end
16
+
17
+ def search
18
+ @search ||= begin
19
+ Admission
20
+ .extending(Scopes)
21
+ .joins(:patient) # required for PatientsRansackHelper - see Admission
22
+ .includes(
23
+ hospital_ward: [:hospital_unit],
24
+ patient: { current_modality: [:description] }
25
+ )
26
+ .order(created_at: :desc)
27
+ .ransack(query)
28
+ end
29
+ end
30
+
31
+ module Scopes
32
+ def ransackable_scopes(_auth_object = nil)
33
+ %i(currently_admitted discharged_but_missing_a_summary identity_match)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,51 @@
1
+ module Renalware
2
+ module Admissions
3
+ # Rather than using a Ransack Search object behind the form, as we do in many other places
4
+ # here we use a custom form object. This is mainly because we have a drop down of (virtual)
5
+ # statues, where each maps to a scope on Admission, where we want the selected 'status'
6
+ # to result in its associated scope being called. Ransack doesn't handle this, not
7
+ # surprisingly. So we have this thin form object around Ransack and do some pre-processing
8
+ # on the Status attribute (see #status_scope).
9
+ class AdmissionSearchForm
10
+ include ActiveModel::Model
11
+ include Virtus::Model
12
+
13
+ attribute :hospital_unit_id, Integer
14
+ attribute :hospital_ward_id, Integer
15
+ attribute :status, String
16
+ attribute :term, String
17
+
18
+ # Pass our simple form attributes to Ransack - we lean on Ransack to do querying
19
+ # so as to avoid unnecessary code here, though the magic obfuscates things a little...
20
+ def submit
21
+ @search ||= begin
22
+ options = {
23
+ hospital_ward_hospital_unit_id_eq: hospital_unit_id,
24
+ hospital_ward_id_eq: hospital_ward_id,
25
+ identity_match: term
26
+ }.merge!(status_scope)
27
+
28
+ AdmissionQuery.call(options)
29
+ end
30
+ end
31
+
32
+ def status_dropdown_options
33
+ [
34
+ ["Currently admitted", :currently_admitted],
35
+ ["Discharged but missing summary", :discharged_but_missing_a_summary]
36
+ ]
37
+ end
38
+
39
+ # If a status was selected in the drop down, map this to a ransack way of saying
40
+ # "call this scope on Admission", which is to pass the following (note the true
41
+ # which indicates the scope should be used):
42
+ #
43
+ # { name_of_scope: true }
44
+ #
45
+ def status_scope
46
+ return {} if status.blank?
47
+ { status.to_sym => true }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -21,6 +21,7 @@ module Renalware
21
21
  validates :date, timeliness: { type: :date }
22
22
  validates :time, timeliness: { type: :time, allow_blank: true }
23
23
  validates :pulse, "renalware/patients/pulse" => true
24
+ validates :height, "renalware/patients/height" => true
24
25
  validates :temperature, "renalware/patients/temperature" => true
25
26
 
26
27
  enumerize :urine_blood, in: %i(neg trace very_low low medium high)
@@ -0,0 +1,31 @@
1
+ require_dependency "renalware/feeds"
2
+
3
+ module Renalware
4
+ module Feeds
5
+ class File < ApplicationRecord
6
+ include Accountable
7
+ extend Enumerize
8
+
9
+ validates :location, presence: true
10
+ validates :status, presence: true
11
+ validates :created_by, presence: true
12
+ validates :file_type, presence: true
13
+
14
+ belongs_to :file_type
15
+
16
+ enum status: { waiting: 0, processing: 1, success: 2, failure: 3 }
17
+
18
+ scope :ordered, ->{ order(created_at: :desc) }
19
+
20
+ def self.build(location:, file_type:, user: SystemUser.find)
21
+ new(
22
+ location: location,
23
+ file_type: file_type,
24
+ status: :waiting,
25
+ updated_by: user,
26
+ created_by: user
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require_dependency "renalware/feeds"
2
+
3
+ module Renalware
4
+ module Feeds
5
+ class FileType < ApplicationRecord
6
+ validates :name, presence: true
7
+ validates :description, presence: true
8
+ validates :prompt, presence: true
9
+
10
+ has_many :files
11
+ end
12
+ end
13
+ end