renalware-core 2.0.139 → 2.0.140

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/renalware/rollup_compiled.js +50 -0
  3. data/app/assets/stylesheets/renalware/medications_pdf.scss +17 -1
  4. data/app/assets/stylesheets/renalware/modules/_medications.scss +17 -0
  5. data/app/assets/stylesheets/renalware/partials/_utilities.scss +8 -0
  6. data/app/controllers/renalware/medications/home_delivery/events_controller.rb +134 -0
  7. data/app/javascript/renalware/controllers/foundation_modal_controller.js +19 -0
  8. data/app/javascript/renalware/controllers/medications/home_delivery_modal_controller.js +24 -0
  9. data/app/javascript/renalware/index.js +4 -0
  10. data/app/models/renalware/drugs/homecare_form.rb +17 -0
  11. data/app/models/renalware/drugs/supplier.rb +12 -0
  12. data/app/models/renalware/feeds/hl7_message.rb +2 -2
  13. data/app/models/renalware/medications.rb +6 -0
  14. data/app/models/renalware/medications/delivery/event.rb +48 -0
  15. data/app/models/renalware/medications/delivery/event_prescription.rb +24 -0
  16. data/app/models/renalware/medications/delivery/homecare_forms_adapter.rb +104 -0
  17. data/app/models/renalware/medications/delivery/purchase_order_number.rb +27 -0
  18. data/app/models/renalware/medications/prescriptions_by_drug_type_id_query.rb +21 -0
  19. data/app/models/renalware/medications/provider.rb +20 -0
  20. data/app/views/renalware/medications/home_delivery/events/_edit.html.slim +71 -0
  21. data/app/views/renalware/medications/home_delivery/events/edit.html.slim +1 -0
  22. data/app/views/renalware/medications/home_delivery/events/edit.js.erb +4 -0
  23. data/app/views/renalware/medications/home_delivery/events/new.js.erb +3 -0
  24. data/app/views/renalware/medications/home_delivery/events/update.js.erb +5 -0
  25. data/app/views/renalware/medications/home_delivery/prescriptions/index.pdf.slim +4 -1
  26. data/app/views/renalware/medications/prescriptions/_form.html.slim +4 -0
  27. data/app/views/renalware/medications/prescriptions/index.html.slim +15 -5
  28. data/app/views/renalware/shared/_modal_close_link.html.slim +1 -1
  29. data/config/routes/medications.rb +5 -4
  30. data/db/migrate/20200301113102_create_drug_homecare_suppliers.rb +73 -0
  31. data/db/migrate/20200301124200_create_medication_delivery_events.rb +49 -0
  32. data/db/migrate/20200301124300_create_medication_delivery_event_prescriptions.rb +35 -0
  33. data/db/migrate/20200306183423_add_next_delivery_date_to_prescriptions.rb +7 -0
  34. data/lib/renalware/configuration.rb +7 -0
  35. data/lib/renalware/engine.rb +1 -0
  36. data/lib/renalware/version.rb +1 -1
  37. data/spec/factories/drugs/homecare_forms.rb +13 -0
  38. data/spec/factories/drugs/suppliers.rb +7 -0
  39. data/spec/factories/medications/delivery/events.rb +13 -0
  40. data/spec/support/pages/medications/home_delivery_dialog.rb +77 -0
  41. metadata +39 -13
  42. data/app/controllers/renalware/medications/home_delivery/prescriptions_controller.rb +0 -51
  43. data/app/models/renalware/letters/printing/create_pdf_by_interleaving_address_sheet_and_letter_for_each_recipient.rb.dead +0 -90
  44. data/app/models/renalware/pathology/consultant.rb.dead +0 -10
  45. data/app/models/renalware/pathology/view_observation_results.rb.dead +0 -64
  46. data/app/models/renalware/patients/ingestion/update_master_patient_index_job.rb.dead +0 -20
  47. data/app/presenters/renalware/admin/users/summary_part.rb.dead +0 -25
  48. data/app/presenters/renalware/ukrdc/modality_presenter.rb.dead +0 -8
  49. data/app/views/renalware/admin/users/_summary_part.html.slim.dead +0 -4
  50. data/app/views/renalware/letters/lists/index.html.slim.dead +0 -101
  51. data/app/views/renalware/letters/lists/index.html.slim.dead1 +0 -90
  52. data/app/views/renalware/mdm/_biopsies.html.slim.dead +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee5bbbb1fccc3b511b0db010b45ea33b71d5faf427402b0560160d0cb4b3546d
