[MERGE]
[odoo/odoo.git] / addons / hr_holidays / hr_holidays.py
index 59264ae..2e1fe79 100644 (file)
 #
 ##############################################################################
 
-import time
 import datetime
+from itertools import groupby
+from operator import itemgetter
 
 import netsvc
 from osv import fields, osv
 from tools.translate import _
 
+
 class hr_holidays_status(osv.osv):
     _name = "hr.holidays.status"
     _description = "Leave Type"
 
-    def get_days_cat(self, cr, uid, ids, category_id, return_false, context=None):
-        if context is None:
-            context = {}
-        res = {}
-        for record in self.browse(cr, uid, ids, context=context):
-            res[record.id] = {}
-            max_leaves = leaves_taken = 0
-            if not return_false:
-                cr.execute("""SELECT type, sum(number_of_days) FROM hr_holidays WHERE category_id = %s AND state='validate' AND holiday_status_id = %s GROUP BY type""", (str(category_id), str(record.id)))
-                for line in cr.fetchall():
-                    if line[0] =='remove':
-                        leaves_taken = -line[1]
-                    if line[0] =='add':
-                        max_leaves = line[1]
-            res[record.id]['max_leaves'] = max_leaves
-            res[record.id]['leaves_taken'] = leaves_taken
-            res[record.id]['remaining_leaves'] = max_leaves - leaves_taken
-        return res
-
     def get_days(self, cr, uid, ids, employee_id, return_false, context=None):
-        if context is None:
-            context = {}
+        cr.execute("""SELECT id, type, number_of_days, holiday_status_id FROM hr_holidays WHERE employee_id = %s AND state='validate' AND holiday_status_id in %s""",
+            [employee_id, tuple(ids)])
+        result = sorted(cr.dictfetchall(), key=lambda x: x['holiday_status_id'])
+        grouped_lines = dict((k, [v for v in itr]) for k, itr in groupby(result, itemgetter('holiday_status_id')))
         res = {}
         for record in self.browse(cr, uid, ids, context=context):
             res[record.id] = {}
             max_leaves = leaves_taken = 0
             if not return_false:
-                cr.execute("""SELECT type, sum(number_of_days) FROM hr_holidays WHERE employee_id = %s AND state='validate' AND holiday_status_id = %s GROUP BY type""", (str(employee_id), str(record.id)))
-                for line in cr.fetchall():
-                    if line[0] =='remove':
-                        leaves_taken = -line[1]
-                    if line[0] =='add':
-                        max_leaves = line[1]
+                if record.id in grouped_lines:
+                    leaves_taken = -sum([item['number_of_days'] for item in grouped_lines[record.id] if item['type'] == 'remove'])
+                    max_leaves = sum([item['number_of_days'] for item in grouped_lines[record.id] if item['type'] == 'add'])
             res[record.id]['max_leaves'] = max_leaves
             res[record.id]['leaves_taken'] = leaves_taken
             res[record.id]['remaining_leaves'] = max_leaves - leaves_taken
         return res
 
     def _user_left_days(self, cr, uid, ids, name, args, context=None):
-        if context is None:
-            context = {}
         return_false = False
         employee_id = False
         res = {}
-
         if context and context.has_key('employee_id'):
             if not context['employee_id']:
                 return_false = True
@@ -90,17 +69,16 @@ class hr_holidays_status(osv.osv):
         if employee_id:
             res = self.get_days(cr, uid, ids, employee_id, return_false, context=context)
         else:
-            res = dict.fromkeys(ids, {name: 0})
+            res = dict.fromkeys(ids, {'leaves_taken': 0, 'remaining_leaves': 0, 'max_leaves': 0})
         return res
 
