Files
tryton/modules/timesheet/line.py
T

333 lines
12 KiB
Python
Raw Normal View History

2014-12-02 12:56:21 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
2018-06-26 19:11:58 +02:00
2015-02-09 23:02:56 +01:00
import datetime
2013-09-06 22:35:00 +02:00
from sql import Literal
from sql.aggregate import Max, Sum
from sql.functions import Extract
2013-09-06 22:35:00 +02:00
2018-12-29 14:20:30 +01:00
from trytond.i18n import gettext
from trytond.model import Index, ModelSQL, ModelView, Unique, fields
2011-07-03 13:19:21 +02:00
from trytond.pool import Pool
2022-11-24 19:16:51 +01:00
from trytond.pyson import Date, Eval, PYSONEncoder, TimeDelta
2021-12-11 17:58:45 +01:00
from trytond.transaction import Transaction
from trytond.wizard import Button, StateAction, StateView, Wizard
2011-07-03 13:19:21 +02:00
2018-12-29 14:20:30 +01:00
from .exceptions import DurationValidationError
2008-05-29 17:55:36 +02:00
2009-02-28 17:07:12 +01:00
class Line(ModelSQL, ModelView):
2008-05-29 17:55:36 +02:00
'Timesheet Line'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.line'
2017-04-06 15:33:15 +02:00
company = fields.Many2One('company.company', 'Company', required=True,
help="The company on which the time is spent.")
employee = fields.Many2One(
'company.employee', "Employee", required=True, domain=[
2014-12-03 16:14:26 +01:00
('company', '=', Eval('company', -1)),
2016-10-19 23:09:33 +02:00
['OR',
('start_date', '=', None),
2021-10-03 13:45:32 +02:00
('start_date', '<=', Eval('date', None)),
2016-10-19 23:09:33 +02:00
],
['OR',
('end_date', '=', None),
2021-10-03 13:45:32 +02:00
('end_date', '>=', Eval('date', None)),
2016-10-19 23:09:33 +02:00
],
2014-12-03 16:14:26 +01:00
],
2017-04-06 15:33:15 +02:00
help="The employee who spends the time.")
date = fields.Date(
"Date", required=True,
2017-04-06 15:33:15 +02:00
help="When the time is spent.")
2022-11-24 19:16:51 +01:00
duration = fields.TimeDelta(
'Duration', 'company_work_time', required=True,
domain=[
('duration', '>=', TimeDelta()),
])
work = fields.Many2One(
'timesheet.work', "Work", required=True,
domain=[
2014-12-03 16:14:26 +01:00
('company', '=', Eval('company', -1)),
2013-01-26 15:13:51 +01:00
['OR',
('timesheet_start_date', '=', None),
2021-10-03 13:45:32 +02:00
('timesheet_start_date', '<=', Eval('date', None)),
2013-01-26 15:13:51 +01:00
],
['OR',
('timesheet_end_date', '=', None),
2021-10-03 13:45:32 +02:00
('timesheet_end_date', '>=', Eval('date', None)),
2013-01-26 15:13:51 +01:00
],
],
2017-04-21 15:19:12 +02:00
help="The work on which the time is spent.")
2017-04-06 15:33:15 +02:00
description = fields.Char('Description',
help="Additional description of the work done.")
uuid = fields.Char("UUID", readonly=True, strip=False)
2008-05-29 17:55:36 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def __setup__(cls):
super(Line, cls).__setup__()
2021-03-11 19:08:45 +01:00
cls._order = [
('date', 'DESC'),
('id', 'DESC'),
]
2018-08-25 12:48:24 +02:00
t = cls.__table__()
cls._sql_constraints = [
('uuid_unique', Unique(t, t.uuid),
2018-12-29 14:20:30 +01:00
'timesheet.msg_line_uuid_unique'),
2018-08-25 12:48:24 +02:00
]
cls._sql_indexes.update({
Index(
t,
(t.date, Index.Equality()),
(t.company, Index.Equality()),
(t.employee, Index.Equality())),
Index(
t,
(t.date, Index.Range()),
(t.employee, Index.Equality())),
Index(
t,
(Extract('YEAR', t.date), Index.Equality()),
(Extract('WEEK', t.date), Index.Equality()),
(t.employee, Index.Equality())),
Index(
t,
(Extract('YEAR', t.date), Index.Equality()),
(Extract('MONTH', t.date), Index.Equality()),
(t.employee, Index.Equality())),
})
2014-12-03 16:14:26 +01:00
@staticmethod
def default_company():
return Transaction().context.get('company')
2012-09-24 22:18:28 +02:00
@staticmethod
def default_employee():
User = Pool().get('res.user')
2008-05-29 17:55:36 +02:00
employee_id = None
2010-08-10 11:59:04 -04:00
if Transaction().context.get('employee'):
employee_id = Transaction().context['employee']
2008-05-29 17:55:36 +02:00
else:
2012-09-24 22:18:28 +02:00
user = User(Transaction().user)
2008-05-29 17:55:36 +02:00
if user.employee:
employee_id = user.employee.id
if employee_id:
return employee_id
2008-05-29 17:55:36 +02:00
2012-09-24 22:18:28 +02:00
@staticmethod
def default_date():
Date_ = Pool().get('ir.date')
return Transaction().context.get('date') or Date_.today()
2008-10-08 12:20:33 +02:00
2015-02-09 23:02:56 +01:00
@classmethod
2022-04-11 23:24:21 +02:00
def validate_fields(cls, lines, field_names):
super().validate_fields(lines, field_names)
cls.check_duration(lines, field_names)
2015-02-09 23:02:56 +01:00
2022-04-11 23:24:21 +02:00
@classmethod
def check_duration(cls, lines, field_names=None):
if field_names and 'duration' not in field_names:
return
for line in lines:
if line.duration < datetime.timedelta():
raise DurationValidationError(
gettext('timesheet.msg_line_duration_positive',
line=line.rec_name))
2015-02-09 23:02:56 +01:00
2019-12-11 18:42:41 +01:00
@classmethod
def copy(cls, lines, default=None):
if default is not None:
default = default.copy()
else:
default = {}
default.setdefault('uuid')
return super().copy(lines, default=default)
2015-02-09 23:02:56 +01:00
@property
def hours(self):
return self.duration.total_seconds() / 60 / 60
2018-08-25 12:48:24 +02:00
def to_json(self):
return {
'id': self.id,
'work': self.work.id,
'work.name': self.work.rec_name,
'duration': self.duration.total_seconds(),
'description': self.description,
'uuid': self.uuid,
}
2008-05-29 17:55:36 +02:00
2012-01-02 18:10:18 +01:00
class EnterLinesStart(ModelView):
'Enter Lines'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.line.enter.start'
2008-09-10 09:53:32 +02:00
employee = fields.Many2One('company.employee', 'Employee', required=True,
2016-10-19 23:09:33 +02:00
domain=[
('company', '=', Eval('context', {}).get('company', -1)),
['OR',
('start_date', '=', None),
2021-10-03 13:45:32 +02:00
('start_date', '<=', Eval('date', None)),
2016-10-19 23:09:33 +02:00
],
['OR',
('end_date', '=', None),
2021-10-03 13:45:32 +02:00
('end_date', '>=', Eval('date', None)),
2016-10-19 23:09:33 +02:00
],
],
2017-04-06 15:33:15 +02:00
help="The employee who spends the time.")
date = fields.Date('Date', required=True,
help="When the time is spent.")
2008-05-29 17:55:36 +02:00
2012-09-24 22:18:28 +02:00
@staticmethod
def default_employee():
Line = Pool().get('timesheet.line')
return Line.default_employee()
2008-05-29 17:55:36 +02:00
2012-09-24 22:18:28 +02:00
@staticmethod
def default_date():
Line = Pool().get('timesheet.line')
return Line.default_date()
2008-05-29 17:55:36 +02:00
class EnterLines(Wizard):
'Enter Lines'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.line.enter'
2012-01-02 18:10:18 +01:00
start = StateView('timesheet.line.enter.start',
'timesheet.line_enter_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Enter', 'enter', 'tryton-ok', default=True),
2008-05-29 17:55:36 +02:00
])
2012-01-02 18:10:18 +01:00
enter = StateAction('timesheet.act_line_form')
2012-09-24 22:18:28 +02:00
def do_enter(self, action):
pool = Pool()
Lang = pool.get('ir.lang')
2012-09-24 22:18:28 +02:00
date = self.start.date
2012-01-02 18:10:18 +01:00
date = Date(date.year, date.month, date.day)
action['pyson_domain'] = PYSONEncoder().encode([
2012-09-24 22:18:28 +02:00
('employee', '=', self.start.employee.id),
2015-08-22 08:58:28 +02:00
('company', '=', self.start.employee.company.id),
2012-01-02 18:10:18 +01:00
('date', '=', date),
])
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:18:28 +02:00
'employee': self.start.employee.id,
2015-08-22 08:58:28 +02:00
'company': self.start.employee.company.id,
2012-01-02 18:10:18 +01:00
'date': date,
})
action['name'] += ' @ %(date)s - %(employee)s' % {
'date': Lang.get().strftime(self.start.date),
'employee': self.start.employee.rec_name,
}
2012-01-02 18:10:18 +01:00
return action, {}
2012-09-24 22:18:28 +02:00
def transition_enter(self):
2012-01-02 18:10:18 +01:00
return 'end'
2008-05-29 17:55:36 +02:00
2009-02-28 17:07:12 +01:00
class HoursEmployee(ModelSQL, ModelView):
2008-05-29 17:55:36 +02:00
'Hours per Employee'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.hours_employee'
employee = fields.Many2One('company.employee', 'Employee')
2015-02-09 23:02:56 +01:00
duration = fields.TimeDelta('Duration', 'company_work_time')
2008-05-29 17:55:36 +02:00
2012-09-24 22:18:28 +02:00
@staticmethod
def table_query():
2013-09-06 22:35:00 +02:00
pool = Pool()
Line = pool.get('timesheet.line')
line = Line.__table__()
where = Literal(True)
2010-08-10 11:59:04 -04:00
if Transaction().context.get('start_date'):
2013-09-06 22:35:00 +02:00
where &= line.date >= Transaction().context['start_date']
2010-08-10 11:59:04 -04:00
if Transaction().context.get('end_date'):
2013-09-06 22:35:00 +02:00
where &= line.date <= Transaction().context['end_date']
return line.select(
line.employee.as_('id'),
Max(line.create_uid).as_('create_uid'),
Max(line.create_date).as_('create_date'),
Max(line.write_uid).as_('write_uid'),
Max(line.write_date).as_('write_date'),
line.employee,
2015-02-09 23:02:56 +01:00
Sum(line.duration).as_('duration'),
2013-09-06 22:35:00 +02:00
where=where,
group_by=line.employee)
2008-05-29 17:55:36 +02:00
class HoursEmployeeContext(ModelView):
'Hours per Employee Context'
__name__ = 'timesheet.hours_employee.context'
2008-05-29 17:55:36 +02:00
start_date = fields.Date('Start Date')
end_date = fields.Date('End Date')
2009-02-28 17:07:12 +01:00
class HoursEmployeeWeekly(ModelSQL, ModelView):
2008-06-17 17:43:39 +02:00
'Hours per Employee per Week'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.hours_employee_weekly'
year = fields.Integer("Year")
week = fields.Integer("Week")
employee = fields.Many2One('company.employee', 'Employee')
2015-02-09 23:02:56 +01:00
duration = fields.TimeDelta('Duration', 'company_work_time')
2008-06-17 17:43:39 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def __setup__(cls):
super(HoursEmployeeWeekly, cls).__setup__()
cls._order.insert(0, ('year', 'DESC'))
cls._order.insert(1, ('week', 'DESC'))
cls._order.insert(2, ('employee', 'ASC'))
2008-06-17 17:43:39 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def table_query(cls):
2013-09-06 22:35:00 +02:00
pool = Pool()
Line = pool.get('timesheet.line')
line = Line.__table__()
year_column = Extract('YEAR', line.date).as_('year')
week_column = Extract('WEEK', line.date).as_('week')
2013-09-06 22:35:00 +02:00
return line.select(
Max(Extract('WEEK', line.date)
+ Extract('YEAR', line.date) * 100
+ line.employee * 1000000).as_('id'),
Max(line.create_uid).as_('create_uid'),
Max(line.create_date).as_('create_date'),
Max(line.write_uid).as_('write_uid'),
Max(line.write_date).as_('write_date'),
year_column,
week_column,
line.employee,
2015-02-09 23:02:56 +01:00
Sum(line.duration).as_('duration'),
2013-09-06 22:35:00 +02:00
group_by=(year_column, week_column, line.employee))
2008-06-17 17:43:39 +02:00
2009-02-28 17:07:12 +01:00
class HoursEmployeeMonthly(ModelSQL, ModelView):
2008-06-17 17:43:39 +02:00
'Hours per Employee per Month'
2012-09-24 22:18:28 +02:00
__name__ = 'timesheet.hours_employee_monthly'
year = fields.Integer("Year")
2019-09-28 23:52:02 +02:00
month = fields.Many2One('ir.calendar.month', "Month")
employee = fields.Many2One('company.employee', 'Employee')
2015-02-09 23:02:56 +01:00
duration = fields.TimeDelta('Duration', 'company_work_time')
2008-06-17 17:43:39 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def __setup__(cls):
super(HoursEmployeeMonthly, cls).__setup__()
cls._order.insert(0, ('year', 'DESC'))
2019-09-28 23:52:02 +02:00
cls._order.insert(1, ('month.index', 'DESC'))
2012-09-24 22:18:28 +02:00
cls._order.insert(2, ('employee', 'ASC'))
2008-06-17 17:43:39 +02:00
2012-09-24 22:18:28 +02:00
@classmethod
def table_query(cls):
2013-09-06 22:35:00 +02:00
pool = Pool()
Line = pool.get('timesheet.line')
2019-09-28 23:52:02 +02:00
Month = pool.get('ir.calendar.month')
2013-09-06 22:35:00 +02:00
line = Line.__table__()
2019-09-28 23:52:02 +02:00
month = Month.__table__()
year_column = Extract('YEAR', line.date).as_('year')
2019-09-28 23:52:02 +02:00
month_index = Extract('MONTH', line.date)
return line.join(month, condition=month_index == month.id).select(
2013-09-06 22:35:00 +02:00
Max(Extract('MONTH', line.date)
+ Extract('YEAR', line.date) * 100
+ line.employee * 1000000).as_('id'),
Max(line.create_uid).as_('create_uid'),
Max(line.create_date).as_('create_date'),
Max(line.write_uid).as_('write_uid'),
Max(line.write_date).as_('write_date'),
year_column,
2019-09-28 23:52:02 +02:00
month.id.as_('month'),
2013-09-06 22:35:00 +02:00
line.employee,
2015-02-09 23:02:56 +01:00
Sum(line.duration).as_('duration'),
2019-09-28 23:52:02 +02:00
group_by=(year_column, month.id, line.employee))