Passed
Push — master ( 61fb2b...e9b448 )
by Ramon
05:21
created

bika.lims.browser.sample.view   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 605
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 43
eloc 511
dl 0
loc 605
rs 8.96
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A SamplesView._schedule_sampling_permissions() 0 10 1
B SamplesView.__init__() 0 350 3
F SamplesView.folderitem() 0 135 19
D SamplesView.folderitems() 0 32 12
A SampleView.__call__() 0 3 1
A SamplesView.before_render() 0 13 2
A SamplesView.isItemAllowed() 0 11 3
A SamplesView.getFilterBar() 0 10 2

How to fix   Complexity   

Complexity

Complex classes like bika.lims.browser.sample.view 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
from DateTime import DateTime
9
from Products.CMFCore.utils import getToolByName
10
from bika.lims import PMF
11
from bika.lims import api
12
from bika.lims import bikaMessageFactory as _
13
from bika.lims.browser.bika_listing import BikaListingView
14
from bika.lims.browser.sample.samples_filter_bar \
15
    import SamplesBikaListingFilterBar
16
from bika.lims.permissions import *
17
from bika.lims.utils import getUsers
18
from bika.lims.utils import t
19
20
from . import SampleEdit
21
22
23
class SampleView(SampleEdit):
24
    """
25
    The view of a single sample
26
    """
27
    def __call__(self):
28
        self.allow_edit = False
29
        return SampleEdit.__call__(self)
30
31
32
class SamplesView(BikaListingView):
33
    """
34
    A list of samples view (folder view)
35
    """
36
37
    def __init__(self, context, request):
38
        super(SamplesView, self).__init__(context, request)
39
40
        request.set('disable_plone.rightcolumn', 1)
41
42
        self.catalog = 'bika_catalog'
43
        self.contentFilter = {'portal_type': 'Sample',
44
                              'sort_on':'created',
45
                              'sort_order': 'reverse',
46
                              'path': {'query': "/",
47
                                       'level': 0 }
48
                              }
49
        # So far we will only print if the sampling workflow is activated
50
        if self.context.bika_setup.getSamplingWorkflowEnabled():
51
            self.context_actions = {
52
                _('Print sample sheets'): {
53
                    'url': 'print_sampling_sheets',
54
                    'icon': '++resource++bika.lims.images/print_32.png'}
55
                    }
56
        else:
57
                self.context_actions = {}
58
        self.show_sort_column = False
59
        self.show_select_row = False
60
        self.show_select_column = True
61
        self.allow_edit = True
62
        self.form_id = "samples"
63
64
        if self.view_url.find("/samples") > -1:
65
            self.request.set('disable_border', 1)
66
        else:
67
            self.view_url = self.view_url + "/samples"
68
69
        self.icon = self.portal_url + "/++resource++bika.lims.images/sample_big.png"
70
        self.title = self.context.translate(_("Samples"))
71
        self.description = ""
72
        SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled()
73
        mtool = getToolByName(self.context, 'portal_membership')
74
        member = mtool.getAuthenticatedMember()
75
        user_is_preserver = 'Preserver' in member.getRoles()
76
        # Check if the filter bar functionality is activated or not
77
        self.filter_bar_enabled =\
78
            self.context.bika_setup.getDisplayAdvancedFilterBarForSamples()
79
        # Defined in the __init__.py
