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.
- checksums.yaml +4 -4
- data/Rakefile +0 -2
- data/app/assets/javascripts/renalware/application.js.erb +0 -1
- data/app/assets/javascripts/renalware/feed_only_inputs.js.erb +26 -0
- data/app/assets/javascripts/renalware/feeds.js +50 -0
- data/app/assets/javascripts/renalware/person_ajax_search.js +43 -0
- data/app/assets/stylesheets/renalware/application.scss +0 -1
- data/app/assets/stylesheets/renalware/modules/_admin.scss +7 -0
- data/app/assets/stylesheets/renalware/modules/_pathology.scss +1 -1
- data/app/assets/stylesheets/renalware/modules/_patients.scss +6 -0
- data/app/assets/stylesheets/renalware/modules/_snippets.scss +2 -2
- data/app/assets/stylesheets/renalware/partials/_forms.scss +5 -1
- data/app/assets/stylesheets/renalware/partials/_layout.scss +4 -0
- data/app/{views/renalware/patients/_side_menu.html.slim → components/renalware/patients/side_menu_component.html.slim} +0 -0
- data/app/components/renalware/patients/side_menu_component.rb +18 -0
- data/app/controllers/renalware/clinical/body_compositions_controller.rb +6 -0
- data/app/controllers/renalware/feeds/hl7_test_messages_controller.rb +60 -0
- data/app/controllers/renalware/hd/mdm_patients_controller.rb +16 -6
- data/app/controllers/renalware/hd/scheduling/diaries_controller.rb +91 -0
- data/app/controllers/renalware/hd/scheduling/diary_slots_controller.rb +169 -0
- data/app/controllers/renalware/hd/session_forms/batches_controller.rb +1 -1
- data/app/controllers/renalware/pathology/observation_requests_controller.rb +23 -4
- data/app/controllers/renalware/pathology/requests/requests_controller.rb +0 -4
- data/app/controllers/renalware/patients/abridgements_controller.rb +39 -0
- data/app/controllers/renalware/pd/regimes_controller.rb +26 -0
- data/app/controllers/renalware/problems/problems_controller.rb +2 -2
- data/app/helpers/renalware/application_helper.rb +9 -0
- data/app/helpers/renalware/article_helper.rb +18 -0
- data/app/helpers/renalware/form_helper.rb +3 -2
- data/app/helpers/renalware/users_helper.rb +5 -1
- data/app/javascript/controllers/clipboard_controller.js +16 -0
- data/app/javascript/packs/renalware_core.js +20 -0
- data/app/jobs/feed_job.rb +1 -3
- data/app/jobs/hl7_message_example.yml +2 -2
- data/app/models/renalware/feeds/files/practice_memberships/import_job.rb +3 -0
- data/app/models/renalware/feeds/files/primary_care_physicians/import_job.rb +2 -0
- data/app/models/renalware/feeds/hl7_message.rb +57 -6
- data/app/models/renalware/feeds/hl7_test_form.rb +10 -0
- data/app/models/renalware/feeds/hl7_test_message.rb +11 -0
- data/app/models/renalware/feeds/message_parser.rb +6 -2
- data/app/models/renalware/feeds/message_processor.rb +44 -32
- data/app/models/renalware/feeds/persist_message.rb +9 -3
- data/app/models/renalware/feeds.rb +2 -0
- data/app/models/renalware/hd/scheduling/archive_arguments.rb +19 -0
- data/app/models/renalware/hd/scheduling/diary.rb +54 -0
- data/app/models/renalware/hd/scheduling/diary_housekeeping_job.rb +84 -0
- data/app/models/renalware/hd/scheduling/diary_range.rb +69 -0
- data/app/models/renalware/hd/scheduling/diary_slot.rb +88 -0
- data/app/models/renalware/hd/scheduling/find_or_create_diary_by_week_query.rb +52 -0
- data/app/models/renalware/hd/scheduling/find_or_create_master_diary.rb +27 -0
- data/app/models/renalware/hd/scheduling/master_diary.rb +35 -0
- data/app/models/renalware/hd/scheduling/weekly_diary.rb +47 -0
- data/app/models/renalware/pathology/message_listener.rb +2 -2
- data/app/models/renalware/pathology/requests/global_rule/latest_crf_older_than_weeks.rb +38 -0
- data/app/models/renalware/pathology/requests/global_rule/patient_is_diabetic.rb +1 -1
- data/app/models/renalware/patient.rb +1 -1
- data/app/models/renalware/patients/abridgement.rb +18 -0
- data/app/models/renalware/patients/abridgement_search_form.rb +12 -0
- data/app/models/renalware/patients/ingestion/command.rb +25 -0
- data/app/models/renalware/patients/ingestion/command_factory.rb +135 -0
- data/app/models/renalware/patients/ingestion/commands/add_or_update_patient.rb +65 -0
- data/app/models/renalware/patients/ingestion/message_listener.rb +21 -0
- data/app/models/renalware/patients/ingestion/message_mapper.rb +26 -0
- data/app/models/renalware/patients/ingestion/message_mappers/patient.rb +73 -0
- data/app/models/renalware/patients/ingestion/update_master_patient_index.rb +60 -0
- data/app/models/renalware/patients/ingestion/update_master_patient_index_job.rb.dead +20 -0
- data/app/models/renalware/patients.rb +4 -3
- data/app/models/renalware/problems/problem.rb +6 -2
- data/app/models/renalware/ukrdc/incoming/paths.rb +6 -7
- data/app/policies/renalware/admin/devops_policy.rb +18 -0
- data/app/policies/renalware/hd/{diary_policy.rb → scheduling/diary_policy.rb} +3 -1
- data/app/presenters/renalware/clinical/profile_presenter.rb +2 -1
- data/app/presenters/renalware/directory/person_auto_complete_presenter.rb +1 -1
- data/app/presenters/renalware/hd/scheduling/diary_presenter.rb +84 -0
- data/app/presenters/renalware/hd/scheduling/diary_slot_presenter.rb +74 -0
- data/app/presenters/renalware/hd/scheduling/null_slot.rb +42 -0
- data/app/presenters/renalware/pd/dashboard_presenter.rb +3 -2
- data/app/views/renalware/accesses/procedures/_form.html.slim +5 -1
- data/app/views/renalware/accesses/procedures/_list.html.slim +11 -4
- data/app/views/renalware/accesses/procedures/show.html.slim +17 -19
- data/app/views/renalware/addresses/_form.html.slim +17 -12
- data/app/views/renalware/admin/cache/show.html.slim +24 -0
- data/app/views/renalware/clinical/body_compositions/_list.html.slim +7 -43
- data/app/views/renalware/clinical/body_compositions/_table.html.slim +42 -0
- data/app/views/renalware/clinical/body_compositions/index.html.slim +9 -0
- data/app/views/renalware/clinical/dry_weights/_list.html.slim +2 -8
- data/app/views/renalware/clinical/dry_weights/_table.html.slim +7 -0
- data/app/views/renalware/clinical/profiles/show.html.slim +4 -2
- data/app/views/renalware/feeds/hl7_test_messages/create.js.erb +10 -0
- data/app/views/renalware/feeds/hl7_test_messages/new.slim +18 -0
- data/app/views/renalware/hd/mdm_patients/_filters.html.slim +0 -11
- data/app/views/renalware/hd/mdm_patients/_page_actions.html.slim +29 -0
- data/app/views/renalware/hd/mdm_patients/index.html.slim +7 -4
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_page_actions.html.slim +4 -4
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_table.html.slim +0 -0
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_weekly_diary.html.slim +1 -1
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/edit.html.slim +6 -6
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/index.html.slim +0 -0
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/show.pdf.slim +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_form.html.slim +15 -6
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_slot.html.slim +2 -2
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_tab.html.slim +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/create.js.erb +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/destroy.js.erb +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/edit.html.slim +2 -2
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.html.slim +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.js.erb +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/show.js.erb +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/update.js.erb +1 -1
- data/app/views/renalware/hospitals/units/index.html.slim +2 -2
- data/app/views/renalware/layouts/_patient.html.slim +2 -1
- data/app/views/renalware/letters/contacts/_form.html.slim +10 -13
- data/app/views/renalware/letters/letters/_form.html.slim +2 -9
- data/app/views/renalware/navigation/_developer.html.slim +4 -0
- data/app/views/renalware/navigation/_menu.html.slim +2 -0
- data/app/views/renalware/pathology/observation_requests/_filters.html.slim +17 -0
- data/app/views/renalware/pathology/observation_requests/index.html.slim +2 -1
- data/app/views/renalware/patients/_layout.html.slim +1 -1
- data/app/views/renalware/patients/_side_menu.html.slim.dead +7 -0
- data/app/views/renalware/patients/abridgements/_abridgement.html.slim +8 -0
- data/app/views/renalware/patients/abridgements/_table.html.slim +12 -0
- data/app/views/renalware/patients/abridgements/index.html.slim +22 -0
- data/app/views/renalware/patients/alerts/create.json +3 -0
- data/app/views/renalware/patients/patients/_form.html.slim +36 -17
- data/app/views/renalware/patients/patients/edit.html.slim +1 -1
- data/app/views/renalware/patients/patients/new.html.slim +1 -1
- data/app/views/renalware/patients/side_menu/_actions.html.slim +2 -0
- data/app/views/renalware/pd/_apd_regimes.html.slim +1 -1
- data/app/views/renalware/pd/_capd_regimes.html.slim +1 -1
- data/app/views/renalware/pd/dashboards/show/_apd_regimes.html.slim +11 -2
- data/app/views/renalware/pd/dashboards/show/_capd_regimes.html.slim +11 -2
- data/app/views/renalware/pd/regimes/index.html.slim +7 -0
- data/app/views/renalware/renal/profiles/_form.html.slim +7 -24
- data/app/views/renalware/shared/documents/_binary_marker_input.html.slim +2 -2
- data/app/views/renalware/shared/documents/_blood_group_input.html.slim +4 -2
- data/app/views/renalware/transplants/registrations/_form.html.slim +22 -17
- data/config/locales/renalware/clinical/body_composition.yml +6 -3
- data/config/locales/renalware/clinical/dry_weight.en.yml +4 -3
- data/config/locales/renalware/hd/diary_slots.en.yml +3 -2
- data/config/locales/renalware/letters/contact.en.yml +0 -2
- data/config/routes/feeds.rb +5 -0
- data/config/routes/hd.rb +11 -7
- data/config/routes/letters.rb +0 -5
- data/config/routes/patients.rb +1 -0
- data/config/routes/pd.rb +2 -2
- data/config/routes/renal.rb +0 -5
- data/config/routes.rb +1 -0
- data/config/webpack/development.js +5 -0
- data/config/webpack/environment.js +3 -0
- data/config/webpack/production.js +5 -0
- data/config/webpack/test.js +5 -0
- data/config/webpacker.yml +103 -0
- data/db/functions/hd_diary_archive_elapsed_master_slots_v01.sql +40 -0
- data/db/migrate/20190322120025_create_feed_hl7_test_messages.rb +12 -0
- data/db/migrate/20190325134823_create_patients_master_index.rb +24 -0
- data/db/migrate/20190327100851_add_handled_to_feed_messages.rb +5 -0
- data/db/migrate/20191012121433_add_consultant_to_users.rb +7 -0
- data/db/migrate/20191018143635_create_hd_diary_matrix_view.rb +7 -0
- data/db/migrate/20191018144917_create_fn_to_archive_master_slots.rb +9 -0
- data/db/views/hd_diary_matrix_v01.sql +38 -0
- data/lib/core_extensions/active_record/sort.rb +27 -9
- data/lib/renalware/configuration.rb +3 -0
- data/lib/renalware/engine.rb +31 -0
- data/lib/renalware/version.rb +1 -1
- data/lib/renalware/week_period.rb +8 -7
- data/lib/renalware.rb +13 -1
- data/lib/tasks/hd.rake +7 -0
- data/lib/tasks/pathology.rake +1 -1
- data/lib/tasks/renalware.rake +89 -4
- data/spec/factories/hd/scheduling/diaries.rb +18 -0
- data/spec/factories/hd/{slots.rb → scheduling/slots.rb} +1 -1
- data/spec/factories/patients/abridgements.rb +9 -0
- data/spec/support/hl7_helpers.rb +13 -0
- data/spec/support/pages/letters/form.rb +4 -1
- metadata +126 -50
- data/app/assets/javascripts/renalware/auto_complete.js +0 -63
- data/app/controllers/renalware/hd/diaries_controller.rb +0 -89
- data/app/controllers/renalware/hd/diary_slots_controller.rb +0 -175
- data/app/controllers/renalware/letters/descriptions_controller.rb +0 -22
- data/app/controllers/renalware/renal/prd_descriptions_controller.rb +0 -15
- data/app/models/renalware/hd/archive_yesterdays_slots_job.rb +0 -69
- data/app/models/renalware/hd/diary.rb +0 -41
- data/app/models/renalware/hd/diary_slot.rb +0 -83
- data/app/models/renalware/hd/find_or_create_diary_by_week_query.rb +0 -50
- data/app/models/renalware/hd/find_or_create_master_diary.rb +0 -26
- data/app/models/renalware/hd/master_diary.rb +0 -32
- data/app/models/renalware/hd/weekly_diary.rb +0 -45
- data/app/models/renalware/renal/prd_descriptions/search_query.rb +0 -35
- data/app/presenters/renalware/hd/diary_presenter.rb +0 -79
- data/app/presenters/renalware/hd/diary_slot_presenter.rb +0 -72
- data/app/presenters/renalware/hd/null_slot.rb +0 -40
- data/app/views/renalware/renal/prd_descriptions/search.json.jbuilder +0 -6
- data/lib/test_support/autocomplete_helpers.rb +0 -14
- data/spec/factories/hd/diaries.rb +0 -14
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/patients"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module Patients
|
|
7
|
+
module Ingestion
|
|
8
|
+
# Responsible for making commands to process messages based on the
|
|
9
|
+
# message type.
|
|
10
|
+
#
|
|
11
|
+
class CommandFactory
|
|
12
|
+
def for(message)
|
|
13
|
+
case message.action
|
|
14
|
+
when :add_person_information then make_add_patient(message)
|
|
15
|
+
when :update_person_information then make_update_patient(message)
|
|
16
|
+
# when :admit_patient then make_admit_patient(message)
|
|
17
|
+
# when :merge_patient then make_merge_patient(message)
|
|
18
|
+
# when :update_admission then make_update_admission(message)
|
|
19
|
+
# when :cancel_admission then make_cancel_admission(message)
|
|
20
|
+
# when :transfer_patient then make_transfer_patient(message)
|
|
21
|
+
# when :discharge_patient then make_discharge_patient(message)
|
|
22
|
+
# when :cancel_discharge then make_cancel_discharge(message)
|
|
23
|
+
# when :add_consultant then make_add_consultant(message)
|
|
24
|
+
else :no_matching_command
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# def make_add_patient_with_finder(message)
|
|
31
|
+
# CommandWithFinder.new(
|
|
32
|
+
# make_add_patient(message),
|
|
33
|
+
# message, finder: Finder::Patient.new
|
|
34
|
+
# )
|
|
35
|
+
# end
|
|
36
|
+
|
|
37
|
+
# def make_add_patient_with_finder(message)
|
|
38
|
+
# CommandWithFinder.new(
|
|
39
|
+
# make_add_patient(message),
|
|
40
|
+
# message, finder: Finder::Patient.new
|
|
41
|
+
# )
|
|
42
|
+
# end
|
|
43
|
+
|
|
44
|
+
def make_add_patient(message)
|
|
45
|
+
Commands::AddOrUpdatePatient.new(message)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def make_update_patient(message)
|
|
49
|
+
Commands::AddOrUpdatePatient.new(message)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# def make_merge_patient(message)
|
|
53
|
+
# Commands::MergePatient.new(message,
|
|
54
|
+
# major_patient_finder: make_patient_finder_with_add_if_missing,
|
|
55
|
+
# minor_patient_finder: make_minor_patient_finder_with_add_if_missing)
|
|
56
|
+
# end
|
|
57
|
+
|
|
58
|
+
# def make_admit_patient(message)
|
|
59
|
+
# Commands::AdmitPatient.new(message,
|
|
60
|
+
# patient_finder: make_patient_finder_with_add_if_missing)
|
|
61
|
+
# end
|
|
62
|
+
|
|
63
|
+
# def make_update_admission(message)
|
|
64
|
+
# Commands::UpdateAdmission.new(message,
|
|
65
|
+
# admission_finder: make_admission_finder_with_logging_if_missing)
|
|
66
|
+
# end
|
|
67
|
+
|
|
68
|
+
# def make_cancel_admission(message)
|
|
69
|
+
# Commands::CancelAdmission.new(message,
|
|
70
|
+
# admission_finder: make_admission_finder_with_logging_if_missing)
|
|
71
|
+
# end
|
|
72
|
+
|
|
73
|
+
# def make_transfer_patient(message)
|
|
74
|
+
# Commands::TransferPatient.new(message,
|
|
75
|
+
# admission_finder: make_admission_finder_with_admit_if_missing)
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
# def make_discharge_patient(message)
|
|
79
|
+
# Commands::DischargePatient.new(message,
|
|
80
|
+
# admission_finder: make_admission_finder_with_logging_if_missing)
|
|
81
|
+
# end
|
|
82
|
+
|
|
83
|
+
# def make_cancel_discharge(message)
|
|
84
|
+
# Commands::CancelDischarge.new(message)
|
|
85
|
+
# end
|
|
86
|
+
|
|
87
|
+
# def make_add_consultant(message)
|
|
88
|
+
# Commands::AddConsultant.new(message)
|
|
89
|
+
# end
|
|
90
|
+
|
|
91
|
+
# def make_admission_finder_with_logging_if_missing
|
|
92
|
+
# MissingAdmissionLogger.new(make_admission_finder)
|
|
93
|
+
# end
|
|
94
|
+
|
|
95
|
+
# def make_admission_finder_with_admit_if_missing
|
|
96
|
+
# MissingRecordHandler.new(make_admission_finder,
|
|
97
|
+
# policy: make_missing_admission_handler)
|
|
98
|
+
# end
|
|
99
|
+
|
|
100
|
+
# def make_admission_finder
|
|
101
|
+
# Finder::Admission.new
|
|
102
|
+
# end
|
|
103
|
+
|
|
104
|
+
# def make_patient_finder_with_add_if_missing
|
|
105
|
+
# MissingRecordHandler.new(Finder::Patient.new,
|
|
106
|
+
# policy: make_missing_patient_handler)
|
|
107
|
+
# end
|
|
108
|
+
|
|
109
|
+
# def make_minor_patient_finder_with_add_if_missing
|
|
110
|
+
# missing_patient_handler = lambda { |message|
|
|
111
|
+
# Commands::AddPatient.new(
|
|
112
|
+
# message,
|
|
113
|
+
# mapper_factory: MessageMappers::MinorPatient
|
|
114
|
+
# ).call
|
|
115
|
+
# }
|
|
116
|
+
|
|
117
|
+
# MissingRecordHandler.new(Finder::MinorPatient.new,
|
|
118
|
+
# policy: missing_patient_handler)
|
|
119
|
+
# end
|
|
120
|
+
|
|
121
|
+
# def make_missing_patient_handler
|
|
122
|
+
# lambda { |message|
|
|
123
|
+
# make_add_patient(message).call
|
|
124
|
+
# }
|
|
125
|
+
# end
|
|
126
|
+
|
|
127
|
+
# def make_missing_admission_handler
|
|
128
|
+
# lambda { |message|
|
|
129
|
+
# make_admit_patient(message).call
|
|
130
|
+
# }
|
|
131
|
+
# end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/patients/ingestion/command"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module Patients
|
|
7
|
+
module Ingestion
|
|
8
|
+
module Commands
|
|
9
|
+
# We could be here as a results of 2 scenarios:
|
|
10
|
+
# - ADT28 add patient
|
|
11
|
+
# - ADT31 update patient
|
|
12
|
+
#
|
|
13
|
+
# In both circumstances our action is the same:
|
|
14
|
+
# 1. If the patient exists as a Renalware::Patient, update their details
|
|
15
|
+
# 2. Find or create a Patients::Abridgement for this patient
|
|
16
|
+
# 3. Update their abridgement info, including their Renalware::Patient id if one exists
|
|
17
|
+
#
|
|
18
|
+
# So basically we are maintaining patient data in 2 places:
|
|
19
|
+
# a) in Renalware::Patient and its associated address and demographics tables
|
|
20
|
+
# b) in Renalware::Patients::Abrigement, which is an abbreviated version of the patient's
|
|
21
|
+
# details (name, numbers, DOB ect), enabling us to find and import a new patient by
|
|
22
|
+
# taking the abridgement, finding all previously received ADT and ORU etc feed_messages
|
|
23
|
+
# for the patient and replaying those messages to build the patient with their
|
|
24
|
+
# and pathology. If a patient is already a Renalware::Patient then in theory we do
|
|
25
|
+
# not need to maintain an abridgement for them, but for consistentency we do; it has
|
|
26
|
+
# advantages when trying to add a new patient in the Renalware UI - e.g. it can show you
|
|
27
|
+
# that that patient is already added because there is a patient_id on the abridgement.
|
|
28
|
+
class AddOrUpdatePatient < Command
|
|
29
|
+
def initialize(message, mapper_factory: MessageMappers::Patient)
|
|
30
|
+
@mapper_factory = mapper_factory
|
|
31
|
+
|
|
32
|
+
super(message)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :mapper_factory
|
|
36
|
+
|
|
37
|
+
def call
|
|
38
|
+
# For now skip updating the patient, just update the index ie create/update a
|
|
39
|
+
# patient abridgement
|
|
40
|
+
# update_patient_if_exists
|
|
41
|
+
UpdateMasterPatientIndex.new(message).call
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def update_patient_if_exists
|
|
47
|
+
patient = find_patient
|
|
48
|
+
return if patient.blank?
|
|
49
|
+
|
|
50
|
+
patient = mapper_factory.new(message, patient).fetch
|
|
51
|
+
patient.by = SystemUser.find
|
|
52
|
+
patient.save!
|
|
53
|
+
patient
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find_patient
|
|
57
|
+
Patient.find_by(
|
|
58
|
+
local_patient_id: message.patient_identification.internal_id
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/patients"
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# When subscribed to HL7 `message_arrived` messages, gets notified of incoming HL7 messages
|
|
7
|
+
#
|
|
8
|
+
module Renalware
|
|
9
|
+
module Patients
|
|
10
|
+
module Ingestion
|
|
11
|
+
class MessageListener
|
|
12
|
+
def adt_message_arrived(hl7_message:, **)
|
|
13
|
+
return unless hl7_message.adt?
|
|
14
|
+
|
|
15
|
+
command = Command.for(hl7_message)
|
|
16
|
+
command.call
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Renalware
|
|
4
|
+
module Patients
|
|
5
|
+
module Ingestion
|
|
6
|
+
# Responsible for mapping attributes from a message to attributes
|
|
7
|
+
# to domain models.
|
|
8
|
+
#
|
|
9
|
+
class MessageMapper
|
|
10
|
+
def initialize(message)
|
|
11
|
+
@message = message
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attr_reader :message
|
|
15
|
+
|
|
16
|
+
def fetch
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# def source
|
|
21
|
+
# Message.for(message)
|
|
22
|
+
# end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/patients"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module Patients
|
|
7
|
+
module Ingestion
|
|
8
|
+
module MessageMappers
|
|
9
|
+
# Given an HL7 message that instructs us to update a patient (eg ADT^A31) or add a new one
|
|
10
|
+
# (ADT^A28) we parse the patient level information from the HL7 message and update or create
|
|
11
|
+
# the patient.
|
|
12
|
+
class Patient < MessageMapper
|
|
13
|
+
delegate :patient_identification, to: :message
|
|
14
|
+
delegate :address, to: :patient_identification
|
|
15
|
+
|
|
16
|
+
def initialize(message, patient = nil)
|
|
17
|
+
@patient = patient || ::Renalware::Patient.new
|
|
18
|
+
|
|
19
|
+
super(message)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_reader :patient
|
|
23
|
+
|
|
24
|
+
def fetch
|
|
25
|
+
map_attributes
|
|
26
|
+
patient
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
32
|
+
def map_attributes
|
|
33
|
+
patient.attributes = {
|
|
34
|
+
local_patient_id: patient_identification.internal_id,
|
|
35
|
+
nhs_number: patient_identification.external_id,
|
|
36
|
+
given_name: patient_identification.given_name,
|
|
37
|
+
family_name: patient_identification.family_name,
|
|
38
|
+
suffix: patient_identification.suffix,
|
|
39
|
+
title: patient_identification.title,
|
|
40
|
+
born_on: Time.zone.parse(patient_identification.dob)&.to_date,
|
|
41
|
+
died_on: Time.zone.parse(patient_identification.death_date)&.to_date,
|
|
42
|
+
sex: patient_identification.sex,
|
|
43
|
+
practice: find_practice(message.practice_code) || patient.practice,
|
|
44
|
+
primary_care_physician: find_primary_care_physician(message.gp_code)
|
|
45
|
+
}
|
|
46
|
+
patient.build_current_address if patient.current_address.blank?
|
|
47
|
+
patient.current_address.attributes = {
|
|
48
|
+
street_1: address[0],
|
|
49
|
+
street_2: address[1],
|
|
50
|
+
street_3: nil,
|
|
51
|
+
town: address[2],
|
|
52
|
+
county: address[3],
|
|
53
|
+
postcode: address.last
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
57
|
+
|
|
58
|
+
# If for some reason we cannot find the new practice (perhaps we have not imported it yet)
|
|
59
|
+
# then be sure to leave the patient's current practice unchanged.
|
|
60
|
+
def find_practice(code)
|
|
61
|
+
Patients::Practice.find_by(code: code) || patient.practice
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# If for some reason we cannot find the new gp (perhaps we have not imported them yet)
|
|
65
|
+
# then be sure to leave the patient's current gp unchanged.
|
|
66
|
+
def find_primary_care_physician(code)
|
|
67
|
+
Patients::PrimaryCarePhysician.find_by(code: code) || patient.primary_care_physician
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "renalware/feeds"
|
|
4
|
+
require "attr_extras"
|
|
5
|
+
|
|
6
|
+
module Renalware
|
|
7
|
+
module Patients
|
|
8
|
+
module Ingestion
|
|
9
|
+
class UpdateMasterPatientIndex
|
|
10
|
+
pattr_initialize :hl7_message
|
|
11
|
+
attr_reader :rw_patient
|
|
12
|
+
delegate :patient_identification, to: :hl7_message
|
|
13
|
+
|
|
14
|
+
def self.call(hl7_message)
|
|
15
|
+
new(hl7_message).call
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
return unless hl7_message.adt?
|
|
20
|
+
|
|
21
|
+
@rw_patient = find_patient_in_renalware
|
|
22
|
+
update_or_create_abridged_patient
|
|
23
|
+
# update_primary_care_physician
|
|
24
|
+
# update_practice
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def find_patient_in_renalware
|
|
30
|
+
::Renalware::Patient.find_by(
|
|
31
|
+
local_patient_id: patient_identification.internal_id
|
|
32
|
+
) || NullObject.instance
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# rubocop:disable Metrics/AbcSize
|
|
36
|
+
def update_or_create_abridged_patient
|
|
37
|
+
find_or_initialize_abridged_patient.update!(
|
|
38
|
+
given_name: patient_identification.given_name,
|
|
39
|
+
family_name: patient_identification.family_name,
|
|
40
|
+
sex: patient_identification.sex,
|
|
41
|
+
title: patient_identification.title,
|
|
42
|
+
suffix: patient_identification.suffix,
|
|
43
|
+
born_on: patient_identification.born_on,
|
|
44
|
+
died_at: patient_identification.died_at,
|
|
45
|
+
patient_id: rw_patient.id,
|
|
46
|
+
practice_code: hl7_message.practice_code,
|
|
47
|
+
gp_code: hl7_message.gp_code
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
# rubocop:enable Metrics/AbcSize
|
|
51
|
+
|
|
52
|
+
def find_or_initialize_abridged_patient
|
|
53
|
+
Patients::Abridgement.find_or_initialize_by(
|
|
54
|
+
hospital_number: patient_identification.internal_id
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# # frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# require "renalware/feeds"
|
|
4
|
+
# require "attr_extras"
|
|
5
|
+
|
|
6
|
+
# module Renalware
|
|
7
|
+
# module Patients
|
|
8
|
+
# module Ingestion
|
|
9
|
+
# class UpdateMasterPatientIndex < ApplicationJob
|
|
10
|
+
# queue_as :master_patient_index
|
|
11
|
+
# queue_with_priority 10
|
|
12
|
+
|
|
13
|
+
# def perform(feed_message:)
|
|
14
|
+
# raise "todo"
|
|
15
|
+
# # UpdateMasterPatientIndex.call()
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
@@ -13,9 +13,10 @@ module Renalware
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def configure
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
SubscriptionRegistry.instance.register(
|
|
17
|
+
Feeds::MessageProcessor,
|
|
18
|
+
Ingestion::MessageListener
|
|
19
|
+
)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def self.cast_user(user)
|
|
@@ -12,11 +12,15 @@ module Renalware
|
|
|
12
12
|
has_paper_trail class_name: "Renalware::Problems::Version", on: [:create, :update, :destroy]
|
|
13
13
|
|
|
14
14
|
belongs_to :patient, touch: true
|
|
15
|
-
has_many :notes, dependent: :destroy
|
|
15
|
+
has_many :notes, -> { ordered }, dependent: :destroy
|
|
16
16
|
|
|
17
17
|
scope :ordered, -> { order(position: :asc) }
|
|
18
|
-
scope :with_notes, -> {
|
|
18
|
+
scope :with_notes, -> { eager_load(:notes).merge(Renalware::Problems::Note.ordered) }
|
|
19
19
|
scope :with_patient, -> { includes(:patient) }
|
|
20
|
+
scope :with_versions, -> { includes(versions: :item) }
|
|
21
|
+
|
|
22
|
+
# This scope is called by CoreExtensions::ActiveRecord::Sort
|
|
23
|
+
scope :position_sorting_scope, ->(problem) { where(patient_id: problem.patient.id) }
|
|
20
24
|
|
|
21
25
|
validates :patient, presence: true
|
|
22
26
|
validates :description, presence: true
|
|
@@ -6,17 +6,16 @@ module Renalware
|
|
|
6
6
|
module UKRDC
|
|
7
7
|
module Incoming
|
|
8
8
|
class Paths
|
|
9
|
-
def initialize
|
|
10
|
-
FileUtils.mkdir_p incoming
|
|
11
|
-
FileUtils.mkdir_p archive
|
|
12
|
-
end
|
|
13
|
-
|
|
14
9
|
def incoming
|
|
15
|
-
@incoming ||=
|
|
10
|
+
@incoming ||= begin
|
|
11
|
+
working_path.join("incoming").tap { |path| FileUtils.mkdir_p(path) }
|
|
12
|
+
end
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def archive
|
|
19
|
-
@archive ||=
|
|
16
|
+
@archive ||= begin
|
|
17
|
+
working_path.join("archive", "incoming").tap { |path| FileUtils.mkdir_p(path) }
|
|
18
|
+
end
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
private
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/admin"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module Admin
|
|
7
|
+
class DevopsPolicy < BasePolicy
|
|
8
|
+
def show?
|
|
9
|
+
user_is_devops?
|
|
10
|
+
end
|
|
11
|
+
alias index? show?
|
|
12
|
+
alias edit? show?
|
|
13
|
+
alias update? show?
|
|
14
|
+
alias destroy? show?
|
|
15
|
+
alias new? show?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -39,7 +39,7 @@ module Renalware
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def dry_weights
|
|
42
|
-
@dry_weights ||= DryWeight.for_patient(patient).ordered
|
|
42
|
+
@dry_weights ||= DryWeight.for_patient(patient).ordered.limit(5)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def body_compositions
|
|
@@ -48,6 +48,7 @@ module Renalware
|
|
|
48
48
|
.for_patient(patient)
|
|
49
49
|
.includes([:modality_description, :assessor])
|
|
50
50
|
.ordered
|
|
51
|
+
.limit(5)
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "collection_presenter"
|
|
4
|
+
|
|
5
|
+
# TODO: mixing query and presenter here..
|
|
6
|
+
module Renalware
|
|
7
|
+
module HD
|
|
8
|
+
module Scheduling
|
|
9
|
+
class DiaryPresenter
|
|
10
|
+
attr_reader :user, :weekly_diary, :master_diary, :null_diary
|
|
11
|
+
delegate :id, :hospital_unit_id, :to_s, :week, :created_at, to: :weekly_diary
|
|
12
|
+
|
|
13
|
+
# https://github.com/avdi/naught
|
|
14
|
+
NullDiary = Naught.build do |config|
|
|
15
|
+
config.black_hole
|
|
16
|
+
config.define_explicit_conversions
|
|
17
|
+
config.predicates_return false
|
|
18
|
+
|
|
19
|
+
def master?
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def slot_for(diary_id, diurnal_period_code_id, station_id, day_of_week)
|
|
24
|
+
NullSlot.new(diary_id, diurnal_period_code_id, station_id, day_of_week)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(user, weekly_diary)
|
|
29
|
+
@user = user
|
|
30
|
+
@weekly_diary = weekly_diary
|
|
31
|
+
@master_diary = weekly_diary.master_diary
|
|
32
|
+
@null_diary = NullDiary.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def each_diurnal_period
|
|
36
|
+
DiurnalPeriodCode.all.each do |diurnal_period_code|
|
|
37
|
+
yield(diurnal_period_code) if block_given?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def each_station
|
|
42
|
+
stations.each_with_index { |station, index| yield(station, index + 1) if block_given? }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# rubocop:disable Metrics/LineLength, Metrics/AbcSize
|
|
46
|
+
def each_day(diurnal_period, station)
|
|
47
|
+
(1..last_day_of_week).each do |day_of_week|
|
|
48
|
+
diurnal_period_id = diurnal_period.id
|
|
49
|
+
station_id = station.id
|
|
50
|
+
valid_from = weekly_diary.week.date_on_first_day_of_week
|
|
51
|
+
slot = weekly_diary.slot_for(diurnal_period_id, station_id, day_of_week) ||
|
|
52
|
+
master_diary.slot_for(diurnal_period_id, station_id, day_of_week, valid_from: valid_from) ||
|
|
53
|
+
null_diary.slot_for(weekly_diary.id, diurnal_period_id, station_id, day_of_week)
|
|
54
|
+
yield(slot) if block_given?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
# rubocop:enable Metrics/LineLength, Metrics/AbcSize
|
|
58
|
+
|
|
59
|
+
def day_names
|
|
60
|
+
all_day_names = Time::DAYS_INTO_WEEK.keys
|
|
61
|
+
all_day_names.take(last_day_of_week)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def stations
|
|
65
|
+
@stations ||= begin
|
|
66
|
+
Station.includes(:location).for_unit(hospital_unit_id).ordered.map do |station|
|
|
67
|
+
StationPresenter.new(station)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def station_locations
|
|
73
|
+
StationLocation.all
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def last_day_of_week
|
|
79
|
+
Renalware.config.include_sunday_on_hd_diaries ? 7 : 6
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/hd"
|
|
4
|
+
require_dependency "collection_presenter"
|
|
5
|
+
|
|
6
|
+
# TODO: mixing query and presenter here..
|
|
7
|
+
module Renalware
|
|
8
|
+
module HD
|
|
9
|
+
module Scheduling
|
|
10
|
+
class DiarySlotPresenter < SimpleDelegator
|
|
11
|
+
delegate :master?, to: :diary, allow_nil: true
|
|
12
|
+
|
|
13
|
+
# Patients who prefer to dialyse on this day e.g. Mon and in this period e.g. AM.
|
|
14
|
+
# Flag those already assigned so they cannot be chosen.
|
|
15
|
+
def patients_preferring_to_dialyse_today_in_this_period
|
|
16
|
+
patients = Renalware::HD::PatientsDialysingByDayAndPeriodQuery
|
|
17
|
+
.new(
|
|
18
|
+
diary.hospital_unit_id,
|
|
19
|
+
day_of_week,
|
|
20
|
+
diurnal_period_code.code
|
|
21
|
+
).call.all
|
|
22
|
+
simplify(patients)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Patients who prefer to dialyse on this day e.g. Mon
|
|
26
|
+
# Flag those already assigned so they cannot be chosen.
|
|
27
|
+
def patients_preferring_to_dialyse_today
|
|
28
|
+
patients = Renalware::HD::PatientsDialysingByDayQuery
|
|
29
|
+
.new(
|
|
30
|
+
diary.hospital_unit_id,
|
|
31
|
+
day_of_week
|
|
32
|
+
).call.all
|
|
33
|
+
simplify(patients)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# rubocop:disable Metrics/MethodLength
|
|
37
|
+
def patient_search_options
|
|
38
|
+
hospital_unit = Renalware::Hospitals::Unit.find(diary.hospital_unit_id)
|
|
39
|
+
[
|
|
40
|
+
OpenStruct.new(
|
|
41
|
+
id: :dialysing_on_day_and_period,
|
|
42
|
+
name: "Dialysing #{day_of_week_name} #{diurnal_period_code.to_s.upcase}"
|
|
43
|
+
),
|
|
44
|
+
OpenStruct.new(
|
|
45
|
+
id: :dialysing_on_day,
|
|
46
|
+
name: "Dialysing on #{day_of_week_name}"
|
|
47
|
+
),
|
|
48
|
+
OpenStruct.new(
|
|
49
|
+
id: :dialysing_at_unit,
|
|
50
|
+
name: "All #{hospital_unit.unit_code} HD patients"
|
|
51
|
+
),
|
|
52
|
+
OpenStruct.new(
|
|
53
|
+
id: :dialysing_at_hospital,
|
|
54
|
+
name: "All HD patients"
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
end
|
|
58
|
+
# rubocop:enable Metrics/MethodLength
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def simplify(patients)
|
|
63
|
+
patients.map do |patient|
|
|
64
|
+
hd_profile = patient.hd_profile
|
|
65
|
+
text = "#{patient.to_s(:long)} - "\
|
|
66
|
+
"#{hd_profile&.schedule_definition} "\
|
|
67
|
+
"#{hd_profile&.hospital_unit&.unit_code}".strip.truncate(65)
|
|
68
|
+
OpenStruct.new(id: patient.id, text: text)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|