309 lines
14 KiB
Python
309 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError, ValidationError
|
|
from datetime import datetime
|
|
|
|
|
|
class YuthonMedicalManage(models.Model):
|
|
_name = 'yuthon.medical.manage'
|
|
_description = '体检费管理'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string="员工姓名")
|
|
employee_number = fields.Char( string='序号', related='employee_id.number', store=True, readonly=True)
|
|
start_date = fields.Date(string='开始日期')
|
|
year = fields.Char(string="年份")
|
|
current_year_remaining = fields.Float(string="本年剩余", compute="_compute_current_year_remaining")
|
|
entry_date = fields.Date(related='employee_id.entry_date', string="入职日期", store=True)
|
|
remainder_the_year = fields.Float(string="本年剩余")
|
|
last_year_quota = fields.Float(string="去年额度")
|
|
last_year_used = fields.Float(string="去年使用", compute="_compute_last_year_used")
|
|
last_year_remaining = fields.Float(string="去年剩余")
|
|
prev_last_year_remaining = fields.Float(string="前年剩余")
|
|
this_year_usage = fields.Float(string='本年使用', compute="_compute_this_year_usage")
|
|
this_year_quota = fields.Float(string='本年额度')
|
|
birthday = fields.Date(related='employee_id.birthday', string="出生年月")
|
|
marital_status = fields.Selection([('married', '已婚'), ('unmarried', '未婚')],
|
|
related='employee_id.marital', string='婚姻状况')
|
|
termination_date = fields.Date(string="离退日期", compute="_compute_termination_date")
|
|
company_id = fields.Many2one(related="employee_id.company_id", string="公司", default=lambda self: self.env.company)
|
|
|
|
@api.depends('employee_id')
|
|
def _compute_termination_date(self):
|
|
for record in self:
|
|
record.termination_date = record.employee_id.contract_id.termination_date
|
|
|
|
@api.depends('this_year_quota', 'this_year_usage', 'last_year_remaining')
|
|
def _compute_current_year_remaining(self):
|
|
for record in self:
|
|
record.current_year_remaining = record.this_year_quota + record.last_year_remaining - record.this_year_usage
|
|
if record.current_year_remaining != record.remainder_the_year:
|
|
record.remainder_the_year = record.current_year_remaining
|
|
|
|
def update_remainder_the_year(self):
|
|
soong_ids = self.env["yuthon.medical.manage"].browse(
|
|
self._context.get('active_ids', self._context.get('active_id')))
|
|
for soong_id in soong_ids:
|
|
soong_id.remainder_the_year = soong_id.this_year_quota + soong_id.last_year_remaining - soong_id.this_year_usage
|
|
if soong_id.year:
|
|
soong_id.start_date = f"{soong_id.year}-01-01"
|
|
|
|
@api.depends('employee_id', 'year')
|
|
def _compute_last_year_used(self):
|
|
if not self:
|
|
return
|
|
for record in self:
|
|
line_domain = ([
|
|
('employee_id', '=', record.employee_id.id),
|
|
('enable', '=', True),
|
|
('medical_date', '>=', f"{str(int(record.year)-1)}-01-01"),
|
|
('medical_date', '<=', f"{str(int(record.year)-1)}-12-31")
|
|
])
|
|
all_lines = self.env['yuthon.medical.line'].search(line_domain)
|
|
record.last_year_used = sum(all_lines.mapped('medical_fee'))
|
|
|
|
@api.depends('employee_id', 'year')
|
|
def _compute_this_year_usage(self):
|
|
if not self:
|
|
return
|
|
for record in self:
|
|
line_domain = ([
|
|
('employee_id', '=', record.employee_id.id),
|
|
('enable', '=', True),
|
|
('medical_date', '>=', f"{record.year}-01-01"),
|
|
('medical_date', '<=', f"{record.year}-12-31")
|
|
])
|
|
all_lines = self.env['yuthon.medical.line'].search(line_domain)
|
|
record.this_year_usage = sum(all_lines.mapped('medical_fee'))
|
|
|
|
def _calculate_medical_quota(self, employee, year):
|
|
current_date = fields.Date.today()
|
|
valid_rules = self.env['yuthon.medical.rule'].search([
|
|
('start_date', '<=', current_date),
|
|
'|', ('end_date', '>=', current_date), ('end_date', '=', False)
|
|
], order='start_date desc', limit=1)
|
|
rule = valid_rules
|
|
|
|
id_card = employee.identification_id.strip() if employee.identification_id else ''
|
|
birth_str = id_card[6:14]
|
|
birth_date = datetime.strptime(birth_str, '%Y%m%d').date()
|
|
|
|
# 计算周岁(今天 - 出生日期)
|
|
today = fields.Date.today()
|
|
age = 0
|
|
if birth_date:
|
|
age = today.year - birth_date.year
|
|
base_quota = rule.base_amount
|
|
if age >= rule.starting_age and rule.increase_interval_years > 0 and rule.increment_amount > 0:
|
|
exceed_age_years = age - rule.starting_age
|
|
increment_times = exceed_age_years // rule.increase_interval_years
|
|
base_quota += rule.increment_amount * increment_times
|
|
|
|
if rule.cap > 0:
|
|
base_quota = min(base_quota, rule.cap)
|
|
|
|
# 女性婚姻状态补助
|
|
final_quota = base_quota
|
|
if employee.user_sex == 'girl':
|
|
if employee.marital == 'single':
|
|
final_quota += rule.allowance_unmarried_women
|
|
elif employee.marital in ['married', 'divorced']:
|
|
final_quota += rule.allowance_married_women
|
|
|
|
entry_date = fields.Date.from_string(employee.entry_date)
|
|
if not entry_date:
|
|
return final_quota
|
|
|
|
entry_year = entry_date.year
|
|
# 判断是否为当年入职
|
|
if entry_year == int(year):
|
|
entry_month = entry_date.month
|
|
ratio = (12 - entry_month + 1) / 12
|
|
final_quota = final_quota * ratio
|
|
final_quota = round(max(final_quota, 0.0), 2)
|
|
|
|
return final_quota
|
|
|
|
def medical_manage(self):
|
|
current_date = fields.Date.today()
|
|
current_year = str(current_date.year)
|
|
last_year = str(int(current_year) - 1)
|
|
valid_rules = self.env['yuthon.medical.rule'].search([
|
|
('start_date', '<=', current_date),
|
|
'|', ('end_date', '>=', current_date), ('end_date', '=', False)
|
|
], order='start_date desc', limit=1)
|
|
rule = valid_rules
|
|
target_companies = rule.party_ids.mapped('party')
|
|
party_setting_records = self.env['yuthon.party.setting'].search([
|
|
('party', 'in', target_companies)
|
|
]).ids
|
|
open_employees = self.env['hr.employee'].search([
|
|
('user_state', '=', 'in'),
|
|
('company_id.name', '=', '集团本部'),
|
|
('contract_id.party_id', 'in', party_setting_records),
|
|
('contract_type_id.name', '!=', '实习协议')
|
|
])
|
|
for employee in open_employees:
|
|
medical_manage_rec = self.env['yuthon.medical.manage'].search([
|
|
('employee_id', '=', employee.id),
|
|
('year', '=', current_year)
|
|
], limit=1)
|
|
if not medical_manage_rec:
|
|
medical_manage_rec = self.env['yuthon.medical.manage'].create({
|
|
'employee_id': employee.id,
|
|
'year': current_year,
|
|
'this_year_usage': 0.0,
|
|
})
|
|
else:
|
|
continue
|
|
|
|
this_year_quota = self._calculate_medical_quota(employee, current_year)
|
|
if not this_year_quota:
|
|
medical_manage_rec.unlink()
|
|
continue
|
|
medical_manage_rec.write({'this_year_quota': this_year_quota,
|
|
})
|
|
medical_manage_rec.remainder_the_year = medical_manage_rec.this_year_quota + medical_manage_rec.last_year_remaining - medical_manage_rec.this_year_usage
|
|
medical_manage_rec.start_date = current_date
|
|
|
|
# 回填上年数据
|
|
last_year_rec = self.env['yuthon.medical.manage'].search([
|
|
('employee_id', '=', employee.id),
|
|
('year', '=', last_year)
|
|
], limit=1)
|
|
if last_year_rec:
|
|
medical_manage_rec.write({
|
|
'last_year_quota': last_year_rec.this_year_quota,
|
|
'last_year_remaining': min(last_year_rec.this_year_quota * 2, last_year_rec.current_year_remaining),
|
|
})
|
|
|
|
# 回填前年数据
|
|
prev_last_year_vals = {
|
|
'prev_last_year_remaining': min(last_year_rec.this_year_quota * 2, last_year_rec.current_year_remaining),
|
|
}
|
|
medical_manage_rec.write(prev_last_year_vals)
|
|
|
|
def compute_medical_manage(self):
|
|
medical_records = self.env['yuthon.medical.manage'].browse(self.env.context.get('active_ids'))
|
|
for medical_record in medical_records:
|
|
current_year = str(medical_record.year)
|
|
last_year = str(int(current_year) - 1)
|
|
for employee in medical_record.employee_id:
|
|
this_year_quota = self._calculate_medical_quota(employee, current_year)
|
|
medical_record.write({'this_year_quota': this_year_quota,
|
|
})
|
|
medical_record.remainder_the_year = medical_record.this_year_quota + medical_record.last_year_remaining - medical_record.this_year_usage
|
|
# 回填上年数据
|
|
last_year_rec = self.env['yuthon.medical.manage'].search([
|
|
('employee_id', '=', employee.id),
|
|
('year', '=', last_year)
|
|
], limit=1)
|
|
if last_year_rec:
|
|
medical_record.write({
|
|
'last_year_quota': last_year_rec.this_year_quota,
|
|
'last_year_remaining': min(last_year_rec.this_year_quota * 2, last_year_rec.current_year_remaining),
|
|
})
|
|
# 回填前年数据
|
|
prev_last_year_vals = {
|
|
'prev_last_year_remaining': min(last_year_rec.last_year_quota * 2, last_year_rec.last_year_remaining),
|
|
}
|
|
medical_record.write(prev_last_year_vals)
|
|
|
|
|
|
|
|
def button_details(self):
|
|
tree_id = self.env.ref('yuthon_hr_employee.yuthon_medical_line_tree').id
|
|
return {
|
|
"type": "ir.actions.act_window",
|
|
"name": "查看详情",
|
|
"res_model": "yuthon.medical.line",
|
|
"views": [[tree_id, "tree"]],
|
|
"domain": [('employee_id', '=', self.employee_id.id)],
|
|
}
|
|
|
|
def property_reimbursement_form(self):
|
|
form_id = self.env.ref('yuthon_hr_employee_approval.view_property_reimbursement_form_form').id
|
|
return {
|
|
"type": "ir.actions.act_window",
|
|
"name": "报销单",
|
|
"res_model": "property.reimbursement.form",
|
|
"views": [[form_id, "form"]],
|
|
}
|
|
|
|
def medical_manage_wizard(self):
|
|
return {
|
|
'name': '体检费导入',
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'medical.manage.wizard',
|
|
'view_mode': 'form',
|
|
'target': 'new',
|
|
}
|
|
|
|
def update_initial_value(self):
|
|
medical_ids = self.env["yuthon.medical.manage"].browse(
|
|
self._context.get('active_ids', self._context.get('active_id')))
|
|
for rec in medical_ids:
|
|
current_year = str(rec.year)
|
|
last_year = str(int(current_year) - 1)
|
|
prev_last_year = str(int(current_year) - 2)
|
|
last_year_quota = self._calculate_medical_quota(rec.employee_id, last_year)
|
|
this_year_quota = self._calculate_medical_quota(rec.employee_id, current_year)
|
|
prev_last_year_quota = self._calculate_medical_quota(rec.employee_id, prev_last_year)
|
|
prev_last_year_remaining = min(prev_last_year_quota * 2, rec.prev_last_year_remaining)
|
|
last_year_remaining = min(last_year_quota * 2, rec.last_year_remaining)
|
|
rec.write({
|
|
'this_year_quota': this_year_quota,
|
|
'last_year_quota': last_year_quota,
|
|
'prev_last_year_remaining': prev_last_year_remaining,
|
|
'last_year_remaining': last_year_remaining,
|
|
})
|
|
|
|
class YuthonMedicalLine(models.Model):
|
|
_name = 'yuthon.medical.line'
|
|
_description = '体检费明细'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string="姓名")
|
|
medical_date = fields.Date(string="报销日期")
|
|
medical_fee = fields.Float(string="金额")
|
|
enable = fields.Boolean(string="启用", default=True)
|
|
remake = fields.Text(string="备注")
|
|
document_ids = fields.Many2many('ir.attachment', string="附件")
|
|
|
|
@api.constrains('employee_id', 'medical_date')
|
|
def _check_duplicate_medical_line(self):
|
|
for rec in self:
|
|
domain = [
|
|
('employee_id', '=', rec.employee_id.id),
|
|
('medical_date', '=', rec.medical_date),
|
|
('id', '!=', rec.id)
|
|
]
|
|
duplicate_rec = self.search(domain, limit=1)
|
|
if duplicate_rec:
|
|
if not self.env.context.get('confirm_update_medical_line'):
|
|
raise UserError(_(
|
|
f"检测到员工【{rec.employee_id.name}】在【{rec.medical_date}】已有体检费记录,请重新选择日期"
|
|
|
|
))
|
|
|
|
def write(self, vals):
|
|
res = super(YuthonMedicalLine, self).write(vals)
|
|
if 'medical_fee' in vals or 'medical_date' in vals or 'employee_id' in vals:
|
|
for line in self:
|
|
current_year = fields.Date.from_string(line.medical_date).year
|
|
employee = line.employee_id
|
|
current_manage = self.env['yuthon.medical.manage'].search([
|
|
('employee_id', '=', employee.id),
|
|
('year', '=', str(current_year))
|
|
], limit=1)
|
|
if current_manage:
|
|
current_manage._compute_this_year_usage()
|
|
current_manage._compute_current_year_remaining()
|
|
|
|
next_manage = self.env['yuthon.medical.manage'].search([
|
|
('employee_id', '=', employee.id),
|
|
('year', '=', str(current_year + 1))
|
|
], limit=1)
|
|
if next_manage:
|
|
next_manage.last_year_remaining = current_manage.current_year_remaining
|
|
|
|
return res
|