80
        self.columns = {
81
            'getSampleID': {
82
                'title': _('Sample ID'),
83
                'index': 'getSampleID'},
84
            'Client': {
85
                'title': _("Client"),
86
                'index': 'getClientTitle',
87
                'toggle': True, },
88
            'Creator': {
89
                'title': PMF('Creator'),
90
                'index': 'Creator',
91
                'toggle': True},
92
            'Created': {
93
                'title': PMF('Date Created'),
94
                'index': 'created',
95
                'toggle': False},
96
            'Requests': {
97
                'title': _('Requests'),
98
                'sortable': False,
99
                'toggle': False},
100
            'getClientReference': {
101
                'title': _('Client Ref'),
102
                'index': 'getClientReference',
103
                'toggle': True},
104
            'getClientSampleID': {
105
                'title': _('Client SID'),
106
                'index': 'getClientSampleID',
107
                'toggle': True},
108
            'getSampleTypeTitle': {
109
                'title': _('Sample Type'),
110
                'index': 'getSampleTypeTitle'},
111
            'getSamplePointTitle': {
112
                'title': _('Sample Point'),
113
                'index': 'getSamplePointTitle',
114
                'toggle': False},
115
            'getStorageLocation': {
116
                'sortable': False,
117
                'title': _('Storage Location'),
118
                'toggle': False},
119
            'SamplingDeviation': {
120
                'title': _('Sampling Deviation'),
121
                'sortable': False,
122
                'toggle': False},
123
            'AdHoc': {
124
                'title': _('Ad-Hoc'),
125
                'sortable': False,
126
                'toggle': False},
127
            'SamplingDate': {
128
                'title': _('Sampling Date'),
129
                'index': 'getSamplingDate',
130
                'input_class': 'datetimepicker_nofuture autosave',
131
                'input_width': '10',
132
                'toggle': SamplingWorkflowEnabled},
133
            'DateSampled': {
134
                'title': _('Date Sampled'),
135
                'index': 'getDateSampled',
136
                'toggle': True,
137
                'input_class': 'datetimepicker_nofuture autosave',
138
                'input_width': '10'},
139
            'getSampler': {
140
                'title': _('Sampler'),
141
                'toggle': SamplingWorkflowEnabled},
142
            'getScheduledSamplingSampler': {
143
                'title': _('Sampler for scheduled sampling'),
144
                'input_class': 'autosave',
145
                'sortable': False,
146
                'toggle': self.context.bika_setup.getScheduleSamplingEnabled()
147
                },
148
            'getDatePreserved': {
149
                'title': _('Date Preserved'),
150
                'toggle': user_is_preserver,
151
                'input_class': 'datepicker_nofuture',
152
                'input_width': '10'},
153
            'getPreserver': {
154
                'title': _('Preserver'),
155
                'toggle': user_is_preserver},
156
            'DateReceived': {
157
                'title': _('Date Received'),
158
                'index': 'getDateReceived',
159
                'toggle': False},
160
            'state_title': {
161
                'title': _('State'),
162
                'sortable': False,
163
                'index': 'review_state'},
164
        }
