Files
gzth/yuthon_contract/models/inherit_hr_contract.py
T
2026-01-14 20:07:53 +08:00

409 lines
15 KiB
Python

# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools
from odoo.exceptions import ValidationError, UserError
from dateutil.relativedelta import relativedelta
from datetime import date
from datetime import timedelta
class HrContract(models.Model):
_inherit = "hr.contract"
_description = "员工合同拓展"
code = fields.Char(
string="编号",
default=lambda self: self.env["ir.sequence"].next_by_code("contract_code"),
)
name = fields.Char(string="合同名称", compute="_compute_name", readonly=False)
is_annual_salary = fields.Boolean(string="是否年薪")
resource_calendar_id = fields.Many2one("resource.calendar", string="考勤时间表")
state = fields.Selection(
[
("draft", "草稿"),
("open", "运行中"),
("close", "完成"),
("cancel", "已中止"),
],
string="状态",
default="draft",
readonly=True,
copy=False,
)
date_of_entry = fields.Date(related="employee_id.entry_date", string="入职时间")
salary_group_id = fields.Many2one(
"yuthon.salary.group", string="工资单分组", store=True, index=True
)
is_internship = fields.Boolean(string="实习期", compute="_compute_name", store=True)
version = fields.Char(string="版本", default="V1.0")
date_end = fields.Date(string="合同结束时间")
termination_date = fields.Date(string="中止时间")
reason_suspension = fields.Selection(
[
("turnover", "离职"),
("died", "意外离世"),
("other", "异动"),
],
string="中止原因",
)
work_entry_source = fields.Selection(
[
("calendar", "考勤安排"),
("attendance", "Attendances"),
("planning", "特殊排版"),
]
)
is_probation = fields.Boolean(string="试用期")
start_date = fields.Date(
string="试用开始日期", required=True, default=fields.Date.today
)
end_date = fields.Date(
string="试用结束日期",
required=True,
default=lambda self: fields.Date.today()
+ relativedelta(months=+2)
- relativedelta(days=1),
)
salary_day = fields.Float(string="日薪")
party_id = fields.Many2one("yuthon.party.setting", string="甲方(用人单位)")
representatives = fields.Char(
related="party_id.representatives", string="法定代表人或委托代理人"
)
contract_type_id = fields.Many2one(
"hr.contract.type",
default=lambda self: self.env["hr.contract.type"]
.search([("name", "=", "正式合同(一签)")], limit=1)
.id
or False,
string="合同类型",
)
economy_type = fields.Char(related="party_id.economy_type", string="经济类型")
address = fields.Text(related="party_id.address", string="通讯地址")
contact = fields.Char(related="party_id.contact", string="联系人")
phone = fields.Char(related="party_id.phone", string="电话")
documents_ids = fields.Many2many("ir.attachment", string="合同附件")
current_contract = fields.Boolean(string="当前合同", default=True, compute="_compute_current_contract", store=True)
is_company = fields.Boolean(
string="本公司",
default=True,
compute="_compute_is_company",
search="_search_part_of_company",
)
def update_version(self):
contract_ids = self.env["hr.contract"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for contract in contract_ids:
contract.version = "V1.0"
def yuthon_employee_add(self):
contract_ids = self.env["hr.contract"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for record in contract_ids:
if len(record) > 1:
raise UserError("只能选择一个合同补充")
return {
'type': 'ir.actions.act_window',
'name': '员工补充协议',
'res_model': 'yuthon.employee.add',
'view_mode': 'form',
'target': 'current',
'context': {
'default_work_end': False,
'default_self_users_ids':[(6, 0, [self.employee_id.user_id.id])],
'default_contract_id': contract_ids.id,
'default_employee_id': contract_ids.employee_id.id
}}
@api.depends("date_start", "date_end")
def _compute_current_contract(self):
today = date.today()
for contract in self:
start_valid = contract.date_start and contract.date_start <= today
end_valid = not contract.date_end or contract.date_end >= today
contract.current_contract = start_valid and end_valid
@api.onchange("date_start")
def _onchange_date_end(self):
for record in self:
if record.date_start:
record.employee_id.entry_date = record.date_start
record.date_end = (
record.date_start + relativedelta(years=1) - relativedelta(days=1)
)
@api.onchange("contract_type_id")
def _onchange_contract_type_id(self):
for record in self:
if record.contract_type_id:
if record.contract_type_id.name == "正式合同(一签)":
record.date_end = (
record.date_start
+ relativedelta(years=1)
- relativedelta(days=1)
)
elif record.contract_type_id.name == "正式合同(二签)":
record.date_end = (
record.date_start
+ relativedelta(years=3)
- relativedelta(days=1)
)
@api.onchange("date_start")
def _onchange_date_start(self):
for record in self:
if record.date_start and record.state == "open" and record.employee_id:
record.employee_id.entry_date = record.date_start
def renew(self):
contract_ids = self.env["hr.contract"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for record in contract_ids:
if len(record) > 1:
raise UserError("只能选择一个合同续签")
return {
"name": "续签",
"type": "ir.actions.act_window",
"res_model": "yuthon.renewal.approval",
"view_mode": "form",
"context": {
"default_employee_id": self.employee_id.id,
"default_current_status": self.employee_id.contract_id.date_end,
"default_department1_id": self.employee_id.department_id.id,
"default_renewal_date": self.employee_id.contract_id.date_end + relativedelta(years=3),
"default_contract_id": self.id,
},
}
def pub_leaving_employee(self):
record_id = self.env["hr.contract"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
if len(record_id) != 1:
raise UserError("请选择一个合同")
form_id = self.env.ref(
"yuthon_hr_employee_approval.view_yuthon_leaving_approval_form"
).id
return {
"type": "ir.actions.act_window",
"name": "离职申请",
"res_model": "yuthon.leaving.approval",
"views": [[form_id, "form"]],
"context": {
"default_employee_id": self.employee_id.id,
},
}
def write(self, vals):
"""在写入时自动更新合同状态"""
today = fields.Date.today()
update_state = False
if "date_start" in vals:
update_state = True
if "date_end" in vals:
update_state = True
if "termination_date" in vals:
update_state = True
if update_state:
for contract in self:
# 获取最新的开始日期
start_date = fields.Date.to_date(
vals.get("date_start", contract.date_start)
)
# 获取最新的结束日期(空值视为无限大)
end_date = vals.get("date_end", contract.date_end)
end_date = fields.Date.to_date(end_date) if end_date else None
# 获取最新的中止时间(空值视为未中止)
termination_date = vals.get(
"termination_date", contract.termination_date
)
termination_date = (
fields.Date.to_date(termination_date) if termination_date else None
)
# 判断合同状态
if (
termination_date and termination_date < today
): # 新增:优先判断是否已中止
new_state = "cancel"
elif start_date > today:
new_state = "draft"
elif end_date and end_date < today:
new_state = "close"
else:
new_state = "open"
# 更新当前合同的状态
if "state" not in vals:
vals["state"] = new_state
return super(HrContract, self).write(vals)
def update_contract_states(self):
today = date.today()
active_contracts = self.search(
[
("state", "not in", ["cancel"]),
]
)
for contract in active_contracts:
new_state = (
"open"
if not contract.date_end or contract.date_end >= today
else "close"
)
if new_state == "open":
conflicting_contracts = self.search(
[
("id", "!=", contract.id),
("employee_id", "=", contract.employee_id.id),
("state", "=", "open"),
]
)
if conflicting_contracts:
continue
contract.state = new_state
@api.depends_context("uid", "company")
@api.depends("company_id")
def _compute_is_company(self):
active_company_ids = self.env.companies
for employee in self:
employee.is_company = employee.company_id in active_company_ids
def _search_part_of_company(self, operator, value):
if operator not in ("=", "!=") or not isinstance(value, bool):
raise UserError(("Operation not supported"))
company_ids = self.env.companies.ids # 获取公司ID列表
# 处理反向操作符
if not value:
operator = "!=" if operator == "=" else "="
# 使用company_id in company_ids的结构
if operator == "=":
return [("company_id", "in", company_ids)]
else: # operator == '!='
return [("company_id", "not in", company_ids)]
# @api.onchange('resource_calendar_id')
# def _onchange_resource_calendar_id(self):
# if self.resource_calendar_id:
# self.employee_id.sudo().write({'resource_calendar_id': self.resource_calendar_id.id})
@api.depends("contract_type_id")
def _compute_simplified_name(self):
for record in self:
if record.contract_type_id and record.employee_id:
record.name = record.contract_type_id.name + "合同"
else:
record.name = " "
if record.contract_type_id:
if record.contract_type_id.name == "实习协议":
record.is_internship = True
else:
record.is_internship = False
@api.depends("contract_type_id")
def _compute_name(self):
for record in self:
if record.contract_type_id and record.employee_id:
record.name = (
record.employee_id.name + record.contract_type_id.name + "合同"
)
else:
record.name = " "
if record.contract_type_id:
if record.contract_type_id.name == "实习协议":
record.is_internship = True
else:
record.is_internship = False
def action_hr_contract(self):
return {
"type": "ir.actions.act_window",
"name": "批量导入合同",
"res_model": "yuthon.contract.wizard",
"view_mode": "form",
"target": "new",
}
def update_contract(self):
contract_ids = self.env["hr.contract"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for contract in contract_ids:
company_id = contract.employee_id.company_id
resource_calendar_id = self.env["resource.calendar"].search(
[("company_id", "=", company_id.id)], limit=1
)
contract.resource_calendar_id = resource_calendar_id.id
@api.onchange("salary_group_id")
def _compute_salary_group_id(self):
for contract_id in self:
employee = self.env["hr.employee"].search(
[("id", "=", contract_id.employee_id.id)], limit=1
)
if employee:
employee.salary_group_id = contract_id.salary_group_id.id
else:
employee.salary_group_id = False
@api.onchange("is_annual_salary")
def _compute_is_annual_salary(self):
for contract_id in self:
employee = self.env["hr.employee"].search(
[("id", "=", contract_id.employee_id.id)], limit=1
)
if employee:
employee.is_annual_salary = contract_id.is_annual_salary
else:
employee.is_annual_salary = False
@api.model_create_multi
def create(self, vals_list):
today = fields.Date.today()
# 先处理状态
for vals in vals_list:
start_date = (
fields.Date.to_date(vals.get("date_start"))
if vals.get("date_start")
else None
)
end_date = (
fields.Date.to_date(vals.get("date_end"))
if vals.get("date_end")
else None
)
termination_date = (
fields.Date.to_date(vals.get("termination_date"))
if vals.get("termination_date")
else None
)
if termination_date and termination_date < today:
vals["state"] = "cancel"
elif start_date and start_date > today:
vals["state"] = "draft"
elif end_date and end_date < today:
vals["state"] = "close"
else:
vals["state"] = "open"
# 创建合同
contracts = super().create(vals_list)
# 更新员工合同字段
for contract in contracts:
if contract.employee_id:
contract.employee_id.write({"contract_id": contract.id,
'is_accum_salary': True,
'is_membership': True,
})
return contracts