Projet

Général

Profil

0001-statistics-filter-forms-count-by-fields-60777.patch

Valentin Deniaud, 03 février 2022 18:02

Télécharger (25 ko)

Voir les différences:

Subject: [PATCH 1/2] statistics: filter forms count by fields (#60777)

 tests/admin_pages/test_form.py |  25 +++
 tests/api/test_statistics.py   | 298 +++++++++++++++++++++++++++++++++
 wcs/backoffice/management.py   |   7 +-
 wcs/fields.py                  |  15 +-
 wcs/statistics/views.py        | 105 +++++++++++-
 5 files changed, 444 insertions(+), 6 deletions(-)
tests/admin_pages/test_form.py
3137 3137
    ]
3138 3138
    resp = resp.click('edit page fields', index=0)
3139 3139
    assert '<h2>form title - page 1 - first page</h2>' in resp.text
3140

  
3141

  
3142
def test_field_display_locations_statistics_choice(pub):
3143
    create_superuser(pub)
3144
    create_role(pub)
3145

  
3146
    FormDef.wipe()
3147
    formdef = FormDef()
3148
    formdef.name = 'form title'
3149
    formdef.fields = [
3150
        fields.StringField(id='1', label='String field', varname='1'),
3151
        fields.ItemField(id='2', label='Item field', type='item', varname='2'),
3152
        fields.ItemsField(id='3', label='Items field', type='items', varname='3'),
3153
        fields.BoolField(id='4', label='Bool field', type='bool', varname='4'),
3154
    ]
3155
    formdef.store()
3156
    formdef.data_class().wipe()
3157

  
3158
    app = login(get_app(pub))
3159
    resp = app.get('/backoffice/forms/%s/fields/1/' % formdef.id)
3160
    assert 'Statistics' not in resp.text
3161

  
3162
    for i in range(2, 5):
3163
        resp = app.get('/backoffice/forms/%s/fields/%s/' % (formdef.id, i))
3164
        assert 'Statistics' in resp.text
tests/api/test_statistics.py
3 3

  
4 4
import pytest
5 5

  
6
from wcs import fields
7
from wcs.blocks import BlockDef
6 8
from wcs.categories import Category
7 9
from wcs.formdef import FormDef
8 10
from wcs.qommon.http_request import HTTPRequest
11
from wcs.wf.jump import JumpWorkflowStatusItem
12
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
9 13

  
10 14
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app
11 15
from .utils import sign_uri
......
14 18
@pytest.fixture
15 19
def pub():
16 20
    pub = create_temporary_pub(sql_mode=True)
21
    BlockDef.wipe()
17 22
    Category.wipe()
18 23
    FormDef.wipe()
24
    Workflow.wipe()
19 25

  
20 26
    req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
21 27
    pub.set_app_dir(req)
......
34 40
    return pub
35 41

  
36 42

  
43
@pytest.fixture
44
def formdef(pub):
45
    workflow = Workflow(name='Workflow One')
46
    new_status = workflow.add_status(name='New status')
47
    workflow.add_status(name='End status')
48
    jump = JumpWorkflowStatusItem()
49
    jump.id = '_jump'
50
    jump.status = '2'
51
    jump.timeout = 86400
52
    new_status.items.append(jump)
53
    jump.parent = new_status
54
    workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
55
    workflow.backoffice_fields_formdef.fields = [
56
        fields.BoolField(
57
            id='1', varname='checkbox', label='Checkbox', type='bool', display_locations=['statistics']
58
        ),
59
    ]
60
    workflow.store()
61

  
62
    block = BlockDef()
63
    block.name = 'foobar'
64
    block.fields = [
65
        fields.BoolField(id='1', label='Bool', type='bool', varname='bool', display_locations=['statistics'])
66
    ]
67
    block.store()
68

  
69
    formdef = FormDef()
70
    formdef.name = 'test'
71
    formdef.workflow_id = workflow.id
72
    item_field = fields.ItemField(
73
        id='2', varname='test-item', label='Test item', type='item', items=['foo', 'bar', 'baz']
74
    )
75
    item_field.display_locations = ['statistics']
76
    items_field = fields.ItemsField(
77
        id='3', varname='test-items', label='Test items', type='items', items=['foo', 'bar', 'baz']
78
    )
79
    items_field.display_locations = ['statistics']
