Repository: carpentries/amy

Issue:
Make "Agreement document" required field in membership model
At the Membership team meeting today, we discussed that the field for "Agreement Document" should be a required field.  Keeping this issue open to note other changes to fields in the membership model we should make.  

Tagging @elletjies  FYI, please feel free to add anything else here


Discussion:
I haven't seen any other response from @elletjies so I think this should be it for now.  Note we are considering other changes to membership separately (including the enforcement of registration codes and changes to pricing for in-person/online workshops).  

@pbanaszkiewicz @elichad is there any other information needed to implement this feature?


@maneesha I missed this. I think this is all for now. 
This should be straightforward, so I'll include this in the membership codes project to make sure it gets done alongside our other membership-related changes.

Resolving patch:
diff --git a/amy/workshops/migrations/0269_alter_membership_agreement_link.py b/amy/workshops/migrations/0269_alter_membership_agreement_link.py
new file mode 100644
--- /dev/null
+++ b/amy/workshops/migrations/0269_alter_membership_agreement_link.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.20 on 2023-11-23 11:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('workshops', '0268_trainingrequest_eventbrite_url'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='membership',
+            name='agreement_link',
+            field=models.URLField(default='', help_text='Link to member agreement document or folder in Google Drive', verbose_name='Link to member agreement'),
+        ),
+    ]
diff --git a/amy/workshops/models.py b/amy/workshops/models.py
--- a/amy/workshops/models.py
+++ b/amy/workshops/models.py
@@ -309,7 +309,7 @@ class Membership(models.Model):
     )
 
     agreement_link = models.URLField(
-        blank=True,
+        blank=False,
         default="",
         verbose_name="Link to member agreement",
         help_text="Link to member agreement document or folder in Google Drive",


Test patch:
diff --git a/amy/fiscal/tests/test_membership.py b/amy/fiscal/tests/test_membership.py
--- a/amy/fiscal/tests/test_membership.py
+++ b/amy/fiscal/tests/test_membership.py
@@ -571,6 +571,7 @@ def test_creating_membership_with_no_comment(self):
             "public_status": "public",
             "agreement_start": date(2021, 1, 28),
             "agreement_end": date(2022, 1, 28),
+            "agreement_link": "https://example.com",
             "variant": "partner",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
@@ -594,6 +595,7 @@ def test_creating_membership_with_comment(self):
             "public_status": "public",
             "agreement_start": date(2021, 1, 28),
             "agreement_end": date(2022, 1, 28),
+            "agreement_link": "https://example.com",
             "variant": "partner",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
@@ -647,6 +649,7 @@ def test_membership_edit_form_no_comment(self):
             "public_status": "public",
             "agreement_start": date(2021, 1, 28),
             "agreement_end": date(2022, 1, 28),
+            "agreement_link": "https://example.com",
             "variant": "partner",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
@@ -667,6 +670,7 @@ def test_membership_agreement_dates_validation(self):
             "public_status": "public",
             "agreement_start": date(2021, 1, 26),
             "agreement_end": date(2020, 1, 26),
+            "agreement_link": "https://example.com",
             "variant": "partner",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
@@ -688,6 +692,7 @@ def test_changing_consortium_to_nonconsortium(self):
             variant="partner",
             agreement_start=date(2021, 3, 21),
             agreement_end=date(2022, 3, 21),
+            agreement_link="https://example.com",
             contribution_type="financial",
             workshops_without_admin_fee_per_agreement=10,
             public_instructor_training_seats=25,
@@ -710,6 +715,7 @@ def test_changing_consortium_to_nonconsortium(self):
             "public_status": membership.public_status,
             "agreement_start": membership.agreement_start,
             "agreement_end": membership.agreement_end,
+            "agreement_link": membership.agreement_link,
             "variant": membership.variant,
             "contribution_type": membership.contribution_type,
             "public_instructor_training_seats": membership.public_instructor_training_seats,  # noqa
@@ -741,6 +747,7 @@ def test_edit_membership_rolled_fields(self):
             agreement_start=date(2021, 8, 1),
             agreement_end=date(2022, 7, 31),
             contribution_type="financial",
+            agreement_link="https://example.com",
             workshops_without_admin_fee_per_agreement=10,
             public_instructor_training_seats=10,
             inhouse_instructor_training_seats=10,
@@ -751,6 +758,7 @@ def test_edit_membership_rolled_fields(self):
             variant="partner",
             agreement_start=date(2022, 8, 1),
             agreement_end=date(2023, 7, 31),
+            agreement_link="https://example.com",
             contribution_type="financial",
             workshops_without_admin_fee_per_agreement=10,
             public_instructor_training_seats=10,
@@ -762,6 +770,7 @@ def test_edit_membership_rolled_fields(self):
             variant="partner",
             agreement_start=date(2023, 8, 1),
             agreement_end=date(2024, 7, 31),
+            agreement_link="https://example.com",
             contribution_type="financial",
             workshops_without_admin_fee_per_agreement=10,
             public_instructor_training_seats=10,
@@ -790,6 +799,7 @@ def test_edit_membership_rolled_fields(self):
             "variant": membership2.variant,
             "agreement_start": membership2.agreement_start,
             "agreement_end": membership2.agreement_end,
+            "agreement_link": membership2.agreement_link,
             "contribution_type": membership2.contribution_type,
             "public_instructor_training_seats": membership2.public_instructor_training_seats,  # noqa
             "additional_public_instructor_training_seats": membership2.additional_public_instructor_training_seats,  # noqa
@@ -844,6 +854,7 @@ def test_membership_edit_extensions(self):
                     variant="partner",
                     agreement_start=date(2021, 8, 1),
                     agreement_end=agreement_end,
+                    agreement_link="https://example.com",
                     extensions=extensions,
                     contribution_type="financial",
                     workshops_without_admin_fee_per_agreement=10,
@@ -856,6 +867,7 @@ def test_membership_edit_extensions(self):
                     "variant": membership.variant,
                     "agreement_start": membership.agreement_start,
                     "agreement_end": membership.agreement_end,
+                    "agreement_link": membership.agreement_link,
                     "extensions_0": extensions[0] + increment,
                     "extensions_1": extensions[1] + increment,
                     "extensions_2": extensions[2] + increment,
@@ -910,6 +922,7 @@ def test_new_nonconsortium_membership_redirects_to_details(self):
             "variant": "partner",
             "agreement_start": "2021-02-14",
             "agreement_end": "2022-02-14",
+            "agreement_link": "https://example.com",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
             "additional_public_instructor_training_seats": 0,
@@ -934,6 +947,7 @@ def test_new_consortium_membership_redirects_to_members(self):
             "variant": "partner",
             "agreement_start": "2021-02-14",
             "agreement_end": "2022-02-14",
+            "agreement_link": "https://example.com",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
             "additional_public_instructor_training_seats": 0,
@@ -958,6 +972,7 @@ def test_new_nonconsortium_membership_has_main_member(self):
             "variant": "partner",
             "agreement_start": "2021-02-14",
             "agreement_end": "2022-02-14",
+            "agreement_link": "https://example.com",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
             "additional_public_instructor_training_seats": 0,
@@ -984,6 +999,7 @@ def test_new_consortium_membership_has_main_member(self):
             "variant": "partner",
             "agreement_start": "2021-02-14",
             "agreement_end": "2022-02-14",
+            "agreement_link": "https://example.com",
             "contribution_type": "financial",
             "public_instructor_training_seats": 0,
             "additional_public_instructor_training_seats": 0,
@@ -1157,6 +1173,7 @@ def setUp(self):
             "variant": "partner",
             "agreement_start": "2021-03-01",
             "agreement_end": "2022-03-01",
+            "agreement_link": "https://example.com",
             "contribution_type": "financial",
             "workshops_without_admin_fee_per_agreement": 10,
             "public_instructor_training_seats": 12,
@@ -1183,6 +1200,7 @@ def setUpMembership(
             variant="partner",
             agreement_start=date(2020, 3, 1),
             agreement_end=date(2021, 3, 1),
+            agreement_link="https://example.com",
             contribution_type="financial",
             workshops_without_admin_fee_per_agreement=workshops_without_admin_fee_per_agreement,  # noqa
             public_instructor_training_seats=public_instructor_training_seats,  # noqa