@@ -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
|
||||
|
||||
|
@@ -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"/>
|
||||
|
||||
@@ -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})
|
||||
@@ -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': {
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user