80
    block_field = fields.BlockField(id='4', label='Block Data', varname='blockdata', type='block:foobar')
81
    formdef.fields = [item_field, items_field, block_field]
82
    formdef.store()
83
    formdef.data_class().wipe()
84
    return formdef
85

  
86

  
37 87
def teardown_module(module):
38 88
    clean_temporary_pub()
39 89

  
......
58 108
    assert len(category_filter['options']) == 3
59 109

  
60 110

  
111
def test_statistics_index_forms(pub):
112
    formdef = FormDef()
113
    formdef.name = 'test 1'
114
    formdef.fields = []
115
    formdef.store()
116
    formdef.data_class().wipe()
117

  
118
    formdef2 = FormDef()
119
    formdef2.name = 'test 2'
120
    formdef2.fields = []
121
    formdef2.store()
122
    formdef2.data_class().wipe()
123

  
124
    resp = get_app(pub).get(sign_uri('/api/statistics/'))
125
    form_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'form'][0]
126
    assert form_filter['options'] == [
127
        {'id': '_all', 'label': 'All'},
128
        {'id': 'test-1', 'label': 'test 1'},
129
        {'id': 'test-2', 'label': 'test 2'},
130
    ]
131

  
132

  
61 133
def test_statistics_forms_count(pub):
62 134
    category_a = Category(name='Category A')
63 135
    category_a.store()
......
95 167
        'data': {
96 168
            'series': [{'data': [20, 0, 30], 'label': 'Forms Count'}],
97 169
            'x_labels': ['2021-01', '2021-02', '2021-03'],
170
            'subfilters': [],
98 171
        },
99 172
        'err': 0,
100 173
    }
......
104 177
        'data': {
105 178
            'series': [{'data': [50], 'label': 'Forms Count'}],
106 179
            'x_labels': ['2021'],
180
            'subfilters': [],
107 181
        },
108 182
        'err': 0,
109 183
    }
......
113 187
        'data': {
114 188
            'series': [{'data': [30, 0, 0, 0, 20, 0, 0], 'label': 'Forms Count'}],
115 189
            'x_labels': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
190
            'subfilters': [],
116 191
        },
117 192
        'err': 0,
118 193
    }
......
127 202
                }
128 203
            ],
129 204
            'x_labels': list(range(24)),
205
            'subfilters': [],
130 206
        },
131 207
        'err': 0,
132 208
    }
......
140 216
        'data': {
141 217
            'series': [{'data': [20], 'label': 'Forms Count'}],
142 218
            'x_labels': ['2021-01'],
219
            'subfilters': [],
143 220
        },
144 221
        'err': 0,
145 222
    }
146 223

  
224
    # apply form filter
225
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
226
    assert resp.json['data']['series'] == [{'data': [20], 'label': 'Forms Count'}]
227
    assert resp.json['data']['x_labels'] == ['2021-01']
228

  
229
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % 'invalid'), status=400)
230
    assert resp.text == 'invalid form'
231

  
147 232
    # apply period filter
148 233
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?end=2021-02-01'))
149 234
    assert resp.json == {
150 235
        'data': {
151 236
            'series': [{'data': [20], 'label': 'Forms Count'}],
152 237
            'x_labels': ['2021-01'],
238
            'subfilters': [],
153 239
        },
154 240
        'err': 0,
155 241
    }
242

  
243

  
244
def test_statistics_forms_count_subfilters(pub, formdef):
245
    for i in range(2):
246
        formdata = formdef.data_class()()
247
        formdata.data['2'] = 'foo' if i % 2 else 'baz'
248
        formdata.data['2_display'] = 'Foo' if i % 2 else 'Baz'
249
        formdata.data['3'] = ['foo'] if i % 2 else ['bar', 'baz']
250
        formdata.data['3_display'] = 'Foo' if i % 2 else 'Bar, Baz'
251
        formdata.just_created()
252
        formdata.receipt_time = datetime.datetime(2021, 1, 1, 0, 0).timetuple()
253
        formdata.store()
254

  
255
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
256

  
257
    # check item field subfilter
258
    assert resp.json['data']['subfilters'][0] == {
259
        'id': 'filter-test-item',
260
        'label': 'Test item',
261
        'options': [{'id': 'baz', 'label': 'Baz'}, {'id': 'foo', 'label': 'Foo'}],
262
        'required': False,
263
    }
264

  
265
    # check items field subfilter
