clinicedc 2.0.38__py3-none-any.whl → 2.0.40__py3-none-any.whl

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.

Potentially problematic release.


This version of clinicedc might be problematic. Click here for more details.

Files changed (157) hide show
  1. {clinicedc-2.0.38.dist-info → clinicedc-2.0.40.dist-info}/METADATA +3 -12
  2. {clinicedc-2.0.38.dist-info → clinicedc-2.0.40.dist-info}/RECORD +146 -153
  3. {clinicedc-2.0.38.dist-info → clinicedc-2.0.40.dist-info}/WHEEL +1 -1
  4. edc_adverse_event/dashboard_urls.py +2 -0
  5. edc_adverse_event/middleware.py +7 -6
  6. edc_adverse_event/navbars.py +4 -8
  7. edc_adverse_event/templates/edc_adverse_event/tmg/tmg_ae_listboard_result.html +27 -23
  8. edc_adverse_event/templatetags/edc_adverse_event_extras.py +21 -34
  9. edc_adverse_event/urls.py +14 -6
  10. edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +6 -8
  11. edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +2 -4
  12. edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +9 -7
  13. edc_adverse_event/views/home_view.py +1 -2
  14. edc_adverse_event/views/tmg/death_listboard_view.py +8 -6
  15. edc_adverse_event/views/tmg/home_view.py +4 -3
  16. edc_adverse_event/views/tmg/summary_listboard_view.py +4 -4
  17. edc_appointment/utils.py +3 -6
  18. edc_appointment/views/unscheduled_appointment_view.py +1 -1
  19. edc_consent/form_validators/consent_definition_form_validator_mixin.py +5 -2
  20. edc_consent/model_mixins/consent_version_model_mixin.py +1 -1
  21. edc_consent/navbars.py +2 -1
  22. edc_crf/model_mixins/crf_model_mixin.py +5 -1
  23. edc_crf/model_mixins/crf_no_manager_model_mixin.py +2 -2
  24. edc_crf/model_mixins/singleton_crf_model_mixin.py +1 -1
  25. edc_dashboard/middleware.py +10 -16
  26. edc_dashboard/middleware_mixins.py +10 -0
  27. edc_dashboard/navbars.py +1 -1
  28. edc_dashboard/url_config.py +50 -31
  29. edc_dashboard/url_names.py +23 -17
  30. edc_dashboard/utils.py +4 -4
  31. edc_dashboard/view_mixins/template_request_context_mixin.py +5 -8
  32. edc_dashboard/view_mixins/url_request_context_mixin.py +38 -26
  33. edc_dashboard/views/administration_view.py +2 -2
  34. edc_dashboard/views/dashboard_view.py +5 -10
  35. edc_data_manager/handlers/handlers.py +17 -5
  36. edc_data_manager/models/query_rule.py +7 -7
  37. edc_data_manager/navbar_item.py +1 -1
  38. edc_data_manager/rule/query_rule_wrapper.py +1 -1
  39. edc_data_manager/rule/rule_runner.py +6 -6
  40. edc_device/navbars.py +1 -1
  41. edc_export/navbars.py +2 -2
  42. edc_glucose/model_mixin_factories/fasting_model_mixin_factory.py +1 -1
  43. edc_identifier/identifier.py +6 -9
  44. edc_lab_dashboard/dashboard_urls.py +7 -5
  45. edc_lab_dashboard/middleware.py +10 -17
  46. edc_lab_dashboard/navbars.py +9 -9
  47. edc_lab_dashboard/templates/edc_lab_dashboard/listboard/tags/status_column.html +7 -0
  48. edc_lab_dashboard/urls.py +2 -5
  49. edc_lab_dashboard/view_mixins/form_action_view_mixin.py +1 -2
  50. edc_lab_dashboard/views/action_views/action_view.py +6 -6
  51. edc_lab_dashboard/views/action_views/aliquot_view.py +1 -1
  52. edc_lab_dashboard/views/action_views/manage_box_item_view.py +2 -3
  53. edc_lab_dashboard/views/action_views/manage_manifest_view.py +1 -1
  54. edc_lab_dashboard/views/action_views/manifest_view.py +2 -2
  55. edc_lab_dashboard/views/action_views/pack_view.py +2 -2
  56. edc_lab_dashboard/views/action_views/process_view.py +1 -1
  57. edc_lab_dashboard/views/action_views/receive_view.py +1 -1
  58. edc_lab_dashboard/views/action_views/requisition_view.py +1 -1
  59. edc_lab_dashboard/views/action_views/verify_box_item_view.py +1 -1
  60. edc_lab_dashboard/views/listboard_views/manage_box_listboard_view.py +4 -5
  61. edc_lab_dashboard/views/listboard_views/manifest_listboard_view.py +5 -6
  62. edc_lab_dashboard/views/listboard_views/process_listboard_view.py +4 -5
  63. edc_lab_dashboard/views/listboard_views/receive_listboard_view.py +5 -6
  64. edc_lab_dashboard/views/listboard_views/verify_box_listboard_view.py +5 -6
  65. edc_label/navbars.py +1 -1
  66. edc_list_data/admin.py +3 -3
  67. edc_list_data/load_model_data.py +1 -1
  68. edc_list_data/management/commands/load_list_data.py +2 -2
  69. edc_list_data/site_list_data.py +4 -4
  70. edc_listboard/middleware.py +9 -8
  71. edc_listboard/templates/edc_listboard/listboard.html +1 -1
  72. edc_listboard/view_mixins/listboard_filter_view_mixin.py +1 -1
  73. edc_listboard/view_mixins/search_form_view_mixin.py +1 -1
  74. edc_listboard/views/listboard_view.py +16 -25
  75. edc_listboard/views/screen/screening_listboard_view.py +2 -2
  76. edc_listboard/views/subject/subject_listboard_view.py +2 -2
  77. edc_locator/forms/subject_locator_form_validator.py +2 -2
  78. edc_ltfu/action_items.py +1 -2
  79. edc_ltfu/forms/ltfu_form_validator_mixin.py +3 -3
  80. edc_ltfu/modeladmin_mixin.py +1 -1
  81. edc_ltfu/modelform_mixins.py +2 -2
  82. edc_metadata/admin/modeladmin_mixins.py +11 -9
  83. edc_metadata/management/commands/update_metadata.py +1 -1
  84. edc_metadata/management/commands/update_metadata_schedule_names.py +7 -7
  85. edc_metadata/management/commands/validate_entry_status.py +1 -1
  86. edc_metadata/management/commands/validate_rule_groups.py +1 -1
  87. edc_metadata/metadata/metadata_getter.py +3 -5
  88. edc_metadata/metadata_handler.py +5 -5
  89. edc_metadata/metadata_mixins/source_model_metadata_mixin.py +1 -1
  90. edc_metadata/metadata_refresher.py +1 -1
  91. edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
  92. edc_metadata/metadata_rules/logic.py +3 -3
  93. edc_metadata/metadata_rules/persistant_singleton_mixin.py +2 -4
  94. edc_metadata/metadata_rules/requisition/requisition_rule_group.py +1 -1
  95. edc_metadata/metadata_rules/rule.py +4 -3
  96. edc_metadata/metadata_rules/rule_group.py +2 -2
  97. edc_metadata/metadata_rules/rule_group_meta_options.py +2 -2
  98. edc_metadata/metadata_rules/rule_group_metaclass.py +21 -22
  99. edc_metadata/metadata_rules/site.py +1 -1
  100. edc_metadata/metadata_updater.py +4 -3
  101. edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +3 -5
  102. edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +1 -1
  103. edc_metadata/next_form_getter.py +15 -19
  104. edc_metadata/offline_models.py +1 -1
  105. edc_metadata/requisition/requisition_metadata_handler.py +5 -5
  106. edc_metadata/update_metadata_on_schedule_change.py +2 -4
  107. edc_metadata/utils.py +1 -1
  108. edc_model/models/signals.py +7 -2
  109. edc_model_admin/mixins/model_admin_redirect_on_delete_mixin.py +4 -3
  110. edc_navbar/apps.py +0 -2
  111. edc_navbar/navbar.py +1 -1
  112. edc_navbar/navbar_item.py +29 -16
  113. edc_navbar/navbars.py +6 -19
  114. edc_navbar/site_navbars.py +6 -7
  115. edc_navbar/system_checks.py +3 -10
  116. edc_navbar/utils.py +14 -0
  117. edc_navbar/view_mixin.py +6 -9
  118. edc_pharmacy/navbars.py +1 -1
  119. edc_pharmacy/views/confirm_stock_from_queryset_view.py +3 -3
  120. edc_protocol/middleware.py +9 -13
  121. edc_protocol/navbars.py +1 -1
  122. edc_refusal/forms.py +1 -3
  123. edc_reportable/utils/convert_units.py +1 -1
  124. edc_review_dashboard/middleware.py +6 -3
  125. edc_review_dashboard/navbars.py +1 -2
  126. edc_review_dashboard/urls.py +3 -2
  127. edc_review_dashboard/views/subject_review_listboard_view.py +4 -2
  128. edc_subject_dashboard/dashboard_templates.py +1 -3
  129. edc_subject_dashboard/dashboard_urls.py +8 -0
  130. edc_subject_dashboard/middleware.py +10 -7
  131. edc_subject_dashboard/templates/edc_subject_dashboard/buttons/refresh_appointments_button.html +1 -1
  132. edc_subject_dashboard/templates/edc_subject_dashboard/dashboard.html +1 -1
  133. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +3 -1
  134. edc_subject_dashboard/urls.py +13 -4
  135. edc_subject_dashboard/views/base_requisition_view.py +2 -1
  136. edc_subject_dashboard/views/subject_dashboard_view.py +1 -2
  137. edc_timepoint/__init__.py +0 -2
  138. edc_timepoint/model_mixins.py +1 -2
  139. edc_timepoint/utils.py +1 -1
  140. edc_timepoint/visit_timepoint_lookup.py +6 -0
  141. edc_visit_schedule/admin/subject_schedule_history_admin.py +1 -2
  142. edc_visit_schedule/navbars.py +3 -4
  143. edc_visit_schedule/visit/visit.py +15 -0
  144. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +5 -0
  145. edc_visit_tracking/models/subject_visit.py +5 -0
  146. edc_lab_dashboard/model_wrappers/__init__.py +0 -8
  147. edc_lab_dashboard/model_wrappers/aliquot_model_wrapper.py +0 -31
  148. edc_lab_dashboard/model_wrappers/base_box_item_model_wrapper.py +0 -21
  149. edc_lab_dashboard/model_wrappers/box_model_wrapper.py +0 -12
  150. edc_lab_dashboard/model_wrappers/manage_box_item_model_wrapper.py +0 -6
  151. edc_lab_dashboard/model_wrappers/manifest_item_model_wrapper.py +0 -21
  152. edc_lab_dashboard/model_wrappers/manifest_model_wrapper.py +0 -11
  153. edc_lab_dashboard/model_wrappers/requisition_model_wrapper.py +0 -25
  154. edc_lab_dashboard/model_wrappers/result_model_wrapper.py +0 -8
  155. edc_lab_dashboard/model_wrappers/verify_box_model_wrapper.py +0 -10
  156. edc_navbar/get_default_navbar.py +0 -9
  157. {clinicedc-2.0.38.dist-info → clinicedc-2.0.40.dist-info}/licenses/LICENSE +0 -0
