renalware-core 2.0.146 → 2.0.147

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/renalware/charting.js +1 -1
  3. data/app/assets/javascripts/renalware/rollup_compiled.js +87 -0
  4. data/app/assets/stylesheets/renalware/partials/_forms.scss +5 -0
  5. data/app/components/renalware/system/admin_menu_component.html.slim +1 -0
  6. data/app/controllers/renalware/admin/playgrounds_controller.rb +65 -0
  7. data/app/controllers/renalware/deaths_controller.rb +6 -5
  8. data/app/controllers/renalware/medications/home_delivery/events_controller.rb +0 -3
  9. data/app/controllers/renalware/medications/home_delivery/prescriptions_controller.rb +43 -0
  10. data/app/controllers/renalware/patients/primary_care_physician_controller.rb +6 -0
  11. data/app/javascript/renalware/controllers/charts_controller.js +52 -0
  12. data/app/javascript/renalware/controllers/medications/prescriptions_controller.js +24 -0
  13. data/app/javascript/renalware/index.js +6 -0
  14. data/app/models/renalware/medications.rb +2 -0
  15. data/app/models/renalware/medications/delivery/prescriptions_due_for_delivery_query.rb +53 -0
  16. data/app/models/renalware/patient.rb +4 -0
  17. data/app/models/renalware/patients/deceased_patients_query.rb +42 -0
  18. data/app/models/renalware/ukrdc/create_encrypted_patient_xml_files.rb +44 -16
  19. data/app/models/renalware/ukrdc/create_patient_xml_file.rb +1 -1
  20. data/app/views/renalware/accesses/assessments/_form.html.slim +2 -2
  21. data/app/views/renalware/accesses/plans/new.html.slim +1 -1
  22. data/app/views/renalware/accesses/procedures/_form.html.slim +2 -2
  23. data/app/views/renalware/accesses/profiles/_form.html.slim +2 -2
  24. data/app/views/renalware/admin/playgrounds/pathology_chart_data.js.erb +1 -0
  25. data/app/views/renalware/admin/playgrounds/show.html.slim +59 -0
  26. data/app/views/renalware/admin/users/_filters.html.slim +1 -1
  27. data/app/views/renalware/admissions/admissions/index.html.slim +2 -2
  28. data/app/views/renalware/admissions/consults/_form.html.slim +1 -1
  29. data/app/views/renalware/admissions/consults/index.html.slim +2 -2
  30. data/app/views/renalware/deaths/index.html.slim +18 -10
  31. data/app/views/renalware/events/events/toggled_cell/_biopsy.html.slim +1 -1
  32. data/app/views/renalware/events/events/toggled_cell/_simple.html.slim +1 -1
  33. data/app/views/renalware/events/events/toggled_cell/_swab.html.slim +1 -1
  34. data/app/views/renalware/hd/transmission_logs/index.html.slim +1 -2
  35. data/app/views/renalware/letters/mailshots/mailshots/_form.html.slim +2 -1
  36. data/app/views/renalware/mdm_patients/_patient.html.slim +1 -2
  37. data/app/views/renalware/medications/drug_types/prescriptions/_filters.html.slim +1 -3
  38. data/app/views/renalware/medications/home_delivery/prescriptions/index.html.slim +51 -0
  39. data/app/views/renalware/medications/prescriptions/_filter_form.html.slim +1 -1
  40. data/app/views/renalware/medications/prescriptions/_form.html.slim +20 -12
  41. data/app/views/renalware/navigation/_renal.html.slim +2 -0
  42. data/app/views/renalware/patients/_header.html.slim +1 -1
  43. data/app/views/renalware/patients/alerts/_alert.html.slim +1 -1
  44. data/app/views/renalware/patients/alerts/_form.html.slim +1 -1
  45. data/app/views/renalware/patients/patients/_form.html.slim +1 -2
  46. data/app/views/renalware/patients/patients/new.html.slim +6 -5
  47. data/app/views/renalware/patients/patients/show/_primary_care_physician.html.slim +9 -1
  48. data/app/views/renalware/patients/primary_care_physician/destroy.js.erb +1 -0
  49. data/app/views/renalware/pd/dashboards/show/_page_actions.html.slim +2 -2
  50. data/app/views/renalware/pd/exit_site_infections/show.html.slim +1 -1
  51. data/app/views/renalware/pd/peritonitis_episodes/show.html.slim +1 -1
  52. data/app/views/renalware/reporting/audits/edit.html.slim +1 -3
  53. data/app/views/renalware/research/_alert.html.slim +1 -1
  54. data/app/views/renalware/snippets/snippets/_row.html.slim +3 -4
  55. data/app/views/renalware/system/downloads/index.html.slim +2 -3
  56. data/app/views/renalware/transplants/live_donors/_filters.html.slim +2 -2
  57. data/config/initializers/groupdate.rb +3 -0
  58. data/config/locales/renalware/medications/prescription.yml +2 -1
  59. data/config/locales/renalware/navigation/renal.en.yml +1 -0
  60. data/config/routes/admin.rb +5 -0
  61. data/config/routes/medications.rb +5 -0
  62. data/config/routes/patients.rb +1 -1
  63. data/db/functions/pathology_chart_data_v01.sql +13 -0
  64. data/db/migrate/20200313120655_create_pathology_chart_data_function.rb +13 -0
  65. data/lib/renalware/engine.rb +1 -0
  66. data/lib/renalware/version.rb +1 -1
  67. data/spec/support/pages/medications/prescription_fom.rb +2 -2
  68. data/vendor/assets/javascripts/renalware/highcharts.js +506 -0
  69. metadata +32 -5
  70. data/app/views/renalware/medications/home_delivery/prescriptions/index.pdf.slim +0 -103
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea66f0da3fb417c2ff7f515964db415e68e61f447fdf742c97906d635aecb7a6
4
- data.tar.gz: a1f6203e5b3f637bd9a85413ddbfe25739916e1ac33dc1f44e080acb4303f533
3
+ metadata.gz: a0a85e291938153f0f3d994195230457b6550239d0e8dde9e7d4a0b8a72f7819
4
+ data.tar.gz: 34d8b8b3b54731448ec32c05c136e3f371e4725a5a7efc2f7946264d041153d0
5
5
  SHA512:
