diff --git a/student_organization/__init__.py b/student_organization/__init__.py new file mode 100644 index 0000000..9a7e03e --- /dev/null +++ b/student_organization/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/student_organization/__manifest__.py b/student_organization/__manifest__.py new file mode 100644 index 0000000..bb1e444 --- /dev/null +++ b/student_organization/__manifest__.py @@ -0,0 +1,19 @@ +{ + 'name': 'student_organization', + 'version': '1.3', + 'summary': '', + 'sequence': 11, + 'depends': ['base','hr'], + 'data':[ + 'security/ir.model.access.csv', + 'views/view_student_organization.xml', + 'views/view_student_info.xml', + 'data/basic_grade.xml', + 'data/student_org.xml', + ], + + 'installable': True, + 'application': True, + + 'license': 'LGPL-3', +} diff --git a/student_organization/__pycache__/__init__.cpython-312.pyc b/student_organization/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..af2bdea Binary files /dev/null and b/student_organization/__pycache__/__init__.cpython-312.pyc differ diff --git a/student_organization/data/basic_grade.xml b/student_organization/data/basic_grade.xml new file mode 100644 index 0000000..65ef685 --- /dev/null +++ b/student_organization/data/basic_grade.xml @@ -0,0 +1,105 @@ + + + + 大一 + 1 + + + 大二 + 2 + + + 大三 + 3 + + + 大四 + 4 + + + + + 2010 + 1 + + + 2011 + 2 + + + 2012 + 3 + + + 2013 + 4 + + + 2014 + 5 + + + 2015 + 6 + + + 2016 + 7 + + + 2017 + 8 + + + 2018 + 9 + + + 2019 + 10 + + + 2020 + 11 + + + 2021 + 12 + + + 2022 + 13 + + + 2023 + 14 + + + 2024 + 15 + + + 2025 + 16 + + + 2026 + 17 + + + 2027 + 18 + + + 2028 + 19 + + + 2029 + 20 + + + 2030 + 21 + + \ No newline at end of file diff --git a/student_organization/data/student_org.xml b/student_organization/data/student_org.xml new file mode 100644 index 0000000..9f25991 --- /dev/null +++ b/student_organization/data/student_org.xml @@ -0,0 +1,249 @@ + + + + + + 信息工程学院 + 01 + college + 10 + + + + 经济管理学院 + 02 + college + 20 + + + + + 计算机科学与技术 + 080901 + major + + 10 + 4 + bachelor + + + + 软件工程 + 080902 + major + + 20 + 4 + bachelor + + + + 数据科学与大数据技术 + 080910T + major + + 30 + 4 + bachelor + + + + + 工商管理 + 120201K + major + + 10 + 4 + bachelor + + + + 市场营销 + 120202 + major + + 20 + 4 + bachelor + + + + 会计学 + 120203K + major + + 30 + 4 + bachelor + + + + + 计算机1班 + 08090101 + class + + 10 + 2024级 + + + + 计算机2班 + 08090102 + class + + 20 + 2024级 + + + + 计算机3班 + 08090103 + class + + 30 + 2024级 + + + + + 软件1班 + 08090201 + class + + 10 + 2024级 + + + + 软件2班 + 08090202 + class + + 20 + 2024级 + + + + 软件3班 + 08090203 + class + + 30 + 2024级 + + + + + 大数据1班 + 080910T01 + class + + 10 + 2024级 + + + + 大数据2班 + 080910T02 + class + + 20 + 2024级 + + + + 大数据3班 + 080910T03 + class + + 30 + 2024级 + + + + + 工商1班 + 120201K01 + class + + 10 + 2024级 + + + + 工商2班 + 120201K02 + class + + 20 + 2024级 + + + + 工商3班 + 120201K03 + class + + 30 + 2024级 + + + + + 营销1班 + 12020201 + class + + 10 + 2024级 + + + + 营销2班 + 12020202 + class + + 20 + 2024级 + + + + 营销3班 + 12020203 + class + + 30 + 2024级 + + + + + 会计1班 + 120203K01 + class + + 10 + 2024级 + + + + 会计2班 + 120203K02 + class + + 20 + 2024级 + + + + 会计3班 + 120203K03 + class + + 30 + 2024级 + + + \ No newline at end of file diff --git a/student_organization/models/__init__.py b/student_organization/models/__init__.py new file mode 100644 index 0000000..936e066 --- /dev/null +++ b/student_organization/models/__init__.py @@ -0,0 +1,3 @@ +from . import student_organization +from . import basic_grade +from . import student_info diff --git a/student_organization/models/__pycache__/__init__.cpython-312.pyc b/student_organization/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..67717f4 Binary files /dev/null and b/student_organization/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/student_organization/models/__pycache__/basic_grade.cpython-312.pyc b/student_organization/models/__pycache__/basic_grade.cpython-312.pyc new file mode 100644 index 0000000..13976b6 Binary files /dev/null and b/student_organization/models/__pycache__/basic_grade.cpython-312.pyc differ diff --git a/student_organization/models/__pycache__/student_info.cpython-312.pyc b/student_organization/models/__pycache__/student_info.cpython-312.pyc new file mode 100644 index 0000000..e7fb7d1 Binary files /dev/null and b/student_organization/models/__pycache__/student_info.cpython-312.pyc differ diff --git a/student_organization/models/__pycache__/student_organization.cpython-312.pyc b/student_organization/models/__pycache__/student_organization.cpython-312.pyc new file mode 100644 index 0000000..c218c9e Binary files /dev/null and b/student_organization/models/__pycache__/student_organization.cpython-312.pyc differ diff --git a/student_organization/models/basic_grade.py b/student_organization/models/basic_grade.py new file mode 100644 index 0000000..f745475 --- /dev/null +++ b/student_organization/models/basic_grade.py @@ -0,0 +1,20 @@ +from odoo import api,fields,models +from datetime import datetime +class BasicGradeXx(models.Model): + _name = 'basic.grade.xx' #xx 详细 + _rec_name = 'grade' + grade=fields.Char(string='年级') + sequence=fields.Integer(string='序号') + @api.model + def _get_current_year_range_domain(self): + year = datetime.now().year + return [('name', '>=', str(year - 4)), ('name', '<=', + str(year + 1))] # 别的直接调用domain = lambda self: self.env['basic.grade.xx']._get_current_year_range_domain() + + +class BasicGradeBx(models.Model): + _name = 'basic.grade.bx' #xx 不详细 + _rec_name = 'grade' + grade=fields.Char(string='年级') + sequence = fields.Integer(string='序号') + diff --git a/student_organization/models/student_info.py b/student_organization/models/student_info.py new file mode 100644 index 0000000..ca54486 --- /dev/null +++ b/student_organization/models/student_info.py @@ -0,0 +1,54 @@ +from odoo import api,models,fields + +class StudentInfo(models.Model): + _name="student.info" + + stu_name=fields.Char(string="姓名",tracking=True) + stu_num=fields.Char(string="学号",tracking=True) + stu_sex = fields.Selection([('male', '男'),('female', '女')], string="性别", default='male', required=True) + stu_birthday = fields.Date(string="出生日期", tracking=True) + stu_id_card = fields.Char(string="身份证号", index=True, tracking=True) + stu_nation = fields.Char(string="民族", default="汉族") + stu_shenfen = fields.Selection([ + ('mass', '群众'), + ('league', '共青团员'), + ('party', '中共党员'), + ('other', '其他') + ], string="政治面貌", default='mass') + stu_phone = fields.Char(string="手机号") + stu_email = fields.Char(string="邮箱") + stu_address = fields.Text(string="家庭地址") + stu_emergency_contact = fields.Char(string="紧急联系人") + stu_emergency_phone = fields.Char(string="紧急联系电话") + stu_photo = fields.Binary(string="照片", attachment=True) + stu_begin_date = fields.Date(string="入学日期", required=True, tracking=True) + stu_end_date = fields.Date(string="毕业日期") + stu_grade_xx = fields.Many2one('basic.grade.xx',string="年级", tracking=True,domain = lambda self: self.env['basic.grade.xx']._get_current_year_range_domain()) + stu_grade_bx=fields.Many2one('basic.grade.xx',string='年级',readonle=1) + stu_status = fields.Selection([ + ('studying', '在读'), + ('graduated', '已毕业'), + ('suspended', '休学'), + ('expelled', '退学'), + ('transferred', '转出') + ], string="学籍状态", default='studying', tracking=True) + org_path = fields.Char(string='组织路径', compute='_compute_org_path', + store=True, index=True) + + class_id = fields.Many2one('student.organization', string="行政班", tracking=True,domain="[('org_type', '=', 'class')]") + parent_path = fields.Char(related='class_id.parent_path',store=True) + class_name = fields.Char(string="班级名称", related='class_id.name', store=True) + major_id = fields.Many2one('student.organization', string="专业", tracking=True,domain="[('org_type', '=', 'major')]") + major_name = fields.Char(string="专业名称", related='major_id.name', store=True) + department_id = fields.Many2one('student.organization', string="院系",store=True,domain="[('org_type', '=', 'college')]") + + + # user_id = fields.Many2one('res.users', string="系统用户", ondelete='restrict') + @api.depends('parent_path') + def _compute_org_path(self): + for record in self: + if record.class_id: + # 直接使用班级的 parent_path + 班级ID + record.org_path = f"{record.class_id.parent_path}{record.class_id.id}/" + else: + record.org_path = False \ No newline at end of file diff --git a/student_organization/models/student_organization.py b/student_organization/models/student_organization.py new file mode 100644 index 0000000..5e9eccd --- /dev/null +++ b/student_organization/models/student_organization.py @@ -0,0 +1,75 @@ +from odoo import api, fields, models + + +class StudentOrganization(models.Model): + _name = 'student.organization' + _description = '学生架构' + _rec_name = 'full_name' + _order = 'parent_id, sequence, id' + _parent_store = True + + _parent_order = 'sequence, name' + + # 基本信息 + name = fields.Char(string='名称', required=True, translate=True) + code = fields.Char(string='代码') + sequence = fields.Integer(string='序号', default=10) + + org_type = fields.Selection([ + ('college', '学院'), + ('major', '专业'), + ('class', '班级'), #用法 domain="[('org_type', '=', 'class')]" + ], string='类型', required=True) + + # 层级关系 + parent_id = fields.Many2one('student.organization', string='上级组织', ondelete='cascade') + child_ids = fields.One2many('student.organization', 'parent_id', string='下级组织') + parent_path = fields.Char(index=True) + + # 完整名称(显示层级) + full_name = fields.Char(string='完整名称', compute='_compute_full_name', store=True) + + # 负责人信息(学院用) + manager_id = fields.Many2one('res.users', string='负责人') + + # 联系方式(学院用) + phone = fields.Char(string='电话') + mobile = fields.Char(string='手机') + email = fields.Char(string='邮箱') + address = fields.Text(string='办公地址') + + # 专业专用字段 + duration = fields.Integer(string='修业年限(年)', default=4) + degree = fields.Selection([ + ('bachelor', '学士'), + ('master', '硕士'), + ('doctor', '博士'), + ], string='学位') + + # 班级专用字段 + grade = fields.Char(string='年级') + + homeroom_teacher = fields.Many2one('hr.employee', string='导员') + + # 统计字段 + student_count = fields.Integer(string='学生数', compute='_compute_student_count') + + @api.depends('parent_id.full_name', 'name') + def _compute_full_name(self): + for record in self: + if record.parent_id: + record.full_name = f'{record.parent_id.full_name} / {record.name}' + else: + record.full_name = record.name + + def _compute_student_count(self): + for record in self: + if record.org_type == 'class': + # 班级的学生数 + record.student_count = self.env['student.info'].search_count([('class_id', '=', record.id)]) + else: + # 学院/专业的学生数(统计下级) + students = self.env['student.info'].search([ + ('org_path', 'like', f'{record.parent_path}%') + ]) if record.parent_path else self.env['student.info'].search([]) + record.student_count = len(students) \ No newline at end of file diff --git a/student_organization/security/ir.model.access.csv b/student_organization/security/ir.model.access.csv new file mode 100644 index 0000000..bf78021 --- /dev/null +++ b/student_organization/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_student_organization_sys,student.organization.access.sys,model_student_organization,base.group_system,1,1,1,1 +access_student_info_sys,student.info.access.sys,model_student_info,base.group_system,1,1,1,1 +access_basic_grade_xx_sys,basic.grade.access.sys,model_basic_grade_xx,base.group_system,1,1,1,1 +access_basic_grade_bx_sys,basic.grade.access.sys,model_basic_grade_bx,base.group_system,1,1,1,1 \ No newline at end of file diff --git a/student_organization/views/view_student_info.xml b/student_organization/views/view_student_info.xml new file mode 100644 index 0000000..4cfd0ec --- /dev/null +++ b/student_organization/views/view_student_info.xml @@ -0,0 +1,95 @@ + + + student.info.list + student.info + + + + + + + + + + + + + + student.info.form + student.info + +
+ +
+
+
+

+ +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 学生信息 + student.info + list,form + + + + student.info.search + student.info + + + + + + + + + + + 学生 + + 9 + + + \ No newline at end of file diff --git a/student_organization/views/view_student_organization.xml b/student_organization/views/view_student_organization.xml new file mode 100644 index 0000000..fbf46be --- /dev/null +++ b/student_organization/views/view_student_organization.xml @@ -0,0 +1,105 @@ + + + + student.organization.list + student.organization + + + + + + + + + + + + + + + student.organization.form + student.organization + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + student.organization.sub.list + student.organization + + + + + + + + + + + + + + 组织架构 + student.organization + list,form,search + + + + + + + 学生架构 + 11 + + + + 组织架构 + + + +
\ No newline at end of file