Completed
Branch master (9edffc)
by Jordi
04:36
created

ARTemplate.getSamplingRequiredDefaultValue()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
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
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
import sys
9
10
from AccessControl import ClassSecurityInfo
11
from bika.lims import api
12
from bika.lims import bikaMessageFactory as _
13
from bika.lims.browser.fields.remarksfield import RemarksField
14
from bika.lims.browser.widgets import ARTemplateAnalysesWidget
15
from bika.lims.browser.widgets import ARTemplatePartitionsWidget
16
from bika.lims.browser.widgets import ReferenceWidget
17
from bika.lims.browser.widgets import RemarksWidget
18
from bika.lims.config import PROJECTNAME
19
from bika.lims.content.bikaschema import BikaSchema
20
from bika.lims.interfaces import IARTemplate
21
from Products.Archetypes.public import BaseContent
22
from Products.Archetypes.public import BooleanField
23
from Products.Archetypes.public import BooleanWidget
24
from Products.Archetypes.public import ComputedField
25
from Products.Archetypes.public import ComputedWidget
26
from Products.Archetypes.public import DisplayList
27
from Products.Archetypes.public import ReferenceField
28
from Products.Archetypes.public import Schema
29
from Products.Archetypes.public import registerType
30
from Products.Archetypes.references import HoldingReference
31
from Products.ATExtensions.field.records import RecordsField
32
from Products.CMFCore.utils import getToolByName
33
from zope.interface import implements
34
35
schema = BikaSchema.copy() + Schema((
36
    ReferenceField(
37
        "SamplePoint",
38
        vocabulary_display_path_bound=sys.maxint,
39
        allowed_types=("SamplePoint",),
40
        relationship="ARTemplateSamplePoint",
41
        referenceClass=HoldingReference,
42
        accessor="getSamplePoint",
43
        edit_accessor="getSamplePoint",
44
        mutator="setSamplePoint",
45
        widget=ReferenceWidget(
46
            label=_("Sample Point"),
47
            description=_("Location where sample is collected"),
48
            visible={
49
                "edit": "visible", "view": "visible", "add": "visible",
50
                "secondary": "invisible",
51
            },
52
            catalog_name="bika_setup_catalog",
53
            base_query={"inactive_state": "active"},
54
            showOn=True,
55
        ),
56
    ),
57
    ComputedField(
58
        "SamplePointUID",
59
        expression="context.Schema()['SamplePoint'].get(context) and context.Schema()['SamplePoint'].get(context).UID() or ''",
60
        widget=ComputedWidget(
61
            visible=False,
62
        ),
63
    ),
64
    ReferenceField(
65
        "SampleType",
66
        vocabulary_display_path_bound=sys.maxint,
67
        allowed_types=("SampleType",),
68
        relationship="ARTemplateSampleType",
69
        referenceClass=HoldingReference,
70
        accessor="getSampleType",
71
        edit_accessor="getSampleType",
72
        mutator="setSampleType",
73
        widget=ReferenceWidget(
74
            label=_("Sample Type"),
75
            description=_("Create a new sample of this type"),
76
            visible={
77
                "edit": "visible", "view": "visible", "add": "visible",
78
                "secondary": "invisible"
79
            },
80
            catalog_name="bika_setup_catalog",
81
            base_query={"inactive_state": "active"},
82
            showOn=True,
83
        ),
84
    ),
85
    ComputedField(
86
        "SampleTypeUID",
87
        expression="context.Schema()['SampleType'].get(context) and context.Schema()['SampleType'].get(context).UID() or ''",
88
        widget=ComputedWidget(
89
            visible=False,
90
        ),
91
    ),
92
    BooleanField(
93
        "Composite",
94
        default=False,
95
        widget=BooleanWidget(
96
            label=_("Composite sample"),
97
            description=_("The sample is a mix of sub samples"),
98
        ),
99
    ),
100
    BooleanField(
101
        "SamplingRequired",
102
        default_method='getSamplingRequiredDefaultValue',
103
        widget=BooleanWidget(
104
            label=_("Sample collected by the laboratory"),
105
            description=_("Enable sampling workflow for the created sample")
106
        ),
107
    ),
108
    RemarksField(
109
        "Remarks",
110
        searchable=True,
111
        widget=RemarksWidget(
112
            label=_("Remarks"),
113
        ),
114
    ),
115
    RecordsField(
116
        "Partitions",
117
        schemata="Sample Partitions",
118
        required=0,
119
        type="artemplate_parts",
120
        subfields=(
121
            "part_id",
122
            "Container",
123
            "Preservation",
124
            "SampleType",
125
            "container_uid",
126
            "preservation_uid",
127
            "sampletype_uid"
128
        ),
129
        subfield_labels={
130
            "part_id": _("Partition"),
131
            "Container": _("Container"),
132
            "Preservation": _("Preservation"),
133
            "SampleType": _("Sample Type")
134
        },
135
        subfield_sizes={
136
            "part_id": 15,
137
            "Container": 35,
138
            "Preservation": 35,
139
            "SampleType": 35,
140
        },
141
        subfield_hidden={
142
            "preservation_uid": True,
143
            "container_uid": True,
144
            "sampletype_uid": True,
145
        },
146
        default=[{
147
            "part_id": "part-1",
148
            "Container": "",
149
            "Preservation": "",
150
            "SampleType": "",
151
            "container_uid": "",
152
            "preservation_uid": "",
153
            "sampletype_uid": "",
154
        }],
155
        widget=ARTemplatePartitionsWidget(
156
            label=_("Sample Partitions"),
157
            description=_(
158
                "Configure the sample partitions and preservations "
159
                "for this template. Assign analyses to the different "
160
                "partitions on the template's Analyses tab"),
161
            combogrid_options={
162
                "Container": {
163
                    "colModel": [
164
                        {
165
                            "columnName": "container_uid",
166
                            "hidden": True},
167
                        {
168
                            "columnName": "Container",
169
                            "width": "30",
170
                            "label": _("Container")
171
                        }, {
172
                            "columnName": "Description",
173
                            "width": "70",
174
                            "label": _("Description")
175
                        }],
176
                    "url": "getcontainers",
177
                    "showOn": True,
178
                    "width": "550px"
179
                },
180
                "Preservation": {
181
                    "colModel": [
182
                        {
183
                            "columnName": "preservation_uid",
184
                            "hidden": True
185
                        }, {
186
                            "columnName": "Preservation",
187
                            "width": "30",
188
                            "label": _("Preservation")
189
                        }, {
190
                            "columnName": "Description",
191
                            "width": "70",
192
                            "label": _("Description")
193
                        }],
194
                    "url": "getpreservations",
195
                    "showOn": True,
196
                    "width": "550px"
197
                },
198
                "SampleType": {
199
                    "colModel": [
200
                        {
201
                            "columnName": "sampletype_uid",
202
                            "hidden": True
203
                        }, {
204
                            "columnName": "SampleType",
205
                            "width": "30",
206
                            "label": _("SampleType")
207
                        }, {
208
                            "columnName": "Description",
209
                            "width": "70",
210
                            "label": _("Description")
211
                        }],
212
                    "url": "get_sampletypes",
213
                    "showOn": True,
214
                    "width": "550px"
215
                },
216
            },
217
        ),
218
    ),
219
220
    ReferenceField(
221
        "AnalysisProfile",
222
        schemata="Analyses",
223
        required=0,
224
        multiValued=0,
225
        allowed_types=("AnalysisProfile",),
226
        relationship="ARTemplateAnalysisProfile",
227
        widget=ReferenceWidget(
228
            label=_("Analysis Profile"),
229
            description=_("Add analyses from the selected profile "
230
                          "to the template"),
231
            visible={
232
                "edit": "visible",
233
                "view": "visible",
234
                "add": "visible",
235
                "secondary": "invisible"
236
            },
237
            catalog_name="bika_setup_catalog",
238
            base_query={"inactive_state": "active"},
239
            showOn=True,
240
        ),
241
    ),
242
    RecordsField(
243
        "Analyses",
244
        schemata="Analyses",
245
        required=0,
246
        type="analyses",
247
        subfields=("service_uid", "partition"),
248
        subfield_labels={
249
            "service_uid": _("Title"),
250
            "partition": _("Partition")
251
        },
252
        default=[],
253
        widget=ARTemplateAnalysesWidget(
254
            label=_("Analyses"),
255
            description=_("Select analyses to include in this template"),
256
        )
257
    ),
258
    # Custom settings for the assigned analysis services
259
    # https://jira.bikalabs.com/browse/LIMS-1324
260
    # Fields:
261
    #   - uid: Analysis Service UID
262
    #   - hidden: True/False. Hide/Display in results reports
263
    RecordsField(
264
        "AnalysisServicesSettings",
265
        required=0,
266
        subfields=("uid", "hidden",),
267
        widget=ComputedWidget(visible=False),
268
    ),
269
))
270
271
schema["description"].widget.visible = True
272
schema["title"].widget.visible = True
273
schema["title"].validators = ("uniquefieldvalidator",)
274
# Update the validation layer after change the validator in runtime
275
schema["title"]._validationLayer()
276
277
278
class ARTemplate(BaseContent):
279
    security = ClassSecurityInfo()
