diff --git a/primed/cdsa/migrations/0011_signedagreement_add_replaced_status.py b/primed/cdsa/migrations/0011_signedagreement_add_replaced_status.py new file mode 100644 index 00000000..f1c1bb06 --- /dev/null +++ b/primed/cdsa/migrations/0011_signedagreement_add_replaced_status.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.8 on 2024-01-18 23:49 + +from django.db import migrations +import model_utils.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ("cdsa", "0010_alter_historicalsignedagreement_status_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="historicalsignedagreement", + name="status", + field=model_utils.fields.StatusField( + choices=[ + ("active", "Active"), + ("withdrawn", "Withdrawn"), + ("lapsed", "Lapsed"), + ("replaced", "Replaced"), + ], + default="active", + max_length=100, + no_check_for_status=True, + verbose_name="status", + ), + ), + migrations.AlterField( + model_name="signedagreement", + name="status", + field=model_utils.fields.StatusField( + choices=[ + ("active", "Active"), + ("withdrawn", "Withdrawn"), + ("lapsed", "Lapsed"), + ("replaced", "Replaced"), + ], + default="active", + max_length=100, + no_check_for_status=True, + verbose_name="status", + ), + ), + ] diff --git a/primed/cdsa/models.py b/primed/cdsa/models.py index 5dd8a053..a2b1e0dc 100644 --- a/primed/cdsa/models.py +++ b/primed/cdsa/models.py @@ -99,14 +99,17 @@ class SignedAgreementStatusMixin: class StatusChoices(models.TextChoices): ACTIVE = "active", "Active" - """SignedAgreements that are currently active.""" + """SignedAgreements that are currently active.""" # pragma: no cover WITHDRAWN = "withdrawn", "Withdrawn" """SignedAgreements that have been withdrawn for some reason (e.g., PI changed institution, study no longer wanted to participate.)""" LAPSED = "lapsed", "Lapsed" - """SignedAgreements from a AgreementMajorVersion that is no longer valid.""" + """SignedAgreements from a AgreementMajorVersion that is no longer valid.""" # pragma: no cover + + REPLACED = "replaced", "Replaced" + """SignedAgreements that have been replaced by a newer version.""" # pragma: no cover STATUS = StatusChoices.choices diff --git a/primed/cdsa/tests/test_models.py b/primed/cdsa/tests/test_models.py index 1165c684..f39ba093 100644 --- a/primed/cdsa/tests/test_models.py +++ b/primed/cdsa/tests/test_models.py @@ -209,21 +209,6 @@ def test_get_absolute_url(self): instance.signed_agreement.get_absolute_url(), instance.get_absolute_url() ) - def test_statuses(self): - """All allowed statuses.""" - instance = factories.SignedAgreementFactory.create( - status=models.SignedAgreement.StatusChoices.ACTIVE - ) - instance.full_clean() - instance = factories.SignedAgreementFactory.create( - status=models.SignedAgreement.StatusChoices.WITHDRAWN - ) - instance.full_clean() - instance = factories.SignedAgreementFactory.create( - status=models.SignedAgreement.StatusChoices.LAPSED - ) - instance.full_clean() - def test_member_choices(self): """Can create instances with all of the member choices.""" instance = factories.SignedAgreementFactory.create( @@ -319,6 +304,11 @@ def test_status_field(self): ) self.assertEqual(instance.status, instance.StatusChoices.LAPSED) instance.full_clean() + instance = factories.SignedAgreementFactory.create( + status=models.SignedAgreement.StatusChoices.REPLACED + ) + self.assertEqual(instance.status, instance.StatusChoices.REPLACED) + instance.full_clean() # not allowed instance = factories.SignedAgreementFactory.create(status="foo") diff --git a/primed/cdsa/tests/test_views.py b/primed/cdsa/tests/test_views.py index 3fb7b4fe..2302edb8 100644 --- a/primed/cdsa/tests/test_views.py +++ b/primed/cdsa/tests/test_views.py @@ -548,6 +548,10 @@ def test_only_sets_active_signed_agreements_to_lapsed(self): version__major_version=instance, status=models.SignedAgreement.StatusChoices.LAPSED, ) + replaced_agreement = factories.SignedAgreementFactory.create( + version__major_version=instance, + status=models.SignedAgreement.StatusChoices.REPLACED, + ) self.client.force_login(self.user) response = self.client.post(self.get_url(instance.version), {}) self.assertEqual(response.status_code, 302) @@ -559,6 +563,10 @@ def test_only_sets_active_signed_agreements_to_lapsed(self): self.assertEqual( withdrawn_agreement.status, models.SignedAgreement.StatusChoices.WITHDRAWN ) + replaced_agreement.refresh_from_db() + self.assertEqual( + replaced_agreement.status, models.SignedAgreement.StatusChoices.REPLACED + ) def test_only_sets_associated_signed_agreements_to_lapsed(self): """Does not set SignedAgreements associated with a different version to LAPSED.""" @@ -5293,6 +5301,9 @@ def test_only_includes_active_agreements(self): withdrawn_agreement = factories.MemberAgreementFactory.create( signed_agreement__status=models.SignedAgreement.StatusChoices.WITHDRAWN ) + replaced_agreement = factories.MemberAgreementFactory.create( + signed_agreement__status=models.SignedAgreement.StatusChoices.REPLACED + ) self.client.force_login(self.user) response = self.client.get(self.get_url()) self.assertIn("table", response.context_data) @@ -5301,6 +5312,7 @@ def test_only_includes_active_agreements(self): self.assertIn(active_agreement.signed_agreement, table.data) self.assertNotIn(lapsed_agreement.signed_agreement, table.data) self.assertNotIn(withdrawn_agreement.signed_agreement, table.data) + self.assertNotIn(replaced_agreement.signed_agreement, table.data) class SignedAgreementAuditTest(TestCase): @@ -5758,6 +5770,9 @@ def test_only_includes_active_agreements(self): withdrawn_agreement = factories.DataAffiliateAgreementFactory.create( signed_agreement__status=models.SignedAgreement.StatusChoices.WITHDRAWN ) + replaced_agreement = factories.DataAffiliateAgreementFactory.create( + signed_agreement__status=models.SignedAgreement.StatusChoices.REPLACED + ) self.client.force_login(self.user) response = self.client.get(self.get_url()) self.assertIn("table", response.context_data) @@ -5766,6 +5781,7 @@ def test_only_includes_active_agreements(self): self.assertIn(active_agreement, table.data) self.assertNotIn(lapsed_agreement, table.data) self.assertNotIn(withdrawn_agreement, table.data) + self.assertNotIn(replaced_agreement, table.data) class UserAccessRecordsList(TestCase): @@ -5943,6 +5959,12 @@ def test_only_includes_active_agreements(self): withdrawn_member = GroupAccountMembershipFactory.create( group=withdrawn_agreement.signed_agreement.anvil_access_group ) + replaced_agreement = factories.MemberAgreementFactory.create( + signed_agreement__status=models.SignedAgreement.StatusChoices.REPLACED + ) + replaced_member = GroupAccountMembershipFactory.create( + group=replaced_agreement.signed_agreement.anvil_access_group + ) self.client.force_login(self.user) response = self.client.get(self.get_url()) self.assertIn("table", response.context_data) @@ -5951,6 +5973,7 @@ def test_only_includes_active_agreements(self): self.assertIn(active_member, table.data) self.assertNotIn(lapsed_member, table.data) self.assertNotIn(withdrawn_member, table.data) + self.assertNotIn(replaced_member, table.data) class CDSAWorkspaceRecordsList(TestCase): @@ -6021,6 +6044,11 @@ def test_only_includes_workspaces_with_active_agreements(self): study=withdrawn_workspace.study, signed_agreement__status=models.SignedAgreement.StatusChoices.WITHDRAWN, ) + replaced_workspace = factories.CDSAWorkspaceFactory.create() + factories.DataAffiliateAgreementFactory.create( + study=replaced_workspace.study, + signed_agreement__status=models.SignedAgreement.StatusChoices.REPLACED, + ) self.client.force_login(self.user) response = self.client.get(self.get_url()) self.assertIn("table", response.context_data) @@ -6029,6 +6057,7 @@ def test_only_includes_workspaces_with_active_agreements(self): self.assertIn(active_workspace, table.data) self.assertNotIn(lapsed_workspace, table.data) self.assertNotIn(withdrawn_workspace, table.data) + self.assertNotIn(replaced_workspace, table.data) class CDSAWorkspaceDetailTest(TestCase):