-    # To do: we can add remaining_leaves_category field to display remaining leaves for particular type
     _columns = {
-        'name': fields.char('Name', size=64, required=True, translate=True),
-        'categ_id': fields.many2one('crm.case.categ', 'Meeting Category', domain="[('object_id.model', '=', 'crm.meeting')]", help='If you link this type of leave with a category in the CRM, it will synchronize each leave asked with a case in this category, to display it in the company shared calendar for example.'),
-        'color_name': fields.selection([('red', 'Red'), ('lightgreen', 'Light Green'), ('lightblue','Light Blue'), ('lightyellow', 'Light Yellow'), ('magenta', 'Magenta'),('lightcyan', 'Light Cyan'),('black', 'Black'),('lightpink', 'Light Pink'),('brown', 'Brown'),('violet', 'Violet'),('lightcoral', 'Light Coral'),('lightsalmon', 'Light Salmon'),('lavender', 'Lavender'),('wheat', 'Wheat'),('ivory', 'Ivory')],'Color in Report', required=True, help='This color will be used in the leaves summary located in Reporting\Leaves by Departement'),
-        'limit': fields.boolean('Allow to Override Limit', help='If you thick this checkbox, the system will allow, for this section, the employees to take more leaves than the available ones.'),
+        'name': fields.char('Leave Type', size=64, required=True, translate=True),
+        'categ_id': fields.many2one('crm.case.categ', 'Meeting', domain="[('object_id.model', '=', 'crm.meeting')]", help='If you set a meeting type, OpenERP will create a meeting in the calendar once a leave is validated.'),
+        'color_name': fields.selection([('red', 'Red'),('blue','Blue'), ('lightgreen', 'Light Green'), ('lightblue','Light Blue'), ('lightyellow', 'Light Yellow'), ('magenta', 'Magenta'),('lightcyan', 'Light Cyan'),('black', 'Black'),('lightpink', 'Light Pink'),('brown', 'Brown'),('violet', 'Violet'),('lightcoral', 'Light Coral'),('lightsalmon', 'Light Salmon'),('lavender', 'Lavender'),('wheat', 'Wheat'),('ivory', 'Ivory')],'Color in Report', required=True, help='This color will be used in the leaves summary located in Reporting\Leaves by Departement'),
+        'limit': fields.boolean('Allow to Override Limit', help='If you tick this checkbox, the system will allow, for this section, the employees to take more leaves than the available ones.'),
         'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the leave type without removing it."),
-        'max_leaves': fields.function(_user_left_days, method=True, string='Maximum Leaves Allowed', help='This value is given by the sum of all holidays requests with a positive value.', multi='user_left_days'),
+        'max_leaves': fields.function(_user_left_days, method=True, string='Maximum Allowed', help='This value is given by the sum of all holidays requests with a positive value.', multi='user_left_days'),
         'leaves_taken': fields.function(_user_left_days, method=True, string='Leaves Already Taken', help='This value is given by the sum of all holidays requests with a negative value.', multi='user_left_days'),
         'remaining_leaves': fields.function(_user_left_days, method=True, string='Remaining Leaves', help='Maximum Leaves Allowed - Leaves Already Taken', multi='user_left_days'),
         'double_validation': fields.boolean('Apply Double Validation', help="If its True then its Allocation/Request have to be validated by second validator")
@@ -108,8 +86,7 @@ class hr_holidays_status(osv.osv):
     _defaults = {
         'color_name': 'red',
         'active': True,
-        }
-
+    }
 hr_holidays_status()
 
 class hr_holidays(osv.osv):
@@ -118,95 +95,81 @@ class hr_holidays(osv.osv):
     _order = "type desc, date_from asc"
 
     def _employee_get(obj, cr, uid, context=None):
-        if context is None:
-            context = {}
         ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
         if ids:
             return ids[0]
         return False
 
+    def _compute_number_of_days(self, cr, uid, ids, name, args, context=None):
+        result = {}
+        for hol in self.browse(cr, uid, ids, context=context):
+            if hol.type=='remove':
+                result[hol.id] = -hol.number_of_days_temp
+            else:
+                result[hol.id] = hol.number_of_days_temp
+        return result
+
     _columns = {
-        'name': fields.char('Description', required=True, readonly=True, size=64, states={'draft':[('readonly',False)]}),
-        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Waiting Validation'), ('refuse', 'Refused'), ('validate1', 'Waiting Second Validation'), ('validate', 'Validated'), ('cancel', 'Cancelled')], 'State', readonly=True, help='When the holiday request is created the state is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the state is \'Waiting Validation\'.\
-            If the admin accepts it, the state is \'Validated\'. If it is refused, the state is \'Refused\'.'),
+        'name': fields.char('Description', required=True, size=64),
+        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Waiting Approval'), ('refuse', 'Refused'), 
+            ('validate1', 'Waiting Second Approval'), ('validate', 'Approved'), ('cancel', 'Cancelled')],
+            'State', readonly=True, help='When the holiday request is created the state is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the state is \'Waiting Approval\'.\
+            If the admin accepts it, the state is \'Approved\'. If it is refused, the state is \'Refused\'.'),
+        'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True),
         'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)]}),
