From 85d4b288105eb4c75f9ef50207c5d7801a2dfbcc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Tue, 17 May 2022 08:25:55 +0200
Subject: [PATCH 1/2] workflows: save workflow form data on "choice" action
 buttons (#65334)

---
 tests/backoffice_pages/test_all.py | 62 ++++++++++++++++++++++++++++++
 tests/form_pages/test_all.py       |  7 +++-
 wcs/wf/form.py                     |  9 +++--
 3 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/tests/backoffice_pages/test_all.py b/tests/backoffice_pages/test_all.py
index 636ec45af..ab3748bc7 100644
--- a/tests/backoffice_pages/test_all.py
+++ b/tests/backoffice_pages/test_all.py
@@ -3236,6 +3236,68 @@ def test_backoffice_workflow_display_form_with_block_add(pub):
     }
 
 
+def test_backoffice_workflow_form_with_other_buttons(pub):
+    user = create_user(pub)
+    create_environment(pub)
+
+    wf = Workflow.get_default_workflow()
+    wf.id = '2'
+    wf.store()
+    wf = Workflow.get(wf.id)
+    status = wf.get_status('new')
+    status.items = []
+    display_form = status.add_action('form', id='_display_form')
+    display_form.by = [user.roles[0]]
+    display_form.varname = 'blah'
+    display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
+    display_form.formdef.fields.append(
+        fields.StringField(id='1', label='Test', varname='str', type='string', required=True)
+    )
+    choice_ok = status.add_action('choice', id='_ok')
+    choice_ok.label = 'OK'
+    choice_ok.status = 'accepted'
+    choice_ok.by = [user.roles[0]]
+
+    choice_ko = status.add_action('choice', id='_ko')
+    choice_ko.label = 'KO'
+    choice_ko.status = 'accepted'
+    choice_ko.ignore_form_errors = True
+    choice_ko.by = [user.roles[0]]
+
+    jump = status.add_action('jumponsubmit', id='_jump')
+    jump.status = 'accepted'
+
+    wf.store()
+    formdef = FormDef.get_by_urlname('form-title')
+    formdef.workflow_id = wf.id
+    formdef.store()
+
+    for button_name in ('submit', 'button_ok', 'button_ko'):
+        formdata = formdef.data_class()()
+        formdata.data = {}
+        formdata.just_created()
+        formdata.jump_status('new')
+        formdata.store()
+
+        app = login(get_app(pub))
+        resp = app.get(formdata.get_url(backoffice=True))
+        resp.form['fblah_1'] = 'blah'
+        resp = resp.form.submit(button_name)
+
+        formdata.refresh_from_storage()
+        pub.substitutions.reset()
+        pub.substitutions.feed(formdata)
+        context = pub.substitutions.get_context_variables(mode='lazy')
+        assert formdata.status == 'wf-accepted'
+        if button_name == 'button_ko':
+            assert context['form_workflow_data_blah_var_str'] == 'blah'  # leak
+            with pytest.raises(KeyError):
+                assert context['form_workflow_form_blah_var_str'] == 'blah'
+        else:
+            assert context['form_workflow_form_blah_var_str'] == 'blah'
+            assert context['form_workflow_data_blah_var_str'] == 'blah'
+
+
 def test_backoffice_criticality_formdata_view(pub):
     create_user(pub)
     create_environment(pub)
diff --git a/tests/form_pages/test_all.py b/tests/form_pages/test_all.py
index 6fd2dda72..c778e9d89 100644
--- a/tests/form_pages/test_all.py
+++ b/tests/form_pages/test_all.py
@@ -8223,8 +8223,11 @@ def test_frontoffice_workflow_form_and_other_button(pub, button_position):
     pub.substitutions.reset()
     pub.substitutions.feed(formdata)
     context = pub.substitutions.get_context_variables(mode='lazy')
-    # check workflow form data is not saved (good)
-    assert 'form_workflow_form_blah_var_foo' not in context
+    # check workflow form data is saved if button comes after form action
+    if button_position == 'before':
+        assert 'form_workflow_form_blah_var_foo' not in context
+    else:
+        assert 'form_workflow_form_blah_var_foo' in context
     # but legacy behaviout it leaks into workflow_data :/
     assert context['form_workflow_data_blah_var_foo'] == 'a'
 
diff --git a/wcs/wf/form.py b/wcs/wf/form.py
index 3b049c3fd..cd6f3c539 100644
--- a/wcs/wf/form.py
+++ b/wcs/wf/form.py
@@ -294,9 +294,12 @@ class FormWorkflowStatusItem(WorkflowStatusItem):
                     add_element_widget = widget.get_widget('add_element')
                     if add_element_widget and add_element_widget.parse():
                         raise RedisplayFormException()
-        if form.get_submit() == 'submit' and not form.has_errors():
-            self.evaluate_live_form(form, formdata, user, submit=True)
-            formdata.store()
+        elif not form.has_errors():
+            button_name = form.get_submit()
+            button = form.get_widget(button_name)
+            if button and not getattr(button, 'ignore_form_errors', False):
+                self.evaluate_live_form(form, formdata, user, submit=True)
+                formdata.store()
         get_publisher().substitutions.unfeed(lambda x: x.__class__.__name__ == 'ConditionVars')
 
     def get_parameters_view(self):
-- 
2.36.1

