Passed
Push — 2.x ( 502a35...e9d213 )
by Ramon
05:16
created

bika.lims.browser.worksheet.views.add_analyses   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 23
eloc 155
dl 0
loc 256
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A AddAnalysesView.update() 0 10 3
A AddAnalysesView.folderitem() 0 32 4
A AddAnalysesView.is_manage_allowed() 0 5 1
A AddAnalysesView.is_edit_allowed() 0 5 1
B AddAnalysesView.__call__() 0 32 5
B AddAnalysesView.__init__() 0 67 1
A AddAnalysesView.getWorksheetTemplates() 0 7 1
A AddAnalysesView.add_status_message() 0 4 1
A AddAnalysesView.worksheet_template_setup_url() 0 6 1
A AddAnalysesView.handle_submit() 0 16 3

1 Function

Rating   Name   Duplication   Size   Complexity  
A getServiceUidsByMethod() 0 13 2
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-2021 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
import collections
22
23
from bika.lims import api
24
from bika.lims import bikaMessageFactory as _
25
from bika.lims.browser.bika_listing import BikaListingView
26
from bika.lims.browser.worksheet.tools import showRejectionMessage
27
from bika.lims.config import PRIORITIES
28
from bika.lims.utils import get_image
29
from bika.lims.utils import t
30
from bika.lims.vocabularies import CatalogVocabulary
31
from DateTime import DateTime
32
from plone.memoize import view
33
from plone.protect import CheckAuthenticator
34
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
35
from senaite.core.catalog import SETUP_CATALOG
36
from senaite.core.catalog import ANALYSIS_CATALOG
37
from senaite.core.permissions.worksheet import can_edit_worksheet
38
from senaite.core.permissions.worksheet import can_manage_worksheets
39
40
41
def getServiceUidsByMethod(method):
42
    if not api.is_uid(method):
43
        method = api.get_uid(method)
44
45
    query = {
46
        "portal_type": "AnalysisService",
47
        "is_active": True,
48
        "method_available_uid": method,
49
    }
50
    setup_catalog = api.get_tool(SETUP_CATALOG)
51
    uids = map(api.get_uid, setup_catalog(query))
52
53
    return uids
54
55
56
class AddAnalysesView(BikaListingView):
57
    """Assign Analyses View for Worksheets
58
    """
59
    template = ViewPageTemplateFile("../templates/add_analyses.pt")
60
61
    def __init__(self, context, request):
62
        super(AddAnalysesView, self).__init__(context, request)
63
64
        self.catalog = ANALYSIS_CATALOG
65
66
        self.contentFilter = {
67
            "portal_type": "Analysis",
68
            "review_state": "unassigned",
69
            "isSampleReceived": True,
70
            "sort_on": "getPrioritySortkey",
71
        }
72
73
        self.icon = "{}/{}".format(
74
            self.portal_url,
75
            "++plone++senaite.core.static/assets/icons/worksheet.svg"
76
        )
77
78
        self.title = self.context.translate(_("Add Analyses"))
79
        self.context_actions = {}
80
81
        # initial review state for first form display of the worksheet
82
        # add_analyses search view - first batch of analyses, latest first.
83
84
        self.show_select_row = False
85
        self.show_select_column = True
86
        self.pagesize = 50
87
88
        self.columns = collections.OrderedDict((
89
            ("Priority", {
90
                "title": "",
91
                "sortable": True,
92
                "index": "getPrioritySortkey"}),
93
            ("Client", {
94
                "title": _("Client"),
95
                "attr": "getClientTitle",
96
                "replace_url": "getClientURL",
97
                "index": "getClientTitle"}),
98
            ("getClientOrderNumber", {
99
                "title": _("Order"),
100
                "toggle": False,
101
                "attr": "getClientOrderNumber"}),
102
            ("getRequestID", {
103
                "title": _("Request ID"),
104
                "attr": "getRequestID",
105
                "replace_url": "getRequestURL",
106
                "index": "getRequestID"}),
107
            ("getCategoryTitle", {
108
                "title": _("Category"),
109
                "attr": "getCategoryTitle"}),
110
            ("Title", {
111
                "title": _("Analysis"),
112
                "index": "getId"}),
113
            ("getDateReceived", {
114
                "title": _("Date Received"),
115
                "index": "getDateReceived"}),
116
            ("getDueDate", {
117
                "title": _("Due Date"),
118
                "index": "getDueDate"}),
119
        ))