266
    assert resp.json['data']['subfilters'][1] == {
267
        'id': 'filter-test-items',
268
        'label': 'Test items',
269
        'options': [
270
            {'id': 'bar', 'label': 'Bar'},
271
            {'id': 'baz', 'label': 'Baz'},
272
            {'id': 'foo', 'label': 'Foo'},
273
        ],
274
        'required': False,
275
    }
276

  
277
    # check block boolean field subfilter
278
    assert resp.json['data']['subfilters'][2] == {
279
        'id': 'filter-blockdata_bool',
280
        'label': 'Bool',
281
        'options': [{'id': 'true', 'label': 'Yes'}, {'id': 'false', 'label': 'No'}],
282
        'required': False,
283
    }
284

  
285
    # check boolean backoffice field subfilter
286
    assert resp.json['data']['subfilters'][3] == {
287
        'id': 'filter-checkbox',
288
        'label': 'Checkbox',
289
        'options': [{'id': 'true', 'label': 'Yes'}, {'id': 'false', 'label': 'No'}],
290
        'required': False,
291
    }
292

  
293
    # check status subfilter
294
    assert resp.json['data']['subfilters'][-1] == {
295
        'default': '_all',
296
        'id': 'filter-status',
297
        'label': 'Status',
298
        'options': [
299
            {'id': '_all', 'label': 'All'},
300
            {'id': 'pending', 'label': 'Open'},
301
            {'id': 'done', 'label': 'Done'},
302
            {'id': '1', 'label': 'New status'},
303
            {'id': '2', 'label': 'End status'},
304
        ],
305
        'required': True,
306
    }
307

  
308
    # add item field with no formdata, it should not appear
309
    item_field = fields.ItemField(
310
        id='20',
311
        varname='test-item-no-formdata',
312
        label='Test item no formdata',
313
        type='item',
314
        items=['foo', 'bar', 'baz'],
315
        display_locations=['statistics'],
316
    )
317
    formdef.fields.append(item_field)
318
    formdef.store()
319
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
320
    assert new_resp.json == resp.json
321

  
322
    # add boolean field with no varname, it should not appear
323
    bool_field = fields.BoolField(id='21', label='Checkbox', type='bool', display_locations=['statistics'])
324
    formdef.fields.append(bool_field)
325
    formdef.store()
326
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
327
    assert new_resp.json == resp.json
328

  
329
    # add boolean field with no display location, it should not appear
330
    bool_field = fields.BoolField(
331
        id='22', varname='checkbox', label='Checkbox', type='bool', display_locations=['validation']
332
    )
333
    formdef.fields.append(bool_field)
334
    formdef.store()
335
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
336
    assert new_resp.json == resp.json
337

  
338
    # add not filterable field, it should not appear
339
    formdef.fields.append(fields.StringField(id='23', varname='test string', label='Test', type='string'))
340
    formdef.store()
341
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
342
    assert new_resp.json == resp.json
343

  
344
    # remove fields and statuses
345
    workflow = Workflow(name='Empty wf')
346
    workflow.store()
347
    formdef.workflow = workflow
348
    formdef.fields.clear()
349
    formdef.store()
350
    formdef.data_class().wipe()
351

  
352
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=%s' % formdef.url_name))
353
    assert resp.json['data'] == {
354
        'series': [{'data': [], 'label': 'Forms Count'}],
355
        'subfilters': [],
356
        'x_labels': [],
357
    }
358

  
359

  
360
def test_statistics_forms_count_subfilters_query(pub, formdef):
361
    for i in range(20):
362
        formdata = formdef.data_class()()
363
        formdata.just_created()
364
        if i % 3:
365
            formdata.data['1'] = True
366
            formdata.data['2'] = 'foo'
367
            formdata.data['3'] = ['bar', 'baz']
368
            formdata.data['4'] = {'data': [{'1': True}]}
369
        elif i % 2:
370
            formdata.data['1'] = False
371
            formdata.data['2'] = 'baz'
372
            formdata.data['3'] = ['baz']
373
            formdata.data['4'] = {'data': [{'1': False}]}
374
            formdata.jump_status('2')
375
        formdata.receipt_time = datetime.datetime(2021, 1, 1, 0, 0).timetuple()
376
        formdata.store()
377

  
378
    # query all formdata
379
    url = '/api/statistics/forms/count/?form=%s' % formdef.url_name
