Passed
Push — master ( 8785a0...af2087 )
by Jordi
05:32
created

ManageResultsView.getInstruments()   A

Complexity

Conditions 4

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 12
rs 9.9
c 0
b 0
f 0
cc 4
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
from bika.lims.browser.worksheet.views import AnalysesTransposedView
24
25
26
class ManageResultsView(BrowserView):
27
    """Worksheet Manage Results View
28
    """
29
    implements(IViewView)
30
    template = ViewPageTemplateFile("../templates/results.pt")
31
32
    def __init__(self, context, request):
33
        super(ManageResultsView, self).__init__(context, request)
34
        self.icon = "{}/{}".format(
35
            self.portal_url,
36
            "/++resource++bika.lims.images/worksheet_big.png"
37
        )
38
39
        self.layout_displaylist = WORKSHEET_LAYOUT_OPTIONS
40
41
    def __call__(self):
42
        # TODO: Refactor Worfklow
43
        grant = self.is_edit_allowed() and self.is_manage_allowed()
44
        if not grant:
45
            redirect_url = api.get_url(self.context)
46
            return self.request.response.redirect(redirect_url)
47
        # TODO: Refactor this function call
48
        showRejectionMessage(self.context)
49
50
        # Save the results layout
51
        rlayout = self.request.get("resultslayout", "")
52
        if rlayout and rlayout in WORKSHEET_LAYOUT_OPTIONS.keys() \
53
           and rlayout != self.context.getResultsLayout():
54
            self.context.setResultsLayout(rlayout)
55
            message = _("Changes saved.")
56
            self.context.plone_utils.addPortalMessage(message, "info")
57
58
        # Classic/Transposed View Switch
59
        if self.context.getResultsLayout() == "1":
60
            view = "analyses_classic_view"
61
            self.Analyses = api.get_view(
62
                view, context=self.context, request=self.request)
63
        else:
64
            # TODO: Refactor transposed view to new listing
65
            self.Analyses = AnalysesTransposedView(self.context, self.request)
66
67
        self.analystname = self.context.getAnalystName()
68
        self.instrumenttitle = self.get_instrument_title()
69
70
        # Check if the instruments used are valid
71
        self.checkInstrumentsValidity()
72
73
        return self.template()
74
75
    def get_analysts(self):
76
        """Returns Analysts
77
        """
78
        roles = ["Manager", "LabManager", "Analyst"]
79
        return getUsers(self.context, roles)
80
81
    @view.memoize
82
    def get_instrument_title(self):
83
        """Return the current instrument title
84
        """
85
        instrument = self.context.getInstrument()
86
        if not instrument:
87
            return ""
88
        return api.get_title(instrument)
89
90
    @view.memoize
91
    def is_edit_allowed(self):
92
        """Check if edit is allowed
93
        """
94
        checkPermission = self.context.portal_membership.checkPermission
95
        return checkPermission(EditWorksheet, self.context)
96
97
    @view.memoize
98
    def is_manage_allowed(self):
99
        """Check if manage is allowed
100
        """
101
        checkPermission = self.context.portal_membership.checkPermission
102
        return checkPermission(ManageWorksheets, self.context)
103
104
    @view.memoize
105
    def is_assignment_allowed(self):
106
        """Check if analyst assignment is allowed
107
        """
108
        if not self.is_manage_allowed():
109
            return False
110
        review_state = api.get_workflow_status_of(self.context)
111
        edit_states = ["open", "attachment_due", "to_be_verified"]
112
        return review_state in edit_states
113
114
    def getInstruments(self):
115
        # TODO: Return only the allowed instruments for at least one contained
116
        # analysis
117
        bsc = getToolByName(self, 'bika_setup_catalog')
118
        items = [('', '')] + [(o.UID, o.Title) for o in
119
                              bsc(portal_type='Instrument',
120
                                  inactive_state='active')]
121
        o = self.context.getInstrument()
122
        if o and o.UID() not in [i[0] for i in items]:
123
            items.append((o.UID(), o.Title()))
124
        items.sort(lambda x, y: cmp(x[1].lower(), y[1].lower()))
125
        return DisplayList(list(items))
126
127
    def get_wide_interims(self):
128
        """Returns a dictionary with the analyses services from the current
129
        worksheet which have at least one interim with 'Wide' attribute set to
130
        true and state 'sample_received'
131
132
        The structure of the returned dictionary is the following:
133
        <Analysis_keyword>: {
134
            'analysis': <Analysis_name>,
135
            'keyword': <Analysis_keyword>,
136
            'interims': {
137
                <Interim_keyword>: {
138
                    'value': <Interim_default_value>,
139
                    'keyword': <Interim_key>,
140
                    'title': <Interim_title>
141
                }
142
            }
143
        }
144
        """
145
        outdict = {}
146
        allowed_states = ["sample_received"]
147
        for analysis in self._getAnalyses():
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._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, "warn")
199
200
    def _getAnalyses(self):
201
        """
202
        This function returns a list with the analyses related to the worksheet
203
        and filtered by the current selected department in the department
204
        porlet.
205
        @returna list of analyses objects.
206
        """
207
        ans = [a for a in self.context.getAnalyses() if self._isItemAllowed(a)]
208
        return ans
209
210
    def _isItemAllowed(self, obj):
211
        """
212
        It checks if the analysis service can be added to the list depending
213
        on the department filter. If the analysis service is not assigned to a
214
        department, show it.
215
        If department filtering is disabled in bika_setup, will return True.
216
        @Obj: it is an analysis object.
217
        @return: boolean
218
        """
219
        if not self.context.bika_setup.getAllowDepartmentFiltering():
220
            return True
221
        # Gettin the department from analysis service
222
        serv_dep = obj.getDepartment()
223
        result = True
224
        if serv_dep:
225
            # Getting the cookie value
226
            cookie_dep_uid = self.request.get('filter_by_department_info', '')
227
            # Comparing departments' UIDs
228
            result = True if serv_dep.UID() in\
229
                cookie_dep_uid.split(',') else False
230
        return result
231