renalware-core 2.0.0.pre.beta7 → 2.0.0.pre.beta8

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 (204) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/renalware/searchables.js +3 -0
  3. data/app/assets/javascripts/renalware/select2-ajax-search.js +86 -0
  4. data/app/assets/javascripts/renalware/sortable.js +12 -1
  5. data/app/assets/stylesheets/renalware/base/_variables.scss +7 -1
  6. data/app/assets/stylesheets/renalware/modules/_admissions.scss +39 -0
  7. data/app/assets/stylesheets/renalware/modules/_letters.scss +12 -0
  8. data/app/assets/stylesheets/renalware/modules/_messaging.scss +0 -4
  9. data/app/assets/stylesheets/renalware/partials/_animations.scss +12 -0
  10. data/app/assets/stylesheets/renalware/partials/_modal_window.scss +44 -0
  11. data/app/assets/stylesheets/renalware/partials/_tables.scss +6 -0
  12. data/app/controllers/renalware/admissions/requests_controller.rb +100 -0
  13. data/app/controllers/renalware/devise/passwords_controller.rb +6 -0
  14. data/app/controllers/renalware/letters/electronic_receipts_controller.rb +81 -0
  15. data/app/controllers/renalware/letters/letters_controller.rb +18 -3
  16. data/app/controllers/renalware/messaging/internal/messages_controller.rb +75 -0
  17. data/app/controllers/renalware/messaging/internal/receipts_controller.rb +74 -0
  18. data/app/controllers/renalware/patients/patients_controller.rb +11 -1
  19. data/app/controllers/renalware/session_timeout_controller.rb +1 -1
  20. data/app/documents/renalware/hd/profile_document.rb +1 -1
  21. data/app/helpers/renalware/application_helper.rb +5 -0
  22. data/app/helpers/renalware/xhr_helper.rb +7 -0
  23. data/app/models/concerns/renalware/deviseable.rb +1 -1
  24. data/app/models/renalware/admissions.rb +7 -0
  25. data/app/models/renalware/admissions/request.rb +23 -0
  26. data/app/models/renalware/admissions/request_reason.rb +11 -0
  27. data/app/models/renalware/feeds/message_processor.rb +2 -2
  28. data/app/models/renalware/feeds/persist_message.rb +2 -0
  29. data/app/models/renalware/hd/sessions/auditable_session.rb +4 -0
  30. data/app/models/renalware/hd/sessions/auditable_session_collection.rb +5 -0
  31. data/app/models/renalware/hd/update_rolling_patient_statistics.rb +2 -2
  32. data/app/models/renalware/letters/electronic_receipt.rb +35 -0
  33. data/app/models/renalware/letters/electronic_recipient_options.rb +78 -0
  34. data/app/models/renalware/letters/letter.rb +4 -0
  35. data/app/models/renalware/letters/letter_factory.rb +21 -1
  36. data/app/models/renalware/messaging.rb +21 -5
  37. data/app/models/renalware/messaging/internal/author.rb +11 -0
  38. data/app/models/renalware/messaging/internal/message.rb +15 -0
  39. data/app/models/renalware/messaging/internal/message_factory.rb +20 -0
  40. data/app/models/renalware/messaging/internal/message_form.rb +36 -0
  41. data/app/models/renalware/messaging/internal/message_form_builder.rb +52 -0
  42. data/app/models/renalware/messaging/internal/receipt.rb +26 -0
  43. data/app/models/renalware/messaging/internal/recipient.rb +12 -0
  44. data/app/models/renalware/messaging/internal/recipient_options.rb +87 -0
  45. data/app/models/renalware/messaging/internal/send_message.rb +24 -0
  46. data/app/models/renalware/messaging/message.rb +4 -3
  47. data/app/models/renalware/pathology.rb +1 -1
  48. data/app/models/renalware/pathology/message_param_parser.rb +2 -0
  49. data/app/models/renalware/patients/search_filter.rb +32 -0
  50. data/app/models/renalware/patients/search_form.rb +17 -0
  51. data/app/models/renalware/patients/search_query.rb +20 -21
  52. data/app/models/renalware/patients/summary.rb +1 -1
  53. data/app/models/renalware/user.rb +18 -2
  54. data/app/policies/renalware/admissions/request_policy.rb +8 -0
  55. data/app/policies/renalware/letters/electronic_receipt_policy.rb +23 -0
  56. data/app/policies/renalware/messaging/{message_policy.rb → internal/message_policy.rb} +2 -3
  57. data/app/policies/renalware/messaging/internal/receipt_policy.rb +25 -0
  58. data/app/presenters/renalware/dashboard/dashboard_presenter.rb +9 -2
  59. data/app/presenters/renalware/hd/station_presenter.rb +0 -1
  60. data/app/presenters/renalware/letters/electronic_receipt_presenter.rb +15 -0
  61. data/app/presenters/renalware/letters/letter_presenter.rb +5 -0
  62. data/app/presenters/renalware/mdm_presenter.rb +2 -0
  63. data/app/presenters/renalware/messaging/internal/message_presenter.rb +21 -0
  64. data/app/presenters/renalware/messaging/internal/receipt_presenter.rb +13 -0
  65. data/app/presenters/renalware/pathology/observation_presenter.rb +4 -0
  66. data/app/presenters/renalware/ukrdc/patient_presenter.rb +5 -0
  67. data/app/views/renalware/admissions/requests/_create_request_link.html.slim +10 -0
  68. data/app/views/renalware/admissions/requests/_form.html.slim +31 -0
  69. data/app/views/renalware/admissions/requests/_modal_dialog_placeholder.html.slim +2 -0
  70. data/app/views/renalware/admissions/requests/_request.html.slim +34 -0
  71. data/app/views/renalware/admissions/requests/_table.html.slim +19 -0
  72. data/app/views/renalware/admissions/requests/create.js.erb +3 -0
  73. data/app/views/renalware/admissions/requests/destroy.js.erb +3 -0
  74. data/app/views/renalware/admissions/requests/edit.html.slim +4 -0
  75. data/app/views/renalware/admissions/requests/edit.js.erb +4 -0
  76. data/app/views/renalware/admissions/requests/index.html.slim +3 -0
  77. data/app/views/renalware/admissions/requests/new.html.slim +4 -0
  78. data/app/views/renalware/admissions/requests/new.js.erb +4 -0
  79. data/app/views/renalware/admissions/requests/update.js.erb +9 -0
  80. data/app/views/renalware/api/ukrdc/patients/_allergies.xml.builder +1 -1
  81. data/app/views/renalware/api/ukrdc/patients/_clinical_relationships.xml.builder +0 -1
  82. data/app/views/renalware/api/ukrdc/patients/_lab_orders.xml.builder +7 -2
  83. data/app/views/renalware/api/ukrdc/patients/_observations.xml.builder +1 -1
  84. data/app/views/renalware/api/ukrdc/patients/_patient.xml.builder +2 -0
  85. data/app/views/renalware/api/ukrdc/patients/_sending_facility.xml.builder +1 -1
  86. data/app/views/renalware/api/ukrdc/patients/lab_orders/_lab_order.xml.builder +46 -0
  87. data/app/views/renalware/api/ukrdc/patients/lab_orders/_result_item.xml.builder +14 -0
  88. data/app/views/renalware/clinical/allergies/_mini.html.slim +1 -0
  89. data/app/views/renalware/dashboard/dashboards/_content.html.slim +6 -2
  90. data/app/views/renalware/dashboard/letters/_letter.html.slim +7 -7
  91. data/app/views/renalware/dashboard/letters/_table.html.slim +2 -2
  92. data/app/views/renalware/devise/passwords/edit.html.erb +27 -0
  93. data/app/views/renalware/devise/passwords/new.html.erb +18 -0
  94. data/app/views/renalware/devise/registrations/new.html.slim +25 -0
  95. data/app/views/renalware/letters/electronic_receipts/_table.html.slim +45 -0
  96. data/app/views/renalware/letters/electronic_receipts/mark_as_read.js.erb +6 -0
  97. data/app/views/renalware/letters/electronic_receipts/read.html.slim +5 -0
  98. data/app/views/renalware/letters/electronic_receipts/sent.html.slim +40 -0
  99. data/app/views/renalware/letters/electronic_receipts/unread.html.slim +5 -0
  100. data/app/views/renalware/letters/formatted_letters/_letter.html.slim +12 -1
  101. data/app/views/renalware/letters/letters/_actions.html.slim +1 -1
  102. data/app/views/renalware/letters/letters/_electronic_ccs.html.slim +16 -0
  103. data/app/views/renalware/letters/letters/_form.html.slim +8 -3
  104. data/app/views/renalware/letters/letters/edit.html.slim +7 -1
  105. data/app/views/renalware/letters/letters/new.html.slim +6 -1
  106. data/app/views/renalware/letters/shared/_electronic_cc_type_tabs.html.slim +7 -0
  107. data/app/views/renalware/messaging/{messages → internal/messages}/_form.html.slim +2 -1
  108. data/app/views/renalware/messaging/{messages → internal/messages}/_modal_dialog_placeholder.html.slim +0 -0
  109. data/app/views/renalware/messaging/{messages → internal/messages}/_send_message_link.html.slim +1 -1
  110. data/app/views/renalware/messaging/{messages → internal/messages}/_send_reply_link.html.slim +3 -3
  111. data/app/views/renalware/messaging/{messages → internal/messages}/create.js.erb +0 -0
  112. data/app/views/renalware/messaging/{messages → internal/messages}/new.html.slim +0 -0
  113. data/app/views/renalware/messaging/{messages → internal/messages}/new.js.erb +0 -0
  114. data/app/views/renalware/messaging/{receipts → internal/receipts}/_receipt.html.slim +2 -2
  115. data/app/views/renalware/messaging/{messages/_message.html.slim → internal/receipts/_sent_receipt.html.slim} +2 -1
  116. data/app/views/renalware/messaging/internal/receipts/_sent_table.html.slim +12 -0
  117. data/app/views/renalware/messaging/{receipts → internal/receipts}/_table.html.slim +2 -2
  118. data/app/views/renalware/messaging/{receipts → internal/receipts}/mark_as_read.js.erb +0 -0
  119. data/app/views/renalware/messaging/{receipts → internal/receipts}/read.html.slim +2 -1
  120. data/app/views/renalware/messaging/internal/receipts/sent.html.slim +7 -0
  121. data/app/views/renalware/messaging/{receipts → internal/receipts}/unread.html.slim +2 -1
  122. data/app/views/renalware/messaging/shared/_messages_type_tabs.html.slim +3 -3
  123. data/app/views/renalware/navigation/_main.html.slim +1 -1
  124. data/app/views/renalware/navigation/_patients_admin.html.slim +2 -0
  125. data/app/views/renalware/navigation/_user.html.slim +2 -1
  126. data/app/views/renalware/patients/_search_form.html.slim +12 -0
  127. data/app/views/renalware/patients/side_menu/_actions.html.slim +6 -2
  128. data/app/views/renalware/renal/profiles/_form.html.slim +0 -1
  129. data/app/views/renalware/renal/profiles/_mini.html.slim +1 -0
  130. data/app/views/renalware/{snippets/snippets → shared}/_modal_close_link.html.slim +0 -0
  131. data/app/views/renalware/snippets/snippets/_list.html.slim +1 -1
  132. data/app/views/renalware/transplants/donations/_form.html.slim +17 -16
  133. data/config/initializers/simple_form_foundation.rb +0 -1
  134. data/config/locales/renalware/admissions/requests.en.yml +12 -0
  135. data/config/locales/renalware/letters/contact.en.yml +3 -0
  136. data/config/locales/renalware/messaging/internal/messages.en.yml +33 -0
  137. data/config/locales/renalware/patients/search_form.en.yml +5 -0
  138. data/config/locales/renalware/patients/side_menu.en.yml +1 -0
  139. data/config/routes.rb +32 -10
  140. data/db/migrate/20170908155011_add_shortfall_column_to_hd_patient_statistics.rb +7 -0
  141. data/db/migrate/20170908160250_update_hd_overall_audit_to_version4.rb +8 -0
  142. data/db/migrate/20170911133224_add_type_to_messaging_messages.rb +16 -0
  143. data/db/migrate/20170912092135_create_letters_electronic_receipts.rb +11 -0
  144. data/db/migrate/20170920113628_create_admissions_requests.rb +31 -0
  145. data/db/seeds/default/reporting/audits.yml +1 -0
  146. data/db/views/reporting_hd_overall_audit_v04.sql +13 -0
  147. data/lib/renalware/version.rb +1 -1
  148. data/lib/subscription_registry.rb +1 -1
  149. data/spec/factories/accesses/plans.rb +2 -3
  150. data/spec/factories/accesses/profiles.rb +1 -2
  151. data/spec/factories/admissions/request_reasons.rb +8 -0
  152. data/spec/factories/admissions/requests.rb +9 -0
  153. data/spec/factories/clinical/body_compositions.rb +2 -5
  154. data/spec/factories/clinical/dry_weights.rb +2 -3
  155. data/spec/factories/clinics/clinic_visits.rb +2 -3
  156. data/spec/factories/directory/people.rb +1 -2
  157. data/spec/factories/events/events.rb +1 -2
  158. data/spec/factories/hd/preference_sets.rb +1 -2
  159. data/spec/factories/hd/profiles.rb +2 -3
  160. data/spec/factories/hd/sessions.rb +4 -3
  161. data/spec/factories/letters/electronic_receipts.rb +6 -0
  162. data/spec/factories/letters/letters.rb +3 -3
  163. data/spec/factories/medications/prescription.rb +1 -2
  164. data/spec/factories/medications/prescription_terminations.rb +1 -2
  165. data/spec/factories/messaging/internal/authors.rb +5 -0
  166. data/spec/factories/messaging/{message.rb → internal/messages.rb} +1 -1
  167. data/spec/factories/messaging/internal/receipts.rb +7 -0
  168. data/spec/factories/messaging/internal/recipients.rb +5 -0
  169. data/spec/factories/modalities/modalities.rb +1 -3
  170. data/spec/factories/pathology/requests/request.rb +1 -3
  171. data/spec/factories/patients/alerts.rb +1 -2
  172. data/spec/factories/patients/patients.rb +5 -3
  173. data/spec/factories/pd/assessments.rb +1 -2
  174. data/spec/factories/pd/fluid_descriptions.rb +0 -1
  175. data/spec/factories/pd/training_sessions.rb +1 -2
  176. data/spec/factories/problems/problems.rb +1 -2
  177. data/spec/factories/shared/accountable.rb +35 -0
  178. data/spec/factories/system/roles.rb +2 -4
  179. data/spec/factories/system/users.rb +30 -15
  180. data/spec/factories/transplants/donor_stage.rb +1 -2
  181. data/spec/factories/transplants/registration_statuses.rb +2 -4
  182. data/spec/support/login_macros.rb +1 -1
  183. metadata +108 -40
  184. data/app/controllers/renalware/messaging/messages_controller.rb +0 -73
  185. data/app/controllers/renalware/messaging/receipts_controller.rb +0 -55
  186. data/app/controllers/renalware/messaging/sent_messages_controller.rb +0 -22
  187. data/app/models/renalware/messaging/author.rb +0 -9
  188. data/app/models/renalware/messaging/message_factory.rb +0 -18
  189. data/app/models/renalware/messaging/message_form.rb +0 -34
  190. data/app/models/renalware/messaging/message_form_builder.rb +0 -50
  191. data/app/models/renalware/messaging/receipt.rb +0 -19
  192. data/app/models/renalware/messaging/recipient.rb +0 -10
  193. data/app/models/renalware/messaging/recipient_options.rb +0 -85
  194. data/app/models/renalware/messaging/send_message.rb +0 -22
  195. data/app/policies/renalware/messaging/receipt_policy.rb +0 -19
  196. data/app/presenters/renalware/messaging/internal_message_presenter.rb +0 -19
  197. data/app/presenters/renalware/messaging/receipt_presenter.rb +0 -11
  198. data/app/views/renalware/devise/registrations/new.html.erb +0 -46
  199. data/app/views/renalware/messaging/messages/_table.html.slim +0 -13
  200. data/app/views/renalware/messaging/messages/sent.html.slim +0 -4
  201. data/config/locales/renalware/messaging/messages.en.yml +0 -29
  202. data/spec/factories/messaging/authors.rb +0 -5
  203. data/spec/factories/messaging/receipt.rb +0 -7
  204. data/spec/factories/messaging/recipients.rb +0 -5
