meta-edc 1.0.0__py3-none-any.whl → 1.0.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: meta-edc
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: META Trial EDC (http://www.isrctn.com/ISRCTN76157257)
5
5
  Home-page: https://github.com/meta-trial/meta-edc
6
6
  Author: Erik van Widenfelt
@@ -345,11 +345,11 @@ meta_pharmacy/models/substitutions.py,sha256=9FjjD4x66B8SxABZR5atan2S5uE4nJH0tn0
345
345
  meta_pharmacy/utils/__init__.py,sha256=PiPRCZqgxPiudXWEvQmXOqFZMoj56NEiOeRuYEyE_9w,71
346
346
  meta_pharmacy/utils/update_initial_pharmacy_data.py,sha256=Od0QL41unsDEGDBYsVCe8k-T3GpMae0DtHt61vz4sYM,4621
347
347
  meta_prn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
348
- meta_prn/action_items.py,sha256=R83aFDxyOEkmzfJwWMcRYXWXZBcv3hTp_QzHNJPLNPM,9108
348
+ meta_prn/action_items.py,sha256=99NxsonE_iXscoRLZ00lymAgjDqGbhiUhzgTMk9Ib30,9272
349
349
  meta_prn/admin_site.py,sha256=E4dJ6ofu9Kp-1SIWIuY3PraVPbEJSWBBqhorJPGUNqU,161
350
350
  meta_prn/apps.py,sha256=NEqrwzEW277BAPGeL1H1KdK9e74FqXfYHK6o46BtaJA,280
351
351
  meta_prn/baker_recipes.py,sha256=jDGg3btxjtvnsph_AnKoZBDUeTfokMs5iQWnQBJD-jw,660
352
- meta_prn/choices.py,sha256=QKqCh2mN_Fgt9Z_la_YVeAqlzRxd507TurFVOOc71G0,3210
352
+ meta_prn/choices.py,sha256=Cb55BmvEgLyIhLzWDRw2aMkGr_WOyBgvcOZpVYgxSS8,3336
353
353
  meta_prn/constants.py,sha256=Z0atxRnTIj-_bWbfYY0vZIwfmbwaFRpSZqb1-K1B4Jo,1018
354
354
  meta_prn/list_data.py,sha256=Se-GxHTuxmU_j17tIdLicKlW6d5E9pVKvYVrTLZQFUo,2336
355
355
  meta_prn/pregnancy_action_item_mixin.py,sha256=E_7aFSs_PXkqlRqRbKohWZSnE7rUcFVr0LacF7EjrvM,1018
@@ -463,6 +463,7 @@ meta_prn/tests/urls.py,sha256=JtaYMEhXBim3a2uPLNvyoulbEutvtbTlmH-ez9Ws8u8,270
463
463
  meta_prn/tests/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
464
464
  meta_prn/tests/tests/test_actions.py,sha256=KjMznJALY4zB3-4WQHubum_B6sE6pyf0_pg9i57Ri9w,3811
465
465
  meta_prn/tests/tests/test_dm_referral.py,sha256=FP5NO464D6n6Oe5uAsv9oIPZ08VQsWmBQmhQajIrWKU,8381
466
+ meta_prn/tests/tests/test_eos_events.py,sha256=T4ZMNM2kjseE_Viy9HAM7sx3TyeSsPyv5VXHgBDLFKs,5449
466
467
  meta_prn/tests/tests/test_manager_order.py,sha256=KYda9YaWJNf761_YiMcXkxlllt2Al27MYgaWO859DWI,548
467
468
  meta_prn/tests/tests/test_pregnancy_notification.py,sha256=anAzrfIAEMles-IH-PGkVBCS0vyUzxBOJ2EQtQBbnOI,3982
468
469
  meta_rando/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -490,7 +491,7 @@ meta_reports/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
490
491
  meta_reports/admin/__init__.py,sha256=om3lFa4YxsZSNlYIi2sZv8li2irOMoSeBtOpPk4V3lk,488
491
492
  meta_reports/admin/endpoints_admin.py,sha256=7wZCdC-D-QHI1bb_ucgyDZYlnYD7mWtcZpcH_LftkLs,514
492
493
  meta_reports/admin/endpoints_all_admin.py,sha256=_czdezZf9fSjwZJmO-3HbmdXrXP6nk8-HdiweqUzPRE,476
493
- meta_reports/admin/last_imp_refill_admin.py,sha256=w-0wIanAk7vXwUufd9v_ZEWhYJ3s8Q2fDP3csRRxgls,5946
494
+ meta_reports/admin/last_imp_refill_admin.py,sha256=RKODpodLqQsKx1v4ybqVULo38s2bNXd1nsUpCdPlJ1A,6431
494
495
  meta_reports/admin/list_filters.py,sha256=pByBzz9-qGwqBfdZFlByxJUZDTJQXOTWfNLjmK8KF00,870
495
496
  meta_reports/admin/modeladmin_mixins.py,sha256=tEZYw0xNMfBvo2RLDrYfi_S9lbZU02dwtLxdRDZob4Q,3663
496
497
  meta_reports/admin/dbviews/__init__.py,sha256=2yPu0SO7ZX9yjan0OS9izzws14YYoXcGXmZhwJhax1I,675
@@ -1183,9 +1184,9 @@ tests/etc/user-rsa-restricted-private.pem,sha256=CUcHW9bznWdmmASN00hCzvxFPAFl4N2
1183
1184
  tests/etc/user-rsa-restricted-public.pem,sha256=mt84djoL-uHw6Wc5SJh0zml6VzXulnf8eQSFg7-fheg,450
1184
1185
  tests/etc/user-salt-local.key,sha256=x5anBw9fvbHurczouT3CjrkWb_xs7Ypm1htIJsgiuiw,256
1185
1186
  tests/etc/user-salt-restricted.key,sha256=pxmpcfBRNB-4C6wTvHXz-9fOfJgKIFOjaAF8ZFfa4q4,256
1186
- meta_edc-1.0.0.dist-info/AUTHORS,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1187
- meta_edc-1.0.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1188
- meta_edc-1.0.0.dist-info/METADATA,sha256=XRxGxnPZR6V4r-xp4mPNJzdJSfdwrSXrTHC7goKUUdM,43527
1189
- meta_edc-1.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
1190
- meta_edc-1.0.0.dist-info/top_level.txt,sha256=RkzjNXwRq2kg_uZ_1bDwPUntijSXoY2YBqtByDwvvrc,244
1191
- meta_edc-1.0.0.dist-info/RECORD,,
1187
+ meta_edc-1.0.2.dist-info/AUTHORS,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1188
+ meta_edc-1.0.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1189
+ meta_edc-1.0.2.dist-info/METADATA,sha256=5KWkarvYtcSI6PzhZvKjGItS0aBzrrhQcttY4YtU1Cw,43527
1190
+ meta_edc-1.0.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
1191
+ meta_edc-1.0.2.dist-info/top_level.txt,sha256=RkzjNXwRq2kg_uZ_1bDwPUntijSXoY2YBqtByDwvvrc,244
1192
+ meta_edc-1.0.2.dist-info/RECORD,,
meta_prn/action_items.py CHANGED
@@ -43,6 +43,7 @@ class OffscheduleAction(ActionWithNotification):
43
43
  DEATH_REPORT_ACTION,
44
44
  LTFU_ACTION,
45
45
  BLOOD_RESULTS_RFT_ACTION,
46
+ SUBJECT_TRANSFER_ACTION,
46
47
  ]