-        'user_id':fields.many2one('res.users', 'User', states={'draft':[('readonly',False)]}, select=True, readonly=True),
         'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)]}),
-        'holiday_status_id' : fields.many2one("hr.holidays.status", " Leave  Type", required=True,readonly=True, states={'draft':[('readonly',False)]}),
-        'employee_id' : fields.many2one('hr.employee', "Employee", select=True, invisible=False, readonly=True, states={'draft':[('readonly',False)]}, help='Leave Manager can let this field empty if this leave request/allocation is for every employee'),
-        'manager_id': fields.many2one('hr.employee', 'Leave Manager', invisible=False, readonly=True, help='This area is automaticly filled by the user who validate the leave'),
-        'notes': fields.text('Notes',readonly=True, states={'draft':[('readonly',False)]}),
-        'number_of_days': fields.float('Number of Days', readonly=True, states={'draft':[('readonly',False)]}),
+        'holiday_status_id': fields.many2one("hr.holidays.status", "Leave Type", required=True,readonly=True, states={'draft':[('readonly',False)]}),
+        'employee_id': fields.many2one('hr.employee', "Employee", select=True, invisible=False, readonly=True, states={'draft':[('readonly',False)]}, help='Leave Manager can let this field empty if this leave request/allocation is for every employee'),
+        #'manager_id': fields.many2one('hr.employee', 'Leave Manager', invisible=False, readonly=True, help='This area is automaticly filled by the user who validate the leave'),
+        #'notes': fields.text('Notes',readonly=True, states={'draft':[('readonly',False)]}),
+        'manager_id': fields.many2one('hr.employee', 'First Approval', invisible=False, readonly=True, help='This area is automaticly filled by the user who validate the leave'),
+        'notes': fields.text('Reasons',readonly=True, states={'draft':[('readonly',False)]}),
         'number_of_days_temp': fields.float('Number of Days', readonly=True, states={'draft':[('readonly',False)]}),
-        'case_id': fields.many2one('crm.meeting', 'Case'),
+        'number_of_days': fields.function(_compute_number_of_days, method=True, string='Number of Days', store=True),
+        'case_id': fields.many2one('crm.meeting', 'Meeting'),
         'type': fields.selection([('remove','Leave Request'),('add','Allocation Request')], 'Request Type', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose 'Leave Request' if someone wants to take an off-day. \nChoose 'Allocation Request' if you want to increase the number of leaves available for someone"),
-        'allocation_type': fields.selection([('employee','Employee Request'),('company','Company Allocation')], 'Allocation Type', required=True, readonly=True, states={'draft':[('readonly',False)]}, help='This field is only for informative purposes, to depict if the leave request/allocation comes from an employee or from the company'),
         'parent_id': fields.many2one('hr.holidays', 'Parent'),
         'linked_request_ids': fields.one2many('hr.holidays', 'parent_id', 'Linked Requests',),
         'department_id':fields.related('employee_id', 'department_id', string='Department', type='many2one', relation='hr.department', readonly=True, store=True),
-        'category_id': fields.many2one('hr.employee.category', "Category", help='Category Of employee'),
-        'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Category')], 'Holiday Type', help='By Employee: Allocation/Request for individual Employee, By Employee Category: Allocation/Request for group of employees in category'),
-        'manager_id2': fields.many2one('hr.employee', 'Second Validator', readonly=True, help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)')
-            }
-
+        'category_id': fields.many2one('hr.employee.category', "Category", help='Category of Employee'),
+        'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Category')], 'Allocation Type', help='By Employee: Allocation/Request for individual Employee, By Employee Category: Allocation/Request for group of employees in category', required=True),
+        'manager_id2': fields.many2one('hr.employee', 'Second Approval', readonly=True, help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)')
+    }
     _defaults = {
-        'employee_id': _employee_get ,
+        'employee_id': _employee_get,
         'state': 'draft',
         'type': 'remove',
-        'allocation_type': 'employee',
         'user_id': lambda obj, cr, uid, context: uid,
         'holiday_type': 'employee'
-        }
+    }
+    _sql_constraints = [
+        ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "You have to select an employee or a category"),
+        ('date_check', "CHECK ( number_of_days_temp > 0 )", "The number of days must be greater than 0 !"),
+        ('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be before the end date !")
+    ]
 
     def _create_resource_leave(self, cr, uid, vals, context=None):
         '''This method will create entry in resource calendar leave object at the time of holidays validated '''
