fix: ensure has_value_changed works for datetime, date and timedelta fields

This commit is contained in:
scdanieli 2024-02-18 16:05:31 +01:00
parent 526359b20c
commit a1cb19c820
3 changed files with 23 additions and 4 deletions

View file

@ -4,6 +4,7 @@ import hashlib
import json
import time
from collections.abc import Generator, Iterable
from datetime import date, datetime, timedelta
from typing import TYPE_CHECKING, Any, Optional
from werkzeug.exceptions import NotFound
@ -22,7 +23,7 @@ from frappe.model.utils import is_virtual_doctype
from frappe.model.workflow import set_workflow_state_on_action, validate_workflow
from frappe.types import DF
from frappe.utils import compare, cstr, date_diff, file_lock, flt, now
from frappe.utils.data import get_absolute_url
from frappe.utils.data import get_absolute_url, get_datetime, get_timedelta, getdate
from frappe.utils.global_search import update_global_search
if TYPE_CHECKING:
@ -456,7 +457,21 @@ class Document(BaseDocument):
def has_value_changed(self, fieldname):
"""Return True if value has changed before and after saving."""
previous = self.get_doc_before_save()
return previous.get(fieldname) != self.get(fieldname) if previous else True
if not previous:
return True
previous_value = previous.get(fieldname)
current_value = self.get(fieldname)
if isinstance(previous_value, datetime):
current_value = get_datetime(current_value)
elif isinstance(previous_value, date):
current_value = getdate(current_value)
elif isinstance(previous_value, timedelta):
current_value = get_timedelta(current_value)
return previous_value != current_value
def set_new_name(self, force=False, set_name=None, set_child_names=True):
"""Calls `frappe.naming.set_new_name` for parent and child docs."""

View file

@ -605,6 +605,7 @@ class TestDateUtils(FrappeTestCase):
self.assertIsInstance(get_timedelta(str(datetime_input)), timedelta)
self.assertIsInstance(get_timedelta(str(timedelta_input)), timedelta)
self.assertIsInstance(get_timedelta(str(time_input)), timedelta)
self.assertIsInstance(get_timedelta(get_timedelta("100:2:12")), timedelta)
def test_to_timedelta(self):
self.assertEqual(to_timedelta("00:00:01"), timedelta(seconds=1))

View file

@ -161,13 +161,13 @@ def get_datetime(
return parser.parse(datetime_str)
def get_timedelta(time: str | None = None) -> datetime.timedelta | None:
def get_timedelta(time: str | datetime.timedelta | None = None) -> datetime.timedelta | None:
"""Return `datetime.timedelta` object from string value of a valid time format.
Return None if `time` is not a valid format.
Args:
time (str): A valid time representation. This string is parsed
time (str | datetime.timedelta): A valid time representation. This string is parsed
using `dateutil.parser.parse`. Examples of valid inputs are:
'0:0:0', '17:21:00', '2012-01-19 17:21:00'. Checkout
https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.parse
@ -175,6 +175,9 @@ def get_timedelta(time: str | None = None) -> datetime.timedelta | None:
Return:
datetime.timedelta: Timedelta object equivalent of the passed `time` string
"""
if isinstance(time, datetime.timedelta):
return time
time = time or "0:0:0"
try: