diff --git a/docs/operations/data_migration.md b/docs/operations/data_migration.md
index cd748b22d..5914eb179 100644
--- a/docs/operations/data_migration.md
+++ b/docs/operations/data_migration.md
@@ -816,3 +816,25 @@ Example: `cf ssh getgov-za`
| | Parameter | Description |
|:-:|:-------------------------- |:-----------------------------------------------------------------------------------|
| 1 | **federal_cio_csv_path** | Specifies where the federal CIO csv is |
+
+## Populate Domain Request Dates
+This section outlines how to run the populate_domain_request_dates script
+
+### Running on sandboxes
+
+#### Step 1: Login to CloudFoundry
+```cf login -a api.fr.cloud.gov --sso```
+
+#### Step 2: SSH into your environment
+```cf ssh getgov-{space}```
+
+Example: `cf ssh getgov-za`
+
+#### Step 3: Create a shell instance
+```/tmp/lifecycle/shell```
+
+#### Step 4: Running the script
+```./manage.py populate_domain_request_dates```
+
+### Running locally
+```docker-compose exec app ./manage.py populate_domain_request_dates```
diff --git a/src/registrar/admin.py b/src/registrar/admin.py
index b2c41c07f..11a41a22d 100644
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -1698,7 +1698,9 @@ def queryset(self, request, queryset):
# Columns
list_display = [
"requested_domain",
- "submission_date",
+ "first_submitted_date",
+ "last_submitted_date",
+ "last_status_update",
"status",
"generic_org_type",
"federal_type",
@@ -1901,7 +1903,7 @@ def get_fieldsets(self, request, obj=None):
# Table ordering
# NOTE: This impacts the select2 dropdowns (combobox)
# Currentl, there's only one for requests on DomainInfo
- ordering = ["-submission_date", "requested_domain__name"]
+ ordering = ["-last_submitted_date", "requested_domain__name"]
change_form_template = "django/admin/domain_request_change_form.html"
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index f3b41eb51..70659b009 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -1599,7 +1599,7 @@ document.addEventListener('DOMContentLoaded', function() {
const domainName = request.requested_domain ? request.requested_domain : `New domain request
(${utcDateString(request.created_at)})`;
const actionUrl = request.action_url;
const actionLabel = request.action_label;
- const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString('en-US', options) : `Not submitted`;
+ const submissionDate = request.last_submitted_date ? new Date(request.last_submitted_date).toLocaleDateString('en-US', options) : `Not submitted`;
// Even if the request is not deletable, we may need this empty string for the td if the deletable column is displayed
let modalTrigger = '';
@@ -1699,7 +1699,7 @@ document.addEventListener('DOMContentLoaded', function() {
${domainName}
|
-
+ |
${submissionDate}
|
diff --git a/src/registrar/fixtures_domain_requests.py b/src/registrar/fixtures_domain_requests.py
index 50f611474..a5ec3fc74 100644
--- a/src/registrar/fixtures_domain_requests.py
+++ b/src/registrar/fixtures_domain_requests.py
@@ -95,7 +95,7 @@ def _set_non_foreign_key_fields(cls, da: DomainRequest, app: dict):
# TODO for a future ticket: Allow for more than just "federal" here
da.generic_org_type = app["generic_org_type"] if "generic_org_type" in app else "federal"
- da.submission_date = fake.date()
+ da.last_submitted_date = fake.date()
da.federal_type = (
app["federal_type"]
if "federal_type" in app
diff --git a/src/registrar/management/commands/populate_domain_request_dates.py b/src/registrar/management/commands/populate_domain_request_dates.py
new file mode 100644
index 000000000..d975a035d
--- /dev/null
+++ b/src/registrar/management/commands/populate_domain_request_dates.py
@@ -0,0 +1,45 @@
+import logging
+from django.core.management import BaseCommand
+from registrar.management.commands.utility.terminal_helper import PopulateScriptTemplate, TerminalColors
+from registrar.models import DomainRequest
+from auditlog.models import LogEntry
+
+logger = logging.getLogger(__name__)
+
+
+class Command(BaseCommand, PopulateScriptTemplate):
+ help = "Loops through each domain request object and populates the last_status_update and first_submitted_date"
+
+ def handle(self, **kwargs):
+ """Loops through each DomainRequest object and populates
+ its last_status_update and first_submitted_date values"""
+ self.mass_update_records(DomainRequest, None, ["last_status_update", "first_submitted_date"])
+
+ def update_record(self, record: DomainRequest):
+ """Defines how we update the first_submitted_date and last_status_update fields"""
+
+ # Retrieve and order audit log entries by timestamp in descending order
+ audit_log_entries = LogEntry.objects.filter(object_pk=record.pk).order_by("-timestamp")
+ # Loop through logs in descending order to find most recent status change
+ for log_entry in audit_log_entries:
+ if "status" in log_entry.changes_dict:
+ record.last_status_update = log_entry.timestamp.date()
+ break
+
+ # Loop through logs in ascending order to find first submission
+ for log_entry in audit_log_entries.reverse():
+ status = log_entry.changes_dict.get("status")
+ if status and status[1] == "submitted":
+ record.first_submitted_date = log_entry.timestamp.date()
+ break
+
+ logger.info(
+ f"""{TerminalColors.OKCYAN}Updating {record} =>
+ first submitted date: {record.first_submitted_date},
+ last status update: {record.last_status_update}{TerminalColors.ENDC}
+ """
+ )
+
+ def should_skip_record(self, record) -> bool:
+ # make sure the record had some kind of history
+ return not LogEntry.objects.filter(object_pk=record.pk).exists()
diff --git a/src/registrar/management/commands/utility/terminal_helper.py b/src/registrar/management/commands/utility/terminal_helper.py
index 2c69e1080..b9e11be5d 100644
--- a/src/registrar/management/commands/utility/terminal_helper.py
+++ b/src/registrar/management/commands/utility/terminal_helper.py
@@ -86,7 +86,7 @@ def mass_update_records(self, object_class, filter_conditions, fields_to_update,
You must define update_record before you can use this function.
"""
- records = object_class.objects.filter(**filter_conditions)
+ records = object_class.objects.filter(**filter_conditions) if filter_conditions else object_class.objects.all()
readable_class_name = self.get_class_name(object_class)
# Code execution will stop here if the user prompts "N"
diff --git a/src/registrar/migrations/0120_add_domainrequest_submission_dates.py b/src/registrar/migrations/0120_add_domainrequest_submission_dates.py
new file mode 100644
index 000000000..df409cf39
--- /dev/null
+++ b/src/registrar/migrations/0120_add_domainrequest_submission_dates.py
@@ -0,0 +1,47 @@
+# Generated by Django 4.2.10 on 2024-08-16 15:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("registrar", "0119_remove_user_portfolio_and_more"),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name="domainrequest",
+ old_name="submission_date",
+ new_name="last_submitted_date",
+ ),
+ migrations.AlterField(
+ model_name="domainrequest",
+ name="last_submitted_date",
+ field=models.DateField(
+ blank=True, default=None, help_text="Date last submitted", null=True, verbose_name="last submitted on"
+ ),
+ ),
+ migrations.AddField(
+ model_name="domainrequest",
+ name="first_submitted_date",
+ field=models.DateField(
+ blank=True,
+ default=None,
+ help_text="Date initially submitted",
+ null=True,
+ verbose_name="first submitted on",
+ ),
+ ),
+ migrations.AddField(
+ model_name="domainrequest",
+ name="last_status_update",
+ field=models.DateField(
+ blank=True,
+ default=None,
+ help_text="Date of the last status update",
+ null=True,
+ verbose_name="last updated on",
+ ),
+ ),
+ ]
diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py
index 966c880d7..7ee80e43a 100644
--- a/src/registrar/models/domain_request.py
+++ b/src/registrar/models/domain_request.py
@@ -563,15 +563,32 @@ def get_action_needed_reason_label(cls, action_needed_reason: str):
help_text="Acknowledged .gov acceptable use policy",
)
- # submission date records when domain request is submitted
- submission_date = models.DateField(
+ # Records when the domain request was first submitted
+ first_submitted_date = models.DateField(
null=True,
blank=True,
default=None,
- verbose_name="submitted at",
- help_text="Date submitted",
+ verbose_name="first submitted on",
+ help_text="Date initially submitted",
)
+ # Records when domain request was last submitted
+ last_submitted_date = models.DateField(
+ null=True,
+ blank=True,
+ default=None,
+ verbose_name="last submitted on",
+ help_text="Date last submitted",
+ )
+
+ # Records when domain request status was last updated by an admin or analyst
+ last_status_update = models.DateField(
+ null=True,
+ blank=True,
+ default=None,
+ verbose_name="last updated on",
+ help_text="Date of the last status update",
+ )
notes = models.TextField(
null=True,
blank=True,
@@ -621,6 +638,9 @@ def save(self, *args, **kwargs):
self.sync_organization_type()
self.sync_yes_no_form_fields()
+ if self._cached_status != self.status:
+ self.last_status_update = timezone.now().date()
+
super().save(*args, **kwargs)
# Handle the action needed email.
@@ -803,8 +823,12 @@ def submit(self):
if not DraftDomain.string_could_be_domain(self.requested_domain.name):
raise ValueError("Requested domain is not a valid domain name.")
- # Update submission_date to today
- self.submission_date = timezone.now().date()
+ # if the domain has not been submitted before this must be the first time
+ if not self.first_submitted_date:
+ self.first_submitted_date = timezone.now().date()
+
+ # Update last_submitted_date to today
+ self.last_submitted_date = timezone.now().date()
self.save()
# Limit email notifications to transitions from Started and Withdrawn
diff --git a/src/registrar/templates/emails/action_needed_reasons/already_has_domains.txt b/src/registrar/templates/emails/action_needed_reasons/already_has_domains.txt
index b1b3b0a1c..2e3012c91 100644
--- a/src/registrar/templates/emails/action_needed_reasons/already_has_domains.txt
+++ b/src/registrar/templates/emails/action_needed_reasons/already_has_domains.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/action_needed_reasons/bad_name.txt b/src/registrar/templates/emails/action_needed_reasons/bad_name.txt
index 7d088aa4e..9481a1e63 100644
--- a/src/registrar/templates/emails/action_needed_reasons/bad_name.txt
+++ b/src/registrar/templates/emails/action_needed_reasons/bad_name.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/action_needed_reasons/eligibility_unclear.txt b/src/registrar/templates/emails/action_needed_reasons/eligibility_unclear.txt
index d3a986183..705805998 100644
--- a/src/registrar/templates/emails/action_needed_reasons/eligibility_unclear.txt
+++ b/src/registrar/templates/emails/action_needed_reasons/eligibility_unclear.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/action_needed_reasons/questionable_senior_official.txt b/src/registrar/templates/emails/action_needed_reasons/questionable_senior_official.txt
index e20e4cb60..5967d7089 100644
--- a/src/registrar/templates/emails/action_needed_reasons/questionable_senior_official.txt
+++ b/src/registrar/templates/emails/action_needed_reasons/questionable_senior_official.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Action needed
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/domain_request_withdrawn.txt b/src/registrar/templates/emails/domain_request_withdrawn.txt
index 6efa92d64..0db00feea 100644
--- a/src/registrar/templates/emails/domain_request_withdrawn.txt
+++ b/src/registrar/templates/emails/domain_request_withdrawn.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
Your .gov domain request has been withdrawn and will not be reviewed by our team.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Withdrawn
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/status_change_approved.txt b/src/registrar/templates/emails/status_change_approved.txt
index 70f813599..66f8f8b6c 100644
--- a/src/registrar/templates/emails/status_change_approved.txt
+++ b/src/registrar/templates/emails/status_change_approved.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
Congratulations! Your .gov domain request has been approved.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Approved
You can manage your approved domain on the .gov registrar .
diff --git a/src/registrar/templates/emails/status_change_rejected.txt b/src/registrar/templates/emails/status_change_rejected.txt
index 2fcbb1d83..4e5250162 100644
--- a/src/registrar/templates/emails/status_change_rejected.txt
+++ b/src/registrar/templates/emails/status_change_rejected.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
Your .gov domain request has been rejected.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Rejected
----------------------------------------------------------------
diff --git a/src/registrar/templates/emails/submission_confirmation.txt b/src/registrar/templates/emails/submission_confirmation.txt
index 740e6f393..c8ff4c7eb 100644
--- a/src/registrar/templates/emails/submission_confirmation.txt
+++ b/src/registrar/templates/emails/submission_confirmation.txt
@@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
We received your .gov domain request.
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
-REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
+REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
STATUS: Submitted
----------------------------------------------------------------
diff --git a/src/registrar/templates/includes/domain_requests_table.html b/src/registrar/templates/includes/domain_requests_table.html
index 487c1cee5..bd909350c 100644
--- a/src/registrar/templates/includes/domain_requests_table.html
+++ b/src/registrar/templates/includes/domain_requests_table.html
@@ -45,7 +45,7 @@ Domain requests
Domain name |
- Date submitted |
+ Date submitted |
Status |
Action |
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index f5f62cf3e..bcd45f103 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -777,13 +777,13 @@ def sharedSetUp(cls):
cls.domain_request_3.alternative_domains.add(website, website_2)
cls.domain_request_3.current_websites.add(website_3, website_4)
cls.domain_request_3.cisa_representative_email = "test@igorville.com"
- cls.domain_request_3.submission_date = get_time_aware_date(datetime(2024, 4, 2))
+ cls.domain_request_3.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
cls.domain_request_3.save()
- cls.domain_request_4.submission_date = get_time_aware_date(datetime(2024, 4, 2))
+ cls.domain_request_4.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
cls.domain_request_4.save()
- cls.domain_request_6.submission_date = get_time_aware_date(datetime(2024, 4, 2))
+ cls.domain_request_6.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
cls.domain_request_6.save()
@classmethod
diff --git a/src/registrar/tests/test_admin_request.py b/src/registrar/tests/test_admin_request.py
index 4a828fe42..b1169a9ef 100644
--- a/src/registrar/tests/test_admin_request.py
+++ b/src/registrar/tests/test_admin_request.py
@@ -451,7 +451,7 @@ def test_submitter_sortable(self):
# Assert that our sort works correctly
self.test_helper.assert_table_sorted(
- "11",
+ "13",
(
"submitter__first_name",
"submitter__last_name",
@@ -460,7 +460,7 @@ def test_submitter_sortable(self):
# Assert that sorting in reverse works correctly
self.test_helper.assert_table_sorted(
- "-11",
+ "-13",
(
"-submitter__first_name",
"-submitter__last_name",
@@ -483,7 +483,7 @@ def test_investigator_sortable(self):
# Assert that our sort works correctly
self.test_helper.assert_table_sorted(
- "12",
+ "14",
(
"investigator__first_name",
"investigator__last_name",
@@ -492,7 +492,7 @@ def test_investigator_sortable(self):
# Assert that sorting in reverse works correctly
self.test_helper.assert_table_sorted(
- "-12",
+ "-14",
(
"-investigator__first_name",
"-investigator__last_name",
@@ -505,7 +505,7 @@ def test_investigator_sortable(self):
@less_console_noise_decorator
def test_default_sorting_in_domain_requests_list(self):
"""
- Make sure the default sortin in on the domain requests list page is reverse submission_date
+ Make sure the default sortin in on the domain requests list page is reverse last_submitted_date
then alphabetical requested_domain
"""
@@ -515,12 +515,12 @@ def test_default_sorting_in_domain_requests_list(self):
for name in ["ccc.gov", "bbb.gov", "eee.gov", "aaa.gov", "zzz.gov", "ddd.gov"]
]
- domain_requests[0].submission_date = timezone.make_aware(datetime(2024, 10, 16))
- domain_requests[1].submission_date = timezone.make_aware(datetime(2001, 10, 16))
- domain_requests[2].submission_date = timezone.make_aware(datetime(1980, 10, 16))
- domain_requests[3].submission_date = timezone.make_aware(datetime(1998, 10, 16))
- domain_requests[4].submission_date = timezone.make_aware(datetime(2013, 10, 16))
- domain_requests[5].submission_date = timezone.make_aware(datetime(1980, 10, 16))
+ domain_requests[0].last_submitted_date = timezone.make_aware(datetime(2024, 10, 16))
+ domain_requests[1].last_submitted_date = timezone.make_aware(datetime(2001, 10, 16))
+ domain_requests[2].last_submitted_date = timezone.make_aware(datetime(1980, 10, 16))
+ domain_requests[3].last_submitted_date = timezone.make_aware(datetime(1998, 10, 16))
+ domain_requests[4].last_submitted_date = timezone.make_aware(datetime(2013, 10, 16))
+ domain_requests[5].last_submitted_date = timezone.make_aware(datetime(1980, 10, 16))
# Save the modified domain requests to update their attributes in the database
for domain_request in domain_requests:
@@ -1585,7 +1585,9 @@ def test_readonly_when_restricted_creator(self):
"cisa_representative_last_name",
"has_cisa_representative",
"is_policy_acknowledged",
- "submission_date",
+ "first_submitted_date",
+ "last_submitted_date",
+ "last_status_update",
"notes",
"alternative_domains",
]
diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py
index 8bb15921d..ed2b75791 100644
--- a/src/registrar/tests/test_reports.py
+++ b/src/registrar/tests/test_reports.py
@@ -768,7 +768,7 @@ def test_get_sliced_requests(self):
with less_console_noise():
filter_condition = {
"status": DomainRequest.DomainRequestStatus.SUBMITTED,
- "submission_date__lte": self.end_date,
+ "last_submitted_date__lte": self.end_date,
}
submitted_requests_sliced_at_end_date = DomainRequestExport.get_sliced_requests(filter_condition)
expected_content = [3, 2, 0, 0, 0, 0, 1, 0, 0, 1]
diff --git a/src/registrar/tests/test_views_requests_json.py b/src/registrar/tests/test_views_requests_json.py
index 7bdc922cf..20a4069f7 100644
--- a/src/registrar/tests/test_views_requests_json.py
+++ b/src/registrar/tests/test_views_requests_json.py
@@ -25,91 +25,91 @@ def setUpClass(cls):
DomainRequest.objects.create(
creator=cls.user,
requested_domain=lamb_chops,
- submission_date="2024-01-01",
+ last_submitted_date="2024-01-01",
status=DomainRequest.DomainRequestStatus.STARTED,
created_at="2024-01-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=short_ribs,
- submission_date="2024-02-01",
+ last_submitted_date="2024-02-01",
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
created_at="2024-02-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=beef_chuck,
- submission_date="2024-03-01",
+ last_submitted_date="2024-03-01",
status=DomainRequest.DomainRequestStatus.REJECTED,
created_at="2024-03-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=stew_beef,
- submission_date="2024-04-01",
+ last_submitted_date="2024-04-01",
status=DomainRequest.DomainRequestStatus.STARTED,
created_at="2024-04-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-05-01",
+ last_submitted_date="2024-05-01",
status=DomainRequest.DomainRequestStatus.STARTED,
created_at="2024-05-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-06-01",
+ last_submitted_date="2024-06-01",
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
created_at="2024-06-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-07-01",
+ last_submitted_date="2024-07-01",
status=DomainRequest.DomainRequestStatus.REJECTED,
created_at="2024-07-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-08-01",
+ last_submitted_date="2024-08-01",
status=DomainRequest.DomainRequestStatus.STARTED,
created_at="2024-08-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-09-01",
+ last_submitted_date="2024-09-01",
status=DomainRequest.DomainRequestStatus.STARTED,
created_at="2024-09-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-10-01",
+ last_submitted_date="2024-10-01",
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
created_at="2024-10-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-11-01",
+ last_submitted_date="2024-11-01",
status=DomainRequest.DomainRequestStatus.REJECTED,
created_at="2024-11-01",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-11-02",
+ last_submitted_date="2024-11-02",
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
created_at="2024-11-02",
),
DomainRequest.objects.create(
creator=cls.user,
requested_domain=None,
- submission_date="2024-12-01",
+ last_submitted_date="2024-12-01",
status=DomainRequest.DomainRequestStatus.APPROVED,
created_at="2024-12-01",
),
@@ -138,7 +138,7 @@ def test_get_domain_requests_json_authenticated(self):
# Extract fields from response
requested_domains = [request["requested_domain"] for request in data["domain_requests"]]
- submission_dates = [request["submission_date"] for request in data["domain_requests"]]
+ last_submitted_dates = [request["last_submitted_date"] for request in data["domain_requests"]]
statuses = [request["status"] for request in data["domain_requests"]]
created_ats = [request["created_at"] for request in data["domain_requests"]]
ids = [request["id"] for request in data["domain_requests"]]
@@ -154,7 +154,7 @@ def test_get_domain_requests_json_authenticated(self):
self.domain_requests[i].requested_domain.name if self.domain_requests[i].requested_domain else None,
requested_domains[i],
)
- self.assertEqual(self.domain_requests[i].submission_date, submission_dates[i])
+ self.assertEqual(self.domain_requests[i].last_submitted_date, last_submitted_dates[i])
self.assertEqual(self.domain_requests[i].get_status_display(), statuses[i])
self.assertEqual(
parse_datetime(self.domain_requests[i].created_at.isoformat()), parse_datetime(created_ats[i])
@@ -287,26 +287,30 @@ def test_pagination(self):
def test_sorting(self):
"""test that sorting works properly on the result set"""
- response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "desc"})
+ response = self.app.get(
+ reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "desc"}
+ )
self.assertEqual(response.status_code, 200)
data = response.json
- # Check if sorted by submission_date in descending order
- submission_dates = [req["submission_date"] for req in data["domain_requests"]]
- self.assertEqual(submission_dates, sorted(submission_dates, reverse=True))
+ # Check if sorted by last_submitted_date in descending order
+ last_submitted_dates = [req["last_submitted_date"] for req in data["domain_requests"]]
+ self.assertEqual(last_submitted_dates, sorted(last_submitted_dates, reverse=True))
- response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "asc"})
+ response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "asc"})
self.assertEqual(response.status_code, 200)
data = response.json
- # Check if sorted by submission_date in ascending order
- submission_dates = [req["submission_date"] for req in data["domain_requests"]]
- self.assertEqual(submission_dates, sorted(submission_dates))
+ # Check if sorted by last_submitted_date in ascending order
+ last_submitted_dates = [req["last_submitted_date"] for req in data["domain_requests"]]
+ self.assertEqual(last_submitted_dates, sorted(last_submitted_dates))
def test_filter_approved_excluded(self):
"""test that approved requests are excluded from result set."""
# sort in reverse chronological order of submission date, since most recent request is approved
- response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "desc"})
+ response = self.app.get(
+ reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "desc"}
+ )
self.assertEqual(response.status_code, 200)
data = response.json
diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py
index db961a36d..7ca3b7e97 100644
--- a/src/registrar/utility/csv_export.py
+++ b/src/registrar/utility/csv_export.py
@@ -1235,7 +1235,9 @@ def parse_row(cls, columns, model):
"State/territory": model.get("state_territory"),
"Request purpose": model.get("purpose"),
"CISA regional representative": model.get("cisa_representative_email"),
- "Submitted at": model.get("submission_date"),
+ "Last submitted date": model.get("last_submitted_date"),
+ "First submitted date": model.get("first_submitted_date"),
+ "Last status update": model.get("last_status_update"),
}
row = [FIELDS.get(column, "") for column in columns]
@@ -1279,8 +1281,8 @@ def get_filter_conditions(cls, start_date=None, end_date=None):
end_date_formatted = format_end_date(end_date)
return Q(
status=DomainRequest.DomainRequestStatus.SUBMITTED,
- submission_date__lte=end_date_formatted,
- submission_date__gte=start_date_formatted,
+ last_submitted_date__lte=end_date_formatted,
+ last_submitted_date__gte=start_date_formatted,
)
@classmethod
@@ -1304,7 +1306,9 @@ def get_columns(cls):
"""
return [
"Domain request",
- "Submitted at",
+ "Last submitted date",
+ "First submitted date",
+ "Last status update",
"Status",
"Domain type",
"Federal type",
diff --git a/src/registrar/views/domain_requests_json.py b/src/registrar/views/domain_requests_json.py
index 2e58c8e48..6b0b346f8 100644
--- a/src/registrar/views/domain_requests_json.py
+++ b/src/registrar/views/domain_requests_json.py
@@ -46,7 +46,7 @@ def get_domain_requests_json(request):
domain_requests_data = [
{
"requested_domain": domain_request.requested_domain.name if domain_request.requested_domain else None,
- "submission_date": domain_request.submission_date,
+ "last_submitted_date": domain_request.last_submitted_date,
"status": domain_request.get_status_display(),
"created_at": format(domain_request.created_at, "c"), # Serialize to ISO 8601
"id": domain_request.id,
diff --git a/src/registrar/views/report_views.py b/src/registrar/views/report_views.py
index 428298b52..abdbd37c9 100644
--- a/src/registrar/views/report_views.py
+++ b/src/registrar/views/report_views.py
@@ -26,7 +26,7 @@ def get(self, request):
created_at__gt=thirty_days_ago, status=models.DomainRequest.DomainRequestStatus.APPROVED
)
avg_approval_time = last_30_days_approved_applications.annotate(
- approval_time=F("approved_domain__created_at") - F("submission_date")
+ approval_time=F("approved_domain__created_at") - F("last_submitted_date")
).aggregate(Avg("approval_time"))["approval_time__avg"]
# Format the timedelta to display only days
if avg_approval_time is not None:
@@ -104,11 +104,11 @@ def get(self, request):
filter_submitted_requests_start_date = {
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
- "submission_date__lte": start_date_formatted,
+ "last_submitted_date__lte": start_date_formatted,
}
filter_submitted_requests_end_date = {
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
- "submission_date__lte": end_date_formatted,
+ "last_submitted_date__lte": end_date_formatted,
}
submitted_requests_sliced_at_start_date = csv_export.DomainRequestExport.get_sliced_requests(
filter_submitted_requests_start_date
|