Passed
Push — master ( d8e2ec...90ae0b )
by Jordi
10:07 queued 04:19
created

BatchBookView.folderitems()   F

Complexity

Conditions 34

Size

Total Lines 143
Code Lines 112

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 112
dl 0
loc 143
rs 0
c 0
b 0
f 0
cc 34
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like build.bika.lims.browser.batch.batchbook.BatchBookView.folderitems() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE
4
#
5
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
import re
9
from operator import itemgetter
10
11
from AccessControl import getSecurityManager
12
13
from Products.CMFPlone import PloneMessageFactory
14
from Products.CMFCore.permissions import ModifyPortalContent
15
16
from bika.lims import api
17
from bika.lims import bikaMessageFactory as _
18
from bika.lims.browser.bika_listing import BikaListingView
19
from bika.lims.permissions import EditResults
20
from bika.lims.permissions import AddAnalysisRequest
21
from bika.lims.permissions import ManageAnalysisRequests
22
23
24
class BatchBookView(BikaListingView):
25
26
    def __init__(self, context, request):
27
        super(BatchBookView, self).__init__(context, request)
28
        self.icon = self.portal_url + \
29
            "/++resource++bika.lims.images/batchbook_big.png"
30
        self.context_actions = {}
31
        self.contentFilter = {"sort_on": "created"}
32
        self.title = context.Title()
33
        self.Description = context.Description()
34
        self.show_select_all_checkbox = True
35
36
        self.show_column_toggles = True
37
        self.show_select_row = False
38
        self.show_select_column = True
39
        self.pagesize = 999999
40
        self.form_id = "list"
41
        self.page_start_index = 0
42
        self.show_categories = True
43
        self.expand_all_categories = True
44
45
        self.insert_submit_button = False
46
47
        request.set('disable_plone.rightcolumn', 1)
48
49
        self.columns = {
50
            'AnalysisRequest': {
51
                'title': _('Sample'),
52
                'index': 'id',
53
                'sortable': True,
54
            },
55
56
            'SampleType': {
57
                'title': _('Sample Type'),
58
                'sortable': True,
59
            },
60
            'SamplePoint': {
61
                'title': _('Sample Point'),
62
                'sortable': True,
63
            },
64
            'ClientOrderNumber': {
65
                'title': _('Client Order Number'),
66
                'sortable': True,
67
            },
68
            'created': {
69
                'title': PloneMessageFactory('Date Created'),
70
                'index': 'created',
71
                'toggle': False,
72
            },
73
            'state_title': {
74
                'title': _('State'),
75
                'index': 'review_state'
76
            },
77
        }
78
79
        self.review_states = [
80
            {'id': 'default',
81
             'title': _('All'),
82
             'contentFilter': {},
83
             'columns': ['AnalysisRequest',
84
                         'ClientOrderNumber',
85
                         'SampleType',
86
                         'SamplePoint',
87
                         'created',
88
                         'state_title'],
89
             },
90
        ]
91
92
    @property
93
    def copy_to_new_allowed(self):
94
        mtool = api.get_tool('portal_membership')
95
        if mtool.checkPermission(ManageAnalysisRequests, self.context) \
96
                or mtool.checkPermission(ModifyPortalContent, self.context) \
97
                or mtool.checkPermission(AddAnalysisRequest, self.portal):
98
            return True
99
        return False
100
101
    def __call__(self):
102
        # Allow "Modify portal content" to see edit widgets
103
        mtool = api.get_tool('portal_membership')
104
        self.allow_edit = mtool.checkPermission("Modify portal content", self.context)
105
        # Allow certain users to duplicate ARs (Copy to new).
106
        if self.copy_to_new_allowed:
107
            review_states = []
108
            for review_state in self.review_states:
109
                custom_transitions = review_state.get('custom_transitions', [])
110
                custom_transitions.extend(
111
                    [{'id': 'copy_to_new',
112
                      'title': _('Copy to new'),
113
                      'url': 'workflow_action?action=copy_to_new'},
114
                     ])
115
                review_state['custom_transitions'] = custom_transitions
116
                review_states.append(review_state)
117
            self.review_states = review_states
118
        return super(BatchBookView, self).__call__()
119
120
    def folderitems(self):
121
        """Accumulate a list of all AnalysisRequest objects contained in
122
        this Batch, as well as those which are inherited.
123
        """
124
        wf = api.get_tool('portal_workflow')
125
        schema = self.context.Schema()
126
127
        ars = []
128
129
        for o in schema.getField('InheritedObjects').get(self.context):
130
            if o.portal_type == 'AnalysisRequest':
131
                if o not in ars:
132
                    ars.append(o)
133
            elif o.portal_type == 'Batch':
134
                for ar in o.getAnalysisRequests(is_active=True):
135
                    if ar not in ars:
136
                        ars.append(ar)
137
138
        for ar in self.context.getAnalysisRequests(is_active=True):