-        if context is None:
-            context = {}
         obj_res_leave = self.pool.get('resource.calendar.leaves')
         return obj_res_leave.create(cr, uid, vals, context=context)
 
     def _remove_resouce_leave(self, cr, uid, ids, context=None):
         '''This method will create entry in resource calendar leave object at the time of holidays cancel/removed'''
         obj_res_leave = self.pool.get('resource.calendar.leaves')
-        if context is None:
-            context = {}
         leave_ids = obj_res_leave.search(cr, uid, [('holiday_id', 'in', ids)], context=context)
         return obj_res_leave.unlink(cr, uid, leave_ids)
 
-    def create(self, cr, uid, vals, context=None):
-        if context is None:
-            context = {}
-        if 'holiday_type' in vals:
-            if vals['holiday_type'] == 'employee':
-                vals.update({'category_id': False})
-            else:
-                vals.update({'employee_id': False})
-        if context.has_key('type'):
-            vals['type'] = context['type']
-        if context.has_key('allocation_type'):
-            vals['allocation_type'] = context['allocation_type']
-        return super(hr_holidays, self).create(cr, uid, vals, context=context)
-
-    def write(self, cr, uid, ids, vals, context=None):
-        if context is None:
-            context = {}
-        if 'holiday_type' in vals:
-            if vals['holiday_type'] == 'employee':
-                vals.update({'category_id': False})
-            else:
-                vals.update({'employee_id': False})
-        return super(hr_holidays, self).write(cr, uid, ids, vals, context=context)
-
     def onchange_type(self, cr, uid, ids, holiday_type):
         result = {}
-        if holiday_type=='employee':
+        if holiday_type == 'employee':
             ids_employee = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
             if ids_employee:
                 result['value'] = {
                     'employee_id': ids_employee[0]
-                                    }
+                }
         return result
 
+    # TODO: can be improved using resource calendar method
     def _get_number_of_days(self, date_from, date_to):
         """Returns a float equals to the timedelta between two dates given as string."""
 
@@ -217,36 +180,10 @@ class hr_holidays(osv.osv):
         diff_day = timedelta.days + float(timedelta.seconds) / 86400
         return diff_day
 
-    def _update_user_holidays(self, cr, uid, ids):
-        for record in self.browse(cr, uid, ids):
-            if record.state=='validate':
-                if record.case_id:
-                    self.pool.get('crm.meeting').unlink(cr, uid, [record.case_id.id])
-                if record.linked_request_ids:
-                    list_ids = []
-                    [list_ids.append(i) for id in record.linked_request_ids]
-                    self.holidays_cancel(cr, uid, list_ids)
-                    self.unlink(cr, uid, list_ids)
-
-    def _check_date(self, cr, uid, ids):
-        for rec in self.read(cr, uid, ids, ['number_of_days_temp', 'date_from','date_to', 'type']):
-            if rec['number_of_days_temp'] < 0:
-                return False
-            if rec['type'] == 'add':
-                continue
-            date_from = time.strptime(rec['date_from'], '%Y-%m-%d %H:%M:%S')
-            date_to = time.strptime(rec['date_to'], '%Y-%m-%d %H:%M:%S')
-            if date_from > date_to:
-                return False
-        return True
-
-    _constraints = [(_check_date, 'Start date should not be larger than end date!\nNumber of Days should be greater than 1!', ['number_of_days_temp'])]
-
     def unlink(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        self._update_user_holidays(cr, uid, ids)
-        self._remove_resouce_leave(cr, uid, ids, context=context)
+        for rec in self.browse(cr, uid, ids, context=context):
+            if rec.state<>'draft':
+                raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is not in draft state !'))
         return super(hr_holidays, self).unlink(cr, uid, ids, context)
 
     def onchange_date_from(self, cr, uid, ids, date_to, date_from):
@@ -262,203 +199,115 @@ class hr_holidays(osv.osv):
         }
         return result
 
-    def onchange_date_to(self, cr, uid, ids, date_from, date_to):
-        return self.onchange_date_from(cr, uid, ids, date_to, date_from)
-
     def onchange_sec_id(self, cr, uid, ids, status, context=None):
-        if context is None:
-            context = {}
         warning = {}
         if status:
