Passed
Push — master ( af2087...3e7509 )
by Ramon
05:04
created

bika.lims.content.sample   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 827
Duplicated Lines 6.05 %

Importance

Changes 0
Metric Value
wmc 58
eloc 658
dl 50
loc 827
rs 4.502
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A Sample.guard_to_be_preserved() 0 3 1
A Sample.disposal_date() 0 15 4
A Sample.getSamplers() 0 2 1
A Sample.getLastARNumber() 0 9 2
A Sample.getAnalyses() 0 12 3
A Sample.getSamplePartitions() 0 5 1
A Sample.getClientTitle() 0 6 2
A Sample.guard_receive_transition() 0 3 1
A Sample.getContactTitle() 0 2 1
A Sample.Title() 0 3 1
A Sample.setClientReference() 0 6 2
A Sample.setAdHoc() 0 6 2
A Sample._renameAfterCreation() 0 3 1
A Sample.guard_schedule_sampling_transition() 0 3 1
A Sample._getCatalogTool() 0 3 1
A Sample.getAnalysisRequests() 0 4 1
A Sample.getProfilesTitle() 0 2 1
A Sample.setClientSampleID() 0 6 2
B Sample.setSamplePoint() 20 20 7
B Sample.setSampleType() 20 20 6
A Sample.getSampleID() 0 3 1
A Sample.getSampleState() 0 5 1
A Sample.getSamplingWorkflowEnabledDefault() 0 2 1
A Sample.getAnalysisService() 0 10 4
A Sample.getAnalysts() 10 10 4
A Sample.setComposite() 0 6 2
A Sample.getBatchUIDs() 0 11 4

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 bika.lims.content.sample 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
"""Sample represents a physical sample submitted for testing
9
"""
10
from AccessControl import ClassSecurityInfo
11
from bika.lims import bikaMessageFactory as _
12
from bika.lims.api import get_object_by_uid
13
from bika.lims.browser.fields.remarksfield import RemarksField
14
from bika.lims.browser.fields.uidreferencefield import get_backreferences
15
from bika.lims.utils import t, getUsers
16
from Products.ATExtensions.field import RecordsField
17
from bika.lims.browser.widgets.datetimewidget import DateTimeWidget
18
from bika.lims.browser.widgets import RejectionWidget
19
from bika.lims.browser.widgets import RemarksWidget
20
from bika.lims.config import PROJECTNAME
21
from bika.lims.content.bikaschema import BikaSchema
22
from bika.lims.interfaces import ISample
23
from bika.lims.permissions import SampleSample
24
from bika.lims.permissions import ScheduleSampling
25
from bika.lims.workflow.sample import guards
26
from Products.Archetypes import atapi
27
from Products.Archetypes.public import *
28
from Products.Archetypes.references import HoldingReference
29
from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin
30
from Products.ATContentTypes.utils import DT2dt, dt2DT
31
from Products.CMFCore import permissions
32
from Products.CMFCore.utils import getToolByName
33
from Products.CMFPlone.utils import safe_unicode
34
from zope.interface import implements
35
36
from bika.lims.browser.fields import DateTimeField
37
from bika.lims.browser.widgets import ReferenceWidget
38
from bika.lims.browser.widgets import SelectionWidget as BikaSelectionWidget
39
40
import sys
41
from bika.lims.utils import to_unicode
42
43
schema = BikaSchema.copy() + Schema((
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Schema'
Loading history...
Comprehensibility Best Practice introduced by
The variable Schema does not seem to be defined.
Loading history...
44
    StringField('SampleID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
Comprehensibility Best Practice introduced by
The variable StringField does not seem to be defined.
Loading history...
45
        required=1,
46
        searchable=True,
47
        mode="rw",
48
        read_permission=permissions.View,
49
        write_permission=permissions.ModifyPortalContent,
50
        widget=StringWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringWidget'
Loading history...
Comprehensibility Best Practice introduced by
The variable StringWidget does not seem to be defined.
Loading history...
51
            label=_("Sample ID"),
52
            description=_("The ID assigned to the client's sample by the lab"),
53
            visible={'edit': 'invisible',
54
                     'view': 'invisible'},
55
            render_own_label=True,
56
        ),
57
    ),
58
    StringField('ClientReference',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
59
        mode="rw",
60
        read_permission=permissions.View,
61
        write_permission=permissions.ModifyPortalContent,
62
        widget=StringWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringWidget'
Loading history...
63
            label=_("Client Reference"),
64
            visible={'edit': 'visible',
65
                     'view': 'visible',
66
                     'header_table': 'visible',
67
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
68
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
69
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
70
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
71
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
72
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
73
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
74
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
75
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
76
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
77
                     },
78
            render_own_label=True,
79
        ),
80
    ),