380
    resp = get_app(pub).get(sign_uri(url))
381
    assert resp.json['data']['series'][0]['data'][0] == 20
382

  
383
    # filter on boolean field
384
    resp = get_app(pub).get(sign_uri(url + '&filter-checkbox=true'))
385
    assert resp.json['data']['series'][0]['data'][0] == 13
386

  
387
    resp = get_app(pub).get(sign_uri(url + '&filter-checkbox=false'))
388
    assert resp.json['data']['series'][0]['data'][0] == 3
389

  
390
    resp = get_app(pub).get(sign_uri(url + '&filter-checkbox='))
391
    assert resp.json['data']['series'][0]['data'][0] == 20
392

  
393
    resp = get_app(pub).get(sign_uri(url + '&filter-checkbox=xxx'), status=400)
394
    assert resp.text == 'Invalid value "xxx" for "filter-checkbox"'
395

  
396
    # filter on item field
397
    resp = get_app(pub).get(sign_uri(url + '&filter-test-item=foo'))
398
    assert resp.json['data']['series'][0]['data'][0] == 13
399

  
400
    resp = get_app(pub).get(sign_uri(url + '&filter-test-item=baz'))
401
    assert resp.json['data']['series'][0]['data'][0] == 3
402

  
403
    resp = get_app(pub).get(sign_uri(url + '&filter-test-item=bar'))
404
    assert resp.json['data']['series'][0]['data'] == []
405

  
406
    resp = get_app(pub).get(sign_uri(url + '&filter-test-item='))
407
    assert resp.json['data']['series'][0]['data'][0] == 20
408

  
409
    resp = get_app(pub).get(sign_uri(url + '&filter-test-item=xxx'))
410
    assert resp.json['data']['series'][0]['data'] == []
411

  
412
    # filter on items field
413
    resp = get_app(pub).get(sign_uri(url + '&filter-test-items=foo'))
414
    assert resp.json['data']['series'][0]['data'] == []
415

  
416
    resp = get_app(pub).get(sign_uri(url + '&filter-test-items=bar'))
417
    assert resp.json['data']['series'][0]['data'][0] == 13
418

  
419
    resp = get_app(pub).get(sign_uri(url + '&filter-test-items=baz'))
420
    assert resp.json['data']['series'][0]['data'][0] == 16
421

  
422
    # filter on block boolean field
423
    resp = get_app(pub).get(sign_uri(url + '&filter-blockdata_bool=true'))
424
    assert resp.json['data']['series'][0]['data'][0] == 13
425

  
426
    resp = get_app(pub).get(sign_uri(url + '&filter-blockdata_bool=false'))
427
    assert resp.json['data']['series'][0]['data'][0] == 3
428

  
429
    # filter on status
430
    resp = get_app(pub).get(sign_uri(url + '&filter-status=_all'))
431
    assert resp.json['data']['series'][0]['data'][0] == 20
432

  
433
    resp = get_app(pub).get(sign_uri(url + '&filter-status=1'))
434
    assert resp.json['data']['series'][0]['data'][0] == 17
435

  
436
    resp = get_app(pub).get(sign_uri(url + '&filter-status=pending'))
437
    assert resp.json['data']['series'][0]['data'][0] == 17
438

  
439
    resp = get_app(pub).get(sign_uri(url + '&filter-status=2'))
440
    assert resp.json['data']['series'][0]['data'][0] == 3
441

  
442
    resp = get_app(pub).get(sign_uri(url + '&filter-status=done'))
443
    assert resp.json['data']['series'][0]['data'][0] == 3
444

  
445
    resp = get_app(pub).get(sign_uri(url + '&filter-status='))
446
    assert resp.json['data']['series'][0]['data'][0] == 20
447

  
448
    resp = get_app(pub).get(sign_uri(url + '&filter-status=xxx'))
449
    assert resp.json['data']['series'][0]['data'][0] == 20
450

  
451
    # invalid filter
452
    resp = get_app(pub).get(sign_uri(url + '&filter-xxx=yyy'))
453
    assert resp.json['data']['series'][0]['data'] == []
wcs/backoffice/management.py
925 925
            return ('start', 'end')
926 926
        return ()
927 927

  
928
    def get_item_filter_options(self, filter_field, selected_filter, criterias):
928
    def get_item_filter_options(self, filter_field, selected_filter, criterias=None):
