Passed
Push — 2.x ( d668b2...78a11b )
by Ramon
05:54
created

bika.lims.content.referencesample   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 295
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 30
eloc 199
dl 0
loc 295
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
B ReferenceSample.isValid() 0 19 7
A ReferenceSample._renameAfterCreation() 0 3 1
B ReferenceSample.getReferenceDefinitions() 0 27 7
A ReferenceSample.current_date() 0 2 1
A ReferenceSample.getServices() 0 8 2
A ReferenceSample.workflow_script_dispose() 0 4 1
A ReferenceSample.getSupportedServices() 0 13 3
A ReferenceSample.workflow_script_expire() 0 4 1
A ReferenceSample.getResultsRangeDict() 0 9 2
A ReferenceSample.getManufacturers() 0 10 4
A ReferenceSample.getReferenceAnalyses() 0 3 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-2021 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
"""ReferenceSample represents a reference sample used for quality control testing
22
"""
23
24
from AccessControl import ClassSecurityInfo
25
from bika.lims import api
26
from bika.lims import bikaMessageFactory as _
27
from bika.lims.browser.fields import ReferenceResultsField
28
from bika.lims.browser.widgets import DateTimeWidget as bika_DateTimeWidget
29
from bika.lims.browser.widgets import ReferenceResultsWidget
30
from bika.lims.config import PROJECTNAME
31
from bika.lims.content.bikaschema import BikaSchema
32
from bika.lims.interfaces import IDeactivable
33
from bika.lims.interfaces import IReferenceSample
34
from bika.lims.utils import t
35
from bika.lims.utils import to_unicode as _u
36
from DateTime import DateTime
37
from Products.Archetypes.config import REFERENCE_CATALOG
38
from Products.Archetypes.public import *
39
from Products.Archetypes.references import HoldingReference
40
from Products.CMFCore.utils import getToolByName
41
from senaite.core.p3compat import cmp
42
from zope.interface import implements
43
44
schema = BikaSchema.copy() + Schema((
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable Schema does not seem to be defined.
Loading history...
45
    ReferenceField('ReferenceDefinition',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReferenceField does not seem to be defined.
Loading history...
46
        schemata = 'Description',
47
        allowed_types = ('ReferenceDefinition',),
48
        relationship = 'ReferenceSampleReferenceDefinition',
49
        referenceClass = HoldingReference,
50
        vocabulary = "getReferenceDefinitions",
51
        widget = ReferenceWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReferenceWidget does not seem to be defined.
Loading history...
52
            checkbox_bound = 0,
53
            label=_("Reference Definition"),
54
        ),
55
    ),
56
    BooleanField('Blank',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BooleanField does not seem to be defined.
Loading history...
57
        schemata = 'Description',
58
        default = False,
59
        widget = BooleanWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BooleanWidget does not seem to be defined.
Loading history...
60
            label=_("Blank"),
61
            description=_("Reference sample values are zero or 'blank'"),
62
        ),
63
    ),
64
    BooleanField('Hazardous',
65
        schemata = 'Description',
66
        default = False,
67
        widget = BooleanWidget(
68
            label=_("Hazardous"),
69
            description=_("Samples of this type should be treated as hazardous"),
70
        ),
71
    ),
72
    ReferenceField('Manufacturer',
73
        schemata = 'Description',
74
        allowed_types = ('Manufacturer',),
75
        relationship = 'ReferenceSampleManufacturer',
76
        vocabulary = "getManufacturers",
77
        referenceClass = HoldingReference,
78
        widget = ReferenceWidget(
79
            checkbox_bound = 0,
80
            label=_("Manufacturer"),
81
        ),
82
    ),
83
    StringField('CatalogueNumber',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable StringField does not seem to be defined.
Loading history...
84
        schemata = 'Description',
85
        widget = StringWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable StringWidget does not seem to be defined.
Loading history...
86
            label=_("Catalogue Number"),
87
        ),
