diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 6aabfdd52..6f4c7e75c 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1500,6 +1500,8 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "authorizing_official", "other_contacts", "no_other_contacts_rationale", + "cisa_representative_first_name", + "cisa_representative_last_name", "cisa_representative_email", ] }, @@ -1575,6 +1577,8 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "no_other_contacts_rationale", "anything_else", "is_policy_acknowledged", + "cisa_representative_first_name", + "cisa_representative_last_name", "cisa_representative_email", ] autocomplete_fields = [ diff --git a/src/registrar/forms/domain_request_wizard.py b/src/registrar/forms/domain_request_wizard.py index fc176ce82..61afd6b57 100644 --- a/src/registrar/forms/domain_request_wizard.py +++ b/src/registrar/forms/domain_request_wizard.py @@ -648,20 +648,27 @@ class NoOtherContactsForm(BaseDeletableRegistrarForm): class CisaRepresentativeForm(BaseDeletableRegistrarForm): + cisa_representative_first_name = forms.CharField( + label="First name / given name", + error_messages={"required": "Enter the first name / given name of the CISA regional representative."}, + ) + cisa_representative_last_name = forms.CharField( + label="Last name / family name", + error_messages={"required": "Enter the last name / family name of the CISA regional representative."}, + ) cisa_representative_email = forms.EmailField( - required=True, + label="Your representative’s email (optional)", max_length=None, - label="Your representative’s email", + required=False, + error_messages={ + "invalid": ("Enter your representative’s email address in the required format, like name@example.com."), + }, validators=[ MaxLengthValidator( 320, message="Response must be less than 320 characters.", ) ], - error_messages={ - "invalid": ("Enter your email address in the required format, like name@example.com."), - "required": ("Enter the email address of your CISA regional representative."), - }, ) diff --git a/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py b/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py new file mode 100644 index 000000000..89f24a5e1 --- /dev/null +++ b/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 4.2.10 on 2024-06-12 20:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0100_domainrequest_action_needed_reason"), + ] + + operations = [ + migrations.AddField( + model_name="domaininformation", + name="cisa_representative_first_name", + field=models.CharField( + blank=True, db_index=True, null=True, verbose_name="CISA regional representative first name" + ), + ), + migrations.AddField( + model_name="domaininformation", + name="cisa_representative_last_name", + field=models.CharField( + blank=True, db_index=True, null=True, verbose_name="CISA regional representative last name" + ), + ), + migrations.AddField( + model_name="domaininformation", + name="has_anything_else_text", + field=models.BooleanField( + blank=True, help_text="Determines if the user has a anything_else or not", null=True + ), + ), + migrations.AddField( + model_name="domaininformation", + name="has_cisa_representative", + field=models.BooleanField( + blank=True, help_text="Determines if the user has a representative email or not", null=True + ), + ), + migrations.AddField( + model_name="domainrequest", + name="cisa_representative_first_name", + field=models.CharField( + blank=True, db_index=True, null=True, verbose_name="CISA regional representative first name" + ), + ), + migrations.AddField( + model_name="domainrequest", + name="cisa_representative_last_name", + field=models.CharField( + blank=True, db_index=True, null=True, verbose_name="CISA regional representative last name" + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="cisa_representative_email", + field=models.EmailField( + blank=True, max_length=320, null=True, verbose_name="CISA regional representative email" + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="cisa_representative_email", + field=models.EmailField( + blank=True, max_length=320, null=True, verbose_name="CISA regional representative email" + ), + ), + ] diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index bc35d4e30..62db04ac8 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -214,13 +214,45 @@ class DomainInformation(TimeStampedModel): verbose_name="Additional details", ) + # This is a drop-in replacement for a has_anything_else_text() function. + # In order to track if the user has clicked the yes/no field (while keeping a none default), we need + # a tertiary state. We should not display this in /admin. + has_anything_else_text = models.BooleanField( + null=True, + blank=True, + help_text="Determines if the user has a anything_else or not", + ) + cisa_representative_email = models.EmailField( null=True, blank=True, - verbose_name="CISA regional representative", + verbose_name="CISA regional representative email", max_length=320, ) + cisa_representative_first_name = models.CharField( + null=True, + blank=True, + verbose_name="CISA regional representative first name", + db_index=True, + ) + + cisa_representative_last_name = models.CharField( + null=True, + blank=True, + verbose_name="CISA regional representative last name", + db_index=True, + ) + + # This is a drop-in replacement for an has_cisa_representative() function. + # In order to track if the user has clicked the yes/no field (while keeping a none default), we need + # a tertiary state. We should not display this in /admin. + has_cisa_representative = models.BooleanField( + null=True, + blank=True, + help_text="Determines if the user has a representative email or not", + ) + is_policy_acknowledged = models.BooleanField( null=True, blank=True, @@ -241,6 +273,30 @@ class DomainInformation(TimeStampedModel): except Exception: return "" + def sync_yes_no_form_fields(self): + """Some yes/no forms use a db field to track whether it was checked or not. + We handle that here for def save(). + """ + # This ensures that if we have prefilled data, the form is prepopulated + if self.cisa_representative_first_name is not None or self.cisa_representative_last_name is not None: + self.has_cisa_representative = ( + self.cisa_representative_first_name != "" and self.cisa_representative_last_name != "" + ) + + # This check is required to ensure that the form doesn't start out checked + if self.has_cisa_representative is not None: + self.has_cisa_representative = ( + self.cisa_representative_first_name != "" and self.cisa_representative_first_name is not None + ) and (self.cisa_representative_last_name != "" and self.cisa_representative_last_name is not None) + + # This ensures that if we have prefilled data, the form is prepopulated + if self.anything_else is not None: + self.has_anything_else_text = self.anything_else != "" + + # This check is required to ensure that the form doesn't start out checked. + if self.has_anything_else_text is not None: + self.has_anything_else_text = self.anything_else != "" and self.anything_else is not None + def sync_organization_type(self): """ Updates the organization_type (without saving) to match @@ -275,6 +331,7 @@ class DomainInformation(TimeStampedModel): def save(self, *args, **kwargs): """Save override for custom properties""" + self.sync_yes_no_form_fields() self.sync_organization_type() super().save(*args, **kwargs) diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 8dfa419c9..1ad8ae7b3 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -477,10 +477,24 @@ class DomainRequest(TimeStampedModel): cisa_representative_email = models.EmailField( null=True, blank=True, - verbose_name="CISA regional representative", + verbose_name="CISA regional representative email", max_length=320, ) + cisa_representative_first_name = models.CharField( + null=True, + blank=True, + verbose_name="CISA regional representative first name", + db_index=True, + ) + + cisa_representative_last_name = models.CharField( + null=True, + blank=True, + verbose_name="CISA regional representative last name", + db_index=True, + ) + # This is a drop-in replacement for an has_cisa_representative() function. # In order to track if the user has clicked the yes/no field (while keeping a none default), we need # a tertiary state. We should not display this in /admin. @@ -577,16 +591,17 @@ class DomainRequest(TimeStampedModel): """Some yes/no forms use a db field to track whether it was checked or not. We handle that here for def save(). """ - # This ensures that if we have prefilled data, the form is prepopulated - if self.cisa_representative_email is not None: - self.has_cisa_representative = self.cisa_representative_email != "" + if self.cisa_representative_first_name is not None or self.cisa_representative_last_name is not None: + self.has_cisa_representative = ( + self.cisa_representative_first_name != "" and self.cisa_representative_last_name != "" + ) # This check is required to ensure that the form doesn't start out checked if self.has_cisa_representative is not None: self.has_cisa_representative = ( - self.cisa_representative_email != "" and self.cisa_representative_email is not None - ) + self.cisa_representative_first_name != "" and self.cisa_representative_first_name is not None + ) and (self.cisa_representative_last_name != "" and self.cisa_representative_last_name is not None) # This ensures that if we have prefilled data, the form is prepopulated if self.anything_else is not None: @@ -984,11 +999,12 @@ class DomainRequest(TimeStampedModel): def has_additional_details(self) -> bool: """Combines the has_anything_else_text and has_cisa_representative fields, then returns if this domain request has either of them.""" - # Split out for linter - has_details = False - if self.has_anything_else_text or self.has_cisa_representative: - has_details = True + # Split out for linter + has_details = True + + if self.has_anything_else_text is None or self.has_cisa_representative is None: + has_details = False return has_details def is_federal(self) -> Union[bool, None]: @@ -1097,14 +1113,19 @@ class DomainRequest(TimeStampedModel): return True return False - def _cisa_rep_and_email_check(self): - # Has a CISA rep + email is NOT empty or NOT an empty string OR doesn't have CISA rep - return ( + def _cisa_rep_check(self): + # Either does not have a CISA rep, OR has a CISA rep + both first name + # and last name are NOT empty and are NOT an empty string + to_return = ( self.has_cisa_representative is True - and self.cisa_representative_email is not None - and self.cisa_representative_email != "" + and self.cisa_representative_first_name is not None + and self.cisa_representative_first_name != "" + and self.cisa_representative_last_name is not None + and self.cisa_representative_last_name != "" ) or self.has_cisa_representative is False + return to_return + def _anything_else_radio_button_and_text_field_check(self): # Anything else boolean is True + filled text field and it's not an empty string OR the boolean is No return ( @@ -1112,7 +1133,7 @@ class DomainRequest(TimeStampedModel): ) or self.has_anything_else_text is False def _is_additional_details_complete(self): - return self._cisa_rep_and_email_check() and self._anything_else_radio_button_and_text_field_check() + return self._cisa_rep_check() and self._anything_else_radio_button_and_text_field_check() def _is_policy_acknowledgement_complete(self): return self.is_policy_acknowledged is not None diff --git a/src/registrar/templates/domain_request_additional_details.html b/src/registrar/templates/domain_request_additional_details.html index e13d3c7ee..96c89d8ad 100644 --- a/src/registrar/templates/domain_request_additional_details.html +++ b/src/registrar/templates/domain_request_additional_details.html @@ -9,7 +9,6 @@ {# commented out so it does not appear at this point on this page #} {% endblock %} - {% block form_fields %}
@@ -22,13 +21,13 @@ {% input_with_errors forms.0.has_cisa_representative %} {% endwith %} {# forms.0 is a small yes/no form that toggles the visibility of "cisa representative" formset #} -
-
+
+ {% input_with_errors forms.1.cisa_representative_first_name %} + {% input_with_errors forms.1.cisa_representative_last_name %} {% input_with_errors forms.1.cisa_representative_email %} {# forms.1 is a form for inputting the e-mail of a cisa representative #} -
@@ -42,7 +41,6 @@ {% input_with_errors forms.2.has_anything_else_text %} {% endwith %} {# forms.2 is a small yes/no form that toggles the visibility of "cisa representative" formset #} -
@@ -50,6 +48,5 @@ {% input_with_errors forms.3.anything_else %} {% endwith %} {# forms.3 is a form for inputting the e-mail of a cisa representative #} -
{% endblock %} diff --git a/src/registrar/templates/domain_request_review.html b/src/registrar/templates/domain_request_review.html index 1f21683a5..bb8ad498e 100644 --- a/src/registrar/templates/domain_request_review.html +++ b/src/registrar/templates/domain_request_review.html @@ -157,18 +157,33 @@ {% if step == Step.ADDITIONAL_DETAILS %} {% namespaced_url 'domain-request' step as domain_request_url %} - {% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"Incomplete"|safe %} - {% include "includes/summary_item.html" with title=title sub_header_text='CISA regional representative' value=domain_request.cisa_representative_email heading_level=heading_level editable=True edit_link=domain_request_url custom_text_for_value_none='No' %} - {% endwith %} + {% with title=form_titles|get_item:step %} + {% if domain_request.has_additional_details %} + {% include "includes/summary_item.html" with title="Additional Details" value=" " heading_level=heading_level editable=True edit_link=domain_request_url %} +

CISA Regional Representative

+ -

Anything else

- +

Anything else

+ + {% else %} + {% include "includes/summary_item.html" with title="Additional Details" value="Incomplete"|safe heading_level=heading_level editable=True edit_link=domain_request_url %} + {% endif %} + {% endwith %} {% endif %} diff --git a/src/registrar/templates/domain_request_status.html b/src/registrar/templates/domain_request_status.html index ac447476d..16ce26f4c 100644 --- a/src/registrar/templates/domain_request_status.html +++ b/src/registrar/templates/domain_request_status.html @@ -118,7 +118,15 @@ {# We always show this field even if None #} {% if DomainRequest %} - {% include "includes/summary_item.html" with title='Additional details' sub_header_text='CISA regional representative' value=DomainRequest.cisa_representative_email custom_text_for_value_none='No' heading_level=heading_level %} +

CISA Regional Representative

+ +

Anything else

{% endif %} - {% endwith %}
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index f049388df..f6ad8d3e9 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -808,12 +808,13 @@ def create_ready_domain(): # TODO in 1793: Remove the federal agency/updated federal agency fields -def completed_domain_request( +def completed_domain_request( # noqa has_other_contacts=True, has_current_website=True, has_alternative_gov_domain=True, has_about_your_organization=True, has_anything_else=True, + has_cisa_representative=True, status=DomainRequest.DomainRequestStatus.STARTED, user=False, submitter=False, @@ -895,6 +896,10 @@ def completed_domain_request( domain_request.current_websites.add(current) if has_alternative_gov_domain: domain_request.alternative_domains.add(alt) + if has_cisa_representative: + domain_request.cisa_representative_first_name = "CISA-first-name" + domain_request.cisa_representative_last_name = "CISA-last-name" + domain_request.cisa_representative_email = "cisaRep@igorville.gov" return domain_request diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index ff19d06be..e567f9329 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -2326,6 +2326,8 @@ class TestDomainRequestAdmin(MockEppLib): "anything_else", "has_anything_else_text", "cisa_representative_email", + "cisa_representative_first_name", + "cisa_representative_last_name", "has_cisa_representative", "is_policy_acknowledged", "submission_date", @@ -2358,6 +2360,8 @@ class TestDomainRequestAdmin(MockEppLib): "no_other_contacts_rationale", "anything_else", "is_policy_acknowledged", + "cisa_representative_first_name", + "cisa_representative_last_name", "cisa_representative_email", ] diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index e42451be9..53af1674e 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -1802,93 +1802,129 @@ class TestDomainRequestIncomplete(TestCase): def test_is_additional_details_complete(self): test_cases = [ # CISA Rep - Yes + # Firstname - Yes + # Lastname - Yes # Email - Yes # Anything Else Radio - Yes # Anything Else Text - Yes { "has_cisa_representative": True, + "cisa_representative_first_name": "cisa-first-name", + "cisa_representative_last_name": "cisa-last-name", "cisa_representative_email": "some@cisarepemail.com", "has_anything_else_text": True, "anything_else": "Some text", "expected": True, }, # CISA Rep - Yes + # Firstname - Yes + # Lastname - Yes # Email - Yes # Anything Else Radio - Yes # Anything Else Text - None { "has_cisa_representative": True, + "cisa_representative_first_name": "cisa-first-name", + "cisa_representative_last_name": "cisa-last-name", "cisa_representative_email": "some@cisarepemail.com", "has_anything_else_text": True, "anything_else": None, "expected": True, }, # CISA Rep - Yes - # Email - Yes + # Firstname - Yes + # Lastname - Yes + # Email - None >> e-mail is optional so it should not change anything setting this to None # Anything Else Radio - No # Anything Else Text - No { "has_cisa_representative": True, - "cisa_representative_email": "some@cisarepemail.com", + "cisa_representative_first_name": "cisa-first-name", + "cisa_representative_last_name": "cisa-last-name", + "cisa_representative_email": None, "has_anything_else_text": False, "anything_else": None, "expected": True, }, # CISA Rep - Yes - # Email - Yes - # Anything Else Radio - None - # Anything Else Text - None - { - "has_cisa_representative": True, - "cisa_representative_email": "some@cisarepemail.com", - "has_anything_else_text": None, - "anything_else": None, - "expected": False, - }, - # CISA Rep - Yes + # Firstname - Yes + # Lastname - Yes # Email - None # Anything Else Radio - None # Anything Else Text - None { "has_cisa_representative": True, + "cisa_representative_first_name": "cisa-first-name", + "cisa_representative_last_name": "cisa-last-name", "cisa_representative_email": None, "has_anything_else_text": None, "anything_else": None, "expected": False, }, # CISA Rep - Yes + # Firstname - None + # Lastname - None + # Email - None + # Anything Else Radio - None + # Anything Else Text - None + { + "has_cisa_representative": True, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, + "cisa_representative_email": None, + "has_anything_else_text": None, + "anything_else": None, + "expected": False, + }, + # CISA Rep - Yes + # Firstname - None + # Lastname - None # Email - None # Anything Else Radio - No # Anything Else Text - No - # sync_yes_no will override has_cisa_representative to be False if cisa_representative_email is None + # sync_yes_no will override has_cisa_representative to be False if cisa_representative_first_name is None # therefore, our expected will be True { "has_cisa_representative": True, - # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields + # Above will be overridden to False if cisa_representative_first_name is None + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": False, "anything_else": None, "expected": True, }, # CISA Rep - Yes + # Firstname - None + # Lastname - None # Email - None # Anything Else Radio - Yes # Anything Else Text - None + # NOTE: We should never have an instance where only firstname or only lastname are populated + # (they are both required) { "has_cisa_representative": True, - # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields + # Above will be overridden to False if cisa_representative_first_name is None or + # cisa_representative_last_name is None bc of sync_yes_no_form_fields + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": True, "anything_else": None, "expected": True, }, # CISA Rep - Yes + # Firstname - None + # Lastname - None # Email - None # Anything Else Radio - Yes # Anything Else Text - Yes { "has_cisa_representative": True, - # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields + # Above will be overridden to False if cisa_representative_first_name is None or + # cisa_representative_last_name is None bc of sync_yes_no_form_fields + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": True, "anything_else": "Some text", @@ -1899,6 +1935,8 @@ class TestDomainRequestIncomplete(TestCase): # Anything Else Text - Yes { "has_cisa_representative": False, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": True, "anything_else": "Some text", @@ -1909,6 +1947,8 @@ class TestDomainRequestIncomplete(TestCase): # Anything Else Text - None { "has_cisa_representative": False, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": True, "anything_else": None, @@ -1919,6 +1959,8 @@ class TestDomainRequestIncomplete(TestCase): # Anything Else Text - None { "has_cisa_representative": False, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": None, "anything_else": None, @@ -1930,6 +1972,8 @@ class TestDomainRequestIncomplete(TestCase): # Anything Else Text - No { "has_cisa_representative": False, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": False, "anything_else": None, @@ -1939,6 +1983,8 @@ class TestDomainRequestIncomplete(TestCase): # Anything Else Radio - None { "has_cisa_representative": None, + "cisa_representative_first_name": None, + "cisa_representative_last_name": None, "cisa_representative_email": None, "has_anything_else_text": None, "anything_else": None, diff --git a/src/registrar/tests/test_views_request.py b/src/registrar/tests/test_views_request.py index 4f2170c87..b46b89b9a 100644 --- a/src/registrar/tests/test_views_request.py +++ b/src/registrar/tests/test_views_request.py @@ -366,6 +366,8 @@ class DomainRequestTests(TestWithUser, WebTest): additional_details_form["additional_details-has_cisa_representative"] = "True" additional_details_form["additional_details-has_anything_else_text"] = "True" + additional_details_form["additional_details-cisa_representative_first_name"] = "CISA-first-name" + additional_details_form["additional_details-cisa_representative_last_name"] = "CISA-last-name" additional_details_form["additional_details-cisa_representative_email"] = "FakeEmail@gmail.com" additional_details_form["additional_details-anything_else"] = "Nothing else." @@ -374,6 +376,8 @@ class DomainRequestTests(TestWithUser, WebTest): additional_details_result = additional_details_form.submit() # validate that data from this step are being saved domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.cisa_representative_first_name, "CISA-first-name") + self.assertEqual(domain_request.cisa_representative_last_name, "CISA-last-name") self.assertEqual(domain_request.cisa_representative_email, "FakeEmail@gmail.com") self.assertEqual(domain_request.anything_else, "Nothing else.") # the post request should return a redirect to the next form in @@ -719,6 +723,8 @@ class DomainRequestTests(TestWithUser, WebTest): additional_details_form["additional_details-has_cisa_representative"] = "True" additional_details_form["additional_details-has_anything_else_text"] = "True" + additional_details_form["additional_details-cisa_representative_first_name"] = "cisa-first-name" + additional_details_form["additional_details-cisa_representative_last_name"] = "cisa-last-name" additional_details_form["additional_details-cisa_representative_email"] = "FakeEmail@gmail.com" additional_details_form["additional_details-anything_else"] = "Nothing else." @@ -727,6 +733,8 @@ class DomainRequestTests(TestWithUser, WebTest): additional_details_result = additional_details_form.submit() # validate that data from this step are being saved domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.cisa_representative_first_name, "cisa-first-name") + self.assertEqual(domain_request.cisa_representative_last_name, "cisa-last-name") self.assertEqual(domain_request.cisa_representative_email, "FakeEmail@gmail.com") self.assertEqual(domain_request.anything_else, "Nothing else.") # the post request should return a redirect to the next form in @@ -1125,11 +1133,10 @@ class DomainRequestTests(TestWithUser, WebTest): def test_yes_no_form_inits_yes_for_cisa_representative_and_anything_else(self): """On the Additional Details page, the yes/no form gets initialized with YES selected - for both yes/no radios if the domain request has a value for cisa_representative and + for both yes/no radios if the domain request has a values for cisa_representative_first_name and anything_else""" - domain_request = completed_domain_request(user=self.user, has_anything_else=True) - domain_request.cisa_representative_email = "test@igorville.gov" + domain_request = completed_domain_request(user=self.user, has_anything_else=True, has_cisa_representative=True) domain_request.anything_else = "1234" domain_request.save() @@ -1181,12 +1188,13 @@ class DomainRequestTests(TestWithUser, WebTest): """On the Additional details page, the form preselects "no" when has_cisa_representative and anything_else is no""" - domain_request = completed_domain_request(user=self.user, has_anything_else=False) + domain_request = completed_domain_request( + user=self.user, has_anything_else=False, has_cisa_representative=False + ) # Unlike the other contacts form, the no button is tracked with these boolean fields. # This means that we should expect this to correlate with the no button. domain_request.has_anything_else_text = False - domain_request.has_cisa_representative = False domain_request.save() # prime the form by visiting /edit @@ -1205,7 +1213,7 @@ class DomainRequestTests(TestWithUser, WebTest): # Check the cisa representative yes/no field yes_no_cisa = additional_details_form["additional_details-has_cisa_representative"].value - self.assertEquals(yes_no_cisa, "False") + self.assertEquals(yes_no_cisa, None) # Check the anything else yes/no field yes_no_anything_else = additional_details_form["additional_details-has_anything_else_text"].value @@ -1215,11 +1223,15 @@ class DomainRequestTests(TestWithUser, WebTest): """When a user submits the Additional Details form with no selected for all fields, the domain request's data gets wiped when submitted""" domain_request = completed_domain_request(name="nocisareps.gov", user=self.user) + domain_request.cisa_representative_first_name = "cisa-firstname1" + domain_request.cisa_representative_last_name = "cisa-lastname1" domain_request.cisa_representative_email = "fake@faketown.gov" domain_request.save() # Make sure we have the data we need for the test self.assertEqual(domain_request.anything_else, "There is more") + self.assertEqual(domain_request.cisa_representative_first_name, "cisa-firstname1") + self.assertEqual(domain_request.cisa_representative_last_name, "cisa-lastname1") self.assertEqual(domain_request.cisa_representative_email, "fake@faketown.gov") # prime the form by visiting /edit @@ -1253,25 +1265,31 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # Verify that the anything_else and cisa_representative have been deleted from the DB + # Verify that the anything_else and cisa_representative information have been deleted from the DB domain_request = DomainRequest.objects.get(requested_domain__name="nocisareps.gov") # Check that our data has been cleared self.assertEqual(domain_request.anything_else, None) + self.assertEqual(domain_request.cisa_representative_first_name, None) + self.assertEqual(domain_request.cisa_representative_last_name, None) self.assertEqual(domain_request.cisa_representative_email, None) # Double check the yes/no fields self.assertEqual(domain_request.has_anything_else_text, False) - self.assertEqual(domain_request.has_cisa_representative, False) + self.assertEqual(domain_request.cisa_representative_first_name, None) + self.assertEqual(domain_request.cisa_representative_last_name, None) + self.assertEqual(domain_request.cisa_representative_email, None) def test_submitting_additional_details_populates_cisa_representative_and_anything_else(self): """When a user submits the Additional Details form, the domain request's data gets submitted""" - domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False) + domain_request = completed_domain_request( + name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False + ) # Make sure we have the data we need for the test self.assertEqual(domain_request.anything_else, None) - self.assertEqual(domain_request.cisa_representative_email, None) + self.assertEqual(domain_request.cisa_representative_first_name, None) # These fields should not be selected at all, since we haven't initialized the form yet self.assertEqual(domain_request.has_anything_else_text, None) @@ -1294,6 +1312,8 @@ class DomainRequestTests(TestWithUser, WebTest): # Set fields to true, and set data on those fields additional_details_form["additional_details-has_cisa_representative"] = "True" additional_details_form["additional_details-has_anything_else_text"] = "True" + additional_details_form["additional_details-cisa_representative_first_name"] = "cisa-firstname" + additional_details_form["additional_details-cisa_representative_last_name"] = "cisa-lastname" additional_details_form["additional_details-cisa_representative_email"] = "test@faketest.gov" additional_details_form["additional_details-anything_else"] = "redandblue" @@ -1302,10 +1322,12 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # Verify that the anything_else and cisa_representative exist in the db + # Verify that the anything_else and cisa_representative information exist in the db domain_request = DomainRequest.objects.get(requested_domain__name="cisareps.gov") self.assertEqual(domain_request.anything_else, "redandblue") + self.assertEqual(domain_request.cisa_representative_first_name, "cisa-firstname") + self.assertEqual(domain_request.cisa_representative_last_name, "cisa-lastname") self.assertEqual(domain_request.cisa_representative_email, "test@faketest.gov") self.assertEqual(domain_request.has_cisa_representative, True) @@ -1313,7 +1335,9 @@ class DomainRequestTests(TestWithUser, WebTest): def test_if_cisa_representative_yes_no_form_is_yes_then_field_is_required(self): """Applicants with a cisa representative must provide a value""" - domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False) + domain_request = completed_domain_request( + name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False + ) # prime the form by visiting /edit self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) @@ -1338,7 +1362,8 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - self.assertContains(response, "Enter the email address of your CISA regional representative.") + self.assertContains(response, "Enter the first name / given name of the CISA regional representative.") + self.assertContains(response, "Enter the last name / family name of the CISA regional representative.") def test_if_anything_else_yes_no_form_is_yes_then_field_is_required(self): """Applicants with a anything else must provide a value""" @@ -1373,7 +1398,9 @@ class DomainRequestTests(TestWithUser, WebTest): def test_additional_details_form_fields_required(self): """When a user submits the Additional Details form without checking the has_cisa_representative and has_anything_else_text fields, the form should deny this action""" - domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False) + domain_request = completed_domain_request( + name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False + ) self.assertEqual(domain_request.has_anything_else_text, None) self.assertEqual(domain_request.has_cisa_representative, None) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 3f6cc6b0e..6d3079bc1 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -381,6 +381,7 @@ def export_data_type_to_csv(csv_file): """ All domains report with extra columns. This maps to the "All domain metadata" button. + Exports domains of all statuses. """ writer = csv.writer(csv_file) @@ -408,15 +409,8 @@ def export_data_type_to_csv(csv_file): "federal_agency", "domain__name", ] - filter_condition = { - "domain__state__in": [ - Domain.State.READY, - Domain.State.DNS_NEEDED, - Domain.State.ON_HOLD, - ], - } write_csv_for_domains( - writer, columns, sort_fields, filter_condition, should_get_domain_managers=True, should_write_header=True + writer, columns, sort_fields, filter_condition={}, should_get_domain_managers=True, should_write_header=True ) diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index 95a139211..d14262107 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -369,7 +369,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): or self.domain_request.no_other_contacts_rationale is not None ), "additional_details": ( - (self.domain_request.anything_else is not None and self.domain_request.cisa_representative_email) + (self.domain_request.anything_else is not None and self.domain_request.has_cisa_representative) or self.domain_request.is_policy_acknowledged is not None ), "requirements": self.domain_request.is_policy_acknowledged is not None, @@ -380,7 +380,6 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): def get_context_data(self): """Define context for access on all wizard pages.""" has_profile_flag = flag_is_active(self.request, "profile_feature") - logger.debug("PROFILE FLAG is %s" % has_profile_flag) context_stuff = {} if DomainRequest._form_complete(self.domain_request):