Passed
Push — master ( 70be41...e1228c )
by Ramon
11:12
created

bika.lims.content.labcontact.LabContact.Title()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
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
# 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-2019 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
import sys
22
23
from AccessControl import ClassSecurityInfo
24
from bika.lims import api
25
from bika.lims import bikaMessageFactory as _
26
from bika.lims.browser.fields import UIDReferenceField
27
from bika.lims.config import PROJECTNAME
28
from bika.lims.content.contact import Contact
29
from bika.lims.content.person import Person
30
from bika.lims.interfaces import IDeactivable
31
from bika.lims.interfaces import IHaveDepartment
32
from bika.lims.interfaces import ILabContact
33
from Products.Archetypes import atapi
34
from Products.Archetypes.Field import ImageField
35
from Products.Archetypes.Field import ImageWidget
36
from Products.Archetypes.Field import ReferenceField
37
from Products.Archetypes.Field import ReferenceWidget
38
from Products.Archetypes.public import SelectionWidget
39
from Products.Archetypes.public import registerType
40
from Products.Archetypes.references import HoldingReference
41
from Products.CMFPlone.utils import safe_unicode
42
from zope.interface import implements
43
44
45
schema = Person.schema.copy() + atapi.Schema((
46
47
    ImageField(
48
        "Signature",
49
        widget=ImageWidget(
50
            label=_("Signature"),
51
            description=_(
52
                "Upload a scanned signature to be used on printed "
53
                "analysis results reports. Ideal size is 250 pixels "
54
                "wide by 150 high"),
55
        ),
56
    ),
57
58
    ReferenceField(
59
        "Departments",
60
        required=0,
61
        vocabulary_display_path_bound=sys.maxint,
62
        allowed_types=("Department",),
63
        relationship="LabContactDepartment",
64
        vocabulary="_departmentsVoc",
65
        referenceClass=HoldingReference,
66
        multiValued=1,
67
        widget=ReferenceWidget(
68
            checkbox_bound=0,
69
            label=_("Departments"),
70
            description=_("The laboratory departments"),
71
        ),
72
    ),
73
74
    UIDReferenceField(
75
        "DefaultDepartment",
76
        required=0,
77
        vocabulary_display_path_bound=sys.maxint,
78
        vocabulary="_defaultDepsVoc",
79
        accessor="getDefaultDepartmentUID",
80
        widget=SelectionWidget(
81
            visible=True,
82
            format="select",
83
            label=_("Default Department"),
84
            description=_("Default Department"),
85
        ),
86
    ),
87
))
88
89
schema["JobTitle"].schemata = "default"
90
# Don't make title required - it will be computed from the Person's Fullname
91
schema["title"].required = 0
92
schema["title"].widget.visible = False
93
schema["Department"].required = 0
94
schema["Department"].widget.visible = False
95
96
97
class LabContact(Contact):
98
    """A Lab Contact, which can be linked to a System User
99
    """
100
    implements(ILabContact, IHaveDepartment, IDeactivable)
101
102
    schema = schema
103
    displayContentsTab = False
104
    security = ClassSecurityInfo()
105
    _at_rename_after_creation = True
106
107
    def _renameAfterCreation(self, check_auto_id=False):
108
        from bika.lims.idserver import renameAfterCreation
109
        renameAfterCreation(self)
110
111
    def Title(self):
112
        """Return the contact's Fullname as title
113
        """
114
        return safe_unicode(self.getFullname()).encode("utf-8")
115
116
    @security.public
117
    def getDepartment(self):
118
        """Required by IHaveDepartment. Returns the list of departments this
119
        laboratory contact is assigned to plus the default department
120
        """
121
        departments = self.getDepartments() + [self.getDefaultDepartment()]
122
        return filter(None, list(set(departments)))
123
124
    @security.public
125
    def getDefaultDepartment(self):
126
        """Returns the assigned default department
127
128
        :returns: Department object
129
        """
130
        return self.getField("DefaultDepartment").get(self)
131
132
    @security.public
133
    def getDefaultDepartmentUID(self):
134
        """Returns the UID of the assigned default department
135
136
        NOTE: This is the default accessor of the `DefaultDepartment` schema
137
        field and needed for the selection widget to render the selected value
138
        properly in _view_ mode.
139
140
        :returns: Default Department UID
141
        """
142
        department = self.getDefaultDepartment()
143
        if not department:
144
            return None
145
        return api.get_uid(department)
146
147
    def hasUser(self):
148
        """Check if contact has user
149
        """
150
        username = self.getUsername()
151
        if not username:
152
            return False
153
        user = api.get_user(username)
154
        return user is not None
155
156
    def _departmentsVoc(self):
157
        """Vocabulary of available departments
158
        """
159
        query = {
160
            "portal_type": "Department",
161
            "is_active": True
162
        }
163
        results = api.search(query, "bika_setup_catalog")
164
        items = map(lambda dept: (api.get_uid(dept), api.get_title(dept)),
165
                    results)
166
        dept_uids = map(api.get_uid, results)
167
        # Currently assigned departments
168
        depts = self.getDepartments()
169
        # If one department assigned to the Lab Contact is disabled, it will
170
        # be shown in the list until the department has been unassigned.
171
        for dept in depts:
172
            uid = api.get_uid(dept)
173
            if uid in dept_uids:
174
                continue
175
            items.append((uid, api.get_title(dept)))
176
177
        return api.to_display_list(items, sort_by="value", allow_empty=False)
178
179
    def _defaultDepsVoc(self):
180
        """Vocabulary of all departments
181
        """
182
        # Getting the assigned departments
183
        deps = self.getDepartments()
184
        items = []
185
        for d in deps:
186
            items.append((api.get_uid(d), api.get_title(d)))
187
        return api.to_display_list(items, sort_by="value", allow_empty=True)
188
189
    def addDepartment(self, dep):
190
        """Adds a department
191
192
        :param dep: UID or department object
193
        :returns: True when the department was added
194
        """
195
        if api.is_uid(dep):
196
            dep = api.get_object_by_uid(dep)
197
        deps = self.getDepartments()
198
        if dep not in deps:
199
            return False
200
        deps.append(dep)
201
        self.setDepartments(deps)
202
        return True
203
204
    def removeDepartment(self, dep):
205
        """Removes a department
206
207
        :param dep: UID or department object
208
        :returns: True when the department was removed
209
        """
210
        if api.is_uid(dep):
211
            dep = api.get_object_by_uid(dep)
212
        deps = self.getDepartments()
213
        if dep not in deps:
214
            return False
215
        deps.remove(dep)
216
        self.setDepartments(deps)
217
        return True
218
219
220
registerType(LabContact, PROJECTNAME)
221