Passed
Push — 2.x ( 2459cb...f048b4 )
by Ramon
06:30
created

  A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
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-2021 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
from AccessControl import ClassSecurityInfo
22
from bika.lims import api
23
from bika.lims import bikaMessageFactory as _
24
from bika.lims.browser.fields import UIDReferenceField
25
from bika.lims.browser.widgets import ReferenceWidget
26
from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG
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.public import registerType
37
from Products.CMFPlone.utils import safe_unicode
38
from zope.interface import implements
39
40
schema = Person.schema.copy() + atapi.Schema((
41
42
    ImageField(
43
        "Signature",
44
        widget=ImageWidget(
45
            label=_("Signature"),
46
            description=_(
47
                "Upload a scanned signature to be used on printed "
48
                "analysis results reports. Ideal size is 250 pixels "
49
                "wide by 150 high"),
50
        ),
51
    ),
52
53
    UIDReferenceField(
54
        "Departments",
55
        required=0,
56
        allowed_types=("Department",),
57
        vocabulary="_departmentsVoc",
58
        multiValued=1,
59
        widget=ReferenceWidget(
60
            label=_("Departments"),
61
            description=_("The laboratory departments"),
62
        ),
63
    ),
64
65
    UIDReferenceField(
66
        "DefaultDepartment",
67
        required=0,
68
        allowed_types=("Department",),
69
        widget=ReferenceWidget(
70
            label=_("Default Department"),
71
            description=_("Default Department"),
72
            showOn=True,
73
            catalog_name=SETUP_CATALOG,
74
            base_query={
75
                "is_active": True,
76
                "sort_on": "sortable_title",
77
                "sort_order": "ascending"
78
            },
79
        ),
80
    ),
81
))
82
83
schema["JobTitle"].schemata = "default"
84
# Don't make title required - it will be computed from the Person's Fullname
85
schema["title"].required = 0
86
schema["title"].widget.visible = False
87
schema["Department"].required = 0
88
schema["Department"].widget.visible = False
89
90
91
class LabContact(Contact):
92
    """A Lab Contact, which can be linked to a System User
93
    """
94
    implements(ILabContact, IHaveDepartment, IDeactivable)
95
96
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
97
    displayContentsTab = False
98
    security = ClassSecurityInfo()
99
    _at_rename_after_creation = True
100
101
    def _renameAfterCreation(self, check_auto_id=False):
102
        from bika.lims.idserver import renameAfterCreation
103
        renameAfterCreation(self)
104
105
    def Title(self):
106
        """Return the contact's Fullname as title
107
        """
108
        return safe_unicode(self.getFullname()).encode("utf-8")
109
110
    @security.public
111
    def getDepartment(self):
112
        """Required by IHaveDepartment. Returns the list of departments this
113
        laboratory contact is assigned to plus the default department
114
        """
115
        departments = self.getDepartments() + [self.getDefaultDepartment()]
116
        return filter(None, list(set(departments)))
117
118
    @security.public
119
    def getDefaultDepartment(self):
120
        """Returns the assigned default department
121
122
        :returns: Department object
123
        """
124
        return self.getField("DefaultDepartment").get(self)
125
126
    def hasUser(self):
127
        """Check if contact has user
128
        """
129
        username = self.getUsername()
130
        if not username:
131
            return False
132
        user = api.get_user(username)
133
        return user is not None
134
135
    def _departmentsVoc(self):
136
        """Vocabulary of available departments
137
        """
138
        query = {
139
            "portal_type": "Department",
140
            "is_active": True
141
        }
142
        results = api.search(query, "senaite_catalog_setup")
143
        items = map(lambda dept: (api.get_uid(dept), api.get_title(dept)),
144
                    results)
145
        dept_uids = map(api.get_uid, results)
146
        # Currently assigned departments
147
        depts = self.getDepartments()
148
        # If one department assigned to the Lab Contact is disabled, it will
149
        # be shown in the list until the department has been unassigned.
150
        for dept in depts:
151
            uid = api.get_uid(dept)
152
            if uid in dept_uids:
153
                continue
154
            items.append((uid, api.get_title(dept)))
155
156
        return api.to_display_list(items, sort_by="value", allow_empty=False)
157
158
159
    def addDepartment(self, dep):
160
        """Adds a department
161
162
        :param dep: UID or department object
163
        :returns: True when the department was added
164
        """
165
        if api.is_uid(dep):
166
            dep = api.get_object_by_uid(dep)
167
        deps = self.getDepartments()
168
        if dep not in deps:
169
            return False
170
        deps.append(dep)
171
        self.setDepartments(deps)
172
        return True
173
174
    def removeDepartment(self, dep):
175
        """Removes a department
176
177
        :param dep: UID or department object
178
        :returns: True when the department was removed
179
        """
180
        if api.is_uid(dep):
181
            dep = api.get_object_by_uid(dep)
182
        deps = self.getDepartments()
183
        if dep not in deps:
184
            return False
185
        deps.remove(dep)
186
        self.setDepartments(deps)
187
        return True
188
189
190
registerType(LabContact, PROJECTNAME)
191