-            brows_obj = self.pool.get('hr.holidays.status').browse(cr, uid, [status], context=context)[0]
+            brows_obj = self.pool.get('hr.holidays.status').browse(cr, uid, status, context=context)
             if brows_obj.categ_id and brows_obj.categ_id.section_id and not brows_obj.categ_id.section_id.allow_unlink:
                 warning = {
                     'title': "Warning for ",
                     'message': "You won\'t be able to cancel this leave request because the CRM Sales Team of the leave type disallows."
-                        }
+                }
         return {'warning': warning}
 
     def set_to_draft(self, cr, uid, ids, *args):
-        wf_service = netsvc.LocalService("workflow")
         self.write(cr, uid, ids, {
             'state': 'draft',
             'manager_id': False,
-            'number_of_days': 0,
         })
+        wf_service = netsvc.LocalService("workflow")
         for id in ids:
             wf_service.trg_create(uid, 'hr.holidays', id, cr)
         return True
 
-    def holidays_validate2(self, cr, uid, ids, *args):
-        vals = {'state':'validate1'}
-        self.check_holidays(cr, uid, ids)
-        ids2 = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)])
-        if ids2:
-            vals['manager_id'] = ids2[0]
-        else:
-            raise osv.except_osv(_('Warning !'),_('No user related to the selected employee.'))
-        self.write(cr, uid, ids, vals)
-        return True
-
     def holidays_validate(self, cr, uid, ids, *args):
+        self.check_holidays(cr, uid, ids)
         obj_emp = self.pool.get('hr.employee')
-        data_holiday = self.browse(cr, uid, ids)
+        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
+        manager = ids2 and ids2[0] or False
+        return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager})
+
+    def holidays_validate2(self, cr, uid, ids, *args):
         self.check_holidays(cr, uid, ids)
-        vals = {'state':'validate'}
+        obj_emp = self.pool.get('hr.employee')
         ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
-        if ids2:
-            if data_holiday[0].state == 'validate1':
-                vals['manager_id2'] = ids2[0]
-            else:
-                vals['manager_id'] = ids2[0]
-        else:
-            raise osv.except_osv(_('Warning !'), _('No user related to the selected employee.'))
-        self.write(cr, uid, ids, vals)
+        manager = ids2 and ids2[0] or False
+        self.write(cr, uid, ids, {'state':'validate', 'manager_id2': manager})
+        data_holiday = self.browse(cr, uid, ids)
         for record in data_holiday:
             if record.holiday_type == 'employee' and record.type == 'remove':
+                meeting_obj = self.pool.get('crm.meeting')
                 vals = {
-                   'name': record.name,
-                   'date_from': record.date_from,
-                   'date_to': record.date_to,
-                   'calendar_id': record.employee_id.calendar_id.id,
-                   'company_id': record.employee_id.company_id.id,
-                   'resource_id': record.employee_id.resource_id.id,
-                   'holiday_id': record.id
-                     }
-                self._create_resource_leave(cr, uid, vals)
-            elif record.holiday_type == 'category' and record.type == 'remove':
-                emp_ids = obj_emp.search(cr, uid, [('category_id', '=', record.category_id.id)])
+                    'name': record.name,
+                    'categ_id': record.holiday_status_id.categ_id.id,
+                    'duration': record.number_of_days_temp * 8,
+                    'note': record.notes,
+                    'user_id': record.user_id.id,
+                    'date': record.date_from,
+                    'end_date': record.date_to,
+                    'date_deadline': record.date_to,
+                }
+                case_id = meeting_obj.create(cr, uid, vals)
+                self.write(cr, uid, ids, {'case_id': case_id})
+            elif record.holiday_type == 'category':
+                emp_ids = obj_emp.search(cr, uid, [('category_ids', 'child_of', [record.category_id.id])])
+                leave_ids = []
                 for emp in obj_emp.browse(cr, uid, emp_ids):
                     vals = {
-                       'name': record.name,
-                       'date_from': record.date_from,
-                       'date_to': record.date_to,
-                       'calendar_id': emp.calendar_id.id,
-                       'company_id': emp.company_id.id,
-                       'resource_id': emp.resource_id.id,
-                       'holiday_id':record.id
-                         }
-                    self._create_resource_leave(cr, uid, vals)
+                        'name': record.name,
+                        'type': record.type,
+                        'holiday_type': 'employee',
+                        'holiday_status_id': record.holiday_status_id.id,
+                        'date_from': record.date_from,
+                        'date_to': record.date_to,
+                        'notes': record.notes,
+                        'number_of_days_temp': record.number_of_days_temp,
+                        'parent_id': record.id,
+                        'employee_id': emp.id
+                    }
+                    leave_ids.append(self.create(cr, uid, vals, context=None))
+                wf_service = netsvc.LocalService("workflow")
+                for leave_id in leave_ids:
+                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'confirm', cr)
+                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'validate', cr)
+                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'second_validate', cr)
         return True
 
     def holidays_confirm(self, cr, uid, ids, *args):
