renalware-core 2.0.111 → 2.0.112
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +9 -0
- data/app/assets/javascripts/renalware/application.js.erb +7 -8
- data/app/assets/javascripts/renalware/charting/charting.js.erb +4 -0
- data/app/assets/javascripts/renalware/dialogs.js.erb +0 -11
- data/app/assets/javascripts/renalware/hd.js +59 -9
- data/app/assets/stylesheets/renalware/application.scss +2 -3
- data/app/assets/stylesheets/renalware/modules/_hd.scss +19 -0
- data/app/assets/stylesheets/renalware/modules/_patients.scss +7 -0
- data/app/assets/stylesheets/renalware/print/pathology_request_forms.scss +26 -0
- data/app/assets/stylesheets/renalware/protocol_pdf.scss +9 -4
- data/app/controllers/renalware/hd/mdm_patients_controller.rb +17 -6
- data/app/controllers/renalware/hd/protocols_controller.rb +22 -31
- data/app/controllers/renalware/hd/session_forms/batches_controller.rb +82 -0
- data/app/controllers/renalware/pathology/requests/requests_controller.rb +20 -6
- data/app/controllers/renalware/surveys/dashboards_controller.rb +24 -0
- data/app/jobs/renalware/hd/session_forms/batch_print_job.rb +40 -0
- data/app/models/concerns/renalware/pdf_compilation.rb +60 -0
- data/app/models/renalware/clinical/allergy_status_form.rb +1 -1
- data/app/models/renalware/clinical/delete_allergy.rb +1 -1
- data/app/models/renalware/clinics/appointment_query.rb +1 -5
- data/app/models/renalware/hd.rb +6 -0
- data/app/models/renalware/hd/patient_listener.rb +1 -1
- data/app/models/renalware/hd/session_forms/batch.rb +26 -0
- data/app/models/renalware/hd/session_forms/batch_compile_pdfs.rb +86 -0
- data/app/models/renalware/hd/session_forms/batch_item.rb +15 -0
- data/app/models/renalware/hd/session_forms/form.rb +16 -0
- data/app/models/renalware/hd/session_forms/pdf_renderer.rb +74 -0
- data/app/models/renalware/letters/batch.rb +2 -0
- data/app/models/renalware/letters/printing/batch_compile_pdfs.rb +0 -3
- data/app/models/renalware/medications/patient_listener.rb +1 -1
- data/app/models/renalware/pathology/ordered_patient_query.rb +1 -1
- data/app/models/renalware/pathology/request_for_patient_request_description_query.rb +1 -1
- data/app/models/renalware/pd/apd/non_tidal_regime_calculations.rb +1 -1
- data/app/models/renalware/pd/apd/tidal_regime_calculations.rb +1 -1
- data/app/models/renalware/snippets/snippet_query.rb +1 -1
- data/app/models/renalware/surveys.rb +9 -0
- data/app/models/renalware/surveys/eq5d_pivoted_response.rb +11 -0
- data/app/models/renalware/surveys/eq5d_summary_part.rb +51 -0
- data/app/models/renalware/surveys/pos_s_pivoted_response.rb +11 -0
- data/app/models/renalware/surveys/pos_s_summary_part.rb +51 -0
- data/app/models/renalware/surveys/question.rb +22 -0
- data/app/models/renalware/surveys/response.rb +28 -0
- data/app/models/renalware/surveys/survey.rb +17 -0
- data/app/models/renalware/ukrdc.rb +3 -0
- data/app/models/renalware/ukrdc/incoming/file_list.rb +21 -0
- data/app/models/renalware/ukrdc/incoming/import_survey.rb +57 -0
- data/app/models/renalware/ukrdc/incoming/import_surveys.rb +77 -0
- data/app/models/renalware/ukrdc/incoming/paths.rb +30 -0
- data/app/models/renalware/ukrdc/incoming/xml_document.rb +68 -0
- data/app/models/renalware/ukrdc/transmission_log.rb +14 -3
- data/app/policies/renalware/hd/session_forms/batch_policy.rb +13 -0
- data/app/policies/renalware/surveys/survey_policy.rb +10 -0
- data/app/presenters/renalware/hd/session_presenter.rb +1 -1
- data/app/views/renalware/clinics/appointments/index.html.slim +22 -11
- data/app/views/renalware/hd/dashboards/_page_actions.html.slim +1 -1
- data/app/views/renalware/hd/diary_slots/_form.html.slim +0 -3
- data/app/views/renalware/hd/mdm_patients/_filters.html.slim +11 -0
- data/app/views/renalware/hd/mdm_patients/_page_actions.html.slim +0 -0
- data/app/views/renalware/hd/mdm_patients/index.html.slim +9 -1
- data/app/views/renalware/hd/protocols/{show.pdf.slim → _protocol.pdf.slim} +1 -7
- data/app/views/renalware/hd/protocols/index.pdf.slim +4 -0
- data/app/views/renalware/hd/session_forms/batches/_create.html.slim +25 -0
- data/app/views/renalware/hd/session_forms/batches/create.js.erb +3 -0
- data/app/views/renalware/hd/sessions/_row.html.slim +1 -1
- data/app/views/renalware/hd/sessions/_thead.html.slim +1 -1
- data/app/views/renalware/pathology/historical_observation_results/_table.html.slim +1 -1
- data/app/views/renalware/pathology/recent_observation_results/_table.html.slim +1 -1
- data/app/views/renalware/pathology/requests/requests/create.pdf.slim +2 -1
- data/app/views/renalware/pathology/requests/requests/new.html.slim +18 -13
- data/app/views/renalware/pathology/requests/requests/request_form/_crs.pdf.slim +1 -0
- data/app/views/renalware/pathology/requests/requests/request_form/_crs_form.html.slim +46 -45
- data/app/views/renalware/pathology/requests/requests/request_form/_manual_form_global.html.slim +9 -8
- data/app/views/renalware/pathology/requests/requests/request_form/_manual_form_patient.html.slim +9 -8
- data/app/views/renalware/pathology/requests/requests/show.pdf.slim +2 -1
- data/app/views/renalware/patients/side_menu/_general.html.slim +4 -0
- data/app/views/renalware/surveys/_eq5d_summary_part.html.slim +26 -0
- data/app/views/renalware/surveys/_pos_s_summary_part.html.slim +26 -0
- data/app/views/renalware/surveys/dashboards/show.html.slim +32 -0
- data/config/initializers/chartkick.rb +6 -0
- data/config/initializers/core_extensions.rb +4 -4
- data/config/initializers/inflections.rb +3 -0
- data/config/locales/renalware/patients/side_menu.en.yml +1 -0
- data/config/routes/hd.rb +5 -1
- data/config/routes/patients.rb +4 -0
- data/db/migrate/20190927124840_create_hd_session_form_batches.rb +16 -0
- data/db/migrate/20190927130911_create_hd_session_form_batch_items.rb +17 -0
- data/db/migrate/20191008010839_create_surveys.rb +70 -0
- data/db/migrate/20191008024636_create_eq5d_views.rb +8 -0
- data/db/migrate/20191008030154_add_validation_regex_to_patient_survey_questions.rb +7 -0
- data/db/migrate/20191008045159_allow_null_patient_in_ukrdc_transmission_logs.rb +8 -0
- data/db/seeds/default/patients/seeds.rb +2 -0
- data/db/seeds/default/patients/surveys/eq5d_5l.rb +22 -0
- data/db/seeds/default/patients/surveys/eq5d_5l_questions.csv +7 -0
- data/db/seeds/default/patients/surveys/pos_s.rb +22 -0
- data/db/seeds/default/patients/surveys/pos_s_questions.csv +23 -0
- data/db/views/survey_eq5d_pivoted_responses_v01.sql +41 -0
- data/db/views/survey_pos_s_pivoted_responses_v01.sql +36 -0
- data/lib/core_extensions/active_record/migration_helpers.rb +1 -1
- data/lib/core_extensions/active_support/duration.rb +1 -1
- data/lib/core_extensions/scenic.rb +1 -1
- data/lib/renalware/engine.rb +4 -4
- data/lib/renalware/version.rb +1 -1
- data/lib/tasks/ukrdc.rake +9 -0
- data/spec/factories/patients/surveys.rb +24 -0
- data/spec/support/ukrdc_helpers.rb +16 -0
- metadata +98 -59
- data/app/views/renalware/letters/batches/show.html.slim +0 -7
- data/app/views/renalware/pathology/requests/requests/_pdf_header.html.slim +0 -13
- data/vendor/assets/javascripts/renalware/masonry.min.js +0 -9
- data/vendor/assets/javascripts/renalware/print.min.js +0 -1
- data/vendor/assets/stylesheets/renalware/balloon.css +0 -383
- data/vendor/assets/stylesheets/renalware/print.min.css +0 -1
- data/vendor/assets/stylesheets/renalware/select2/css/select2.css +0 -431
- data/vendor/assets/stylesheets/renalware/select2/css/select2.min.css +0 -1
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "attr_extras"
|
4
|
+
require_dependency "renalware/hd"
|
5
|
+
|
6
|
+
module Renalware
|
7
|
+
module HD
|
8
|
+
module SessionForms
|
9
|
+
class BatchItem < ApplicationRecord
|
10
|
+
belongs_to :batch, counter_cache: true
|
11
|
+
enum status: { queued: 0, compiled: 10 }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module HD
|
7
|
+
module SessionForms
|
8
|
+
class Form
|
9
|
+
include ActiveModel::Model
|
10
|
+
include Virtus::Model
|
11
|
+
|
12
|
+
attribute :patient_ids, String
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renalware
|
4
|
+
module HD
|
5
|
+
module SessionForms
|
6
|
+
# Renders 1 or more HD Protocols (Session Forms) to PDF. If > 1 patient
|
7
|
+
class PdfRenderer
|
8
|
+
def initialize(patients:, output_html_for_debugging: false)
|
9
|
+
@patients = Array(patients)
|
10
|
+
@output_html_for_debugging = output_html_for_debugging
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
return pdf_html if output_html_for_debugging?
|
15
|
+
|
16
|
+
WickedPdf.new.pdf_from_string(pdf_html, pdf_options)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :patients, :output_html_for_debugging
|
22
|
+
|
23
|
+
def pdf_html
|
24
|
+
@pdf_html ||= begin
|
25
|
+
# Note we don't actually hit the ProtocolController#index action here.
|
26
|
+
controller.render_to_string(
|
27
|
+
template: "renalware/hd/protocols/index",
|
28
|
+
layout: "renalware/layouts/pdf",
|
29
|
+
locals: {
|
30
|
+
protocols: protocols_to_render,
|
31
|
+
host: "localhost"
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def controller
|
38
|
+
@controller ||= MyController.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def protocols_to_render
|
42
|
+
patients.map { |pat| ProtocolPresenter.new(pat, controller.view_context) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def pdf_options
|
46
|
+
{
|
47
|
+
page_size: "A4",
|
48
|
+
orientation: "Landscape",
|
49
|
+
layout: "renalware/layouts/pdf",
|
50
|
+
print_media_type: true,
|
51
|
+
margin: { top: 10, bottom: 10, left: 10, right: 10 },
|
52
|
+
footer: {
|
53
|
+
font_size: 8
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def output_html_for_debugging?
|
59
|
+
output_html_for_debugging == true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Local ProtocolsController controller used for 'rendering anywhere'.
|
63
|
+
# Using ProtocolsController here m,ainly to benefit from the view paths associated with it.
|
64
|
+
class MyController < ProtocolsController
|
65
|
+
def url_options
|
66
|
+
{
|
67
|
+
host: ENV.fetch("HOST", "localhost")
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -10,9 +10,6 @@ module Renalware
|
|
10
10
|
# - compiles each letter along with its recipient cover sheets
|
11
11
|
# - adds blank pages to make sure the letter always starts on an odd page
|
12
12
|
# - appends all PDF letters
|
13
|
-
# 2-page documents (from the contents of the /2 folder)
|
14
|
-
# - moves these compiled PDFs to a network share.
|
15
|
-
# - removes the temp folder structure - auto
|
16
13
|
class BatchCompilePdfs
|
17
14
|
include PdfCombining
|
18
15
|
PAGE_COUNTS = %w(2 3 4 5 6 7 8 9 10).freeze
|
@@ -5,7 +5,7 @@ require_dependency "renalware/medications"
|
|
5
5
|
module Renalware
|
6
6
|
module Medications
|
7
7
|
class PatientListener
|
8
|
-
def patient_modality_changed_to_death(patient:,
|
8
|
+
def patient_modality_changed_to_death(patient:, actor:, **)
|
9
9
|
TerminateAllPatientPrescriptions.call(patient: patient, by: actor)
|
10
10
|
end
|
11
11
|
end
|
@@ -26,7 +26,7 @@ module Renalware
|
|
26
26
|
def volume_calculable?
|
27
27
|
raise ArgumentError, "Tidal indicator not set" unless tidal?
|
28
28
|
|
29
|
-
fill_volume.to_i
|
29
|
+
fill_volume.to_i.positive? && cycles.to_i.positive? && tidal_percentage.to_i.positive?
|
30
30
|
end
|
31
31
|
|
32
32
|
def volume_when_1st_and_then_every_3rd_exchange_is_full_and_the_remainder_are_tidal
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/surveys"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Surveys
|
7
|
+
class EQ5DSummaryPart < Renalware::SummaryPart
|
8
|
+
def rows
|
9
|
+
@rows ||= EQ5DPivotedResponse.where(patient_id: patient.id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def question_labels
|
13
|
+
survey
|
14
|
+
.questions
|
15
|
+
.order(:position)
|
16
|
+
.select(:code, :label)
|
17
|
+
.each_with_object({}) { |q, hash| hash[q.code] = q.label }
|
18
|
+
end
|
19
|
+
|
20
|
+
def data_for_question_code(_code)
|
21
|
+
Renalware::Surveys::Response
|
22
|
+
.where(patient_id: patient.id, question_id: 1)
|
23
|
+
.pluck(:answered_on, :value)
|
24
|
+
.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_headings
|
28
|
+
@column_headings ||= begin
|
29
|
+
headings = ["Date"]
|
30
|
+
|
31
|
+
headings.concat(
|
32
|
+
Renalware::Survey
|
33
|
+
.find_by!(code: "eq5d")
|
34
|
+
.questions
|
35
|
+
.order(:position)
|
36
|
+
.pluck(:label)
|
37
|
+
)
|
38
|
+
headings
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_partial_path
|
43
|
+
"renalware/surveys/eq5d_summary_part"
|
44
|
+
end
|
45
|
+
|
46
|
+
def survey
|
47
|
+
@survey ||= Renalware::Surveys::Survey.find_by!(code: "eq5d")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/surveys"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Surveys
|
7
|
+
class POSSSummaryPart < Renalware::SummaryPart
|
8
|
+
def rows
|
9
|
+
@rows ||= POSSPivotedResponse.where(patient_id: patient.id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def question_labels
|
13
|
+
survey
|
14
|
+
.questions
|
15
|
+
.order(:position)
|
16
|
+
.select(:code, :label)
|
17
|
+
.each_with_object({}) { |q, hash| hash[q.code] = q.label }
|
18
|
+
end
|
19
|
+
|
20
|
+
def data_for_question_code(_code)
|
21
|
+
Renalware::Surveys::Response
|
22
|
+
.where(patient_id: patient.id, question_id: 1)
|
23
|
+
.pluck(:answered_on, :value)
|
24
|
+
.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_headings
|
28
|
+
@column_headings ||= begin
|
29
|
+
headings = ["Date"]
|
30
|
+
|
31
|
+
headings.concat(
|
32
|
+
Renalware::Survey
|
33
|
+
.find_by!(code: "prom")
|
34
|
+
.questions
|
35
|
+
.order(:position)
|
36
|
+
.pluck(:label)
|
37
|
+
)
|
38
|
+
headings
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_partial_path
|
43
|
+
"renalware/surveys/pos_s_summary_part"
|
44
|
+
end
|
45
|
+
|
46
|
+
def survey
|
47
|
+
@survey ||= Renalware::Surveys::Survey.find_by!(code: "prom")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/surveys"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Surveys
|
7
|
+
class Question < ApplicationRecord
|
8
|
+
include PatientScope
|
9
|
+
acts_as_paranoid
|
10
|
+
belongs_to :survey
|
11
|
+
has_many(
|
12
|
+
:responses,
|
13
|
+
class_name: "Response",
|
14
|
+
dependent: :nullify,
|
15
|
+
foreign_key: :question_id
|
16
|
+
)
|
17
|
+
validates :code, presence: true, uniqueness: { scope: :survey_id }
|
18
|
+
validates :label, presence: true
|
19
|
+
validates :position, presence: true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/surveys"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Surveys
|
7
|
+
class Response < ApplicationRecord
|
8
|
+
belongs_to :question, class_name: "Question"
|
9
|
+
validates :patient_id, presence: true
|
10
|
+
validates :answered_on, presence: true
|
11
|
+
validates :question, presence: true
|
12
|
+
validate :value_is_in_range
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def value_is_in_range
|
17
|
+
return if question&.validation_regex.blank?
|
18
|
+
|
19
|
+
unless value =~ /#{question.validation_regex}/
|
20
|
+
errors.add(
|
21
|
+
:value,
|
22
|
+
"(#{value}) must comply to regular expression /#{question.validation_regex}/"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/surveys"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Surveys
|
7
|
+
class Survey < ApplicationRecord
|
8
|
+
acts_as_paranoid
|
9
|
+
has_many :questions, dependent: :destroy
|
10
|
+
validates :name, presence: true, uniqueness: true
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "attr_extras"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module UKRDC
|
7
|
+
module Incoming
|
8
|
+
class FileList
|
9
|
+
pattr_initialize [pattern: "*.xml", paths: Paths.new]
|
10
|
+
|
11
|
+
# Helper which yields each file in the incoming folder.
|
12
|
+
def each_file
|
13
|
+
Dir.glob(paths.incoming.join(pattern)).sort.each do |filepath|
|
14
|
+
filename = File.basename(filepath)
|
15
|
+
yield(Pathname(filepath), filename) if block_given?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
require "attr_extras"
|
5
|
+
|
6
|
+
module Renalware
|
7
|
+
module UKRDC
|
8
|
+
module Incoming
|
9
|
+
class ImportSurvey
|
10
|
+
pattr_initialize [:patient, :survey_hash]
|
11
|
+
|
12
|
+
def call
|
13
|
+
responses.each do |question_code, answer|
|
14
|
+
question = question_having_code(question_code)
|
15
|
+
|
16
|
+
Surveys::Response.create!(
|
17
|
+
patient_id: patient.id,
|
18
|
+
question: question,
|
19
|
+
value: answer,
|
20
|
+
answered_on: answered_on
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def responses
|
28
|
+
survey_hash[:responses]
|
29
|
+
end
|
30
|
+
|
31
|
+
def survey
|
32
|
+
@survey ||= begin
|
33
|
+
survey_code = survey_hash[:code].downcase
|
34
|
+
Surveys::Survey.includes(:questions).find_by!(code: survey_code)
|
35
|
+
end
|
36
|
+
rescue ActiveRecord::RecordNotFound
|
37
|
+
raise UKRDC::SurveyNotFoundError, "Survey with name #{survey_hash[:code]} not found"
|
38
|
+
end
|
39
|
+
|
40
|
+
def question_having_code(code)
|
41
|
+
survey.questions.detect { |q| q.code == code }.tap do |question|
|
42
|
+
if question.nil?
|
43
|
+
raise(
|
44
|
+
UKRDC::QuestionNotFoundError,
|
45
|
+
"Question with code #{code} not found in survey #{survey.name}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def answered_on
|
52
|
+
survey_hash[:time]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|