Passed
Push — master ( d135c8...c0d002 )
by Ramon
05:03
created

build.bika.lims.adapters.widgetvisibility   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 245
Duplicated Lines 16.33 %

Importance

Changes 0
Metric Value
wmc 50
eloc 134
dl 40
loc 245
rs 8.4
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
B ClientFieldVisibility.isVisible() 0 18 6
A PreservationFieldsVisibility.__init__() 0 4 1
A ScheduledSamplingFieldsVisibility.__init__() 0 4 1
A PrimaryAnalysisRequestFieldVisibility.isVisible() 15 15 4
A RegistryHiddenFieldsVisibility.isVisible() 0 2 1
A DateReceivedFieldVisibility.__init__() 0 3 1
A ScheduledSamplingFieldsVisibility.isVisible() 0 4 2
A BatchFieldVisibility.isVisible() 0 4 2
A SecondaryDateSampledFieldVisibility.isVisible() 10 10 3
A SecondaryDateSampledFieldVisibility.__init__() 3 3 1
A ClientFieldVisibility.__init__() 0 3 1
A SenaiteATWidgetVisibility.__call__() 0 5 4
A BatchFieldVisibility.__init__() 0 3 1
A PreservationFieldsVisibility.isVisible() 0 4 2
C SamplingFieldsVisibility.isVisible() 0 24 9
A AccountancyFieldsVisibility.__init__() 0 5 1
A RegistryHiddenFieldsVisibility.__init__() 0 4 1
A DateReceivedFieldVisibility.isVisible() 0 11 3
A SenaiteATWidgetVisibility.__init__() 0 4 1
A SamplingFieldsVisibility.__init__() 0 4 1
A SenaiteATWidgetVisibility.isVisible() 0 12 1
A PrimaryAnalysisRequestFieldVisibility.__init__() 3 3 1
A AccountancyFieldsVisibility.isVisible() 0 4 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like build.bika.lims.adapters.widgetvisibility 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 bika.lims.interfaces import IATWidgetVisibility
9
from bika.lims.interfaces import IAnalysisRequestSecondary
10
from bika.lims.interfaces import IBatch
11
from bika.lims.interfaces import IClient
12
from bika.lims.utils import getHiddenAttributesForClass
13
from zope.interface import implements
14
15
_marker = []
16
17
18
class SenaiteATWidgetVisibility(object):
19
    implements(IATWidgetVisibility)
20
21
    def __init__(self, context, sort=1000, field_names=None):
22
        self.context = context
23
        self.sort = sort
24
        self.field_names = field_names or list()
25
26
    def __call__(self, context, mode, field, default):
27
        state = default if default else "visible"
28
        if not field or field.getName() not in self.field_names:
29
            return state
30
        return self.isVisible(field, mode, default)
31
32
    def isVisible(self, field, mode="view", default="visible"):
33
        """Returns if the field is visible in a given mode
34
35
        Possible returned values are:
36
        - hidden: Field rendered as a hidden input field
37
        - invisible: Field not rendered at all
38
        - visible: Field rendered as a label or editable field depending on the
39
            mode. E.g. if mode is "edit" and the value returned is "visible",
40
            the field will be rendered as an input. If the mode is "view", the
41
            field will be rendered as a span.
42
        """
43
        raise NotImplementedError("Must be implemented by subclass")
44
45
46
class ClientFieldVisibility(SenaiteATWidgetVisibility):
47
    """The Client field is editable by default in ar_add.  This adapter
48
    will force the Client field to be hidden when it should not be set
49
    by the user.
50
    """
51
    def __init__(self, context):
52
        super(ClientFieldVisibility, self).__init__(
53
            context=context, sort=10, field_names=["Client"])
54
55
    def isVisible(self, field, mode="view", default="visible"):
56
        if mode == "add":
57
            parent = self.context.aq_parent
58
            if IClient.providedBy(parent):
59
                # Note we return "hidden" here instead of "invisible": we want
60
                # the field to be auto-filled and processed on submit
61
                return "hidden"
62
            if IBatch.providedBy(parent) and parent.getClient():
63
                # The Batch has a Client assigned already!
64
                # Note we can have Batches without a client assigned
65
                return "hidden"
66
        elif mode == "edit":
67
            # This is already managed by wf permission, but is **never** a good
68
            # idea to allow the user to change the Client from an AR (basically
69
            # because otherwise, we'd need to move the object from one client
70
            # folder to another!).
71
            return "invisible"
72
        return default
73
74
75
class BatchFieldVisibility(SenaiteATWidgetVisibility):
76
    """This will force the 'Batch' field to 'hidden' in ar_add when the parent
77
    context is a Batch.
78
    """
79
    def __init__(self, context):
80
        super(BatchFieldVisibility, self).__init__(
81
            context=context, sort=10, field_names=["Batch"])
82
83
    def isVisible(self, field, mode="view", default="visible"):
84
        if IBatch.providedBy(self.context.aq_parent):
85
            return "hidden"
86
        return default
87
88
89
class PreservationFieldsVisibility(SenaiteATWidgetVisibility):
90
    """Display/Hide fields related with Preservation Workflow
91
    """
92
    def __init__(self, context):
93
        super(PreservationFieldsVisibility, self).__init__(
94
            context=context, sort=10,
95
            field_names=["DatePreserved", "Preserver"])
96
97
    def isVisible(self, field, mode="view", default="visible"):
98
        if not self.context.bika_setup.getSamplePreservationEnabled():
99
            return "invisible"
100
        return default
101
102
103
class ScheduledSamplingFieldsVisibility(SenaiteATWidgetVisibility):
104
    """Display/Hide fields related with ScheduledSampling Workflow
105
    """
