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

« back to all changes in this revision

Viewing changes to msf_homere_interface/hr.py

  • Committer: Olivier DOSSMANN
  • Date: 2013-05-31 14:22:09 UTC
  • mto: This revision was merged to the branch mainline in revision 1687.
  • Revision ID: od@tempo-consulting.fr-20130531142209-sbcwvzuema11guzz
UF-1991 [FIX] Problem with wizard on "msg" field. Change it to "name".

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: