diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 59c0e83a9..782b59eb0 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1,6 +1,7 @@ from datetime import date import logging import copy +from typing import Optional from django import forms from django.db.models import Value, CharField, Q from django.db.models.functions import Concat, Coalesce @@ -1728,6 +1729,42 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): custom_election_board.admin_order_field = "is_election_board" # type: ignore custom_election_board.short_description = "Election office" # type: ignore + + # Define methods to display fields from the related portfolio + def portfolio_senior_official(self, obj) -> Optional[SeniorOfficial]: + return obj.portfolio.senior_official if obj.portfolio and obj.portfolio.senior_official else None + portfolio_senior_official.short_description = "Senior official" + def portfolio_organization_type(self, obj): + return obj.portfolio.organization_type if obj.portfolio else "" + portfolio_organization_type.short_description = "Organization type" + def portfolio_federal_type(self, obj): + return BranchChoices.get_branch_label(obj.portfolio.federal_type) if obj.portfolio and obj.portfolio.federal_type else "-" + portfolio_federal_type.short_description = "Federal type" + def portfolio_organization_name(self, obj): + return obj.portfolio.organization_name if obj.portfolio else "" + portfolio_organization_name.short_description = "Organization name" + def portfolio_federal_agency(self, obj): + return obj.portfolio.federal_agency if obj.portfolio else "" + portfolio_federal_agency.short_description = "Federal agency" + def portfolio_state_territory(self, obj): + return obj.portfolio.state_territory if obj.portfolio else "" + portfolio_state_territory.short_description = "State, territory, or military post" + def portfolio_address_line1(self, obj): + return obj.portfolio.address_line1 if obj.portfolio else "" + portfolio_address_line1.short_description = "Address line 1" + def portfolio_address_line2(self, obj): + return obj.portfolio.address_line2 if obj.portfolio else "" + portfolio_address_line2.short_description = "Address line 2" + def portfolio_city(self, obj): + return obj.portfolio.city if obj.portfolio else "" + portfolio_city.short_description = "City" + def portfolio_zipcode(self, obj): + return obj.portfolio.zipcode if obj.portfolio else "" + portfolio_zipcode.short_description = "Zip code" + def portfolio_urbanization(self, obj): + return obj.portfolio.urbanization if obj.portfolio else "" + portfolio_urbanization.short_description = "Urbanization" + # 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): @@ -1790,6 +1827,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): { "fields": [ "senior_official", + "portfolio_senior_official", "other_contacts", "no_other_contacts_rationale", "cisa_representative_first_name", @@ -1846,10 +1884,55 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): ], }, ), + # the below three sections are for portfolio fields + ( + "Type of organization", + { + "fields": [ + "portfolio_organization_type", + "portfolio_federal_type", + ] + } + ), + ( + "Organization name and mailing address", + { + "fields": [ + "portfolio_organization_name", + "portfolio_federal_agency", + ] + }, + ), + ( + "Show details", + { + "classes": ["collapse--dgfieldset"], + "description": "Extends organization name and mailing address", + "fields": [ + "portfolio_state_territory", + "portfolio_address_line1", + "portfolio_address_line2", + "portfolio_city", + "portfolio_zipcode", + "portfolio_urbanization", + ], + }, + ), ] # Readonly fields for analysts and superusers readonly_fields = ( + "portfolio_senior_official", + "portfolio_organization_type", + "portfolio_federal_type", + "portfolio_organization_name", + "portfolio_federal_agency", + "portfolio_state_territory", + "portfolio_address_line1", + "portfolio_address_line2", + "portfolio_city", + "portfolio_zipcode", + "portfolio_urbanization", "other_contacts", "current_websites", "alternative_domains", diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 3bd7e0163..8efab10d0 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -86,6 +86,68 @@ function handleSuborganizationFields( portfolioDropdown.on("change", toggleSuborganizationFields); } +function handlePortfolioSelection() { + // These dropdown are select2 fields so they must be interacted with via jquery + const portfolioDropdown = django.jQuery("#id_portfolio"); + const suborganizationDropdown = django.jQuery("#id_sub_organization"); + const suborganizationField = document.querySelector(".field-sub_organization"); + const seniorOfficialField = document.querySelector(".field-senior_official"); + const portfolioSeniorOfficialField = document.querySelector(".field-portfolio_senior_official"); + const otherEmployeesField = document.querySelector(".field-other_contacts"); + const noOtherContactsRationaleField = document.querySelector(".field-no_other_contacts_rationale"); + const cisaRepresentativeFirstNameField = document.querySelector(".field-cisa_representative_first_name"); + const cisaRepresentativeLastNameField = document.querySelector(".field-cisa_representative_last_name"); + const cisaRepresentativeEmailField = document.querySelector(".field-cisa_representative_email"); + const orgTypeFieldSet = document.querySelector(".field-is_election_board").parentElement; + const orgTypeFieldSetDetails = orgTypeFieldSet.nextElementSibling; + const orgNameFieldSet = document.querySelector(".field-organization_name").parentElement; + const orgNameFieldSetDetails = orgNameFieldSet.nextElementSibling; + const portfolioOrgTypeFieldSet = document.querySelector(".field-portfolio_organization_type").parentElement; + const portfolioOrgNameFieldSet = document.querySelector(".field-portfolio_organization_name").parentElement; + const portfolioOrgNameFieldSetDetails = portfolioOrgNameFieldSet.nextElementSibling; + + + function toggleSuborganizationFields() { + if (portfolioDropdown.val()) { + showElement(suborganizationField); + hideElement(seniorOfficialField); + showElement(portfolioSeniorOfficialField); + hideElement(otherEmployeesField); + hideElement(noOtherContactsRationaleField); + hideElement(cisaRepresentativeFirstNameField); + hideElement(cisaRepresentativeLastNameField); + hideElement(cisaRepresentativeEmailField); + hideElement(orgTypeFieldSet); + hideElement(orgTypeFieldSetDetails); + hideElement(orgNameFieldSet); + hideElement(orgNameFieldSetDetails); + showElement(portfolioOrgTypeFieldSet); + showElement(portfolioOrgNameFieldSet); + showElement(portfolioOrgNameFieldSetDetails); + }else { + hideElement(suborganizationField); + showElement(seniorOfficialField); + hideElement(portfolioSeniorOfficialField); + showElement(otherEmployeesField); + showElement(noOtherContactsRationaleField); + showElement(cisaRepresentativeFirstNameField); + showElement(cisaRepresentativeLastNameField); + showElement(cisaRepresentativeEmailField); + showElement(orgTypeFieldSet); + showElement(orgTypeFieldSetDetails); + showElement(orgNameFieldSet); + showElement(orgNameFieldSetDetails); + hideElement(portfolioOrgTypeFieldSet); + hideElement(portfolioOrgNameFieldSet); + hideElement(portfolioOrgNameFieldSetDetails); + } + } + + // Run the function once on page startup, then attach an event listener + toggleSuborganizationFields(); + portfolioDropdown.on("change", toggleSuborganizationFields); +} + // <<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>> // Initialization code. @@ -1181,7 +1243,7 @@ document.addEventListener('DOMContentLoaded', function() { updateSeniorOfficialDropdown($seniorOfficial, seniorOfficialId, seniorOfficialName); }else { if (readonlySeniorOfficial) { - let seniorOfficialLink = `${seniorOfficialName}` + let seniorOfficialLink = `${seniorOfficialName}` readonlySeniorOfficial.innerHTML = seniorOfficialName ? seniorOfficialLink : "-"; } } @@ -1276,6 +1338,7 @@ document.addEventListener('DOMContentLoaded', function() { const domainRequestPage = document.getElementById("domainrequest_form"); if (domainRequestPage) { handleSuborganizationFields(); + handlePortfolioSelection(); } })(); diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 317604c5e..a73a4d5e6 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -66,6 +66,10 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) No changelog to display. {% endif %} + {% elif field.field.name == "portfolio_senior_official" %} + {% if original_object.portfolio.senior_official %} +
{{ field.contents }}
+ {% endif %} {% elif field.field.name == "other_contacts" %} {% if all_contacts.count > 2 %}
@@ -332,6 +336,11 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {% include "django/admin/includes/contact_detail_list.html" with user=original_object.senior_official no_title_top_padding=field.is_readonly %}
+ {% elif field.field.name == "portfolio_senior_official" %} +
+ + {% include "django/admin/includes/contact_detail_list.html" with user=original_object.portfolio.senior_official no_title_top_padding=field.is_readonly %} +
{% elif field.field.name == "other_contacts" and original_object.other_contacts.all %} {% with all_contacts=original_object.other_contacts.all %} {% if all_contacts.count > 2 %}