renalware-core 2.0.110 → 2.0.111
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/renalware/medications_pdf.scss +6 -0
- data/app/assets/stylesheets/renalware/protocol_pdf.scss +4 -0
- data/app/controllers/renalware/admin/users_controller.rb +1 -1
- data/app/controllers/renalware/base_controller.rb +13 -1
- data/app/controllers/renalware/patients/patients_controller.rb +5 -1
- data/app/jobs/renalware/hd/update_rolling_patient_statistics_dj_job.rb +1 -1
- data/app/jobs/renalware/letters/calculate_page_count_job.rb +1 -1
- data/app/models/renalware/feeds.rb +2 -0
- data/app/models/renalware/feeds/message_processor.rb +2 -0
- data/app/models/renalware/feeds/persist_message.rb +6 -0
- data/app/policies/renalware/user_policy.rb +11 -0
- data/app/presenters/renalware/hd/protocol_presenter.rb +4 -2
- data/app/presenters/renalware/mdm_presenter.rb +3 -3
- data/app/presenters/renalware/transplants/mdm_presenter.rb +1 -1
- data/app/views/renalware/admin/users/edit.html.slim +3 -2
- data/app/views/renalware/api/ukrdc/patients/_clinic_visit_observation.xml.builder +4 -1
- data/app/views/renalware/api/ukrdc/patients/_hd_session_observations.xml.builder +4 -1
- data/app/views/renalware/hd/protocols/_profile.html.slim +2 -0
- data/app/views/renalware/hd/protocols/_recent_pathology.html.slim +3 -3
- data/app/views/renalware/hd/sessions/_empty_row.html.slim +6 -2
- data/app/views/renalware/hd/sessions/_row.html.slim +16 -16
- data/app/views/renalware/medications/home_delivery/prescriptions/index.pdf.slim +5 -1
- data/config/locales/renalware/hd/protocol.en.yml +1 -0
- data/lib/renalware/configuration.rb +2 -2
- data/lib/renalware/version.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcb6fe2a9d36fece24e482f2cf318d89af11914dab2beb7b346bf3a6cba9c8b8
|
4
|
+
data.tar.gz: ecde69203a3b74dacc87163bb1b19bf103eb79b2a7e34742fe824d6a53e62f7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 878519c049773af3fe86eb79f5a20274b470d6cbc4c132c3db7c25c67f324bc32a77bb8d6e0d9a9c1270c5090adc6187031b366be4443d4d7df66e60f2d44742
|
7
|
+
data.tar.gz: 0f3cf22ee16a7737816afd2a0245aa0676d3cb3d1ab7c10b85c5873250c90da20e91e7ca96e7b2a1d32ce51231a71b85cdb43e9f0c2ee944da1d8d9da67a3836
|
@@ -22,6 +22,9 @@ module Renalware
|
|
22
22
|
|
23
23
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
24
24
|
|
25
|
+
class PatientNotFoundError < StandardError; end
|
26
|
+
rescue_from PatientNotFoundError, with: :patient_not_found
|
27
|
+
|
25
28
|
# Expose a few attributes for use in the patient layout and its partials.
|
26
29
|
# As a rule, we should be passing variables explicitly to all view using `locals`;
|
27
30
|
# however, while not a fan of `helper_method`, exposing e.g. current_patient this (akin to
|
@@ -31,7 +34,11 @@ module Renalware
|
|
31
34
|
alias_attribute :current_patient, :patient
|
32
35
|
|
33
36
|
def patient
|
34
|
-
@patient ||=
|
37
|
+
@patient ||= begin
|
38
|
+
Renalware::Patient.find_by(secure_id: params[:patient_id]).tap do |patient_|
|
39
|
+
raise PatientNotFoundError unless patient_
|
40
|
+
end
|
41
|
+
end
|
35
42
|
end
|
36
43
|
|
37
44
|
protected
|
@@ -73,5 +80,10 @@ module Renalware
|
|
73
80
|
flash[:error] = "You are not authorized to perform this action."
|
74
81
|
redirect_to dashboard_path
|
75
82
|
end
|
83
|
+
|
84
|
+
def patient_not_found
|
85
|
+
flash[:error] = "Patient not found"
|
86
|
+
redirect_to dashboard_path
|
87
|
+
end
|
76
88
|
end
|
77
89
|
end
|
@@ -66,7 +66,11 @@ module Renalware
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def patient
|
69
|
-
@patient ||=
|
69
|
+
@patient ||= begin
|
70
|
+
Renalware::Patient.find_by(secure_id: params[:id]).tap do |patient_|
|
71
|
+
raise PatientNotFoundError unless patient_
|
72
|
+
end
|
73
|
+
end
|
70
74
|
end
|
71
75
|
|
72
76
|
private
|
@@ -6,7 +6,7 @@ require "attr_extras"
|
|
6
6
|
|
7
7
|
module Renalware
|
8
8
|
module Letters
|
9
|
-
# This class is both a
|
9
|
+
# This class is both a Wisper listener (subscribing to ApproveLetter events) and an ActiveJob.
|
10
10
|
# Should be configured in the broadcast_subscription_map to listen to events from ApproveLetter
|
11
11
|
# and be invoked aysnchronously via a background queue ie delayed_job.
|
12
12
|
#
|
@@ -46,6 +46,8 @@ module Renalware
|
|
46
46
|
# - so that any error in the listener has its own try mechansim and does not cause the
|
47
47
|
# current job to retry,
|
48
48
|
broadcast(:message_processed, feed_message: feed_message)
|
49
|
+
rescue Feeds::DuplicateMessageReceivedError => e
|
50
|
+
Rails.logger.warn("Rejected duplicate HL7 message: #{e.message}")
|
49
51
|
rescue StandardError => e
|
50
52
|
notify_exception(e)
|
51
53
|
raise e
|
@@ -16,6 +16,12 @@ module Renalware
|
|
16
16
|
body_hash: Digest::MD5.hexdigest(hl7_message.to_s),
|
17
17
|
patient_identifier: hl7_message.patient_identification&.internal_id
|
18
18
|
)
|
19
|
+
rescue ActiveRecord::RecordNotUnique => e
|
20
|
+
# If a duplicate messages comes in (we have calculated the body_hash for the message and it
|
21
|
+
# turns out that body_hash is not unique in the database, meaning the message is already
|
22
|
+
# stored) then raise a custom error so it can be handled upstream - ie we can choose to
|
23
|
+
# ignore it.
|
24
|
+
raise Feeds::DuplicateMessageReceivedError, e.message
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
@@ -6,6 +6,17 @@ module Renalware
|
|
6
6
|
super && !user_update_self?
|
7
7
|
end
|
8
8
|
|
9
|
+
def assign_role?(role)
|
10
|
+
return false if role.hidden
|
11
|
+
|
12
|
+
can_assign_role = case role.name
|
13
|
+
when "devops", "super_admin" then false
|
14
|
+
when "admin" then user_is_super_admin?
|
15
|
+
else true
|
16
|
+
end
|
17
|
+
can_assign_role && update?
|
18
|
+
end
|
19
|
+
|
9
20
|
private
|
10
21
|
|
11
22
|
def user_update_self?
|
@@ -43,13 +43,15 @@ module Renalware
|
|
43
43
|
|
44
44
|
def sessions
|
45
45
|
@sessions ||= begin
|
46
|
-
hd_sessions =
|
46
|
+
hd_sessions =
|
47
|
+
Sessions::ProtocolSessionsQuery.new(patient: patient)
|
48
|
+
.call.includes(:patient, :signed_on_by, :signed_off_by)
|
47
49
|
::CollectionPresenter.new(hd_sessions, Protocol::SessionPresenter, view_context)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
53
|
def prescriptions
|
52
|
-
prescriptions = patient.prescriptions.to_be_administered_on_hd
|
54
|
+
prescriptions = patient.prescriptions.includes(:drug).to_be_administered_on_hd
|
53
55
|
::CollectionPresenter.new(prescriptions, ::Renalware::Medications::PrescriptionPresenter)
|
54
56
|
end
|
55
57
|
|
@@ -23,12 +23,12 @@ module Renalware
|
|
23
23
|
@pathology ||= pathology_for_codes
|
24
24
|
end
|
25
25
|
|
26
|
-
def pathology_for_codes(codes = nil)
|
26
|
+
def pathology_for_codes(codes = nil, per_page: 10, page: 1)
|
27
27
|
Pathology::CreateObservationsGroupedByDateTable.new(
|
28
28
|
patient: patient,
|
29
29
|
observation_descriptions: pathology_descriptions_for_codes(codes),
|
30
|
-
page:
|
31
|
-
per_page:
|
30
|
+
page: page,
|
31
|
+
per_page: per_page
|
32
32
|
).call
|
33
33
|
end
|
34
34
|
|
@@ -24,12 +24,13 @@
|
|
24
24
|
|
25
25
|
br
|
26
26
|
br
|
27
|
-
- Renalware::Role.all.each_with_index do |role, index|
|
27
|
+
- Renalware::Role.all.order(id: :asc).each_with_index do |role, index|
|
28
28
|
- element_id = "user_role_ids_#{index}"
|
29
|
+
- policy = Pundit.policy(current_user, @user)
|
29
30
|
= check_box_tag "user[role_ids][]",
|
30
31
|
role.id,
|
31
32
|
@user.has_role?(role.name),
|
32
|
-
disabled: role
|
33
|
+
disabled: !(policy.assign_role?(role)),
|
33
34
|
id: element_id,
|
34
35
|
class: "inline"
|
35
36
|
= label_tag element_id, role.name.humanize
|
@@ -15,7 +15,10 @@ if measurement.present? && measurement.to_f.nonzero?
|
|
15
15
|
xml.Description I18n.t("loinc.#{i18n_key}.description")
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
# Only take the first 20 characters, and then strip leading and trailing space.
|
19
|
+
# This is to allow for rogue values like
|
20
|
+
# '615 615'
|
21
|
+
xml.ObservationValue measurement.to_s[0, 19].strip
|
19
22
|
xml.ObservationUnits I18n.t("loinc.#{i18n_key}.units")
|
20
23
|
|
21
24
|
xml.Clinician do
|
@@ -27,7 +27,10 @@ observation_times = {
|
|
27
27
|
xml.Description I18n.t("loinc.#{i18n_key}.description")
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
# Only take the first 20 characters, and then strip leading and trailing space.
|
31
|
+
# This is to allow for rogue values like
|
32
|
+
# '615 615'
|
33
|
+
xml.ObservationValue value.to_s[0, 19].strip
|
31
34
|
xml.ObservationUnits I18n.t("loinc.#{i18n_key}.units")
|
32
35
|
xml.PrePost pre_post.to_s.upcase # eg PRE or POST
|
33
36
|
end
|
@@ -3,12 +3,12 @@ table.recent-pathology
|
|
3
3
|
tr
|
4
4
|
th.code HGB
|
5
5
|
td.result= recent_pathology.hgb_result
|
6
|
-
td.observed_at= (l(recent_pathology.hgb_observed_at))
|
6
|
+
td.nowrap.observed_at= (l(recent_pathology.hgb_observed_at))
|
7
7
|
tr
|
8
8
|
th.code PLT
|
9
9
|
td.result= recent_pathology.plt_result
|
10
|
-
td.observed_at= (l(recent_pathology.plt_observed_at))
|
10
|
+
td.nowrap.observed_at= (l(recent_pathology.plt_observed_at))
|
11
11
|
tr
|
12
12
|
th.code CRP
|
13
13
|
td.result= recent_pathology.crp_result
|
14
|
-
td.observed_at= (l(recent_pathology.crp_observed_at))
|
14
|
+
td.nowrap.observed_at= (l(recent_pathology.crp_observed_at))
|
@@ -1,6 +1,5 @@
|
|
1
1
|
/ An empty session table row for use in the printed protocol (data-entry form)
|
2
2
|
tr.empty-session-row.first
|
3
|
-
td(rowspan=2)
|
4
3
|
td(rowspan=2)
|
5
4
|
td
|
6
5
|
td
|
@@ -9,7 +8,8 @@ tr.empty-session-row.first
|
|
9
8
|
td
|
10
9
|
td
|
11
10
|
td
|
12
|
-
td
|
11
|
+
td
|
12
|
+
td
|
13
13
|
td(rowspan=2)
|
14
14
|
td(rowspan=2)
|
15
15
|
td(rowspan=2)
|
@@ -20,6 +20,7 @@ tr.empty-session-row.first
|
|
20
20
|
td(rowspan=2)
|
21
21
|
td(rowspan=2)
|
22
22
|
td
|
23
|
+
td
|
23
24
|
tr.empty-session-row
|
24
25
|
td
|
25
26
|
td
|
@@ -29,3 +30,6 @@ tr.empty-session-row
|
|
29
30
|
td
|
30
31
|
td
|
31
32
|
td
|
33
|
+
td
|
34
|
+
td
|
35
|
+
td
|
@@ -14,16 +14,16 @@ tr.hd-session-row(class=[session.state, stripe_class])
|
|
14
14
|
td= session.before_measurement_for(:pulse)
|
15
15
|
td= session.before_measurement_for(:temperature)
|
16
16
|
td= session.before_measurement_for(:respiratory_rate)
|
17
|
-
td= session.before_measurement_for(:bm_stix)
|
18
|
-
td= session.before_measurement_for(:blood_pressure)
|
19
|
-
td(rowspan=2)= session.arterial_pressure
|
20
|
-
td(rowspan=2)= session.venous_pressure
|
21
|
-
td(rowspan=2)= session.blood_flow
|
22
|
-
td(rowspan=2)= session.litres_processed
|
23
|
-
td(rowspan=2)= session.fluid_removed
|
24
|
-
td(rowspan=2)= session.machine_no
|
25
|
-
td(rowspan=2)= session.machine_ktv
|
26
|
-
td(rowspan=2)= session.machine_urr
|
17
|
+
td.nowrap= session.before_measurement_for(:bm_stix)
|
18
|
+
td.nowrap= session.before_measurement_for(:blood_pressure)
|
19
|
+
td.nowrap(rowspan=2)= session.arterial_pressure
|
20
|
+
td.nowrap(rowspan=2)= session.venous_pressure
|
21
|
+
td.nowrap(rowspan=2)= session.blood_flow
|
22
|
+
td.nowrap(rowspan=2)= session.litres_processed
|
23
|
+
td.nowrap(rowspan=2)= session.fluid_removed
|
24
|
+
td.nowrap(rowspan=2)= session.machine_no
|
25
|
+
td.nowrap(rowspan=2)= session.machine_ktv
|
26
|
+
td.nowrap(rowspan=2)= session.machine_urr
|
27
27
|
td.print-only(rowspan=2)
|
28
28
|
td.print-only(rowspan=2)= session.notes
|
29
29
|
td.print-only= session.signed_on_by
|
@@ -31,15 +31,15 @@ tr.hd-session-row(class=[session.state, stripe_class])
|
|
31
31
|
tr(class=[session.state, stripe_class])
|
32
32
|
td= tooltip(label: session.summarised_access_used, content: session.access_used)
|
33
33
|
td= session.end_time
|
34
|
-
td
|
34
|
+
td.nowrap
|
35
35
|
= session.after_measurement_for(:weight)
|
36
36
|
- if (change = session.change_in(:weight))
|
37
37
|
i=" (#{change})"
|
38
|
-
td= session.after_measurement_for(:pulse)
|
39
|
-
td= session.after_measurement_for(:temperature)
|
40
|
-
td= session.after_measurement_for(:respiratory_rate)
|
41
|
-
td= session.after_measurement_for(:bm_stix)
|
42
|
-
td= session.after_measurement_for(:blood_pressure)
|
38
|
+
td.nowrap= session.after_measurement_for(:pulse)
|
39
|
+
td.nowrap= session.after_measurement_for(:temperature)
|
40
|
+
td.nowrap= session.after_measurement_for(:respiratory_rate)
|
41
|
+
td.nowrap= session.after_measurement_for(:bm_stix)
|
42
|
+
td.nowrap= session.after_measurement_for(:blood_pressure)
|
43
43
|
td.print-only= session.signed_off_by
|
44
44
|
= content_tag(:tr, id: "hd-session-#{session.id}", style: "display: none")
|
45
45
|
td(colspan=19)
|
@@ -8,7 +8,11 @@ html
|
|
8
8
|
= wicked_pdf_stylesheet_link_tag "renalware/medications_pdf"
|
9
9
|
heading
|
10
10
|
.our-ref= "RW ref: #{patient.hospital_identifier}"
|
11
|
-
span.logo
|
11
|
+
span.logo
|
12
|
+
= wicked_pdf_image_tag "renalware/NHS-Black.jpg", width: 50
|
13
|
+
.address
|
14
|
+
= Renalware.config.hospital_address.split(",").join("<br>").html_safe
|
15
|
+
|
12
16
|
main
|
13
17
|
h1 Home Delivery Medication List
|
14
18
|
= "As at #{l(Time.zone.now)}"
|
@@ -22,7 +22,8 @@ module Renalware
|
|
22
22
|
Dotenv::Railtie.load
|
23
23
|
|
24
24
|
config_accessor(:site_name) { "Renalware" }
|
25
|
-
config_accessor(:hospital_name) { "KINGS COLLEGE HOSPITAL" }
|
25
|
+
config_accessor(:hospital_name) { ENV.fetch("HOSPITAL_NAME", "KINGS COLLEGE HOSPITAL") }
|
26
|
+
config_accessor(:hospital_address) { ENV.fetch("HOSPITAL_ADDRESS", "") } # comma-delimited
|
26
27
|
config_accessor(:delay_after_which_a_finished_session_becomes_immutable) { 6.hours }
|
27
28
|
config_accessor(:new_clinic_visit_deletion_window) { 24.hours }
|
28
29
|
config_accessor(:new_clinic_visit_edit_window) { 7.days }
|
@@ -84,7 +85,6 @@ module Renalware
|
|
84
85
|
config_accessor(:render_pdf_as_html_for_debugging) { false }
|
85
86
|
|
86
87
|
config_accessor(:hd_session_prescriptions_require_signoff) { true }
|
87
|
-
|
88
88
|
config_accessor(:batch_printing_enabled) { true }
|
89
89
|
|
90
90
|
# A host app can override this to add/remove/re-order the clinical summary display
|
data/lib/renalware/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: renalware-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.111
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Airslie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_type
|
@@ -86,28 +86,28 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: '16.0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: '16.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: client_side_validations-simple_form
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: '9.0'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: '9.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: clipboard-rails
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -772,14 +772,14 @@ dependencies:
|
|
772
772
|
requirements:
|
773
773
|
- - "~>"
|
774
774
|
- !ruby/object:Gem::Version
|
775
|
-
version:
|
775
|
+
version: '5.0'
|
776
776
|
type: :runtime
|
777
777
|
prerelease: false
|
778
778
|
version_requirements: !ruby/object:Gem::Requirement
|
779
779
|
requirements:
|
780
780
|
- - "~>"
|
781
781
|
- !ruby/object:Gem::Version
|
782
|
-
version:
|
782
|
+
version: '5.0'
|
783
783
|
- !ruby/object:Gem::Dependency
|
784
784
|
name: sinatra
|
785
785
|
requirement: !ruby/object:Gem::Requirement
|