Project

General

Profile

0001-statistics-merge-category-selection-into-form-option.patch

Valentin Deniaud, 16 May 2022 04:29 PM

Download (10.8 KB)

View differences:

Subject: [PATCH] statistics: merge category selection into form options
 (#62532)

 tests/api/test_statistics.py | 112 ++++++++++++++++++++++++++++++++++-
 wcs/statistics/views.py      |  58 ++++++++++++++----
 2 files changed, 156 insertions(+), 14 deletions(-)
tests/api/test_statistics.py
6 6
from wcs import fields
7 7
from wcs.blocks import BlockDef
8 8
from wcs.carddef import CardDef
9
from wcs.categories import Category
9
from wcs.categories import CardDefCategory, Category
10 10
from wcs.formdef import FormDef
11 11
from wcs.qommon.http_request import HTTPRequest
12 12
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
......
112 112
        {'id': 'category-a', 'label': 'Category A'},
113 113
        {'id': 'category-b', 'label': 'Category B'},
114 114
    ]
115
    assert category_filter['deprecated'] is True
115 116

  
116 117

  
117 118
def test_statistics_index_forms(pub):
......
135 136
        {'id': 'test-2', 'label': 'test 2'},
136 137
    ]
137 138

  
139
    category_a = Category(name='Category A')
140
    category_a.store()
141
    category_b = Category(name='Category B')
142
    category_b.store()
143
    formdef2.category_id = category_a.id
144
    formdef2.store()
145

  
146
    formdef3 = FormDef()
147
    formdef3.name = 'test 3'
148
    formdef3.category_id = category_b.id
149
    formdef3.store()
150
    formdef3.data_class().wipe()
151

  
152
    resp = get_app(pub).get(sign_uri('/api/statistics/'))
153
    form_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'form'][0]
154
    assert form_filter['options'] == [
155
        [None, [{'id': '_all', 'label': 'All Forms'}]],
156
        [
157
            'Category A',
158
            [
159
                {'id': 'category:category-a', 'label': 'All forms of category Category A'},
160
                {'id': 'test-2', 'label': 'test 2'},
161
            ],
162
        ],
163
        [
164
            'Category B',
165
            [
166
                {'id': 'category:category-b', 'label': 'All forms of category Category B'},
167
                {'id': 'test-3', 'label': 'test 3'},
168
            ],
169
        ],
170
        ['Misc', [{'id': 'test-1', 'label': 'test 1'}]],
171
    ]
172

  
173
    # check Misc is not shown if all forms have categories
174
    formdef.category_id = category_a.id
175
    formdef.store()
176

  
177
    resp = get_app(pub).get(sign_uri('/api/statistics/'))
178
    form_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'form'][0]
179
    assert form_filter['options'] == [
180
        [None, [{'id': '_all', 'label': 'All Forms'}]],
181
        [
182
            'Category A',
183
            [
184
                {'id': 'category:category-a', 'label': 'All forms of category Category A'},
185
                {'id': 'test-1', 'label': 'test 1'},
186
                {'id': 'test-2', 'label': 'test 2'},
187
            ],
188
        ],
189
        [
190
            'Category B',
191
            [
192
                {'id': 'category:category-b', 'label': 'All forms of category Category B'},
193
                {'id': 'test-3', 'label': 'test 3'},
194
            ],
195
        ],
196
    ]
197

  
198

  
199
def test_statistics_index_cards(pub):
200
    carddef = CardDef()
201
    carddef.name = 'test 1'
202
    carddef.fields = []
203
    carddef.store()
204
    carddef.data_class().wipe()
205

  
206
    carddef2 = CardDef()
207
    carddef2.name = 'test 2'
208
    carddef2.fields = []
209
    carddef2.store()
210
    carddef2.data_class().wipe()
211

  
212
    resp = get_app(pub).get(sign_uri('/api/statistics/'))
213
    form_filter = [x for x in resp.json['data'][1]['filters'] if x['id'] == 'form'][0]
214
    assert form_filter['options'] == [
215
        {'id': 'test-1', 'label': 'test 1'},
216
        {'id': 'test-2', 'label': 'test 2'},
217
    ]
218

  
219
    category_a = CardDefCategory(name='Category A')
220
    category_a.store()
221
    category_b = CardDefCategory(name='Category B')
222
    category_b.store()
223
    carddef2.category_id = category_a.id
224
    carddef2.store()
225

  
226
    carddef3 = CardDef()
227
    carddef3.name = 'test 3'
228
    carddef3.category_id = category_b.id
229
    carddef3.store()
230
    carddef3.data_class().wipe()
231

  
232
    resp = get_app(pub).get(sign_uri('/api/statistics/'))
233
    form_filter = [x for x in resp.json['data'][1]['filters'] if x['id'] == 'form'][0]
234
    assert form_filter['options'] == [
235
        ['Category A', [{'id': 'test-2', 'label': 'test 2'}]],
236
        ['Category B', [{'id': 'test-3', 'label': 'test 3'}]],
237
        ['Misc', [{'id': 'test-1', 'label': 'test 1'}]],
238
    ]
239

  
138 240

  
139 241
def test_statistics_forms_count(pub):
140 242
    category_a = Category(name='Category A')
......
222 324
    # time_interval=day is not supported