165
166
        self.review_states = [
167
            {'id': 'default',
168
             'title': _('Active'),
169
             'contentFilter': {'cancellation_state': 'active',
170
                               'sort_on': 'created'},
171
             'columns': ['getSampleID',
172
                         'Client',
173
                         'Creator',
174
                         'Created',
175
                         'Requests',
176
                         'getClientReference',
177
                         'getClientSampleID',
178
                         'getSampleTypeTitle',
179
                         'getSamplePointTitle',
180
                         'getStorageLocation',
181
                         'SamplingDeviation',
182
                         'AdHoc',
183
                         'SamplingDate',
184
                         'getScheduledSamplingSampler',
185
                         'DateSampled',
186
                         'getSampler',
187
                         'getDatePreserved',
188
                         'getPreserver',
189
                         'DateReceived',
190
                         'state_title'],
191
             'custom_actions': [{
192
                 'id': 'print_stickers',
193
                 'title': _('Print stickers'),
194
                 'url': 'workflow_action?action=print_stickers'}],},
195
            {'id': 'to_be_sampled',
196
             'title': _('To be sampled'),
197
             'contentFilter': {'review_state': ('to_be_sampled',
198
                                                'scheduled_sampling'),
199
                               'cancellation_state': 'active',
200
                               'sort_on': 'created',
201
                               'sort_order': 'reverse'},
202
             'columns': ['getSampleID',
203
                         'Client',
204
                         'Requests',
205
                         'getClientReference',
206
                         'getClientSampleID',
207
                         'SamplingDate',
208
                         'getScheduledSamplingSampler',
209
                         'DateSampled',
210
                         'getSampler',
211
                         'getPreserver',
212
                         'getSampleTypeTitle',
213
                         'getSamplePointTitle',
214
                         'state_title'],
215
             'transitions': [
216
                {'id': 'schedule_sampling'}, {'id': 'sample'}],
217
             'custom_actions': [{
218
                 'id': 'print_stickers',
219
                 'title': _('Print stickers'),
220
                 'url': 'workflow_action?action=print_stickers'}],
221
             },
222
            {'id': 'sample_due',
223
             'title': _('Due'),
224
             'contentFilter': {'review_state': ('to_be_preserved',
225
                                                'sample_due'),
226
                               'sort_on': 'created',
227
                               'sort_order': 'reverse'},
228
             'columns': ['getSampleID',
229
                         'Client',
230
                         'Creator',
231
                         'Created',
232
                         'Requests',
233
                         'getClientReference',
234
                         'getClientSampleID',
235
                         'SamplingDate',
236
                         'getScheduledSamplingSampler',
237
                         'getScheduledSamplingSampler',
238
                         'DateSampled',
239
                         'getSampler',
240
                         'getDatePreserved',
241
                         'getPreserver',
242
                         'getSampleTypeTitle',
243
                         'getSamplePointTitle',
244
                         'getStorageLocation',
245
                         'SamplingDeviation',
246
                         'AdHoc',
247
                         'state_title']},
248
            {'id': 'sample_received',
249
             'title': _('Received'),
250
             'contentFilter': {'review_state':'sample_received',
251
                              'sort_order': 'reverse',
252
                              'sort_on':'created'},
253
             'columns': ['getSampleID',
254
                         'Client',
255
                         'Creator',
256
                         'Created',
257
                         'Requests',
258
                         'getClientReference',
259
                         'getClientSampleID',
260
                         'getSampleTypeTitle',
261
                         'getSamplePointTitle',
262
                         'getStorageLocation',
263
                         'SamplingDeviation',
264
                         'AdHoc',
265
                         'SamplingDate',
266
                         'getScheduledSamplingSampler',
267
                         'DateSampled',
268
                         'getSampler',
269
                         'getDatePreserved',
270
                         'getPreserver',
271
                         'DateReceived'],
272
             'custom_actions': [{
273
                 'id': 'print_stickers',
274
                 'title': _('Print stickers'),
275
                 'url': 'workflow_action?action=print_stickers'}],},
276
            {'id':'expired',
277
             'title': _('Expired'),
278
             'contentFilter':{'review_state':'expired',
279
                              'sort_order': 'reverse',
280
                              'sort_on':'created'},
281
             'columns': ['getSampleID',
282
                         'Client',
283
                         'Creator',
284
                         'Created',
285
                         'Requests',
286
                         'getClientReference',
287
                         'getClientSampleID',
288
                         'getSampleTypeTitle',
289
                         'getSamplePointTitle',
290
                         'getStorageLocation',
291
                         'SamplingDeviation',
292
                         'AdHoc',
293
                         'SamplingDate',
294
                         'getScheduledSamplingSampler',
295
                         'DateSampled',
296
                         'getSampler',
297
                         'getDatePreserved',
298
                         'getPreserver',
299
                         'DateReceived'],
300
             'custom_actions': [{
301
                 'id': 'print_stickers',
302
                 'title': _('Print stickers'),
303
                 'url': 'workflow_action?action=print_stickers'}],},
304
            {'id':'disposed',
305
             'title': _('Disposed'),
306
             'contentFilter':{'review_state':'disposed',
307
                              'sort_order': 'reverse',
308
                              'sort_on':'created'},
309
             'columns': ['getSampleID',
310
                         'Client',
311
                         'Creator',
312
                         'Created',
313
                         'Requests',
314
                         'getClientReference',
315
                         'getClientSampleID',
316
                         'getSampleTypeTitle',
317
                         'getSamplePointTitle',
318
                         'getStorageLocation',
319
                         'SamplingDeviation',
320
                         'AdHoc',
321
                         'SamplingDate',
322
                         'getScheduledSamplingSampler',
323
                         'DateSampled',
324
                         'getSampler',
325
                         'getDatePreserved',
326
                         'getPreserver',
327
                         'DateReceived'],
328
             'custom_actions': [{
329
                 'id': 'print_stickers',
330
                 'title': _('Print stickers'),
331
                 'url': 'workflow_action?action=print_stickers'}],},
332
            {'id':'cancelled',
333
             'title': _('Cancelled'),
334
             'contentFilter': {'cancellation_state': 'cancelled',
335
                               'sort_order': 'reverse',
336
                               'sort_on':'created'},
337
             'transitions': [{'id':'reinstate'}, ],
338
             'columns': ['getSampleID',
339
                         'Client',
340
                         'Creator',
341
                         'Created',
342
                         'Requests',
343
                         'getClientReference',
344
                         'getClientSampleID',
345
                         'getSampleTypeTitle',
346
                         'getSamplePointTitle',
347
                         'getStorageLocation',
348
                         'SamplingDeviation',
349
                         'AdHoc',
350
                         'SamplingDate',
351
                         'getScheduledSamplingSampler',
352
                         'DateReceived',
353
                         'DateSampled',
354
                         'getSampler',
355
                         'getDatePreserved',
356
                         'getPreserver',
357
                         'state_title']},
358
            {'id': 'rejected',
359
             'title': _('Rejected'),
360
             'contentFilter': {'review_state': 'rejected',
361
                               'sort_order': 'reverse',
362
                               'sort_on': 'created'},
363
             'transitions': [],
364
             'custom_actions': [{
365
                 'id': 'print_stickers',
366
                 'title': _('Print stickers'),
367
                 'url': 'workflow_action?action=print_stickers'}],
368
             'columns': ['getSampleID',
369
                         'Client',
370
                         'Creator',
371
                         'Created',
372
                         'Requests',
373
                         'getClientReference',
374
                         'getClientSampleID',
375
                         'getSampleTypeTitle',
376
                         'getSamplePointTitle',
377
                         'getStorageLocation',
378
                         'SamplingDeviation',
379
                         'AdHoc',
380
                         'SamplingDate',
381
                         'DateReceived',
382
                         'DateSampled',
383
                         'getSampler',
384
                         'getDatePreserved',
385
                         'getPreserver',
386
                         'state_title']},
387
        ]