81
    StringField('ClientSampleID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
82
        mode="rw",
83
        read_permission=permissions.View,
84
        write_permission=permissions.ModifyPortalContent,
85
        widget=StringWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringWidget'
Loading history...
86
            label=_("Client SID"),
87
            visible={'edit': 'visible',
88
                     'view': 'visible',
89
                     'header_table': 'visible',
90
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
91
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
92
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
93
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
94
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
95
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
96
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
97
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
98
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
99
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
100
                     },
101
            render_own_label=True,
102
        ),
103
    ),
104
    ReferenceField('SampleType',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReferenceField does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'ReferenceField'
Loading history...
105
        required=1,
106
        vocabulary_display_path_bound=sys.maxsize,
107
        allowed_types=('SampleType',),
108
        relationship='SampleSampleType',
109
        referenceClass=HoldingReference,
110
        mode="rw",
111
        read_permission=permissions.View,
112
        write_permission=permissions.ModifyPortalContent,
113
        widget=ReferenceWidget(
114
            label=_("Sample Type"),
115
            render_own_label=True,
116
            visible={'edit': 'visible',
117
                     'view': 'visible',
118
                     'header_table': 'visible',
119
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
120
                     'to_be_sampled':     {'view': 'visible', 'edit': 'invisible'},
121
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
122
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
123
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
124
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
125
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
126
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
127
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
128
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
129
                     },
130
            catalog_name='bika_setup_catalog',
131
            base_query={'inactive_state': 'active'},
132
            showOn=True,
133
        ),
134
    ),
135
    ComputedField('SampleTypeTitle',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ComputedField does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
136
        expression="here.getSampleType() and here.getSampleType().Title() or ''",
137
        widget=ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ComputedWidget does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedWidget'
Loading history...
138
            visible=False,
139
        ),
140
    ),
141
    ReferenceField('SamplePoint',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ReferenceField'
Loading history...
142
        vocabulary_display_path_bound=sys.maxsize,
143
        allowed_types=('SamplePoint',),
144
        relationship = 'SampleSamplePoint',
145
        referenceClass = HoldingReference,
146
        mode="rw",
147
        read_permission=permissions.View,
148
        write_permission=permissions.ModifyPortalContent,
149
        widget=ReferenceWidget(
150
            label=_("Sample Point"),
151
            render_own_label=True,
152
            visible={'edit': 'visible',
153
                     'view': 'visible',
154
                     'header_table': 'visible',
155
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
156
                     'to_be_sampled':     {'view': 'visible', 'edit': 'invisible'},
157
                     'scheduled_sampling': {'view': 'visible', 'edit': 'invisible'},
158
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
159
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
160
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
161
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
162
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
163
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
164
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
165
                     },
166
            catalog_name='bika_setup_catalog',
167
            base_query={'inactive_state': 'active'},
168
            showOn=True,
169
        ),
170
    ),
171
    ComputedField('SamplePointTitle',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
172
        expression = "here.getSamplePoint() and here.getSamplePoint().Title() or ''",
173
        widget = ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedWidget'
Loading history...
174
            visible=False,
175
        ),
176
    ),
