diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/project_timesheet_holidays/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/project_timesheet_holidays/models')
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 |
