Passed
Push — master ( ac8f85...f8b67c )
by Ramon
05:19
created

guard_create_partitions()   A

Complexity

Conditions 5

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 21
rs 9.3333
c 0
b 0
f 0
cc 5
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.workflow import getCurrentState
10
from bika.lims.workflow import isActive
11
from bika.lims.workflow import isTransitionAllowed
12
13
# States to be omitted in regular transitions
14
ANALYSIS_DETTACHED_STATES = ['cancelled', 'rejected', 'retracted']
15
16
def to_be_preserved(obj):
17
    """ Returns True if the Sample from this AR needs to be preserved
18
    Returns false if the Analysis Request has no Sample assigned yet or
19
    does not need to be preserved
20
    Delegates to Sample's guard_to_be_preserved
21
    """
22
    sample = obj.getSample()
23
    return sample and sample.guard_to_be_preserved()
24
25
26
def schedule_sampling(obj):
27
    """
28
    Prevent the transition if:
29
    - if the user isn't part of the sampling coordinators group
30
      and "sampling schedule" checkbox is set in bika_setup
31
    - if no date and samples have been defined
32
      and "sampling schedule" checkbox is set in bika_setup
33
    """
34
    return obj.bika_setup.getScheduleSamplingEnabled()
35
36
37
def guard_create_partitions(analysis_request):
38
    """Returns true if partitions can be created using the analysis request
39
    passed in as the source.
40
    """
41
    if not analysis_request.bika_setup.getShowPartitions():
42
        # If partitions are disabled in Setup, return False
43
        return False
44
45
    if analysis_request.isPartition():
46
        # Do not allow the creation of partitions from partitions
47
        return False
48
49
    # Allow only the creation of partitions if all analyses from the Analysis
50
    # Request are in unassigned state. Otherwise, we could end up with
51
    # inconsistencies, because original analyses are deleted when the partition
52
    # is created. Note here we exclude analyses from children (partitions).
53
    analyses = analysis_request.objectValues("Analysis")
54
    for analysis in analyses:
55
        if api.get_workflow_status_of(analysis) != "unassigned":
56
            return False
57
    return analyses and True or False
58
59
60
def guard_submit(analysis_request):
61
    """Return whether the transition "submit" can be performed or not.
62
    Returns True if there is at least one analysis in a non-dettached state and
63
    all analyses in a non-dettached analyses have been submitted.
64
    """
65
    analyses_ready = False
66
    for analysis in analysis_request.getAnalyses():
67
        analysis_status = api.get_workflow_status_of(api.get_object(analysis))
68
        if analysis_status in ANALYSIS_DETTACHED_STATES:
69
            continue
70
        if analysis_status in ['assigned', 'unassigned']:
71
            return False
72
        analyses_ready = True
73
    return analyses_ready
74
75
76
def guard_verify(analysis_request):
77
    """Returns whether the transition "verify" can be performed or not.
78
    Returns True if at there is at least one analysis in a non-dettached state
79
    and all analyses in a non-dettached state are in "verified" state.
80
    """
81
    analyses_ready = False
82
    for analysis in analysis_request.getAnalyses():
83
        analysis_status = api.get_workflow_status_of(api.get_object(analysis))
84
        if analysis_status in ANALYSIS_DETTACHED_STATES:
85
            continue
86
        if analysis_status != 'verified':
87
            return False
88
        analyses_ready = True
89
    return analyses_ready
90
91
92
def prepublish(obj):
93
    """Returns True if 'prepublish' transition can be applied to the Analysis
94
    Request passed in.
95
    Returns true if the Analysis Request is active (not in a cancelled/inactive
96
    state), the 'publish' transition cannot be performed yet, and at least one
97
    of its analysis is under to_be_verified state or has been already verified.
98
    As per default DC workflow definition in bika_ar_workflow, note that
99
    prepublish does not transitions the Analysis Request to any other state
100
    different from the actual one, neither its children. This 'fake' transition
101
    is only used for the prepublish action to be displayed when the Analysis
102
    Request' status is other than verified, so the labman can generate a
103
    provisional report, also if results are not yet definitive.
104
    :returns: true or false
105
    """
106
    if isTransitionAllowed(obj, 'publish'):
107
        return False
108
109
    analyses = obj.getAnalyses(full_objects=True)
110
    for an in analyses:
111
        # If the analysis is not active, omit
112
        if not isActive(an):
113
            continue
114
115
        # Check if the current state is 'verified'
116
        status = getCurrentState(an)
117
        if status in ['verified', 'to_be_verified']:
118
            return True
119
120
    # This analysis request has no single result ready to be verified or
121
    # verified yet. In this situation, it doesn't make sense to publish a
122
    # provisional results reports without a single result to display
123
    return False
124
125
126
def guard_rollback_to_receive(analysis_request):
127
    """Return whether 'rollback_to_receive' transition can be performed or not
128
    """
129
    # Can rollback to receive if at least one analysis hasn't been submitted yet
130
    # or if all analyses have been rejected or retracted
131
    analyses = analysis_request.getAnalyses()
132
    skipped = 0
133
    for analysis in analyses:
134
        analysis_object = api.get_object(analysis)
135
        state = getCurrentState(analysis_object)
136
        if state in ["unassigned", "assigned"]:
137
            return True
138
        if state in ["retracted", "rejected"]:
139
            skipped += 1
140
    return len(analyses) == skipped
141
142
143
def guard_cancel(analysis_request):
144
    """Returns whether 'cancel' transition can be performed or not. Returns
145
    True only if all analyses are in "unassigned" status
146
    """
147
    # Ask to partitions
148
    for partition in analysis_request.getDescendants(all_descendants=False):
149
        if not isTransitionAllowed(partition, "cancel"):
150
            return False
151
152
    # Look through analyses. We've checked the partitions already, so there is
153
    # no need to look through analyses from partitions again, but through the
154
    # analyses directly bound to the current Analysis Request.
155
    for analysis in analysis_request.objectValues("Analysis"):
156
        if api.get_workflow_status_of(analysis) != "unassigned":
157
            return False
158
159
    return True
160
161
162
def guard_reinstate(analysis_request):
163
    """Returns whether 'reinstate" transition can be performed or not. Returns
164
    True only if this is not a partition or the parent analysis request can be
165
    reinstated or is not in a cancelled state
166
    """
167
    parent = analysis_request.getParentAnalysisRequest()
168
    if not parent:
169
        return True
170
    if api.get_workflow_status_of(parent) != "cancelled":
171
        return True
172
    return isTransitionAllowed(parent, "reinstate")
173