146 lines
6.1 KiB
Python
146 lines
6.1 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from collections import defaultdict
|
|
from random import randint
|
|
|
|
from odoo import fields, models, api, _
|
|
|
|
|
|
class HrPayrollHeadcount(models.Model):
|
|
_name = 'hr.payroll.headcount'
|
|
_description = 'Payroll Headcount'
|
|
|
|
name = fields.Char(string='Name', compute='_compute_name', store=True)
|
|
is_name_custom = fields.Boolean(string='Custom Name', compute="_compute_is_name_custom")
|
|
company_id = fields.Many2one('res.company', default=lambda self: self.env.company.id)
|
|
line_ids = fields.One2many('hr.payroll.headcount.line', 'headcount_id')
|
|
employee_count = fields.Integer(string='Employee Count')
|
|
date_from = fields.Date(string='From', default=lambda self: fields.date.today(), required=True)
|
|
date_to = fields.Date(string='To')
|
|
|
|
_sql_constraints = [
|
|
('date_range', 'CHECK (date_from <= date_to)', 'The start date must be anterior to the end date.'),
|
|
]
|
|
|
|
@api.depends('date_from', 'date_to', 'company_id')
|
|
def _compute_name(self):
|
|
for headcount in self:
|
|
if not headcount.is_name_custom:
|
|
headcount.name = headcount.get_default_name()
|
|
|
|
@api.depends('name')
|
|
def _compute_is_name_custom(self):
|
|
for headcount in self:
|
|
if headcount.name and headcount.name != headcount.get_default_name():
|
|
headcount.is_name_custom = True
|
|
else:
|
|
headcount.is_name_custom = False
|
|
|
|
def get_default_name(self):
|
|
self.ensure_one()
|
|
if self.date_from == self.date_to or not self.date_to:
|
|
return _(
|
|
'Headcount for %(company_name)s on the %(date)s',
|
|
company_name=self.company_id.name,
|
|
date=self.date_from)
|
|
return _(
|
|
'Headcount for %(company_name)s from %(date_from)s to %(date_to)s',
|
|
company_name=self.company_id.name,
|
|
date_from=self.date_from,
|
|
date_to=self.date_to)
|
|
|
|
def action_populate(self):
|
|
self.ensure_one()
|
|
if not self.date_to:
|
|
self.date_to = self.date_from
|
|
contracts = self.env['hr.contract'].search([
|
|
('company_id', '=', self.company_id.id),
|
|
'|',
|
|
('date_end', '=', False),
|
|
('date_end', '>=', self.date_from),
|
|
('date_start', '<=', self.date_to),
|
|
'|',
|
|
('state', 'in', ['open', 'close']),
|
|
'&',
|
|
('state', '=', 'draft'),
|
|
('kanban_state', '=', 'done'),
|
|
], order='employee_id, date_start DESC')
|
|
|
|
contracts_by_employee_id = defaultdict(lambda: self.env['hr.contract'])
|
|
working_rates = set()
|
|
for contract in contracts:
|
|
contracts_by_employee_id[contract.employee_id.id] |= contract
|
|
working_rates.add(round(contract.hours_per_week, 2))
|
|
|
|
existing_working_rates = self.env['hr.payroll.headcount.working.rate']\
|
|
.search([('rate', 'in', list(working_rates))])
|
|
working_rate_to_create = working_rates - set(existing_working_rates.mapped('rate'))
|
|
if working_rate_to_create:
|
|
created_working_rate = self.env['hr.payroll.headcount.working.rate']\
|
|
.create([{'rate': rate} for rate in working_rate_to_create])
|
|
existing_working_rates |= created_working_rate
|
|
|
|
working_rate_id_by_value = {}
|
|
for working_rate in existing_working_rates:
|
|
working_rate_id_by_value[working_rate.rate] = working_rate.id
|
|
|
|
lines = [
|
|
(0, 0, {
|
|
'contract_id': contracts[0].id,
|
|
'working_rate_ids': [
|
|
(6, 0, [working_rate_id_by_value[round(contract.hours_per_week, 2)] for contract in contracts]),
|
|
],
|
|
'contract_names': ', '.join(contract.name for contract in contracts),
|
|
})
|
|
for contracts in contracts_by_employee_id.values()]
|
|
self.line_ids = [(5, 0, 0)] + lines
|
|
self.employee_count = len(self.line_ids)
|
|
|
|
def action_open_lines(self):
|
|
self.ensure_one()
|
|
return {
|
|
'name': _("Headcount's employees"),
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'hr.payroll.headcount.line',
|
|
'view_mode': 'list',
|
|
'domain': [('headcount_id', '=', self.id)],
|
|
'target': 'current',
|
|
'context': {
|
|
'search_default_group_by_department': True,
|
|
},
|
|
}
|
|
|
|
|
|
class HrPayrollHeadcountLine(models.Model):
|
|
_name = 'hr.payroll.headcount.line'
|
|
_description = 'Headcount Line'
|
|
|
|
headcount_id = fields.Many2one('hr.payroll.headcount', string='headcount_id', required=True, ondelete='cascade')
|
|
working_rate_ids = fields.Many2many('hr.payroll.headcount.working.rate', required=True, string='Working Rate')
|
|
contract_names = fields.Char(string='Contract Names', required=True, readonly=True)
|
|
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, readonly=True)
|
|
department_id = fields.Many2one(related='contract_id.department_id', string='Department')
|
|
job_id = fields.Many2one(related='contract_id.job_id', string='Job Title')
|
|
currency_id = fields.Many2one(related='contract_id.currency_id', string='Currency')
|
|
wage_on_payroll = fields.Monetary(string='Wage On Payroll', currency_field='currency_id', compute='_compute_wage_on_payroll')
|
|
employee_id = fields.Many2one(related="contract_id.employee_id", required=True, readonly=True)
|
|
employee_type = fields.Selection(related='employee_id.employee_type', string='Employee Type')
|
|
|
|
@api.depends('contract_id')
|
|
def _compute_wage_on_payroll(self):
|
|
for line in self:
|
|
line.wage_on_payroll = line.contract_id._get_contract_wage()
|
|
|
|
|
|
class HrPayrollHeadcountWorkingRate(models.Model):
|
|
_name = 'hr.payroll.headcount.working.rate'
|
|
_description = 'Working Rate'
|
|
|
|
rate = fields.Float(string='Rate')
|
|
color = fields.Integer(string='Color', default=lambda self: randint(1, 11))
|
|
|
|
@api.depends('rate')
|
|
def _compute_display_name(self):
|
|
for working_rate in self:
|
|
working_rate.display_name = _('%(rate)s Hours/week', rate=working_rate.rate)
|