renalware-core 2.0.5 → 2.0.7

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/renalware/primary_care_physician_search.js +7 -3
  3. data/app/assets/stylesheets/renalware/modules/_letters.scss +5 -0
  4. data/app/assets/stylesheets/renalware/modules/_patients.scss +11 -0
  5. data/app/assets/stylesheets/renalware/modules/_snippets.scss +45 -1
  6. data/app/assets/stylesheets/renalware/partials/_errors.scss +1 -0
  7. data/app/assets/stylesheets/renalware/partials/_tables.scss +14 -0
  8. data/app/controllers/renalware/admissions/consults_controller.rb +5 -1
  9. data/app/controllers/renalware/clinics/clinic_visits_controller.rb +1 -1
  10. data/app/controllers/renalware/hd/current_profile_controller.rb +1 -1
  11. data/app/controllers/renalware/hd/preference_sets_controller.rb +1 -1
  12. data/app/controllers/renalware/medications/prescriptions_controller.rb +0 -1
  13. data/app/controllers/renalware/patients/practices_controller.rb +21 -1
  14. data/app/controllers/renalware/patients/worry_controller.rb +1 -1
  15. data/app/controllers/renalware/renal/aki_alerts_controller.rb +1 -1
  16. data/app/controllers/renalware/renal/profiles_controller.rb +1 -1
  17. data/app/controllers/renalware/transplants/donor_workups_controller.rb +1 -1
  18. data/app/controllers/renalware/transplants/recipient_workups_controller.rb +1 -1
  19. data/app/helpers/renalware/layout_helper.rb +2 -2
  20. data/app/models/concerns/renalware/patients_ransack_helper.rb +0 -1
  21. data/app/models/renalware/admissions/consult.rb +1 -1
  22. data/app/models/renalware/admissions/consult_query.rb +19 -3
  23. data/app/models/renalware/feeds/files/practices/convert_xml_to_csv.rb +6 -2
  24. data/app/models/renalware/letters/letter_factory.rb +3 -1
  25. data/app/models/renalware/letters/recipient.rb +34 -9
  26. data/app/models/renalware/patients/patient_hospital_identifiers.rb +4 -0
  27. data/app/models/renalware/patients/practice_search_query.rb +5 -2
  28. data/app/models/renalware/transplants/registration_status.rb +1 -1
  29. data/app/presenters/renalware/hd/session_presenter.rb +2 -1
  30. data/app/presenters/renalware/summary_part.rb +1 -1
  31. data/app/views/renalware/addresses/_address.html.slim +2 -2
  32. data/app/views/renalware/addresses/_form.html.slim +3 -3
  33. data/app/views/renalware/admissions/admissions/_form.html.slim +1 -1
  34. data/app/views/renalware/admissions/admissions/_table.html.slim +6 -7
  35. data/app/views/renalware/admissions/consults/_filters.html.slim +12 -9
  36. data/app/views/renalware/admissions/consults/_form.html.slim +2 -2
  37. data/app/views/renalware/admissions/consults/_table.html.slim +45 -25
  38. data/app/views/renalware/api/ukrdc/patients/_lab_orders.xml.builder +1 -1
  39. data/app/views/renalware/api/ukrdc/patients/_observations.xml.builder +1 -1
  40. data/app/views/renalware/directory/people/_address_form.html.slim +3 -3
  41. data/app/views/renalware/letters/contacts/_new.html.slim +10 -8
  42. data/app/views/renalware/letters/contacts/_new_person.html.slim +15 -19
  43. data/app/views/renalware/letters/contacts/_person_form.html.slim +48 -25
  44. data/app/views/renalware/letters/formatted_letters/_letter.html.slim +14 -3
  45. data/app/views/renalware/letters/letters/_cc_recipient_form.html.slim +1 -1
  46. data/app/views/renalware/letters/letters/_form.html.slim +1 -1
  47. data/app/views/renalware/letters/letters/_main_recipient.html.slim +5 -5
  48. data/app/views/renalware/letters/letters/contact_added.js.erb +4 -2
  49. data/app/views/renalware/patients/alerts/_list.html.slim +1 -1
  50. data/app/views/renalware/problems/problems/edit.html.slim +2 -3
  51. data/app/views/renalware/problems/problems/new.html.slim +2 -3
  52. data/app/views/renalware/snippets/snippets/_list.html.slim +3 -8
  53. data/app/views/renalware/snippets/snippets/_row.html.slim +5 -4
  54. data/app/views/renalware/snippets/snippets/_table.html.slim +24 -23
  55. data/app/views/renalware/snippets/snippets/edit.html.slim +2 -3
  56. data/app/views/renalware/snippets/snippets/index.html.slim +3 -2
  57. data/app/views/renalware/snippets/snippets/new.html.slim +2 -5
  58. data/lib/renalware/version.rb +1 -1
  59. metadata +2 -2
