Repository: cisagov/manage.get.gov

Issue:
Domain Application admin page limit options on the drop down
### Story

As an analyst
I want to click the status drop down on the Domain Application section and only see the statuses that are allowed by the django FSM. 
so that I don't get an error message when changing states


### Acceptance Criteria

using the django admin dropdown for status under Domain Application should match the [status document](https://docs.google.com/document/d/1no29E2c9QWIHf_2wv3GCy6AotZ2_PVbIBiavKW-opxE/edit#heading=h.3as4poj)
no unallowed status show

### Additional Context

_No response_

### Issue Links

_No response_


Discussion:

Resolving patch:
diff --git a/src/registrar/admin.py b/src/registrar/admin.py
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -1,4 +1,6 @@
 import logging
+from django import forms
+from django_fsm import get_available_FIELD_transitions
 from django.contrib import admin, messages
 from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
 from django.contrib.contenttypes.models import ContentType
@@ -252,6 +254,37 @@ class ContactAdmin(ListHeaderAdmin):
     search_help_text = "Search by firstname, lastname or email."
 
 
+class DomainApplicationAdminForm(forms.ModelForm):
+    """Custom form to limit transitions to available transitions"""
+
+    class Meta:
+        model = models.DomainApplication
+        fields = "__all__"
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        application = kwargs.get("instance")
+        if application and application.pk:
+            current_state = application.status
+
+            # first option in status transitions is current state
+            available_transitions = [(current_state, current_state)]
+
+            transitions = get_available_FIELD_transitions(
+                application, models.DomainApplication._meta.get_field("status")
+            )
+
+            for transition in transitions:
+                available_transitions.append((transition.target, transition.target))
+
+            # only set the available transitions if the user is not restricted
+            # from editing the domain application; otherwise, the form will be
+            # readonly and the status field will not have a widget
+            if not application.creator.is_restricted():
+                self.fields["status"].widget.choices = available_transitions
+
+
 class DomainApplicationAdmin(ListHeaderAdmin):
 
     """Customize the applications listing view."""
@@ -283,6 +316,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
     search_help_text = "Search by domain or submitter."
 
     # Detail view
+    form = DomainApplicationAdminForm
     fieldsets = [
         (None, {"fields": ["status", "investigator", "creator"]}),
         (


Test patch:
diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py
--- a/src/registrar/tests/test_admin.py
+++ b/src/registrar/tests/test_admin.py
@@ -5,6 +5,7 @@
 from registrar.admin import (
     DomainAdmin,
     DomainApplicationAdmin,
+    DomainApplicationAdminForm,
     ListHeaderAdmin,
     MyUserAdmin,
     AuditedAdmin,
@@ -92,6 +93,48 @@ def tearDown(self):
         User.objects.all().delete()
 
 
+class TestDomainApplicationAdminForm(TestCase):
+    def setUp(self):
+        # Create a test application with an initial state of started
+        self.application = completed_application()
+
+    def test_form_choices(self):
+        # Create a form instance with the test application
+        form = DomainApplicationAdminForm(instance=self.application)
+
+        # Verify that the form choices match the available transitions for started
+        expected_choices = [("started", "started"), ("submitted", "submitted")]
+        self.assertEqual(form.fields["status"].widget.choices, expected_choices)
+
+    def test_form_choices_when_no_instance(self):
+        # Create a form instance without an instance
+        form = DomainApplicationAdminForm()
+
+        # Verify that the form choices show all choices when no instance is provided;
+        # this is necessary to show all choices when creating a new domain
+        # application in django admin;
+        # note that FSM ensures that no domain application exists with invalid status,
+        # so don't need to test for invalid status
+        self.assertEqual(
+            form.fields["status"].widget.choices,
+            DomainApplication._meta.get_field("status").choices,
+        )
+
+    def test_form_choices_when_ineligible(self):
+        # Create a form instance with a domain application with ineligible status
+        ineligible_application = DomainApplication(status="ineligible")
+
+        # Attempt to create a form with the ineligible application
+        # The form should not raise an error, but choices should be the
+        # full list of possible choices
+        form = DomainApplicationAdminForm(instance=ineligible_application)
+
+        self.assertEqual(
+            form.fields["status"].widget.choices,
+            DomainApplication._meta.get_field("status").choices,
+        )
+
+
 class TestDomainApplicationAdmin(TestCase):
     def setUp(self):
         self.site = AdminSite()