模块迁移
This commit is contained in:
parent
26c311d913
commit
524aacbacb
2
yuthon_salary/__init__.py
Normal file
2
yuthon_salary/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
42
yuthon_salary/__manifest__.py
Normal file
42
yuthon_salary/__manifest__.py
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': '宇森教育薪资管理',
|
||||
'summary': '学校教育行业教职工薪资管理系统',
|
||||
'description': '''
|
||||
专为学校教育行业设计的教职工薪资管理系统,主要功能包括:
|
||||
|
||||
- 教职工薪资档案管理
|
||||
- 薪资结构配置(基本工资、岗位工资、绩效工资)
|
||||
- 课时费管理(按科目、年级、职称差异化计费)
|
||||
- 班主任津贴管理
|
||||
- 社保公积金扣缴配置
|
||||
- 个人所得税自动计算
|
||||
- 薪资单生成与审批
|
||||
- 薪资条发放与查询
|
||||
- 薪资报表统计分析
|
||||
|
||||
适用于幼儿园、小学、中学、高中、职业院校等各类教育机构。
|
||||
''',
|
||||
'author': '宇森科技',
|
||||
'version': '18.0.1.0',
|
||||
'category': 'Human Resources/Payroll',
|
||||
'sequence': 250,
|
||||
'depends': ['base', 'hr', 'hr_contract', 'mail', 'yuthon_base'],
|
||||
'data': [
|
||||
'security/yuthon_salary_groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/yuthon_salary_security.xml',
|
||||
'data/salary_item_data.xml',
|
||||
'views/salary_item_views.xml',
|
||||
'views/salary_structure_views.xml',
|
||||
'views/employee_salary_views.xml',
|
||||
'views/class_hour_views.xml',
|
||||
'views/class_teacher_allowance_views.xml',
|
||||
'views/salary_slip_views.xml',
|
||||
'views/salary_report_views.xml',
|
||||
'views/menu_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
152
yuthon_salary/data/salary_item_data.xml
Normal file
152
yuthon_salary/data/salary_item_data.xml
Normal file
@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- 默认薪资项目 -->
|
||||
<record id="salary_item_basic" model="yuthon.salary.item">
|
||||
<field name="name">基本工资</field>
|
||||
<field name="code">BASIC</field>
|
||||
<field name="category">basic</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">fixed</field>
|
||||
<field name="sequence">10</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_position" model="yuthon.salary.item">
|
||||
<field name="name">岗位工资</field>
|
||||
<field name="code">POSITION</field>
|
||||
<field name="category">position</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">fixed</field>
|
||||
<field name="sequence">20</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_performance" model="yuthon.salary.item">
|
||||
<field name="name">绩效工资</field>
|
||||
<field name="code">PERFORMANCE</field>
|
||||
<field name="category">performance</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">30</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_class_hour" model="yuthon.salary.item">
|
||||
<field name="name">课时费</field>
|
||||
<field name="code">CLASS_HOUR</field>
|
||||
<field name="category">class_hour</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">40</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_class_teacher" model="yuthon.salary.item">
|
||||
<field name="name">班主任津贴</field>
|
||||
<field name="code">CLASS_TEACHER</field>
|
||||
<field name="category">allowance</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">manual</field>
|
||||
<field name="sequence">50</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_seniority" model="yuthon.salary.item">
|
||||
<field name="name">工龄津贴</field>
|
||||
<field name="code">SENIORITY</field>
|
||||
<field name="category">allowance</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">fixed</field>
|
||||
<field name="sequence">60</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_education" model="yuthon.salary.item">
|
||||
<field name="name">学历津贴</field>
|
||||
<field name="code">EDUCATION</field>
|
||||
<field name="category">allowance</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">fixed</field>
|
||||
<field name="sequence">70</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_title" model="yuthon.salary.item">
|
||||
<field name="name">职称津贴</field>
|
||||
<field name="code">TITLE</field>
|
||||
<field name="category">allowance</field>
|
||||
<field name="item_type">income</field>
|
||||
<field name="calculation_method">fixed</field>
|
||||
<field name="sequence">80</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_pension" model="yuthon.salary.item">
|
||||
<field name="name">养老保险(个人)</field>
|
||||
<field name="code">PENSION</field>
|
||||
<field name="category">social</field>
|
||||
<field name="item_type">deduction</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">110</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_medical" model="yuthon.salary.item">
|
||||
<field name="name">医疗保险(个人)</field>
|
||||
<field name="code">MEDICAL</field>
|
||||
<field name="category">social</field>
|
||||
<field name="item_type">deduction</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">120</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_unemployment" model="yuthon.salary.item">
|
||||
<field name="name">失业保险(个人)</field>
|
||||
<field name="code">UNEMPLOYMENT</field>
|
||||
<field name="category">social</field>
|
||||
<field name="item_type">deduction</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">130</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_provident_fund" model="yuthon.salary.item">
|
||||
<field name="name">住房公积金(个人)</field>
|
||||
<field name="code">PROVIDENT_FUND</field>
|
||||
<field name="category">social</field>
|
||||
<field name="item_type">deduction</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="sequence">140</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_item_income_tax" model="yuthon.salary.item">
|
||||
<field name="name">个人所得税</field>
|
||||
<field name="code">INCOME_TAX</field>
|
||||
<field name="category">tax</field>
|
||||
<field name="item_type">deduction</field>
|
||||
<field name="calculation_method">formula</field>
|
||||
<field name="is_taxable">True</field>
|
||||
<field name="sequence">150</field>
|
||||
</record>
|
||||
|
||||
<!-- 序列号 -->
|
||||
<record id="seq_employee_salary" model="ir.sequence">
|
||||
<field name="name">教职工薪资档案编号</field>
|
||||
<field name="code">yuthon.employee.salary</field>
|
||||
<field name="prefix">ESA%(year)s</field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_class_hour" model="ir.sequence">
|
||||
<field name="name">课时记录编号</field>
|
||||
<field name="code">yuthon.class.hour</field>
|
||||
<field name="prefix">CH%(year)s</field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_class_teacher_allowance" model="ir.sequence">
|
||||
<field name="name">班主任津贴编号</field>
|
||||
<field name="code">yuthon.class.teacher.allowance</field>
|
||||
<field name="prefix">CTA%(year)s%(month)s</field>
|
||||
<field name="padding">3</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_salary_slip" model="ir.sequence">
|
||||
<field name="name">薪资单编号</field>
|
||||
<field name="code">yuthon.salary.slip</field>
|
||||
<field name="prefix">SLIP%(year)s%(month)s</field>
|
||||
<field name="padding">3</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
1
yuthon_salary/models/.gitkeep
Normal file
1
yuthon_salary/models/.gitkeep
Normal file
@ -0,0 +1 @@
|
||||
# Placeholder
|
||||
7
yuthon_salary/models/__init__.py
Normal file
7
yuthon_salary/models/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import salary_item
|
||||
from . import salary_structure
|
||||
from . import employee_salary
|
||||
from . import class_hour
|
||||
from . import class_teacher_allowance
|
||||
from . import salary_slip
|
||||
85
yuthon_salary/models/class_hour.py
Normal file
85
yuthon_salary/models/class_hour.py
Normal file
@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class ClassHour(models.Model):
|
||||
"""课时记录 - 记录教职工的授课课时"""
|
||||
_name = 'yuthon.class.hour'
|
||||
_description = '课时记录'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'date desc, id desc'
|
||||
|
||||
name = fields.Char(string='课时编号', required=True, copy=False, readonly=True, default='新建')
|
||||
employee_id = fields.Many2one('hr.employee', string='授课教师', required=True)
|
||||
department_id = fields.Many2one('hr.department', string='所属部门', related='employee_id.department_id', store=True)
|
||||
|
||||
# 授课信息
|
||||
date = fields.Date(string='授课日期', required=True, default=fields.Date.today)
|
||||
subject = fields.Char(string='科目', required=True)
|
||||
grade = fields.Char(string='年级/班级')
|
||||
class_type = fields.Selection([
|
||||
('normal', '常规课'),
|
||||
('overtime', '超课时'),
|
||||
('weekend', '周末课'),
|
||||
('holiday', '节假日课'),
|
||||
('makeup', '补课'),
|
||||
('exam', '考试监考'),
|
||||
('activity', '课外活动'),
|
||||
], string='课程类型', required=True, default='normal')
|
||||
|
||||
# 课时计算
|
||||
hours = fields.Float(string='课时数', required=True, default=1.0)
|
||||
rate = fields.Float(string='课时费标准(元/课时)', required=True, default=0.0)
|
||||
amount = fields.Float(string='课时费金额', compute='_compute_amount', store=True)
|
||||
|
||||
# 状态
|
||||
state = fields.Selection([
|
||||
('draft', '草稿'),
|
||||
('submitted', '已提交'),
|
||||
('approved', '已确认'),
|
||||
('paid', '已发薪'),
|
||||
], string='状态', default='draft', tracking=True)
|
||||
|
||||
# 关联薪资单
|
||||
salary_slip_id = fields.Many2one('yuthon.salary.slip', string='关联薪资单', readonly=True)
|
||||
|
||||
note = fields.Text(string='备注')
|
||||
company_id = fields.Many2one('res.company', string='学校', default=lambda self: self.env.company)
|
||||
|
||||
@api.depends('hours', 'rate')
|
||||
def _compute_amount(self):
|
||||
for record in self:
|
||||
record.amount = record.hours * record.rate
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('name', '新建') == '新建':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('yuthon.class.hour') or '新建'
|
||||
return super(ClassHour, self).create(vals_list)
|
||||
|
||||
def action_submit(self):
|
||||
self.write({'state': 'submitted'})
|
||||
|
||||
def action_approve(self):
|
||||
self.write({'state': 'approved'})
|
||||
|
||||
def action_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
|
||||
@api.onchange('employee_id', 'class_type')
|
||||
def _onchange_employee_class_type(self):
|
||||
if self.employee_id and self.employee_id.user_id:
|
||||
salary_record = self.env['yuthon.employee.salary'].search([
|
||||
('employee_id', '=', self.employee_id.id),
|
||||
('state', '=', 'active')
|
||||
], limit=1, order='id desc')
|
||||
if salary_record:
|
||||
if self.class_type == 'normal':
|
||||
self.rate = salary_record.class_hour_rate_normal
|
||||
elif self.class_type == 'overtime':
|
||||
self.rate = salary_record.class_hour_rate_overtime
|
||||
elif self.class_type == 'weekend':
|
||||
self.rate = salary_record.class_hour_rate_weekend
|
||||
elif self.class_type == 'holiday':
|
||||
self.rate = salary_record.class_hour_rate_holiday
|
||||
104
yuthon_salary/models/class_teacher_allowance.py
Normal file
104
yuthon_salary/models/class_teacher_allowance.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class ClassTeacherAllowance(models.Model):
|
||||
"""班主任津贴 - 管理班主任的月度津贴"""
|
||||
_name = 'yuthon.class.teacher.allowance'
|
||||
_description = '班主任津贴'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'year desc, month desc, id desc'
|
||||
|
||||
name = fields.Char(string='津贴编号', required=True, copy=False, readonly=True, default='新建')
|
||||
employee_id = fields.Many2one('hr.employee', string='班主任', required=True)
|
||||
department_id = fields.Many2one('hr.department', string='所属部门', related='employee_id.department_id', store=True)
|
||||
|
||||
# 班级信息
|
||||
class_name = fields.Char(string='班级名称', required=True)
|
||||
grade_level = fields.Selection([
|
||||
('junior', '低年级'),
|
||||
('middle', '中年级'),
|
||||
('senior', '高年级'),
|
||||
('junior_high', '初中'),
|
||||
('senior_high', '高中'),
|
||||
], string='年级段')
|
||||
student_count = fields.Integer(string='学生人数', default=0)
|
||||
|
||||
# 考核评分
|
||||
year = fields.Integer(string='年度', required=True, default=lambda self: fields.Date.today().year)
|
||||
month = fields.Integer(string='月份', required=True, default=lambda self: fields.Date.today().month)
|
||||
|
||||
# 津贴构成
|
||||
base_allowance = fields.Float(string='基础津贴', required=True, default=0.0)
|
||||
student_count_bonus = fields.Float(string='学生人数补贴', default=0.0)
|
||||
performance_bonus = fields.Float(string='绩效奖金', default=0.0)
|
||||
special_allowance = fields.Float(string='特殊补贴', default=0.0)
|
||||
deduction = fields.Float(string='扣款', default=0.0)
|
||||
|
||||
total_amount = fields.Float(string='津贴合计', compute='_compute_total', store=True)
|
||||
|
||||
# 考核维度
|
||||
discipline_score = fields.Float(string='纪律管理评分', default=100.0)
|
||||
hygiene_score = fields.Float(string='卫生管理评分', default=100.0)
|
||||
activity_score = fields.Float(string='活动组织评分', default=100.0)
|
||||
parent_score = fields.Float(string='家长沟通评分', default=100.0)
|
||||
overall_score = fields.Float(string='综合评分', compute='_compute_score', store=True)
|
||||
|
||||
# 状态
|
||||
state = fields.Selection([
|
||||
('draft', '草稿'),
|
||||
('submitted', '已提交'),
|
||||
('approved', '已审核'),
|
||||
('paid', '已发薪'),
|
||||
], string='状态', default='draft', tracking=True)
|
||||
|
||||
salary_slip_id = fields.Many2one('yuthon.salary.slip', string='关联薪资单', readonly=True)
|
||||
note = fields.Text(string='备注')
|
||||
company_id = fields.Many2one('res.company', string='学校', default=lambda self: self.env.company)
|
||||
|
||||
@api.depends('base_allowance', 'student_count_bonus', 'performance_bonus', 'special_allowance', 'deduction')
|
||||
def _compute_total(self):
|
||||
for record in self:
|
||||
record.total_amount = (
|
||||
record.base_allowance +
|
||||
record.student_count_bonus +
|
||||
record.performance_bonus +
|
||||
record.special_allowance -
|
||||
record.deduction
|
||||
)
|
||||
|
||||
@api.depends('discipline_score', 'hygiene_score', 'activity_score', 'parent_score')
|
||||
def _compute_score(self):
|
||||
for record in self:
|
||||
record.overall_score = (
|
||||
record.discipline_score +
|
||||
record.hygiene_score +
|
||||
record.activity_score +
|
||||
record.parent_score
|
||||
) / 4.0
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('name', '新建') == '新建':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('yuthon.class.teacher.allowance') or '新建'
|
||||
return super(ClassTeacherAllowance, self).create(vals_list)
|
||||
|
||||
def action_submit(self):
|
||||
self.write({'state': 'submitted'})
|
||||
|
||||
def action_approve(self):
|
||||
self.write({'state': 'approved'})
|
||||
|
||||
def action_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
|
||||
@api.onchange('employee_id')
|
||||
def _onchange_employee(self):
|
||||
if self.employee_id:
|
||||
salary_record = self.env['yuthon.employee.salary'].search([
|
||||
('employee_id', '=', self.employee_id.id),
|
||||
('state', '=', 'active')
|
||||
], limit=1, order='id desc')
|
||||
if salary_record:
|
||||
self.base_allowance = salary_record.class_teacher_allowance
|
||||
117
yuthon_salary/models/employee_salary.py
Normal file
117
yuthon_salary/models/employee_salary.py
Normal file
@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class EmployeeSalary(models.Model):
|
||||
"""教职工薪资档案 - 记录每位教职工的薪资配置"""
|
||||
_name = 'yuthon.employee.salary'
|
||||
_description = '教职工薪资档案'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'employee_id'
|
||||
|
||||
name = fields.Char(string='档案编号', required=True, copy=False, readonly=True, default='新建')
|
||||
employee_id = fields.Many2one('hr.employee', string='教职工', required=True)
|
||||
department_id = fields.Many2one('hr.department', string='所属部门', related='employee_id.department_id', store=True)
|
||||
job_id = fields.Many2one('hr.job', string='岗位', related='employee_id.job_id', store=True)
|
||||
|
||||
# 基本信息
|
||||
employee_type = fields.Selection([
|
||||
('full_time', '正式编制'),
|
||||
('contract', '合同制'),
|
||||
('temporary', '临聘'),
|
||||
('intern', '实习'),
|
||||
('part_time', '兼职'),
|
||||
], string='用工类型', required=True, default='full_time')
|
||||
teacher_title = fields.Selection([
|
||||
('none', '无职称'),
|
||||
('third', '三级教师'),
|
||||
('second', '二级教师'),
|
||||
('first', '一级教师'),
|
||||
('senior', '高级教师'),
|
||||
('special', '特级教师'),
|
||||
('lecturer', '讲师'),
|
||||
('associate_prof', '副教授'),
|
||||
('professor', '教授'),
|
||||
], string='教师职称', default='none')
|
||||
education_level = fields.Selection([
|
||||
('college', '大专'),
|
||||
('bachelor', '本科'),
|
||||
('master', '硕士'),
|
||||
('doctor', '博士'),
|
||||
], string='学历层次', default='bachelor')
|
||||
|
||||
# 薪资结构
|
||||
structure_id = fields.Many2one('yuthon.salary.structure', string='适用薪资结构')
|
||||
|
||||
# 基本工资
|
||||
basic_salary = fields.Float(string='基本工资', required=True, default=0.0, tracking=True)
|
||||
position_salary = fields.Float(string='岗位工资', default=0.0, tracking=True)
|
||||
performance_salary = fields.Float(string='绩效工资基数', default=0.0, tracking=True)
|
||||
|
||||
# 课时费标准(按职称/科目差异化)
|
||||
class_hour_rate_normal = fields.Float(string='常规课时费标准(元/课时)', default=0.0)
|
||||
class_hour_rate_overtime = fields.Float(string='超课时费标准(元/课时)', default=0.0)
|
||||
class_hour_rate_weekend = fields.Float(string='周末课时费标准(元/课时)', default=0.0)
|
||||
class_hour_rate_holiday = fields.Float(string='节假日课时费标准(元/课时)', default=0.0)
|
||||
|
||||
# 班主任津贴
|
||||
is_class_teacher = fields.Boolean(string='是否班主任', default=False)
|
||||
class_teacher_allowance = fields.Float(string='班主任津贴', default=0.0)
|
||||
class_level = fields.Selection([
|
||||
('junior', '低年级'),
|
||||
('middle', '中年级'),
|
||||
('senior', '高年级'),
|
||||
('junior_high', '初中'),
|
||||
('senior_high', '高中'),
|
||||
], string='任教年级段')
|
||||
|
||||
# 其他固定津贴
|
||||
seniority_allowance = fields.Float(string='工龄津贴', default=0.0)
|
||||
education_allowance = fields.Float(string='学历津贴', default=0.0)
|
||||
title_allowance = fields.Float(string='职称津贴', default=0.0)
|
||||
other_allowance = fields.Float(string='其他津贴', default=0.0)
|
||||
|
||||
# 社保公积金
|
||||
social_insurance_base = fields.Float(string='社保基数', default=0.0)
|
||||
provident_fund_base = fields.Float(string='公积金基数', default=0.0)
|
||||
pension_rate_personal = fields.Float(string='养老保险个人比例(%)', default=8.0)
|
||||
medical_rate_personal = fields.Float(string='医疗保险个人比例(%)', default=2.0)
|
||||
unemployment_rate_personal = fields.Float(string='失业保险个人比例(%)', default=0.5)
|
||||
provident_fund_rate_personal = fields.Float(string='公积金个人比例(%)', default=12.0)
|
||||
|
||||
# 个税
|
||||
tax_deduction_point = fields.Float(string='个税起征点', default=5000.0)
|
||||
special_deduction = fields.Float(string='专项附加扣除', default=0.0)
|
||||
|
||||
# 银行卡信息
|
||||
bank_name = fields.Char(string='开户银行')
|
||||
bank_account = fields.Char(string='银行卡号')
|
||||
bank_branch = fields.Char(string='开户支行')
|
||||
|
||||
# 状态
|
||||
state = fields.Selection([
|
||||
('draft', '草稿'),
|
||||
('active', '生效'),
|
||||
('suspended', '停薪'),
|
||||
('resigned', '离职'),
|
||||
], string='状态', default='draft', tracking=True)
|
||||
|
||||
effective_date = fields.Date(string='生效日期', default=fields.Date.today)
|
||||
note = fields.Text(string='备注')
|
||||
company_id = fields.Many2one('res.company', string='学校', default=lambda self: self.env.company)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('name', '新建') == '新建':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('yuthon.employee.salary') or '新建'
|
||||
return super(EmployeeSalary, self).create(vals_list)
|
||||
|
||||
def action_activate(self):
|
||||
self.write({'state': 'active'})
|
||||
|
||||
def action_suspend(self):
|
||||
self.write({'state': 'suspended'})
|
||||
|
||||
def action_resign(self):
|
||||
self.write({'state': 'resigned'})
|
||||
44
yuthon_salary/models/salary_item.py
Normal file
44
yuthon_salary/models/salary_item.py
Normal file
@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SalaryItem(models.Model):
|
||||
"""薪资项目 - 定义薪资单中的各个项目"""
|
||||
_name = 'yuthon.salary.item'
|
||||
_description = '薪资项目'
|
||||
_order = 'sequence, id'
|
||||
|
||||
name = fields.Char(string='项目名称', required=True)
|
||||
code = fields.Char(string='项目编码', required=True)
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
category = fields.Selection([
|
||||
('basic', '基本工资'),
|
||||
('position', '岗位工资'),
|
||||
('performance', '绩效工资'),
|
||||
('class_hour', '课时费'),
|
||||
('allowance', '津贴补贴'),
|
||||
('deduction', '扣款项'),
|
||||
('social', '社保公积金'),
|
||||
('tax', '个人所得税'),
|
||||
('other_income', '其他收入'),
|
||||
('other_deduction', '其他扣款'),
|
||||
], string='项目类别', required=True)
|
||||
item_type = fields.Selection([
|
||||
('income', '收入项'),
|
||||
('deduction', '扣款项'),
|
||||
], string='项目类型', required=True, default='income')
|
||||
calculation_method = fields.Selection([
|
||||
('fixed', '固定金额'),
|
||||
('formula', '公式计算'),
|
||||
('manual', '手动录入'),
|
||||
], string='计算方式', required=True, default='fixed')
|
||||
formula = fields.Text(string='计算公式')
|
||||
is_taxable = fields.Boolean(string='是否计税', default=False)
|
||||
is_social_base = fields.Boolean(string='是否社保基数', default=False)
|
||||
is_required = fields.Boolean(string='必填项', default=False)
|
||||
active = fields.Boolean(string='启用', default=True)
|
||||
note = fields.Text(string='备注')
|
||||
|
||||
_sql_constraints = [
|
||||
('code_uniq', 'unique(code)', '项目编码必须唯一!'),
|
||||
]
|
||||
201
yuthon_salary/models/salary_slip.py
Normal file
201
yuthon_salary/models/salary_slip.py
Normal file
@ -0,0 +1,201 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SalarySlip(models.Model):
|
||||
"""薪资单 - 教职工月度薪资发放记录"""
|
||||
_name = 'yuthon.salary.slip'
|
||||
_description = '薪资单'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'year desc, month desc, employee_id'
|
||||
|
||||
name = fields.Char(string='薪资单编号', required=True, copy=False, readonly=True, default='新建')
|
||||
employee_id = fields.Many2one('hr.employee', string='教职工', required=True)
|
||||
department_id = fields.Many2one('hr.department', string='所属部门', related='employee_id.department_id', store=True)
|
||||
job_id = fields.Many2one('hr.job', string='岗位', related='employee_id.job_id', store=True)
|
||||
|
||||
# 薪资周期
|
||||
year = fields.Integer(string='年度', required=True, default=lambda self: fields.Date.today().year)
|
||||
month = fields.Integer(string='月份', required=True, default=lambda self: fields.Date.today().month)
|
||||
date_from = fields.Date(string='开始日期', required=True)
|
||||
date_to = fields.Date(string='结束日期', required=True)
|
||||
|
||||
# 关联档案
|
||||
salary_record_id = fields.Many2one('yuthon.employee.salary', string='薪资档案')
|
||||
|
||||
# 收入项
|
||||
basic_salary = fields.Float(string='基本工资', default=0.0)
|
||||
position_salary = fields.Float(string='岗位工资', default=0.0)
|
||||
performance_salary = fields.Float(string='绩效工资', default=0.0)
|
||||
class_hour_fee = fields.Float(string='课时费', default=0.0)
|
||||
class_teacher_allowance = fields.Float(string='班主任津贴', default=0.0)
|
||||
seniority_allowance = fields.Float(string='工龄津贴', default=0.0)
|
||||
education_allowance = fields.Float(string='学历津贴', default=0.0)
|
||||
title_allowance = fields.Float(string='职称津贴', default=0.0)
|
||||
other_income = fields.Float(string='其他收入', default=0.0)
|
||||
|
||||
# 扣款项
|
||||
pension_personal = fields.Float(string='养老保险(个人)', default=0.0)
|
||||
medical_personal = fields.Float(string='医疗保险(个人)', default=0.0)
|
||||
unemployment_personal = fields.Float(string='失业保险(个人)', default=0.0)
|
||||
provident_fund_personal = fields.Float(string='公积金(个人)', default=0.0)
|
||||
other_deduction = fields.Float(string='其他扣款', default=0.0)
|
||||
|
||||
# 个税
|
||||
taxable_income = fields.Float(string='应纳税所得额', compute='_compute_totals', store=True)
|
||||
personal_income_tax = fields.Float(string='个人所得税', compute='_compute_tax', store=True)
|
||||
|
||||
# 合计
|
||||
total_income = fields.Float(string='应发合计', compute='_compute_totals', store=True)
|
||||
total_deduction = fields.Float(string='扣款合计', compute='_compute_totals', store=True)
|
||||
net_salary = fields.Float(string='实发工资', compute='_compute_totals', store=True)
|
||||
|
||||
# 银行信息
|
||||
bank_name = fields.Char(string='开户银行')
|
||||
bank_account = fields.Char(string='银行卡号')
|
||||
|
||||
# 状态
|
||||
state = fields.Selection([
|
||||
('draft', '草稿'),
|
||||
('confirmed', '已确认'),
|
||||
('approved', '已审核'),
|
||||
('paid', '已发放'),
|
||||
], string='状态', default='draft', tracking=True)
|
||||
|
||||
line_ids = fields.One2many('yuthon.salary.slip.line', 'slip_id', string='薪资明细')
|
||||
note = fields.Text(string='备注')
|
||||
company_id = fields.Many2one('res.company', string='学校', default=lambda self: self.env.company)
|
||||
|
||||
@api.depends('basic_salary', 'position_salary', 'performance_salary', 'class_hour_fee',
|
||||
'class_teacher_allowance', 'seniority_allowance', 'education_allowance',
|
||||
'title_allowance', 'other_income',
|
||||
'pension_personal', 'medical_personal', 'unemployment_personal',
|
||||
'provident_fund_personal', 'other_deduction', 'personal_income_tax')
|
||||
def _compute_totals(self):
|
||||
for slip in self:
|
||||
income = (
|
||||
slip.basic_salary + slip.position_salary + slip.performance_salary +
|
||||
slip.class_hour_fee + slip.class_teacher_allowance +
|
||||
slip.seniority_allowance + slip.education_allowance +
|
||||
slip.title_allowance + slip.other_income
|
||||
)
|
||||
deduction = (
|
||||
slip.pension_personal + slip.medical_personal +
|
||||
slip.unemployment_personal + slip.provident_fund_personal +
|
||||
slip.other_deduction + slip.personal_income_tax
|
||||
)
|
||||
slip.total_income = income
|
||||
slip.total_deduction = deduction
|
||||
slip.taxable_income = max(0, income - deduction + slip.personal_income_tax - 5000)
|
||||
slip.net_salary = income - deduction
|
||||
|
||||
@api.depends('taxable_income')
|
||||
def _compute_tax(self):
|
||||
"""简化版个税计算(中国个税累进税率)"""
|
||||
for slip in self:
|
||||
taxable = slip.taxable_income
|
||||
if taxable <= 0:
|
||||
slip.personal_income_tax = 0
|
||||
elif taxable <= 3000:
|
||||
slip.personal_income_tax = taxable * 0.03
|
||||
elif taxable <= 12000:
|
||||
slip.personal_income_tax = taxable * 0.10 - 210
|
||||
elif taxable <= 25000:
|
||||
slip.personal_income_tax = taxable * 0.20 - 1410
|
||||
elif taxable <= 35000:
|
||||
slip.personal_income_tax = taxable * 0.25 - 2660
|
||||
elif taxable <= 55000:
|
||||
slip.personal_income_tax = taxable * 0.30 - 4410
|
||||
elif taxable <= 80000:
|
||||
slip.personal_income_tax = taxable * 0.35 - 7160
|
||||
else:
|
||||
slip.personal_income_tax = taxable * 0.45 - 15160
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('name', '新建') == '新建':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('yuthon.salary.slip') or '新建'
|
||||
return super(SalarySlip, self).create(vals_list)
|
||||
|
||||
def action_calculate(self):
|
||||
"""自动计算薪资"""
|
||||
for slip in self:
|
||||
if slip.salary_record_id:
|
||||
record = slip.salary_record_id
|
||||
slip.basic_salary = record.basic_salary
|
||||
slip.position_salary = record.position_salary
|
||||
slip.performance_salary = record.performance_salary
|
||||
slip.seniority_allowance = record.seniority_allowance
|
||||
slip.education_allowance = record.education_allowance
|
||||
slip.title_allowance = record.title_allowance
|
||||
slip.bank_name = record.bank_name
|
||||
slip.bank_account = record.bank_account
|
||||
|
||||
# 计算社保
|
||||
if record.social_insurance_base > 0:
|
||||
slip.pension_personal = record.social_insurance_base * record.pension_rate_personal / 100
|
||||
slip.medical_personal = record.social_insurance_base * record.medical_rate_personal / 100
|
||||
slip.unemployment_personal = record.social_insurance_base * record.unemployment_rate_personal / 100
|
||||
if record.provident_fund_base > 0:
|
||||
slip.provident_fund_personal = record.provident_fund_base * record.provident_fund_rate_personal / 100
|
||||
|
||||
# 统计课时费
|
||||
class_hours = self.env['yuthon.class.hour'].search([
|
||||
('employee_id', '=', slip.employee_id.id),
|
||||
('date', '>=', slip.date_from),
|
||||
('date', '<=', slip.date_to),
|
||||
('state', 'in', ['approved', 'paid']),
|
||||
])
|
||||
slip.class_hour_fee = sum(ch.amount for ch in class_hours)
|
||||
|
||||
# 统计班主任津贴
|
||||
allowances = self.env['yuthon.class.teacher.allowance'].search([
|
||||
('employee_id', '=', slip.employee_id.id),
|
||||
('year', '=', slip.year),
|
||||
('month', '=', slip.month),
|
||||
('state', 'in', ['approved', 'paid']),
|
||||
])
|
||||
slip.class_teacher_allowance = sum(a.total_amount for a in allowances)
|
||||
|
||||
slip._compute_totals()
|
||||
slip._compute_tax()
|
||||
|
||||
def action_confirm(self):
|
||||
self.write({'state': 'confirmed'})
|
||||
|
||||
def action_approve(self):
|
||||
self.write({'state': 'approved'})
|
||||
|
||||
def action_pay(self):
|
||||
self.write({'state': 'paid'})
|
||||
|
||||
def action_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
|
||||
@api.constrains('year', 'month')
|
||||
def _check_year_month(self):
|
||||
for slip in self:
|
||||
if slip.month < 1 or slip.month > 12:
|
||||
raise ValidationError(_('月份必须在 1-12 之间!'))
|
||||
if slip.year < 2000 or slip.year > 2100:
|
||||
raise ValidationError(_('年度格式不正确!'))
|
||||
|
||||
|
||||
class SalarySlipLine(models.Model):
|
||||
"""薪资单明细行"""
|
||||
_name = 'yuthon.salary.slip.line'
|
||||
_description = '薪资单明细'
|
||||
_order = 'sequence, id'
|
||||
|
||||
slip_id = fields.Many2one('yuthon.salary.slip', string='薪资单', required=True, ondelete='cascade')
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
item_id = fields.Many2one('yuthon.salary.item', string='薪资项目')
|
||||
name = fields.Char(string='项目名称')
|
||||
item_type = fields.Selection([
|
||||
('income', '收入'),
|
||||
('deduction', '扣款'),
|
||||
], string='类型')
|
||||
amount = fields.Float(string='金额', default=0.0)
|
||||
note = fields.Char(string='备注')
|
||||
66
yuthon_salary/models/salary_structure.py
Normal file
66
yuthon_salary/models/salary_structure.py
Normal file
@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SalaryStructure(models.Model):
|
||||
"""薪资结构 - 定义不同岗位/职称的薪资构成"""
|
||||
_name = 'yuthon.salary.structure'
|
||||
_description = '薪资结构'
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(string='结构名称', required=True)
|
||||
code = fields.Char(string='结构编码', required=True)
|
||||
description = fields.Text(string='说明')
|
||||
# 适用对象
|
||||
applicable_type = fields.Selection([
|
||||
('teacher', '任课教师'),
|
||||
('admin', '行政人员'),
|
||||
('leadership', '领导班子'),
|
||||
('support', '后勤人员'),
|
||||
('intern', '实习教师'),
|
||||
('all', '全体适用'),
|
||||
], string='适用类型', required=True, default='teacher')
|
||||
# 适用学校类型
|
||||
school_type = fields.Selection([
|
||||
('kindergarten', '幼儿园'),
|
||||
('primary', '小学'),
|
||||
('junior', '初中'),
|
||||
('senior', '高中'),
|
||||
('vocational', '职业院校'),
|
||||
('university', '高等院校'),
|
||||
('all', '全部适用'),
|
||||
], string='适用学校类型', required=True, default='all')
|
||||
line_ids = fields.One2many('yuthon.salary.structure.line', 'structure_id', string='薪资项目明细')
|
||||
active = fields.Boolean(string='启用', default=True)
|
||||
company_id = fields.Many2one('res.company', string='学校', default=lambda self: self.env.company)
|
||||
|
||||
# 合计字段
|
||||
total_basic = fields.Float(string='基本收入合计', compute='_compute_totals', store=True)
|
||||
total_deduction = fields.Float(string='扣款合计', compute='_compute_totals', store=True)
|
||||
total_net = fields.Float(string='实发合计', compute='_compute_totals', store=True)
|
||||
|
||||
@api.depends('line_ids.amount', 'line_ids.item_id.item_type')
|
||||
def _compute_totals(self):
|
||||
for structure in self:
|
||||
income = sum(line.amount for line in structure.line_ids if line.item_id.item_type == 'income')
|
||||
deduction = sum(line.amount for line in structure.line_ids if line.item_id.item_type == 'deduction')
|
||||
structure.total_basic = income
|
||||
structure.total_deduction = deduction
|
||||
structure.total_net = income - deduction
|
||||
|
||||
_sql_constraints = [
|
||||
('code_uniq', 'unique(code)', '结构编码必须唯一!'),
|
||||
]
|
||||
|
||||
|
||||
class SalaryStructureLine(models.Model):
|
||||
"""薪资结构明细行"""
|
||||
_name = 'yuthon.salary.structure.line'
|
||||
_description = '薪资结构明细'
|
||||
_order = 'sequence, id'
|
||||
|
||||
structure_id = fields.Many2one('yuthon.salary.structure', string='薪资结构', required=True, ondelete='cascade')
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
item_id = fields.Many2one('yuthon.salary.item', string='薪资项目', required=True)
|
||||
amount = fields.Float(string='默认金额', default=0.0)
|
||||
note = fields.Char(string='备注')
|
||||
19
yuthon_salary/security/ir.model.access.csv
Normal file
19
yuthon_salary/security/ir.model.access.csv
Normal file
@ -0,0 +1,19 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_salary_item_user,yuthon.salary.item.user,model_yuthon_salary_item,base.group_user,1,0,0,0
|
||||
access_salary_item_manager,yuthon.salary.item.manager,model_yuthon_salary_item,yuthon_salary.group_manager,1,1,1,1
|
||||
access_salary_structure_user,yuthon.salary.structure.user,model_yuthon_salary_structure,base.group_user,1,0,0,0
|
||||
access_salary_structure_manager,yuthon.salary.structure.manager,model_yuthon_salary_structure,yuthon_salary.group_manager,1,1,1,1
|
||||
access_salary_structure_line_user,yuthon.salary.structure.line.user,model_yuthon_salary_structure_line,base.group_user,1,0,0,0
|
||||
access_salary_structure_line_manager,yuthon.salary.structure.line.manager,model_yuthon_salary_structure_line,yuthon_salary.group_manager,1,1,1,1
|
||||
access_employee_salary_user,yuthon.employee.salary.user,model_yuthon_employee_salary,base.group_user,1,0,0,0
|
||||
access_employee_salary_manager,yuthon.employee.salary.manager,model_yuthon_employee_salary,yuthon_salary.group_manager,1,1,1,1
|
||||
access_employee_salary_hr,yuthon.employee.salary.hr,model_yuthon_employee_salary,yuthon_salary.group_hr,1,1,1,0
|
||||
access_class_hour_user,yuthon.class.hour.user,model_yuthon_class_hour,base.group_user,1,1,1,0
|
||||
access_class_hour_manager,yuthon.class.hour.manager,model_yuthon_class_hour,yuthon_salary.group_manager,1,1,1,1
|
||||
access_class_teacher_allowance_user,yuthon.class.teacher.allowance.user,model_yuthon_class_teacher_allowance,base.group_user,1,1,1,0
|
||||
access_class_teacher_allowance_manager,yuthon.class.teacher.allowance.manager,model_yuthon_class_teacher_allowance,yuthon_salary.group_manager,1,1,1,1
|
||||
access_salary_slip_user,yuthon.salary.slip.user,model_yuthon_salary_slip,base.group_user,1,0,0,0
|
||||
access_salary_slip_manager,yuthon.salary.slip.manager,model_yuthon_salary_slip,yuthon_salary.group_manager,1,1,1,1
|
||||
access_salary_slip_hr,yuthon.salary.slip.hr,model_yuthon_salary_slip,yuthon_salary.group_hr,1,1,1,0
|
||||
access_salary_slip_line_user,yuthon.salary.slip.line.user,model_yuthon_salary_slip_line,base.group_user,1,0,0,0
|
||||
access_salary_slip_line_manager,yuthon.salary.slip.line.manager,model_yuthon_salary_slip_line,yuthon_salary.group_manager,1,1,1,1
|
||||
|
17
yuthon_salary/security/yuthon_salary_groups.xml
Normal file
17
yuthon_salary/security/yuthon_salary_groups.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- 薪资管理角色组 -->
|
||||
<record id="group_hr" model="res.groups">
|
||||
<field name="name">薪资专员</field>
|
||||
<field name="category_id" ref="base.module_category_human_resources"/>
|
||||
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_manager" model="res.groups">
|
||||
<field name="name">薪资管理员</field>
|
||||
<field name="category_id" ref="base.module_category_human_resources"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_hr'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
50
yuthon_salary/security/yuthon_salary_security.xml
Normal file
50
yuthon_salary/security/yuthon_salary_security.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- 薪资管理相关规则 -->
|
||||
<record id="rule_employee_salary_multi_company" model="ir.rule">
|
||||
<field name="name">教职工薪资档案:多学校隔离</field>
|
||||
<field name="model_id" ref="model_yuthon_employee_salary"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
|
||||
<record id="rule_salary_slip_multi_company" model="ir.rule">
|
||||
<field name="name">薪资单:多学校隔离</field>
|
||||
<field name="model_id" ref="model_yuthon_salary_slip"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
|
||||
<record id="rule_class_hour_multi_company" model="ir.rule">
|
||||
<field name="name">课时记录:多学校隔离</field>
|
||||
<field name="model_id" ref="model_yuthon_class_hour"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
|
||||
<record id="rule_class_teacher_allowance_multi_company" model="ir.rule">
|
||||
<field name="name">班主任津贴:多学校隔离</field>
|
||||
<field name="model_id" ref="model_yuthon_class_teacher_allowance"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
|
||||
<!-- 教职工只能查看自己的薪资单 -->
|
||||
<record id="rule_salary_slip_own_employee" model="ir.rule">
|
||||
<field name="name">教职工只能查看自己的薪资单</field>
|
||||
<field name="model_id" ref="model_yuthon_salary_slip"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||
</record>
|
||||
|
||||
<!-- 教职工只能查看自己的课时记录 -->
|
||||
<record id="rule_class_hour_own_employee" model="ir.rule">
|
||||
<field name="name">教职工只能查看自己的课时记录</field>
|
||||
<field name="model_id" ref="model_yuthon_class_hour"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
87
yuthon_salary/views/class_hour_views.xml
Normal file
87
yuthon_salary/views/class_hour_views.xml
Normal file
@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_class_hour_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.hour.tree</field>
|
||||
<field name="model">yuthon.class.hour</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="subject"/>
|
||||
<field name="grade"/>
|
||||
<field name="class_type"/>
|
||||
<field name="hours"/>
|
||||
<field name="rate"/>
|
||||
<field name="amount"/>
|
||||
<field name="state" widget="badge" decoration-success="state == 'approved'" decoration-info="state == 'submitted'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_class_hour_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.hour.form</field>
|
||||
<field name="model">yuthon.class.hour</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="action_submit" string="提交" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||
<button name="action_approve" string="确认" type="object" class="oe_highlight" invisible="state != 'submitted'"/>
|
||||
<button name="action_draft" string="退回草稿" type="object" invisible="state != 'submitted'"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,submitted,approved,paid"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id" readonly="1"/>
|
||||
<field name="date"/>
|
||||
<field name="subject"/>
|
||||
<field name="grade"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="class_type"/>
|
||||
<field name="hours"/>
|
||||
<field name="rate"/>
|
||||
<field name="amount" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="note" placeholder="备注..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_class_hour_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.hour.search</field>
|
||||
<field name="model">yuthon.class.hour</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="subject"/>
|
||||
<filter name="draft" string="草稿" domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="approved" string="已确认" domain="[('state', '=', 'approved')]"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="group_employee" string="按教师" context="{'group_by': 'employee_id'}"/>
|
||||
<filter name="group_class_type" string="按课程类型" context="{'group_by': 'class_type'}"/>
|
||||
<filter name="group_month" string="按月" context="{'group_by': 'date:month'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_class_hour" model="ir.actions.act_window">
|
||||
<field name="name">课时记录</field>
|
||||
<field name="res_model">yuthon.class.hour</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
106
yuthon_salary/views/class_teacher_allowance_views.xml
Normal file
106
yuthon_salary/views/class_teacher_allowance_views.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_class_teacher_allowance_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.teacher.allowance.tree</field>
|
||||
<field name="model">yuthon.class.teacher.allowance</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="year"/>
|
||||
<field name="month"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="class_name"/>
|
||||
<field name="student_count"/>
|
||||
<field name="total_amount"/>
|
||||
<field name="overall_score"/>
|
||||
<field name="state" widget="badge" decoration-success="state == 'approved'" decoration-info="state == 'submitted'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_class_teacher_allowance_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.teacher.allowance.form</field>
|
||||
<field name="model">yuthon.class.teacher.allowance</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="action_submit" string="提交" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||
<button name="action_approve" string="审核" type="object" class="oe_highlight" invisible="state != 'submitted'"/>
|
||||
<button name="action_draft" string="退回草稿" type="object" invisible="state != 'submitted'"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,submitted,approved,paid"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="基本信息">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id" readonly="1"/>
|
||||
<field name="class_name"/>
|
||||
<field name="grade_level"/>
|
||||
<field name="student_count"/>
|
||||
</group>
|
||||
<group string="考核周期">
|
||||
<field name="year"/>
|
||||
<field name="month"/>
|
||||
<field name="overall_score" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="津贴明细">
|
||||
<group>
|
||||
<field name="base_allowance"/>
|
||||
<field name="student_count_bonus"/>
|
||||
<field name="performance_bonus"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="special_allowance"/>
|
||||
<field name="deduction"/>
|
||||
<field name="total_amount" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="考核评分">
|
||||
<group>
|
||||
<field name="discipline_score"/>
|
||||
<field name="hygiene_score"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="activity_score"/>
|
||||
<field name="parent_score"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="note" placeholder="备注..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_class_teacher_allowance_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.class.teacher.allowance.search</field>
|
||||
<field name="model">yuthon.class.teacher.allowance</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="class_name"/>
|
||||
<filter name="draft" string="草稿" domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="approved" string="已审核" domain="[('state', '=', 'approved')]"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="group_employee" string="按班主任" context="{'group_by': 'employee_id'}"/>
|
||||
<filter name="group_month" string="按月" context="{'group_by': 'month'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_class_teacher_allowance" model="ir.actions.act_window">
|
||||
<field name="name">班主任津贴</field>
|
||||
<field name="res_model">yuthon.class.teacher.allowance</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
138
yuthon_salary/views/employee_salary_views.xml
Normal file
138
yuthon_salary/views/employee_salary_views.xml
Normal file
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_employee_salary_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.salary.tree</field>
|
||||
<field name="model">yuthon.employee.salary</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="job_id"/>
|
||||
<field name="teacher_title"/>
|
||||
<field name="basic_salary"/>
|
||||
<field name="state" widget="badge" decoration-success="state == 'active'" decoration-muted="state == 'draft'" decoration-danger="state == 'resigned'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_employee_salary_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.salary.form</field>
|
||||
<field name="model">yuthon.employee.salary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="action_activate" string="生效" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||
<button name="action_suspend" string="停薪" type="object" invisible="state != 'active'"/>
|
||||
<button name="action_resign" string="离职" type="object" invisible="state not in ('active', 'suspended')"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,active,suspended,resigned"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="基本信息">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id" readonly="1"/>
|
||||
<field name="job_id" readonly="1"/>
|
||||
<field name="employee_type"/>
|
||||
<field name="teacher_title"/>
|
||||
<field name="education_level"/>
|
||||
<field name="effective_date"/>
|
||||
</group>
|
||||
<group string="薪资结构">
|
||||
<field name="structure_id"/>
|
||||
<field name="basic_salary"/>
|
||||
<field name="position_salary"/>
|
||||
<field name="performance_salary"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="课时费标准">
|
||||
<group>
|
||||
<group>
|
||||
<field name="class_hour_rate_normal"/>
|
||||
<field name="class_hour_rate_overtime"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="class_hour_rate_weekend"/>
|
||||
<field name="class_hour_rate_holiday"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="津贴补贴">
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_class_teacher"/>
|
||||
<field name="class_teacher_allowance" invisible="is_class_teacher == False"/>
|
||||
<field name="class_level" invisible="is_class_teacher == False"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="seniority_allowance"/>
|
||||
<field name="education_allowance"/>
|
||||
<field name="title_allowance"/>
|
||||
<field name="other_allowance"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="社保公积金">
|
||||
<group>
|
||||
<group>
|
||||
<field name="social_insurance_base"/>
|
||||
<field name="provident_fund_base"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pension_rate_personal"/>
|
||||
<field name="medical_rate_personal"/>
|
||||
<field name="unemployment_rate_personal"/>
|
||||
<field name="provident_fund_rate_personal"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="银行卡信息">
|
||||
<group>
|
||||
<field name="bank_name"/>
|
||||
<field name="bank_account"/>
|
||||
<field name="bank_branch"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<field name="note" placeholder="备注..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_employee_salary_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.salary.search</field>
|
||||
<field name="model">yuthon.employee.salary</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<filter name="active" string="已生效" domain="[('state', '=', 'active')]"/>
|
||||
<filter name="draft" string="草稿" domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="resigned" string="已离职" domain="[('state', '=', 'resigned')]"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="group_department" string="按部门" context="{'group_by': 'department_id'}"/>
|
||||
<filter name="group_title" string="按职称" context="{'group_by': 'teacher_title'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_employee_salary" model="ir.actions.act_window">
|
||||
<field name="name">教职工薪资档案</field>
|
||||
<field name="res_model">yuthon.employee.salary</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
68
yuthon_salary/views/menu_views.xml
Normal file
68
yuthon_salary/views/menu_views.xml
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- 根菜单 -->
|
||||
<menuitem id="menu_yuthon_salary_root"
|
||||
name="薪资管理"
|
||||
web_icon="yuthon_salary,static/description/icon.png"
|
||||
sequence="50"/>
|
||||
|
||||
<!-- 配置菜单 -->
|
||||
<menuitem id="menu_salary_config"
|
||||
name="配置"
|
||||
parent="menu_yuthon_salary_root"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_salary_item"
|
||||
name="薪资项目"
|
||||
parent="menu_salary_config"
|
||||
action="action_salary_item"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_salary_structure"
|
||||
name="薪资结构"
|
||||
parent="menu_salary_config"
|
||||
action="action_salary_structure"
|
||||
sequence="20"/>
|
||||
|
||||
<!-- 档案菜单 -->
|
||||
<menuitem id="menu_salary_employee"
|
||||
name="教职工薪资"
|
||||
parent="menu_yuthon_salary_root"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_employee_salary"
|
||||
name="薪资档案"
|
||||
parent="menu_salary_employee"
|
||||
action="action_employee_salary"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_class_hour"
|
||||
name="课时记录"
|
||||
parent="menu_salary_employee"
|
||||
action="action_class_hour"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_class_teacher_allowance"
|
||||
name="班主任津贴"
|
||||
parent="menu_salary_employee"
|
||||
action="action_class_teacher_allowance"
|
||||
sequence="30"/>
|
||||
|
||||
<!-- 薪资发放菜单 -->
|
||||
<menuitem id="menu_salary_payment"
|
||||
name="薪资发放"
|
||||
parent="menu_yuthon_salary_root"
|
||||
sequence="30"/>
|
||||
|
||||
<menuitem id="menu_salary_slip"
|
||||
name="薪资单"
|
||||
parent="menu_salary_payment"
|
||||
action="action_salary_slip"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_salary_report"
|
||||
name="薪资报表"
|
||||
parent="menu_salary_payment"
|
||||
action="action_salary_report"
|
||||
sequence="20"/>
|
||||
</odoo>
|
||||
71
yuthon_salary/views/salary_item_views.xml
Normal file
71
yuthon_salary/views/salary_item_views.xml
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_salary_item_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.item.tree</field>
|
||||
<field name="model">yuthon.salary.item</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="category"/>
|
||||
<field name="item_type"/>
|
||||
<field name="calculation_method"/>
|
||||
<field name="is_required"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_item_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.item.form</field>
|
||||
<field name="model">yuthon.salary.item</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="sequence"/>
|
||||
<field name="category"/>
|
||||
<field name="item_type"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="calculation_method"/>
|
||||
<field name="is_taxable"/>
|
||||
<field name="is_social_base"/>
|
||||
<field name="is_required"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="formula" placeholder="请输入计算公式..." invisible="calculation_method != 'formula'"/>
|
||||
<field name="note" placeholder="备注说明..."/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_item_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.item.search</field>
|
||||
<field name="model">yuthon.salary.item</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<filter name="income" string="收入项" domain="[('item_type', '=', 'income')]"/>
|
||||
<filter name="deduction" string="扣款项" domain="[('item_type', '=', 'deduction')]"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="group_category" string="按类别" context="{'group_by': 'category'}"/>
|
||||
<filter name="group_type" string="按类型" context="{'group_by': 'item_type'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_salary_item" model="ir.actions.act_window">
|
||||
<field name="name">薪资项目</field>
|
||||
<field name="res_model">yuthon.salary.item</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
28
yuthon_salary/views/salary_report_views.xml
Normal file
28
yuthon_salary/views/salary_report_views.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_salary_slip_pivot" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.slip.pivot</field>
|
||||
<field name="model">yuthon.salary.slip</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot>
|
||||
<field name="department_id" type="row"/>
|
||||
<field name="year" type="col"/>
|
||||
<field name="month" type="col"/>
|
||||
<field name="total_income" type="measure"/>
|
||||
<field name="total_deduction" type="measure"/>
|
||||
<field name="net_salary" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_slip_graph" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.slip.graph</field>
|
||||
<field name="model">yuthon.salary.slip</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph type="bar">
|
||||
<field name="department_id" type="row"/>
|
||||
<field name="net_salary" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
137
yuthon_salary/views/salary_slip_views.xml
Normal file
137
yuthon_salary/views/salary_slip_views.xml
Normal file
@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_salary_slip_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.slip.tree</field>
|
||||
<field name="model">yuthon.salary.slip</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="year"/>
|
||||
<field name="month"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="total_income"/>
|
||||
<field name="total_deduction"/>
|
||||
<field name="net_salary"/>
|
||||
<field name="state" widget="badge" decoration-success="state == 'paid'" decoration-info="state == 'approved'" decoration-muted="state == 'draft'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_slip_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.slip.form</field>
|
||||
<field name="model">yuthon.salary.slip</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="action_calculate" string="计算薪资" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||
<button name="action_confirm" string="确认" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||
<button name="action_approve" string="审核" type="object" class="oe_highlight" invisible="state != 'confirmed'"/>
|
||||
<button name="action_pay" string="发放" type="object" class="oe_highlight" invisible="state != 'approved'"/>
|
||||
<button name="action_draft" string="退回草稿" type="object" invisible="state not in ('confirmed', 'approved')"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,approved,paid"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="基本信息">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id" readonly="1"/>
|
||||
<field name="job_id" readonly="1"/>
|
||||
<field name="salary_record_id"/>
|
||||
</group>
|
||||
<group string="薪资周期">
|
||||
<field name="year"/>
|
||||
<field name="month"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="收入明细">
|
||||
<group>
|
||||
<field name="basic_salary"/>
|
||||
<field name="position_salary"/>
|
||||
<field name="performance_salary"/>
|
||||
<field name="class_hour_fee"/>
|
||||
<field name="class_teacher_allowance"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="seniority_allowance"/>
|
||||
<field name="education_allowance"/>
|
||||
<field name="title_allowance"/>
|
||||
<field name="other_income"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="扣款明细">
|
||||
<group>
|
||||
<field name="pension_personal"/>
|
||||
<field name="medical_personal"/>
|
||||
<field name="unemployment_personal"/>
|
||||
<field name="provident_fund_personal"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="personal_income_tax"/>
|
||||
<field name="other_deduction"/>
|
||||
</group>
|
||||
</group>
|
||||
<group class="oe_subtotal_footer">
|
||||
<group>
|
||||
<field name="total_income"/>
|
||||
<field name="total_deduction"/>
|
||||
<div class="oe_subtotal_footer_separator">
|
||||
<label for="net_salary"/>
|
||||
</div>
|
||||
<field name="net_salary" nolabel="1" class="oe_subtotal_footer_separator"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="发放信息">
|
||||
<field name="bank_name"/>
|
||||
<field name="bank_account"/>
|
||||
</group>
|
||||
<field name="note" placeholder="备注..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_slip_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.slip.search</field>
|
||||
<field name="model">yuthon.salary.slip</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<filter name="draft" string="草稿" domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="confirmed" string="已确认" domain="[('state', '=', 'confirmed')]"/>
|
||||
<filter name="approved" string="已审核" domain="[('state', '=', 'approved')]"/>
|
||||
<filter name="paid" string="已发放" domain="[('state', '=', 'paid')]"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="group_department" string="按部门" context="{'group_by': 'department_id'}"/>
|
||||
<filter name="group_month" string="按月" context="{'group_by': 'month'}"/>
|
||||
<filter name="group_state" string="按状态" context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_salary_slip" model="ir.actions.act_window">
|
||||
<field name="name">薪资单</field>
|
||||
<field name="res_model">yuthon.salary.slip</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<!-- 薪资报表动作 -->
|
||||
<record id="action_salary_report" model="ir.actions.act_window">
|
||||
<field name="name">薪资报表</field>
|
||||
<field name="res_model">yuthon.salary.slip</field>
|
||||
<field name="view_mode">list,form,pivot,graph</field>
|
||||
</record>
|
||||
</odoo>
|
||||
63
yuthon_salary/views/salary_structure_views.xml
Normal file
63
yuthon_salary/views/salary_structure_views.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_salary_structure_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.structure.tree</field>
|
||||
<field name="model">yuthon.salary.structure</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="applicable_type"/>
|
||||
<field name="school_type"/>
|
||||
<field name="total_basic"/>
|
||||
<field name="total_deduction"/>
|
||||
<field name="total_net"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_salary_structure_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.salary.structure.form</field>
|
||||
<field name="model">yuthon.salary.structure</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="applicable_type"/>
|
||||
<field name="school_type"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="total_basic"/>
|
||||
<field name="total_deduction"/>
|
||||
<field name="total_net"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="description" placeholder="薪资结构说明..."/>
|
||||
<notebook>
|
||||
<page string="薪资项目明细">
|
||||
<field name="line_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="item_id"/>
|
||||
<field name="amount"/>
|
||||
<field name="note"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_salary_structure" model="ir.actions.act_window">
|
||||
<field name="name">薪资结构</field>
|
||||
<field name="res_model">yuthon.salary.structure</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue
Block a user