388
389
    def before_render(self):
390
        """Before template render hook
391
        """
392
        # If the current user is a client contact, display those samples that
393
        # belong to same client only
394
        super(SamplesView, self).before_render()
395
        client = api.get_current_client()
396
        if client:
397
            self.contentFilter['path'] = {
398
                "query": "/".join(client.getPhysicalPath()),
399
                "level": 0 }
400
            # No need to display the Client column
401
            self.remove_column('Client')
402
403
    def folderitem(self, obj, item, index):
404
        workflow = getToolByName(self.context, "portal_workflow")
405
        mtool = getToolByName(self.context, 'portal_membership')
406
        member = mtool.getAuthenticatedMember()
407
        translate = self.context.translate
408
        roles = member.getRoles()
409
        hideclientlink = 'RegulatoryInspector' in roles \
410
            and 'Manager' not in roles \
411
            and 'LabManager' not in roles \
412
            and 'LabClerk' not in roles
413
        if not item.has_key('obj'):
414
            return item
415
        obj = item['obj']
416
417
        item['replace']['getSampleID'] = "<a href='%s'>%s</a>" % \
418
            (item['url'], obj.getSampleID())
419
        item['replace']['Requests'] = ",".join(
420
            ["<a href='%s'>%s</a>" % (o.absolute_url(), o.Title())
421
             for o in obj.getAnalysisRequests()])
422
        item['Client'] = obj.aq_parent.Title()
423
        if hideclientlink == False:
424
            item['replace']['Client'] = "<a href='%s'>%s</a>" % \
425
                (obj.aq_parent.absolute_url(), obj.aq_parent.Title())
426
        item['Creator'] = self.user_fullname(obj.Creator())
427
428
        item['DateReceived'] = self.ulocalized_time(obj.getDateReceived())
429
430
        deviation = obj.getSamplingDeviation()
431
        item['SamplingDeviation'] = deviation and deviation.Title() or ''
