Passed
Push — 2.x ( 1a21e9...2cfd51 )
by Ramon
07:19
created

DefaultResultsRangeProvider.get_results_range_by()   A

Complexity

Conditions 2

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
cc 2
nop 3
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-2024 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
from operator import itemgetter
22
23
from bika.lims import logger
24
from bika.lims import bikaMessageFactory as _
25
from bika.lims.interfaces.analysis import IRequestAnalysis
26
from Products.Archetypes.interfaces import IFieldDefaultProvider
27
from Products.Archetypes.Registry import registerField
28
from senaite.core.browser.fields.record import RecordField
29
from zope.interface import implements
30
31
# A tuple of (subfield_id, subfield_label,)
32
SUB_FIELDS = (
33
    ("keyword", _("Analysis Service")),
34
    ("min_operator", _("Min operator")),
35
    ("min", _('Min')),
36
    ("max_operator", _("Max operator")),
37
    ("max", _('Max')),
38
    ("warn_min", _('Min warn')),
39
    ("warn_max", _('Max warn')),
40
    ("hidemin", _('< Min')),
41
    ("hidemax", _('> Max')),
42
    ("rangecomment", _(
43
        u"label_specs_rangecomment",
44
        default=u"Out of range comment"
45
    )),
46
)
47
48
49
class ResultRangeField(RecordField):
50
    """A field that stores a results range
51
    """
52
    _properties = RecordField._properties.copy()
53
    _properties.update({
54
        "type": "results_range_field",
55
        "subfields": map(itemgetter(0), SUB_FIELDS),
56
        "subfield_labels": dict(SUB_FIELDS),
57
    })
58
59
    def set(self, instance, value, **kwargs):
60
        from bika.lims.content.analysisspec import ResultsRangeDict
61
        if isinstance(value, ResultsRangeDict):
62
            # Better store a built-in dict so it will always be available even
63
            # if ResultsRangeDict is removed or changed
64
            value = dict(value)
65
66
        super(ResultRangeField, self).set(instance, value, **kwargs)
67
68
    def get(self, instance, **kwargs):
69
        from bika.lims.content.analysisspec import ResultsRangeDict
70
        value = super(ResultRangeField, self).get(instance, **kwargs)
71
        if value:
72
            return ResultsRangeDict(dict(value.items()))
73
        return {}
74
75
76
registerField(ResultRangeField, title="ResultRange",
77
              description="Used for storing a result range",)
78
79
80
class DefaultResultsRangeProvider(object):
81
    """Default Results Range provider for analyses
82
    This is used for backwards-compatibility for when the analysis' ResultsRange
83
    was obtained directly from Sample's ResultsRanges field, before this:
84
    https://github.com/senaite/senaite.core/pull/1506
85
    """
86
    implements(IFieldDefaultProvider)
87
88
    def __init__(self, context):
89
        self.context = context
90
91
    def __call__(self):
92
        """Get the default value.
93
        """
94
        if not IRequestAnalysis.providedBy(self.context):
95
            return {}
96
97
        # Get the AnalysisRequest to look at
98
        analysis = self.context
99
        sample = analysis.getRequest()
100
101
        # Search by keyword
102
        # or service uid for backwards compatibility
103
        search_by = analysis.getKeyword() or analysis.getServiceUID()
104
        if not search_by:
105
            return {}
106
107
        return self.get_results_range_by(sample, search_by)
108
109
    def get_results_range_by(self, sample, search_by):
110
        rr = {}
111
        try:
112
            field = sample.getField("ResultRange", {})
113
            rr = field.get(sample, search_by=search_by)
114
        except AttributeError as e:
115
            logger.error("Failed to get results range for sample "
116
                         "'{}' by '{}': "
117
                         "{}".format(sample.getId(), search_by, str(e)))
118
        return rr
119