From ad1aaa245d6d7cf67f5b3c76e72652b1232644ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sun, 30 Jun 2019 17:22:45 +0200
Subject: [PATCH] workflows: add support for django template as anchor date
 (#33862)

---
 tests/test_workflow_import.py |  2 ++
 tests/test_workflows.py       | 32 ++++++++++++++++++++++++++++++++
 wcs/workflows.py              | 18 +++++++++++++++---
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/tests/test_workflow_import.py b/tests/test_workflow_import.py
index b2d98190e..a353a4d62 100644
--- a/tests/test_workflow_import.py
+++ b/tests/test_workflow_import.py
@@ -638,12 +638,14 @@ def test_global_anchor_expression_trigger(pub):
     ac1 = wf.add_global_action('Action', 'ac1')
     trigger = ac1.append_trigger('timeout')
     trigger.anchor_expression = 'False'
+    trigger.anchor_template = '{{x}}'
     trigger.anchor = 'python'
 
     wf2 = assert_import_export_works(wf, include_id=True)
     assert wf2.global_actions[0].triggers[-1].id == trigger.id
     assert wf2.global_actions[0].triggers[-1].anchor == trigger.anchor
     assert wf2.global_actions[0].triggers[-1].anchor_expression == trigger.anchor_expression
+    assert wf2.global_actions[0].triggers[-1].anchor_template == trigger.anchor_template
 
 
 def test_global_webservice_trigger(pub):
diff --git a/tests/test_workflows.py b/tests/test_workflows.py
index 8db74524e..aeed463e0 100644
--- a/tests/test_workflows.py
+++ b/tests/test_workflows.py
@@ -3436,6 +3436,38 @@ def test_global_timeouts(two_pubs):
     assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'green'
     formdata1.store()
 
+    # django template
+    trigger.anchor = 'template'
+    trigger.anchor_template = '{{ form_receipt_date|date:"Y-m-d" }}'
+    workflow.store()
+    pub.apply_global_action_timeouts()
+    assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'yellow'
+    formdata1.store()
+
+    # django template
+    trigger.anchor = 'template'
+    trigger.anchor_template = '{{ form_receipt_date|date:"Y-m-d" }}'
+    workflow.store()
+    pub.apply_global_action_timeouts()
+    assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'yellow'
+    formdata1.store()
+
+    # django template (with local date format)
+    trigger.anchor = 'template'
+    trigger.anchor_template = '{{ form_receipt_date }}'
+    workflow.store()
+    pub.apply_global_action_timeouts()
+    assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'yellow'
+    formdata1.store()
+
+    # django template (with local date/time format)
+    trigger.anchor = 'template'
+    trigger.anchor_template = '{{ form_receipt_datetime }}'
+    workflow.store()
+    pub.apply_global_action_timeouts()
+    assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'yellow'
+    formdata1.store()
+
 
 def test_global_timeouts_latest_arrival(two_pubs):
     pub = two_pubs
diff --git a/wcs/workflows.py b/wcs/workflows.py
index 6cb4a8418..952699f0c 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -1062,12 +1062,13 @@ class WorkflowGlobalActionTimeoutTrigger(WorkflowGlobalActionTrigger):
     key = 'timeout'
     anchor = None
     anchor_expression = ''
+    anchor_template = ''
     anchor_status_first = None
     anchor_status_latest = None
     timeout = None
 
     def get_parameters(self):
-        return ('anchor', 'anchor_expression', 'anchor_status_first',
+        return ('anchor', 'anchor_expression', 'anchor_template', 'anchor_status_first',
                 'anchor_status_latest', 'timeout')
 
     def get_anchor_labels(self):
@@ -1076,6 +1077,7 @@ class WorkflowGlobalActionTimeoutTrigger(WorkflowGlobalActionTrigger):
                 ('1st-arrival', _('First arrival in status')),
                 ('latest-arrival', _('Latest arrival in status')),
                 ('finalized', _('Arrival in final status')),
+                ('template', _('String / Template')),
                 ('python', _('Python expression')),
         ])
 
@@ -1110,11 +1112,18 @@ class WorkflowGlobalActionTimeoutTrigger(WorkflowGlobalActionTrigger):
                  options=options, value=self.anchor, required=True,
                  attrs={'data-dynamic-display-parent': 'true'})
 
-        form.add(StringWidget, 'anchor_expression', title=_('Expression'), size=80,
+        form.add(StringWidget, 'anchor_expression', title=_('Python Expression to get reference date'), size=80,
                  value=self.anchor_expression,
-                 hint=_('This will only apply to open forms.'),
+                 hint=_('This should produce a date; it will only apply to open forms.'),
                  attrs={'data-dynamic-display-child-of': 'anchor',
                         'data-dynamic-display-value': _('Python expression')})
+
+        form.add(StringWidget, 'anchor_template', title=_('String / Template with reference date'), size=80,
+                 value=self.anchor_template,
+                 hint=_('This should be a date; it will only apply to open forms.'),
+                 attrs={'data-dynamic-display-child-of': 'anchor',
+                        'data-dynamic-display-value': _('String / Template')})
+
         possible_status = [(None, _('Current Status'), None)]
         possible_status.extend([('wf-%s' % x.id, x.name, x.id) for x in workflow.possible_status])
         form.add(SingleSelectWidget, 'anchor_status_first', title=_('Status'),
@@ -1180,6 +1189,9 @@ class WorkflowGlobalActionTimeoutTrigger(WorkflowGlobalActionTrigger):
                         anchor_date = evolution.time
                     else:
                         break
+        elif self.anchor == 'template':
+            variables = get_publisher().substitutions.get_context_variables()
+            anchor_date = Template(self.anchor_template, autoescape=False).render(variables)
         elif self.anchor == 'python':
             variables = get_publisher().substitutions.get_context_variables()
             try:
-- 
2.26.2