280
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
281
    displayContentsTab = False
282
    _at_rename_after_creation = True
283
    implements(IARTemplate)
284
285
    def _renameAfterCreation(self, check_auto_id=False):
286
        from bika.lims.idserver import renameAfterCreation
287
        renameAfterCreation(self)
288
289
    security.declarePublic("AnalysisProfiles")
290
291
    def AnalysisProfiles(self, instance=None):
292
        instance = instance or self
293
        bsc = getToolByName(instance, "bika_setup_catalog")
294
        items = []
295
        for p in bsc(
296
                portal_type="AnalysisProfile",
297
                inactive_state="active",
298
                sort_on="sortable_title"):
299
            p = p.getObject()
300
            title = p.Title()
301
            items.append((p.UID(), title))
302
        items = [["", ""]] + list(items)
303
        return DisplayList(items)
304
305
    def getClientUID(self):
306
        """This populates the getClientUID catalog
307
        If the parent is the system bika_artemplates folder,
308
        then that folder's UID must be returned in this index.
309
        """
310
        return self.aq_parent.UID()
311
312
    def getAnalysisServiceSettings(self, uid):
313
        """Returns a dictionary with the settings for the analysis service that
314
           match with the uid provided.
315
316
        If there are no settings for the analysis service and template, returns
317
        a dictionary with the key 'uid'
318
        """