120
121
        self.review_states = [
122
            {
123
                "id": "default",
124
                "title": _("All"),
125
                "contentFilter": {},
126
                "transitions": [{"id": "assign"}, ],
127
                "columns": self.columns.keys(),
128
            },
129
        ]
130
131
    def __call__(self):
132
        super(AddAnalysesView, self).__call__()
133
134
        # TODO: Refactor Worfklow
135
        grant = self.is_edit_allowed() and self.is_manage_allowed()
136
        if not grant:
137
            redirect_url = api.get_url(self.context)
138
            return self.request.response.redirect(redirect_url)
139
140
        # TODO: Refactor this function call
141
        showRejectionMessage(self.context)
142
143
        # Handle form submission
144
        if self.request.form.get("submitted"):
145
            CheckAuthenticator(self.request)
146
            success = self.handle_submit()
147
            if success:
148
                self.add_status_message(_("Changes saved."))
149
                redirect_url = "{}/{}".format(
150
                    api.get_url(self.context), "manage_results")
151
                self.request.response.redirect(redirect_url)
152
            else:
153
                self.add_status_message(
154
                    _("No analyses were added to this worksheet."),
155
                    level="warning")
156
            return self.template()
157
158
        # handle subpath calls
159
        if len(self.traverse_subpath) > 0:
160
            return self.handle_subpath()
161
162
        return self.template()
163
164
    def update(self):
165
        """Update hook
166
        """
167
        super(AddAnalysesView, self).update()
168
        wst = self.context.getWorksheetTemplate()
169
        if wst:
170
            method = wst.getRawRestrictToMethod()
171
            # restrict the available analysis services by method
172
            if method:
173
                self.contentFilter["getServiceUID"] = getServiceUidsByMethod(method)
174
175
    def handle_submit(self):
176
        """Handle form submission
177
        """
178
        wst_uid = self.request.form.get("getWorksheetTemplate")
179
        if not wst_uid:
180
            return False
181
182
        layout = self.context.getLayout()
183
        wst = api.get_object_by_uid(wst_uid)
184
185
        self.request["context_uid"] = api.get_uid(self.context)
186
        self.context.applyWorksheetTemplate(wst)
187
188
        if len(self.context.getLayout()) == len(layout):
189
            return False
190
        return True
191
192
    @property
193
    def worksheet_template_setup_url(self):
194
        """Returns the Worksheet Template Setup URL
195
        """
196
        setup = api.get_setup()
197
        return "{}/{}".format(api.get_url(setup), "bika_worksheettemplates")
198
199
    @view.memoize
200
    def is_edit_allowed(self):
201
        """Check if edit is allowed
202
        """
203
        return can_edit_worksheet(self.context)
204
205
    @view.memoize
206
    def is_manage_allowed(self):
207
        """Check if manage is allowed
208
        """
209
        return can_manage_worksheets(self.context)
210
211
    def add_status_message(self, message, level="info"):
212
        """Set a portal status message
213
        """
214
        return self.context.plone_utils.addPortalMessage(message, level)
215
216
    def folderitem(self, obj, item, index):
217
        """Service triggered each time an item is iterated in folderitems.
218
219
        The use of this service prevents the extra-loops in child objects.
220
221
        :obj: the instance of the class to be foldered
222
        :item: dict containing the properties of the object to be used by
223
            the template
224
        :index: current index of the item
225
        """
226
        DueDate = obj.getDueDate
227
228
        item["getDateReceived"] = self.ulocalized_time(obj.getDateReceived)
229
        item["getDueDate"] = self.ulocalized_time(DueDate)
230
231
        if DueDate and DueDate < DateTime():
232
            item["after"]["DueDate"] = get_image(
233
                "late.png", title=t(_("Late Analysis")))
234
235
        # Add Priority column
236
        priority_sort_key = obj.getPrioritySortkey
237
        if not priority_sort_key:
238
            # Default priority is Medium = 3.
239
            # The format of PrioritySortKey is <priority>.<created>
240
            priority_sort_key = "3.%s" % obj.created.ISO8601()
241
242
        priority = priority_sort_key.split(".")[0]
243
        priority_text = t(PRIORITIES.getValue(priority))
244
        html = "<div title='{}' class='priority-ico priority-{}'><div>"
245
        item["replace"]["Priority"] = html.format(priority_text, priority)
246
247
        return item
248
249
    def getWorksheetTemplates(self):
250
        """Return WS Templates
251
        """
252
        vocabulary = CatalogVocabulary(self)
253
        vocabulary.catalog = "senaite_catalog_setup"
254
        return vocabulary(
255
            portal_type="WorksheetTemplate", sort_on="sortable_title")
256