添加功能

This commit is contained in:
zhou
2025-07-24 20:37:19 +08:00
parent 37e2e46836
commit 6eb570456f
9 changed files with 221 additions and 6 deletions
+1 -1
View File
@@ -157,7 +157,7 @@ class YuthonProperty(models.Model):
'admin_id': latest_info.admin_id,
'company_id': latest_info.company_id,
})
contract_line_ids = self.env['property.lease.contract.line'].search([('address_id', '=', rec.id)])
contract_line_ids = self.env['property.lease.contract.line'].search([('address_id', F'=', rec.id)])
for contract_line_id in contract_line_ids:
contract_line_id.admin_line_id = latest_info.admin_id
+1
View File
@@ -29,6 +29,7 @@
'views/yuthon_welfare_expenses_views.xml',
'views/yuthon_payroll_retired_views.xml',
'views/yuthon_salary_year_views.xml',
'wizard/rank_log_wizard_views.xml',
'wizard/yuthon_salary_wizard_views.xml',
'wizard/temporary_payslip_wizard_views.xml',
'wizard/yuthon_payroll_wizard_views.xml',
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<record forcecreate="True" id="update_rank_log_time" model="ir.cron">
<field name="name">定时任务:更新职级日志</field>
<field name="model_id" ref="model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">model.rank_log_time()</field>
<field eval="True" name="active"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">months</field>
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 00:00:00')"/>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
</record>
</data>
</odoo>
@@ -1,6 +1,8 @@
from odoo import api, fields, models, _
import re
from pypinyin import pinyin, Style
from datetime import date
class HrPayrollStructure(models.Model):
@@ -25,6 +27,7 @@ class HrPayrollStructure(models.Model):
position_subsidy = fields.Monetary(string="岗位补贴", currency_field="currency_id")
integrated_subsidy = fields.Monetary(string="综合补贴", currency_field="currency_id")
advance_performance_bonuses = fields.Monetary(string="预发绩效奖金", currency_field="currency_id")
renk_log_ids = fields.One2many("rank.log.line", "structure_id", string="职级日志明细行")
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
@@ -105,6 +108,19 @@ class HrPayrollStructure(models.Model):
"view_mode": "form",
}
def write(self, vals):
result = super(HrPayrollStructure, self).write(vals)
field_mapping = {
'base_salary': '基本工资',
'rank_salary': '职级工资',
'communication_subsidy': '通讯补贴',
'position_salary': '岗位工资'
}
for field, name in field_mapping.items():
if field in vals:
self._handle_salary_rule(name, self[field])
return result
def action_yuthon_payroll_wizard(self):
return {
"type": "ir.actions.act_window",
@@ -184,3 +200,72 @@ class HrPayrollStructure(models.Model):
for rule in payroll.rule_ids:
if rule.name == '工会会费':
rule.write({'category_id': category_id.id})
def rank_log_wizard(self):
return {
"type": "ir.actions.act_window",
"name": "职级日志",
"res_model": "rank.log.wizard",
"view_mode": "form",
"target": "new",
}
def update_rank(self):
payroll_ids = self.env["hr.payroll.structure"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for payroll in payroll_ids:
log_data = {
'structure_id': payroll.id,
'base_salary': payroll.base_salary,
'rank_salary': payroll.rank_salary,
'communication_subsidy': payroll.communication_subsidy,
'position_salary': payroll.position_salary,
'advance_performance_bonuses': payroll.advance_performance_bonuses,
'effective_date': payroll.create_time,
'lapse_date': payroll.end_time,
'is_enable': payroll.is_enable
}
self.env['rank.log.line'].create(log_data)
def empty_the_log(self):
payroll_ids = self.env["hr.payroll.structure"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for payroll in payroll_ids:
payroll.renk_log_ids.unlink()
def rank_log_time(self):
"""定时任务:根据日志记录的生效时间更新主模型字段值"""
today = date.today()
for structure in self.search([]):
# 获取该职级下所有有效的日志记录
valid_logs = structure.renk_log_ids.filtered(
lambda log: log.is_enable and
log.effective_date and
log.effective_date <= today and
(not log.lapse_date or log.lapse_date >= today)
).sorted(key=lambda l: l.effective_date, reverse=True)
if valid_logs:
latest_log = valid_logs[0]
structure.write({
'base_salary': latest_log.base_salary,
'rank_salary': latest_log.rank_salary,
'communication_subsidy': latest_log.communication_subsidy,
'position_salary': latest_log.position_salary,
'advance_performance_bonuses': latest_log.advance_performance_bonuses,
})
class RankLogLine(models.Model):
_name = 'rank.log.line'
_description = '职级日志'
structure_id = fields.Many2one('hr.payroll.structure', string='关联职级')
base_salary = fields.Float(string="基本工资")
rank_salary = fields.Float(string="职级工资")
communication_subsidy = fields.Float(string="通讯补贴")
position_salary = fields.Float(string="岗位工资")
advance_performance_bonuses = fields.Float(string="预发绩效奖金")
effective_date = fields.Date(string="生效日期")
lapse_date = fields.Date(string="失效日期")
is_enable = fields.Boolean(string="启用")
+3 -1
View File
@@ -31,4 +31,6 @@ access_yuthon_salary_project, access_yuthon_salary_project,model_yuthon_salary_p
access_yuthon_salary_asset, access_yuthon_salary_asset,model_yuthon_salary_asset,base.group_user,1,1,1,1
access_salary_payroll_distribution,access_salary_payroll_distribution,model_salary_payroll_distribution,base.group_user,1,1,1,1
access_yuthon_welfare_expenses,access_yuthon_welfare_expenses,model_yuthon_welfare_expenses,base.group_user,1,1,1,1
access_initialize_payroll_wizard,access_initialize_payroll_wizard,model_initialize_payroll_wizard,base.group_user,1,1,1,1
access_initialize_payroll_wizard,access_initialize_payroll_wizard,model_initialize_payroll_wizard,base.group_user,1,1,1,1
access_rank_log_line,access_rank_log_line,model_rank_log_line,base.group_user,1,1,1,1
access_rank_log_wizard,access_rank_log_wizard,model_rank_log_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
31 access_initialize_payroll_wizard access_initialize_payroll_wizard model_initialize_payroll_wizard base.group_user 1 1 1 1
32 access_rank_log_line access_rank_log_line model_rank_log_line base.group_user 1 1 1 1
33 access_rank_log_wizard access_rank_log_wizard model_rank_log_wizard base.group_user 1 1 1 1
34
35
36
@@ -76,6 +76,22 @@
<xpath expr="//field[@name='partner_id']" position="after">
<field name="company_id"/>
</xpath>
<xpath expr="//page[@name='other_input']" position="after">
<page string="职级日志">
<field name="renk_log_ids">
<tree editable="bottom">
<field name="base_salary"/>
<field name="rank_salary"/>
<field name="communication_subsidy"/>
<field name="position_salary"/>
<field name="advance_performance_bonuses"/>
<field name="effective_date"/>
<field name="lapse_date"/>
<field name="is_enable" optional="hide"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
<record id="hr_payroll_structure_search" model="ir.ui.view">
@@ -125,6 +141,13 @@
<field name="binding_model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">action = model.action_select_delete_wizard()</field>
</record>
<record id="all_rank_log_wizard" model="ir.actions.server">
<field name="name">职级日志导入</field>
<field name="model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">action = model.rank_log_wizard()</field>
</record>
<record id="select_delete_structure" model="ir.actions.server">
<field name="name">删除工资项</field>
@@ -133,11 +156,18 @@
<field name="state">code</field>
<field name="code">action = model.delete_structure()</field>
</record>
<record id="select_update_lc" model="ir.actions.server">
<field name="name">一次性</field>
<record id="select_update_rank_log" model="ir.actions.server">
<field name="name">更新日志</field>
<field name="model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">action = model.update_payroll_items()</field>
<field name="code">action = model.update_rank()</field>
</record>
<record id="select_empty_the_log" model="ir.actions.server">
<field name="name">清空职级日志</field>
<field name="model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">action = model.empty_the_log()</field>
</record>
</odoo>
+2 -1
View File
@@ -10,4 +10,5 @@ from . import payroll_retired_wizard
from . import salary_print_wizard
from . import salary_year_wizard
from . import payslip_send_wizard
from . import initialize_payroll_wizard
from . import initialize_payroll_wizard
from . import rank_log_wizard
+44
View File
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
class RankLogWizard(models.Model):
_name = 'rank.log.wizard'
_description = '职级日志导入弹窗'
excel_file = fields.Binary(string="上传Excel表")
excel_name = fields.Char(string="文件名")
def confirm(self):
if not self.excel_file:
raise ValidationError('请上传文件。')
book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file))
sh = book.sheet_by_index(0)
for rx in range(1, sh.nrows):
row = sh.row(rx)
self.payroll_rank_log(row)
def payroll_rank_log(self, row):
structure_id = self.env['hr.payroll.structure'].search([('name', '=', row[1].value)])
base_salary = row[2].value
rank_salary = row[3].value
advance_performance_bonuses = row[4].value
communication_subsidy = row[5].value
position_salary = row[6].value
log_data = {
'structure_id': structure_id.id,
'base_salary': float(base_salary) if base_salary else 0.0,
'rank_salary': float(rank_salary) if rank_salary else 0.0,
'advance_performance_bonuses': float(advance_performance_bonuses) if advance_performance_bonuses else 0.0,
'communication_subsidy': float(communication_subsidy) if communication_subsidy else 0.0,
'position_salary': float(position_salary) if position_salary else 0.0,
'effective_date': fields.Date.today(),
'is_enable': True
}
self.env['rank.log.line'].create(log_data)
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="labor_template_downloads_rank_log_action" model="ir.actions.act_url">
<field name="name">职级日志模板</field>
<field name="target">self</field>
<field name="url">.</field>
</record>
<record id="rank_log_wizard_form" model="ir.ui.view">
<field name="name">审批意见弹窗</field>
<field name="model">rank.log.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<header>
<button name="%(labor_template_downloads_tian_he_action)d" string="模板下载" type="action"
class="btn btn-primary"/>
</header>
<group>
<group>
<field name="excel_file" filename="excel_name"/>
<field name="excel_name" invisible="1"/>
</group>
<group>
</group>
</group>
</sheet>
<footer>
<button name="confirm" string="确认" type="object" class="oe_highlight"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>