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
|
@@ -10,8 +10,12 @@ module Renalware
|
|
|
10
10
|
|
|
11
11
|
def index
|
|
12
12
|
observation_requests = find_observation_requests
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
render locals: {
|
|
14
|
+
observation_requests: observation_requests.result .page(page).per(per_page),
|
|
15
|
+
search: observation_requests,
|
|
16
|
+
obr_filter_options: obr_filter_options,
|
|
17
|
+
patient: @patient
|
|
18
|
+
}
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
def show
|
|
@@ -22,16 +26,31 @@ module Renalware
|
|
|
22
26
|
|
|
23
27
|
private
|
|
24
28
|
|
|
29
|
+
# Select just the OBR description ids and codes that have been associated with this patient.
|
|
30
|
+
# We'll uses them to build a filter dropdown list.
|
|
31
|
+
def obr_filter_options
|
|
32
|
+
@patient.observation_requests
|
|
33
|
+
.joins(:description)
|
|
34
|
+
.order("pathology_request_descriptions.code asc")
|
|
35
|
+
.pluck(
|
|
36
|
+
Arel.sql(
|
|
37
|
+
"distinct on(pathology_request_descriptions.code) pathology_request_descriptions.code"
|
|
38
|
+
),
|
|
39
|
+
"pathology_request_descriptions.id",
|
|
40
|
+
"pathology_request_descriptions.name"
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
25
44
|
def find_observation_requests
|
|
26
45
|
@patient.observation_requests
|
|
27
|
-
.page(page)
|
|
28
46
|
.includes(:description)
|
|
29
47
|
.ordered
|
|
48
|
+
.ransack(params[:q])
|
|
30
49
|
end
|
|
31
50
|
|
|
32
51
|
def find_observation_request
|
|
33
52
|
@patient.observation_requests
|
|
34
|
-
.includes(
|
|
53
|
+
.includes(observations: :description)
|
|
35
54
|
.find(params[:id])
|
|
36
55
|
end
|
|
37
56
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_dependency "renalware/patients"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module Patients
|
|
7
|
+
class AbridgementsController < BaseController
|
|
8
|
+
def index
|
|
9
|
+
authorize Abridgement, :index?
|
|
10
|
+
render locals: {
|
|
11
|
+
form: AbridgementSearchForm.new,
|
|
12
|
+
results: abridgements_matching_search_criteria,
|
|
13
|
+
results_matching_dob: abridgements_matching_dobs
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def abridgements_matching_search_criteria
|
|
20
|
+
return [] if search_params.blank?
|
|
21
|
+
|
|
22
|
+
Abridgement.where(hospital_number: search_params)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def abridgements_matching_dobs
|
|
26
|
+
return [] if abridgements_matching_search_criteria.empty?
|
|
27
|
+
|
|
28
|
+
dobs = abridgements_matching_search_criteria.map(&:born_on).uniq.compact
|
|
29
|
+
return [] if dobs.empty?
|
|
30
|
+
|
|
31
|
+
Abridgement.where(born_on: dobs) - abridgements_matching_search_criteria
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def search_params
|
|
35
|
+
params.dig(:search, :criteria)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -5,8 +5,26 @@ require_dependency "renalware/hd/base_controller"
|
|
|
5
5
|
module Renalware
|
|
6
6
|
module PD
|
|
7
7
|
class RegimesController < BaseController
|
|
8
|
+
include Renalware::Concerns::Pageable
|
|
8
9
|
before_action :load_patient
|
|
9
10
|
|
|
11
|
+
def index
|
|
12
|
+
regimes = regime_type_class.for_patient(patient).with_bags.ordered.page(page).per(per_page)
|
|
13
|
+
render locals: {
|
|
14
|
+
patient: patient,
|
|
15
|
+
regimes: regimes,
|
|
16
|
+
pd_type_string: pd_type_string
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def capd_regimes
|
|
21
|
+
@capd_regimes ||= CAPDRegime.for_patient(patient).with_bags.ordered.page(1).per(5)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def apd_regimes
|
|
25
|
+
@apd_regimes ||= APDRegime.for_patient(patient).with_bags.ordered.page(1).per(5)
|
|
26
|
+
end
|
|
27
|
+
|
|
10
28
|
def new
|
|
11
29
|
regime = cloned_last_known_regime_of_type || patient.pd_regimes.new(type: regime_type)
|
|
12
30
|
|
|
@@ -70,6 +88,14 @@ module Renalware
|
|
|
70
88
|
params[:type] ? "Renalware::#{params[:type]}" : nil
|
|
71
89
|
end
|
|
72
90
|
|
|
91
|
+
def regime_type_class
|
|
92
|
+
@regime_type_class ||= regime_type.constantize
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def pd_type_string
|
|
96
|
+
regime_type_class.new.pd_type.upcase # CAPD or APD
|
|
97
|
+
end
|
|
98
|
+
|
|
73
99
|
def cloned_last_known_regime_of_type
|
|
74
100
|
regime = patient.pd_regimes
|
|
75
101
|
.order(start_date: :desc, created_at: :desc)
|
|
@@ -4,7 +4,7 @@ module Renalware
|
|
|
4
4
|
module Problems
|
|
5
5
|
class ProblemsController < BaseController
|
|
6
6
|
def index
|
|
7
|
-
problems = patient.problems
|
|
7
|
+
problems = patient.problems.with_notes
|
|
8
8
|
authorize problems
|
|
9
9
|
render locals: {
|
|
10
10
|
patient: patient,
|
|
@@ -14,7 +14,7 @@ module Renalware
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def show
|
|
17
|
-
problem = patient.problems.with_archived.
|
|
17
|
+
problem = patient.problems.with_archived.with_versions.find(params[:id])
|
|
18
18
|
notes = problem.notes.with_updated_by.ordered
|
|
19
19
|
authorize problem
|
|
20
20
|
render locals: {
|
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
require "inline_image"
|
|
4
4
|
require "git_commit_sha"
|
|
5
5
|
require "breadcrumb"
|
|
6
|
+
require "webpacker/helper"
|
|
6
7
|
|
|
7
8
|
module Renalware
|
|
8
9
|
module ApplicationHelper
|
|
9
10
|
include Renalware::Engine.routes.url_helpers
|
|
11
|
+
include ::Webpacker::Helper
|
|
12
|
+
|
|
13
|
+
# See https://github.com/rails/webpacker/blob/master/docs/engines.md
|
|
14
|
+
def current_webpacker_instance
|
|
15
|
+
Renalware.webpacker
|
|
16
|
+
end
|
|
10
17
|
|
|
11
18
|
def default_patient_link(patient)
|
|
12
19
|
link_to(patient.to_s(:default), patient_clinical_summary_path(patient))
|
|
@@ -37,9 +44,11 @@ module Renalware
|
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
# For use in pages
|
|
47
|
+
# rubocop:disable Rails/OutputSafety
|
|
40
48
|
def page_heading(title)
|
|
41
49
|
content_for(:page_title) { title.html_safe }
|
|
42
50
|
end
|
|
51
|
+
# rubocop:enable Rails/OutputSafety
|
|
43
52
|
|
|
44
53
|
def t?(key)
|
|
45
54
|
t(key, cascade: false, raise: false, default: "").present?
|
|
@@ -21,5 +21,23 @@ module Renalware
|
|
|
21
21
|
output.concat(capture(&block)) if block_given?
|
|
22
22
|
output.safe_concat("</article>")
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
# Renders
|
|
26
|
+
# <span>5 of 16<div>
|
|
27
|
+
# if the collection has been paginated, otherwise
|
|
28
|
+
# <span>5<div>
|
|
29
|
+
def collection_count(collection)
|
|
30
|
+
return unless collection&.respond_to?(:length)
|
|
31
|
+
|
|
32
|
+
parts = ["("]
|
|
33
|
+
parts.append(collection.length)
|
|
34
|
+
if collection.respond_to?(:total_count)
|
|
35
|
+
if collection.total_count > collection.length
|
|
36
|
+
parts.append(" of #{collection.total_count}")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
parts.append(")")
|
|
40
|
+
content_tag("span", parts.join(""))
|
|
41
|
+
end
|
|
24
42
|
end
|
|
25
43
|
end
|
|
@@ -6,13 +6,14 @@ module Renalware
|
|
|
6
6
|
" field_with_errors" if model.errors.key?(attr)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def render_input(builder, attribute)
|
|
9
|
+
def render_input(builder, attribute, html_options: {})
|
|
10
10
|
renderable = builder.object.public_send(attribute)
|
|
11
11
|
return unless renderable
|
|
12
12
|
|
|
13
13
|
render input_partial_path_for(renderable),
|
|
14
14
|
attribute: attribute,
|
|
15
|
-
f: builder
|
|
15
|
+
f: builder,
|
|
16
|
+
html_options: html_options
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def input_partial_path_for(renderable)
|
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Renalware
|
|
4
4
|
module UsersHelper
|
|
5
|
+
def current_user_is_developer?
|
|
6
|
+
current_user.has_role?(:devops)
|
|
7
|
+
end
|
|
8
|
+
|
|
5
9
|
def current_user_is_super_admin?
|
|
6
|
-
current_user.has_role?(:super_admin) ||
|
|
10
|
+
current_user.has_role?(:super_admin) || current_user_is_developer?
|
|
7
11
|
end
|
|
8
12
|
|
|
9
13
|
def current_user_is_admin?
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Controller } from "stimulus"
|
|
2
|
+
|
|
3
|
+
// Experimental Stimulus clipboard controller. No IE11 support.
|
|
4
|
+
// Can be enhanced but initially this exists just so we can test stimulus/webpack integration
|
|
5
|
+
// when the engine is pulled into a host app
|
|
6
|
+
export default class extends Controller {
|
|
7
|
+
static targets = ["source", "result"]
|
|
8
|
+
|
|
9
|
+
copy(event) {
|
|
10
|
+
event.preventDefault()
|
|
11
|
+
this.sourceTarget.select()
|
|
12
|
+
document.execCommand("copy")
|
|
13
|
+
console.log("Copied")
|
|
14
|
+
this.resultTarget.innerHTML = "Copied"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// This file is automatically compiled by Webpack, along with any other files
|
|
2
|
+
// present in this directory. You're encouraged to place your actual application logic in
|
|
3
|
+
// a relevant structure within app/javascript and only use these pack files to reference
|
|
4
|
+
// that code so it'll be compiled.
|
|
5
|
+
// Uncomment to copy all static images under ../images to the output folder and reference
|
|
6
|
+
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
|
|
7
|
+
// or the `imagePath` JavaScript helper below.
|
|
8
|
+
//
|
|
9
|
+
// const images = require.context('../images', true)
|
|
10
|
+
// const imagePath = (name) => images(name, true)
|
|
11
|
+
|
|
12
|
+
// require("@rails/ujs").start()
|
|
13
|
+
// require("@rails/activestorage").start()
|
|
14
|
+
|
|
15
|
+
import { Application } from "stimulus"
|
|
16
|
+
import { definitionsFromContext } from "stimulus/webpack-helpers"
|
|
17
|
+
|
|
18
|
+
const application = Application.start()
|
|
19
|
+
const context = require.context("../controllers", true, /\.js$/)
|
|
20
|
+
application.load(definitionsFromContext(context))
|
data/app/jobs/feed_job.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/struct:FeedJob
|
|
2
2
|
raw_message: |
|
|
3
3
|
MSH|^~\&|HM|LBE|SCM||20091112164645||ORU^R01|1258271|P|2.3.1|||AL||||
|
|
4
|
-
PID|||
|
|
4
|
+
PID|||Z100002^^^PAS Number||RABBIT^JESSICA^^^MS||19880924|F|||18 RABBITHOLE ROAD^LONDON^^^SE8 8JR|||||||||||||||||||
|
|
5
5
|
PV1||Inpatient|NIBC^^^^^^^^|||||MID^KINGS MIDWIVES||||||||||NHS|HXF888888^^^Visit Number|||||||||
|
|
6
6
|
ORC|RE|^PCS|09B0099478^LA||CM||||200911111841|||MID^KINGS MIDWIVES|||||||
|
|
7
|
-
OBR|1
|
|
7
|
+
OBR|1|PlacerOrderNumber1^PCS|09B0099478^LA|FBC^FULL BLOOD COUNT^MB||200911111841|200911111841|||||||200911111841|B^Blood|MID^KINGS MIDWIVES||09B0099478||||200911121646||HM|F||||||||||||||||||
|
|
8
8
|
OBX|1|TX|WBC^WBC^MB||6.09||||||F|||200911112026||BBKA^Donald DUCK|
|
|
9
9
|
OBX|2|TX|RBC^RBC^MB||4.00||||||F|||200911112026||BBKA^Donald DUCK|
|
|
10
10
|
OBX|3|TX|HGB^Hb^MB||11.8||||||F|||200911112026||BBKA^Donald DUCK|
|
|
@@ -11,6 +11,8 @@ module Renalware
|
|
|
11
11
|
include Feeds::Job
|
|
12
12
|
FILE_TO_EXTRACT_FROM_ARCHIVE = /epracmem.csv/.freeze
|
|
13
13
|
|
|
14
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
15
|
+
# TODO: refactor
|
|
14
16
|
def perform(file)
|
|
15
17
|
logging_to_stringio(strio = StringIO.new)
|
|
16
18
|
log "Before upload there are #{practice_membership_count} practice memberships"
|
|
@@ -25,6 +27,7 @@ module Renalware
|
|
|
25
27
|
ensure
|
|
26
28
|
file.update!(status: status, result: strio.string, time_taken: elapsed_ms)
|
|
27
29
|
end
|
|
30
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
28
31
|
|
|
29
32
|
private
|
|
30
33
|
|
|
@@ -12,6 +12,7 @@ module Renalware
|
|
|
12
12
|
|
|
13
13
|
FILE_TO_EXTRACT_FROM_ARCHIVE = /^egpcur.csv$/.freeze
|
|
14
14
|
|
|
15
|
+
# rubocop:disable Metrics/AbcSize
|
|
15
16
|
def perform(file)
|
|
16
17
|
logging_to_stringio(strio = StringIO.new)
|
|
17
18
|
log "PrimaryCarePhysician count before update: #{primary_care_physician_count}"
|
|
@@ -26,6 +27,7 @@ module Renalware
|
|
|
26
27
|
ensure
|
|
27
28
|
file.update!(status: status, result: strio.string, time_taken: elapsed_ms)
|
|
28
29
|
end
|
|
30
|
+
# rubocop:enable Metrics/AbcSize
|
|
29
31
|
|
|
30
32
|
private
|
|
31
33
|
|
|
@@ -11,10 +11,19 @@ module Renalware
|
|
|
11
11
|
# HL7Message.new(raw_message).patient_identification.internal_id
|
|
12
12
|
#
|
|
13
13
|
class HL7Message < SimpleDelegator
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
ACTIONS = {
|
|
15
|
+
"ADT^A28" => :add_person_information,
|
|
16
|
+
"ADT^A31" => :update_person_information,
|
|
17
|
+
"ADT^A08" => :update_admission,
|
|
18
|
+
"ADT^A01" => :admit_patient,
|
|
19
|
+
"ADT^A02" => :transfer_patient,
|
|
20
|
+
"ADT^A03" => :discharge_patient,
|
|
21
|
+
"ADT^A11" => :cancel_admission,
|
|
22
|
+
"MFN^M02" => :add_consultant,
|
|
23
|
+
"ADT^A34" => :merge_patient,
|
|
24
|
+
"ADT^A13" => :cancel_discharge,
|
|
25
|
+
"ORU^R01" => :add_pathology_observations
|
|
26
|
+
}.freeze
|
|
18
27
|
|
|
19
28
|
class ObservationRequest < SimpleDelegator
|
|
20
29
|
alias_attribute :date_time, :observation_date
|
|
@@ -117,6 +126,8 @@ module Renalware
|
|
|
117
126
|
alias_attribute :external_id, :patient_id
|
|
118
127
|
alias_attribute :sex, :admin_sex
|
|
119
128
|
alias_attribute :dob, :patient_dob
|
|
129
|
+
alias_attribute :born_on, :patient_dob
|
|
130
|
+
alias_attribute :died_at, :death_date
|
|
120
131
|
|
|
121
132
|
def internal_id
|
|
122
133
|
patient_id_list.split("^").first
|
|
@@ -134,6 +145,18 @@ module Renalware
|
|
|
134
145
|
patient_name[1]
|
|
135
146
|
end
|
|
136
147
|
|
|
148
|
+
def suffix
|
|
149
|
+
patient_name[3]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def title
|
|
153
|
+
patient_name[4]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def address
|
|
157
|
+
super.split("^")
|
|
158
|
+
end
|
|
159
|
+
|
|
137
160
|
private
|
|
138
161
|
|
|
139
162
|
def patient_name
|
|
@@ -153,8 +176,36 @@ module Renalware
|
|
|
153
176
|
self[:MSH].message_control_id
|
|
154
177
|
end
|
|
155
178
|
|
|
156
|
-
|
|
157
|
-
|
|
179
|
+
# Adding this so it is part of the interface and we can mock an HL7Message in tests
|
|
180
|
+
def to_hl7
|
|
181
|
+
super
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def message_type
|
|
185
|
+
type.split("^").first
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def event_type
|
|
189
|
+
parts = type.split("^")
|
|
190
|
+
parts.length == 2 && parts.last
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
%i(ORU ADT).each do |msg_type|
|
|
194
|
+
define_method(:"#{msg_type.to_s.downcase}?") do
|
|
195
|
+
msg_type.to_s == message_type
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def action
|
|
200
|
+
ACTIONS.fetch(type)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def practice_code
|
|
204
|
+
self[:PD1].e3.split("^")[2] if self[:PD1]
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def gp_code
|
|
208
|
+
self[:PD1].e4.split("^")[0] if self[:PD1]
|
|
158
209
|
end
|
|
159
210
|
end
|
|
160
211
|
end
|
|
@@ -8,9 +8,13 @@ module Renalware
|
|
|
8
8
|
# message object.
|
|
9
9
|
#
|
|
10
10
|
class MessageParser
|
|
11
|
+
def self.parse(*args)
|
|
12
|
+
new.parse(*args)
|
|
13
|
+
end
|
|
14
|
+
|
|
11
15
|
def parse(message_string)
|
|
12
|
-
lines = message_string.split("\n").join("\r")
|
|
13
|
-
HL7Message.new(lines)
|
|
16
|
+
lines = message_string.split("\n").join("\r").lines
|
|
17
|
+
HL7Message.new(::HL7::Message.new(lines))
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_dependency "renalware/feeds"
|
|
4
|
+
require "attr_extras"
|
|
4
5
|
|
|
5
6
|
module Renalware
|
|
6
7
|
module Feeds
|
|
@@ -9,32 +10,48 @@ module Renalware
|
|
|
9
10
|
#
|
|
10
11
|
class MessageProcessor
|
|
11
12
|
include Broadcasting
|
|
13
|
+
attr_reader :raw_message, :hl7_message, :feed_message
|
|
12
14
|
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
# We want to wrap message processing in a transaction because if message processing
|
|
16
|
+
# fails we don't want to leave an unprocessed message in the feed_messages table.
|
|
17
|
+
# If we did, and the same FeedJob retires a few minutes later, if will try to save to
|
|
18
|
+
# feed_messages with the same MD5 body_hash (the message is identical to one already saved)
|
|
19
|
+
# resulting in unique key violation.
|
|
20
|
+
# Using a transaction here prevents any orphaned records if there is an error.
|
|
21
|
+
# However we should be aware that any listeners raising an error will prevent successful
|
|
22
|
+
# in all other listeners. So a listener should be careful to catch errors and not re-raise
|
|
23
|
+
# them, or use the :message_processed message (lower down) which is safer.
|
|
16
24
|
def call(raw_message)
|
|
17
|
-
|
|
25
|
+
@raw_message = raw_message
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
# fails we don't want to leave an unprocessed message in the feed_messages table.
|
|
21
|
-
# If we did, and the same FeedJob retires a few minutes later, if will try to save to
|
|
22
|
-
# feed_messages with the same MD5 body_hash (the message is identical to one already saved)
|
|
23
|
-
# resulting in unique key violation.
|
|
24
|
-
# Using a transaction here prevents any orphaned records if there is an error.
|
|
25
|
-
# However we should be aware that any listeners raising an error will prevent successful
|
|
26
|
-
# in all other listeners. So a listener should be careful to catch errors and not re-raise
|
|
27
|
-
# them, or use the :message_processed message (lower down) which is safer.
|
|
27
|
+
parse_raw_message_into_hl7_object
|
|
28
28
|
ActiveRecord::Base.transaction do
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
broadcast(
|
|
32
|
-
:message_arrived,
|
|
33
|
-
hl7_message: hl7_message,
|
|
34
|
-
feed_message: feed_message
|
|
35
|
-
)
|
|
29
|
+
create_feed_message_using_raw_message_and_basic_extracted_patient_data
|
|
30
|
+
allow_listeners_to_process_the_message
|
|
36
31
|
end
|
|
37
32
|
|
|
33
|
+
allow_listeners_to_post_process_the_message
|
|
34
|
+
rescue StandardError => exception
|
|
35
|
+
notify_exception(exception)
|
|
36
|
+
raise exception
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def notify_exception(exception)
|
|
42
|
+
Engine.exception_notifier.notify(exception)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def allow_listeners_to_process_the_message
|
|
46
|
+
message_to_broadcast = "#{hl7_message.message_type.downcase}_message_arrived"
|
|
47
|
+
broadcast(
|
|
48
|
+
message_to_broadcast.to_sym,
|
|
49
|
+
hl7_message: hl7_message,
|
|
50
|
+
feed_message: feed_message
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def allow_listeners_to_post_process_the_message
|
|
38
55
|
# Another event, this one letting anyone interested know that a message been successfully
|
|
39
56
|
# processed. They might want to forward the message on somewhere else for instance.
|
|
40
57
|
# Think Diaverum.
|
|
@@ -44,8 +61,9 @@ module Renalware
|
|
|
44
61
|
# e.g. forwarding, logging etc.
|
|
45
62
|
# Its is recommended here to use an async listener - see example in renalware-diaverum
|
|
46
63
|
# - so that any error in the listener has its own try mechansim and does not cause the
|
|
47
|
-
# current job to retry
|
|
48
|
-
|
|
64
|
+
# current job to retry.
|
|
65
|
+
message_to_broadcast = "#{hl7_message.message_type.downcase}_message_processed"
|
|
66
|
+
broadcast(message_to_broadcast.to_sym, feed_message: feed_message)
|
|
49
67
|
rescue Feeds::DuplicateMessageReceivedError => e
|
|
50
68
|
Rails.logger.warn("Rejected duplicate HL7 message: #{e.message}")
|
|
51
69
|
rescue StandardError => e
|
|
@@ -53,10 +71,8 @@ module Renalware
|
|
|
53
71
|
raise e
|
|
54
72
|
end
|
|
55
73
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def build_hl7_object_from(raw_message)
|
|
59
|
-
MessageParser.new.parse(raw_message)
|
|
74
|
+
def parse_raw_message_into_hl7_object
|
|
75
|
+
@hl7_message = MessageParser.parse(raw_message)
|
|
60
76
|
end
|
|
61
77
|
|
|
62
78
|
# If the incoming message has already been processed we should not be processing it again.
|
|
@@ -64,12 +80,8 @@ module Renalware
|
|
|
64
80
|
# same message payload is saved twice - in this case we exit #call early, the broadcast
|
|
65
81
|
# is not issued and therefore the message is not processed. The message will go back into
|
|
66
82
|
# the delayed_job queue and retry, failing until it finally gives up!
|
|
67
|
-
def
|
|
68
|
-
PersistMessage.new.call(hl7_message)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def notify_exception(exception)
|
|
72
|
-
Engine.exception_notifier.notify(exception)
|
|
83
|
+
def create_feed_message_using_raw_message_and_basic_extracted_patient_data
|
|
84
|
+
@feed_message = PersistMessage.new.call(hl7_message)
|
|
73
85
|
end
|
|
74
86
|
end
|
|
75
87
|
end
|
|
@@ -8,21 +8,27 @@ module Renalware
|
|
|
8
8
|
# hl7_message is an HL7Message (a decorator around ::HL7::Message)
|
|
9
9
|
# If the same message is persisted twice we'll get an ActiveRecord::RecordNotUnique error
|
|
10
10
|
# but that's fine as we don't want to process the same HL7 message twice.
|
|
11
|
+
# rubocop:disable Metrics/MethodLength
|
|
11
12
|
def call(hl7_message)
|
|
13
|
+
body_hash = Digest::MD5.hexdigest(hl7_message.to_hl7)
|
|
12
14
|
Message.create!(
|
|
13
15
|
event_code: hl7_message.type,
|
|
14
16
|
header_id: hl7_message.header_id,
|
|
15
17
|
body: hl7_message.to_s,
|
|
16
|
-
body_hash:
|
|
18
|
+
body_hash: body_hash,
|
|
17
19
|
patient_identifier: hl7_message.patient_identification&.internal_id
|
|
18
20
|
)
|
|
19
|
-
rescue ActiveRecord::RecordNotUnique
|
|
21
|
+
rescue ActiveRecord::RecordNotUnique
|
|
20
22
|
# If a duplicate messages comes in (we have calculated the body_hash for the message and it
|
|
21
23
|
# turns out that body_hash is not unique in the database, meaning the message is already
|
|
22
24
|
# stored) then raise a custom error so it can be handled upstream - ie we can choose to
|
|
23
25
|
# ignore it.
|
|
24
|
-
raise
|
|
26
|
+
raise(
|
|
27
|
+
DuplicateMessageError,
|
|
28
|
+
"header_id=#{hl7_message.header_id}, body_hash=#{body_hash}"
|
|
29
|
+
)
|
|
25
30
|
end
|
|
31
|
+
# rubocop:enable Metrics/MethodLength
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "renalware/hd"
|
|
4
|
+
|
|
5
|
+
module Renalware
|
|
6
|
+
module HD
|
|
7
|
+
module Scheduling
|
|
8
|
+
class ArchiveArguments
|
|
9
|
+
attr_reader :from_week_period, :to_week_period, :up_until_date
|
|
10
|
+
|
|
11
|
+
def initialize(from: nil, to: nil)
|
|
12
|
+
@from_week_period = WeekPeriod.from_date(from || 1.year.ago)
|
|
13
|
+
@up_until_date = (to || Time.zone.now - 1.day).to_date
|
|
14
|
+
@to_week_period = WeekPeriod.from_date(@up_until_date)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|