Completed
Pull Request — 2.x (#1739)
by Jordi
06:02
created

senaite.core.browser.samples.view   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 718
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 60
eloc 549
dl 0
loc 718
rs 3.6
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
F SamplesView.folderitem() 0 188 36
A SamplesView.before_render() 0 13 2
A SamplesView.getDefaultAddCount() 0 2 1
B SamplesView.__init__() 0 370 1
F SamplesView.update() 0 80 16
A SamplesView.copy_to_new_allowed() 0 6 2
A SamplesView.show_partitions() 0 6 2

How to fix   Complexity   

Complexity

Complex classes like senaite.core.browser.samples.view often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
22
import collections
23
24
from bika.lims import _
25
from bika.lims import api
26
from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING
27
from bika.lims.config import PRIORITIES
28
from bika.lims.permissions import AddAnalysisRequest
29
from bika.lims.permissions import TransitionSampleSample
30
from bika.lims.utils import get_image
31
from bika.lims.utils import get_progress_bar_html
32
from bika.lims.utils import getUsers
33
from bika.lims.utils import t
34
from DateTime import DateTime
35
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
36
from senaite.app.listing import ListingView
37
38
39
class SamplesView(ListingView):
40
    """Listing View for Samples (AnalysisRequest content type) in the System
41
    """
42
43
    template = ViewPageTemplateFile("templates/samples.pt")
44
45
    def __init__(self, context, request):
46
        super(SamplesView, self).__init__(context, request)
47
48
        self.catalog = CATALOG_ANALYSIS_REQUEST_LISTING
49
        self.contentFilter = {
50
            "sort_on": "created",
51
            "sort_order": "descending",
52
            "isRootAncestor": True,  # only root ancestors
53
        }
54
55
        self.title = self.context.translate(_("Samples"))
56
        self.description = ""
57
58
        self.show_select_column = True
59
        self.form_id = "analysisrequests"
60
        self.context_actions = {}
61
62
        self.url = api.get_url(self.context)
63
64
        # Toggle some columns if the sampling workflow is enabled
65
        sampling_enabled = api.get_setup().getSamplingWorkflowEnabled()
66
67
        self.columns = collections.OrderedDict((
68
            ("Priority", {
69
                "title": "",
70
                "index": "getPrioritySortkey",
71
                "sortable": True, }),
72
            ("Progress", {
73
                "title": "Progress",
74
                "index": "getProgress",
75
                "sortable": True,
76
                "toggle": True}),
77
            ("getId", {
78
                "title": _("Sample ID"),
79
                "attr": "getId",
80
                "replace_url": "getURL",
81
                "index": "getId"}),
82
            ("getClientOrderNumber", {
83
                "title": _("Client Order"),
84
                "sortable": True,
85
                "toggle": False}),
86
            ("Creator", {
87
                "title": _("Creator"),
88
                "index": "getCreatorFullName",
89
                "sortable": True,
90
                "toggle": True}),
91
            ("Created", {
92
                "title": _("Date Registered"),
93
                "index": "created",
94
                "toggle": False}),
95
            ("SamplingDate", {
96
                "title": _("Expected Sampling Date"),
97
                "index": "getSamplingDate",
98
                "toggle": sampling_enabled}),
99
            ("getDateSampled", {
100
                "title": _("Date Sampled"),
101
                "toggle": True,
102
                "input_class": "datetimepicker_nofuture",
103
                "input_width": "10"}),
104
            ("getDatePreserved", {
105
                "title": _("Date Preserved"),
106
                "toggle": False,
107
                "input_class": "datetimepicker_nofuture",
108
                "input_width": "10",
109
                "sortable": False}),  # no datesort without index
110
            ("getDateReceived", {
111
                "title": _("Date Received"),
112
                "toggle": False}),
113
            ("getDueDate", {
114
                "title": _("Due Date"),
115
                "toggle": False}),
116
            ("getDateVerified", {
117
                "title": _("Date Verified"),
118
                "input_width": "10",
119
                "toggle": False}),
120
            ("getDatePublished", {
121
                "title": _("Date Published"),
122
                "toggle": False}),
123
            ("BatchID", {
124
                "title": _("Batch ID"),
125
                "index": "getBatchID",
126
                "sortable": True,
127
                "toggle": False}),
128
            ("Client", {
129
                "title": _("Client"),
130
                "index": "getClientTitle",
131
                "attr": "getClientTitle",
132
                "replace_url": "getClientURL",
133
                "toggle": True}),
134
            ("ClientID", {
135
                "title": _("Client ID"),
136
                "index": "getClientID",
137
                "attr": "getClientID",
138
                "replace_url": "getClientURL",
139
                "toggle": True}),
140
            ("Province", {
141
                "title": _("Province"),
142
                "sortable": True,
143
                "index": "getProvince",
144
                "attr": "getProvince",
145
                "toggle": False}),
146
            ("District", {
147
                "title": _("District"),
148
                "sortable": True,
149
                "index": "getDistrict",
150
                "attr": "getDistrict",
151
                "toggle": False}),
152
            ("getClientReference", {
153
                "title": _("Client Ref"),
154
                "sortable": True,
155
                "index": "getClientReference",
156
                "toggle": False}),
157
            ("getClientSampleID", {
158
                "title": _("Client SID"),
159
                "toggle": False}),
160
            ("ClientContact", {
161
                "title": _("Contact"),
162
                "sortable": True,
163
                "index": "getContactFullName",
164
                "toggle": False}),
165
            ("getSampleTypeTitle", {
166
                "title": _("Sample Type"),
167
                "sortable": True,
168
                "toggle": True}),
169
            ("getSamplePointTitle", {
170
                "title": _("Sample Point"),
171
                "sortable": True,
172
                "index": "getSamplePointTitle",
173
                "toggle": False}),
174
            ("getStorageLocation", {
175
                "title": _("Storage Location"),
176
                "sortable": True,
177
                "index": "getStorageLocationTitle",
178
                "toggle": False}),
179
            ("SamplingDeviation", {
180
                "title": _("Sampling Deviation"),
181
                "sortable": True,
182
                "index": "getSamplingDeviationTitle",
183
                "toggle": False}),
184
            ("getSampler", {
185
                "title": _("Sampler"),
186
                "toggle": sampling_enabled}),
187
            ("getPreserver", {
188
                "title": _("Preserver"),
189
                "sortable": False,
190
                "toggle": False}),
191
            ("getProfilesTitle", {
192
                "title": _("Profile"),
193
                "sortable": True,
194
                "index": "getProfilesTitle",
195
                "toggle": False}),
196
            ("getAnalysesNum", {
197
                "title": _("Number of Analyses"),
198
                "sortable": True,
199
                "index": "getAnalysesNum",
200
                "toggle": False}),
201
            ("getTemplateTitle", {
202
                "title": _("Template"),
203
                "sortable": True,
204
                "index": "getTemplateTitle",
205
                "toggle": False}),
206
            ("Printed", {
207
                "title": _("Printed"),
208
                "sortable": False,
209
                "index": "getPrinted",
210
                "toggle": False}),
211
            ("state_title", {
212
                "title": _("State"),
213
                "sortable": True,
214
                "index": "review_state"}),
215
        ))
216
217
        # custom print transition
218
        print_stickers = {
219
            "id": "print_stickers",
220
            "title": _("Print stickers"),
221
            "url": "workflow_action?action=print_stickers"
222
        }
223
224
        self.review_states = [
225
            {
226
                "id": "default",
227
                "title": _("Active"),
228
                "contentFilter": {
229
                    "review_state": (
230
                        "sample_registered",
231
                        "scheduled_sampling",
232
                        "to_be_sampled",
233
                        "sample_due",
234
                        "sample_received",
235
                        "to_be_preserved",
236
                        "to_be_verified",
237
                        "verified",
238
                    ),
239
                    "sort_on": "created",
240
                    "sort_order": "descending",
241
                },
242
                "custom_transitions": [print_stickers],
243
                "columns": self.columns.keys(),
244
            }, {
245
                "id": "to_be_sampled",
246
                "title": _("To Be Sampled"),
247
                "contentFilter": {
248
                    "review_state": ("to_be_sampled",),
249
                    "sort_on": "created",
250
                    "sort_order": "descending"},
251
                "custom_transitions": [print_stickers],
252
                "columns": self.columns.keys()
253
            }, {
254
                "id": "to_be_preserved",
255
                "title": _("To Be Preserved"),
256
                "contentFilter": {
257
                    "review_state": ("to_be_preserved",),
258
                    "sort_on": "created",
259
                    "sort_order": "descending",
260
                },
261
                "custom_transitions": [print_stickers],
262
                "columns": self.columns.keys(),
263
            }, {
264
                "id": "scheduled_sampling",
265
                "title": _("Scheduled sampling"),
266
                "contentFilter": {
267
                    "review_state": ("scheduled_sampling",),
268
                    "sort_on": "created",
269
                    "sort_order": "descending",
270
                },
271
                "custom_transitions": [print_stickers],
272
                "columns": self.columns.keys(),
273
            }, {
274
                "id": "sample_due",
275
                "title": _("Due"),
276
                "contentFilter": {
277
                    "review_state": (
278
                        "to_be_sampled",
279
                        "to_be_preserved",
280
                        "sample_due"),
281
                    "sort_on": "created",
282
                    "sort_order": "descending"},
283
                "custom_transitions": [print_stickers],
284
                "columns": self.columns.keys(),
285
            }, {
286
                "id": "sample_received",
287
                "title": _("Received"),
288
                "contentFilter": {
289
                    "review_state": "sample_received",
290
                    "sort_on": "created",
291
                    "sort_order": "descending",
292
                },
293
                "custom_transitions": [print_stickers],
294
                "columns": self.columns.keys(),
295
            }, {
296
                "id": "to_be_verified",
297
                "title": _("To be verified"),
298
                "contentFilter": {
299
                    "review_state": "to_be_verified",
300
                    "sort_on": "created",
301
                    "sort_order": "descending",
302
                },
303
                "custom_transitions": [print_stickers],
304
                "columns": self.columns.keys(),
305
            }, {
306
                "id": "verified",
307
                "title": _("Verified"),
308
                "contentFilter": {
309
                    "review_state": "verified",
310
                    "sort_on": "created",
311
                    "sort_order": "descending",
312
                },
313
                "custom_transitions": [print_stickers],
314
                "columns": self.columns.keys(),
315
            }, {
316
                "id": "published",
317
                "title": _("Published"),
318
                "contentFilter": {
319
                    "review_state": ("published"),
320
                    "sort_on": "created",
321
                    "sort_order": "descending",
322
                },
323
                "custom_transitions": [],
324
                "columns": self.columns.keys(),
325
            }, {
326
                "id": "cancelled",
327
                "title": _("Cancelled"),
328
                "contentFilter": {
329
                    "review_state": "cancelled",
330
                    "sort_on": "created",
331
                    "sort_order": "descending",
332
                },
333
                "custom_transitions": [],
334
                "columns": self.columns.keys(),
335
            }, {
336
                "id": "invalid",
337
                "title": _("Invalid"),
338
                "contentFilter": {
339
                    "review_state": "invalid",
340
                    "sort_on": "created",
341
                    "sort_order": "descending",
342
                },
343
                "custom_transitions": [print_stickers],
344
                "columns": self.columns.keys(),
345
            }, {
346
                "id": "all",
347
                "title": _("All"),
348
                "contentFilter": {
349
                    "sort_on": "created",
350
                    "sort_order": "descending",
351
                },
352
                "custom_transitions": [print_stickers],
353
                "columns": self.columns.keys(),
354
            }, {
355
                "id": "rejected",
356
                "title": _("Rejected"),
357
                "contentFilter": {
358
                    "review_state": "rejected",
359
                    "sort_on": "created",
360
                    "sort_order": "descending",
361
                },
362
                "custom_transitions": [
363
                    {
364
                        "id": "print_stickers",
365
                        "title": _("Print stickers"),
366
                        "url": "workflow_action?action=print_stickers"},
367
                ],
368
                "columns": self.columns.keys(),
369
            }, {
370
                "id": "assigned",
371
                "title": get_image("assigned.png",
372
                                   title=t(_("Assigned"))),
373
                "contentFilter": {
374
                    "assigned_state": "assigned",
375
                    "review_state": ("sample_received",),
376
                    "sort_on": "created",
377
                    "sort_order": "descending",
378
                },
379
                "custom_transitions": [print_stickers],
380
                "columns": self.columns.keys(),
381
            }, {
382
                "id": "unassigned",
383
                "title": get_image("unassigned.png",
384
                                   title=t(_("Unsassigned"))),
385
                "contentFilter": {
386
                    "assigned_state": "unassigned",
387
                    "review_state": (
388
                        "sample_received",
389
                    ),
390
                    "sort_on": "created",
391
                    "sort_order": "descending",
392
                },
393
                "custom_transitions": [print_stickers],
394
                "columns": self.columns.keys(),
395
            }, {
396
                "id": "late",
397
                "title": get_image("late.png",
398
                                   title=t(_("Late"))),
399
                "contentFilter": {
400
                    # Query only for unpublished ARs that are late
401
                    "review_state": (
402
                        "sample_received",
403
                        "to_be_verified",
404
                        "verified",
405
                    ),
406
                    "getDueDate": {
407
                        "query": DateTime(),
408
                        "range": "max",
409
                    },
410
                    "sort_on": "created",
411
                    "sort_order": "descending",
412
                },
413
                "custom_transitions": [print_stickers],
414
                "columns": self.columns.keys(),
415
            }
416
        ]
417
418
    def update(self):
419
        """Called before the listing renders
420
        """
421
        super(SamplesView, self).update()
422
423
        self.workflow = api.get_tool("portal_workflow")
424
        self.member = self.mtool.getAuthenticatedMember()
425
        self.roles = self.member.getRoles()
426
427
        setup = api.get_bika_setup()
428
429
        # remove `to_be_sampled` filter
430
        if not setup.getSamplingWorkflowEnabled():
431
            self.review_states = filter(
432
                lambda x: x.get("id") != "to_be_sampled", self.review_states)
433
434
        # remove `scheduled_sampling` filter
435
        if not setup.getScheduleSamplingEnabled():
436
            self.review_states = filter(
437
                lambda x: x.get("id") != "scheduled_sampling",
438
                self.review_states)
439
440
        # remove `to_be_preserved` filter
441
        if not setup.getSamplePreservationEnabled():
442
            self.review_states = filter(
443
                lambda x: x.get("id") != "to_be_preserved", self.review_states)
444
445
        # remove `rejected` filter
446
        if not setup.getRejectionReasons():
447
            self.review_states = filter(
448
                lambda x: x.get("id") != "rejected", self.review_states)
449
450
        self.hideclientlink = "RegulatoryInspector" in self.roles \
451
                              and "Manager" not in self.roles \
452
                              and "LabManager" not in self.roles \
453
                              and "LabClerk" not in self.roles
454
455
        self.editresults = -1
456
        self.clients = {}
457
        # self.user_is_preserver = "Preserver" in self.roles
458
        # Printing workflow enabled?
459
        # If not, remove the Column
460
        self.printwfenabled = \
461
            self.context.bika_setup.getPrintingWorkflowEnabled()
462
        printed_colname = "Printed"
463
        if not self.printwfenabled and printed_colname in self.columns:
464
            # Remove "Printed" columns
465
            del self.columns[printed_colname]
466
            tmprvs = []
467
            for rs in self.review_states:
468
                tmprs = rs
469
                tmprs["columns"] = [c for c in rs.get("columns", []) if
470
                                    c != printed_colname]
471
                tmprvs.append(tmprs)
472
            self.review_states = tmprvs
473
        elif self.printwfenabled:
474
            # Print button to choose multiple ARs and print them.
475
            review_states = []
476
            action = "print_sample"
477
            url = "{}/workflow_action?action={}".format(self.url, action)
478
            for review_state in self.review_states:
479
                review_state.get("custom_transitions", []).extend(
480
                    [{"id": "print_sample",
481
                      "title": _("Print"),
482
                      "url": url}, ])
483
                review_states.append(review_state)
484
            self.review_states = review_states
485
486
        # Only "senaite.core: ManageAnalysisRequests" may see the copy button.
487
        if self.copy_to_new_allowed:
488
            review_states = []
489
            action = "copy_to_new"
490
            url = "{}/workflow_action?action={}".format(self.url, action)
491
            for review_state in self.review_states:
492
                review_state.get("custom_transitions", []).extend(
493
                    [{"id": "copy_to_new",
494
                      "title": _("Copy to new"),
495
                      "url": url}, ])
496
                review_states.append(review_state)
497
            self.review_states = review_states
498
499
    def before_render(self):
500
        """Before template render hook
501
        """
502
        # If the current user is a client contact, display those analysis
503
        # requests that belong to same client only
504
        super(SamplesView, self).before_render()
505
        client = api.get_current_client()
506
        if client:
507
            self.contentFilter['path'] = {
508
                "query": "/".join(client.getPhysicalPath()),
509
                "level": 0}
510
            # No need to display the Client column
511
            self.remove_column('Client')
512
513
    def folderitem(self, obj, item, index):
514
        # Additional info from AnalysisRequest to be added in the item
515
        # generated by default by bikalisting.
516
        # Call the folderitem method from the base class
517
        item = super(SamplesView, self).folderitem(obj, item, index)
518
        if not item:
519
            return None
520
521
        item["Creator"] = self.user_fullname(obj.Creator)
522
        # If we redirect from the folderitems view we should check if the
523
        # user has permissions to medify the element or not.
524
        priority_sort_key = obj.getPrioritySortkey
525
        if not priority_sort_key:
526
            # Default priority is Medium = 3.
527
            # The format of PrioritySortKey is <priority>.<created>
528
            priority_sort_key = "3.%s" % obj.created.ISO8601()
529
        priority = priority_sort_key.split(".")[0]
530
        priority_text = PRIORITIES.getValue(priority)
531
        priority_div = """<div class="priority-ico priority-%s">
532
                          <span class="notext">%s</span><div>
533
                       """
534
        item["replace"]["Priority"] = priority_div % (priority, priority_text)
535
        item["replace"]["getProfilesTitle"] = obj.getProfilesTitleStr
536
537
        analysesnum = obj.getAnalysesNum
538
        if analysesnum:
539
            num_verified = str(analysesnum[0])
540
            num_total = str(analysesnum[1])
541
            item["getAnalysesNum"] = "{0}/{1}".format(num_verified, num_total)
542
        else:
543
            item["getAnalysesNum"] = ""
544
545
        # Progress
546
        progress_perc = obj.getProgress
547
        item["Progress"] = progress_perc
548
        item["replace"]["Progress"] = get_progress_bar_html(progress_perc)
549
550
        item["BatchID"] = obj.getBatchID
551
        if obj.getBatchID:
552
            item['replace']['BatchID'] = "<a href='%s'>%s</a>" % \
553
                                         (obj.getBatchURL, obj.getBatchID)
554
        # TODO: SubGroup ???
555
        # val = obj.Schema().getField('SubGroup').get(obj)
556
        # item['SubGroup'] = val.Title() if val else ''
557
558
        date = obj.getSamplingDate
559
        item["SamplingDate"] = \
560
            self.ulocalized_time(date, long_format=1) if date else ""
561
        date = obj.getDateReceived
562
        item["getDateReceived"] = \
563
            self.ulocalized_time(date, long_format=1) if date else ""
564
        date = obj.getDueDate
565
        item["getDueDate"] = \
566
            self.ulocalized_time(date, long_format=1) if date else ""
567
        date = obj.getDatePublished
568
        item["getDatePublished"] = \
569
            self.ulocalized_time(date, long_format=1) if date else ""
570
        date = obj.getDateVerified
571
        item["getDateVerified"] = \
572
            self.ulocalized_time(date, long_format=1) if date else ""
573
574
        if self.printwfenabled:
575
            item["Printed"] = ""
576
            printed = obj.getPrinted if hasattr(obj, "getPrinted") else "0"
577
            print_icon = ""
578
            if printed == "0":
579
                print_icon = get_image("delete.png",
580
                                       title=t(_("Not printed yet")))
581
            elif printed == "1":
582
                print_icon = get_image("ok.png",
583
                                       title=t(_("Printed")))
584
            elif printed == "2":
585
                print_icon = get_image(
586
                    "exclamation.png",
587
                    title=t(_("Republished after last print")))
588
            item["after"]["Printed"] = print_icon
589
        item["SamplingDeviation"] = obj.getSamplingDeviationTitle
590
591
        item["getStorageLocation"] = obj.getStorageLocationTitle
592
593
        after_icons = ""
594
        if obj.assigned_state == 'assigned':
595
            after_icons += get_image("worksheet.png",
596
                                     title=t(_("All analyses assigned")))
597
        if item["review_state"] == 'invalid':
598
            after_icons += get_image("delete.png",
599
                                     title=t(_("Results have been withdrawn")))
600
601
        due_date = obj.getDueDate
602
        if due_date and due_date < (obj.getDatePublished or DateTime()):
603
            due_date_str = self.ulocalized_time(due_date)
604
            img_title = "{}: {}".format(t(_("Late Analyses")), due_date_str)
605
            after_icons += get_image("late.png", title=img_title)
606
607
        if obj.getSamplingDate and obj.getSamplingDate > DateTime():
608
            after_icons += get_image("calendar.png",
609
                                     title=t(_("Future dated sample")))
610
        if obj.getInvoiceExclude:
611
            after_icons += get_image("invoice_exclude.png",
612
                                     title=t(_("Exclude from invoice")))
613
        if obj.getHazardous:
614
            after_icons += get_image("hazardous.png",
615
                                     title=t(_("Hazardous")))
616
617
        if obj.getInternalUse:
618
            after_icons += get_image("locked.png", title=t(_("Internal use")))
619
620
        if after_icons:
621
            item['after']['getId'] = after_icons
622
623
        item['Created'] = self.ulocalized_time(obj.created, long_format=1)
624
        if obj.getContactUID:
625
            item['ClientContact'] = obj.getContactFullName
626
            item['replace']['ClientContact'] = "<a href='%s'>%s</a>" % \
627
                                               (obj.getContactURL, obj.getContactFullName)
628
        else:
629
            item["ClientContact"] = ""
630
        # TODO-performance: If SamplingWorkflowEnabled, we have to get the
631
        # full object to check the user permissions, so far this is
632
        # a performance hit.
633
        if obj.getSamplingWorkflowEnabled:
634
            # We don't do anything with Sampling Date.
635
            # User can modify Sampling date
636
            # inside AR view. In this listing view,
637
            # we only let the user to edit Date Sampled
638
            # and Sampler if he wants to make 'sample' transaction.
639
            if not obj.getDateSampled:
640
                datesampled = self.ulocalized_time(
641
                    DateTime(), long_format=True)
642
                item["class"]["getDateSampled"] = "provisional"
643
            else:
644
                datesampled = self.ulocalized_time(obj.getDateSampled,
645
                                                   long_format=True)
646
647
            sampler = obj.getSampler
648
            if sampler:
649
                item["replace"]["getSampler"] = obj.getSamplerFullName
650
            if "Sampler" in self.roles and not sampler:
651
                sampler = self.member.id
652
                item["class"]["getSampler"] = "provisional"
653
            # sampling workflow - inline edits for Sampler and Date Sampled
654
            if item["review_state"] == 'to_be_sampled':
655
                # We need to get the full object in order to check
656
                # the permissions
657
                full_object = obj.getObject()
658
                checkPermission = \
659
                    self.context.portal_membership.checkPermission
660
661
                # TODO Do we really need this check?
662
                if checkPermission(TransitionSampleSample, full_object):
663
                    item["required"] = ["getSampler", "getDateSampled"]
664
                    item["allow_edit"] = ["getSampler", "getDateSampled"]
665
                    # TODO-performance: hit performance while getting the
666
                    # sample object...
667
                    # TODO Can LabManagers be a Sampler?!
668
                    samplers = getUsers(full_object, ["Sampler", ])
669
                    username = self.member.getUserName()
670
                    users = [({
671
                        "ResultValue": u,
672
                        "ResultText": samplers.getValue(u)}) for u in samplers]
673
                    item['choices'] = {'getSampler': users}
674
                    Sampler = sampler and sampler or \
675
                              (username in samplers.keys() and username) or ''
676
                    sampler = Sampler
677
                else:
678
                    datesampled = self.ulocalized_time(obj.getDateSampled,
679
                                                       long_format=True)
680
                    sampler = obj.getSamplerFullName if obj.getSampler else ''
681
        else:
682
            datesampled = self.ulocalized_time(obj.getDateSampled,
683
                                               long_format=True)
684
            sampler = ""
685
        item["getDateSampled"] = datesampled
686
        item["getSampler"] = sampler
687
688
        # These don't exist on ARs
689
        # XXX This should be a list of preservers...
690
        item["getPreserver"] = ""
691
        item["getDatePreserved"] = ""
692
693
        # Assign the parent sample of this partition
694
        item["parent"] = obj.getRawParentAnalysisRequest
695
696
        # Assign the partitions of this sample
697
        if self.show_partitions:
698
            item["children"] = obj.getDescendantsUIDs or []
699
700
        return item
701
702
    @property
703
    def copy_to_new_allowed(self):
704
        mtool = api.get_tool("portal_membership")
705
        if mtool.checkPermission(AddAnalysisRequest, self.context):
706
            return True
707
        return False
708
709
    def getDefaultAddCount(self):
710
        return self.context.bika_setup.getDefaultNumberOfARsToAdd()
711
712
    @property
713
    def show_partitions(self):
714
        if api.get_current_client():
715
            # If current user is a client contact, delegate to ShowPartitions
716
            return api.get_setup().getShowPartitions()
717
        return True
718