Passed
Push — master ( 0b6604...4c3d35 )
by Ramon
04:28
created

InternalUseFieldVisibility.__init__()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE.
4
#
5
# SENAITE.CORE is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free Software
7
# Foundation, version 2.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
# details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 51
16
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#
18
# Copyright 2018-2019 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
from bika.lims import api
22
from bika.lims.interfaces import IATWidgetVisibility
23
from bika.lims.interfaces import IAnalysisRequestSecondary
24
from bika.lims.interfaces import IBatch
25
from bika.lims.interfaces import IClient
26
from bika.lims.utils import getHiddenAttributesForClass
27
from zope.interface import implements
28
29
_marker = []
30
31
32
class SenaiteATWidgetVisibility(object):
33
    implements(IATWidgetVisibility)
34
35
    def __init__(self, context, sort=1000, field_names=None):
36
        self.context = context
37
        self.sort = sort
38
        self.field_names = field_names or list()
39
40
    def __call__(self, context, mode, field, default):
41
        state = default if default else "visible"
42
        if not field or field.getName() not in self.field_names:
43
            return state
44
        return self.isVisible(field, mode, default)
45
46
    def isVisible(self, field, mode="view", default="visible"):
47
        """Returns if the field is visible in a given mode
48
49
        Possible returned values are:
50
        - hidden: Field rendered as a hidden input field
51
        - invisible: Field not rendered at all
52
        - visible: Field rendered as a label or editable field depending on the
53
            mode. E.g. if mode is "edit" and the value returned is "visible",
54
            the field will be rendered as an input. If the mode is "view", the
55
            field will be rendered as a span.
56
        """
57
        raise NotImplementedError("Must be implemented by subclass")
58
59
60
class ClientFieldVisibility(SenaiteATWidgetVisibility):
61
    """The Client field is editable by default in ar_add.  This adapter
62
    will force the Client field to be hidden when it should not be set
63
    by the user.
64
    """
65
    def __init__(self, context):
66
        super(ClientFieldVisibility, self).__init__(
67
            context=context, sort=10, field_names=["Client"])
68
69
    def isVisible(self, field, mode="view", default="visible"):
70
        if mode == "add":
71
            parent = self.context.aq_parent
72
            if IClient.providedBy(parent):
73
                # Note we return "hidden" here instead of "invisible": we want
74
                # the field to be auto-filled and processed on submit
75
                return "hidden"
76
            if IBatch.providedBy(parent) and parent.getClient():
77
                # The Batch has a Client assigned already!
78
                # Note we can have Batches without a client assigned
79
                return "hidden"
80
        elif mode == "edit":
81
            # This is already managed by wf permission, but is **never** a good
82
            # idea to allow the user to change the Client from an AR (basically
83
            # because otherwise, we'd need to move the object from one client
84
            # folder to another!).
85
            return "invisible"
86
        return default
87
88
89
class BatchFieldVisibility(SenaiteATWidgetVisibility):
90
    """This will force the 'Batch' field to 'hidden' in ar_add when the parent
91
    context is a Batch and in Analysis Request view when current user is a
92
    client and the assigned batch does not have a client assigned.
93
    """
94
    def __init__(self, context):
95
        super(BatchFieldVisibility, self).__init__(
96
            context=context, sort=10, field_names=["Batch"])
97
98
    def isVisible(self, field, mode="view", default="visible"):
99
        if IBatch.providedBy(self.context.aq_parent):
100
            return "hidden"
101
102
        if mode == "edit":
103
            client = api.get_current_client()
104
            if client:
105
                # If current user is a client contact and the batch this Sample
106
                # is assigned to does not have a client assigned (e.g., the
107
                # batch was assigned by lab personnel), hide this field
108
                batch = self.context.getBatch()
109
                if batch.getClient() != client:
110
                    return "invisible"
111
112
        return default
113
114
115
class PreservationFieldsVisibility(SenaiteATWidgetVisibility):
116
    """Display/Hide fields related with Preservation Workflow
117
    """