-        for record in self.browse(cr, uid, ids):
-            user_id = False
-            leave_asked = record.number_of_days_temp
-            if record.holiday_type == 'employee' and record.type == 'remove':
-                if record.employee_id and not record.holiday_status_id.limit:
-                    leaves_rest = self.pool.get('hr.holidays.status').get_days( cr, uid, [record.holiday_status_id.id], record.employee_id.id, False)[record.holiday_status_id.id]['remaining_leaves']
-                    if leaves_rest < leave_asked:
-                        raise osv.except_osv(_('Warning!'),_('You cannot validate leaves for %s while available leaves are less than asked leaves.' %(record.employee_id.name)))
-                nb = -(record.number_of_days_temp)
-            elif record.holiday_type == 'category' and record.type == 'remove':
-                if record.category_id and not record.holiday_status_id.limit:
-                    leaves_rest = self.pool.get('hr.holidays.status').get_days_cat( cr, uid, [record.holiday_status_id.id], record.category_id.id, False)[record.holiday_status_id.id]['remaining_leaves']
-                    if leaves_rest < leave_asked:
-                        raise osv.except_osv(_('Warning!'),_('You cannot validate leaves for %s while available leaves are less than asked leaves.' %(record.category_id.name)))
-                nb = -(record.number_of_days_temp)
-            else:
-                nb = record.number_of_days_temp
-
-            if record.holiday_type == 'employee' and record.employee_id:
-                user_id = record.employee_id.user_id and record.employee_id.user_id.id or uid
-
-            self.write(cr, uid, [record.id], {'state':'confirm', 'number_of_days': nb, 'user_id': user_id })
-        return True
+        self.check_holidays(cr, uid, ids)
+        return self.write(cr, uid, ids, {'state':'confirm'})
 
     def holidays_refuse(self, cr, uid, ids, *args):
-        vals = {'state': 'refuse'}
-        ids2 = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
-        if ids2:
-            vals['manager_id'] = ids2[0]
-        self.write(cr, uid, ids, vals)
+        obj_emp = self.pool.get('hr.employee')
+        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
+        manager = ids2 and ids2[0] or False
+        self.write(cr, uid, ids, {'state': 'refuse', 'manager_id2': manager})
+        self.holidays_cancel(cr, uid, ids)
         return True
 
     def holidays_cancel(self, cr, uid, ids, *args):
-        self._update_user_holidays(cr, uid, ids)
-        self.write(cr, uid, ids, {'state': 'cancel'})
-        self._remove_resouce_leave(cr, uid, ids)
-        return True
+        obj_crm_meeting = self.pool.get('crm.meeting')
+        for record in self.browse(cr, uid, ids):
+            # Delete the meeting
+            if record.case_id:
+                obj_crm_meeting.unlink(cr, uid, [record.case_id.id])
+
+            # If a category that created several holidays, cancel all related
+            wf_service = netsvc.LocalService("workflow")
+            for res in record.linked_request_ids:
+                wf_service.trg_validate(uid, 'hr.holidays', res.id, 'cancel', cr)
 
-    def holidays_draft(self, cr, uid, ids, *args):
-        self.write(cr, uid, ids, {'state': 'draft'})
         return True
 
     def check_holidays(self, cr, uid, ids):
         holi_status_obj = self.pool.get('hr.holidays.status')
-        emp_obj = self.pool.get('hr.employee')
-        meeting_obj = self.pool.get('crm.meeting')
         for record in self.browse(cr, uid, ids):