177
    ReferenceField(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ReferenceField'
Loading history...
178
        'StorageLocation',
179
        allowed_types='StorageLocation',
180
        relationship='AnalysisRequestStorageLocation',
181
        mode="rw",
182
        read_permission=permissions.View,
183
        write_permission=permissions.ModifyPortalContent,
184
        widget=ReferenceWidget(
185
            label=_("Storage Location"),
186
            description=_("Location where sample is kept"),
187
            size=20,
188
            render_own_label=True,
189
            visible={'edit': 'visible',
190
                     'view': 'visible',
191
                     'header_table': 'visible',
192
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
193
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
194
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
195
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
196
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
197
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
198
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
199
                     'expired':           {'view': 'visible', 'edit': 'visible'},
200
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
201
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
202
                     },
203
            catalog_name='bika_setup_catalog',
204
            base_query={'inactive_state': 'active'},
205
            showOn=True,
206
        ),
207
    ),
208
    BooleanField('SamplingWorkflowEnabled',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BooleanField does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'BooleanField'
Loading history...
209
                 default_method='getSamplingWorkflowEnabledDefault'
210
    ),
211
    DateTimeField('DateSampled',
212
        mode="rw",
213
        read_permission=permissions.View,
214
        write_permission=SampleSample,
215
        widget = DateTimeWidget(
216
            label=_("Date Sampled"),
217
            show_time=True,
218
            size=20,
219
            visible={'edit': 'visible',
220
                     'view': 'visible',
221
                     'header_table': 'visible',
222
                     'sample_registered': {'view': 'invisible', 'edit': 'invisible'},
223
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
224
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
225
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
226
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
227
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
228
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
229
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
230
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
231
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
232
                     },
233
            render_own_label=True,
234
        ),
235
    ),
236
    StringField('Sampler',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
237
        mode="rw",
238
        read_permission=permissions.View,
239
        write_permission=SampleSample,
240
        vocabulary='getSamplers',
241
        widget=BikaSelectionWidget(
242
            format='select',
243
            label=_("Sampler"),
244
            visible={'edit': 'visible',
245
                     'view': 'visible',
246
                     'header_table': 'visible',
247
                     'sample_registered': {'view': 'invisible', 'edit': 'invisible'},
248
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
249
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
250
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
251
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
252
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
253
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
254
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
255
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
256
                     'rejected':          {'view': 'visible', 'edit': 'visible'}
257
                     },
258
            render_own_label=True,
259
        ),
260
    ),
261
    StringField('ScheduledSamplingSampler',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
262
        mode="rw",
263
        read_permission=permissions.View,
264
        write_permission=ScheduleSampling,
265
        vocabulary='getSamplers',
266
        widget=BikaSelectionWidget(
267
            description=_("Define the sampler supposed to do the sample in "
268
                          "the scheduled date"),
269
            format='select',
270
            label=_("Sampler for scheduled sampling"),
271
            visible={'edit': 'visible',
272
                     'view': 'visible',
273
                     'header_table': 'visible',
274
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
275
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
276
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
277
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
278
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
279
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
280
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
281
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
282
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
283
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
284
                     },
285
            render_own_label=True,
286
        ),
287
    ),
288
    DateTimeField('SamplingDate',
289
        mode="rw",
290
        read_permission=permissions.View,
291
        write_permission=permissions.ModifyPortalContent,
292
        widget = DateTimeWidget(
293
            label=_("Expected Sampling Date"),
294
            description=_("Define when the sampler has to take the samples"),
295
            show_time=True,
296
            visible={'edit': 'visible',
297
                     'view': 'visible',
298
                     'header_table': 'visible',
299
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
300
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
301
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
302
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
303
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
304
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
305
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
306
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
307
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
308
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
309
                     },
310
            render_own_label=True,
311
        ),
312
    ),
