Merge pull request !3058 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2025-06-03 11:19:35 +00:00
committed by Gitee
14 changed files with 184 additions and 50 deletions
@@ -12,7 +12,10 @@ class YuthonVacationReports(models.Model):
company_id = fields.Many2one(related="employee_id.company_id", string="公司")
leave = fields.Float(string='年假')
working_overtime = fields.Float(string='加班时')
meal_fee = fields.Integer(string="误餐费")
meal_fee = fields.Integer(string="误餐次数")
leave_ids = fields.One2many('vacation.leave.line', 'vacation_id', string='年假明细')
overtime_ids = fields.One2many('vacation.over.line', 'vacation_id', string='加班明细')
meal_fee_ids = fields.One2many('vacation.meal.line', 'vacation_id', string='误餐明细')
def button_fixes_approval(self):
form_id = self.env.ref('yuthon_holiday.view_yuthon_fixes_approval_form').id
@@ -37,8 +40,9 @@ class YuthonVacationReports(models.Model):
'res_model': 'soong.workflow.record',
'view_mode': 'tree',
'domain': domain,
'context': {'group_by': ['workflow_id']}
}
'context': {'group_by': ['workflow_id'],
'tree_view_ref':'yuthon_holiday.details_tree_view',
}}
return action
def update_vacation(self):
@@ -66,6 +70,55 @@ class YuthonVacationReports(models.Model):
})
def log(self):
return {
"type": "ir.actions.act_window",
"res_model": 'yuthon.vacation.reports',
"res_id": self.id,
"name": "详情",
"view_mode": "form",
}
class VacationLeaveLine(models.Model):
_name = 'vacation.leave.line'
_description = '年假明细'
vacation_id = fields.Many2one('yuthon.vacation.reports', string='关联假期报表')
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
update_date = fields.Date(string='更新时间')
update_lines = fields.Text(string='更新额度')
class VacationOverline(models.Model):
_name = 'vacation.over.line'
_description = '加班明细'
vacation_id = fields.Many2one('yuthon.vacation.reports', string='关联假期报表')
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
update_date = fields.Date(string='更新时间')
update_lines = fields.Text(string='更新额度')
class VacationMealLine(models.Model):
_name = 'vacation.meal.line'
_description = '误餐明细'
vacation_id = fields.Many2one('yuthon.vacation.reports', string='关联假期报表')
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
update_date = fields.Date(string='更新时间')
update_lines = fields.Text(string='更新额度')
class DetailsTree(models.Model):
_name = 'details.tree'
_description = '明细表'
code = fields.Char()
name = fields.Char()
@@ -7,3 +7,7 @@ access_yuthon_holiday_setting,yuthon_holiday_setting,model_yuthon_holiday_settin
access_leave_allocation_wizard,leave_allocation_wizard,model_leave_allocation_wizard,base.group_user,1,1,1,1
access_yuthon_leave_wizard,yuthon_leave_wizard,model_yuthon_leave_wizard,base.group_user,1,1,1,1
access_yuthon_vacation_reports,yuthon_vacation_reports,model_yuthon_vacation_reports,base.group_user,1,1,1,1
access_vacation_leave_line,vacation_leave_line,model_vacation_leave_line,base.group_user,1,1,1,1
access_vacation_meal_line,vacation_meal_line,model_vacation_meal_line,base.group_user,1,1,1,1
access_vacation_over_line,vacation_over_line,model_vacation_over_line,base.group_user,1,1,1,1
access_details_tree, details_tree,model_details_tree,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
7 access_leave_allocation_wizard leave_allocation_wizard model_leave_allocation_wizard base.group_user 1 1 1 1
8 access_yuthon_leave_wizard yuthon_leave_wizard model_yuthon_leave_wizard base.group_user 1 1 1 1
9 access_yuthon_vacation_reports yuthon_vacation_reports model_yuthon_vacation_reports base.group_user 1 1 1 1
10 access_vacation_leave_line vacation_leave_line model_vacation_leave_line base.group_user 1 1 1 1
11 access_vacation_meal_line vacation_meal_line model_vacation_meal_line base.group_user 1 1 1 1
12 access_vacation_over_line vacation_over_line model_vacation_over_line base.group_user 1 1 1 1
13 access_details_tree details_tree model_details_tree base.group_user 1 1 1 1
@@ -12,13 +12,56 @@
<field name="company_id" optional="hide"/>
<button name="vacation_details" string="详情" type="object" class="oe_highlight"/>
<button name="button_fixes_approval" string="修正" type="object" class="oe_highlight"/>
<button name="log" string="日志" type="object" class="oe_highlight"/>
</tree>
</field>
</record>
<record id="view_yuthon_vacation_reports_form" model="ir.ui.view">
<field name="name">yuthon.vacation.reports.form</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<form string="假期报表">
<sheet>
<notebook>
<page string="年假">
<field name="leave_ids">
<tree editable="bottom">
<field name="vacation_id" column_invisible="1"/>
<field name="update_type"/>
<field name="update_date"/>
<field name="update_lines"/>
</tree>
</field>
</page>
<page string="加班">
<field name="overtime_ids">
<tree editable="bottom">
<field name="vacation_id" column_invisible="1"/>
<field name="update_type"/>
<field name="update_date"/>
<field name="update_lines"/>
</tree>
</field>
</page>
<page string="误餐">
<field name="meal_fee_ids">
<tree editable="bottom">
<field name="vacation_id" column_invisible="1"/>
<field name="update_type"/>
<field name="update_date"/>
<field name="update_lines"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_yuthon_vacation_reports_action" model="ir.actions.act_window">
<field name="name">假期报表</field>
<field name="res_model">yuthon.vacation.reports</field>
<field name="view_mode">tree</field>
<field name="name">假期报表</field>
<field name="res_model">yuthon.vacation.reports</field>
<field name="view_mode">tree</field>
</record>
<record id="all_update_employee" model="ir.actions.server">
<field name="name">更新报表</field>
@@ -27,5 +70,17 @@
<field name="state">code</field>
<field name="code">action = model.update_vacation()</field>
</record>
<record id="details_tree_view" model="ir.ui.view">
<field name="name">details.tree.tree</field>
<field name="model">details.tree</field>
<field name="arch" type="xml">
<tree>
<field name="code"/>
<field name="name"/>
</tree>
</field>
</record>
</odoo>
@@ -58,7 +58,9 @@
<field name="name">hr.attendance.month.detail.tree</field>
<field name="model">hr.attendance.month.detail</field>
<field name="arch" type="xml">
<tree string="hr attendance detail" editable="bottom" js_class="custom_month_statements_button">
<tree string="hr attendance detail" editable="bottom" js_class="custom_month_statements_button"
decoration-success="state == 'confirmed'"
decoration-danger="state == 'unconfirmed'">
<header>
<button class="oe_stat_button" name="send_confirm_attendance" string="发送考勤确认" type="object"
icon="fa-bars"/>
@@ -254,7 +256,7 @@
</record>
<record id="hr_attendance_month_detail_action" model="ir.actions.act_window">
<field name="name">出勤统计明细</field>
<field name="name">考勤确认单</field>
<field name="res_model">hr.attendance.month.detail</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_hr_attendance_month_detail_search"/>
@@ -121,21 +121,27 @@ class HrAttendanceMonthWizard(models.TransientModel):
all_employee_ids.update(calendar.resource_user_ids.ids)
all_employee_ids = list(all_employee_ids)
hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "in", user_obj.ids)])
# 白名单
resource_user_ids = hr_employee_obj.mapped('resource_calendar_id.resource_user_ids').ids
# 循环所有员工对每个人进行统计
for employee in hr_employee_obj:
if employee.id not in all_employee_ids:
# 判断当前是否已经创建了考勤明细
attendance_month_detail_obj = self._get_attendance_month_detail(employee)
attendance_month_detail_obj.hr_attendance_month_id = attendance_month_obj.id
# 判断当前用户是否已经确认签字,签字后不再更新
if attendance_month_detail_obj.state == 'confirmed' and attendance_month_detail_obj.signature:
continue
# 更新用户的考勤明细
attendance_month_detail_obj.analysis_attendance_month_detail()
self.get_leave_and_overtime_info(employee.id)
# 返回action动作
action = self._hr_attendance_month_detail_action()
return action
if (
employee.id not in resource_user_ids and
employee.contract.state not in ['draft', 'cancel']
):
if employee.id not in all_employee_ids:
# 判断当前是否已经创建了考勤明细
attendance_month_detail_obj = self._get_attendance_month_detail(employee)
attendance_month_detail_obj.hr_attendance_month_id = attendance_month_obj.id
# 判断当前用户是否已经确认签字,签字后不再更新
if attendance_month_detail_obj.state == 'confirmed' and attendance_month_detail_obj.signature:
continue
# 更新用户的考勤明细
attendance_month_detail_obj.analysis_attendance_month_detail()
self.get_leave_and_overtime_info(employee.id)
# 返回action动作
action = self._hr_attendance_month_detail_action()
return action
# 考勤定时任务
def button_attendance_month(self):
@@ -174,26 +174,20 @@
<field name="normal_overtime_hours" readonly="0"/>
<field name="weekend_overtime_hours" readonly="0"/>
<field name="holiday_overtime_hours" readonly="0"/>
<field name="all_overtime_hours" readonly="1"/>
<field name="overtime_this_month" readonly="1"/>
</group>
<group>
<field name="normal_overtime_hours1" readonly="0"/>
<field name="weekend_overtime_hours1" readonly="0"/>
<field name="holiday_overtime_hours1" readonly="0"/>
<field name="result_overtime" readonly="1"/>
<field name="overtime_last_month" readonly="1"/>
</group>
<group>
<button name="put_overtime_return" string="详情" type="object" class="oe_highlight"/>
</group>
</group>
<group col="2">
<group>
<field name="all_overtime_hours" readonly="1"/>
<field name="overtime_this_month" readonly="1"/>
</group>
<group>
<field name="result_overtime" readonly="1"/>
<field name="overtime_last_month" readonly="1"/>
</group>
</group>
<group>
<field name="holiday_hours"/>
<field name="replacement_card_count"/>
+1 -1
View File
@@ -128,7 +128,7 @@ class InheritHrPayslip(models.Model):
def action_refresh_from_work_entries(self):
payslip_records = self.browse(self._context.get('active_ids', self._context.get('active_id')))
payslips = payslip_records or self
# 过滤出状态为草稿或已验证的工资单
# 过滤出状态为草稿或已验证的工资单f
payslips = payslips.filtered(
lambda slip: slip.state in ['draft', 'verify']
and not slip.employee_id.contract_id.is_probation
@@ -9,6 +9,9 @@ class InheritHrPayslipRun(models.Model):
_inherit = 'hr.payslip.run'
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',
string="阶段")
def Fileline(self):
domain = [('is_salary_push', '=', True), ('is_salary_release', '=', True)]
@@ -24,8 +27,11 @@ class InheritHrPayslipRun(models.Model):
def _onchange_document_ids(self):
for rec in self:
if rec.document_ids:
rec.state = 'verify'
rec.run_stage = 'to_be_issued'
def add_comment(self):
for rec in self:
rec.state = 'close'
rec.run_stage = 'issued'
@@ -8,10 +8,14 @@
<xpath expr="//tree" position="attributes">
<attribute name="editable">bottom</attribute>
</xpath>
<xpath expr="//field[@name='state']" position="attributes">
<attribute name="column_invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='company_id']" position="after">
<field name="document_ids" widget="preview_many2many"/>
<field name="run_stage"/>
<button type="object" name="Fileline" string="归档明细" class="oe_highlight"/>
<button type="object" name="add_comment" string="完成" class="oe_highlight"/>
<button type="object" name="add_comment" string="完成" class="oe_highlight" invisible="run_stage == 'issued'"/>
</xpath>
</field>
</record>
@@ -11,6 +11,7 @@ class PutWizard(models.TransientModel):
payslip_records = self.env["hr.payslip"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in payslip_records:
record.payslip_run_id.run_stage = 'individual_tax'
record.write({'is_push': True})
@@ -24,6 +25,7 @@ class ReturnWizard(models.TransientModel):
payslip_records = self.env["hr.payslip"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in payslip_records:
record.payslip_run_id.run_stage = 'payroll_calculations'
record.write({'is_push': False})
@@ -37,6 +39,7 @@ class PutSalaryWizard(models.TransientModel):
payslip_records = self.env["hr.payslip"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in payslip_records:
record.payslip_run_id.run_stage = 'finalized'
record.write({'is_salary_push': True, 'is_salary_release': False})
@@ -50,4 +53,5 @@ class ReturnSalaryWizard(models.TransientModel):
payslip_records = self.env["hr.payslip"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in payslip_records:
record.payslip_run_id.run_stage = 'individual_tax'
record.write({'is_salary_push': False, 'is_salary_release': False})
+10 -11
View File
@@ -31,11 +31,15 @@ class SalaryComputeWizard(models.Model):
@api.onchange('company_id')
def onchange_company_id(self):
user_obj = self.env['res.users'].sudo().search([])
hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "in", user_obj.ids)])
resource_user_ids = hr_employee_obj.mapped('resource_calendar_id.resource_user_ids').ids
if self.company_id:
employees = self.env['hr.employee'].search([
('id', 'not in', resource_user_ids),
('company_id', '=', self.company_id.id),
('is_salary', '=', True),
('contract_id.state', '!=', 'cancel'),
('contract_id.state', 'not in', ['draft', 'cancel']),
('contract_id', '!=', False),
])
self.employee_ids = [(6, 0, employees.ids)]
@@ -48,17 +52,12 @@ class SalaryComputeWizard(models.Model):
self.employee_number = len(self.employee_ids)
def confirm(self):
attendance_records = self.env['hr.attendance.month'].search([
('current_year', '=', self.select_year),
('current_month', '=', self.select_time),
])
# if not attendance_records:
# raise ValidationError(
# f"在 {self.select_year} 年 {self.select_time} 月没有出勤月度汇总记录,请先完成考勤统计。")
# if not all(record.is_state for record in attendance_records):
# raise ValidationError(
# f"在 {self.select_year} 年 {self.select_time} 月的出勤月度汇总记录未全部确认,请先确认考勤。"
for employee in self.employee_ids:
detail_id = self.env['hr.attendance.month.detail'].search([('employee_id', '=', employee.id),
('current_year', '=', self.select_year),
('current_month', '=', self.select_time)])
if detail_id.state == 'unconfirmed':
raise UserError(f'{employee.name}的{self.select_time}考勤还未确认,请先确认考勤再进行工资计算!')
contract_id = self.env['hr.contract'].search([('employee_id', '=', employee.id)], limit=1)
year = int(self.select_year)
month = int(self.select_time)
@@ -7,11 +7,11 @@
<form>
<sheet>
<group>
<field name="company_id" domain="[('id', '=', company_id)]"/>
<field name="employee_ids" widget="many2many_tags" force_save="1" options="{'no_create': True}"/>
<field name="employee_number" column_invisible="1"/>
<field name="select_year"/>
<field name="select_time"/>
<field name="company_id" domain="[('id', '=', company_id)]" column_invisible="1"/>
<field name="employee_ids" widget="many2many_tags" force_save="1" options="{'no_create': True}"/>
<field name="employee_number" column_invisible="1"/>
</group>
<footer>
<button type="object" name="confirm" string="确认" class="oe_highlight"/>
@@ -163,6 +163,13 @@ class SalaryPrintWizard(models.Model):
login = self.env.user.login
if self.password != login:
raise ValidationError('密码错误!')
payslip_id = self.env['hr.payslip'].search([
('is_salary_push', '=', True),
('is_salary_release', '=', False),
('payslip_run_id.name', 'like', f'%年-{self.current_month}') # 匹配格式:"2025年-一月"
])
payslip_id.payslip_run_id.write({'run_stage': 'to_be_signed'})
return {
'type': 'ir.actions.report',
'data': {
+1 -1
View File
@@ -145,7 +145,7 @@
<!-- sequence="7"-->
<!-- action="yuthon_hr_attendance.hr_attendance_month_action"/>-->
<menuitem id="menu_hr_attendance_month_detail_view_attendances"
name="考勤详情"
name="考勤确认单"
parent="hr_attendance_root_board_menu"
sequence="10"
action="yuthon_hr_attendance.hr_attendance_month_detail_action"/>