renalware-core 2.0.24 → 2.0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -5
- data/app/assets/images/renalware/print-button-example.png +0 -0
- data/app/assets/stylesheets/renalware/partials/_layout.scss +4 -0
- data/app/assets/stylesheets/renalware/pdf.scss +12 -0
- data/app/assets/stylesheets/renalware/protocol_pdf.scss +4 -0
- data/app/assets/stylesheets/renalware/table_pdf.scss +210 -0
- data/app/controllers/renalware/admissions/consults_controller.rb +24 -6
- data/app/controllers/renalware/concerns/pdf_renderable.rb +11 -2
- data/app/controllers/renalware/renal/aki_alerts_controller.rb +29 -7
- data/app/controllers/renalware/transplants/registration_statuses_controller.rb +1 -1
- data/app/models/renalware/admissions/consult_query.rb +3 -0
- data/app/models/renalware/feeds/message_processor.rb +5 -0
- data/app/models/renalware/feeds/persist_message.rb +4 -1
- data/app/models/renalware/renal.rb +1 -1
- data/app/models/renalware/renal/aki_alert.rb +1 -0
- data/app/presenters/renalware/admissions/admission_presenter.rb +1 -1
- data/app/views/renalware/admissions/consults/_filters.html.slim +10 -1
- data/app/views/renalware/admissions/consults/_filters.pdf.slim +32 -0
- data/app/views/renalware/admissions/consults/_table.html.slim +9 -8
- data/app/views/renalware/admissions/consults/_table.pdf.slim +35 -0
- data/app/views/renalware/admissions/consults/index.html.slim +7 -0
- data/app/views/renalware/admissions/consults/index.pdf.slim +10 -0
- data/app/views/renalware/hd/sessions/_empty_row.html.slim +2 -0
- data/app/views/renalware/hd/sessions/_row.html.slim +3 -0
- data/app/views/renalware/hd/sessions/_show.html.slim +5 -6
- data/app/views/renalware/hd/sessions/_thead.html.slim +4 -0
- data/app/views/renalware/layouts/pdf.pdf.slim +1 -1
- data/app/views/renalware/letters/contacts/_edit.html.slim +1 -1
- data/app/views/renalware/renal/aki_alerts/_filters.pdf.slim +25 -0
- data/app/views/renalware/renal/aki_alerts/_table.pdf.slim +29 -0
- data/app/views/renalware/renal/aki_alerts/edit.html.slim +1 -1
- data/app/views/renalware/renal/aki_alerts/index.html.slim +10 -0
- data/app/views/renalware/renal/aki_alerts/index.pdf.slim +14 -0
- data/app/views/renalware/shared/_please_print_using_print_button_warning.html.slim +18 -0
- data/app/views/renalware/transplants/donor_followups/_form.html.slim +2 -2
- data/app/views/renalware/transplants/recipient_followups/_form.html.slim +6 -1
- data/app/views/renalware/transplants/registration_statuses/_inputs.html.slim +4 -0
- data/app/views/renalware/transplants/registration_statuses/_list.html.slim +18 -5
- data/config/locales/custom.yml +2 -3
- data/config/locales/renalware/hd/session.en.yml +3 -0
- data/db/migrate/20180510151959_update_hd_overall_audit_to_version_7.rb +6 -0
- data/db/migrate/20180511100345_add_notes_to_transplant_registration_statuses.rb +5 -0
- data/db/migrate/20180511140415_add_message_hash_messaging_messages.rb +6 -0
- data/db/seeds/default/deaths/death_causes.rb +4 -4
- data/db/seeds/default/patients/patients_languages.rb +4 -3
- data/db/seeds/default/renal/prd_descriptions.rb +7 -5
- data/db/seeds/default/system/countries.rb +10 -6
- data/db/views/reporting_hd_overall_audit_v07.sql +44 -0
- data/lib/renalware/configuration.rb +4 -0
- data/lib/renalware/engine.rb +2 -0
- data/lib/renalware/version.rb +1 -1
- data/spec/factories/admissions/consults.rb +12 -0
- data/spec/support/capybara.rb +16 -21
- metadata +15 -3
- data/spec/support/poltergeist.rb +0 -4
@@ -10,6 +10,7 @@ module Renalware
|
|
10
10
|
def initialize(query = nil)
|
11
11
|
@query = query || {}
|
12
12
|
@query[:ended_on_null] ||= true
|
13
|
+
@query[:s] ||= "hospital_ward_name"
|
13
14
|
end
|
14
15
|
|
15
16
|
def call
|
@@ -20,6 +21,7 @@ module Renalware
|
|
20
21
|
# It might be better to refactor PatientsRansackHelper so we can include where required
|
21
22
|
# eg below using .extending(PatientsRansackHelper) rather than relying on it being in
|
22
23
|
# included in the model file.
|
24
|
+
# rubocop:disable Metrics/MethodLength
|
23
25
|
def search
|
24
26
|
@search ||= begin
|
25
27
|
Consult
|
@@ -35,6 +37,7 @@ module Renalware
|
|
35
37
|
.ransack(query)
|
36
38
|
end
|
37
39
|
end
|
40
|
+
# rubocop:enable Metrics/MethodLength
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
@@ -27,6 +27,11 @@ module Renalware
|
|
27
27
|
MessageParser.new.parse(raw_message)
|
28
28
|
end
|
29
29
|
|
30
|
+
# If the incoming message has already been processed we should not be processing it again.
|
31
|
+
# To help enforce this there is a unique MD5 hash on feed_messages which will baulk if the
|
32
|
+
# same message payload is saved twice - in this case we exit #call early, the broadcast
|
33
|
+
# is not issued and therefore the message is not processed. The message will go back into
|
34
|
+
# the delayed_job queue and retry, failing until it finally gives up!
|
30
35
|
def persist_message(message_payload)
|
31
36
|
PersistMessage.new.call(message_payload)
|
32
37
|
end
|
@@ -6,11 +6,14 @@ module Renalware
|
|
6
6
|
module Feeds
|
7
7
|
class PersistMessage
|
8
8
|
# message_payload is an HL7Message (a decorator around ::HL7::Message)
|
9
|
+
# If the same message is persisted twice we'll get an ActiveRecord::RecordNotUnique error
|
10
|
+
# but that's fine as we don't want to process the same HL7 message twice.
|
9
11
|
def call(message_payload)
|
10
12
|
Message.create!(
|
11
13
|
event_code: message_payload.type,
|
12
14
|
header_id: message_payload.header_id,
|
13
|
-
body: message_payload.to_s
|
15
|
+
body: message_payload.to_s,
|
16
|
+
body_hash: Digest::MD5.hexdigest(message_payload.to_s)
|
14
17
|
)
|
15
18
|
end
|
16
19
|
end
|
@@ -11,11 +11,16 @@
|
|
11
11
|
= f.input :consult_site_id_eq,
|
12
12
|
collection: Renalware::Admissions::ConsultSite.pluck(:name, :id),
|
13
13
|
label: "Site"
|
14
|
-
.columns.medium-
|
14
|
+
.columns.medium-1.large-1
|
15
15
|
= f.input :seen_by_id_eq,
|
16
16
|
include_blank: false,
|
17
17
|
collection: [["Anyone", nil], ["Me", current_user.id]],
|
18
18
|
label: "Seen by"
|
19
|
+
.columns.medium-1.large-1
|
20
|
+
= f.input :rrt_eq,
|
21
|
+
include_blank: true,
|
22
|
+
collection: [["Yes", true], ["No", false]],
|
23
|
+
label: "RRT"
|
19
24
|
.columns.medium-1.large-1
|
20
25
|
= f.input :aki_risk_eq,
|
21
26
|
include_blank: true,
|
@@ -26,6 +31,10 @@
|
|
26
31
|
include_blank: true,
|
27
32
|
collection: [["Yes", true], ["No", false]],
|
28
33
|
label: "Active"
|
34
|
+
.columns.medium-2.large-2
|
35
|
+
= f.input :patient_current_modality_description_id_eq,
|
36
|
+
collection: Renalware::Modalities::Description.pluck("name", "id"),
|
37
|
+
label: "Modality"
|
29
38
|
.columns.medium-2.large-2.actions.end
|
30
39
|
= f.submit "Filter", class: "button"
|
31
40
|
span= " or "
|
@@ -0,0 +1,32 @@
|
|
1
|
+
// Compile a summary of filters applied. Leave out anything not set.
|
2
|
+
- filters = params.fetch(:q, {}).reject{ |key, value| value.blank? }
|
3
|
+
|
4
|
+
.filter-summary
|
5
|
+
table
|
6
|
+
tr
|
7
|
+
th Filters
|
8
|
+
- if filters.empty?
|
9
|
+
td None
|
10
|
+
- else
|
11
|
+
- if filters[:identity_match].present?
|
12
|
+
th Query:
|
13
|
+
td= filters[:identity_match]
|
14
|
+
- if filters[:consult_site_id_eq].present?
|
15
|
+
th Site:
|
16
|
+
td= Renalware::Admissions::ConsultSite.find_by(id: filters[:consult_site_id_eq]).name
|
17
|
+
- if filters[:rrt_eq].present?
|
18
|
+
th RRT:
|
19
|
+
td= yes_no(filters[:rrt_eq] == "true")
|
20
|
+
- if filters[:seen_by_id_eq].present?
|
21
|
+
th Seen By:
|
22
|
+
td= Renalware::User.find(filters[:seen_by_id_eq])&.to_s
|
23
|
+
- if filters[:aki_risk_eq].present?
|
24
|
+
th AKI Risk:
|
25
|
+
td= yes_no(filters[:ended_on_null]&.humanize)
|
26
|
+
- if filters[:ended_on_null].present?
|
27
|
+
th Active:
|
28
|
+
td= yes_no(filters[:ended_on_null] == "true")
|
29
|
+
- modality_id = filters[:patient_current_modality_description_id_eq]
|
30
|
+
- if modality_id.present?
|
31
|
+
th Modality:
|
32
|
+
td= Renalware::Modalities::Description.where(id: modality_id).first&.name
|
@@ -7,10 +7,8 @@
|
|
7
7
|
= sort_link(query, :patient, ["patient_family_name", "patient_given_name asc"], "Patient")
|
8
8
|
th.col-width-nhs-no.noprint NHS No.
|
9
9
|
th.col-width-reference-no Hosp Nos.
|
10
|
-
th.col-width-medium= sort_link(query,
|
11
|
-
|
12
|
-
[:consult_site_name, :hospital_ward_name],
|
13
|
-
"Location")
|
10
|
+
th.col-width-medium= sort_link(query, :hospital_ward_name, "Ward")
|
11
|
+
th.col-width-tiny RRT
|
14
12
|
th.col-width-date.noprint= sort_link(query, :started_on, "Started")
|
15
13
|
th.col-width-date.noprint= sort_link(query, :ended_on, "Ended")
|
16
14
|
th.col-width-small.show-for-large-up
|
@@ -19,13 +17,11 @@
|
|
19
17
|
th.col-width-date.show-for-large-up= sort_link(query, :patient_born_on, "DOB")
|
20
18
|
th.col-width-tiny.show-for-large-up Age
|
21
19
|
th.col-width-tiny.noprint= sort_link(query, :aki_risk, "AKI Risk")
|
22
|
-
/th.show-for-large-up Author
|
23
|
-
/th.col-width-medium.show-for-xlarge-up Description
|
24
20
|
|
25
21
|
tbody
|
26
22
|
- consults.each do |consult|
|
27
23
|
- uid = "consult-#{consult.id}"
|
28
|
-
tr
|
24
|
+
tr.keep-with-next
|
29
25
|
td.actions-dropdown.going-right.noprint
|
30
26
|
/ As we have lots of possible actions, group them in a button group.
|
31
27
|
/ A wrapping div is required for now in order for the button group display correctly
|
@@ -61,7 +57,8 @@
|
|
61
57
|
td= default_patient_link(consult.patient)
|
62
58
|
td.noprint= consult.patient_nhs_number
|
63
59
|
td= consult.patient_hospital_identifiers&.to_s_multiline
|
64
|
-
td= consult.
|
60
|
+
td= consult.hospital_ward
|
61
|
+
td= yes_no(consult.rrt?)
|
65
62
|
td.noprint= l(consult.started_on)
|
66
63
|
td.noprint= l(consult.ended_on)
|
67
64
|
td.show-for-large-up.col-width-medium-with-ellipsis= consult.patient_current_modality
|
@@ -82,3 +79,7 @@
|
|
82
79
|
dt Description
|
83
80
|
dd= simple_format consult.description
|
84
81
|
td
|
82
|
+
/ When printing we just show the notes on the second row
|
83
|
+
tr.print-only.child-row
|
84
|
+
td(colspan=12)= simple_format consult.description
|
85
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
table
|
2
|
+
thead
|
3
|
+
tr
|
4
|
+
th.col-width-large PATIENT
|
5
|
+
th.col-width-reference-no HOSP NOs.
|
6
|
+
th.col-width-large LOCATION
|
7
|
+
th MODALITY
|
8
|
+
th.col-width-tiny SEX
|
9
|
+
th.col-width-date DOB
|
10
|
+
|
11
|
+
- consults.each do |consult|
|
12
|
+
tr
|
13
|
+
/ Nested tables. Yum. But necessary to get wkhtml2pdf to avoid orphaning the
|
14
|
+
/ second 'notes' row (using css - see class definition) from the first 'patient details' row.
|
15
|
+
/ When having just one table with 2 rows per consult, wkhtml2pdf sometimes breaks a page
|
16
|
+
/ between the 2 rows when we really want to keep them together. Using a table like this and
|
17
|
+
/ applying page-break-inside: avoid to it we can avoid this problem. The downside is that the
|
18
|
+
/ columns may not always line up exactly if the content is wide.
|
19
|
+
table.nested-table-in-order-to-prevent-orphaned-rows.spacy
|
20
|
+
tbody
|
21
|
+
tr.consult-details
|
22
|
+
td.col-width-large
|
23
|
+
b= consult.patient.to_s(:default)
|
24
|
+
td.col-width-reference-no= consult.patient_hospital_identifiers&.to_s_multiline
|
25
|
+
td.col-width-large
|
26
|
+
- unit = consult.hospital_ward&.hospital_unit
|
27
|
+
= [unit&.unit_code,
|
28
|
+
consult&.hospital_ward,
|
29
|
+
consult.other_site_or_ward].compact.join(" / ")
|
30
|
+
td= consult.patient_current_modality
|
31
|
+
td.col-width-tiny= consult.patient_sex
|
32
|
+
td.col-width-date= l(consult.patient.born_on)
|
33
|
+
|
34
|
+
tr.consult-notes
|
35
|
+
td(colspan=6)= simple_format consult.description
|
@@ -2,8 +2,15 @@
|
|
2
2
|
|
3
3
|
= content_for(:actions) do
|
4
4
|
= link_to("Add", new_admissions_consult_path, class: :button)
|
5
|
+
= link_to(admissions_consults_path(q: params[:q]&.permit!, format: :pdf), class: "button secondary") do
|
6
|
+
i.fa.fa-print
|
7
|
+
| Print (PDF)
|
8
|
+
/data: { target: admissions_consults_path(format: :pdf)
|
5
9
|
|
6
10
|
= within_admin_layout(title: "Admission Consults") do
|
11
|
+
= render "renalware/shared/please_print_using_print_button_warning"
|
12
|
+
= render "renalware/admissions/requests/modal_dialog_placeholder"
|
13
|
+
|
7
14
|
.panel.radius.compact
|
8
15
|
| If the patient is not on Renalware yet, please
|
9
16
|
= link_to("add them", new_patient_path)
|
@@ -18,7 +18,9 @@ tr.hd-session-row(class=[session.state, stripe_class])
|
|
18
18
|
td(rowspan=2)= session.machine_no
|
19
19
|
td(rowspan=2)= session.machine_ktv
|
20
20
|
td(rowspan=2)= session.machine_urr
|
21
|
+
td.print-only(rowspan=2)
|
21
22
|
td.print-only(rowspan=2)= session.notes
|
23
|
+
td.print-only
|
22
24
|
|
23
25
|
tr(class=[session.state, stripe_class])
|
24
26
|
td= tooltip(label: session.summarised_access_used, content: session.access_used)
|
@@ -31,3 +33,4 @@ tr(class=[session.state, stripe_class])
|
|
31
33
|
td= session.after_measurement_for(:temperature)
|
32
34
|
td= session.after_measurement_for(:bm_stix)
|
33
35
|
td= session.after_measurement_for(:blood_pressure)
|
36
|
+
td.print-only
|
@@ -1,6 +1,6 @@
|
|
1
1
|
.document-view
|
2
|
-
.
|
3
|
-
.
|
2
|
+
.grid
|
3
|
+
.row
|
4
4
|
= render "renalware/shared/attributes_group",
|
5
5
|
legend: "Sign-In", destination: "signin",
|
6
6
|
models: { session => [:performed_on,
|
@@ -28,7 +28,6 @@
|
|
28
28
|
group: session.document.observations_after,
|
29
29
|
legend: "Post-Dialysis Observations", destination: "after"
|
30
30
|
|
31
|
-
.columns.large-6
|
32
31
|
- %W(Dialysis HDF).each do |group|
|
33
32
|
= render "renalware/shared/documents/attributes_group",
|
34
33
|
group: session.document.public_send(group.parameterize(separator: "_")),
|
@@ -39,6 +38,6 @@
|
|
39
38
|
legend: "Notes/Complications", destination: "complications",
|
40
39
|
models: { session.document.complications => attributes_list,
|
41
40
|
session => [:notes] }
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
.row
|
42
|
+
.columns
|
43
|
+
= render "prescription_administrations", session: session
|
@@ -18,6 +18,8 @@ thead
|
|
18
18
|
th.col-width-tiny.text-center(colspan=3)= t(".machine")
|
19
19
|
th.col-width-drugs.text-center.print-only(rowspan=3)= t(".hd_drugs_administered")
|
20
20
|
th.col-width-notes.text-center.print-only(rowspan=3)= t(".notes")
|
21
|
+
th.col-width-user.text-center.print-only= t(".user")
|
22
|
+
|
21
23
|
|
22
24
|
tr.row2
|
23
25
|
th(rowspan=2)= t(".access")
|
@@ -30,6 +32,7 @@ thead
|
|
30
32
|
th.col-width-minute.col-width-tiny(rowspan=2)=t(".machine_no")
|
31
33
|
th.col-width-minute.col-width-tiny(rowspan=2)=t(".machine_ktv")
|
32
34
|
th.col-width-minute.col-width-tiny(rowspan=2)=t(".machine_urr")
|
35
|
+
th.print-only= t(".put_on_by")
|
33
36
|
tr.row2
|
34
37
|
th.col-width-time= t(".end_time")
|
35
38
|
th= t(".post_with_changed")
|
@@ -37,3 +40,4 @@ thead
|
|
37
40
|
th= t(".post")
|
38
41
|
th= t(".post")
|
39
42
|
th= t(".post")
|
43
|
+
th.print-only= t(".taken_off_by")
|
@@ -15,7 +15,7 @@
|
|
15
15
|
remote: true,
|
16
16
|
wrapper: :horizontal_form) do |f|
|
17
17
|
|
18
|
-
= f.input :default_cc, as: :inline_radio_buttons
|
18
|
+
= f.input :default_cc, as: :inline_radio_buttons, readonly: nil
|
19
19
|
= f.input :description_id, collection: contact_descriptions
|
20
20
|
= f.input :other_description
|
21
21
|
= f.input :notes, as: :text
|
@@ -0,0 +1,25 @@
|
|
1
|
+
// Compile a summary of filters applied. Leave out anything not set.
|
2
|
+
- filters = params.fetch(:q, {}).reject{ |key, value| value.blank? }
|
3
|
+
|
4
|
+
.filter-summary
|
5
|
+
table
|
6
|
+
tr
|
7
|
+
th Filters
|
8
|
+
- if filters.empty?
|
9
|
+
td None
|
10
|
+
- else
|
11
|
+
- if filters[:term].present?
|
12
|
+
th Query:
|
13
|
+
td= filters[:term]
|
14
|
+
- if filters[:on_hotlist].present?
|
15
|
+
th On Hotlist:
|
16
|
+
td= yes_no(filters[:on_hotlist] == "true")
|
17
|
+
- if filters[:action].present?
|
18
|
+
th Action:
|
19
|
+
td= Renalware::Renal::AKIAlertAction.find(filters[:action])&.to_s
|
20
|
+
- if filters[:hospital_unit_id].present?
|
21
|
+
th Site:
|
22
|
+
td= Renalware::Hospitals::Unit.find_by(id: filters[:hospital_unit_id])
|
23
|
+
- if filters[:hospital_ward_id].present?
|
24
|
+
th Ward:
|
25
|
+
td= Renalware::Hospitals::Ward.find_by(id: filters[:hospital_ward_id])
|
@@ -0,0 +1,29 @@
|
|
1
|
+
table
|
2
|
+
thead
|
3
|
+
tr
|
4
|
+
th.col-width-large PATIENT
|
5
|
+
th.col-width-reference-no HOSP NOs.
|
6
|
+
th.col-width-medium WARD
|
7
|
+
th MODALITY
|
8
|
+
th.col-width-tiny CRE
|
9
|
+
th.col-width-date CRE DATE
|
10
|
+
th.col-width-tiny SEX
|
11
|
+
th.col-width-date DOB
|
12
|
+
|
13
|
+
- alerts.each do |alert|
|
14
|
+
tr
|
15
|
+
table.nested-table-in-order-to-prevent-orphaned-rows.spacy
|
16
|
+
tbody
|
17
|
+
tr.alert-details
|
18
|
+
td.col-width-large
|
19
|
+
b= alert.patient.to_s(:default)
|
20
|
+
td.col-width-reference-no= alert.patient&.hospital_identifiers&.to_s_multiline
|
21
|
+
td.col-width-medium= alert.hospital_ward
|
22
|
+
td= alert.patient&.current_modality
|
23
|
+
td.col-width-tiny= alert.max_cre
|
24
|
+
td.col-width-date= I18n.l(alert.cre_date)
|
25
|
+
td.col-width-tiny= alert.patient&.sex
|
26
|
+
td.col-width-date= l(alert.patient&.born_on)
|
27
|
+
|
28
|
+
tr.alert-notes
|
29
|
+
td(colspan=8)= simple_format alert.notes
|
@@ -7,7 +7,7 @@
|
|
7
7
|
as: :grouped_select,
|
8
8
|
group_method: :wards,
|
9
9
|
collection: Renalware::Hospitals::Unit.includes(:wards).ordered,
|
10
|
-
label_method:
|
10
|
+
label_method: ->(ward){ [ward.name, ward.code].compact.join(" - ") },
|
11
11
|
wrapper: :horizontal_medium
|
12
12
|
= f.input :hotlist, wrapper: :horizontal_small, as: :inline_radio_buttons
|
13
13
|
= f.input :max_cre, wrapper: :horizontal_small
|
@@ -1,4 +1,14 @@
|
|
1
|
+
= content_for(:actions) do
|
2
|
+
/ Make sure when generating the PDF we pass in exactly the same params eg q and named_filter
|
3
|
+
/ An alternative to what we have used here is to use
|
4
|
+
/ url_for(request.filtered_parameters&.merge({format: :pdf})
|
5
|
+
/ however this seems to loose the ransack sort option in params[:q][:s]
|
6
|
+
= link_to(renal_filtered_aki_alerts_path(q: params[:q]&.permit!, format: :pdf), class: "button secondary") do
|
7
|
+
i.fa.fa-print
|
8
|
+
| Print (PDF)
|
9
|
+
|
1
10
|
= within_admin_layout(title: "AKI Alerts") do
|
11
|
+
= render "renalware/shared/please_print_using_print_button_warning"
|
2
12
|
= render "filters", form: form, path_params: path_params
|
3
13
|
= render "table", alerts: alerts, search: search
|
4
14
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
- content_for(:head) do
|
2
|
+
= wicked_pdf_stylesheet_link_tag "renalware/table_pdf"
|
3
|
+
|
4
|
+
.pdf
|
5
|
+
.header
|
6
|
+
h1 AKI Alerts
|
7
|
+
- if params[:named_filter].present?
|
8
|
+
h1.muted
|
9
|
+
| /
|
10
|
+
= params[:named_filter]&.humanize
|
11
|
+
h2.muted= I18n.l(Time.zone.today)
|
12
|
+
= render "filters"
|
13
|
+
= render "table", alerts: alerts
|
14
|
+
|