118
    def __init__(self, context):
119
        super(PreservationFieldsVisibility, self).__init__(
120
            context=context, sort=10,
121
            field_names=["DatePreserved", "Preserver"])
122
123
    def isVisible(self, field, mode="view", default="visible"):
124
        if not self.context.bika_setup.getSamplePreservationEnabled():
125
            return "invisible"
126
        return default
127
128
129
class ScheduledSamplingFieldsVisibility(SenaiteATWidgetVisibility):
130
    """Display/Hide fields related with ScheduledSampling Workflow
131
    """
132
    def __init__(self, context):
133
        super(ScheduledSamplingFieldsVisibility, self).__init__(
134
            context=context, sort=10,
135
            field_names=["ScheduledSamplingSampler", "SamplingRound"])
136
137
    def isVisible(self, field, mode="view", default="visible"):
138
        if not self.context.bika_setup.getScheduleSamplingEnabled():
139
            return "invisible"
140
        return default
141
142
143
class SamplingFieldsVisibility(SenaiteATWidgetVisibility):
144
    """
145
    This will handle Handling 'DateSampled' and 'SamplingDate' fields'
146
    visibilities based on Sampling Workflow (SWF)status. We must check the
147
    attribute saved on the sample, not the bika_setup value though. See the
148
    internal comments how it enables/disables WidgetVisibility depending on SWF.
149
    """
150
    def __init__(self, context):
151
        super(SamplingFieldsVisibility, self).__init__(
152
            context=context, sort=10,
153
            field_names=["Sampler", "DateSampled", "SamplingDate"])
154
155
    def isVisible(self, field, mode="view", default="visible"):
156
        # If object has been already created, get SWF statues from it.
157
        swf_enabled = False
158
        if hasattr(self.context, 'getSamplingWorkflowEnabled') and \
159
                self.context.getSamplingWorkflowEnabled() is not '':
160
            swf_enabled = self.context.getSamplingWorkflowEnabled()
161
        else:
162
            swf_enabled = self.context.bika_setup.getSamplingWorkflowEnabled()
163
164
        if mode == "add":
165
            if field.getName() == "DateSampled":
166
                field.required = not swf_enabled
167
                return swf_enabled and "invisible" or "edit"
168
            elif field.getName() == "SamplingDate":
169
                field.required = swf_enabled
170
                return swf_enabled and "edit" or "invisible"
171
            elif field.getName() == "Sampler":
172
                return swf_enabled and "edit" or "invisible"
173
174
        elif not swf_enabled:
175
            if field.getName() != "DateSampled":
176
                return "invisible"
177
178
        return default
179
180
181
class RegistryHiddenFieldsVisibility(SenaiteATWidgetVisibility):
182
    """Do not display fields declared in bika.lims.hiddenattributes registry key
183
    """
184
    def __init__(self, context):
185
        field_names = getHiddenAttributesForClass(context.portal_type)
186
        super(RegistryHiddenFieldsVisibility, self).__init__(
187
            context=context, sort=float("inf"), field_names=[field_names, ])
188
189
    def isVisible(self, field, mode="view", default="visible"):
190
        return "invisible"
191
192
193
class AccountancyFieldsVisibility(SenaiteATWidgetVisibility):
194
    """Display/Hide fields related with Accountancy (Discount, prices, invoice)
195
    """
196
    def __init__(self, context):
197
        super(AccountancyFieldsVisibility, self).__init__(
198
            context=context, sort=3,
199
            field_names=["BulkDiscount", "MemberDiscountApplies",
200
                         "InvoiceExclude", "MemberDiscount"])
201
202
    def isVisible(self, field, mode="view", default="visible"):
203
        if not self.context.bika_setup.getShowPrices():
204
            return "invisible"
205
        return default
