diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 803443bc9..9239a0488 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -339,6 +339,10 @@ function enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, elementPk, } // Listen to Back/Forward button navigation and handle rejectionReasonFormGroup display based on session storage + + // When you navigate using forward/back after changing status but not saving, when you land back on the DA page the + // status select will say (for example) Rejected but the selected option can be something else. To manage the show/hide + // accurately for this edge case, we use cache and test for the back/forward navigation. const observer = new PerformanceObserver((list) => { list.getEntries().forEach((entry) => { if (entry.type === "back_forward") { diff --git a/src/registrar/migrations/0070_domainapplication_rejection_reason.py b/src/registrar/migrations/0070_domainapplication_rejection_reason.py index defeb4d95..60dc8ac73 100644 --- a/src/registrar/migrations/0070_domainapplication_rejection_reason.py +++ b/src/registrar/migrations/0070_domainapplication_rejection_reason.py @@ -27,6 +27,7 @@ class Migration(migrations.Migration): ), ("organization_eligibility", "Organization isn't eligible for a .gov"), ("naming_requirements", "Naming requirements not met"), + ("other", "Other"), ], null=True, ), diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index ca6a996ce..609b9df33 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -363,6 +363,7 @@ class DomainApplication(TimeStampedModel): ) ORGANIZATION_ELIGIBILITY = "organization_eligibility", "Organization isn't eligible for a .gov" NAMING_REQUIREMENTS = "naming_requirements", "Naming requirements not met" + OTHER = "other", "Other" # #### Internal fields about the application ##### status = FSMField( diff --git a/src/registrar/templates/emails/status_change_rejected.txt b/src/registrar/templates/emails/status_change_rejected.txt index 4beacf25a..3dae38c0d 100644 --- a/src/registrar/templates/emails/status_change_rejected.txt +++ b/src/registrar/templates/emails/status_change_rejected.txt @@ -8,8 +8,9 @@ REQUEST RECEIVED ON: {{ application.submission_date|date }} STATUS: Rejected ---------------------------------------------------------------- - -REJECTION REASON{% if application.rejection_reason == 'domain_purpose' %} +{% if application.rejection_reason != 'other' %} +REJECTION REASON{% endif %} +{% if application.rejection_reason == 'domain_purpose' %} Your domain request was rejected because the purpose you provided did not meet our requirements. You didn’t provide enough information about how you intend to use the domain. @@ -63,6 +64,17 @@ general public. Learn more about naming requirements for your type of organizati YOU CAN SUBMIT A NEW REQUEST We encourage you to request a domain that meets our requirements. If you have questions or want to discuss potential domain names, reply to this email. +{% elif application.rejection_reason == 'other' %} +YOU CAN SUBMIT A NEW REQUEST +If your organization is eligible for a .gov domain and you meet our other requirements, you can submit a new request. + +Learn more about: +- Eligibility for a .gov domain +- Choosing a .gov domain name + + +NEED ASSISTANCE? +If you have questions about this domain request or need help choosing a new domain name, reply to this email. {% endif %} THANK YOU diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 69e756026..4e449ca5d 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -712,6 +712,34 @@ class TestDomainApplicationAdmin(MockEppLib): self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) + def test_save_model_sends_rejected_email_other(self): + """When transitioning to rejected on a domain request, an email is sent + explaining why when the reason is other.""" + + with less_console_noise(): + # Ensure there is no user with this email + EMAIL = "mayor@igorville.gov" + User.objects.filter(email=EMAIL).delete() + + # Create a sample application + application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + + # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name + self.transition_state_and_send_email( + application, + DomainApplication.ApplicationStatus.REJECTED, + DomainApplication.RejectionReasons.OTHER, + ) + self.assert_email_is_accurate( + "Choosing a .gov domain name", 0, EMAIL + ) + self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) + + # Approve + self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) + self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) + def test_transition_to_rejected_without_rejection_reason_does_trigger_error(self): """ When transitioning to rejected without a rejection reason, admin throws a user friendly message.