6
- metadata.gz: d0269f2b3d9fdda86ea868fdf074314cce11f647030768d922ebfe1650eaf67fcd8f22bf321bd4f409daf2e4c1f991934b1e817e4ef213ccf37d873ced1fe797
7
- data.tar.gz: 740773f49f38ab01bfea92f1a06dc0c1cc83af18ccc8a7d483bb1ea01aaff2a71501df866f28de44c21d178b81d59e204660dc7c9d7a7a085b33b7b9fbfc2eb9
6
+ metadata.gz: 2da7dbc33f709e9effcb837f78c0678bbe375d977e8c276aa70dbcb2f94366f5df7c518f554ccd9f8611a3b801a2e74c4a11ffb21a08356d6fcd77e15b0015ed
7
+ data.tar.gz: a1d6d42f2adf772b8201e982fd8cb850403ce6cd70c87820b96a581356f7dab2efdc826db6bc96ba628b8ae44a39790c236f725bfee3a68170cc75ca91941bd4
@@ -1,2 +1,2 @@
1
1
  //= require chartkick
2
- //= require Chart.bundle
2
+ //= require highcharts
@@ -3923,6 +3923,87 @@ var _default$4 = function(_Controller) {
3923
3923
 
3924
3924
  _defineProperty(_default$4, "targets", [ "trix" ]);
3925
3925
 
3926
+ var _default$5 = function(_Controller) {
3927
+ _inherits(_default, _Controller);
3928
+ function _default() {
3929
+ _classCallCheck(this, _default);
3930
+ return _possibleConstructorReturn(this, _getPrototypeOf(_default).apply(this, arguments));
3931
+ }
3932
+ _createClass(_default, [ {
3933
+ key: "connect",
3934
+ value: function connect() {
3935
+ var radio_value = this.providersTarget.querySelector("input:checked").value;
3936
+ this.toggleDeliveryDatesVisibility(radio_value);
3937
+ }
3938
+ }, {
3939
+ key: "toggleDeliveryDates",
3940
+ value: function toggleDeliveryDates(event) {
3941
+ this.toggleDeliveryDatesVisibility(event.target.value);
3942
+ }
3943
+ }, {
3944
+ key: "toggleDeliveryDatesVisibility",
3945
+ value: function toggleDeliveryDatesVisibility(radio_value) {
3946
+ if (radio_value == "home_delivery") {
3947
+ this.homeDeliveryDatesTarget.style.display = "block";
3948
+ } else {
3949
+ this.homeDeliveryDatesTarget.style.display = "none";
3950
+ }
3951
+ }
3952
+ } ]);
3953
+ return _default;
3954
+ }(Controller);
3955
+
3956
+ _defineProperty(_default$5, "targets", [ "homeDeliveryDates", "providers" ]);
3957
+
3958
+ var Chartkick = window.Chartkick;
3959
+
3960
+ var _default$6 = function(_Controller) {
3961
+ _inherits(_default, _Controller);
3962
+ function _default() {
3963
+ _classCallCheck(this, _default);
3964
+ return _possibleConstructorReturn(this, _getPrototypeOf(_default).apply(this, arguments));
3965
+ }
3966
+ _createClass(_default, [ {
3967
+ key: "redisplay",
3968
+ value: function redisplay(event) {
3969
+ var json = event.detail[0];
3970
+ if (this.chartCreated()) {
3971
+ this.chartTarget.getChartObject().updateData(json);
3972
+ } else {
3973
+ new Chartkick.LineChart("chart1", json, this.chartOptions);
3974
+ }
3975
+ }
3976
+ }, {
3977
+ key: "chartCreated",
3978
+ value: function chartCreated() {
3979
+ return Object.prototype.hasOwnProperty.call(this.chartTarget, "getChartObject");
3980
+ }
3981
+ }, {
3982
+ key: "chartOptions",
3983
+ get: function get() {
3984
+ return {
3985
+ curve: false,
3986
+ library: {
3987
+ chart: {
3988
+ zoomType: "x"
3989
+ },
3990
+ plotOptions: {
3991
+ series: {
3992
+ animation: {
3993
+ duration: 400
3994
+ }
3995
+ }
3996
+ },
3997
+ colors: [ "#005eb8", "#009639", "#434348", "#90ed7d", "#f7a35c", "#8085e9", "#f15c80", "#e4d354" ]
3998
+ }
3999
+ };
4000
+ }
4001
+ } ]);
4002
+ return _default;
4003
+ }(Controller);
4004
+
4005
+ _defineProperty(_default$6, "targets", [ "chart" ]);
4006
+
3926
4007
  var application = Application.start();
3927
4008
 
3928
4009
  application.register("toggle", _default);
@@ -3934,3 +4015,9 @@ application.register("home-delivery-modal", _default$2);
3934
4015
  application.register("snippets", _default$3);
3935
4016
 
3936
4017
  application.register("letters-form", _default$4);
4018
+
4019
+ application.register("prescriptions", _default$5);
4020
+
4021
+ application.register("charts", _default$6);
4022
+
4023
+ window.Chartkick.use(window.Highcharts);
@@ -207,6 +207,11 @@ article {
207
207
  float: right;
208
208
  padding: 0.3rem 0.4rem;
209
209
  text-decoration: none;
210
+ margin-left: 0.5rem;
211
+
212
+ &.button-danger {
213
+ background-color: $nhs-red;
214
+ }
210
215
  }
211
216
 
212
217
  .button:hover {
@@ -23,4 +23,5 @@ ul.side-nav.side-nav--admin
23
23
  = super_admin_menu_item "HD Cannulation Types", renalware.hd_cannulation_types_path, %r{hd/cannulation_types}
24
24
  = super_admin_menu_item "Print batches", renalware.letters_batches_path, %r{letters/batches}
25
25
  = admin_menu_item "Mailshots", renalware.letters_mailshots_path, %r{letters/mailshots}
26
+ = super_admin_menu_item "Playground", renalware.admin_playground_path, %r{admin/playground}
26
27
  = developer_menu_item "HL7 Test", renalware.new_feeds_hl7_test_message_path
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Renalware
4
+ class Admin::PlaygroundsController < BaseController
5
+ def show
6
+ authorize User, :index?
7
+ render locals: { form: ChartForm.new(obx_code: "CRE", period: "all") }
8
+ end
9
+
10
+ # Returns test json to display a chart of one obx code over time for a patient
11
+ def pathology_chart_data
12
+ authorize User, :index?
13
+ form = ChartForm.new(chart_params)
14
+ chart = Chart.new(form)
15
+ render json: chart.json
16
+ end
17
+
18
+ class ChartForm
19
+ include ActiveModel::Model
20
+ include Virtus::Model
21
+
22
+ attribute :patient_id, Integer
23
+ attribute :obx_code, String
24
+ attribute :period, String
25
+
26
+ # Map a period string to a date, eg 6m = 6 months ago
27
+ def start_date
28
+ time = case period
29
+ when "yr" then 1.year.ago
30
+ when "6m" then 6.months.ago
31
+ when "3m" then 3.months.ago
32
+ when "1m" then 1.month.ago
33
+ when "1wk" then 1.week.ago
34
+ else 100.years.ago
35
+ end
36
+ time.to_date.to_s
37
+ end
38
+ end
39
+
40
+ def chart_params
41
+ return {} unless params.key?(:chart)
42
+
43
+ params.require(:chart).permit!
44
+ end
45
+
46
+ class Chart
47
+ pattr_initialize :form
48
+
49
+ def json
50
+ return {} if form.patient_id.blank?
51
+
52
+ ActiveRecord::Base.connection.execute(
53
+ Arel.sql(<<-SQL)
54
+ select
55
+ observed_on as x,
56
+ result as y
57
+ from renalware.pathology_chart_data(#{form.patient_id},
58
+ '#{form.obx_code}',
59
+ '#{form.start_date}')
60
+ SQL
61
+ ).to_a.each_with_object({}) { |h, hash| hash[Date.parse(h["x"])] = h["y"] }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -3,15 +3,16 @@
3
3
  module Renalware
4
4
  class DeathsController < BaseController
5
5
  include PresenterHelper
6
- include Renalware::Concerns::Pageable
6
+ include Pagy::Backend
7
7
 
8
8
  def index
9
- patients = Patient.dead.page(page).per(per_page)
10
- search = patients.ransack(params[:q])
9
+ query = Patients::DeceasedPatientsQuery.new(params[:q])
10
+ pagy, patients = pagy(query.call.includes(previous_modality: :description))
11
11
  authorize patients
12
12
  render locals: {
13
- patients: present(search.result, PatientPresenter),
14
- q: search
13
+ patients: present(patients, PatientPresenter),
14
+ q: query.search,
15
+ pagy: pagy
15
16
  }
16
17
  end
17
18
 
@@ -31,9 +31,7 @@ module Renalware
31
31
  authorize event
32
32
 
33
33
  event.prescriptions = prescriptions_for(event)
34
-
35
34
  event.valid?
36
- # byebug
37
35
  render(:edit, layout: false, locals: { event: event })
38
36
  end
39
37
 
@@ -64,7 +62,6 @@ module Renalware
64
62
  last_delivery_date: last_delivery_date,
65
63
  next_delivery_date: next_delivery_date
66
64
  )
67
-
68
65
  end
69
66
  render :update, locals: { event: event }
70
67
  else
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/medications"
4
+
5
+ module Renalware
6
+ module Medications
7
+ module HomeDelivery
8
+ class PrescriptionsController < BaseController
9
+ include Pagy::Backend
10
+
11
+ def index
12
+ form = SearchForm.new(search_params)
13
+ query = Medications::Delivery::PrescriptionsDueForDeliveryQuery.new(
14
+ drug_type_code: params[:named_filter],
15
+ modality_description_id: form.modality_description_id,
16
+ query: params[:q]
17
+ )
18
+ pagy, prescriptions = pagy(query.call)
19
+ authorize prescriptions
20
+ render :index, locals: {
21
+ prescriptions: prescriptions,
22
+ pagy: pagy,
23
+ query: query.search,
24
+ form: form
25
+ }
26
+ end
27
+
28
+ class SearchForm
29
+ include ActiveModel::Model
30
+ include Virtus::Model
31
+
32
+ attribute :modality_description_id, Integer
33
+ end
34
+
35
+ def search_params
36
+ return {} unless params.key?(:search)
37
+
38
+ params.require(:search).permit(:modality_description_id)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -26,6 +26,12 @@ module Renalware
26
26
  end
27
27
  end
28
28
 
29
+ def destroy
30
+ authorize patient
31
+ patient.update_by(current_user, primary_care_physician_id: nil, practice_id: nil)
32
+ render locals: { patient: patient }
33
+ end
34
+
29
35
  private
30
36
 
31
37
  # There maybe times (for instance after migration from a previous system) where the
@@ -0,0 +1,52 @@
1
+ // NB Chartkick and Highcharts are defined as global in rollup
2
+ const Chartkick = window.Chartkick
3
+
4
+ import { Controller } from "stimulus"
5
+
6
+ export default class extends Controller {
7
+ static targets = [ "chart" ]
8
+
9
+ // Called on ajax:success
10
+ redisplay(event) {
11
+ // let [json, status, xhr] = event.detail
12
+ let json = event.detail[0]
13
+ if (this.chartCreated()) {
14
+ this.chartTarget.getChartObject().updateData(json)
15
+ } else {
16
+ new Chartkick.LineChart("chart1", json, this.chartOptions)
17
+ }
18
+ }
19
+
20
+ // Returns true if the chart target has already been initialised
21
+ chartCreated() {
22
+ return Object.prototype.hasOwnProperty.call(this.chartTarget, "getChartObject")
23
+ }
24
+
25
+ get chartOptions() {
26
+ return {
27
+ curve: false,
28
+ library: {
29
+ chart: {
30
+ zoomType: "x"
31
+ },
32
+ plotOptions: {
33
+ series: {
34
+ animation: {
35
+ duration: 400
36
+ }
37
+ }
38
+ },
39
+ colors: [
40
+ "#005eb8",
41
+ "#009639",
42
+ "#434348",
43
+ "#90ed7d",
44
+ "#f7a35c",
45
+ "#8085e9",
46
+ "#f15c80",
47
+ "#e4d354"
48
+ ]
49
+ }
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,24 @@
1
+ import { Controller } from "stimulus"
2
+
3
+ // Handles the modal dialog used for presenting Home Delivery print options to
4
+ // the user. Used on the prescrptions page.
5
+ export default class extends Controller {
6
+ static targets = [ "homeDeliveryDates", "providers" ]
7
+
8
+ connect() {
9
+ let radio_value = this.providersTarget.querySelector("input:checked").value
10
+ this.toggleDeliveryDatesVisibility(radio_value)
11
+ }
12
+
13
+ toggleDeliveryDates(event) {
14
+ this.toggleDeliveryDatesVisibility(event.target.value)
15
+ }
16
+
17
+ toggleDeliveryDatesVisibility(radio_value) {
18
+ if (radio_value == "home_delivery") {
19
+ this.homeDeliveryDatesTarget.style.display = "block"
20
+ } else {
21
+ this.homeDeliveryDatesTarget.style.display = "none"
22
+ }
23
+ }
24
+ }
@@ -18,6 +18,8 @@ import HDPrescriptionController from "./controllers/hd/prescription_administrati
18
18
  import MedicationsHomeDeliveryModalController from "./controllers/medications/home_delivery_modal_controller"
19
19
  import SnippetsController from "./controllers/snippets_controller"
20
20
  import LettersFormController from "./controllers/letters/form_controller"
21
+ import PrescriptionsController from "./controllers/medications/prescriptions_controller"
22
+ import ChartsController from "./controllers/charts_controller"
21
23
 
22
24
  const application = Application.start()
23
25
  application.register("toggle", ToggleController)
@@ -25,3 +27,7 @@ application.register("hd-prescription-administration", HDPrescriptionController)
25
27
  application.register("home-delivery-modal", MedicationsHomeDeliveryModalController)
26
28
  application.register("snippets", SnippetsController)
27
29
  application.register("letters-form", LettersFormController)
30
+ application.register("prescriptions", PrescriptionsController)
31
+ application.register("charts", ChartsController)
32
+
33
+ window.Chartkick.use(window.Highcharts)
@@ -9,6 +9,8 @@ module Renalware
9
9
  end
10
10
 
11
11
  module Delivery
12
+ DRUG_TYPE_FILTERS = %i(esa immunosuppressant).freeze
13
+
12
14
  def self.table_name_prefix
13
15
  "medication_delivery_"
14
16
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/medications"
4
+
5
+ module Renalware
6
+ module Medications
7
+ module Delivery
8
+ # Find current home delivery prescriptions with a next_delivery_date falling
9
+ # within the specified range.
10
+ class PrescriptionsDueForDeliveryQuery
11
+ attr_reader :drug_type_code, :from, :to, :query, :modality_description_id
12
+
13
+ def initialize(
14
+ drug_type_code: nil,
15
+ from: nil,
16
+ to: nil,
17
+ modality_description_id: nil,
18
+ query: {}
19
+ )
20
+ @from = (from || 4.weeks.ago).beginning_of_day
21
+ @to = (to || 2.weeks.since).end_of_day
22
+ @drug_type_code = drug_type_code
23
+ @query = query
24
+ @modality_description_id = modality_description_id
25
+ end
26
+
27
+ def call
28
+ query = search.result
29
+ .current
30
+ .includes(:patient)
31
+ .eager_load(drug: [:classifications, :drug_types])
32
+ .joins("inner join patient_current_modalities pcm on pcm.patient_id = patients.id")
33
+ .where(provider: :home_delivery)
34
+ .where(next_delivery_date: (from..to))
35
+ .order(next_delivery_date: :asc)
36
+
37
+ if drug_type_code.present?
38
+ query = query.where("lower(drug_types.code) = ?", drug_type_code)
39
+ end
40
+
41
+ if modality_description_id.present?
42
+ query = query.where("pcm.modality_description_id = ?", modality_description_id)
43
+ end
44
+ query
45
+ end
46
+
47
+ def search
48
+ @search ||= Medications::Prescription.ransack(query)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end