do not add an evolution on static jump (#22236)
This commit is contained in:
parent
771dec087b
commit
ce94b90179
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import pytest
|
||||
import hashlib
|
||||
|
@ -3821,17 +3822,46 @@ def test_form_worklow_multiple_identical_status(pub):
|
|||
user.roles = [role.id]
|
||||
user.store()
|
||||
|
||||
assert len(formdef.data_class().get(formdata.id).evolution) == 1
|
||||
assert formdef.data_class().get(formdata.id).evolution[0].last_jump_datetime is None
|
||||
|
||||
login(app, username='foo', password='foo')
|
||||
resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
|
||||
formdata = formdef.data_class().get(formdata.id)
|
||||
# status is not changed: no new evolution, only a new last_jump_datetime
|
||||
assert len(formdata.evolution) == 1
|
||||
assert formdata.status == 'wf-st1'
|
||||
assert formdata.evolution[0].last_jump_datetime is not None
|
||||
|
||||
# add a comment to last evolution, forcing create a new one
|
||||
formdata.evolution[-1].comment = 'new-evolution-1'
|
||||
formdata.store()
|
||||
resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
|
||||
formdata = formdef.data_class().get(formdata.id)
|
||||
assert len(formdata.evolution) == 2
|
||||
assert formdata.status == 'wf-st1'
|
||||
|
||||
# again
|
||||
formdata.evolution[-1].comment = 'new-evolution-2'
|
||||
formdata.store()
|
||||
resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
|
||||
|
||||
assert len(formdef.data_class().get(formdata.id).evolution) == 4
|
||||
assert formdef.data_class().get(formdata.id).status == 'wf-st1'
|
||||
# last evolution is empty, this last trigger does not create a new one
|
||||
resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
|
||||
|
||||
# finally, 3 evolutions: new-evolution-1, new-evolution-2, empty
|
||||
formdata = formdef.data_class().get(formdata.id)
|
||||
assert len(formdata.evolution) == 3
|
||||
assert formdata.status == 'wf-st1'
|
||||
assert formdata.evolution[0].comment == 'new-evolution-1'
|
||||
assert formdata.evolution[1].comment == 'new-evolution-2'
|
||||
assert formdata.evolution[2].comment is None
|
||||
|
||||
resp = app.get(formdata.get_url())
|
||||
assert resp.body.count('Status1') == 2 # once in summary and once in journal
|
||||
assert resp.body.count('CSS-STATUS1') == 1
|
||||
assert resp.body.count('Status1') == 3 # once in summary and two in journal
|
||||
assert resp.body.count('CSS-STATUS1') == 2
|
||||
assert resp.body.count('new-evolution-1') == 1
|
||||
assert resp.body.count('new-evolution-2') == 1
|
||||
|
||||
def test_display_message(pub):
|
||||
user = create_user(pub)
|
||||
|
|
|
@ -1456,6 +1456,7 @@ def test_last_update_time():
|
|||
formdata1 = data_class()
|
||||
formdata1.status = 'wf-st1'
|
||||
formdata1.just_created()
|
||||
formdata1.evolution[0].comment = 'comment'
|
||||
formdata1.jump_status('st1') # will add another evolution entry
|
||||
formdata1.evolution[0].time = datetime.datetime(2015, 1, 1, 0, 0, 0).timetuple()
|
||||
formdata1.evolution[1].time = datetime.datetime(2015, 1, 2, 0, 0, 0).timetuple()
|
||||
|
@ -1464,6 +1465,7 @@ def test_last_update_time():
|
|||
formdata2 = data_class()
|
||||
formdata2.status = 'wf-st1'
|
||||
formdata2.just_created()
|
||||
formdata2.evolution[0].comment = 'comment'
|
||||
formdata2.jump_status('st1') # will add another evolution entry
|
||||
formdata2.evolution[0].time = datetime.datetime(2015, 1, 3, 0, 0, 0).timetuple()
|
||||
formdata2.evolution[1].time = datetime.datetime(2015, 1, 4, 0, 0, 0).timetuple()
|
||||
|
|
|
@ -1187,9 +1187,7 @@ class FormDefPage(Directory):
|
|||
if form.get_widget('date').parse():
|
||||
date = form.get_widget('date').parse()
|
||||
date = time.strptime(date, misc.date_format())
|
||||
all_forms = [x for x in all_forms if (
|
||||
x.evolution and x.evolution[-1].time < date) or (
|
||||
x.receipt_time < date)]
|
||||
all_forms = [x for x in all_forms if x.last_update_time < date]
|
||||
|
||||
self.fd = StringIO()
|
||||
t = tarfile.open('wcs.tar.gz', 'w:gz', fileobj=self.fd)
|
||||
|
|
|
@ -131,6 +131,7 @@ class Evolution(object):
|
|||
who = None
|
||||
status = None
|
||||
time = None
|
||||
last_jump_datetime = None
|
||||
comment = None
|
||||
parts = None
|
||||
|
||||
|
@ -179,6 +180,7 @@ class Evolution(object):
|
|||
def get_json_export_dict(self, user, anonymise=False):
|
||||
data = {
|
||||
'time': self.time,
|
||||
'last_jump_datetime': self.last_jump_datetime,
|
||||
}
|
||||
if self.status:
|
||||
data['status'] = self.status[3:]
|
||||
|
@ -556,13 +558,23 @@ class FormData(StorableObject):
|
|||
previous_status = self.pop_previous_marked_status()
|
||||
assert previous_status, 'failed to compute previous status'
|
||||
status_id = previous_status.id
|
||||
evo = Evolution(self)
|
||||
evo.time = time.localtime()
|
||||
evo.status = 'wf-%s' % status_id
|
||||
status = 'wf-%s' % status_id
|
||||
if not self.evolution:
|
||||
self.evolution = []
|
||||
elif (self.status == status
|
||||
and self.evolution[-1].status == status
|
||||
and not self.evolution[-1].comment
|
||||
and not self.evolution[-1].display_parts()):
|
||||
# if status do not change and last evolution is empty,
|
||||
# just update last jump time on last evolution, do not add one
|
||||
self.evolution[-1].last_jump_datetime = datetime.datetime.now()
|
||||
self.store()
|
||||
return
|
||||
evo = Evolution(self)
|
||||
evo.time = time.localtime()
|
||||
evo.status = status
|
||||
self.evolution.append(evo)
|
||||
self.status = evo.status
|
||||
self.status = status
|
||||
self.store()
|
||||
|
||||
def get_url(self, backoffice = False):
|
||||
|
@ -855,7 +867,9 @@ 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].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
|
||||
|
|
38
wcs/sql.py
38
wcs/sql.py
|
@ -375,6 +375,7 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
|
|||
who varchar,
|
||||
status varchar,
|
||||
time timestamp,
|
||||
last_jump_datetime timestamp,
|
||||
comment text,
|
||||
parts bytea,
|
||||
formdata_id integer REFERENCES %s (id) ON DELETE CASCADE)''' % (
|
||||
|
@ -471,6 +472,15 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
|
|||
for field in (existing_fields - needed_fields):
|
||||
cur.execute('''ALTER TABLE %s DROP COLUMN %s CASCADE''' % (table_name, field))
|
||||
|
||||
# migrations on _evolutions table
|
||||
cur.execute('''SELECT column_name FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = '%s_evolutions'
|
||||
''' % table_name)
|
||||
evo_existing_fields = set([x[0] for x in cur.fetchall()])
|
||||
if 'last_jump_datetime' not in evo_existing_fields:
|
||||
cur.execute('''ALTER TABLE %s_evolutions ADD COLUMN last_jump_datetime timestamp''' % table_name)
|
||||
|
||||
if rebuild_views or len(existing_fields - needed_fields):
|
||||
# views may have been dropped when dropping columns, so we recreate
|
||||
# them even if not asked to.
|
||||
|
@ -1201,7 +1211,8 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
self._evolution = []
|
||||
return self._evolution
|
||||
conn, cur = get_connection_and_cursor()
|
||||
sql_statement = '''SELECT id, who, status, time, comment, parts FROM %s_evolutions
|
||||
sql_statement = '''SELECT id, who, status, time, last_jump_datetime,
|
||||
comment, parts FROM %s_evolutions
|
||||
WHERE formdata_id = %%(id)s
|
||||
ORDER BY id''' % self._table_name
|
||||
cur.execute(sql_statement, {'id': self.id})
|
||||
|
@ -1218,11 +1229,12 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
@classmethod
|
||||
def _row2evo(cls, row, formdata):
|
||||
o = wcs.formdata.Evolution(formdata)
|
||||
o._sql_id, o.who, o.status, o.time, o.comment = [str_encode(x) for x in tuple(row[:5])]
|
||||
o._sql_id, o.who, o.status, o.time, o.last_jump_datetime, o.comment = [
|
||||
str_encode(x) for x in tuple(row[:6])]
|
||||
if o.time:
|
||||
o.time = o.time.timetuple()
|
||||
if row[5]:
|
||||
o.parts = cPickle.loads(str(row[5]))
|
||||
if row[6]:
|
||||
o.parts = cPickle.loads(str(row[6]))
|
||||
return o
|
||||
|
||||
def set_evolution(self, value):
|
||||
|
@ -1243,7 +1255,8 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
if not object_dict:
|
||||
return
|
||||
conn, cur = get_connection_and_cursor()
|
||||
sql_statement = '''SELECT id, who, status, time, comment, parts, formdata_id
|
||||
sql_statement = '''SELECT id, who, status, time, last_jump_datetime,
|
||||
comment, parts, formdata_id
|
||||
FROM %s_evolutions''' % cls._table_name
|
||||
sql_statement += ''' WHERE formdata_id IN %(object_ids)s ORDER BY id'''
|
||||
cur.execute(sql_statement, {'object_ids': tuple(object_dict.keys())})
|
||||
|
@ -1255,7 +1268,7 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
row = cur.fetchone()
|
||||
if row is None:
|
||||
break
|
||||
_sql_id, who, status, time, comment, parts, formdata_id = tuple(row[:7])
|
||||
_sql_id, who, status, time, last_jump_datetime, comment, parts, formdata_id = tuple(row[:8])
|
||||
formdata = object_dict.get(formdata_id)
|
||||
if not formdata:
|
||||
continue
|
||||
|
@ -1354,6 +1367,7 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
sql_dict.update({'id': evo._sql_id})
|
||||
sql_statement = '''UPDATE %s_evolutions SET
|
||||
time = %%(time)s,
|
||||
last_jump_datetime = %%(last_jump_datetime)s,
|
||||
status = %%(status)s,
|
||||
comment = %%(comment)s,
|
||||
parts = %%(parts)s
|
||||
|
@ -1362,16 +1376,19 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData):
|
|||
else:
|
||||
sql_statement = '''INSERT INTO %s_evolutions (
|
||||
id, who, status,
|
||||
time, comment, parts,
|
||||
time, last_jump_datetime,
|
||||
comment, parts,
|
||||
formdata_id)
|
||||
VALUES (DEFAULT, %%(who)s, %%(status)s,
|
||||
%%(time)s, %%(comment)s,
|
||||
%%(time)s, %%(last_jump_datetime)s,
|
||||
%%(comment)s,
|
||||
%%(parts)s, %%(formdata_id)s)
|
||||
RETURNING id''' % self._table_name
|
||||
sql_dict.update({
|
||||
'who': evo.who,
|
||||
'status': evo.status,
|
||||
'time': datetime.datetime.fromtimestamp(time.mktime(evo.time)),
|
||||
'last_jump_datetime': evo.last_jump_datetime,
|
||||
'comment': evo.comment,
|
||||
'formdata_id': self.id,
|
||||
})
|
||||
|
@ -2123,7 +2140,7 @@ def get_yearly_totals(period_start=None, period_end=None, criterias=None):
|
|||
return result
|
||||
|
||||
|
||||
SQL_LEVEL = 26
|
||||
SQL_LEVEL = 27
|
||||
|
||||
def migrate_global_views(conn, cur):
|
||||
cur.execute('''SELECT COUNT(*) FROM information_schema.tables
|
||||
|
@ -2201,7 +2218,7 @@ def migrate():
|
|||
raise RuntimeError()
|
||||
if sql_level < 1: # 1: introduction of tracking_code table
|
||||
do_tracking_code_table()
|
||||
if sql_level < 26:
|
||||
if sql_level < 27:
|
||||
# 2: introduction of formdef_id in views
|
||||
# 5: add concerned_roles_array, is_at_endpoint and fts to views
|
||||
# 7: add backoffice_submission to tables
|
||||
|
@ -2216,6 +2233,7 @@ def migrate():
|
|||
# 20: remove user hash stuff
|
||||
# 22: rebuild views
|
||||
# 26: add digest to formdata
|
||||
# 27: add last_jump_datetime in evolutions tables
|
||||
migrate_views(conn, cur)
|
||||
if sql_level < 21:
|
||||
# 3: introduction of _structured for user fields
|
||||
|
|
|
@ -13,7 +13,11 @@
|
|||
{% if evolution.status %}
|
||||
<div class="evolution-metadata">
|
||||
<span class="status">{{evolution.get_status_label}}</span>
|
||||
<span class="time">{{evolution.datetime}}</span>
|
||||
<span class="time">{{evolution.datetime}}
|
||||
{% if evolution.last_jump_datetime and user.is_admin %}
|
||||
<span class="last-jump">({% trans "last check:" %} {{ evolution.last_jump_datetime }})</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="msg">
|
||||
|
|
|
@ -243,10 +243,7 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem):
|
|||
|
||||
if self.timeout:
|
||||
timeout = int(self.compute(self.timeout))
|
||||
if formdata.evolution:
|
||||
last = formdata.evolution[-1].time
|
||||
else:
|
||||
last = formdata.receipt_time
|
||||
last = formdata.last_update_time
|
||||
if last:
|
||||
diff = time.time() - time.mktime(last)
|
||||
must_jump = (diff > timeout) and must_jump
|
||||
|
|
|
@ -1040,13 +1040,13 @@ class WorkflowGlobalActionTimeoutTrigger(WorkflowGlobalActionTrigger):
|
|||
anchor_status = self.anchor_status_first or formdata.status
|
||||
for evolution in formdata.evolution:
|
||||
if evolution.status == anchor_status:
|
||||
anchor_date = evolution.time
|
||||
anchor_date = evolution.last_jump_datetime or evolution.time
|
||||
break
|
||||
elif self.anchor == 'latest-arrival':
|
||||
anchor_status = self.anchor_status_latest or formdata.status
|
||||
for evolution in reversed(formdata.evolution):
|
||||
if evolution.status == anchor_status:
|
||||
anchor_date = evolution.time
|
||||
anchor_date = evolution.last_jump_datetime or evolution.time
|
||||
break
|
||||
elif self.anchor == 'python':
|
||||
variables = get_publisher().substitutions.get_context_variables()
|
||||
|
|
Loading…
Reference in New Issue