Passed
Push — master ( 70be41...e1228c )
by Ramon
11:12
created

Method.getInstrumentUIDs()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nop 1
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 AccessControl import ClassSecurityInfo
22
from bika.lims import api
23
from bika.lims import bikaMessageFactory as _
24
from bika.lims.browser.fields import UIDReferenceField
25
from bika.lims.config import PROJECTNAME
26
from bika.lims.content.bikaschema import BikaSchema
27
from bika.lims.interfaces import IDeactivable
28
from bika.lims.interfaces import IHaveInstrument
29
from bika.lims.interfaces import IMethod
30
from bika.lims.utils import t
31
from plone.app.blob.field import FileField as BlobFileField
32
from Products.Archetypes.public import BaseFolder
33
from Products.Archetypes.public import BooleanField
34
from Products.Archetypes.public import BooleanWidget
35
from Products.Archetypes.public import ComputedField
36
from Products.Archetypes.public import FileWidget
37
from Products.Archetypes.public import LinesField
38
from Products.Archetypes.public import MultiSelectionWidget
39
from Products.Archetypes.public import Schema
40
from Products.Archetypes.public import SelectionWidget
41
from Products.Archetypes.public import StringField
42
from Products.Archetypes.public import StringWidget
43
from Products.Archetypes.public import TextAreaWidget
44
from Products.Archetypes.public import TextField
45
from Products.Archetypes.public import registerType
46
from Products.Archetypes.utils import DisplayList
47
from Products.CMFCore.utils import getToolByName
48
from zope.interface import implements
49
50
51
schema = BikaSchema.copy() + Schema((
52
53
    # Method ID should be unique, specified on MethodSchemaModifier
54
    StringField(
55
        "MethodID",
56
        searchable=1,
57
        required=0,
58
        validators=("uniquefieldvalidator",),
59
        widget=StringWidget(
60
            visible={"view": "visible", "edit": "visible"},
61
            label=_("Method ID"),
62
            description=_("Define an identifier code for the method. "
63
                          "It must be unique."),
64
        ),
65
    ),
66
67
    TextField(
68
        "Instructions",
69
        default_content_type="text/plain",
70
        allowed_content_types=("text/plain", ),
71
        default_output_type="text/plain",
72
        widget=TextAreaWidget(
73
            label=_("Instructions"),
74
            description=_("Technical description and instructions "
75
                          "intended for analysts"),
76
        ),
77
    ),
78
79
    BlobFileField(
80
        "MethodDocument",  # XXX Multiple Method documents please
81
        widget=FileWidget(
82
            label=_("Method Document"),
83
            description=_("Load documents describing the method here"),
84
        )
85
    ),
86
87
    # The instruments linked to this method. Don't use this
88
    # method, use getInstrumentUIDs() or getInstruments() instead
89
    LinesField(
90
        "_Instruments",
91
        vocabulary="getInstrumentsDisplayList",
92
        widget=MultiSelectionWidget(
93
            modes=("edit"),
94
            label=_("Instruments"),
95
            description=_(
96
                "The selected instruments have support for this method. "
97
                "Use the Instrument edit view to assign "
98
                "the method to a specific instrument"),
99
        ),
100
    ),
101
102
    # All the instruments available in the system. Don't use this
103
    # method to retrieve the instruments linked to this method, use
104
    # getInstruments() or getInstrumentUIDs() instead.
105
    LinesField(
106
        "_AvailableInstruments",
107
        vocabulary="_getAvailableInstrumentsDisplayList",
108
        widget=MultiSelectionWidget(
109
            modes=("edit"),
110
        )
111
    ),
112
113
    # If no instrument selected, always True. Otherwise, the user will
114
    # be able to set or unset the value. The behavior for this field
115
    # is controlled with javascript.
116
    BooleanField(
117
        "ManualEntryOfResults",
118
        default=False,
119
        widget=BooleanWidget(
120
            label=_("Manual entry of results"),
121
            description=_("The results for the Analysis Services that use "
122
                          "this method can be set manually"),
123
            modes=("edit"),
124
        )
125
    ),
126
127
    # Only shown in readonly view. Not in edit view
128
    ComputedField(
129
        "ManualEntryOfResultsViewField",
130
        expression="context.isManualEntryOfResults()",
131
        widget=BooleanWidget(
132
            label=_("Manual entry of results"),
133
            description=_("The results for the Analysis Services that use "
134
                          "this method can be set manually"),
135
            modes=("view"),
136
        ),
137
    ),
138
139
    # Calculations associated to this method. The analyses services
140
    # with this method assigned will use the calculation selected here.
141
    UIDReferenceField(
142
        "Calculation",
143
        vocabulary="_getCalculations",
144
        allowed_types=("Calculation",),
145
        accessor="getCalculationUID",
146
        widget=SelectionWidget(
147
            visible={"edit": "visible", "view": "visible"},
148
            format="select",
149
            checkbox_bound=0,
150
            label=_("Calculation"),
151
            description=_(
152
                "If required, select a calculation for the The analysis "
153
                "services linked to this method. Calculations can be "
154
                "configured under the calculations item in the LIMS set-up"),
155
            catalog_name="bika_setup_catalog",
156
            base_query={"is_active": True},
157
        )
158
    ),
159
    BooleanField(
160
        "Accredited",
161
        schemata="default",
162
        default=True,
163
        widget=BooleanWidget(
164
            label=_("Accredited"),
165
            description=_("Check if the method has been accredited"))
166
    ),
167
))
168
169
schema["description"].schemata = "default"
170
schema["description"].widget.visible = True
171
schema["description"].widget.label = _("Description")
172
schema["description"].widget.description = _(
173
    "Describes the method in layman terms. "
174
    "This information is made available to lab clients")
