odoo-module-hr_employee_tim.../models/hr_timesheet_dh.py

325 lines
14 KiB
Python
Raw Normal View History

2020-12-07 19:56:56 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# Clear Groups for Odoo
# Copyright (C) 2016 Bytebrand GmbH (<http://www.bytebrand.net>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import datetime as dtime
from datetime import datetime, timedelta
from openerp import api, fields, models, _
from dateutil import rrule, parser
from openerp.tools.translate import _
class HrTimesheetDh(models.Model):
"""
Addition plugin for HR timesheet for work with duty hours
"""
_inherit = 'hr_timesheet_sheet.sheet'
@api.multi
def _duty_hours(self):
for sheet in self:
sheet['total_duty_hours'] = 0.0
if sheet.state == 'done':
sheet['total_duty_hours'] = sheet.total_duty_hours_done
else:
dates = list(rrule.rrule(rrule.DAILY,
dtstart=parser.parse(sheet.date_from),
until=parser.parse(sheet.date_to)))
period = {'date_from': sheet.date_from,
'date_to': sheet.date_to}
for date_line in dates:
duty_hours = sheet.calculate_duty_hours(date_from=date_line,
period=period,
)
sheet['total_duty_hours'] += duty_hours
sheet['total_duty_hours'] = (sheet.total_duty_hours -
sheet.total_attendance)
@api.multi
def count_leaves(self, date_from, employee_id, period):
holiday_obj = self.env['hr.holidays']
start_leave_period = end_leave_period = False
if period.get('date_from') and period.get('date_to'):
start_leave_period = period.get('date_from')
end_leave_period = period.get('date_to')
holiday_ids = holiday_obj.search(
['|', '&',
('date_from', '>=', start_leave_period),
('date_from', '<=', end_leave_period),
'&', ('date_to', '<=', end_leave_period),
('date_to', '>=', start_leave_period),
('employee_id', '=', employee_id),
('state', '=', 'validate'),
('type', '=', 'remove')])
leaves = []
for leave in holiday_ids:
leave_date_from = datetime.strptime(leave.date_from,
'%Y-%m-%d %H:%M:%S')
leave_date_to = datetime.strptime(leave.date_to,
'%Y-%m-%d %H:%M:%S')
leave_dates = list(rrule.rrule(rrule.DAILY,
dtstart=parser.parse(
leave.date_from),
until=parser.parse(leave.date_to)))
for date in leave_dates:
if date.strftime('%Y-%m-%d') == date_from.strftime('%Y-%m-%d'):
leaves.append(
(leave_date_from, leave_date_to, leave.number_of_days))
break
return leaves
@api.multi
def get_overtime(self, start_date):
for sheet in self:
if sheet.state == 'done':
return sheet.total_duty_hours_done * -1
return self.calculate_diff(start_date)
@api.multi
def _overtime_diff(self):
for sheet in self:
old_timesheet_start_from = parser.parse(
sheet.date_from) - timedelta(days=1)
prev_timesheet_diff = \
self.get_previous_month_diff(
sheet.employee_id.id,
old_timesheet_start_from.strftime('%Y-%m-%d')
)
sheet['calculate_diff_hours'] = (
self.get_overtime(datetime.today().strftime('%Y-%m-%d'), ) +
prev_timesheet_diff)
sheet['prev_timesheet_diff'] = prev_timesheet_diff
@api.multi
def _get_analysis(self):
res = {}
for sheet in self:
function_call = True
data = self.attendance_analysis(sheet.id, function_call)
values = []
output = [
'<style>.attendanceTable td,.attendanceTable th {padding: 3px; border: 1px solid #C0C0C0; border-collapse: collapse; text-align: right;} </style><table class="attendanceTable" >']
for val in data.values():
if isinstance(val, (int, float)):
output.append('<tr>')
prev_ts = _('Previous Timesheet:')
output.append('<th colspan="2">' + prev_ts + ' </th>')
output.append('<td colspan="3">' + str(val) + '</td>')
output.append('</tr>')
for k, v in data.items():
if isinstance(v, list):
output.append('<tr>')
for th in v[0].keys():
output.append('<th>' + th + '</th>')
output.append('</tr>')
for res in v:
values.append(res.values())
for tr in values:
output.append('<tr>')
for td in tr:
output.append('<td>' + td + '</td>')
output.append('</tr>')
if isinstance(v, dict):
output.append('<tr>')
total_ts = _('Total:')
output.append('<th>' + total_ts + ' </th>')
for td in v.values():
output.append('<td>' + '%s' % round(td, 4) + '</td>')
output.append('</tr>')
output.append('</table>')
sheet['analysis'] = '\n'.join(output)
total_duty_hours = fields.Float(compute='_duty_hours',
string='Total Duty Hours',
multi="_duty_hours")
total_duty_hours_done = fields.Float(string='Total Duty Hours',
readonly=True,
default=0.0)
total_diff_hours = fields.Float(string='Total Diff Hours',
readonly=True,
default=0.0)
calculate_diff_hours = fields.Char(compute='_overtime_diff',
string="Diff (worked-duty)",
multi="_diff")
prev_timesheet_diff = fields.Char(compute='_overtime_diff',
method=True,
string="Diff from old",
multi="_diff")
analysis = fields.Text(compute='_get_analysis',
type="text",
string="Attendance Analysis")
@api.multi
def calculate_duty_hours(self, date_from, period):
contract_obj = self.env['hr.contract']
calendar_obj = self.env['resource.calendar']
duty_hours = 0.0
contract_ids = contract_obj.search(
[
('employee_id', '=', self.employee_id.id),
('date_start', '<=', date_from),
'|',
('date_end', '>=', date_from),
('date_end', '=', None)
]
)
for contract in contract_ids:
ctx = dict(self.env.context).copy()
ctx.update(period)
dh = calendar_obj.get_working_hours_of_date(
cr=self._cr,
uid=self.env.user.id,
ids=contract.working_hours.id,
start_dt=date_from,
resource_id=self.employee_id.id,
context=ctx)
leaves = self.count_leaves(date_from, self.employee_id.id, period)
if not leaves:
if not dh:
dh = 0.00
duty_hours += dh
else:
if leaves[-1] and leaves[-1][-1]:
if float(leaves[-1][-1]) == (-0.5):
duty_hours += dh / 2
return duty_hours
@api.multi
def get_previous_month_diff(self, employee_id, prev_timesheet_date_from):
total_diff = 0.0
timesheet_ids = self.search(
[('employee_id', '=', employee_id),
('date_from', '<', prev_timesheet_date_from)
])
for timesheet in timesheet_ids:
total_diff += timesheet.get_overtime(
start_date=prev_timesheet_date_from)
return total_diff
@api.multi
def _get_user_datetime_format(self):
""" Get user's language & fetch date/time formats of
that language """
lang_obj = self.env['res.lang']
language = self.env.user.lang
lang_ids = lang_obj.search([('code', '=', language)])
date_format = _('%Y-%m-%d')
time_format = _('%H:%M:%S')
for lang in lang_ids:
date_format = lang.date_format
time_format = lang.time_format
return date_format, time_format
@api.multi
def attendance_analysis(self, timesheet_id=None, function_call=False):
attendance_obj = self.env['hr.attendance']
date_format, time_format = self._get_user_datetime_format()
for sheet in self:
if sheet.id == timesheet_id:
employee_id = sheet.employee_id.id
start_date = sheet.date_from
end_date = sheet.date_to
previous_month_diff = self.get_previous_month_diff(
employee_id, start_date)
current_month_diff = previous_month_diff
res = {
'previous_month_diff': previous_month_diff,
'hours': []
}
period = {'date_from': start_date,
'date_to': end_date
}
dates = list(rrule.rrule(rrule.DAILY,
dtstart=parser.parse(start_date),
until=parser.parse(
end_date)))
work_current_month_diff = 0.0
total = {'worked_hours': 0.0, 'duty_hours': 0.0,
'diff':
current_month_diff, 'work_current_month_diff': ''}
for date_line in dates:
dh = sheet.calculate_duty_hours(date_from=date_line,
period=period,
)
worked_hours = 0.0
for att in sheet.period_ids:
if att.name == date_line.strftime('%Y-%m-%d'):
worked_hours = att.total_attendance
diff = worked_hours - dh
current_month_diff += diff
work_current_month_diff += diff
if function_call:
res['hours'].append({
_('Date'): date_line.strftime(date_format),
_('Duty Hours'):
attendance_obj.float_time_convert(dh),
_('Worked Hours'):
attendance_obj.float_time_convert(worked_hours),
_('Difference'): self.sign_float_time_convert(diff),
_('Running'): self.sign_float_time_convert(
current_month_diff)})
else:
res['hours'].append({
'name': date_line.strftime(date_format),
'dh': attendance_obj.float_time_convert(dh),
'worked_hours': attendance_obj.float_time_convert(
worked_hours),
'diff': self.sign_float_time_convert(diff),
'running': self.sign_float_time_convert(
current_month_diff)
})
total['duty_hours'] += dh
total['worked_hours'] += worked_hours
total['diff'] += diff
total['work_current_month_diff'] = work_current_month_diff
res['total'] = total
return res
@api.multi
def sign_float_time_convert(self, float_time):
sign = '-' if float_time < 0 else ''
attendance_obj = self.pool.get('hr.attendance')
return sign + attendance_obj.float_time_convert(float_time)
@api.multi
def write(self, vals):
if 'state' in vals and vals['state'] == 'done':
vals['total_diff_hours'] = self.calculate_diff(None)
for sheet in self:
vals['total_duty_hours_done'] = sheet.total_duty_hours
elif 'state' in vals and vals['state'] == 'draft':
vals['total_diff_hours'] = 0.0
res = super(HrTimesheetDh, self).write(vals)
return res
@api.multi
def calculate_diff(self, end_date=None):
for sheet in self:
return sheet.total_duty_hours * (-1)