@@ -38,9 +38,11 @@ module Renalware
38
38
  Letter::Draft.new(params.merge!(type: Letter::Draft.name, patient: patient))
39
39
  end
40
40
 
41
+ # note both practice and gp need to be present before we can the pcp - we'll use the
42
+ # practice address but the GP's name as the salutation.
41
43
  def include_primary_care_physician_as_default_main_recipient
42
44
  return if letter.main_recipient.present?
43
- if patient.primary_care_physician.present?
45
+ if patient.primary_care_physician.present? && patient.practice_id.present?
44
46
  letter.build_main_recipient(person_role: :primary_care_physician)
45
47
  else
46
48
  letter.build_main_recipient(person_role: :patient)
@@ -32,13 +32,9 @@ module Renalware
32
32
  end
33
33
 
34
34
  def current_address
35
- if patient?
36
- letter.patient.current_address
37
- elsif primary_care_physician?
38
- address_for_primary_care_physician
39
- else
40
- addressee.address
41
- end
35
+ return address_for_patient if patient?
36
+ return practice_address_for_patient if primary_care_physician?
37
+ address_for_addressee_eg_contact
42
38
  end
43
39
 
44
40
  def for_contact?(contact)
@@ -48,17 +44,46 @@ module Renalware
48
44
 
49
45
  private
50
46
 
51
- def address_for_primary_care_physician
47
+ def address_for_patient
48
+ letter.patient.current_address.tap do |address|
49
+ ensure_address_has_a_name_required_when_displaying_letters(
50
+ address,
51
+ letter.patient.full_name
52
+ )
53
+ end
54
+ end
55
+
56
+ def practice_address_for_patient
52
57
  address = letter.patient&.practice&.address
53
58
  if address.present? && letter.primary_care_physician.present?
54
- address.name = letter.primary_care_physician.salutation
59
+ ensure_address_has_a_name_required_when_displaying_letters(
60
+ address,
61
+ letter.primary_care_physician.salutation
62
+ )
55
63
  end
56
64
  address
57
65
  end
58
66
 
67
+ def address_for_addressee_eg_contact
68
+ addressee.address.tap do |address|
69
+ ensure_address_has_a_name_required_when_displaying_letters(address, addressee.to_s)
70
+ end
71
+ end
72
+
59
73
  def patient_or_primary_care_physician?
60
74
  patient? || primary_care_physician?
61
75
  end
76
+
77
+ # Make sure we have a 'name' set in the address record set as this is used in the letter
78
+ # e.g. Roger Robar <- address.name
79
+ # 123 Toon Town
80
+ # ...
81
+ # Note address.name is a redundant field not consistently populated in the app
82
+ # and should be removed. However its consumed in a quite a few laces building letters
83
+ # and displaying the letter form, hence this hack.
84
+ def ensure_address_has_a_name_required_when_displaying_letters(address, name)
85
+ address.name = name if address.present? && address.name.blank?
86
+ end
62
87
  end
63
88
  end
64
89
  end
@@ -49,6 +49,10 @@ module Renalware
49
49
  all.map{ |name, hosp_no| "#{name}: #{hosp_no}" }.join(" ")
50
50
  end
51
51
 