313
    ReferenceField('SamplingDeviation',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ReferenceField'
Loading history...
314
        vocabulary_display_path_bound = sys.maxsize,
315
        allowed_types = ('SamplingDeviation',),
316
        relationship = 'SampleSamplingDeviation',
317
        referenceClass = HoldingReference,
318
        mode="rw",
319
        read_permission=permissions.View,
320
        write_permission=permissions.ModifyPortalContent,
321
        widget=ReferenceWidget(
322
            label=_("Sampling Deviation"),
323
            render_own_label=True,
324
            visible={'edit': 'visible',
325
                     'view': 'visible',
326
                     'header_table': 'visible',
327
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
328
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
329
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
330
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
331
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
332
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
333
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
334
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
335
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
336
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
337
                     },
338
            catalog_name='bika_setup_catalog',
339
            base_query={'inactive_state': 'active'},
340
            showOn=True,
341
        ),
342
    ),
343
    ReferenceField('SampleCondition',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ReferenceField'
Loading history...
344
        vocabulary_display_path_bound = sys.maxsize,
345
        allowed_types = ('SampleCondition',),
346
        relationship = 'SampleSampleCondition',
347
        referenceClass = HoldingReference,
348
        mode="rw",
349
        read_permission=permissions.View,
350
        write_permission=permissions.ModifyPortalContent,
351
        widget=ReferenceWidget(
352
            label=_("Sample Condition"),
353
            render_own_label=True,
354
            visible={'edit': 'visible',
355
                     'view': 'visible',
356
                     'header_table': 'visible',
357
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
358
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
359
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
360
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
361
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
362
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
363
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
364
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
365
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
366
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
367
                     },
368
            catalog_name='bika_setup_catalog',
369
            base_query={'inactive_state': 'active'},
370
            showOn=True,
371
        ),
372
    ),
373
    StringField(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringField'
Loading history...
374
        'EnvironmentalConditions',
375
        mode="rw",
376
        read_permission=permissions.View,
377
        write_permission=permissions.ModifyPortalContent,
378
        widget=StringWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'StringWidget'
Loading history...
379
            label=_("Environmental Conditions"),
380
            visible={'edit': 'visible',
381
                     'view': 'visible',
382
                     'add': 'edit',
383
                     'header_table': 'prominent',
384
                     'sample_registered': {'view': 'visible', 'edit': 'visible', 'add': 'edit'},
385
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
386
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
387
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
388
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
389
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
390
                     'attachment_due':    {'view': 'visible', 'edit': 'visible'},
391
                     'to_be_verified':    {'view': 'visible', 'edit': 'visible'},
392
                     'verified':          {'view': 'visible', 'edit': 'invisible'},
393
                     'published':         {'view': 'visible', 'edit': 'invisible'},
394
                     'invalid':           {'view': 'visible', 'edit': 'invisible'},
395
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
396
                     },
397
            render_own_label=True,
398
            size=20,
399
        ),
400
    ),
401
    # Another way to obtain a transition date is using getTransitionDate
402
    # function. We are using a DateTimeField/Widget here because in some
403
    # cases the user may want to change the Received Date.
404
    # AnalysisRequest and Sample's DateReceived fields needn't to have
405
    # the same value.
406
    # This field is updated in workflow_script_receive method.
407
    DateTimeField('DateReceived',
408
        mode="rw",
409
        read_permission=permissions.View,
410
        write_permission=permissions.ModifyPortalContent,
411
        widget = DateTimeWidget(
412
            label=_("Date Received"),
413
            show_time=True,
414
            datepicker_nofuture=1,
415
            visible={'edit': 'visible',
416
                     'view': 'visible',
417
                     'header_table': 'visible',
418
                     'sample_registered': {'view': 'visible', 'edit': 'invisible'},
419
                     'to_be_sampled':     {'view': 'visible', 'edit': 'invisible'},
420
                     'scheduled_sampling': {'view': 'visible', 'edit': 'invisible'},
421
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
422
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
423
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
424
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
425
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
426
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
427
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
428
                     },
429
            render_own_label=True,
430
        ),
431
    ),
