From 44614fae1825482a1733fd371c6cda2105b6cf29 Mon Sep 17 00:00:00 2001 From: Adrienne Stilp Date: Fri, 15 Dec 2023 17:12:06 -0800 Subject: [PATCH] Add model method to get partner workspaces for an upload cycle Because the partner workspaces are not linked directly to an upload cycle, we need to use some logic to get the partner workspaces that should be included in an upload cycle. For a given research center and consent group, only the PartnerUploadWorkspace with the highest version and with a date completed less than the upload cycle end date will be included for that upload cycle. Use this method in the UploadCycleDetail view instead of filtering partner workspaces directly. --- gregor_django/gregor_anvil/models.py | 20 +++ .../gregor_anvil/tests/test_models.py | 117 ++++++++++++++++++ gregor_django/gregor_anvil/views.py | 3 +- 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/gregor_django/gregor_anvil/models.py b/gregor_django/gregor_anvil/models.py index e29dcdca..22eefa79 100644 --- a/gregor_django/gregor_anvil/models.py +++ b/gregor_django/gregor_anvil/models.py @@ -113,6 +113,26 @@ def get_absolute_url(self): """Return the absolute url for this object.""" return reverse("gregor_anvil:upload_cycles:detail", args=[self.cycle]) + def get_partner_upload_workspaces(self): + """Return a queryset of PartnerUploadWorkspace objects that are included in this upload cycle. + + For a given PartnerGroup and ConsentGroup, the workspace with the highest version that also has a date_completed + that is before the end_date of this upload cycle is included. + """ + qs = PartnerUploadWorkspace.objects.filter( + date_completed__lte=self.end_date + ).order_by("-version") + # This is not ideal, but we can't use .distinct on fields. + pks_to_keep = [] + for partner_group in PartnerGroup.objects.all(): + for consent_group in ConsentGroup.objects.all(): + instance = qs.filter( + partner_group=partner_group, consent_group=consent_group + ).first() + if instance: + pks_to_keep.append(instance.pk) + return qs.filter(pk__in=pks_to_keep) + class UploadWorkspace(TimeStampedModel, BaseWorkspaceData): """A model to track additional data about an upload workspace.""" diff --git a/gregor_django/gregor_anvil/tests/test_models.py b/gregor_django/gregor_anvil/tests/test_models.py index 73d86a96..2e56ecf9 100644 --- a/gregor_django/gregor_anvil/tests/test_models.py +++ b/gregor_django/gregor_anvil/tests/test_models.py @@ -208,6 +208,123 @@ def test_start_date_equal_to_end_date(self): self.assertEqual(len(e.exception.error_dict[NON_FIELD_ERRORS]), 1) self.assertIn("after start_date", e.exception.message_dict[NON_FIELD_ERRORS][0]) + def test_get_partner_upload_workspaces_no_date_completed(self): + """PartnerUploadWorkspace with no date_completed is not included.""" + upload_cycle = factories.UploadCycleFactory.create() + factories.PartnerUploadWorkspaceFactory.create(date_completed=None) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 0) + + def test_get_partner_uplod_workspaces_with_date_completed(self): + """PartnerUploadWorkspace with date_completed before UploadCycle end_date is included.""" + upload_cycle = factories.UploadCycleFactory.create() + workspace = factories.PartnerUploadWorkspaceFactory.create( + date_completed=upload_cycle.end_date - timedelta(days=4) + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 1) + self.assertIn(workspace, included_workspaces) + + def test_get_partner_upload_workspaces_with_date_completed_after_end_date(self): + """PartnerUploadWorkspace with date_completed after UploadCycle end_date is not included.""" + upload_cycle = factories.UploadCycleFactory.create() + factories.PartnerUploadWorkspaceFactory.create( + date_completed=upload_cycle.end_date + timedelta(days=4) + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 0) + + def test_get_partner_upload_workspaces_with_date_completed_equal_to_end_date(self): + """PartnerUploadWorkspace with date_completed equal to UploadCycle end_date is included.""" + upload_cycle = factories.UploadCycleFactory.create() + workspace = factories.PartnerUploadWorkspaceFactory.create( + date_completed=upload_cycle.end_date + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 1) + self.assertIn(workspace, included_workspaces) + + def test_get_partner_upload_workspaces_higher_versions_with_date_completed(self): + """Only the highest version is included when two PartnerUploadWorkspaces have date_completed.""" + upload_cycle = factories.UploadCycleFactory.create() + workspace_1 = factories.PartnerUploadWorkspaceFactory.create( + version=1, date_completed=upload_cycle.end_date - timedelta(days=4) + ) + workspace_2 = factories.PartnerUploadWorkspaceFactory.create( + partner_group=workspace_1.partner_group, + consent_group=workspace_1.consent_group, + version=2, + date_completed=upload_cycle.end_date - timedelta(days=3), + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 1) + self.assertNotIn(workspace_1, included_workspaces) + self.assertIn(workspace_2, included_workspaces) + + def test_get_partner_upload_workspaces_higher_version_no_date_completed(self): + """PartnerUploadWorkspaces with higher versions and no date_completed are not included.""" + upload_cycle = factories.UploadCycleFactory.create() + workspace_1 = factories.PartnerUploadWorkspaceFactory.create( + version=1, date_completed=upload_cycle.end_date - timedelta(days=4) + ) + workspace_2 = factories.PartnerUploadWorkspaceFactory.create( + partner_group=workspace_1.partner_group, + consent_group=workspace_1.consent_group, + version=2, + date_completed=None, + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 1) + self.assertIn(workspace_1, included_workspaces) + self.assertNotIn(workspace_2, included_workspaces) + + def test_get_partner_upload_workspaces_different_partner_groups(self): + """PartnerUploadWorkspaces with different PartnerGroups are both included.""" + upload_cycle = factories.UploadCycleFactory.create() + workspace_1 = factories.PartnerUploadWorkspaceFactory.create( + version=1, date_completed=upload_cycle.end_date - timedelta(days=4) + ) + workspace_2 = factories.PartnerUploadWorkspaceFactory.create( + consent_group=workspace_1.consent_group, + version=2, + date_completed=upload_cycle.end_date - timedelta(days=3), + ) + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 2) + self.assertIn(workspace_1, included_workspaces) + self.assertIn(workspace_2, included_workspaces) + + def test_get_partner_upload_workspaces_different_consent_groups(self): + """PartnerUploadWorkspaces with different ConsentGroups are both included.""" + + def test_get_partner_upload_workspaces_full_test(self): + upload_cycle = factories.UploadCycleFactory.create() + workspace_1 = factories.PartnerUploadWorkspaceFactory.create( + version=1, date_completed=upload_cycle.end_date - timedelta(days=4) + ) + workspace_2 = factories.PartnerUploadWorkspaceFactory.create( + partner_group=workspace_1.partner_group, + consent_group=workspace_1.consent_group, + version=2, + date_completed=upload_cycle.end_date - timedelta(days=3), + ) + workspace_3 = factories.PartnerUploadWorkspaceFactory.create( + version=1, date_completed=upload_cycle.end_date - timedelta(days=2) + ) + workspace_4 = factories.PartnerUploadWorkspaceFactory.create( + partner_group=workspace_3.partner_group, + consent_group=workspace_3.consent_group, + version=2, + date_completed=None, + ) + # import ipdb; ipdb.set_trace() + included_workspaces = upload_cycle.get_partner_upload_workspaces() + self.assertEqual(included_workspaces.count(), 2) + self.assertNotIn(workspace_1, included_workspaces) + self.assertIn(workspace_2, included_workspaces) + self.assertIn(workspace_3, included_workspaces) + self.assertNotIn(workspace_4, included_workspaces) + class UploadWorkspaceTest(TestCase): """Tests for the UploadWorkspace model.""" diff --git a/gregor_django/gregor_anvil/views.py b/gregor_django/gregor_anvil/views.py index 385092cb..0b8e7b8b 100644 --- a/gregor_django/gregor_anvil/views.py +++ b/gregor_django/gregor_anvil/views.py @@ -109,8 +109,9 @@ def get_tables_data(self): dcc_processed_data_workspace_qs = Workspace.objects.filter( dccprocesseddataworkspace__upload_cycle=self.object, ) + partner_workspaces = self.object.get_partner_upload_workspaces() partner_workspace_qs = Workspace.objects.filter( - partneruploadworkspace__date_completed__lte=self.object.end_date, + partneruploadworkspace__in=partner_workspaces ) return [ upload_workspace_qs,