From 867b16202740dc2e57f21e908f1bae1a354450de Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 24 Apr 2019 18:25:32 +0200
Subject: [PATCH 2/2] unfeed: clean cached values of substitution variables
 using a condition when editing on workflow (#32558)

---
 tests/test_form_pages.py | 94 ++++++++++++++++++++++++++++++++++++++++
 wcs/forms/root.py        | 11 +++--
 2 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index a760e4b4..0f85d935 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -6226,3 +6226,97 @@ def test_unfeed_structured_list_when_condition_changes(pub):
 
     assert formdata.data['bo1'] == 'B2'
     assert formdata.data['bo2'] == 'moreB2'
+
+def test_form_edit_and_backoffice_field_condition_change(pub):
+    """
+    mix bitween test_form_edit_and_backoffice_field_change
+    and test_unfeed_structured_list_when_condition_changes:
+    test unfeed on ConditionVars within edit context
+    """
+    Workflow.wipe()
+    workflow = Workflow(name='test')
+    workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
+    workflow.backoffice_fields_formdef.fields = [
+        fields.StringField(
+            id='bo1', label='both text', type='string', varname='both_text'),
+        fields.StringField(
+            id='bo2', label='both more', type='string', varname='both_more')
+    ]
+
+    st1 = workflow.add_status('Status1', 'st1')
+    setbo = SetBackofficeFieldsWorkflowStatusItem()
+    setbo.parent = st1
+    setbo.fields = [
+        {'field_id': 'bo1',
+         'value': '{{ form_var_listA }} vs {{ form_var_listB }}'},
+        {'field_id': 'bo2',
+         'value': '{{ form_var_listA_more }} vs {{ form_var_listB_more }}'}
+         ]
+    editable = EditableWorkflowStatusItem()
+    editable.id = '_editable'
+    editable.by = ['_submitter']
+    editable.parent = st1
+    editable.status = st1.id
+    st1.items = [setbo, editable]
+    workflow.store()
+
+    items_A = [{'id': '1', 'text': 'A1', 'more':'moreA1'}]
+    items_B = [{'id': '1', 'text': 'B1', 'more':'moreB1'},
+               {'id': '2', 'text': 'B2', 'more':'moreB2'}]
+    formdef = create_formdef()
+    formdef.fields = [
+        fields.ItemField(id='1', varname='choice', items=['A', 'B'],
+                         type='item', label='list to choice'),
+        fields.ItemField(id='2', varname='listA', type='item', label='list A',
+                         data_source={'type': 'formula', 'value': str(items_A)},
+                         condition={'type': 'python',
+                                    'value': 'form_var_choice_raw == "A"'}),
+        fields.ItemField(id='3', varname='listB', type='item', label='list B',
+                         data_source={'type': 'formula', 'value': str(items_B)},
+                         condition={'type': 'python',
+                                    'value': 'form_var_choice_raw == "B"'})
+        ]
+    formdef.confirmation = False
+    formdef.workflow_id = workflow.id
+    formdef.store()
+    formdef.data_class().wipe()
+
+    create_user(pub)
+    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
+
+    resp.form['f1'].value = 'B'
+    resp.form['f2'].value = '1'
+    resp.form['f3'].value = '2'
+
+    resp = resp.form.submit('submit').follow()
+    assert 'The form has been recorded' in resp.body
+
+    assert formdef.data_class().count() == 1
+    formdata = formdef.data_class().select()[0]
+    assert formdata.data['1'] == 'B'
+    assert formdata.data.get('2') is None
+    assert formdata.data['3'] == '2'
+
+    # check unfeed on FormPage::submitted()
+    assert formdata.data['bo1'] == 'None vs B2'
+    assert formdata.data['bo2'] == ' vs moreB2'
+
+    app = login(get_app(pub), username='foo', password='foo')
+    resp = app.get('/test/%s/' % formdata.id)
+    assert 'button_editable-button' in resp.body
+
+    resp = resp.form.submit('button_editable').follow()
+    assert resp.form['f1'].value == 'B'
+    resp.form['f1'].value = 'A'
+    resp = resp.form.submit('submit').follow()  # -> saved
+    assert 'The form has been recorded' in resp.body
+
+    assert formdef.data_class().count() == 1
+    formdata = formdef.data_class().select()[0]
+    assert formdata.data['1'] == 'A'
+    assert formdata.data['2'] == '1'
+    assert formdata.data.get('3') is None
+
+    # check unfeed on FormPage::submitted_existing()
+    assert formdata.data['bo1'] == 'A1 vs None'
+    assert formdata.data['bo2'] == 'moreA1 vs '
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index 7f92ab53..8e9a3531 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -1117,6 +1117,11 @@ class FormPage(Directory, FormTemplateMixin):
 
         return json.dumps({'result': result})
 
+    @staticmethod
+    def remove_previous_formdata_from_substitution_variables():
+        get_publisher().substitutions.unfeed(lambda x: x.__class__.__name__ == 'ConditionVars')
+        get_publisher().substitutions.unfeed(lambda x: isinstance(x, FormData))
+
     def submitted(self, form, existing_formdata = None):
         if existing_formdata: # modifying
             filled = existing_formdata
@@ -1148,8 +1153,7 @@ class FormPage(Directory, FormTemplateMixin):
         get_logger().info('form %s - done (id: %s)' % (self.formdef.name, filled.id))
         url = None
         if existing_formdata is None:
-            get_publisher().substitutions.unfeed(lambda x: x.__class__.__name__ == 'ConditionVars')
-            get_publisher().substitutions.unfeed(lambda x: isinstance(x, FormData))
+            self.remove_previous_formdata_from_substitution_variables()
             url = filled.perform_workflow()
 
         if not filled.user_id:
@@ -1182,8 +1186,7 @@ class FormPage(Directory, FormTemplateMixin):
                 new_data[k] = v
         self.edited_data.data = new_data
         self.edited_data.store()
-        # remove previous formdata from substitution variables
-        get_publisher().substitutions.unfeed(lambda x: isinstance(x, FormData))
+        self.remove_previous_formdata_from_substitution_variables()
         # and add new one
         get_publisher().substitutions.feed(self.edited_data)
         wf_status = self.edited_data.get_status()
-- 
2.20.1

