# -*- coding: utf-8 -*- ############################################################################## # # TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright # (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. # # This program is free software: you can redistribute it and/or modify it under the # terms of the GNU Affero General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License along with # this program. If not, see . # ############################################################################## from openerp import models, api, fields, _ from openerp.osv import osv from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT from datetime import datetime, timedelta from openerp.exceptions import Warning import math from openerp import SUPERUSER_ID class HRHolidayTimesheet(models.Model): _name = "hr.holidays.timesheet" date = fields.Date('Date') holiday_id = fields.Many2one("hr.holidays", "Holiday") sheet_id = fields.Many2one('hr_timesheet_sheet.sheet', 'Sheet') timesheet_id = fields.Many2one("hr.analytic.timesheet", "Timesheet") duration = fields.Float("Hours") class HRTimesheetSheet(models.Model): _inherit = "hr_timesheet_sheet.sheet" @api.model def create(self, values): res = super(HRTimesheetSheet, self).create(values) res.calc_leave_hours() return res @api.multi def calc_leave_hours(self): leave_obj = self.env['hr.holidays'] leave_recs = leave_obj.search([('employee_id', '=', self.employee_id.id), ('state', '=', 'validate'), ('state', '!=', 'refuse')]) for leave in leave_recs: leave_processed = True for hl_ts_rec in leave.holidays_timesheet_ids: if not hl_ts_rec.timesheet_id: #print"Calc leave hours - No Timesheet_id", hl_ts_rec leave_processed = False if not leave_processed: leave.make_timesheet_entry() class HRHoliday(models.Model): _inherit = "hr.holidays" holidays_timesheet_ids = fields.One2many("hr.holidays.timesheet", "holiday_id", "Timesheet") @api.multi def holidays_refuse(self): res = super(HRHoliday, self).holidays_refuse() for hl_ts_rec in self.sudo().holidays_timesheet_ids: hl_ts_rec.timesheet_id.unlink() hl_ts_rec.write({'sheet_id': False}) return res @api.multi def holidays_validate(self): res = super(HRHoliday, self).holidays_validate() self.make_timesheet_entry() return res @api.multi def make_holidays_timesheet(self, res): result = [] holi_ts_obj = self.env['hr.holidays.timesheet'] cur_recs = holi_ts_obj.search([('holiday_id', '=', self.id)]) res_days = res.keys() for rec in cur_recs: if rec.date not in res_days: rec.unlink() for day, duration in res.iteritems(): holiday = None holiday = self.env['itis.holiday'].search([('date', '=', day)]) if holiday: continue cur_rec = holi_ts_obj.search([('holiday_id', '=', self.id), ('date', '=', day)]) if not cur_rec.id: cur_rec = holi_ts_obj.create({'date': day, 'duration': duration, "holiday_id": self.id}) if cur_rec.duration != duration: cur_rec.update({'duration': duration}) result.append(cur_rec) return result @api.multi def make_timesheet_entry(self): res = self.count_day_hours_leave() res = self.make_holidays_timesheet(res) account_id = False if self.is_ot_leave: account_id = self.env.user.company_id.ot_leave_account_id else: account_id = self.env.user.company_id.leave_account_id if not account_id: raise Warning(_('Please set the analytic account for Leaves.\nPlease contact your administrator for the same.')) sheet_obj = self.env['hr_timesheet_sheet.sheet'] timesheets = sheet_obj.search([("employee_id", '=', self.employee_id.id)]) for hl_ts_rec in res: if hl_ts_rec.timesheet_id: continue cur_day = datetime.strptime(hl_ts_rec.date, DEFAULT_SERVER_DATE_FORMAT) for timesheet in timesheets: ts_date_from = datetime.strptime(timesheet.date_from, DEFAULT_SERVER_DATE_FORMAT) ts_date_to = datetime.strptime(timesheet.date_to, DEFAULT_SERVER_DATE_FORMAT) if cur_day >= ts_date_from and cur_day <= ts_date_to: if timesheet.state != 'draft': continue #raise Warning(_('The Time period is allready closed. \n Please contact the Human Resource Team if the leave request should be confirmed nevertheless')) #print"cur_day ", cur_day ana_ts_id = self.create_timesheet(account_id, timesheet, hl_ts_rec.duration, hl_ts_rec.date) hl_ts_rec.write({'timesheet_id': ana_ts_id[0], 'sheet_id': timesheet.id}) return True @api.one def create_timesheet(self, account_id, sheet, duration, day): timesheet_obj = self.pool.get('hr.analytic.timesheet') cr = self.env.cr uid = self.env.uid emp_obj = self.env['hr.employee'] hour = duration res = timesheet_obj.default_get(cr, uid, ['product_id','product_uom_id']) # res.update({ # 'general_account_id': False, # }) if not res['product_id']: res['product_id'] = 1 if not res['product_uom_id']: res['product_uom_id'] = 5 if not res['product_uom_id']: raise osv.except_osv(_('User Error!'), _('Please define cost unit for this employee.')) up = timesheet_obj.on_change_unit_amount(cr, uid, False, res['product_id'], hour,False, res['product_uom_id'])['value'] print"UP ", up res['name'] = "Leave on " + day res['account_id'] = account_id.id res['unit_amount'] = hour emp_journal = emp_obj.search([('user_id', '=', self.employee_id.user_id.id)]).journal_id res['journal_id'] = emp_journal and emp_journal.id or False res.update(up) up = timesheet_obj.on_change_account_id(cr, uid, [], res['account_id']).get('value', {}) res.update(up) print"RES ", res # if not res['general_account_id']: # res['general_account_id'] = 698 res.update({ 'date': day, 'user_id': self.employee_id.user_id.id, 'sheet_id': sheet.id, }) return timesheet_obj.create(cr, SUPERUSER_ID, res, context=res) @api.multi def count_day_hours_leave(self): res = {} date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATETIME_FORMAT) date_to = datetime.strptime(self.date_to, DEFAULT_SERVER_DATETIME_FORMAT) same_day = self.check_same_day(date_from, date_to) temp_date = date_from day_hours = 0.0 weekday = temp_date.weekday() for contract in self.employee_id.contract_ids: cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) cont_end_date = False if not contract.date_end: if cont_start_date <= temp_date: if same_day: cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) day_hours = cur_hour day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] new_hour = res.get(day_str, 0.0) + cur_hour if self.leave_selection =='half_day': new_hour =new_hour/2 res.update({day_str: new_hour}) else: fday_cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) day_hours += fday_cur_hour lday_cur_hour = self.get_day_hours(date_to, contract.working_hours.attendance_ids) day_hours = lday_cur_hour fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour if self.leave_selection =='half_day': fday_new_hour =fday_new_hour/2 res.update({fday_str: fday_new_hour}) lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour if self.leave_selection_date_to =='half_day': lday_new_hour =lday_new_hour/2 #if temp_date == self.start_date and self.start_date_leave_selection == 'half_day': # lday_new_hour =lday_new_hour/2 #elif temp_date == self.end_date and self.end_date_leave_selection == 'half_day': # lday_new_hour =lday_new_hour/2 res.update({lday_str: lday_new_hour}) else: cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) cont_end_date += timedelta(days=1) if cont_start_date <= temp_date and cont_end_date >= temp_date: if same_day: cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) day_hours += cur_hour day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] new_hour = res.get(day_str, 0.0) + cur_hour if self.leave_selection =='half_day': new_hour =new_hour/2 res.update({day_str: new_hour}) else: fday_cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) day_hours += fday_cur_hour lday_cur_hour = self.get_day_hours(date_to, contract.working_hours.attendance_ids) day_hours = lday_cur_hour fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour if self.leave_selection =='half_day': fday_new_hour =fday_new_hour/2 res.update({fday_str: fday_new_hour}) lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour if self.leave_selection_date_to =='half_day': lday_new_hour =lday_new_hour/2 res.update({lday_str: lday_new_hour}) date_from = datetime.strptime(self.date_from.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) date_to = datetime.strptime(self.date_to.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) temp_date = date_from temp_date += timedelta(days=1) while temp_date < date_to: weekday = temp_date.weekday() for contract in self.employee_id.contract_ids: cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) cont_end_date = False if not contract.date_end: if cont_start_date <= temp_date: cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) day_hours += cur_hour day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] new_hour = res.get(day_str, 0.0) + cur_hour res.update({day_str: new_hour}) else: cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) # cont_end_date += timedelta(days=1) if cont_start_date <= temp_date and cont_end_date >= temp_date: cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) day_hours = cur_hour day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] new_hour = res.get(day_str, 0.0) + cur_hour res.update({day_str: new_hour}) temp_date += timedelta(days=1) return res @api.onchange("number_of_days_temp","leave_selection","leave_selection_date_to") def calc_days(self): res = 0 if not self.date_from or not self.date_to: return {} date_from = datetime.strptime(self.date_from.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) date_to = datetime.strptime(self.date_to.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) # if date_from == date_to: # if self.leave_selection =='half_day' or self.leave_selection_date_to =='half_day': # self.number_of_days_temp = 0.5 # return {} temp_date = date_from while temp_date <= date_to: holiday = None holiday = self.env['itis.holiday'].search([('date', '=', temp_date)]) if holiday: temp_date += timedelta(days=1) continue weekday = temp_date.weekday() for contract in self.employee_id.contract_ids: cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) cont_end_date = False if not contract.date_end: if cont_start_date <= temp_date: if self.get_hours(weekday, contract.working_hours.attendance_ids) > 0.0: if temp_date == date_from and self.leave_selection =='half_day': res += 0.25 break if temp_date == date_to and self.leave_selection_date_to =='half_day': res += 0.25 break res += 1 else: cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) # cont_end_date += timedelta(days=1) if cont_start_date <= temp_date and cont_end_date >= temp_date: if self.get_hours(weekday, contract.working_hours.attendance_ids) > 0.0: if temp_date == date_from and self.leave_selection =='half_day': res += 0.25 break if temp_date == date_to and self.leave_selection_date_to =='half_day': res += 0.25 break res += 1 temp_date += timedelta(days=1) self.number_of_days_temp = res return {} class HRHolidayStatus(models.Model): _inherit = "hr.holidays.status" def name_get(self, cr, uid, ids, context=None): if context is None: context = {} if not context.get('employee_id',False): # leave counts is based on employee_id, would be inaccurate if not based on correct employee return super(HRHolidayStatus, self).name_get(cr, uid, ids, context=context) res = [] for record in self.browse(cr, uid, ids, context=context): name = record.name if not record.limit: name = name res.append((record.id, name)) return res