edc_navbar/view_mixin.py CHANGED
@@ -1,14 +1,12 @@
1
1
  from typing import Any
2
2
 
3
- from django.apps import apps as django_apps
4
-
5
- from .get_default_navbar import get_default_navbar
6
3
  from .site_navbars import site_navbars
4
+ from .utils import get_default_navbar_name
7
5
 
8
6
 
9
7
  class NavbarViewMixin:
10
8
  navbar_selected_item = None
11
- navbar_name = get_default_navbar()
9
+ navbar_name = get_default_navbar_name()
12
10
 
13
11
  def get_context_data(self, **kwargs) -> dict[str, Any]:
14
12
  """Add rendered navbar <navbar_name> to the context for
@@ -16,18 +14,17 @@ class NavbarViewMixin:
16
14
 
17
15
  Also adds the "default" navbar.
18
16
  """
19
- kwargs = self.get_navbar_context_data(kwargs)
17
+ kwargs = self.get_context_data_for_navbars(kwargs)
20
18
  return super().get_context_data(**kwargs)
21
19
 
22
20
  def get_navbar_name(self):
23
21
  return self.navbar_name
24
22
 
25
- def get_navbar_context_data(self, context) -> dict:
23
+ def get_context_data_for_navbars(self, context) -> dict:
26
24
  navbar = site_navbars.get_navbar(name=self.get_navbar_name())