139
            if ar not in ars:
140
                ars.append(ar)
141
142
        self.categories = []
143
        analyses = {}
144
        items = []
145
        distinct = []  # distinct analyses (each one a different service)
146
        keywords = []
147
        for ar in ars:
148
            analyses[ar.id] = []
149
            for analysis in ar.getAnalyses(full_objects=True):
150
                analyses[ar.id].append(analysis)
151
                if analysis.getKeyword() not in keywords:
152
                    # we use a keyword check, because versioned services are !=.
153
                    keywords.append(analysis.getKeyword())
154
                    distinct.append(analysis)
155
156
            batchlink = ""
157
            batch = ar.getBatch()
158
            if batch:
159
                batchlink = "<a href='%s'>%s</a>" % (
160
                    batch.absolute_url(), batch.Title())
161
162
            arlink = "<a href='%s'>%s</a>" % (
163
                ar.absolute_url(), ar.Title())
164
165
            subgroup = ar.Schema()['SubGroup'].get(ar)
166
            sub_title = subgroup.Title() if subgroup else 'No Subgroup'
167
            sub_sort = subgroup.getSortKey() if subgroup else '1'
168
            sub_class = re.sub(r"[^A-Za-z\w\d\-\_]", '', sub_title)
169
170
            if [sub_sort, sub_title] not in self.categories:
171
                self.categories.append([sub_sort, sub_title])
172
173
            review_state = wf.getInfoFor(ar, 'review_state')
174
            state_title = wf.getTitleForStateOnType(
175
                review_state, 'AnalysisRequest')
176
177
            item = {
178
                'obj': ar,
179
                'id': ar.id,
180
                'uid': ar.UID(),
181
                'category': sub_title,
182
                'title': ar.Title(),
183
                'type_class': 'contenttype-AnalysisRequest',
184
                'url': ar.absolute_url(),
185
                'relative_url': ar.absolute_url(),
186
                'view_url': ar.absolute_url(),
187
                'created': self.ulocalized_time(ar.created(), long_format=1),
188
                'sort_key': ar.created(),
189
                'replace': {
190
                    'Batch': batchlink,
191
                    'AnalysisRequest': arlink,
192
                },
193
                'before': {},
194
                'after': {},
195
                'choices': {},
196
                'class': {'Batch': 'Title'},
197
                'state_class': 'state-active subgroup_{0}'.format(sub_class) if sub_class else 'state-active',
198
                'allow_edit': [],
199
                'Batch': '',
200
                'SamplePoint': ar.getSamplePoint().Title() if ar.getSamplePoint() else '',
201
                'SampleType': ar.getSampleType().Title() if ar.getSampleType() else '',
202
                'ClientOrderNumber': ar.getClientOrderNumber(),
203
                'AnalysisRequest': '',
204
                'state_title': state_title,
205
            }
206
            items.append(item)
207
208
        unitstr = '<em class="discreet" style="white-space:nowrap;">%s</em>'
209
        checkPermission = getSecurityManager().checkPermission
210
211
        # Insert columns for analyses
212
        for d_a in distinct:
213
            keyword = d_a.getKeyword()
214
            short = d_a.getShortTitle()
215
            title = d_a.Title()
216
            self.columns[keyword] = {
217
                'title':  short if short else title,
218
                'sortable': True
219
            }
220
            self.review_states[0]['columns'].insert(
221
                len(self.review_states[0]['columns']) - 1, keyword)
222
223
            # Insert values for analyses
224
            for i, item in enumerate(items):
225
                for analysis in analyses[item['id']]:
226
                    if keyword not in items[i]:
227
                        items[i][keyword] = ''
228
                    if analysis.getKeyword() != keyword:
229
                        continue
230
231
                    edit = checkPermission(EditResults, analysis)
232
                    calculation = analysis.getCalculation()
233
                    if self.allow_edit and edit and not calculation:
234
                        items[i]['allow_edit'].append(keyword)
235
                        if not self.insert_submit_button:
236
                            self.insert_submit_button = True
237
238
                    value = analysis.getResult()
239
                    items[i][keyword] = value
240
                    items[i]['class'][keyword] = ''
241
242
                    if value or (edit and not calculation):
243
244
                        unit = unitstr % d_a.getUnit()
245
                        items[i]['after'][keyword] = unit
246
247
                if keyword not in items[i]['class']:
248
                    items[i]['class'][keyword] = 'empty'
249
        if self.insert_submit_button:
250
            transitions = self.review_states[0].get('custom_transitions', [])
251
            transitions.append({
252
                'id': 'submit',
253
                'title': _('Submit')
254
            })
255
            self.review_states[0]['custom_transitions'] = transitions
256
257
        self.categories.sort()
258
        self.categories = [x[1] for x in self.categories]
259
260
        items = sorted(items, key=itemgetter("sort_key"))
261
262
        return items
263