1134 lines
57 KiB
Python
1134 lines
57 KiB
Python
# -*- coding: utf-8 -*-
|
|
from datetime import datetime
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import ValidationError, UserError
|
|
from datetime import date, timedelta, datetime as dt
|
|
from dateutil import relativedelta
|
|
import logging
|
|
from num2words import num2words
|
|
from hijri_converter import convert
|
|
import math
|
|
import calendar
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
date_format = "%Y-%m-%d"
|
|
|
|
|
|
class HrTermination(models.Model):
|
|
_name = 'hr.termination'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_rec_name = 'employee_id'
|
|
_description = 'Termination'
|
|
_order = 'last_work_date DESC'
|
|
|
|
# default compute function
|
|
def _get_employee_id(self):
|
|
# assigning the related employee of the logged in user
|
|
employee_id = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
|
if employee_id:
|
|
return employee_id.id
|
|
else:
|
|
return False
|
|
|
|
name = fields.Char(string='Order Reference', copy=False, readonly=True, index=True,
|
|
default=lambda self: _('New'))
|
|
joined_date = fields.Date(string="Join Date", help='Joining date of the employee')
|
|
resign_confirm_date = fields.Date(string="Termination confirm date", help='Date on which the request is confirmed')
|
|
approved_revealing_date = fields.Date(string="Approved Date", help='The date approved for the revealing')
|
|
term_reason = fields.Text(string="Reason", help='Specify reason for leaving the company')
|
|
notice_period = fields.Char(string="Notice Period", compute='_notice_period')
|
|
contract_start_date = fields.Date(related='contract_id.date_start')
|
|
contract_end_date = fields.Date(related='contract_id.date_end')
|
|
salary = fields.Float(related='contract_id.total_allowance')
|
|
first_hire_date = fields.Date(related='employee_id.first_hiring_date')
|
|
last_work_date = fields.Date(tracking=True)
|
|
salary_date_from = fields.Date(store=True, help='Calculate The Last Salary Date From')
|
|
salary_date_to = fields.Date( store=True, help='Calculate The Last Salary Date To')
|
|
paid_duration = fields.Float(compute='_get_paid_duration')
|
|
salary_for_eos = fields.Float()
|
|
service_year = fields.Integer()
|
|
service_month = fields.Integer()
|
|
service_day = fields.Integer()
|
|
reason = fields.Text()
|
|
unpaid_year = fields.Integer()
|
|
unpaid_month = fields.Integer()
|
|
unpaid_day = fields.Integer()
|
|
reason = fields.Text()
|
|
remaining_accommodation = fields.Float()
|
|
salary_amount = fields.Float()
|
|
deduction_balance = fields.Float()
|
|
loan_deduction = fields.Float()
|
|
sal_adv_deduction = fields.Float()
|
|
eos_calc = fields.Float()
|
|
all_leave_balance = fields.Float(store=True, )
|
|
leave_balance = fields.Float(compute='_leave_balance', store=True)
|
|
leave_balance_money = fields.Float(compute='_compute_holiday_amount',store=True)
|
|
air_ticket_amount = fields.Float()
|
|
total_amount = fields.Float()
|
|
notes = fields.Text()
|
|
cause_type_amount = fields.Float()
|
|
allowance_total = fields.Float()
|
|
deduction_total = fields.Float()
|
|
loans_total = fields.Float(compute='_compute_loans_totals',store=True)
|
|
net = fields.Float(store=1)
|
|
total_loans = fields.Float(store=1)
|
|
state = fields.Selection(selection=[
|
|
("draft", "Draft"),
|
|
("submit", "Waiting Direct Manager"),
|
|
("direct_manager", "Waiting Department Manager"),
|
|
("hr_manager", "Wait HR Officer"),
|
|
("finance_manager", "Wait HR Manager"),
|
|
("gm_manager", "Wait CEO Manager"),
|
|
("done", "Wait Transfer"),
|
|
("pay", "Transferred"),
|
|
("refused", "Refused")], default='draft', tracking=True)
|
|
from_hr = fields.Boolean()
|
|
# relational fields
|
|
allowance_deduction_ids = fields.One2many('hr.salary.rule.line', 'allowance_deduction_inverse_id')
|
|
cause_type = fields.Many2one('hr.termination.type', tracking=True)
|
|
journal = fields.Many2one('account.journal')
|
|
employee_id = fields.Many2one(comodel_name='hr.employee', string="Employee", default=_get_employee_id,
|
|
help='Name of the employee for whom the request is creating',
|
|
domain=[('state', '=', 'open')])
|
|
manager_id = fields.Many2one('hr.employee', string='Direct Manager', related='employee_id.parent_id', store=True,
|
|
readonly=True,
|
|
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
|
employee_no = fields.Char(related='employee_id.emp_no', readonly=True,string='Employee Number', store=True)
|
|
department_id = fields.Many2one(comodel_name='hr.department', string="Department",
|
|
related='employee_id.department_id',
|
|
help='Department of the employee', store=True)
|
|
job_id = fields.Many2one(comodel_name='hr.job', related='employee_id.job_id')
|
|
contract_id = fields.Many2one(comodel_name='hr.contract', related='employee_id.contract_id')
|
|
calculation_method = fields.Many2many('hr.salary.rule')
|
|
loans_ids = fields.Many2many('hr.loan.salary.advance',
|
|
domain="[('employee_id', '=', employee_id)]")
|
|
account_move_id = fields.Many2one('account.move')
|
|
salary_termination = fields.Boolean(default=True)
|
|
|
|
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
|
|
|
|
'''@api.onchange('last_work_date')
|
|
def _check_last_date(self):
|
|
for rec in self:
|
|
td = datetime.now().strftime('%Y-%m-%d')
|
|
today = datetime.strptime(td, "%Y-%m-%d").date()
|
|
if str(today) > str(rec.last_work_date):
|
|
raise UserError(_('You can Not Request End of Service On a Previous Date'))'''
|
|
|
|
def unlink(self):
|
|
for item in self:
|
|
if item.state != 'draft':
|
|
raise UserError(_('You can not delete record in state not in draft'))
|
|
return super(HrTermination, self).unlink()
|
|
|
|
# To get salary rules from Termination setting
|
|
@api.onchange('cause_type')
|
|
def _get_salary_rule(self):
|
|
for rec in self:
|
|
rec.calculation_method = False
|
|
if rec.cause_type:
|
|
rec.calculation_method = rec.cause_type.allowance_ids.ids
|
|
else:
|
|
rec.calculation_method = False
|
|
self.re_compute_salary_rules_and_loans()
|
|
|
|
@api.onchange('last_work_date')
|
|
def _get_salary_date(self):
|
|
for rec in self:
|
|
if rec.last_work_date:
|
|
date_to = datetime.strptime(str(rec.last_work_date), "%Y-%m-%d").date()
|
|
day = date_to.day
|
|
rec.salary_date_to = date_to
|
|
rec.salary_date_from = date_to - relativedelta.relativedelta(days=day - 1)
|
|
#if not rec.first_hire_date:
|
|
#raise UserError(
|
|
#_('You can not Request End of Service The Employee have Not First Hiring Date'))
|
|
|
|
@api.onchange('employee_id', 'last_work_date')
|
|
def _all_holiday_balance(self):
|
|
holiday_balance = self.env['hr.holidays'].search([('type', '=', 'add'),
|
|
('check_allocation_view', '=', 'balance'),
|
|
('holiday_status_id.leave_type', '=', 'annual'),
|
|
('employee_id', '=', self.employee_id.id)],
|
|
limit=1)
|
|
|
|
self.all_leave_balance = holiday_balance.remaining_leaves
|
|
|
|
# Function to get Yearly holiday balance
|
|
|
|
@api.depends('employee_id', 'last_work_date')
|
|
def _leave_balance(self):
|
|
for rec in self:
|
|
leave = self.env['hr.holidays'].search([('type', '=', 'add'),
|
|
('check_allocation_view', '=', 'balance'),
|
|
('holiday_status_id.leave_type', '=', 'annual'),
|
|
('employee_id', '=', rec.employee_id.id)],
|
|
limit=1)
|
|
if leave.holiday_ids and rec.last_work_date and leave.holiday_status_id.duration_ids:
|
|
cron_run_date = datetime.strptime(str(leave.holiday_ids[-1].cron_run_date), "%Y-%m-%d").date()
|
|
date_to_check = (datetime.utcnow() + timedelta(hours=3)).date()
|
|
last_working_date = datetime.strptime(str(rec.last_work_date), "%Y-%m-%d").date()
|
|
#if cron_run_date < date_to_check:
|
|
# date_to_check = cron_run_date
|
|
#to_work_days = (last_working_date - date_to_check).days
|
|
|
|
first_hiring_date = datetime.strptime(str(leave.hiring_date), "%Y-%m-%d").date()
|
|
last_work_date = datetime.strptime(str(rec.last_work_date), "%Y-%m-%d").date()
|
|
working_days = (last_work_date - first_hiring_date).days + 1
|
|
working_years = working_days / 365
|
|
for item in leave.holiday_status_id.duration_ids:
|
|
if item.date_from <= working_years < item.date_to:
|
|
holiday_duration = item.duration
|
|
###get last cron date to compute leave_balance_date
|
|
diff_days = 0
|
|
new_balance=0
|
|
"""the last working date less than cron run date"""
|
|
if cron_run_date < last_working_date:
|
|
diff_days = (last_working_date - cron_run_date).days
|
|
for i in range(1, diff_days + 1):
|
|
cala_date = cron_run_date + timedelta(days=i)
|
|
balance_day = leave.remaining_leaves_of_day_by_date(rec.employee_id, str(cala_date),
|
|
leave.holiday_status_id , is_month=False, is_years=False)
|
|
new_balance = new_balance + balance_day
|
|
else:
|
|
diff_days = -(cron_run_date - last_working_date).days
|
|
for i in range(1, -diff_days + 1):
|
|
cala_date = last_working_date + timedelta(days=i)
|
|
balance_day = leave.remaining_leaves_of_day_by_date(rec.employee_id, str(cala_date),
|
|
leave.holiday_status_id , is_month=False, is_years=False)
|
|
new_balance = new_balance - balance_day
|
|
####################### END
|
|
#upcoming_leave = ((holiday_duration / 12) / 30.39) * to_work_days
|
|
leave_balance = round(rec.employee_id.remaining_leaves + new_balance, 2)
|
|
|
|
exceed_days = leave.holiday_status_id.number_of_save_days + holiday_duration
|
|
if leave_balance > exceed_days:
|
|
rec.leave_balance = exceed_days
|
|
else:
|
|
rec.leave_balance = round(rec.employee_id.remaining_leaves + new_balance, 2)
|
|
self._compute_holiday_amount()
|
|
|
|
def current_date_hijri(self):
|
|
year = datetime.now().year
|
|
day = datetime.now().day
|
|
month = datetime.now().month
|
|
return convert.Gregorian(year, month, day).to_hijri()
|
|
|
|
def amount_to_word(self, amount):
|
|
return num2words(amount, lang=self.env.user.lang)
|
|
|
|
# Compute holiday amount
|
|
@api.onchange('employee_id', 'leave_balance')
|
|
def _compute_holiday_amount(self):
|
|
for item in self:
|
|
if item.salary:
|
|
|
|
days = item.employee_id.resource_calendar_id.work_days
|
|
day_amount = item.salary / (days or 1)
|
|
holiday_amount = item.leave_balance * day_amount
|
|
item.leave_balance_money = round(holiday_amount,2)
|
|
|
|
@api.onchange('salary_termination')
|
|
def _check_last_salary(self):
|
|
if self.salary_termination:
|
|
payslips = self.env['hr.payslip'].search(
|
|
['&', ('date_from', '>=', self.salary_date_from), ('date_to', '<=', self.salary_date_to),
|
|
('employee_id', '=', self.employee_id.id)])
|
|
if payslips:
|
|
raise ValidationError(
|
|
_('Sorry this payslip is already calculated for this employee %s')
|
|
% (self.employee_id.name))
|
|
|
|
# Compute paid duration
|
|
@api.depends('salary_date_from', 'salary_date_to', 'last_work_date')
|
|
def _get_paid_duration(self):
|
|
for item in self:
|
|
if item.salary_date_from:
|
|
if item.salary_date_to and item.last_work_date:
|
|
last_work = dt.strptime(str(item.last_work_date), date_format)
|
|
start_date = dt.strptime(str(item.salary_date_from), date_format)
|
|
end_date = dt.strptime(str(item.salary_date_to), date_format)
|
|
if end_date >= start_date:
|
|
value = relativedelta.relativedelta(end_date, start_date)
|
|
if value.months < 1:
|
|
if value.days == 30:
|
|
item.paid_duration = 31
|
|
else:
|
|
item.paid_duration = value.days + 1
|
|
else:
|
|
raise UserError(_('Duration must be less than or equal month'))
|
|
else:
|
|
raise UserError(_('Salary Date to must be greater than Salary Date from'))
|
|
|
|
if start_date > last_work:
|
|
raise UserError(_('Salary Date to must be Less than Last Work Date'))
|
|
|
|
else:
|
|
item.paid_duration = 0.0
|
|
else:
|
|
item.paid_duration = 0.0
|
|
|
|
# Create rule line in allowance_deduction
|
|
|
|
def create_rule_line(self, rule, amount, items, is_advantage, cause_type_factor,advantages_out_rule):
|
|
# If cause type have factor then multiply it in salary rule amount
|
|
if self.cause_type and cause_type_factor == 1:
|
|
if self.cause_type.allowance_id and self.cause_type_amount:
|
|
amount = round(self.cause_type_amount,2)
|
|
# If cause type have holiday then multiply it in salary rule holiday amount
|
|
holiday_allow = self.cause_type.holiday_allowance
|
|
holiday_deduc = self.cause_type.holiday_deduction
|
|
if holiday_allow and holiday_allow.id == rule.id:
|
|
amount = self.leave_balance_money
|
|
if holiday_deduc and holiday_deduc.id == rule.id:
|
|
amount = -(self.leave_balance_money)
|
|
record = {
|
|
'salary_rule_id': rule.id,
|
|
'amount': amount,
|
|
'is_advantage': is_advantage,
|
|
'advantages_out_rule': advantages_out_rule,
|
|
}
|
|
items.append(record)
|
|
|
|
if amount > 0 and not holiday_deduc.id == rule.id:
|
|
record = {
|
|
'salary_rule_id': rule.id,
|
|
'amount': amount,
|
|
'is_advantage': is_advantage,
|
|
'advantages_out_rule': advantages_out_rule,
|
|
}
|
|
items.append(record)
|
|
# compute_salary_rule(item.benefits_discounts, items,duration_percentage, item, 0)
|
|
def compute_salary_rule(self, rule, items, paid_percentage, advantages, cause_type_factor):
|
|
is_advantage = False
|
|
advantages_out_rule = False
|
|
try:
|
|
if self.employee_id.sudo().contract_id:
|
|
if advantages:
|
|
is_advantage = True
|
|
#TODO
|
|
if advantages.type == 'customize' and not advantages.out_rule:
|
|
#if advantages.type == 'customize' and self.contract_id.contractor_type.salary_type == 'amount':
|
|
amount = advantages.amount / paid_percentage
|
|
else:
|
|
amount = advantages.amount
|
|
advantages_out_rule = True
|
|
|
|
if advantages.type == 'exception':
|
|
amount = (self.compute_rule(rule,
|
|
self.employee_id.sudo().contract_id) - advantages.amount) / paid_percentage
|
|
else:
|
|
amount = self.compute_rule(rule, self.employee_id.sudo().contract_id) / paid_percentage
|
|
self.create_rule_line(rule, amount, items, is_advantage, cause_type_factor ,advantages_out_rule)
|
|
|
|
else:
|
|
raise UserError(_('Employee "%s" has no contract') % self.employee_id.name)
|
|
except:
|
|
raise UserError(_('Wrong quantity defined for salary Rule " %s " ') % (rule.name))
|
|
return round(amount,2)
|
|
|
|
# Compute salary rules
|
|
|
|
def compute_rule(self, rule, contract):
|
|
localdict = dict(employee=contract.employee_id, contract=contract)
|
|
if rule.amount_select == 'percentage':
|
|
total_percent = 0
|
|
if rule.related_benefits_discounts:
|
|
for line in rule.related_benefits_discounts:
|
|
if line.amount_select == 'fix':
|
|
total_percent += self.compute_rule(line, contract)
|
|
elif line.amount_select == 'percentage':
|
|
total_percent += self.compute_rule(line, contract)
|
|
else:
|
|
total_percent += self.compute_rule(line, contract)
|
|
if total_percent:
|
|
if rule.salary_type == 'fixed':
|
|
try:
|
|
return float(total_percent * rule.amount_percentage / 100)
|
|
except:
|
|
raise UserError(
|
|
_('Wrong percentage base or quantity defined for salary rule %s (%s).') % (
|
|
rule.name, rule.code))
|
|
elif rule.salary_type == 'related_levels':
|
|
levels_ids = rule.salary_amount_ids.filtered(
|
|
lambda item: item.salary_scale_level.id == contract.salary_level.id)
|
|
if levels_ids:
|
|
for l in levels_ids:
|
|
try:
|
|
return float(l.salary * total_percent / 100)
|
|
except:
|
|
raise UserError(
|
|
_('Wrong quantity defined for salary rule %s (%s).') % (
|
|
rule.name, rule.code))
|
|
else:
|
|
return 0
|
|
elif rule.salary_type == 'related_groups':
|
|
groups_ids = rule.salary_amount_ids.filtered(
|
|
lambda item: item.salary_scale_group.id == contract.salary_group.id)
|
|
if groups_ids:
|
|
for g in groups_ids:
|
|
try:
|
|
return float(g.salary * total_percent / 100)
|
|
except:
|
|
raise UserError(
|
|
_('Wrong quantity defined for salary rule %s (%s).') % (
|
|
rule.name, rule.code))
|
|
else:
|
|
return 0
|
|
elif rule.salary_type == 'related_degrees':
|
|
degrees_ids = rule.salary_amount_ids.filtered(
|
|
lambda item: item.salary_scale_degree.id == contract.salary_degree.id)
|
|
if degrees_ids:
|
|
for d in degrees_ids:
|
|
try:
|
|
return float(d.salary * total_percent / 100)
|
|
except:
|
|
raise UserError(
|
|
_('Wrong quantity defined for salary rule %s (%s).') % (
|
|
rule.name, rule.code))
|
|
else:
|
|
return 0
|
|
else:
|
|
try:
|
|
return 0
|
|
except:
|
|
raise Warning(_('There is no total for rule : %s') % (rule.name))
|
|
|
|
elif rule.amount_select == 'fix':
|
|
return rule._compute_rule(localdict)[0]
|
|
|
|
else:
|
|
return rule._compute_rule(localdict)[0]
|
|
|
|
# fill allowance deduction with cause type ,salary_date_from and salary_date_to
|
|
|
|
@api.onchange('calculation_method', 'cause_type', 'salary_date_from', 'salary_date_to', 'employee_id')
|
|
def compute_salary_rules_and_loans(self):
|
|
self.re_compute_salary_rules_and_loans()
|
|
|
|
# Re-compute salary rules and loans when press re-compute button
|
|
|
|
@api.onchange('salary_termination')
|
|
def compute_salary_termination(self):
|
|
for rec in self:
|
|
if rec.salary_termination == False:
|
|
rec.calculation_method = False
|
|
else:
|
|
if rec.cause_type:
|
|
rec.calculation_method = rec.cause_type.allowance_ids.ids
|
|
self.re_compute_salary_rules_and_loans()
|
|
|
|
def re_compute_salary_rules_and_loans(self):
|
|
self._get_duration_service()
|
|
self._get_loans_ids()
|
|
self._all_holiday_balance()
|
|
# for itemss in self:
|
|
# itemss.total_loans = itemss.loans_total
|
|
# itemss.net = abs(itemss.allowance_total) - abs(itemss.deduction_total)
|
|
# itemss.net -= abs(itemss.total_loans)
|
|
# for item in self:
|
|
# Make the maximum paid duration is 30
|
|
if self.last_work_date:
|
|
_, number_of_days = calendar.monthrange(self.last_work_date.year, self.last_work_date.month)
|
|
if self.paid_duration > 0:
|
|
if number_of_days == 31:
|
|
duration_percentage = 31 / self.paid_duration
|
|
|
|
elif number_of_days == 28:
|
|
duration_percentage = 28 / self.paid_duration
|
|
|
|
elif number_of_days == 29:
|
|
duration_percentage = 29 / self.paid_duration
|
|
else:
|
|
duration_percentage = 30 / self.paid_duration
|
|
else:
|
|
duration_percentage = 1
|
|
|
|
# Initialize values
|
|
items = []
|
|
self.allowance_deduction_ids = False
|
|
rule_line = self.env['hr.salary.rule.line'].search([('allowance_deduction_inverse_id', '=', False)])
|
|
if rule_line:
|
|
rule_line.sudo().unlink()
|
|
|
|
# Get all advantages from contract
|
|
if self.sudo().contract_id:
|
|
if self.sudo().contract_id.advantages:
|
|
for item in self.sudo().contract_id.advantages:
|
|
if item.date_from and item.amount > 0 and self.last_work_date:
|
|
td = datetime.now().strftime('%Y-%m-%d')
|
|
today = datetime.strptime(str(td), "%Y-%m-%d").date()
|
|
start = datetime.strptime(str(item.date_from), "%Y-%m-%d").date()
|
|
last_work = datetime.strptime(str(self.last_work_date), "%Y-%m-%d").date()
|
|
|
|
#if item.benefits_discounts in self.calculation_method:
|
|
if item.date_to:
|
|
end = datetime.strptime(str(item.date_to), "%Y-%m-%d").date()
|
|
if start <= last_work <= end:
|
|
amount = self.compute_salary_rule(item.benefits_discounts, items,
|
|
duration_percentage, item, 0)
|
|
else:
|
|
if last_work >= start:
|
|
amount = self.compute_salary_rule(item.benefits_discounts, items,
|
|
duration_percentage, item, 0)
|
|
|
|
# Get all salary rules from calculation method
|
|
'''if self.calculation_method:
|
|
# initialize values
|
|
total, self.salary_for_eos = 0.0, 0.0
|
|
|
|
for rule in self.calculation_method:
|
|
total += self.compute_salary_rule(rule, items, duration_percentage, False, 0)
|
|
self.salary_for_eos += total
|
|
else:
|
|
self.salary_for_eos = 0.0'''
|
|
if self.calculation_method:
|
|
total, self.salary_for_eos = 0.0, 0.0
|
|
for rule in self.calculation_method:
|
|
if rule._origin.id:
|
|
rule = rule.browse([rule._origin.id])
|
|
self.compute_salary_rule(rule, items, duration_percentage, False, 0)
|
|
for item in items:
|
|
if rule.id == item.get('salary_rule_id') and rule.category_id.rule_type =='allowance':
|
|
total += item.get('amount')
|
|
if rule.id == item.get('salary_rule_id') and rule.category_id.rule_type =='deduction':
|
|
total -= item.get('amount')
|
|
self.salary_for_eos += total
|
|
else:
|
|
self.salary_for_eos = 0.0
|
|
|
|
# Get salary rule form cause type
|
|
|
|
if self.first_hire_date:
|
|
if self.last_work_date:
|
|
if self.cause_type:
|
|
start_date = dt.strptime(str(self.first_hire_date), "%Y-%m-%d")
|
|
end_date = dt.strptime(str(self.last_work_date), "%Y-%m-%d")
|
|
total_rules, amount_of_year, amount_of_month, amount_of_day, self.cause_type_amount = 0.0, 0.0, 0.0, 0.0, 0.0
|
|
|
|
if end_date >= start_date:
|
|
years = self.service_year
|
|
days = self.service_day
|
|
months = self.service_month
|
|
all_duration = months + (days / 30) + (years * 12)
|
|
if self.cause_type.allowance_ids and self.cause_type.termination_duration_ids:
|
|
|
|
# Get total for all salary rules form cause type
|
|
rule_flag = False
|
|
for rule in self.cause_type.allowance_ids:
|
|
rule_flag = False
|
|
# Check if salary rule does not duplicated when come from contract and is allowance only
|
|
if rule.category_id.rule_type =='allowance':
|
|
if items:
|
|
for record in items:
|
|
|
|
if record.get('salary_rule_id') == rule.id and record.get('is_advantage') is True and record.get('advantages_out_rule'):
|
|
total_rules += record.get('amount')
|
|
rule_flag = True
|
|
if record.get('salary_rule_id') == rule.id and record.get('is_advantage') is True and not record.get('advantages_out_rule'):
|
|
# Change salary rule value in "salary for eos" by that in contract that is duplicated
|
|
total_rules += record.get('amount') * duration_percentage
|
|
rule_flag = True
|
|
|
|
if rule_flag is False:
|
|
total_rules += self.compute_rule(rule, self.employee_id.sudo().contract_id)
|
|
reward_amount = 0
|
|
resedual = all_duration
|
|
line_amount = 0
|
|
duration_to = 0
|
|
# search line cause_type and get amount for each line factor
|
|
for line in self.cause_type.termination_duration_ids:
|
|
line_amount = line.amount
|
|
if line.date_to <= all_duration:
|
|
if line.amount > 0:
|
|
duration_to = line.date_to - duration_to
|
|
reward_amount += total_rules * (duration_to / 12) * line.factor
|
|
resedual = all_duration - line.date_to
|
|
|
|
else:
|
|
if line.date_to > all_duration:
|
|
reward_amount += total_rules * resedual / 12 * line.factor
|
|
break
|
|
resedual = 0
|
|
|
|
reward_amount = reward_amount * line_amount
|
|
self.cause_type_amount = round(reward_amount,2)
|
|
amount = self.compute_salary_rule(self.cause_type.allowance_id, items,
|
|
duration_percentage, False, 1)
|
|
if self.cause_type.holiday:
|
|
if self.leave_balance_money >= 0:
|
|
amount = self.compute_salary_rule(self.cause_type.holiday_allowance, items,
|
|
duration_percentage, False, 1)
|
|
if self.leave_balance_money < 0:
|
|
amount = self.compute_salary_rule(self.cause_type.holiday_deduction, items,
|
|
duration_percentage, False, 1)
|
|
|
|
# update employee last work date
|
|
# self.employee_id.write({'leaving_date': self.last_work_date})
|
|
|
|
# Check if salary rule does not duplicated when come from contract
|
|
lines_data = []
|
|
for item in items:
|
|
if not item.get('is_advantage'):
|
|
lines_data.append(item)
|
|
for advantages in self.sudo().contract_id.advantages:
|
|
if advantages.benefits_discounts.id == item.get('salary_rule_id') and advantages.out_rule:
|
|
lines_data.append(item)
|
|
for rule in self.calculation_method :
|
|
if (rule._origin.id == item.get('salary_rule_id') or rule.id == item.get('salary_rule_id')) and item.get('is_advantage'):
|
|
lines_data.append(item)
|
|
set_data2 = {tuple(item.items()) for item in lines_data}
|
|
|
|
# Convert back to list of dictionaries
|
|
lines_data = [dict(item) for item in set_data2]
|
|
# if lines_data:
|
|
# for record in lines_data:
|
|
# for element in lines_data:
|
|
# if record.get('salary_rule_id') == element.get('salary_rule_id'):
|
|
# if record.get('is_advantage') is True and element.get('is_advantage') is False:
|
|
# lines_data.remove(element)
|
|
|
|
if lines_data:
|
|
for record in lines_data:
|
|
for element in lines_data:
|
|
if record.get('salary_rule_id') == element.get('salary_rule_id'):
|
|
if record.get('is_advantage') is True and element.get('is_advantage') is False:
|
|
lines_data.remove(element)
|
|
|
|
# Change salary rule value in "salary for eos" by that in contract that is duplicated
|
|
rule = self.env['hr.salary.rule'].browse(element.get('salary_rule_id'))
|
|
self.salary_for_eos -= (self.compute_rule(rule,self.employee_id.sudo().contract_id) / duration_percentage)
|
|
# self.salary_for_eos += record.get('amount')
|
|
for line in lines_data:
|
|
del line['advantages_out_rule']
|
|
self.allowance_deduction_ids = [(0, 0, line) for line in lines_data]
|
|
|
|
# Compute total allowance ,deduction ,loans and net
|
|
self._leave_balance()
|
|
self._compute_deduction_allowance_total()
|
|
self.allowance_deduction_ids.get_account_ids()
|
|
|
|
# default loans lines
|
|
@api.onchange('employee_id')
|
|
def _get_loans_ids(self):
|
|
self.loans_ids = False
|
|
record_list = []
|
|
record_ids = self.env['hr.loan.salary.advance'].search([('state', '=', 'pay'),('employee_id','=', self.employee_id.id)])
|
|
for item in self:
|
|
if item.employee_id:
|
|
for line in record_ids:
|
|
if line.employee_id.id == item.employee_id.id:
|
|
if (line.remaining_loan_amount > 0.0 and line.state == 'pay') or (
|
|
line.remaining_loan_amount > 0.0 and line.state == 'closed'):
|
|
record_list.append(line.id)
|
|
item.loans_ids = record_list
|
|
|
|
# compute duration service in years , months and days
|
|
@api.onchange('first_hire_date', 'last_work_date', 'employee_id')
|
|
def _get_duration_service(self):
|
|
for item in self:
|
|
if item.first_hire_date and item.last_work_date:
|
|
start_date = dt.strptime(str(item.first_hire_date), "%Y-%m-%d")
|
|
end_date = dt.strptime(str(item.last_work_date), "%Y-%m-%d") + timedelta(days=1)
|
|
|
|
if end_date > start_date:
|
|
unpaid_year = unpaid_month = unpaid_day = 0
|
|
modules = self.env['ir.module.module'].sudo().search([('state', '=', 'installed'),
|
|
('name', '=', 'hr_holidays_public')])
|
|
if modules:
|
|
holidays = self.env['hr.holidays'].search(
|
|
[('holiday_status_id.payslip_type', '=', 'unpaid'),
|
|
('holiday_status_id.type_unpaid', '=', 'termaintion'),
|
|
('employee_id', '=', self.employee_id.id),
|
|
('date_from', '>=', item.first_hire_date),
|
|
('date_to', '<=', item.last_work_date),
|
|
('state', '=', 'validate1')])
|
|
for h in holidays:
|
|
date_from = dt.strptime(str(h.date_from).split()[0], "%Y-%m-%d")
|
|
date_to = dt.strptime(str(h.date_to).split()[0], "%Y-%m-%d") + timedelta(days=1)
|
|
r = relativedelta.relativedelta(date_to, date_from)
|
|
unpaid_year += r.years
|
|
unpaid_month += r.months
|
|
unpaid_day += r.days
|
|
official_holiday_year = h.official_holiday_days and int(h.official_holiday_days / 365) or 0
|
|
official_holiday_month = h.official_holiday_days and int(
|
|
(h.official_holiday_days % 365) / 30.5) or 0
|
|
official_holiday_day = h.official_holiday_days and math.ceil(
|
|
(h.official_holiday_days % 365) % 30.5) or 0
|
|
if unpaid_day >= official_holiday_day:
|
|
unpaid_day = unpaid_day - official_holiday_day
|
|
else:
|
|
unpaid_day = 30 - (official_holiday_day - unpaid_day)
|
|
unpaid_month = unpaid_month - 1
|
|
if unpaid_month >= official_holiday_month:
|
|
unpaid_month = unpaid_month - official_holiday_month
|
|
else:
|
|
unpaid_month = 12 - (official_holiday_month - unpaid_month)
|
|
unpaid_year = unpaid_year - 1
|
|
unpaid_year = unpaid_year - official_holiday_year
|
|
r = relativedelta.relativedelta(end_date, start_date)
|
|
year = r.years
|
|
month = r.months
|
|
day = r.days
|
|
item.unpaid_year = unpaid_year
|
|
item.unpaid_month = unpaid_month
|
|
item.unpaid_day = unpaid_day
|
|
if day >= item.unpaid_day:
|
|
day = day - item.unpaid_day
|
|
else:
|
|
day = 30 - (item.unpaid_day - day)
|
|
month = month - 1
|
|
if month >= item.unpaid_month:
|
|
month = month - item.unpaid_month
|
|
else:
|
|
month = 12 - (item.unpaid_month - month)
|
|
year = year - 1
|
|
year = year - item.unpaid_year
|
|
|
|
item.service_day = day
|
|
item.service_month = month
|
|
item.service_year = year
|
|
else:
|
|
raise UserError(
|
|
_('Leaving Date must be greater than First Hiring Date'))
|
|
else:
|
|
item.service_year = 0
|
|
item.service_month = 0
|
|
item.service_day = 0
|
|
item.unpaid_year = 0
|
|
item.unpaid_month = 0
|
|
item.unpaid_day = 0
|
|
|
|
# compute total loans amount
|
|
@api.depends('loans_ids')
|
|
def _compute_loans_totals(self):
|
|
total = 0.0
|
|
for item in self:
|
|
if item.loans_ids:
|
|
for line in item.loans_ids:
|
|
total += line.remaining_loan_amount
|
|
item.loans_total = total
|
|
item.total_loans = round(total,2)
|
|
|
|
# compute total allowance and deduction amount
|
|
@api.onchange('allowance_deduction_ids')
|
|
def _compute_deduction_allowance_total(self):
|
|
total_deduction = 0.0
|
|
total_allowance = 0.0
|
|
for item in self.allowance_deduction_ids:
|
|
if item.category_id.rule_type == 'deduction':
|
|
total_deduction += round(item.amount,2)
|
|
|
|
elif item.category_id.rule_type == 'allowance':
|
|
total_allowance += round(item.amount,2)
|
|
|
|
# Other salary rules treat as allowance
|
|
elif item.category_id.rule_type != 'deduction':
|
|
total_allowance += round(item.amount,2)
|
|
|
|
self.deduction_total = total_deduction
|
|
self.allowance_total = total_allowance
|
|
self.net = abs(round(self.allowance_total,2)) - abs(round(self.deduction_total,2))
|
|
self.net -= abs(round(self.total_loans,2))
|
|
|
|
# Compute net
|
|
# @api.depends('allowance_total')
|
|
# def _compute_net(self):
|
|
# for item in self:
|
|
# print("******************,",item.total_loans)
|
|
# print("******************,",item.allowance_total)
|
|
# print("******************,",item.deduction_total)
|
|
# item.net = abs(item.allowance_total) - abs(item.deduction_total)
|
|
# item.net -= abs(item.total_loans)
|
|
|
|
def set_to_draft(self):
|
|
for item in self:
|
|
state = item.state
|
|
holiday_balance = self.env['hr.holidays'].search([('type', '=', 'add'),
|
|
('check_allocation_view', '=', 'balance'),
|
|
('holiday_status_id.leave_type', '=', 'annual'),
|
|
('employee_id', '=', self.employee_id.id)],
|
|
limit=1)
|
|
last_date = item.write_date.date().month
|
|
# check if the moved journal entry if un posted then delete
|
|
if item.account_move_id:
|
|
if item.account_move_id.state == 'draft':
|
|
# item.account_move_id.state = 'canceled'
|
|
item.account_move_id.unlink()
|
|
item.account_move_id = False
|
|
self.state = 'draft'
|
|
else:
|
|
raise UserError(_(
|
|
'You can not re-draft termination because account move with ID "%s" in state Posted') % item.account_move_id.name)
|
|
|
|
# Check Employee contract to Return employee to service
|
|
if state == 'pay':
|
|
if item.employee_id.state == 'out_of_service':
|
|
if item.employee_id.sudo().contract_id.state == 'end_contract':
|
|
item.employee_id.state = 'open'
|
|
item.employee_id.leaving_date = False
|
|
item.employee_id.sudo().contract_id.state = 'program_directory'
|
|
item.employee_id.sudo().contract_id.date_end = False
|
|
|
|
for loans in item.loans_ids:
|
|
for install in loans.deduction_lines:
|
|
#loan_date = datetime.strptime(install.write_date, "%Y-%m-%d %H:%M:%S").date().month
|
|
if install.paid == True and install.termination_paid == True:
|
|
install.paid = False
|
|
install.termination_paid = False
|
|
loans.state = 'pay'
|
|
if holiday_balance:
|
|
holiday_balance.remaining_leaves = item.all_leave_balance
|
|
item.state = 'draft'
|
|
|
|
# change status workflow
|
|
|
|
def submit(self):
|
|
# Check if exp_custody_petty_cash module is installed
|
|
Module = self.env['ir.module.module'].sudo()
|
|
emp_modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_employee_custody')])
|
|
petty_cash_modules = Module.search([('state', '=', 'installed'), ('name', '=', 'hr_expense_petty_cash')])
|
|
asset_modules = Module.search([('state', '=', 'installed'), ('name', '=', 'odex25_account_asset')])
|
|
custody_request_module = Module.search([('state', '=', 'installed'), ('name', '=', 'employee_custody_request')])
|
|
|
|
# modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_custody_petty_cash')])
|
|
''''if asset_modules:
|
|
# Check if employee has Employee expense Payment not in state Return done
|
|
employee_expense_payment = self.env['account.asset'].search(
|
|
[('employee_id', '=', self.employee_id.id),('state', 'in', ['open'])])
|
|
if len(employee_expense_payment) > 0:
|
|
if self._context['lang'] != 'ar_001':
|
|
raise UserError(("You can not create termination when there is" + str(len(employee_expense_payment))+"employee Deferred Expenses in state not in state Return Done for"+self.employee_id.name+"please reconcile it"))
|
|
else:
|
|
raise UserError("لايمكن اجراء انهاء خدمة حيث يوجد "+str(len(employee_expense_payment))+" طلبات مصروفات مقدمة للموظف "+self.employee_id.name)
|
|
if emp_modules:
|
|
# Check if employee has Employee Custody not in state Return done
|
|
employee_custody = self.env['custom.employee.custody'].search(
|
|
[('employee_id', '=', self.employee_id.id), ('state', 'in', ['submit', 'direct', 'admin', 'approve'])])
|
|
if len(employee_custody) > 0:
|
|
raise UserError(
|
|
(
|
|
'You can not create termination when there is "%s" employee custody in state not in state Return Done for "%s" please reconcile it') % (
|
|
len(employee_custody), self.employee_id.name))'''
|
|
if petty_cash_modules:
|
|
|
|
# Check if employee has Employee Petty Cash Payment not in state Return done
|
|
employee_petty_cash_payment = self.env['petty.cash'].search(
|
|
[('partner_id', '=', self.employee_id.user_id.partner_id.id),
|
|
('state', 'in', ['submit', 'direct', 'fm', 'ceo', 'accepted', 'validate'])])
|
|
if len(employee_petty_cash_payment) > 0:
|
|
raise UserError(
|
|
_(
|
|
'You can not create termination when there is "%s" employee petty cash payment in state not in state Return Done for "%s" please reconcile it') % (
|
|
len(employee_petty_cash_payment), self.employee_id.name))
|
|
if custody_request_module:
|
|
exceeded_custody = self.env['hr.request.pledge'].search([
|
|
('employee_id', '=', self.employee_id.id),
|
|
('custody_status', '=', 'exceeded')
|
|
])
|
|
if exceeded_custody:
|
|
raise UserError(_(
|
|
'You cannot terminate the employee "%s" because there are "%s" custody requests that exceeded the allowed amount and are not yet closed.'
|
|
) % (self.employee_id.name, len(exceeded_custody)))
|
|
|
|
for item in self:
|
|
# Check if Net less than 0.0
|
|
if item.net < 0:
|
|
raise UserError(_('Net can not be negative value !!'))
|
|
self.leaves_clearance_constrains()
|
|
item.state = 'submit'
|
|
|
|
def direct_manager(self):
|
|
for rec in self:
|
|
rec.leaves_clearance_constrains()
|
|
manager = rec.sudo().employee_id.parent_id
|
|
hr_manager = rec.sudo().employee_id.company_id.hr_manager_id
|
|
if manager:
|
|
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
|
|
rec.write({'state': 'direct_manager'})
|
|
else:
|
|
raise UserError(_("Sorry, The Approval For The Direct Manager '%s' Only OR HR Manager!")%(rec.employee_id.parent_id.name))
|
|
else:
|
|
rec.write({'state': 'direct_manager'})
|
|
|
|
def hr_manager(self):
|
|
for rec in self:
|
|
rec.re_compute_salary_rules_and_loans()
|
|
manager = rec.sudo().employee_id.coach_id
|
|
hr_manager = rec.sudo().employee_id.company_id.hr_manager_id
|
|
if manager:
|
|
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
|
|
rec.write({'state': 'hr_manager'})
|
|
else:
|
|
raise UserError(_("Sorry, The Approval For The Department Manager '%s' Only OR HR Manager!")%(rec.employee_id.coach_id.name))
|
|
else:
|
|
rec.write({'state': 'hr_manager'})
|
|
|
|
# change status workflow
|
|
def finance_manager(self):
|
|
self.re_compute_salary_rules_and_loans()
|
|
# check for clearance for employee
|
|
employee_clearance = self.env['hr.clearance.form'].search([('employee_id', '=', self.employee_id.id),
|
|
('clearance_type', '!=', 'vacation'),
|
|
('state', 'in', ['done', 'wait'])])
|
|
if len(employee_clearance) == 0 and self.cause_type.clearance:
|
|
raise UserError(
|
|
_('You can not create termination when missing clearance for Employee %s') % self.employee_id.name)
|
|
if self.employee_id:
|
|
# self.employee_id.state = 'under_out_of_service'
|
|
self.employee_id.sudo().contract_id.state = 'end_contract'
|
|
self.state = 'finance_manager'
|
|
|
|
def general_manager(self):
|
|
self.state = 'gm_manager'
|
|
|
|
def complete(self):
|
|
self.state = 'done'
|
|
|
|
def pay(self):
|
|
line_vals = []
|
|
for item in self.allowance_deduction_ids:
|
|
# check if amount greater than 0.0 to fill move account lines
|
|
if item.amount > 0.0:
|
|
# check for deduction credit account
|
|
if item.category_id.rule_type == 'deduction' :
|
|
if not item.account_credit_id:
|
|
raise UserError(
|
|
_('Undefined credit account for salary rule %s.') % (item.salary_rule_id.name))
|
|
# check for allowance debit account
|
|
elif item.category_id.rule_type == 'allowance':
|
|
if not item.account_debit_id:
|
|
raise UserError(
|
|
_('Undefined debit account for salary rule %s.') % (item.salary_rule_id.name))
|
|
else:
|
|
if not item.account_debit_id:
|
|
raise UserError(_('Check account debit for salary rule "%s" ') % (
|
|
item.salary_rule_id.name))
|
|
|
|
# fill move lines with allowance deduction
|
|
amount = round(item.amount,2)
|
|
if item.category_id.rule_type == 'allowance':
|
|
line_vals.append({
|
|
'name': item.salary_rule_id.name,
|
|
'debit': abs(amount),
|
|
'account_id': item.account_debit_id.id,
|
|
'partner_id': self.employee_id.user_id.partner_id.id})
|
|
|
|
elif item.category_id.rule_type == 'deduction':
|
|
line_vals.append({
|
|
'name': item.salary_rule_id.name,
|
|
'credit': abs(amount),
|
|
'account_id': item.account_credit_id.id,
|
|
'partner_id': self.employee_id.user_id.partner_id.id})
|
|
else:
|
|
line_vals.append({
|
|
'name': item.salary_rule_id.name,
|
|
'debit': abs(amount),
|
|
'account_id': item.account_debit_id.id,
|
|
'partner_id': self.employee_id.user_id.partner_id.id})
|
|
|
|
for item in self.loans_ids:
|
|
line_vals.append({
|
|
'name': item.request_type.name,
|
|
'credit': abs(round(item.remaining_loan_amount,2)),
|
|
'account_id': item.request_type.account_id.id,
|
|
'partner_id': self.employee_id.user_id.partner_id.id})
|
|
|
|
line_vals.append({
|
|
'name': 'Total Net',
|
|
'credit': abs(round(self.net,2)),
|
|
'account_id': self.journal.default_account_id.id,
|
|
'partner_id': self.employee_id.user_id.partner_id.id})
|
|
|
|
move = self.env['account.move'].create({
|
|
'state': 'draft',
|
|
'journal_id': self.journal.id,
|
|
'date': date.today(),
|
|
'ref': 'Termination of "%s" ' % self.employee_id.name,
|
|
'line_ids': [(0, 0, value) for value in line_vals],
|
|
'res_model': 'hr.termination',
|
|
'res_id': self.id
|
|
})
|
|
|
|
for item in self.loans_ids:
|
|
for install in item.deduction_lines:
|
|
if not install.paid:
|
|
install.paid = True
|
|
install.termination_paid = True
|
|
item.state = 'closed'
|
|
self.write({'account_move_id': move.id})
|
|
|
|
# update employee last work date
|
|
if self.last_work_date:
|
|
self.employee_id.write({'leaving_date': self.last_work_date})
|
|
self.employee_id.sudo().contract_id.write({'date_end': self.last_work_date})
|
|
for item in self:
|
|
# Change employee state when termination to "Out Of Service"
|
|
# Change employee contract state to "End Contract"
|
|
if item.employee_id:
|
|
item.employee_id.sudo().contract_id.state = 'end_contract'
|
|
item.employee_id.state = 'out_of_service'
|
|
holiday_balance = self.env['hr.holidays'].search([('type', '=', 'add'),
|
|
('check_allocation_view', '=', 'balance'),
|
|
('holiday_status_id.leave_type', '=', 'annual'),
|
|
('employee_id', '=', self.employee_id.id)],
|
|
limit=1)
|
|
holiday_balance.remaining_leaves = 0
|
|
self.state = 'pay'
|
|
|
|
|
|
|
|
def refused(self):
|
|
self.state = 'refused'
|
|
|
|
#Refuse For The Direct Manager Only
|
|
def direct_manager_refused(self):
|
|
for rec in self:
|
|
manager = rec.sudo().employee_id.parent_id
|
|
hr_manager = rec.sudo().employee_id.user_id.company_id.hr_manager_id
|
|
if manager:
|
|
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
|
|
rec.refused()
|
|
else:
|
|
raise UserError(_("Sorry, The Refuse For The Direct Manager '%s' Only OR HR Manager!") % (manager.name))
|
|
else:
|
|
rec.refused()
|
|
|
|
#Refuse For The Department Manager Only
|
|
def dep_manager_refused(self):
|
|
for rec in self:
|
|
manager = rec.sudo().employee_id.coach_id
|
|
hr_manager = rec.sudo().employee_id.user_id.company_id.hr_manager_id
|
|
if manager:
|
|
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
|
|
rec.refused()
|
|
else:
|
|
raise UserError(_("Sorry, The Refuse For The Department Manager '%s' Only !")%(rec.employee_id.coach_id.name))
|
|
else:
|
|
rec.refused()
|
|
|
|
# check for employee unclosed leaves and check for clearance for employee constrain
|
|
|
|
@api.constrains('employee_id')
|
|
def leaves_clearance_constrains(self):
|
|
|
|
# check for employee unclosed leaves
|
|
employee_holidays = self.env['hr.holidays'].search(
|
|
[('employee_id', '=', self.employee_id.id), ('type', '=', 'remove'),
|
|
('state', 'not in', ['refuse', 'validate1', 'refused'])], limit=1)
|
|
if len(employee_holidays) > 0:
|
|
raise UserError(
|
|
_('Sorry ! This Employee have un approved or Reject Holiday Request : \n %s') % (
|
|
employee_holidays.holiday_status_id.name))
|
|
|
|
# check for clearance for employee
|
|
'''employee_clearance = self.env['hr.clearance.form'].search(
|
|
[('employee_id', '=', self.employee_id.id), ('state', 'not in', ['draft', 'refuse'])])
|
|
if len(employee_clearance) == 0 and self.cause_type.clearance == True:
|
|
raise UserError(
|
|
_('You can not create termination when missing clearance for "%s"') % self.employee_id.name)'''
|
|
|
|
# Override create function
|
|
|
|
@api.constrains('employee_id')
|
|
def net_constains(self):
|
|
if self.net < 0.0:
|
|
raise UserError(_('The Net must be not negative value .'))
|
|
|
|
|
|
class HrTerminationType(models.Model):
|
|
_name = 'hr.termination.type'
|
|
_description = 'HR Termination Type'
|
|
|
|
name = fields.Char(translate=True)
|
|
year = fields.Integer()
|
|
clearance = fields.Boolean()
|
|
factor = fields.Float()
|
|
holiday = fields.Boolean()
|
|
holiday_allowance = fields.Many2one('hr.salary.rule', domain=[('rules_type', '=', 'termination'),
|
|
('category_id.rule_type', '=', 'allowance')])
|
|
holiday_deduction = fields.Many2one('hr.salary.rule', domain=[('rules_type', '=', 'termination'),
|
|
('category_id.rule_type', '=', 'deduction')])
|
|
|
|
# Relational fields
|
|
allowance_ids = fields.Many2many('hr.salary.rule')
|
|
allowance_id = fields.Many2one('hr.salary.rule', domain=[('rules_type', '=', 'termination'),
|
|
('category_id.rule_type', '=', 'allowance')])
|
|
termination_duration_ids = fields.Many2many('hr.termination.duration')
|
|
|
|
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
|
|
|
|
def unlink(self):
|
|
for item in self:
|
|
i = self.env['hr.termination'].search([('cause_type', '=', item.id)])
|
|
if i:
|
|
raise UserError(
|
|
_('You can not delete record There is a related other record %s termination') % i.employee_id.id.name)
|
|
return super(HrTerminationType, self).unlink()
|
|
|
|
@api.constrains('holiday_allowance', 'allowance_id')
|
|
def _check_allowance_id(self):
|
|
for allowance in self:
|
|
if allowance.allowance_id.id == allowance.holiday_allowance.id:
|
|
raise ValidationError(
|
|
_('You cannot chosen The same allowance at the end of service and holiday allowance'))
|
|
|
|
|
|
class HrTerminationDuration(models.Model):
|
|
_name = 'hr.termination.duration'
|
|
_description = 'HR Termination Duration'
|
|
|
|
name = fields.Char(translate=True, required=True)
|
|
date_from = fields.Float()
|
|
date_to = fields.Float()
|
|
factor = fields.Float()
|
|
amount = fields.Float()
|
|
|
|
|
|
class HrAllowanceDeduction(models.Model):
|
|
_name = 'hr.allowance.deduction'
|
|
_description = 'HR Allowance Deduction'
|
|
|
|
name = fields.Char()
|
|
amount = fields.Float()
|
|
|
|
# relational fields
|
|
type = fields.Many2one('hr.salary.rule')
|
|
account_credit_id = fields.Many2one('account.account', related='type.rule_credit_account_id')
|
|
account_debit_id = fields.Many2one('account.account', related='type.rule_debit_account_id')
|
|
|
|
|
|
class HrSalaryRuleAndLoansLines(models.Model):
|
|
_name = 'hr.salary.rule.line'
|
|
_description = 'HR Salary Rule Line'
|
|
|
|
amount = fields.Float()
|
|
is_advantage = fields.Boolean()
|
|
|
|
# Relational fields
|
|
allowance_deduction_inverse_id = fields.Many2one('hr.termination') # Inverse
|
|
salary_rule_id = fields.Many2one('hr.salary.rule')
|
|
category_id = fields.Many2one('hr.salary.rule.category', related='salary_rule_id.category_id', readonly=True,
|
|
required=False)
|
|
account_credit_id = fields.Many2one('account.account', required=False,store=True)
|
|
account_debit_id = fields.Many2one('account.account', required=False,store=True)
|
|
|
|
'''def _get_accounts(self):
|
|
for rec in self:
|
|
emp_type = rec.allowance_deduction_inverse_id.employee_id.employee_type_id.id
|
|
rec.account_credit_id = rec.salary_rule_id.get_credit_account_id(emp_type)
|
|
rec.account_debit_id = rec.salary_rule_id.get_debit_account_id(emp_type)'''
|
|
|
|
#get acoount IDs base on salary rule config
|
|
def get_account_ids(self):
|
|
for rec in self:
|
|
emp_type = rec.allowance_deduction_inverse_id.employee_id.employee_type_id.id
|
|
if rec.category_id.rule_type=='allowance':
|
|
account_debit = rec.salary_rule_id.get_debit_account_id(emp_type)
|
|
rec.account_debit_id = account_debit
|
|
if rec.category_id.rule_type=='deduction':
|
|
account_credit = rec.salary_rule_id.get_credit_account_id(emp_type)
|
|
rec.account_credit_id = account_credit
|
|
|