renalware-core 2.0.0.pre.rc6 → 2.0.0.pre.rc7
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/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
|