renalware-core 2.0.0.pre.rc6 → 2.0.0.pre.rc7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/app/controllers/renalware/events/investigations_controller.rb +10 -0
- data/app/controllers/renalware/transplants/donor_dashboards_controller.rb +1 -7
- data/app/controllers/renalware/transplants/recipient_dashboards_controller.rb +1 -21
- data/app/models/renalware/events/investigation.rb +31 -0
- data/app/models/renalware/feeds/hl7_message.rb +29 -34
- data/app/models/renalware/feeds/message_parser.rb +2 -1
- data/app/models/renalware/pathology/create_observation_requests.rb +25 -0
- data/app/models/renalware/pathology/message_listener.rb +7 -5
- data/app/models/renalware/pathology/{message_param_parser.rb → observation_requests_attributes_builder.rb} +31 -27
- data/app/models/renalware/patients/practice_search_query.rb +1 -1
- data/app/policies/renalware/events/investigation_policy.rb +8 -0
- data/app/presenters/renalware/pathology/observation_presenter.rb +1 -1
- data/app/presenters/renalware/transplants/consent_presenter.rb +1 -1
- data/app/presenters/renalware/transplants/donor_dashboard_presenter.rb +35 -0
- data/app/presenters/renalware/transplants/mdm_presenter.rb +2 -0
- data/app/presenters/renalware/transplants/patient_presenter.rb +2 -0
- data/app/presenters/renalware/transplants/recipient_dashboard_presenter.rb +39 -0
- data/app/presenters/renalware/transplants/wait_list_registration_presenter.rb +2 -0
- data/app/views/renalware/api/ukrdc/patients/_documents.xml.builder +12 -9
- data/app/views/renalware/api/ukrdc/patients/_sending_facility.xml.builder +4 -4
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_lab_order.xml.builder +1 -1
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_result_item.xml.builder +1 -1
- data/app/views/renalware/api/ukrdc/patients/show.xml.builder +1 -5
- data/app/views/renalware/events/events/_event.html.slim +7 -1
- data/app/views/renalware/events/events/_table.html.slim +2 -1
- data/app/views/renalware/events/events/cell/_investigation.html.slim +9 -0
- data/app/views/renalware/events/events/inputs/_investigation.html.slim +4 -0
- data/app/views/renalware/events/events/toggled_cell/_investigation.html.slim +11 -0
- data/app/views/renalware/events/investigations/_list.html.slim +12 -0
- data/app/views/renalware/events/investigations/edit.html.slim +13 -0
- data/app/views/renalware/transplants/donor_dashboards/show.html.slim +27 -20
- data/app/views/renalware/transplants/recipient_dashboards/_page_actions.html.slim +4 -0
- data/app/views/renalware/transplants/recipient_dashboards/show.html.slim +22 -17
- data/config/locales/renalware/events/investigation.en.yml +58 -0
- data/config/locales/renalware/transplants/donor_dashboard.en.yml +1 -0
- data/config/locales/renalware/transplants/recipient_dashboards.en.yml +1 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20180119121243_create_trigger_to_preprocess_hl7_msg.rb +5 -3
- data/db/migrate/20180125201356_make_obs_set_trigger_change_updated_at.rb +191 -0
- data/db/migrate/20180126142314_add_uuid_to_letters.rb +6 -0
- data/db/seeds/default/events/event_types.csv +1 -0
- data/lib/renalware/configuration.rb +1 -0
- data/lib/renalware/version.rb +1 -1
- data/lib/test_support/text_editor_helpers.rb +6 -0
- data/spec/factories/events/events.rb +24 -1
- data/spec/factories/events/events_types.rb +17 -2
- data/spec/support/database_functions_spec_helper.rb +6 -0
- metadata +18 -4
- data/app/models/renalware/pathology/create_observations.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe0192f8e977702f2adbf2a0f2893b3552b9e6bd573f721208e0250e03e03312
|
4
|
+
data.tar.gz: 87a77ba05e6a2dfb83cddbdb4d1d2de1bfe19aaf2c50515e57677db00588f7d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f6ef5e4f2f0fc65a67b0d6cb9c649685ec7ed98db4b0129a1ffb5f96d566e6a283f1fd436cff669188cd34778561b696f2a68c86b9d539790131110b6705e00
|
7
|
+
data.tar.gz: e61ff85f88683a31976a64dc74dfd65be9250168c7de67225c73db358591b387cef1f8add0ddb9bbf08cb6ade2becdbcc8e4f142de7c6893f4bde1c412dd027d
|
data/README.md
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
require_dependency "renalware/events"
|
2
|
+
|
3
|
+
# This controller is mostly empty - we are using it for mainly routing and to let us
|
4
|
+
# override the events 'new' and 'edit' templates. See the base class for most functionality.
|
5
|
+
module Renalware
|
6
|
+
module Events
|
7
|
+
class InvestigationsController < EventsController
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -6,13 +6,7 @@ module Renalware
|
|
6
6
|
before_action :load_patient
|
7
7
|
|
8
8
|
def show
|
9
|
-
render locals: {
|
10
|
-
patient: patient,
|
11
|
-
donations: Donation.for_patient(patient).reversed,
|
12
|
-
donor_workup: DonorWorkup.for_patient(patient).first_or_initialize,
|
13
|
-
donor_operations: DonorOperation.for_patient(patient).reversed,
|
14
|
-
donor_stages: DonorStage.for_patient(patient).ordered
|
15
|
-
}
|
9
|
+
render locals: { dashboard: DonorDashboardPresenter.new(patient) }
|
16
10
|
end
|
17
11
|
end
|
18
12
|
end
|
@@ -5,27 +5,7 @@ module Renalware
|
|
5
5
|
class RecipientDashboardsController < BaseController
|
6
6
|
def show
|
7
7
|
authorize patient
|
8
|
-
render locals:
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def locals
|
14
|
-
{
|
15
|
-
patient: patient,
|
16
|
-
recipient_workup: RecipientWorkup.for_patient(patient).first_or_initialize,
|
17
|
-
registration: registration_presenter,
|
18
|
-
recipient_operations: RecipientOperation.for_patient(patient).reversed,
|
19
|
-
donations: Donation.for_recipient(patient).reversed
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
def registration_presenter
|
24
|
-
WaitListRegistrationPresenter.new(registration)
|
25
|
-
end
|
26
|
-
|
27
|
-
def registration
|
28
|
-
Registration.for_patient(patient).first_or_initialize
|
8
|
+
render locals: { dashboard: RecipientDashboardPresenter.new(patient) }
|
29
9
|
end
|
30
10
|
end
|
31
11
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_dependency "renalware/events"
|
2
|
+
require "document/base"
|
3
|
+
require "document/embedded"
|
4
|
+
require "document/enum"
|
5
|
+
|
6
|
+
module Renalware
|
7
|
+
module Events
|
8
|
+
class Investigation < Event
|
9
|
+
include Document::Base
|
10
|
+
|
11
|
+
scope :transplant_donors, lambda{
|
12
|
+
where("document ->> 'modality' = ?", "transplant_donor")
|
13
|
+
}
|
14
|
+
scope :transplant_recipients, lambda{
|
15
|
+
where("document ->> 'modality' = ?", "transplant_recipient")
|
16
|
+
}
|
17
|
+
|
18
|
+
class Document < Document::Embedded
|
19
|
+
attribute :modality,
|
20
|
+
::Document::Enum,
|
21
|
+
enums: %i(transplant_donor transplant_recipient other)
|
22
|
+
attribute :type, ::Document::Enum # See i18n for options
|
23
|
+
attribute :result, String
|
24
|
+
validates :modality, presence: true
|
25
|
+
validates :type, presence: true
|
26
|
+
validates :result, presence: true
|
27
|
+
end
|
28
|
+
has_document
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -15,8 +15,9 @@ module Renalware
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class ObservationRequest < SimpleDelegator
|
18
|
-
|
19
|
-
|
18
|
+
alias_attribute :date_time, :observation_date
|
19
|
+
|
20
|
+
def initialize(observation_request_segment)
|
20
21
|
super(observation_request_segment)
|
21
22
|
end
|
22
23
|
|
@@ -24,8 +25,14 @@ module Renalware
|
|
24
25
|
universal_service_id.split("^").first
|
25
26
|
end
|
26
27
|
|
28
|
+
# Select only OBX children. OBR can have other types of child
|
29
|
+
# segments but we want to ignore those.
|
27
30
|
def observations
|
28
|
-
|
31
|
+
@observations ||= begin
|
32
|
+
children
|
33
|
+
.select{ |segment| segment.is_a? HL7::Message::Segment::OBX }
|
34
|
+
.map{ |obx_segment| Observation.new(obx_segment) }
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
def ordering_provider_name
|
@@ -36,10 +43,6 @@ module Renalware
|
|
36
43
|
super.split("^").first
|
37
44
|
end
|
38
45
|
|
39
|
-
def date_time
|
40
|
-
observation_date
|
41
|
-
end
|
42
|
-
|
43
46
|
private
|
44
47
|
|
45
48
|
def ordering_provider
|
@@ -48,6 +51,9 @@ module Renalware
|
|
48
51
|
end
|
49
52
|
|
50
53
|
class Observation < SimpleDelegator
|
54
|
+
alias_attribute :date_time, :observation_date
|
55
|
+
alias_attribute :value, :observation_value
|
56
|
+
|
51
57
|
def identifier
|
52
58
|
observation_id.split("^").first
|
53
59
|
end
|
@@ -57,14 +63,6 @@ module Renalware
|
|
57
63
|
""
|
58
64
|
end
|
59
65
|
|
60
|
-
def date_time
|
61
|
-
observation_date
|
62
|
-
end
|
63
|
-
|
64
|
-
def value
|
65
|
-
observation_value
|
66
|
-
end
|
67
|
-
|
68
66
|
# Because some units of measurement, such as 10^12/L for WBC, contain a caret, the caret
|
69
67
|
# will initially have been encoded by Mirth as \S\ (a Mirth escape sequence for ^
|
70
68
|
# or whatever the mirth component separator character is configured to be)
|
@@ -72,28 +70,33 @@ module Renalware
|
|
72
70
|
# the `\12` within the message is interpreted as a `\n` (form feed) by
|
73
71
|
# delayed_job when it is read into the yaml format string in the HL7 messages.
|
74
72
|
# While it might be possible to write out yaml into delayed_job using a format
|
75
|
-
# that will not un-escape on reading, the approach here is that the
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
73
|
+
# that will not un-escape on reading, the approach here is that the we have preprocessed
|
74
|
+
# the message using a trigger (at the point it is inserted into delayed_jobs) by
|
75
|
+
# replacing any instance of \S\ with \\S\\ in the message.
|
76
|
+
# Thus the raw data for units in the database will look like `10\\S\\12/L`.
|
77
|
+
# When ever this string is loaded by Ruby it will un-escaped and become "\S\"
|
78
|
+
# No `\12` is not found and un-escaped to \n"
|
79
|
+
# Note in the gsub here we double escape the \'s
|
79
80
|
def units
|
80
81
|
super&.gsub("\\S\\", "^")
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
84
|
-
|
85
|
-
|
85
|
+
# There is a problem here is there are < 1 OBR
|
86
|
+
# i.e. self[:OBR] could be an array
|
87
|
+
def observation_requests
|
88
|
+
Array(self[:OBR]).map{ |obr| ObservationRequest.new(obr) }
|
86
89
|
end
|
87
90
|
|
88
91
|
class PatientIdentification < SimpleDelegator
|
92
|
+
alias_attribute :external_id, :patient_id
|
93
|
+
alias_attribute :sex, :admin_sex
|
94
|
+
alias_attribute :dob, :patient_dob
|
95
|
+
|
89
96
|
def internal_id
|
90
97
|
patient_id_list.split("^").first
|
91
98
|
end
|
92
99
|
|
93
|
-
def external_id
|
94
|
-
patient_id
|
95
|
-
end
|
96
|
-
|
97
100
|
def name
|
98
101
|
Name.new(patient_name)
|
99
102
|
end
|
@@ -106,14 +109,6 @@ module Renalware
|
|
106
109
|
patient_name[1]
|
107
110
|
end
|
108
111
|
|
109
|
-
def sex
|
110
|
-
admin_sex
|
111
|
-
end
|
112
|
-
|
113
|
-
def dob
|
114
|
-
patient_dob
|
115
|
-
end
|
116
|
-
|
117
112
|
private
|
118
113
|
|
119
114
|
def patient_name
|
@@ -134,7 +129,7 @@ module Renalware
|
|
134
129
|
end
|
135
130
|
|
136
131
|
def to_s
|
137
|
-
@message_string
|
132
|
+
@message_string.tr("\r", "\n")
|
138
133
|
end
|
139
134
|
end
|
140
135
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_dependency "renalware/pathology"
|
2
|
+
|
3
|
+
#
|
4
|
+
# Create pathology observations requests and their child observations for an existing
|
5
|
+
# patient from HL7 message content.
|
6
|
+
#
|
7
|
+
module Renalware
|
8
|
+
module Pathology
|
9
|
+
class CreateObservationRequests
|
10
|
+
def call(params)
|
11
|
+
Array(params).each do |request|
|
12
|
+
patient = find_patient(request.fetch(:patient_id))
|
13
|
+
observation_params = request.fetch(:observation_request)
|
14
|
+
patient.observation_requests.create!(observation_params)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def find_patient(id)
|
21
|
+
::Renalware::Pathology::Patient.find_by(id: id) || NullObject.instance
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -9,19 +9,21 @@ module Renalware
|
|
9
9
|
class MessageListener
|
10
10
|
def message_processed(message_payload)
|
11
11
|
pathology_params = parse_pathology_params(message_payload)
|
12
|
-
|
13
|
-
#
|
12
|
+
create_observation_requests_and_their_child_observations_from(pathology_params)
|
13
|
+
#
|
14
|
+
# Note: The the current_observation_set for the patient is updated by a trigger here
|
15
|
+
#
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
17
19
|
|
18
20
|
def parse_pathology_params(message_payload)
|
19
|
-
|
21
|
+
ObservationRequestsAttributesBuilder.new(message_payload).parse
|
20
22
|
end
|
21
23
|
|
22
|
-
def
|
24
|
+
def create_observation_requests_and_their_child_observations_from(pathology_params)
|
23
25
|
return if pathology_params.nil? # eg patient does not exist
|
24
|
-
|
26
|
+
CreateObservationRequests.new.call(pathology_params)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -4,12 +4,14 @@ module Renalware
|
|
4
4
|
module Pathology
|
5
5
|
# Responsible for transforming an HL7 message payload into a params hash
|
6
6
|
# that can be persisted by ObservationRequest.
|
7
|
-
#
|
8
|
-
|
9
|
-
|
7
|
+
# Note:
|
8
|
+
# - A message can have multiple observation_requests, each with its own observations.
|
9
|
+
# - This class could be removed and a Builder class used to create the database models
|
10
|
+
# directly - this would remove the extra level of indirection that this class introduces.
|
11
|
+
class ObservationRequestsAttributesBuilder
|
12
|
+
delegate :patient_identification, :observation_requests, to: :message_payload
|
10
13
|
delegate :internal_id, to: :patient_identification
|
11
|
-
|
12
|
-
alias_attribute :request, :observation_request
|
14
|
+
alias_attribute :requests, :observation_requests
|
13
15
|
|
14
16
|
# message_payload is an HL7Message (a decorator around an ::HL7::Message)
|
15
17
|
def initialize(message_payload, logger = Delayed::Worker.logger)
|
@@ -17,6 +19,9 @@ module Renalware
|
|
17
19
|
@logger = logger
|
18
20
|
end
|
19
21
|
|
22
|
+
# Return an array of observation request attributes (with a nested array of
|
23
|
+
# child observation attributes) for each OBR in the HL7 message.
|
24
|
+
# The resulting array will be used to create the corresponding database records.
|
20
25
|
def parse
|
21
26
|
if renalware_patient?
|
22
27
|
build_patient_params
|
@@ -34,32 +39,38 @@ module Renalware
|
|
34
39
|
|
35
40
|
attr_reader :message_payload, :logger
|
36
41
|
|
37
|
-
def
|
38
|
-
|
42
|
+
def build_patient_params
|
43
|
+
patient = find_patient(internal_id)
|
44
|
+
request_params.each do |request_param|
|
45
|
+
request_param[:patient_id] = patient.id
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
def request_params
|
42
50
|
@request_params ||= build_observation_request_params
|
43
51
|
end
|
44
52
|
|
53
|
+
# rubocop:disable Metrics/MethodLength
|
45
54
|
def build_observation_request_params
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
requests.each_with_object([]) do |request, arr|
|
56
|
+
request_description = find_request_description(request.identifier)
|
57
|
+
hash = {
|
58
|
+
observation_request: {
|
59
|
+
description_id: request_description.id,
|
60
|
+
requestor_name: request.ordering_provider_name,
|
61
|
+
requestor_order_number: request.placer_order_number,
|
62
|
+
requested_at: parse_time(request.date_time),
|
63
|
+
observations_attributes: build_observations_params(request)
|
64
|
+
}
|
55
65
|
}
|
56
|
-
|
66
|
+
arr << hash
|
67
|
+
end
|
57
68
|
end
|
69
|
+
# rubocop:enable Metrics/MethodLength
|
58
70
|
|
59
|
-
def build_observations_params
|
60
|
-
observations.map do |observation|
|
71
|
+
def build_observations_params(request)
|
72
|
+
request.observations.map do |observation|
|
61
73
|
observation_description = find_observation_description(observation.identifier)
|
62
|
-
|
63
74
|
{
|
64
75
|
description_id: observation_description.id,
|
65
76
|
observed_at: parse_time(observation.date_time),
|
@@ -69,13 +80,6 @@ module Renalware
|
|
69
80
|
end
|
70
81
|
end
|
71
82
|
|
72
|
-
def build_patient_params
|
73
|
-
request_params.tap do |p|
|
74
|
-
patient = find_patient(internal_id)
|
75
|
-
p[:patient_id] = patient.id
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
83
|
def find_request_description(code)
|
80
84
|
RequestDescription.find_by!(code: code)
|
81
85
|
end
|
@@ -12,7 +12,7 @@ module Renalware
|
|
12
12
|
|
13
13
|
term = "%#{search_term}%"
|
14
14
|
Practice.select(:id, :name)
|
15
|
-
.
|
15
|
+
.left_outer_joins(:address)
|
16
16
|
.where("patient_practices.name ILIKE ? OR addresses.postcode ILIKE ?", term, term)
|
17
17
|
# .select("patient_practices.id", "patient_practices.name")
|
18
18
|
end
|
@@ -3,7 +3,7 @@ require_dependency "renalware/pathology"
|
|
3
3
|
module Renalware
|
4
4
|
module Pathology
|
5
5
|
class ObservationPresenter < SimpleDelegator
|
6
|
-
delegate :name, :code, to: :description, prefix: true, allow_nil: true
|
6
|
+
delegate :name, :code, :loinc_code, to: :description, prefix: true, allow_nil: true
|
7
7
|
delegate :measurement_unit, to: :description
|
8
8
|
delegate :name, to: :measurement_unit, prefix: true
|
9
9
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_dependency "renalware/transplants"
|
2
|
+
require "attr_extras"
|
3
|
+
|
4
|
+
module Renalware
|
5
|
+
module Transplants
|
6
|
+
class DonorDashboardPresenter
|
7
|
+
attr_reader_initialize :patient
|
8
|
+
|
9
|
+
def donor_stages
|
10
|
+
@donor_stages ||= DonorStage.for_patient(patient).ordered
|
11
|
+
end
|
12
|
+
|
13
|
+
def donor_workup
|
14
|
+
@donor_workups ||= DonorWorkup.for_patient(patient).first_or_initialize
|
15
|
+
end
|
16
|
+
|
17
|
+
def donations
|
18
|
+
@donations ||= Donation.for_patient(patient).reversed
|
19
|
+
end
|
20
|
+
|
21
|
+
def donor_operations
|
22
|
+
@donor_operations ||= DonorOperation.for_patient(patient).reversed
|
23
|
+
end
|
24
|
+
|
25
|
+
def investigations
|
26
|
+
@investigations ||= begin
|
27
|
+
Events::Investigation
|
28
|
+
.for_patient(patient)
|
29
|
+
.transplant_donors
|
30
|
+
.ordered
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|