Repository: cisagov/manage.get.gov

Issue:
Update the stored expiration date value anytime it's received
### Issue description

Because we are storing the expiration date on our domain model we need to ensure this stored value is updated based on what we receive from the registry. It currently, is autmatically returned anytime we get an info domain, so we just need to add a check on the _fetch_cache function so that if the expiration date is not the same as what we have stored, we update our stored value.

Note, this comes into play because an analyst could technically go through the admin portal on cloudflare to update the expiration date for a domain making our stored value out of sync.

### Acceptance criteria

- on an InfoDomain, update the stored domain.expiration_date with the returned value from the registry (may require formatting)
- add a unit test to verify this is working

### Additional context

_No response_

### Links to other issues

blocked by: #1217 



Discussion:

Resolving patch:
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -212,11 +212,9 @@ def last_updated_date(self) -> date:
     @Cache
     def registry_expiration_date(self) -> date:
         """Get or set the `ex_date` element from the registry.
-        Additionally, update the expiration date in the registrar"""
+        Additionally, _get_property updates the expiration date in the registrar"""
         try:
-            self.expiration_date = self._get_property("ex_date")
-            self.save()
-            return self.expiration_date
+            return self._get_property("ex_date")
         except Exception as e:
             # exception raised during the save to registrar
             logger.error(f"error updating expiration date in registrar: {e}")
@@ -1610,6 +1608,12 @@ def _fetch_cache(self, fetch_hosts=False, fetch_contacts=False):
                 if old_cache_contacts is not None:
                     cleaned["contacts"] = old_cache_contacts
 
+            # if expiration date from registry does not match what is in db,
+            # update the db
+            if "ex_date" in cleaned and cleaned["ex_date"] != self.expiration_date:
+                self.expiration_date = cleaned["ex_date"]
+                self.save()
+
             self._cache = cleaned
 
         except RegistryError as e:


Test patch:
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -617,6 +617,7 @@ def dummyInfoContactResultData(
             common.Status(state="serverTransferProhibited", description="", lang="en"),
             common.Status(state="inactive", description="", lang="en"),
         ],
+        ex_date=datetime.date(2023, 5, 25),
     )
     mockDataInfoContact = mockDataInfoDomain.dummyInfoContactResultData(
         "123", "123@mail.gov", datetime.datetime(2023, 5, 25, 19, 45, 35), "lastPw"
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -1987,6 +1987,13 @@ def test_renew_domain_error(self):
         with self.assertRaises(RegistryError):
             self.domain_w_error.renew_domain()
 
+    def test_expiration_date_updated_on_info_domain_call(self):
+        """assert that expiration date in db is updated on info domain call"""
+        # force fetch_cache to be called
+        self.domain.statuses
+        test_date = datetime.date(2023, 5, 25)
+        self.assertEquals(self.domain.expiration_date, test_date)
+
 
 class TestAnalystClientHold(MockEppLib):
     """Rule: Analysts may suspend or restore a domain by using client hold"""