-            if not record.number_of_days:
-                raise osv.except_osv(_('Warning!'), _('Wrong leave definition.'))
-            if record.holiday_type=='employee' and record.employee_id:
-                leave_asked = record.number_of_days
-                if leave_asked < 0.00:
-                    if not record.holiday_status_id.limit:
-                        leaves_rest = holi_status_obj.get_days(cr, uid, [record.holiday_status_id.id], record.employee_id.id, False)[record.holiday_status_id.id]['remaining_leaves']
-                        if leaves_rest < -(leave_asked):
-                            raise osv.except_osv(_('Warning!'),_('You Cannot Validate leaves while available leaves are less than asked leaves.'))
-            elif record.holiday_type == 'category' and record.category_id:
-                leave_asked = record.number_of_days
-                if leave_asked < 0.00:
-                    if not record.holiday_status_id.limit:
-                        leaves_rest = holi_status_obj.get_days_cat(cr, uid, [record.holiday_status_id.id], record.category_id.id, False)[record.holiday_status_id.id]['remaining_leaves']
-                        if leaves_rest < -(leave_asked):
-                            raise osv.except_osv(_('Warning!'),_('You Cannot Validate leaves while available leaves are less than asked leaves.'))
-            else:# This condition will never meet!!
-                holiday_ids = []
-                vals = {
-                    'name' : record.name,
-                    'holiday_status_id' : record.holiday_status_id.id,
-                    'state': 'draft',
-                    'date_from' : record.date_from,
-                    'date_to' : record.date_to,
-                    'notes' : record.notes,
-                    'number_of_days': record.number_of_days,
-                    'number_of_days_temp': record.number_of_days_temp,
-                    'type': record.type,
-                    'allocation_type': record.allocation_type,
-                    'parent_id': record.id,
-                }
-                employee_ids = emp_obj.search(cr, uid, [])
-                for employee in employee_ids:
-                    vals['employee_id'] = employee
-                    user_id = emp_obj.search(cr, uid, [('user_id','=',uid)])
-                    if user_id:
-                        vals['user_id'] = user_id[0]
-                    holiday_ids.append(self.create(cr, uid, vals, context=None))
-                self.holidays_confirm(cr, uid, holiday_ids)
-                self.holidays_validate(cr, uid, holiday_ids)
-
-            #if record.holiday_status_id.categ_id and record.date_from and record.date_to and record.employee_id:
-#            if record.holiday_status_id.categ_id and record.date_from and record.date_to:
-#                vals={}
-#                vals['name']=record.name
-#                vals['categ_id']=record.holiday_status_id.categ_id.id
-#                epoch_c = time.mktime(time.strptime(record.date_to,'%Y-%m-%d %H:%M:%S'))
-#                epoch_d = time.mktime(time.strptime(record.date_from,'%Y-%m-%d %H:%M:%S'))
-#                diff_day = (epoch_c - epoch_d)/(3600*24)
-#                vals['duration'] = (diff_day) * 8
-#                vals['note'] = record.notes
-##                vals['user_id'] = record.user_id.id
-#                vals['date'] = record.date_from
-#                if record.holiday_type=='employee':
-#                    vals['user_id'] = record.user_id.id
-            if record.holiday_status_id.categ_id and record.date_from and record.date_to and record.employee_id:
-                diff_day = self._get_number_of_days(record.date_from, record.date_to)
-                vals = {
-                    'name' : record.name,
-                    'categ_id' : record.holiday_status_id.categ_id.id,
-                    'duration' : (diff_day) * 8,
-                    'note' : record.notes,
-                    'user_id' : record.user_id.id,
-                    'date' : record.date_from,
-                }
-                case_id = meeting_obj.create(cr, uid, vals)
-                self.write(cr, uid, ids, {'case_id': case_id})
-
+            if record.holiday_type == 'employee' and record.type == 'remove':
+                if record.employee_id and not record.holiday_status_id.limit:
+                    leaves_rest = holi_status_obj.get_days( cr, uid, [record.holiday_status_id.id], record.employee_id.id, False)[record.holiday_status_id.id]['remaining_leaves']
+                    if leaves_rest < record.number_of_days_temp:
+                        raise osv.except_osv(_('Warning!'),_('You cannot validate leaves for employee %s: too few remaining days (%s).') % (record.employee_id.name, leaves_rest))
         return True
-
 hr_holidays()
 
 class resource_calendar_leaves(osv.osv):
@@ -466,8 +315,7 @@ class resource_calendar_leaves(osv.osv):
     _description = "Leave Detail"
     _columns = {
         'holiday_id': fields.many2one("hr.holidays", "Holiday"),
-        }
+    }
 
 resource_calendar_leaves()
 
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: