354 lines
18 KiB
Python
354 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from datetime import datetime
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class HrContractSalaryScale(models.Model):
|
|
_inherit = 'hr.contract'
|
|
|
|
salary_level = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
|
|
salary_scale = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])], index=True)
|
|
salary_group = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
|
|
salary_degree = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
|
|
hide = fields.Boolean(string='Hide', compute="compute_type")
|
|
required_condition = fields.Boolean(string='Required Condition', compute='compute_move_type')
|
|
total_allowance = fields.Float(string='Total Allowance', compute='compute_function',store=True)
|
|
total_deduction = fields.Float(string='Total Deduction', compute='compute_function',store=True)
|
|
total_net = fields.Float(string='Total Net', compute='compute_function',store=True)
|
|
advantages = fields.One2many('contract.advantage', 'contract_advantage_id', string='Advantages')
|
|
house_allowance_temp = fields.Float(string='House Allowance', compute='compute_function',store=True)
|
|
transport_allowance = fields.Float(string='Transport Allowance', compute='compute_function',store=True)
|
|
|
|
@api.constrains('advantages', 'salary', 'salary_group')
|
|
def amount_constrains(self):
|
|
for rec in self:
|
|
localdict = dict(employee=rec.employee_id.id, contract=rec.env['hr.contract'].search([
|
|
('employee_id', '=', rec.employee_id.id)]))
|
|
if rec.salary_group.gread_max > 0 and rec.salary_group.gread_min > 0:
|
|
if rec.salary > rec.salary_group.gread_max or rec.salary < rec.salary_group.gread_min:
|
|
raise UserError(_('The Basic Salary Is Greater Than Group Gread Max Or less than Gread Min'))
|
|
for item in self.advantages:
|
|
item.to_get_contract_id()
|
|
if item.benefits_discounts._compute_rule(localdict)[0] < item.amount and item.type == 'exception':
|
|
raise UserError(_(
|
|
'The amount you put is greater than fact value of this Salary rule %s (%s).') % (
|
|
item.benefits_discounts.name, item.benefits_discounts.code))
|
|
|
|
@api.depends('salary_scale.transfer_type')
|
|
def compute_move_type(self):
|
|
self.compute_function()
|
|
if self.salary_scale.transfer_type == 'one_by_one':
|
|
self.required_condition = True
|
|
else:
|
|
self.required_condition = False
|
|
|
|
@api.depends('salary_scale', 'salary_level', 'salary_group', 'salary_degree','salary','advantages','house_allowance_temp','transport_allowance','total_deduction','salary_insurnce','total_allowance','state')
|
|
def compute_function(self):
|
|
for item in self:
|
|
item.house_allowance_temp = 0
|
|
item.transport_allowance = 0
|
|
item.total_net = 0
|
|
contract = self.env['hr.contract'].search([('employee_id', '=', item.employee_id.id)])
|
|
localdict = dict(employee=item.employee_id.id, contract=contract)
|
|
current_date = datetime.now().date()
|
|
|
|
# customize type in advantages
|
|
allowance_customize_items = item.advantages.filtered(
|
|
lambda key: key.type == 'customize' and key.out_rule is False and
|
|
key.benefits_discounts.category_id.rule_type == 'allowance' and
|
|
(datetime.strptime(str(key.date_to), "%Y-%m-%d").date() if key.date_to else current_date)
|
|
>= current_date >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date())
|
|
|
|
allow_sum_custom = sum(x.amount for x in allowance_customize_items)
|
|
for x in allowance_customize_items:
|
|
if x.benefits_discounts.rules_type == 'house':
|
|
item.house_allowance_temp += x.amount
|
|
|
|
if x.benefits_discounts.rules_type == 'transport':
|
|
item.transport_allowance += x.amount
|
|
# allow_custom_ids = [record.benefits_discounts.id for record in allowance_customize_items]
|
|
|
|
deduction_customize_items = item.advantages.filtered(
|
|
lambda key: key.type == 'customize' and key.out_rule is False and
|
|
key.benefits_discounts.category_id.rule_type == 'deduction' and
|
|
(datetime.strptime(str(key.date_to), "%Y-%m-%d").date() if key.date_to else current_date)
|
|
>= current_date >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date())
|
|
|
|
ded_sum_custom = sum(x.amount for x in deduction_customize_items)
|
|
ded_custom_ids = [record.benefits_discounts.id for record in deduction_customize_items]
|
|
|
|
# exception type in advantages
|
|
exception_items = item.advantages.filtered(lambda key: key.type == 'exception')
|
|
total_rule_result, sum_except, sum_customize_expect = 0.0, 0.0, 0.0
|
|
|
|
for x in exception_items:
|
|
rule_result = x.benefits_discounts._compute_rule(localdict)[0]
|
|
if x.date_from >= str(current_date):
|
|
total_rule_result = rule_result
|
|
elif str(current_date) > x.date_from:
|
|
if x.date_to and str(current_date) <= x.date_to:
|
|
total_rule_result = rule_result - x.amount
|
|
elif x.date_to and str(current_date) >= x.date_to:
|
|
total_rule_result = 0 # rule_result
|
|
elif not x.date_to:
|
|
total_rule_result = rule_result - x.amount
|
|
else:
|
|
if rule_result > x.amount:
|
|
total_rule_result = rule_result - x.amount
|
|
|
|
if total_rule_result:
|
|
if x.benefits_discounts.category_id.rule_type == 'allowance':
|
|
sum_customize_expect += total_rule_result
|
|
if x.benefits_discounts.rules_type == 'house':
|
|
item.house_allowance_temp += total_rule_result - x.amount
|
|
else:
|
|
sum_except += total_rule_result
|
|
|
|
if exception_items:
|
|
exception_items = item.advantages.filtered(
|
|
lambda key: (datetime.strptime(str(key.date_to),
|
|
"%Y-%m-%d").date().month if key.date_to else current_date.month)
|
|
>= current_date.month >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date().month)
|
|
|
|
except_ids = [record.benefits_discounts.id for record in exception_items]
|
|
|
|
rule_ids = item.salary_scale.rule_ids.filtered(
|
|
lambda key: key.id not in ded_custom_ids and key.id not in except_ids)
|
|
|
|
level_rule_ids = item.salary_level.benefits_discounts_ids.filtered(lambda key: key.id not in except_ids)
|
|
# key.id not in allow_custom_ids and key.id not in ded_custom_ids and
|
|
|
|
group_rule_ids = item.salary_group.benefits_discounts_ids.filtered(lambda key: key.id not in except_ids)
|
|
# key.id not in allow_custom_ids and key.id not in ded_custom_ids and
|
|
|
|
total_allowance = 0
|
|
total_ded = 0
|
|
for line in rule_ids:
|
|
if line.category_id.rule_type == 'allowance':
|
|
try:
|
|
total_allowance += line._compute_rule(localdict)[0]
|
|
except:
|
|
total_allowance += 0
|
|
|
|
if line.category_id.rule_type == 'deduction':
|
|
try:
|
|
total_ded += line._compute_rule(localdict)[0]
|
|
except:
|
|
total_ded += 0
|
|
|
|
|
|
if line.rules_type == 'house':
|
|
item.house_allowance_temp += line._compute_rule(localdict)[0]
|
|
if line.rules_type == 'transport':
|
|
item.transport_allowance += line._compute_rule(localdict)[0]
|
|
|
|
item.total_allowance = total_allowance
|
|
item.total_deduction = -total_ded
|
|
|
|
if item.salary_level:
|
|
total_allowance = 0
|
|
total_deduction = 0
|
|
for line in level_rule_ids:
|
|
if line.category_id.rule_type == 'allowance':
|
|
try:
|
|
total_allowance += line._compute_rule(localdict)[0]
|
|
except:
|
|
total_allowance += 0
|
|
elif line.category_id.rule_type == 'deduction':
|
|
try:
|
|
total_deduction += line._compute_rule(localdict)[0]
|
|
except:
|
|
total_deduction += 0
|
|
|
|
item.total_allowance += total_allowance
|
|
item.total_deduction += -total_deduction
|
|
|
|
if item.salary_group:
|
|
total_allowance = 0
|
|
total_deduction = 0
|
|
for line in group_rule_ids:
|
|
if line.category_id.rule_type == 'allowance':
|
|
total_allowance += line._compute_rule(localdict)[0]
|
|
elif line.category_id.rule_type == 'deduction':
|
|
total_deduction += line._compute_rule(localdict)[0]
|
|
|
|
item.total_allowance += total_allowance
|
|
item.total_deduction += -total_deduction
|
|
|
|
item.total_allowance += allow_sum_custom
|
|
item.total_allowance += sum_customize_expect
|
|
item.total_deduction += -ded_sum_custom
|
|
item.total_deduction += -sum_except
|
|
item.total_net = item.total_allowance + item.total_deduction
|
|
|
|
# filter salary_level,salary_group,salary_degree
|
|
|
|
@api.onchange('salary_scale')
|
|
def onchange_salary_scale(self):
|
|
for item in self:
|
|
if item.salary_scale:
|
|
level_ids = self.env['hr.payroll.structure'].search(
|
|
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'level')])
|
|
group_ids = self.env['hr.payroll.structure'].search(
|
|
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'group')])
|
|
degree_ids = self.env['hr.payroll.structure'].search(
|
|
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'degree')])
|
|
return {'domain': {'salary_level': [('id', 'in', level_ids.ids)],
|
|
'salary_group': [('id', 'in', group_ids.ids)],
|
|
'salary_degree': [('id', 'in', degree_ids.ids)]}}
|
|
else:
|
|
item.total_allowance = 0.0
|
|
item.total_deduction = 0.0
|
|
item.total_net = 0.0
|
|
return {'domain': {'salary_level': [('id', 'in', [])],
|
|
'salary_group': [('id', 'in', [])],
|
|
'salary_degree': [('id', 'in', [])]}}
|
|
|
|
# filter depend on salary_level
|
|
|
|
@api.onchange('salary_level')
|
|
def onchange_salary_level(self):
|
|
for item in self:
|
|
if item.salary_level:
|
|
group_ids = self.env['hr.payroll.structure'].search(
|
|
[('salary_scale_level_id', '=', item.salary_level.id), ('type', '=', 'group')])
|
|
return {'domain': {'salary_group': [('id', 'in', group_ids.ids)],
|
|
'salary_degree': [('id', 'in', [])]}}
|
|
else:
|
|
return {'domain': {'salary_group': [('id', 'in', [])],
|
|
'salary_degree': [('id', 'in', [])]}}
|
|
|
|
# filter depend on salary_group
|
|
|
|
@api.onchange('salary_group')
|
|
def onchange_salary_group(self):
|
|
for item in self:
|
|
if item.salary_group:
|
|
degree_ids = self.env['hr.payroll.structure'].search(
|
|
[('salary_scale_group_id', '=', item.salary_group.id), ('type', '=', 'degree')])
|
|
return {'domain': {'salary_degree': [('id', 'in', degree_ids.ids)]}}
|
|
else:
|
|
return {'domain': {'salary_degree': [('id', 'in', [])]}}
|
|
|
|
@api.depends('salary_degree')
|
|
def _get_amount(self):
|
|
for record in self:
|
|
record.transport_allowance_temp = record.transport_allowance * record.wage / 100 \
|
|
if record.transport_allowance_type == 'perc' else record.transport_allowance
|
|
record.house_allowance_temp = record.house_allowance * record.wage / 100 \
|
|
if record.house_allowance_type == 'perc' else record.house_allowance
|
|
record.communication_allowance_temp = record.communication_allowance * record.wage / 100 \
|
|
if record.communication_allowance_type == 'perc' else record.communication_allowance
|
|
record.field_allowance_temp = record.field_allowance * record.wage / 100 \
|
|
if record.field_allowance_type == 'perc' else record.field_allowance
|
|
record.special_allowance_temp = record.special_allowance * record.wage / 100 \
|
|
if record.special_allowance_type == 'perc' else record.special_allowance
|
|
record.other_allowance_temp = record.other_allowance * record.wage / 100 \
|
|
if record.other_allowance_type == 'perc' else record.other_allowance
|
|
|
|
@api.depends('contractor_type.salary_type')
|
|
def compute_type(self):
|
|
if self.contractor_type.salary_type == 'scale':
|
|
self.hide = True
|
|
else:
|
|
self.hide = False
|
|
|
|
|
|
class Advantages(models.Model):
|
|
_name = 'contract.advantage'
|
|
_rec_name = 'benefits_discounts'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
|
|
date_from = fields.Date(string='Date From')
|
|
date_to = fields.Date(string='Date To')
|
|
amount = fields.Float(string='Amount', tracking=True)
|
|
type = fields.Selection(selection=[
|
|
('customize', 'Customize'),
|
|
('exception', 'Exception')
|
|
], string='Type', default="customize")
|
|
# to link employee move line from official mission to advantages line in contract
|
|
official_mission_id = fields.Boolean(string="Official Mission", default=False)
|
|
# To link employee move line from over time to advantages line in contract
|
|
over_time_id = fields.Boolean(string="OverTime", default=False)
|
|
# To link employee move line from employee reward to advantages line in contract
|
|
reward_id = fields.Boolean(string="Reward", default=False)
|
|
penalty_id = fields.Boolean(string='Penalty Name', default=False)
|
|
|
|
# Relational fields
|
|
benefits_discounts = fields.Many2one(comodel_name='hr.salary.rule', string='Benefits/Discounts')
|
|
contract_advantage_id = fields.Many2one('hr.contract')
|
|
done = fields.Boolean(string="Done in Payroll")
|
|
out_rule = fields.Boolean(string="Out of Payroll", default=True)
|
|
|
|
employee_id = fields.Many2one('hr.employee', 'Employee Name', domain=[('state', '=', 'open')], tracking=True)
|
|
state = fields.Selection(selection=[
|
|
('draft', 'Draft'),
|
|
('confirm', 'Confirmed'),
|
|
('refused', 'Refused')
|
|
], default='draft', tracking=True)
|
|
|
|
comments = fields.Text(string='Comments')
|
|
payroll_month = fields.Text(string='Payroll Month', tracking=True)
|
|
company_id = fields.Many2one('res.company', string='Company', related='employee_id.company_id', store=True)
|
|
|
|
@api.constrains('date_from', 'date_to', 'amount')
|
|
def _chick_date(self):
|
|
for rec in self:
|
|
if rec.date_to:
|
|
if rec.date_to <= rec.date_from:
|
|
raise UserError(_('The Date Form Must be Less than Date To'))
|
|
if rec.amount <= 0:
|
|
raise UserError(_('The Amount Must be Greater Than Zero The Employee %s')% rec.employee_id.name)
|
|
|
|
def confirm(self):
|
|
self.state = 'confirm'
|
|
|
|
def refused(self):
|
|
self.state = 'refused'
|
|
|
|
def draft(self):
|
|
for rec in self:
|
|
rec.state = 'draft'
|
|
|
|
@api.onchange('employee_id')
|
|
def to_get_contract_id(self):
|
|
contract_id = self.employee_id.contract_id
|
|
self.employee_id = self.contract_advantage_id.employee_id.id
|
|
if contract_id:
|
|
self.contract_advantage_id = contract_id.id
|
|
self.employee_id = self.contract_advantage_id.employee_id.id
|
|
else:
|
|
return False
|
|
|
|
def unlink(self):
|
|
for item in self:
|
|
if item.state != 'draft':
|
|
raise UserError(_('You cannot delete The Salary rule %s For the Employee %s is Not Draft') % (
|
|
item.benefits_discounts.name, item.employee_id.name))
|
|
# if item.done == True:
|
|
# raise UserError(_('Sorry, The Salary rule %s For the Employee %s is Already Computed in Payroll') % (
|
|
# item.benefits_discounts.name, item.employee_id.name))
|
|
return super(Advantages, self).unlink()
|
|
|
|
@api.constrains('employee_id', 'date_from', 'date_to', 'benefits_discounts')
|
|
def check_rule_dates(self):
|
|
""" Function Can Not add Same Advantage at The Same Month
|
|
same employee.
|
|
"""
|
|
for rec in self:
|
|
domain = [
|
|
('date_from', '<=', rec.date_to),
|
|
('date_to', '>=', rec.date_from),
|
|
('employee_id', '=', rec.employee_id.id),
|
|
('id', '!=', rec.id),
|
|
('benefits_discounts', '=', rec.benefits_discounts.id), ]
|
|
advantages_id = self.search_count(domain)
|
|
if advantages_id:
|
|
# for adv in advantages_id:
|
|
raise UserError(
|
|
_('You Can Not add Same Allowance/Deduction at The Same Employee %s For The Same Month!')
|
|
% rec.employee_id.name)
|