223 325
    get_app(pub).get(sign_uri('/api/statistics/forms/count/?time_interval=day'), status=400)
224 326

  
225
    # apply category filter
226
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?category=category-a'))
327
    # apply category filter through form parameter
328
    resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?form=category:category-a'))
227 329
    assert resp.json == {
228 330
        'data': {
229 331
            'series': [{'data': [20], 'label': 'Forms Count'}],
......
233 335
        'err': 0,
234 336
    }
235 337

  
338
    # apply category filter (legacy)
339
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?category=category-a'))
340
    assert new_resp.json == resp.json
341

  
236 342
    # apply category id filter (legacy)
237 343
    new_resp = get_app(pub).get(sign_uri('/api/statistics/forms/count/?category=%s' % category_a.id))
238 344
    assert new_resp.json == resp.json
wcs/statistics/views.py
44 44
    def get(self, request, *args, **kwargs):
45 45
        if not get_publisher().is_using_postgresql():
46 46
            return JsonResponse({'data': [], 'err': 0})
47

  
47 48
        categories = Category.select()
48 49
        categories.sort(key=lambda x: misc.simplify(x.name))
49 50
        category_options = [{'id': '_all', 'label': C_('categories|All')}] + [
50 51
            {'id': x.url_name, 'label': x.name} for x in categories
51 52
        ]
52
        forms = FormDef.select(lightweight=True)
53
        forms.sort(key=lambda x: misc.simplify(x.name))
54
        form_options = [{'id': '_all', 'label': _('All Forms')}] + [
55
            {'id': x.url_name, 'label': x.name} for x in forms
56
        ]
57
        cards = CardDef.select(lightweight=True)
58
        cards.sort(key=lambda x: misc.simplify(x.name))
59
        card_options = [{'id': x.url_name, 'label': x.name} for x in cards]
60 53
        return JsonResponse(
61 54
            {
62 55
                'data': [
......
95 88
                                'options': category_options,
96 89
                                'required': True,
97 90
                                'default': '_all',
91
                                'deprecated': True,
92
                                'deprecation_hint': _(
93
                                    'Category should now be selected using the Form field below.'
94
                                ),
98 95
                            },
99 96
                            {
100 97
                                'id': 'form',
101 98
                                'label': _('Form'),
102
                                'options': form_options,
99
                                'options': self.get_form_options(FormDef),
103 100
                                'required': True,
104 101
                                'default': '_all',
105 102
                                'has_subfilters': True,
......
138 135
                            {
139 136
                                'id': 'form',
140 137
                                'label': _('Card'),
141
                                'options': card_options,
138
                                'options': self.get_form_options(CardDef, include_all_option=False),
142 139
                                'required': True,
143 140
                                'default': '',
144 141
                                'has_subfilters': True,
......
149 146
            }
150 147
        )
151 148

  
149
    @staticmethod
150
    def get_form_options(formdef_class, include_all_option=True):
151
        all_forms_option = [{'id': '_all', 'label': _('All Forms')}]
152

  
153
        forms = formdef_class.select(lightweight=True)
154
        forms.sort(key=lambda x: misc.simplify(x.name))
155

  
156
        forms_with_category = [x for x in forms if x.category]
157
        if not forms_with_category:
158
            form_options = [{'id': x.url_name, 'label': x.name} for x in forms]
159
            return all_forms_option + form_options if include_all_option else form_options
160

  
161
        form_options = collections.defaultdict(list)
162
        for x in forms_with_category:
163
            if x.category.name not in form_options and include_all_option:
164
                form_options[x.category.name] = [
165
                    {
166
                        'id': 'category:' + x.category.url_name,
167
                        'label': _('All forms of category %s') % x.category.name,
168
                    }
169
                ]
170
            form_options[x.category.name].append({'id': x.url_name, 'label': x.name})
171
        form_options = sorted(
172
            ((category, forms) for category, forms in form_options.items()), key=lambda x: misc.simplify(x[0])
173
        )
174

  
175
        forms_without_category_options = [
176
            {'id': x.url_name, 'label': x.name} for x in forms if not x.category
177
        ]
178
        if forms_without_category_options:
179
            form_options.append((_('Misc'), forms_without_category_options))
180

  
181
        if include_all_option:
182
            form_options = [(None, all_forms_option)] + form_options
183

  
184
        return form_options
185

  
152 186

  
153 187
class FormsCountView(RestrictedView):
154 188
    formdef_class = FormDef
......
167 201
        formdef_slug = request.GET.get('form', '_all' if self.has_global_count_support else '_nothing')
168 202
        group_by = request.GET.get('group-by')
169 203
        subfilters = []
170
        if formdef_slug != '_all':
204
        if formdef_slug != '_all' and not formdef_slug.startswith('category:'):
171 205
            try:
172 206
                formdef = self.formdef_class.get_by_urlname(formdef_slug, ignore_migration=True)
173 207
            except KeyError:
......
189 223
        else:
190 224
            totals_kwargs['criterias'].append(StrictNotEqual('status', 'draft'))
191 225

  
226
            if formdef_slug.startswith('category:'):
227
                category_slug = formdef_slug.split(':', 1)[1]
192 228
            if category_slug != '_all':
193 229
                try:
194 230
                    category = Category.get_by_urlname(category_slug)
195
-