265 lines
13 KiB
Python
265 lines
13 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class HrContractSalaryBenefit(models.Model):
|
|
_name = 'hr.contract.salary.benefit'
|
|
_description = 'Salary Package Benefit'
|
|
_order = 'sequence'
|
|
|
|
def _get_field_domain(self):
|
|
fields_ids = self.env['hr.version']._get_benefit_fields(triggers=False)
|
|
return [
|
|
('model', '=', 'hr.version'),
|
|
('name', 'in', fields_ids),
|
|
('ttype', 'not in', ('one2many', 'many2one', 'many2many'))]
|
|
|
|
def _get_binary_field_domain(self):
|
|
return [
|
|
('model', '=', 'hr.version'),
|
|
('ttype', '=', 'binary')]
|
|
|
|
def _get_public_field_names(self):
|
|
return [(field.id, field.field_description) for field in self.sudo().env['ir.model.fields']\
|
|
.search(self._get_field_domain())]
|
|
|
|
name = fields.Char(translate=True)
|
|
show_name = fields.Boolean(string="Show Name", default=True, help='Whether the name should be displayed in the Salary Configurator')
|
|
active = fields.Boolean(default=True)
|
|
source = fields.Selection([
|
|
('field', 'Field'),
|
|
], string="Benefit Source", default='field', required=True)
|
|
res_field_id = fields.Many2one(
|
|
'ir.model.fields',
|
|
string="Employee Record Related Field",
|
|
compute="_compute_benefits",
|
|
store=True,
|
|
readonly=False,
|
|
required=False,
|
|
domain=_get_field_domain,
|
|
ondelete='cascade',
|
|
help="Select the contract's field where the value of the benefit will be written",
|
|
)
|
|
cost_res_field_id = fields.Many2one(
|
|
'ir.model.fields',
|
|
string="Cost Field",
|
|
compute="_compute_benefits",
|
|
store=True,
|
|
readonly=False,
|
|
domain=_get_field_domain,
|
|
ondelete='cascade',
|
|
help="Select the contract's field to consider in salary computation",
|
|
)
|
|
# LUL rename into field and cost_field to be consistent with fold_field and manual_field?
|
|
res_field_public = fields.Selection(
|
|
selection="_get_public_field_names",
|
|
string="Benefit Field",
|
|
readonly=False,
|
|
compute="_compute_res_field_public",
|
|
inverse="_inverse_res_field_public",
|
|
)
|
|
cost_res_field_public = fields.Selection(
|
|
selection="_get_public_field_names",
|
|
string="Cost Field (Public)",
|
|
readonly=False,
|
|
compute="_compute_cost_res_field_public",
|
|
inverse="_inverse_cost_res_field_public",
|
|
)
|
|
field = fields.Char(compute="_compute_field", store=True, readonly=True)
|
|
cost_field = fields.Char(related="cost_res_field_id.name", string="Cost Field Name", readonly=True, compute_sudo=True)
|
|
sequence = fields.Integer(default=100)
|
|
benefit_type_id = fields.Many2one(
|
|
'hr.contract.salary.benefit.type', required=True, string="Benefit Type",
|
|
default=lambda self: self.env.ref('hr_contract_salary.l10n_be_monthly_benefit', raise_if_not_found=False),
|
|
help="Allow to define the periodicity and output type of the advantage")
|
|
benefit_ids = fields.Many2many(
|
|
'hr.contract.salary.benefit',
|
|
'hr_contract_salary_benefit_rel',
|
|
'benefit_ids',
|
|
'mandatory_benefit_ids',
|
|
help='Select other Benefits that need to be selected to make this Benefit available',
|
|
string="Mandatory Benefits",
|
|
compute="_compute_benefits",
|
|
store=True,
|
|
readonly=False,
|
|
domain="[('id', '!=', id), ('structure_type_id', '=', structure_type_id)]",
|
|
)
|
|
folded = fields.Boolean()
|
|
fold_label = fields.Char(translate=True)
|
|
fold_res_field_id = fields.Many2one(
|
|
'ir.model.fields', string="Fold Condition", domain=_get_field_domain, ondelete='cascade',
|
|
help='The field here needs to be set for this benefit to be folded by default.')
|
|
fold_field = fields.Char(related='fold_res_field_id.name', string="Fold Field Name", readonly=True)
|
|
manual_res_field_id = fields.Many2one(
|
|
'ir.model.fields', domain=_get_field_domain, ondelete='cascade',
|
|
help='Contract field used to manually encode an benefit value.')
|
|
manual_field = fields.Char(related='manual_res_field_id.name', string="Manual Field Name", readonly=True)
|
|
country_id = fields.Many2one('res.country')
|
|
structure_type_id = fields.Many2one('hr.payroll.structure.type', string="Salary Structure Type", required=True, index=True)
|
|
icon = fields.Char(compute='_compute_icon', store=True, readonly=False)
|
|
display_type = fields.Selection(selection=[
|
|
('always', 'Always Selected'),
|
|
('dropdown', 'Dropdown'),
|
|
('dropdown-group', 'Dropdown Group'),
|
|
('radio', 'Radio Buttons'),
|
|
('slider', 'Slider'),
|
|
('manual', 'Manual Input'),
|
|
('text', 'Text'),
|
|
])
|
|
description = fields.Html('Description', translate=True)
|
|
slider_min = fields.Float()
|
|
slider_max = fields.Float()
|
|
slider_step = fields.Integer(default=1)
|
|
value_ids = fields.One2many('hr.contract.salary.benefit.value', 'benefit_id')
|
|
always_show_description = fields.Boolean(string="Always Show Description", help="If unchecked, Description will only be shown when Benefit is selected", default=True)
|
|
requested_documents_field_ids = fields.Many2many('ir.model.fields', domain=_get_binary_field_domain, string="Requested Documents (IDs)")
|
|
requested_documents_fields_string = fields.Text('Requested Documents', compute="_compute_requested_fields_string", readonly=True)
|
|
requested_documents = fields.Char(compute='_compute_requested_documents', string="Requested Documents Fields", compute_sudo=True)
|
|
has_admin_access = fields.Boolean(compute='_compute_has_admin_access')
|
|
|
|
uom = fields.Selection([
|
|
('days', 'Days'),
|
|
('percent', 'Percent'),
|
|
('currency', 'Currency')], string="Unit of Measure", default='currency')
|
|
|
|
activity_type_id = fields.Many2one('mail.activity.type', string='Activity Type', help="The type of activity that will be created automatically on the contract if this benefit is chosen by the employee.")
|
|
activity_creation = fields.Selection([
|
|
('running', 'Employee signs his contract'),
|
|
('countersigned', 'Contract is countersigned')], default='running',
|
|
help='Choose when the activity is created:\n'
|
|
'- Employee signs his contract: Activity is created as soon as the employee signed the contract\n'
|
|
'- Contract is countersigned: HR responsible have signed the contract and conclude the process.')
|
|
activity_creation_type = fields.Selection([
|
|
('always', 'When the benefit is set'),
|
|
('onchange', 'When the benefit is modified')], default='always',
|
|
help='Define when the system creates a new activity:\n'
|
|
'- When the benefit is set: Unique creation the first time the employee will take the benefit\n'
|
|
'- When the benefit is modified: Activity will be created for each change regarding the benefit.')
|
|
activity_responsible_id = fields.Many2one('res.users', 'Assigned to')
|
|
sign_template_id = fields.Many2one('sign.template', string="Template to Sign", help="Documents selected here will be requested to the employee for additional signatures related to the benefit. eg: A company car policy to approve if you choose a company car.")
|
|
sign_copy_partner_id = fields.Many2one('res.partner', string="Send a copy to", help="Email address to which to transfer the signature.")
|
|
sign_frenquency = fields.Selection([
|
|
('onchange', 'When the benefit is set'),
|
|
('always', 'When the benefit is modified')], string="Sign Creation Type", default="onchange",
|
|
help='Define when the system creates a new sign request:\n'
|
|
'- When the benefit is set: Unique signature request the first time the employee will take the benefit\n'
|
|
'- When the benefit is modified: Signature request will be created for each change regarding the benefit.')
|
|
|
|
_required_fold_res_field_id = models.Constraint(
|
|
'check (folded = FALSE OR (folded = TRUE AND fold_res_field_id IS NOT NULL))',
|
|
"A folded field is required",
|
|
)
|
|
|
|
@api.depends('res_field_id')
|
|
def _compute_field(self):
|
|
for record in self:
|
|
if record.source == 'field':
|
|
record.field = record.res_field_id.name
|
|
else:
|
|
record.field = False
|
|
|
|
@api.depends('res_field_id')
|
|
def _compute_res_field_public(self):
|
|
for record in self:
|
|
record.res_field_public = record.res_field_id.id
|
|
|
|
@api.depends('cost_res_field_id')
|
|
def _compute_cost_res_field_public(self):
|
|
for record in self:
|
|
record.cost_res_field_public = record.cost_res_field_id.id
|
|
|
|
def _inverse_res_field_public(self):
|
|
for record in self:
|
|
record.res_field_id = self.sudo().env['ir.model.fields'].browse(record.res_field_public)
|
|
|
|
def _inverse_cost_res_field_public(self):
|
|
for record in self:
|
|
record.cost_res_field_id = self.sudo().env['ir.model.fields'].browse(record.cost_res_field_public)
|
|
|
|
@api.depends_context('lang')
|
|
@api.depends('requested_documents_field_ids')
|
|
def _compute_requested_fields_string(self):
|
|
self.requested_documents_fields_string = False
|
|
for record in self:
|
|
if record.requested_documents_field_ids:
|
|
record.requested_documents_fields_string = ', '.join([f.field_description for f in record.sudo().requested_documents_field_ids])
|
|
|
|
@api.depends('requested_documents_field_ids')
|
|
def _compute_requested_documents(self):
|
|
names = []
|
|
for benefit in self:
|
|
benefit.requested_documents = ','.join(benefit.requested_documents_field_ids.mapped('name'))
|
|
names.extend(benefit.requested_documents_field_ids.mapped('name'))
|
|
self._set_requested_documents_as_required(names)
|
|
|
|
@api.depends('structure_type_id')
|
|
def _compute_benefits(self):
|
|
self.res_field_id = False
|
|
self.cost_res_field_id = False
|
|
for benefit in self:
|
|
benefit.benefit_ids = benefit.benefit_ids.filtered(lambda b: b.structure_type_id == self.structure_type_id)
|
|
|
|
def _set_requested_documents_as_required(self, names):
|
|
personal_infos = self.env['hr.contract.salary.personal.info'].search([('field', 'in', names)])
|
|
if personal_infos:
|
|
personal_infos.is_required = True
|
|
|
|
@api.depends_context('uid')
|
|
def _compute_has_admin_access(self):
|
|
self.has_admin_access = self.env.user._is_system()
|
|
|
|
@api.constrains('slider_min', 'slider_max')
|
|
def _check_min_inferior_to_max(self):
|
|
for record in self:
|
|
if record.display_type == 'slider' and record.slider_min > record.slider_max:
|
|
raise ValidationError(_('The minimum value for the slider should be inferior to the maximum value.'))
|
|
|
|
@api.constrains('display_type', 'res_field_id', 'source')
|
|
def _check_benefits_field(self):
|
|
white_list = ['radio', 'slider', 'manual', 'always']
|
|
for record in self:
|
|
if record.source == 'rule' and record.display_type not in white_list:
|
|
raise ValidationError(self.env._('The display type of a benefit linked to a salary rule must be one of the following: %s') % ', '.join(white_list))
|
|
if record.source == 'field' and not record.res_field_id and record.display_type != 'always':
|
|
raise ValidationError(self.env._('Benefits that are not linked to a field or salary rule should always be displayed.'))
|
|
|
|
@api.depends('show_name')
|
|
def _compute_icon(self):
|
|
self.filtered(lambda b: not b.show_name).icon = False
|
|
|
|
|
|
class HrContractSalaryBenefitType(models.Model):
|
|
_name = 'hr.contract.salary.benefit.type'
|
|
_description = 'Contract Benefit Type'
|
|
_order = 'sequence'
|
|
|
|
name = fields.Char(translate=True)
|
|
periodicity = fields.Selection([
|
|
('monthly', 'Monthly'),
|
|
('yearly', 'Yearly'),
|
|
], default='monthly')
|
|
sequence = fields.Integer(default=100)
|
|
|
|
|
|
class HrContractSalaryBenefitValue(models.Model):
|
|
_name = 'hr.contract.salary.benefit.value'
|
|
_description = 'Contract Benefit Value'
|
|
_order = 'sequence'
|
|
|
|
name = fields.Char(translate=True)
|
|
sequence = fields.Integer(default=100)
|
|
benefit_id = fields.Many2one('hr.contract.salary.benefit', index='btree_not_null')
|
|
value = fields.Float()
|
|
selector_highlight = fields.Selection(selection=[('none', 'None'), ('red', 'Red')], string="Selector Highlight", default='none')
|
|
always_show_description = fields.Boolean()
|
|
|
|
display_type = fields.Selection([
|
|
('line', 'Line'),
|
|
('section', 'Section'),
|
|
],
|
|
default='line',
|
|
)
|
|
benefit_display_type = fields.Selection(related='benefit_id.display_type', string='Benefit Display Type')
|