929 929
        criterias = (criterias or [])[:]
930 930
        # remove potential filter on self (Equal for item, Intersects for items)
931 931
        criterias = [
......
1579 1579
                field.has_relations = True
1580 1580
                yield RelatedField(carddef, card_field, field)
1581 1581

  
1582
        yield FakeField('status', 'status', _('Status'))
1582
        yield FakeField('status', 'status', _('Status'), include_in_statistics=True)
1583 1583
        yield FakeField('anonymised', 'anonymised', _('Anonymised'))
1584 1584

  
1585 1585
    def get_default_columns(self):
......
3441 3441

  
3442 3442

  
3443 3443
class FakeField:
3444
    def __init__(self, id, type_, label, addable=True):
3444
    def __init__(self, id, type_, label, addable=True, include_in_statistics=False):
3445 3445
        self.id = id
3446 3446
        self.contextual_id = self.id
3447 3447
        self.type = type_
......
3451 3451
        self.contextual_varname = self.varname
3452 3452
        self.store_display_value = None
3453 3453
        self.addable = addable
3454
        self.include_in_statistics = include_in_statistics
3454 3455

  
3455 3456
    def get_view_value(self, value):
3456 3457
        # just here to quack like a duck
wcs/fields.py
255 255
    convert_value_to_str = None
256 256
    convert_value_from_anything = None
257 257
    allow_complex = False
258
    allow_statistics = False
258 259
    display_locations = []
259 260
    prefill = None
260 261
    keep_raw_value = True
......
295 296
    def include_in_summary_page(self):
296 297
        return 'summary' in (self.display_locations or [])
297 298

  
299
    @property
300
    def include_in_statistics(self):
301
        return self.varname and 'statistics' in (self.display_locations or [])
302

  
298 303
    @property
299 304
    def unhtmled_label(self):
300 305
        return force_str(html.unescape(force_text(re.sub('<.*?>', ' ', self.label or ''))).strip())
......
727 732
                widget.extra_css_class = self.extra_css_class
728 733

  
729 734
    def get_display_locations_options(self):
730
        return [
735
        options = [
731 736
            ('validation', _('Validation Page')),
732 737
            ('summary', _('Summary Page')),
733 738
            ('listings', _('Management Listings')),
734 739
        ]
735 740

  
741
        if self.allow_statistics and self.varname:
742
            options.append(('statistics', _('Statistics')))
743

  
744
        return options
745

  
736 746
    def fill_admin_form(self, form):
737 747
        form.add(StringWidget, 'label', title=_('Label'), value=self.label, required=True, size=50)
738 748
        form.add(CheckboxWidget, 'required', title=_('Required'), value=self.required)
......
1233 1243
    key = 'bool'
1234 1244
    description = _('Check Box (single choice)')
1235 1245
    allow_complex = True
1246
    allow_statistics = True
1236 1247

  
1237 1248
    widget_class = CheckboxWidget
1238 1249
    required = False
......
1872 1883
    key = 'item'
1873 1884
    description = _('List')
1874 1885
    allow_complex = True
1886
    allow_statistics = True
1875 1887

  
1876 1888
    items = []
1877 1889
    show_as_radio = None
......
2257 2269
    key = 'items'
2258 2270
    description = _('Multiple choice list')
2259 2271
    allow_complex = True
2272
    allow_statistics = True
2260 2273

  
2261 2274
    items = []
2262 2275
    min_choices = 0
wcs/statistics/views.py
20 20
from quixote import get_publisher
21 21

  
22 22
from wcs.api_utils import is_url_signed
23
from wcs.backoffice.management import FormPage
23 24
from wcs.categories import Category
25
from wcs.formdef import FormDef
24 26
from wcs.qommon import _, misc
25 27
from wcs.qommon.misc import C_
26
from wcs.qommon.storage import Equal
28
from wcs.qommon.storage import Equal, NotEqual, Or
27 29

  
28 30

  
29 31
class RestrictedView(View):
......
42 44
        category_options = [{'id': '_all', 'label': C_('categories|All')}] + [
43 45
            {'id': x.id, 'label': x.name} for x in categories
44 46
        ]
47
        forms = FormDef.select()
48
        forms.sort(key=lambda x: misc.simplify(x.name))
49
        form_options = [{'id': '_all', 'label': _('All')}] + [
50
            {'id': x.url_name, 'label': x.name} for x in forms
51
        ]
45 52
        return JsonResponse(
46 53
            {
47 54
                'data': [
......
81 88
                                'required': True,
82 89
                                'default': '_all',
83 90
                            },
91
                            {
92
                                'id': 'form',
93
                                'label': _('Form'),
94
                                'options': form_options,
95
                                'required': True,
96
                                'default': '_all',
97
                            },
84 98
                        ],
85 99
                    }
86 100
                ]
......
99 113
            'criterias': [],
100 114
        }
