From ee9b7eecb07dd73c44357ed2fe37201b401bb1f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 4 Mar 2022 11:00:37 +0100
Subject: [PATCH] backoffice: sort by display for fields with display value
 (#60742)

---
 tests/backoffice_pages/test_sort.py | 89 +++++++++++++++++++++++++++--
 wcs/forms/backoffice.py             | 16 ++++--
 2 files changed, 94 insertions(+), 11 deletions(-)

diff --git a/tests/backoffice_pages/test_sort.py b/tests/backoffice_pages/test_sort.py
index e464624f9..3872e631e 100644
--- a/tests/backoffice_pages/test_sort.py
+++ b/tests/backoffice_pages/test_sort.py
@@ -278,6 +278,86 @@ def test_backoffice_varname_order(pub):
     assert ids == list(reversed(formdata_ids))
 
 
+def test_backoffice_item_columns_order(pub):
+    pub.user_class.wipe()
+    create_superuser(pub)
+    pub.role_class.wipe()
+    role = pub.role_class(name='test')
+    role.store()
+
+    CardDef.wipe()
+    carddef = CardDef()
+    carddef.name = 'foo'
+    carddef.fields = [
+        fields.StringField(id='1', label='First Name', type='string', varname='first_name'),
+        fields.StringField(id='2', label='Last Name', type='string', varname='last_name'),
+    ]
+    carddef.digest_templates = {'default': '{{ form_var_first_name }} {{ form_var_last_name }}'}
+    carddef.store()
+    carddef.data_class().wipe()
+    card = carddef.data_class()()
+    card.data = {
+        '1': 'Foo',
+        '2': 'Bar',
+    }
+    card.store()
+    card2 = carddef.data_class()()
+    card2.data = {
+        '1': 'Bar2',
+        '2': 'Foo2',
+    }
+    card2.store()
+
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'form-title'
+    formdef.fields = [
+        fields.ItemField(
+            id='456', label='card field', type='item', data_source={'type': 'carddef:foo'}, varname='item'
+        ),
+    ]
+    formdef.workflow_roles = {'_receiver': role.id}
+    formdef.store()
+
+    data_class = formdef.data_class()
+    data_class.wipe()
+
+    formdata1 = data_class()
+    formdata1.data = {'456': str(card.id), '456_display': card.default_digest}
+    formdata1.just_created()
+    formdata1.jump_status('new')
+    formdata1.store()
+
+    formdata2 = data_class()
+    formdata2.data = {'456': str(card2.id), '456_display': card2.default_digest}
+    formdata2.just_created()
+    formdata2.jump_status('new')
+    formdata2.store()
+
+    formdata3 = data_class()
+    formdata3.data = {}
+    formdata3.just_created()
+    formdata3.jump_status('new')
+    formdata3.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/management/form-title/?order_by=f456')
+    ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
+    assert ids == [formdata2.id, formdata1.id, formdata3.id]
+
+    resp = app.get('/backoffice/management/form-title/?order_by=-f456')
+    ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
+    assert ids == [formdata3.id, formdata1.id, formdata2.id]
+
+    resp = app.get('/backoffice/management/form-title/?order_by=item')
+    ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
+    assert ids == [formdata2.id, formdata1.id, formdata3.id]
+
+    resp = app.get('/backoffice/management/form-title/?order_by=-item')
+    ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
+    assert ids == [formdata3.id, formdata1.id, formdata2.id]
+
+
 def test_backoffice_block_columns_order(pub):
     pub.user_class.wipe()
     create_superuser(pub)
@@ -367,20 +447,19 @@ def test_backoffice_block_columns_order(pub):
     formdata3.jump_status('new')
     formdata3.store()
 
-    # XXX ordering is done on card id, to be fixed with #60742
     app = login(get_app(pub))
     resp = app.get('/backoffice/management/form-title/?order_by=f8-456')
     ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
-    assert ids == [formdata1.id, formdata2.id, formdata3.id]
+    assert ids == [formdata2.id, formdata1.id, formdata3.id]
 
     resp = app.get('/backoffice/management/form-title/?order_by=-f8-456')
     ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
-    assert ids == [formdata3.id, formdata2.id, formdata1.id]
+    assert ids == [formdata3.id, formdata1.id, formdata2.id]
 
     resp = app.get('/backoffice/management/form-title/?order_by=data_item')
     ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
-    assert ids == [formdata1.id, formdata2.id, formdata3.id]
+    assert ids == [formdata2.id, formdata1.id, formdata3.id]
 
     resp = app.get('/backoffice/management/form-title/?order_by=-data_item')
     ids = [int(x.strip('/')) for x in re.findall(r'data-link="(.*?)"', resp.text)]
-    assert ids == [formdata3.id, formdata2.id, formdata1.id]
+    assert ids == [formdata3.id, formdata1.id, formdata2.id]
diff --git a/wcs/forms/backoffice.py b/wcs/forms/backoffice.py
index 5a036f59e..a99965b76 100644
--- a/wcs/forms/backoffice.py
+++ b/wcs/forms/backoffice.py
@@ -222,21 +222,25 @@ class FormDefUI:
             if order_by.startswith('-'):
                 order_by = order_by[1:]
                 direction = '-'
-            field_found = False
             for field in self.formdef.iter_fields(include_block_fields=True):
                 if getattr(field, 'block_field', None):
                     if field.key == 'items':
                         # not yet
                         continue
-                if order_by in [field.contextual_varname, 'f%s' % field.contextual_id]:
-                    field_found = True
+                if order_by not in [field.contextual_varname, 'f%s' % field.contextual_id]:
+                    continue
                 if field.contextual_varname == order_by:
                     order_by = "f%s" % field.contextual_id
                 if getattr(field, 'block_field', None) and 'f%s' % field.contextual_id == order_by:
                     # field of block field, sort on the first element
-                    order_by = "f%s->'data'->0->>'%s'" % (field.block_field.id, field.id)
-                if field_found:
-                    break
+                    order_by = "f%s->'data'->0->>'%s%s'" % (
+                        field.block_field.id,
+                        field.id,
+                        "_display" if field.store_display_value else "",
+                    )
+                elif field.store_display_value:
+                    order_by += "_display"
+                break
             order_by = '%s%s' % (direction, order_by)
             ordered_ids = formdata_class.get_sorted_ids(order_by, clause=criterias)
             item_ids_dict = {x: True for x in item_ids}
-- 
2.34.1