432
433
        item['getStorageLocation'] = obj.getStorageLocation() and obj.getStorageLocation().Title() or ''
434
        item['AdHoc'] = obj.getAdHoc() and True or ''
435
436
        item['Created'] = self.ulocalized_time(obj.created(), long_format=1)
437
438
        sd = obj.getSamplingDate()
439
        item['SamplingDate'] = \
440
            self.ulocalized_time(sd, long_format=1) if sd else ''
441
442
        after_icons = ''
443
        if obj.getSampleType().getHazardous():
444
            after_icons += "<img title='%s' " \
445
                "src='%s/++resource++bika.lims.images/hazardous.png'>" % \
446
                (t(_("Hazardous")),
447
                 self.portal_url)
448
        if sd and sd > DateTime():
449
            after_icons += "<img title='%s' " \
450
                "src='%s/++resource++bika.lims.images/calendar.png' >" % \
451
                (t(_("Future dated sample")),
452
                 self.portal_url)
453
        if after_icons:
454
            item['after']['getSampleID'] = after_icons
455
456
        if obj.getSamplingWorkflowEnabled():
457
            datesampled = self.ulocalized_time(
458
                obj.getDateSampled(), long_format=True)
459
            if not datesampled:
460
                datesampled = self.ulocalized_time(
461
                    DateTime(), long_format=True)
462
                item['class']['DateSampled'] = 'provisional'
463
            sampler = obj.getSampler().strip()
464
            if sampler:
465
                item['replace']['getSampler'] = self.user_fullname(sampler)
466
            if 'Sampler' in member.getRoles() and not sampler:
467
                sampler = member.id
468
                item['class']['getSampler'] = 'provisional'
469
        else:
470
            datesampled = self.ulocalized_time(obj.getDateSampled(), long_format=True)
471
            sampler = ''
472
473
        item['DateSampled'] = datesampled
474
        item['getSampler'] = sampler
475
        # sampling workflow - inline edits for Sampler, Date Sampled and
476
        # Scheduled Sampling Sampler
477
        checkPermission = self.context.portal_membership.checkPermission
478
        state = workflow.getInfoFor(obj, 'review_state')
479
        if state in ['to_be_sampled', 'scheduled_sampling']:
480
            item['required'] = []
481
            item['allow_edit'] = []
482
            item['choices'] = {}
483
            samplers = getUsers(obj, ['Sampler', 'LabManager', 'Manager'])
484
            users = [(
485
                {'ResultValue': u, 'ResultText': samplers.getValue(u)})
486
                for u in samplers]
487
            # both situations
488
            if checkPermission(SampleSample, obj) or\
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SampleSample does not seem to be defined.
Loading history...
489
                    self._schedule_sampling_permissions():
490
                item['required'].append('getSampler')
491
                item['allow_edit'].append('getSampler')
492
                item['choices']['getSampler'] = users
493
            # sampling permissions
494
            if checkPermission(SampleSample, obj):
495
                getAuthenticatedMember = self.context.\
496
                    portal_membership.getAuthenticatedMember
497
                username = getAuthenticatedMember().getUserName()
498
                Sampler = sampler and sampler or \
499
                    (username in samplers.keys() and username) or ''
500
                item['required'].append('DateSampled')
501
                item['allow_edit'].append('DateSampled')
502
                item['getSampler'] = Sampler
503
            # coordinator permissions
504
            if self._schedule_sampling_permissions():
505
                item['required'].append('SamplingDate')
506
                item['allow_edit'].append('SamplingDate')
507
                item['required'].append('getScheduledSamplingSampler')
508
                item['allow_edit'].append(
509
                    'getScheduledSamplingSampler')
510
                item['choices']['getScheduledSamplingSampler'] = users
511
        # These don't exist on samples
512
        # the columns exist just to set "preserve" transition from lists.
513
        # XXX This should be a list of preservers...
514
        item['getPreserver'] = ''
515
        item['getDatePreserved'] = ''
516
        # Here we are defining the name of the content field represented by
517
        # the column
518
        item['field']['getSampler'] = 'Sampler'