47
48
  reference_model = "meta_prn.offschedule"
48
49
  show_link_to_changelist = True
@@ -72,6 +73,7 @@ class OffschedulePregnancyAction(ActionWithNotification):
72
73
  UNBLINDING_REVIEW_ACTION,
73
74
  DEATH_REPORT_ACTION,
74
75
  LTFU_ACTION,
76
+ SUBJECT_TRANSFER_ACTION,
75
77
  DELIVERY_ACTION,
76
78
  ]
77
79
  reference_model = "meta_prn.offschedulepregnancy"
@@ -85,6 +87,27 @@ class OffschedulePregnancyAction(ActionWithNotification):
85
87
  return next_actions
86
88
 
87
89
 
90
+ class OffscheduleDmReferralAction(ActionWithNotification):
91
+ name = OFFSCHEDULE_DM_REFERRAL_ACTION
92
+ display_name = "Submit Off-Schedule (Diabetes Referral)"
93
+ notification_display_name = "Off-Schedule (Diabetes Referral)"
94
+ parent_action_names = [
95
+ DM_FOLLOWUP_ACTION,
96
+ DEATH_REPORT_ACTION,
97
+ LTFU_ACTION,
98
+ SUBJECT_TRANSFER_ACTION,
99
+ ]
100
+ reference_model = "meta_prn.offscheduledmreferral"
101
+ show_link_to_changelist = True
102
+ admin_site_name = "meta_prn_admin"
103
+ priority = HIGH_PRIORITY
104
+ singleton = True
105
+
106
+ def get_next_actions(self):
107
+ next_actions = [END_OF_STUDY_ACTION]
108
+ return next_actions
109
+
110
+
88
111
  class EndOfStudyAction(ActionWithNotification):