432
    ComputedField('ClientUID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
433
        expression = 'context.aq_parent.UID()',
434
        widget = ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedWidget'
Loading history...
435
            visible=False,
436
        ),
437
    ),
438
    ComputedField('SampleTypeUID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
439
                  expression='context.getSampleType() and \
440
                             context.getSampleType().UID() or None',
441
                  widget=ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedWidget'
Loading history...
442
                    visible=False,
443
                  ),
444
    ),
445
    ComputedField('SamplePointUID',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
446
        expression = 'context.getSamplePoint() and context.getSamplePoint().UID() or None',
447
        widget = ComputedWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedWidget'
Loading history...
448
            visible=False,
449
        ),
450
    ),
451
    BooleanField('Composite',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'BooleanField'
Loading history...
452
        default = False,
453
        mode="rw",
454
        read_permission=permissions.View,
455
        write_permission=permissions.ModifyPortalContent,
456
        widget = BooleanWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BooleanWidget does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'BooleanWidget'
Loading history...
457
            label=_("Composite"),
458
            visible={'edit': 'visible',
459
                     'view': 'visible',
460
                     'header_table': 'visible',
461
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
462
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
463
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
464
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
465
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
466
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
467
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
468
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
469
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
470
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
471
                     },
472
            render_own_label=True,
473
        ),
474
    ),
475
    DateTimeField('DateExpired',
476
        mode="rw",
477
        read_permission=permissions.View,
478
        write_permission=permissions.ModifyPortalContent,
479
        widget = DateTimeWidget(
480
            label=_("Date Expired"),
481
            visible={'edit': 'visible',
482
                     'view': 'visible',
483
                     'header_table': 'visible',
484
                     'sample_registered': {'view': 'invisible', 'edit': 'invisible'},
485
                     'to_be_sampled':     {'view': 'invisible', 'edit': 'invisible'},
486
                     'scheduled_sampling': {'view': 'invisible', 'edit': 'invisible'},
487
                     'sampled':           {'view': 'invisible', 'edit': 'invisible'},
488
                     'to_be_preserved':   {'view': 'invisible', 'edit': 'invisible'},
489
                     'sample_due':        {'view': 'invisible', 'edit': 'invisible'},
490
                     'sample_received':   {'view': 'invisible', 'edit': 'invisible'},
491
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
492
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
493
                     'rejected':          {'view': 'invisible', 'edit': 'invisible'},
494
                     },
495
            render_own_label=True,
496
        ),
497
    ),
498
    ComputedField('DisposalDate',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ComputedField'
Loading history...
499
        expression = 'context.disposal_date()',
500
        widget=DateTimeWidget(
501
            visible={'edit': 'visible',
502
                     'view': 'visible',
503
                     'header_table': 'visible',
504
                     'sample_registered': {'view': 'invisible', 'edit': 'invisible'},
505
                     'to_be_sampled':     {'view': 'visible', 'edit': 'invisible'},
506
                     'scheduled_sampling': {'view': 'visible', 'edit': 'invisible'},
507
                     'sampled':           {'view': 'visible', 'edit': 'invisible'},
508
                     'to_be_preserved':   {'view': 'visible', 'edit': 'invisible'},
509
                     'sample_due':        {'view': 'visible', 'edit': 'invisible'},
510
                     'sample_received':   {'view': 'visible', 'edit': 'invisible'},
511
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
512
                     'disposed':          {'view': 'invisible', 'edit': 'invisible'},
513
                     'rejected':          {'view': 'invisible', 'edit': 'invisible'},
514
                     },
515
            render_own_label=True,
516
        ),
517
    ),
