From 176da7546b12cd06763c2c3a10468575e9a10d70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 31 Jul 2026 20:38:10 +0800
Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=BF=81=E7=A7=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_attendance/__manifest__.py | 33 +++++++
yuthon_attendance/data/demo.xml | 31 +++++++
.../security/ir.model.access.csv | 2 +
yuthon_attendance/views/attendance_views.xml | 38 ++++++++
yuthon_employee/data/demo.xml | 39 ++++++++
yuthon_employee/security/ir.model.access.csv | 2 +
yuthon_employee/views/employee_views.xml | 88 +++++++++++++++++++
yuthon_salary/security/ir.model.access.csv | 3 +
yuthon_salary/views/payslip_views.xml | 34 +++++++
yuthon_salary/wizards/__init__.py | 1 +
yuthon_salary/wizards/payslip_generate.py | 41 +++++++++
11 files changed, 312 insertions(+)
diff --git a/yuthon_attendance/__manifest__.py b/yuthon_attendance/__manifest__.py
index e69de29..7868dd5 100644
--- a/yuthon_attendance/__manifest__.py
+++ b/yuthon_attendance/__manifest__.py
@@ -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,
+}
diff --git a/yuthon_attendance/data/demo.xml b/yuthon_attendance/data/demo.xml
index e69de29..340143f 100644
--- a/yuthon_attendance/data/demo.xml
+++ b/yuthon_attendance/data/demo.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ 2024-09-02
+
+
+
+
+
+ 2024-09-03
+
+
+
+
+
+
+
+ 2024-09-02
+
+
+
+
+
+ 2024-09-02
+
+
+
+
diff --git a/yuthon_attendance/security/ir.model.access.csv b/yuthon_attendance/security/ir.model.access.csv
index e69de29..313c5a6 100644
--- a/yuthon_attendance/security/ir.model.access.csv
+++ b/yuthon_attendance/security/ir.model.access.csv
@@ -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
diff --git a/yuthon_attendance/views/attendance_views.xml b/yuthon_attendance/views/attendance_views.xml
index bafe960..d8da8fa 100644
--- a/yuthon_attendance/views/attendance_views.xml
+++ b/yuthon_attendance/views/attendance_views.xml
@@ -111,4 +111,42 @@
parent="yuthon_employee.menu_yuthon_hr_root"
action="action_yuthon_attendance" sequence="20"/>
+
+
+
+ yuthon.employee.list.inherit.attendance
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+ yuthon.employee.form.inherit.attendance
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yuthon_employee/data/demo.xml b/yuthon_employee/data/demo.xml
index e69de29..0ba1ade 100644
--- a/yuthon_employee/data/demo.xml
+++ b/yuthon_employee/data/demo.xml
@@ -0,0 +1,39 @@
+
+
+
+
+ T2024001
+ 张三
+ male
+ teaching
+ 讲师
+ 13800000001
+ zhangsan@school.edu
+ 8000.0
+ 2024-09-01
+
+
+
+ A2024002
+ 李四
+ female
+ admin
+ 教务员
+ 13800000002
+ lisi@school.edu
+ 6000.0
+ 2024-09-01
+
+
+
+ T2024003
+ 王五
+ male
+ teaching
+ 副教授
+ 13800000003
+ wangwu@school.edu
+ 12000.0
+ 2024-09-01
+
+
diff --git a/yuthon_employee/security/ir.model.access.csv b/yuthon_employee/security/ir.model.access.csv
index e69de29..a7bf7eb 100644
--- a/yuthon_employee/security/ir.model.access.csv
+++ b/yuthon_employee/security/ir.model.access.csv
@@ -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
diff --git a/yuthon_employee/views/employee_views.xml b/yuthon_employee/views/employee_views.xml
index e69de29..0018dbb 100644
--- a/yuthon_employee/views/employee_views.xml
+++ b/yuthon_employee/views/employee_views.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+ yuthon.employee.list
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ yuthon.employee.form
+ yuthon.employee
+
+
+
+
+
+
+
+ yuthon.employee搜索
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 教职工
+ yuthon.employee
+ list,form
+
+
+
+
+
+
+
+
diff --git a/yuthon_salary/security/ir.model.access.csv b/yuthon_salary/security/ir.model.access.csv
index e69de29..dc19f9a 100644
--- a/yuthon_salary/security/ir.model.access.csv
+++ b/yuthon_salary/security/ir.model.access.csv
@@ -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
diff --git a/yuthon_salary/views/payslip_views.xml b/yuthon_salary/views/payslip_views.xml
index 2331ab8..885e6a1 100644
--- a/yuthon_salary/views/payslip_views.xml
+++ b/yuthon_salary/views/payslip_views.xml
@@ -105,4 +105,38 @@
parent="yuthon_employee.menu_yuthon_hr_root"
action="action_yuthon_payslip" sequence="30"/>
+
+
+
+ yuthon.employee.list.inherit.salary
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+ yuthon.employee.form.inherit.salary
+ yuthon.employee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yuthon_salary/wizards/__init__.py b/yuthon_salary/wizards/__init__.py
index e69de29..c478c96 100644
--- a/yuthon_salary/wizards/__init__.py
+++ b/yuthon_salary/wizards/__init__.py
@@ -0,0 +1 @@
+from . import payslip_generate
diff --git a/yuthon_salary/wizards/payslip_generate.py b/yuthon_salary/wizards/payslip_generate.py
index e69de29..b414a3f 100644
--- a/yuthon_salary/wizards/payslip_generate.py
+++ b/yuthon_salary/wizards/payslip_generate.py
@@ -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)],
+ }