319
        settings = self.getAnalysisServicesSettings()
320
        sets = [s for s in settings if s.get("uid", "") == uid]
321
        return sets[0] if sets else {"uid": uid}
322
323 View Code Duplication
    def isAnalysisServiceHidden(self, uid):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
324
        """ Checks if the analysis service that match with the uid
325
            provided must be hidden in results.
326
            If no hidden assignment has been set for the analysis in
327
            this template, returns the visibility set to the analysis
328
            itself.
329
            Raise a TypeError if the uid is empty or None
330
            Raise a ValueError if there is no hidden assignment in this
331
                template or no analysis service found for this uid.
332
        """
333
        if not uid:
334
            raise TypeError("None type or empty uid")
335
        sets = self.getAnalysisServiceSettings(uid)
336
        if "hidden" not in sets:
337
            uc = getToolByName(self, "uid_catalog")
338
            serv = uc(UID=uid)
339
            if serv and len(serv) == 1:
340
                return serv[0].getObject().getRawHidden()
341
            else:
342
                raise ValueError("%s is not valid" % uid)
343
        return sets.get("hidden", False)
344
345
    def remove_service(self, service):
346
        """Removes the service passed in from the services offered by the
347
        current Template. If the Analysis Service passed in is not assigned to
348
        this Analysis Template, returns False.
349
        :param service: the service to be removed from this AR Template
350
        :type service: AnalysisService
351
        :return: True if the AnalysisService has been removed successfully
352
        """
353
        uid = api.get_uid(service)
354
355
        # Remove the service from the referenced services
356
        services = self.getAnalyses()
357
        num_services = len(services)
358
        services = [item for item in services
359
                    if item.get("service_uid", "") != uid]
360
        removed = len(services) < num_services
361
        self.setAnalyses(services)
362
363
        # Remove the service from the settings map
364
        settings = self.getAnalysisServicesSettings()
365
        settings = [item for item in settings if item.get('uid', '') != uid]
366
        self.setAnalysisServicesSettings(settings)
367
368
        return removed
369
370
    def getSamplingRequiredDefaultValue(self):
371
        """Returns the default value for field SamplingRequired, that is the
372
        value for setting SamplingWorkflowEnabled from setup
373
        """
374
        return self.bika_setup.getSamplingWorkflowEnabled()
375
376
registerType(ARTemplate, PROJECTNAME)
377