Passed
Push — master ( 6d6a8c...6374c8 )
by Ramon
05:17
created

bika.lims.browser.worksheet.views.results.ManageResultsView._getAnalyses()   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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