52
+ def to_s_multiline
53
+ all.map{ |name, hosp_no| "#{name}: #{hosp_no}" }.join("<br>").html_safe
54
+ end
55
+
52
56
  # Returns true if the patient has a hospital number at the requested hospital.
53
57
  # Example usage
54
58
  # PatientHospitalIdentifiers.new(patient).patient_at?(:KCH) # => true
@@ -13,8 +13,11 @@ module Renalware
13
13
  term = "%#{search_term}%"
14
14
  Practice.select(:id, :name)
15
15
  .left_outer_joins(:address)
16
- .where("patient_practices.name ILIKE ? OR addresses.postcode ILIKE ?", term, term)
17
- # .select("patient_practices.id", "patient_practices.name")
16
+ .includes(:address)
17
+ .where("patient_practices.name ILIKE ? "\
18
+ "OR addresses.street_1 ILIKE ? " \
19
+ "OR addresses.postcode ILIKE ?", term, term, term)
20
+ .limit(50)
18
21
  end
19
22
  end
20
23
  end
@@ -26,7 +26,7 @@ module Renalware
26
26
  end
27
27
 
28
28
  def to_s
29
- description.to_s if description
29
+ description&.to_s
30
30
  end
31
31
  end
32
32
  end
@@ -73,7 +73,8 @@ module Renalware
73
73
  when ::Float; (post - pre).round(1)
74
74
  when ::Integer; (post - pre)
75
75
  end
76
- # raise "Unsupported class '#{pre.class}'' - cannot calculate the change"
76
+ rescue StandardError => exception
77
+ nil
77
78
  end
78
79
 
79
80
  def summarised_access_used
@@ -7,7 +7,7 @@ module Renalware
7
7
  # reporting dashboards or summary pages. The Clinical Summary for instance comprises an array
8
8
  # of various SummaryParts
9
9
  class SummaryPart
10
- DATE_FORMAT = "%Y%m%d%H%M%S%L".freeze
10
+ DATE_FORMAT = "%Y%m%d%H%M%S%L"
11
11
  rattr_initialize :patient
12
12
  attr_implement :to_partial_path
13
13
 
@@ -1,6 +1,6 @@
1
1
  dl.dl-horizontal
2
- dt Name
3
- dd= address.name
2
+ / dt Name
3
+ / dd= address.name
4
4
 
5
5
  dt Organisation Name
6
6
  dd= address.organisation_name
@@ -1,6 +1,6 @@
1
- = a.input :name,
2
- placeholder: "If different than above (optional)",
3
- wrapper: :horizontal_medium
1
+ / = a.input :name,
2
+ / placeholder: "If different than above (optional)",
3
+ / wrapper: :horizontal_medium
4
4
  = a.input :street_1, wrapper: :horizontal_large
5
5
  = a.input :street_2, wrapper: :horizontal_large
6
6
  = a.input :street_3, wrapper: :horizontal_large
@@ -13,7 +13,7 @@
13
13
  / at option index 1.
14
14
  = f.input :patient_id,
15
15
  wrapper: :horizontal_medium,
16
- collection: [[admission.patient&.to_s, admission.patient&.id]],
16
+ collection: [[admission.patient&.to_s(:long), admission.patient&.id]],
17
17
  selected: 1,