27
25
  navbar.set_active(self.get_navbar_selected(**context))
28
26
  context.update(navbar=navbar)
29
- app_config = django_apps.get_app_config("edc_navbar")
30
- default_navbar_name = app_config.default_navbar_name
27
+ default_navbar_name = get_default_navbar_name()
31
28
  if default_navbar_name and self.get_navbar_name() != default_navbar_name:
32
29
  default_navbar = site_navbars.get_navbar(name=default_navbar_name)
33
30
  default_navbar.set_active(self.navbar_selected_item)
@@ -36,5 +33,5 @@ class NavbarViewMixin:
36
33
  )
37
34
  return context
38
35
 
39
- def get_navbar_selected(self, **kwargs) -> str:
36
+ def get_navbar_selected(self, **kwargs) -> str: # noqa: ARG002
40
37
  return self.navbar_selected_item
edc_pharmacy/navbars.py CHANGED
@@ -6,7 +6,7 @@ pharmacy_navbar_item = NavbarItem(
6
6
  title="",
7
7
  fa_icon="fa-prescription",
8
8
  codename="edc_pharmacy.nav_pharmacy_section",
9
- url_name="edc_pharmacy:home_url",
9
+ url_with_namespace="edc_pharmacy:home_url",
10
10
  )
11
11
 
12
12
  navbar = Navbar(name="pharmacy")
@@ -9,7 +9,6 @@ from django.urls import reverse
9
9
  from django.utils.decorators import method_decorator
10
10
  from django.utils.translation import gettext as _
11
11
  from django.views.generic.base import TemplateView
12
-
13
12
  from edc_constants.constants import CONFIRMED
14
13
  from edc_dashboard.view_mixins import EdcViewMixin
15
14
  from edc_navbar import NavbarViewMixin
