renalware-core 2.0.89 → 2.0.90
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/renalware/hd/profile_for_modality.rb +20 -0
- data/app/models/renalware/hd/profiles_in_date_range_query.rb +32 -0
- data/app/models/renalware/hd/revise_hd_profile.rb +3 -5
- data/app/models/renalware/modalities/description.rb +8 -0
- data/app/models/renalware/pd/regime_for_modality.rb +21 -0
- data/app/models/renalware/pd/regimes_in_date_range_query.rb +30 -0
- data/app/models/renalware/ukrdc/create_encrypted_patient_xml_files.rb +6 -1
- data/app/models/renalware/ukrdc/treatment.rb +5 -0
- data/app/models/renalware/ukrdc/treatment_timeline/generate_timeline.rb +13 -7
- data/app/models/renalware/ukrdc/treatment_timeline/generate_treatments.rb +9 -4
- data/app/models/renalware/ukrdc/treatment_timeline/generator_factory.rb +1 -1
- data/app/models/renalware/ukrdc/treatment_timeline/generic/generator.rb +45 -0
- data/app/models/renalware/ukrdc/treatment_timeline/hd/generator.rb +128 -0
- data/app/models/renalware/ukrdc/treatment_timeline/hd/modality_code_map.rb +29 -0
- data/app/models/renalware/ukrdc/treatment_timeline/hd/profile_decorator.rb +45 -0
- data/app/models/renalware/ukrdc/treatment_timeline/pd/generator.rb +119 -0
- data/app/models/renalware/ukrdc/treatment_timeline/pd/modality_code_map.rb +35 -0
- data/app/models/renalware/ukrdc/treatment_timeline/pd/regime_decorator.rb +37 -0
- data/app/models/renalware/ukrdc/treatment_timeline/prepare_tables.rb +1 -0
- data/app/presenters/renalware/hd/session_presenter.rb +6 -0
- data/app/presenters/renalware/ukrdc/patient_presenter.rb +17 -6
- data/app/views/renalware/api/ukrdc/patients/_medications.xml.builder +1 -8
- data/app/views/renalware/api/ukrdc/patients/_treatments.xml.builder +84 -45
- data/app/views/renalware/api/ukrdc/patients/procedures/_dialysis_session.xml.builder +1 -1
- data/app/views/renalware/api/ukrdc/patients/treatments/_generic.xml.builder +15 -0
- data/app/views/renalware/api/ukrdc/patients/treatments/_hd.xml.builder +30 -0
- data/app/views/renalware/api/ukrdc/patients/treatments/_pd.xml.builder +13 -0
- data/db/migrate/20190705083727_alter_ukrdc_treatments.rb +8 -0
- data/db/migrate/20190705105921_create_hd_profile_for_modalites.rb +7 -0
- data/db/migrate/20190709101610_create_pd_regime_for_modalities.rb +7 -0
- data/db/views/hd_profile_for_modalities_v01.sql +63 -0
- data/db/views/pd_regime_for_modalities_v01.sql +60 -0
- data/lib/renalware/version.rb +1 -1
- data/lib/tasks/ukrdc.rake +2 -1
- data/spec/factories/hd/profiles.rb +24 -0
- data/spec/factories/pd/pd_regimes.rb +8 -0
- data/spec/factories/ukrdc/modality_codes.rb +30 -0
- metadata +21 -9
- data/app/models/renalware/ukrdc/treatment_timeline/generators/deaths_timeline.rb +0 -17
- data/app/models/renalware/ukrdc/treatment_timeline/generators/generic_timeline.rb +0 -17
- data/app/models/renalware/ukrdc/treatment_timeline/generators/hd_timeline.rb +0 -145
- data/app/models/renalware/ukrdc/treatment_timeline/generators/low_clearance_timelinex.rb +0 -17
- data/app/models/renalware/ukrdc/treatment_timeline/generators/pd_timeline.rb +0 -18
- data/app/models/renalware/ukrdc/treatment_timeline/generators/transplants_donor_timeline.rb +0 -17
- data/app/models/renalware/ukrdc/treatment_timeline/generators/transplants_recipient_timeline.rb +0 -17
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module UKRDC
|
7
|
+
module TreatmentTimeline
|
8
|
+
module HD
|
9
|
+
class ModalityCodeMap
|
10
|
+
def code_for_profile(profile)
|
11
|
+
hd_type = profile&.hd_type
|
12
|
+
return default_code if hd_type.blank?
|
13
|
+
|
14
|
+
ukrr_name = case hd_type.to_s.downcase
|
15
|
+
when "hd" then "Haemodialysis"
|
16
|
+
when "hdf_pre", "hdf_post" then "Haemodiafiltration"
|
17
|
+
end
|
18
|
+
|
19
|
+
ModalityCode.find_by!(description: ukrr_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_code
|
23
|
+
ModalityCode.find_by!(description: "Haemodialysis")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
module Renalware
|
5
|
+
module UKRDC
|
6
|
+
module TreatmentTimeline
|
7
|
+
module HD
|
8
|
+
# Decorates an HD::Profile, adding methods that detect any changes significant enough
|
9
|
+
# to warrant generating a new UKRDC Treatment.
|
10
|
+
class ProfileDecorator < DumbDelegator
|
11
|
+
def initialize(profile, last_profile: nil)
|
12
|
+
@last_profile = last_profile
|
13
|
+
super(profile)
|
14
|
+
end
|
15
|
+
|
16
|
+
def hd_type
|
17
|
+
document.dialysis.hd_type
|
18
|
+
end
|
19
|
+
|
20
|
+
def changed?
|
21
|
+
return true if last_profile.blank?
|
22
|
+
|
23
|
+
hd_type_changed? || hospital_unit_changed?
|
24
|
+
end
|
25
|
+
|
26
|
+
def unchanged?
|
27
|
+
!changed?
|
28
|
+
end
|
29
|
+
|
30
|
+
def hd_type_changed?
|
31
|
+
last_profile.document.dialysis.hd_type != hd_type
|
32
|
+
end
|
33
|
+
|
34
|
+
def hospital_unit_changed?
|
35
|
+
last_profile.hospital_unit_id != hospital_unit_id
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :last_profile
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
require "attr_extras"
|
5
|
+
|
6
|
+
module Renalware
|
7
|
+
module UKRDC
|
8
|
+
module TreatmentTimeline
|
9
|
+
module PD
|
10
|
+
# Generates a set of treatments based on a PD modality.
|
11
|
+
#
|
12
|
+
# There will be an initial treatment triggered by the modality itself, and then
|
13
|
+
# a treatment for each significant change in the pd regime during the period of the
|
14
|
+
# modality (until it ends)
|
15
|
+
#
|
16
|
+
class Generator
|
17
|
+
pattr_initialize :modality
|
18
|
+
delegate :patient, to: :modality
|
19
|
+
|
20
|
+
def call
|
21
|
+
create_treatment_from_modality
|
22
|
+
create_treatments_within_modality
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_treatment_from_modality
|
28
|
+
create_treatment(
|
29
|
+
pd_regime_at_start_of_modality,
|
30
|
+
modality.started_on,
|
31
|
+
modality.ended_on
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Find the modality that was active on the day of the modality change
|
36
|
+
# The profile might have been added up to say 14 days later however so if there is none
|
37
|
+
# active on the day the modality was created, search up to 14 days ahead until we find
|
38
|
+
# one. Return nil if none found.
|
39
|
+
def pd_regime_at_start_of_modality
|
40
|
+
@pd_regime_at_start_of_modality ||= begin
|
41
|
+
pd_regime_id = Renalware::PD::RegimeForModality.find_by!(
|
42
|
+
modality_id: modality.id
|
43
|
+
)&.pd_regime_id
|
44
|
+
return if pd_regime_id.blank?
|
45
|
+
|
46
|
+
Renalware::PD::Regime.find(pd_regime_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Things that trigger a new Treatment for an PD patient
|
51
|
+
# - change of regime type eg from APD to CAPD
|
52
|
+
# - ?
|
53
|
+
# Loop through the patient's regimes and trigger a new treatment when these change
|
54
|
+
def create_treatments_within_modality
|
55
|
+
last_regime = pd_regime_at_start_of_modality
|
56
|
+
|
57
|
+
pd_regimes.each do |regime_|
|
58
|
+
regime = PD::RegimeDecorator.new(regime_, last_regime: last_regime)
|
59
|
+
create_treatment_from(regime) if last_regime.nil? || regime.changed?
|
60
|
+
last_regime = regime
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Note be sure not to include the regime at the start of the modality otherwise we could
|
65
|
+
# output this as a duplicate treatment
|
66
|
+
def pd_regimes
|
67
|
+
regimes = Renalware::PD::RegimesInDateRangeQuery.new(
|
68
|
+
patient: patient,
|
69
|
+
from: modality.started_on,
|
70
|
+
to: modality.ended_on
|
71
|
+
).call
|
72
|
+
regimes - Array(pd_regime_at_start_of_modality)
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_treatment_from(regime)
|
76
|
+
start_date = regime.present? ? regime.start_date : modality.started_on
|
77
|
+
end_date = regime.present? ? regime.end_date : modality.ended_on
|
78
|
+
|
79
|
+
create_treatment(regime, start_date, end_date)
|
80
|
+
end
|
81
|
+
|
82
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
83
|
+
def create_treatment(regime, start_date, end_date)
|
84
|
+
treatments << Treatment.create!(
|
85
|
+
patient: patient,
|
86
|
+
clinician: modality.created_by,
|
87
|
+
started_on: start_date,
|
88
|
+
ended_on: end_date,
|
89
|
+
modality_id: modality.id,
|
90
|
+
modality_description_id: modality.description_id,
|
91
|
+
modality_code: treatment_for_pd_regime(regime),
|
92
|
+
pd_regime_id: regime&.id
|
93
|
+
)
|
94
|
+
|
95
|
+
# Update the end date on the previous treatment - ie the one we just added is
|
96
|
+
# taking over as the currently active treatment
|
97
|
+
unless treatments.length <= 1
|
98
|
+
previous_treatment = treatments[treatments.length - 2]
|
99
|
+
previous_treatment.update!(ended_on: start_date)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
103
|
+
|
104
|
+
def treatments
|
105
|
+
@treatments ||= []
|
106
|
+
end
|
107
|
+
|
108
|
+
def treatment_for_pd_regime(regime)
|
109
|
+
ModalityCodeMap.new.code_for_pd_regime(regime)
|
110
|
+
end
|
111
|
+
|
112
|
+
def pd_patient
|
113
|
+
Renalware::PD.cast_patient(patient)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module UKRDC
|
7
|
+
module TreatmentTimeline
|
8
|
+
module PD
|
9
|
+
class ModalityCodeMap
|
10
|
+
def code_for_pd_regime(regime)
|
11
|
+
return default_code if regime.blank?
|
12
|
+
|
13
|
+
ukrr_name = if regime.treatment =~ /assisted/i
|
14
|
+
case regime.pd_type
|
15
|
+
when :apd then "Assisted APD"
|
16
|
+
when :capd then "Assisted CAPD"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
case regime.pd_type
|
20
|
+
when :apd then "APD"
|
21
|
+
when :capd then "CAPD"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ModalityCode.find_by!(description: ukrr_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_code
|
29
|
+
ModalityCode.find_by!(txt_code: 19)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/ukrdc"
|
4
|
+
require "attr_extras"
|
5
|
+
|
6
|
+
module Renalware
|
7
|
+
module UKRDC
|
8
|
+
module TreatmentTimeline
|
9
|
+
module PD
|
10
|
+
class RegimeDecorator < DumbDelegator
|
11
|
+
def initialize(regime, last_regime:)
|
12
|
+
@last_regime = last_regime
|
13
|
+
super(regime)
|
14
|
+
end
|
15
|
+
|
16
|
+
def changed?
|
17
|
+
return true if last_regime.blank?
|
18
|
+
|
19
|
+
regime_type_changed?
|
20
|
+
end
|
21
|
+
|
22
|
+
def regime_type_changed?
|
23
|
+
last_regime&.type != type
|
24
|
+
end
|
25
|
+
|
26
|
+
def unchanged?
|
27
|
+
!changed?
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :last_regime
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -13,6 +13,7 @@ module Renalware
|
|
13
13
|
# If the site has not defined the ukrdc_prepare_tables SQL function then we exit gracefully.
|
14
14
|
class PrepareTables
|
15
15
|
def self.call
|
16
|
+
Treatment.delete_all
|
16
17
|
connection = ActiveRecord::Base.connection
|
17
18
|
result = connection.execute(<<-SQL)
|
18
19
|
select 1 where exists(select 1 from pg_proc where proname = 'ukrdc_prepare_tables');
|
@@ -143,6 +143,12 @@ module Renalware
|
|
143
143
|
access_type_abbreviation.split(" ").first
|
144
144
|
end
|
145
145
|
|
146
|
+
def access_rr41_code
|
147
|
+
return if access_type_abbreviation.blank?
|
148
|
+
|
149
|
+
access_type_abbreviation.split(" ").last
|
150
|
+
end
|
151
|
+
|
146
152
|
protected
|
147
153
|
|
148
154
|
attr_reader :session, :view_context
|
@@ -38,12 +38,12 @@ module Renalware
|
|
38
38
|
super
|
39
39
|
end
|
40
40
|
|
41
|
-
def modalities
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
41
|
+
# def modalities
|
42
|
+
# __getobj__
|
43
|
+
# .modalities
|
44
|
+
# .includes(:description)
|
45
|
+
# .order(started_on: :asc, created_at: :asc)
|
46
|
+
# end
|
47
47
|
|
48
48
|
def dead?
|
49
49
|
current_modality_death?
|
@@ -100,11 +100,22 @@ module Renalware
|
|
100
100
|
.includes(:updated_by)
|
101
101
|
end
|
102
102
|
|
103
|
+
def treatments
|
104
|
+
@treatments ||= begin
|
105
|
+
UKRDC::Treatment.where(patient_id: id).delete_all
|
106
|
+
UKRDC::TreatmentTimeline::GenerateTimeline.new(self).call
|
107
|
+
UKRDC::Treatment.where(patient_id: id).order(:patient_id, :started_on)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
103
111
|
# We always send the patients current prescriptions.
|
112
|
+
# Because the XSD rejects non-numeric dose amounts, only send prescriptions with a
|
113
|
+
# dose_amount of eg 10 or 10.23 or .23
|
104
114
|
def prescriptions
|
105
115
|
__getobj__
|
106
116
|
.prescriptions
|
107
117
|
.includes(:termination, :medication_route, :drug)
|
118
|
+
.where("dose_amount ~ '^[ ]*(\\d+|\\d+\.\\d+|\\.\\d+)[ ]*$'")
|
108
119
|
.order(:prescribed_on)
|
109
120
|
end
|
110
121
|
|
@@ -26,14 +26,7 @@ xml.Medications do
|
|
26
26
|
xml.Comments [prescription.dose_amount,
|
27
27
|
prescription.dose_unit&.text,
|
28
28
|
prescription.frequency].compact.join(" ")
|
29
|
-
|
30
|
-
# rubocop:disable Style/RescueModifier
|
31
|
-
# Only output DoseQuantity is it is an integer or decimal
|
32
|
-
dose_amount_is_a_number = Float(prescription.dose_amount) rescue nil
|
33
|
-
# rubocop:enable Style/RescueModifier
|
34
|
-
if dose_amount_is_a_number
|
35
|
-
xml.DoseQuantity prescription.dose_amount
|
36
|
-
end
|
29
|
+
xml.DoseQuantity prescription.dose_amount&.strip
|
37
30
|
|
38
31
|
if prescription.dose_unit.present?
|
39
32
|
xml.DoseUoM do
|
@@ -2,52 +2,91 @@
|
|
2
2
|
|
3
3
|
xml = builder
|
4
4
|
|
5
|
+
patient.treatments.each do |treatment|
|
6
|
+
namespace = treatment.modality_description.namespace&.downcase
|
7
|
+
partial = namespace&.to_sym || "generic"
|
8
|
+
locals = { treatment: treatment, builder: builder, patient: patient }
|
9
|
+
|
10
|
+
full_partial_path = "renalware/api/ukrdc/patients/treatments/#{partial}"
|
11
|
+
partial_exists = lookup_context.find_all(full_partial_path, [], true).any?
|
12
|
+
|
13
|
+
partial = partial_exists ? partial : "generic"
|
14
|
+
render "renalware/api/ukrdc/patients/treatments/#{partial}", **locals
|
15
|
+
|
16
|
+
# xml.Treatment do
|
17
|
+
# xml.EncounterNumber "#{treatment.modality_id}-#{treatment.hd_profile_id}"
|
18
|
+
# xml.EncounterType "N"
|
19
|
+
# xml.FromTime treatment.started_on&.iso8601
|
20
|
+
# xml.ToTime(treatment.ended_on&.iso8601) if treatment.ended_on.present?
|
21
|
+
|
22
|
+
# if treatment.hospital_unit.present?
|
23
|
+
# xml.HealthCareFacility do
|
24
|
+
# xml.CodingStandard "ODS"
|
25
|
+
# xml.Code treatment.hospital_unit.unit_code
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
|
29
|
+
# xml.AdmitReason do
|
30
|
+
# xml.CodingStandard "CF_RR7_TREATMENT"
|
31
|
+
# xml.Code treatment.modality_code.txt_code
|
32
|
+
# end
|
33
|
+
|
34
|
+
# # HD
|
35
|
+
# rr8 = treatment.hospital_unit&.unit_type_rr8
|
36
|
+
# if rr8.present?
|
37
|
+
# xml.Attributes do
|
38
|
+
# xml.QBL05 rr8 # eg HOME
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
|
5
44
|
# A temporary output of the treatment timeline using just modality descriptions with a
|
6
45
|
# crude renal reg modality code assigned to them - HD, PD, Transplant, vCKD - all other modalities
|
7
46
|
# fall through the gaps at this stage until we implement this properly. Also sub RR modal codes
|
8
47
|
# like CAPD and HDF are not yet implemented, just the top level modality.
|
9
|
-
patient.modalities.each do |modality|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
48
|
+
# patient.modalities.each do |modality|
|
49
|
+
# ukrdc_modality_code_id = modality.description.ukrdc_modality_code_id
|
50
|
+
|
51
|
+
# next if ukrdc_modality_code_id.blank?
|
52
|
+
|
53
|
+
# ukrdc_modality_code = Renalware::UKRDC::ModalityCode.find(ukrdc_modality_code_id)
|
54
|
+
|
55
|
+
# xml.Treatment do
|
56
|
+
# xml.EncounterNumber modality.id
|
57
|
+
# xml.EncounterType "N"
|
58
|
+
# xml.FromTime modality.started_on&.iso8601
|
59
|
+
# xml.ToTime(modality.ended_on&.iso8601) if modality.ended_on.present?
|
60
|
+
|
61
|
+
# xml.HealthCareFacility do
|
62
|
+
# xml.CodingStandard "ODS"
|
63
|
+
# xml.Code Renalware.config.ukrdc_site_code
|
64
|
+
# end
|
65
|
+
|
66
|
+
# xml.AdmitReason do
|
67
|
+
# xml.CodingStandard "CF_RR7_TREATMENT"
|
68
|
+
# xml.Code ukrdc_modality_code.txt_code
|
69
|
+
# end
|
70
|
+
|
71
|
+
# # This is a bit of hack to get the HD Profile location for the current modality
|
72
|
+
# if [1, 2, 3, 4, 5, 9].include?(ukrdc_modality_code.txt_code.to_i) # HD
|
73
|
+
# profile = Renalware::HD::Profile
|
74
|
+
# .where(patient_id: patient.id)
|
75
|
+
# .where(<<-SQL).order(created_at: :desc).first
|
76
|
+
# created_at::date <= '#{modality.started_on}'
|
77
|
+
# and (
|
78
|
+
# deactivated_at is NULL or
|
79
|
+
# (
|
80
|
+
# deactivated_at > '#{modality.started_on}'
|
81
|
+
# )
|
82
|
+
# )
|
83
|
+
# SQL
|
84
|
+
|
85
|
+
# if profile&.hospital_unit&.unit_type_rr8.present?
|
86
|
+
# xml.Attributes do
|
87
|
+
# xml.QBL05 profile.hospital_unit.unit_type_rr8 # eg HOME
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
# end
|