206
207
208
class DateReceivedFieldVisibility(SenaiteATWidgetVisibility):
209
    """DateReceived is editable in sample context, only if all related analyses
210
    are not yet submitted and if not a secondary sample.
211
    """
212
    def __init__(self, context):
213
        super(DateReceivedFieldVisibility, self).__init__(
214
            context=context, sort=3, field_names=["DateReceived"])
215
216
    def isVisible(self, field, mode="view", default="visible"):
217
        """Returns whether the field is visible in a given mode
218
        """
219
        if mode != "edit":
220
            return default
221
222
        # If this is a Secondary Analysis Request, this field is not editable
223
        if IAnalysisRequestSecondary.providedBy(self.context):
224
            return "invisible"
225
226
        return self.context.isOpen() and "visible" or "invisible"
227
228
229
class SecondaryDateSampledFieldVisibility(SenaiteATWidgetVisibility):
230
    """DateSampled is editable in sample unless secondary sample
231
    """
232
    def __init__(self, context):
233
        super(SecondaryDateSampledFieldVisibility, self).__init__(
234
            context=context, sort=20, field_names=["DateSampled"])
235
236
    def isVisible(self, field, mode="view", default="visible"):
237
        """Returns whether the field is visible in a given mode
238
        """
239
        if mode != "edit":
240
            return default
241
242
        # If this is a Secondary Analysis Request, this field is not editable
243
        if IAnalysisRequestSecondary.providedBy(self.context):
244
            return "invisible"
245
246
        # Delegate to SamplingFieldsVisibility adapter
247
        return SamplingFieldsVisibility(self.context).isVisible(
248
            field, mode=mode, default=default)
249
250
251
class PrimaryAnalysisRequestFieldVisibility(SenaiteATWidgetVisibility):
252
    """PrimarySample field is not visible unless the current Sample is a
253
    Secondary Sample. And even in such case, the field cannot be edited
254
    """
255
    def __init__(self, context):
256
        super(PrimaryAnalysisRequestFieldVisibility, self).__init__(
257
            context=context, sort=3, field_names=["PrimaryAnalysisRequest"])
258
259
    def isVisible(self, field, mode="view", default="visible"):
260
        """Returns whether the field is visible in a given mode
261
        """
262
        if mode == "add":
263
            return default
264
265
        if not IAnalysisRequestSecondary.providedBy(self.context):
266
            # If not a secondary Analysis Request, don't render the field
267
            return "hidden"
268
269
        # No mather if the mode is edit or view, display it always as readonly
270
        if mode == "edit":
271
            return "invisible"
272
273
        return default
274
275
276
class BatchClientFieldVisibility(SenaiteATWidgetVisibility):
277
    """Client field in a Batch in only editable while it is being created or
278
    when the Batch does not contain any sample
279
    """
280
    def __init__(self, context):
281
        super(BatchClientFieldVisibility, self).__init__(
282
            context=context, sort=3, field_names=["Client"])
283
284
    def isVisible(self, field, mode="view", default="visible"):
285
        """Returns whether the field is visible in a given state
286
        """
287
        if self.context.getClient():
288
            # This batch has a client assigned already and this cannot be
289
            # changed to prevent inconsistencies (client contacts can access
290
            # to batches that belong to their same client)
291
            return "invisible"
292
293
        if mode == "edit":
294
            # This batch does not have a client assigned, but allow the client
295
            # field to be editable only if does not contain any sample
296
            if self.context.getAnalysisRequestsBrains():
297
                return "invisible"
298
299
        return default
300
301
302
class InternalUseFieldVisibility(SenaiteATWidgetVisibility):
303
    """InternalUse field must only be visible to lab personnel
304
    """
305
    def __init__(self, context):
306
        super(InternalUseFieldVisibility, self).__init__(
307
            context=context, sort=3, field_names=["InternalUse"])
308
309
    def isVisible(self, field, mode="view", default="visible"):
310
        """Returns whether the field is visible in a given mode
311
        """
312
        return api.get_current_client() and "invisible" or default
313