@@ -20,6 +20,10 @@ module Renalware
20
20
  dependent: :destroy,
21
21
  inverse_of: :letter
22
22
  has_many :recipients, dependent: :destroy
23
+ has_many :electronic_receipts, dependent: :destroy
24
+ has_many :electronic_cc_recipients,
25
+ through: :electronic_receipts,
26
+ source: :recipient
23
27
  has_one :signature, dependent: :destroy
24
28
  has_one :archive, foreign_key: "letter_id"
25
29
 
@@ -10,7 +10,9 @@ module Renalware
10
10
  end
11
11
 
12
12
  def build
13
+ @electronic_cc_recipient_ids = params.delete(:electronic_cc_recipient_ids)
13
14
  @letter = build_letter
15
+ build_electronic_ccs
14
16
  include_primary_care_physician_as_default_main_recipient
15
17
  assign_default_ccs
16
18
  build_salutation
@@ -25,7 +27,7 @@ module Renalware
25
27
 
26
28
  private
27
29
 
28
- attr_reader :patient, :letter, :params
30
+ attr_reader :patient, :letter, :params, :electronic_cc_recipient_ids
29
31
 
30
32
  def build_letter
31
33
  # We should not have to set the STI type manually here but in some circumstances
@@ -48,6 +50,24 @@ module Renalware
48
50
  patient.contacts.default_ccs