519
        item['field']['getScheduledSamplingSampler'] =\
520
            'ScheduledSamplingSampler'
521
        # inline edits for Preserver and Date Preserved
522
        checkPermission = self.context.portal_membership.checkPermission
523
        if checkPermission(PreserveSample, obj):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PreserveSample does not seem to be defined.
Loading history...
524
            item['required'] = ['getPreserver', 'getDatePreserved']
525
            item['allow_edit'] = ['getPreserver', 'getDatePreserved']
526
            preservers = getUsers(obj, ['Preserver', 'LabManager', 'Manager'])
527
            getAuthenticatedMember = self.context.portal_membership.getAuthenticatedMember
528
            username = getAuthenticatedMember().getUserName()
529
            users = [({'ResultValue': u, 'ResultText': preservers.getValue(u)})
530
                     for u in preservers]
531
            item['choices'] = {'getPreserver': users}
532
            preserver = username in preservers.keys() and username or ''
533
            item['getPreserver'] = preserver
534
            item['getDatePreserved'] = self.ulocalized_time(DateTime())
535
            item['class']['getPreserver'] = 'provisional'
536
            item['class']['getDatePreserved'] = 'provisional'
537
        return item
538
539
    def folderitems(self, full_objects=False):
540
        items = BikaListingView.folderitems(self, full_objects=False)
541
        # Hide Preservation/Sampling workflow actions if the edit columns
542
        # are not displayed.
543
        # Hide schedule_sampling if user has no rights
544
        toggle_cols = self.get_toggle_cols()
545
        new_states = []
546
        for i,state in enumerate(self.review_states):
547
            if state and self.review_state and state['id'] == self.review_state.get('id', ''):
548
                if 'getSampler' not in toggle_cols \
549
                   or 'DateSampled' not in toggle_cols:
550
                    if 'hide_transitions' in state:
551
                        state['hide_transitions'].append('sample')
552
                    else:
553
                        state['hide_transitions'] = ['sample',]
554
                if 'getPreserver' not in toggle_cols \
555
                   or 'getDatePreserved' not in toggle_cols:
556
                    if 'hide_transitions' in state:
557
                        state['hide_transitions'].append('preserve')
558
                    else:
559
                        state['hide_transitions'] = ['preserve',]
560
                # Check if the user has the rights to schedule samplings and
561
                # the check-box 'ScheduleSamplingEnabled' in bikasetup is set
562
                if self._schedule_sampling_permissions():
563
                    # Show the workflow transition button 'schedule_sampling'
564
                    pass
565
                else:
566
                    # Hiddes the button
567
                    state['hide_transitions'] = ['schedule_sampling', ]
568
            new_states.append(state)
569
        self.review_states = new_states
570
        return items
571
572
    def _schedule_sampling_permissions(self):
573
        """
574
        This function checks if all the 'schedule a sampling' conditions
575
        are met
576
        """
577
        mtool = getToolByName(self.context, 'portal_membership')
578
        member = mtool.getAuthenticatedMember()
579
        roles = member.getRoles()
580
        return self.context.bika_setup.getScheduleSamplingEnabled() and\
581
            ('SamplingCoordinator' in roles or 'Manager' in roles)
582
583
    def isItemAllowed(self, obj):
584
        """
585
        Checks the BikaLIMS conditions and also checks filter bar conditions
586
        @Obj: it is a sample object.
587
        @return: boolean
588
        """
589
        # TODO-performance:we are expecting for the sample object.
590
        # Should be only a brain
591
        if self.filter_bar_enabled and not self.filter_bar_check_item(obj):
592
            return False
593
        return super(SamplesView, self).isItemAllowed(obj)
594
595
    def getFilterBar(self):
596
        """
597
        This function creates an instance of BikaListingFilterBar if the
598
        class has not created one yet.
599
        :returns: a BikaListingFilterBar instance
600
        """
601
        self._advfilterbar = self._advfilterbar if self._advfilterbar else \
602
            SamplesBikaListingFilterBar(
603
                context=self.context, request=self.request)
604
        return self._advfilterbar
605