meta-edc 0.3.53__py3-none-any.whl → 1.0.1__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.
- meta_ae/action_items.py +9 -4
- meta_ae/admin/ae_initial_admin.py +5 -2
- meta_ae/admin/modeladmin_mixins.py +5 -3
- meta_ae/templatetags/meta_ae_extras.py +1 -3
- meta_consent/action_items.py +1 -0
- meta_consent/migrations/0030_auto_20250120_2114.py +40 -0
- meta_consent/migrations/0031_alter_historicalsubjectconsent_guardian_name_and_more.py +124 -0
- meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/dashboard/sidebar.html +1 -1
- meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/dashboard/top_bar.html +1 -1
- meta_dashboard/templates/meta_dashboard/subject/dashboard.html +14 -0
- meta_dashboard/templatetags/meta_dashboard_extras.py +6 -11
- meta_dashboard/views/subject/dashboard/dashboard_view.py +6 -5
- meta_edc/admin.py +2 -3
- meta_edc/settings/debug.py +2 -2
- meta_edc/settings/defaults.py +1 -3
- meta_edc/templates/meta_edc/{bootstrap3/base.html → base.html} +1 -1
- meta_edc/templates/meta_edc/{bootstrap3/home.html → home.html} +1 -1
- meta_edc/views/home_view.py +1 -2
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/METADATA +2 -2
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/RECORD +56 -50
- meta_prn/action_items.py +23 -16
- meta_prn/admin/end_of_study_admin.py +12 -6
- meta_prn/admin/offschedule_admin.py +8 -6
- meta_prn/admin/offschedule_dm_referral_admin.py +8 -6
- meta_prn/admin/offschedule_postnatal_admin.py +10 -1
- meta_prn/admin/offschedule_pregnancy_admin.py +10 -1
- meta_prn/choices.py +4 -0
- meta_prn/form_validators/end_of_study.py +10 -4
- meta_prn/templates/meta_prn/eos/additional_instructions.html +3 -0
- meta_prn/templates/meta_prn/offschedule/additional_instructions.html +2 -0
- meta_prn/tests/tests/test_eos_events.py +134 -0
- meta_reports/admin/dbviews/imp_substitutions_admin.py +1 -1
- meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +1 -1
- meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +1 -1
- meta_reports/admin/last_imp_refill_admin.py +5 -19
- meta_reports/templates/meta_reports/last_imp_refill/changelist_note.html +13 -0
- meta_screening/admin/subject_screening_admin.py +13 -3
- meta_screening/eligibility/eligibility.py +14 -7
- meta_screening/model_mixins/part_one_fields_model_mixin.py +15 -14
- meta_subject/admin/birth_outcome_admin.py +1 -1
- meta_subject/admin/delivery_admin.py +1 -1
- meta_subject/form_validators/dm_endpoint_form_validator.py +3 -1
- meta_subject/models/diabetes/dm_followup.py +3 -3
- tests/test_settings.py +0 -1
- meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard.html +0 -14
- /meta_ae/templates/meta_ae/{bootstrap3/ae_initial_description.html → aeinitial_description.html} +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/add_consent_button.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/dashboard_button.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/eligibility_button.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/refusal_button.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/screening_button.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/screening → screening}/listboard.html +0 -0
- /meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/listboard.html +0 -0
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/AUTHORS +0 -0
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/LICENSE +0 -0
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/WHEEL +0 -0
- {meta_edc-0.3.53.dist-info → meta_edc-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
from django.test import TestCase
|
2
|
+
from edc_action_item.models import ActionItem
|
3
|
+
from edc_constants.constants import FEMALE, NEW, PATIENT, YES
|
4
|
+
from edc_offstudy.constants import END_OF_STUDY_ACTION
|
5
|
+
from edc_pharmacy.models import Medication
|
6
|
+
from edc_transfer.constants import SUBJECT_TRANSFER_ACTION, TRANSFERRED
|
7
|
+
from edc_utils import get_utcnow
|
8
|
+
from edc_visit_schedule.constants import OFFSCHEDULE_ACTION
|
9
|
+
|
10
|
+
from meta_lists.models import OffstudyReasons, TransferReasons
|
11
|
+
from meta_pharmacy.constants import METFORMIN
|
12
|
+
from meta_prn.action_items import OffscheduleAction, SubjectTransferAction
|
13
|
+
from meta_prn.constants import OFFSTUDY_MEDICATION_ACTION
|
14
|
+
from meta_prn.models import EndOfStudy, OffSchedule, OffStudyMedication, SubjectTransfer
|
15
|
+
from meta_screening.tests.meta_test_case_mixin import MetaTestCaseMixin
|
16
|
+
|
17
|
+
|
18
|
+
class TestEosEvents(MetaTestCaseMixin, TestCase):
|
19
|
+
def setUp(self):
|
20
|
+
super().setUp()
|
21
|
+
self.subject_screening = self.get_subject_screening(gender=FEMALE)
|
22
|
+
self.subject_consent = self.get_subject_consent(self.subject_screening)
|
23
|
+
self.subject_visit = self.get_subject_visit(
|
24
|
+
subject_screening=self.subject_screening,
|
25
|
+
subject_consent=self.subject_consent,
|
26
|
+
)
|
27
|
+
self.data = dict(
|
28
|
+
subject_visit=self.subject_visit.pk,
|
29
|
+
report_datetime=self.subject_visit.report_datetime,
|
30
|
+
)
|
31
|
+
|
32
|
+
def test_transfer_to_offschedule_in_order(self):
|
33
|
+
SubjectTransferAction(
|
34
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
35
|
+
skip_get_current_site=True,
|
36
|
+
site_id=self.subject_consent.site_id,
|
37
|
+
)
|
38
|
+
action_types = [
|
39
|
+
obj.action_type.name
|
40
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
41
|
+
]
|
42
|
+
self.assertEqual(action_types, [SUBJECT_TRANSFER_ACTION])
|
43
|
+
|
44
|
+
# add a subject transfer object, which triggers next action item
|
45
|
+
transfer_reason = TransferReasons.objects.get(name="moved")
|
46
|
+
subject_transfer = SubjectTransfer.objects.create(
|
47
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
48
|
+
initiated_by="patient",
|
49
|
+
may_return=YES,
|
50
|
+
may_contact=YES,
|
51
|
+
)
|
52
|
+
subject_transfer.transfer_reason.add(transfer_reason)
|
53
|
+
|
54
|
+
action_types = [
|
55
|
+
obj.action_type.name
|
56
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
57
|
+
]
|
58
|
+
self.assertEqual(action_types, [OFFSCHEDULE_ACTION, OFFSTUDY_MEDICATION_ACTION])
|
59
|
+
|
60
|
+
OffSchedule.objects.create(subject_identifier=self.subject_consent.subject_identifier)
|
61
|
+
|
62
|
+
action_types = [
|
63
|
+
obj.action_type.name
|
64
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
65
|
+
]
|
66
|
+
self.assertEqual(action_types, [OFFSTUDY_MEDICATION_ACTION])
|
67
|
+
|
68
|
+
offstudy_rx = OffStudyMedication.objects.create(
|
69
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
70
|
+
stop_date=get_utcnow().date(),
|
71
|
+
last_dose_date=get_utcnow().date(),
|
72
|
+
reason=PATIENT,
|
73
|
+
)
|
74
|
+
offstudy_rx.medications.add(Medication.objects.get(name=METFORMIN))
|
75
|
+
|
76
|
+
action_types = [
|
77
|
+
obj.action_type.name
|
78
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
79
|
+
]
|
80
|
+
self.assertEqual(action_types, [END_OF_STUDY_ACTION])
|
81
|
+
|
82
|
+
EndOfStudy.objects.create(
|
83
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
84
|
+
last_seen_date=get_utcnow().date(),
|
85
|
+
offstudy_reason=OffstudyReasons.objects.get(name=TRANSFERRED),
|
86
|
+
)
|
87
|
+
|
88
|
+
action_types = [
|
89
|
+
obj.action_type.name
|
90
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
91
|
+
]
|
92
|
+
self.assertEqual(action_types, [])
|
93
|
+
|
94
|
+
def test_transfer_to_offschedule_raises(self):
|
95
|
+
|
96
|
+
OffscheduleAction(
|
97
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
98
|
+
skip_get_current_site=True,
|
99
|
+
site_id=self.subject_consent.site_id,
|
100
|
+
)
|
101
|
+
|
102
|
+
OffSchedule.objects.create(subject_identifier=self.subject_consent.subject_identifier)
|
103
|
+
|
104
|
+
action_types = [
|
105
|
+
obj.action_type.name
|
106
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
107
|
+
]
|
108
|
+
self.assertEqual(action_types, [OFFSTUDY_MEDICATION_ACTION])
|
109
|
+
|
110
|
+
offstudy_rx = OffStudyMedication.objects.create(
|
111
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
112
|
+
stop_date=get_utcnow().date(),
|
113
|
+
last_dose_date=get_utcnow().date(),
|
114
|
+
reason=PATIENT,
|
115
|
+
)
|
116
|
+
offstudy_rx.medications.add(Medication.objects.get(name=METFORMIN))
|
117
|
+
|
118
|
+
action_types = [
|
119
|
+
obj.action_type.name
|
120
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
121
|
+
]
|
122
|
+
self.assertEqual(action_types, [END_OF_STUDY_ACTION])
|
123
|
+
|
124
|
+
EndOfStudy.objects.create(
|
125
|
+
subject_identifier=self.subject_consent.subject_identifier,
|
126
|
+
last_seen_date=get_utcnow().date(),
|
127
|
+
offstudy_reason=OffstudyReasons.objects.get(name=TRANSFERRED),
|
128
|
+
)
|
129
|
+
|
130
|
+
action_types = [
|
131
|
+
obj.action_type.name
|
132
|
+
for obj in ActionItem.objects.filter(status=NEW).order_by("action_type__name")
|
133
|
+
]
|
134
|
+
self.assertEqual(action_types, [])
|
@@ -65,7 +65,7 @@ class ImpSubstitutionsAdmin(
|
|
65
65
|
pass
|
66
66
|
url = reverse(self.get_subject_dashboard_url_name(obj=obj), kwargs=kwargs)
|
67
67
|
context = dict(title=_("Go to subject's dashboard@1000"), url=url, label=label)
|
68
|
-
return render_to_string("dashboard_button.html", context=context)
|
68
|
+
return render_to_string("edc_subject_dashboard/dashboard_button.html", context=context)
|
69
69
|
|
70
70
|
@admin.display(description="Subject", ordering="subject_identifier")
|
71
71
|
def subject(self, obj):
|
@@ -69,7 +69,7 @@ class MissingScreeningOgttAdmin(
|
|
69
69
|
args=(obj.original_id,),
|
70
70
|
)
|
71
71
|
context = dict(title=_("Go to subject screening"), url=url, label=label)
|
72
|
-
return render_to_string("dashboard_button.html", context=context)
|
72
|
+
return render_to_string("edc_subject_dashboard/dashboard_button.html", context=context)
|
73
73
|
|
74
74
|
@admin.display(description="Screen date", ordering="screening_datetime")
|
75
75
|
def screening_date(self, obj):
|
@@ -55,4 +55,4 @@ class PatientHistoryMissingBaselineCd4Admin(
|
|
55
55
|
pass
|
56
56
|
url = reverse(self.get_subject_dashboard_url_name(obj=obj), kwargs=kwargs)
|
57
57
|
context = dict(title=_("Go to subject's dashboard@1000"), url=url, label=label)
|
58
|
-
return render_to_string("dashboard_button.html", context=context)
|
58
|
+
return render_to_string("edc_subject_dashboard/dashboard_button.html", context=context)
|
@@ -2,7 +2,8 @@ from django.contrib import admin, messages
|
|
2
2
|
from django.core.exceptions import FieldDoesNotExist
|
3
3
|
from django.db import models
|
4
4
|
from django.db.models import QuerySet
|
5
|
-
from django.
|
5
|
+
from django.template.loader import render_to_string
|
6
|
+
from django.utils.safestring import mark_safe
|
6
7
|
from edc_model_admin.dashboard import ModelAdminDashboardMixin
|
7
8
|
from edc_model_admin.list_filters import PastDateListFilter
|
8
9
|
from edc_model_admin.mixins import TemplatesModelAdminMixin
|
@@ -70,24 +71,9 @@ class LastImpRefillAdmin(
|
|
70
71
|
|
71
72
|
change_list_title = "List of most recent IMP refills per subject"
|
72
73
|
|
73
|
-
change_list_note =
|
74
|
-
""
|
75
|
-
|
76
|
-
refilled and adds the subject's next visit. Subjects taken "Off Schedule"
|
77
|
-
are not included in this report. To update ALL rows in this report, tick
|
78
|
-
at least one row and select 'Update report' action below.
|
79
|
-
<BR><BR>
|
80
|
-
This report has additional search features for numeric columns:
|
81
|
-
<code>days_since</code>, <code>days_until</code>, <code>imp_visit_code</code>
|
82
|
-
and <code>next_visit_code</code>.
|
83
|
-
<BR><BR>For example, type <code>days_until>=25</code> in the search below
|
84
|
-
to show rows for subjects who have an appointment 25 or more days from the
|
85
|
-
date this report was created. You might also try typing
|
86
|
-
<code>days_since>365</code> or <code>days_until<0</code>.
|
87
|
-
<BR><BR>
|
88
|
-
This also works: <code>next_visit_code>=1060</code>.
|
89
|
-
"""
|
90
|
-
)
|
74
|
+
change_list_note = mark_safe(
|
75
|
+
render_to_string("meta_reports/last_imp_refill/changelist_note.html")
|
76
|
+
) # nosec B308, B703
|
91
77
|
|
92
78
|
actions = [update_report, export_to_csv]
|
93
79
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
{% load i18n %}
|
2
|
+
{% trans "This report fetches the most recent Study Medication report where IMP was refilled and adds the subject's next visit. Subjects taken 'Off Schedule' are not included in this report. To update ALL rows in this report, tick at least one row and select 'Update report' action below." %}
|
3
|
+
<BR><BR>
|
4
|
+
{% trans "This report has additional search features for numeric columns" %}:
|
5
|
+
<code>days_since</code>, <code>days_until</code>, <code>imp_visit_code</code> {% trans "and" %} <code>next_visit_code</code>.
|
6
|
+
<BR><BR>
|
7
|
+
{% trans "For example, type" %}
|
8
|
+
<code>days_until>=25</code>
|
9
|
+
{% trans "in the search below to show rows for subjects who have an appointment 25 or more days from the date this report was created. You might also try typing" %}
|
10
|
+
<code>days_since>365</code> or <code>days_until<0</code>.
|
11
|
+
<BR><BR>
|
12
|
+
{% trans "This also works" %}:
|
13
|
+
<code>next_visit_code>=1060</code>.
|
@@ -3,6 +3,7 @@ from django.template.loader import render_to_string
|
|
3
3
|
from django.urls.base import reverse
|
4
4
|
from django.urls.exceptions import NoReverseMatch
|
5
5
|
from django.utils.html import format_html
|
6
|
+
from django.utils.safestring import mark_safe
|
6
7
|
from django.utils.translation import gettext_lazy as _
|
7
8
|
from django_audit_fields.admin import audit_fieldset_tuple
|
8
9
|
from edc_constants.constants import YES
|
@@ -160,7 +161,10 @@ class SubjectScreeningAdmin(ModelAdminSubjectDashboardMixin, SimpleHistoryAdmin)
|
|
160
161
|
]
|
161
162
|
if obj.repeat_glucose_opinion == YES:
|
162
163
|
data.append(f"Contact #: {obj.contact_number or '--'}")
|
163
|
-
return format_html(
|
164
|
+
return format_html(
|
165
|
+
"{}",
|
166
|
+
mark_safe("<BR>".join(data)), # nosec B703, B308
|
167
|
+
)
|
164
168
|
|
165
169
|
def reasons(self, obj=None):
|
166
170
|
if not obj.reasons_ineligible:
|
@@ -177,8 +181,14 @@ class SubjectScreeningAdmin(ModelAdminSubjectDashboardMixin, SimpleHistoryAdmin)
|
|
177
181
|
url=f"{screening_listboard_url}?q={obj.screening_identifier}",
|
178
182
|
label="Screening",
|
179
183
|
)
|
180
|
-
button = render_to_string(
|
181
|
-
|
184
|
+
button = render_to_string(
|
185
|
+
"edc_subject_dashboard/dashboard_button.html", context=context
|
186
|
+
)
|
187
|
+
return format_html(
|
188
|
+
"{button}<BR>{status}",
|
189
|
+
button=button,
|
190
|
+
status=eligibility.eligibility_status(add_urls=True),
|
191
|
+
)
|
182
192
|
|
183
193
|
def dashboard(self, obj=None, label=None):
|
184
194
|
try:
|
@@ -195,15 +195,22 @@ class MetaEligibility:
|
|
195
195
|
args=(self.part_three.model_obj.id,),
|
196
196
|
)
|
197
197
|
status_str = format_html(
|
198
|
-
|
199
|
-
|
200
|
-
|
198
|
+
'<A href="{url_p1}">P1: {p1_eligible}</A>'
|
199
|
+
'<BR><A href="{url_p2}">P2: {p2_eligible}</A>'
|
200
|
+
'<BR><A href="{url_p3}">P3: {p3_eligible}</A><BR>',
|
201
|
+
url_p1=url_p1,
|
202
|
+
p1_eligible=self.part_one.eligible.upper(),
|
203
|
+
url_p2=url_p2,
|
204
|
+
p2_eligible=self.part_two.eligible.upper(),
|
205
|
+
url_p3=url_p3,
|
206
|
+
p3_eligible=self.part_three.eligible.upper(),
|
201
207
|
)
|
202
208
|
else:
|
203
|
-
status_str = (
|
204
|
-
|
205
|
-
|
206
|
-
|
209
|
+
status_str = format_html(
|
210
|
+
"P1: {p1_eligible}<BR>" "P2: {p2_eligible}<BR>" "P3: {p3_eligible}<BR>",
|
211
|
+
p1_eligible=self.part_one.eligible.upper(),
|
212
|
+
p2_eligible=self.part_two.eligible.upper(),
|
213
|
+
p3_eligible=self.part_three.eligible.upper(),
|
207
214
|
)
|
208
215
|
display_label = self.display_label
|
209
216
|
if "PENDING" in display_label:
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from django.db import models
|
2
|
-
from django.utils.html import format_html
|
3
2
|
from django.utils.safestring import mark_safe
|
4
3
|
from django_crypto_fields.fields import EncryptedCharField
|
5
4
|
from edc_constants.choices import SELECTION_METHOD, YES_NO, YES_NO_NA, YESDEFAULT_NO
|
@@ -11,10 +10,10 @@ from ..constants import PREG_YES_NO_NA
|
|
11
10
|
|
12
11
|
class PartOneFieldsModelMixin(models.Model):
|
13
12
|
screening_consent = models.CharField(
|
14
|
-
verbose_name=
|
13
|
+
verbose_name=mark_safe(
|
15
14
|
"Has the subject given his/her verbal consent to be screened for "
|
16
15
|
"the <u>META Phase 3</u> trial?"
|
17
|
-
),
|
16
|
+
), # nosec B308
|
18
17
|
max_length=15,
|
19
18
|
choices=YES_NO,
|
20
19
|
)
|
@@ -26,7 +25,9 @@ class PartOneFieldsModelMixin(models.Model):
|
|
26
25
|
)
|
27
26
|
|
28
27
|
meta_phase_two = models.CharField(
|
29
|
-
verbose_name=
|
28
|
+
verbose_name=mark_safe(
|
29
|
+
"Was the subject enrolled in the <u>META Phase 2</u> trial?"
|
30
|
+
), # nosec B308
|
30
31
|
max_length=15,
|
31
32
|
choices=YES_NO,
|
32
33
|
null=True,
|
@@ -44,9 +45,9 @@ class PartOneFieldsModelMixin(models.Model):
|
|
44
45
|
)
|
45
46
|
|
46
47
|
art_six_months = models.CharField(
|
47
|
-
verbose_name=
|
48
|
+
verbose_name=mark_safe(
|
48
49
|
"Has the patient been on anti-retroviral therapy for <u>at least 6 months</u>"
|
49
|
-
),
|
50
|
+
), # nosec B308
|
50
51
|
max_length=15,
|
51
52
|
choices=YES_NO_NA,
|
52
53
|
)
|
@@ -59,10 +60,10 @@ class PartOneFieldsModelMixin(models.Model):
|
|
59
60
|
)
|
60
61
|
|
61
62
|
vl_undetectable = models.CharField(
|
62
|
-
verbose_name=
|
63
|
+
verbose_name=mark_safe(
|
63
64
|
"Does the patient have a viral load measure of less than 1000 copies per ml "
|
64
65
|
"taken <u>within the last 12 months</u>"
|
65
|
-
),
|
66
|
+
), # nosec B308
|
66
67
|
max_length=15,
|
67
68
|
choices=YES_NO_NA,
|
68
69
|
)
|
@@ -86,10 +87,10 @@ class PartOneFieldsModelMixin(models.Model):
|
|
86
87
|
)
|
87
88
|
|
88
89
|
staying_nearby_12 = models.CharField(
|
89
|
-
verbose_name=
|
90
|
+
verbose_name=mark_safe(
|
90
91
|
"Is the patient planning to remain in the catchment area "
|
91
92
|
"for <u>at least 12 months</u>"
|
92
|
-
),
|
93
|
+
), # nosec B308
|
93
94
|
max_length=15,
|
94
95
|
choices=YES_NO,
|
95
96
|
null=True,
|
@@ -101,18 +102,18 @@ class PartOneFieldsModelMixin(models.Model):
|
|
101
102
|
)
|
102
103
|
|
103
104
|
continue_part_two = models.CharField(
|
104
|
-
verbose_name=mark_safe(
|
105
|
+
verbose_name=mark_safe(
|
105
106
|
"Continue with <U>part two</U> of the screening process?"
|
106
|
-
),
|
107
|
+
), # nosec B308
|
107
108
|
max_length=15,
|
108
109
|
choices=YESDEFAULT_NO,
|
109
110
|
default=YES,
|
110
|
-
help_text=mark_safe(
|
111
|
+
help_text=mark_safe(
|
111
112
|
"<B>Important</B>: This response will be be automatically "
|
112
113
|
"set to YES if:<BR><BR>"
|
113
114
|
"- the participant meets the eligibility criteria for part one, or;<BR><BR>"
|
114
115
|
"- the eligibility criteria for part two is already complete.<BR>"
|
115
|
-
),
|
116
|
+
), # nosec B308
|
116
117
|
)
|
117
118
|
|
118
119
|
class Meta:
|
@@ -72,7 +72,7 @@ class BirthOutcomesAdmin(
|
|
72
72
|
url = reverse("meta_subject_admin:meta_subject_delivery_changelist")
|
73
73
|
url = f"{url}?q={obj.subject_identifier}"
|
74
74
|
context = dict(title="Delivery", url=url, label="Delivery")
|
75
|
-
return render_to_string("dashboard_button.html", context=context)
|
75
|
+
return render_to_string("edc_subject_dashboard/dashboard_button.html", context=context)
|
76
76
|
|
77
77
|
def get_subject_dashboard_url_kwargs(self, obj):
|
78
78
|
return dict(subject_identifier=obj.subject_identifier)
|
@@ -116,4 +116,4 @@ class DeliveryAdmin(
|
|
116
116
|
url = reverse("meta_subject_admin:meta_subject_birthoutcomes_changelist")
|
117
117
|
url = f"{url}?q={obj.subject_identifier}"
|
118
118
|
context = dict(title="Outcomes", url=url, label="Outcomes")
|
119
|
-
return render_to_string("dashboard_button.html", context=context)
|
119
|
+
return render_to_string("edc_subject_dashboard/dashboard_button.html", context=context)
|
@@ -2,6 +2,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|
2
2
|
from django.template.loader import render_to_string
|
3
3
|
from django.urls import reverse
|
4
4
|
from django.utils.html import format_html
|
5
|
+
from django.utils.safestring import mark_safe
|
5
6
|
from edc_crf.crf_form_validator import CrfFormValidator
|
6
7
|
from edc_form_validators import INVALID_ERROR
|
7
8
|
|
@@ -28,7 +29,8 @@ class DmEndpointFormValidator(CrfFormValidator):
|
|
28
29
|
self.raise_validation_error(
|
29
30
|
{
|
30
31
|
"__all__": format_html(
|
31
|
-
|
32
|
+
"Subject has not reached the protocol endpoint. See {link}",
|
33
|
+
link=mark_safe(link), # nosec B703, B308
|
32
34
|
)
|
33
35
|
},
|
34
36
|
INVALID_ERROR,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
2
2
|
from django.db import models
|
3
|
-
from django.utils.
|
3
|
+
from django.utils.safestring import mark_safe
|
4
4
|
from edc_action_item.models import ActionItem
|
5
5
|
from edc_adherence.choices import MISSED_PILLS
|
6
6
|
from edc_constants.choices import YES_NO, YES_NO_NA
|
@@ -186,10 +186,10 @@ class DmFollowup(CrfWithActionModelMixin, BaseUuidModel):
|
|
186
186
|
)
|
187
187
|
|
188
188
|
visual_score_confirmed = models.IntegerField(
|
189
|
-
verbose_name=
|
189
|
+
verbose_name=mark_safe(
|
190
190
|
"<B><font color='orange'>Interviewer</font></B>: "
|
191
191
|
"please transcribe the score indicated from above."
|
192
|
-
),
|
192
|
+
), # nosec B308
|
193
193
|
validators=[MinValueValidator(0), MaxValueValidator(100)],
|
194
194
|
help_text="%",
|
195
195
|
null=True,
|
tests/test_settings.py
CHANGED
@@ -74,7 +74,6 @@ project_settings = DefaultTestSettings(
|
|
74
74
|
subject_dashboard_template="meta_dashboard/subject/dashboard.html",
|
75
75
|
subject_review_listboard_template="edc_review_dashboard/subject_review_listboard.html",
|
76
76
|
),
|
77
|
-
EDC_BOOTSTRAP=3,
|
78
77
|
EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend",
|
79
78
|
EMAIL_CONTACTS={
|
80
79
|
"ae_reports": "someone@example.com",
|
@@ -1,14 +0,0 @@
|
|
1
|
-
{% extends 'edc_subject_dashboard/bootstrap3/dashboard.html' %}
|
2
|
-
|
3
|
-
{% load static %}
|
4
|
-
|
5
|
-
{% block locator_information %}{% endblock locator_information %}
|
6
|
-
|
7
|
-
{% block top_bar %}
|
8
|
-
|
9
|
-
{% include "meta_dashboard/bootstrap3/subject/dashboard/top_bar.html" %}
|
10
|
-
|
11
|
-
{% endblock top_bar %}
|
12
|
-
|
13
|
-
|
14
|
-
{% block side_bar %}{% include 'meta_dashboard/bootstrap3/subject/dashboard/sidebar.html' %}{% endblock side_bar %}
|
/meta_ae/templates/meta_ae/{bootstrap3/ae_initial_description.html → aeinitial_description.html}
RENAMED
File without changes
|
/meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/add_consent_button.html
RENAMED
File without changes
|
/meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/dashboard_button.html
RENAMED
File without changes
|
/meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/eligibility_button.html
RENAMED
File without changes
|
File without changes
|
/meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/screening_button.html
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|