4
- data.tar.gz: 47ae0ff945b16751f7022fd5f028f042296d8cf584e9dee0182b045055abdf15
3
+ metadata.gz: abfba627f20bbeeb5aa182276641415ee232b06c18828704f79d39dbef50b8b8
4
+ data.tar.gz: 6fc22ef861076f9267a984f28b422352cdd5456d53604022235ea7066888cef2
5
5
  SHA512:
6
- metadata.gz: b49d2caf1bfe93714f7327a4ce9dc6b15946db0c5cb07ca889dc1b7df3114cb95ce3307cd6c08a9c9776bb6110e1541e7cd61178a3052b60241ad5440b92f804
7
- data.tar.gz: 7c6e278b64db0a4da5a60756061bea054cf716ae314f6d0509c14d7b008652ca02769904fc31c01cfeafe2931bdda8789f6954f394a4e2ca41fcb2bbccf3bb39
6
+ metadata.gz: 9cfaafd2587fbb7f516bf1ce666582301dc289e6b51590152d7520032ec4f021dbda8a087209f5741b3fc9013b1764ac4d6e7db6360bc4874d49fea7b09ad323
7
+ data.tar.gz: 23d14274d5a863b32913c964e5d3fbce3ee7de0fec570767979424f6c6ae69cd64b7d5ec310f37b77cf71220ecffd112fb7a033ebb7a55d7972c68d4c415f647
@@ -3877,6 +3877,52 @@ var _default$3 = function(_Controller) {
3877
3877
 
3878
3878
  _defineProperty(_default$3, "targets", [ "container", "radio" ]);
3879
3879
 
3880
+ var $$2 = window.$;
3881
+
3882
+ var _default$4 = function(_Controller) {
3883
+ _inherits(_default, _Controller);
3884
+ function _default() {
3885
+ _classCallCheck(this, _default);
3886
+ return _possibleConstructorReturn(this, _getPrototypeOf(_default).apply(this, arguments));
3887
+ }
3888
+ _createClass(_default, [ {
3889
+ key: "refreshForm",
3890
+ value: function refreshForm() {
3891
+ $$2(this.formTarget[0]).trigger("submit.rails");
3892
+ }
3893
+ }, {
3894
+ key: "askForPrintFeedback",
3895
+ value: function askForPrintFeedback() {
3896
+ this.printOptionsTarget.classList.toggle("visuallyhidden");
3897
+ this.printFeedbackTarget.classList.toggle("visuallyhidden");
3898
+ }
3899
+ } ]);
3900
+ return _default;
3901
+ }(Controller);
3902
+
3903
+ _defineProperty(_default$4, "targets", [ "form", "printOptions", "printFeedback" ]);
3904
+
3905
+ var $$3 = window.$;
3906
+
3907
+ var _default$5 = function(_Controller) {
3908
+ _inherits(_default, _Controller);
3909
+ function _default() {
3910
+ _classCallCheck(this, _default);
3911
+ return _possibleConstructorReturn(this, _getPrototypeOf(_default).apply(this, arguments));
3912
+ }
3913
+ _createClass(_default, [ {
3914
+ key: "openRemotePartial",
3915
+ value: function openRemotePartial() {
3916
+ $$3(this.containerTarget).html("");
3917
+ url = this.data.get("url");
3918
+ $$3(this.containerTarget).load(url).foundation("reveal", "open");
3919
+ }
3920
+ } ]);
3921
+ return _default;
3922
+ }(Controller);
3923
+
3924
+ _defineProperty(_default$5, "targets", [ "container" ]);
3925
+
3880
3926
  var application = Application.start();
3881
3927
 
3882
3928
  application.register("test", _default);
@@ -3885,4 +3931,8 @@ application.register("another_test", _default$1);
3885
3931
 
3886
3932
  application.register("toggle", _default$2);
3887
3933
 
3934
+ application.register("foundation-modal", _default$5);
3935
+
3888
3936
  application.register("hd-prescription-administration", _default$3);
3937
+
3938
+ application.register("home-delivery-modal", _default$4);
@@ -56,11 +56,27 @@ dl {
56
56
  heading {
57
57
  text-align: right;
58
58
 
59
- .our-ref {
59
+ .references {
60
60
  float: left;
61
61
  font-weight: normal;
62
62
  font-size: 0.8em;
63
63
  color: #666;
64
+ clear: both;
65
+ text-align: left;
66
+ }
67
+
68
+ .our-ref {
69
+ margin-top: .5rem;
70
+ }
71
+
72
+ .purchase_order_no {
73
+ font-size: 1.5em;
74
+ color: #000;
75
+ margin-top: .5rem;
76
+ }
77
+
78
+ .drug_types {
79
+ margin-top: .5rem;
64
80
  }
65
81
 
66
82
  .trust {
@@ -123,3 +123,20 @@ dl.medication-history {
123
123
  width: 5rem;
124
124
  }
125
125
  }
126
+
127
+ #print-home-delivery-drugs-modal .modal {
128
+ .modal__header h2 span {
129
+ color: $dark-grey;
130
+ font-weight: normal;
131
+ }
132
+
133
+ .show-after-printing {
134
+ a {
135
+ margin-right: 1rem;
136
+ }
137
+ }
138
+
139
+ .panel {
140
+ padding: 0.5rem 1rem;
141
+ }
142
+ }
@@ -23,3 +23,11 @@
23
23
  margin-right: 0;
24
24
  max-width: inherit;
25
25
  }
26
+
27
+ .visuallyhidden {
28
+ position: absolute;
29
+ overflow: hidden;
30
+ clip: rect(0 0 0 0);
31
+ height: 1px; width: 1px;
32
+ margin: -1px; padding: 0; border: 0;
33
+ }
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/medications"
4
+
5
+ module Renalware
6
+ module Medications
7
+ module HomeDelivery
8
+ # Works with a modal.
9
+ class EventsController < BaseController
10
+ # A major REST faux pas, our #new action actually creates something - an instance of a
11
+ # HomeDelivery::Event. We use this to render a modal form where the user can choose which
12
+ # drug types they want to print a PDF for, and what some parameters are for the PDF
13
+ # e.g. the prescription duration. See also Drugs::HomecareForm.
14
+ # The overall idea is that when you bring up the modal dialog to print a home delivery PDF
15
+ # there is always an Event object created behind it, and when you change the params (drug
16
+ # type, prescription duration) it updates the stored event, ready for printing.
17
+ # Although this means we might create rows that are never printed if the user cancels out
18
+ # of the dialog, this is OK as the #printed flag will not be set on those rows so they can
19
+ # be housekept away
20
+ def new
21
+ homecare_form = Drugs::HomecareForm.first
22
+
23
+ event = Delivery::Event.create!(
24
+ patient: patient,
25
+ drug_type_id: homecare_form&.drug_type&.id,
26
+ homecare_form: homecare_form,
27
+ reference_number: Medications::Delivery::PurchaseOrderNumber.next,
28
+ prescription_duration: homecare_form&.prescription_duration_default,
29
+ by: current_user
30
+ )
31
+ authorize event
32
+
33
+ event.prescriptions = prescriptions_for(event)
34
+
35
+ event.valid?
36
+ # byebug
37
+ render(:edit, layout: false, locals: { event: event })
38
+ end
39
+
40
+ # Once #new is called when the modal is first displayed, successive updates come in here
41
+ def update
42
+ event = find_and_auth_event
43
+ event.assign_attributes(event_params)
44
+ event.homecare_form = homecare_form_for(event)
45
+ event.prescriptions = prescriptions_for(event)
46
+
47
+ if event.changed.include?("drug_type_id")
48
+ event.prescription_duration = event.homecare_form&.prescription_duration_default
49
+ end
50
+ event.printed = event_params[:printed].present? # button
51
+
52
+ if event.update_by(current_user, {})
53
+ if event.printed?
54
+ # If printed == true that means the user has clicked on the 'Printed' successfully
55
+ # so we just hide the modal - we are done.
56
+ event.update!(printed: true)
57
+ event.prescriptions.each do |pres|
58
+ last_delivery_date = Time.zone.today
59
+ unit_count = event.prescription_duration.to_i
60
+ unit = event.homecare_form.prescription_duration_unit.to_sym
61
+ next_delivery_date = last_delivery_date + unit_count.send(unit) # eg. 6.months
62
+
63
+ pres.update_columns(
64
+ last_delivery_date: last_delivery_date,
65
+ next_delivery_date: next_delivery_date
66
+ )
67
+
68
+ end
69
+ render :update, locals: { event: event }
70
+ else
71
+ # The user has updated the drug id or prescription duration in the dialog
72
+ # and we have come in here as an ajax PATCH as a result. We are updating the event as
73
+ # the options are changes in the dialog, so when the clicks on the Print link, the
74
+ # event reflects the chosen options.
75
+ render :edit, locals: { event: event }
76
+ end
77
+ else
78
+ render :edit, locals: { event: event }
79
+ end
80
+ end
81
+
82
+ # GET PDF - display the pdf
83
+ def show
84
+ event = find_and_auth_event
85
+ respond_to do |format|
86
+ format.pdf { render_renalware_forms_pdf(event) }
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def prescriptions_for(event)
93
+ PrescriptionsByDrugTypeIdQuery.new(
94
+ patient: event.patient,
95
+ drug_type_id: event.drug_type_id,
96
+ provider: :home_delivery
97
+ ).call
98
+ end
99
+
100
+ def render_renalware_forms_pdf(event)
101
+ pdf = Medications::Delivery::HomecareFormsAdapter.new(delivery_event: event).call
102
+ send_data(
103
+ pdf.render,
104
+ filename: pdf_filename_for(event),
105
+ type: "application/pdf",
106
+ disposition: "inline"
107
+ )
108
+ end
109
+
110
+ def event_is_valid_for_creating_a_homecare_pdf_form(event)
111
+ event.errors.add(:homecare_form, "Ugh")
112
+ end
113
+
114
+ def pdf_filename_for(event)
115
+ [patient.nhs_number, event.reference_number, "homecare"].join("-") + ".pdf"
116
+ end
117
+
118
+ def find_and_auth_event
119
+ Delivery::Event.find(params[:id]).tap { |event| authorize event }
120
+ end
121
+
122
+ def homecare_form_for(event)
123
+ Drugs::HomecareForm.find_by(drug_type_id: event.drug_type_id)
124
+ end
125
+
126
+ def event_params
127
+ params
128
+ .require(:event)
129
+ .permit(:prescription_duration, :drug_type_id, :printed)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,19 @@
1
+ const $ = window.$
2
+ import { Controller } from "stimulus"
3
+
4
+ // Controller for handling Foundation 'reveal' dialogs.
5
+ // Assumes jQuery and foundation/reveal available.
6
+ // The .container target is the html element the .reveal-modal class into which
7
+ // the remote content will be loaded. Using a named target rather finding
8
+ // .reveal-modal in case there are nested modal-controllers and >1 of this
9
+ // elements exist in scope.
10
+ export default class extends Controller {
11
+ static targets = [ "container" ]
12
+
13
+ // Open a dialog using a url to load a partial via ajax.
14
+ openRemotePartial() {
15
+ $(this.containerTarget).html("") // prevent old content from being initially re-displayed
16
+ url = this.data.get("url")
17
+ $(this.containerTarget).load(url).foundation('reveal', 'open');
18
+ }
19
+ }
@@ -0,0 +1,24 @@
1
+ const $ = window.$
2
+ import { Controller } from "stimulus"
3
+
4
+ // Handles the modal dialog used for presenting Home Delivery print options to
5
+ // the user. Used on the prescrptions page.
6
+ export default class extends Controller {
7
+ static targets = [ "form", "printOptions", "printFeedback" ]
8
+
9
+ // Submit and re-display the form when 'drug type' or 'prescription duration'
10
+ // dropdowns are changed
11
+ refreshForm() {
12
+ $(this.formTarget[0]).trigger('submit.rails');
13
+ }
14
+
15
+ // When the user has clicked Print (launching the PDF in a new tab), hide
16
+ // the Print button and display content which asks whether printing was
17
+ // successful or not. Click one of these 2 buttons will dismiss the modal.
18
+ // FYI if they say Yes (printing was a success) the home delivery
19
+ // event (the object 'behind' our modal form) is updated with printed=true.
20
+ askForPrintFeedback() {
21
+ this.printOptionsTarget.classList.toggle("visuallyhidden")
22
+ this.printFeedbackTarget.classList.toggle("visuallyhidden")
23
+ }
24
+ }
@@ -17,9 +17,13 @@ import TestController from "./controllers/test_controller"
17
17
  import AnotherTestController from "./controllers/another_test_controller"
18
18
  import ToggleController from "./controllers/toggle_controller"
19
19
  import HDPrescriptionController from "./controllers/hd/prescription_administration_controller"
20
+ import MedicationsHomeDeliveryModalController from "./controllers/medications/home_delivery_modal_controller"
21
+ import FoundationModalController from "./controllers/foundation_modal_controller"
20
22
 
21
23
  const application = Application.start()
22
24
  application.register("test", TestController)
23
25
  application.register("another_test", AnotherTestController)
24
26
  application.register("toggle", ToggleController)
27
+ application.register("foundation-modal", FoundationModalController)
25
28
  application.register("hd-prescription-administration", HDPrescriptionController)
29
+ application.register("home-delivery-modal", MedicationsHomeDeliveryModalController)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/drugs"
4
+
5
+ module Renalware
6
+ module Drugs
7
+ class HomecareForm < ApplicationRecord
8
+ self.table_name = "drug_homecare_forms"
9
+ belongs_to :drug_type, class_name: "Drugs::Type"
10
+ belongs_to :supplier, class_name: "Drugs::Supplier"
11
+ validates :form_name, presence: true
12
+ validates :form_version, presence: true
13
+ validates :prescription_durations, presence: true # an Array of Integers
14
+ validates :prescription_duration_unit, presence: true # e.g. 'month'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/drugs"
4
+
5
+ module Renalware
6
+ module Drugs
7
+ class Supplier < ApplicationRecord
8
+ self.table_name = "drug_suppliers"
9
+ validates :name, presence: true
10
+ end
11
+ end
12
+ end
@@ -19,8 +19,8 @@ module Renalware
19
19
  "ADT^A02" => :transfer_patient,
20
20
  "ADT^A03" => :discharge_patient,
21
21
  "ADT^A11" => :cancel_admission,
22
- "MFN^M02" => :add_consultant,
23
- "ADT^A34" => :merge_patient,
22
+ "MFN^M02" => :add_consultant, # no
23
+ "ADT^A34" => :merge_patient, # no
24
24
  "ADT^A13" => :cancel_discharge,
25
25
  "ORU^R01" => :add_pathology_observations
26
26
  }.freeze
@@ -7,5 +7,11 @@ module Renalware
7
7
  def self.table_name_prefix
8
8
  "medication_"
9
9
  end
10
+
11
+ module Delivery
12
+ def self.table_name_prefix
13
+ "medication_delivery_"
14
+ end
15
+ end
10
16
  end
11
17
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/medications"
4
+
5
+ module Renalware
6
+ module Medications
7
+ module Delivery
8
+ # For example a home delivery form was printed.
9
+ class Event < ApplicationRecord
10
+ include Accountable
11
+ acts_as_paranoid
12
+
13
+ belongs_to :patient, class_name: "Renalware::Patient"
14
+ belongs_to :drug_type, class_name: "Drugs::Type"
15
+ belongs_to :homecare_form, class_name: "Drugs::HomecareForm"
16
+ has_many(
17
+ :event_prescriptions,
18
+ class_name: "Delivery::EventPrescription",
19
+ dependent: :restrict_with_exception
20
+ )
21
+ has_many(
22
+ :prescriptions,
23
+ through: :event_prescriptions,
24
+ class_name: "Medications::Prescription",
25
+ dependent: :restrict_with_exception
26
+ )
27
+
28
+ validates :patient, presence: true
29
+ validates :homecare_form, presence: true
30
+ validates :reference_number, presence: true, if: :printed?
31
+ validates :prescription_duration, presence: true, if: :printed?
32
+ validate :renalware_forms_args, on: :update
33
+
34
+ def self.policy_class
35
+ Renalware::BasePolicy
36
+ end
37
+
38
+ def renalware_forms_args
39
+ adapater = Delivery::HomecareFormsAdapter.new(delivery_event: self)
40
+ args = adapater.build_args
41
+ unless adapater.valid?(args)
42
+ errors.add(:base, args.errors.full_messages&.join(", "))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "renalware/medications"
4
+
5
+ module Renalware
6
+ module Medications
7
+ module Delivery
8
+ # Represents a prescription associated with for example a home_delivery print event.
9
+ # Usually creating a home delivery prescriptions print event will mean we create a row for
10
+ # drug types esa, immunosupressant or both. In the future other drug types may be associated
11
+ # with the printing of prescriptions for a particular provider, so while this approach seems
12
+ # a bit overkill, being normalised like this (as opposed to just say storing the drug type ids
13
+ # or their codes in an array on medication_delivery_events) is more flexible and also provides
14
+ # more scope for reporting.
15
+ class EventPrescription < ApplicationRecord
16
+ belongs_to :event, class_name: "Delivery::Event"
17
+ belongs_to :prescription, class_name: "Medications::Prescription"
18
+
19
+ validates :event, presence: true
20
+ validates :prescription, presence: true
21
+ end
22
+ end
23
+ end
24
+ end