{% if not has_domain_requests_portfolio_permission %}
diff --git a/src/registrar/templates/includes/domains_table.html b/src/registrar/templates/includes/domains_table.html
index 4f0e20bde..73331c3f0 100644
--- a/src/registrar/templates/includes/domains_table.html
+++ b/src/registrar/templates/includes/domains_table.html
@@ -1,5 +1,10 @@
{% load static %}
+
+
+{% comment %} Stores the json endpoint in a url for easier access {% endcomment %}
+{% url 'get_domains_json' as url %}
+
{% if not has_domains_portfolio_permission %}
diff --git a/src/registrar/tests/test_api.py b/src/registrar/tests/test_api.py
new file mode 100644
index 000000000..0025bc902
--- /dev/null
+++ b/src/registrar/tests/test_api.py
@@ -0,0 +1,67 @@
+from django.urls import reverse
+from django.test import TestCase, Client
+from registrar.models import FederalAgency, SeniorOfficial, User
+from django.contrib.auth import get_user_model
+from registrar.tests.common import create_superuser, create_user
+
+
+class GetSeniorOfficialJsonTest(TestCase):
+ def setUp(self):
+ self.client = Client()
+ p = "password"
+ self.user = get_user_model().objects.create_user(username="testuser", password=p)
+
+ self.superuser = create_superuser()
+ self.analyst_user = create_user()
+
+ self.agency = FederalAgency.objects.create(agency="Test Agency")
+ self.senior_official = SeniorOfficial.objects.create(
+ first_name="John", last_name="Doe", title="Director", federal_agency=self.agency
+ )
+
+ self.api_url = reverse("get-senior-official-from-federal-agency-json")
+
+ def tearDown(self):
+ User.objects.all().delete()
+ SeniorOfficial.objects.all().delete()
+ FederalAgency.objects.all().delete()
+
+ def test_get_senior_official_json_authenticated_superuser(self):
+ """Test that a superuser can fetch the senior official information."""
+ p = "adminpass"
+ self.client.login(username="superuser", password=p)
+ response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
+ self.assertEqual(response.status_code, 200)
+ data = response.json()
+ self.assertEqual(data["id"], self.senior_official.id)
+ self.assertEqual(data["first_name"], "John")
+ self.assertEqual(data["last_name"], "Doe")
+ self.assertEqual(data["title"], "Director")
+
+ def test_get_senior_official_json_authenticated_analyst(self):
+ """Test that an analyst user can fetch the senior official's information."""
+ p = "userpass"
+ self.client.login(username="staffuser", password=p)
+ response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
+ self.assertEqual(response.status_code, 200)
+ data = response.json()
+ self.assertEqual(data["id"], self.senior_official.id)
+ self.assertEqual(data["first_name"], "John")
+ self.assertEqual(data["last_name"], "Doe")
+ self.assertEqual(data["title"], "Director")
+
+ def test_get_senior_official_json_unauthenticated(self):
+ """Test that an unauthenticated user receives a 403 with an error message."""
+ p = "password"
+ self.client.login(username="testuser", password=p)
+ response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
+ self.assertEqual(response.status_code, 302)
+
+ def test_get_senior_official_json_not_found(self):
+ """Test that a request for a non-existent agency returns a 404 with an error message."""
+ p = "adminpass"
+ self.client.login(username="superuser", password=p)
+ response = self.client.get(self.api_url, {"agency_name": "Non-Federal Agency"})
+ self.assertEqual(response.status_code, 404)
+ data = response.json()
+ self.assertEqual(data["error"], "Senior Official not found")
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index 5167aac99..f4e998fff 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -2266,3 +2266,57 @@ class TestDomainRequestIncomplete(TestCase):
self.domain_request.generic_org_type = None
self.domain_request.save()
self.assertFalse(self.domain_request._form_complete(request))
+
+
+class TestPortfolio(TestCase):
+ def setUp(self):
+ self.user, _ = User.objects.get_or_create(
+ username="intern@igorville.com", email="intern@igorville.com", first_name="Lava", last_name="World"
+ )
+ super().setUp()
+
+ def tearDown(self):
+ super().tearDown()
+ Portfolio.objects.all().delete()
+ User.objects.all().delete()
+
+ def test_urbanization_field_resets_when_not_puetro_rico(self):
+ """The urbanization field should only be populated when the state is puetro rico.
+ Otherwise, this field should be empty."""
+ # Start out as PR, then change the field
+ portfolio = Portfolio.objects.create(
+ creator=self.user,
+ organization_name="Test Portfolio",
+ state_territory=DomainRequest.StateTerritoryChoices.PUERTO_RICO,
+ urbanization="test",
+ )
+
+ self.assertEqual(portfolio.urbanization, "test")
+ self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
+
+ portfolio.state_territory = DomainRequest.StateTerritoryChoices.ALABAMA
+ portfolio.save()
+
+ self.assertEqual(portfolio.urbanization, None)
+ self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
+
+ def test_can_add_urbanization_field(self):
+ """Ensures that you can populate the urbanization field when conditions are right"""
+ # Create a portfolio that cannot have this field
+ portfolio = Portfolio.objects.create(
+ creator=self.user,
+ organization_name="Test Portfolio",
+ state_territory=DomainRequest.StateTerritoryChoices.ALABAMA,
+ urbanization="test",
+ )
+
+ # Implicitly check if this gets cleared on create. It should.
+ self.assertEqual(portfolio.urbanization, None)
+ self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
+
+ portfolio.state_territory = DomainRequest.StateTerritoryChoices.PUERTO_RICO
+ portfolio.urbanization = "test123"
+ portfolio.save()
+
+ self.assertEqual(portfolio.urbanization, "test123")
+ self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
diff --git a/src/registrar/views/utility/__init__.py b/src/registrar/views/utility/__init__.py
index 7299c0368..7219f4358 100644
--- a/src/registrar/views/utility/__init__.py
+++ b/src/registrar/views/utility/__init__.py
@@ -8,3 +8,4 @@ from .permission_views import (
DomainInvitationPermissionDeleteView,
DomainRequestWizardPermissionView,
)
+from .api_views import get_senior_official_from_federal_agency_json
diff --git a/src/registrar/views/utility/api_views.py b/src/registrar/views/utility/api_views.py
new file mode 100644
index 000000000..2c9414d1d
--- /dev/null
+++ b/src/registrar/views/utility/api_views.py
@@ -0,0 +1,36 @@
+import logging
+from django.http import JsonResponse
+from django.forms.models import model_to_dict
+from registrar.models import FederalAgency, SeniorOfficial
+from django.contrib.admin.views.decorators import staff_member_required
+from django.contrib.auth.decorators import login_required
+
+logger = logging.getLogger(__name__)
+
+
+@login_required
+@staff_member_required
+def get_senior_official_from_federal_agency_json(request):
+ """Returns federal_agency information as a JSON"""
+
+ # This API is only accessible to admins and analysts
+ superuser_perm = request.user.has_perm("registrar.full_access_permission")
+ analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
+ if not request.user.is_authenticated or not any([analyst_perm, superuser_perm]):
+ return JsonResponse({"error": "You do not have access to this resource"}, status=403)
+
+ agency_name = request.GET.get("agency_name")
+ agency = FederalAgency.objects.filter(agency=agency_name).first()
+ senior_official = SeniorOfficial.objects.filter(federal_agency=agency).first()
+ if agency and senior_official:
+ # Convert the agency object to a dictionary
+ so_dict = model_to_dict(senior_official)
+
+ # The phone number field isn't json serializable, so we
+ # convert this to a string first if it exists.
+ if "phone" in so_dict and so_dict.get("phone"):
+ so_dict["phone"] = str(so_dict["phone"])
+
+ return JsonResponse(so_dict)
+ else:
+ return JsonResponse({"error": "Senior Official not found"}, status=404)