renalware-core 2.0.139 → 2.0.140

Sign up to get free protection for your applications and to get access to all the features.
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