Passed
Push — master ( ef1ceb...20aa4c )
by Jordi
06:12
created

ARTemplateAnalysesView.folderitems()   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
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
import collections
9
import itertools
10
from operator import itemgetter
11
12
from AccessControl import ClassSecurityInfo
13
from bika.lims import api
14
from bika.lims import bikaMessageFactory as _
15
from bika.lims.browser.bika_listing import BikaListingView
16
from bika.lims.utils import get_image
17
from bika.lims.utils import t
18
from plone.memoize import view
19
from Products.Archetypes.Registry import registerWidget
20
from Products.Archetypes.Widget import TypesWidget
21
from zope.i18n.locales import locales
22
23
24
class ARTemplateAnalysesView(BikaListingView):
25
    """ bika listing to display Analyses table for an ARTemplate.
26
    """
27
28
    def __init__(self, context, request):
29
        super(ARTemplateAnalysesView, self).__init__(context, request)
30
31
        self.catalog = "bika_setup_catalog"
32
        self.contentFilter = {
33
            "portal_type": "AnalysisService",
34
            "sort_on": "sortable_title",
35
            "inactive_state": "active"
36
        }
37
        self.context_actions = {}
38
39
        self.show_sort_column = False
40
        self.show_select_row = False
41
        self.show_select_all_checkbox = False
42
        self.show_column_toggles = False
43
        self.show_select_column = True
44
        self.pagesize = 999999
45
        self.allow_edit = True
46
        self.show_search = False
47
        self.omit_form = True
48
49
        # Categories
50
        self.categories = []
51
        self.do_cats = self.context.bika_setup.getCategoriseAnalysisServices()
52
        if self.do_cats:
53
            self.show_categories = True
54
            self.expand_all_categories = False
55
            self.ajax_categories = True
56
            self.category_index = "getCategoryTitle"
57
58
        self.partition_choices = []
59
        for part in self.context.getPartitions():
60
            part_id = part.get("part_id")
61
            self.partition_choices.append({
62
                "ResultValue": part_id,
63
                "ResultText": part_id,
64
            })
65
66
        self.columns = collections.OrderedDict((
67
            ("Title", {
68
                "title": _("Service"),
69
                "index": "sortable_title",
70
                "sortable": False}),
71
            ("Price", {
72
                "title": _("Price"),
73
                "sortable": False}),
74
            ("Partition", {
75
                "title": _("Partition"),
76
                "sortable": False}),
77
            ("Hidden", {
78
                "title": _("Hidden"),
79
                "sortable": False,
80
                "type": "boolean"}),
81
        ))
82
83
        columns = ["Title", "Price", "Partition", "Hidden"]
84
        if not self.show_prices():
85
            columns.remove("Price")
86
87
        self.review_states = [
88
            {
89
                "id": "default",
90
                "title": _("All"),
91
                "contentFilter": {"inactive_state": "active"},
92
                "transitions": [],
93
                "columns": columns,
94
            }
95
        ]
96
97
    def update(self):
98
        """Update hook
99
        """
100
        super(ARTemplateAnalysesView, self).update()
101
        self.allow_edit = self.is_edit_allowed()
102
        self.configuration = self.get_configuration()
103
104
    def get_settings(self):
105
        """Returns a mapping of UID -> setting
106
        """
107
        settings = self.context.getAnalysisServicesSettings()
108
        mapping = dict(map(lambda s: (s.get("uid"), s), settings))
109
        return mapping
110
111
    def get_configuration(self):
112
        """Returns a mapping of UID -> configuration
113
        """
114
        mapping = {}
115
        settings = self.get_settings()
116
        for record in self.context.getAnalyses():
117
            uid = record.get("service_uid")
118
            setting = settings.get(uid, {})
119
            config = {
120
                "partition": record.get("partition"),
121
                "hidden": setting.get("hidden", False),
122
            }
123
            mapping[uid] = config
124
        return mapping
125
126
    @view.memoize
127
    def show_prices(self):
128
        """Checks if prices should be shown or not
129
        """
130
        setup = api.get_setup()
131
        return setup.getShowPrices()
132
133
    @view.memoize
134
    def get_currency_symbol(self):
135
        """Get the currency Symbol
136
        """
137
        locale = locales.getLocale('en')
138
        setup = api.get_setup()
139
        currency = setup.getCurrency()
140
        return locale.numbers.currencies[currency].symbol
141
142
    @view.memoize
143
    def is_edit_allowed(self):
144
        """Check if edit is allowed
145
        """
146
        current_user = api.get_current_user()
147
        roles = current_user.getRoles()
148
        if "LabManager" in roles:
149
            return True
150
        if "Manager" in roles:
151
            return True
152
        return False
153
154
    @view.memoize
155
    def get_editable_columns(self):
156
        """Return editable fields
157
        """