49
51
  end
50
52
 
53
+ # Deal with wiring up new electronic CCs in the new, unsaved letter.
54
+ # NB: The way electronic CCs are handled on building a new Letter and on updating an existing
55
+ # one is different: when updating an existing letter (see code elsewhere) we lean on rails
56
+ # doing some magic for us; as long as we have an array of electronic_cc_recipients in the
57
+ # params, it will add/remove an associated electronic_receipt object for us (assigning the
58
+ # letter_id to them in the process), because we used
59
+ # has_many :electronic_cc_recipients, through: :electronic_receipts
60
+ # However, here, as we have no letter.id (letter is unsaved), Rails cannot yet create the
61
+ # implied electronic_receipt object for each electronic_cc_recipient for us - we must do it
62
+ # ourselves using electronic_receipts.build so rails will update the letter id in each when
63
+ # the parent letter is saved.
64
+ def build_electronic_ccs
65
+ return if electronic_cc_recipient_ids.blank?
66
+ electronic_cc_recipient_ids.reject(&:blank?).map do |user_id|
67
+ letter.electronic_receipts.build(recipient_id: user_id)
68
+ end
69
+ end
70
+
51
71
  def build_salutation
52
72
  letter.salutation ||= begin
53
73
  main_recipient = letter.main_recipient
