Merge pull request !3117 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2025-06-05 13:09:39 +00:00
committed by Gitee
12 changed files with 206 additions and 83 deletions
@@ -98,6 +98,8 @@ class VacationOverline(models.Model):
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
update_date = fields.Date(string='更新时间')
update_lines = fields.Text(string='更新额度')
text = fields.Text(string='备注')
class VacationMealLine(models.Model):
@@ -108,6 +110,7 @@ class VacationMealLine(models.Model):
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
update_date = fields.Date(string='更新时间')
update_lines = fields.Text(string='更新额度')
text = fields.Text(string='备注')
class DetailsTree(models.Model):
@@ -40,6 +40,7 @@
<field name="update_type"/>
<field name="update_date"/>
<field name="update_lines"/>
<field name="text"/>
</tree>
</field>
</page>
@@ -50,6 +51,7 @@
<field name="update_type"/>
<field name="update_date"/>
<field name="update_lines"/>
<field name="text"/>
</tree>
</field>
</page>
+1
View File
@@ -34,6 +34,7 @@
'wizard/yuthon_payroll_wizard_views.xml',
'wizard/payroll_labor_wizard_views.xml',
'wizard/payroll_retired_wizard_views.xml',
'wizard/payslip_send_wizard_views.xml',
'wizard/salary_year_wizard.xml',
'wizard/salary_compute_wizard_views.xml',
'wizard/salary_payslip_wizard_views.xml',
+27 -1
View File
@@ -101,6 +101,7 @@ class InheritHrPayslip(models.Model):
cumulative_deductions = fields.Float(string='累计减免税额')
amount_tax_withheld = fields.Float(string='累计应扣缴税额')
is_bold = fields.Boolean()
confirm_status = fields.Selection([('confirm', '已确认'), ('un_confirm', '未确认')], string='确认状态', default='un_confirm')
remake = fields.Text(string='备注')
# 物管常用项
@@ -237,6 +238,18 @@ class InheritHrPayslip(models.Model):
}
}
def payslip_wizard(self):
return {
"type": "ir.actions.act_window",
"name": "工资条推送",
"res_model": "payslip.send.wizard",
"view_mode": "form",
"target": "new",
"context": {
'default_employee_id': self.id.employee_id.id
}
}
def action_salary_payslip_wizard(self):
return {
"type": "ir.actions.act_window",
@@ -415,4 +428,17 @@ class InheritHrPayslip(models.Model):
for record in payslip_ids:
record.write({
'salary_group_id': record.employee_id.contract_id.salary_group_id.id,
})
})
@api.model
def get_view(self, view_id=None, view_type='form', **options):
# 检查是否通过特定动作触发
if options.get('action_id') == 3666:
# 获取当前用户相关的未确认工资单
domain = [
('employee_id.user_id', '=', self.env.uid),
]
unconfirmed_slips = self.search(domain)
if unconfirmed_slips:
unconfirmed_slips.write({'confirm_status': 'confirm'})
return super().get_view(view_id, view_type, **options)
+23 -5
View File
@@ -11,6 +11,7 @@ class InheritHrPayslipRun(models.Model):
document_ids = fields.Many2many('ir.attachment', string="签名扫描件")
run_stage = fields.Selection([('payroll_calculations', '薪资计算'), ('individual_tax', '个税计算'), ('finalized', '待审定'),
('to_be_signed', '待签名'), ('to_be_issued', '待发放'), ('issued', '已发放')], default='payroll_calculations',
store=True,
string="阶段")
def Fileline(self):
@@ -21,6 +22,7 @@ class InheritHrPayslipRun(models.Model):
'res_model': 'hr.payslip',
"view_mode": "tree",
"domain": domain,
"context": "{'tree_view_ref': 'yuthon_salary.my_hr_payslip_view_tree'}"
}
@api.onchange('document_ids')
@@ -29,11 +31,6 @@ class InheritHrPayslipRun(models.Model):
if rec.document_ids:
rec.run_stage = 'to_be_issued'
def add_comment(self):
for rec in self:
rec.run_stage = 'issued'
def open_payslip(self):
return {
"name": "详情",
@@ -43,5 +40,26 @@ class InheritHrPayslipRun(models.Model):
"res_id": self.id,
}
def payslip_wizard(self):
employee_list = []
run_payslips = self.env["hr.payslip"].search([
('payslip_run_id', '=', self.id)
])
for slip in run_payslips:
employee_list.append(slip.employee_id.id)
return {
"type": "ir.actions.act_window",
"name": "工资条推送",
"res_model": "payslip.send.wizard",
"view_mode": "form",
"target": "new",
"context": {
'default_employee_ids': employee_list,
'default_payslip_run_id': self.id
}
}
@@ -9,6 +9,7 @@ access_salary_compute_wizard,access_salary_compute_wizard,model_salary_compute_w
access_yuthon_account_group,access_yuthon_account_group,model_yuthon_account_group,base.group_user,1,1,1,1
access_salary_payslip_wizard,access_salary_payslip_wizard,model_salary_payslip_wizard,base.group_user,1,1,1,1
access_select_delete_wizard,access_select_delete_wizard,model_select_delete_wizard,base.group_user,1,1,1,1
access_payslip_send_wizard, access_payslip_send_wizard,model_payslip_send_wizard,base.group_user,1,1,1,1
access_yuthon_salary_year,access_yuthon_salary_year,model_yuthon_salary_year,base.group_user,1,1,1,1
access_yuthon_personal_rule,access_yuthon_personal_rule,model_yuthon_personal_rule,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
9 access_yuthon_account_group access_yuthon_account_group model_yuthon_account_group base.group_user 1 1 1 1
10 access_salary_payslip_wizard access_salary_payslip_wizard model_salary_payslip_wizard base.group_user 1 1 1 1
11 access_select_delete_wizard access_select_delete_wizard model_select_delete_wizard base.group_user 1 1 1 1
12 access_payslip_send_wizard access_payslip_send_wizard model_payslip_send_wizard base.group_user 1 1 1 1
13 access_yuthon_salary_year access_yuthon_salary_year model_yuthon_salary_year base.group_user 1 1 1 1
14 access_yuthon_personal_rule access_yuthon_personal_rule model_yuthon_personal_rule base.group_user 1 1 1 1
15 access_put_wizard access_put_wizard model_put_wizard base.group_user 1 1 1 1
@@ -15,7 +15,7 @@
<field name="document_ids" widget="preview_many2many"/>
<field name="run_stage" readonly="1"/>
<button type="object" name="Fileline" string="归档明细" class="oe_highlight"/>
<button type="object" name="add_comment" string="完成" class="oe_highlight" invisible="run_stage == 'issued'" groups="yuthon_salary.salary_rule_confirm_group"/>
<button type="object" name="payslip_wizard" string="发放工资条" class="oe_highlight" invisible="run_stage == 'issued'" groups="yuthon_salary.salary_rule_confirm_group"/>
<button type="object" name="open_payslip" string="详情" class="oe_highlight"/>
</xpath>
</field>
@@ -108,79 +108,6 @@
</xpath>
</field>
</record>
<!--薪资归档-->
<record id="view_hr_payslip_tree3" model="ir.ui.view">
<field name="name">hr.payslip.tree</field>
<field name="model">hr.payslip</field>
<field name="arch" type="xml">
<tree string="薪资归档" default_order="employee_id" limit="20">
<field name="employee_id" string="姓名" options="{'no_open': True}"/>
<field name="date_of_entry" optional="show"/>
<field name="company_id" string="公司" optional="hide"/>
<field name="struct_id" string="职级" optional="show"/>
<field name="bank_account_id" optional="show"/>
<field name="actual_salary" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="total_before_tax" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="b_year" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="three_one" optional="show"/>
<field name="tax_payable" decoration-danger="1" decoration-bf="1" readonly="1" optional="show"/>
<field name="union_dues" decoration-danger="1" decoration-bf="1" optional="show" groups="yuthon_salary.group_jtbb_user"/>
<field name="base_salary" required="1" optional="show"/>
<field name="rank_salary" required="1" optional="show"/>
<field name="performance_bonuses" required="1" optional="show"/>
<field name="seniority_allowance" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="safety_subsidy" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="job_performance" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="excellent_employees" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="duty" decoration-success="1" groups="yuthon_salary.group_wg_user, yuthon_salary.group_lc_user" optional="show"/>
<field name="annuity" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="position_subsidy" decoration-success="1" groups="yuthon_salary.group_wg_user" optional="show"/>
<field name="environmental_allowance" decoration-success="1" groups="yuthon_salary.group_lc_user" optional="show"/>
<field name="quality_allowance" decoration-success="1" groups="yuthon_salary.group_lc_user" optional="show"/>
<field name="post_salary" required="1" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="seniority_salary" required="1" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="high_temperature_allowance" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="commuting_allowance" required="1" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="full_attendance_award" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="overtime_pay" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="meal_misunderstanding_fee" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="condolence_fund" decoration-success="1" groups="yuthon_salary.group_wg_user, yuthon_salary.group_jtbb_user" optional="show"/>
<field name="retroactive_allowance" decoration-success="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="base_salary_deduction" decoration-success="1" decoration-bf="1" groups="yuthon_salary.group_jtbb_user" optional="show"/>
<field name="basic_endowment_insurance" decoration-info="1" optional="show"/>
<field name="basic_medical_insurance" decoration-info="1" optional="show"/>
<field name="unemployment_insurance" decoration-info="1" optional="show"/>
<field name="housing_provident_fund" decoration-info="1" optional="show"/>
<field name="work_injury_insurance" decoration-info="1" optional="show"/>
<field name="specialized_deduction" decoration-warning="1" optional="show"/>
<field name="infant_care" decoration-warning="1" optional="show"/>
<field name="child_education" decoration-warning="1" optional="show"/>
<field name="elderly_support" decoration-warning="1" optional="show"/>
<field name="housing_loan_interest" decoration-warning="1" optional="show"/>
<field name="housing_rent" decoration-warning="1" optional="show"/>
<field name="continuing_education" decoration-warning="1" optional="show"/>
<field name="individual_tax_refund" decoration-danger="1" optional="show"/>
<field name="temporary_performance_bonus" decoration-danger="1" optional="show"/>
<field name="social_security" decoration-danger="1" optional="show"/>
<field name="liquidation_year" decoration-danger="1" optional="show"/>
<field name="year_compute" decoration-danger="1" optional="show"/>
<field name="year_jie" decoration-danger="1" optional="show"/>
<field name="performance_up" decoration-danger="1" optional="show"/>
<field name="jing_te" decoration-danger="1" optional="show"/>
<field name="year_gong" decoration-danger="1" optional="show"/>
<field name="study_on" decoration-danger="1" optional="show"/>
<field name="commuting_deduction" decoration-danger="1" optional="show"/>
<field name="performance_deduction" decoration-danger="1" optional="show"/>
<field name="deduction_standard" decoration-danger="1" optional="show"/>
<field name="safety_incentives" decoration-danger="1" optional="show"/>
<field name="last_year_safety" decoration-danger="1" optional="show"/>
<field name="last_year_performance_evaluation" decoration-danger="1" optional="show"/>
<field name="salary_state" optional="show"/>
<field name="is_salary_release" column_invisible="1"/>
<field name="is_salary_push" column_invisible="1"/>
</tree>
</field>
</record>
<record id="hr_payroll_inherit_form" model="ir.ui.view">
<field name="name">hr.payroll.inherit.form</field>
<field name="model">hr.payslip</field>
@@ -419,6 +346,26 @@
</tree>
</field>
</record>
<record id="my_hr_payslip_view_tree" model="ir.ui.view">
<field name="name">my.hr.payslip.view.tree</field>
<field name="model">hr.payslip</field>
<field name="arch" type="xml">
<tree string="我的薪资" create="false" delete="false" edit="false">
<field name="employee_id" optional="show"/>
<field name="actual_salary" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="total_before_tax" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="b_year" decoration-danger="1" decoration-bf="1" optional="show"/>
<field name="three_one" optional="show"/>
<field name="tax_payable" decoration-danger="1" decoration-bf="1" readonly="1" optional="show"/>
<field name="union_dues" decoration-danger="1" decoration-bf="1" optional="show" groups="yuthon_salary.group_jtbb_user"/>
<field name="is_salary_release" column_invisible="1"/>
<field name="is_salary_push" column_invisible="1"/>
<button name="payslip_wizard" string="发送" type="object" class="oe_highlight" invisible="confirm_status == 'confirm'"/>
<field name="confirm_status"/>
</tree>
</field>
</record>
<record id="hr_payslip_view_form_inherit" model="ir.ui.view">
<field name="name">hr.payslip.view.form.inherit</field>
<field name="model">hr.payslip</field>
@@ -461,7 +408,7 @@
<field name="domain">[('is_salary_push', '=', True), ('is_salary_release', '=', True)]</field>
<field name="context">{'search_default_group_by_employee': 1}</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_salary.view_hr_payslip_tree3')}),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_salary.my_hr_payslip_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('hr_payroll.view_hr_payslip_form')})]"/>
</record>
<record id="action_view_hr_payslip_month_form1" model="ir.actions.act_window">
@@ -484,6 +431,15 @@
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_salary.view_hr_payslip_tree2')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('hr_payroll.view_hr_payslip_form')})]"/>
</record>
<record id="action_view_my_payslip" model="ir.actions.act_window">
<field name="name">我的薪资</field>
<field name="res_model">hr.payslip</field>
<field name="view_mode">tree,form,search</field>
<field name="domain">[('is_salary_push', '=', True), ('is_salary_release', '=', True), ('employee_id.user_id', '=', uid)]</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_salary.my_hr_payslip_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('hr_payroll.view_hr_payslip_form')})]"/>
</record>
<record id="all_data_return_salary" model="ir.actions.server">
<field name="name">批量退回个税计算</field>
<field name="model_id" ref="hr_payroll.model_hr_payslip"/>
+2 -1
View File
@@ -8,4 +8,5 @@ from . import temporary_payslip_wizard
from . import payroll_labor_wizard
from . import payroll_retired_wizard
from . import salary_print_wizard
from . import salary_year_wizard
from . import salary_year_wizard
from . import payslip_send_wizard
@@ -0,0 +1,83 @@
from odoo import models, fields, api, _, SUPERUSER_ID
import logging
from odoo.exceptions import UserError, ValidationError
class PayslipSendWizard(models.Model):
_name = 'payslip.send.wizard'
_description = '发送员工工资条二次确认弹窗'
employee_id = fields.Many2one('hr.employee', string='员工')
name = fields.Char(string='你确定要发送吗?', readonly=1)
employee_ids = fields.Many2many('hr.employee', string='员工')
payslip_run_id = fields.Many2one('hr.payslip.run', string='工资单')
def button_send(self):
self.ensure_one()
for employee_id in self.env['hr.employee'].search([('id', '=', self.employee_id.id)]):
if not employee_id.wecom_userid:
raise UserError("请同步{}的企业微信".format(employee_id.name))
menu_id = self.env['ir.ui.menu'].search([('name', '=', '我的薪资')])
url = f'https://oa.thtzjt.com/web?oauth_uid={employee_id.wecom_userid}#id={self.id}&cids=2&action={menu_id.action.id}&model=hr.payslip&view_type=form&menu_id={menu_id.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task',
user_id=employee_id.wecom_userid,
title="薪资确认",
url=url, btntxt="详细信息")
def button_all_send(self):
self.ensure_one()
for employee_id in self.env['hr.employee'].search([('id', '=', self.employee_ids.ids)]):
if not employee_id.wecom_userid:
raise UserError("请同步{}的企业微信".format(employee_id.name))
menu_id = self.env['ir.ui.menu'].search([('name', '=', '我的薪资')])
url = f'https://oa.thtzjt.com/web?oauth_uid={employee_id.wecom_userid}#id={self.id}&cids=2&action={menu_id.action.id}&model=hr.payslip&view_type=form&menu_id={menu_id.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task',
user_id=employee_id.wecom_userid,
title="薪资确认",
url=url, btntxt="详细信息")
self.payslip_run_id.run_stage = 'issued'
run_payslips = self.env["hr.payslip"].search([
('payslip_run_id', '=', self.payslip_run_id.id)
])
for slip in run_payslips:
meal_misunderstanding_fee = slip.meal_misunderstanding_fee
overtime_pay = slip.overtime_pay
base_salary = slip.base_salary
# 反推加班小时数
overtime_list = []
if overtime_pay > 0:
overtime_hours = (overtime_pay / ((base_salary / 21.75 / 8) * 1.5)) + 40
else:
overtime_hours = 0
employee = slip.employee_id
# 反推误餐次数
meal_list = []
meal_supplement = employee.meal_supplement
# 公式:meal_fee = meal_number * 40 + meal_supplement
if meal_misunderstanding_fee > meal_supplement:
meal_number = (meal_misunderstanding_fee - meal_supplement) / 40
else:
meal_number = 0
reports_id = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', employee.id),
])
if reports_id:
overtime_list.append((0, 0, {
'vacation_id': reports_id.id,
'update_type': 'reduce',
'update_date': fields.Datetime.now(),
'update_lines': overtime_hours,
'text': f'{self.payslip_run_id.name}薪资结算'
}))
meal_list.append((0, 0, {
'vacation_id': reports_id.id,
'update_type': 'reduce',
'update_date': fields.Datetime.now(),
'update_lines': meal_number,
'text': f'{self.payslip_run_id.name}薪资结算'
}))
reports_id.write({
'overtime_ids': overtime_list,
'meal_fee_ids': meal_list,
})
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="payslip_send_wizard_form" model="ir.ui.view">
<field name="name">推送弹窗</field>
<field name="model">payslip.send.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<group>
<field name="employee_ids" widget="many2many_tags" invisible="1"/>
<field name="payslip_run_id" invisible="1"/>
<field name="employee_id" invisible="1"/>
<field name="name" invisible="1"/>
</group>
</group>
</sheet>
<footer>
<button name="button_send" string="确认" type="object" class="oe_highlight" invisible="not employee_id"/>
<button name="button_all_send" string="确认" type="object" class="oe_highlight" invisible="not employee_ids"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
+6 -1
View File
@@ -590,11 +590,16 @@
parent="holiday_manage_menu_root_board"
action="yuthon_hr_attendance.hr_attendance_action1"
sequence="5"/>
<menuitem id="menu_hr_attendance_month_my_detail"
<menuitem id="menu_hr_attendance_month_my_detail"
name="考勤确认"
parent="holiday_manage_menu_root_board"
sequence="10"
action="yuthon_hr_attendance.hr_attendance_month_my_detail_action"/>
<menuitem id="salary_view_my_payslip_board"
name="我的薪资"
parent="holiday_manage_menu_root_board"
sequence="20"
action="yuthon_salary.action_view_my_payslip"/>
<menuitem id="menu_hr_attendance_approval_request_board"
name="流程"
parent="holiday_manage_menu_root_board"