diff --git a/src/registrar/assets/src/js/getgov/main.js b/src/registrar/assets/src/js/getgov/main.js index 67db06376..796e6f815 100644 --- a/src/registrar/assets/src/js/getgov/main.js +++ b/src/registrar/assets/src/js/getgov/main.js @@ -25,7 +25,7 @@ nameserversFormListener(); hookupYesNoListener("other_contacts-has_other_contacts",'other-employees', 'no-other-employees'); hookupYesNoListener("additional_details-has_anything_else_text",'anything-else', null); hookupYesNoListener("additional_details-has_cisa_representative",'cisa-representative', null); -hookupYesNoListener("feb_naming_requirements", "", "domain-naming-requirements-details-container"); +hookupYesNoListener("dotgov_domain-feb_naming_requirements", null, "domain-naming-requirements-details-container"); initializeUrbanizationToggle(); diff --git a/src/registrar/forms/domain_request_wizard.py b/src/registrar/forms/domain_request_wizard.py index 91c8ccb9b..98ccc9122 100644 --- a/src/registrar/forms/domain_request_wizard.py +++ b/src/registrar/forms/domain_request_wizard.py @@ -625,8 +625,11 @@ class ExecutiveNamingRequirementsYesNoForm(BaseYesNoForm): def clean(self): # Skip validation if this form is not applicable. if not (self.domain_request.is_federal() and self.domain_request.federal_type == "Executive"): - # If not executive, default to "yes" - self.cleaned_data["feb_naming_requirements"] = "yes" + # Initialize cleaned_data if it doesn't exist + if not hasattr(self, 'cleaned_data'): + self.cleaned_data = {} + # If not executive, default to None + self.cleaned_data["feb_naming_requirements"] = None return self.cleaned_data # Only validate the yes/no field here; details are handled by the separate details form. @@ -639,7 +642,7 @@ class ExecutiveNamingRequirementsYesNoForm(BaseYesNoForm): """ if not self.is_valid(): return - obj.feb_naming_requirements = (self.cleaned_data["feb_naming_requirements"] == "yes") + obj.feb_naming_requirements = (self.cleaned_data.get("feb_naming_requirements", None) == "yes") obj.save() @classmethod @@ -660,6 +663,7 @@ class ExecutiveNamingRequirementsDetailsForm(BaseDeletableRegistrarForm): widget=forms.Textarea(attrs={'maxlength': '2000'}), max_length=2000, required=True, + error_messages={"required": ("This field is required.")}, label="", help_text="Maximum 2000 characters allowed.", ) @@ -670,6 +674,25 @@ class ExecutiveNamingRequirementsDetailsForm(BaseDeletableRegistrarForm): obj.feb_naming_requirements_details = self.cleaned_data["feb_naming_requirements_details"] obj.save() + def is_valid(self): + """ + Validate that details are provided when required. + If the form is marked for deletion, bypass validation. + """ + if self.form_data_marked_for_deletion: + return True + + is_valid = super().is_valid() + if not is_valid: + return False + + # Check if the details field has content + details = self.cleaned_data.get('feb_naming_requirements_details', '').strip() + if not details: + return False + + return True + class PurposeForm(RegistrarForm): purpose = forms.CharField( label="Purpose", diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index ceaa19e77..e90edfa72 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -1401,13 +1401,12 @@ class DomainRequest(TimeStampedModel): def is_feb(self) -> bool: """Is this domain request for a Federal Executive Branch agency?""" - # if not self.generic_org_type: - # # generic_org_type is either blank or None, assume no - # return False - # if self.generic_org_type == DomainRequest.OrganizationChoices.FEDERAL: - # return self.federal_type == DomainRequest.FederalChoices.EXECUTIVE - # return False - return True # TODO: this is for testing, remove before merging + if not self.generic_org_type: + # generic_org_type is either blank or None, assume no + return False + if self.generic_org_type == DomainRequest.OrganizationChoices.FEDERAL: + return self.federal_type == DomainRequest.FederalChoices.EXECUTIVE + return False def is_federal(self) -> Union[bool, None]: """Is this domain request for a federal agency? diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index 83662505f..fce15af24 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -674,27 +674,33 @@ class DotgovDomain(DomainRequestWizard): 2: ExecutiveNamingRequirementsYesNoForm 3: ExecutiveNamingRequirementsDetailsForm """ + logger.debug("Validating dotgov domain form") # If not a federal executive branch agency, mark executive-related forms for deletion. if not (self.domain_request.is_feb()): forms_list[2].mark_form_for_deletion() forms_list[3].mark_form_for_deletion() return all(form.is_valid() for form in forms_list) - valid = True - yesno_form = forms_list[2] - details_form = forms_list[3] + if not forms_list[2].is_valid(): + logger.debug("Dotgov domain form is invalid") + if forms_list[2].cleaned_data.get("feb_naming_requirements", None) != "no": + forms_list[3].mark_form_for_deletion() + return False + + logger.debug(f"feb_naming_requirements: {forms_list[2].cleaned_data.get('feb_naming_requirements', None)}") - if yesno_form.cleaned_data.get("feb_naming_requirements") == "yes": - # If the user selects "yes", no details are needed. - details_form.mark_form_for_deletion() + if forms_list[2].cleaned_data.get("feb_naming_requirements", None) != "no": + logger.debug("Marking details form for deletion") + # If the user selects "yes" or has made no selection, no details are needed. + forms_list[3].mark_form_for_deletion() valid = all( form.is_valid() for i, form in enumerate(forms_list) if i != 3 ) else: # "No" was selected – details are required. valid = ( - yesno_form.is_valid() and - details_form.is_valid() and + forms_list[2].is_valid() and + forms_list[3].is_valid() and all(form.is_valid() for i, form in enumerate(forms_list) if i not in [2, 3]) ) return valid