summaryrefslogtreecommitdiff
path: root/addons/project_timesheet_holidays/models
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/project_timesheet_holidays/models
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/project_timesheet_holidays/models')
-rw-r--r--addons/project_timesheet_holidays/models/__init__.py7
-rw-r--r--addons/project_timesheet_holidays/models/account_analytic.py16
-rw-r--r--addons/project_timesheet_holidays/models/hr_holidays.py107
-rw-r--r--addons/project_timesheet_holidays/models/res_company.py71
-rw-r--r--addons/project_timesheet_holidays/models/res_config_settings.py25
5 files changed, 226 insertions, 0 deletions
diff --git a/addons/project_timesheet_holidays/models/__init__.py b/addons/project_timesheet_holidays/models/__init__.py
new file mode 100644
index 00000000..4dee3582
--- /dev/null
+++ b/addons/project_timesheet_holidays/models/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import res_company # has to be before hr_holidays to create needed columns on res.company
+from . import account_analytic
+from . import hr_holidays
+from . import res_config_settings
diff --git a/addons/project_timesheet_holidays/models/account_analytic.py b/addons/project_timesheet_holidays/models/account_analytic.py
new file mode 100644
index 00000000..2ae5fa36
--- /dev/null
+++ b/addons/project_timesheet_holidays/models/account_analytic.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+
+
+class AccountAnalyticLine(models.Model):
+ _inherit = 'account.analytic.line'
+
+ holiday_id = fields.Many2one("hr.leave", string='Leave Request')
+
+ def unlink(self):
+ if any(line.holiday_id for line in self):
+ raise UserError(_('You cannot delete timesheet lines attached to a leaves. Please cancel the leaves instead.'))
+ return super(AccountAnalyticLine, self).unlink()
diff --git a/addons/project_timesheet_holidays/models/hr_holidays.py b/addons/project_timesheet_holidays/models/hr_holidays.py
new file mode 100644
index 00000000..d7128f42
--- /dev/null
+++ b/addons/project_timesheet_holidays/models/hr_holidays.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+
+class HolidaysType(models.Model):
+ _inherit = "hr.leave.type"
+
+ def _default_project_id(self):
+ company = self.company_id if self.company_id else self.env.company
+ return company.leave_timesheet_project_id.id
+
+ def _default_task_id(self):
+ company = self.company_id if self.company_id else self.env.company
+ return company.leave_timesheet_task_id.id
+
+ timesheet_generate = fields.Boolean(
+ 'Generate Timesheet', compute='_compute_timesheet_generate', store=True, readonly=False,
+ help="If checked, when validating a time off, timesheet will be generated in the Vacation Project of the company.")
+ timesheet_project_id = fields.Many2one('project.project', string="Project", default=_default_project_id, domain="[('company_id', '=', company_id)]", help="The project will contain the timesheet generated when a time off is validated.")
+ timesheet_task_id = fields.Many2one(
+ 'project.task', string="Task for timesheet", compute='_compute_timesheet_task_id',
+ store=True, readonly=False, default=_default_task_id,
+ domain="[('project_id', '=', timesheet_project_id),"
+ "('company_id', '=', company_id)]")
+
+ @api.depends('timesheet_task_id', 'timesheet_project_id')
+ def _compute_timesheet_generate(self):
+ for leave_type in self:
+ leave_type.timesheet_generate = leave_type.timesheet_task_id and leave_type.timesheet_project_id
+
+ @api.depends('timesheet_project_id')
+ def _compute_timesheet_task_id(self):
+ for leave_type in self:
+ company = leave_type.company_id if leave_type.company_id else self.env.company
+ default_task_id = company.leave_timesheet_task_id
+
+ if default_task_id and default_task_id.project_id == leave_type.timesheet_project_id:
+ leave_type.timesheet_task_id = default_task_id
+ else:
+ leave_type.timesheet_task_id = False
+
+ @api.constrains('timesheet_generate', 'timesheet_project_id', 'timesheet_task_id')
+ def _check_timesheet_generate(self):
+ for holiday_status in self:
+ if holiday_status.timesheet_generate:
+ if not holiday_status.timesheet_project_id or not holiday_status.timesheet_task_id:
+ raise ValidationError(_("Both the internal project and task are required to "
+ "generate a timesheet for the time off %s. If you don't want a timesheet, you should "
+ "leave the internal project and task empty.") % (holiday_status.name))
+
+
+class Holidays(models.Model):
+ _inherit = "hr.leave"
+
+ timesheet_ids = fields.One2many('account.analytic.line', 'holiday_id', string="Analytic Lines")
+
+ def _validate_leave_request(self):
+ """ Timesheet will be generated on leave validation only if a timesheet_project_id and a
+ timesheet_task_id are set on the corresponding leave type. The generated timesheet will
+ be attached to this project/task.
+ """
+ # create the timesheet on the vacation project
+ for holiday in self.filtered(
+ lambda request: request.holiday_type == 'employee' and
+ request.holiday_status_id.timesheet_project_id and
+ request.holiday_status_id.timesheet_task_id):
+ holiday._timesheet_create_lines()
+
+ return super(Holidays, self)._validate_leave_request()
+
+ def _timesheet_create_lines(self):
+ self.ensure_one()
+ vals_list = []
+ work_hours_data = self.employee_id.list_work_time_per_day(
+ self.date_from,
+ self.date_to,
+ )
+ for index, (day_date, work_hours_count) in enumerate(work_hours_data):
+ vals_list.append(self._timesheet_prepare_line_values(index, work_hours_data, day_date, work_hours_count))
+ timesheets = self.env['account.analytic.line'].sudo().create(vals_list)
+ return timesheets
+
+ def _timesheet_prepare_line_values(self, index, work_hours_data, day_date, work_hours_count):
+ self.ensure_one()
+ return {
+ 'name': "%s (%s/%s)" % (self.holiday_status_id.name or '', index + 1, len(work_hours_data)),
+ 'project_id': self.holiday_status_id.timesheet_project_id.id,
+ 'task_id': self.holiday_status_id.timesheet_task_id.id,
+ 'account_id': self.holiday_status_id.timesheet_project_id.analytic_account_id.id,
+ 'unit_amount': work_hours_count,
+ 'user_id': self.employee_id.user_id.id,
+ 'date': day_date,
+ 'holiday_id': self.id,
+ 'employee_id': self.employee_id.id,
+ 'company_id': self.holiday_status_id.timesheet_task_id.company_id.id or self.holiday_status_id.timesheet_project_id.company_id.id,
+ }
+
+ def action_refuse(self):
+ """ Remove the timesheets linked to the refused holidays """
+ result = super(Holidays, self).action_refuse()
+ timesheets = self.sudo().mapped('timesheet_ids')
+ timesheets.write({'holiday_id': False})
+ timesheets.unlink()
+ return result
diff --git a/addons/project_timesheet_holidays/models/res_company.py b/addons/project_timesheet_holidays/models/res_company.py
new file mode 100644
index 00000000..bd50f4a0
--- /dev/null
+++ b/addons/project_timesheet_holidays/models/res_company.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+
+class Company(models.Model):
+ _inherit = 'res.company'
+
+ leave_timesheet_project_id = fields.Many2one(
+ 'project.project', string="Internal Project",
+ help="Default project value for timesheet generated from time off type.")
+ leave_timesheet_task_id = fields.Many2one(
+ 'project.task', string="Time Off Task",
+ domain="[('project_id', '=', leave_timesheet_project_id)]")
+
+ @api.constrains('leave_timesheet_project_id')
+ def _check_leave_timesheet_project_id_company(self):
+ for company in self:
+ if company.leave_timesheet_project_id:
+ if company.leave_timesheet_project_id.sudo().company_id != company:
+ raise ValidationError(_('The Internal Project of a company should be in that company.'))
+
+ def init(self):
+ for company in self.search([('leave_timesheet_project_id', '=', False)]):
+ company = company.with_company(company)
+ project = company.env['project.project'].search([
+ ('name', '=', _('Internal')),
+ ('allow_timesheets', '=', True),
+ ('company_id', '=', company.id),
+ ], limit=1)
+ if not project:
+ project = company.env['project.project'].create({
+ 'name': _('Internal'),
+ 'allow_timesheets': True,
+ 'company_id': company.id,
+ })
+ company.write({
+ 'leave_timesheet_project_id': project.id,
+ })
+ if not company.leave_timesheet_task_id:
+ task = company.env['project.task'].create({
+ 'name': _('Time Off'),
+ 'project_id': company.leave_timesheet_project_id.id,
+ 'active': False,
+ 'company_id': company.id,
+ })
+ company.write({
+ 'leave_timesheet_task_id': task.id,
+ })
+
+ def _create_internal_project_task(self):
+ projects = super()._create_internal_project_task()
+ for project in projects:
+ company = project.company_id
+ company = company.with_company(company)
+ if not company.leave_timesheet_project_id:
+ company.write({
+ 'leave_timesheet_project_id': project.id,
+ })
+ if not company.leave_timesheet_task_id:
+ task = company.env['project.task'].sudo().create({
+ 'name': _('Time Off'),
+ 'project_id': company.leave_timesheet_project_id.id,
+ 'active': False,
+ 'company_id': company.id,
+ })
+ company.write({
+ 'leave_timesheet_task_id': task.id,
+ })
diff --git a/addons/project_timesheet_holidays/models/res_config_settings.py b/addons/project_timesheet_holidays/models/res_config_settings.py
new file mode 100644
index 00000000..c4b864ab
--- /dev/null
+++ b/addons/project_timesheet_holidays/models/res_config_settings.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ leave_timesheet_project_id = fields.Many2one(
+ related='company_id.leave_timesheet_project_id', required=True, string="Internal Project",
+ domain="[('company_id', '=', company_id)]", readonly=False)
+ leave_timesheet_task_id = fields.Many2one(
+ related='company_id.leave_timesheet_task_id', string="Time Off Task", readonly=False,
+ domain="[('company_id', '=', company_id), ('project_id', '=?', leave_timesheet_project_id)]")
+
+ @api.onchange('leave_timesheet_project_id')
+ def _onchange_timesheet_project_id(self):
+ if self.leave_timesheet_project_id != self.leave_timesheet_task_id.project_id:
+ self.leave_timesheet_task_id = False
+
+ @api.onchange('leave_timesheet_task_id')
+ def _onchange_timesheet_task_id(self):
+ if self.leave_timesheet_task_id:
+ self.leave_timesheet_project_id = self.leave_timesheet_task_id.project_id