renalware-core 2.0.113 → 2.0.115
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +0 -2
- data/app/assets/javascripts/renalware/application.js.erb +0 -1
- data/app/assets/javascripts/renalware/feed_only_inputs.js.erb +26 -0
- data/app/assets/javascripts/renalware/feeds.js +50 -0
- data/app/assets/javascripts/renalware/person_ajax_search.js +43 -0
- data/app/assets/stylesheets/renalware/application.scss +0 -1
- data/app/assets/stylesheets/renalware/modules/_admin.scss +7 -0
- data/app/assets/stylesheets/renalware/modules/_pathology.scss +1 -1
- data/app/assets/stylesheets/renalware/modules/_patients.scss +6 -0
- data/app/assets/stylesheets/renalware/modules/_snippets.scss +2 -2
- data/app/assets/stylesheets/renalware/partials/_forms.scss +5 -1
- data/app/assets/stylesheets/renalware/partials/_layout.scss +4 -0
- data/app/{views/renalware/patients/_side_menu.html.slim → components/renalware/patients/side_menu_component.html.slim} +0 -0
- data/app/components/renalware/patients/side_menu_component.rb +18 -0
- data/app/controllers/renalware/clinical/body_compositions_controller.rb +6 -0
- data/app/controllers/renalware/feeds/hl7_test_messages_controller.rb +60 -0
- data/app/controllers/renalware/hd/mdm_patients_controller.rb +16 -6
- data/app/controllers/renalware/hd/scheduling/diaries_controller.rb +91 -0
- data/app/controllers/renalware/hd/scheduling/diary_slots_controller.rb +169 -0
- data/app/controllers/renalware/hd/session_forms/batches_controller.rb +1 -1
- data/app/controllers/renalware/pathology/observation_requests_controller.rb +23 -4
- data/app/controllers/renalware/pathology/requests/requests_controller.rb +0 -4
- data/app/controllers/renalware/patients/abridgements_controller.rb +39 -0
- data/app/controllers/renalware/pd/regimes_controller.rb +26 -0
- data/app/controllers/renalware/problems/problems_controller.rb +2 -2
- data/app/helpers/renalware/application_helper.rb +9 -0
- data/app/helpers/renalware/article_helper.rb +18 -0
- data/app/helpers/renalware/form_helper.rb +3 -2
- data/app/helpers/renalware/users_helper.rb +5 -1
- data/app/javascript/controllers/clipboard_controller.js +16 -0
- data/app/javascript/packs/renalware_core.js +20 -0
- data/app/jobs/feed_job.rb +1 -3
- data/app/jobs/hl7_message_example.yml +2 -2
- data/app/models/renalware/feeds/files/practice_memberships/import_job.rb +3 -0
- data/app/models/renalware/feeds/files/primary_care_physicians/import_job.rb +2 -0
- data/app/models/renalware/feeds/hl7_message.rb +57 -6
- data/app/models/renalware/feeds/hl7_test_form.rb +10 -0
- data/app/models/renalware/feeds/hl7_test_message.rb +11 -0
- data/app/models/renalware/feeds/message_parser.rb +6 -2
- data/app/models/renalware/feeds/message_processor.rb +44 -32
- data/app/models/renalware/feeds/persist_message.rb +9 -3
- data/app/models/renalware/feeds.rb +2 -0
- data/app/models/renalware/hd/scheduling/archive_arguments.rb +19 -0
- data/app/models/renalware/hd/scheduling/diary.rb +54 -0
- data/app/models/renalware/hd/scheduling/diary_housekeeping_job.rb +84 -0
- data/app/models/renalware/hd/scheduling/diary_range.rb +69 -0
- data/app/models/renalware/hd/scheduling/diary_slot.rb +88 -0
- data/app/models/renalware/hd/scheduling/find_or_create_diary_by_week_query.rb +52 -0
- data/app/models/renalware/hd/scheduling/find_or_create_master_diary.rb +27 -0
- data/app/models/renalware/hd/scheduling/master_diary.rb +35 -0
- data/app/models/renalware/hd/scheduling/weekly_diary.rb +47 -0
- data/app/models/renalware/pathology/message_listener.rb +2 -2
- data/app/models/renalware/pathology/requests/global_rule/latest_crf_older_than_weeks.rb +38 -0
- data/app/models/renalware/pathology/requests/global_rule/patient_is_diabetic.rb +1 -1
- data/app/models/renalware/patient.rb +1 -1
- data/app/models/renalware/patients/abridgement.rb +18 -0
- data/app/models/renalware/patients/abridgement_search_form.rb +12 -0
- data/app/models/renalware/patients/ingestion/command.rb +25 -0
- data/app/models/renalware/patients/ingestion/command_factory.rb +135 -0
- data/app/models/renalware/patients/ingestion/commands/add_or_update_patient.rb +65 -0
- data/app/models/renalware/patients/ingestion/message_listener.rb +21 -0
- data/app/models/renalware/patients/ingestion/message_mapper.rb +26 -0
- data/app/models/renalware/patients/ingestion/message_mappers/patient.rb +73 -0
- data/app/models/renalware/patients/ingestion/update_master_patient_index.rb +60 -0
- data/app/models/renalware/patients/ingestion/update_master_patient_index_job.rb.dead +20 -0
- data/app/models/renalware/patients.rb +4 -3
- data/app/models/renalware/problems/problem.rb +6 -2
- data/app/models/renalware/ukrdc/incoming/paths.rb +6 -7
- data/app/policies/renalware/admin/devops_policy.rb +18 -0
- data/app/policies/renalware/hd/{diary_policy.rb → scheduling/diary_policy.rb} +3 -1
- data/app/presenters/renalware/clinical/profile_presenter.rb +2 -1
- data/app/presenters/renalware/directory/person_auto_complete_presenter.rb +1 -1
- data/app/presenters/renalware/hd/scheduling/diary_presenter.rb +84 -0
- data/app/presenters/renalware/hd/scheduling/diary_slot_presenter.rb +74 -0
- data/app/presenters/renalware/hd/scheduling/null_slot.rb +42 -0
- data/app/presenters/renalware/pd/dashboard_presenter.rb +3 -2
- data/app/views/renalware/accesses/procedures/_form.html.slim +5 -1
- data/app/views/renalware/accesses/procedures/_list.html.slim +11 -4
- data/app/views/renalware/accesses/procedures/show.html.slim +17 -19
- data/app/views/renalware/addresses/_form.html.slim +17 -12
- data/app/views/renalware/admin/cache/show.html.slim +24 -0
- data/app/views/renalware/clinical/body_compositions/_list.html.slim +7 -43
- data/app/views/renalware/clinical/body_compositions/_table.html.slim +42 -0
- data/app/views/renalware/clinical/body_compositions/index.html.slim +9 -0
- data/app/views/renalware/clinical/dry_weights/_list.html.slim +2 -8
- data/app/views/renalware/clinical/dry_weights/_table.html.slim +7 -0
- data/app/views/renalware/clinical/profiles/show.html.slim +4 -2
- data/app/views/renalware/feeds/hl7_test_messages/create.js.erb +10 -0
- data/app/views/renalware/feeds/hl7_test_messages/new.slim +18 -0
- data/app/views/renalware/hd/mdm_patients/_filters.html.slim +0 -11
- data/app/views/renalware/hd/mdm_patients/_page_actions.html.slim +29 -0
- data/app/views/renalware/hd/mdm_patients/index.html.slim +7 -4
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_page_actions.html.slim +4 -4
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_table.html.slim +0 -0
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/_weekly_diary.html.slim +1 -1
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/edit.html.slim +6 -6
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/index.html.slim +0 -0
- data/app/views/renalware/hd/{diaries → scheduling/diaries}/show.pdf.slim +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_form.html.slim +15 -6
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_slot.html.slim +2 -2
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/_tab.html.slim +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/create.js.erb +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/destroy.js.erb +1 -1
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/edit.html.slim +2 -2
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.html.slim +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/new.js.erb +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/show.js.erb +0 -0
- data/app/views/renalware/hd/{diary_slots → scheduling/diary_slots}/update.js.erb +1 -1
- data/app/views/renalware/hospitals/units/index.html.slim +2 -2
- data/app/views/renalware/layouts/_patient.html.slim +2 -1
- data/app/views/renalware/letters/contacts/_form.html.slim +10 -13
- data/app/views/renalware/letters/letters/_form.html.slim +2 -9
- data/app/views/renalware/navigation/_developer.html.slim +4 -0
- data/app/views/renalware/navigation/_menu.html.slim +2 -0
- data/app/views/renalware/pathology/observation_requests/_filters.html.slim +17 -0
- data/app/views/renalware/pathology/observation_requests/index.html.slim +2 -1
- data/app/views/renalware/patients/_layout.html.slim +1 -1
- data/app/views/renalware/patients/_side_menu.html.slim.dead +7 -0
- data/app/views/renalware/patients/abridgements/_abridgement.html.slim +8 -0
- data/app/views/renalware/patients/abridgements/_table.html.slim +12 -0
- data/app/views/renalware/patients/abridgements/index.html.slim +22 -0
- data/app/views/renalware/patients/alerts/create.json +3 -0
- data/app/views/renalware/patients/patients/_form.html.slim +36 -17
- data/app/views/renalware/patients/patients/edit.html.slim +1 -1
- data/app/views/renalware/patients/patients/new.html.slim +1 -1
- data/app/views/renalware/patients/side_menu/_actions.html.slim +2 -0
- data/app/views/renalware/pd/_apd_regimes.html.slim +1 -1
- data/app/views/renalware/pd/_capd_regimes.html.slim +1 -1
- data/app/views/renalware/pd/dashboards/show/_apd_regimes.html.slim +11 -2
- data/app/views/renalware/pd/dashboards/show/_capd_regimes.html.slim +11 -2
- data/app/views/renalware/pd/regimes/index.html.slim +7 -0
- data/app/views/renalware/renal/profiles/_form.html.slim +7 -24
- data/app/views/renalware/shared/documents/_binary_marker_input.html.slim +2 -2
- data/app/views/renalware/shared/documents/_blood_group_input.html.slim +4 -2
- data/app/views/renalware/transplants/registrations/_form.html.slim +22 -17
- data/config/locales/renalware/clinical/body_composition.yml +6 -3
- data/config/locales/renalware/clinical/dry_weight.en.yml +4 -3
- data/config/locales/renalware/hd/diary_slots.en.yml +3 -2
- data/config/locales/renalware/letters/contact.en.yml +0 -2
- data/config/routes/feeds.rb +5 -0
- data/config/routes/hd.rb +11 -7
- data/config/routes/letters.rb +0 -5
- data/config/routes/patients.rb +1 -0
- data/config/routes/pd.rb +2 -2
- data/config/routes/renal.rb +0 -5
- data/config/routes.rb +1 -0
- data/config/webpack/development.js +5 -0
- data/config/webpack/environment.js +3 -0
- data/config/webpack/production.js +5 -0
- data/config/webpack/test.js +5 -0
- data/config/webpacker.yml +103 -0
- data/db/functions/hd_diary_archive_elapsed_master_slots_v01.sql +40 -0
- data/db/migrate/20190322120025_create_feed_hl7_test_messages.rb +12 -0
- data/db/migrate/20190325134823_create_patients_master_index.rb +24 -0
- data/db/migrate/20190327100851_add_handled_to_feed_messages.rb +5 -0
- data/db/migrate/20191012121433_add_consultant_to_users.rb +7 -0
- data/db/migrate/20191018143635_create_hd_diary_matrix_view.rb +7 -0
- data/db/migrate/20191018144917_create_fn_to_archive_master_slots.rb +9 -0
- data/db/views/hd_diary_matrix_v01.sql +38 -0
- data/lib/core_extensions/active_record/sort.rb +27 -9
- data/lib/renalware/configuration.rb +3 -0
- data/lib/renalware/engine.rb +31 -0
- data/lib/renalware/version.rb +1 -1
- data/lib/renalware/week_period.rb +8 -7
- data/lib/renalware.rb +13 -1
- data/lib/tasks/hd.rake +7 -0
- data/lib/tasks/pathology.rake +1 -1
- data/lib/tasks/renalware.rake +89 -4
- data/spec/factories/hd/scheduling/diaries.rb +18 -0
- data/spec/factories/hd/{slots.rb → scheduling/slots.rb} +1 -1
- data/spec/factories/patients/abridgements.rb +9 -0
- data/spec/support/hl7_helpers.rb +13 -0
- data/spec/support/pages/letters/form.rb +4 -1
- metadata +126 -50
- data/app/assets/javascripts/renalware/auto_complete.js +0 -63
- data/app/controllers/renalware/hd/diaries_controller.rb +0 -89
- data/app/controllers/renalware/hd/diary_slots_controller.rb +0 -175
- data/app/controllers/renalware/letters/descriptions_controller.rb +0 -22
- data/app/controllers/renalware/renal/prd_descriptions_controller.rb +0 -15
- data/app/models/renalware/hd/archive_yesterdays_slots_job.rb +0 -69
- data/app/models/renalware/hd/diary.rb +0 -41
- data/app/models/renalware/hd/diary_slot.rb +0 -83
- data/app/models/renalware/hd/find_or_create_diary_by_week_query.rb +0 -50
- data/app/models/renalware/hd/find_or_create_master_diary.rb +0 -26
- data/app/models/renalware/hd/master_diary.rb +0 -32
- data/app/models/renalware/hd/weekly_diary.rb +0 -45
- data/app/models/renalware/renal/prd_descriptions/search_query.rb +0 -35
- data/app/presenters/renalware/hd/diary_presenter.rb +0 -79
- data/app/presenters/renalware/hd/diary_slot_presenter.rb +0 -72
- data/app/presenters/renalware/hd/null_slot.rb +0 -40
- data/app/views/renalware/renal/prd_descriptions/search.json.jbuilder +0 -6
- data/lib/test_support/autocomplete_helpers.rb +0 -14
- data/spec/factories/hd/diaries.rb +0 -14
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
|
5
|
+
# A Diary is the schedule of HD Station/Patients assignments for one week for a particular unit.
|
6
|
+
# A Diary is split into Periods (eg. am pm eve), and each Period has a matrix of slots
|
7
|
+
# Imagine Days eg 1 to 6 on the X axis and Stations on the Y axis, and into each 'slot' we
|
8
|
+
# put a patient.
|
9
|
+
# A patient can only be in one slot in any period.
|
10
|
+
#
|
11
|
+
# Do not create instances of this class explicity, always use the STI sub classes eg MasterDiary.
|
12
|
+
module Renalware
|
13
|
+
module HD
|
14
|
+
module Scheduling
|
15
|
+
class Diary < ApplicationRecord
|
16
|
+
include Accountable
|
17
|
+
self.table_name = :hd_diaries
|
18
|
+
has_many :slots, class_name: "DiarySlot", dependent: :restrict_with_exception
|
19
|
+
belongs_to :hospital_unit, class_name: "Hospitals::Unit"
|
20
|
+
has_many :patients,
|
21
|
+
through: :slots, class_name: "Renalware::HD::Patient",
|
22
|
+
dependent: :restrict_with_exception
|
23
|
+
validates :hospital_unit_id, presence: true
|
24
|
+
validates :master, inclusion: { in: [true, false], allow_nil: true }
|
25
|
+
composed_of :week,
|
26
|
+
mapping: [%w(week_number week_number), %w(year year)],
|
27
|
+
constructor: lambda { |week_number, year|
|
28
|
+
WeekPeriod.new(week_number: week_number, year: year)
|
29
|
+
}
|
30
|
+
|
31
|
+
def self.policy_class
|
32
|
+
DiaryPolicy
|
33
|
+
end
|
34
|
+
|
35
|
+
# Searchs the object graph rather than a SQL search
|
36
|
+
def slot_for(diurnal_period_code_id, station_id, day_of_week, valid_from: nil)
|
37
|
+
slots.find do |slot|
|
38
|
+
found = slot.diurnal_period_code_id == diurnal_period_code_id &&
|
39
|
+
slot.station_id == station_id &&
|
40
|
+
slot.day_of_week == day_of_week
|
41
|
+
|
42
|
+
# This applies to master diaries only really, where we only
|
43
|
+
# show recurring slots if they were created before the timeframe
|
44
|
+
# of the current week being viewed.
|
45
|
+
if found && valid_from
|
46
|
+
found = (slot.created_at <= valid_from.end_of_week)
|
47
|
+
end
|
48
|
+
found
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "renalware/hd"
|
4
|
+
|
5
|
+
# A cron job creates this delayed job, which does the following:
|
6
|
+
# For all Weekly Diaries in the past, plus this week
|
7
|
+
# for each day that is in the past
|
8
|
+
# mark any slots in the weekly diary as archived
|
9
|
+
# and where the weekly diary is inheriting slots from the master diary
|
10
|
+
# create corresponding slots in the weekly diary (ie migrate those slots from master to weekly)
|
11
|
+
# and archive them.
|
12
|
+
# No slots before the current day should be touched
|
13
|
+
module Renalware
|
14
|
+
module HD
|
15
|
+
module Scheduling
|
16
|
+
DiaryHousekeepingJob = Struct.new(:up_until) do
|
17
|
+
def max_attempts
|
18
|
+
1
|
19
|
+
end
|
20
|
+
|
21
|
+
def queue_name
|
22
|
+
"hd_diary_houskeeping"
|
23
|
+
end
|
24
|
+
|
25
|
+
def priority
|
26
|
+
5 # medium
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy_failed_jobs?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# :reek:UtilityFunction
|
34
|
+
def perform
|
35
|
+
up_until ||= Time.zone.today - 1.day
|
36
|
+
up_until = up_until.to_date
|
37
|
+
create_missing_weekly_diaries
|
38
|
+
move_elapsed_master_slots_into_weekly_slot_equivalent
|
39
|
+
archive_old_weekly_slots(up_until)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Just inc case there are some missing weekly diaries
|
45
|
+
def create_missing_weekly_diaries
|
46
|
+
args = ArchiveArguments.new
|
47
|
+
Hospitals::Unit.hd_sites.each do |unit|
|
48
|
+
DiaryRange.new(
|
49
|
+
from_week_period: args.from_week_period,
|
50
|
+
to_week_period: args.to_week_period,
|
51
|
+
unit: unit
|
52
|
+
).create_missing_weekly_diaries(by: User.first)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Copy any master slots that are now in the past (as of midnight Sunday just gone) and
|
57
|
+
# which do not already have a weekly slot overriding the master, into weekly slots.
|
58
|
+
# This is to stop changes to the master diary affecting diary history.
|
59
|
+
# This executes a SQL view to do the dirty work. It references a SQL view called
|
60
|
+
# hd_diary_matrix to help it to decide which master slots to copy to the weekly diary.
|
61
|
+
# That view could be useful for other things. We could in fact build the diary UI from it.
|
62
|
+
def move_elapsed_master_slots_into_weekly_slot_equivalent
|
63
|
+
Rails.logger.debug("DEBUG: SELECT renalware.hd_diary_archive_elapsed_master_slots()")
|
64
|
+
conn = ActiveRecord::Base.connection
|
65
|
+
conn.execute("SELECT renalware.hd_diary_archive_elapsed_master_slots()")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Flag elapsed slots as archived. Principally this will help us to stop them from being
|
69
|
+
# changed.
|
70
|
+
def archive_old_weekly_slots(up_until)
|
71
|
+
slots = DiarySlot
|
72
|
+
.unarchived
|
73
|
+
.joins(:diary)
|
74
|
+
.where(hd_diaries: { year: up_until.year, week_number: up_until.cweek })
|
75
|
+
.where(day_of_week: up_until.cwday)
|
76
|
+
|
77
|
+
ids = slots.pluck(:id)
|
78
|
+
Rails.logger.info("Archiving #{ids.length} slots up_until #{up_until} with ids #{ids}")
|
79
|
+
slots.update_all(archived: true, archived_at: Time.zone.now)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "renalware/hd"
|
4
|
+
require "renalware/week_period"
|
5
|
+
require "attr_extras"
|
6
|
+
|
7
|
+
module Renalware
|
8
|
+
module HD
|
9
|
+
module Scheduling
|
10
|
+
# Represents a range of WeekPeriods and their diaries for a hospital unit
|
11
|
+
class DiaryRange
|
12
|
+
pattr_initialize [:from_week_period!, :to_week_period!, :unit!]
|
13
|
+
|
14
|
+
# If there are any missing weekly diaries in the date range, create them
|
15
|
+
def create_missing_weekly_diaries(by:)
|
16
|
+
week_periods_in_range.each do |period|
|
17
|
+
WeeklyDiary.find_or_create_by!(
|
18
|
+
hospital_unit_id: unit.id,
|
19
|
+
week_number: period.week_number,
|
20
|
+
year: period.year
|
21
|
+
) do |diary|
|
22
|
+
log_weekly_diary_creation(period)
|
23
|
+
diary.master_diary = master_diary_for(unit, by)
|
24
|
+
diary.by = by
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def log_weekly_diary_creation(period)
|
30
|
+
Rails.logger.debug(
|
31
|
+
"DEBUG: Creating weekly diary for unit #{unit.id} period "\
|
32
|
+
"#{period.week_number}/#{period.year}"
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def from_date
|
37
|
+
from_week_period.date_on_first_day_of_week
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_date
|
41
|
+
to_week_period.date_on_first_day_of_week
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Returns an array of WeekPeriods for each cwyear and cweek in the date range.
|
47
|
+
def week_periods_in_range
|
48
|
+
@week_periods_in_range ||= begin
|
49
|
+
# The array in the uniq block here serves to filter the date range. It filters out
|
50
|
+
# just the dates representing the first day of each unique week/year.
|
51
|
+
mondays_in_date_range = (from_date..to_date).uniq { |dt| [dt.cwyear, dt.cweek] }
|
52
|
+
# Now map the dates (one per week) into WeekPeriods
|
53
|
+
mondays_in_date_range.map do |date|
|
54
|
+
WeekPeriod.new(week_number: date.cweek, year: date.cwyear)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def master_diary_for(unit, by)
|
60
|
+
MasterDiary.find_or_create_by!(hospital_unit_id: unit.id) do |diary|
|
61
|
+
Rails.logger.debug "DEBUG: Creating master diary for unit #{unit.id}"
|
62
|
+
diary.master = true
|
63
|
+
diary.by = by
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module HD
|
7
|
+
module Scheduling
|
8
|
+
class DiarySlot < ApplicationRecord
|
9
|
+
self.table_name = :hd_diary_slots
|
10
|
+
# Changing to_ary from private to public here is a hack required to remove a SimpleDelgator
|
11
|
+
# warning in eg Renalware::HD::Scheduling::WeeklyDiary::WeeklySlotDecorator:
|
12
|
+
#
|
13
|
+
# `respond_to?': delegator does not forward private method #to_ary
|
14
|
+
#
|
15
|
+
# Yielding a slot from DiaryPresenter to the view seems to want to call #to_ary on it, (have
|
16
|
+
# not looked into why) and as the slot is wrapped in a decorator using SimpleDelegator,
|
17
|
+
# SimpleDelegatr complains it can't delegate to a private method.
|
18
|
+
# An alternative is to define the following in each Slot decorator
|
19
|
+
#
|
20
|
+
# def respond_to?(method, include_private = false)
|
21
|
+
# return false if method == :to_ary
|
22
|
+
# super
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# or to use method_missnig instead of SimpleDelegator in Slot Decorators.
|
26
|
+
#
|
27
|
+
public :to_ary
|
28
|
+
|
29
|
+
# Virtual attribute used on a form to determine what action as preformed on the slot
|
30
|
+
attr_accessor :change_type
|
31
|
+
# Virtual to help the prepopulation of select2 with the offending patient if an error
|
32
|
+
attr_accessor :patient_ids
|
33
|
+
|
34
|
+
include Accountable
|
35
|
+
belongs_to :diary, class_name: "Renalware::HD::Scheduling::Diary", touch: true
|
36
|
+
belongs_to :patient, touch: true
|
37
|
+
belongs_to :station, class_name: "Renalware::HD::Station"
|
38
|
+
belongs_to :diurnal_period_code
|
39
|
+
|
40
|
+
validates :diary, presence: true
|
41
|
+
validates :patient, presence: true
|
42
|
+
validates :station, presence: true
|
43
|
+
validates :diurnal_period_code, presence: true
|
44
|
+
validates :day_of_week, presence: true, inclusion: { in: 1..7 }
|
45
|
+
|
46
|
+
scope :weekly, -> { joins(:diary).where(hd_diaries: { master: false }) }
|
47
|
+
scope :archived, -> { weekly.where(archived: true) }
|
48
|
+
scope :unarchived, -> { weekly.where(archived: false) }
|
49
|
+
|
50
|
+
# A patient can only be assigned to one station in any period (e.g. am)/day combination
|
51
|
+
# for a diary. I.e. they can't be on two stations on Monday morning.
|
52
|
+
validates :patient_id,
|
53
|
+
uniqueness: { scope: [:diary, :diurnal_period_code, :day_of_week] }
|
54
|
+
|
55
|
+
# Scoped to a diary, the combination of day + station + diurnal_period is unique
|
56
|
+
validates :diurnal_period_code_id,
|
57
|
+
uniqueness: { scope: [:diary, :station_id, :day_of_week] }
|
58
|
+
|
59
|
+
delegate :id, to: :diary, prefix: true
|
60
|
+
|
61
|
+
def self.policy_class
|
62
|
+
DiaryPolicy
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_master_diary?
|
66
|
+
diary&.master?
|
67
|
+
end
|
68
|
+
|
69
|
+
def description
|
70
|
+
period = diurnal_period_code.code.upcase # e.g. AM
|
71
|
+
if diary.master
|
72
|
+
"Recurring every #{day_of_week_name} #{period}"
|
73
|
+
else
|
74
|
+
"This week only on #{day_of_week_name} #{period}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def day_of_week_name
|
79
|
+
Time::DAYS_INTO_WEEK.keys[day_of_week - 1].capitalize
|
80
|
+
end
|
81
|
+
|
82
|
+
def cell_id
|
83
|
+
"#{diurnal_period_code&.id}-#{station&.id}-#{day_of_week}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
require "renalware/week_period"
|
5
|
+
##
|
6
|
+
# Returns a hospital unit's diary for the requested week (passed to #new as a WeekPeriod
|
7
|
+
# value object).
|
8
|
+
#
|
9
|
+
module Renalware
|
10
|
+
module HD
|
11
|
+
module Scheduling
|
12
|
+
class FindOrCreateDiaryByWeekQuery
|
13
|
+
attr_reader :unit_id, :period, :by, :relation
|
14
|
+
|
15
|
+
def initialize(unit_id:, week_period:, by:, relation: WeeklyDiary.all)
|
16
|
+
@relation = relation
|
17
|
+
@period = week_period
|
18
|
+
@unit_id = unit_id
|
19
|
+
@by = by
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
find_or_create_diary
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Find the diary for the current unit/week/year, or, if for example if a user wants to fill
|
29
|
+
# next week's diary and it does not yet exist, create it
|
30
|
+
# NB we _always_ return a diary from this method - whether it is found or built just-in-time
|
31
|
+
def find_or_create_diary
|
32
|
+
attrs = {
|
33
|
+
hospital_unit_id: unit_id,
|
34
|
+
week_number: period.week_number,
|
35
|
+
year: period.year,
|
36
|
+
master: false
|
37
|
+
}
|
38
|
+
relation.find_by(**attrs) || build_diary(**attrs)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create a new Weekly diary for the current week/year/unit
|
42
|
+
# Add in DiaryPeriods for each currently defined diurnal period eg am pm eve
|
43
|
+
def build_diary(attrs)
|
44
|
+
master_diary = FindOrCreateMasterDiary.for_unit(unit_id, by)
|
45
|
+
diary = WeeklyDiary.create!(**attrs, by: by, master_diary: master_diary)
|
46
|
+
# Reload the diary using the supplied relation (might be egager_loads etc)
|
47
|
+
relation.find(diary.id)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renalware
|
4
|
+
module HD
|
5
|
+
module Scheduling
|
6
|
+
class FindOrCreateMasterDiary
|
7
|
+
attr_reader :unit_id, :user
|
8
|
+
|
9
|
+
def self.for_unit(unit_id, user)
|
10
|
+
new(unit_id, user).call
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(unit_id, user)
|
14
|
+
@unit_id = unit_id
|
15
|
+
@user = user
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
MasterDiary.find_or_initialize_by(hospital_unit_id: unit_id).tap do |master|
|
20
|
+
master.by = user
|
21
|
+
master.save!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module HD
|
7
|
+
module Scheduling
|
8
|
+
class MasterDiary < Diary
|
9
|
+
# Overwrite the existing master attribute to ensure it defaults to true
|
10
|
+
attribute :master, :boolean, default: true
|
11
|
+
validates :hospital_unit_id, uniqueness: true
|
12
|
+
has_many :weekly_diaries, class_name: "WeeklyDiary"
|
13
|
+
# While our DB constraints could check for the string
|
14
|
+
# "Renalware::HD::Scheduling::MasterDiary" in the type column, this feels a bit fragile, so
|
15
|
+
# instead a MasterDiary must have a corresponding
|
16
|
+
# master = TRUE column
|
17
|
+
validates :master, inclusion: { in: [true], allow_nil: false }
|
18
|
+
|
19
|
+
class MasterSlotDecorator < SimpleDelegator
|
20
|
+
def master?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def decorate_slot(slot)
|
26
|
+
MasterSlotDecorator.new(slot)
|
27
|
+
end
|
28
|
+
|
29
|
+
def slot_for(*args)
|
30
|
+
(slot = super) && decorate_slot(slot)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/hd"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module HD
|
7
|
+
module Scheduling
|
8
|
+
class WeeklyDiary < Diary
|
9
|
+
# Overwrite the existing master attribute to ensure it defaults to false
|
10
|
+
attribute :master, :boolean, default: false
|
11
|
+
belongs_to :master_diary, class_name: "Renalware::HD::Scheduling::MasterDiary"
|
12
|
+
validates :week_number,
|
13
|
+
presence: true,
|
14
|
+
uniqueness: { scope: [:year, :hospital_unit_id] },
|
15
|
+
inclusion: { in: 1..53 }
|
16
|
+
validates :year, presence: true
|
17
|
+
validates :master, inclusion: { in: [false], allow_nil: false }
|
18
|
+
validates :master_diary, presence: true
|
19
|
+
delegate :to_s, to: :week
|
20
|
+
scope :ordered, -> { order(year: :desc, week_number: :desc) }
|
21
|
+
|
22
|
+
def applies_to_current_week?
|
23
|
+
today = Time.zone.today
|
24
|
+
[today.cweek, today.year] == [week.week_number, week.year]
|
25
|
+
end
|
26
|
+
|
27
|
+
def archived?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
class WeeklySlotDecorator < SimpleDelegator
|
32
|
+
def master?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def decorate_slot(slot)
|
38
|
+
WeeklySlotDecorator.new(slot)
|
39
|
+
end
|
40
|
+
|
41
|
+
def slot_for(*args)
|
42
|
+
(slot = super) && decorate_slot(slot)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -3,14 +3,14 @@
|
|
3
3
|
require_dependency "renalware/pathology"
|
4
4
|
|
5
5
|
#
|
6
|
-
# When subscribed to HL7 `
|
6
|
+
# When subscribed to HL7 `oru_message_arrived` messages, gets notified of incoming HL7 messages
|
7
7
|
# and creates the observations contained therein provided the patient exists.
|
8
8
|
#
|
9
9
|
module Renalware
|
10
10
|
module Pathology
|
11
11
|
class MessageListener
|
12
12
|
# Note: We are already inside a transaction here
|
13
|
-
def
|
13
|
+
def oru_message_arrived(hl7_message:, **)
|
14
14
|
pathology_params = parse_pathology_params(hl7_message)
|
15
15
|
create_observation_requests_and_their_child_observations_from(pathology_params)
|
16
16
|
#
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/pathology/requests"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Pathology
|
7
|
+
module Requests
|
8
|
+
class GlobalRule
|
9
|
+
class LatestCRFOlderThanWeeks < GlobalRule
|
10
|
+
validates :param_comparison_value, presence: true
|
11
|
+
|
12
|
+
# Returns true if the patient has a transplant registration with a latest CRF date
|
13
|
+
# older than <param_comparison_value> weeks ago.
|
14
|
+
def observation_required_for_patient?(patient, date)
|
15
|
+
registration = registration_for(patient)
|
16
|
+
return false unless registration
|
17
|
+
|
18
|
+
latest_crf_date = registration.document.crf.latest.recorded_on
|
19
|
+
return false if latest_crf_date.blank?
|
20
|
+
|
21
|
+
max_crf_date = date - param_comparison_value.to_i.weeks
|
22
|
+
latest_crf_date < max_crf_date
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"latest CRF older than #{param_comparison_value} weeks"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def registration_for(patient)
|
32
|
+
Transplants::Registration.for_patient(patient).first
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -58,7 +58,7 @@ module Renalware
|
|
58
58
|
has_many :exit_site_infections, class_name: "PD::ExitSiteInfection"
|
59
59
|
has_many :peritonitis_episodes, class_name: "PD::PeritonitisEpisode"
|
60
60
|
has_many :pd_regimes, class_name: "PD::Regime"
|
61
|
-
has_many :problems, class_name: "Problems::Problem"
|
61
|
+
has_many :problems, -> { ordered }, class_name: "Problems::Problem"
|
62
62
|
has_many :prescriptions, class_name: "Medications::Prescription"
|
63
63
|
has_many :drugs, through: :prescriptions
|
64
64
|
has_many :medication_routes, through: :prescriptions, class_name: "Medications::MedicationRoute"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/patients"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Patients
|
7
|
+
class Abridgement < ApplicationRecord
|
8
|
+
self.table_name = "patient_master_index"
|
9
|
+
validates :hospital_number, presence: true
|
10
|
+
validates :given_name, presence: true
|
11
|
+
validates :family_name, presence: true
|
12
|
+
|
13
|
+
def self.policy_class
|
14
|
+
::Renalware::BasePolicy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency "renalware/patients"
|
4
|
+
|
5
|
+
module Renalware
|
6
|
+
module Patients
|
7
|
+
module Ingestion
|
8
|
+
class Command
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
def initialize(message)
|
12
|
+
@message = message
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.for(message)
|
16
|
+
CommandFactory.new.for(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|