~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to msf_homere_interface/hr.py

UF-73: [MERGE] Merge with unifield-wm branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
# -*- coding: utf-8 -*-
3
 
##############################################################################
4
 
#
5
 
#    OpenERP, Open Source Management Solution
6
 
#    Copyright (C) 2012 TeMPO Consulting, MSF. All Rights Reserved
7
 
#    Developer: Olivier DOSSMANN
8
 
#
9
 
#    This program is free software: you can redistribute it and/or modify
10
 
#    it under the terms of the GNU Affero General Public License as
11
 
#    published by the Free Software Foundation, either version 3 of the
12
 
#    License, or (at your option) any later version.
13
 
#
14
 
#    This program is distributed in the hope that it will be useful,
15
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
#    GNU Affero General Public License for more details.
18
 
#
19
 
#    You should have received a copy of the GNU Affero General Public License
20
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
#
22
 
##############################################################################
23
 
 
24
 
from osv import osv
25
 
from osv import fields
26
 
from lxml import etree
27
 
from tools.translate import _
28
 
 
29
 
class hr_employee(osv.osv):
30
 
    _name = 'hr.employee'
31
 
    _inherit = 'hr.employee'
32
 
 
33
 
    _order = 'name_resource'
34
 
 
35
 
    def _get_allow_edition(self, cr, uid, ids, field_name=None, arg=None, context=None):
36
 
        """
37
 
        For given ids get True or False regarding payroll system configuration (activated or not).
38
 
        If payroll_ok is True, so don't permit Local employee edition.
39
 
        Otherwise permit user to edit them.
40
 
        """
41
 
        if not context:
42
 
            context = {}
43
 
        res = {}
44
 
        allowed = False
45
 
        setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
46
 
        if setup and not setup.payroll_ok:
47
 
            allowed = True
48
 
        for e in ids:
49
 
            res[e] = allowed
50
 
        return res
51
 
 
52
 
    def onchange_type(self, cr, uid, ids, e_type=None, context=None):
53
 
        """
54
 
        Update allow_edition field when changing employee_type
55
 
        """
56
 
        res = {}
57
 
        if not context:
58
 
            context = {}
59
 
        if not e_type:
60
 
            return res
61
 
        elif e_type == 'local':
62
 
            if not 'value' in res:
63
 
                res['value'] = {}
64
 
            allowed = False
65
 
            setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
66
 
            if setup and not setup.payroll_ok:
67
 
                allowed = True
68
 
            res['value'].update({'allow_edition': allowed,})
69
 
        return res
70
 
 
71
 
    _columns = {
72
 
        'employee_type': fields.selection([('', ''), ('local', 'Local Staff'), ('ex', 'Expatriate employee')], string="Type", required=True),
73
 
        'cost_center_id': fields.many2one('account.analytic.account', string="Cost Center", required=False, domain="[('category','=','OC'), ('type', '!=', 'view'), ('state', '=', 'open')]"),
74
 
        'funding_pool_id': fields.many2one('account.analytic.account', string="Funding Pool", domain="[('category', '=', 'FUNDING'), ('type', '!=', 'view'), ('state', '=', 'open')]"),
75
 
        'free1_id': fields.many2one('account.analytic.account', string="Free 1", domain="[('category', '=', 'FREE1'), ('type', '!=', 'view'), ('state', '=', 'open')]"),
76
 
        'free2_id': fields.many2one('account.analytic.account', string="Free 2", domain="[('category', '=', 'FREE2'), ('type', '!=', 'view'), ('state', '=', 'open')]"),
77
 
        'homere_codeterrain': fields.char(string='Homere field: codeterrain', size=20, readonly=True, required=False),
78
 
        'homere_id_staff': fields.integer(string='Homere field: id_staff', size=10, readonly=True, required=False),
79
 
        'homere_id_unique': fields.char(string='Homere field: id_unique', size=42, readonly=True, required=False),
80
 
        'gender': fields.selection([('male', 'Male'),('female', 'Female'), ('unknown', 'Unknown')], 'Gender'),
81
 
        'private_phone': fields.char(string='Private Phone', size=32),
82
 
        'name_resource': fields.related('resource_id', 'name', string="Name", type='char', size=128, store=True),
83
 
        'destination_id': fields.many2one('account.analytic.account', string="Destination", domain="[('category', '=', 'DEST'), ('type', '!=', 'view'), ('state', '=', 'open')]"),
84
 
        'allow_edition': fields.function(_get_allow_edition, method=True, type='boolean', store=False, string="Allow local employee edition?", readonly=True),
85
 
        'photo': fields.binary('Photo', readonly=True),
86
 
    }