518
    DateTimeField('DateDisposed',
519
        mode="rw",
520
        read_permission=permissions.View,
521
        write_permission=permissions.ModifyPortalContent,
522
        widget = DateTimeWidget(
523
            label=_("Date Disposed"),
524
            visible={'edit': 'visible',
525
                     'view': 'visible',
526
                     'header_table': 'visible',
527
                     'sample_registered': {'view': 'invisible', 'edit': 'invisible'},
528
                     'to_be_sampled':     {'view': 'invisible', 'edit': 'invisible'},
529
                     'scheduled_sampling': {'view': 'invisible', 'edit': 'invisible'},
530
                     'sampled':           {'view': 'invisible', 'edit': 'invisible'},
531
                     'to_be_preserved':   {'view': 'invisible', 'edit': 'invisible'},
532
                     'sample_due':        {'view': 'invisible', 'edit': 'invisible'},
533
                     'sample_received':   {'view': 'invisible', 'edit': 'invisible'},
534
                     'expired':           {'view': 'invisible', 'edit': 'invisible'},
535
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
536
                     'rejected':          {'view': 'invisible', 'edit': 'invisible'},
537
                     },
538
            render_own_label=True,
539
        ),
540
    ),
541
    BooleanField('AdHoc',
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'BooleanField'
Loading history...
542
        default=False,
543
        mode="rw",
544
        read_permission=permissions.View,
545
        write_permission=permissions.ModifyPortalContent,
546
        widget=BooleanWidget(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'BooleanWidget'
Loading history...
547
            label=_("Ad-Hoc"),
548
            visible={'edit': 'visible',
549
                     'view': 'visible',
550
                     'header_table': 'visible',
551
                     'sample_registered': {'view': 'visible', 'edit': 'visible'},
552
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
553
                     'scheduled_sampling': {'view': 'visible', 'edit': 'visible'},
554
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
555
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
556
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
557
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
558
                     'expired':           {'view': 'visible', 'edit': 'invisible'},
559
                     'disposed':          {'view': 'visible', 'edit': 'invisible'},
560
                     'rejected':          {'view': 'visible', 'edit': 'invisible'},
561
                     },
562
           render_own_label=True,
563
        ),
564
    ),
565
    RemarksField(
566
        'Remarks',
567
        searchable=True,
568
        widget=RemarksWidget(
569
            label=_("Remarks"),
570
        ),
571
    ),
572
    RecordsField('RejectionReasons',
573
        widget = RejectionWidget(
574
            label=_("Sample Rejection"),
575
            description = _("Set the Sample Rejection workflow and the reasons"),
576
            render_own_label=False,
577
            visible={'edit': 'invisible',
578
                     'view': 'visible',
579
                     'add': 'edit',
580
                     'secondary': 'disabled',
581
                     'header_table': 'visible',
582
                     'sample_registered': {'view': 'visible', 'edit': 'visible', 'add': 'edit'},
583
                     'to_be_sampled':     {'view': 'visible', 'edit': 'visible'},
584
                     'sampled':           {'view': 'visible', 'edit': 'visible'},
585
                     'to_be_preserved':   {'view': 'visible', 'edit': 'visible'},
586
                     'sample_due':        {'view': 'visible', 'edit': 'visible'},
587
                     'sample_received':   {'view': 'visible', 'edit': 'visible'},
588
                     'attachment_due':    {'view': 'visible', 'edit': 'visible'},
589
                     'to_be_verified':    {'view': 'visible', 'edit': 'visible'},
590
                     'verified':          {'view': 'visible', 'edit': 'visible'},
591
                     'published':         {'view': 'visible', 'edit': 'visible'},
592
                     'invalid':           {'view': 'visible', 'edit': 'visible'},
593
                     'rejected':          {'view': 'visible', 'edit': 'visible'},
594
                     },
595
        ),
596
    ),
597
))
598
599
600
schema['title'].required = False
601
602
603
class Sample(BaseFolder, HistoryAwareMixin):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable BaseFolder does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
Undefined variable 'BaseFolder'
Loading history...
604
    implements(ISample)
605
    security = ClassSecurityInfo()
606
    displayContentsTab = False
607
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
608
609
    _at_rename_after_creation = True
610
611
    def _renameAfterCreation(self, check_auto_id=False):