106
    def __init__(self, context):
107
        super(ScheduledSamplingFieldsVisibility, self).__init__(
108
            context=context, sort=10,
109
            field_names=["ScheduledSamplingSampler", "SamplingRound"])
110
111
    def isVisible(self, field, mode="view", default="visible"):
112
        if not self.context.bika_setup.getScheduleSamplingEnabled():
113
            return "invisible"
114
        return default
115
116
117
class SamplingFieldsVisibility(SenaiteATWidgetVisibility):
118
    """
119
    This will handle Handling 'DateSampled' and 'SamplingDate' fields'
120
    visibilities based on Sampling Workflow (SWF)status. We must check the
121
    attribute saved on the sample, not the bika_setup value though. See the
122
    internal comments how it enables/disables WidgetVisibility depending on SWF.
123
    """
124
    def __init__(self, context):
125
        super(SamplingFieldsVisibility, self).__init__(
126
            context=context, sort=10,
127
            field_names=["Sampler", "DateSampled", "SamplingDate"])
128
129
    def isVisible(self, field, mode="view", default="visible"):
130
        # If object has been already created, get SWF statues from it.
131
        swf_enabled = False
132
        if hasattr(self.context, 'getSamplingWorkflowEnabled') and \
133
                self.context.getSamplingWorkflowEnabled() is not '':
134
            swf_enabled = self.context.getSamplingWorkflowEnabled()
135
        else:
136
            swf_enabled = self.context.bika_setup.getSamplingWorkflowEnabled()
137
138
        if mode == "add":
139
            if field.getName() == "DateSampled":
140
                field.required = not swf_enabled
141
                return swf_enabled and "invisible" or "edit"
142
            elif field.getName() == "SamplingDate":
143
                field.required = swf_enabled
144
                return swf_enabled and "edit" or "invisible"
145
            elif field.getName() == "Sampler":
146
                return swf_enabled and "edit" or "invisible"
147
148
        elif not swf_enabled:
149
            if field.getName() != "DateSampled":
150
                return "invisible"
151
152
        return default
153
154
155
class RegistryHiddenFieldsVisibility(SenaiteATWidgetVisibility):
156
    """Do not display fields declared in bika.lims.hiddenattributes registry key
157
    """
158
    def __init__(self, context):
159
        field_names = getHiddenAttributesForClass(context.portal_type)
160
        super(RegistryHiddenFieldsVisibility, self).__init__(
161
            context=context, sort=-1, field_names=[field_names,])
162
163
    def isVisible(self, field, mode="view", default="visible"):
164
        return "invisible"
165
166
167
class AccountancyFieldsVisibility(SenaiteATWidgetVisibility):
168
    """Display/Hide fields related with Accountancy (Discount, prices, invoice)
169
    """
170
    def __init__(self, context):
171
        super(AccountancyFieldsVisibility, self).__init__(
172
            context=context, sort=3,
173
            field_names=["BulkDiscount", "MemberDiscountApplies",
174
                         "InvoiceExclude", "MemberDiscount"])
175
176
    def isVisible(self, field, mode="view", default="visible"):
177
        if not self.context.bika_setup.getShowPrices():
178
            return "invisible"
179
        return default
180
181
182
class DateReceivedFieldVisibility(SenaiteATWidgetVisibility):
183
    """DateReceived is editable in sample context, only if all related analyses
184
    are not yet submitted and if not a secondary sample.
185
    """
186
    def __init__(self, context):
187
        super(DateReceivedFieldVisibility, self).__init__(
188
            context=context, sort=3, field_names=["DateReceived"])
189
190
    def isVisible(self, field, mode="view", default="visible"):
191
        """Returns whether the field is visible in a given mode
192
        """
193
        if mode != "edit":
194
            return default
195
196
        # If this is a Secondary Analysis Request, this field is not editable
197
        if IAnalysisRequestSecondary.providedBy(self.context):
198
            return "invisible"
199
200
        return self.context.isOpen() and "visible" or "invisible"
201
202
203 View Code Duplication
class SecondaryDateSampledFieldVisibility(SenaiteATWidgetVisibility):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
204
    """DateSampled is editable in sample unless secondary sample
205
    """
206
    def __init__(self, context):
207
        super(SecondaryDateSampledFieldVisibility, self).__init__(
208
            context=context, sort=3, field_names=["DateSampled"])
209
210
    def isVisible(self, field, mode="view", default="visible"):
211
        """Returns whether the field is visible in a given mode
212
        """
213
        if mode != "edit":
214
            return default
215
216
        # If this is a Secondary Analysis Request, this field is not editable
217
        if IAnalysisRequestSecondary.providedBy(self.context):
218
            return "invisible"
219
        return default
220
221
222 View Code Duplication
class PrimaryAnalysisRequestFieldVisibility(SenaiteATWidgetVisibility):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
223
    """PrimarySample field is not visible unless the current Sample is a
224
    Secondary Sample. And even in such case, the field cannot be edited
225
    """
226
    def __init__(self, context):
227
        super(PrimaryAnalysisRequestFieldVisibility, self).__init__(
228
            context=context, sort=3, field_names=["PrimaryAnalysisRequest"])
229
230
    def isVisible(self, field, mode="view", default="visible"):
231
        """Returns whether the field is visible in a given mode
232
        """
233
        if mode == "add":
234
            return default
235
236
        if not IAnalysisRequestSecondary.providedBy(self.context):
237
            # If not a secondary Analysis Request, don't render the field
238
            return "hidden"
239
240
        # No mather if the mode is edit or view, display it always as readonly
241
        if mode == "edit":
242
            return "invisible"
243
244
        return default
245