renalware-core 2.0.78 → 2.0.79
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/renalware/application.js.erb +1 -0
- data/app/assets/javascripts/renalware/layout.js +3 -0
- data/app/assets/stylesheets/renalware/modules/_patients.scss +2 -1
- data/app/controllers/renalware/admin/feeds/files_controller.rb +7 -1
- data/app/controllers/renalware/patients/practices_controller.rb +1 -1
- data/app/controllers/renalware/patients/primary_care_physician_controller.rb +32 -13
- data/app/controllers/renalware/virology/dashboards_controller.rb +1 -4
- data/app/controllers/renalware/virology/profiles_controller.rb +10 -5
- data/app/documents/renalware/hd/session_document.rb +4 -0
- data/app/documents/renalware/patient_document.rb +15 -1
- data/app/documents/renalware/renal/profile_document.rb +22 -0
- data/app/documents/renalware/virology/profile_document.rb +1 -0
- data/app/models/renalware/clinics/remembered_clinic_visit_preferences.rb +1 -1
- data/app/models/renalware/feeds/files/practice_memberships/import_job.rb +2 -8
- data/app/models/renalware/feeds/files/primary_care_physicians/import_csv.rb +2 -2
- data/app/models/renalware/hd/session/closed.rb +2 -0
- data/app/models/renalware/patients/last_successful_practice_sync_date_query.rb +28 -0
- data/app/models/renalware/patients/practice.rb +0 -2
- data/app/models/renalware/patients/practice_search_query.rb +4 -2
- data/app/models/renalware/patients/sync_gps_via_file_download_job.rb +52 -0
- data/app/models/renalware/patients/sync_ods_job.rb +53 -0
- data/app/models/renalware/patients/sync_practices_via_api.rb +157 -0
- data/app/models/renalware/system/api_log.rb +29 -0
- data/app/presenters/renalware/admissions/consult_summary_part.rb +36 -0
- data/app/presenters/renalware/ukrdc/patient_presenter.rb +66 -6
- data/app/presenters/renalware/virology/dashboard_presenter.rb +32 -0
- data/app/validators/renalware/patients/respiratory_rate_validator.rb +17 -0
- data/app/views/renalware/admissions/consults/_summary_part.html.slim +17 -0
- data/app/views/renalware/admissions/consults/_table.html.slim +58 -19
- data/app/views/renalware/api/ukrdc/patients/_diagnoses.xml.builder +43 -3
- data/app/views/renalware/api/ukrdc/patients/_medications.xml.builder +23 -3
- data/app/views/renalware/api/ukrdc/patients/_social_histories.xml.builder +2 -2
- data/app/views/renalware/hd/protocols/_virology.html.slim +2 -0
- data/app/views/renalware/hd/sessions/_form.html.slim +4 -0
- data/app/views/renalware/pathology/historical_observation_results/index.html.slim +2 -2
- data/app/views/renalware/virology/dashboards/_latest_hep_b_antibody_statuses.html.slim +5 -0
- data/app/views/renalware/virology/dashboards/show.html.slim +6 -3
- data/app/views/renalware/virology/profiles/_summary.html.slim +2 -2
- data/app/views/renalware/virology/profiles/edit.html.slim +1 -0
- data/config/locales/renalware/hd/session.en.yml +4 -0
- data/config/locales/renalware/virology/virology.en.yml +1 -0
- data/db/functions/import_practice_memberships_csv_v03.sql +65 -0
- data/db/migrate/20190531172829_add_last_change_date_to_patient_practices.rb +26 -0
- data/db/migrate/20190602114659_create_system_api_logs.rb +15 -0
- data/db/migrate/20190603084428_add_pages_to_system_api_logs.rb +5 -0
- data/db/migrate/20190603135247_add_columns_to_patient_primary_care_physicians.rb +8 -0
- data/db/migrate/20190603143834_update_import_practice_memberships_csv.rb +13 -0
- data/db/migrate/20190603165812_drop_import_practices_csv_function.rb +13 -0
- data/db/seeds/default/feeds/import_file_types.rb +0 -8
- data/db/seeds/default/renal/prd_descriptions.csv +266 -266
- data/lib/document/enum.rb +4 -0
- data/lib/renalware/configuration.rb +1 -0
- data/lib/renalware/version.rb +1 -1
- data/lib/tasks/feeds/files.rake +0 -16
- data/lib/tasks/hd.rake +2 -0
- data/lib/tasks/ods.rake +10 -0
- data/spec/factories/feeds/file.rb +0 -4
- data/spec/factories/feeds/file_types.rb +2 -7
- data/spec/factories/hd/hd_session_document.rb +2 -0
- data/spec/factories/system/api_logs.rb +19 -0
- data/spec/support/pathology_spec_helper.rb +12 -8
- data/vendor/assets/javascripts/renalware/double_scroll.js +128 -0
- metadata +23 -9
- data/app/models/renalware/feeds/files/practices/convert_xml_to_csv.rb +0 -153
- data/app/models/renalware/feeds/files/practices/country_map.rb +0 -36
- data/app/models/renalware/feeds/files/practices/csv_file.rb +0 -25
- data/app/models/renalware/feeds/files/practices/csv_organisation.rb +0 -37
- data/app/models/renalware/feeds/files/practices/import_csv.rb +0 -32
- data/app/models/renalware/feeds/files/practices/import_job.rb +0 -61
- data/app/models/renalware/feeds/files/practices/xml_parser.rb +0 -102
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_dependency "renalware/feeds"
|
4
|
-
|
5
|
-
module Renalware
|
6
|
-
module Feeds
|
7
|
-
module Files
|
8
|
-
module Practices
|
9
|
-
class CountryMap
|
10
|
-
UK_COUNTRIES = [
|
11
|
-
"ENGLAND",
|
12
|
-
"WALES",
|
13
|
-
"SCOTLAND",
|
14
|
-
"NORTHERN IRELAND"
|
15
|
-
].freeze
|
16
|
-
|
17
|
-
class Country
|
18
|
-
include Virtus.model
|
19
|
-
attribute :region
|
20
|
-
attribute :country
|
21
|
-
end
|
22
|
-
|
23
|
-
def map(country)
|
24
|
-
return if country.blank?
|
25
|
-
|
26
|
-
if UK_COUNTRIES.include?(country.upcase.strip)
|
27
|
-
Country.new(country: "United Kingdom", region: country.strip.titleize)
|
28
|
-
else
|
29
|
-
Country.new(country: country)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_dependency "renalware/feeds"
|
4
|
-
|
5
|
-
module Renalware
|
6
|
-
module Feeds
|
7
|
-
module Files
|
8
|
-
module Practices
|
9
|
-
class CSVFile
|
10
|
-
include Virtus.model
|
11
|
-
attribute :dir, Pathname
|
12
|
-
|
13
|
-
def create
|
14
|
-
path = ::File.join(dir, "practices.csv")
|
15
|
-
CSV.open(path, "wb", quote_char: '"', force_quotes: false) do |csv|
|
16
|
-
csv << CSVOrganisation.headers
|
17
|
-
yield(csv)
|
18
|
-
end
|
19
|
-
path
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_dependency "renalware/feeds"
|
4
|
-
|
5
|
-
module Renalware
|
6
|
-
module Feeds
|
7
|
-
module Files
|
8
|
-
module Practices
|
9
|
-
class CSVOrganisation
|
10
|
-
include Virtus.model
|
11
|
-
attribute :code, String
|
12
|
-
attribute :name, String
|
13
|
-
attribute :telephone, String
|
14
|
-
attribute :street_1, String
|
15
|
-
attribute :street_2, String
|
16
|
-
attribute :street_3, String
|
17
|
-
attribute :city, String
|
18
|
-
attribute :county, String
|
19
|
-
attribute :postcode, String
|
20
|
-
attribute :region, String # used to capture England, Wales etc
|
21
|
-
attribute :country_id, Integer # will normally be id for United Kingdom country
|
22
|
-
attribute :roles
|
23
|
-
attribute :active
|
24
|
-
attribute :skip, Boolean
|
25
|
-
|
26
|
-
def self.headers
|
27
|
-
attribute_set.map(&:name) - [:roles, :skip]
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_a
|
31
|
-
self.class.headers.map { |key| public_send(key) }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_dependency "renalware/feeds"
|
4
|
-
require "attr_extras"
|
5
|
-
|
6
|
-
module Renalware
|
7
|
-
module Feeds
|
8
|
-
module Files
|
9
|
-
module Practices
|
10
|
-
class ImportCSV
|
11
|
-
pattr_initialize :csv_path
|
12
|
-
|
13
|
-
def call
|
14
|
-
Rails.logger.info("Importing CSV file #{csv_path}...")
|
15
|
-
import_practices_csv_using_sql_function
|
16
|
-
Rails.logger.info("... done")
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
# See migration for SQL function definition
|
22
|
-
def import_practices_csv_using_sql_function
|
23
|
-
conn = ActiveRecord::Base.connection
|
24
|
-
conn.execute(
|
25
|
-
"SELECT import_practices_csv(#{conn.quote(csv_path.realpath.to_s)})"
|
26
|
-
)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_dependency "renalware/feeds"
|
4
|
-
|
5
|
-
module Renalware
|
6
|
-
module Feeds
|
7
|
-
module Files
|
8
|
-
module Practices
|
9
|
-
class ImportJob < ApplicationJob
|
10
|
-
include StringLogging
|
11
|
-
include Feeds::Job
|
12
|
-
FILE_TO_EXTRACT_FROM_ARCHIVE = /HSCOrgRefData_Full_/
|
13
|
-
|
14
|
-
# Initialize with the absolute path to an fullfile.zip file
|
15
|
-
# e.g. /Users/tim/Downloads/hscorgrefdataxml_data_1.0.1_20170526000001.zip
|
16
|
-
# downloaded from
|
17
|
-
# https://isd.digital.nhs.uk/trud3/user/authenticated/group/0/pack/5/subpack/341/releases
|
18
|
-
#
|
19
|
-
# Example usage:
|
20
|
-
# # Download and unzip hscorgrefdataxml_data_1.0.1_000001.zip and grab the fullfile.zip
|
21
|
-
# Practices::Import.new("/Users/tim/Downloads/fullfile.zip")
|
22
|
-
|
23
|
-
# Arguments:
|
24
|
-
# file - a Feeds::File object previously persisted.
|
25
|
-
def perform(file)
|
26
|
-
logging_to_stringio(strio = StringIO.new) # so we can write the error to the File model
|
27
|
-
file.update!(status: :processing, attempts: file.attempts + 1)
|
28
|
-
status = :success
|
29
|
-
elapsed_ms = Benchmark.ms do
|
30
|
-
process_archive(file.location)
|
31
|
-
end
|
32
|
-
rescue StandardError => e
|
33
|
-
Rails.logger.error(formatted_exception(e))
|
34
|
-
status = :failure
|
35
|
-
raise e
|
36
|
-
ensure
|
37
|
-
file.update!(status: status, result: strio.string, time_taken: elapsed_ms)
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def process_archive(zipfile)
|
43
|
-
log "Practice count before update: #{practice_count}"
|
44
|
-
log "Opening #{zipfile}"
|
45
|
-
ZipArchive.new(zipfile).unzip do |files|
|
46
|
-
xml_pathname = find_file_in(files, FILE_TO_EXTRACT_FROM_ARCHIVE)
|
47
|
-
csv_path = Practices::ConvertXmlToCsv.call(xml_pathname)
|
48
|
-
FileUtils.copy(csv_path, Rails.root.join("generated_organisations.csv"))
|
49
|
-
Practices::ImportCSV.new(csv_path).call
|
50
|
-
end
|
51
|
-
log "Practice count after update: #{practice_count}"
|
52
|
-
end
|
53
|
-
|
54
|
-
def practice_count
|
55
|
-
Renalware::Patients::Practice.count
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
4
|
-
# rubocop:disable Metrics/AbcSize
|
5
|
-
# -----
|
6
|
-
# From https://gist.github.com/kmile/827475
|
7
|
-
# A small DSL for helping parsing documents using Nokogiri::XML::Reader. The
|
8
|
-
# XML Reader is a good way to move a cursor through a (large) XML document fast,
|
9
|
-
# but is not as cumbersome as writing a full SAX document handler. Read about
|
10
|
-
# it here: http://nokogiri.org/Nokogiri/XML/Reader.html
|
11
|
-
#
|
12
|
-
# Just pass the reader in this parser and specify the nodes that you are interested
|
13
|
-
# in in a block. You can just parse every node or only look inside certain nodes.
|
14
|
-
#
|
15
|
-
# A small example:
|
16
|
-
#
|
17
|
-
# Xml::Parser.new(Nokogiri::XML::Reader(open(file))) do
|
18
|
-
# inside_element 'User' do
|
19
|
-
# for_element 'Name' do puts "Username: #{inner_xml}" end
|
20
|
-
# for_element 'Email' do puts "Email: #{inner_xml}" end
|
21
|
-
#
|
22
|
-
# for_element 'Address' do
|
23
|
-
# puts 'Start of address:'
|
24
|
-
# inside_element do
|
25
|
-
# for_element 'Street' do puts "Street: #{inner_xml}" end
|
26
|
-
# for_element 'Zipcode' do puts "Zipcode: #{inner_xml}" end
|
27
|
-
# for_element 'City' do puts "City: #{inner_xml}" end
|
28
|
-
# end
|
29
|
-
# puts 'End of address'
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# It does NOT fail on missing tags, and does not guarantee order of execution. It parses
|
35
|
-
# every tag regardless of nesting. The only way to guarantee scope is by using
|
36
|
-
# the `inside_element` method. This limits the parsing to the current or the named tag.
|
37
|
-
# If tags are encountered multiple times, their blocks will be called multiple times.
|
38
|
-
|
39
|
-
require "nokogiri"
|
40
|
-
require_dependency "renalware/feeds"
|
41
|
-
|
42
|
-
# Note I moved XmlParse into this namespace as I was getting strange
|
43
|
-
# 'uninitialised constant XmlParser' errors in production when it was in /lib
|
44
|
-
|
45
|
-
module Renalware
|
46
|
-
module Feeds
|
47
|
-
module Files
|
48
|
-
module Practices
|
49
|
-
class XmlParser
|
50
|
-
def initialize(node, &block)
|
51
|
-
@node = node
|
52
|
-
@node.each do
|
53
|
-
self.instance_eval(&block)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def name
|
58
|
-
@node.name
|
59
|
-
end
|
60
|
-
|
61
|
-
def inner_xml
|
62
|
-
@node.inner_xml.strip
|
63
|
-
end
|
64
|
-
|
65
|
-
def is_start?
|
66
|
-
@node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
|
67
|
-
end
|
68
|
-
|
69
|
-
def is_end?
|
70
|
-
@node.node_type == Nokogiri::XML::Reader::TYPE_END_ELEMENT
|
71
|
-
end
|
72
|
-
|
73
|
-
def attribute(attribute)
|
74
|
-
@node.attribute(attribute)
|
75
|
-
end
|
76
|
-
|
77
|
-
def for_element(name, &block)
|
78
|
-
return unless self.name == name and is_start?
|
79
|
-
|
80
|
-
self.instance_eval(&block)
|
81
|
-
end
|
82
|
-
|
83
|
-
def inside_element(name = nil, &block)
|
84
|
-
return if @node.self_closing?
|
85
|
-
return unless name.nil? or (self.name == name and is_start?)
|
86
|
-
|
87
|
-
name = @node.name
|
88
|
-
depth = @node.depth
|
89
|
-
|
90
|
-
@node.each do
|
91
|
-
return if self.name == name and is_end? and @node.depth == depth
|
92
|
-
|
93
|
-
self.instance_eval(&block)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
102
|
-
# rubocop:enable Metrics/AbcSize
|