89
112
  name = END_OF_STUDY_ACTION
90
113
  display_name = "Submit End of Study Report"
@@ -150,22 +173,6 @@ class DmReferralAction(ActionWithNotification):
150
173
  return next_actions
151
174
 
152
175
 
153
- class OffscheduleDmReferralAction(ActionWithNotification):
154
- name = OFFSCHEDULE_DM_REFERRAL_ACTION
155
- display_name = "Submit Off-Schedule (Diabetes Referral)"
156
- notification_display_name = "Off-Schedule (Diabetes Referral)"
157
- parent_action_names = [DM_FOLLOWUP_ACTION]
158
- reference_model = "meta_prn.offscheduledmreferral"
159
- show_link_to_changelist = True
160
- admin_site_name = "meta_prn_admin"
161
- priority = HIGH_PRIORITY
162
- singleton = True
163
-
164
- def get_next_actions(self):
165
- next_actions = [END_OF_STUDY_ACTION]
166
- return next_actions
167
-
168
-
169
176
  class OffStudyMedicationAction(ActionWithNotification):
170
177
  name = OFFSTUDY_MEDICATION_ACTION
171
178
  display_name = "Withdrawal Study Medication"
meta_prn/choices.py CHANGED
@@ -2,6 +2,9 @@ from edc_constants.constants import NOT_APPLICABLE, OTHER, PATIENT, PREGNANCY, U
2
2
 
3
3
  from .constants import CLINICIAN, INVESTIGATOR, REFERRAL, SAE
4
4
 
5
+ # from edc_transfer.constants import TRANSFERRED
6
+
7
+
5
8
  CLINICAL_WITHDRAWAL_REASONS = (
6
9
  ("kidney_disease", "Development of chronic kidney disease"),
7
10
  ("liver_disease", "Development of chronic liver disease"),
@@ -96,6 +99,7 @@ WITHDRAWAL_STUDY_MEDICATION_REASONS = (
96
99
  ),
97
100
  (INVESTIGATOR, " Investigator decision"),
98
101
  (REFERRAL, "Referral to Diabetes clinic"),
102
+ # (TRANSFERRED, "Patient decision to transfer out of catchment area"),
99
103
  (PATIENT, "Patient decision"),
100
104
  (OTHER, "Other reason (specify below)"),
101
105
  )
@@ -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, [])
@@ -1,3 +1,4 @@
1
+ import pandas as pd
1
2
  from django.contrib import admin, messages
2
3
  from django.core.exceptions import FieldDoesNotExist
3
4
  from django.db import models
@@ -42,14 +43,24 @@ def update_report(modeladmin, request, queryset):
42
43
  modeladmin.model(
43
44
  subject_identifier=row["subject_identifier"],
44
45
  site_id=row["site_id"],
45
- imp_visit_date=row["imp_visit_date"],
46
+ imp_visit_date=(
47
+ None if pd.isna(row["imp_visit_date"]) else row["imp_visit_date"]
48
+ ),
46
49
  imp_visit_code=row["imp_visit_code"],
47
- next_appt_date=row["next_appt_datetime"],
48
- next_visit_code=row["next_visit_code"],
50
+ next_appt_date=(
51
+ None if pd.isna(row["next_appt_datetime"]) else row["next_appt_datetime"]
52
+ ),
53
+ next_visit_code=(
54
+ None if pd.isna(row["next_visit_code"]) else row["next_visit_code"]
55
+ ),
49
56
  days_since=row["days_since"].days,
50
- days_until=row["days_until"].days,
51
- visit_code=str(int(row["imp_visit_code"])),
52
- visit_code_sequence=row["imp_visit_code"] % 1,
57
+ days_until=None if pd.isna(row["days_until"]) else row["days_until"].days,
58
+ visit_code=(
59
+ None if pd.isna(row["imp_visit_code"]) else str(int(row["imp_visit_code"]))
60
+ ),
61
+ visit_code_sequence=(
62
+ None if pd.isna(row["imp_visit_code"]) else row["imp_visit_code"] % 1
63
+ ),
53
64
  report_model=modeladmin.model._meta.label_lower,
54
65
  created=now,
55
66
  )