Passed
Push — master ( b3968c...f42093 )
by Ramon
09:42 queued 05:33
created

ManageResultsView.is_edit_allowed()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
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 Products.Archetypes.public import DisplayList
22
from Products.CMFCore.utils import getToolByName
23
from Products.CMFPlone.utils import safe_unicode
24
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
25
from plone.app.layout.globals.interfaces import IViewView
26
from plone.memoize import view
27
from zope.interface import implements
28
29
from bika.lims import api
30
from bika.lims import bikaMessageFactory as _
31
from bika.lims.browser import BrowserView
32
from bika.lims.browser.worksheet.tools import showRejectionMessage
33
from bika.lims.config import WORKSHEET_LAYOUT_OPTIONS
34
from bika.lims.permissions import ManageWorksheets
35
from bika.lims.utils import getUsers
36
37
38
class ManageResultsView(BrowserView):
39
    """Worksheet Manage Results View
40
    """
41
    implements(IViewView)
42
    template = ViewPageTemplateFile("../templates/results.pt")
43
44
    def __init__(self, context, request):
45
        super(ManageResultsView, self).__init__(context, request)
46
        self.icon = "{}/{}".format(
47
            self.portal_url,
48
            "/++resource++bika.lims.images/worksheet_big.png"
49
        )
50
51
        self.layout_displaylist = WORKSHEET_LAYOUT_OPTIONS
52
53
    def __call__(self):
54
        # TODO: Refactor this function call
55
        showRejectionMessage(self.context)
56
57
        # Save the results layout
58
        rlayout = self.request.get("resultslayout", "")
59
        if rlayout and rlayout in WORKSHEET_LAYOUT_OPTIONS.keys() \
60
           and rlayout != self.context.getResultsLayout():
61
            self.context.setResultsLayout(rlayout)
62
            message = _("Changes saved.")
63
            self.context.plone_utils.addPortalMessage(message, "info")
64
65
        # Classic/Transposed View Switch
66
        if self.context.getResultsLayout() == "1":
67
            view = "analyses_classic_view"
68
            self.Analyses = api.get_view(
69
                view, context=self.context, request=self.request)
70
        else:
71
            view = "analyses_transposed_view"
72
            self.Analyses = api.get_view(
73
                view, context=self.context, request=self.request)
74
75
        self.analystname = self.context.getAnalystName()
76
        self.instrumenttitle = self.get_instrument_title()
77
78
        # Check if the instruments used are valid
79
        self.checkInstrumentsValidity()
80
81
        return self.template()
82
83
    def get_analysts(self):
84
        """Returns Analysts
85
        """
86
        roles = ["Manager", "LabManager", "Analyst"]
87
        return getUsers(self.context, roles)
88
89
    @view.memoize
90
    def get_instrument_title(self):
91
        """Return the current instrument title
92
        """
93
        instrument = self.context.getInstrument()
94
        if not instrument:
95
            return ""
96
        return api.get_title(instrument)
97
98
    @view.memoize
99
    def is_manage_allowed(self):
100
        """Check if manage is allowed
101
        """
102
        checkPermission = self.context.portal_membership.checkPermission
103
        return checkPermission(ManageWorksheets, self.context)
104
105
    @view.memoize
106
    def is_assignment_allowed(self):
107
        """Check if analyst assignment is allowed
108
        """
109
        if not self.is_manage_allowed():
110
            return False
111
        review_state = api.get_workflow_status_of(self.context)
112
        edit_states = ["open", "attachment_due", "to_be_verified"]
113
        return review_state in edit_states
114
115
    def getInstruments(self):
116
        # TODO: Return only the allowed instruments for at least one contained
117
        # analysis
118
        bsc = getToolByName(self, 'bika_setup_catalog')
119
        items = [('', '')] + [(o.UID, o.Title) for o in
120
                              bsc(portal_type='Instrument',
121
                                  is_active=True)]
122
        o = self.context.getInstrument()
123
        if o and o.UID() not in [i[0] for i in items]:
124
            items.append((o.UID(), o.Title()))
125
        items.sort(lambda x, y: cmp(x[1].lower(), y[1].lower()))
126
        return DisplayList(list(items))
127
128
    def get_wide_interims(self):
129
        """Returns a dictionary with the analyses services from the current
130
        worksheet which have at least one interim with 'Wide' attribute set to
131
        true and that have not been yet submitted
132
133
        The structure of the returned dictionary is the following:
134
        <Analysis_keyword>: {
135
            'analysis': <Analysis_name>,
136
            'keyword': <Analysis_keyword>,
137
            'interims': {
138
                <Interim_keyword>: {
139
                    'value': <Interim_default_value>,
140
                    'keyword': <Interim_key>,
141
                    'title': <Interim_title>
142
                }
143
            }
144
        }
145
        """
146
        outdict = {}
147
        allowed_states = ['assigned', 'unassigned']
148
        for analysis in self.context.getAnalyses():
149
            # TODO Workflow - Analysis Use a query instead of this
150
            if api.get_workflow_status_of(analysis) not in allowed_states:
151
                continue
152
153
            if analysis.getKeyword() in outdict.keys():
154
                continue
155
156
            andict = {
157
                "analysis": analysis.Title(),
158
                "keyword": analysis.getKeyword(),
159
                "interims": {}
160
            }
161
162
            # Analysis Service interim defaults
163
            for field in analysis.getInterimFields():
164
                if field.get("wide", False):
165
                    andict["interims"][field["keyword"]] = field
166
167
            if andict["interims"]:
168
                outdict[analysis.getKeyword()] = andict
169
        return outdict
170
171 View Code Duplication
    def checkInstrumentsValidity(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
172
        """Checks the validity of the instruments used in the Analyses If an
173
        analysis with an invalid instrument (out-of-date or with calibration
174
        tests failed) is found, a warn message will be displayed.
175
        """
176
        invalid = []
177
        ans = self.context.getAnalyses()
178
        for an in ans:
179
            valid = an.isInstrumentValid()
180
            if not valid:
181
                instrument = an.getInstrument()
182
                inv = "%s (%s)" % (
183
                    safe_unicode(an.Title()), safe_unicode(instrument.Title()))
184
                if inv not in invalid:
185
                    invalid.append(inv)
186
        if len(invalid) > 0:
187
            message = _("Some analyses use out-of-date or uncalibrated "
188
                        "instruments. Results edition not allowed")
189
            message = "%s: %s" % (message, (", ".join(invalid)))
190
            self.context.plone_utils.addPortalMessage(message, "warning")
191