18
18
  input_html: { \
19
19
  class: "patient-id-select2 patient-ajax-search",
@@ -3,6 +3,8 @@
3
3
  table
4
4
  thead
5
5
  tr
6
+ - unless compact
7
+ th.col-width-tiny(rowspan=2)
6
8
  th.col-width-medium(rowspan=2) Site/Ward
7
9
  - unless compact
8
10
  th.at-least.col-width-medium(rowspan=2) Patient
@@ -13,8 +15,6 @@
13
15
  th.col-width-tiny(rowspan=2) Age
14
16
  th.admission.subhead(colspan=3) Admission
15
17
  th.discharge.subhead(colspan=4) Discharge
16
- - unless compact
17
- th.col-width-tiny(rowspan=2)
18
18
 
19
19
  tr
20
20
  th.col-width-date Date
@@ -29,6 +29,10 @@
29
29
  tbody
30
30
  - admissions.each do |admission|
31
31
  tr
32
+ - unless compact
33
+ td
34
+ - if policy(admission).edit?
35
+ = link_to "Edit", edit_admissions_admission_path(admission)
32
36
  td= admission.unit_and_ward
33
37
  - unless compact
34
38
  td= default_patient_link(admission.patient)
@@ -51,11 +55,6 @@
51
55
  - else
52
56
  | -
53
57
 
54
- - unless compact
55
- td
56
- - if policy(admission).edit?
57
- = link_to "Edit", edit_admissions_admission_path(admission)
58
-
59
58
  = content_tag(:tr, id: "admission-quick-preview-#{admission.id}", style: "display: none")
60
59
  td
61
60
  td(colspan=13)
@@ -5,29 +5,32 @@
5
5
  method: :get do |f|
6
6
  .row
7
7
  .columns.medium-3.large-2
8
+ = f.input :identity_match, label: "Hosp/NHS no. or name"
9
+
10
+ .columns.medium-2.large-2
8
11
  = f.input :consult_site_id_eq,
9
12
  collection: Renalware::Admissions::ConsultSite.pluck(:name, :id),
10
13
  label: "Site"
11
- .columns.medium-2.large-1
14
+ .columns.medium-1.large-1
12
15
  = f.input :requires_aki_nurse_eq,
13
16
  collection: [["Yes", true], ["No", false]],
14
- label: "AKI Nurse req."
17
+ label: "AKI Nurse?"
15
18
  .columns.medium-2.large-1
16
19
  = f.input :seen_by_id_eq,
17
20
  include_blank: false,
18
21
  collection: [["Anyone", nil], ["Me", current_user.id]],
19
22
  label: "Seen by"
20
- .columns.medium-2.large-1
23
+ .columns.medium-1.large-1
21
24
  = f.input :aki_risk_eq,
22
25
  include_blank: true,
23
26
  collection: Renalware::Admissions::Consult.aki_risk.values.map{ |value| [value.text, value] },
24
27
  label: "AKI Risk"
25
- / .columns.medium-2.large-1
26
- / = f.input :stopped_on_eq_nil,
27
- / include_blank: false,
28
- / collection: [["Yes", true], ["No", false]],
29
- / label: "Active"
28
+ .columns.medium-1.large-1
29
+ = f.input :ended_on_null,
30
+ include_blank: true,
31
+ collection: [["Yes", true], ["No", false]],
32
+ label: "Active"
30
33
  .columns.medium-2.large-2.actions.end
31
34
  = f.submit "Filter", class: "button"
32
35
  span= " or "
33
- = link_to t("helpers.reset"), admissions_consults_path
36
+ = link_to t("helpers.reset"), admissions_consults_path(reset: 1)
@@ -9,7 +9,7 @@
9
9
  / at option index 1.
10
10
  = f.input :patient_id,
11
11
  wrapper: :horizontal_medium,
12
- collection: [[consult.patient&.to_s, consult.patient&.id]],
12
+ collection: [[consult.patient&.to_s(:long), consult.patient&.id]],
13
13
  selected: 1,
14
14
  input_html: { \
15
15
  class: "patient-id-select2 patient-ajax-search",
@@ -45,7 +45,7 @@
45
45
 
46
46
  = f.input :aki_risk, include_blank: "Please select", wrapper: :horizontal_small
47
47
  = f.input :requires_aki_nurse, as: :inline_radio_buttons, wrapper: :horizontal_small
48
- = f.input :description, wrapper: :horizontal_large, input_html: { rows: 5 }
48
+ = f.input :description, wrapper: :horizontal_large, input_html: { rows: 10 }
49
49
 
50
50
  = f.submit class: :button
51
51
  span= " or "
@@ -2,38 +2,30 @@
2
2
  table
3
3
  thead
4
4
  tr
5
- th= sort_link(query, :consult_site_id, "Location")
6
- th.at-least.col-width-medium Patient
5
+ th.col-width-medium
6
+ th.col-width-medium= sort_link(query,
7
+ :location,
8
+ [:consult_site_name, :hospital_ward_name],
9
+ "Location")
10
+ th.col-width-large
11
+ = sort_link(query, :patient, ["patient_family_name", "patient_given_name asc"], "Patient")
7
12
  th.col-width-nhs-no NHS No.
8
13
  th.col-width-reference-no Hosp Nos.
9
- th.col-width-date Started
10
- th.col-width-date Ended
11
- th.col-width-medium Modality
12
- th.col-width-tiny Sex
13
- th.col-width-tiny Age
14
+ th.col-width-date= sort_link(query, :started_on, "Started")
15
+ th.col-width-date= sort_link(query, :ended_on, "Ended")
16
+ th.col-width-small.show-for-large-up Modality
17
+ th.col-width-tiny.show-for-large-up Sex
18
+ th.col-width-tiny.show-for-large-up Age
14
19
  th.col-width-tiny= sort_link(query, :aki_risk, "AKI Risk")
15
20
  th.col-width-tiny= sort_link(query, :requires_aki_nurse, " AKI Nurse?")
16
- th.show-for-large-up Author
17
- th.col-width-medium Description
18
- th.col-width-tiny
21
+ /th.show-for-large-up Author
22
+ /th.col-width-medium.show-for-xlarge-up Description
23
+
19
24
  tbody
20
25
  - consults.each do |consult|
21
26
  - uid = "consult-#{consult.id}"
22
27
  tr
23
- td= consult.location
24
- td= consult.patient_name
25
- td= consult.patient_nhs_number
26
- td= consult.patient_hospital_identifiers
27
- td= l(consult.started_on)
28
- td= l(consult.ended_on)
29
- td= consult.patient_current_modality
30
- td= consult.patient_sex
31
- td= consult.patient_age
32
- td= consult.aki_risk&.text
33
- td= yes_no(consult.requires_aki_nurse)
34
- td.show-for-large-up.consult-author.col-width-medium-with-ellipsis(title=consult.created_by)= consult.created_by
35
- td.col-width-medium-with-ellipsis(title=consult.description)= consult.description
36
- td.actions-dropdown
28
+ td.actions-dropdown.going-right
37
29
  / As we have lots of possible actions, group them in a button group.
38
30
  / A wrapping div is required for now in order for the button group display correctly
39
31
  / (though we could style the td like a div I guess).
@@ -42,7 +34,7 @@
42
34
  data-dropdown=uid
43
35
  aria-controls=uid
44
36
  aria-expanded="false")
45
- | Actions&hellip;
37
+ | Actions
46
38
  ul.f-dropdown(id="#{uid}" data-dropdown-content aria-hidden="true")
47
39
 
48
40
  = dropdown_btn_item(icon: "fa-edit",
@@ -61,3 +53,31 @@
61
53
  li= render "renalware/admissions/requests/create_request_link",
62
54
  patient: consult.patient,
63
55
  link_text: "Request Admission"
56
+ | &nbsp;&nbsp;
57
+ = link_to("Toggle",
58
+ "#consult-quick-preview-#{consult.id}",
59
+ data: { behaviour: "toggler" })
60
+ td= consult.location
61
+ td= default_patient_link(consult.patient)
62
+ td= consult.patient_nhs_number
63
+ td= consult.patient_hospital_identifiers&.to_s_multiline
64
+ td= l(consult.started_on)
65
+ td= l(consult.ended_on)
66
+ td.show-for-large-up= consult.patient_current_modality
67
+ td.show-for-large-up= consult.patient_sex
68
+ td.show-for-large-up= consult.patient_age
69
+ td= consult.aki_risk&.text
70
+ td= yes_no(consult.requires_aki_nurse)
71
+ /td.show-for-xlarge-up.consult-author.col-width-medium-with-ellipsis(title=consult.created_by)= consult.created_by
72
+ /td.col-width-medium-with-ellipsis(title=consult.description)= consult.description
73
+ = content_tag(:tr, id: "consult-quick-preview-#{consult.id}", style: "display: none")
74
+ td(colspan=12)
75
+ .quick-preview
76
+ dl.dl-horizontal
77
+ dt Author
78
+ dd=consult.created_by
79
+ dt Modality
80
+ dd= consult.patient_current_modality
81
+ dt Description
82
+ dd= simple_format consult.description
83
+ td
@@ -4,7 +4,7 @@ xml = builder
4
4
  xml.LabOrders(
5
5
  start: patient.changes_since.to_date.iso8601,
6
6
  stop: patient.changes_up_until.to_date.iso8601
7
- ) do
7
+ ) do
8
8
  render partial: "renalware/api/ukrdc/patients/lab_orders/lab_order",
9
9
  collection: patient.observation_requests,
10
10
  as: :request,
@@ -7,7 +7,7 @@ xml = builder
7
7
  xml.Observations(
8
8
  start: patient.changes_since.to_date.iso8601,
9
9
  stop: patient.changes_up_until.to_date.iso8601
10
- ) do
10
+ ) do
11
11
  patient.clinic_visits.each do |visit|