158
        columns = ["Partition", "Hidden"]
159
        return columns
160
161
    def folderitem(self, obj, item, index):
162
        """Service triggered each time an item is iterated in folderitems.
163
164
        The use of this service prevents the extra-loops in child objects.
165
166
        :obj: the instance of the class to be foldered
167
        :item: dict containing the properties of the object to be used by
168
            the template
169
        :index: current index of the item
170
        """
171
        # ensure we have an object and not a brain
172
        obj = api.get_object(obj)
173
        uid = api.get_uid(obj)
174
175
        # get the category
176
        category = obj.getCategoryTitle()
177
        item["category"] = category
178
        if category not in self.categories:
179
            self.categories.append(category)
180
181
        config = self.configuration.get(uid, {})
182
        partition = config.get("partition", "part-1")
183
        hidden = config.get("hidden", False)
184
185
        item["Price"] = obj.getPrice()
186
        item["allow_edit"] = self.get_editable_columns()
187
        item["required"].append("Partition")
188
        item["choices"]["Partition"] = self.partition_choices
189
        item["Partition"] = partition
190
        item["Hidden"] = hidden
191
        item["selected"] = uid in self.configuration
192
193
        # Icons
194
        after_icons = ""
195
        if obj.getAccredited():
196
            after_icons += get_image(
197
                "accredited.png", title=t(_("Accredited")))
198
        if obj.getAttachmentOption() == "r":
199
            after_icons += get_image(
200
                "attach_reqd.png", title=t(_("Attachment required")))
201
        if obj.getAttachmentOption() == "n":
202
            after_icons += get_image(
203
                "attach_no.png", title=t(_('Attachment not permitted')))
204
        if after_icons:
205
            item["after"]["Title"] = after_icons
206
207
        return item
208
209
    def folderitems(self):
210
        """XXX refactor if possible to non-classic mode
211
        """
212
        items = super(ARTemplateAnalysesView, self).folderitems()
213
        self.categories.sort()
214
        return items
215
216
217
class ARTemplateAnalysesWidget(TypesWidget):
218
    """AR Template Analyses Widget
219
    """
220
    _properties = TypesWidget._properties.copy()
221
    _properties.update({
222
        "macro": "bika_widgets/artemplateanalyseswidget",
223
        "helper_js": ("bika_widgets/artemplateanalyseswidget.js",),
224
        "helper_css": ("bika_widgets/artemplateanalyseswidget.css",),
225
    })
226
227
    security = ClassSecurityInfo()
228
229
    security.declarePublic("process_form")
230
231
    def process_form(self, instance, field, form, empty_marker=None,
232
                     emptyReturnsMarker=False):
233
        """Return a list of dictionaries fit for ARTemplate/Analyses field
234
           consumption.
235
        """
236
        value = []
237
238
        # selected services
239
        service_uids = form.get("uids", [])
240
        # defined partitions
241
        partitions = form.get("Partition", [])
242
        partitions = partitions and partitions[0] or {}
243
        # hidden services
244
        hidden_services = form.get("Hidden", {})
245
246
        # get the service objects
247
        services = map(api.get_object_by_uid, service_uids)
248
        # get dependencies
249
        dependencies = map(lambda s: s.getServiceDependencies(), services)
250
        dependencies = list(itertools.chain.from_iterable(dependencies))
251
        # Merge dependencies and services
252
        services = set(services + dependencies)
253
254
        # get the profile
255
        profile_uid = form.get("AnalysisProfile_uid")
256
        if profile_uid:
257
            profile = api.get_object_by_uid(profile_uid)
258
            # update the services with those from the profile
259
            services.update(profile.getService())
260
261
        as_settings = []
262
        for service in services:
263
            service_uid = api.get_uid(service)
264
            value.append({
265
                "service_uid": service_uid,
266
                "partition": partitions.get(service_uid, "part-1")
267
            })
268
269
            hidden = hidden_services.get(service_uid, "") == "on"
270
            as_settings.append({"uid": service_uid, "hidden": hidden})
271
272
        # set the analysis services settings
273
        instance.setAnalysisServicesSettings(as_settings)
274
275
        # This returns the value for the Analyses Schema Field
276
        return value, {}
277
278
    security.declarePublic("Analyses")
279
280
    def Analyses(self, field, allow_edit=False):
281
        """Render Analyses Listing Table
282
        """
283
        instance = getattr(self, "instance", field.aq_parent)
284
        view = api.get_view(
285
            "table_ar_template_analyses",
286
            context=instance,
287
            request=self.REQUEST)
288
        # Call listing hooks
289
        view.update()
290
        view.before_render()
291
        return view.ajax_contents_table()
292
293
294
registerWidget(ARTemplateAnalysesWidget,
295
               title="AR Template Analyses Layout",
296
               description=("AR Template Analyses Layout"))
297