@@ -2,20 +2,36 @@ require_dependency "renalware"
2
2
 
3
3
  module Renalware
4
4
  module Messaging
5
- def self.table_name_prefix
5
+ module_function
6
+ def table_name_prefix
6
7
  "messaging_"
7
8
  end
8
9
 
9
- def self.cast_patient(patient)
10
+ def cast_patient(patient)
10
11
  ActiveType.cast(patient, ::Renalware::Messaging::Patient)
11
12
  end
12
13
 
13
- def self.cast_author(author)
14
+ def cast_author(author)
14
15
  ActiveType.cast(author, ::Renalware::Messaging::Author)
15
16
  end
16
17
 
17
- def self.cast_recipient(recipient)
18
- ActiveType.cast(recipient, ::Renalware::Messaging::Recipient)
18
+ # def cast_recipient(recipient)
19
+ # ActiveType.cast(recipient, ::Renalware::Messaging::Recipient)
20
+ # end
21
+
22
+ module Internal
23
+ module_function
24
+ def cast_patient(patient)
25
+ ActiveType.cast(patient, ::Renalware::Messaging::Internal::Patient)
26
+ end
27
+
28
+ def cast_author(author)
29
+ ActiveType.cast(author, ::Renalware::Messaging::Internal::Author)
30
+ end
31
+
32
+ def cast_recipient(recipient)
33
+ ActiveType.cast(recipient, ::Renalware::Messaging::Internal::Recipient)
34
+ end
19
35
  end