88
    ),
89
    StringField('LotNumber',
90
        schemata = 'Description',
91
        widget = StringWidget(
92
            label=_("Lot Number"),
93
        ),
94
    ),
95
    TextField(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable TextField does not seem to be defined.
Loading history...
96
        "Remarks",
97
        allowable_content_types=("text/plain",),
98
        schemata="Description",
99
        widget=TextAreaWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable TextAreaWidget does not seem to be defined.
Loading history...
100
            label=_("Remarks"),
101
        )
102
    ),
103
    DateTimeField('DateSampled',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable DateTimeField does not seem to be defined.
Loading history...
104
        schemata = 'Dates',
105
        widget = bika_DateTimeWidget(
106
            label=_("Date Sampled"),
107
        ),
108
    ),
109
    DateTimeField('DateReceived',
110
        schemata = 'Dates',
111
        default_method = 'current_date',
112
        widget = bika_DateTimeWidget(
113
            label=_("Date Received"),
114
        ),
115
    ),
116
    DateTimeField('DateOpened',
117
        schemata = 'Dates',
118
        widget = bika_DateTimeWidget(
119
            label=_("Date Opened"),
120
        ),
121
    ),
122
    DateTimeField('ExpiryDate',
123
        schemata = 'Dates',
124
        required = 1,
125
        widget = bika_DateTimeWidget(
126
            label=_("Expiry Date"),
127
        ),
128
    ),
129
    DateTimeField('DateExpired',
130
        schemata = 'Dates',
131
        widget = bika_DateTimeWidget(
132
            label=_("Date Expired"),
133
            visible = {'edit':'hidden'},
134
        ),
135
    ),
136
    DateTimeField('DateDisposed',
137
        schemata = 'Dates',
138
        widget = bika_DateTimeWidget(
139
            label=_("Date Disposed"),
140
            visible = {'edit':'hidden'},
141
        ),
142
    ),
143
    ReferenceResultsField('ReferenceResults',
144
        schemata = 'Reference Values',
145
        required = 1,
146
        subfield_validators = {
147
                    'result':'referencevalues_validator',},
148
        widget = ReferenceResultsWidget(
149
            label=_("Expected Values"),
150
        ),
151
    ),
152
    ComputedField('SupplierUID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ComputedField does not seem to be defined.
Loading history...
153
        expression = 'context.aq_parent.UID()',
154
        widget = ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ComputedWidget does not seem to be defined.
Loading history...
155
            visible = False,
156
        ),
157
    ),
158
    ComputedField('ReferenceDefinitionUID',
159
        expression = 'here.getReferenceDefinition() and here.getReferenceDefinition().UID() or None',
160
        widget = ComputedWidget(
161
            visible = False,
162
        ),
163
    ),
164
))
165
166
schema['title'].schemata = 'Description'
167
168
class ReferenceSample(BaseFolder):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BaseFolder does not seem to be defined.
Loading history...
169
    implements(IReferenceSample, IDeactivable)
170
    security = ClassSecurityInfo()
171
    displayContentsTab = False
172
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
173
174
    _at_rename_after_creation = True
175
    def _renameAfterCreation(self, check_auto_id=False):
176
        from bika.lims.idserver import renameAfterCreation
177
        renameAfterCreation(self)
178
179
    security.declarePublic('current_date')
180
    def current_date(self):
181
        return DateTime()
182
183
    def getReferenceDefinitions(self):
184
185
        def make_title(o):
186
            # the javascript uses these strings to decide if it should
187
            # check the blank or hazardous checkboxes when a reference
188
            # definition is selected (./js/referencesample.js)
189
            if not o:
190
                return ''
191
            title = _u(o.Title())
192
            if o.getBlank():
193
                title += " %s" % t(_('(Blank)'))
194
            if o.getHazardous():
195
                title += " %s" % t(_('(Hazardous)'))
196
197
            return title
