renalware-core 2.0.113 → 2.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -2
  3. data/app/assets/javascripts/renalware/application.js.erb +0 -1
  4. data/app/assets/javascripts/renalware/feed_only_inputs.js.erb +26 -0
  5. data/app/assets/javascripts/renalware/feeds.js +50 -0
  6. data/app/assets/javascripts/renalware/person_ajax_search.js +43 -0
  7. data/app/assets/stylesheets/renalware/application.scss +0 -1
  8. data/app/assets/stylesheets/renalware/modules/_admin.scss +7 -0
  9. data/app/assets/stylesheets/renalware/modules/_pathology.scss +1 -1
  10. data/app/assets/stylesheets/renalware/modules/_patients.scss +6 -0
  11. data/app/assets/stylesheets/renalware/modules/_snippets.scss +2 -2
  12. data/app/assets/stylesheets/renalware/partials/_forms.scss +5 -1
  13. data/app/assets/stylesheets/renalware/partials/_layout.scss +4 -0
  14. data/app/{views/renalware/patients/_side_menu.html.slim → components/renalware/patients/side_menu_component.html.slim} +0 -0
  15. data/app/components/renalware/patients/side_menu_component.rb +18 -0
  16. data/app/controllers/renalware/clinical/body_compositions_controller.rb +6 -0
  17. data/app/controllers/renalware/feeds/hl7_test_messages_controller.rb +60 -0
  18. data/app/controllers/renalware/hd/mdm_patients_controller.rb +16 -6
  19. data/app/controllers/renalware/hd/scheduling/diaries_controller.rb +91 -0
  20. data/app/controllers/renalware/hd/scheduling/diary_slots_controller.rb +169 -0
  21. data/app/controllers/renalware/hd/session_forms/batches_controller.rb +1 -1
  22. data/app/controllers/renalware/pathology/observation_requests_controller.rb +23 -4
  23. data/app/controllers/renalware/pathology/requests/requests_controller.rb +0 -4
  24. data/app/controllers/renalware/patients/abridgements_controller.rb +39 -0
  25. data/app/controllers/renalware/pd/regimes_controller.rb +26 -0
  26. data/app/controllers/renalware/problems/problems_controller.rb +2 -2
  27. data/app/helpers/renalware/application_helper.rb +9 -0
  28. data/app/helpers/renalware/article_helper.rb +18 -0
  29. data/app/helpers/renalware/form_helper.rb +3 -2
  30. data/app/helpers/renalware/users_helper.rb +5 -1
  31. data/app/javascript/controllers/clipboard_controller.js +16 -0
  32. data/app/javascript/packs/renalware_core.js +20 -0
  33. data/app/jobs/feed_job.rb +1 -3
  34. data/app/jobs/hl7_message_example.yml +2 -2
  35. data/app/models/renalware/feeds/files/practice_memberships/import_job.rb +3 -0
  36. data/app/models/renalware/feeds/files/primary_care_physicians/import_job.rb +2 -0
  37. data/app/models/renalware/feeds/hl7_message.rb +57 -6
  38. data/app/models/renalware/feeds/hl7_test_form.rb +10 -0
  39. data/app/models/renalware/feeds/hl7_test_message.rb +11 -0
  40. data/app/models/renalware/feeds/message_parser.rb +6 -2
  41. data/app/models/renalware/feeds/message_processor.rb +44 -32
  42. data/app/models/renalware/feeds/persist_message.rb +9 -3
  43. data/app/models/renalware/feeds.rb +2 -0
  44. data/app/models/renalware/hd/scheduling/archive_arguments.rb +19 -0
  45. data/app/models/renalware/hd/scheduling/diary.rb +54 -0
  46. data/app/models/renalware/hd/scheduling/diary_housekeeping_job.rb +84 -0
  47. data/app/models/renalware/hd/scheduling/diary_range.rb +69 -0
  48. data/app/models/renalware/hd/scheduling/diary_slot.rb +88 -0
  49. data/app/models/renalware/hd/scheduling/find_or_create_diary_by_week_query.rb +52 -0
  50. data/app/models/renalware/hd/scheduling/find_or_create_master_diary.rb +27 -0
  51. data/app/models/renalware/hd/scheduling/master_diary.rb +35 -0
  52. data/app/models/renalware/hd/scheduling/weekly_diary.rb +47 -0
  53. data/app/models/renalware/pathology/message_listener.rb +2 -2
  54. data/app/models/renalware/pathology/requests/global_rule/latest_crf_older_than_weeks.rb +38 -0
  55. data/app/models/renalware/pathology/requests/global_rule/patient_is_diabetic.rb +1 -1
  56. data/app/models/renalware/patient.rb +1 -1
  57. data/app/models/renalware/patients/abridgement.rb +18 -0
  58. data/app/models/renalware/patients/abridgement_search_form.rb +12 -0
  59. data/app/models/renalware/patients/ingestion/command.rb +25 -0
  60. data/app/models/renalware/patients/ingestion/command_factory.rb +135 -0
  61. data/app/models/renalware/patients/ingestion/commands/add_or_update_patient.rb +65 -0
  62. data/app/models/renalware/patients/ingestion/message_listener.rb +21 -0
  63. data/app/models/renalware/patients/ingestion/message_mapper.rb +26 -0
  64. data/app/models/renalware/patients/ingestion/message_mappers/patient.rb +73 -0
  65. data/app/models/renalware/patients/ingestion/update_master_patient_index.rb +60 -0
  66. data/app/models/renalware/patients/ingestion/update_master_patient_index_job.rb.dead +20 -0
  67. data/app/models/renalware/patients.rb +4 -3
  68. data/app/models/renalware/problems/problem.rb +6 -2
  69. data/app/models/renalware/ukrdc/incoming/paths.rb +6 -7
  70. data/app/policies/renalware/admin/devops_policy.rb +18 -0
  71. data/app/policies/renalware/hd/{diary_policy.rb → scheduling/diary_policy.rb} +3 -1
  72. data/app/presenters/renalware/clinical/profile_presenter.rb +2 -1
  73. data/app/presenters/renalware/directory/person_auto_complete_presenter.rb +1 -1
  74. data/app/presenters/renalware/hd/scheduling/diary_presenter.rb +84 -0
  75. data/app/presenters/renalware/hd/scheduling/diary_slot_presenter.rb +74 -0
  76. data/app/presenters/renalware/hd/scheduling/null_slot.rb +42 -0
  77. data/app/presenters/renalware/pd/dashboard_presenter.rb +3 -2
  78. data/app/views/renalware/accesses/procedures/_form.html.slim +5 -1
  79. data/app/views/renalware/accesses/procedures/_list.html.slim +11 -4
  80. data/app/views/renalware/accesses/procedures/show.html.slim +17 -19
  81. data/app/views/renalware/addresses/_form.html.slim +17 -12
  82. data/app/views/renalware/admin/cache/show.html.slim +24 -0
  83. data/app/views/renalware/clinical/body_compositions/_list.html.slim +7 -43
  84. data/app/views/renalware/clinical/body_compositions/_table.html.slim +42 -0
  85. data/app/views/renalware/clinical/body_compositions/index.html.slim +9 -0
  86. data/app/views/renalware/clinical/dry_weights/_list.html.slim +2 -8
  87. data/app/views/renalware/clinical/dry_weights/_table.html.slim +7 -0
  88. data/app/views/renalware/clinical/profiles/show.html.slim +4 -2
  89. data/app/views/renalware/feeds/hl7_test_messages/create.js.erb +10 -0
  90. data/app/views/renalware/feeds/hl7_test_messages/new.slim +18 -0
  91. data/app/views/renalware/hd/mdm_patients/_filters.html.slim +0 -11
  92. data/app/views/renalware/hd/mdm_patients/_page_actions.html.slim +29 -0
  93. data/app/views/renalware/hd/mdm_patients/index.html.slim +7 -4
  94. data/app/views/renalware/hd/{diaries → scheduling/diaries}/_page_actions.html.slim +4 -4
  95. data/app/views/renalware/hd/{diaries → scheduling/diaries}/_table.html.slim +0 -0
  96. data/app/views/renalware/hd/{diaries → scheduling/diaries}/_weekly_diary.html.slim +1 -1
  97. data/app/views/renalware/hd/{diaries → scheduling/diaries}/edit.html.slim +6 -6
  98. data/app/views/renalware/hd/{diaries → scheduling/diaries}/index.html.slim +0 -0
  99. data/app/views/renalware/hd/{diaries → scheduling/diaries}/show.pdf.slim +0 -0
  100. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_form.html.slim +15 -6
  101. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_slot.html.slim +2 -2
  102. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_tab.html.slim +1 -1
  103. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/create.js.erb +1 -1
  104. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/destroy.js.erb +1 -1
  105. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/edit.html.slim +2 -2
  106. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.html.slim +0 -0
  107. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.js.erb +0 -0
  108. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/show.js.erb +0 -0
  109. data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/update.js.erb +1 -1
  110. data/app/views/renalware/hospitals/units/index.html.slim +2 -2
  111. data/app/views/renalware/layouts/_patient.html.slim +2 -1
  112. data/app/views/renalware/letters/contacts/_form.html.slim +10 -13
  113. data/app/views/renalware/letters/letters/_form.html.slim +2 -9
  114. data/app/views/renalware/navigation/_developer.html.slim +4 -0
  115. data/app/views/renalware/navigation/_menu.html.slim +2 -0
  116. data/app/views/renalware/pathology/observation_requests/_filters.html.slim +17 -0
  117. data/app/views/renalware/pathology/observation_requests/index.html.slim +2 -1
  118. data/app/views/renalware/patients/_layout.html.slim +1 -1
  119. data/app/views/renalware/patients/_side_menu.html.slim.dead +7 -0
  120. data/app/views/renalware/patients/abridgements/_abridgement.html.slim +8 -0
  121. data/app/views/renalware/patients/abridgements/_table.html.slim +12 -0
  122. data/app/views/renalware/patients/abridgements/index.html.slim +22 -0
  123. data/app/views/renalware/patients/alerts/create.json +3 -0
  124. data/app/views/renalware/patients/patients/_form.html.slim +36 -17
  125. data/app/views/renalware/patients/patients/edit.html.slim +1 -1
  126. data/app/views/renalware/patients/patients/new.html.slim +1 -1
  127. data/app/views/renalware/patients/side_menu/_actions.html.slim +2 -0
  128. data/app/views/renalware/pd/_apd_regimes.html.slim +1 -1
  129. data/app/views/renalware/pd/_capd_regimes.html.slim +1 -1
  130. data/app/views/renalware/pd/dashboards/show/_apd_regimes.html.slim +11 -2
  131. data/app/views/renalware/pd/dashboards/show/_capd_regimes.html.slim +11 -2
  132. data/app/views/renalware/pd/regimes/index.html.slim +7 -0
  133. data/app/views/renalware/renal/profiles/_form.html.slim +7 -24
  134. data/app/views/renalware/shared/documents/_binary_marker_input.html.slim +2 -2
  135. data/app/views/renalware/shared/documents/_blood_group_input.html.slim +4 -2
  136. data/app/views/renalware/transplants/registrations/_form.html.slim +22 -17
  137. data/config/locales/renalware/clinical/body_composition.yml +6 -3
  138. data/config/locales/renalware/clinical/dry_weight.en.yml +4 -3
  139. data/config/locales/renalware/hd/diary_slots.en.yml +3 -2
  140. data/config/locales/renalware/letters/contact.en.yml +0 -2
  141. data/config/routes/feeds.rb +5 -0
  142. data/config/routes/hd.rb +11 -7
  143. data/config/routes/letters.rb +0 -5
  144. data/config/routes/patients.rb +1 -0
  145. data/config/routes/pd.rb +2 -2
  146. data/config/routes/renal.rb +0 -5
  147. data/config/routes.rb +1 -0
  148. data/config/webpack/development.js +5 -0
  149. data/config/webpack/environment.js +3 -0
  150. data/config/webpack/production.js +5 -0
  151. data/config/webpack/test.js +5 -0
  152. data/config/webpacker.yml +103 -0
  153. data/db/functions/hd_diary_archive_elapsed_master_slots_v01.sql +40 -0
  154. data/db/migrate/20190322120025_create_feed_hl7_test_messages.rb +12 -0
  155. data/db/migrate/20190325134823_create_patients_master_index.rb +24 -0
  156. data/db/migrate/20190327100851_add_handled_to_feed_messages.rb +5 -0
  157. data/db/migrate/20191012121433_add_consultant_to_users.rb +7 -0
  158. data/db/migrate/20191018143635_create_hd_diary_matrix_view.rb +7 -0
  159. data/db/migrate/20191018144917_create_fn_to_archive_master_slots.rb +9 -0
  160. data/db/views/hd_diary_matrix_v01.sql +38 -0
  161. data/lib/core_extensions/active_record/sort.rb +27 -9
  162. data/lib/renalware/configuration.rb +3 -0
  163. data/lib/renalware/engine.rb +31 -0
  164. data/lib/renalware/version.rb +1 -1
  165. data/lib/renalware/week_period.rb +8 -7
  166. data/lib/renalware.rb +13 -1
  167. data/lib/tasks/hd.rake +7 -0
  168. data/lib/tasks/pathology.rake +1 -1
  169. data/lib/tasks/renalware.rake +89 -4
  170. data/spec/factories/hd/scheduling/diaries.rb +18 -0
  171. data/spec/factories/hd/{slots.rb → scheduling/slots.rb} +1 -1
  172. data/spec/factories/patients/abridgements.rb +9 -0
  173. data/spec/support/hl7_helpers.rb +13 -0
  174. data/spec/support/pages/letters/form.rb +4 -1
  175. metadata +126 -50
  176. data/app/assets/javascripts/renalware/auto_complete.js +0 -63
  177. data/app/controllers/renalware/hd/diaries_controller.rb +0 -89
  178. data/app/controllers/renalware/hd/diary_slots_controller.rb +0 -175
  179. data/app/controllers/renalware/letters/descriptions_controller.rb +0 -22
  180. data/app/controllers/renalware/renal/prd_descriptions_controller.rb +0 -15
  181. data/app/models/renalware/hd/archive_yesterdays_slots_job.rb +0 -69
  182. data/app/models/renalware/hd/diary.rb +0 -41
  183. data/app/models/renalware/hd/diary_slot.rb +0 -83
  184. data/app/models/renalware/hd/find_or_create_diary_by_week_query.rb +0 -50
  185. data/app/models/renalware/hd/find_or_create_master_diary.rb +0 -26
  186. data/app/models/renalware/hd/master_diary.rb +0 -32
  187. data/app/models/renalware/hd/weekly_diary.rb +0 -45
  188. data/app/models/renalware/renal/prd_descriptions/search_query.rb +0 -35
  189. data/app/presenters/renalware/hd/diary_presenter.rb +0 -79
  190. data/app/presenters/renalware/hd/diary_slot_presenter.rb +0 -72
  191. data/app/presenters/renalware/hd/null_slot.rb +0 -40
  192. data/app/views/renalware/renal/prd_descriptions/search.json.jbuilder +0 -6
  193. data/lib/test_support/autocomplete_helpers.rb +0 -14
  194. data/spec/factories/hd/diaries.rb +0 -14
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd/base_controller"
4
-
5
- # The route to the edit route for this controller takes /:year/:week_number segments
6
- # rather than an id. THat is because when we load the diary, and when we navigate back and forth
7
- # through diaries, we are concerned with the week more then an id. Its easier to navigate to the
8
- # next week with /2017/52 than by looking up the id of the next diary ahead of time.
9
- module Renalware
10
- module HD
11
- class DiariesController < BaseController
12
- include Renalware::Concerns::PdfRenderable
13
- include Renalware::Concerns::Pageable
14
-
15
- def edit
16
- authorize weekly_diary, :show?
17
- render locals: {
18
- unit: unit,
19
- diary: DiaryPresenter.new(current_user, weekly_diary)
20
- }
21
- end
22
-
23
- # Renders a list of diaries for a hospital unit
24
- def index
25
- authorize WeeklyDiary, :index?
26
- render locals: { unit: unit, diaries: weekly_diaries }
27
- end
28
-
29
- def show
30
- diary = WeeklyDiary.find(params[:id])
31
- respond_to do |format|
32
- format.pdf do
33
- authorize diary
34
- options = default_pdf_options.merge!(
35
- pdf: pdf_filename,
36
- locals: { unit: unit, diary: DiaryPresenter.new(current_user, diary) }
37
- )
38
- render options
39
- end
40
- end
41
- end
42
-
43
- private
44
-
45
- # TODO: give a sensible name
46
- def pdf_filename
47
- "hd_unit_diary"
48
- end
49
-
50
- def weekly_diary
51
- @weekly_diary ||= begin
52
- FindOrCreateDiaryByWeekQuery.new(
53
- relation: WeeklyDiary.eager_load(
54
- slots: [:patient, :station, :diurnal_period_code],
55
- master_diary: { slots: [:patient, :station, :diurnal_period_code] }
56
- ),
57
- unit_id: unit_id,
58
- week_period: week_period,
59
- by: current_user
60
- ).call
61
- end
62
- end
63
-
64
- # The route segments are /:year/:week_number
65
- # We use a WeekPeriod value object to wrap those two things.
66
- def week_period
67
- WeekPeriod.new(
68
- week_number: params[:week_number],
69
- year: params[:year]
70
- )
71
- end
72
-
73
- def unit_id
74
- params[:unit_id]
75
- end
76
-
77
- def unit
78
- Hospitals::Unit.find(unit_id)
79
- end
80
-
81
- def weekly_diaries
82
- WeeklyDiary
83
- .where(hospital_unit_id: unit_id)
84
- .ordered
85
- .page(page).per(per_page)
86
- end
87
- end
88
- end
89
- end
@@ -1,175 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # rubocop:disable Metrics/ClassLength
4
- require_dependency "renalware/hd/base_controller"
5
-
6
- module Renalware
7
- module HD
8
- class DiarySlotsController < BaseController
9
- # GET html - renders a form
10
- # Here we will have been passed in the query string:
11
- # - the unit id
12
- # - the dirunal_period_code id
13
- # - the week and year (and thus the diary)
14
- # and from that lot we could look up the master and weekly diaries
15
- def new
16
- # Be default this assume we are going to add a slot to the weekly diary
17
- # but in which button is clicked in the modal dialog determines which diary
18
- # (master or weekly) the slot will be added to.
19
- slot = DiarySlot.new(
20
- diary: weekly_diary,
21
- station_id: params[:station_id],
22
- day_of_week: params[:day_of_week],
23
- diurnal_period_code_id: params[:diurnal_period_code_id]
24
- )
25
- authorize slot
26
- render locals: locals_for(slot), layout: false
27
- end
28
-
29
- # POST create js
30
- # Here we may be adding a slot to the weekly or master diary.
31
- # That should be transparent to us - we make the change and render
32
- # create.js.erb which, on the client, will cause an ajax js call to #show. That secondary call
33
- # is the one that refreshes the slot in the table with its latest state.
34
- # We do this to avoid having to to a check (in each action in this controller) to see if we
35
- # are on the master or weekly diary; if we always refresh the diary slot in the ui after any
36
- # action, then it will always update correctly.
37
- def create
38
- diary = Diary.find(params[:diary_id])
39
- slot = diary.slots.new(slot_params)
40
- slot.patient_id = posted_patient_id
41
- authorize slot
42
- if slot.save_by(current_user)
43
- render locals: { diary: diary, slot: diary.decorate_slot(slot) }
44
- else
45
- render :new, locals: { slot: DiarySlotPresenter.new(slot) }, layout: false
46
- end
47
- end
48
-
49
- # GET .js refresh a slot in a *weekly* diary
50
- # See comment on #create.
51
- # See show.js.erb where we refresh the slot in the diary
52
- # To get here we will have manufactured a url like this
53
- # hd/diaries/2/slots/day/1/period/1/station/1
54
- # as those bit are will we know.
55
- # Basically we are saying find for this weekly diary, find the matching
56
- # slot for the station/day/period combo and render the weekly slot if there is
57
- # one, or the master behind it if there is one of those, otherwise render an Add button.
58
- def show
59
- authorize DiarySlot, :show?
60
- slot = weekly_then_master_then_empty_slot
61
- render layout: false, locals: { slot: DiarySlotPresenter.new(slot) }
62
- end
63
-
64
- def edit
65
- authorize slot
66
- render layout: false, locals: { slot: DiarySlotPresenter.new(slot) }
67
- end
68
-
69
- # DELETE js
70
- # Delete the slot (we don't know if its on the master or weekly diary).
71
- # NB as per #create and #update, the rendered js file (destroy.js.erb) will make a secondary
72
- # back into #show to refresh the UI (i.e. we don't attempt to update the UI in destroy.js.erb)
73
- def destroy
74
- authorize slot
75
- slot.destroy!
76
- render locals: { slot: DiarySlotPresenter.new(slot) }
77
- end
78
-
79
- # PATCH js
80
- # See also comments in #create and #destroy.
81
- def update
82
- authorize slot
83
- slot.patient_id = slot_params[:patient_id]
84
- slot.save_by!(current_user)
85
- diary = slot.diary
86
- render locals: { diary: diary, slot: diary.decorate_slot(slot) }
87
- end
88
-
89
- private
90
-
91
- # Find the corresponding slot in the master if there is one, otherwise an empty slot
92
- # with an 'Add' button ready to set up a new patient
93
- def weekly_then_master_then_empty_slot
94
- empty_slot = build_empty_weekly_slot
95
- find_weekly_slot(empty_slot) || find_master_slot(empty_slot) || empty_slot
96
- end
97
-
98
- def find_master_slot(args)
99
- slot = master_diary.slots.find_by(
100
- diurnal_period_code_id: args.diurnal_period_code_id,
101
- station_id: args.station_id,
102
- day_of_week: args.day_of_week
103
- )
104
- slot && master_diary.decorate_slot(slot)
105
- end
106
-
107
- def find_weekly_slot(args)
108
- slot = weekly_diary.slots.find_by(
109
- diurnal_period_code_id: args.diurnal_period_code_id,
110
- station_id: args.station_id,
111
- day_of_week: args.day_of_week
112
- )
113
- slot && weekly_diary.decorate_slot(slot)
114
- end
115
-
116
- # Used for searching etc
117
- def build_empty_weekly_slot
118
- weekly_diary.slots.new(
119
- day_of_week: params[:day_of_week],
120
- station_id: params[:station_id],
121
- diurnal_period_code_id: params[:diurnal_period_code_id]
122
- )
123
- end
124
-
125
- def slot
126
- @slot ||= HD::DiarySlot.find(params[:id])
127
- end
128
-
129
- # In the url the :diary_id param is always the weekly diary id!
130
- def weekly_diary
131
- @weekly_diary ||= WeeklyDiary.find(params[:diary_id])
132
- end
133
-
134
- def master_diary
135
- weekly_diary.master_diary
136
- end
137
-
138
- def locals_for(slot)
139
- {
140
- slot: DiarySlotPresenter.new(slot),
141
- weekly_diary: weekly_diary
142
- }
143
- end
144
-
145
- # In the modal dialog that submits the patient_id there are several (select2) dropdown
146
- # a user can use to choose the patient. Each one has the name patient_id[] so they are
147
- # submitted in the form as an array. However the array can only hold one id value ie we
148
- # might get posted patient_id: ["", "123", ""] but never ["2", "123", ""].
149
- # Here we reduce that array down to one patient id.
150
- def posted_patient_id
151
- patient_ids = Array(slot_params[:patient_id]).reject(&:blank?).uniq
152
- if patient_ids.length > 1
153
- raise ArgumentError, "More than one id submitted in patient_id[] : #{patient_ids}"
154
- end
155
-
156
- patient_ids.first
157
- end
158
-
159
- def slot_params
160
- params
161
- .require(:hd_diary_slot)
162
- .permit(
163
- :master_slot,
164
- :day_of_week,
165
- :diurnal_period_code_id,
166
- :station_id,
167
- :target_diary_id,
168
- :change_type,
169
- patient_id: []
170
- )
171
- end
172
- end
173
- end
174
- end
175
- # rubocop:enable Metrics/ClassLength
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/letters"
4
-
5
- module Renalware
6
- module Letters
7
- class DescriptionsController < ApplicationController
8
- def search
9
- query = Letters::Descriptions::SearchQuery.new(params[:term])
10
- render json: DescriptionAutocompleteResponse.to_json(query.call)
11
- end
12
-
13
- class DescriptionAutocompleteResponse
14
- def self.to_json(collection)
15
- collection.map do |item|
16
- { id: item.id, label: item.text }
17
- end.to_json
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/renal"
4
-
5
- module Renalware
6
- module Renal
7
- class PRDDescriptionsController < BaseController
8
- skip_after_action :verify_authorized, only: [:search]
9
-
10
- def search
11
- @prd_descriptions = PRDDescriptions::SearchQuery.new(term: params[:term]).call
12
- end
13
- end
14
- end
15
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "renalware/hd"
4
-
5
- # A cron job creates this delayed job, which does the following:
6
- # For all Weekly Diaries in the past, plus this week
7
- # for each day that is in the past
8
- # mark any slots in the weekly diary as archived
9
- # and where the weekly diary is inheriting slots from the master diary
10
- # create corresponding slots in the weekly diary (ie migrate thos slots from master to weekly)
11
- # and archive them.
12
- # Not slots before the current day (or the up_until: arg) should be touched
13
- #
14
- #
15
- # OK we have a problem,
16
- # If last week there was no weekly diary created... then there is nothing to archive if eg today is
17
- # Monday.
18
- # So really whats the query for finding slots to archive?
19
- # We need to really always inner join onto weekly diaryies, and within tose for their slots
20
- # select unarchved onces in the past.
21
- # So we MUST always have weekly diaries for every possible week and not rely om a user working te UI
22
- # to create these JIT - because if they don't, unless we have a fn to creatae missing diaries,
23
- # (from which date?) then we can't query
24
- # So either
25
- # - seed next 10 years (520 per unit)
26
- # - have a fn to generate missing diaries - might be better and safer in the long run?
27
- # - Otherwise after 5 or 10 years or whatever its bound to have cased a problem.
28
-
29
- module Renalware
30
- module HD
31
- class ArchiveYesterdaysSlotsJob < ApplicationJob
32
- attr_reader :up_until
33
-
34
- # :reek:UtilityFunction
35
- def perform(up_until: nil)
36
- @up_until = up_until&.to_date
37
- @up_until ||= (Time.zone.today - 1.day)
38
-
39
- diary = Diary.find_by(year: @up_until.year, week_number: @up_until.cweek)
40
- return unless diary
41
-
42
- diary
43
- .slots
44
- .unarchived
45
- .where(day_of_week: @up_until.cwday)
46
- .update_all(archived: true, archived_at: Time.zone.now)
47
- # DiarySlot
48
- # .unarchived
49
- # .joins(:diary)
50
- # .where(hd_diaries: { year: up_until.year, week_number: up_until.cweek)
51
-
52
- # .update_all(archived: true, archived_at: Time.zone.now)
53
- end
54
-
55
- private
56
-
57
- def create_missing_weekly_diaries
58
- # intering query
59
- # basic implemenraiton
60
- # select all weeklydiaries pluch year week from installation start date??? to now
61
- # loop through
62
- # diary year 2017 week 1
63
- # MISSING diary year 2017 week 1 - so create
64
- # diary year 2017 week 3
65
- # select
66
- end
67
- end
68
- end
69
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd"
4
-
5
- # A Diary is the schedule of HD Station/Patients assignments for one week for a particular unit.
6
- # A Diary is split into Periods (eg. am pm eve), and each Period has a matrix of slots
7
- # Imagine Days eg 1 to 6 on the X axis and Stations on the Y axis, and into each 'slot' we
8
- # put a patient.
9
- # A patient can only be in one slot in any period.
10
- #
11
- # Do not create instances of this class explicity, always use the STI sub classes eg MasterDiary.
12
- module Renalware
13
- module HD
14
- class Diary < ApplicationRecord
15
- include Accountable
16
-
17
- has_many :slots, class_name: "Renalware::HD::DiarySlot"
18
- has_many :patients, through: :slots, class_name: "Renalware::HD::Patient"
19
- validates :hospital_unit_id, presence: true
20
- validates :master, inclusion: { in: [true, false], allow_nil: true }
21
- composed_of :week,
22
- mapping: [%w(week_number week_number), %w(year year)],
23
- constructor: lambda { |week_number, year|
24
- WeekPeriod.new(week_number: week_number, year: year)
25
- }
26
-
27
- def self.policy_class
28
- DiaryPolicy
29
- end
30
-
31
- # Searchs the object graph rather than a SQL search
32
- def slot_for(diurnal_period_code_id, station_id, day_of_week)
33
- slots.find do |slot|
34
- slot.diurnal_period_code_id == diurnal_period_code_id &&
35
- slot.station_id == station_id &&
36
- slot.day_of_week == day_of_week
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd"
4
-
5
- module Renalware
6
- module HD
7
- # TODO: Document
8
- class DiarySlot < ApplicationRecord
9
- # Changing to_ary from private to public here is a hack required to remove a SimpleDelgator
10
- # warning in eg Renalware::HD::WeeklyDiary::WeeklySlotDecorator:
11
- #
12
- # `respond_to?': delegator does not forward private method #to_ary
13
- #
14
- # Yielding a slot from DiaryPresenter to the view seems to want to call #to_ary on it, (have
15
- # not looked into why) and as the slot is wrapped in a decorator using SimpleDelegator,
16
- # SimpleDelegatr complains it can't delegate to a private method.
17
- # An alternative is to define the following in each Slot decorator
18
- #
19
- # def respond_to?(method, include_private = false)
20
- # return false if method == :to_ary
21
- # super
22
- # end
23
- #
24
- # or to use method_missnig instead of SimpleDelegator in Slot Decorators.
25
- #
26
- public :to_ary
27
-
28
- # Virtual attribute used on a form to determine what action as preformed on the slot
29
- attr_accessor :change_type
30
-
31
- include Accountable
32
- belongs_to :diary, class_name: "Renalware::HD::Diary", touch: true
33
- belongs_to :patient, touch: true
34
- belongs_to :station, class_name: "Renalware::HD::Station"
35
- belongs_to :diurnal_period_code
36
-
37
- validates :diary, presence: true
38
- validates :patient, presence: true
39
- validates :station, presence: true
40
- validates :diurnal_period_code, presence: true
41
- validates :day_of_week, presence: true, inclusion: { in: 1..7 }
42
-
43
- scope :weekly, -> { joins(:diary).where(hd_diaries: { master: false }) }
44
- scope :archived, -> { weekly.where(archived: true) }
45
- scope :unarchived, -> { weekly.where(archived: false) }
46
-
47
- # A patient can only be assigned to one station in any period (e.g. am)/day combination
48
- # for a diary. I.e. they can't be on two stations on Monday morning.
49
- validates :patient_id,
50
- uniqueness: { scope: [:diary, :diurnal_period_code, :day_of_week] }
51
-
52
- # Scoped to a diary, the combination of day + station + diurnal_period is unique
53
- validates :diurnal_period_code_id, uniqueness: { scope: [:diary, :station_id, :day_of_week] }
54
-
55
- delegate :id, to: :diary, prefix: true
56
-
57
- def self.policy_class
58
- DiaryPolicy
59
- end
60
-
61
- def on_master_diary?
62
- diary&.master?
63
- end
64
-
65
- def description
66
- period = diurnal_period_code.code.upcase # e.g. AM
67
- if diary.master
68
- "Recurring every #{day_of_week_name} #{period}"
69
- else
70
- "This week only on #{day_of_week_name} #{period}"
71
- end
72
- end
73
-
74
- def day_of_week_name
75
- Time::DAYS_INTO_WEEK.keys[day_of_week - 1].capitalize
76
- end
77
-
78
- def cell_id
79
- "#{diurnal_period_code&.id}-#{station&.id}-#{day_of_week}"
80
- end
81
- end
82
- end
83
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd"
4
- require "renalware/week_period"
5
- ##
6
- # Returns a hospital unit's diary for the requested week (passed to #new as a WeekPeriod
7
- # value object).
8
- #
9
- module Renalware
10
- module HD
11
- class FindOrCreateDiaryByWeekQuery
12
- attr_reader :unit_id, :period, :by, :relation
13
-
14
- def initialize(unit_id:, week_period:, by:, relation: WeeklyDiary.all)
15
- @relation = relation
16
- @period = week_period
17
- @unit_id = unit_id
18
- @by = by
19
- end
20
-
21
- def call
22
- find_or_create_diary
23
- end
24
-
25
- private
26
-
27
- # Find the diary for the current unit/week/year, or, if for example if a user wants to fill
28
- # next week's diary and it does not yet exist, create it
29
- # NB we _always_ return a diary from this method - whether it is found or built just-in-time,
30
- def find_or_create_diary
31
- attrs = {
32
- hospital_unit_id: unit_id,
33
- week_number: period.week_number,
34
- year: period.year,
35
- master: false
36
- }
37
- relation.find_by(**attrs) || build_diary(**attrs)
38
- end
39
-
40
- # Create a new Weekly diary for the current week/year/unit
41
- # Add in DiaryPeriods for each currently defined diurnal period eg am pm eve
42
- def build_diary(attrs)
43
- master_diary = FindOrCreateMasterDiary.for_unit(unit_id, by)
44
- diary = WeeklyDiary.create!(**attrs, by: by, master_diary: master_diary)
45
- # Reload the diary using the supplied relation (might be egager_loads etc)
46
- relation.find(diary.id)
47
- end
48
- end
49
- end
50
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Renalware
4
- module HD
5
- class FindOrCreateMasterDiary
6
- attr_reader :unit_id, :user
7
-
8
- def self.for_unit(unit_id, user)
9
- new(unit_id, user).call
10
- end
11
-
12
- def initialize(unit_id, user)
13
- @unit_id = unit_id
14
- @user = user
15
- end
16
-
17
- # TODO: !alwasy suing first :0)
18
- def call
19
- MasterDiary.find_or_initialize_by(hospital_unit_id: unit_id).tap do |master|
20
- master.by = user
21
- master.save!
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd"
4
-
5
- module Renalware
6
- module HD
7
- class MasterDiary < Diary
8
- # Overwrite the existing master attribute to ensure it defaults to true
9
- attribute :master, :boolean, default: true
10
- validates :hospital_unit_id, uniqueness: true
11
- has_many :weekly_diaries, class_name: "Renalware::HD::WeeklyDiary"
12
- # While out DB constraints could check for the string "Renalware::HD::MasterDiary" in the type
13
- # column, this feels a bit fragile, so instead a MasterDiary must have a corresponding
14
- # master = TRUE column
15
- validates :master, inclusion: { in: [true], allow_nil: false }
16
-
17
- class MasterSlotDecorator < SimpleDelegator
18
- def master?
19
- true
20
- end
21
- end
22
-
23
- def decorate_slot(slot)
24
- MasterSlotDecorator.new(slot)
25
- end
26
-
27
- def slot_for(*args)
28
- (slot = super) && decorate_slot(slot)
29
- end
30
- end
31
- end
32
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/hd"
4
-
5
- module Renalware
6
- module HD
7
- class WeeklyDiary < Diary
8
- # Overwrite the existing master attribute to ensure it defaults to false
9
- attribute :master, :boolean, default: false
10
- belongs_to :master_diary, class_name: "Renalware::HD::MasterDiary"
11
- validates :week_number,
12
- presence: true,
13
- uniqueness: { scope: [:year, :hospital_unit_id] },
14
- inclusion: { in: 1..53 }
15
- validates :year, presence: true
16
- validates :master, inclusion: { in: [false], allow_nil: false }
17
- validates :master_diary, presence: true
18
- delegate :to_s, to: :week
19
- scope :ordered, -> { order(year: :desc, week_number: :desc) }
20
-
21
- def applies_to_current_week?
22
- today = Time.zone.today
23
- [today.cweek, today.year] == [week.week_number, week.year]
24
- end
25
-
26
- def archived?
27
- false
28
- end
29
-
30
- class WeeklySlotDecorator < SimpleDelegator
31
- def master?
32
- false
33
- end
34
- end
35
-
36
- def decorate_slot(slot)
37
- WeeklySlotDecorator.new(slot)
38
- end
39
-
40
- def slot_for(*args)
41
- (slot = super) && decorate_slot(slot)
42
- end
43
- end
44
- end
45
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_dependency "renalware/renal"
4
-
5
- module Renalware
6
- module Renal
7
- module PRDDescriptions
8
- class SearchQuery
9
- attr_reader :term, :page, :per_page
10
-
11
- def initialize(term:, page: 1, per_page: 50)
12
- @term = term
13
- @page = page
14
- @per_page = per_page
15
- end
16
-
17
- def call
18
- search.result.page(page).per(per_page).select(fields)
19
- end
20
-
21
- private
22
-
23
- def search
24
- @search ||= PRDDescription.ransack(term_or_code_cont: term).tap do |s|
25
- s.sorts = ["term"]
26
- end
27
- end
28
-
29
- def fields
30
- %i(id code term)
31
- end
32
- end
33
- end
34
- end
35
- end