From b6d2f27e0fffa02dd594ee3a7802be408005b54b Mon Sep 17 00:00:00 2001
From: Thomas NOEL <tnoel@entrouvert.com>
Date: Thu, 1 Apr 2021 16:51:27 +0200
Subject: [PATCH] formdata: do not consider empty evolution in last_update_time
 (#52629)

---
 tests/backoffice_pages/test_all.py | 56 ++++++++++++++++++++++++++++++
 wcs/formdata.py                    | 13 +++----
 wcs/sql.py                         |  5 +--
 3 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/tests/backoffice_pages/test_all.py b/tests/backoffice_pages/test_all.py
index 23fc24ed..da6cf6f2 100644
--- a/tests/backoffice_pages/test_all.py
+++ b/tests/backoffice_pages/test_all.py
@@ -2547,8 +2547,64 @@ def test_backoffice_wfedit(pub):
     resp = resp.form.submit('submit')
     resp = resp.follow()
     assert form_class().get(number31.id).data['2'] == 'bar'
+
+
+    # status and last_update_time tests
+    epoch = time.localtime(0)  # 1970-01-01 00:00
+    number31.evolution[-1].time = epoch
     number31.store()
 
+    # verify edit cancel doesn't change last_uptime_time
+    assert number31.last_update_time.tm_year == 1970
+    resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
+    resp = resp.form.submit('button_wfedit')
+    resp = resp.follow()
+    resp.form['f2'].value = 'foo'
+    resp = resp.form.submit('cancel')
+    resp = resp.follow()
+    number31 = form_class().get(number31.id)
+    assert number31.data['2'] == 'baz'
+    assert number31.status == 'wf-%s' % st1.id
+    assert number31.last_update_time.tm_year == 1970
+    # edited (without status change) do not update last_update_time
+    resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
+    resp = resp.form.submit('button_wfedit')
+    resp = resp.follow()
+    resp.form['f2'].value = 'foo'
+    resp = resp.form.submit('submit')
+    resp = resp.follow()
+    number31 = form_class().get(number31.id)
+    assert number31.data['2'] == 'foo'
+    assert number31.status == 'wf-%s' % st1.id
+    assert number31.last_update_time.tm_year == 1970
+
+    # change status after edition
+    st2 = workflow.add_status('Edited')
+    wfedit.status = st2
+    workflow.store()
+    # cancel do not change last_uptime_time
+    resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
+    resp = resp.form.submit('button_wfedit')
+    resp = resp.follow()
+    resp.form['f2'].value = 'bar'
+    resp = resp.form.submit('cancel')
+    resp = resp.follow()
+    number31 = form_class().get(number31.id)
+    assert number31.data['2'] == 'foo'
+    assert number31.status == 'wf-%s' % st1.id
+    assert number31.last_update_time.tm_year == 1970
+    # edited: change status and last_update_time
+    resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
+    resp = resp.form.submit('button_wfedit')
+    resp = resp.follow()
+    resp.form['f2'].value = 'bar'
+    resp = resp.form.submit('submit')
+    resp = resp.follow()
+    number31 = form_class().get(number31.id)
+    assert number31.data['2'] == 'bar'
+    assert number31.status == 'wf-%s' % st2.id
+    assert number31.last_update_time.tm_year > 1970
+
 
 def test_backoffice_wfedit_disabled(pub):
     user = create_user(pub)
diff --git a/wcs/formdata.py b/wcs/formdata.py
index a0f369cf..ba2b2544 100644
--- a/wcs/formdata.py
+++ b/wcs/formdata.py
@@ -1054,12 +1054,13 @@ class FormData(StorableObject):
     def get_last_update_time(self):
         if hasattr(self, '_last_update_time'):
             return self._last_update_time
-        if self.evolution and self.evolution[-1].last_jump_datetime:
-            return self.evolution[-1].last_jump_datetime.timetuple()
-        elif self.evolution and self.evolution[-1].time:
-            return self.evolution[-1].time
-        else:
-            return self.receipt_time
+        for evolution in reversed(self.evolution or []):
+            if evolution.status:
+                if evolution.last_jump_datetime:
+                    return evolution.last_jump_datetime.timetuple()
+                if evolution.time:
+                    return evolution.time
+        return self.receipt_time
 
     def set_last_update_time(self, value):
         self._last_update_time = value
diff --git a/wcs/sql.py b/wcs/sql.py
index d08e8472..fb6925d8 100644
--- a/wcs/sql.py
+++ b/wcs/sql.py
@@ -3301,7 +3301,7 @@ def get_period_total(
 # latest migration, number + description (description is not used
 # programmaticaly but will make sure git conflicts if two migrations are
 # separately added with the same number)
-SQL_LEVEL = (50, 'switch role uuid column to varchar')
+SQL_LEVEL = (51, 'reindex formdata for last_update_time')
 
 
 def migrate_global_views(conn, cur):
@@ -3426,7 +3426,7 @@ def migrate():
         # 21: (second part), store ascii_name of users
         # 23: (first part), use misc.simplify() over full text queries
         set_reindex('user', 'needed', conn=conn, cur=cur)
-    if sql_level < 41:
+    if sql_level < 51:
         # 17: store last_update_time in tables
         # 18: add user name to full-text search index
         # 21: (third part), add user ascii_names to full-text index
@@ -3436,6 +3436,7 @@ def migrate():
         # 31: add user_label to formdata
         # 38: extract submission_agent_id to its own column
         # 41: update full text normalization
+        # 51: new last_update_time calculation
         set_reindex('formdata', 'needed', conn=conn, cur=cur)
     if sql_level < 46:
         from wcs.carddef import CardDef
-- 
2.30.2