612
        from bika.lims.idserver import renameAfterCreation
613
        renameAfterCreation(self)
614
615
    def _getCatalogTool(self):
616
        from bika.lims.catalog import getCatalog
617
        return getCatalog(self)
618
619
    def getSampleID(self):
620
        """ Return the Sample ID as title """
621
        return safe_unicode(self.getId()).encode('utf-8')
622
623
    def Title(self):
624
        """ Return the Sample ID as title """
625
        return self.getSampleID()
626
627
    def getSamplingWorkflowEnabledDefault(self):
628
        return self.bika_setup.getSamplingWorkflowEnabled()
629
630
    def getContactTitle(self):
631
        return ""
632
633
    def getClientTitle(self):
634
        proxies = self.getAnalysisRequests()
635
        if not proxies:
636
            return ""
637
        value = proxies[0].aq_parent.Title()
638
        return value
639
640
    def getProfilesTitle(self):
641
        return ""
642
643
    def getAnalysisService(self):
644
        analyses = []
645
        for ar in self.getAnalysisRequests():
646
            analyses += list(ar.getAnalyses(full_objects=True))
647
        value = []
648
        for analysis in analyses:
649
            val = analysis.Title()
650
            if val not in value:
651
                value.append(val)
652
        return value
653
654 View Code Duplication
    def getAnalysts(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
655
        analyses = []
656
        for ar in self.getAnalysisRequests():
657
            analyses += list(ar.getAnalyses(full_objects=True))
658
        value = []
659
        for analysis in analyses:
660
            val = analysis.getAnalyst()
661
            if val not in value:
662
                value.append(val)
663
        return value
664
665
    # Forms submit Title Strings which need
666
    # to be converted to objects somewhere along the way...
667 View Code Duplication
    def setSampleType(self, value, **kw):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
668
        """ Accept Object, Title or UID, and convert SampleType title to UID
669
        before saving.
670
        """
671
        if hasattr(value, "portal_type") and value.portal_type == "SampleType":
672
            pass
673
        else:
674
            bsc = getToolByName(self, 'bika_setup_catalog')
675
            sampletypes = bsc(portal_type='SampleType', title=to_unicode(value))
676
            if sampletypes:
677
                value = sampletypes[0].UID
678
            else:
679
                sampletypes = bsc(portal_type='SampleType', UID=value)
680
                if sampletypes:
681
                    value = sampletypes[0].UID
682
                else:
683
                    value = None
684
        for ar in self.getAnalysisRequests():
685
            ar.Schema()['SampleType'].set(ar, value)
686
        return self.Schema()['SampleType'].set(self, value)
687
688
    # Forms submit Title Strings which need
689
    # to be converted to objects somewhere along the way...
690 View Code Duplication
    def setSamplePoint(self, value, **kw):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
691
        """ Accept Object, Title or UID, and convert SampleType title to UID
692
        before saving.
693
        """
694
        if hasattr(value, "portal_type") and value.portal_type == "SamplePoint":
695
            pass
696
        elif value:
697
            bsc = getToolByName(self, 'bika_setup_catalog')
698
            sampletypes = bsc(portal_type='SamplePoint', title=to_unicode(value))
699
            if sampletypes:
700
                value = sampletypes[0].UID
701
            else:
702
                sampletypes = bsc(portal_type='SamplePoint', UID=value)
703
                if sampletypes:
704
                    value = sampletypes[0].UID
705
                else:
706
                    value = None
707
        for ar in self.getAnalysisRequests():
708
            ar.Schema()['SamplePoint'].set(ar, value)
709
        return self.Schema()['SamplePoint'].set(self, value)
710
711
    def setClientReference(self, value, **kw):
712
        """ Set the field on Analysis Requests.
713
        """
714
        for ar in self.getAnalysisRequests():
715
            ar.Schema()['ClientReference'].set(ar, value)
716
        self.Schema()['ClientReference'].set(self, value)
717
718
    def setClientSampleID(self, value, **kw):
719
        """ Set the field on Analysis Requests.
720
        """
721
        for ar in self.getAnalysisRequests():
722
            ar.Schema()['ClientSampleID'].set(ar, value)
723
        self.Schema()['ClientSampleID'].set(self, value)
724
725
    def setAdHoc(self, value, **kw):
726
        """ Set the field on Analysis Requests.
727
        """
728
        for ar in self.getAnalysisRequests():
729
            ar.Schema()['AdHoc'].set(ar, value)
730
        self.Schema()['AdHoc'].set(self, value)
731
732
    def setComposite(self, value, **kw):
733
        """ Set the field on Analysis Requests.
734
        """
735
        for ar in self.getAnalysisRequests():
736
            ar.Schema()['Composite'].set(ar, value)
737
        self.Schema()['Composite'].set(self, value)
738
739
    security.declarePublic('getAnalysisRequests')
740
741
    def getAnalysisRequests(self):
742
        backrefs = get_backreferences(self, 'AnalysisRequestSample')
743
        ars = map(get_object_by_uid, backrefs)
744
        return ars
745
746
    security.declarePublic('getAnalyses')
747
748
    def getAnalyses(self, contentFilter=None, **kwargs):
749
        """ return list of all analyses against this sample
750
        """
751
        # contentFilter and kwargs are combined.  They both exist for
752
        # compatibility between the two signatures; kwargs has been added
753
        # to be compatible with how getAnalyses() is used everywhere else.
754
        cf = contentFilter if contentFilter else {}
755
        cf.update(kwargs)
756
        analyses = []
757
        for ar in self.getAnalysisRequests():
758
            analyses.extend(ar.getAnalyses(**cf))
759
        return analyses
760
761
    def getSamplers(self):
762
        return getUsers(self, ['Sampler', ])
763
764
    def disposal_date(self):
765
        """ Calculate the disposal date by returning the latest
766
            disposal date in this sample's partitions """
767
768
        parts = self.objectValues("SamplePartition")
769
        dates = []
770
        for part in parts:
771
            date = part.getDisposalDate()
772
            if date:
773
                dates.append(date)
774
        if dates:
775
            dis_date = dt2DT(max([DT2dt(date) for date in dates]))
776
        else:
777
            dis_date = None
778
        return dis_date
779
780
    def getLastARNumber(self):
781
        ARs = self.getBackReferences("AnalysisRequestSample")
782
        prefix = self.getSampleType().getPrefix()
783
        ar_ids = sorted([AR.id for AR in ARs if AR.id.startswith(prefix)])
784
        try:
785
            last_ar_number = int(ar_ids[-1].split("-R")[-1])
786
        except:
787
            return 0
788
        return last_ar_number
789
790
    def getSampleState(self):
791
        """Returns the sample veiew_state
792
        """
793
        workflow = getToolByName(self, 'portal_workflow')
794
        return workflow.getInfoFor(self, 'review_state')
795
796
    def getSamplePartitions(self):
797
        """Returns the Sample Partitions associated to this Sample
798
        """
799
        partitions = self.objectValues('SamplePartition')
800
        return partitions
801
802
    def getBatchUIDs(self):
803
        """Returns the UIDs of the Batches to which this Sample is assigned
804
        through Analysis Requests
805
        """
806
        batch_uids = list()
807
        for analysis_request in self.getAnalysisRequests():
808
            batch_uid = analysis_request.getBatchUID()
809
            if not batch_uid or batch_uid in batch_uids:
810
                continue
811
            batch_uids.append(batch_uid)
812
        return batch_uids
813
814
    @security.public
815
    def guard_to_be_preserved(self):
816
        return guards.to_be_preserved(self)
817
818
    @security.public
819
    def guard_receive_transition(self):
820
        return guards.receive(self)
821
822
    @security.public
823
    def guard_schedule_sampling_transition(self):
824
        return guards.schedule_sampling(self)
825
826
atapi.registerType(Sample, PROJECTNAME)
827