From 61c32351ddadf38f8ae04c6d3fd3e375d90f6edd Mon Sep 17 00:00:00 2001 From: matthewswspence Date: Fri, 14 Mar 2025 15:58:05 -0500 Subject: [PATCH] add new fields to admin and refactor a bit --- src/registrar/admin.py | 76 ++++++++++++++++++- src/registrar/forms/feb.py | 18 ++--- src/registrar/models/domain_request.py | 24 ++++-- .../portfolio_request_review_steps.html | 4 +- src/registrar/tests/test_admin_request.py | 4 +- 5 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 09d0eaa81..98b833f5f 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -2535,6 +2535,40 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): portfolio_urbanization.short_description = "Urbanization" # type: ignore + # ------ FEB fields ------ + def feb_naming_requirements_details(self, obj): + return obj.feb_naming_requirements_details if obj.feb_naming_requirements else "" + + feb_naming_requirements_details.short_description = "Domain Name Rationale:" # type: ignore + + def feb_purpose_choice(self, obj): + return obj.feb_purpose_choice if obj.feb_purpose_choice else "" + + feb_purpose_choice.short_description = "Purpose type:" # type: ignore + + def time_frame_details(self, obj): + return obj.time_frame_details if obj.has_timeframe else "" + + time_frame_details.short_description = "Target time frame:" # type: ignore + + def interagency_initiative_details(self, obj): + return obj.interagency_initiative_details if obj.is_interagency_initiative else "" + + interagency_initiative_details.short_description = "Interagency Initiative:" # type: ignore + + def eop_stakeholder_first_name(self, obj): + return obj.eop_stakeholder_first_name if obj.eop_stakeholder_first_name else "" + + def eop_stakeholder_last_name(self, obj): + return obj.eop_stakeholder_last_name if obj.eop_stakeholder_last_name else "" + + def eop_stakeholder_email(self, obj): + return obj.eop_stakeholder_email if obj.eop_stakeholder_email else "" + + eop_stakeholder_first_name.short_description = "EOP Stakeholder First Name" # type: ignore + eop_stakeholder_last_name.short_description = "EOP Stakeholder Last Name" # type: ignore + eop_stakeholder_email.short_description = "EOP Stakeholder Email" # type: ignore + # This is just a placeholder. This field will be populated in the detail_table_fieldset view. # This is not a field that exists on the model. def status_history(self, obj): @@ -2615,7 +2649,16 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): ] }, ), - (".gov domain", {"fields": ["requested_domain", "alternative_domains"]}), + ( + ".gov domain", + { + "fields": [ + "requested_domain", + "alternative_domains", + "feb_naming_requirements_details", + ] + }, + ), ( "Contacts", { @@ -2627,10 +2670,25 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "cisa_representative_first_name", "cisa_representative_last_name", "cisa_representative_email", + "eop_stakeholder_first_name", + "eop_stakeholder_last_name", + "eop_stakeholder_email", + ] + }, + ), + ( + "Background info", + { + "fields": [ + "feb_purpose_choice", + "purpose", + "time_frame_details", + "interagency_initiative_details", + "anything_else", + "current_websites", ] }, ), - ("Background info", {"fields": ["purpose", "anything_else", "current_websites"]}), ( "Type of organization", { @@ -2781,6 +2839,20 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "suborganization_city", "suborganization_state_territory", ] + # Hide FEB fields behind the organization requests flag + # and only show them if the portfolio is executive + if not (obj and obj.portfolio and obj.portfolio.federal_type == BranchChoices.EXECUTIVE): + excluded_fields.extend([ + "feb_naming_requirements_details", + "feb_purpose_choice", + "time_frame_details", + "interagency_initiative_details", + "eop_stakeholder_first_name", + "eop_stakeholder_last_name", + "eop_stakeholder_email", + ]) + # This makes .gov domain collapsable underneath Requested By + fieldsets[2][1]["classes"] = ["collapse--dgfieldset"] modified_fieldsets = [] for name, data in fieldsets: fields = data.get("fields", []) diff --git a/src/registrar/forms/feb.py b/src/registrar/forms/feb.py index 05b2acf3f..339151c71 100644 --- a/src/registrar/forms/feb.py +++ b/src/registrar/forms/feb.py @@ -147,8 +147,6 @@ class EOPContactForm(BaseDeletableRegistrarForm): Executive Branch (FEB) agency is working with. """ - field_name = "eop_contact" - first_name = forms.CharField( label="First name / given name", error_messages={"required": "Enter the first name / given name of this contact."}, @@ -178,12 +176,10 @@ class EOPContactForm(BaseDeletableRegistrarForm): @classmethod def from_database(cls, obj): - if not obj.eop_contact: - return {} return { - "first_name": obj.eop_contact.first_name, - "last_name": obj.eop_contact.last_name, - "email": obj.eop_contact.email, + "first_name": obj.eop_stakeholder_first_name, + "last_name": obj.eop_stakeholder_last_name, + "email": obj.eop_stakeholder_email, } def to_database(self, obj): @@ -195,11 +191,9 @@ class EOPContactForm(BaseDeletableRegistrarForm): return if not self.is_valid(): return - obj.eop_contact = Contact.objects.create( - first_name=self.cleaned_data["first_name"], - last_name=self.cleaned_data["last_name"], - email=self.cleaned_data["email"], - ) + obj.eop_stakeholder_first_name = self.cleaned_data["first_name"] + obj.eop_stakeholder_last_name = self.cleaned_data["last_name"] + obj.eop_stakeholder_email = self.cleaned_data["email"] obj.save() diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index f80ab08d0..28079b1e1 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -515,12 +515,15 @@ class DomainRequest(TimeStampedModel): feb_naming_requirements_details = models.TextField( null=True, blank=True, + help_text="Required if requested domain that doesn't meet naming requirements", + verbose_name="Domain name rationale", ) feb_purpose_choice = models.CharField( null=True, blank=True, choices=FEBPurposeChoices.choices, + verbose_name="Purpose type", ) working_with_eop = models.BooleanField( @@ -528,17 +531,26 @@ class DomainRequest(TimeStampedModel): blank=True, ) - eop_contact = models.ForeignKey( - "registrar.Contact", + eop_stakeholder_first_name = models.CharField( null=True, blank=True, - related_name="eop_contact", - on_delete=models.PROTECT, + verbose_name="EOP Stakeholder First Name", + ) + + eop_stakeholder_last_name = models.CharField( + null=True, + blank=True, + verbose_name="EOP Stakeholder Last Name", + ) + + eop_stakeholder_email = models.EmailField( + null=True, + blank=True, + verbose_name="EOP Stakeholder Email", ) # This field is alternately used for generic domain purpose explanations # and for explanations of the specific purpose chosen with feb_purpose_choice - # by a Federal Executive Branch agency. purpose = models.TextField( null=True, blank=True, @@ -552,6 +564,7 @@ class DomainRequest(TimeStampedModel): time_frame_details = models.TextField( null=True, blank=True, + verbose_name="Target time frame", ) is_interagency_initiative = models.BooleanField( @@ -562,6 +575,7 @@ class DomainRequest(TimeStampedModel): interagency_initiative_details = models.TextField( null=True, blank=True, + verbose_name="Interagency initiative", ) alternative_domains = models.ManyToManyField( diff --git a/src/registrar/templates/includes/portfolio_request_review_steps.html b/src/registrar/templates/includes/portfolio_request_review_steps.html index 2a255b532..3a3c29ee2 100644 --- a/src/registrar/templates/includes/portfolio_request_review_steps.html +++ b/src/registrar/templates/includes/portfolio_request_review_steps.html @@ -110,8 +110,8 @@ {% if domain_request.working_with_eop is None %}

Incomplete

{% elif domain_request.working_with_eop %} -

{{domain_request.eop_contact.first_name}} {{domain_request.eop_contact.last_name}}

-

{{domain_request.eop_contact.email}}

+

{{domain_request.eop_stakeholder_first_name}} {{domain_request.eop_stakeholder_last_name}}

+

{{domain_request.eop_stakeholder_email}}

{% else %}

No

{% endif %} diff --git a/src/registrar/tests/test_admin_request.py b/src/registrar/tests/test_admin_request.py index 7bc150326..b7d9b7e81 100644 --- a/src/registrar/tests/test_admin_request.py +++ b/src/registrar/tests/test_admin_request.py @@ -1985,7 +1985,9 @@ class TestDomainRequestAdmin(MockEppLib): "feb_naming_requirements_details", "feb_purpose_choice", "working_with_eop", - "eop_contact", + "eop_stakeholder_first_name", + "eop_stakeholder_last_name", + "eop_stakeholder_email", "purpose", "has_timeframe", "time_frame_details",