101 115
        category_id = request.GET.get('category', '_all')
102
        if category_id != '_all':
116
        formdef_slug = request.GET.get('form', '_all')
117
        subfilters = []
118
        if formdef_slug != '_all':
119
            try:
120
                formdef = FormDef.get_by_urlname(formdef_slug, ignore_migration=True)
121
            except KeyError:
122
                return HttpResponseBadRequest('invalid form')
123
            form_page = FormPage(formdef=formdef, update_breadcrumbs=False)
124

  
125
            totals_kwargs['criterias'].append(Equal('formdef_id', formdef.id))
126
            totals_kwargs['criterias'].extend(self.get_filters_criterias(formdef, form_page))
127

  
128
            subfilters = self.get_subfilters(form_page)
129
        elif category_id != '_all':
103 130
            totals_kwargs['criterias'].append(Equal('category_id', category_id))
131

  
104 132
        time_interval_methods = {
105 133
            'month': sql.get_monthly_totals,
106 134
            'year': sql.get_yearly_totals,
......
122 150
                            'data': [x[1] for x in totals],
123 151
                        }
124 152
                    ],
153
                    'subfilters': subfilters,
125 154
                },
126 155
                'err': 0,
127 156
            }
128 157
        )
158

  
159
    def get_filters_criterias(self, formdef, form_page):
160
        criterias = form_page.get_criterias_from_query()
161

  
162
        selected_status = self.request.GET.get('filter-status')
163
        applied_filters = None
164
        if selected_status and selected_status != '_all':
165
            if selected_status == 'pending':
166
                applied_filters = ['wf-%s' % x.id for x in formdef.workflow.get_not_endpoint_status()]
167
            elif selected_status == 'done':
168
                applied_filters = ['wf-%s' % x.id for x in formdef.workflow.get_endpoint_status()]
169
            else:
170
                try:
171
                    formdef.workflow.get_status(selected_status)
172
                    applied_filters = ['wf-%s' % selected_status]
173
                except KeyError:
174
                    pass
175

  
176
        if applied_filters:
177
            criterias.append(Or([Equal('status', x) for x in applied_filters]))
178
        else:
179
            criterias = [NotEqual('status', 'draft')] + criterias
180

  
181
        return criterias
182

  
183
    @staticmethod
184
    def get_subfilters(form_page):
185
        subfilters = []
186
        for field in form_page.get_formdef_fields():
187
            if not getattr(field, 'include_in_statistics', False) or not field.contextual_varname:
188
                continue
189

  
190
            field_key = 'filter-%s' % field.contextual_varname
191
            field.required = False
192

  
193
            if field.type == 'status':
194
                waitpoint_status = form_page.formdef.workflow.get_waitpoint_status()
195
                if not waitpoint_status:
196
                    continue
197

  
198
                field.required = True
199
                field.default_filter_value = '_all'
200
                options = [
201
                    ('_all', _('All')),
202
                    ('pending', C_('statistics|Open')),
203
                    ('done', _('Done')),
204
                ]
205
                for status in waitpoint_status:
206
                    options.append((status.id, status.name))
207
            elif field.type in ('item', 'items'):
208
                if not get_publisher().is_using_postgresql():
209
                    continue
210
                options = form_page.get_item_filter_options(field, selected_filter='all')
211
                if not options:
212
                    continue
213
            elif field.type == 'bool':
214
                options = [('true', _('Yes')), ('false', _('No'))]
215
            else:
216
                continue
217

  
218
            filter_description = {
219
                'id': field_key,
220
                'label': field.label,
221
                'options': [{'id': x[0], 'label': x[1]} for x in options],
222
                'required': field.required,
223
            }
224
            if hasattr(field, 'default_filter_value'):
225
                filter_description['default'] = field.default_filter_value
226

  
227
            subfilters.append(filter_description)
228

  
229
        return subfilters
129
-