20
36
  end
21
37
  end
@@ -0,0 +1,11 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class Author < ActiveType::Record[Renalware::User]
7
+ has_many :messages
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class Message < Renalware::Messaging::Message
7
+ belongs_to :author, class_name: "Internal::Author"
8
+ has_many :receipts
9
+ has_many :recipients, through: :receipts
10
+ belongs_to :replying_to_message, class_name: name
11
+ scope :ordered, ->{ order(sent_at: :desc) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class MessageFactory
7
+ def self.build(**attributes)
8
+ attributes[:sent_at] ||= Time.zone.now
9
+ recipient_ids = attributes.delete(:recipient_ids) || []
10
+
11
+ Message.new(attributes).tap do |message|
12
+ recipient_ids.each do |recipient_id|
13
+ message.receipts.build(recipient_id: recipient_id)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ # A form object used behind the html messages#new form, and serving to helps us capture
4
+ # attributes for a Message and its Recipients. The MessageForm is passed to the SendMessage
5
+ # object where it is persisted as a Message with many Recipients through Receipts.
6
+ module Renalware
7
+ module Messaging
8
+ module Internal
9
+ class MessageForm
10
+ include ActiveModel::Model
11
+ include Virtus::Model
12
+
13
+ attribute :body, String
14
+ attribute :subject, String
15
+ attribute :urgent, Boolean, default: false
16
+ attribute :recipient_ids, Array, default: []
17
+ attribute :replying_to_message_id
18
+
19
+ validates :body, presence: true
20
+ validates :subject, presence: true
21
+ validates :recipient_ids, presence: true, length: { minimum: 1 }
22
+
23
+ def initialize(attributes = {})
24
+ remove_blank_recipient_ids_from(attributes)
25
+ super
26
+ end
27
+
28
+ private
29
+
30
+ def remove_blank_recipient_ids_from(params)
31
+ params[:recipient_ids].reject!(&:blank?) if params.key?(:recipient_ids)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,52 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ # Builds a new MessageForm form object. MessageForm is used behind the html form when displaying a
4
+ # `Send Message` Dialog the first time. Note that we don't use this builder again on e.g.
5
+ # form submission - at that point all the required params are in the form payload - this is
6
+ # only for the initial MesageForm creation.
7
+ #
8
+ module Renalware
9
+ module Messaging
10
+ module Internal
11
+ class MessageFormBuilder
12
+ attr_reader :patient, :params
13
+
14
+ def initialize(patient:, params:)
15
+ @patient = patient
16
+ @params = params
17
+ end
18
+
19
+ def call
20
+ MessageForm.new(
21
+ subject: build_subject,
22
+ recipient_ids: build_recipient_ids,
23
+ replying_to_message_id: replying_to_message_id
24
+ )
25
+ end
26
+
27
+ private
28
+
29
+ def build_subject
30
+ replying? ? "Re: #{replying_to_message.subject}" : patient.to_s
31
+ end
32
+
33
+ def build_recipient_ids
34
+ replying? ? Array(replying_to_message.author_id) : []
35
+ end
36
+
37
+ def replying_to_message
38
+ return NullObject.instance unless replying?
39
+ @replying_to_message ||= Message.find(replying_to_message_id)
40
+ end
41
+
42
+ def replying_to_message_id
43
+ params[:replying_to_message_id]
44
+ end
45
+
46
+ def replying?
47
+ replying_to_message_id.present?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class Receipt < ApplicationRecord
7
+ validates :recipient, presence: true
8
+ validates :message, presence: true
9
+
10
+ belongs_to :message
11
+ belongs_to :recipient
12
+
13
+ scope :unread, -> { where(read_at: nil) }
14
+ scope :read, -> { where.not(read_at: nil) }
15
+ scope :ordered, -> { joins(:message).merge(Message.ordered) }
16
+ scope :sent_by, lambda{ |user_id|
17
+ joins(:message).where(messaging_messages: { author_id: user_id })
18
+ }
19
+
20
+ def read?
21
+ read_at.present?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class Recipient < ActiveType::Record[Renalware::User]
7
+ has_many :receipts
8
+ has_many :messages, through: :receipts
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,87 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ # Builds grouped drop down options for potential private message recipients.
4
+ # The groups are:
5
+ # - users who have recently received a message about the current patient
6
+ # - users who have recently received a message from the current author (excluding those already
7
+ # listed in the above group)
8
+ # - all remaining users
9
+ #
10
+ # The author is excluded from all lists so they cannot send to themselves
11
+ #
12
+ module Renalware
13
+ module Messaging
14
+ module Internal
15
+ class RecipientOptions
16
+ attr_reader :patient, :author
17
+
18
+ class Group
19
+ include Virtus.model
20
+ attribute :name, String
21
+ attribute :users, Array, default: []
22
+ end
23
+
24
+ def initialize(patient, author)
25
+ @patient = patient
26
+ @author = author
27
+ end
28
+
29
+ def to_a
30
+ [
31
+ users_having_previously_received_a_message_about_patient,
32
+ users_having_recently_received_messages_from_author,
33
+ all_other_users
34
+ ]
35
+ end
36
+
37
+ private
38
+
39
+ def users_having_previously_received_a_message_about_patient
40
+ Group.new(
41
+ name: "Previous patient recipients",
42
+ users: Recipient.where(id: ids_of_users_having_received_a_message_about_patient)
43
+ )
44
+ end
45
+
46
+ def users_having_recently_received_messages_from_author
47
+ Group.new(
48
+ name: "Other recent recipients",
49
+ users: Recipient.where(id: ids_of_users_having_received_messages_from_author)
50
+ )
51
+ end
52
+
53
+ def all_other_users
54
+ ids_to_exclude = ids_of_users_having_received_a_message_about_patient +
55
+ ids_of_users_having_received_messages_from_author
56
+ Group.new(
57
+ name: "All other users",
58
+ users: Recipient.where.not(id: ids_to_exclude)
59
+ )
60
+ end
61
+
62
+ def ids_of_users_having_received_a_message_about_patient
63
+ @ids_of_users_having_received_a_message_about_patient ||= begin
64
+ Message
65
+ .includes(:receipts)
66
+ .eager_load(:receipts)
67
+ .where(patient: patient)
68
+ .limit(20)
69
+ .pluck(:author_id, :recipient_id)
70
+ .flatten.uniq.compact
71
+ end
72
+ end
73
+
74
+ def ids_of_users_having_received_messages_from_author
75
+ @ids_of_users_having_received_messages_from_author ||= begin
76
+ ids = Message
77
+ .includes(:receipts).eager_load(:receipts)
78
+ .where(author: author)
79
+ .limit(20)
80
+ .pluck(:recipient_id).uniq.compact
81
+ ids - ids_of_users_having_received_a_message_about_patient
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,24 @@
1
+ require_dependency "renalware/messaging"
2
+
3
+ module Renalware
4
+ module Messaging
5
+ module Internal
6
+ class SendMessage
7
+
8
+ def self.call(*args)
9
+ new.call(*args)
10
+ end
11
+
12
+ def call(author:, patient:, form:)
13
+ Message.transaction do
14
+ message = MessageFactory.build(patient: patient,
15
+ author: author,
16
+ **form.attributes)
17
+ message.save!
18
+ message
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,9 @@
1
1
  require_dependency "renalware/messaging"
2
2
 
3
+ #
4
+ # Abstract Message base class.
5
+ # Use Internal::Message etc. subclasses (stored via STI).
6
+ #
3
7
  module Renalware
4
8
  module Messaging
5
9
  class Message < ApplicationRecord
@@ -11,9 +15,6 @@ module Renalware
11
15
 
12
16
  belongs_to :patient
13
17
  belongs_to :author
14
- belongs_to :replying_to_message, class_name: name
15
- has_many :receipts
16
- has_many :recipients, through: :receipts
17
18
  end
18
19
  end
19
20
  end
@@ -10,7 +10,7 @@ module Renalware
10
10
  "pathology_"
11
11
  end
12
12
 
13
- def self.cast_patient(patient)
13
+ def cast_patient(patient)
14
14
  ActiveType.cast(patient, ::Renalware::Pathology::Patient)
15
15
  end
16
16
 
@@ -6,6 +6,8 @@ module Renalware
6
6
  # that can be persisted by ObservationRequest.
7
7
  #
8
8
  class MessageParamParser
9
+
10
+ # message_payload is an HL7Message (a decorator around an ::HL7::Message)
9
11
  def parse(message_payload)
10
12
  request = message_payload.observation_request
11
13
 
@@ -0,0 +1,32 @@
1
+ # Works in concert with Patients::SearchQuery and Patients::SearchForm.
2
+ # Example usage in a controller:
3
+ #
4
+ # my_relation = Thing.all.joins(:patient)
5
+ # filter = Patients::SearchFilter.new(search_term, request)
6
+ # my_relation = patient_filter.call(my_relation)
7
+ # render locals: { search_form: filter.search_form }
8
+ require_dependency "renalware/patients"
9
+
10
+ module Renalware
11
+ module Patients
12
+ class SearchFilter
13
+ attr_reader :search_form
14
+
15
+ def initialize(search_term, request)
16
+ @search_form = build_search_form(search_term, request)
17
+ end
18
+
19
+ def call(relation)
20
+ matching_patients = Patients::SearchQuery.new(term: search_form.term).call
21
+ relation.merge(matching_patients)
22
+ end
23
+
24
+ def build_search_form(search_term, request)
25
+ Patients::SearchForm.new(
26
+ term: search_term,
27
+ url: request.path
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end