175
176
177
class Method(BaseFolder):
178
    """Method content
179
    """
180
    implements(IMethod, IDeactivable, IHaveInstrument)
181
182
    security = ClassSecurityInfo()
183
    displayContentsTab = False
184
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
185
    _at_rename_after_creation = True
186
187
    def _renameAfterCreation(self, check_auto_id=False):
188
        from bika.lims.idserver import renameAfterCreation
189
        renameAfterCreation(self)
190
191
    @security.public
192
    def getCalculation(self):
193
        """Returns the assigned calculation
194
195
        :returns: Calculation object
196
        """
197
        return self.getField("Calculation").get(self)
198
199
    @security.public
200
    def getCalculationUID(self):
201
        """Returns the UID of the assigned calculation
202
203
        NOTE: This is the default accessor of the `Calculation` schema field
204
        and needed for the selection widget to render the selected value
205
        properly in _view_ mode.
206
207
        :returns: Calculation UID
208
        """
209
        calculation = self.getCalculation()
210
        if not calculation:
211
            return None
212
        return api.get_uid(calculation)
213
214
    def isManualEntryOfResults(self):
215
        """Indicates if manual entry of results is allowed.
216
217
        If no instrument is selected for this method, returns True. Otherwise,
218
        returns False by default, but its value can be modified using the
219
        ManualEntryOfResults Boolean Field
220
        """
221
        instruments = self.getInstruments()
222
        return len(instruments) == 0 or self.getManualEntryOfResults()
223
224 View Code Duplication
    def _getCalculations(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
225
        """Available Calculations registered in Setup
226
        """
227
        bsc = getToolByName(self, "bika_setup_catalog")
228
        items = [(c.UID, c.Title)
229
                 for c in bsc(portal_type="Calculation",
230
                              is_active=True)]
231
        items.sort(lambda x, y: cmp(x[1], y[1]))
232
        items.insert(0, ("", t(_("None"))))
233
        return DisplayList(items)
234
235
    def getInstrument(self):
236
        """Instruments capable to perform this method.
237
        Required by IHaveInstrument
238
        """
239
        return self.getInstruments()
240
241
    def getInstruments(self):
242
        """Instruments capable to perform this method
243
        """
244
        return self.getBackReferences("InstrumentMethods")
245
246
    def getInstrumentUIDs(self):
247
        """UIDs of the instruments capable to perform this method
248
        """
249
        return map(api.get_uid, self.getInstruments())
250
251
    def getInstrumentsDisplayList(self):
252
        """Instruments capable to perform this method
253
        """
254
        items = [(i.UID(), i.Title()) for i in self.getInstruments()]
255
        return DisplayList(list(items))
256
257 View Code Duplication
    def _getAvailableInstrumentsDisplayList(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
258
        """Available instruments registered in the system
259
260
        Only instruments with state=active will be fetched
261
        """
262
        bsc = getToolByName(self, "bika_setup_catalog")
263
        items = [(i.UID, i.Title)
264
                 for i in bsc(portal_type="Instrument",
265
                              is_active=True)]
266
        items.sort(lambda x, y: cmp(x[1], y[1]))
267
        return DisplayList(list(items))
268
269
270
registerType(Method, PROJECTNAME)
271