模块迁移
This commit is contained in:
parent
cfe31fc044
commit
176da7546b
@ -0,0 +1,33 @@
|
||||
{
|
||||
'name': 'Yuthon 出勤管理',
|
||||
'version': '18.0.1.0.0',
|
||||
'summary': '打卡出勤:签到/签退,自动计算工时、迟到与状态',
|
||||
'description': """
|
||||
教学模块②(关系层):yuthon_attendance
|
||||
======================================
|
||||
依赖 yuthon_employee。定义出勤记录模型 yuthon.attendance(挂在员工下,
|
||||
一对一 N:1),并演示计算字段(working_hours / status / late_minutes)
|
||||
与模块组合(_inherit yuthon.employee 追加反向 attendance_ids)。
|
||||
|
||||
教学要点:
|
||||
- Many2one 关系:employee_id 外键 + ondelete='cascade'
|
||||
- computed field:@api.depends 计算工时、迟到分钟、出勤状态
|
||||
- 约束:_sql_constraints(一人一天一条)、check_in < check_out
|
||||
- 分析视图:graph / pivot 统计出勤
|
||||
""",
|
||||
'author': 'Yuthon',
|
||||
'website': '',
|
||||
'category': 'Education',
|
||||
'depends': ['yuthon_employee', 'web'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/attendance_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/demo.xml',
|
||||
],
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- 演示数据:出勤记录。employee_id 通过 ref 引用 yuthon_employee 的 demo。 -->
|
||||
<!-- 张三:9月2日正常、9月3日迟到 -->
|
||||
<record id="attendance_zhang_0902" model="yuthon.attendance">
|
||||
<field name="employee_id" ref="yuthon_employee.employee_zhang"/>
|
||||
<field name="date">2024-09-02</field>
|
||||
<field name="check_in" eval="datetime.datetime(2024, 9, 2, 8, 30, 0)"/>
|
||||
<field name="check_out" eval="datetime.datetime(2024, 9, 2, 17, 30, 0)"/>
|
||||
</record>
|
||||
<record id="attendance_zhang_0903" model="yuthon.attendance">
|
||||
<field name="employee_id" ref="yuthon_employee.employee_zhang"/>
|
||||
<field name="date">2024-09-03</field>
|
||||
<field name="check_in" eval="datetime.datetime(2024, 9, 3, 9, 35, 0)"/>
|
||||
<field name="check_out" eval="datetime.datetime(2024, 9, 3, 17, 30, 0)"/>
|
||||
</record>
|
||||
|
||||
<!-- 李四:9月2日缺勤(无签到) -->
|
||||
<record id="attendance_li_0902" model="yuthon.attendance">
|
||||
<field name="employee_id" ref="yuthon_employee.employee_li"/>
|
||||
<field name="date">2024-09-02</field>
|
||||
</record>
|
||||
|
||||
<!-- 王五:9月2日正常 -->
|
||||
<record id="attendance_wang_0902" model="yuthon.attendance">
|
||||
<field name="employee_id" ref="yuthon_employee.employee_wang"/>
|
||||
<field name="date">2024-09-02</field>
|
||||
<field name="check_in" eval="datetime.datetime(2024, 9, 2, 8, 50, 0)"/>
|
||||
<field name="check_out" eval="datetime.datetime(2024, 9, 2, 18, 0, 0)"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_yuthon_attendance,yuthon.attendance,yuthon_attendance.model_yuthon_attendance,base.group_user,1,1,1,1
|
||||
|
@ -111,4 +111,42 @@
|
||||
parent="yuthon_employee.menu_yuthon_hr_root"
|
||||
action="action_yuthon_attendance" sequence="20"/>
|
||||
|
||||
<!-- ============ 注入「教职工」视图(模块组合演示) ============ -->
|
||||
<!-- 列表:追加出勤记录数列 -->
|
||||
<record id="view_yuthon_employee_list_attendance" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.list.inherit.attendance</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="inherit_id" ref="yuthon_employee.view_yuthon_employee_list"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='base_salary']" position="after">
|
||||
<field name="attendance_count"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 表单:注入出勤记录页 -->
|
||||
<record id="view_yuthon_employee_form_attendance" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.form.inherit.attendance</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="inherit_id" ref="yuthon_employee.view_yuthon_employee_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<notebook>
|
||||
<page string="出勤记录">
|
||||
<field name="attendance_ids">
|
||||
<list>
|
||||
<field name="date"/>
|
||||
<field name="check_in"/>
|
||||
<field name="check_out"/>
|
||||
<field name="working_hours"/>
|
||||
<field name="status"/>
|
||||
<field name="late_minutes"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- 演示数据:3 名教职工(数据根)。出勤/薪资 demo 通过 ref 引用这里的 id。 -->
|
||||
<record id="employee_zhang" model="yuthon.employee">
|
||||
<field name="employee_no">T2024001</field>
|
||||
<field name="name">张三</field>
|
||||
<field name="gender">male</field>
|
||||
<field name="department">teaching</field>
|
||||
<field name="job_title">讲师</field>
|
||||
<field name="phone">13800000001</field>
|
||||
<field name="email">zhangsan@school.edu</field>
|
||||
<field name="base_salary">8000.0</field>
|
||||
<field name="hire_date">2024-09-01</field>
|
||||
</record>
|
||||
|
||||
<record id="employee_li" model="yuthon.employee">
|
||||
<field name="employee_no">A2024002</field>
|
||||
<field name="name">李四</field>
|
||||
<field name="gender">female</field>
|
||||
<field name="department">admin</field>
|
||||
<field name="job_title">教务员</field>
|
||||
<field name="phone">13800000002</field>
|
||||
<field name="email">lisi@school.edu</field>
|
||||
<field name="base_salary">6000.0</field>
|
||||
<field name="hire_date">2024-09-01</field>
|
||||
</record>
|
||||
|
||||
<record id="employee_wang" model="yuthon.employee">
|
||||
<field name="employee_no">T2024003</field>
|
||||
<field name="name">王五</field>
|
||||
<field name="gender">male</field>
|
||||
<field name="department">teaching</field>
|
||||
<field name="job_title">副教授</field>
|
||||
<field name="phone">13800000003</field>
|
||||
<field name="email">wangwu@school.edu</field>
|
||||
<field name="base_salary">12000.0</field>
|
||||
<field name="hire_date">2024-09-01</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_yuthon_employee,yuthon.employee,yuthon_employee.model_yuthon_employee,base.group_user,1,1,1,1
|
||||
|
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============ 列表视图 ============ -->
|
||||
<record id="view_yuthon_employee_list" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.list</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="教职工">
|
||||
<field name="employee_no"/>
|
||||
<field name="name"/>
|
||||
<field name="gender"/>
|
||||
<field name="department"/>
|
||||
<field name="job_title"/>
|
||||
<field name="base_salary"/>
|
||||
<field name="active" optional="hide"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============ 表单视图 ============ -->
|
||||
<record id="view_yuthon_employee_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.form</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="教职工">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_no"/>
|
||||
<field name="name"/>
|
||||
<field name="gender"/>
|
||||
<field name="department"/>
|
||||
<field name="job_title"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="phone"/>
|
||||
<field name="email"/>
|
||||
<field name="base_salary"/>
|
||||
<field name="hire_date"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============ 搜索视图 ============ -->
|
||||
<record id="view_yuthon_employee_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee搜索</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="搜索教职工">
|
||||
<field name="employee_no"/>
|
||||
<field name="name"/>
|
||||
<field name="department"/>
|
||||
<separator/>
|
||||
<filter name="filter_teaching" string="教学部"
|
||||
domain="[('department', '=', 'teaching')]"/>
|
||||
<filter name="filter_active" string="在职"
|
||||
domain="[('active', '=', True)]"/>
|
||||
<separator/>
|
||||
<group expand="0" string="分组">
|
||||
<filter name="groupby_department" string="按部门"
|
||||
context="{'group_by': 'department'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============ 动作 ============ -->
|
||||
<record id="action_yuthon_employee" model="ir.actions.act_window">
|
||||
<field name="name">教职工</field>
|
||||
<field name="res_model">yuthon.employee</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="search_view_id" ref="view_yuthon_employee_search"/>
|
||||
</record>
|
||||
|
||||
<!-- ============ 根菜单(人事管理) ============ -->
|
||||
<menuitem id="menu_yuthon_hr_root" name="人事管理"
|
||||
web_icon="yuthon_employee,static/description/icon.png"
|
||||
sequence="10"/>
|
||||
<menuitem id="menu_yuthon_employee" name="教职工"
|
||||
parent="menu_yuthon_hr_root"
|
||||
action="action_yuthon_employee" sequence="20"/>
|
||||
|
||||
</odoo>
|
||||
@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_yuthon_payslip,yuthon.payslip,yuthon_salary.model_yuthon_payslip,base.group_user,1,1,1,1
|
||||
access_yuthon_payslip_generate,yuthon.payslip.generate.wizard,yuthon_salary.model_yuthon_payslip_generate_wizard,base.group_user,1,0,1,0
|
||||
|
@ -105,4 +105,38 @@
|
||||
parent="yuthon_employee.menu_yuthon_hr_root"
|
||||
action="action_yuthon_payslip" sequence="30"/>
|
||||
|
||||
<!-- ============ 注入「教职工」视图(模块组合演示) ============ -->
|
||||
<!-- 列表:追加工资条数列 -->
|
||||
<record id="view_yuthon_employee_list_salary" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.list.inherit.salary</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="inherit_id" ref="yuthon_employee.view_yuthon_employee_list"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='attendance_count']" position="after">
|
||||
<field name="payslip_count"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 表单:注入工资条页 -->
|
||||
<record id="view_yuthon_employee_form_salary" model="ir.ui.view">
|
||||
<field name="name">yuthon.employee.form.inherit.salary</field>
|
||||
<field name="model">yuthon.employee</field>
|
||||
<field name="inherit_id" ref="yuthon_employee.view_yuthon_employee_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="工资条">
|
||||
<field name="payslip_ids">
|
||||
<list>
|
||||
<field name="period_start"/>
|
||||
<field name="period_end"/>
|
||||
<field name="net_salary"/>
|
||||
<field name="state"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@ -0,0 +1 @@
|
||||
from . import payslip_generate
|
||||
@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class PayslipGenerateWizard(models.TransientModel):
|
||||
"""生成月度工资条向导:批量给选定教职工创建 yuthon.payslip。
|
||||
|
||||
教学要点:TransientModel(向导模型,数据临时、自动清理)+ 批量创建。
|
||||
"""
|
||||
_name = 'yuthon.payslip.generate.wizard'
|
||||
_description = '生成月度工资条向导'
|
||||
|
||||
period_start = fields.Date(string='起始日期', required=True)
|
||||
period_end = fields.Date(string='结束日期', required=True)
|
||||
allowance = fields.Float(string='津贴/补贴', default=0.0)
|
||||
employee_ids = fields.Many2many(
|
||||
'yuthon.employee',
|
||||
string='教职工',
|
||||
)
|
||||
|
||||
def action_generate(self):
|
||||
"""为每位选定教职工创建一条工资条(带默认值,算出迟到/缺勤/实发)。"""
|
||||
self.ensure_one()
|
||||
Payslip = self.env['yuthon.payslip']
|
||||
employees = self.employee_ids or self.env['yuthon.employee'].search([])
|
||||
created = Payslip
|
||||
for emp in employees:
|
||||
created |= Payslip.create({
|
||||
'employee_id': emp.id,
|
||||
'period_start': self.period_start,
|
||||
'period_end': self.period_end,
|
||||
'allowance': self.allowance,
|
||||
})
|
||||
# 返回刚生成的工资条列表视图
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '工资条',
|
||||
'res_model': 'yuthon.payslip',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('id', 'in', created.ids)],
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user