From 7c7b3aa9f1d1a08a89da89e66c4915d1a71d527c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 15 Oct 2021 11:10:56 +0200
Subject: [PATCH] fields: fix live prefill for item fields with carddef
 datasource (#57877)

---
 tests/form_pages/test_live.py        | 84 ++++++++++++++++++++++++++++
 wcs/forms/common.py                  |  6 ++
 wcs/qommon/static/js/qommon.forms.js |  7 ++-
 3 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/tests/form_pages/test_live.py b/tests/form_pages/test_live.py
index 774212ea..7ab84168 100644
--- a/tests/form_pages/test_live.py
+++ b/tests/form_pages/test_live.py
@@ -799,6 +799,90 @@ def test_field_live_string_prefill(pub, http_requests):
     live_resp = app.post('/foo/live?modified_field_id=user', params=resp.form.submit_fields(), status=403)
 
 
+def test_field_live_item_datasource_carddef_prefill(pub, http_requests):
+    CardDef.wipe()
+
+    carddef_related = CardDef()
+    carddef_related.name = 'bar'
+    carddef_related.digest_templates = {'default': '{{ form_var_bar }}'}
+    carddef_related.fields = [
+        fields.StringField(id='1', type='string', label='string', varname='bar'),
+    ]
+    carddef_related.store()
+    carddef_related.data_class().wipe()
+    for value in ['A', 'B', 'C']:
+        carddata = carddef_related.data_class()()
+        carddata.data = {
+            '1': value,
+        }
+        carddata.just_created()
+        carddata.store()
+
+    carddef = CardDef()
+    carddef.name = 'foo'
+    carddef.digest_templates = {'default': '{{ form_var_foo }}'}
+    carddef.fields = [
+        fields.StringField(id='1', type='string', label='string', varname='foo'),
+        fields.ItemField(
+            type='item',
+            id='2',
+            varname='item',
+            data_source={'type': 'carddef:bar'},
+        ),
+    ]
+    carddef.store()
+    carddef.data_class().wipe()
+    carddata1 = carddef.data_class()()
+    carddata1.data = {
+        '1': 'bar',
+        '2': '1',
+        '2_display': 'A',
+    }
+    carddata1.just_created()
+    carddata1.store()
+    carddata2 = carddef.data_class()()
+    carddata2.data = {
+        '1': 'baz',
+        '2': '2',
+        '2_display': 'B',
+    }
+    carddata2.just_created()
+    carddata2.store()
+
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'Foo'
+    formdef.fields = [
+        fields.ItemField(
+            type='item', id='1', label='foo', varname='foo', data_source={'type': 'carddef:foo'}
+        ),
+        fields.ItemField(
+            type='item',
+            id='2',
+            label='item',
+            varname='item',
+            prefill={'type': 'string', 'value': '{{ form_var_foo_live_var_item }}'},
+            data_source={'type': 'carddef:bar'},
+        ),
+    ]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    app = get_app(pub)
+    resp = app.get('/foo/')
+    assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
+    assert resp.pyquery('#var_item.widget-prefilled')  # second field is marked as prefilled
+    assert resp.form['f2'].value == '1'
+    resp.form['f1'] = str(carddata2.id)
+    live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
+    assert live_resp.json['result']['2'] == {'visible': True, 'content': '2'}
+
+    resp.form['f2'] = '3'  # manually changed -> widget-prefilled class will be removed
+    resp.form['f1'] = str(carddata1.id)
+    live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
+    assert live_resp.json['result']['2'] == {'visible': True}
+
+
 def test_field_live_block_string_prefill(pub, http_requests):
     FormDef.wipe()
     BlockDef.wipe()
diff --git a/wcs/forms/common.py b/wcs/forms/common.py
index 6a98af6c..1caa4f67 100644
--- a/wcs/forms/common.py
+++ b/wcs/forms/common.py
@@ -798,6 +798,12 @@ class FormStatusPage(Directory, FormTemplateMixin):
                 update_prefill = bool('prefilled_%s' % field.id in get_request().form)
                 if update_prefill:
                     value = field.get_prefill_value()[0]
+                    if field.key == 'item':
+                        for option in field.get_options():
+                            # get raw value from display value
+                            if option[1] == value:
+                                value = option[0]
+                                break
                     entry['content'] = value
             elif field.prefill and field.prefill.get('type') == 'user':
                 update_prefill = bool(get_request().form.get('modified_field_id') == 'user')
diff --git a/wcs/qommon/static/js/qommon.forms.js b/wcs/qommon/static/js/qommon.forms.js
index e03bf9f0..62017576 100644
--- a/wcs/qommon/static/js/qommon.forms.js
+++ b/wcs/qommon/static/js/qommon.forms.js
@@ -477,9 +477,14 @@ $(function() {
                 // replace comment content
                 $widget.html(value.content);
               } else {
-                // replace text input value
                 if ($(widget).is('.widget-prefilled') || $(widget).is('.widget-readonly') || data.modified_field == 'user') {
+                  // replace text input value
                   $(widget).find('input[type=text], input[type=tel], input[type=numeric], input[type=email], textarea').val(value.content);
+                  // replace select value
+                  $(widget).find('select').val(value.content);
+                  // replace radio value
+                  $(widget).find('input[type=radio]').prop('checked', false);
+                  $(widget).find('input[type=radio][value="'+value.content+'"]').prop('checked', true);
                 }
               }
             });
-- 
2.33.0

