renalware-core 2.0.113 → 2.0.115

Sign up to get free protection for your applications and to get access to all the features.
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