renalware-core 2.0.89 → 2.0.90
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/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
|