198
199
        bsc = getToolByName(self, 'senaite_catalog_setup')
200
        defs = [o.getObject() for o in
201
                bsc(portal_type = 'ReferenceDefinition',
202
                    is_active = True)]
203
        items = [('','')] + [(o.UID(), make_title(o)) for o in defs]
204
        o = self.getReferenceDefinition()
205
        it = make_title(o)
206
        if o and (o.UID(), it) not in items:
207
            items.append((o.UID(), it))
208
        items.sort(lambda x,y: cmp(x[1], y[1]))
209
        return DisplayList(list(items))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable DisplayList does not seem to be defined.
Loading history...
210
211
    def getManufacturers(self):
212
        bsc = getToolByName(self, 'senaite_catalog_setup')
213
        items = [('','')] + [(o.UID, o.Title) for o in
214
                               bsc(portal_type='Manufacturer',
215
                                   is_active = True)]
216
        o = self.getReferenceDefinition()
217
        if o and o.UID() not in [i[0] for i in items]:
218
            items.append((o.UID(), o.Title()))
219
        items.sort(lambda x,y: cmp(x[1], y[1]))
220
        return DisplayList(list(items))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable DisplayList does not seem to be defined.
Loading history...
221
222
    security.declarePublic('getResultsRangeDict')
223
    def getResultsRangeDict(self):
224
        specs = {}
225
        for spec in self.getReferenceResults():
226
            uid = spec['uid']
227
            specs[uid] = {}
228
            specs[uid]['result'] = spec['result']
229
            specs[uid]['min'] = spec.get('min', '')
230
            specs[uid]['max'] = spec.get('max', '')
231
        return specs
232
233
    def getSupportedServices(self, only_uids=True):
234
        """Return a list with the services supported by this reference sample,
235
        those for which there is a valid results range assigned in reference
236
        results
237
        :param only_uids: returns a list of uids or a list of objects
238
        :return: list of uids or AnalysisService objects
239
        """
240
        uids = map(lambda range: range['uid'], self.getReferenceResults())
241
        uids = filter(api.is_uid, uids)
242
        if only_uids:
243
            return uids
244
        brains = api.search({'UID': uids}, 'uid_catalog')
245
        return map(api.get_object, brains)
246
247
    security.declarePublic('getReferenceAnalyses')
248
    def getReferenceAnalyses(self):
249
        """ return all analyses linked to this reference sample """
250
        return self.objectValues('ReferenceAnalysis')
251
252
    security.declarePublic('getServices')
253
    def getServices(self):
254
        """ get all services for this Sample """
255
        tool = getToolByName(self, REFERENCE_CATALOG)
256
        services = []
257
        for spec in self.getReferenceResults():
258
            service = tool.lookupObject(spec['uid'])
259
            services.append(service)
260
        return services
261
262
    def isValid(self):
263
        """
264
        Returns if the current Reference Sample is valid. This is, the sample
265
        hasn't neither been expired nor disposed.
266
        """
267
        today = DateTime()
268
        expiry_date = self.getExpiryDate()
269
        if expiry_date and today > expiry_date:
270
            return False
271
        # TODO: Do We really need ExpiryDate + DateExpired? Any difference?
272
        date_expired = self.getDateExpired()
273
        if date_expired and today > date_expired:
274
            return False
275
276
        date_disposed = self.getDateDisposed()
277
        if date_disposed and today > date_disposed:
278
            return False
279
280
        return True
281
282
    # XXX workflow methods
283
    def workflow_script_expire(self):
284
        """ expire sample """
285
        self.setDateExpired(DateTime())
286
        self.reindexObject()
287
288
    def workflow_script_dispose(self):
289
        """ dispose sample """
290
        self.setDateDisposed(DateTime())
291
        self.reindexObject()
292
293
294
registerType(ReferenceSample, PROJECTNAME)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable registerType does not seem to be defined.
Loading history...
295