meta-edc 0.3.33__py3-none-any.whl → 0.3.34__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.
Files changed (41) hide show
  1. meta_auth/auth_objects.py +15 -0
  2. meta_auth/auths.py +5 -2
  3. meta_edc/settings/debug.py +2 -2
  4. meta_edc/settings/defaults.py +4 -0
  5. meta_edc/urls.py +1 -0
  6. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/METADATA +6 -3
  7. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/RECORD +40 -29
  8. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/WHEEL +1 -1
  9. meta_pharmacy/admin.py +128 -0
  10. meta_pharmacy/admin_site.py +5 -0
  11. meta_pharmacy/apps.py +3 -0
  12. meta_pharmacy/constants.py +10 -0
  13. meta_pharmacy/forms.py +65 -0
  14. meta_pharmacy/migrations/0002_initial.py +693 -0
  15. meta_pharmacy/migrations/0003_auto_20240909_2335.py +64 -0
  16. meta_pharmacy/models.py +102 -0
  17. meta_pharmacy/urls.py +8 -0
  18. meta_prn/action_items.py +9 -1
  19. meta_reports/admin/__init__.py +1 -0
  20. meta_reports/admin/dbviews/__init__.py +1 -0
  21. meta_reports/admin/dbviews/imp_substitutions_admin.py +88 -0
  22. meta_reports/migrations/0017_auto_20240819_1711.py +1 -0
  23. meta_reports/migrations/0047_impsubstitutions.py +56 -0
  24. meta_reports/migrations/0048_auto_20240909_2338.py +48 -0
  25. meta_reports/models/__init__.py +1 -0
  26. meta_reports/models/dbviews/__init__.py +1 -0
  27. meta_reports/models/dbviews/imp_substitutions/__init__.py +1 -0
  28. meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +37 -0
  29. meta_reports/models/dbviews/imp_substitutions/view_definition.py +20 -0
  30. meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +0 -1
  31. meta_sites/tests/test_sites.py +1 -1
  32. meta_subject/migrations/0107_auto_20220415_0043.py +28 -22
  33. meta_subject/migrations/0126_auto_20220719_2142.py +4 -4
  34. meta_subject/migrations/0131_auto_20220722_0411.py +28 -23
  35. meta_subject/migrations/0132_auto_20220722_1825.py +10 -6
  36. meta_subject/migrations/0135_auto_20220722_2212.py +39 -35
  37. meta_subject/migrations/0150_auto_20220914_0039.py +15 -11
  38. meta_analytics/notebooks/meta_endpoints.ipynb +0 -286
  39. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/AUTHORS +0 -0
  40. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/LICENSE +0 -0
  41. {meta_edc-0.3.33.dist-info → meta_edc-0.3.34.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,64 @@
1
+ # Generated by Django 5.1 on 2024-09-09 20:35
2
+ from pathlib import Path
3
+
4
+ import pandas as pd
5
+ from django.apps import apps as django_apps
6
+ from django.conf import settings
7
+ from django.db import migrations
8
+ from edc_utils import get_utcnow
9
+ from tqdm import tqdm
10
+
11
+
12
+ def populate_substitutions(apps, schema_editor):
13
+ """import CSV file into pandas dataframe and use DF to
14
+ populate the model.
15
+
16
+ CSV file was sent to ERIK on 2024-09-09 in relation to
17
+ a possible protocol violation where a subject was given the
18
+ incorrect IMP. The CSV file lists `sid` where a bottle was not ready
19
+ to dispense and a bottle of `dispensed_sid` was dispensed instead.
20
+ """
21
+ path = Path(settings.META_PHARMACY_RX_SUBSTITUTION_FILE).expanduser()
22
+ df = pd.read_csv(path, header=1)
23
+ df = df.rename(
24
+ columns={"MISSING DRUG": "sid", "SUBSTITUTE": "dispensed_sid", "SITE": "site_id"}
25
+ )
26
+ df = df.rename(
27
+ columns={"MISSING DRUG": "sid", "SUBSTITUTE": "dispensed_sid", "SITE": "site_id"}
28
+ )
29
+ df["sid"] = df["sid"].apply(pd.to_numeric, errors="coerce")
30
+ df["dispensed_sid"] = df["dispensed_sid"].apply(pd.to_numeric, errors="coerce")
31
+ df["site_id"] = df["site_id"].apply(pd.to_numeric, errors="coerce")
32
+ now = get_utcnow()
33
+ model_cls = django_apps.get_model("meta_pharmacy.substitutions")
34
+ df_error = df[df["dispensed_sid"].isna()]
35
+ df_error = df_error.reset_index()
36
+ df_ok = df[df["dispensed_sid"].notna()]
37
+ df_ok = df_ok.reset_index()
38
+ data = [
39
+ model_cls(
40
+ row_index=row["index"],
41
+ report_datetime=now,
42
+ site_id=row["site_id"],
43
+ sid=row["sid"],
44
+ dispensed_sid=row["dispensed_sid"],
45
+ user_created="erikvw",
46
+ created=now,
47
+ locale_created="en-gb",
48
+ )
49
+ for _, row in df_ok.iterrows()
50
+ ]
51
+ created = len(model_cls.objects.bulk_create(data))
52
+ for obj in tqdm(model_cls.objects.all(), total=created):
53
+ obj.save()
54
+ if not df_error.empty:
55
+ print(df_error[["index", "sid"]])
56
+
57
+
58
+ class Migration(migrations.Migration):
59
+
60
+ dependencies = [
61
+ ("meta_pharmacy", "0002_initial"),
62
+ ]
63
+
64
+ operations = [migrations.RunPython(populate_substitutions)]
meta_pharmacy/models.py CHANGED
@@ -0,0 +1,102 @@
1
+ from django.core.exceptions import ObjectDoesNotExist
2
+ from django.db import models
3
+ from django.db.models import Index
4
+ from edc_constants.choices import YES_NO_NOT_EVALUATED
5
+ from edc_constants.constants import NO, NOT_EVALUATED, YES
6
+ from edc_identifier.model_mixins import NonUniqueSubjectIdentifierFieldMixin
7
+ from edc_model.models import BaseUuidModel, HistoricalRecords
8
+ from edc_pharmacy.models import Rx as BaseRx
9
+ from edc_sites.managers import CurrentSiteManager
10
+ from edc_sites.model_mixins import SiteModelMixin
11
+
12
+ from meta_pharmacy.constants import MISSING_SUBJECT_IDENTIFIER
13
+ from meta_rando.models import RandomizationList
14
+
15
+
16
+ class MyManager(models.Manager):
17
+ use_in_migrations = True
18
+
19
+
20
+ class Rx(BaseRx):
21
+ """A proxy model of edc_pharmacy.Rx.
22
+
23
+ For autocomplete only.
24
+ """
25
+
26
+ def save(self, *args, **kwargs):
27
+ raise NotImplementedError(
28
+ "This proxy model may not be saved. Permissions should be view only"
29
+ )
30
+
31
+ class Meta:
32
+ proxy = True
33
+
34
+
35
+ class Substitutions(NonUniqueSubjectIdentifierFieldMixin, SiteModelMixin, BaseUuidModel):
36
+ """A model to capture a CSV file that lists IMP substitutions
37
+ made where a bottle of `sid` is substituted with a bottle of
38
+ `dispensed_sid`.
39
+
40
+ The IMP substitutions were not done by any approved procedure. SID
41
+ values are sequential and not designed for human transcription.
42
+ """
43
+
44
+ report_datetime = models.DateTimeField()
45
+
46
+ row_index = models.IntegerField(null=True)
47
+
48
+ rx = models.ForeignKey(Rx, on_delete=models.PROTECT, null=True, blank=True)
49
+
50
+ sid = models.IntegerField(verbose_name="SID")
51
+
52
+ visit_no = models.IntegerField("Visit Number", null=True, blank=True)
53
+
54
+ dispensed_sid = models.IntegerField(verbose_name="Dispensed SID")
55
+
56
+ updated_visit_no = models.IntegerField("Visit Number", null=True, blank=True)
57
+
58
+ updated_subject_identifier = models.CharField(
59
+ max_length=50, verbose_name="Taken from subject", null=True, blank=True
60
+ )
61
+
62
+ arm_match = models.CharField(
63
+ max_length=15, choices=YES_NO_NOT_EVALUATED, default=NOT_EVALUATED
64
+ )
65
+
66
+ notes = models.TextField(verbose_name="Notes")
67
+
68
+ objects = MyManager()
69
+ on_site = CurrentSiteManager()
70
+ history = HistoricalRecords(inherit=True)
71
+
72
+ def __str__(self):
73
+ if self.rx:
74
+ return self.rx.subject_identifier
75
+ return str(self.sid)
76
+
77
+ def save(self, *args, **kwargs):
78
+ if not self.rx:
79
+ try:
80
+ self.rx = Rx.objects.get(rando_sid=self.sid)
81
+ except ObjectDoesNotExist:
82
+ self.status = MISSING_SUBJECT_IDENTIFIER
83
+ else:
84
+ self.subject_identifier = self.rx.subject_identifier
85
+ else:
86
+ self.subject_identifier = self.rx.subject_identifier
87
+ rando_a = RandomizationList.objects.get(sid=self.sid)
88
+ rando_b = RandomizationList.objects.get(sid=self.dispensed_sid)
89
+ if rando_a.assignment != rando_b.assignment:
90
+ self.arm_match = NO
91
+ else:
92
+ self.arm_match = YES
93
+
94
+ super().save(*args, **kwargs)
95
+
96
+ class Meta(SiteModelMixin.Meta, BaseUuidModel.Meta):
97
+ verbose_name_plural = "IMP Substitutions"
98
+ verbose_name = "IMP Substitution"
99
+ indexes = [
100
+ Index(fields=["sid", "dispensed_sid", "subject_identifier"]),
101
+ Index(fields=["row_index"]),
102
+ ]
meta_pharmacy/urls.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.urls.conf import path
2
+ from django.views.generic import RedirectView
3
+
4
+ app_name = "meta_pharmacy"
5
+
6
+ urlpatterns = [
7
+ path("", RedirectView.as_view(url=f"/{app_name}/admin/"), name="home_url"),
8
+ ]
meta_prn/action_items.py CHANGED
@@ -27,6 +27,7 @@ from .constants import (
27
27
  OFFSCHEDULE_PREGNANCY_ACTION,
28
28
  OFFSTUDY_MEDICATION_ACTION,
29
29
  PREGNANCY_NOTIFICATION_ACTION,
30
+ REFERRAL,
30
31
  UNBLINDING_REQUEST_ACTION,
31
32
  UNBLINDING_REVIEW_ACTION,
32
33
  )
@@ -136,7 +137,7 @@ class DmReferralAction(ActionWithNotification):
136
137
  name = DM_REFFERAL_ACTION
137
138
  display_name = "Diabetes referral"
138
139
  notification_display_name = "Diabetes referral"
139
- parent_action_names = None
140
+ parent_action_names = [OFFSTUDY_MEDICATION_ACTION]
140
141
  reference_model = "meta_prn.dmreferral"
141
142
  show_link_to_changelist = True
142
143
  show_link_to_add = True
@@ -182,6 +183,13 @@ class OffStudyMedicationAction(ActionWithNotification):
182
183
  priority = HIGH_PRIORITY
183
184
  singleton = True
184
185
 
186
+ def get_next_actions(self):
187
+ if self.reference_obj.reason == REFERRAL:
188
+ next_actions = [DM_REFFERAL_ACTION]
189
+ else:
190
+ next_actions = [END_OF_STUDY_ACTION]
191
+ return next_actions
192
+
185
193
 
186
194
  class UnblindingRequestAction(ActionWithNotification):
187
195
  name = UNBLINDING_REQUEST_ACTION
@@ -1,5 +1,6 @@
1
1
  from .dbviews import (
2
2
  GlucoseSummaryAdmin,
3
+ ImpSubstitutionsAdmin,
3
4
  MissingOgttNoteModelAdmin,
4
5
  MissingScreeningOgttAdmin,
5
6
  OnStudyMissingLabValuesAdmin,
@@ -1,4 +1,5 @@
1
1
  from .glucose_summary_admin import GlucoseSummaryAdmin
2
+ from .imp_substitutions_admin import ImpSubstitutionsAdmin
2
3
  from .missing_screening_ogtt_admin import (
3
4
  MissingOgttNoteModelAdmin,
4
5
  MissingScreeningOgttAdmin,
@@ -0,0 +1,88 @@
1
+ from django.apps import apps as django_apps
2
+ from django.contrib import admin
3
+ from django.core.exceptions import ObjectDoesNotExist
4
+ from django.template.loader import render_to_string
5
+ from django.urls import reverse
6
+ from django.utils.translation import gettext_lazy as _
7
+ from edc_appointment.models import Appointment
8
+ from edc_model_admin.dashboard import ModelAdminDashboardMixin
9
+ from edc_model_admin.mixins import TemplatesModelAdminMixin
10
+ from edc_qareports.modeladmin_mixins import QaReportModelAdminMixin
11
+ from edc_sites.admin import SiteModelAdminMixin
12
+ from edc_visit_schedule.admin import ScheduleStatusListFilter
13
+ from edc_visit_schedule.constants import DAY1
14
+
15
+ from ...admin_site import meta_reports_admin
16
+ from ...models import ImpSubstitutions
17
+
18
+
19
+ @admin.register(ImpSubstitutions, site=meta_reports_admin)
20
+ class ImpSubstitutionsAdmin(
21
+ QaReportModelAdminMixin,
22
+ SiteModelAdminMixin,
23
+ ModelAdminDashboardMixin,
24
+ TemplatesModelAdminMixin,
25
+ admin.ModelAdmin,
26
+ ):
27
+ ordering = ["site", "subject_identifier"]
28
+ list_display = [
29
+ "dashboard",
30
+ "render_button",
31
+ "subject",
32
+ "sid",
33
+ "dispensed_sid",
34
+ "arm_match",
35
+ "allocated_date",
36
+ "user_created",
37
+ "user_modified",
38
+ "modified",
39
+ ]
40
+
41
+ list_filter = ["arm_match", ScheduleStatusListFilter, "allocated_datetime"]
42
+
43
+ search_fields = ["subject_identifier", "sid", "dispensed_sid"]
44
+
45
+ def dashboard(self, obj=None, label=None) -> str:
46
+ kwargs = self.get_subject_dashboard_url_kwargs(obj)
47
+ try:
48
+ kwargs.update(
49
+ appointment=str(
50
+ Appointment.objects.get(
51
+ subject_identifier=obj.subject_identifier,
52
+ visit_code=DAY1,
53
+ visit_code_sequence=0,
54
+ ).id
55
+ )
56
+ )
57
+ except ObjectDoesNotExist:
58
+ pass
59
+ url = reverse(self.get_subject_dashboard_url_name(obj=obj), kwargs=kwargs)
60
+ context = dict(title=_("Go to subject's dashboard@1000"), url=url, label=label)
61
+ return render_to_string("dashboard_button.html", context=context)
62
+
63
+ @admin.display(description="Subject", ordering="subject_identifier")
64
+ def subject(self, obj):
65
+ return obj.subject_identifier
66
+
67
+ @admin.display(description="Allocated", ordering="allocated_datetime")
68
+ def allocated_date(self, obj=None):
69
+ return obj.allocated_datetime.date() if obj.allocated_datetime else None
70
+
71
+ @admin.display(description="Update")
72
+ def render_button(self, obj=None):
73
+ crf_model_cls = django_apps.get_model("meta_pharmacy", "substitutions")
74
+ url = reverse(
75
+ f"meta_pharmacy_admin:{crf_model_cls._meta.label_lower.replace('.', '_')}_change",
76
+ args=(obj.original_id,),
77
+ )
78
+ url = (
79
+ f"{url}?next={self.admin_site.name}:"
80
+ f"{self.model._meta.label_lower.replace('.', '_')}_changelist"
81
+ )
82
+ title = _(f"View {crf_model_cls._meta.verbose_name}")
83
+ label = _("View")
84
+ crf_button = render_to_string(
85
+ "edc_qareports/columns/change_button.html",
86
+ context=dict(title=title, url=url, label=label),
87
+ )
88
+ return crf_button
@@ -9,6 +9,7 @@ class Migration(migrations.Migration):
9
9
 
10
10
  dependencies = [
11
11
  ("meta_reports", "0016_missingscreeningogtt"),
12
+ ("meta_screening", "0067_alter_historicalscreeningpartone_report_datetime_and_more"),
12
13
  ]
13
14
 
14
15
  operations = [
@@ -0,0 +1,56 @@
1
+ # Generated by Django 5.1 on 2024-09-09 20:37
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("meta_reports", "0046_auto_20240829_0250"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name="ImpSubstitutions",
15
+ fields=[
16
+ (
17
+ "id",
18
+ models.BigAutoField(
19
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
20
+ ),
21
+ ),
22
+ ("report_model", models.CharField(max_length=50)),
23
+ ("subject_identifier", models.CharField(max_length=25)),
24
+ ("created", models.DateTimeField()),
25
+ ("original_id", models.UUIDField(null=True)),
26
+ ("sid", models.IntegerField(null=True, verbose_name="Original SID")),
27
+ (
28
+ "dispensed_sid",
29
+ models.IntegerField(null=True, verbose_name="Dispensed SID"),
30
+ ),
31
+ (
32
+ "arm_match",
33
+ models.CharField(
34
+ choices=[
35
+ ("Yes", "Yes"),
36
+ ("No", "No"),
37
+ ("not_evaluated", "Not evaluated"),
38
+ ],
39
+ default="not_evaluated",
40
+ max_length=15,
41
+ ),
42
+ ),
43
+ ("allocated_datetime", models.DateTimeField(null=True)),
44
+ ("user_created", models.CharField(max_length=25)),
45
+ ("user_modified", models.CharField(max_length=25)),
46
+ ("modified", models.DateTimeField(null=True)),
47
+ ],
48
+ options={
49
+ "verbose_name": "IMP Substitutions",
50
+ "verbose_name_plural": "IMP Substitutions",
51
+ "db_table": "imp_subjectitutions_view",
52
+ "managed": False,
53
+ "default_permissions": ("view", "export", "viewallsites"),
54
+ },
55
+ ),
56
+ ]
@@ -0,0 +1,48 @@
1
+ # Generated by Django 5.1 on 2024-09-09 20:38
2
+
3
+ import django_db_views.migration_functions
4
+ import django_db_views.operations
5
+ from django.db import migrations
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ("meta_reports", "0047_impsubstitutions"),
12
+ ]
13
+
14
+ operations = [
15
+ django_db_views.operations.ViewRunPython(
16
+ code=django_db_views.migration_functions.ForwardViewMigration(
17
+ "select *, uuid() as id, now() as `created`, 'meta_reports.imp_subjectitutions_view' as `report_model` from (SELECT s.subject_identifier, s.sid, s.dispensed_sid, arm_match, r.allocated_datetime, s.site_id, s.user_created, s.user_modified, s.modified, s.id AS original_id FROM meta_pharmacy_substitutions AS s LEFT JOIN meta_rando_randomizationlist AS r ON r.subject_identifier = s.subject_identifier ORDER BY s.subject_identifier) as A ORDER BY subject_identifier, site_id",
18
+ "imp_subjectitutions_view",
19
+ engine="django.db.backends.mysql",
20
+ ),
21
+ reverse_code=django_db_views.migration_functions.BackwardViewMigration(
22
+ "", "imp_subjectitutions_view", engine="django.db.backends.mysql"
23
+ ),
24
+ atomic=False,
25
+ ),
26
+ django_db_views.operations.ViewRunPython(
27
+ code=django_db_views.migration_functions.ForwardViewMigration(
28
+ "select *, get_random_uuid() as id, now() as created, 'meta_reports.imp_subjectitutions_view' as report_model from (SELECT s.subject_identifier, s.sid, s.dispensed_sid, arm_match, r.allocated_datetime, s.site_id, s.user_created, s.user_modified, s.modified, s.id AS original_id FROM meta_pharmacy_substitutions AS s LEFT JOIN meta_rando_randomizationlist AS r ON r.subject_identifier = s.subject_identifier ORDER BY s.subject_identifier NULLS FIRST) as A ORDER BY subject_identifier, site_id",
29
+ "imp_subjectitutions_view",
30
+ engine="django.db.backends.postgresql",
31
+ ),
32
+ reverse_code=django_db_views.migration_functions.BackwardViewMigration(
33
+ "", "imp_subjectitutions_view", engine="django.db.backends.postgresql"
34
+ ),
35
+ atomic=False,
36
+ ),
37
+ django_db_views.operations.ViewRunPython(
38
+ code=django_db_views.migration_functions.ForwardViewMigration(
39
+ "select *, uuid() as id, datetime() as created, 'meta_reports.imp_subjectitutions_view' as report_model from (SELECT s.subject_identifier, s.sid, s.dispensed_sid, arm_match, r.allocated_datetime, s.site_id, s.user_created, s.user_modified, s.modified, s.id AS original_id FROM meta_pharmacy_substitutions AS s LEFT JOIN meta_rando_randomizationlist AS r ON r.subject_identifier = s.subject_identifier ORDER BY s.subject_identifier) as A ORDER BY subject_identifier, site_id",
40
+ "imp_subjectitutions_view",
41
+ engine="django.db.backends.sqlite3",
42
+ ),
43
+ reverse_code=django_db_views.migration_functions.BackwardViewMigration(
44
+ "", "imp_subjectitutions_view", engine="django.db.backends.sqlite3"
45
+ ),
46
+ atomic=False,
47
+ ),
48
+ ]
@@ -1,6 +1,7 @@
1
1
  from .dbviews import (
2
2
  NOTE_STATUSES,
3
3
  GlucoseSummary,
4
+ ImpSubstitutions,
4
5
  MissingOgttNote,
5
6
  MissingScreeningOgtt,
6
7
  OnStudyMissingLabValues,
@@ -1,4 +1,5 @@
1
1
  from .glucose_summary import GlucoseSummary
2
+ from .imp_substitutions import ImpSubstitutions
2
3
  from .missing_screening_ogtt import NOTE_STATUSES, MissingOgttNote, MissingScreeningOgtt
3
4
  from .on_study_missing_lab_values import OnStudyMissingLabValues
4
5
  from .on_study_missing_values import OnStudyMissingValues
@@ -0,0 +1 @@
1
+ from .unmanaged_model import ImpSubstitutions
@@ -0,0 +1,37 @@
1
+ from django.db import models
2
+ from django_db_views.db_view import DBView
3
+ from edc_constants.choices import YES_NO_NOT_EVALUATED
4
+ from edc_constants.constants import NOT_EVALUATED
5
+ from edc_qareports.model_mixins import QaReportModelMixin, qa_reports_permissions
6
+
7
+ from .view_definition import get_view_definition
8
+
9
+
10
+ class ImpSubstitutions(QaReportModelMixin, DBView):
11
+
12
+ original_id = models.UUIDField(null=True)
13
+
14
+ sid = models.IntegerField(verbose_name="Original SID", null=True)
15
+
16
+ dispensed_sid = models.IntegerField(verbose_name="Dispensed SID", null=True)
17
+
18
+ arm_match = models.CharField(
19
+ max_length=15, choices=YES_NO_NOT_EVALUATED, default=NOT_EVALUATED
20
+ )
21
+
22
+ allocated_datetime = models.DateTimeField(null=True)
23
+
24
+ user_created = models.CharField(max_length=25)
25
+
26
+ user_modified = models.CharField(max_length=25)
27
+
28
+ modified = models.DateTimeField(null=True)
29
+
30
+ view_definition = get_view_definition()
31
+
32
+ class Meta:
33
+ managed = False
34
+ db_table = "imp_subjectitutions_view"
35
+ verbose_name = "IMP Substitutions"
36
+ verbose_name_plural = "IMP Substitutions"
37
+ default_permissions = qa_reports_permissions
@@ -0,0 +1,20 @@
1
+ from edc_qareports.sql_generator import SqlViewGenerator
2
+
3
+
4
+ def get_view_definition() -> dict:
5
+ subquery = """
6
+ select s.subject_identifier, s.sid, s.dispensed_sid, arm_match, r.allocated_datetime,
7
+ s.site_id, s.user_created, s.user_modified, s.modified, s.id as original_id
8
+ from meta_pharmacy_substitutions as s left join meta_rando_randomizationlist as r
9
+ on r.subject_identifier=s.subject_identifier
10
+ order by s.subject_identifier
11
+ """ # noqa
12
+ sql_view = SqlViewGenerator(
13
+ report_model="meta_reports.imp_subjectitutions_view",
14
+ ordering=["subject_identifier", "site_id"],
15
+ )
16
+ return {
17
+ "django.db.backends.mysql": sql_view.as_mysql(subquery),
18
+ "django.db.backends.postgresql": sql_view.as_postgres(subquery),
19
+ "django.db.backends.sqlite3": sql_view.as_sqlite(subquery),
20
+ }
@@ -12,7 +12,6 @@ qa_cases = [
12
12
  label="No VL value or VL date",
13
13
  dbtable="meta_subject_patienthistory",
14
14
  label_lower="meta_subject.patienthistory",
15
- fld_name="viral_load_date",
16
15
  where="crf.viral_load is null or crf.viral_load_date is null",
17
16
  ),
18
17
  CrfCase(
@@ -1,5 +1,5 @@
1
1
  from django.test import TestCase
2
- from edc_sites import InvalidSiteError
2
+ from edc_sites.exceptions import InvalidSiteError
3
3
  from edc_sites.site import sites
4
4
 
5
5
 
@@ -1,5 +1,5 @@
1
1
  # Generated by Django 3.2.11 on 2022-04-14 21:43
2
-
2
+ from django.core.exceptions import ObjectDoesNotExist
3
3
  from django.db import migrations
4
4
  from django.db.migrations import RunPython
5
5
  from edc_consent.utils import get_consent_model_name
@@ -10,28 +10,34 @@ from meta_pharmacy.constants import METFORMIN
10
10
 
11
11
 
12
12
  def func(apps, schema_editor):
13
- medication = apps.get_model("edc_pharmacy.medication")._default_manager.get(name=METFORMIN)
14
- site_model_cls = apps.get_model("sites.site")
15
- subject_identifiers = [
16
- tpl[0]
17
- for tpl in apps.get_model("edc_pharmacy.rx")._default_manager.values_list(
18
- "subject_identifier"
19
- )
20
- ]
21
- for subject_consent in apps.get_model(get_consent_model_name())._default_manager.exclude(
22
- subject_identifier__in=subject_identifiers
23
- ):
24
- site = site_model_cls.objects.get(id=subject_consent.site.id)
25
- create_prescription(
26
- subject_identifier=subject_consent.subject_identifier,
27
- report_datetime=subject_consent.consent_datetime,
28
- randomizer_name=get_meta_version(),
29
- medications=[METFORMIN],
30
- site_id=site.id,
13
+ try:
14
+ medication = apps.get_model("edc_pharmacy.medication")._default_manager.get(
15
+ name=METFORMIN
31
16
  )
32
- for obj in apps.get_model("edc_pharmacy.rx")._default_manager.all():
33
- obj.medications.clear()
34
- obj.medications.add(medication)
17
+ except ObjectDoesNotExist:
18
+ pass
19
+ else:
20
+ site_model_cls = apps.get_model("sites.site")
21
+ subject_identifiers = [
22
+ tpl[0]
23
+ for tpl in apps.get_model("edc_pharmacy.rx")._default_manager.values_list(
24
+ "subject_identifier"
25
+ )
26
+ ]
27
+ for subject_consent in apps.get_model(
28
+ get_consent_model_name()
29
+ )._default_manager.exclude(subject_identifier__in=subject_identifiers):
30
+ site = site_model_cls.objects.get(id=subject_consent.site.id)
31
+ create_prescription(
32
+ subject_identifier=subject_consent.subject_identifier,
33
+ report_datetime=subject_consent.consent_datetime,
34
+ randomizer_name=get_meta_version(),
35
+ medications=[METFORMIN],
36
+ site_id=site.id,
37
+ )
38
+ for obj in apps.get_model("edc_pharmacy.rx")._default_manager.all():
39
+ obj.medications.clear()
40
+ obj.medications.add(medication)
35
41
 
36
42
 
37
43
  class Migration(migrations.Migration):
@@ -4,11 +4,11 @@ from django.db import migrations
4
4
 
5
5
 
6
6
  def update_egfr_drop_action(apps, schema_editor):
7
- action_item_model_cls = apps.get_model("edc_action_item.actionitem")
7
+ # action_item_model_cls = apps.get_model("edc_action_item.actionitem")
8
8
  crf_metadata_model_cls = apps.get_model("edc_metadata.crfmetadata")
9
- action_item_model_cls.objects.filter(
10
- reference_model="meta_subject.egfrnotification"
11
- ).update(reference_model="meta_subject.egfrdropnotification")
9
+ # action_item_model_cls.objects.filter(
10
+ # reference_model="meta_subject.egfrnotification"
11
+ # ).update(reference_model="meta_subject.egfrdropnotification")
12
12
  crf_metadata_model_cls.objects.filter(model="meta_subject.egfrnotification").update(
13
13
  model="meta_subject.egfrdropnotification"
14
14
  )
@@ -1,5 +1,5 @@
1
1
  # Generated by Django 3.2.11 on 2022-07-22 01:11
2
-
2
+ from django.core.exceptions import ObjectDoesNotExist
3
3
  from django.db import migrations
4
4
  from edc_action_item.identifiers import ActionIdentifier
5
5
  from edc_constants.constants import CLOSED, HIGH_PRIORITY
@@ -13,28 +13,33 @@ def update_missing_action_items_for_missed_visits(apps, schema_editor):
13
13
  actionitem_model_cls = apps.get_model("edc_action_item.actionitem")
14
14
  subjectvisitmissed_model_cls = apps.get_model("meta_subject.subjectvisitmissed")
15
15
  subjectvisit_model_cls = apps.get_model("meta_subject.subjectvisit")
16
- action_type = actiontype_model_cls.objects.get(name=MISSED_VISIT_ACTION)
17
-
18
- total = subjectvisitmissed_model_cls.objects.filter(action_identifier__isnull=True).count()
19
- for obj in tqdm(
20
- subjectvisitmissed_model_cls.objects.filter(action_identifier__isnull=True),
21
- total=total,
22
- ):
23
- subject_visit = subjectvisit_model_cls.objects.get(id=obj.subject_visit_id)
24
- action_item = actionitem_model_cls.objects.create(
25
- subject_identifier=subject_visit.subject_identifier,
26
- action_identifier=ActionIdentifier(site_id=subject_visit.site_id).identifier,
27
- report_datetime=subject_visit.report_datetime,
28
- action_type=action_type,
29
- reference_model="meta_subject.subjectvisitmissed",
30
- linked_to_reference=True,
31
- priority=HIGH_PRIORITY,
32
- status=CLOSED,
33
- auto_created=True,
34
- site_id=subject_visit.site_id,
35
- )
36
- obj.action_identifier = action_item.action_identifier
37
- obj.save_base(update_fields=["action_identifier"])
16
+ try:
17
+ action_type = actiontype_model_cls.objects.get(name=MISSED_VISIT_ACTION)
18
+ except ObjectDoesNotExist:
19
+ pass
20
+ else:
21
+ total = subjectvisitmissed_model_cls.objects.filter(
22
+ action_identifier__isnull=True
23
+ ).count()
24
+ for obj in tqdm(
25
+ subjectvisitmissed_model_cls.objects.filter(action_identifier__isnull=True),
26
+ total=total,
27
+ ):
28
+ subject_visit = subjectvisit_model_cls.objects.get(id=obj.subject_visit_id)
29
+ action_item = actionitem_model_cls.objects.create(
30
+ subject_identifier=subject_visit.subject_identifier,
31
+ action_identifier=ActionIdentifier(site_id=subject_visit.site_id).identifier,
32
+ report_datetime=subject_visit.report_datetime,
33
+ action_type=action_type,
34
+ reference_model="meta_subject.subjectvisitmissed",
35
+ linked_to_reference=True,
36
+ priority=HIGH_PRIORITY,
37
+ status=CLOSED,
38
+ auto_created=True,
39
+ site_id=subject_visit.site_id,
40
+ )
41
+ obj.action_identifier = action_item.action_identifier
42
+ obj.save_base(update_fields=["action_identifier"])
38
43
 
39
44
 
40
45
  class Migration(migrations.Migration):