tictac/itis_hr_extend/models/hr_leave.py

407 lines
19 KiB
Python

# -*- 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 <https://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, api, fields, _
from openerp.tools import float_round
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
from datetime import datetime, timedelta
from calendar import monthrange
from openerp.exceptions import Warning
import pdb
class HRHolidayStatus(models.Model):
_inherit = "hr.holidays.status"
is_holiday = fields.Boolean(string='Is holiday Type')
is_sick_leave_type = fields.Boolean(string='Is Sick Leave Type')
class HRLeaveNextYear(models.Model):
_name = "hr.leave.nextyear"
date = fields.Date('Date')
holiday_id = fields.Many2one("hr.holidays", "Holiday")
employee_id = fields.Many2one('hr.employee')
leave_days = fields.Float('Tage')
class HRLeaveJournal(models.Model):
_name = "hr.leave.journal"
_order = "year desc"
name = fields.Char("Begründung")
employee_id = fields.Many2one('hr.employee')
year = fields.Integer('Jahr')
# year_type = fields.Selection([('actual','aktuell'),('last','Restanspruch')])
#added for the SOW17
year_type = fields.Selection([('actual','aktuell'),('last','Restanspruch'),('next','next')])
type = fields.Selection([('calculate','Vertraglich'),('leave','Ausgleich'),('manual','Manuell'),('additional','Zusatzurlaub')])
leave_type = fields.Selection([('days','Tage'),('hours','Stunden')])
leave_start = fields.Date('von')
leave_end = fields.Date('bis')
leave_days = fields.Float('Tage')
leave_hours = fields.Float('Stunden')
description = fields.Char('Begründung')
contract_id = fields.Many2one('hr.contract')
last_year_carry_fwd = fields.Boolean('Last Year Carry Fwd Info')
leave_id = fields.Many2one('hr.holidays')
class HREmployee(models.Model):
_inherit = "hr.employee"
leave_days = fields.Float('Urlaubstage', compute="calculate_actual_year_leave_days")
leave_days_last_year = fields.Float('Resturlaub', compute="calculate_last_year_leave_days")
additional_leave_days = fields.Float('Zusatzurlaub', compute="calculate_additional_leave_days")
sum_leaves = fields.Float('Gesamtanspruch', compute="_calculate_sum_leaves")
sum_journal_entries = fields.Integer('Anzahl Journaleinträge', compute="_calculate_sum_journal_entries")
leave_journal_ids = fields.One2many('hr.leave.journal','employee_id')
approved_leaves = fields.Float('abgegoltene Urlaubstage', compute="_calculate_approved_leave_days")
#added new field for the following year june1st SOW17
leave_days_ny = fields.Float('Leaves Following Year', compute="calculate_nextyear_leave_days")
additional_leave_days_ny = fields.Float('Addtional Leaves Following Year', compute="calculate_nextyear_additional_leave_days")
approved_leaves_ny = fields.Float('Approve Leaves Following Year', compute="_calculate_nextyear_approved_leave_days")
sum_leaves_ny = fields.Float('Remaining Leaves Following Year', compute="_calculate_nextyear_sum_leaves")
#added to maintain data for next year so it will be use for dec scheduler
nextyear_leave_ids = fields.One2many('hr.leave.nextyear','employee_id')
approved_leaves_till_march_ny = fields.Float('Approve Leaves Till March', compute="_calculate_nextyear_approved_leave_days_march")
approved_leaves_after_march_ny = fields.Float('Approve Leaves After March', compute="_calculate_nextyear_approved_leave_days_aft_march")
#added field to display remaining leaves of last year based on journal entries from that year
last_year_remaining_leaves = fields.Float('Resturlaub Vorjahr (Zum Jahreswechsel)', compute="calculate_last_year_remaining_leaves")
@api.one
def _calculate_nextyear_approved_leave_days_march(self):
leave_days = 0
next_year = datetime.today().year+1
period_date_start = datetime.strptime('01-01-'+str(next_year),'%d-%m-%Y').date()
period_date_end = datetime.strptime('01-04-'+str(next_year),'%d-%m-%Y').date()
for nextyear_leave in self.nextyear_leave_ids:
leave_date = datetime.strptime(nextyear_leave.date,DEFAULT_SERVER_DATE_FORMAT).date()
if leave_date >=period_date_start and leave_date < period_date_end:
leave_days +=nextyear_leave.leave_days
self.approved_leaves_till_march_ny = leave_days
@api.one
def _calculate_nextyear_approved_leave_days_aft_march(self):
leave_days = 0
next_year = datetime.today().year+1
period_date_start = datetime.strptime('01-04-'+str(next_year),'%d-%m-%Y').date()
period_date_end = datetime.strptime('31-12-'+str(next_year),'%d-%m-%Y').date()
for nextyear_leave in self.nextyear_leave_ids:
leave_date = datetime.strptime(nextyear_leave.date,DEFAULT_SERVER_DATE_FORMAT).date()
if leave_date >=period_date_start and leave_date <= period_date_end:
leave_days +=nextyear_leave.leave_days
self.approved_leaves_after_march_ny = leave_days
#added new functions for the following year june1st SOW17
@api.one
def calculate_nextyear_leave_days(self):
today_date = datetime.today().date()
# for sow17
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
today_date = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date()
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year_type =='next':# condtion to check year type as next
period_date_start = datetime.strptime('01-06-'+str(leave_id.year-1),'%d-%m-%Y').date()
period_date_end = datetime.strptime('01-01-'+str(leave_id.year),'%d-%m-%Y').date()
if today_date >=period_date_start and today_date < period_date_end:
# condition to display value from 01-06-2018 to 03-01-2019,
# when june scheduler run, this value will display again from june to next jan date
if leave_id.type == 'calculate' or leave_id.type == 'manual':
leave_days += leave_id.leave_days
self.leave_days_ny = leave_days
return
@api.one
def calculate_nextyear_additional_leave_days(self):
today_date = datetime.today().date()
# for sow17
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
today_date = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date()
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year_type =='next':
period_date_start = datetime.strptime('01-06-'+str(leave_id.year-1),'%d-%m-%Y').date()
period_date_end = datetime.strptime('01-01-'+str(leave_id.year),'%d-%m-%Y').date()
if today_date >=period_date_start and today_date < period_date_end:
# condition to display value from 01-06-2018 to 03-01-2019,
# when june scheduler run, this value will display again from june to next jan date
if leave_id.type == 'additional':
leave_days += leave_id.leave_days
self.additional_leave_days_ny = leave_days
@api.one
def _calculate_nextyear_approved_leave_days(self):
today_date = datetime.today().date()
# for sow17 testing
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
today_date = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date()
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year_type =='next':
period_date_start = datetime.strptime('01-06-'+str(leave_id.year-1),'%d-%m-%Y').date()
period_date_end = datetime.strptime('01-01-'+str(leave_id.year),'%d-%m-%Y').date()
if today_date >=period_date_start and today_date < period_date_end:
# condition to display value from 01-06-2018 to 03-01-2019,
# when june scheduler run, this value will display again from june to next jan date
if leave_id.type == 'leave' and leave_id.leave_type == 'days':
leave_days += leave_id.leave_days
self.approved_leaves_ny = leave_days
@api.one
def _calculate_nextyear_sum_leaves(self):
sum_leaves = self.leave_days_ny + self.additional_leave_days_ny - self.approved_leaves_ny
self.sum_leaves_ny = sum_leaves
return
#----END----#
@api.one
def _calculate_sum_leaves(self):
sum_leaves = self.leave_days + self.leave_days_last_year + self.additional_leave_days - self.approved_leaves
self.sum_leaves = sum_leaves
return
@api.one
def _calculate_sum_journal_entries(self):
journal_entry_ids = self.env['hr.leave.journal'].search([('employee_id.id','=',self.id),('year','=',datetime.today().year)])
self.sum_journal_entries = len(journal_entry_ids)
@api.one
def calculate_actual_year_leave_days(self):
year = datetime.today().year
# for sow17 testing
for_sow17 = self.env['res.company'].search([('for_sow17','=',True)],limit=1)
if for_sow17:
year = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date().year
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year != year or leave_id.year_type != 'actual':
continue
else:
if leave_id.type == 'calculate':
leave_days += leave_id.leave_days
elif leave_id.type == 'manual':
leave_days += leave_id.leave_days
self.leave_days = leave_days
return
@api.one
def calculate_last_year_leave_days(self):
month = datetime.today().month
year = datetime.today().year
# for sow17 testing
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
year = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date().year
month = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date().month
if month > 3:
self.leave_days_last_year = 0
return
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year != year or leave_id.year_type != 'last' or leave_id.type == 'manual':
continue
else:
if leave_id.type == 'calculate':
leave_days += leave_id.leave_days
elif leave_id.type == 'leave':
leave_days -= leave_id.leave_days
self.leave_days_last_year = leave_days
return
@api.one
def calculate_additional_leave_days(self):
year = datetime.today().year
# for sow17 testing
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
year = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date().year
leave_days = 0
for leave_id in self.leave_journal_ids:
if leave_id.year != year or leave_id.year_type != 'actual':
continue
else:
if leave_id.type == 'additional':
leave_days += leave_id.leave_days
self.additional_leave_days = leave_days
return
@api.one
def _calculate_approved_leave_days(self):
year = datetime.today().year
# for sow17 testing
for_sow17 = self.env['res.company'].sudo().search([('for_sow17','=',True)],limit=1)
if for_sow17:
year = datetime.strptime(for_sow17.next_year_date,DEFAULT_SERVER_DATE_FORMAT).date().year
leave_days = 0
for leave_id in self.leave_journal_ids:
# if leave_id.year != year or leave_id.year_type != 'actual':#original
if leave_id.year != year or leave_id.year_type != 'actual' or leave_id.last_year_carry_fwd: #for sow17 testing
continue
else:
if leave_id.type == 'leave' and leave_id.leave_type == 'days':
leave_days += leave_id.leave_days
self.approved_leaves = leave_days
return
# Function to calculate remaining leaves for last year for information purposes
@api.one
def calculate_last_year_remaining_leaves(self):
year = datetime.today().year-1
#print"Last Year: ",year
leaves_ly = 0
for leave_id in self.leave_journal_ids:
if leave_id.year == year and leave_id.year_type == 'actual' and not leave_id.last_year_carry_fwd:
if leave_id.type in ['calculate', 'manual', 'additional']:
leaves_ly += leave_id.leave_days
elif leave_id.type == 'leave' and leave_id.leave_type == 'days':
leaves_ly -= leave_id.leave_days
#print"leaves_ly =====> ", leaves_ly
self.last_year_remaining_leaves = leaves_ly
return
class HRContract(models.Model):
_inherit = "hr.contract"
def create(self, cr, uid, values, context=None):
new_id = super(HRContract, self).create(cr, uid, values, context=context)
new_rec = self.browse(cr,uid,new_id, context=context)
contract_ids = self.pool.get('hr.leave.journal').search(cr, uid, [('employee_id','=', new_rec.employee_id.id),('type','=','calculate'), ('year_type','=','actual'),('year','=', datetime.today().year)])
if len(contract_ids) == 0:
self.create_leave_journal_entries(cr,uid,new_id,values)
return new_id
@api.one
def create_leave_journal_entries(self,values):
leave_journal_obj = self.env['hr.leave.journal']
leave_days = self.calculate_leave_days(values)
lj_values = {
'employee_id': self.employee_id.id,
'year': datetime.today().year,
'year_type': 'actual',
'type': 'calculate',
'leave_type':'days',
'leave_days': leave_days[0],
'name': 'Vertragsanpassung' + str(datetime.today().date()),
'contract_id': self.id
}
leave_journal_obj.create(lj_values)
return
@api.one
def calculate_leave_days(self,values=None,cyear=None):
leave_days = 0
if not values:
values={}
if not cyear:
cyear = datetime.today().year
date_start = self.date_start
date_end = self.date_end
base_leaves = self.base_leaves
if 'date_start' in values:
date_start = values['date_start']
if 'date_end' in values:
date_end = values['date_end']
if 'base_leaves' in values:
base_leaves = values['base_leaves']
if datetime.strptime(date_start.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT).year < cyear:
if not date_end:
leave_days = base_leaves
elif datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT).year > cyear:
leave_days = base_leaves
# elif datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) >= datetime.strptime('01-07-'+str(cyear),'%d-%m-%Y'):
# leave_days = base_leaves
else:
st = datetime.strptime('01-01-'+str(cyear),'%d-%m-%Y')
leave_days = self.calculate_partial_year(st, datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT), base_leaves)[0]
elif datetime.strptime(date_start.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT).year == cyear:
if not self.date_end:
date_end = datetime.strptime('31-12-'+str(cyear),'%d-%m-%Y')
else:
if datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT).year > cyear:
date_end = datetime.strptime('31-12-'+str(cyear),'%d-%m-%Y')
elif datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT).year == cyear:
date_end = datetime.strptime(date_end.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT)
# Contract starts on 01.01, duration is full year so no need to call calculate_partial_year
ds = datetime.strptime(date_start.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT)
de = date_end
#print"date_start: ",ds.year,ds.month,ds.day
#print"date_end: ",de.year,de.month,de.day
if ds.year == cyear and ds.month == 1 and ds.day == 1 and de.year == cyear and de.month == 12 and de.day == 31:
leave_days = base_leaves
else:
leave_days = self.calculate_partial_year(datetime.strptime(date_start.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT), date_end, base_leaves)[0]
return leave_days
@api.one
def calculate_partial_year(self,date_start,date_end,base_leaves):
date_start_calc = date_start
date_end_calc = date_end
if date_start.day != 1 or date_start.month != 1:
date_start_calc = date_start + timedelta(days=-1)
elif date_end.day != 31 or date_end.month != 12:
date_end_calc = date_end + timedelta(days=1)
# else:
# return base_leaves
full_month = date_end_calc.month - date_start_calc.month
if date_end.day != monthrange(date_end.year, date_end.month)[1] and date_start.day != monthrange(date_start.year, date_start.month)[1]:
if date_end.day <= date_start.day:
full_month -= 1
# if full_month >= 6 and date_end.day >= date_start.day:
# leave_days = base_leaves
# else:
# leave_days = float_round(full_month * float(base_leaves) / 12, precision_rounding = 1)
leave_days = float_round(full_month * float(base_leaves) / 12, precision_rounding = 1)
return leave_days