renalware-core 2.0.0.pre.rc8 → 2.0.0.pre.rc9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/renalware/modules/_clinical.scss +73 -0
- data/app/models/concerns/renalware/clinics/most_recent_measurement_scopes.rb.dead +43 -0
- data/app/models/renalware/clinics/clinic_visit.rb +2 -2
- data/app/models/renalware/clinics/current_observations.rb +57 -0
- data/app/models/renalware/letters/letter.rb +5 -1
- data/app/models/renalware/pathology/current_observation_set.rb +6 -0
- data/app/models/renalware/pathology/observation.rb +1 -0
- data/app/models/renalware/pathology/observation_request.rb +3 -0
- data/app/models/renalware/pathology/observations_jsonb_serializer.rb +7 -6
- data/app/models/renalware/pathology/{view_current_observation_results.rb → view_current_observation_results.rb.dead} +0 -0
- data/app/presenters/renalware/clinical/header_presenter.rb +33 -0
- data/app/presenters/renalware/letters/letter_presenter.rb +5 -1
- data/app/presenters/renalware/letters/part_class_filter.rb +36 -0
- data/app/presenters/renalware/renal/clinical_summary_presenter.rb +0 -1
- data/app/presenters/renalware/ukrdc/patient_presenter.rb +8 -2
- data/app/values/renalware/bmi.rb +20 -0
- data/app/views/renalware/admissions/consults/_table.html.slim +1 -1
- data/app/views/renalware/api/ukrdc/patients/_clinic_visit_observation.xml.builder +1 -1
- data/app/views/renalware/api/ukrdc/patients/_lab_orders.xml.builder +3 -3
- data/app/views/renalware/api/ukrdc/patients/_observations.xml.builder +3 -1
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_lab_order.xml.builder +2 -2
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_result_item.xml.builder +7 -2
- data/app/views/renalware/clinical/_header.html.slim +47 -0
- data/app/views/renalware/clinics/clinic_visits/_table.html.slim +0 -1
- data/app/views/renalware/clinics/visits/_table.html.slim +4 -1
- data/app/views/renalware/events/events/_event.html.slim +1 -1
- data/app/views/renalware/events/events/_table.html.slim +3 -0
- data/app/views/renalware/layouts/_patient.html.slim +1 -0
- data/app/views/renalware/letters/letters/_form.html.slim +1 -1
- data/app/views/renalware/letters/letters/_pathology.html.slim +0 -1
- data/app/views/renalware/mdm_patients/_table.html.slim +1 -1
- data/app/views/renalware/pathology/_navigation.html.slim +1 -1
- data/app/views/renalware/patients/patients/_table.html.slim +2 -2
- data/config/initializers/core_extensions.rb +1 -0
- data/config/initializers/inflections.rb +1 -0
- data/config/locales/renalware/clinical/allergies.en.yml +0 -2
- data/config/locales/renalware/clinical/{dry_weight.yml → dry_weight.en.yml} +0 -0
- data/config/locales/renalware/clinical/header.en.yml +14 -0
- data/db/functions/audit_view_as_json_v01.sql +25 -0
- data/db/functions/count_estimate_v01.sql +20 -0
- data/db/functions/generate_patient_secure_id_v01.sql +21 -0
- data/db/functions/generate_secure_id_v01.sql +18 -0
- data/db/functions/import_gps_csv_v01.sql +129 -0
- data/db/functions/import_practice_memberships_csv_v01.sql +48 -0
- data/db/functions/import_practices_csv_v01.sql +109 -0
- data/db/functions/preprocess_hl7_message_v01.sql +29 -0
- data/db/functions/preprocess_hl7_message_v02.sql +31 -0
- data/db/functions/refresh_all_matierialized_views_v01.sql +32 -0
- data/db/functions/refresh_current_observation_set_v01.sql +39 -0
- data/db/functions/update_current_observation_set_from_trigger_v01.sql +88 -0
- data/db/functions/update_current_observation_set_from_trigger_v02.sql +90 -0
- data/db/migrate/20161124152732_add_deleted_at_to_patient_bookmarks.rb +1 -1
- data/db/migrate/20170608135553_create_functions_to_generate_secure_patient_id.rb +4 -48
- data/db/migrate/20170705090219_create_refresh_all_materialized_views_fn.rb +2 -37
- data/db/migrate/20170707110155_rename_access_plans_to_access_plan_types.rb +1 -1
- data/db/migrate/20170831142819_enable_crosstab_extension.rb +2 -2
- data/db/migrate/20170911133224_add_type_to_messaging_messages.rb +1 -1
- data/db/migrate/20170915115228_add_schedule_diurnal_period_id_to_hd_profiles.rb +1 -1
- data/db/migrate/20171013145849_set_patients_secure_id.rb +1 -1
- data/db/migrate/20171101121130_create_function_to_render_audit_view_as_json.rb +2 -29
- data/db/migrate/20171127092158_create_function_to_import_practices.rb +4 -118
- data/db/migrate/20171127092359_create_fn_to_insert_gps.rb +3 -139
- data/db/migrate/20171206140738_create_fn_to_load_practice_memberships_csv.rb +2 -53
- data/db/migrate/20171213111513_create_fn_to_refresh_current_obs.rb +2 -43
- data/db/migrate/20171214141335_create_trigger_to_update_current_observation_sets.rb +3 -101
- data/db/migrate/20180119121243_create_trigger_to_preprocess_hl7_msg.rb +2 -41
- data/db/migrate/20180121115246_add_include_pathology_in_letter_to_letters_letterheads.rb +5 -0
- data/db/migrate/20180125201356_make_obs_set_trigger_change_updated_at.rb +2 -184
- data/db/migrate/20180130165803_add_deleted_at_indexes.rb +16 -0
- data/db/migrate/20180201090444_add_created_at_to_delayed_jobs_in_hl7_trig_fn.rb +9 -0
- data/db/migrate/20180207082540_create_count_estimate_function.rb +9 -0
- data/db/triggers/feed_messages_preprocessing_trigger_v01.sql +5 -0
- data/db/triggers/update_current_observation_set_trigger_v01.sql +7 -0
- data/lib/core_extensions/active_record/migration_helpers.rb +43 -0
- data/lib/renalware/engine.rb +6 -4
- data/lib/renalware/version.rb +1 -1
- data/spec/factories/pathology/observation_descriptions.rb +7 -1
- data/spec/support/shared_examples/accountable_examples.rb +6 -0
- data/spec/support/shared_examples/supersedable_examples.rb +12 -0
- metadata +33 -10
- data/app/models/renalware/letters/delivery/deliver_letter.rb.dead +0 -41
- data/app/models/renalware/pathology/current_key_observation_set.rb.dead +0 -10
- data/app/models/renalware/pathology/update_current_observations.rb.dead +0 -25
- data/app/presenters/renalware/pathology/current_observation_results.dead/presenter.rb.dead +0 -54
- data/app/views/renalware/letters/formatted_letters/show.rtf.slim.ol +0 -1
- data/app/views/renalware/patients/_prescriptions.html.slim.dead +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3361756d54b9a83fa22bab7f608be70508af45ecfe4b2caa6155c5a179463067
|
4
|
+
data.tar.gz: 82ae6e70d84354b6764a549e1eb8c624b2b9706b3109af3f40f739d90fdb4ca4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e516676b956cc6abf3189e4b270400c13282e774530051637b9c39e914c4c55d1109274b53541ec811f93f160d5aee9193dd4a3ce11943e046b46188d0e3c9b
|
7
|
+
data.tar.gz: 5c45e168decc8c91857411ff6d1736939e206030f3e75749d125798c0d12bfcfc84fe9ab04e881c4e05c74ce315bc4bb546fc37f0dc5dd57068f560a4a782fbf
|
@@ -31,3 +31,76 @@ article.clinical-allergies {
|
|
31
31
|
}
|
32
32
|
}
|
33
33
|
}
|
34
|
+
|
35
|
+
|
36
|
+
.clinical-header {
|
37
|
+
background-color: $table-border-colour;
|
38
|
+
padding: .2em .2em .2em .6em;
|
39
|
+
|
40
|
+
&.lozenge {
|
41
|
+
background-color: $white;
|
42
|
+
padding: .2em .3rem;
|
43
|
+
|
44
|
+
ul {
|
45
|
+
li {
|
46
|
+
padding: 0.3rem 0.3rem;
|
47
|
+
border: none;
|
48
|
+
margin: 0.1rem 0.3rem 0.2rem 0;
|
49
|
+
border-radius: 0.3rem;
|
50
|
+
background-color: $light-grey;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
dl {
|
55
|
+
padding: 0;
|
56
|
+
margin: 0;
|
57
|
+
font-size: 0.9rem;
|
58
|
+
line-height: 0.9rem;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
ul {
|
64
|
+
padding: 0;
|
65
|
+
margin: 0;
|
66
|
+
|
67
|
+
li {
|
68
|
+
display: inline-block;
|
69
|
+
padding: 0;
|
70
|
+
border-bottom: 1px dotted $winter-sky;
|
71
|
+
margin: 0.2rem .6rem .2rem 0
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
dl {
|
76
|
+
padding: 0;
|
77
|
+
margin: 0;
|
78
|
+
font-size: 0.9rem;
|
79
|
+
line-height: 0.8rem;
|
80
|
+
|
81
|
+
dt, dd {
|
82
|
+
padding: 0;
|
83
|
+
margin: 0;
|
84
|
+
display: inline-block;
|
85
|
+
}
|
86
|
+
|
87
|
+
dt {
|
88
|
+
font-weight: normal;
|
89
|
+
}
|
90
|
+
|
91
|
+
dd {
|
92
|
+
font-weight: bold;
|
93
|
+
padding-left: 0.2rem;
|
94
|
+
|
95
|
+
&.date {
|
96
|
+
font-weight: normal;
|
97
|
+
font-style: italic;
|
98
|
+
color: $muted-dark-grey;
|
99
|
+
}
|
100
|
+
|
101
|
+
&.empty {
|
102
|
+
display: none;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_dependency "renalware/letters"
|
2
|
+
|
3
|
+
module Renalware
|
4
|
+
module Clinics
|
5
|
+
module MostRecentMeasurementScopes
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
ClinicalObservation = Struct.new(:date, :measurement)
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
# Returns [date, weight]
|
12
|
+
def most_recent_weight_for(patient)
|
13
|
+
result = ClinicVisit
|
14
|
+
.most_recent_for_patient(patient)
|
15
|
+
.where("weight is not null")
|
16
|
+
.pluck(:date, :weight).first || []
|
17
|
+
|
18
|
+
ClinicalObservation.new(result.first, result.last)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns [date, height]
|
22
|
+
def most_recent_height_for(patient)
|
23
|
+
result = ClinicVisit
|
24
|
+
.most_recent_for_patient(patient)
|
25
|
+
.where("height is not null")
|
26
|
+
.pluck(:date, :height).first || []
|
27
|
+
|
28
|
+
ClinicalObservation.new(result.first, result.last)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns [date, [systolic_bp, diastolic_bp]]
|
32
|
+
def most_recent_blood_pressure_for(patient)
|
33
|
+
result = ClinicVisit
|
34
|
+
.most_recent_for_patient(patient)
|
35
|
+
.where("systolic_bp is not null and diastolic_bp is not null")
|
36
|
+
.pluck(:date, :systolic_bp, :diastolic_bp).first || [nil, nil, nil]
|
37
|
+
|
38
|
+
ClinicalObservation.new(result[0], [result[1], result[2]])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -28,10 +28,10 @@ module Renalware
|
|
28
28
|
enumerize :urine_protein, in: %i(neg trace very_low low medium high)
|
29
29
|
|
30
30
|
scope :ordered, ->{ order(date: :desc, created_at: :desc) }
|
31
|
+
scope :most_recent_for_patient, ->(patient) { for_patient(patient).ordered.limit(1) }
|
31
32
|
|
32
33
|
def bmi
|
33
|
-
|
34
|
-
((weight / height) / height).round(2)
|
34
|
+
BMI.new(weight: weight, height: height).to_f
|
35
35
|
end
|
36
36
|
|
37
37
|
def bp
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_dependency "renalware/letters"
|
2
|
+
require "attr_extras"
|
3
|
+
|
4
|
+
module Renalware
|
5
|
+
module Clinics
|
6
|
+
class CurrentObservations
|
7
|
+
NULL_DATE = nil
|
8
|
+
pattr_initialize :patient
|
9
|
+
|
10
|
+
Observation = Struct.new(:date, :measurement)
|
11
|
+
|
12
|
+
# Returns [date, weight]
|
13
|
+
def weight
|
14
|
+
@weight ||= begin
|
15
|
+
result = ClinicVisit
|
16
|
+
.most_recent_for_patient(patient)
|
17
|
+
.where("weight is not null")
|
18
|
+
.pluck(:date, :weight).first || []
|
19
|
+
|
20
|
+
Observation.new(result.first, result.last)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns [date, height]
|
25
|
+
def height
|
26
|
+
@height ||= begin
|
27
|
+
result = ClinicVisit
|
28
|
+
.most_recent_for_patient(patient)
|
29
|
+
.where("height is not null")
|
30
|
+
.pluck(:date, :height).first || []
|
31
|
+
|
32
|
+
Observation.new(result.first, result.last)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns [date, [systolic_bp, diastolic_bp]]
|
37
|
+
def blood_pressure
|
38
|
+
@blood_pressure ||= begin
|
39
|
+
result = ClinicVisit
|
40
|
+
.most_recent_for_patient(patient)
|
41
|
+
.where("systolic_bp is not null and diastolic_bp is not null")
|
42
|
+
.pluck(:date, :systolic_bp, :diastolic_bp).first || [nil, nil, nil]
|
43
|
+
|
44
|
+
Observation.new(result[0], [result[1], result[2]])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def bmi
|
49
|
+
bmi = BMI.new(
|
50
|
+
height: height.measurement,
|
51
|
+
weight: weight.measurement
|
52
|
+
)
|
53
|
+
Observation.new(NULL_DATE, bmi.to_f)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -5,6 +5,10 @@ module Renalware
|
|
5
5
|
class Letter < ApplicationRecord
|
6
6
|
include Accountable
|
7
7
|
extend Enumerize
|
8
|
+
# The letterhead is the only site-specific element in the letter, so we use this
|
9
|
+
# to determine site-specific settings - in this case whether the letter should contain
|
10
|
+
# pathology. At KCH for example, Darren Valley letters should not contain recent pathology.
|
11
|
+
delegate :include_pathology_in_letter_body?, to: :letterhead, allow_nil: true
|
8
12
|
|
9
13
|
belongs_to :event, polymorphic: true
|
10
14
|
belongs_to :author, class_name: "User"
|
@@ -25,7 +29,7 @@ module Renalware
|
|
25
29
|
through: :electronic_receipts,
|
26
30
|
source: :recipient
|
27
31
|
has_one :signature, dependent: :destroy
|
28
|
-
has_one :archive, foreign_key: "letter_id"
|
32
|
+
has_one :archive, foreign_key: "letter_id", inverse_of: :letter
|
29
33
|
serialize :pathology_snapshot, Pathology::ObservationsJsonbSerializer
|
30
34
|
|
31
35
|
accepts_nested_attributes_for :main_recipient
|
@@ -12,6 +12,7 @@ module Renalware
|
|
12
12
|
|
13
13
|
scope :ordered, -> { order(observed_at: :desc) }
|
14
14
|
scope :for_description, ->(description) { where(description: description) }
|
15
|
+
scope :having_a_loinc_code, -> { joins(:description).where("loinc_code is not null") }
|
15
16
|
|
16
17
|
def observed_on
|
17
18
|
observed_at.to_date
|
@@ -17,6 +17,9 @@ module Renalware
|
|
17
17
|
validates :requested_at, presence: true
|
18
18
|
|
19
19
|
scope :ordered, -> { order(requested_at: :desc) }
|
20
|
+
scope :having_observations_with_a_loinc_code, lambda {
|
21
|
+
joins(observations: :description).where("loinc_code is not null") # TODO: use a merge
|
22
|
+
}
|
20
23
|
|
21
24
|
def requested_on
|
22
25
|
requested_at.to_date
|
@@ -5,6 +5,8 @@ module Renalware
|
|
5
5
|
# We mix this module into any database-returned jsonb hash of observations
|
6
6
|
# (e.g. CurrentObservationSet.values and Letter.pathology_snapshot)
|
7
7
|
module ObservationSetMethods
|
8
|
+
VALID_SUFFIXES = %w(_result _observed_at).freeze
|
9
|
+
|
8
10
|
# Support these syntaxes
|
9
11
|
# values.hgb # => { result: ... observed_at: ...}
|
10
12
|
# values.HGB # => { result: ... observed_at: ...}
|
@@ -12,15 +14,14 @@ module Renalware
|
|
12
14
|
# values.hgb_observed_at # => "2017-17-01"
|
13
15
|
# So the values has methods corresponding to the entire set of possible
|
14
16
|
# OBX codes, and also methods to reach in and get their result and observed_at date.
|
15
|
-
#
|
16
|
-
# Note that if you get a missing method error for something like #hgb_result it means
|
17
|
-
# that HGB does not exist yet as an ObservationDescription so is not found in
|
18
|
-
# AllObservationCodes hence we can't respond to it.
|
19
17
|
# rubocop:disable Style/MethodMissing
|
20
18
|
def method_missing(method_name, *_args, &_block)
|
21
19
|
code, suffix = method_parts(method_name)
|
22
|
-
|
23
|
-
|
20
|
+
if VALID_SUFFIXES.include?(suffix) || AllObservationCodes.include?(code)
|
21
|
+
observation_hash_or_hash_element_for(code, suffix)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
24
25
|
end
|
25
26
|
# rubocop:enable Style/MethodMissing
|
26
27
|
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_dependency "renalware"
|
2
|
+
require "attr_extras"
|
3
|
+
|
4
|
+
module Renalware
|
5
|
+
module Clinical
|
6
|
+
class HeaderPresenter
|
7
|
+
pattr_initialize :patient
|
8
|
+
delegate :weight, :height, :blood_pressure, :bmi, to: :clinical_current_observations
|
9
|
+
delegate :measurement, :date, to: :weight, prefix: true
|
10
|
+
delegate :measurement, :date, to: :height, prefix: true
|
11
|
+
delegate :measurement, :date, to: :blood_pressure, prefix: true
|
12
|
+
delegate :measurement, :date, to: :bmi, prefix: true
|
13
|
+
|
14
|
+
def current_pathology
|
15
|
+
@pathology ||= pathology_current_observation_set.values
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def pathology_current_observation_set
|
21
|
+
pathology_patient.current_observation_set || Pathology::NullObservationSet.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def pathology_patient
|
25
|
+
Pathology.cast_patient(patient)
|
26
|
+
end
|
27
|
+
|
28
|
+
def clinical_current_observations
|
29
|
+
@clinical_current_observations ||= Clinics::CurrentObservations.new(patient)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -41,7 +41,11 @@ module Renalware
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def parts
|
44
|
-
|
44
|
+
filtered_part_classes = PartClassFilter.new(
|
45
|
+
part_classes: letter_event.part_classes,
|
46
|
+
include_pathology_in_letter_body: letterhead.include_pathology_in_letter_body?
|
47
|
+
)
|
48
|
+
filtered_part_classes.to_h.values.map do |part_class|
|
45
49
|
part_class.new(patient, self, letter_event)
|
46
50
|
end
|
47
51
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "renalware/letters"
|
2
|
+
require "attr_extras"
|
3
|
+
|
4
|
+
module Renalware
|
5
|
+
module Letters
|
6
|
+
# Given a hash of letter part classes (i.e. the class names for each Part that should be
|
7
|
+
# included in the letter, where each Part is responsible for rendering a part of the letter)
|
8
|
+
# and other options, this class filters out certain parts based on conditions,
|
9
|
+
# for example if a site does not want pathology, the recent_pathology_results key is
|
10
|
+
# removed from the hash.
|
11
|
+
class PartClassFilter
|
12
|
+
pattr_initialize [:part_classes!, :include_pathology_in_letter_body!]
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
filtered_part_classes
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def filtered_part_classes
|
21
|
+
remove_recent_observations_part_if_no_pathology_required_in_body(part_classes)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Some sites may not require pathology in letters. This is determined by the boolean
|
25
|
+
# #include_pathology_in_letter_body flag on the letterhead, which is site-specific.
|
26
|
+
# TODO: It might be better to link the letterhead to the Hospitals::Site and
|
27
|
+
# put the site-specific configuration in say a jsonb field on the Site.
|
28
|
+
def remove_recent_observations_part_if_no_pathology_required_in_body(part_klasses)
|
29
|
+
unless include_pathology_in_letter_body
|
30
|
+
part_klasses = part_klasses.reject{ |key| key == :recent_pathology_results }
|
31
|
+
end
|
32
|
+
part_klasses
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -5,7 +5,6 @@ module Renalware
|
|
5
5
|
class PatientPresenter < SimpleDelegator
|
6
6
|
delegate :allergies, to: :clinical_patient
|
7
7
|
delegate :clinic_visits, to: :clinics_patient
|
8
|
-
delegate :observation_requests, to: :pathology_patient
|
9
8
|
delegate :profile, to: :renal_patient, allow_nil: true
|
10
9
|
delegate :first_seen_on, to: :profile, allow_nil: true
|
11
10
|
alias_attribute :home_telephone, :telephone1
|
@@ -17,7 +16,7 @@ module Renalware
|
|
17
16
|
|
18
17
|
def current_modality_hd?
|
19
18
|
return false if current_modality.blank?
|
20
|
-
current_modality.description.is_a?(HD::ModalityDescription)
|
19
|
+
current_modality.description.is_a?(Renalware::HD::ModalityDescription)
|
21
20
|
end
|
22
21
|
|
23
22
|
def smoking_history
|
@@ -46,6 +45,13 @@ module Renalware
|
|
46
45
|
email || home_telephone || mobile_telephone
|
47
46
|
end
|
48
47
|
|
48
|
+
def observation_requests
|
49
|
+
pathology_patient
|
50
|
+
.observation_requests
|
51
|
+
.having_observations_with_a_loinc_code
|
52
|
+
.where(patient_id: id)
|
53
|
+
end
|
54
|
+
|
49
55
|
private
|
50
56
|
|
51
57
|
def clinical_patient
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "attr_extras"
|
2
|
+
|
3
|
+
module Renalware
|
4
|
+
# Value object representing Body Mass Index. Accepts only meters and kg
|
5
|
+
#
|
6
|
+
# Example usage:
|
7
|
+
# bmi = Renalware::BMI.new(height: 1.80, weight: 180)
|
8
|
+
# bmi.to_f # => 55.6
|
9
|
+
# bmi.to_s # => "55.6"
|
10
|
+
#
|
11
|
+
class BMI
|
12
|
+
pattr_initialize [:weight!, :height!]
|
13
|
+
delegate :to_s, to: :to_f
|
14
|
+
|
15
|
+
def to_f
|
16
|
+
return unless weight && height && height > 0
|
17
|
+
((weight / height) / height).round(1)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|