Passed
Push — master ( e5d86d...1f1a20 )
by Jordi
04:06
created

ManageResultsView.get_wide_interims()   B

Complexity

Conditions 7

Size

Total Lines 42
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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