@@ -29,8 +28,8 @@ class ConfirmStockFromQuerySetView(
29
28
  navbar_selected_item = "pharmacy"
30
29
  codes_per_page = 12
31
30
 
32
- def get_context_data(self, **kwargs): # noqa: ARG002
33
- return dict(
31
+ def get_context_data(self, **kwargs):
32
+ kwargs.update(
34
33
  CONFIRMED=CONFIRMED,
35
34
  ALREADY_CONFIRMED=ALREADY_CONFIRMED,
36
35
  INVALID=INVALID,
@@ -40,6 +39,7 @@ class ConfirmStockFromQuerySetView(
40
39
  source_changelist_url=self.source_changelist_url,
41
40
  **self.session_data,
42
41
  )
42
+ return super().get_context_data(**kwargs)
43
43
 
44
44
  @property
45
45
  def session_data(self):
@@ -8,18 +8,14 @@ class ResearchProtocolConfigMiddleware:
8
8
  def __call__(self, request):
9
9
  return self.get_response(request)
10
10
 
11
- def process_view(self, request, *args):
12
- pass
13
-
14
11
  def process_template_response(self, request, response): # noqa: ARG002
15
- if not response.context_data:
16
- response.context_data = {}
17
- protocol_config = ResearchProtocolConfig()
18
- response.context_data.update(
19
- copyright=protocol_config.copyright,
20
- disclaimer=protocol_config.disclaimer,
21
- institution=protocol_config.institution,
22
- license=protocol_config.license,
23
- project_name=protocol_config.project_name,
24
- )
12
+ if getattr(response, "context_data", None):
13
+ protocol_config = ResearchProtocolConfig()
14
+ response.context_data.update(
15
+ copyright=protocol_config.copyright,
16
+ disclaimer=protocol_config.disclaimer,
17
+ institution=protocol_config.institution,
18
+ license=protocol_config.license,
19
+ project_name=protocol_config.project_name,
20
+ )
25
21
  return response
edc_protocol/navbars.py CHANGED
@@ -8,7 +8,7 @@ protocol.register(
8
8
  title="Protocol",
9
9
  label="protocol",
10
10
  codename="edc_navbar.nav_edc_protocol",
11
- url_name="edc_protocol:home_url",
11
+ url_with_namespace="edc_protocol:home_url",
12
12
  )
13
13
  )
14
14
 
edc_refusal/forms.py CHANGED
@@ -2,7 +2,6 @@ from django import forms
2
2
  from django.core.exceptions import ObjectDoesNotExist
3
3
  from django.urls.base import reverse
4
4
  from django.utils.html import format_html
5
-
6
5
  from edc_constants.constants import OTHER
7
6
  from edc_dashboard.url_names import url_names
8
7
  from edc_form_validators import FormValidator, FormValidatorMixin
@@ -47,8 +46,7 @@ class AlreadyConsentedFormMixin:
47
46
  kwargs={"subject_identifier": obj.subject_identifier},
48
47
  )
49
48
  msg = format_html(
50
- "Not allowed. Subject has already consented. "
51
- 'See subject <A href="{}">{}</A>',
49
+ 'Not allowed. Subject has already consented. See subject <A href="{}">{}</A>',
52
50
  url,
53
51
  obj.subject_identifier,
54
52
  )
@@ -153,7 +153,7 @@ def convert_units(
153
153
  units_from: str | None = None,
154
154
  units_to: str | None = None,
155
155
  places: int | None = None,
156
- ):
156
+ ) -> int | float:
157
157
  return UnitsConverter(
158
158
  label=label,
159
159
  value=value,
@@ -1,24 +1,27 @@
1
1
  import contextlib
2
2
 
3
3
  from django.conf import settings
4
+ from edc_dashboard.middleware_mixins import EdcTemplateMiddlewareMixin
4
5
 
5
6
  from .dashboard_templates import dashboard_templates
6
7
 
7
8
 
8
- class DashboardMiddleware:
9
+ class DashboardMiddleware(EdcTemplateMiddlewareMixin):
9
10
  def __init__(self, get_response):
10
11
  self.get_response = get_response
11
12
 
12
13
  def __call__(self, request):
14
+ self.check_for_required_request_attrs(request)
13
15
  return self.get_response(request)
14
16
 
15
- def process_view(self, request, *args) -> None: # noqa: ARG002
17
+ def process_view(self, request, *args) -> None:
16
18
  template_data = dashboard_templates
17
19
  with contextlib.suppress(AttributeError):
18
20
  template_data.update(settings.REVIEW_DASHBOARD_BASE_TEMPLATES)
19
21
  request.template_data.update(**template_data)
20
22
 
21
23
  def process_template_response(self, request, response):
22
- if response.context_data:
24
+ if getattr(response, "context_data", None):
23
25
  response.context_data.update(**request.template_data)
26
+ request.template_data.update(**request.template_data)
24
27
  return response
@@ -7,10 +7,9 @@ navbar_item = NavbarItem(
7
7
  label="Review",
8
8
  title="Subject Review",
9
9
  codename="edc_review_dashboard.view_subject_review_listboard",
10
- url_name="subject_review_listboard_url",
10
+ url_names_key="subject_review_listboard_url",
11
11
  )
12
12
 
13
-
14
13
  navbar.register(navbar_item)
15
14
 
16
15
  site_navbars.register(navbar)
@@ -1,6 +1,5 @@
1
1
  from django.contrib import admin
2
2
  from django.urls import path
3
-
4
3
  from edc_data_manager.views import HomeView
5
4
  from edc_protocol.research_protocol_config import ResearchProtocolConfig
6
5
 
@@ -10,7 +9,7 @@ app_name = "edc_review_dashboard"
10
9
 
11
10
  urlpatterns = SubjectReviewListboardView.urls(
12
11
  namespace=app_name,
13
- label="subject_review_listboard",
12
+ url_names_key="subject_review_listboard_url",
14
13
  identifier_pattern=ResearchProtocolConfig().subject_identifier_pattern,
15
14
  )
16
15
 
@@ -18,3 +17,5 @@ urlpatterns += [
18
17
  path("admin/", admin.site.urls),
19
18
  path("", HomeView.as_view(), name="home_url"),
20
19
  ]
20
+
21
+ # aliquot_listboard = ("edc_lab_dashboard:aliquot_listboard_url",)
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from django.db.models.aggregates import Count
6
-
7
6
  from edc_appointment.view_mixins import AppointmentViewMixin
8
7
  from edc_dashboard.url_names import url_names
9
8
  from edc_dashboard.view_mixins import EdcViewMixin
@@ -44,6 +43,7 @@ class SubjectReviewListboardView(
44
43
 
45
44
  listboard_template = "subject_review_listboard_template"
46
45
  listboard_url = "subject_review_listboard_url"
46
+ listboard_back_url = "subject_review_listboard_url"
47
47
  listboard_panel_style = "default"
48
48
  listboard_panel_title = "Subject Review"
49
49
  listboard_view_permission_codename = "edc_review_dashboard.view_subject_review_listboard"
@@ -51,6 +51,7 @@ class SubjectReviewListboardView(
51
51
  navbar_selected_item = "subject_review"
52
52
  ordering = ("subject_identifier", "visit_code", "visit_code_sequence")
53
53
  paginate_by = 25
54
+ paginator_url = "subject_review_listboard_url"
54
55
  search_form_url = "subject_review_listboard_url"
55
56
  search_fields = (
56
57
  "subject_identifier",
@@ -59,7 +60,8 @@ class SubjectReviewListboardView(
59
60
  "user_modified",
60
61
  )
61
62
 
62
- # attr to call SubjectReviewListboardView.urls in urls.py
63
+ # Attribute to call SubjectReviewListboardView.urls in urls.py
64
+ # See UrlRequestContextMixin and UrlConfig
63
65
  urlconfig_getattr = "review_listboard_urls"
64
66
 
65
67
  def get_context_data(self, **kwargs) -> dict[str, Any]:
@@ -2,6 +2,4 @@
2
2
  use settings.DASHBOARD_BASE_TEMPLATES.
3
3
  """
4
4
 
5
- dashboard_templates = dict(
6
- edc_subject_dashboard_template="edc_subject_dashboard/dashboard.html"
7
- )
5
+ dashboard_templates = dict(subject_dashboard_template="edc_subject_dashboard/dashboard.html")
@@ -0,0 +1,8 @@
1
+ import contextlib
2
+
3
+ from django.conf import settings
4
+
5
+ dashboard_urls = dict()
6
+
7
+ with contextlib.suppress(AttributeError):
8
+ dashboard_urls.update(**settings.SUBJECT_DASHBOARD_URL_NAMES)
@@ -1,25 +1,28 @@
1
1
  from django.conf import settings
2
2
 
3
+ from edc_dashboard.middleware_mixins import EdcTemplateMiddlewareMixin
4
+ from edc_subject_dashboard.dashboard_urls import dashboard_urls
5
+
3
6
  from .dashboard_templates import dashboard_templates
4
7
 
5
8
 
6
- class DashboardMiddleware:
9
+ class DashboardMiddleware(EdcTemplateMiddlewareMixin):
7
10
  def __init__(self, get_response):
8
11
  self.get_response = get_response
9
12
 
10
13
  def __call__(self, request):
14
+ self.check_for_required_request_attrs(request)
11
15
  return self.get_response(request)
12
16
 
13
- def process_view(self, request, *args): # noqa: ARG002
17
+ def process_view(self, request, *args):
14
18
  """Adds/Updates references to templates."""
15
- try:
16
- template_data = settings.SUBJECT_DASHBOARD_BASE_TEMPLATES
17
- except AttributeError:
18
- template_data = dashboard_templates
19
+ request.url_name_data.update(**dashboard_urls)
20
+ template_data = getattr(settings, "SUBJECT_DASHBOARD_BASE_TEMPLATES", {})
21
+ template_data.update(**dashboard_templates)
19
22
  request.template_data.update(**template_data)
20
23
 
21
24
  def process_template_response(self, request, response):
22
- if response.context_data:
25
+ if getattr(response, "context_data", None):
23
26
  response.context_data.update(**request.url_name_data)
24
27
  response.context_data.update(**request.template_data)
25
28
  return response
@@ -1 +1 @@
1
- <a {% if url %}href="{{ url }}" {% else %} disabled {% endif %}data-toggle="tooltip" title="Refresh appointments" role="button" class="btn btn-sm btn-default"><i class="fas fa-arrows-rotate fa-1x fa-fw" aria-hidden="true"></i></a>
1
+ <a {% if url %}href="{{ url }}" {% else %} disabled {% endif %}data-toggle="tooltip" title="{{ title|default:"Refresh appointments" }}" role="button" class="btn btn-sm btn-default"><i class="fas fa-arrows-rotate fa-1x fa-fw" aria-hidden="true"></i></a>
@@ -1,4 +1,4 @@
1
- {% extends dashboard_base_template %}
1
+ {% extends dashboard_base_template|default:"edc_dashboard/base.html" %}
2
2
  {% load static i18n %}
3
3
  {% load edc_visit_schedule_extras edc_subject_dashboard_extras edc_dashboard_extras edc_adverse_event_extras %}
4
4
 
@@ -481,10 +481,12 @@ def render_refresh_appointments_button(
481
481
  visit_schedule_name: str | None = None,
482
482
  schedule_name: str | None = None,
483
483
  ) -> dict:
484
+ title = "Refresh appointments"
484
485
  if context["request"].user.userprofile.is_multisite_viewer or context[
485
486
  "request"
486
487
  ].user.userprofile.roles.filter(name=AUDITOR_ROLE):
487
488
  url = None
489
+ title = f"{title} (Disabled for Auditor)"
488
490
  else:
489
491
  url = reverse(
490
492
  "edc_subject_dashboard:refresh_appointments_url",
@@ -494,7 +496,7 @@ def render_refresh_appointments_button(
494
496
  schedule_name=schedule_name,
495
497
  ),
496
498
  )
497
- return dict(url=url)
499
+ return dict(url=url, title=title)
498
500
 
499
501
 
500
502
  @register.inclusion_tag(
@@ -1,5 +1,4 @@
1
1
  from django.urls.conf import path
2
-
3
2
  from edc_dashboard.url_names import url_names
4
3
  from edc_metadata.views import RefreshMetadataActionsView
5
4
 
@@ -37,6 +36,16 @@ urlpatterns = [
37
36
  ),
38
37
  ]
39
38
 
40
- url_names.register(url="requisition_print_actions_url", namespace=app_name)
41
- url_names.register(url="requisition_verify_actions_url", namespace=app_name)
42
- url_names.register(url="refresh_metadata_actions_url", namespace=app_name)
39
+ url_names.register(
40
+ key="requisition_print_actions_url",
41
+ url="requisition_print_actions_url",
42
+ namespace=app_name,
43
+ )
44
+ url_names.register(
45
+ key="requisition_verify_actions_url",
46
+ url="requisition_verify_actions_url",
47
+ namespace=app_name,
48
+ )
49
+ url_names.register(
50
+ key="refresh_metadata_actions_url", url="refresh_metadata_actions_url", namespace=app_name
51
+ )
@@ -9,12 +9,13 @@ from edc_label.printers_mixin import PrintersMixin
9
9
 
10
10
  class BaseRequisitionView(LoginRequiredMixin, PrintersMixin, View):
11
11
  success_url_name = "subject_dashboard_url"
12
+ lab_home_url_name = "requisition_listboard_url"
12
13
 
13
14
  def get_success_url(self):
14
15
  return url_names.get(self.success_url_name)
15
16
 
16
17
  def get(self, request, *args, **kwargs): # noqa: ARG002
17
- url = reverse("edc_lab_dashboard:home_url")
18
+ url = reverse(url_names.get(self.lab_home_url_name))
18
19
  return HttpResponseRedirect(url)
19
20
 
20
21
  def head(self, request, *args, **kwargs):
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from django.core.exceptions import ImproperlyConfigured
6
-
7
6
  from edc_action_item.view_mixins import ActionItemViewMixin
8
7
  from edc_appointment.view_mixins import AppointmentViewMixin
9
8
  from edc_consent.view_mixins import ConsentViewMixin
@@ -44,7 +43,7 @@ class SubjectDashboardView(
44
43
  navbar_selected_item = "consented_subject"
45
44
 
46
45
  dashboard_url_name = "subject_dashboard_url"
47
- dashboard_template = "subject_dashboard_template"
46
+ dashboard_template_name = "subject_dashboard_template"
48
47
 
49
48
  default_manager = "on_site"
50
49
 
edc_timepoint/__init__.py CHANGED
@@ -1,2 +0,0 @@
1
- from .timepoint import Timepoint
2
- from .timepoint_collection import TimepointCollection
@@ -32,8 +32,7 @@ class TimepointLookupModelMixin(models.Model):
32
32
  timepoint_lookup_cls = TimepointLookup
33
33
 
34
34
  def save(self, *args, **kwargs):
35
- timepoint_lookup_cls = getattr(self, "timepoint_lookup_cls", None)
36
- if timepoint_lookup_cls and get_enable_timepoint_checks():
35
+ if get_enable_timepoint_checks() and getattr(self, "timepoint_lookup_cls", None):
37
36
  timepoint_lookup = self.timepoint_lookup_cls()
38
37
  if timepoint_lookup.timepoint_model == self._meta.label_lower:
39
38
  raise ImproperlyConfigured(
edc_timepoint/utils.py CHANGED
@@ -2,4 +2,4 @@ from django.conf import settings
2
2
 
3
3
 
4
4
  def get_enable_timepoint_checks() -> bool:
5
- return getattr(settings, "ENABLE_TIMEPOINT_CHECKS", True)
5
+ return getattr(settings, "EDC_TIMEPOINT_ENABLE_CHECKS", True)
@@ -0,0 +1,6 @@
1
+ from .timepoint_lookup import TimepointLookup
2
+
3
+
4
+ class VisitTimepointLookup(TimepointLookup):
5
+ timepoint_model = "edc_appointment.appointment"
6
+ timepoint_related_model_lookup = "appointment"
@@ -3,7 +3,6 @@ from django.template.loader import render_to_string
3
3
  from django.urls import NoReverseMatch, reverse
4
4
  from django.utils.translation import gettext as _
5
5
  from django_audit_fields import audit_fields, audit_fieldset_tuple
6
-
7
6
  from edc_dashboard.url_names import url_names
8
7
  from edc_model_admin.dashboard import ModelAdminSubjectDashboardMixin
9
8
  from edc_sites.admin import SiteModelAdminMixin
@@ -100,7 +99,7 @@ class SubjectScheduleHistoryAdmin(
100
99
  def review(obj=None) -> str:
101
100
  try:
102
101
  url = (
103
- f"{reverse('edc_review_dashboard:subject_review_listboard_url')}?"
102
+ f"{reverse(url_names.get('subject_review_listboard_url'))}?"
104
103
  f"q={obj.subject_identifier}"
105
104
  )
106
105
  except NoReverseMatch:
@@ -8,7 +8,7 @@ navbar.register(
8
8
  title="Visit Schedule",
9
9
  label="Visit Schedule",
10
10
  fa_icon="fa-calendar",
11
- url_name="edc_visit_schedule:home_url",
11
+ url_with_namespace="edc_visit_schedule:home_url",
12
12
  codename="edc_navbar.nav_visit_schedule",
13
13
  )
14
14
  )
@@ -19,9 +19,8 @@ navbar.register(
19
19
  title="Subject History",
20
20
  label="Subject History",
21
21
  fa_icon="fa-history",
22
- url_name=(
23
- "edc_visit_schedule:edc_visit_schedule_admin:"
24
- "edc_visit_schedule_subjectschedulehistory_changelist"
22
+ url_with_namespace=(
23
+ "edc_visit_schedule_admin:edc_visit_schedule_subjectschedulehistory_changelist"
25
24
  ),
26
25
  codename="edc_navbar.nav_visit_schedule",
27
26
  )
@@ -217,6 +217,14 @@ class Visit:
217
217
 
218
218
  @property
219
219
  def all_crfs(self) -> CrfCollection:
220
+ """Return a new collection containing all crfs.
221
+
222
+ The new collection contains:
223
+ * crfs
224
+ * crfs_unscheduled
225
+ * crfs_prn
226
+ * crfs_missed
227
+ """
220
228
  crfs = list(self.crfs) + [
221
229
  crf
222
230
  for crf in self.crfs_unscheduled
@@ -232,6 +240,13 @@ class Visit:
232
240
 
233
241
  @property
234
242
  def all_requisitions(self) -> RequisitionCollection:
243
+ """Return a new collection containing all requisitions.
244
+
245
+ The new collection contains:
246
+ * requisitions
247
+ * requisitions_unscheduled
248
+ * requisitions_prn
249
+ """
235
250
  names = [r.name for r in self.requisitions]
236
251
  requisitions = list(self.requisitions) + [
237
252
  r for r in self.requisitions_unscheduled if r.name not in names
@@ -11,6 +11,8 @@ from edc_document_status.model_mixins import DocumentStatusModelMixin
11
11
  from edc_identifier.model_mixins import NonUniqueSubjectIdentifierFieldMixin
12
12
  from edc_metadata.model_mixins import MetadataHelperModelMixin
13
13
  from edc_offstudy.model_mixins import OffstudyNonCrfModelMixin
14
+ from edc_timepoint.model_mixins import TimepointLookupModelMixin
15
+ from edc_timepoint.visit_timepoint_lookup import VisitTimepointLookup
14
16
  from edc_visit_schedule.model_mixins import VisitScheduleModelMixin
15
17
 
16
18
  from ...constants import MISSED_VISIT, NO_FOLLOW_UP_REASONS
@@ -29,6 +31,7 @@ class VisitModelMixin(
29
31
  MetadataHelperModelMixin,
30
32
  OffstudyNonCrfModelMixin,
31
33
  RequiresConsentFieldsModelMixin,
34
+ TimepointLookupModelMixin,
32
35
  models.Model,
33
36
  ):
34
37
  """
@@ -41,6 +44,8 @@ class VisitModelMixin(
41
44
  app_label = 'my_app'
42
45
  """
43
46
 
47
+ timepoint_lookup_cls = VisitTimepointLookup
48
+
44
49
  metadata_helper_instance_attr = None
45
50
 
46
51
  appointment = models.OneToOneField("edc_appointment.appointment", on_delete=PROTECT)
@@ -8,6 +8,8 @@ from edc_metadata.model_mixins.creates import CreatesMetadataModelMixin
8
8
  from edc_model.models import BaseUuidModel, HistoricalRecords
9
9
  from edc_sites.managers import CurrentSiteManager
10
10
  from edc_sites.model_mixins import SiteModelMixin
11
+ from edc_timepoint.model_mixins import TimepointLookupModelMixin
12
+ from edc_timepoint.visit_timepoint_lookup import VisitTimepointLookup
11
13
  from edc_visit_tracking.choices import (
12
14
  VISIT_INFO_SOURCE,
13
15
  VISIT_REASON,
@@ -22,8 +24,11 @@ class SubjectVisit(
22
24
  CreatesMetadataModelMixin,
23
25
  SiteModelMixin,
24
26
  RequiresConsentFieldsModelMixin,
27
+ TimepointLookupModelMixin,
25
28
  BaseUuidModel,
26
29
  ):
30
+ timepoint_lookup_cls = VisitTimepointLookup
31
+
27
32
  appointment = models.OneToOneField(
28
33
  get_appointment_model_name(),
29
34
  on_delete=PROTECT,
@@ -1,8 +0,0 @@
1
- # from .aliquot_model_wrapper import AliquotModelWrapper
2
- # from .box_model_wrapper import BoxModelWrapper
3
- # from .manage_box_item_model_wrapper import ManageBoxItemModelWrapper
4
- # from .manifest_item_model_wrapper import ManifestItemModelWrapper
5
- # from .manifest_model_wrapper import ManifestModelWrapper
6
- # from .requisition_model_wrapper import RequisitionModelWrapper
7
- # from .result_model_wrapper import ResultModelWrapper
8
- # from .verify_box_model_wrapper import VerifyBoxItemModelWrapper
@@ -1,31 +0,0 @@
1
- from edc_model_wrapper import ModelWrapper
2
-
3
- from edc_lab.models import Aliquot, BoxItem, ManifestItem
4
-
5
-
6
- class AliquotModelWrapper(ModelWrapper):
7
- model_cls = Aliquot
8
- next_url_name = "aliquot_listboard_url"
9
-
10
- @property
11
- def human_readable_identifier(self):
12
- return self.object.human_readable_identifier
13
-
14
- @property
15
- def box_item(self):
16
- try:
17
- return BoxItem.objects.get(identifier=self.aliquot_identifier)
18
- except BoxItem.DoesNotExist:
19
- return None
20
-
21
- @property
22
- def manifest_item(self):
23
- manifest_item = None
24
- if self.box_item:
25
- try:
26
- manifest_item = ManifestItem.objects.get(
27
- identifier=self.box_item.box.box_identifier
28
- )
29
- except ManifestItem.DoesNotExist:
30
- pass
31
- return manifest_item
@@ -1,21 +0,0 @@
1
- from django.apps import apps as django_apps
2
- from edc_model_wrapper import ModelWrapper
3
-
4
- from edc_lab.models import BoxItem
5
-
6
- edc_lab_app_config = django_apps.get_app_config("edc_lab")
7
-
8
-
9
- class BaseBoxItemModelWrapper(ModelWrapper):
10
- model_cls = BoxItem
11
- action_name = None
12
- next_url_name = None
13
- next_url_attrs = ["box_identifier", "action_name"]
14
-
15
- @property
16
- def human_readable_identifier(self):
17
- return self.object.human_readable_identifier
18
-
19
- @property
20
- def box_identifier(self):
21
- return self.object.box.box_identifier
@@ -1,12 +0,0 @@
1
- from edc_model_wrapper import ModelWrapper
2
-
3
- from edc_lab.models import Box
4
-
5
-
6
- class BoxModelWrapper(ModelWrapper):
7
- model_cls = Box
8
- next_url_name = "pack_listboard_url"
9
-
10
- @property
11
- def human_readable_identifier(self):
12
- return self.object.human_readable_identifier
@@ -1,6 +0,0 @@
1
- from .base_box_item_model_wrapper import BaseBoxItemModelWrapper
2
-
3
-
4
- class ManageBoxItemModelWrapper(BaseBoxItemModelWrapper):
5
- action_name = "manage"
6
- next_url_name = "manage_box_listboard_url"
@@ -1,21 +0,0 @@
1
- from edc_model_wrapper import ModelWrapper
2
-
3
- from edc_lab.models import Box, ManifestItem
4
-
5
-
6
- class ManifestItemModelWrapper(ModelWrapper):
7
- model_cls = ManifestItem
8
- next_url_name = "manage_manifest_listboard_url"
9
- action_name = "manage"
10
-
11
- @property
12
- def manifest_identifier(self):
13
- return self.object.manifest.manifest_identifier
14
-
15
- @property
16
- def box_identifier(self):
17
- return self.object.identifier
18
-
19
- @property
20
- def box(self):
21
- return Box.objects.get(box_identifier=self.object.identifier)