12
12
  render "clinic_visit_observation",
13
13
  visit: visit,
@@ -1,7 +1,7 @@
1
1
  = f.simple_fields_for :address, wrapper: "horizontal_form" do |fa|
2
- = fa.input :name,
3
- placeholder: "If different than above (optional)",
4
- wrapper: :horizontal_medium
2
+ / = fa.input :name,
3
+ / placeholder: "If different than above (optional)",
4
+ / wrapper: :horizontal_medium
5
5
  = fa.input :organisation_name,
6
6
  placeholder: "e.g. practice or hospital name (optional)",
7
7
  wrapper: :horizontal_medium
@@ -1,11 +1,13 @@
1
- .row
2
- .large-12.columns
1
+ .modal
2
+ .modal__header
3
3
  h2= t(".title")
4
+ = render "renalware/shared/modal_close_link"
4
5
 
5
- section.person-from-directory
6
- = render "/renalware/letters/contacts/person_from_directory", contact: contact,
7
- patient: patient, contact_descriptions: contact_descriptions
6
+ .modal__body
7
+ section.person-from-directory
8
+ = render "/renalware/letters/contacts/person_from_directory", contact: contact,
9
+ patient: patient, contact_descriptions: contact_descriptions
8
10
 
9
- section.new-person
10
- = render "/renalware/letters/contacts/new_person", contact: contact,
11
- patient: patient, contact_descriptions: contact_descriptions
11
+ section.new-person
12
+ = render "/renalware/letters/contacts/new_person", contact: contact,
13
+ patient: patient, contact_descriptions: contact_descriptions
@@ -1,16 +1,21 @@
1
- .row
2
- .large-12.columns
3
- .g-center
4
- = link_to "Pick person from directory",
5
- "#",
6
- class: "button secondary",
7
- data: { behaviour: "toggle-section" }
8
-
9
1
  = simple_form_for contact,
10
2
  url: patient_letters_contacts_path(patient),
11
- html: { autocomplete: "off" },
12
- wrapper: "horizontal_form" do |f|
3
+ html: { autocomplete: "off" } do |f|
13
4
 
5
+ .row
6
+ .large-12.columns
7
+ .left
8
+ = link_to "Cancel and go back to Pick person from directory",
9
+ "#",
10
+ class: "button secondary",
11
+ data: { behaviour: "toggle-section" }
12
+ .right
13
+ = f.submit t(".save"), class: "button"
14
+ span= " or "
15
+ = link_to t(".cancel"),
16
+ "#",
17
+ "aria-label" => "Close",
18
+ class: "reveal-modal-close"
14
19
  .row.errors-container
15
20
  .large-12.columns
16
21
  ul.error-messages
@@ -20,12 +25,3 @@
20
25
  = render "/renalware/letters/contacts/person_form", f: f,
21
26
  contact_descriptions: contact_descriptions
22
27
 
23
- .row
24
- .large-12.columns
25
- br
26
- = f.submit t(".save"), class: "button"
27
- span= " or "
28
- = link_to t(".cancel"),
29
- "#",
30
- "aria-label" => "Close",
31
- class: "reveal-modal-close"