87
 
 
88
 
    _defaults = {
89
 
        'employee_type': lambda *a: 'ex',
90
 
        'homere_codeterrain': lambda *a: '',
91
 
        'homere_id_staff': lambda *a: 0.0,
92
 
        'homere_id_unique': lambda *a: '',
93
 
        'gender': lambda *a: 'unknown',
94
 
    }
95
 
 
96
 
    def _check_unicity(self, cr, uid, ids, context=None):
97
 
        """
98
 
        Check that identification_id is not used yet.
99
 
        """
100
 
        # Some verifications
101
 
        if not context:
102
 
            context = {}
103
 
        # Search if no one use this identification_id
104
 
        for e in self.browse(cr, uid, ids):
105
 
            if e.identification_id:
106
 
                same = self.search(cr, uid, [('identification_id', '=', e.identification_id)])
107
 
                if same and len(same) > 1:
108
 
                    return False
109
 
        return True
110
 
 
111
 
    _constraints = [
112
 
        (_check_unicity, "Another employee has the same unique code.", ['identification_id']),
113
 
    ]
114
 
 
115
 
    def create(self, cr, uid, vals, context=None):
116
 
        """
117
 
        Block creation for local staff if no 'from' in context
118
 
        """
119
 
        # Some verifications
120
 
        if not context:
121
 
            context = {}
122
 
        allow_edition = False
123
 
        if 'employee_type' in vals and vals.get('employee_type') == 'local':
124
 
            # Search Payroll functionnality preference (activated or not)
125
 
            # If payroll_ok is False, then we permit user to create local employees
126
 
            setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
127
 
            if setup and not setup.payroll_ok:
128
 
                allow_edition = True
129
 
            # Raise an error if employee is created manually
130
 
            if (not context.get('from', False) or context.get('from') not in ['yaml', 'import']) and not context.get('sync_data', False) and not allow_edition:
131
 
                raise osv.except_osv(_('Error'), _('You are not allowed to create a local staff! Please use Import to create local staff.'))
132
 
#            # Raise an error if no cost_center
133
 
#            if not vals.get('cost_center_id', False):
134
 
#                raise osv.except_osv(_('Warning'), _('You have to complete Cost Center field before employee creation!'))
135
 
            # Add Nat. staff by default if not in vals
136
 
            if not vals.get('destination_id', False):
137
 
                try:
138
 
                    ns_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_destination_national_staff')[1]
139
 
                except ValueError:
140
 
                    ns_id = False
141
 
                vals.update({'destination_id': ns_id})
142
 
 
143
 
        return super(hr_employee, self).create(cr, uid, vals, context)
144
 
 
145
 
    def write(self, cr, uid, ids, vals, context=None):
146
 
        """
147
 
        Block write for local staff if no 'from' in context.
148
 
        Allow only analytic distribution changes (cost center, funding pool, free 1 and free 2)
149
 
        """
150
 
        # Some verifications
151
 
        if not context:
152
 
            context = {}
153
 
        # Prepare some values
154
 
        local = False
155
 
        ex = False
156
 
        allowed = False
157
 
        res = []
158
 
        setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
159
 
        if setup and not setup.payroll_ok:
160
 
            allowed = True
161
 
        # Prepare some variable for process
162
 
        if vals.get('employee_type', False):
163
 
            if vals.get('employee_type') == 'local':
164
 
                local = True
165
 
            elif vals.get('employee_type') == 'ex':
166
 
                ex = True
167
 
        if (context.get('from', False) and context.get('from') in ['yaml', 'import']) or context.get('sync_data', False):
168
 
            allowed = True
169
 
        # Browse all employees
170
 
        for emp in self.browse(cr, uid, ids):
171
 
            new_vals = dict(vals)
172
 
            # Raise an error if attempt to change local into expat and expat into local
173
 
            if emp.employee_type == 'ex' and local and not allowed:
174
 
                raise osv.except_osv(_('Error'), _('You are not allowed to change an expatriate to local staff!'))
175
 
            if emp.employee_type == 'local' and ex and not allowed:
176
 
                raise osv.except_osv(_('Error'), _('You are not allowed to change a local staff to expatriate!'))
177
 
            # Do some modifications for local employees
178
 
            if local or emp.employee_type == 'local':
179
 
                # Do not change any field except analytic distribution (if not allowed)
180
 
                for el in vals:
181
 
                    if el in ['cost_center_id', 'funding_pool_id', 'free1_id', 'free2_id']:
182
 
                        new_vals.update({el: vals[el]})
183
 
            # Write changes
184
 
            employee_id = super(hr_employee, self).write(cr, uid, emp.id, new_vals, context)
185
 
            if employee_id:
186
 
                res.append(employee_id)
187
 
        return res
188
 
 
189
 
    def unlink(self, cr, uid, ids, context=None):
190
 
        """
191
 
        Delete local staff is not allowed except if:
192
 
        - 'unlink' is in context and its value is 'auto'
193
 
        - Payroll functionnality have been DESactivated
194
 
        """
195
 
        # Some verification
196
 
        if not context:
197
 
            context = {}
198
 
        delete_local_staff = False
199
 
        allowed = False
200
 
        setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
201
 
        if setup and not setup.payroll_ok:
202
 
            allowed = True
203
 
        if (context.get('unlink', False) and context.get('unlink') == 'auto') or allowed:
204
 
            delete_local_staff = True
205
 
        setup_id = self.pool.get('unifield.setup.configuration').get_config(cr, uid)
206
 
        if not setup_id.payroll_ok:
207
 
            delete_local_staff = True
208
 
        # Browse all employee
209
 
        for emp in self.browse(cr, uid, ids):
210
 
            if emp.employee_type == 'local' and (not delete_local_staff or not allowed):
211
 
                raise osv.except_osv(_('Warning'), _('You are not allowed to delete local staff manually!'))
212
 
        return super(hr_employee, self).unlink(cr, uid, ids, context)
213
 
 
214
 
    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
215
 
        """
216
 
        Change funding pool domain in order to include MSF Private fund
217
 
        """
218
 
        if not context:
219
 
            context = {}
220
 
        view = super(hr_employee, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
221
 
        form = etree.fromstring(view['arch'])
222
 
        data_obj = self.pool.get('ir.model.data')
223
 
        try:
224
 
            oc_id = data_obj.get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_project')[1]
225
 
        except ValueError:
226
 
            oc_id = 0
227
 
        # Change OC field
228
 
        fields = form.xpath('/' + view_type + '//field[@name="cost_center_id"]')
229
 
        for field in fields:
230
 
            field.set('domain', "[('type', '!=', 'view'), ('state', '=', 'open'), ('id', 'child_of', [%s])]" % oc_id)
231
 
        # Change FP field
232
 
        try:
233
 
            fp_id = data_obj.get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1]
234
 
        except ValueError:
235
 
            fp_id = 0
236
 
        fp_fields = form.xpath('/'  + view_type + '//field[@name="funding_pool_id"]')
237
 
        for field in fp_fields:
238
 
            field.set('domain', "[('category', '=', 'FUNDING'), ('type', '!=', 'view'), ('state', '=', 'open'), '|', ('cost_center_ids', '=', cost_center_id), ('id', '=', %s)]" % fp_id)
239
 
        view['arch'] = etree.tostring(form)
240
 
        return view
241
 
 
242
 
    def onchange_cc(self, cr, uid, ids, cost_center_id=False, funding_pool_id=False):
243
 
        """
244
 
        Update FP or CC regarding both.
245
 
        """
246
 
        # Prepare some values
247
 
        vals = {}
248
 
        if not cost_center_id or not funding_pool_id:
249
 
            return {}
250
 
        if cost_center_id and funding_pool_id:
251
 
            fp = self.pool.get('account.analytic.account').browse(cr, uid, funding_pool_id)
252
 
            try:
253
 
                fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1]
254
 
            except ValueError:
255
 
                fp_id = 0
256
 
            # Exception for MSF Private Fund
257
 
            if funding_pool_id == fp_id:
258
 
                return {}
259
 
            if cost_center_id not in [x.id for x in fp.cost_center_ids]:
260
 
                vals.update({'funding_pool_id': False})
261
 
        return {'value': vals}
262
 
 
263
 
    def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
264
 
        if not args:
265
 
            args=[]
266
 
        if context is None:
267
 
            context={}
268
 
        # UTP-441: only see active employee execept if args also contains a search on 'active' field
269
 
        disrupt = False
270
 
        if context.get('disrupt_inactive', False) and context.get('disrupt_inactive') == True:
271
 
            disrupt = True
272
 
        if not disrupt:
273
 
            if not ('active', '=', False) or not ('active', '=', True) in args:
274
 
                args += [('active', '=', True)]
275
 
        return super(hr_employee, self).name_search(cr, uid, name, args, operator, context, limit)
276
 
 
277
 
hr_employee()
278
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: